1 package com.fasterxml.jackson.core.json;
2
3 import java.io.*;
4
5 import com.fasterxml.jackson.core.*;
6 import com.fasterxml.jackson.core.base.ParserBase;
7 import com.fasterxml.jackson.core.io.CharTypes;
8 import com.fasterxml.jackson.core.io.IOContext;
9 import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
10 import com.fasterxml.jackson.core.util.*;
11
12 import static com.fasterxml.jackson.core.JsonTokenId.*;
13
14 /**
15  * This is a concrete implementation of {@link JsonParser}, which is
16  * based on a {@link java.io.InputStream} as the input source.
17  */

18 public class UTF8StreamJsonParser
19     extends ParserBase
20 {
21     final static byte BYTE_LF = (byte) '\n';
22
23     @SuppressWarnings("deprecation")
24     private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
25     @SuppressWarnings("deprecation")
26     private final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask();
27     @SuppressWarnings("deprecation")
28     private final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask();
29     @SuppressWarnings("deprecation")
30     private final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask();
31     private final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask();
32     private final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask();
33     private final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask();
34     private final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask();
35
36     // This is the main input-code lookup table, fetched eagerly
37     private final static int[] _icUTF8 = CharTypes.getInputCodeUtf8();
38
39     // Latin1 encoding is not supported, but we do use 8-bit subset for
40     // pre-processing task, to simplify first pass, keep it fast.
41     protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
42
43     /*
44     /**********************************************************
45     /* Configuration
46     /**********************************************************
47      */

48
49     /**
50      * Codec used for data binding when (if) requested; typically full
51      * <code>ObjectMapper</code>, but that abstract is not part of core
52      * package.
53      */

54     protected ObjectCodec _objectCodec;
55
56     /**
57      * Symbol table that contains field names encountered so far
58      */

59     final protected ByteQuadsCanonicalizer _symbols;
60
61     /*
62     /**********************************************************
63     /* Parsing state
64     /**********************************************************
65      */

66
67     /**
68      * Temporary buffer used for name parsing.
69      */

70     protected int[] _quadBuffer = new int[16];
71
72     /**
73      * Flag that indicates that the current token has not yet
74      * been fully processed, and needs to be finished for
75      * some access (or skipped to obtain the next token)
76      */

77     protected boolean _tokenIncomplete;
78
79     /**
80      * Temporary storage for partially parsed name bytes.
81      */

82     private int _quad1;
83
84     /**
85      * Value of {@link #_inputPtr} at the time when the first character of
86      * name token was read. Used for calculating token location when requested;
87      * combined with {@link #_currInputProcessed}, may be updated appropriately
88      * as needed.
89      *
90      * @since 2.7
91      */

92     protected int _nameStartOffset; 
93
94     /**
95      * @since 2.7
96      */

97     protected int _nameStartRow;
98
99     /**
100      * @since 2.7
101      */

102     protected int _nameStartCol;
103
104     /*
105     /**********************************************************
106     /* Input buffering (from former 'StreamBasedParserBase')
107     /**********************************************************
108      */

109
110     protected InputStream _inputStream;
111
112     /*
113     /**********************************************************
114     /* Current input data
115     /**********************************************************
116      */

117
118     /**
119      * Current buffer from which data is read; generally data is read into
120      * buffer from input source, but in some cases pre-loaded buffer
121      * is handed to the parser.
122      */

123     protected byte[] _inputBuffer;
124
125     /**
126      * Flag that indicates whether the input buffer is recycable (and
127      * needs to be returned to recycler once we are done) or not.
128      *<p>
129      * If it is not, it also means that parser can NOT modify underlying
130      * buffer.
131      */

132     protected boolean _bufferRecyclable;
133
134     /*
135     /**********************************************************
136     /* Life-cycle
137     /**********************************************************
138      */

139
140     /**
141      * @deprecated Since 2.10
142      */

143     @Deprecated
144     public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in,
145             ObjectCodec codec, ByteQuadsCanonicalizer sym,
146             byte[] inputBuffer, int start, int end,
147             boolean bufferRecyclable)
148     {
149         this(ctxt, features, in, codec, sym,
150             inputBuffer, start, end, 0, bufferRecyclable);
151     }
152
153     public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in,
154             ObjectCodec codec, ByteQuadsCanonicalizer sym,
155             byte[] inputBuffer, int start, int end, int bytesPreProcessed,
156             boolean bufferRecyclable)
157     {
158         super(ctxt, features);
159         _inputStream = in;
160         _objectCodec = codec;
161         _symbols = sym;
162         _inputBuffer = inputBuffer;
163         _inputPtr = start;
164         _inputEnd = end;
165         _currInputRowStart = start - bytesPreProcessed;
166         // If we have offset, need to omit that from byte offset, so:
167         _currInputProcessed = -start + bytesPreProcessed;
168         _bufferRecyclable = bufferRecyclable;
169     }
170
171     @Override
172     public ObjectCodec getCodec() {
173         return _objectCodec;
174     }
175
176     @Override
177     public void setCodec(ObjectCodec c) {
178         _objectCodec = c;
179     }
180
181     /*
182     /**********************************************************
183     /* Overrides for life-cycle
184     /**********************************************************
185      */

186
187     @Override
188     public int releaseBuffered(OutputStream out) throws IOException
189     {
190         int count = _inputEnd - _inputPtr;
191         if (count < 1) {
192             return 0;
193         }
194         // let's just advance ptr to end
195         int origPtr = _inputPtr;
196         _inputPtr += count;
197         out.write(_inputBuffer, origPtr, count);
198         return count;
199     }
200
201     @Override
202     public Object getInputSource() {
203         return _inputStream;
204     }
205
206     /*
207     /**********************************************************
208     /* Overrides, low-level reading
209     /**********************************************************
210      */

211
212     protected final boolean _loadMore() throws IOException
213     {
214         if (_inputStream != null) {
215             int space = _inputBuffer.length;
216             if (space == 0) { // only occurs when we've been closed
217                 return false;
218             }
219             
220             int count = _inputStream.read(_inputBuffer, 0, space);
221             if (count > 0) {
222                 final int bufSize = _inputEnd;
223
224                 _currInputProcessed += bufSize;
225                 _currInputRowStart -= bufSize;
226
227                 // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
228                 //   this increase to avoid "moving" name-offset, resulting most likely
229                 //   in negative value, which is fine as combine value remains unchanged.
230                 _nameStartOffset -= bufSize;
231
232                 _inputPtr = 0;
233                 _inputEnd = count;
234
235                 return true;
236             }
237             // End of input
238             _closeInput();
239             // Should never return 0, so let's fail
240             if (count == 0) {
241                 throw new IOException("InputStream.read() returned 0 characters when trying to read "+_inputBuffer.length+" bytes");
242             }
243         }
244         return false;
245     }
246
247     @Override
248     protected void _closeInput() throws IOException
249     {
250         // We are not to call close() on the underlying InputStream
251         // unless we "own" it, or auto-closing feature is enabled.
252         if (_inputStream != null) {
253             if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
254                 _inputStream.close();
255             }
256             _inputStream = null;
257         }
258     }
259
260     /**
261      * Method called to release internal buffers owned by the base
262      * reader. This may be called along with {@link #_closeInput} (for
263      * example, when explicitly closing this reader instance), or
264      * separately (if need be).
265      */

266     @Override
267     protected void _releaseBuffers() throws IOException
268     {
269         super._releaseBuffers();
270         // Merge found symbols, if any:
271         _symbols.release();
272         if (_bufferRecyclable) {
273             byte[] buf = _inputBuffer;
274             if (buf != null) {
275                 // Let's not set it to nullthis way should get slightly more meaningful
276                 // error messages in case someone closes parser indirectly, without realizing.
277                 if (buf != NO_BYTES) {
278                     _inputBuffer = NO_BYTES;
279                     _ioContext.releaseReadIOBuffer(buf);
280                 }
281             }
282         }
283     }
284
285     /*
286     /**********************************************************
287     /* Public API, data access
288     /**********************************************************
289      */

290
291     @Override
292     public String getText() throws IOException
293     {
294         if (_currToken == JsonToken.VALUE_STRING) {
295             if (_tokenIncomplete) {
296                 _tokenIncomplete = false;
297                 return _finishAndReturnString(); // only strings can be incomplete
298             }
299             return _textBuffer.contentsAsString();
300         }
301         return _getText2(_currToken);
302     }
303
304     @Override // since 2.8
305     public int getText(Writer writer) throws IOException
306     {
307         JsonToken t = _currToken;
308         if (t == JsonToken.VALUE_STRING) {
309             if (_tokenIncomplete) {
310                 _tokenIncomplete = false;
311                 _finishString(); // only strings can be incomplete
312             }
313             return _textBuffer.contentsToWriter(writer);
314         }
315         if (t == JsonToken.FIELD_NAME) {
316             String n = _parsingContext.getCurrentName();
317             writer.write(n);
318             return n.length();
319         }
320         if (t != null) {
321             if (t.isNumeric()) {
322                 return _textBuffer.contentsToWriter(writer);
323             }
324             char[] ch = t.asCharArray();
325             writer.write(ch);
326             return ch.length;
327         }
328         return 0;
329     }
330
331     // // // Let's override default impls for improved performance
332     
333     // @since 2.1
334     @Override
335     public String getValueAsString() throws IOException
336     {
337         if (_currToken == JsonToken.VALUE_STRING) {
338             if (_tokenIncomplete) {
339                 _tokenIncomplete = false;
340                 return _finishAndReturnString(); // only strings can be incomplete
341             }
342             return _textBuffer.contentsAsString();
343         }
344         if (_currToken == JsonToken.FIELD_NAME) {
345             return getCurrentName();
346         }
347         return super.getValueAsString(null);
348     }
349     
350     // @since 2.1
351     @Override
352     public String getValueAsString(String defValue) throws IOException
353     {
354         if (_currToken == JsonToken.VALUE_STRING) {
355             if (_tokenIncomplete) {
356                 _tokenIncomplete = false;
357                 return _finishAndReturnString(); // only strings can be incomplete
358             }
359             return _textBuffer.contentsAsString();
360         }
361         if (_currToken == JsonToken.FIELD_NAME) {
362             return getCurrentName();
363         }
364         return super.getValueAsString(defValue);
365     }
366
367     // since 2.6
368     @Override
369     public int getValueAsInt() throws IOException
370     {
371         JsonToken t = _currToken;
372         if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
373             // inlined 'getIntValue()'
374             if ((_numTypesValid & NR_INT) == 0) {
375                 if (_numTypesValid == NR_UNKNOWN) {
376                     return _parseIntValue();
377                 }
378                 if ((_numTypesValid & NR_INT) == 0) {
379                     convertNumberToInt();
380                 }
381             }
382             return _numberInt;
383         }
384         return super.getValueAsInt(0);
385     }
386
387     // since 2.6
388     @Override
389     public int getValueAsInt(int defValue) throws IOException
390     {
391         JsonToken t = _currToken;
392         if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
393             // inlined 'getIntValue()'
394             if ((_numTypesValid & NR_INT) == 0) {
395                 if (_numTypesValid == NR_UNKNOWN) {
396                     return _parseIntValue();
397                 }
398                 if ((_numTypesValid & NR_INT) == 0) {
399                     convertNumberToInt();
400                 }
401             }
402             return _numberInt;
403         }
404         return super.getValueAsInt(defValue);
405     }
406
407     protected final String _getText2(JsonToken t)
408     {
409         if (t == null) {
410             return null;
411         }
412         switch (t.id()) {
413         case ID_FIELD_NAME:
414             return _parsingContext.getCurrentName();
415
416         case ID_STRING:
417             // fall through
418         case ID_NUMBER_INT:
419         case ID_NUMBER_FLOAT:
420             return _textBuffer.contentsAsString();
421         default:
422             return t.asString();
423         }
424     }
425
426     @Override
427     public char[] getTextCharacters() throws IOException
428     {
429         if (_currToken != null) { // null only before/after document
430             switch (_currToken.id()) {
431                 
432             case ID_FIELD_NAME:
433                 if (!_nameCopied) {
434                     String name = _parsingContext.getCurrentName();
435                     int nameLen = name.length();
436                     if (_nameCopyBuffer == null) {
437                         _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
438                     } else if (_nameCopyBuffer.length < nameLen) {
439                         _nameCopyBuffer = new char[nameLen];
440                     }
441                     name.getChars(0, nameLen, _nameCopyBuffer, 0);
442                     _nameCopied = true;
443                 }
444                 return _nameCopyBuffer;
445     
446             case ID_STRING:
447                 if (_tokenIncomplete) {
448                     _tokenIncomplete = false;
449                     _finishString(); // only strings can be incomplete
450                 }
451                 // fall through
452             case ID_NUMBER_INT:
453             case ID_NUMBER_FLOAT:
454                 return _textBuffer.getTextBuffer();
455                 
456             default:
457                 return _currToken.asCharArray();
458             }
459         }
460         return null;
461     }
462
463     @Override
464     public int getTextLength() throws IOException
465     {
466         if (_currToken != null) { // null only before/after document
467             switch (_currToken.id()) {
468                 
469             case ID_FIELD_NAME:
470                 return _parsingContext.getCurrentName().length();
471             case ID_STRING:
472                 if (_tokenIncomplete) {
473                     _tokenIncomplete = false;
474                     _finishString(); // only strings can be incomplete
475                 }
476                 // fall through
477             case ID_NUMBER_INT:
478             case ID_NUMBER_FLOAT:
479                 return _textBuffer.size();
480                 
481             default:
482                 return _currToken.asCharArray().length;
483             }
484         }
485         return 0;
486     }
487
488     @Override
489     public int getTextOffset() throws IOException
490     {
491         // Most have offset of 0, only some may have other values:
492         if (_currToken != null) {
493             switch (_currToken.id()) {
494             case ID_FIELD_NAME:
495                 return 0;
496             case ID_STRING:
497                 if (_tokenIncomplete) {
498                     _tokenIncomplete = false;
499                     _finishString(); // only strings can be incomplete
500                 }
501                 // fall through
502             case ID_NUMBER_INT:
503             case ID_NUMBER_FLOAT:
504                 return _textBuffer.getTextOffset();
505             default:
506             }
507         }
508         return 0;
509     }
510
511     @Override
512     public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
513     {
514         if (_currToken != JsonToken.VALUE_STRING &&
515                 (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) {
516             _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
517         }
518         // To ensure that we won't see inconsistent data, better clear up state...
519         if (_tokenIncomplete) {
520             try {
521                 _binaryValue = _decodeBase64(b64variant);
522             } catch (IllegalArgumentException iae) {
523                 throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
524             }
525             // let's clear incomplete only now; allows for accessing other textual content in error cases
526             _tokenIncomplete = false;
527         } else { // may actually require conversion...
528             if (_binaryValue == null) {
529                 @SuppressWarnings("resource")
530                 ByteArrayBuilder builder = _getByteArrayBuilder();
531                 _decodeBase64(getText(), builder, b64variant);
532                 _binaryValue = builder.toByteArray();
533             }
534         }
535         return _binaryValue;
536     }
537
538     @Override
539     public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
540     {
541         // if we have already read the token, just use whatever we may have
542         if (!_tokenIncomplete || _currToken != JsonToken.VALUE_STRING) {
543             byte[] b = getBinaryValue(b64variant);
544             out.write(b);
545             return b.length;
546         }
547         // otherwise do "real" incremental parsing...
548         byte[] buf = _ioContext.allocBase64Buffer();
549         try {
550             return _readBinary(b64variant, out, buf);
551         } finally {
552             _ioContext.releaseBase64Buffer(buf);
553         }
554     }
555
556     protected int _readBinary(Base64Variant b64variant, OutputStream out,
557                               byte[] buffer) throws IOException
558     {
559         int outputPtr = 0;
560         final int outputEnd = buffer.length - 3;
561         int outputCount = 0;
562
563         while (true) {
564             // first, we'll skip preceding white space, if any
565             int ch;
566             do {
567                 if (_inputPtr >= _inputEnd) {
568                     _loadMoreGuaranteed();
569                 }
570                 ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
571             } while (ch <= INT_SPACE);
572             int bits = b64variant.decodeBase64Char(ch);
573             if (bits < 0) { // reached the end, fair and square?
574                 if (ch == INT_QUOTE) {
575                     break;
576                 }
577                 bits = _decodeBase64Escape(b64variant, ch, 0);
578                 if (bits < 0) { // white space to skip
579                     continue;
580                 }
581             }
582
583             // enough room? If not, flush
584             if (outputPtr > outputEnd) {
585                 outputCount += outputPtr;
586                 out.write(buffer, 0, outputPtr);
587                 outputPtr = 0;
588             }
589
590             int decodedData = bits;
591
592             // then second base64 char; can't get padding yet, nor ws
593
594             if (_inputPtr >= _inputEnd) {
595                 _loadMoreGuaranteed();
596             }
597             ch = _inputBuffer[_inputPtr++] & 0xFF;
598             bits = b64variant.decodeBase64Char(ch);
599             if (bits < 0) {
600                 bits = _decodeBase64Escape(b64variant, ch, 1);
601             }
602             decodedData = (decodedData << 6) | bits;
603
604             // third base64 char; can be padding, but not ws
605             if (_inputPtr >= _inputEnd) {
606                 _loadMoreGuaranteed();
607             }
608             ch = _inputBuffer[_inputPtr++] & 0xFF;
609             bits = b64variant.decodeBase64Char(ch);
610
611             // First branch: can get padding (-> 1 byte)
612             if (bits < 0) {
613                 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
614                     // as per [JACKSON-631], could also just be 'missing'  padding
615                     if (ch == INT_QUOTE) {
616                         decodedData >>= 4;
617                         buffer[outputPtr++] = (byte) decodedData;
618                         if (b64variant.usesPadding()) {
619                             --_inputPtr; // to keep parser state bit more consistent
620                             _handleBase64MissingPadding(b64variant);
621                         }
622                         break;
623                     }
624                     bits = _decodeBase64Escape(b64variant, ch, 2);
625                 }
626                 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
627                     // Ok, must get padding
628                     if (_inputPtr >= _inputEnd) {
629                         _loadMoreGuaranteed();
630                     }
631                     ch = _inputBuffer[_inputPtr++] & 0xFF;
632                     if (!b64variant.usesPaddingChar(ch)) {
633                         if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) {
634                             throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
635                         }
636                     }
637                     // Got 12 bits, only need 8, need to shift
638                     decodedData >>= 4;
639                     buffer[outputPtr++] = (byte) decodedData;
640                     continue;
641                 }
642             }
643             // Nope, 2 or 3 bytes
644             decodedData = (decodedData << 6) | bits;
645             // fourth and last base64 char; can be padding, but not ws
646             if (_inputPtr >= _inputEnd) {
647                 _loadMoreGuaranteed();
648             }
649             ch = _inputBuffer[_inputPtr++] & 0xFF;
650             bits = b64variant.decodeBase64Char(ch);
651             if (bits < 0) {
652                 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
653                     // as per [JACKSON-631], could also just be 'missing'  padding
654                     if (ch == INT_QUOTE) {
655                         decodedData >>= 2;
656                         buffer[outputPtr++] = (byte) (decodedData >> 8);
657                         buffer[outputPtr++] = (byte) decodedData;
658                         if (b64variant.usesPadding()) {
659                             --_inputPtr; // to keep parser state bit more consistent
660                             _handleBase64MissingPadding(b64variant);
661                         }
662                         break;
663                     }
664                     bits = _decodeBase64Escape(b64variant, ch, 3);
665                 }
666                 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
667                     /* With padding we only get 2 bytes; but we have
668                      * to shift it a bit so it is identical to triplet
669                      * case with partial output.
670                      * 3 chars gives 3x6 == 18 bits, of which 2 are
671                      * dummies, need to discard:
672                      */

673                     decodedData >>= 2;
674                     buffer[outputPtr++] = (byte) (decodedData >> 8);
675                     buffer[outputPtr++] = (byte) decodedData;
676                     continue;
677                 }
678             }
679             // otherwise, our triplet is now complete
680             decodedData = (decodedData << 6) | bits;
681             buffer[outputPtr++] = (byte) (decodedData >> 16);
682             buffer[outputPtr++] = (byte) (decodedData >> 8);
683             buffer[outputPtr++] = (byte) decodedData;
684         }
685         _tokenIncomplete = false;
686         if (outputPtr > 0) {
687             outputCount += outputPtr;
688             out.write(buffer, 0, outputPtr);
689         }
690         return outputCount;
691     }
692
693     /*
694     /**********************************************************
695     /* Public API, traversal, basic
696     /**********************************************************
697      */

698
699     /**
700      * @return Next token from the stream, if any found, or null
701      *   to indicate end-of-input
702      */

703     @Override
704     public JsonToken nextToken() throws IOException
705     {
706         /* First: field names are special -- we will always tokenize
707          * (part of) value along with field name to simplify
708          * state handling. If so, can and need to use secondary token:
709          */

710         if (_currToken == JsonToken.FIELD_NAME) {
711             return _nextAfterName();
712         }
713         // But if we didn't already have a name, and (partially?) decode number,
714         // need to ensure no numeric information is leaked
715         _numTypesValid = NR_UNKNOWN;
716         if (_tokenIncomplete) {
717             _skipString(); // only strings can be partial
718         }
719         int i = _skipWSOrEnd();
720         if (i < 0) { // end-of-input
721             // Close/release things like input source, symbol table and recyclable buffers
722             close();
723             return (_currToken = null);
724         }
725         // clear any data retained so far
726         _binaryValue = null;
727
728         // Closing scope?
729         if (i == INT_RBRACKET) {
730             _closeArrayScope();
731             return (_currToken = JsonToken.END_ARRAY);
732         }
733         if (i == INT_RCURLY) {
734             _closeObjectScope();
735             return (_currToken = JsonToken.END_OBJECT);
736         }
737
738         // Nope: do we then expect a comma?
739         if (_parsingContext.expectComma()) {
740             if (i != INT_COMMA) {
741                 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
742             }
743             i = _skipWS();
744             // Was that a trailing comma?
745             if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
746                 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
747                     return _closeScope(i);
748                 }
749             }
750         }
751
752         /* And should we now have a name? Always true for Object contexts
753          * since the intermediate 'expect-value' state is never retained.
754          */

755         if (!_parsingContext.inObject()) {
756             _updateLocation();
757             return _nextTokenNotInObject(i);
758         }
759         // So first parse the field name itself:
760         _updateNameLocation();
761         String n = _parseName(i);
762         _parsingContext.setCurrentName(n);
763         _currToken = JsonToken.FIELD_NAME;
764
765         i = _skipColon();
766         _updateLocation();
767
768         // Ok: we must have a value... what is it? Strings are very common, check first:
769         if (i == INT_QUOTE) {
770             _tokenIncomplete = true;
771             _nextToken = JsonToken.VALUE_STRING;
772             return _currToken;
773         }        
774         JsonToken t;
775
776         switch (i) {
777         case '-':
778             t = _parseNegNumber();
779             break;
780
781             // Should we have separate handling for plus? Although it is not allowed per se,
782             // it may be erroneously used, and could be indicate by a more specific error message.
783         case '.': // [core#611]:
784             t = _parseFloatThatStartsWithPeriod();
785             break;
786         case '0':
787         case '1':
788         case '2':
789         case '3':
790         case '4':
791         case '5':
792         case '6':
793         case '7':
794         case '8':
795         case '9':
796             t = _parsePosNumber(i);
797             break;
798         case 'f':
799             _matchFalse();
800              t = JsonToken.VALUE_FALSE;
801             break;
802         case 'n':
803             _matchNull();
804             t = JsonToken.VALUE_NULL;
805             break;
806         case 't':
807             _matchTrue();
808             t = JsonToken.VALUE_TRUE;
809             break;
810         case '[':
811             t = JsonToken.START_ARRAY;
812             break;
813         case '{':
814             t = JsonToken.START_OBJECT;
815             break;
816
817         default:
818             t = _handleUnexpectedValue(i);
819         }
820         _nextToken = t;
821         return _currToken;
822     }
823
824     private final JsonToken _nextTokenNotInObject(int i) throws IOException
825     {
826         if (i == INT_QUOTE) {
827             _tokenIncomplete = true;
828             return (_currToken = JsonToken.VALUE_STRING);
829         }
830         switch (i) {
831         case '[':
832             _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
833             return (_currToken = JsonToken.START_ARRAY);
834         case '{':
835             _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
836             return (_currToken = JsonToken.START_OBJECT);
837         case 't':
838             _matchTrue();
839             return (_currToken = JsonToken.VALUE_TRUE);
840         case 'f':
841             _matchFalse();
842             return (_currToken = JsonToken.VALUE_FALSE);
843         case 'n':
844             _matchNull();
845             return (_currToken = JsonToken.VALUE_NULL);
846         case '-':
847             return (_currToken = _parseNegNumber());
848
849             // Should we have separate handling for plus? Although it is not allowed per se,
850             // it may be erroneously used, and could be indicate by a more specific error message.
851         case '.': // [core#611]:
852             return (_currToken = _parseFloatThatStartsWithPeriod());
853         case '0':
854         case '1':
855         case '2':
856         case '3':
857         case '4':
858         case '5':
859         case '6':
860         case '7':
861         case '8':
862         case '9':
863             return (_currToken = _parsePosNumber(i));
864         }
865         return (_currToken = _handleUnexpectedValue(i));
866     }
867     
868     private final JsonToken _nextAfterName()
869     {
870         _nameCopied = false// need to invalidate if it was copied
871         JsonToken t = _nextToken;
872         _nextToken = null;
873
874  // !!! 16-Nov-2015, tatu: TODO: fix [databind#37], copy next location to current here
875         
876         // Also: may need to start new context?
877         if (t == JsonToken.START_ARRAY) {
878             _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
879         } else if (t == JsonToken.START_OBJECT) {
880             _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
881         }
882         return (_currToken = t);
883     }
884
885     @Override
886     public void finishToken() throws IOException {
887         if (_tokenIncomplete) {
888             _tokenIncomplete = false;
889             _finishString(); // only strings can be incomplete
890         }
891     }
892
893     /*
894     /**********************************************************
895     /* Public API, traversal, nextXxxValue/nextFieldName
896     /**********************************************************
897      */

898
899     @Override
900     public boolean nextFieldName(SerializableString str) throws IOException
901     {
902         // // // Note: most of code below is copied from nextToken()
903         _numTypesValid = NR_UNKNOWN;
904         if (_currToken == JsonToken.FIELD_NAME) { // can't have name right after name
905             _nextAfterName();
906             return false;
907         }
908         if (_tokenIncomplete) {
909             _skipString();
910         }
911         int i = _skipWSOrEnd();
912         if (i < 0) { // end-of-input
913             close();
914             _currToken = null;
915             return false;
916         }
917         _binaryValue = null;
918
919         // Closing scope?
920         if (i == INT_RBRACKET) {
921             _closeArrayScope();
922             _currToken = JsonToken.END_ARRAY;
923             return false;
924         }
925         if (i == INT_RCURLY) {
926             _closeObjectScope();
927             _currToken = JsonToken.END_OBJECT;
928             return false;
929         }
930
931         // Nope: do we then expect a comma?
932         if (_parsingContext.expectComma()) {
933             if (i != INT_COMMA) {
934                 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
935             }
936             i = _skipWS();
937
938             // Was that a trailing comma?
939             if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
940                 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
941                     _closeScope(i);
942                     return false;
943                 }
944             }
945         }
946         if (!_parsingContext.inObject()) {
947             _updateLocation();
948             _nextTokenNotInObject(i);
949             return false;
950         }
951         
952         // // // This part differs, name parsing
953         _updateNameLocation();
954         if (i == INT_QUOTE) {
955             // when doing literal match, must consider escaping:
956             byte[] nameBytes = str.asQuotedUTF8();
957             final int len = nameBytes.length;
958             // 22-May-2014, tatu: Actually, let's require 4 more bytes for faster skipping
959             //    of colon that follows name
960             if ((_inputPtr + len + 4) < _inputEnd) { // maybe...
961                 // first check length match by
962                 final int end = _inputPtr+len;
963                 if (_inputBuffer[end] == INT_QUOTE) {
964                     int offset = 0;
965                     int ptr = _inputPtr;
966                     while (true) {
967                         if (ptr == end) { // yes, match!
968                             _parsingContext.setCurrentName(str.getValue());
969                             i = _skipColonFast(ptr+1);
970                             _isNextTokenNameYes(i);
971                             return true;
972                         }
973                         if (nameBytes[offset] != _inputBuffer[ptr]) {
974                             break;
975                         }
976                         ++offset;
977                         ++ptr;
978                     }
979                 }
980             }
981         }
982         return _isNextTokenNameMaybe(i, str);
983     }
984
985     @Override
986     public String nextFieldName() throws IOException
987     {
988         // // // Note: this is almost a verbatim copy of nextToken()
989         _numTypesValid = NR_UNKNOWN;
990         if (_currToken == JsonToken.FIELD_NAME) {
991             _nextAfterName();
992             return null;
993         }
994         if (_tokenIncomplete) {
995             _skipString();
996         }
997         int i = _skipWSOrEnd();
998         if (i < 0) {
999             close();
1000             _currToken = null;
1001             return null;
1002         }
1003         _binaryValue = null;
1004
1005         if (i == INT_RBRACKET) {
1006             _closeArrayScope();
1007             _currToken = JsonToken.END_ARRAY;
1008             return null;
1009         }
1010         if (i == INT_RCURLY) {
1011             _closeObjectScope();
1012             _currToken = JsonToken.END_OBJECT;
1013             return null;
1014         }
1015
1016         // Nope: do we then expect a comma?
1017         if (_parsingContext.expectComma()) {
1018             if (i != INT_COMMA) {
1019                 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
1020             }
1021             i = _skipWS();
1022             // Was that a trailing comma?
1023             if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
1024                 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
1025                     _closeScope(i);
1026                     return null;
1027                 }
1028             }
1029         }
1030
1031         if (!_parsingContext.inObject()) {
1032             _updateLocation();
1033             _nextTokenNotInObject(i);
1034             return null;
1035         }
1036
1037         _updateNameLocation();
1038         final String nameStr = _parseName(i);
1039         _parsingContext.setCurrentName(nameStr);
1040         _currToken = JsonToken.FIELD_NAME;
1041
1042         i = _skipColon();
1043         _updateLocation();
1044         if (i == INT_QUOTE) {
1045             _tokenIncomplete = true;
1046             _nextToken = JsonToken.VALUE_STRING;
1047             return nameStr;
1048         }
1049         JsonToken t;
1050         switch (i) {
1051         case '-':
1052             t = _parseNegNumber();
1053             break;
1054         case '.': // [core#611]:
1055             t = _parseFloatThatStartsWithPeriod();
1056             break;
1057         case '0':
1058         case '1':
1059         case '2':
1060         case '3':
1061         case '4':
1062         case '5':
1063         case '6':
1064         case '7':
1065         case '8':
1066         case '9':
1067             t = _parsePosNumber(i);
1068             break;
1069         case 'f':
1070             _matchFalse();
1071              t = JsonToken.VALUE_FALSE;
1072             break;
1073         case 'n':
1074             _matchNull();
1075             t = JsonToken.VALUE_NULL;
1076             break;
1077         case 't':
1078             _matchTrue();
1079             t = JsonToken.VALUE_TRUE;
1080             break;
1081         case '[':
1082             t = JsonToken.START_ARRAY;
1083             break;
1084         case '{':
1085             t = JsonToken.START_OBJECT;
1086             break;
1087
1088         default:
1089             t = _handleUnexpectedValue(i);
1090         }
1091         _nextToken = t;
1092         return nameStr;
1093     }
1094
1095     // Variant called when we know there's at least 4 more bytes available
1096     private final int _skipColonFast(int ptr) throws IOException
1097     {
1098         int i = _inputBuffer[ptr++];
1099         if (i == INT_COLON) { // common case, no leading space
1100             i = _inputBuffer[ptr++];
1101             if (i > INT_SPACE) { // nor trailing
1102                 if (i != INT_SLASH && i != INT_HASH) {
1103                     _inputPtr = ptr;
1104                     return i;
1105                 }
1106             } else if (i == INT_SPACE || i == INT_TAB) {
1107                 i = (int) _inputBuffer[ptr++];
1108                 if (i > INT_SPACE) {
1109                     if (i != INT_SLASH && i != INT_HASH) {
1110                         _inputPtr = ptr;
1111                         return i;
1112                     }
1113                 }
1114             }
1115             _inputPtr = ptr-1;
1116             return _skipColon2(true); // true -> skipped colon
1117         }
1118         if (i == INT_SPACE || i == INT_TAB) {
1119             i = _inputBuffer[ptr++];
1120         }
1121         if (i == INT_COLON) {
1122             i = _inputBuffer[ptr++];
1123             if (i > INT_SPACE) {
1124                 if (i != INT_SLASH && i != INT_HASH) {
1125                     _inputPtr = ptr;
1126                     return i;
1127                 }
1128             } else if (i == INT_SPACE || i == INT_TAB) {
1129                 i = (int) _inputBuffer[ptr++];
1130                 if (i > INT_SPACE) {
1131                     if (i != INT_SLASH && i != INT_HASH) {
1132                         _inputPtr = ptr;
1133                         return i;
1134                     }
1135                 }
1136             }
1137             _inputPtr = ptr-1;
1138             return _skipColon2(true);
1139         }
1140         _inputPtr = ptr-1;
1141         return _skipColon2(false);
1142     }
1143
1144     private final void _isNextTokenNameYes(int i) throws IOException
1145     {
1146         _currToken = JsonToken.FIELD_NAME;
1147         _updateLocation();
1148
1149         switch (i) {
1150         case '"':
1151             _tokenIncomplete = true;
1152             _nextToken = JsonToken.VALUE_STRING;
1153             return;
1154         case '[':
1155             _nextToken = JsonToken.START_ARRAY;
1156             return;
1157         case '{':
1158             _nextToken = JsonToken.START_OBJECT;
1159             return;
1160         case 't':
1161             _matchTrue();
1162             _nextToken = JsonToken.VALUE_TRUE;
1163             return;
1164         case 'f':
1165             _matchFalse();
1166             _nextToken = JsonToken.VALUE_FALSE;
1167             return;
1168         case 'n':
1169             _matchNull();
1170             _nextToken = JsonToken.VALUE_NULL;
1171             return;
1172         case '-':
1173             _nextToken = _parseNegNumber();
1174             return;
1175         case '.': // [core#611]:
1176             _nextToken = _parseFloatThatStartsWithPeriod();
1177             return;
1178         case '0':
1179         case '1':
1180         case '2':
1181         case '3':
1182         case '4':
1183         case '5':
1184         case '6':
1185         case '7':
1186         case '8':
1187         case '9':
1188             _nextToken = _parsePosNumber(i);
1189             return;
1190         }
1191         _nextToken = _handleUnexpectedValue(i);
1192     }
1193
1194     private final boolean _isNextTokenNameMaybe(int i, SerializableString str) throws IOException
1195     {
1196         // // // and this is back to standard nextToken()
1197
1198         String n = _parseName(i);
1199         _parsingContext.setCurrentName(n);
1200         final boolean match = n.equals(str.getValue());
1201         _currToken = JsonToken.FIELD_NAME;
1202         i = _skipColon();
1203         _updateLocation();
1204
1205         // Ok: we must have a value... what is it? Strings are very common, check first:
1206         if (i == INT_QUOTE) {
1207             _tokenIncomplete = true;
1208             _nextToken = JsonToken.VALUE_STRING;
1209             return match;
1210         }
1211         JsonToken t;
1212
1213         switch (i) {
1214         case '[':
1215             t = JsonToken.START_ARRAY;
1216             break;
1217         case '{':
1218             t = JsonToken.START_OBJECT;
1219             break;
1220         case 't':
1221             _matchTrue();
1222             t = JsonToken.VALUE_TRUE;
1223             break;
1224         case 'f':
1225             _matchFalse();
1226              t = JsonToken.VALUE_FALSE;
1227             break;
1228         case 'n':
1229             _matchNull();
1230             t = JsonToken.VALUE_NULL;
1231             break;
1232         case '-':
1233             t = _parseNegNumber();
1234             break;
1235         case '.': // [core#611]:
1236             t = _parseFloatThatStartsWithPeriod();
1237             break;
1238         case '0':
1239         case '1':
1240         case '2':
1241         case '3':
1242         case '4':
1243         case '5':
1244         case '6':
1245         case '7':
1246         case '8':
1247         case '9':
1248             t = _parsePosNumber(i);
1249             break;
1250         default:
1251             t = _handleUnexpectedValue(i);
1252         }
1253         _nextToken = t;
1254         return match;
1255     }
1256
1257     @Override
1258     public String nextTextValue() throws IOException
1259     {
1260         // two distinct cases; either got name and we know next type, or 'other'
1261         if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
1262             _nameCopied = false;
1263             JsonToken t = _nextToken;
1264             _nextToken = null;
1265             _currToken = t;
1266             if (t == JsonToken.VALUE_STRING) {
1267                 if (_tokenIncomplete) {
1268                     _tokenIncomplete = false;
1269                     return _finishAndReturnString();
1270                 }
1271                 return _textBuffer.contentsAsString();
1272             }
1273             if (t == JsonToken.START_ARRAY) {
1274                 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1275             } else if (t == JsonToken.START_OBJECT) {
1276                 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1277             }
1278             return null;
1279         }
1280         // !!! TODO: optimize this case as well
1281         return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
1282     }
1283
1284     @Override
1285     public int nextIntValue(int defaultValue) throws IOException
1286     {
1287         // two distinct cases; either got name and we know next type, or 'other'
1288         if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
1289             _nameCopied = false;
1290             JsonToken t = _nextToken;
1291             _nextToken = null;
1292             _currToken = t;
1293             if (t == JsonToken.VALUE_NUMBER_INT) {
1294                 return getIntValue();
1295             }
1296             if (t == JsonToken.START_ARRAY) {
1297                 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1298             } else if (t == JsonToken.START_OBJECT) {
1299                 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1300             }
1301             return defaultValue;
1302         }
1303         // !!! TODO: optimize this case as well
1304         return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
1305     }
1306
1307     @Override
1308     public long nextLongValue(long defaultValue) throws IOException
1309     {
1310         // two distinct cases; either got name and we know next type, or 'other'
1311         if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
1312             _nameCopied = false;
1313             JsonToken t = _nextToken;
1314             _nextToken = null;
1315             _currToken = t;
1316             if (t == JsonToken.VALUE_NUMBER_INT) {
1317                 return getLongValue();
1318             }
1319             if (t == JsonToken.START_ARRAY) {
1320                 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1321             } else if (t == JsonToken.START_OBJECT) {
1322                 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1323             }
1324             return defaultValue;
1325         }
1326         // !!! TODO: optimize this case as well
1327         return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
1328     }
1329
1330     @Override
1331     public Boolean nextBooleanValue() throws IOException
1332     {
1333         // two distinct cases; either got name and we know next type, or 'other'
1334         if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
1335             _nameCopied = false;
1336             JsonToken t = _nextToken;
1337             _nextToken = null;
1338             _currToken = t;
1339             if (t == JsonToken.VALUE_TRUE) {
1340                 return Boolean.TRUE;
1341             }
1342             if (t == JsonToken.VALUE_FALSE) {
1343                 return Boolean.FALSE;
1344             }
1345             if (t == JsonToken.START_ARRAY) {
1346                 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1347             } else if (t == JsonToken.START_OBJECT) {
1348                 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1349             }
1350             return null;
1351         }
1352
1353         JsonToken t = nextToken();
1354         if (t == JsonToken.VALUE_TRUE) {
1355             return Boolean.TRUE;
1356         }
1357         if (t == JsonToken.VALUE_FALSE) {
1358             return Boolean.FALSE;
1359         }
1360         return null;
1361     }
1362
1363     /*
1364     /**********************************************************
1365     /* Internal methods, number parsing
1366     /**********************************************************
1367      */

1368
1369     // @since 2.11, [core#611]
1370     protected final JsonToken _parseFloatThatStartsWithPeriod() throws IOException
1371     {
1372         // [core#611]: allow optionally leading decimal point
1373         if (!isEnabled(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1374             return _handleUnexpectedValue(INT_PERIOD);
1375         }
1376         return _parseFloat(_textBuffer.emptyAndGetCurrentSegment(),
1377                 0, INT_PERIOD, false, 0);
1378     }
1379
1380     /**
1381      * Initial parsing method for number values. It needs to be able
1382      * to parse enough input to be able to determine whether the
1383      * value is to be considered a simple integer value, or a more
1384      * generic decimal value: latter of which needs to be expressed
1385      * as a floating point number. The basic rule is that if the number
1386      * has no fractional or exponential part, it is an integer; otherwise
1387      * a floating point number.
1388      *<p>
1389      * Because much of input has to be processed in any case, no partial
1390      * parsing is done: all input text will be stored for further
1391      * processing. However, actual numeric value conversion will be
1392      * deferred, since it is usually the most complicated and costliest
1393      * part of processing.
1394      */

1395     protected JsonToken _parsePosNumber(int c) throws IOException
1396     {
1397         char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
1398         // One special caseif first char is 0, must not be followed by a digit
1399         if (c == INT_0) {
1400             c = _verifyNoLeadingZeroes();
1401         }
1402         // Ok: we can first just add digit we saw first:
1403         outBuf[0] = (char) c;
1404         int intLen = 1;
1405         int outPtr = 1;
1406         // And then figure out how far we can read without further checks
1407         // for either input or output
1408         final int end = Math.min(_inputEnd, _inputPtr + outBuf.length - 1); // 1 == outPtr
1409         // With this, we have a nice and tight loop:
1410         while (true) {
1411             if (_inputPtr >= end) { // split across boundary, offline
1412                 return _parseNumber2(outBuf, outPtr, false, intLen);
1413             }
1414             c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1415             if (c < INT_0 || c > INT_9) {
1416                 break;
1417             }
1418             ++intLen;
1419             outBuf[outPtr++] = (char) c;
1420         }
1421         if (c == INT_PERIOD || c == INT_e || c == INT_E) {
1422             return _parseFloat(outBuf, outPtr, c, false, intLen);
1423         }
1424         --_inputPtr; // to push back trailing char (comma etc)
1425         _textBuffer.setCurrentLength(outPtr);
1426         // As per #105, need separating space between root values; check here
1427         if (_parsingContext.inRoot()) {
1428             _verifyRootSpace(c);
1429         }
1430         // And there we have it!
1431         return resetInt(false, intLen);
1432     }
1433     
1434     protected JsonToken _parseNegNumber() throws IOException
1435     {
1436         char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
1437         int outPtr = 0;
1438
1439         // Need to prepend sign?
1440         outBuf[outPtr++] = '-';
1441         // Must have something after sign too
1442         if (_inputPtr >= _inputEnd) {
1443             _loadMoreGuaranteed();
1444         }
1445         int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1446         // Note: must be followed by a digit
1447         if (c <= INT_0) {
1448             // One special caseif first char is 0, must not be followed by a digit
1449             if (c != INT_0) {
1450                 return _handleInvalidNumberStart(c, true);
1451             }
1452             c = _verifyNoLeadingZeroes();
1453         } else if (c > INT_9) {
1454             return _handleInvalidNumberStart(c, true);
1455         }
1456         
1457         // Ok: we can first just add digit we saw first:
1458         outBuf[outPtr++] = (char) c;
1459         int intLen = 1;
1460
1461         // And then figure out how far we can read without further checks
1462         // for either input or output
1463         final int end = Math.min(_inputEnd, _inputPtr + outBuf.length - outPtr);
1464         // With this, we have a nice and tight loop:
1465         while (true) {
1466             if (_inputPtr >= end) {
1467                 // Long enough to be split across boundary, so:
1468                 return _parseNumber2(outBuf, outPtr, true, intLen);
1469             }
1470             c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1471             if (c < INT_0 || c > INT_9) {
1472                 break;
1473             }
1474             ++intLen;
1475             outBuf[outPtr++] = (char) c;
1476         }
1477         if (c == INT_PERIOD || c == INT_e || c == INT_E) {
1478             return _parseFloat(outBuf, outPtr, c, true, intLen);
1479         }
1480         
1481         --_inputPtr; // to push back trailing char (comma etc)
1482         _textBuffer.setCurrentLength(outPtr);
1483         // As per #105, need separating space between root values; check here
1484         if (_parsingContext.inRoot()) {
1485             _verifyRootSpace(c);
1486         }
1487
1488         // And there we have it!
1489         return resetInt(true, intLen);
1490     }
1491
1492     /**
1493      * Method called to handle parsing when input is split across buffer boundary
1494      * (or output is longer than segment used to store it)
1495      */

1496     private final JsonToken _parseNumber2(char[] outBuf, int outPtr, boolean negative,
1497             int intPartLength) throws IOException
1498     {
1499         // Ok, parse the rest
1500         while (true) {
1501             if (_inputPtr >= _inputEnd && !_loadMore()) {
1502                 _textBuffer.setCurrentLength(outPtr);
1503                 return resetInt(negative, intPartLength);
1504             }
1505             int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1506             if (c > INT_9 || c < INT_0) {
1507                 if (c == INT_PERIOD || c == INT_e || c == INT_E) {
1508                     return _parseFloat(outBuf, outPtr, c, negative, intPartLength);
1509                 }
1510                 break;
1511             }
1512             if (outPtr >= outBuf.length) {
1513                 outBuf = _textBuffer.finishCurrentSegment();
1514                 outPtr = 0;
1515             }
1516             outBuf[outPtr++] = (char) c;
1517             ++intPartLength;
1518         }
1519         --_inputPtr; // to push back trailing char (comma etc)
1520         _textBuffer.setCurrentLength(outPtr);
1521         // As per #105, need separating space between root values; check here
1522         if (_parsingContext.inRoot()) {
1523             _verifyRootSpace(_inputBuffer[_inputPtr] & 0xFF);
1524         }
1525
1526         // And there we have it!
1527         return resetInt(negative, intPartLength);
1528         
1529     }
1530     
1531     /**
1532      * Method called when we have seen one zero, and want to ensure
1533      * it is not followed by another
1534      */

1535     private final int _verifyNoLeadingZeroes() throws IOException
1536     {
1537         // Ok to have plain "0"
1538         if (_inputPtr >= _inputEnd && !_loadMore()) {
1539             return INT_0;
1540         }
1541         int ch = _inputBuffer[_inputPtr] & 0xFF;
1542         // if not followed by a number (probably '.'); return zero as is, to be included
1543         if (ch < INT_0 || ch > INT_9) {
1544             return INT_0;
1545         }
1546         // [JACKSON-358]: we may want to allow them, after all...
1547         if ((_features & FEAT_MASK_LEADING_ZEROS) == 0) {
1548             reportInvalidNumber("Leading zeroes not allowed");
1549         }
1550         // if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number)
1551         ++_inputPtr; // Leading zero to be skipped
1552         if (ch == INT_0) {
1553             while (_inputPtr < _inputEnd || _loadMore()) {
1554                 ch = _inputBuffer[_inputPtr] & 0xFF;
1555                 if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
1556                     return INT_0;
1557                 }
1558                 ++_inputPtr; // skip previous zeroes
1559                 if (ch != INT_0) { // followed by other number; return 
1560                     break;
1561                 }
1562             }
1563         }
1564         return ch;
1565     }
1566
1567     private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
1568             boolean negative, int integerPartLength) throws IOException
1569     {
1570         int fractLen = 0;
1571         boolean eof = false;
1572
1573         // And then see if we get other parts
1574         if (c == INT_PERIOD) { // yes, fraction
1575             if (outPtr >= outBuf.length) {
1576                 outBuf = _textBuffer.finishCurrentSegment();
1577                 outPtr = 0;
1578             }
1579             outBuf[outPtr++] = (char) c;
1580
1581             fract_loop:
1582             while (true) {
1583                 if (_inputPtr >= _inputEnd && !_loadMore()) {
1584                     eof = true;
1585                     break fract_loop;
1586                 }
1587                 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1588                 if (c < INT_0 || c > INT_9) {
1589                     break fract_loop;
1590                 }
1591                 ++fractLen;
1592                 if (outPtr >= outBuf.length) {
1593                     outBuf = _textBuffer.finishCurrentSegment();
1594                     outPtr = 0;
1595                 }
1596                 outBuf[outPtr++] = (char) c;
1597             }
1598             // must be followed by sequence of ints, one minimum
1599             if (fractLen == 0) {
1600                 reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1601             }
1602         }
1603
1604         int expLen = 0;
1605         if (c == INT_e || c == INT_E) { // exponent?
1606             if (outPtr >= outBuf.length) {
1607                 outBuf = _textBuffer.finishCurrentSegment();
1608                 outPtr = 0;
1609             }
1610             outBuf[outPtr++] = (char) c;
1611             // Not optional, can require that we get one more char
1612             if (_inputPtr >= _inputEnd) {
1613                 _loadMoreGuaranteed();
1614             }
1615             c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1616             // Sign indicator?
1617             if (c == '-' || c == '+') {
1618                 if (outPtr >= outBuf.length) {
1619                     outBuf = _textBuffer.finishCurrentSegment();
1620                     outPtr = 0;
1621                 }
1622                 outBuf[outPtr++] = (char) c;
1623                 // Likewise, non optional:
1624                 if (_inputPtr >= _inputEnd) {
1625                     _loadMoreGuaranteed();
1626                 }
1627                 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1628             }
1629
1630             exp_loop:
1631             while (c >= INT_0 && c <= INT_9) {
1632                 ++expLen;
1633                 if (outPtr >= outBuf.length) {
1634                     outBuf = _textBuffer.finishCurrentSegment();
1635                     outPtr = 0;
1636                 }
1637                 outBuf[outPtr++] = (char) c;
1638                 if (_inputPtr >= _inputEnd && !_loadMore()) {
1639                     eof = true;
1640                     break exp_loop;
1641                 }
1642                 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1643             }
1644             // must be followed by sequence of ints, one minimum
1645             if (expLen == 0) {
1646                 reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit");
1647             }
1648         }
1649
1650         // Ok; unless we hit end-of-input, need to push last char read back
1651         if (!eof) {
1652             --_inputPtr;
1653             // As per [core#105], need separating space between root values; check here
1654             if (_parsingContext.inRoot()) {
1655                 _verifyRootSpace(c);
1656             }
1657         }
1658         _textBuffer.setCurrentLength(outPtr);
1659
1660         // And there we have it!
1661         return resetFloat(negative, integerPartLength, fractLen, expLen);
1662     }
1663
1664     /**
1665      * Method called to ensure that a root-value is followed by a space
1666      * token.
1667      *<p>
1668      * NOTE: caller MUST ensure there is at least one character available;
1669      * and that input pointer is AT given char (not past)
1670      */

1671     private final void _verifyRootSpace(int ch) throws IOException
1672     {
1673         // caller had pushed it back, before calling; reset
1674         ++_inputPtr;
1675         // TODO? Handle UTF-8 char decoding for error reporting
1676         switch (ch) {
1677         case ' ':
1678         case '\t':
1679             return;
1680         case '\r':
1681             _skipCR();
1682             return;
1683         case '\n':
1684             ++_currInputRow;
1685             _currInputRowStart = _inputPtr;
1686             return;
1687         }
1688         _reportMissingRootWS(ch);
1689     }
1690
1691     /*
1692     /**********************************************************
1693     /* Internal methods, secondary parsing
1694     /**********************************************************
1695      */

1696     
1697     protected final String _parseName(int i) throws IOException
1698     {
1699         if (i != INT_QUOTE) {
1700             return _handleOddName(i);
1701         }
1702         // First: can we optimize out bounds checks?
1703         if ((_inputPtr + 13) > _inputEnd) { // Need up to 12 chars, plus one trailing (quote)
1704             return slowParseName();
1705         }
1706
1707         // If so, can also unroll loops nicely
1708         /* 25-Nov-2008, tatu: This may seem weird, but here we do
1709          *   NOT want to worry about UTF-8 decoding. Rather, we'll
1710          *   assume that part is ok (if not it will get caught
1711          *   later on), and just handle quotes and backslashes here.
1712          */

1713         final byte[] input = _inputBuffer;
1714         final int[] codes = _icLatin1;
1715
1716         int q = input[_inputPtr++] & 0xFF;
1717
1718         if (codes[q] == 0) {
1719             i = input[_inputPtr++] & 0xFF;
1720             if (codes[i] == 0) {
1721                 q = (q << 8) | i;
1722                 i = input[_inputPtr++] & 0xFF;
1723                 if (codes[i] == 0) {
1724                     q = (q << 8) | i;
1725                     i = input[_inputPtr++] & 0xFF;
1726                     if (codes[i] == 0) {
1727                         q = (q << 8) | i;
1728                         i = input[_inputPtr++] & 0xFF;
1729                         if (codes[i] == 0) {
1730                             _quad1 = q;
1731                             return parseMediumName(i);
1732                         }
1733                         if (i == INT_QUOTE) { // 4 byte/char case or broken
1734                             return findName(q, 4);
1735                         }
1736                         return parseName(q, i, 4);
1737                     }
1738                     if (i == INT_QUOTE) { // 3 byte/char case or broken
1739                         return findName(q, 3);
1740                     }
1741                     return parseName(q, i, 3);
1742                 }                
1743                 if (i == INT_QUOTE) { // 2 byte/char case or broken
1744                     return findName(q, 2);
1745                 }
1746                 return parseName(q, i, 2);
1747             }
1748             if (i == INT_QUOTE) { // one byte/char case or broken
1749                 return findName(q, 1);
1750             }
1751             return parseName(q, i, 1);
1752         }     
1753         if (q == INT_QUOTE) { // special case""
1754             return "";
1755         }
1756         return parseName(0, q, 0); // quoting or invalid char
1757     }
1758
1759     protected final String parseMediumName(int q2) throws IOException
1760     {
1761         final byte[] input = _inputBuffer;
1762         final int[] codes = _icLatin1;
1763
1764         // Ok, got 5 name bytes so far
1765         int i = input[_inputPtr++] & 0xFF;
1766         if (codes[i] != 0) {
1767             if (i == INT_QUOTE) { // 5 bytes
1768                 return findName(_quad1, q2, 1);
1769             }
1770             return parseName(_quad1, q2, i, 1); // quoting or invalid char
1771         }
1772         q2 = (q2 << 8) | i;
1773         i = input[_inputPtr++] & 0xFF;
1774         if (codes[i] != 0) {
1775             if (i == INT_QUOTE) { // 6 bytes
1776                 return findName(_quad1, q2, 2);
1777             }
1778             return parseName(_quad1, q2, i, 2);
1779         }
1780         q2 = (q2 << 8) | i;
1781         i = input[_inputPtr++] & 0xFF;
1782         if (codes[i] != 0) {
1783             if (i == INT_QUOTE) { // 7 bytes
1784                 return findName(_quad1, q2, 3);
1785             }
1786             return parseName(_quad1, q2, i, 3);
1787         }
1788         q2 = (q2 << 8) | i;
1789         i = input[_inputPtr++] & 0xFF;
1790         if (codes[i] != 0) {
1791             if (i == INT_QUOTE) { // 8 bytes
1792                 return findName(_quad1, q2, 4);
1793             }
1794             return parseName(_quad1, q2, i, 4);
1795         }
1796         return parseMediumName2(i, q2);
1797     }
1798
1799     /**
1800      * @since 2.6
1801      */

1802     protected final String parseMediumName2(int q3, final int q2) throws IOException
1803     {
1804         final byte[] input = _inputBuffer;
1805         final int[] codes = _icLatin1;
1806
1807         // Got 9 name bytes so far
1808         int i = input[_inputPtr++] & 0xFF;
1809         if (codes[i] != 0) {
1810             if (i == INT_QUOTE) { // 9 bytes
1811                 return findName(_quad1, q2, q3, 1);
1812             }
1813             return parseName(_quad1, q2, q3, i, 1);
1814         }
1815         q3 = (q3 << 8) | i;
1816         i = input[_inputPtr++] & 0xFF;
1817         if (codes[i] != 0) {
1818             if (i == INT_QUOTE) { // 10 bytes
1819                 return findName(_quad1, q2, q3, 2);
1820             }
1821             return parseName(_quad1, q2, q3, i, 2);
1822         }
1823         q3 = (q3 << 8) | i;
1824         i = input[_inputPtr++] & 0xFF;
1825         if (codes[i] != 0) {
1826             if (i == INT_QUOTE) { // 11 bytes
1827                 return findName(_quad1, q2, q3, 3);
1828             }
1829             return parseName(_quad1, q2, q3, i, 3);
1830         }
1831         q3 = (q3 << 8) | i;
1832         i = input[_inputPtr++] & 0xFF;
1833         if (codes[i] != 0) {
1834             if (i == INT_QUOTE) { // 12 bytes
1835                 return findName(_quad1, q2, q3, 4);
1836             }
1837             return parseName(_quad1, q2, q3, i, 4);
1838         }
1839         return parseLongName(i, q2, q3);
1840     }
1841     
1842     protected final String parseLongName(int q, final int q2, int q3) throws IOException
1843     {
1844         _quadBuffer[0] = _quad1;
1845         _quadBuffer[1] = q2;
1846         _quadBuffer[2] = q3;
1847
1848         // As explained above, will ignore UTF-8 encoding at this point
1849         final byte[] input = _inputBuffer;
1850         final int[] codes = _icLatin1;
1851         int qlen = 3;
1852
1853         while ((_inputPtr + 4) <= _inputEnd) {
1854             int i = input[_inputPtr++] & 0xFF;
1855             if (codes[i] != 0) {
1856                 if (i == INT_QUOTE) {
1857                     return findName(_quadBuffer, qlen, q, 1);
1858                 }
1859                 return parseEscapedName(_quadBuffer, qlen, q, i, 1);
1860             }
1861
1862             q = (q << 8) | i;
1863             i = input[_inputPtr++] & 0xFF;
1864             if (codes[i] != 0) {
1865                 if (i == INT_QUOTE) {
1866                     return findName(_quadBuffer, qlen, q, 2);
1867                 }
1868                 return parseEscapedName(_quadBuffer, qlen, q, i, 2);
1869             }
1870
1871             q = (q << 8) | i;
1872             i = input[_inputPtr++] & 0xFF;
1873             if (codes[i] != 0) {
1874                 if (i == INT_QUOTE) {
1875                     return findName(_quadBuffer, qlen, q, 3);
1876                 }
1877                 return parseEscapedName(_quadBuffer, qlen, q, i, 3);
1878             }
1879
1880             q = (q << 8) | i;
1881             i = input[_inputPtr++] & 0xFF;
1882             if (codes[i] != 0) {
1883                 if (i == INT_QUOTE) {
1884                     return findName(_quadBuffer, qlen, q, 4);
1885                 }
1886                 return parseEscapedName(_quadBuffer, qlen, q, i, 4);
1887             }
1888
1889             // Nope, no end in sight. Need to grow quad array etc
1890             if (qlen >= _quadBuffer.length) {
1891                 _quadBuffer = growArrayBy(_quadBuffer, qlen);
1892             }
1893             _quadBuffer[qlen++] = q;
1894             q = i;
1895         }
1896
1897         /* Let's offline if we hit buffer boundary (otherwise would
1898          * need to [try to] align input, which is bit complicated
1899          * and may not always be possible)
1900          */

1901         return parseEscapedName(_quadBuffer, qlen, 0, q, 0);
1902     }
1903
1904     /**
1905      * Method called when not even first 8 bytes are guaranteed
1906      * to come consecutively. Happens rarely, so this is offlined;
1907      * plus we'll also do full checks for escaping etc.
1908      */

1909     protected String slowParseName() throws IOException
1910     {
1911         if (_inputPtr >= _inputEnd) {
1912             if (!_loadMore()) {
1913                 _reportInvalidEOF(": was expecting closing '\"for name", JsonToken.FIELD_NAME);
1914             }
1915         }
1916         int i = _inputBuffer[_inputPtr++] & 0xFF;
1917         if (i == INT_QUOTE) { // special case""
1918             return "";
1919         }
1920         return parseEscapedName(_quadBuffer, 0, 0, i, 0);
1921     }
1922
1923     private final String parseName(int q1, int ch, int lastQuadBytes) throws IOException {
1924         return parseEscapedName(_quadBuffer, 0, q1, ch, lastQuadBytes);
1925     }
1926
1927     private final String parseName(int q1, int q2, int ch, int lastQuadBytes) throws IOException {
1928         _quadBuffer[0] = q1;
1929         return parseEscapedName(_quadBuffer, 1, q2, ch, lastQuadBytes);
1930     }
1931
1932     private final String parseName(int q1, int q2, int q3, int ch, int lastQuadBytes) throws IOException {
1933         _quadBuffer[0] = q1;
1934         _quadBuffer[1] = q2;
1935         return parseEscapedName(_quadBuffer, 2, q3, ch, lastQuadBytes);
1936     }
1937
1938     /**
1939      * Slower parsing method which is generally branched to when an escape
1940      * sequence is detected (or alternatively for long names, one crossing
1941      * input buffer boundary). Needs to be able to handle more exceptional
1942      * cases, gets slower, and hence is offlined to a separate method.
1943      */

1944     protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int ch,
1945             int currQuadBytes) throws IOException
1946     {
1947         // This may seem weird, but here we do not want to worry about
1948         // UTF-8 decoding yet. Rather, we'll assume that part is ok (if not it will get
1949         // caught later on), and just handle quotes and backslashes here.
1950         final int[] codes = _icLatin1;
1951
1952         while (true) {
1953             if (codes[ch] != 0) {
1954                 if (ch == INT_QUOTE) { // we are done
1955                     break;
1956                 }
1957                 // Unquoted white space?
1958                 if (ch != INT_BACKSLASH) {
1959                     // As per [JACKSON-208], call can now return:
1960                     _throwUnquotedSpace(ch, "name");
1961                 } else {
1962                     // Nope, escape sequence
1963                     ch = _decodeEscaped();
1964                 }
1965                 // Oh crap. May need to UTF-8 (re-)encode it, if it's beyond
1966                 // 7-bit ASCII. Gets pretty messy. If this happens often, may
1967                 // want to use different name canonicalization to avoid these hits.
1968                 if (ch > 127) {
1969                     // Ok, we'll need room for first byte right away
1970                     if (currQuadBytes >= 4) {
1971                         if (qlen >= quads.length) {
1972                             _quadBuffer = quads = growArrayBy(quads, quads.length);
1973                         }
1974                         quads[qlen++] = currQuad;
1975                         currQuad = 0;
1976                         currQuadBytes = 0;
1977                     }
1978                     if (ch < 0x800) { // 2-byte
1979                         currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
1980                         ++currQuadBytes;
1981                         // Second byte gets output below:
1982                     } else { // 3 bytes; no need to worry about surrogates here
1983                         currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
1984                         ++currQuadBytes;
1985                         // need room for middle byte?
1986                         if (currQuadBytes >= 4) {
1987                             if (qlen >= quads.length) {
1988                                 _quadBuffer = quads = growArrayBy(quads, quads.length);
1989                             }
1990                             quads[qlen++] = currQuad;
1991                             currQuad = 0;
1992                             currQuadBytes = 0;
1993                         }
1994                         currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
1995                         ++currQuadBytes;
1996                     }
1997                     // And same last byte in both cases, gets output below:
1998                     ch = 0x80 | (ch & 0x3f);
1999                 }
2000             }
2001             // Ok, we have one more byte to add at any rate:
2002             if (currQuadBytes < 4) {
2003                 ++currQuadBytes;
2004                 currQuad = (currQuad << 8) | ch;
2005             } else {
2006                 if (qlen >= quads.length) {
2007                     _quadBuffer = quads = growArrayBy(quads, quads.length);
2008                 }
2009                 quads[qlen++] = currQuad;
2010                 currQuad = ch;
2011                 currQuadBytes = 1;
2012             }
2013             if (_inputPtr >= _inputEnd) {
2014                 if (!_loadMore()) {
2015                     _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
2016                 }
2017             }
2018             ch = _inputBuffer[_inputPtr++] & 0xFF;
2019         }
2020
2021         if (currQuadBytes > 0) {
2022             if (qlen >= quads.length) {
2023                 _quadBuffer = quads = growArrayBy(quads, quads.length);
2024             }
2025             quads[qlen++] = _padLastQuad(currQuad, currQuadBytes);
2026         }
2027         String name = _symbols.findName(quads, qlen);
2028         if (name == null) {
2029             name = addName(quads, qlen, currQuadBytes);
2030         }
2031         return name;
2032     }
2033
2034     /**
2035      * Method called when we see non-white space character other
2036      * than double quote, when expecting a field name.
2037      * In standard mode will just throw an exception; but
2038      * in non-standard modes may be able to parse name.
2039      */

2040     protected String _handleOddName(int ch) throws IOException
2041     {
2042         // First: may allow single quotes
2043         if (ch == INT_APOS && (_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) {
2044             return _parseAposName();
2045         }
2046         // Allow unquoted names if feature enabled:
2047         if ((_features & FEAT_MASK_ALLOW_UNQUOTED_NAMES) == 0) {
2048             char c = (char) _decodeCharForError(ch);
2049             _reportUnexpectedChar(c, "was expecting double-quote to start field name");
2050         }
2051         /* Also: note that although we use a different table here,
2052          * it does NOT handle UTF-8 decoding. It'll just pass those
2053          * high-bit codes as acceptable for later decoding.
2054          */

2055         final int[] codes = CharTypes.getInputCodeUtf8JsNames();
2056         // Also: must start with a valid character...
2057         if (codes[ch] != 0) {
2058             _reportUnexpectedChar(ch, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name");
2059         }
2060
2061         // Ok, now; instead of ultra-optimizing parsing here (as with regular
2062         // JSON names), let's just use the generic "slow" variant.
2063         // Can measure its impact later on if need be.
2064         int[] quads = _quadBuffer;
2065         int qlen = 0;
2066         int currQuad = 0;
2067         int currQuadBytes = 0;
2068
2069         while (true) {
2070             // Ok, we have one more byte to add at any rate:
2071             if (currQuadBytes < 4) {
2072                 ++currQuadBytes;
2073                 currQuad = (currQuad << 8) | ch;
2074             } else {
2075                 if (qlen >= quads.length) {
2076                     _quadBuffer = quads = growArrayBy(quads, quads.length);
2077                 }
2078                 quads[qlen++] = currQuad;
2079                 currQuad = ch;
2080                 currQuadBytes = 1;
2081             }
2082             if (_inputPtr >= _inputEnd) {
2083                 if (!_loadMore()) {
2084                     _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
2085                 }
2086             }
2087             ch = _inputBuffer[_inputPtr] & 0xFF;
2088             if (codes[ch] != 0) {
2089                 break;
2090             }
2091             ++_inputPtr;
2092         }
2093
2094         if (currQuadBytes > 0) {
2095             if (qlen >= quads.length) {
2096                 _quadBuffer = quads = growArrayBy(quads, quads.length);
2097             }
2098             quads[qlen++] = currQuad;
2099         }
2100         String name = _symbols.findName(quads, qlen);
2101         if (name == null) {
2102             name = addName(quads, qlen, currQuadBytes);
2103         }
2104         return name;
2105     }
2106
2107     /* Parsing to support [JACKSON-173]. Plenty of duplicated code;
2108      * main reason being to try to avoid slowing down fast path
2109      * for valid JSON -- more alternatives, more code, generally
2110      * bit slower execution.
2111      */

2112     protected String _parseAposName() throws IOException
2113     {
2114         if (_inputPtr >= _inputEnd) {
2115             if (!_loadMore()) {
2116                 _reportInvalidEOF(": was expecting closing '\'' for field name", JsonToken.FIELD_NAME);
2117             }
2118         }
2119         int ch = _inputBuffer[_inputPtr++] & 0xFF;
2120         if (ch == INT_APOS) { // special case, ''
2121             return "";
2122         }
2123         int[] quads = _quadBuffer;
2124         int qlen = 0;
2125         int currQuad = 0;
2126         int currQuadBytes = 0;
2127
2128         // Copied from parseEscapedFieldName, with minor mods:
2129
2130         final int[] codes = _icLatin1;
2131
2132         while (true) {
2133             if (ch == INT_APOS) {
2134                 break;
2135             }
2136             // additional check to skip handling of double-quotes
2137             if ((codes[ch] != 0) && (ch != '"')) {
2138                 if (ch != '\\') {
2139                     // Unquoted white space?
2140                     // As per [JACKSON-208], call can now return:
2141                     _throwUnquotedSpace(ch, "name");
2142                 } else {
2143                     // Nope, escape sequence
2144                     ch = _decodeEscaped();
2145                 }
2146                 // as per main code, inefficient but will have to do
2147                 if (ch > 127) {
2148                     // Ok, we'll need room for first byte right away
2149                     if (currQuadBytes >= 4) {
2150                         if (qlen >= quads.length) {
2151                             _quadBuffer = quads = growArrayBy(quads, quads.length);
2152                         }
2153                         quads[qlen++] = currQuad;
2154                         currQuad = 0;
2155                         currQuadBytes = 0;
2156                     }
2157                     if (ch < 0x800) { // 2-byte
2158                         currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
2159                         ++currQuadBytes;
2160                         // Second byte gets output below:
2161                     } else { // 3 bytes; no need to worry about surrogates here
2162                         currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
2163                         ++currQuadBytes;
2164                         // need room for middle byte?
2165                         if (currQuadBytes >= 4) {
2166                             if (qlen >= quads.length) {
2167                                 _quadBuffer = quads = growArrayBy(quads, quads.length);
2168                             }
2169                             quads[qlen++] = currQuad;
2170                             currQuad = 0;
2171                             currQuadBytes = 0;
2172                         }
2173                         currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
2174                         ++currQuadBytes;
2175                     }
2176                     // And same last byte in both cases, gets output below:
2177                     ch = 0x80 | (ch & 0x3f);
2178                 }
2179             }
2180             // Ok, we have one more byte to add at any rate:
2181             if (currQuadBytes < 4) {
2182                 ++currQuadBytes;
2183                 currQuad = (currQuad << 8) | ch;
2184             } else {
2185                 if (qlen >= quads.length) {
2186                     _quadBuffer = quads = growArrayBy(quads, quads.length);
2187                 }
2188                 quads[qlen++] = currQuad;
2189                 currQuad = ch;
2190                 currQuadBytes = 1;
2191             }
2192             if (_inputPtr >= _inputEnd) {
2193                 if (!_loadMore()) {
2194                     _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
2195                 }
2196             }
2197             ch = _inputBuffer[_inputPtr++] & 0xFF;
2198         }
2199
2200         if (currQuadBytes > 0) {
2201             if (qlen >= quads.length) {
2202                 _quadBuffer = quads = growArrayBy(quads, quads.length);
2203             }
2204             quads[qlen++] = _padLastQuad(currQuad, currQuadBytes);
2205         }
2206         String name = _symbols.findName(quads, qlen);
2207         if (name == null) {
2208             name = addName(quads, qlen, currQuadBytes);
2209         }
2210         return name;
2211     }
2212
2213     /*
2214     /**********************************************************
2215     /* Internal methods, symbol (name) handling
2216     /**********************************************************
2217      */

2218
2219     private final String findName(int q1, int lastQuadBytes) throws JsonParseException
2220     {
2221         q1 = _padLastQuad(q1, lastQuadBytes);
2222         // Usually we'll find it from the canonical symbol table already
2223         String name = _symbols.findName(q1);
2224         if (name != null) {
2225             return name;
2226         }
2227         // If not, more work. We'll need add stuff to buffer
2228         _quadBuffer[0] = q1;
2229         return addName(_quadBuffer, 1, lastQuadBytes);
2230     }
2231
2232     private final String findName(int q1, int q2, int lastQuadBytes) throws JsonParseException
2233     {
2234         q2 = _padLastQuad(q2, lastQuadBytes);
2235         // Usually we'll find it from the canonical symbol table already
2236         String name = _symbols.findName(q1, q2);
2237         if (name != null) {
2238             return name;
2239         }
2240         // If not, more work. We'll need add stuff to buffer
2241         _quadBuffer[0] = q1;
2242         _quadBuffer[1] = q2;
2243         return addName(_quadBuffer, 2, lastQuadBytes);
2244     }
2245
2246     private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws JsonParseException
2247     {
2248         q3 = _padLastQuad(q3, lastQuadBytes);
2249         String name = _symbols.findName(q1, q2, q3);
2250         if (name != null) {
2251             return name;
2252         }
2253         int[] quads = _quadBuffer;
2254         quads[0] = q1;
2255         quads[1] = q2;
2256         quads[2] = _padLastQuad(q3, lastQuadBytes);
2257         return addName(quads, 3, lastQuadBytes);
2258     }
2259     
2260     private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) throws JsonParseException
2261     {
2262         if (qlen >= quads.length) {
2263             _quadBuffer = quads = growArrayBy(quads, quads.length);
2264         }
2265         quads[qlen++] = _padLastQuad(lastQuad, lastQuadBytes);
2266         String name = _symbols.findName(quads, qlen);
2267         if (name == null) {
2268             return addName(quads, qlen, lastQuadBytes);
2269         }
2270         return name;
2271     }
2272
2273     /**
2274      * This is the main workhorse method used when we take a symbol
2275      * table miss. It needs to demultiplex individual bytes, decode
2276      * multi-byte chars (if any), and then construct Name instance
2277      * and add it to the symbol table.
2278      */

2279     private final String addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException
2280     {
2281         /* Ok: must decode UTF-8 chars. No other validation is
2282          * needed, since unescaping has been done earlier as necessary
2283          * (as well as error reporting for unescaped control chars)
2284          */

2285         // 4 bytes per quad, except last one maybe less
2286         int byteLen = (qlen << 2) - 4 + lastQuadBytes;
2287
2288         /* And last one is not correctly aligned (leading zero bytes instead
2289          * need to shift a bit, instead of trailing). Only need to shift it
2290          * for UTF-8 decoding; need revert for storage (since key will not
2291          * be aligned, to optimize lookup speed)
2292          */

2293         int lastQuad;
2294
2295         if (lastQuadBytes < 4) {
2296             lastQuad = quads[qlen-1];
2297             // 8/16/24 bit left shift
2298             quads[qlen-1] = (lastQuad << ((4 - lastQuadBytes) << 3));
2299         } else {
2300             lastQuad = 0;
2301         }
2302
2303         // Need some working space, TextBuffer works well:
2304         char[] cbuf = _textBuffer.emptyAndGetCurrentSegment();
2305         int cix = 0;
2306
2307         for (int ix = 0; ix < byteLen; ) {
2308             int ch = quads[ix >> 2]; // current quad, need to shift+mask
2309             int byteIx = (ix & 3);
2310             ch = (ch >> ((3 - byteIx) << 3)) & 0xFF;
2311             ++ix;
2312
2313             if (ch > 127) { // multi-byte
2314                 int needed;
2315                 if ((ch & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF)
2316                     ch &= 0x1F;
2317                     needed = 1;
2318                 } else if ((ch & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF)
2319                     ch &= 0x0F;
2320                     needed = 2;
2321                 } else if ((ch & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all...
2322                     ch &= 0x07;
2323                     needed = 3;
2324                 } else { // 5- and 6-byte chars not valid json chars
2325                     _reportInvalidInitial(ch);
2326                     needed = ch = 1; // never really gets this far
2327                 }
2328                 if ((ix + needed) > byteLen) {
2329                     _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
2330                 }
2331                 
2332                 // Ok, always need at least one more:
2333                 int ch2 = quads[ix >> 2]; // current quad, need to shift+mask
2334                 byteIx = (ix & 3);
2335                 ch2 = (ch2 >> ((3 - byteIx) << 3));
2336                 ++ix;
2337                 
2338                 if ((ch2 & 0xC0) != 0x080) {
2339                     _reportInvalidOther(ch2);
2340                 }
2341                 ch = (ch << 6) | (ch2 & 0x3F);
2342                 if (needed > 1) {
2343                     ch2 = quads[ix >> 2];
2344                     byteIx = (ix & 3);
2345                     ch2 = (ch2 >> ((3 - byteIx) << 3));
2346                     ++ix;
2347                     
2348                     if ((ch2 & 0xC0) != 0x080) {
2349                         _reportInvalidOther(ch2);
2350                     }
2351                     ch = (ch << 6) | (ch2 & 0x3F);
2352                     if (needed > 2) { // 4 bytes? (need surrogates on output)
2353                         ch2 = quads[ix >> 2];
2354                         byteIx = (ix & 3);
2355                         ch2 = (ch2 >> ((3 - byteIx) << 3));
2356                         ++ix;
2357                         if ((ch2 & 0xC0) != 0x080) {
2358                             _reportInvalidOther(ch2 & 0xFF);
2359                         }
2360                         ch = (ch << 6) | (ch2 & 0x3F);
2361                     }
2362                 }
2363                 if (needed > 2) { // surrogate pair? once again, let's output one here, one later on
2364                     ch -= 0x10000; // to normalize it starting with 0x0
2365                     if (cix >= cbuf.length) {
2366                         cbuf = _textBuffer.expandCurrentSegment();
2367                     }
2368                     cbuf[cix++] = (char) (0xD800 + (ch >> 10));
2369                     ch = 0xDC00 | (ch & 0x03FF);
2370                 }
2371             }
2372             if (cix >= cbuf.length) {
2373                 cbuf = _textBuffer.expandCurrentSegment();
2374             }
2375             cbuf[cix++] = (char) ch;
2376         }
2377
2378         // Ok. Now we have the character array, and can construct the String
2379         String baseName = new String(cbuf, 0, cix);
2380         // And finally, un-align if necessary
2381         if (lastQuadBytes < 4) {
2382             quads[qlen-1] = lastQuad;
2383         }
2384         return _symbols.addName(baseName, quads, qlen);
2385     }
2386
2387     /**
2388      * Helper method needed to fix [jackson-core#148], masking of 0x00 character
2389      */

2390     private final static int _padLastQuad(int q, int bytes) {
2391         return (bytes == 4) ? q : (q | (-1 << (bytes << 3)));
2392     }
2393
2394     /*
2395     /**********************************************************
2396     /* Internal methods, String value parsing
2397     /**********************************************************
2398      */

2399
2400     protected void _loadMoreGuaranteed() throws IOException {
2401         if (!_loadMore()) { _reportInvalidEOF(); }
2402     }
2403     
2404     @Override
2405     protected void _finishString() throws IOException
2406     {
2407         // First, single tight loop for ASCII content, not split across input buffer boundary:        
2408         int ptr = _inputPtr;
2409         if (ptr >= _inputEnd) {
2410             _loadMoreGuaranteed();
2411             ptr = _inputPtr;
2412         }
2413         int outPtr = 0;
2414         char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
2415         final int[] codes = _icUTF8;
2416
2417         final int max = Math.min(_inputEnd, (ptr + outBuf.length));
2418         final byte[] inputBuffer = _inputBuffer;
2419         while (ptr < max) {
2420             int c = (int) inputBuffer[ptr] & 0xFF;
2421             if (codes[c] != 0) {
2422                 if (c == INT_QUOTE) {
2423                     _inputPtr = ptr+1;
2424                     _textBuffer.setCurrentLength(outPtr);
2425                     return;
2426                 }
2427                 break;
2428             }
2429             ++ptr;
2430             outBuf[outPtr++] = (char) c;
2431         }
2432         _inputPtr = ptr;
2433         _finishString2(outBuf, outPtr);
2434     }
2435
2436     /**
2437      * @since 2.6
2438      */

2439     protected String _finishAndReturnString() throws IOException
2440     {
2441         // First, single tight loop for ASCII content, not split across input buffer boundary:        
2442         int ptr = _inputPtr;
2443         if (ptr >= _inputEnd) {
2444             _loadMoreGuaranteed();
2445             ptr = _inputPtr;
2446         }
2447         int outPtr = 0;
2448         char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
2449         final int[] codes = _icUTF8;
2450
2451         final int max = Math.min(_inputEnd, (ptr + outBuf.length));
2452         final byte[] inputBuffer = _inputBuffer;
2453         while (ptr < max) {
2454             int c = (int) inputBuffer[ptr] & 0xFF;
2455             if (codes[c] != 0) {
2456                 if (c == INT_QUOTE) {
2457                     _inputPtr = ptr+1;
2458                     return _textBuffer.setCurrentAndReturn(outPtr);
2459                 }
2460                 break;
2461             }
2462             ++ptr;
2463             outBuf[outPtr++] = (char) c;
2464         }
2465         _inputPtr = ptr;
2466         _finishString2(outBuf, outPtr);
2467         return _textBuffer.contentsAsString();
2468     }
2469     
2470     private final void _finishString2(char[] outBuf, int outPtr)
2471         throws IOException
2472     {
2473         int c;
2474
2475         // Here we do want to do full decoding, hence:
2476         final int[] codes = _icUTF8;
2477         final byte[] inputBuffer = _inputBuffer;
2478
2479         main_loop:
2480         while (true) {
2481             // Then the tight ASCII non-funny-char loop:
2482             ascii_loop:
2483             while (true) {
2484                 int ptr = _inputPtr;
2485                 if (ptr >= _inputEnd) {
2486                     _loadMoreGuaranteed();
2487                     ptr = _inputPtr;
2488                 }
2489                 if (outPtr >= outBuf.length) {
2490                     outBuf = _textBuffer.finishCurrentSegment();
2491                     outPtr = 0;
2492                 }
2493                 final int max = Math.min(_inputEnd, (ptr + (outBuf.length - outPtr)));
2494                 while (ptr < max) {
2495                     c = (int) inputBuffer[ptr++] & 0xFF;
2496                     if (codes[c] != 0) {
2497                         _inputPtr = ptr;
2498                         break ascii_loop;
2499                     }
2500                     outBuf[outPtr++] = (char) c;
2501                 }
2502                 _inputPtr = ptr;
2503             }
2504             // Ok: end marker, escape or multi-byte?
2505             if (c == INT_QUOTE) {
2506                 break main_loop;
2507             }
2508
2509             switch (codes[c]) {
2510             case 1: // backslash
2511                 c = _decodeEscaped();
2512                 break;
2513             case 2: // 2-byte UTF
2514                 c = _decodeUtf8_2(c);
2515                 break;
2516             case 3: // 3-byte UTF
2517                 if ((_inputEnd - _inputPtr) >= 2) {
2518                     c = _decodeUtf8_3fast(c);
2519                 } else {
2520                     c = _decodeUtf8_3(c);
2521                 }
2522                 break;
2523             case 4: // 4-byte UTF
2524                 c = _decodeUtf8_4(c);
2525                 // Let's add first part right away:
2526                 outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
2527                 if (outPtr >= outBuf.length) {
2528                     outBuf = _textBuffer.finishCurrentSegment();
2529                     outPtr = 0;
2530                 }
2531                 c = 0xDC00 | (c & 0x3FF);
2532                 // And let the other char output down below
2533                 break;
2534             default:
2535                 if (c < INT_SPACE) {
2536                     // As per [JACKSON-208], call can now return:
2537                     _throwUnquotedSpace(c, "string value");
2538                 } else {
2539                     // Is this good enough error message?
2540                     _reportInvalidChar(c);
2541                 }
2542             }
2543             // Need more room?
2544             if (outPtr >= outBuf.length) {
2545                 outBuf = _textBuffer.finishCurrentSegment();
2546                 outPtr = 0;
2547             }
2548             // Ok, let's add char to output:
2549             outBuf[outPtr++] = (char) c;
2550         }
2551         _textBuffer.setCurrentLength(outPtr);
2552     }
2553
2554     /**
2555      * Method called to skim through rest of unparsed String value,
2556      * if it is not needed. This can be done bit faster if contents
2557      * need not be stored for future access.
2558      */

2559     protected void _skipString() throws IOException
2560     {
2561         _tokenIncomplete = false;
2562
2563         // Need to be fully UTF-8 aware here:
2564         final int[] codes = _icUTF8;
2565         final byte[] inputBuffer = _inputBuffer;
2566
2567         main_loop:
2568         while (true) {
2569             int c;
2570
2571             ascii_loop:
2572             while (true) {
2573                 int ptr = _inputPtr;
2574                 int max = _inputEnd;
2575                 if (ptr >= max) {
2576                     _loadMoreGuaranteed();
2577                     ptr = _inputPtr;
2578                     max = _inputEnd;
2579                 }
2580                 while (ptr < max) {
2581                     c = (int) inputBuffer[ptr++] & 0xFF;
2582                     if (codes[c] != 0) {
2583                         _inputPtr = ptr;
2584                         break ascii_loop;
2585                     }
2586                 }
2587                 _inputPtr = ptr;
2588             }
2589             // Ok: end marker, escape or multi-byte?
2590             if (c == INT_QUOTE) {
2591                 break main_loop;
2592             }
2593             
2594             switch (codes[c]) {
2595             case 1: // backslash
2596                 _decodeEscaped();
2597                 break;
2598             case 2: // 2-byte UTF
2599                 _skipUtf8_2();
2600                 break;
2601             case 3: // 3-byte UTF
2602                 _skipUtf8_3();
2603                 break;
2604             case 4: // 4-byte UTF
2605                 _skipUtf8_4(c);
2606                 break;
2607             default:
2608                 if (c < INT_SPACE) {
2609                     _throwUnquotedSpace(c, "string value");
2610                 } else {
2611                     // Is this good enough error message?
2612                     _reportInvalidChar(c);
2613                 }
2614             }
2615         }
2616     }
2617
2618     /**
2619      * Method for handling cases where first non-space character
2620      * of an expected value token is not legal for standard JSON content.
2621      */

2622     protected JsonToken _handleUnexpectedValue(int c) throws IOException
2623     {
2624         // Most likely an error, unless we are to allow single-quote-strings
2625         switch (c) {
2626         /* This check proceeds only if `Feature.ALLOW_MISSING_VALUES` is enabled;
2627          * it is for missing values. In case of missing values in an array the next token
2628          * will be either ',' or ']'. This case, decrements the already incremented _inputPtr
2629          * in the buffer in case of comma (`,`) so that the existing flow goes back to checking
2630          * the next token which will be comma again and  it parsing continues.
2631          * Also the case returns NULL as current token in case of ',' or ']'.    
2632          */

2633         case ']':
2634             if (!_parsingContext.inArray()) {
2635                 break;
2636             }
2637             // fall through
2638         case ',':
2639             // 28-Mar-2016: [core#116]: If Feature.ALLOW_MISSING_VALUES is enabled
2640             //   we may allow "missing values", that is, encountering a trailing
2641             //   comma or closing marker where value would be expected
2642             // 11-May-2020, tatu: [core#616] No commas in root level
2643             if (!_parsingContext.inRoot()) {
2644                 if ((_features & FEAT_MASK_ALLOW_MISSING) != 0) {
2645                     --_inputPtr;
2646                     return JsonToken.VALUE_NULL;
2647                 }
2648             }
2649             // fall through
2650         case '}':
2651             // Error: neither is valid at this point; valid closers have
2652             // been handled earlier
2653             _reportUnexpectedChar(c, "expected a value");
2654         case '\'':
2655             if ((_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) {
2656                 return _handleApos();
2657             }
2658             break;
2659         case 'N':
2660             _matchToken("NaN", 1);
2661             if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
2662                 return resetAsNaN("NaN", Double.NaN);
2663             }
2664             _reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
2665             break;
2666         case 'I':
2667             _matchToken("Infinity", 1);
2668             if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
2669                 return resetAsNaN("Infinity", Double.POSITIVE_INFINITY);
2670             }
2671             _reportError("Non-standard token 'Infinity': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
2672             break;
2673         case '+': // note: '-' is taken as number
2674             if (_inputPtr >= _inputEnd) {
2675                 if (!_loadMore()) {
2676                     _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_INT);
2677                 }
2678             }
2679             return _handleInvalidNumberStart(_inputBuffer[_inputPtr++] & 0xFF, false);
2680         }
2681         // [core#77] Try to decode most likely token
2682         if (Character.isJavaIdentifierStart(c)) {
2683             _reportInvalidToken(""+((char) c), _validJsonTokenList());
2684         }
2685         // but if it doesn't look like a token:
2686         _reportUnexpectedChar(c, "expected a valid value "+_validJsonValueList());
2687         return null;
2688     }
2689
2690     protected JsonToken _handleApos() throws IOException
2691     {
2692         int c = 0;
2693         // Otherwise almost verbatim copy of _finishString()
2694         int outPtr = 0;
2695         char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
2696
2697         // Here we do want to do full decoding, hence:
2698         final int[] codes = _icUTF8;
2699         final byte[] inputBuffer = _inputBuffer;
2700
2701         main_loop:
2702         while (true) {
2703             // Then the tight ascii non-funny-char loop:
2704             ascii_loop:
2705             while (true) {
2706                 if (_inputPtr >= _inputEnd) {
2707                     _loadMoreGuaranteed();
2708                 }
2709                 if (outPtr >= outBuf.length) {
2710                     outBuf = _textBuffer.finishCurrentSegment();
2711                     outPtr = 0;
2712                 }
2713                 int max = _inputEnd;
2714                 {
2715                     int max2 = _inputPtr + (outBuf.length - outPtr);
2716                     if (max2 < max) {
2717                         max = max2;
2718                     }
2719                 }
2720                 while (_inputPtr < max) {
2721                     c = (int) inputBuffer[_inputPtr++] & 0xFF;
2722                     if (c == INT_APOS || codes[c] != 0) {
2723                         break ascii_loop;
2724                     }
2725                     outBuf[outPtr++] = (char) c;
2726                 }
2727             }
2728
2729             // Ok: end marker, escape or multi-byte?
2730             if (c == INT_APOS) {
2731                 break main_loop;
2732             }
2733
2734             switch (codes[c]) {
2735             case 1: // backslash
2736                 c = _decodeEscaped();
2737                 break;
2738             case 2: // 2-byte UTF
2739                 c = _decodeUtf8_2(c);
2740                 break;
2741             case 3: // 3-byte UTF
2742                 if ((_inputEnd - _inputPtr) >= 2) {
2743                     c = _decodeUtf8_3fast(c);
2744                 } else {
2745                     c = _decodeUtf8_3(c);
2746                 }
2747                 break;
2748             case 4: // 4-byte UTF
2749                 c = _decodeUtf8_4(c);
2750                 // Let's add first part right away:
2751                 outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
2752                 if (outPtr >= outBuf.length) {
2753                     outBuf = _textBuffer.finishCurrentSegment();
2754                     outPtr = 0;
2755                 }
2756                 c = 0xDC00 | (c & 0x3FF);
2757                 // And let the other char output down below
2758                 break;
2759             default:
2760                 if (c < INT_SPACE) {
2761                     _throwUnquotedSpace(c, "string value");
2762                 }
2763                 // Is this good enough error message?
2764                 _reportInvalidChar(c);
2765             }
2766             // Need more room?
2767             if (outPtr >= outBuf.length) {
2768                 outBuf = _textBuffer.finishCurrentSegment();
2769                 outPtr = 0;
2770             }
2771             // Ok, let's add char to output:
2772             outBuf[outPtr++] = (char) c;
2773         }
2774         _textBuffer.setCurrentLength(outPtr);
2775
2776         return JsonToken.VALUE_STRING;
2777     }
2778
2779     /*
2780     /**********************************************************
2781     /* Internal methods, well-known token decoding
2782     /**********************************************************
2783      */

2784
2785     /**
2786      * Method called if expected numeric value (due to leading sign) does not
2787      * look like a number
2788      */

2789     protected JsonToken _handleInvalidNumberStart(int ch, boolean neg) throws IOException
2790     {
2791         while (ch == 'I') {
2792             if (_inputPtr >= _inputEnd) {
2793                 if (!_loadMore()) {
2794                     _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_FLOAT); // possibly?
2795                 }
2796             }
2797             ch = _inputBuffer[_inputPtr++];
2798             String match;
2799             if (ch == 'N') {
2800                 match = neg ? "-INF" :"+INF";
2801             } else if (ch == 'n') {
2802                 match = neg ? "-Infinity" :"+Infinity";
2803             } else {
2804                 break;
2805             }
2806             _matchToken(match, 3);
2807             if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
2808                 return resetAsNaN(match, neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
2809             }
2810             _reportError("Non-standard token '%s': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow",
2811                     match);
2812         }
2813         reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value");
2814         return null;
2815     }
2816
2817     // NOTE: first character already decoded
2818     protected final void _matchTrue() throws IOException
2819     {
2820         int ptr = _inputPtr;
2821         if ((ptr + 3) < _inputEnd) {
2822             byte[] buf = _inputBuffer;
2823             if ((buf[ptr++] == 'r') 
2824                    && (buf[ptr++] == 'u')
2825                    && (buf[ptr++] == 'e')) {
2826                 int ch = buf[ptr] & 0xFF;
2827                 if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
2828                     _inputPtr = ptr;
2829                     return;
2830                 }
2831             }
2832         }
2833         _matchToken2("true", 1);
2834     }
2835
2836     protected final void _matchFalse() throws IOException
2837     {
2838         int ptr = _inputPtr;
2839         if ((ptr + 4) < _inputEnd) {
2840             byte[] buf = _inputBuffer;
2841             if ((buf[ptr++] == 'a') 
2842                    && (buf[ptr++] == 'l')
2843                    && (buf[ptr++] == 's')
2844                    && (buf[ptr++] == 'e')) {
2845                 int ch = buf[ptr] & 0xFF;
2846                 if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
2847                     _inputPtr = ptr;
2848                     return;
2849                 }
2850             }
2851         }
2852         _matchToken2("false", 1);
2853     }
2854
2855     protected final void _matchNull() throws IOException
2856     {
2857         int ptr = _inputPtr;
2858         if ((ptr + 3) < _inputEnd) {
2859             byte[] buf = _inputBuffer;
2860             if ((buf[ptr++] == 'u') 
2861                    && (buf[ptr++] == 'l')
2862                    && (buf[ptr++] == 'l')) {
2863                 int ch = buf[ptr] & 0xFF;
2864                 if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
2865                     _inputPtr = ptr;
2866                     return;
2867                 }
2868             }
2869         }
2870         _matchToken2("null", 1);
2871     }
2872     
2873     protected final void _matchToken(String matchStr, int i) throws IOException
2874     {
2875         final int len = matchStr.length();
2876         if ((_inputPtr + len) >= _inputEnd) {
2877             _matchToken2(matchStr, i);
2878             return;
2879         }
2880         do {
2881             if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) {
2882                 _reportInvalidToken(matchStr.substring(0, i));
2883             }
2884             ++_inputPtr;
2885         } while (++i < len);
2886     
2887         int ch = _inputBuffer[_inputPtr] & 0xFF;
2888         if (ch >= '0' && ch != ']' && ch != '}') { // expected/allowed chars
2889             _checkMatchEnd(matchStr, i, ch);
2890         }
2891     }
2892
2893     private final void _matchToken2(String matchStr, int i) throws IOException
2894     {
2895         final int len = matchStr.length();
2896         do {
2897             if (((_inputPtr >= _inputEnd) && !_loadMore())
2898                 ||  (_inputBuffer[_inputPtr] != matchStr.charAt(i))) {
2899                 _reportInvalidToken(matchStr.substring(0, i));
2900             }
2901             ++_inputPtr;
2902         } while (++i < len);
2903     
2904         // but let's also ensure we either get EOF, or non-alphanum char...
2905         if (_inputPtr >= _inputEnd && !_loadMore()) {
2906             return;
2907         }
2908         int ch = _inputBuffer[_inputPtr] & 0xFF;
2909         if (ch >= '0' && ch != ']' && ch != '}') { // expected/allowed chars
2910             _checkMatchEnd(matchStr, i, ch);
2911         }
2912     }
2913
2914     private final void _checkMatchEnd(String matchStr, int i, int ch) throws IOException {
2915         // but actually only alphanums are problematic
2916         char c = (char) _decodeCharForError(ch);
2917         if (Character.isJavaIdentifierPart(c)) {
2918             _reportInvalidToken(matchStr.substring(0, i));
2919         }
2920     }
2921     
2922     /*
2923     /**********************************************************
2924     /* Internal methods, ws skipping, escape/unescape
2925     /**********************************************************
2926      */

2927
2928     private final int _skipWS() throws IOException
2929     {
2930         while (_inputPtr < _inputEnd) {
2931             int i = _inputBuffer[_inputPtr++] & 0xFF;
2932             if (i > INT_SPACE) {
2933                 if (i == INT_SLASH || i == INT_HASH) {
2934                     --_inputPtr;
2935                     return _skipWS2();
2936                 }
2937                 return i;
2938             }
2939             if (i != INT_SPACE) {
2940                 if (i == INT_LF) {
2941                     ++_currInputRow;
2942                     _currInputRowStart = _inputPtr;
2943                 } else if (i == INT_CR) {
2944                     _skipCR();
2945                 } else if (i != INT_TAB) {
2946                     _throwInvalidSpace(i);
2947                 }
2948             }
2949         }
2950         return _skipWS2();
2951     }
2952
2953     private final int _skipWS2() throws IOException
2954     {
2955         while (_inputPtr < _inputEnd || _loadMore()) {
2956             int i = _inputBuffer[_inputPtr++] & 0xFF;
2957             if (i > INT_SPACE) {
2958                 if (i == INT_SLASH) {
2959                     _skipComment();
2960                     continue;
2961                 }
2962                 if (i == INT_HASH) {
2963                     if (_skipYAMLComment()) {
2964                         continue;
2965                     }
2966                 }
2967                 return i;
2968             }
2969             if (i != INT_SPACE) {
2970                 if (i == INT_LF) {
2971                     ++_currInputRow;
2972                     _currInputRowStart = _inputPtr;
2973                 } else if (i == INT_CR) {
2974                     _skipCR();
2975                 } else if (i != INT_TAB) {
2976                     _throwInvalidSpace(i);
2977                 }
2978             }
2979         }        
2980         throw _constructError("Unexpected end-of-input within/between "+_parsingContext.typeDesc()+" entries");
2981     }
2982
2983     private final int _skipWSOrEnd() throws IOException
2984     {
2985         // Let's handle first character separately since it is likely that
2986         // it is either non-whitespace; or we have longer run of white space
2987         if (_inputPtr >= _inputEnd) {
2988             if (!_loadMore()) {
2989                 return _eofAsNextChar();
2990             }
2991         }
2992         int i = _inputBuffer[_inputPtr++] & 0xFF;
2993         if (i > INT_SPACE) {
2994             if (i == INT_SLASH || i == INT_HASH) {
2995                 --_inputPtr;
2996                 return _skipWSOrEnd2();
2997             }
2998             return i;
2999         }
3000         if (i != INT_SPACE) {
3001             if (i == INT_LF) {
3002                 ++_currInputRow;
3003                 _currInputRowStart = _inputPtr;
3004             } else if (i == INT_CR) {
3005                 _skipCR();
3006             } else if (i != INT_TAB) {
3007                 _throwInvalidSpace(i);
3008             }
3009         }
3010         
3011         while (_inputPtr < _inputEnd) {
3012             i = _inputBuffer[_inputPtr++] & 0xFF;
3013             if (i > INT_SPACE) {
3014                 if (i == INT_SLASH || i == INT_HASH) {
3015                     --_inputPtr;
3016                     return _skipWSOrEnd2();
3017                 }
3018                 return i;
3019             }
3020             if (i != INT_SPACE) {
3021                 if (i == INT_LF) {
3022                     ++_currInputRow;
3023                     _currInputRowStart = _inputPtr;
3024                 } else if (i == INT_CR) {
3025                     _skipCR();
3026                 } else if (i != INT_TAB) {
3027                     _throwInvalidSpace(i);
3028                 }
3029             }
3030         }
3031         return _skipWSOrEnd2();
3032     }
3033
3034     private final int _skipWSOrEnd2() throws IOException
3035     {
3036         while ((_inputPtr < _inputEnd) || _loadMore()) {
3037             int i = _inputBuffer[_inputPtr++] & 0xFF;
3038             if (i > INT_SPACE) {
3039                 if (i == INT_SLASH) {
3040                     _skipComment();
3041                     continue;
3042                 }
3043                 if (i == INT_HASH) {
3044                     if (_skipYAMLComment()) {
3045                         continue;
3046                     }
3047                 }
3048                 return i;
3049             } else if (i != INT_SPACE) {
3050                 if (i == INT_LF) {
3051                     ++_currInputRow;
3052                     _currInputRowStart = _inputPtr;
3053                 } else if (i == INT_CR) {
3054                     _skipCR();
3055                 } else if (i != INT_TAB) {
3056                     _throwInvalidSpace(i);
3057                 }
3058             }
3059         }
3060         // We ran out of input...
3061         return _eofAsNextChar();
3062     }
3063
3064     private final int _skipColon() throws IOException
3065     {
3066         if ((_inputPtr + 4) >= _inputEnd) {
3067             return _skipColon2(false);
3068         }
3069         // Fast path: colon with optional single-space/tab before and/or after:
3070         int i = _inputBuffer[_inputPtr];
3071         if (i == INT_COLON) { // common case, no leading space
3072             i = _inputBuffer[++_inputPtr];
3073             if (i > INT_SPACE) { // nor trailing
3074                 if (i == INT_SLASH || i == INT_HASH) {
3075                     return _skipColon2(true);
3076                 }
3077                 ++_inputPtr;
3078                 return i;
3079             }
3080             if (i == INT_SPACE || i == INT_TAB) {
3081                 i = (int) _inputBuffer[++_inputPtr];
3082                 if (i > INT_SPACE) {
3083                     if (i == INT_SLASH || i == INT_HASH) {
3084                         return _skipColon2(true);
3085                     }
3086                     ++_inputPtr;                    
3087                     return i;
3088                 }
3089             }
3090             return _skipColon2(true); // true -> skipped colon
3091         }
3092         if (i == INT_SPACE || i == INT_TAB) {
3093             i = _inputBuffer[++_inputPtr];
3094         }
3095         if (i == INT_COLON) {
3096             i = _inputBuffer[++_inputPtr];
3097             if (i > INT_SPACE) {
3098                 if (i == INT_SLASH || i == INT_HASH) {
3099                     return _skipColon2(true);
3100                 }
3101                 ++_inputPtr;
3102                 return i;
3103             }
3104             if (i == INT_SPACE || i == INT_TAB) {
3105                 i = (int) _inputBuffer[++_inputPtr];
3106                 if (i > INT_SPACE) {
3107                     if (i == INT_SLASH || i == INT_HASH) {
3108                         return _skipColon2(true);
3109                     }
3110                     ++_inputPtr;
3111                     return i;
3112                 }
3113             }
3114             return _skipColon2(true);
3115         }
3116         return _skipColon2(false);
3117     }
3118
3119     private final int _skipColon2(boolean gotColon) throws IOException
3120     {
3121         while (_inputPtr < _inputEnd || _loadMore()) {
3122             int i = _inputBuffer[_inputPtr++] & 0xFF;
3123
3124             if (i > INT_SPACE) {
3125                 if (i == INT_SLASH) {
3126                     _skipComment();
3127                     continue;
3128                 }
3129                 if (i == INT_HASH) {
3130                     if (_skipYAMLComment()) {
3131                         continue;
3132                     }
3133                 }
3134                 if (gotColon) {
3135                     return i;
3136                 }
3137                 if (i != INT_COLON) {
3138                     _reportUnexpectedChar(i, "was expecting a colon to separate field name and value");
3139                 }
3140                 gotColon = true;
3141             } else if (i != INT_SPACE) {
3142                 if (i == INT_LF) {
3143                     ++_currInputRow;
3144                     _currInputRowStart = _inputPtr;
3145                 } else if (i == INT_CR) {
3146                     _skipCR();
3147                 } else if (i != INT_TAB) {
3148                     _throwInvalidSpace(i);
3149                 }
3150             }
3151         }
3152         _reportInvalidEOF(" within/between "+_parsingContext.typeDesc()+" entries",
3153                 null);
3154         return -1;
3155     }
3156
3157     private final void _skipComment() throws IOException
3158     {
3159         if ((_features & FEAT_MASK_ALLOW_JAVA_COMMENTS) == 0) {
3160             _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)");
3161         }
3162         // First: check which comment (if either) it is:
3163         if (_inputPtr >= _inputEnd && !_loadMore()) {
3164             _reportInvalidEOF(" in a comment"null);
3165         }
3166         int c = _inputBuffer[_inputPtr++] & 0xFF;
3167         if (c == INT_SLASH) {
3168             _skipLine();
3169         } else if (c == INT_ASTERISK) {
3170             _skipCComment();
3171         } else {
3172             _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment");
3173         }
3174     }
3175
3176     private final void _skipCComment() throws IOException
3177     {
3178         // Need to be UTF-8 aware here to decode content (for skipping)
3179         final int[] codes = CharTypes.getInputCodeComment();
3180
3181         // Ok: need the matching '*/'
3182         main_loop:
3183         while ((_inputPtr < _inputEnd) || _loadMore()) {
3184             int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
3185             int code = codes[i];
3186             if (code != 0) {
3187                 switch (code) {
3188                 case '*':
3189                     if (_inputPtr >= _inputEnd && !_loadMore()) {
3190                         break main_loop;
3191                     }
3192                     if (_inputBuffer[_inputPtr] == INT_SLASH) {
3193                         ++_inputPtr;
3194                         return;
3195                     }
3196                     break;
3197                 case INT_LF:
3198                     ++_currInputRow;
3199                     _currInputRowStart = _inputPtr;
3200                     break;
3201                 case INT_CR:
3202                     _skipCR();
3203                     break;
3204                 case 2: // 2-byte UTF
3205                     _skipUtf8_2();
3206                     break;
3207                 case 3: // 3-byte UTF
3208                     _skipUtf8_3();
3209                     break;
3210                 case 4: // 4-byte UTF
3211                     _skipUtf8_4(i);
3212                     break;
3213                 default// e.g. -1
3214                     // Is this good enough error message?
3215                     _reportInvalidChar(i);
3216                 }
3217             }
3218         }
3219         _reportInvalidEOF(" in a comment"null);
3220     }
3221
3222     private final boolean _skipYAMLComment() throws IOException
3223     {
3224         if ((_features & FEAT_MASK_ALLOW_YAML_COMMENTS) == 0) {
3225             return false;
3226         }
3227         _skipLine();
3228         return true;
3229     }
3230
3231     /**
3232      * Method for skipping contents of an input line; usually for CPP
3233      * and YAML style comments.
3234      */

3235     private final void _skipLine() throws IOException
3236     {
3237         // Ok: need to find EOF or linefeed
3238         final int[] codes = CharTypes.getInputCodeComment();
3239         while ((_inputPtr < _inputEnd) || _loadMore()) {
3240             int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
3241             int code = codes[i];
3242             if (code != 0) {
3243                 switch (code) {
3244                 case INT_LF:
3245                     ++_currInputRow;
3246                     _currInputRowStart = _inputPtr;
3247                     return;
3248                 case INT_CR:
3249                     _skipCR();
3250                     return;
3251                 case '*': // nop for these comments
3252                     break;
3253                 case 2: // 2-byte UTF
3254                     _skipUtf8_2();
3255                     break;
3256                 case 3: // 3-byte UTF
3257                     _skipUtf8_3();
3258                     break;
3259                 case 4: // 4-byte UTF
3260                     _skipUtf8_4(i);
3261                     break;
3262                 default// e.g. -1
3263                     if (code < 0) {
3264                         // Is this good enough error message?
3265                         _reportInvalidChar(i);
3266                     }
3267                 }
3268             }
3269         }
3270     }
3271     
3272     @Override
3273     protected char _decodeEscaped() throws IOException
3274     {
3275         if (_inputPtr >= _inputEnd) {
3276             if (!_loadMore()) {
3277                 _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
3278             }
3279         }
3280         int c = (int) _inputBuffer[_inputPtr++];
3281
3282         switch (c) {
3283             // First, ones that are mapped
3284         case 'b':
3285             return '\b';
3286         case 't':
3287             return '\t';
3288         case 'n':
3289             return '\n';
3290         case 'f':
3291             return '\f';
3292         case 'r':
3293             return '\r';
3294
3295             // And these are to be returned as they are
3296         case '"':
3297         case '/':
3298         case '\\':
3299             return (char) c;
3300
3301         case 'u': // and finally hex-escaped
3302             break;
3303
3304         default:
3305             return _handleUnrecognizedCharacterEscape((char) _decodeCharForError(c));
3306         }
3307
3308         // Ok, a hex escape. Need 4 characters
3309         int value = 0;
3310         for (int i = 0; i < 4; ++i) {
3311             if (_inputPtr >= _inputEnd) {
3312                 if (!_loadMore()) {
3313                     _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
3314                 }
3315             }
3316             int ch = _inputBuffer[_inputPtr++];
3317             int digit = CharTypes.charToHex(ch);
3318             if (digit < 0) {
3319                 _reportUnexpectedChar(ch & 0xFF, "expected a hex-digit for character escape sequence");
3320             }
3321             value = (value << 4) | digit;
3322         }
3323         return (char) value;
3324     }
3325
3326     protected int _decodeCharForError(int firstByte) throws IOException
3327     {
3328         int c = firstByte & 0xFF;
3329         if (c > 0x7F) { // if >= 0, is ascii and fine as is
3330             int needed;
3331             
3332             // Ok; if we end here, we got multi-byte combination
3333             if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF)
3334                 c &= 0x1F;
3335                 needed = 1;
3336             } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF)
3337                 c &= 0x0F;
3338                 needed = 2;
3339             } else if ((c & 0xF8) == 0xF0) {
3340                 // 4 bytes; double-char with surrogates and all...
3341                 c &= 0x07;
3342                 needed = 3;
3343             } else {
3344                 _reportInvalidInitial(c & 0xFF);
3345                 needed = 1; // never gets here
3346             }
3347
3348             int d = nextByte();
3349             if ((d & 0xC0) != 0x080) {
3350                 _reportInvalidOther(d & 0xFF);
3351             }
3352             c = (c << 6) | (d & 0x3F);
3353             
3354             if (needed > 1) { // needed == 1 means 2 bytes total
3355                 d = nextByte(); // 3rd byte
3356                 if ((d & 0xC0) != 0x080) {
3357                     _reportInvalidOther(d & 0xFF);
3358                 }
3359                 c = (c << 6) | (d & 0x3F);
3360                 if (needed > 2) { // 4 bytes? (need surrogates)
3361                     d = nextByte();
3362                     if ((d & 0xC0) != 0x080) {
3363                         _reportInvalidOther(d & 0xFF);
3364                     }
3365                     c = (c << 6) | (d & 0x3F);
3366                 }
3367             }
3368         }
3369         return c;
3370     }
3371
3372     /*
3373     /**********************************************************
3374     /* Internal methods,UTF8 decoding
3375     /**********************************************************
3376      */

3377
3378     private final int _decodeUtf8_2(int c) throws IOException
3379     {
3380         if (_inputPtr >= _inputEnd) {
3381             _loadMoreGuaranteed();
3382         }
3383         int d = (int) _inputBuffer[_inputPtr++];
3384         if ((d & 0xC0) != 0x080) {
3385             _reportInvalidOther(d & 0xFF, _inputPtr);
3386         }
3387         return ((c & 0x1F) << 6) | (d & 0x3F);
3388     }
3389
3390     private final int _decodeUtf8_3(int c1) throws IOException
3391     {
3392         if (_inputPtr >= _inputEnd) {
3393             _loadMoreGuaranteed();
3394         }
3395         c1 &= 0x0F;
3396         int d = (int) _inputBuffer[_inputPtr++];
3397         if ((d & 0xC0) != 0x080) {
3398             _reportInvalidOther(d & 0xFF, _inputPtr);
3399         }
3400         int c = (c1 << 6) | (d & 0x3F);
3401         if (_inputPtr >= _inputEnd) {
3402             _loadMoreGuaranteed();
3403         }
3404         d = (int) _inputBuffer[_inputPtr++];
3405         if ((d & 0xC0) != 0x080) {
3406             _reportInvalidOther(d & 0xFF, _inputPtr);
3407         }
3408         c = (c << 6) | (d & 0x3F);
3409         return c;
3410     }
3411
3412     private final int _decodeUtf8_3fast(int c1) throws IOException
3413     {
3414         c1 &= 0x0F;
3415         int d = (int) _inputBuffer[_inputPtr++];
3416         if ((d & 0xC0) != 0x080) {
3417             _reportInvalidOther(d & 0xFF, _inputPtr);
3418         }
3419         int c = (c1 << 6) | (d & 0x3F);
3420         d = (int) _inputBuffer[_inputPtr++];
3421         if ((d & 0xC0) != 0x080) {
3422             _reportInvalidOther(d & 0xFF, _inputPtr);
3423         }
3424         c = (c << 6) | (d & 0x3F);
3425         return c;
3426     }
3427
3428     /**
3429      * @return Character value <b>minus 0x10000</c>; this so that caller
3430      *    can readily expand it to actual surrogates
3431      */

3432     private final int _decodeUtf8_4(int c) throws IOException
3433     {
3434         if (_inputPtr >= _inputEnd) {
3435             _loadMoreGuaranteed();
3436         }
3437         int d = (int) _inputBuffer[_inputPtr++];
3438         if ((d & 0xC0) != 0x080) {
3439             _reportInvalidOther(d & 0xFF, _inputPtr);
3440         }
3441         c = ((c & 0x07) << 6) | (d & 0x3F);
3442
3443         if (_inputPtr >= _inputEnd) {
3444             _loadMoreGuaranteed();
3445         }
3446         d = (int) _inputBuffer[_inputPtr++];
3447         if ((d & 0xC0) != 0x080) {
3448             _reportInvalidOther(d & 0xFF, _inputPtr);
3449         }
3450         c = (c << 6) | (d & 0x3F);
3451         if (_inputPtr >= _inputEnd) {
3452             _loadMoreGuaranteed();
3453         }
3454         d = (int) _inputBuffer[_inputPtr++];
3455         if ((d & 0xC0) != 0x080) {
3456             _reportInvalidOther(d & 0xFF, _inputPtr);
3457         }
3458
3459         /* note: won't change it to negative here, since caller
3460          * already knows it'll need a surrogate
3461          */

3462         return ((c << 6) | (d & 0x3F)) - 0x10000;
3463     }
3464
3465     private final void _skipUtf8_2() throws IOException
3466     {
3467         if (_inputPtr >= _inputEnd) {
3468             _loadMoreGuaranteed();
3469         }
3470         int c = (int) _inputBuffer[_inputPtr++];
3471         if ((c & 0xC0) != 0x080) {
3472             _reportInvalidOther(c & 0xFF, _inputPtr);
3473         }
3474     }
3475
3476     /* Alas, can't heavily optimize skipping, since we still have to
3477      * do validity checks...
3478      */

3479     private final void _skipUtf8_3() throws IOException
3480     {
3481         if (_inputPtr >= _inputEnd) {
3482             _loadMoreGuaranteed();
3483         }
3484         //c &= 0x0F;
3485         int c = (int) _inputBuffer[_inputPtr++];
3486         if ((c & 0xC0) != 0x080) {
3487             _reportInvalidOther(c & 0xFF, _inputPtr);
3488         }
3489         if (_inputPtr >= _inputEnd) {
3490             _loadMoreGuaranteed();
3491         }
3492         c = (int) _inputBuffer[_inputPtr++];
3493         if ((c & 0xC0) != 0x080) {
3494             _reportInvalidOther(c & 0xFF, _inputPtr);
3495         }
3496     }
3497
3498     private final void _skipUtf8_4(int c) throws IOException
3499     {
3500         if (_inputPtr >= _inputEnd) {
3501             _loadMoreGuaranteed();
3502         }
3503         int d = (int) _inputBuffer[_inputPtr++];
3504         if ((d & 0xC0) != 0x080) {
3505             _reportInvalidOther(d & 0xFF, _inputPtr);
3506         }
3507         if (_inputPtr >= _inputEnd) {
3508             _loadMoreGuaranteed();
3509         }
3510         d = (int) _inputBuffer[_inputPtr++];
3511         if ((d & 0xC0) != 0x080) {
3512             _reportInvalidOther(d & 0xFF, _inputPtr);
3513         }
3514         if (_inputPtr >= _inputEnd) {
3515             _loadMoreGuaranteed();
3516         }
3517         d = (int) _inputBuffer[_inputPtr++];
3518         if ((d & 0xC0) != 0x080) {
3519             _reportInvalidOther(d & 0xFF, _inputPtr);
3520         }
3521     }
3522
3523     /*
3524     /**********************************************************
3525     /* Internal methods, input loading
3526     /**********************************************************
3527      */

3528
3529     /**
3530      * We actually need to check the character value here
3531      * (to see if we have \n following \r).
3532      */

3533     protected final void _skipCR() throws IOException
3534     {
3535         if (_inputPtr < _inputEnd || _loadMore()) {
3536             if (_inputBuffer[_inputPtr] == BYTE_LF) {
3537                 ++_inputPtr;
3538             }
3539         }
3540         ++_currInputRow;
3541         _currInputRowStart = _inputPtr;
3542     }
3543
3544         private int nextByte() throws IOException
3545     {
3546         if (_inputPtr >= _inputEnd) {
3547             _loadMoreGuaranteed();
3548         }
3549         return _inputBuffer[_inputPtr++] & 0xFF;
3550     }
3551
3552     /*
3553     /**********************************************************
3554     /* Internal methods, error reporting
3555     /**********************************************************
3556      */

3557
3558     protected void _reportInvalidToken(String matchedPart, int ptr) throws IOException {
3559         _inputPtr = ptr;
3560         _reportInvalidToken(matchedPart, _validJsonTokenList());
3561     }
3562
3563     protected void _reportInvalidToken(String matchedPart) throws IOException {
3564         _reportInvalidToken(matchedPart, _validJsonTokenList());
3565     }
3566
3567     protected void _reportInvalidToken(String matchedPart, String msg) throws IOException
3568     {
3569         /* Let's just try to find what appears to be the token, using
3570          * regular Java identifier character rules. It's just a heuristic,
3571          * nothing fancy here (nor fast).
3572          */

3573         StringBuilder sb = new StringBuilder(matchedPart);
3574         while ((_inputPtr < _inputEnd) || _loadMore()) {
3575             int i = (int) _inputBuffer[_inputPtr++];
3576             char c = (char) _decodeCharForError(i);
3577             if (!Character.isJavaIdentifierPart(c)) {
3578                 // 11-Jan-2016, tatu: note: we will fully consume the character,
3579                 // included or not, so if recovery was possible, it'd be off-by-one...
3580                 break;
3581             }
3582             sb.append(c);
3583             if (sb.length() >= MAX_ERROR_TOKEN_LENGTH) {
3584                 sb.append("...");
3585                 break;
3586             }
3587         }
3588         _reportError("Unrecognized token '%s': was expecting %s", sb, msg);
3589     }
3590
3591     protected void _reportInvalidChar(int c) throws JsonParseException
3592     {
3593         // Either invalid WS or illegal UTF-8 start char
3594         if (c < INT_SPACE) {
3595             _throwInvalidSpace(c);
3596         }
3597         _reportInvalidInitial(c);
3598     }
3599
3600     protected void _reportInvalidInitial(int mask) throws JsonParseException {
3601         _reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask));
3602     }
3603
3604     protected void _reportInvalidOther(int mask) throws JsonParseException {
3605         _reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask));
3606     }
3607
3608     protected void _reportInvalidOther(int mask, int ptr)
3609         throws JsonParseException
3610     {
3611         _inputPtr = ptr;
3612         _reportInvalidOther(mask);
3613     }
3614
3615     /*
3616     /**********************************************************
3617     /* Internal methods, binary access
3618     /**********************************************************
3619      */

3620
3621     /**
3622      * Efficient handling for incremental parsing of base64-encoded
3623      * textual content.
3624      */

3625     @SuppressWarnings("resource")
3626     protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOException
3627     {
3628         ByteArrayBuilder builder = _getByteArrayBuilder();
3629
3630         while (true) {
3631             // first, we'll skip preceding white space, if any
3632             int ch;
3633             do {
3634                 if (_inputPtr >= _inputEnd) {
3635                     _loadMoreGuaranteed();
3636                 }
3637                 ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
3638             } while (ch <= INT_SPACE);
3639             int bits = b64variant.decodeBase64Char(ch);
3640             if (bits < 0) { // reached the end, fair and square?
3641                 if (ch == INT_QUOTE) {
3642                     return builder.toByteArray();
3643                 }
3644                 bits = _decodeBase64Escape(b64variant, ch, 0);
3645                 if (bits < 0) { // white space to skip
3646                     continue;
3647                 }
3648             }
3649             int decodedData = bits;
3650             
3651             // then second base64 char; can't get padding yet, nor ws
3652             
3653             if (_inputPtr >= _inputEnd) {
3654                 _loadMoreGuaranteed();
3655             }
3656             ch = _inputBuffer[_inputPtr++] & 0xFF;
3657             bits = b64variant.decodeBase64Char(ch);
3658             if (bits < 0) {
3659                 bits = _decodeBase64Escape(b64variant, ch, 1);
3660             }
3661             decodedData = (decodedData << 6) | bits;
3662             
3663             // third base64 char; can be padding, but not ws
3664             if (_inputPtr >= _inputEnd) {
3665                 _loadMoreGuaranteed();
3666             }
3667             ch = _inputBuffer[_inputPtr++] & 0xFF;
3668             bits = b64variant.decodeBase64Char(ch);
3669
3670             // First branch: can get padding (-> 1 byte)
3671             if (bits < 0) {
3672                 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
3673                     // could also just be 'missing'  padding
3674                     if (ch == INT_QUOTE) {
3675                         decodedData >>= 4;
3676                         builder.append(decodedData);
3677                         if (b64variant.usesPadding()) {
3678                             --_inputPtr; // to keep parser state bit more consistent
3679                             _handleBase64MissingPadding(b64variant);
3680                         }
3681                         return builder.toByteArray();
3682                     }
3683                     bits = _decodeBase64Escape(b64variant, ch, 2);
3684                 }
3685                 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
3686                     // Ok, must get padding
3687                     if (_inputPtr >= _inputEnd) {
3688                         _loadMoreGuaranteed();
3689                     }
3690                     ch = _inputBuffer[_inputPtr++] & 0xFF;
3691                     if (!b64variant.usesPaddingChar(ch)) {
3692                         if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) {
3693                             throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
3694                         }
3695                     }
3696                     // Got 12 bits, only need 8, need to shift
3697                     decodedData >>= 4;
3698                     builder.append(decodedData);
3699                     continue;
3700                 }
3701             }
3702             // Nope, 2 or 3 bytes
3703             decodedData = (decodedData << 6) | bits;
3704             // fourth and last base64 char; can be padding, but not ws
3705             if (_inputPtr >= _inputEnd) {
3706                 _loadMoreGuaranteed();
3707             }
3708             ch = _inputBuffer[_inputPtr++] & 0xFF;
3709             bits = b64variant.decodeBase64Char(ch);
3710             if (bits < 0) {
3711                 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
3712                     // could also just be 'missing'  padding
3713                     if (ch == INT_QUOTE) {
3714                         decodedData >>= 2;
3715                         builder.appendTwoBytes(decodedData);
3716                         if (b64variant.usesPadding()) {
3717                             --_inputPtr; // to keep parser state bit more consistent
3718                             _handleBase64MissingPadding(b64variant);
3719                         }
3720                         return builder.toByteArray();
3721                     }
3722                     bits = _decodeBase64Escape(b64variant, ch, 3);
3723                 }
3724                 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
3725                     // With padding we only get 2 bytes; but we have to shift it
3726                     // a bit so it is identical to triplet case with partial output.
3727                     // 3 chars gives 3x6 == 18 bits, of which 2 are dummies, need to discard:
3728                     decodedData >>= 2;
3729                     builder.appendTwoBytes(decodedData);
3730                     continue;
3731                 }
3732             }
3733             // otherwise, our triplet is now complete
3734             decodedData = (decodedData << 6) | bits;
3735             builder.appendThreeBytes(decodedData);
3736         }
3737     }
3738
3739     /*
3740     /**********************************************************
3741     /* Improved location updating (refactored in 2.7)
3742     /**********************************************************
3743      */

3744
3745     // As per [core#108], must ensure we call the right method
3746     @Override
3747     public JsonLocation getTokenLocation()
3748     {
3749         if (_currToken == JsonToken.FIELD_NAME) {
3750             long total = _currInputProcessed + (_nameStartOffset-1);
3751             return new JsonLocation(_getSourceReference(),
3752                     total, -1L, _nameStartRow, _nameStartCol);
3753         }
3754         return new JsonLocation(_getSourceReference(),
3755                 _tokenInputTotal-1, -1L, _tokenInputRow, _tokenInputCol);
3756     }
3757
3758     // As per [core#108], must ensure we call the right method
3759     @Override
3760     public JsonLocation getCurrentLocation()
3761     {
3762         int col = _inputPtr - _currInputRowStart + 1; // 1-based
3763         return new JsonLocation(_getSourceReference(),
3764                 _currInputProcessed + _inputPtr, -1L, // bytes, chars
3765                 _currInputRow, col);
3766     }
3767
3768     // @since 2.7
3769     private final void _updateLocation()
3770     {
3771         _tokenInputRow = _currInputRow;
3772         final int ptr = _inputPtr;
3773         _tokenInputTotal = _currInputProcessed + ptr;
3774         _tokenInputCol = ptr - _currInputRowStart;
3775     }
3776
3777     // @since 2.7
3778     private final void _updateNameLocation()
3779     {
3780         _nameStartRow = _currInputRow;
3781         final int ptr = _inputPtr;
3782         _nameStartOffset = ptr;
3783         _nameStartCol = ptr - _currInputRowStart;
3784     }
3785
3786     /*
3787     /**********************************************************
3788     /* Internal methods, other
3789     /**********************************************************
3790      */

3791
3792     private final JsonToken _closeScope(int i) throws JsonParseException {
3793         if (i == INT_RCURLY) {
3794             _closeObjectScope();
3795             return (_currToken = JsonToken.END_OBJECT);
3796         }
3797         _closeArrayScope();
3798         return (_currToken = JsonToken.END_ARRAY);
3799     }
3800
3801     private final void _closeArrayScope() throws JsonParseException {
3802         _updateLocation();
3803         if (!_parsingContext.inArray()) {
3804             _reportMismatchedEndMarker(']', '}');
3805         }
3806         _parsingContext = _parsingContext.clearAndGetParent();
3807     }
3808
3809     private final void _closeObjectScope() throws JsonParseException {
3810         _updateLocation();
3811         if (!_parsingContext.inObject()) {
3812             _reportMismatchedEndMarker('}', ']');
3813         }
3814         _parsingContext = _parsingContext.clearAndGetParent();
3815     }
3816 }
3817