package com.fasterxml.jackson.core.json;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.CharTypes;
import com.fasterxml.jackson.core.io.CharacterEscapes;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.io.NumberOutput;
public class UTF8JsonGenerator
extends JsonGeneratorImpl
{
private final static byte BYTE_u = (byte) 'u';
private final static byte BYTE_0 = (byte) '0';
private final static byte BYTE_LBRACKET = (byte) '[';
private final static byte BYTE_RBRACKET = (byte) ']';
private final static byte BYTE_LCURLY = (byte) '{';
private final static byte BYTE_RCURLY = (byte) '}';
private final static byte BYTE_BACKSLASH = (byte) '\\';
private final static byte BYTE_COMMA = (byte) ',';
private final static byte BYTE_COLON = (byte) ':';
private final static int MAX_BYTES_TO_BUFFER = 512;
private final static byte[] HEX_CHARS = CharTypes.copyHexBytes();
private final static byte[] NULL_BYTES = { 'n', 'u', 'l', 'l' };
private final static byte[] TRUE_BYTES = { 't', 'r', 'u', 'e' };
private final static byte[] FALSE_BYTES = { 'f', 'a', 'l', 's', 'e' };
final protected OutputStream _outputStream;
protected byte _quoteChar = '"';
protected byte[] _outputBuffer;
protected int _outputTail;
protected final int _outputEnd;
protected final int _outputMaxContiguous;
protected char[] _charBuffer;
protected final int _charBufferLength;
protected byte[] _entityBuffer;
protected boolean _bufferRecyclable;
public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
OutputStream out)
{
super(ctxt, features, codec);
_outputStream = out;
_bufferRecyclable = true;
_outputBuffer = ctxt.allocWriteEncodingBuffer();
_outputEnd = _outputBuffer.length;
_outputMaxContiguous = _outputEnd >> 3;
_charBuffer = ctxt.allocConcatBuffer();
_charBufferLength = _charBuffer.length;
if (isEnabled(Feature.ESCAPE_NON_ASCII)) {
setHighestNonEscapedChar(127);
}
}
public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
OutputStream out,
byte[] outputBuffer, int outputOffset, boolean bufferRecyclable)
{
super(ctxt, features, codec);
_outputStream = out;
_bufferRecyclable = bufferRecyclable;
_outputTail = outputOffset;
_outputBuffer = outputBuffer;
_outputEnd = _outputBuffer.length;
_outputMaxContiguous = (_outputEnd >> 3);
_charBuffer = ctxt.allocConcatBuffer();
_charBufferLength = _charBuffer.length;
}
@Override
public Object getOutputTarget() {
return _outputStream;
}
@Override
public int getOutputBuffered() {
return _outputTail;
}
@Override
public void writeFieldName(String name) throws IOException
{
if (_cfgPrettyPrinter != null) {
_writePPFieldName(name);
return;
}
final int status = _writeContext.writeFieldName(name);
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_COMMA;
}
if (_cfgUnqNames) {
_writeStringSegments(name, false);
return;
}
final int len = name.length();
if (len > _charBufferLength) {
_writeStringSegments(name, true);
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
if (len <= _outputMaxContiguous) {
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
}
_writeStringSegment(name, 0, len);
} else {
_writeStringSegments(name, 0, len);
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeFieldName(SerializableString name) throws IOException
{
if (_cfgPrettyPrinter != null) {
_writePPFieldName(name);
return;
}
final int status = _writeContext.writeFieldName(name.getValue());
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_COMMA;
}
if (_cfgUnqNames) {
_writeUnq(name);
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
int len = name.appendQuotedUTF8(_outputBuffer, _outputTail);
if (len < 0) {
_writeBytes(name.asQuotedUTF8());
} else {
_outputTail += len;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
private final void _writeUnq(SerializableString name) throws IOException {
int len = name.appendQuotedUTF8(_outputBuffer, _outputTail);
if (len < 0) {
_writeBytes(name.asQuotedUTF8());
} else {
_outputTail += len;
}
}
@Override
public final void writeStartArray() throws IOException
{
_verifyValueWrite("start an array");
_writeContext = _writeContext.createChildArrayContext();
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeStartArray(this);
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_LBRACKET;
}
}
@Override
public final void writeEndArray() throws IOException
{
if (!_writeContext.inArray()) {
_reportError("Current context not Array but "+_writeContext.typeDesc());
}
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_RBRACKET;
}
_writeContext = _writeContext.clearAndGetParent();
}
@Override
public final void writeStartObject() throws IOException
{
_verifyValueWrite("start an object");
_writeContext = _writeContext.createChildObjectContext();
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeStartObject(this);
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_LCURLY;
}
}
@Override
public void writeStartObject(Object forValue) throws IOException
{
_verifyValueWrite("start an object");
JsonWriteContext ctxt = _writeContext.createChildObjectContext();
_writeContext = ctxt;
if (forValue != null) {
ctxt.setCurrentValue(forValue);
}
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeStartObject(this);
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '{';
}
}
@Override
public final void writeEndObject() throws IOException
{
if (!_writeContext.inObject()) {
_reportError("Current context not Object but "+_writeContext.typeDesc());
}
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_RCURLY;
}
_writeContext = _writeContext.clearAndGetParent();
}
protected final void _writePPFieldName(String name) throws IOException
{
int status = _writeContext.writeFieldName(name);
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
if ((status == JsonWriteContext.STATUS_OK_AFTER_COMMA)) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
} else {
_cfgPrettyPrinter.beforeObjectEntries(this);
}
if (_cfgUnqNames) {
_writeStringSegments(name, false);
return;
}
final int len = name.length();
if (len > _charBufferLength) {
_writeStringSegments(name, true);
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
name.getChars(0, len, _charBuffer, 0);
if (len <= _outputMaxContiguous) {
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
}
_writeStringSegment(_charBuffer, 0, len);
} else {
_writeStringSegments(_charBuffer, 0, len);
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
protected final void _writePPFieldName(SerializableString name) throws IOException
{
final int status = _writeContext.writeFieldName(name.getValue());
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
} else {
_cfgPrettyPrinter.beforeObjectEntries(this);
}
final boolean addQuotes = !_cfgUnqNames;
if (addQuotes) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
_writeBytes(name.asQuotedUTF8());
if (addQuotes) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
}
@Override
public void writeString(String text) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (text == null) {
_writeNull();
return;
}
final int len = text.length();
if (len > _outputMaxContiguous) {
_writeStringSegments(text, true);
return;
}
if ((_outputTail + len) >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
_writeStringSegment(text, 0, len);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeString(Reader reader, int len) throws IOException {
_verifyValueWrite(WRITE_STRING);
if (reader == null) {
_reportError("null reader");
}
int toRead = (len >= 0) ? len : Integer.MAX_VALUE;
final char[] buf = _charBuffer;
if ((_outputTail + len) >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
while (toRead > 0){
int toReadNow = Math.min(toRead, buf.length);
int numRead = reader.read(buf, 0, toReadNow);
if(numRead <= 0){
break;
}
if ((_outputTail + len) >= _outputEnd) {
_flushBuffer();
}
_writeStringSegments(buf, 0, numRead);
toRead -= numRead;
}
if ((_outputTail + len) >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
if (toRead > 0 && len >= 0){
_reportError("Didn't read enough from reader");
}
}
@Override
public void writeString(char[] text, int offset, int len) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
if (len <= _outputMaxContiguous) {
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
}
_writeStringSegment(text, offset, len);
} else {
_writeStringSegments(text, offset, len);
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public final void writeString(SerializableString text) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
int len = text.appendQuotedUTF8(_outputBuffer, _outputTail);
if (len < 0) {
_writeBytes(text.asQuotedUTF8());
} else {
_outputTail += len;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
_writeBytes(text, offset, length);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeUTF8String(byte[] text, int offset, int len) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
if (len <= _outputMaxContiguous) {
_writeUTF8Segment(text, offset, len);
} else {
_writeUTF8Segments(text, offset, len);
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeRaw(String text) throws IOException {
final int len = text.length();
final char[] buf = _charBuffer;
if (len <= buf.length) {
text.getChars(0, len, buf, 0);
writeRaw(buf, 0, len);
} else {
writeRaw(text, 0, len);
}
}
@Override
public void writeRaw(String text, int offset, int len) throws IOException
{
final char[] buf = _charBuffer;
final int cbufLen = buf.length;
if (len <= cbufLen) {
text.getChars(offset, offset+len, buf, 0);
writeRaw(buf, 0, len);
return;
}
final int maxChunk = Math.min(cbufLen,
(_outputEnd >> 2) + (_outputEnd >> 4));
final int maxBytes = maxChunk * 3;
while (len > 0) {
int len2 = Math.min(maxChunk, len);
text.getChars(offset, offset+len2, buf, 0);
if ((_outputTail + maxBytes) > _outputEnd) {
_flushBuffer();
}
if (len2 > 1) {
char ch = buf[len2-1];
if ((ch >= SURR1_FIRST) && (ch <= SURR1_LAST)) {
--len2;
}
}
_writeRawSegment(buf, 0, len2);
offset += len2;
len -= len2;
}
}
@Override
public void writeRaw(SerializableString text) throws IOException
{
byte[] raw = text.asUnquotedUTF8();
if (raw.length > 0) {
_writeBytes(raw);
}
}
@Override
public void writeRawValue(SerializableString text) throws IOException {
_verifyValueWrite(WRITE_RAW);
byte[] raw = text.asUnquotedUTF8();
if (raw.length > 0) {
_writeBytes(raw);
}
}
@Override
public final void writeRaw(char[] cbuf, int offset, int len) throws IOException
{
{
int len3 = len+len+len;
if ((_outputTail + len3) > _outputEnd) {
if (_outputEnd < len3) {
_writeSegmentedRaw(cbuf, offset, len);
return;
}
_flushBuffer();
}
}
len += offset;
main_loop:
while (offset < len) {
inner_loop:
while (true) {
int ch = (int) cbuf[offset];
if (ch > 0x7F) {
break inner_loop;
}
_outputBuffer[_outputTail++] = (byte) ch;
if (++offset >= len) {
break main_loop;
}
}
char ch = cbuf[offset++];
if (ch < 0x800) {
_outputBuffer[_outputTail++] = (byte) (0xc0 | (ch >> 6));
_outputBuffer[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
} else {
offset = _outputRawMultiByteChar(ch, cbuf, offset, len);
}
}
}
@Override
public void writeRaw(char ch) throws IOException
{
if ((_outputTail + 3) >= _outputEnd) {
_flushBuffer();
}
final byte[] bbuf = _outputBuffer;
if (ch <= 0x7F) {
bbuf[_outputTail++] = (byte) ch;
} else if (ch < 0x800) {
bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6));
bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
} else {
_outputRawMultiByteChar(ch, null, 0, 0);
}
}
private final void _writeSegmentedRaw(char[] cbuf, int offset, int len) throws IOException
{
final int end = _outputEnd;
final byte[] bbuf = _outputBuffer;
final int inputEnd = offset + len;
main_loop:
while (offset < inputEnd) {
inner_loop:
while (true) {
int ch = (int) cbuf[offset];
if (ch >= 0x80) {
break inner_loop;
}
if (_outputTail >= end) {
_flushBuffer();
}
bbuf[_outputTail++] = (byte) ch;
if (++offset >= inputEnd) {
break main_loop;
}
}
if ((_outputTail + 3) >= _outputEnd) {
_flushBuffer();
}
char ch = cbuf[offset++];
if (ch < 0x800) {
bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6));
bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
} else {
offset = _outputRawMultiByteChar(ch, cbuf, offset, inputEnd);
}
}
}
private void _writeRawSegment(char[] cbuf, int offset, int end) throws IOException
{
main_loop:
while (offset < end) {
inner_loop:
while (true) {
int ch = (int) cbuf[offset];
if (ch > 0x7F) {
break inner_loop;
}
_outputBuffer[_outputTail++] = (byte) ch;
if (++offset >= end) {
break main_loop;
}
}
char ch = cbuf[offset++];
if (ch < 0x800) {
_outputBuffer[_outputTail++] = (byte) (0xc0 | (ch >> 6));
_outputBuffer[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
} else {
offset = _outputRawMultiByteChar(ch, cbuf, offset, end);
}
}
}
@Override
public void writeBinary(Base64Variant b64variant,
byte[] data, int offset, int len)
throws IOException, JsonGenerationException
{
_verifyValueWrite(WRITE_BINARY);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
_writeBinary(b64variant, data, offset, offset+len);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public int writeBinary(Base64Variant b64variant,
InputStream data, int dataLength)
throws IOException, JsonGenerationException
{
_verifyValueWrite(WRITE_BINARY);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
byte[] encodingBuffer = _ioContext.allocBase64Buffer();
int bytes;
try {
if (dataLength < 0) {
bytes = _writeBinary(b64variant, data, encodingBuffer);
} else {
int missing = _writeBinary(b64variant, data, encodingBuffer, dataLength);
if (missing > 0) {
_reportError("Too few bytes available: missing "+missing+" bytes (out of "+dataLength+")");
}
bytes = dataLength;
}
} finally {
_ioContext.releaseBase64Buffer(encodingBuffer);
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
return bytes;
}
@Override
public void writeNumber(short s) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if ((_outputTail + 6) >= _outputEnd) {
_flushBuffer();
}
if (_cfgNumbersAsStrings) {
_writeQuotedShort(s);
return;
}
_outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
}
private final void _writeQuotedShort(short s) throws IOException {
if ((_outputTail + 8) >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
_outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeNumber(int i) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if ((_outputTail + 11) >= _outputEnd) {
_flushBuffer();
}
if (_cfgNumbersAsStrings) {
_writeQuotedInt(i);
return;
}
_outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
}
private final void _writeQuotedInt(int i) throws IOException
{
if ((_outputTail + 13) >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
_outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeNumber(long l) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if (_cfgNumbersAsStrings) {
_writeQuotedLong(l);
return;
}
if ((_outputTail + 21) >= _outputEnd) {
_flushBuffer();
}
_outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
}
private final void _writeQuotedLong(long l) throws IOException
{
if ((_outputTail + 23) >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
_outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeNumber(BigInteger value) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if (value == null) {
_writeNull();
} else if (_cfgNumbersAsStrings) {
_writeQuotedRaw(value.toString());
} else {
writeRaw(value.toString());
}
}
@Override
public void writeNumber(double d) throws IOException
{
if (_cfgNumbersAsStrings ||
(((Double.isNaN(d) || Double.isInfinite(d))
&& Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)))) {
writeString(String.valueOf(d));
return;
}
_verifyValueWrite(WRITE_NUMBER);
writeRaw(String.valueOf(d));
}
@Override
public void writeNumber(float f) throws IOException
{
if (_cfgNumbersAsStrings ||
(((Float.isNaN(f) || Float.isInfinite(f))
&& Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)))) {
writeString(String.valueOf(f));
return;
}
_verifyValueWrite(WRITE_NUMBER);
writeRaw(String.valueOf(f));
}
@Override
public void writeNumber(BigDecimal value) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if (value == null) {
_writeNull();
} else if (_cfgNumbersAsStrings) {
_writeQuotedRaw(_asString(value));
} else {
writeRaw(_asString(value));
}
}
@Override
public void writeNumber(String encodedValue) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if (_cfgNumbersAsStrings) {
_writeQuotedRaw(encodedValue);
} else {
writeRaw(encodedValue);
}
}
private final void _writeQuotedRaw(String value) throws IOException
{
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
writeRaw(value);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
@Override
public void writeBoolean(boolean state) throws IOException
{
_verifyValueWrite(WRITE_BOOLEAN);
if ((_outputTail + 5) >= _outputEnd) {
_flushBuffer();
}
byte[] keyword = state ? TRUE_BYTES : FALSE_BYTES;
int len = keyword.length;
System.arraycopy(keyword, 0, _outputBuffer, _outputTail, len);
_outputTail += len;
}
@Override
public void writeNull() throws IOException
{
_verifyValueWrite(WRITE_NULL);
_writeNull();
}
@Override
protected final void _verifyValueWrite(String typeMsg) throws IOException
{
final int status = _writeContext.writeValue();
if (_cfgPrettyPrinter != null) {
_verifyPrettyValueWrite(typeMsg, status);
return;
}
byte b;
switch (status) {
case JsonWriteContext.STATUS_OK_AS_IS:
default:
return;
case JsonWriteContext.STATUS_OK_AFTER_COMMA:
b = BYTE_COMMA;
break;
case JsonWriteContext.STATUS_OK_AFTER_COLON:
b = BYTE_COLON;
break;
case JsonWriteContext.STATUS_OK_AFTER_SPACE:
if (_rootValueSeparator != null) {
byte[] raw = _rootValueSeparator.asUnquotedUTF8();
if (raw.length > 0) {
_writeBytes(raw);
}
}
return;
case JsonWriteContext.STATUS_EXPECT_NAME:
_reportCantWriteValueExpectName(typeMsg);
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = b;
}
@Override
public void flush() throws IOException
{
_flushBuffer();
if (_outputStream != null) {
if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
_outputStream.flush();
}
}
}
@Override
public void close() throws IOException
{
super.close();
if ((_outputBuffer != null)
&& isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) {
while (true) {
JsonStreamContext ctxt = getOutputContext();
if (ctxt.inArray()) {
writeEndArray();
} else if (ctxt.inObject()) {
writeEndObject();
} else {
break;
}
}
}
_flushBuffer();
_outputTail = 0;
if (_outputStream != null) {
if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) {
_outputStream.close();
} else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
_outputStream.flush();
}
}
_releaseBuffers();
}
@Override
protected void _releaseBuffers()
{
byte[] buf = _outputBuffer;
if (buf != null && _bufferRecyclable) {
_outputBuffer = null;
_ioContext.releaseWriteEncodingBuffer(buf);
}
char[] cbuf = _charBuffer;
if (cbuf != null) {
_charBuffer = null;
_ioContext.releaseConcatBuffer(cbuf);
}
}
private final void _writeBytes(byte[] bytes) throws IOException
{
final int len = bytes.length;
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
if (len > MAX_BYTES_TO_BUFFER) {
_outputStream.write(bytes, 0, len);
return;
}
}
System.arraycopy(bytes, 0, _outputBuffer, _outputTail, len);
_outputTail += len;
}
private final void _writeBytes(byte[] bytes, int offset, int len) throws IOException
{
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
if (len > MAX_BYTES_TO_BUFFER) {
_outputStream.write(bytes, offset, len);
return;
}
}
System.arraycopy(bytes, offset, _outputBuffer, _outputTail, len);
_outputTail += len;
}
private final void _writeStringSegments(String text, boolean addQuotes) throws IOException
{
if (addQuotes) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
int left = text.length();
int offset = 0;
while (left > 0) {
int len = Math.min(_outputMaxContiguous, left);
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
}
_writeStringSegment(text, offset, len);
offset += len;
left -= len;
}
if (addQuotes) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = _quoteChar;
}
}
private final void _writeStringSegments(char[] cbuf, int offset, int totalLen) throws IOException
{
do {
int len = Math.min(_outputMaxContiguous, totalLen);
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
}
_writeStringSegment(cbuf, offset, len);
offset += len;
totalLen -= len;
} while (totalLen > 0);
}
private final void _writeStringSegments(String text, int offset, int totalLen) throws IOException
{
do {
int len = Math.min(_outputMaxContiguous, totalLen);
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
}
_writeStringSegment(text, offset, len);
offset += len;
totalLen -= len;
} while (totalLen > 0);
}
private final void _writeStringSegment(char[] cbuf, int offset, int len)
throws IOException
{
len += offset;
int outputPtr = _outputTail;
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
while (offset < len) {
int ch = cbuf[offset];
if (ch > 0x7F || escCodes[ch] != 0) {
break;
}
outputBuffer[outputPtr++] = (byte) ch;
++offset;
}
_outputTail = outputPtr;
if (offset < len) {
if (_characterEscapes != null) {
_writeCustomStringSegment2(cbuf, offset, len);
} else if (_maximumNonEscapedChar == 0) {
_writeStringSegment2(cbuf, offset, len);
} else {
_writeStringSegmentASCII2(cbuf, offset, len);
}
}
}
private final void _writeStringSegment(String text, int offset, int len) throws IOException
{
len += offset;
int outputPtr = _outputTail;
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
while (offset < len) {
int ch = text.charAt(offset);
if (ch > 0x7F || escCodes[ch] != 0) {
break;
}
outputBuffer[outputPtr++] = (byte) ch;
++offset;
}
_outputTail = outputPtr;
if (offset < len) {
if (_characterEscapes != null) {
_writeCustomStringSegment2(text, offset, len);
} else if (_maximumNonEscapedChar == 0) {
_writeStringSegment2(text, offset, len);
} else {
_writeStringSegmentASCII2(text, offset, len);
}
}
}
private final void _writeStringSegment2(final char[] cbuf, int offset, final int end) throws IOException
{
if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
_flushBuffer();
}
int outputPtr = _outputTail;
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
while (offset < end) {
int ch = cbuf[offset++];
if (ch <= 0x7F) {
if (escCodes[ch] == 0) {
outputBuffer[outputPtr++] = (byte) ch;
continue;
}
int escape = escCodes[ch];
if (escape > 0) {
outputBuffer[outputPtr++] = BYTE_BACKSLASH;
outputBuffer[outputPtr++] = (byte) escape;
} else {
outputPtr = _writeGenericEscape(ch, outputPtr);
}
continue;
}
if (ch <= 0x7FF) {
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
_outputTail = outputPtr;
}
private final void _writeStringSegment2(final String text, int offset, final int end) throws IOException
{
if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
_flushBuffer();
}
int outputPtr = _outputTail;
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
while (offset < end) {
int ch = text.charAt(offset++);
if (ch <= 0x7F) {
if (escCodes[ch] == 0) {
outputBuffer[outputPtr++] = (byte) ch;
continue;
}
int escape = escCodes[ch];
if (escape > 0) {
outputBuffer[outputPtr++] = BYTE_BACKSLASH;
outputBuffer[outputPtr++] = (byte) escape;
} else {
outputPtr = _writeGenericEscape(ch, outputPtr);
}
continue;
}
if (ch <= 0x7FF) {
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
_outputTail = outputPtr;
}
private final void _writeStringSegmentASCII2(final char[] cbuf, int offset, final int end) throws IOException
{
if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
_flushBuffer();
}
int outputPtr = _outputTail;
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
final int maxUnescaped = _maximumNonEscapedChar;
while (offset < end) {
int ch = cbuf[offset++];
if (ch <= 0x7F) {
if (escCodes[ch] == 0) {
outputBuffer[outputPtr++] = (byte) ch;
continue;
}
int escape = escCodes[ch];
if (escape > 0) {
outputBuffer[outputPtr++] = BYTE_BACKSLASH;
outputBuffer[outputPtr++] = (byte) escape;
} else {
outputPtr = _writeGenericEscape(ch, outputPtr);
}
continue;
}
if (ch > maxUnescaped) {
outputPtr = _writeGenericEscape(ch, outputPtr);
continue;
}
if (ch <= 0x7FF) {
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
_outputTail = outputPtr;
}
private final void _writeStringSegmentASCII2(final String text, int offset, final int end) throws IOException
{
if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
_flushBuffer();
}
int outputPtr = _outputTail;
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
final int maxUnescaped = _maximumNonEscapedChar;
while (offset < end) {
int ch = text.charAt(offset++);
if (ch <= 0x7F) {
if (escCodes[ch] == 0) {
outputBuffer[outputPtr++] = (byte) ch;
continue;
}
int escape = escCodes[ch];
if (escape > 0) {
outputBuffer[outputPtr++] = BYTE_BACKSLASH;
outputBuffer[outputPtr++] = (byte) escape;
} else {
outputPtr = _writeGenericEscape(ch, outputPtr);
}
continue;
}
if (ch > maxUnescaped) {
outputPtr = _writeGenericEscape(ch, outputPtr);
continue;
}
if (ch <= 0x7FF) {
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
_outputTail = outputPtr;
}
private final void _writeCustomStringSegment2(final char[] cbuf, int offset, final int end) throws IOException
{
if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
_flushBuffer();
}
int outputPtr = _outputTail;
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
final int maxUnescaped = (_maximumNonEscapedChar <= 0) ? 0xFFFF : _maximumNonEscapedChar;
final CharacterEscapes customEscapes = _characterEscapes;
while (offset < end) {
int ch = cbuf[offset++];
if (ch <= 0x7F) {
if (escCodes[ch] == 0) {
outputBuffer[outputPtr++] = (byte) ch;
continue;
}
int escape = escCodes[ch];
if (escape > 0) {
outputBuffer[outputPtr++] = BYTE_BACKSLASH;
outputBuffer[outputPtr++] = (byte) escape;
} else if (escape == CharacterEscapes.ESCAPE_CUSTOM) {
SerializableString esc = customEscapes.getEscapeSequence(ch);
if (esc == null) {
_reportError("Invalid custom escape definitions; custom escape not found for character code 0x"
+Integer.toHexString(ch)+", although was supposed to have one");
}
outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
} else {
outputPtr = _writeGenericEscape(ch, outputPtr);
}
continue;
}
if (ch > maxUnescaped) {
outputPtr = _writeGenericEscape(ch, outputPtr);
continue;
}
SerializableString esc = customEscapes.getEscapeSequence(ch);
if (esc != null) {
outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
continue;
}
if (ch <= 0x7FF) {
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
_outputTail = outputPtr;
}
private final void _writeCustomStringSegment2(final String text, int offset, final int end) throws IOException
{
if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
_flushBuffer();
}
int outputPtr = _outputTail;
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
final int maxUnescaped = (_maximumNonEscapedChar <= 0) ? 0xFFFF : _maximumNonEscapedChar;
final CharacterEscapes customEscapes = _characterEscapes;
while (offset < end) {
int ch = text.charAt(offset++);
if (ch <= 0x7F) {
if (escCodes[ch] == 0) {
outputBuffer[outputPtr++] = (byte) ch;
continue;
}
int escape = escCodes[ch];
if (escape > 0) {
outputBuffer[outputPtr++] = BYTE_BACKSLASH;
outputBuffer[outputPtr++] = (byte) escape;
} else if (escape == CharacterEscapes.ESCAPE_CUSTOM) {
SerializableString esc = customEscapes.getEscapeSequence(ch);
if (esc == null) {
_reportError("Invalid custom escape definitions; custom escape not found for character code 0x"
+Integer.toHexString(ch)+", although was supposed to have one");
}
outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
} else {
outputPtr = _writeGenericEscape(ch, outputPtr);
}
continue;
}
if (ch > maxUnescaped) {
outputPtr = _writeGenericEscape(ch, outputPtr);
continue;
}
SerializableString esc = customEscapes.getEscapeSequence(ch);
if (esc != null) {
outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
continue;
}
if (ch <= 0x7FF) {
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
_outputTail = outputPtr;
}
private final int _writeCustomEscape(byte[] outputBuffer, int outputPtr, SerializableString esc, int remainingChars)
throws IOException, JsonGenerationException
{
byte[] raw = esc.asUnquotedUTF8();
int len = raw.length;
if (len > 6) {
return _handleLongCustomEscape(outputBuffer, outputPtr, _outputEnd, raw, remainingChars);
}
System.arraycopy(raw, 0, outputBuffer, outputPtr, len);
return (outputPtr + len);
}
private final int _handleLongCustomEscape(byte[] outputBuffer, int outputPtr, int outputEnd, byte[] raw,
int remainingChars)
throws IOException, JsonGenerationException
{
int len = raw.length;
if ((outputPtr + len) > outputEnd) {
_outputTail = outputPtr;
_flushBuffer();
outputPtr = _outputTail;
if (len > outputBuffer.length) {
_outputStream.write(raw, 0, len);
return outputPtr;
}
System.arraycopy(raw, 0, outputBuffer, outputPtr, len);
outputPtr += len;
}
if ((outputPtr + 6 * remainingChars) > outputEnd) {
_flushBuffer();
return _outputTail;
}
return outputPtr;
}
private final void _writeUTF8Segments(byte[] utf8, int offset, int totalLen)
throws IOException, JsonGenerationException
{
do {
int len = Math.min(_outputMaxContiguous, totalLen);
_writeUTF8Segment(utf8, offset, len);
offset += len;
totalLen -= len;
} while (totalLen > 0);
}
private final void _writeUTF8Segment(byte[] utf8, final int offset, final int len)
throws IOException, JsonGenerationException
{
final int[] escCodes = _outputEscapes;
for (int ptr = offset, end = offset + len; ptr < end; ) {
int ch = utf8[ptr++];
if ((ch >= 0) && escCodes[ch] != 0) {
_writeUTF8Segment2(utf8, offset, len);
return;
}
}
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
}
System.arraycopy(utf8, offset, _outputBuffer, _outputTail, len);
_outputTail += len;
}
private final void _writeUTF8Segment2(final byte[] utf8, int offset, int len)
throws IOException, JsonGenerationException
{
int outputPtr = _outputTail;
if ((outputPtr + (len * 6)) > _outputEnd) {
_flushBuffer();
outputPtr = _outputTail;
}
final byte[] outputBuffer = _outputBuffer;
final int[] escCodes = _outputEscapes;
len += offset;
while (offset < len) {
byte b = utf8[offset++];
int ch = b;
if (ch < 0 || escCodes[ch] == 0) {
outputBuffer[outputPtr++] = b;
continue;
}
int escape = escCodes[ch];
if (escape > 0) {
outputBuffer[outputPtr++] = BYTE_BACKSLASH;
outputBuffer[outputPtr++] = (byte) escape;
} else {
outputPtr = _writeGenericEscape(ch, outputPtr);
}
}
_outputTail = outputPtr;
}
protected final void _writeBinary(Base64Variant b64variant,
byte[] input, int inputPtr, final int inputEnd)
throws IOException, JsonGenerationException
{
int safeInputEnd = inputEnd - 3;
int safeOutputEnd = _outputEnd - 6;
int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
while (inputPtr <= safeInputEnd) {
if (_outputTail > safeOutputEnd) {
_flushBuffer();
}
int b24 = ((int) input[inputPtr++]) << 8;
b24 |= ((int) input[inputPtr++]) & 0xFF;
b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF);
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
_outputBuffer[_outputTail++] = '\\';
_outputBuffer[_outputTail++] = 'n';
chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
}
}
int inputLeft = inputEnd - inputPtr;
if (inputLeft > 0) {
if (_outputTail > safeOutputEnd) {
_flushBuffer();
}
int b24 = ((int) input[inputPtr++]) << 16;
if (inputLeft == 2) {
b24 |= (((int) input[inputPtr++]) & 0xFF) << 8;
}
_outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail);
}
}
protected final int _writeBinary(Base64Variant b64variant,
InputStream data, byte[] readBuffer, int bytesLeft)
throws IOException, JsonGenerationException
{
int inputPtr = 0;
int inputEnd = 0;
int lastFullOffset = -3;
int safeOutputEnd = _outputEnd - 6;
int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
while (bytesLeft > 2) {
if (inputPtr > lastFullOffset) {
inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
inputPtr = 0;
if (inputEnd < 3) {
break;
}
lastFullOffset = inputEnd-3;
}
if (_outputTail > safeOutputEnd) {
_flushBuffer();
}
int b24 = ((int) readBuffer[inputPtr++]) << 8;
b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
bytesLeft -= 3;
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
_outputBuffer[_outputTail++] = '\\';
_outputBuffer[_outputTail++] = 'n';
chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
}
}
if (bytesLeft > 0) {
inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
inputPtr = 0;
if (inputEnd > 0) {
if (_outputTail > safeOutputEnd) {
_flushBuffer();
}
int b24 = ((int) readBuffer[inputPtr++]) << 16;
int amount;
if (inputPtr < inputEnd) {
b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
} else {
amount = 1;
}
_outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
bytesLeft -= amount;
}
}
return bytesLeft;
}
protected final int _writeBinary(Base64Variant b64variant,
InputStream data, byte[] readBuffer)
throws IOException, JsonGenerationException
{
int inputPtr = 0;
int inputEnd = 0;
int lastFullOffset = -3;
int bytesDone = 0;
int safeOutputEnd = _outputEnd - 6;
int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
while (true) {
if (inputPtr > lastFullOffset) {
inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, readBuffer.length);
inputPtr = 0;
if (inputEnd < 3) {
break;
}
lastFullOffset = inputEnd-3;
}
if (_outputTail > safeOutputEnd) {
_flushBuffer();
}
int b24 = ((int) readBuffer[inputPtr++]) << 8;
b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
bytesDone += 3;
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
_outputBuffer[_outputTail++] = '\\';
_outputBuffer[_outputTail++] = 'n';
chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
}
}
if (inputPtr < inputEnd) {
if (_outputTail > safeOutputEnd) {
_flushBuffer();
}
int b24 = ((int) readBuffer[inputPtr++]) << 16;
int amount = 1;
if (inputPtr < inputEnd) {
b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
}
bytesDone += amount;
_outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
}
return bytesDone;
}
private final int _readMore(InputStream in,
byte[] readBuffer, int inputPtr, int inputEnd,
int maxRead) throws IOException
{
int i = 0;
while (inputPtr < inputEnd) {
readBuffer[i++] = readBuffer[inputPtr++];
}
inputPtr = 0;
inputEnd = i;
maxRead = Math.min(maxRead, readBuffer.length);
do {
int length = maxRead - inputEnd;
if (length == 0) {
break;
}
int count = in.read(readBuffer, inputEnd, length);
if (count < 0) {
return inputEnd;
}
inputEnd += count;
} while (inputEnd < 3);
return inputEnd;
}
private final int _outputRawMultiByteChar(int ch, char[] cbuf, int inputOffset, int inputEnd)
throws IOException
{
if (ch >= SURR1_FIRST) {
if (ch <= SURR2_LAST) {
if (inputOffset >= inputEnd || cbuf == null) {
_reportError(String.format(
"Split surrogate on writeRaw() input (last character): first character 0x%4x", ch));
}
_outputSurrogates(ch, cbuf[inputOffset]);
return inputOffset+1;
}
}
final byte[] bbuf = _outputBuffer;
bbuf[_outputTail++] = (byte) (0xe0 | (ch >> 12));
bbuf[_outputTail++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
return inputOffset;
}
protected final void _outputSurrogates(int surr1, int surr2) throws IOException
{
int c = _decodeSurrogate(surr1, surr2);
if ((_outputTail + 4) > _outputEnd) {
_flushBuffer();
}
final byte[] bbuf = _outputBuffer;
bbuf[_outputTail++] = (byte) (0xf0 | (c >> 18));
bbuf[_outputTail++] = (byte) (0x80 | ((c >> 12) & 0x3f));
bbuf[_outputTail++] = (byte) (0x80 | ((c >> 6) & 0x3f));
bbuf[_outputTail++] = (byte) (0x80 | (c & 0x3f));
}
private final int _outputMultiByteChar(int ch, int outputPtr) throws IOException
{
byte[] bbuf = _outputBuffer;
if (ch >= SURR1_FIRST && ch <= SURR2_LAST) {
bbuf[outputPtr++] = BYTE_BACKSLASH;
bbuf[outputPtr++] = BYTE_u;
bbuf[outputPtr++] = HEX_CHARS[(ch >> 12) & 0xF];
bbuf[outputPtr++] = HEX_CHARS[(ch >> 8) & 0xF];
bbuf[outputPtr++] = HEX_CHARS[(ch >> 4) & 0xF];
bbuf[outputPtr++] = HEX_CHARS[ch & 0xF];
} else {
bbuf[outputPtr++] = (byte) (0xe0 | (ch >> 12));
bbuf[outputPtr++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
bbuf[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
}
return outputPtr;
}
private final void _writeNull() throws IOException
{
if ((_outputTail + 4) >= _outputEnd) {
_flushBuffer();
}
System.arraycopy(NULL_BYTES, 0, _outputBuffer, _outputTail, 4);
_outputTail += 4;
}
private int _writeGenericEscape(int charToEscape, int outputPtr) throws IOException
{
final byte[] bbuf = _outputBuffer;
bbuf[outputPtr++] = BYTE_BACKSLASH;
bbuf[outputPtr++] = BYTE_u;
if (charToEscape > 0xFF) {
int hi = (charToEscape >> 8) & 0xFF;
bbuf[outputPtr++] = HEX_CHARS[hi >> 4];
bbuf[outputPtr++] = HEX_CHARS[hi & 0xF];
charToEscape &= 0xFF;
} else {
bbuf[outputPtr++] = BYTE_0;
bbuf[outputPtr++] = BYTE_0;
}
bbuf[outputPtr++] = HEX_CHARS[charToEscape >> 4];
bbuf[outputPtr++] = HEX_CHARS[charToEscape & 0xF];
return outputPtr;
}
protected final void _flushBuffer() throws IOException
{
int len = _outputTail;
if (len > 0) {
_outputTail = 0;
_outputStream.write(_outputBuffer, 0, len);
}
}
}