Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   package com.fasterxml.jackson.core.json;
   
   import java.io.*;
   
This is a concrete implementation of com.fasterxml.jackson.core.JsonParser, which is based on a java.io.InputStream as the input source.
  
  public final class UTF8StreamJsonParser
      extends ParserBase
  {
      final static byte BYTE_LF = (byte'\n';
  
      private final static int[] sInputCodesUtf8 = CharTypes.getInputCodeUtf8();

    
Latin1 encoding is not supported, but we do use 8-bit subset for pre-processing task, to simplify first pass, keep it fast.
  
      private final static int[] sInputCodesLatin1 = CharTypes.getInputCodeLatin1();
      
      /*
      /**********************************************************
      /* Configuration
      /**********************************************************
       */

    
Codec used for data binding when (if) requested; typically full ObjectMapper, but that abstract is not part of core package.
  
      protected ObjectCodec _objectCodec;

    
Symbol table that contains field names encountered so far
  
      final protected BytesToNameCanonicalizer _symbols;
      
      /*
      /**********************************************************
      /* Parsing state
      /**********************************************************
       */
    
    
Temporary buffer used for name parsing.
  
      protected int[] _quadBuffer = new int[16];

    
Flag that indicates that the current token has not yet been fully processed, and needs to be finished for some access (or skipped to obtain the next token)
  
      protected boolean _tokenIncomplete = false;

    
Temporary storage for partially parsed name bytes.
  
      private int _quad1;
      
      /*
      /**********************************************************
      /* Input buffering (from former 'StreamBasedParserBase')
      /**********************************************************
       */
      
      protected InputStream _inputStream;
  
      /*
      /**********************************************************
      /* Current input data
      /**********************************************************
       */

    
Current buffer from which data is read; generally data is read into buffer from input source, but in some cases pre-loaded buffer is handed to the parser.
  
      protected byte[] _inputBuffer;

    
Flag that indicates whether the input buffer is recycable (and needs to be returned to recycler once we are done) or not.

If it is not, it also means that parser can NOT modify underlying buffer.

  
      protected boolean _bufferRecyclable;
      
     /*
     /**********************************************************
     /* Life-cycle
     /**********************************************************
      */
 
     public UTF8StreamJsonParser(IOContext ctxtint featuresInputStream in,
             ObjectCodec codecBytesToNameCanonicalizer sym,
             byte[] inputBufferint startint end,
             boolean bufferRecyclable)
     {
         super(ctxtfeatures);
          = in;
          = codec;
          = sym;
          = inputBuffer;
          = start;
          = end;
          = bufferRecyclable;
     }
 
     @Override
     public ObjectCodec getCodec() {
         return ;
     }
 
     @Override
     public void setCodec(ObjectCodec c) {
          = c;
     }
 
     @Override
     public Version version() {
         return ..version();
     }
     
     /*
     /**********************************************************
     /* Overrides
     /**********************************************************
      */
 
     @Override
     public int releaseBuffered(OutputStream outthrows IOException
     {
         int count =  - ;
         if (count < 1) {
             return 0;
         }
         // let's just advance ptr to end
         int origPtr = ;
         out.write(origPtrcount);
         return count;
     }
 
     @Override
     public Object getInputSource() {
         return ;
     }
     
     /*
     /**********************************************************
     /* Low-level reading, other
     /**********************************************************
      */
 
     @Override
     protected boolean loadMore()
         throws IOException
     {
          += ;
          -= ;
         
         if ( != null) {
             int count = .read(, 0, .);
             if (count > 0) {
                  = 0;
                  = count;
                 return true;
             }
             // End of input
             _closeInput();
             // Should never return 0, so let's fail
             if (count == 0) {
                 throw new IOException("InputStream.read() returned 0 characters when trying to read "+.+" bytes");
             }
         }
         return false;
     }

    
Helper method that will try to load at least specified number bytes in input buffer, possible moving existing data around if necessary
 
     protected boolean _loadToHaveAtLeast(int minAvailable)
         throws IOException
     {
         // No input stream, no leading (either we are closed, or have non-stream input source)
         if ( == null) {
             return false;
         }
         // Need to move remaining data in front?
         int amount =  - ;
         if (amount > 0 &&  > 0) {
              += ;
              -= ;
             System.arraycopy(, 0, amount);
              = amount;
         } else {
              = 0;
         }
          = 0;
         while ( < minAvailable) {
             int count = .read(. - );
             if (count < 1) {
                 // End of input
                 _closeInput();
                 // Should never return 0, so let's fail
                 if (count == 0) {
                     throw new IOException("InputStream.read() returned 0 characters when trying to read "+amount+" bytes");
                 }
                 return false;
             }
              += count;
         }
         return true;
     }
     
     @Override
     protected void _closeInput() throws IOException
     {
         /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
          *   on the underlying InputStream, unless we "own" it, or auto-closing
          *   feature is enabled.
          */
         if ( != null) {
             if (.isResourceManaged() || isEnabled(.)) {
                 .close();
             }
              = null;
         }
     }

    
Method called to release internal buffers owned by the base reader. This may be called along with _closeInput() (for example, when explicitly closing this reader instance), or separately (if need be).
 
     @Override
     protected void _releaseBuffers() throws IOException
     {
         super._releaseBuffers();
         if () {
             byte[] buf = ;
             if (buf != null) {
                  = null;
                 .releaseReadIOBuffer(buf);
             }
         }
     }
 
     /*
     /**********************************************************
     /* Public API, data access
     /**********************************************************
      */
 
     @Override
     public String getText()
         throws IOExceptionJsonParseException
     {
         if ( == .) {
             if () {
                  = false;
                 _finishString(); // only strings can be incomplete
             }
             return .contentsAsString();
         }
         return _getText2();
     }
 
     // // // Let's override default impls for improved performance
     
     // @since 2.1
     @Override
     {
         if ( == .) {
             if () {
                  = false;
                 _finishString(); // only strings can be incomplete
             }
             return .contentsAsString();
         }
         return super.getValueAsString(null);
     }
     
     // @since 2.1
     @Override
     public String getValueAsString(String defValuethrows IOExceptionJsonParseException
     {
         if ( == .) {
             if () {
                  = false;
                 _finishString(); // only strings can be incomplete
             }
             return .contentsAsString();
         }
         return super.getValueAsString(defValue);
     }
     
     protected String _getText2(JsonToken t)
     {
         if (t == null) {
             return null;
         }
         switch (t) {
         case :
             return .getCurrentName();
 
         case :
             // fall through
         case :
         case :
             return .contentsAsString();
         }
         return t.asString();
     }
 
     @Override
     public char[] getTextCharacters()
         throws IOExceptionJsonParseException
     {
         if ( != null) { // null only before/after document
             switch () {
                 
             case :
                 if (!) {
                     String name = .getCurrentName();
                     int nameLen = name.length();
                     if ( == null) {
                          = .allocNameCopyBuffer(nameLen);
                     } else if (. < nameLen) {
                          = new char[nameLen];
                     }
                     name.getChars(0, nameLen, 0);
                      = true;
                 }
                 return ;
     
             case :
                 if () {
                      = false;
                     _finishString(); // only strings can be incomplete
                 }
                 // fall through
             case :
             case :
                 return .getTextBuffer();
                 
             default:
                 return .asCharArray();
             }
         }
         return null;
     }
 
     @Override
     public int getTextLength()
         throws IOExceptionJsonParseException
     {
         if ( != null) { // null only before/after document
             switch () {
                 
             case :
                 return .getCurrentName().length();
             case :
                 if () {
                      = false;
                     _finishString(); // only strings can be incomplete
                 }
                 // fall through
             case :
             case :
                 return .size();
                 
             default:
                 return .asCharArray().length;
             }
         }
         return 0;
     }
 
     @Override
     public int getTextOffset() throws IOExceptionJsonParseException
     {
         // Most have offset of 0, only some may have other values:
         if ( != null) {
             switch () {
             case :
                 return 0;
             case :
                 if () {
                      = false;
                     _finishString(); // only strings can be incomplete
                 }
                 // fall through
             case :
             case :
                 return .getTextOffset();
             }
         }
         return 0;
     }
 
     // No embedded objects with base impl...
     @Override
     public Object getEmbeddedObject() throws IOExceptionJsonParseException {
         return null;
     }
     
     @Override
     public byte[] getBinaryValue(Base64Variant b64variant)
         throws IOExceptionJsonParseException
     {
         if ( != . &&
                 ( != . ||  == null)) {
             _reportError("Current token ("++") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
         }
         /* To ensure that we won't see inconsistent data, better clear up
          * state...
          */
         if () {
             try {
                  = _decodeBase64(b64variant);
             } catch (IllegalArgumentException iae) {
                 throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
             }
             /* let's clear incomplete only now; allows for accessing other
              * textual content in error cases
              */
              = false;
         } else { // may actually require conversion...
             if ( == null) {
                 ByteArrayBuilder builder = _getByteArrayBuilder();
                 _decodeBase64(getText(), builderb64variant);
                  = builder.toByteArray();
             }
         }
         return ;
     }
 
     @Override
     public int readBinaryValue(Base64Variant b64variantOutputStream out)
         throws IOExceptionJsonParseException
     {
         // if we have already read the token, just use whatever we may have
         if (! ||  != .) {
             byte[] b = getBinaryValue(b64variant);
             out.write(b);
             return b.length;
         }
         // otherwise do "real" incremental parsing...
         byte[] buf = .allocBase64Buffer();
         try {
             return _readBinary(b64variantoutbuf);
         } finally {
             .releaseBase64Buffer(buf);
         }
     }
 
     protected int _readBinary(Base64Variant b64variantOutputStream out,
                               byte[] buffer)
         throws IOExceptionJsonParseException
     {
         int outputPtr = 0;
         final int outputEnd = buffer.length - 3;
         int outputCount = 0;
 
         while (true) {
             // first, we'll skip preceding white space, if any
             int ch;
             do {
                 if ( >= ) {
                     loadMoreGuaranteed();
                 }
                 ch = (int[++] & 0xFF;
             } while (ch <= );
             int bits = b64variant.decodeBase64Char(ch);
             if (bits < 0) { // reached the end, fair and square?
                 if (ch == ) {
                     break;
                 }
                 bits = _decodeBase64Escape(b64variantch, 0);
                 if (bits < 0) { // white space to skip
                     continue;
                 }
             }
 
             // enough room? If not, flush
             if (outputPtr > outputEnd) {
                 outputCount += outputPtr;
                 out.write(buffer, 0, outputPtr);
                 outputPtr = 0;
             }
 
             int decodedData = bits;
 
             // then second base64 char; can't get padding yet, nor ws
 
             if ( >= ) {
                 loadMoreGuaranteed();
             }
             ch = [++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
             if (bits < 0) {
                 bits = _decodeBase64Escape(b64variantch, 1);
             }
             decodedData = (decodedData << 6) | bits;
 
             // third base64 char; can be padding, but not ws
             if ( >= ) {
                 loadMoreGuaranteed();
             }
             ch = [++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
 
             // First branch: can get padding (-> 1 byte)
             if (bits < 0) {
                 if (bits != .) {
                     // as per [JACKSON-631], could also just be 'missing'  padding
                     if (ch == '"' && !b64variant.usesPadding()) {
                         decodedData >>= 4;
                         buffer[outputPtr++] = (bytedecodedData;
                         break;
                     }
                     bits = _decodeBase64Escape(b64variantch, 2);
                 }
                 if (bits == .) {
                     // Ok, must get padding
                     if ( >= ) {
                         loadMoreGuaranteed();
                     }
                     ch = [++] & 0xFF;
                     if (!b64variant.usesPaddingChar(ch)) {
                         throw reportInvalidBase64Char(b64variantch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
                     }
                     // Got 12 bits, only need 8, need to shift
                     decodedData >>= 4;
                     buffer[outputPtr++] = (bytedecodedData;
                     continue;
                 }
             }
             // Nope, 2 or 3 bytes
             decodedData = (decodedData << 6) | bits;
             // fourth and last base64 char; can be padding, but not ws
             if ( >= ) {
                 loadMoreGuaranteed();
             }
             ch = [++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
             if (bits < 0) {
                 if (bits != .) {
                     // as per [JACKSON-631], could also just be 'missing'  padding
                     if (ch == '"' && !b64variant.usesPadding()) {
                         decodedData >>= 2;
                         buffer[outputPtr++] = (byte) (decodedData >> 8);
                         buffer[outputPtr++] = (bytedecodedData;
                         break;
                     }
                     bits = _decodeBase64Escape(b64variantch, 3);
                 }
                 if (bits == .) {
                     /* With padding we only get 2 bytes; but we have
                      * to shift it a bit so it is identical to triplet
                      * case with partial output.
                      * 3 chars gives 3x6 == 18 bits, of which 2 are
                      * dummies, need to discard:
                      */
                     decodedData >>= 2;
                     buffer[outputPtr++] = (byte) (decodedData >> 8);
                     buffer[outputPtr++] = (bytedecodedData;
                     continue;
                 }
             }
             // otherwise, our triplet is now complete
             decodedData = (decodedData << 6) | bits;
             buffer[outputPtr++] = (byte) (decodedData >> 16);
             buffer[outputPtr++] = (byte) (decodedData >> 8);
             buffer[outputPtr++] = (bytedecodedData;
         }
          = false;
         if (outputPtr > 0) {
             outputCount += outputPtr;
             out.write(buffer, 0, outputPtr);
         }
         return outputCount;
     }
 
     /*
     /**********************************************************
     /* Public API, traversal, basic
     /**********************************************************
      */

    

Returns:
Next token from the stream, if any found, or null to indicate end-of-input
 
     @Override
     public JsonToken nextToken()
         throws IOExceptionJsonParseException
     {
          = ;
         /* First: field names are special -- we will always tokenize
          * (part of) value along with field name to simplify
          * state handling. If so, can and need to use secondary token:
          */
         if ( == .) {
             return _nextAfterName();
         }
         if () {
             _skipString(); // only strings can be partial
         }
 
         int i = _skipWSOrEnd();
         if (i < 0) { // end-of-input
             /* 19-Feb-2009, tatu: Should actually close/release things
              *    like input source, symbol table and recyclable buffers now.
              */
             close();
             return ( = null);
         }
 
         /* First, need to ensure we know the starting location of token
          * after skipping leading white space
          */
          =  +  - 1;
          = ;
          =  -  - 1;
 
         // finally: clear any data retained so far
          = null;
 
         // Closing scope?
         if (i == ) {
             if (!.inArray()) {
                 _reportMismatchedEndMarker(i'}');
             }
              = .getParent();
             return ( = .);
         }
         if (i == ) {
             if (!.inObject()) {
                 _reportMismatchedEndMarker(i']');
             }
              = .getParent();
             return ( = .);
         }
 
         // Nope: do we then expect a comma?
         if (.expectComma()) {
             if (i != ) {
                 _reportUnexpectedChar(i"was expecting comma to separate "+.getTypeDesc()+" entries");
             }
             i = _skipWS();
         }
 
         /* And should we now have a name? Always true for
          * Object contexts, since the intermediate 'expect-value'
          * state is never retained.
          */
         if (!.inObject()) {
             return _nextTokenNotInObject(i);
         }
         // So first parse the field name itself:
         Name n = _parseFieldName(i);
         .setCurrentName(n.getName());
          = .;
         i = _skipWS();
         if (i != ) {
             _reportUnexpectedChar(i"was expecting a colon to separate field name and value");
         }
         i = _skipWS();
 
         // Ok: we must have a value... what is it? Strings are very common, check first:
         if (i == ) {
              = true;
              = .;
             return ;
         }        
         JsonToken t;
 
         switch (i) {
         case :
             t = .;
             break;
         case :
             t = .;
             break;
         case :
         case :
             // Error: neither is valid at this point; valid closers have
             // been handled earlier
             _reportUnexpectedChar(i"expected a value");
         case :
             _matchToken("true", 1);
             t = .;
             break;
         case :
             _matchToken("false", 1);
              t = .;
             break;
         case :
             _matchToken("null", 1);
             t = .;
             break;
 
         case :
             /* Should we have separate handling for plus? Although
              * it is not allowed per se, it may be erroneously used,
              * and could be indicate by a more specific error message.
              */
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
             t = parseNumberText(i);
             break;
         default:
             t = _handleUnexpectedValue(i);
         }
          = t;
         return ;
     }
 
     private JsonToken _nextTokenNotInObject(int i)
         throws IOExceptionJsonParseException
     {
         if (i == ) {
              = true;
             return ( = .);
         }
         switch (i) {
         case :
             return ( = .);
         case :
             return ( = .);
         case :
         case :
             // Error: neither is valid at this point; valid closers have
             // been handled earlier
             _reportUnexpectedChar(i"expected a value");
         case :
             _matchToken("true", 1);
             return ( = .);
         case :
             _matchToken("false", 1);
             return ( = .);
         case :
             _matchToken("null", 1);
             return ( = .);
         case :
             /* Should we have separate handling for plus? Although
              * it is not allowed per se, it may be erroneously used,
              * and could be indicate by a more specific error message.
              */
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
             return ( = parseNumberText(i));
         }
         return ( = _handleUnexpectedValue(i));
     }
     
     private JsonToken _nextAfterName()
     {
          = false// need to invalidate if it was copied
         JsonToken t = ;
          = null;
         // Also: may need to start new context?
         if (t == .) {
         } else if (t == .) {
         }
         return ( = t);
     }
 
     @Override
     public void close() throws IOException
     {
         super.close();
         // Merge found symbols, if any:
         .release();
     }
     
     /*
     /**********************************************************
     /* Public API, traversal, nextXxxValue/nextFieldName
     /**********************************************************
      */
     
     @Override
     public boolean nextFieldName(SerializableString str)
         throws IOExceptionJsonParseException
     {
         // // // Note: most of code below is copied from nextToken()
         
          = ;
         if ( == .) { // can't have name right after name
             _nextAfterName();
             return false;
         }
         if () {
             _skipString();
         }
         int i = _skipWSOrEnd();
         if (i < 0) { // end-of-input
             close();
              = null;
             return false;
         }
          =  +  - 1;
          = ;
          =  -  - 1;
 
         // finally: clear any data retained so far
          = null;
 
         // Closing scope?
         if (i == ) {
             if (!.inArray()) {
                 _reportMismatchedEndMarker(i'}');
             }
              = .getParent();
              = .;
             return false;
         }
         if (i == ) {
             if (!.inObject()) {
                 _reportMismatchedEndMarker(i']');
             }
              = .getParent();
              = .;
             return false;
         }
 
         // Nope: do we then expect a comma?
         if (.expectComma()) {
             if (i != ) {
                 _reportUnexpectedChar(i"was expecting comma to separate "+.getTypeDesc()+" entries");
             }
             i = _skipWS();
         }
 
         if (!.inObject()) {
             _nextTokenNotInObject(i);
             return false;
         }
         
         // // // This part differs, name parsing
         if (i == ) {
             // when doing literal match, must consider escaping:
             byte[] nameBytes = str.asQuotedUTF8();
             final int len = nameBytes.length;
             if (( + len) < ) { // maybe...
                 // first check length match by
                 final int end = +len;
                 if ([end] == ) {
                     int offset = 0;
                     final int ptr = ;
                     while (true) {
                         if (offset == len) { // yes, match!
                              = end+1; // skip current value first
                             // First part is simple; setting of name
                             .setCurrentName(str.getValue());
                              = .;
                             // But then we also must handle following value etc
                             _isNextTokenNameYes();
                             return true;
                         }
                         if (nameBytes[offset] != [ptr+offset]) {
                             break;
                         }
                         ++offset;
                     }
                 }
             }
         }
         _isNextTokenNameNo(i);
         return false;
     }
 
     private void _isNextTokenNameYes()
         throws IOExceptionJsonParseException
     {
         // very first thing: common case, colon, value, no white space
         int i;
         if ( <  && [] == ) { // fast case first
             ++;
             i = [++];
             if (i == ) {
                  = true;
                  = .;
                 return;
             }
             if (i == ) {
                  = .;
                 return;
             }
             if (i == ) {
                  = .;
                 return;
             }
             i &= 0xFF;
             if (i <=  || i == ) {
                 --;
                 i = _skipWS();
             }
         } else {
             i = _skipColon();
         }
         switch (i) {
         case :
              = true;
              = .;
             return;
         case :
              = .;
             return;
         case :
              = .;
             return;
         case :
         case :
             _reportUnexpectedChar(i"expected a value");
         case :
             _matchToken("true", 1);
              = .;
             return;
         case :
             _matchToken("false", 1);
              = .;
             return;
         case :
             _matchToken("null", 1);
              = .;
             return;
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
         case :
              = parseNumberText(i);
             return;
         }
          = _handleUnexpectedValue(i);
     }
     
     private void _isNextTokenNameNo(int i)
             throws IOExceptionJsonParseException
     {
         // // // and this is back to standard nextToken()
             
         Name n = _parseFieldName(i);
         .setCurrentName(n.getName());
          = .;
         i = _skipWS();
         if (i != ) {
             _reportUnexpectedChar(i"was expecting a colon to separate field name and value");
         }
         i = _skipWS();
 
         // Ok: we must have a value... what is it? Strings are very common, check first:
         if (i == ) {
              = true;
              = .;
            return;
        }        
        JsonToken t;
        switch (i) {
        case :
            t = .;
            break;
        case :
            t = .;
            break;
        case :
        case :
            _reportUnexpectedChar(i"expected a value");
        case :
            _matchToken("true", 1);
            t = .;
            break;
        case :
            _matchToken("false", 1);
             t = .;
            break;
        case :
            _matchToken("null", 1);
            t = .;
            break;
        case :
        case :
        case :
        case :
        case :
        case :
        case :
        case :
        case :
        case :
        case :
            t = parseNumberText(i);
            break;
        default:
            t = _handleUnexpectedValue(i);
        }
         = t;
    }
    @Override
    public String nextTextValue()
        throws IOExceptionJsonParseException
    {
        // two distinct cases; either got name and we know next type, or 'other'
        if ( == .) { // mostly copied from '_nextAfterName'
             = false;
            JsonToken t = ;
             = null;
             = t;
            if (t == .) {
                if () {
                     = false;
                    _finishString();
                }
                return .contentsAsString();
            }
            if (t == .) {
            } else if (t == .) {
            }
            return null;
        }
        // !!! TODO: optimize this case as well
        return (nextToken() == .) ? getText() : null;
    }
    @Override
    public int nextIntValue(int defaultValue)
        throws IOExceptionJsonParseException
    {
        // two distinct cases; either got name and we know next type, or 'other'
        if ( == .) { // mostly copied from '_nextAfterName'
             = false;
            JsonToken t = ;
             = null;
             = t;
            if (t == .) {
                return getIntValue();
            }
            if (t == .