protected final void _flushBuffer() throws IOException { int len = _outputTail - _outputHead; if (len > 0) { int offset = _outputHead; _outputTail = _outputHead = 0; _writer.write(_outputBuffer, offset, len); } }
@Override public void close() throws IOException { _flushBuffer(); /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying Reader, unless we "own" it, or auto-closing * feature is enabled. * One downside: when using UTF8Writer, underlying buffer(s) * may not be properly recycled if we don't close the writer. */ if (_ioContext.isResourceManaged() || isFeatureEnabled(Feature.AUTO_CLOSE_TARGET)) { _writer.close(); } else { // If we can't close it, we should at least flush _writer.flush(); } // Internal buffer(s) generator has can now be released as well _releaseBuffers(); }
/** * @param escCode Character code for escape sequence (\C); or -1 to indicate a generic (\\uXXXX) * sequence. */ private void _writeSingleEscape(int escCode) throws IOException { char[] buf = _entityBuffer; if (buf == null) { buf = new char[6]; buf[0] = '\\'; buf[2] = '0'; buf[3] = '0'; } if (escCode < 0) { // control char, value -(char + 1) int value = -(escCode + 1); buf[1] = 'u'; // We know it's a control char, so only the last 2 chars are non-0 buf[4] = HEX_CHARS[value >> 4]; buf[5] = HEX_CHARS[value & 0xF]; _writer.write(buf, 0, 6); } else { buf[1] = (char) escCode; _writer.write(buf, 0, 2); } }
/** * This method called when the string content is already in a char buffer, and need not be copied * for processing. */ private void _writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { /* Let's just find longest spans of non-escapable * content, and for each see if it makes sense * to copy them, or write through */ len += offset; // -> len marks the end from now on final int[] escCodes = CharTypes.getOutputEscapes(); final int escLen = escCodes.length; while (offset < len) { int start = offset; while (true) { char c = text[offset]; if (c < escLen && escCodes[c] != 0) { break; } if (++offset >= len) { break; } } // Short span? Better just copy it to buffer first: int newAmount = offset - start; if (newAmount < SHORT_WRITE) { // Note: let's reserve room for escaped char (up to 6 chars) if ((_outputTail + newAmount) > _outputEnd) { _flushBuffer(); } if (newAmount > 0) { System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount); _outputTail += newAmount; } } else { // Nope: better just write through _flushBuffer(); _writer.write(text, start, newAmount); } // Was this the end? if (offset >= len) { // yup break; } // Nope, need to escape the char. int escCode = escCodes[text[offset]]; ++offset; int needLen = (escCode < 0) ? 6 : 2; if ((_outputTail + needLen) > _outputEnd) { _flushBuffer(); } _appendSingleEscape(escCode, _outputBuffer, _outputTail); _outputTail += needLen; } }
/** * Method called to output textual context which has been copied to the output buffer prior to * call. If any escaping is needed, it will also be handled by the method. * * <p>Note: when called, textual content to write is within output buffer, right after buffered * content (if any). That's why only length of that text is passed, as buffer and offset are * implied. */ private final void _writeSegment(int end) throws IOException, JsonGenerationException { final int[] escCodes = CharTypes.getOutputEscapes(); final int escLen = escCodes.length; int ptr = 0; output_loop: while (ptr < end) { // Fast loop for chars not needing escaping int start = ptr; while (true) { char c = _outputBuffer[ptr]; if (c < escLen && escCodes[c] != 0) { break; } if (++ptr >= end) { break; } } // Ok, bumped into something that needs escaping. /* First things first: need to flush the buffer. * Inlined, as we don't want to lose tail pointer */ int flushLen = (ptr - start); if (flushLen > 0) { _writer.write(_outputBuffer, start, flushLen); if (ptr >= end) { break output_loop; } } /* In any case, tail will be the new start, so hopefully * we have room now. */ { int escCode = escCodes[_outputBuffer[ptr]]; ++ptr; int needLen = (escCode < 0) ? 6 : 2; // If not, need to call separate method (note: buffer is empty now) if (needLen > _outputTail) { _writeSingleEscape(escCode); } else { // But if it fits, can just prepend to buffer ptr -= needLen; _appendSingleEscape(escCode, _outputBuffer, ptr); } } } }
public void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException { // Only worth buffering if it's a short write? if (len < SHORT_WRITE) { int room = _outputEnd - _outputTail; if (len > room) { _flushBuffer(); } System.arraycopy(text, offset, _outputBuffer, _outputTail, len); _outputTail += len; return; } // Otherwise, better just pass through: _flushBuffer(); _writer.write(text, offset, len); }
private void _writeString(String text) throws IOException, JsonGenerationException { /* One check first: if String won't fit in the buffer, let's * segment writes. No point in extending buffer to huge sizes * (like if someone wants to include multi-megabyte base64 * encoded stuff or such) */ int len = text.length(); if (len > _outputEnd) { // Let's reserve space for entity at begin/end _writeLongString(text); return; } // Ok: we know String will fit in buffer ok // But do we need to flush first? if ((_outputTail + len) > _outputEnd) { _flushBuffer(); } text.getChars(0, len, _outputBuffer, _outputTail); // And then we'll need to verify need for escaping etc: int end = _outputTail + len; final int[] escCodes = CharTypes.getOutputEscapes(); final int escLen = escCodes.length; output_loop: while (_outputTail < end) { // Fast loop for chars not needing escaping escape_loop: while (true) { char c = _outputBuffer[_outputTail]; if (c < escLen && escCodes[c] != 0) { break escape_loop; } if (++_outputTail >= end) { break output_loop; } } // Ok, bumped into something that needs escaping. /* First things first: need to flush the buffer. * Inlined, as we don't want to lose tail pointer */ int flushLen = (_outputTail - _outputHead); if (flushLen > 0) { _writer.write(_outputBuffer, _outputHead, flushLen); } /* In any case, tail will be the new start, so hopefully * we have room now. */ { int escCode = escCodes[_outputBuffer[_outputTail]]; ++_outputTail; int needLen = (escCode < 0) ? 6 : 2; // If not, need to call separate method (note: buffer is empty now) if (needLen > _outputTail) { _outputHead = _outputTail; _writeSingleEscape(escCode); } else { // But if it fits, can just prepend to buffer int ptr = _outputTail - needLen; _outputHead = ptr; _appendSingleEscape(escCode, _outputBuffer, ptr); } } } }
@Override public final void flush() throws IOException { _flushBuffer(); _writer.flush(); }