package com.fasterxml.jackson.dataformat.smile.async;
import java.io.*;
import java.util.Arrays;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.json.JsonReadContext;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
import com.fasterxml.jackson.core.util.ByteArrayBuilder;
import com.fasterxml.jackson.dataformat.smile.*;
public abstract class NonBlockingParserBase
extends SmileParserBase
{
protected final static int MAJOR_INITIAL = 0;
protected final static int MAJOR_ROOT = 1;
protected final static int MAJOR_OBJECT_FIELD = 2;
protected final static int MAJOR_OBJECT_VALUE = 3;
protected final static int MAJOR_ARRAY_ELEMENT = 4;
protected final static int MAJOR_CLOSED = 5;
protected final static int = 1;
protected final static int = 2;
protected final static int MINOR_FIELD_NAME_2BYTE = 3;
protected final static int MINOR_FIELD_NAME_LONG = 4;
protected final static int MINOR_FIELD_NAME_SHORT_ASCII = 5;
protected final static int MINOR_FIELD_NAME_SHORT_UNICODE = 6;
protected final static int MINOR_VALUE_NUMBER_INT = 7;
protected final static int MINOR_VALUE_NUMBER_LONG = 8;
protected final static int MINOR_VALUE_NUMBER_FLOAT = 9;
protected final static int MINOR_VALUE_NUMBER_DOUBLE = 10;
protected final static int MINOR_VALUE_NUMBER_BIGINT_LEN = 11;
protected final static int MINOR_VALUE_NUMBER_BIGINT_BODY = 12;
protected final static int MINOR_VALUE_NUMBER_BIGDEC_SCALE = 13;
protected final static int MINOR_VALUE_NUMBER_BIGDEC_LEN = 14;
protected final static int MINOR_VALUE_NUMBER_BIGDEC_BODY = 15;
protected final static int MINOR_VALUE_STRING_SHORT_ASCII = 16;
protected final static int MINOR_VALUE_STRING_SHORT_UNICODE = 17;
protected final static int MINOR_VALUE_STRING_LONG_ASCII = 18;
protected final static int MINOR_VALUE_STRING_LONG_UNICODE = 19;
protected final static int MINOR_VALUE_STRING_SHARED_2BYTE = 20;
protected final static int MINOR_VALUE_BINARY_RAW_LEN = 21;
protected final static int MINOR_VALUE_BINARY_RAW_BODY = 22;
protected final static int MINOR_VALUE_BINARY_7BIT_LEN = 23;
protected final static int MINOR_VALUE_BINARY_7BIT_BODY = 24;
protected int _majorState;
protected int _minorState;
protected int _majorStateAfterValue;
protected boolean _endOfInput = false;
protected byte[] _inputCopy;
protected int _inputCopyLen;
protected int _pending32;
protected long _pending64;
public NonBlockingParserBase(IOContext ctxt, int parserFeatures, int smileFeatures,
ByteQuadsCanonicalizer sym)
{
super(ctxt, parserFeatures, smileFeatures, sym);
_inputCopy = ctxt.allocReadIOBuffer(500);
_currToken = null;
_majorState = MAJOR_INITIAL;
}
@Override
public ObjectCodec getCodec() {
return null;
}
@Override
public void setCodec(ObjectCodec c) {
throw new UnsupportedOperationException("Can not use ObjectMapper with non-blocking parser");
}
@Override
public boolean canParseAsync() { return true; }
@Override
protected void _releaseBuffers2()
{
byte[] b = _inputCopy;
if (b != null) {
_inputCopy = null;
_ioContext.releaseReadIOBuffer(b);
}
}
protected ByteQuadsCanonicalizer symbolTableForTests() {
return _symbols;
}
@Override
public abstract int releaseBuffered(OutputStream out) throws IOException;
@Override
public Object getInputSource() {
return null;
}
@Override
protected void _closeInput() throws IOException {
}
@Override
protected void _parseNumericValue() throws IOException {
if (_currToken == JsonToken.VALUE_NUMBER_INT || _currToken == JsonToken.VALUE_NUMBER_FLOAT) {
return;
}
_reportError("Current token (%s) not numeric, can not use numeric value accessors", _currToken);
}
@Override
public boolean hasTextCharacters()
{
if (_currToken == JsonToken.VALUE_STRING) {
return _textBuffer.hasTextAsCharacters();
}
if (_currToken == JsonToken.FIELD_NAME) {
return _nameCopied;
}
return false;
}
@Override
public String getText() throws IOException
{
if (_currToken == JsonToken.VALUE_STRING) {
return _textBuffer.contentsAsString();
}
JsonToken t = _currToken;
if (t == null || _currToken == JsonToken.NOT_AVAILABLE) {
return null;
}
if (t == JsonToken.FIELD_NAME) {
return _parsingContext.getCurrentName();
}
if (t.isNumeric()) {
return getNumberValue().toString();
}
return _currToken.asString();
}
@Override
public char[] getTextCharacters() throws IOException
{
switch (currentTokenId()) {
case JsonTokenId.ID_STRING:
return _textBuffer.getTextBuffer();
case JsonTokenId.ID_FIELD_NAME:
if (!_nameCopied) {
String name = _parsingContext.getCurrentName();
int nameLen = name.length();
if (_nameCopyBuffer == null) {
_nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
} else if (_nameCopyBuffer.length < nameLen) {
_nameCopyBuffer = new char[nameLen];
}
name.getChars(0, nameLen, _nameCopyBuffer, 0);
_nameCopied = true;
}
return _nameCopyBuffer;
case JsonTokenId.ID_NUMBER_INT:
case JsonTokenId.ID_NUMBER_FLOAT:
return getNumberValue().toString().toCharArray();
case JsonTokenId.ID_NO_TOKEN:
case JsonTokenId.ID_NOT_AVAILABLE:
return null;
default:
return _currToken.asCharArray();
}
}
@Override
public int getTextLength() throws IOException
{
switch (currentTokenId()) {
case JsonTokenId.ID_STRING:
return _textBuffer.size();
case JsonTokenId.ID_FIELD_NAME:
return _parsingContext.getCurrentName().length();
case JsonTokenId.ID_NUMBER_INT:
case JsonTokenId.ID_NUMBER_FLOAT:
return getNumberValue().toString().length();
case JsonTokenId.ID_NO_TOKEN:
case JsonTokenId.ID_NOT_AVAILABLE:
return 0;
default:
return _currToken.asCharArray().length;
}
}
@Override
public int getTextOffset() throws IOException {
return 0;
}
@Override
public int getText(Writer w) throws IOException
{
if (_currToken == JsonToken.VALUE_STRING) {
return _textBuffer.contentsToWriter(w);
}
if (_currToken == JsonToken.NOT_AVAILABLE) {
_reportError("Current token not available: can not call this method");
}
return super.getText(w);
}
@Override
public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
{
if (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT ) {
_reportError("Current token (%s) not VALUE_EMBEDDED_OBJECT, can not access as binary", _currToken);
}
return _binaryValue;
}
@Override
public Object getEmbeddedObject() throws IOException
{
if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT ) {
return _binaryValue;
}
return null;
}
@Override
public int readBinaryValue(Base64Variant b64variant, OutputStream out)
throws IOException {
if (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT ) {
_reportError("Current token (%s) not VALUE_EMBEDDED_OBJECT, can not access as binary", _currToken);
}
out.write(_binaryValue);
return _binaryValue.length;
}
protected final JsonToken _startArrayScope() throws IOException
{
_parsingContext = _parsingContext.createChildArrayContext(-1, -1);
_majorState = MAJOR_ARRAY_ELEMENT;
_majorStateAfterValue = MAJOR_ARRAY_ELEMENT;
return (_currToken = JsonToken.START_ARRAY);
}
protected final JsonToken _startObjectScope() throws IOException
{
_parsingContext = _parsingContext.createChildObjectContext(-1, -1);
_majorState = MAJOR_OBJECT_FIELD;
_majorStateAfterValue = MAJOR_OBJECT_FIELD;
return (_currToken = JsonToken.START_OBJECT);
}
protected final JsonToken _closeArrayScope() throws IOException
{
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(']', '}');
}
JsonReadContext ctxt = _parsingContext.getParent();
_parsingContext = ctxt;
int st;
if (ctxt.inObject()) {
st = MAJOR_OBJECT_FIELD;
} else if (ctxt.inArray()) {
st = MAJOR_ARRAY_ELEMENT;
} else {
st = MAJOR_ROOT;
}
_majorState = st;
_majorStateAfterValue = st;
return (_currToken = JsonToken.END_ARRAY);
}
protected final JsonToken _closeObjectScope() throws IOException
{
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker('}', ']');
}
JsonReadContext ctxt = _parsingContext.getParent();
_parsingContext = ctxt;
int st;
if (ctxt.inObject()) {
st = MAJOR_OBJECT_FIELD;
} else if (ctxt.inArray()) {
st = MAJOR_ARRAY_ELEMENT;
} else {
st = MAJOR_ROOT;
}
_majorState = st;
_majorStateAfterValue = st;
return (_currToken = JsonToken.END_OBJECT);
}
protected final String _findDecodedFromSymbols(byte[] inBuf, int inPtr, int len) throws IOException
{
if (len < 5) {
int q = inBuf[inPtr] & 0xFF;
if (--len > 0) {
q = (q << 8) + (inBuf[++inPtr] & 0xFF);
if (--len > 0) {
q = (q << 8) + (inBuf[++inPtr] & 0xFF);
if (--len > 0) {
q = (q << 8) + (inBuf[++inPtr] & 0xFF);
}
}
}
_quad1 = q;
return _symbols.findName(q);
}
if (len < 9) {
int q1 = (inBuf[inPtr] & 0xFF) << 8;
q1 += (inBuf[++inPtr] & 0xFF);
q1 <<= 8;
q1 += (inBuf[++inPtr] & 0xFF);
q1 <<= 8;
q1 += (inBuf[++inPtr] & 0xFF);
int q2 = (inBuf[++inPtr] & 0xFF);
len -= 5;
if (len > 0) {
q2 = (q2 << 8) + (inBuf[++inPtr] & 0xFF);
if (--len > 0) {
q2 = (q2 << 8) + (inBuf[++inPtr] & 0xFF);
if (--len > 0) {
q2 = (q2 << 8) + (inBuf[++inPtr] & 0xFF);
}
}
}
_quad1 = q1;
_quad2 = q2;
return _symbols.findName(q1, q2);
}
return _findDecodedLonger(inBuf, inPtr, len);
}
private final String _findDecodedLonger(byte[] inBuf, int inPtr, int len) throws IOException
{
{
int bufLen = (len + 3) >> 2;
if (bufLen > _quadBuffer.length) {
_quadBuffer = Arrays.copyOf(_quadBuffer, bufLen+4);
}
}
int offset = 0;
do {
int q = (inBuf[inPtr++] & 0xFF) << 8;
q |= inBuf[inPtr++] & 0xFF;
q <<= 8;
q |= inBuf[inPtr++] & 0xFF;
q <<= 8;
q |= inBuf[inPtr++] & 0xFF;
_quadBuffer[offset++] = q;
} while ((len -= 4) > 3);
if (len > 0) {
int q = inBuf[inPtr] & 0xFF;
if (--len > 0) {
q = (q << 8) + (inBuf[++inPtr] & 0xFF);
if (--len > 0) {
q = (q << 8) + (inBuf[++inPtr] & 0xFF);
}
}
_quadBuffer[offset++] = q;
}
return _symbols.findName(_quadBuffer, offset);
}
protected final String _addDecodedToSymbols(int len, String name)
{
if (len < 5) {
return _symbols.addName(name, _quad1);
}
if (len < 9) {
return _symbols.addName(name, _quad1, _quad2);
}
int qlen = (len + 3) >> 2;
return _symbols.addName(name, _quadBuffer, qlen);
}
protected final String[] _expandSeenNames(String[] oldShared)
{
int len = oldShared.length;
String[] newShared;
if (len == 0) {
newShared = _smileBufferRecycler.allocSeenNamesBuffer();
if (newShared == null) {
newShared = new String[SmileBufferRecycler.DEFAULT_NAME_BUFFER_LENGTH];
}
} else if (len == SmileConstants.MAX_SHARED_NAMES) {
newShared = oldShared;
_seenNameCount = 0;
} else {
int newSize = (len == SmileBufferRecycler.DEFAULT_STRING_VALUE_BUFFER_LENGTH) ? 256 : SmileConstants.MAX_SHARED_NAMES;
newShared = new String[newSize];
System.arraycopy(oldShared, 0, newShared, 0, oldShared.length);
}
return newShared;
}
protected final JsonToken _eofAsNextToken() throws IOException {
_majorState = MAJOR_CLOSED;
if (!_parsingContext.inRoot()) {
_handleEOF();
}
close();
return (_currToken = null);
}
protected final JsonToken _valueComplete(JsonToken t) throws IOException
{
_majorState = _majorStateAfterValue;
_currToken = t;
return t;
}
protected final JsonToken _handleSharedString(int index) throws IOException
{
if (index >= _seenStringValueCount) {
_reportInvalidSharedStringValue(index);
}
_textBuffer.resetWithString(_seenStringValues[index]);
return _valueComplete(JsonToken.VALUE_STRING);
}
protected final JsonToken _handleSharedName(int index) throws IOException
{
if (index >= _seenNameCount) {
_reportInvalidSharedName(index);
}
_parsingContext.setCurrentName(_seenNames[index]);
_majorState = MAJOR_OBJECT_VALUE;
return (_currToken = JsonToken.FIELD_NAME);
}
protected final void _addSeenStringValue(String v) throws IOException
{
if (_seenStringValueCount < _seenStringValues.length) {
_seenStringValues[_seenStringValueCount++] = v;
return;
}
_expandSeenStringValues(v);
}
private final void _expandSeenStringValues(String v)
{
String[] oldShared = _seenStringValues;
int len = oldShared.length;
String[] newShared;
if (len == 0) {
newShared = _smileBufferRecycler.allocSeenStringValuesBuffer();
if (newShared == null) {
newShared = new String[SmileBufferRecycler.DEFAULT_STRING_VALUE_BUFFER_LENGTH];
}
} else if (len == SmileConstants.MAX_SHARED_STRING_VALUES) {
newShared = oldShared;
_seenStringValueCount = 0;
} else {
int newSize = (len == SmileBufferRecycler.DEFAULT_NAME_BUFFER_LENGTH) ? 256 : SmileConstants.MAX_SHARED_STRING_VALUES;
newShared = new String[newSize];
System.arraycopy(oldShared, 0, newShared, 0, oldShared.length);
}
_seenStringValues = newShared;
_seenStringValues[_seenStringValueCount++] = v;
}
protected ByteArrayBuilder _byteArrayBuilder = null;
public void _initByteArrayBuilder()
{
if (_byteArrayBuilder == null) {
_byteArrayBuilder = new ByteArrayBuilder();
} else {
_byteArrayBuilder.reset();
}
}
protected void (int unmaskedFirstByte) throws IOException
{
String msg;
int b = unmaskedFirstByte & 0xFF;
if (b == '{' || b == '[') {
msg = "Input does not start with Smile format header (first byte = 0x"
+Integer.toHexString(b & 0xFF)+") -- rather, it starts with '"+((char) b)
+"' (plain JSON input?) -- can not parse";
} else {
msg = "Input does not start with Smile format header (first byte = 0x"
+Integer.toHexString(b & 0xFF)+") and parser has REQUIRE_HEADER enabled: can not parse";
}
throw new JsonParseException(this, msg);
}
protected void _reportInvalidSharedName(int index) throws IOException
{
if (_seenNames == null) {
_reportError("Encountered shared name reference, even though document header explicitly declared no shared name references are included");
}
_reportError("Invalid shared name reference %d; only got %d names in buffer (invalid content)",
index, _seenNameCount);
}
protected void _reportInvalidSharedStringValue(int index) throws IOException
{
if (_seenStringValues == null) {
_reportError("Encountered shared text value reference, even though document header did not declare shared text value references may be included");
}
_reportError("Invalid shared text value reference %d; only got %s names in buffer (invalid content)",
index, _seenStringValueCount);
}
protected void _reportInvalidInitial(int mask) throws JsonParseException {
_reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask));
}
protected void _reportInvalidOther(int mask, int ptr) throws JsonParseException {
_inputPtr = ptr;
_reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask));
}
}