Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   package com.fasterxml.jackson.dataformat.smile;
   
   import java.io.IOException;
   import java.io.InputStream;
   import java.io.OutputStream;
   import java.math.BigDecimal;
   import java.math.BigInteger;
   import java.util.Arrays;
  
  
  import static com.fasterxml.jackson.dataformat.smile.SmileConstants.BYTE_MARKER_END_OF_STRING;
  
  public class SmileParser
      extends ParserBase
  {
    
Enumeration that defines all togglable features for Smile generators.
  
      public enum Feature {
        
Feature that determines whether 4-byte Smile header is mandatory in input, or optional. If enabled, it means that only input that starts with the header is accepted as valid; if disabled, header is optional. In latter case,r settings for content are assumed to be defaults.
  
          REQUIRE_HEADER(true)
          ;
  
          final boolean _defaultState;
          final int _mask;
        
        
Method that calculates bit set (flags) of all features that are enabled by default.
  
          public static int collectDefaults()
          {
              int flags = 0;
              for (Feature f : values()) {
                  if (f.enabledByDefault()) {
                      flags |= f.getMask();
                  }
              }
              return flags;
          }
          
          private Feature(boolean defaultState) {
               = defaultState;
               = (1 << ordinal());
          }
          
          public boolean enabledByDefault() { return ; }
          public int getMask() { return ; }
      }
  
      private final static int[] NO_INTS = new int[0];
  
      private final static String[] NO_STRINGS = new String[0];
      
      /*
      /**********************************************************
      /* Configuration
      /**********************************************************
       */
    
    
Codec used for data binding when (if) requested.
  
      protected ObjectCodec _objectCodec;

    
Flag that indicates whether content can legally have raw (unquoted) binary data. Since this information is included both in header and in actual binary data blocks there is redundancy, and we want to ensure settings are compliant. Using application may also want to know this setting in case it does some direct (random) access.
  
      protected boolean _mayContainRawBinary;

    
Helper object used for low-level recycling of Smile-generator specific buffers.
  
      final protected SmileBufferRecycler<String_smileBufferRecycler;
  
      /*
      /**********************************************************
      /* Input source config, state (from ex StreamBasedParserBase)
      /**********************************************************
       */

    
Input stream that can be used for reading more content, if one in use. May be null, if input comes just as a full buffer, or if the stream has been closed.
 
     protected InputStream _inputStream;

    
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;
     
     /*
     /**********************************************************
     /* Additional parsing state
     /**********************************************************
      */

    
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;

    
Type byte of the current token
 
     protected int _typeByte;

    
Specific flag that is set when we encountered a 32-bit floating point value; needed since numeric super classes do not track distinction between float and double, but Smile format does, and we want to retain that separation.
 
     protected boolean _got32BitFloat;
 
     /*
     /**********************************************************
     /* Symbol handling, decoding
     /**********************************************************
      */

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

    
Quads used for hash calculation
 
     protected int _quad1_quad2;
     
    
Array of recently seen field names, which may be back referenced by later fields. Defaults set to enable handling even if no header found.
 
     protected String[] _seenNames = ;
 
     protected int _seenNameCount = 0;

    
Array of recently seen field names, which may be back referenced by later fields Defaults set to disable handling if no header found.
 
     protected String[] _seenStringValues = null;
 
     protected int _seenStringValueCount = -1;
     
     /*
     /**********************************************************
     /* Thread-local recycling
     /**********************************************************
      */
    
    
ThreadLocal contains a java.lang.ref.SoftReference to a buffer recycler used to provide a low-cost buffer recycling for Smile-specific buffers.
 
         = new ThreadLocal<SoftReference<SmileBufferRecycler<String>>>();
 
     /*
     /**********************************************************
     /* Life-cycle
     /**********************************************************
      */
     
     public SmileParser(IOContext ctxtint parserFeaturesint smileFeatures,
             ObjectCodec codec,
             BytesToNameCanonicalizer sym,
             InputStream inbyte[] inputBufferint startint end,
             boolean bufferRecyclable)
     {
         super(ctxtparserFeatures);        
          = codec;
          = sym;
 
          = in;
          = inputBuffer;
          = start;
          = end;
          = bufferRecyclable;
         
          = -1;
          = -1;
     }
 
     @Override
     public ObjectCodec getCodec() {
         return ;
     }
 
     @Override
     public void setCodec(ObjectCodec c) {
          = c;
     }

    
Helper method called when it looks like input might contain the signature; and it is necessary to detect and handle signature to get configuration information it might have.

Returns:
True if valid signature was found and handled; false if not
 
     protected boolean handleSignature(boolean consumeFirstByteboolean throwException)
         throws IOExceptionJsonParseException
     {
         if (consumeFirstByte) {
             ++;
         }
         if ( >= ) {
             loadMoreGuaranteed();
         }
         if ([] != .) {
             if (throwException) {
             	_reportError("Malformed content: signature not valid, starts with 0x3a but followed by 0x"
             			+Integer.toHexString([])+", not 0x29");
             }
             return false;
         }
         if (++ >= ) {
             loadMoreGuaranteed();        	
         }
         if ([] != .) {
             if (throwException) {
             	_reportError("Malformed content: signature not valid, starts with 0x3a, 0x29, but followed by 0x"
             			+Integer.toHexString([])+", not 0xA");
             }
             return false;
         }
     	// Good enough; just need version info from 4th byte...
         if (++ >= ) {
             loadMoreGuaranteed();        	
         }
         int ch = [++];
         int versionBits = (ch >> 4) & 0x0F;
         // but failure with version number is fatal, can not ignore
         if (versionBits != .) {
             _reportError("Header version number bits (0x"+Integer.toHexString(versionBits)+") indicate unrecognized version; only 0x0 handled by parser");
         }
 
         // can avoid tracking names, if explicitly disabled
         if ((ch & .) == 0) {
              = null;
              = -1;
         }
         // conversely, shared string values must be explicitly enabled
         if ((ch & .) != 0) {
              = ;
              = 0;
         }
          = ((ch & .) != 0);
         return true;
     }
 
     protected final static SmileBufferRecycler<String_smileBufferRecycler()
     {
         SmileBufferRecycler<Stringbr = (ref == null) ? null : ref.get();
 
         if (br == null) {
             br = new SmileBufferRecycler<String>();
             .set(new SoftReference<SmileBufferRecycler<String>>(br));
         }
         return br;
     }
 
     /*                                                                                       
     /**********************************************************                              
     /* Versioned                                                                             
     /**********************************************************                              
      */
 
     @Override
     public Version version() {
         return .;
     }
     
     /*
     /**********************************************************
     /* Former StreamBasedParserBase methods
     /**********************************************************
      */
 
     @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 ;
     }

    
Overridden since we do not really have character-based locations, but we do have byte offset to specify.
 
     @Override
     public JsonLocation getTokenLocation()
     {
         // token location is correctly managed...
         return new JsonLocation(.getSourceReference(),
                 // bytes
                 -1, -1, (int); // char offset, line, column
     }   

    
Overridden since we do not really have character-based locations, but we do have byte offset to specify.
 
     @Override
     public JsonLocation getCurrentLocation()
     {
         final long offset =  + ;
         return new JsonLocation(.getSourceReference(),
                 offset// bytes
                 -1, -1, (intoffset); // char offset, line, column
     }
 
     /*
     /**********************************************************
     /* Low-level reading, other
     /**********************************************************
      */
     
     @Override
     protected final boolean loadMore()
         throws IOException
     {
          += ;
         //_currInputRowStart -= _inputEnd;
         
         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

Since:
1.6
 
     protected final 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) {
              += ;
             //_currInputRowStart -= _inputPtr;
             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) {
                 .close();
             }
              = null;
         }
     }
     
     /*
     /**********************************************************
     /* Overridden methods
     /**********************************************************
      */
 
     @Override
     protected void _finishString() throws IOExceptionJsonParseException
     {
         // should never be called; but must be defined for superclass
         _throwInternal();
     }
 
     @Override
     public void close() throws IOException
     {
         super.close();
         // Merge found symbols, if any:
         .release();
     }
 
     @Override
     public boolean hasTextCharacters()
     {
         if ( == .) {
             // yes; is or can be made available efficiently as char[]
             return .hasTextAsCharacters();
         }
         if ( == .) {
             // not necessarily; possible but:
             return ;
         }
         // other types, no benefit from accessing as char[]
         return false;
     }

    
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);
              }
          }
         {
             String[] nameBuf = ;
             if (nameBuf != null && nameBuf.length > 0) {
                  = null;
                 /* 28-Jun-2011, tatu: With 1.9, caller needs to clear the buffer;
                  *   but we only need to clear up to count as it is not a hash area
                  */
                 if ( > 0) {
                     Arrays.fill(nameBuf, 0, null);
                 }
                 .releaseSeenNamesBuffer(nameBuf);
             }
         }
         {
             String[] valueBuf = ;
             if (valueBuf != null && valueBuf.length > 0) {
                  = null;
                 /* 28-Jun-2011, tatu: With 1.9, caller needs to clear the buffer;
                  *   but we only need to clear up to count as it is not a hash area
                  */
                 if ( > 0) {
                     Arrays.fill(valueBuf, 0, null);
                 }
                 .releaseSeenStringValuesBuffer(valueBuf);
             }
         }
     }
     
     /*
     /**********************************************************
     /* Extended API
     /**********************************************************
      */
 
     public boolean mayContainRawBinary() {
         return ;
     }
     
     /*
     /**********************************************************
     /* JsonParser impl
     /**********************************************************
      */
 
     @Override
     public JsonToken nextToken() throws IOExceptionJsonParseException
     {
          = ;
         // For longer tokens (text, binary), we'll only read when requested
         if () {
             _skipIncomplete();
         }
         // also: clear any data retained so far
          = null;
         // Two main modes: values, and field names.
         if (.inObject() &&  != .) {
             return ( = _handleFieldName());
         }
         if ( >= ) {
             if (!loadMore()) {
                 _handleEOF();
                 /* NOTE: here we can and should close input, release buffers,
                  * since this is "hard" EOF, not a boundary imposed by
                  * header token.
                  */
                 close();
                 return ( = null);
             }
         }
         int ch = [++];
          = ch;
         switch ((ch >> 5) & 0x7) {
         case 0: // short shared string value reference
             if (ch == 0) { // important: this is invalid, don't accept
                 _reportError("Invalid token byte 0x00");
             }
             return _handleSharedString(ch-1);
 
         case 1: // simple literals, numbers
             {
                 int typeBits = ch & 0x1F;
                 if (typeBits < 4) {
                     switch (typeBits) {
                     case 0x00:
                         .resetWithEmpty();
                         return ( = .);
                     case 0x01:
                         return ( = .);
                     case 0x02: // false
                         return ( = .);
                     default// 0x03 == true
                         return ( = .);
                     }
                 }
                 // next 3 bytes define subtype
                 if (typeBits < 8) { // VInt (zigzag), BigInteger
                     if ((typeBits & 0x3) <= 0x2) { // 0x3 reserved (should never occur)
                          = true;
                          = 0;
                         return ( = .);
                     }
                     break;
                 }
                 if (typeBits < 12) { // floating-point
                     int subtype = typeBits & 0x3;
                     if (subtype <= 0x2) { // 0x3 reserved (should never occur)
                          = true;
                          = 0;
                          = (subtype == 0);
                         return ( = .);
                     }
                     break;
                 }
                 if (typeBits == 0x1A) { // == 0x3A == ':' -> possibly header signature for next chunk?
                     if (handleSignature(falsefalse)) {
                         /* Ok, now; end-marker and header both imply doc boundary and a
                          * 'null token'; but if both are seen, they are collapsed.
                          * We can check this by looking at current token; if it's null,
                          * need to get non-null token
                          */
                         if ( == null) {
                             return nextToken();
                         }
                         return ( = null);
                     }
             	}
             	_reportError("Unrecognized token byte 0x3A (malformed segment header?");
             }
             // and everything else is reserved, for now
             break;
         case 2: // tiny ASCII
             // fall through            
         case 3: // short ASCII
             // fall through
         case 4: // tiny Unicode
             // fall through
         case 5: // short Unicode
             // No need to decode, unless we have to keep track of back-references (for shared string values)
              = .;
             if ( >= 0) { // shared text values enabled
                 _addSeenStringValue();
             } else {
                  = true;
             }
             return ;
         case 6: // small integers; zigzag encoded
              = SmileUtil.zigzagDecode(ch & 0x1F);
              = ;
             return ( = .);
         case 7: // binary/long-text/long-shared/start-end-markers
             switch (ch & 0x1F) {
             case 0x00: // long variable length ASCII
             case 0x04: // long variable length unicode
                  = true;
                 return ( = .);
             case 0x08: // binary, 7-bit (0xE8)
                  = true;
                 return ( = .);
             case 0x0C: // long shared string (0xEC)
             case 0x0D:
             case 0x0E:
             case 0x0F:
                 if ( >= ) {
                     loadMoreGuaranteed();
                 }
                 return _handleSharedString(((ch & 0x3) << 8) + ([++] & 0xFF));
             case 0x18: // START_ARRAY
                  = .createChildArrayContext(-1, -1);
                 return ( = .);
             case 0x19: // END_ARRAY
                 if (!.inArray()) {
                     _reportMismatchedEndMarker(']''}');
                 }
                  = .getParent();
                 return ( = .);
             case 0x1A: // START_OBJECT
                  = .createChildObjectContext(-1, -1);
                 return ( = .);
             case 0x1B: // not used in this mode; would be END_OBJECT
                 _reportError("Invalid type marker byte 0xFB in value mode (would be END_OBJECT in key mode)");
             case 0x1D: // binary, raw
                  = true;
                 return ( = .);
             case 0x1F: // 0xFF, end of content
                 return ( = null);
             }
             break;
         }
         // If we get this far, type byte is corrupt
         _reportError("Invalid type marker byte 0x"+Integer.toHexString(ch & 0xFF)+" for expected value token");
         return null;
     }
 
     private final JsonToken _handleSharedString(int index)
         throws IOExceptionJsonParseException
     {
         if (index >= ) {
             _reportInvalidSharedStringValue(index);
         }
         return ( = .);
     }
 
     private final void _addSeenStringValue()
         throws IOExceptionJsonParseException
     {
         _finishToken();
         if ( < .) {
             // !!! TODO: actually only store char[], first time around?
             return;
         }
         _expandSeenStringValues();
     }
     
     private final void _expandSeenStringValues()
     {
         String[] oldShared = ;
         int len = oldShared.length;
         String[] newShared;
         if (len == 0) {
             newShared = .allocSeenStringValuesBuffer();
             if (newShared == null) {
                 newShared = new String[.];
             }
         } else if (len == .) { // too many? Just flush...
            newShared = oldShared;
             = 0; // could also clear, but let's not yet bother
         } else {
             int newSize = (len == .) ? 256 : .;
             newShared = new String[newSize];
             System.arraycopy(oldShared, 0, newShared, 0, oldShared.length);
         }
          = newShared;
     }
 
     // base impl is fine:
     //public String getCurrentName() throws IOException, JsonParseException
 
     @Override
     public NumberType getNumberType()
         throws IOExceptionJsonParseException
     {
         if () {
             return .;
         }
         return super.getNumberType();
     }
 
     /*
     /**********************************************************
     /* Public API, traversal, nextXxxValue/nextFieldName
     /**********************************************************
      */
 
     @Override
     public boolean nextFieldName(SerializableString str)
         throws IOExceptionJsonParseException
     {
         // Two parsing modes; can only succeed if expecting field name, so handle that first:
         if (.inObject() &&  != .) {
             byte[] nameBytes = str.asQuotedUTF8();
             final int byteLen = nameBytes.length;
             // need room for type byte, name bytes, possibly end marker, so:
             if (( + byteLen + 1) < ) { // maybe...
                 int ptr = ;
                 int ch = [ptr++];
                  = ch;
                 main_switch:
                 switch ((ch >> 6) & 3) {
                 case 0: // misc, including end marker
                     switch (ch) {
                     case 0x20: // empty String as name, legal if unusual
                          = .;
                          = ptr;
                         .setCurrentName("");
                         return (byteLen == 0);
                     case 0x30: // long shared
                     case 0x31:
                     case 0x32:
                     case 0x33:
                         {
                             int index = ((ch & 0x3) << 8) + ([ptr++] & 0xFF);
                             if (index >= ) {
                                 _reportInvalidSharedName(index);
                             }
                             String name = [index];
                             .setCurrentName(name);
                              = ptr;
                              = .;
                             return (name.equals(str.getValue()));
                         }
                     //case 0x34: // long ASCII/Unicode name; let's not even try...
                     }
                     break;
                 case 1: // short shared, can fully process
                     {
                         int index = (ch & 0x3F);
                         if (index >= ) {
                             _reportInvalidSharedName(index);
                         }
                         .setCurrentName([index]);
                         String name = [index];
                         .setCurrentName(name);
                          = ptr;
                          = .;
                         return (name.equals(str.getValue()));
                     }
                 case 2: // short ASCII
                     {
                         int len = 1 + (ch & 0x3f);
                         if (len == byteLen) {
                             int i = 0;
                             for (; i < len; ++i) {
                                 if (nameBytes[i] != [ptr+i]) {
                                     break main_switch;
                                 }
                             }
                             // yes, does match...
                              = ptr + len;
                             final String name = str.getValue();
                             if ( != null) {
                                if ( >= .) {
                                     = _expandSeenNames();
                                }
                                [++] = name;
                             }
                             .setCurrentName(name);
                              = .;
                             return true;
                         }
                     }
                     break;
                 case 3: // short Unicode
                     // all valid, except for 0xFF
                     {
                         int len = (ch & 0x3F);
                         if (len > 0x37) {
                             if (len == 0x3B) {
                                  = .;
                                 if (!.inObject()) {
                                     _reportMismatchedEndMarker('}'']');
                                 }
                                  = ptr;
                                  = .getParent();
                                 return false;
                             }
                             // error, but let's not worry about that here
                             break;
                         }
                         len += 2; // values from 2 to 57...
                         if (len == byteLen) {
                             int i = 0;
                             for (; i < len; ++i) {
                                 if (nameBytes[i] != [ptr+i]) {
                                     break main_switch;
                                 }
                             }
                             // yes, does match...
                              = ptr + len;
                             final String name = str.getValue();
                             if ( != null) {
                                if ( >= .) {
                                     = _expandSeenNames();
                                }
                                [++] = name;
                             }
                             .setCurrentName(name);
                              = .;
                             return true;
                         }
                     }
                     break;
                 }
             }
             // otherwise fall back to default processing:
             JsonToken t = _handleFieldName();
              = t;
             return (t == .) && str.getValue().equals(.getCurrentName());
         }
         // otherwise just fall back to default handling; should occur rarely
         return (nextToken() == .) && str.getValue().equals(getCurrentName());
     }
 
     @Override
     public String nextTextValue()
         throws IOExceptionJsonParseException
     {
         // can't get text value if expecting name, so
         if (!.inObject() ||  == .) {
             if () {
                 _skipIncomplete();
             }
             int ptr = ;
             if (ptr >= ) {
                 if (!loadMore()) {
                     _handleEOF();
                     close();
                      = null;
                     return null;
                 }
                 ptr = ;
             }
             int ch = [ptr++];
              =  + ;
 
             // also: clear any data retained so far
              = null;
              = ch;
 
             switch ((ch >> 5) & 0x7) {
             case 0: // short shared string value reference
                 if (ch == 0) { // important: this is invalid, don't accept
                     _reportError("Invalid token byte 0x00");
                 }
                 // _handleSharedString...
                 {
                     --ch;
                     if (ch >= ) {
                         _reportInvalidSharedStringValue(ch);
                     }
                      = ptr;
                     String text = [ch];
                     .resetWithString(text);
                      = .;
                     return text;
                 }
 
             case 1: // simple literals, numbers
                 {
                     int typeBits = ch & 0x1F;
                     if (typeBits == 0x00) {
                          = ptr;
                         .resetWithEmpty();
                          = .;
                         return "";
                     }
                 }
                 break;
             case 2: // tiny ASCII
                 // fall through            
             case 3: // short ASCII
                  = .;
                  = ptr;
                 _decodeShortAsciiValue(1 + (ch & 0x3F));
                 {
                     // No need to decode, unless we have to keep track of back-references (for shared string values)
                     String text;
                     if ( >= 0) { // shared text values enabled
                         if ( < .) {
                             text = .contentsAsString();
                             [++] = text;
                         } else {
                             _expandSeenStringValues();
                             text = .contentsAsString();
                         }
                     } else {
                         text = .contentsAsString();
                     }
                     return text;
                 }
 
             case 4: // tiny Unicode
                 // fall through
             case 5: // short Unicode
                  = .;
                  = ptr;
                 _decodeShortUnicodeValue(2 + (ch & 0x3F));
                 {
                     // No need to decode, unless we have to keep track of back-references (for shared string values)
                     String text;
                     if ( >= 0) { // shared text values enabled
                         if ( < .) {
                             text = .contentsAsString();
                             [++] = text;
                         } else {
                             _expandSeenStringValues();
                             text = .contentsAsString();
                         }
                     } else {
                         text = .contentsAsString();
                     }
                     return text;
                 }
             case 6: // small integers; zigzag encoded
                 break;
             case 7: // binary/long-text/long-shared/start-end-markers
                 // TODO: support longer strings too?
                 /*
                 switch (ch & 0x1F) {
                 case 0x00: // long variable length ASCII
                 case 0x04: // long variable length unicode
                    _tokenIncomplete = true;
                    return (_currToken = JsonToken.VALUE_STRING);
                case 0x08: // binary, 7-bit
                    break main;
                case 0x0C: // long shared string
                case 0x0D:
                case 0x0E:
                case 0x0F:
                    if (_inputPtr >= _inputEnd) {
                        loadMoreGuaranteed();
                    }
                    return _handleSharedString(((ch & 0x3) << 8) + (_inputBuffer[_inputPtr++] & 0xFF));
                }
                break;
                */
                break;
            }
        }
        // otherwise fall back to generic handling:
        return (nextToken() == .) ? getText() : null;
    }
    @Override
    public int nextIntValue(int defaultValue)
        throws IOExceptionJsonParseException
    {
        if (nextToken() == .) {
            return getIntValue();
        }
        return defaultValue;
    }
    @Override
    public long nextLongValue(long defaultValue)
        throws IOExceptionJsonParseException
    {
        if (nextToken() == .) {
            return getLongValue();
        }
        return defaultValue;
    }
    @Override
    public Boolean nextBooleanValue()
        throws IOExceptionJsonParseException
    {
        switch (nextToken()) {
        case :
            return .;
        case :
            return .;
        default:
            return null;
        }
    }
    
    /*
    /**********************************************************
    /* Public API, access to token information, text
    /**********************************************************
     */

    
Method for accessing textual representation of the current event; if no current event (before first call to nextToken(), or after encountering end-of-input), returns null. Method can be called for any event.
    @Override    
    public String getText()
        throws IOExceptionJsonParseException
    {
        if () {
             = false;
            // Let's inline part of "_finishToken", common case
            int tb = ;
            int type = (tb >> 5) & 0x7;
            if (type == 2 || type == 3) { // tiny & short ASCII
                _decodeShortAsciiValue(1 + (tb & 0x3F));
                return .contentsAsString();
            }
            if (type == 4 || type == 5) { // tiny & short Unicode
                 // short unicode; note, lengths 2 - 65  (off-by-one compared to ASCII)
                _decodeShortUnicodeValue(2 + (tb & 0x3F));
                return .contentsAsString();
            }
            _finishToken();
        }
        if ( == .) {
            return .contentsAsString();
        }
        JsonToken t = ;
        if (t == null) { // null only before/after document
            return null;
        }
        if (t == .) {
            return .getCurrentName();
        }
        if (t.isNumeric()) {
            // TODO: optimize?
            return getNumberValue().toString();
        }
        return .asString();
    }
    @Override
    public char[] getTextCharacters()
        throws IOExceptionJsonParseException
    {
        if ( != null) { // null only before/after document
            if () {
                _finishToken();
            }
            switch () {                
            case :
                return .getTextBuffer();
            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 ;
                // fall through
            case :
            case :
                // TODO: optimize
                return getNumberValue().toString().toCharArray();
                
            default:
                return .asCharArray();
            }
        }
        return null;
    }
    @Override    
    public int getTextLength()
        throws IOExceptionJsonParseException
    {
        if ( != null) { // null only before/after document
            if () {
                _finishToken();
            }
            switch () {
            case