1 package com.fasterxml.jackson.core.base;
2 
3 import java.io.*;
4 import java.math.BigDecimal;
5 import java.math.BigInteger;
6 import java.util.Arrays;
7 
8 import com.fasterxml.jackson.core.*;
9 import com.fasterxml.jackson.core.JsonParser.Feature;
10 import com.fasterxml.jackson.core.io.IOContext;
11 import com.fasterxml.jackson.core.io.NumberInput;
12 import com.fasterxml.jackson.core.json.DupDetector;
13 import com.fasterxml.jackson.core.json.JsonReadContext;
14 import com.fasterxml.jackson.core.json.PackageVersion;
15 import com.fasterxml.jackson.core.util.ByteArrayBuilder;
16 import com.fasterxml.jackson.core.util.JacksonFeatureSet;
17 import com.fasterxml.jackson.core.util.TextBuffer;
18 
19 /**
20  * Intermediate base class used by all Jackson {@link JsonParser}
21  * implementations. Contains most common things that are independent
22  * of actual underlying input source.
23  */
24 public abstract class ParserBase extends ParserMinimalBase
25 {
26     // JSON capabilities are the same as defaults
27     // @since 2.12
28     protected final static JacksonFeatureSet<StreamReadCapability> JSON_READ_CAPABILITIES
29         = DEFAULT_READ_CAPABILITIES;
30 
31     /*
32     /**********************************************************
33     /* Generic I/O state
34     /**********************************************************
35      */
36 
37     /**
38      * I/O context for this reader. It handles buffer allocation
39      * for the reader.
40      */
41     final protected IOContext _ioContext;
42 
43     /**
44      * Flag that indicates whether parser is closed or not. Gets
45      * set when parser is either closed by explicit call
46      * ({@link #close}) or when end-of-input is reached.
47      */
48     protected boolean _closed;
49 
50     /*
51     /**********************************************************
52     /* Current input data
53     /**********************************************************
54      */
55 
56     // Note: type of actual buffer depends on sub-class, can't include
57 
58     /**
59      * Pointer to next available character in buffer
60      */
61     protected int _inputPtr;
62 
63     /**
64      * Index of character after last available one in the buffer.
65      */
66     protected int _inputEnd;
67 
68     /*
69     /**********************************************************
70     /* Current input location information
71     /**********************************************************
72      */
73 
74     /**
75      * Number of characters/bytes that were contained in previous blocks
76      * (blocks that were already processed prior to the current buffer).
77      */
78     protected long _currInputProcessed;
79 
80     /**
81      * Current row location of current point in input buffer, starting
82      * from 1, if available.
83      */
84     protected int _currInputRow = 1;
85 
86     /**
87      * Current index of the first character of the current row in input
88      * buffer. Needed to calculate column position, if necessary; benefit
89      * of not having column itself is that this only has to be updated
90      * once per line.
91      */
92     protected int _currInputRowStart;
93 
94     /*
95     /**********************************************************
96     /* Information about starting location of event
97     /* Reader is pointing to; updated on-demand
98     /**********************************************************
99      */
100 
101     // // // Location info at point when current token was started
102 
103     /**
104      * Total number of bytes/characters read before start of current token.
105      * For big (gigabyte-sized) sizes are possible, needs to be long,
106      * unlike pointers and sizes related to in-memory buffers.
107      */
108     protected long _tokenInputTotal;
109 
110     /**
111      * Input row on which current token starts, 1-based
112      */
113     protected int _tokenInputRow = 1;
114 
115     /**
116      * Column on input row that current token starts; 0-based (although
117      * in the end it'll be converted to 1-based)
118      */
119     protected int _tokenInputCol;
120 
121     /*
122     /**********************************************************
123     /* Parsing state
124     /**********************************************************
125      */
126 
127     /**
128      * Information about parser context, context in which
129      * the next token is to be parsed (root, array, object).
130      */
131     protected JsonReadContext _parsingContext;
132 
133     /**
134      * Secondary token related to the next token after current one;
135      * used if its type is known. This may be value token that
136      * follows FIELD_NAME, for example.
137      */
138     protected JsonToken _nextToken;
139 
140     /*
141     /**********************************************************
142     /* Buffer(s) for local name(s) and text content
143     /**********************************************************
144      */
145 
146     /**
147      * Buffer that contains contents of String values, including
148      * field names if necessary (name split across boundary,
149      * contains escape sequence, or access needed to char array)
150      */
151     protected final TextBuffer _textBuffer;
152 
153     /**
154      * Temporary buffer that is needed if field name is accessed
155      * using {@link #getTextCharacters} method (instead of String
156      * returning alternatives)
157      */
158     protected char[] _nameCopyBuffer;
159 
160     /**
161      * Flag set to indicate whether the field name is available
162      * from the name copy buffer or not (in addition to its String
163      * representation  being available via read context)
164      */
165     protected boolean _nameCopied;
166 
167     /**
168      * ByteArrayBuilder is needed if 'getBinaryValue' is called. If so,
169      * we better reuse it for remainder of content.
170      */
171     protected ByteArrayBuilder _byteArrayBuilder;
172 
173     /**
174      * We will hold on to decoded binary data, for duration of
175      * current event, so that multiple calls to
176      * {@link #getBinaryValue} will not need to decode data more
177      * than once.
178      */
179     protected byte[] _binaryValue;
180 
181     // Numeric value holders: multiple fields used for
182     // for efficiency
183 
184     /**
185      * Bitfield that indicates which numeric representations
186      * have been calculated for the current type
187      */
188     protected int _numTypesValid = NR_UNKNOWN;
189 
190     // First primitives
191 
192     protected int _numberInt;
193 
194     protected long _numberLong;
195 
196     protected double _numberDouble;
197 
198     // And then object types
199 
200     protected BigInteger _numberBigInt;
201 
202     protected BigDecimal _numberBigDecimal;
203 
204     // And then other information about value itself
205 
206     /**
207      * Flag that indicates whether numeric value has a negative
208      * value. That is, whether its textual representation starts
209      * with minus character.
210      */
211     protected boolean _numberNegative;
212 
213     /**
214      * Length of integer part of the number, in characters
215      */
216     protected int _intLength;
217 
218     /**
219      * Length of the fractional part (not including decimal
220      * point or exponent), in characters.
221      * Not used for  pure integer values.
222      */
223     protected int _fractLength;
224 
225     /**
226      * Length of the exponent part of the number, if any, not
227      * including 'e' marker or sign, just digits.
228      * Not used for  pure integer values.
229      */
230     protected int _expLength;
231 
232     /*
233     /**********************************************************
234     /* Life-cycle
235     /**********************************************************
236      */
237 
ParserBase(IOContext ctxt, int features)238     protected ParserBase(IOContext ctxt, int features) {
239         super(features);
240         _ioContext = ctxt;
241         _textBuffer = ctxt.constructTextBuffer();
242         DupDetector dups = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features)
243                 ? DupDetector.rootDetector(this) : null;
244         _parsingContext = JsonReadContext.createRootContext(dups);
245     }
246 
version()247     @Override public Version version() { return PackageVersion.VERSION; }
248 
249     @Override
getCurrentValue()250     public Object getCurrentValue() {
251         return _parsingContext.getCurrentValue();
252     }
253 
254     @Override
setCurrentValue(Object v)255     public void setCurrentValue(Object v) {
256         _parsingContext.setCurrentValue(v);
257     }
258 
259     /*
260     /**********************************************************
261     /* Overrides for Feature handling
262     /**********************************************************
263      */
264 
265     @Override
enable(Feature f)266     public JsonParser enable(Feature f) {
267         _features |= f.getMask();
268         if (f == Feature.STRICT_DUPLICATE_DETECTION) { // enabling dup detection?
269             if (_parsingContext.getDupDetector() == null) { // but only if disabled currently
270                 _parsingContext = _parsingContext.withDupDetector(DupDetector.rootDetector(this));
271             }
272         }
273         return this;
274     }
275 
276     @Override
disable(Feature f)277     public JsonParser disable(Feature f) {
278         _features &= ~f.getMask();
279         if (f == Feature.STRICT_DUPLICATE_DETECTION) {
280             _parsingContext = _parsingContext.withDupDetector(null);
281         }
282         return this;
283     }
284 
285     @Override
286     @Deprecated
setFeatureMask(int newMask)287     public JsonParser setFeatureMask(int newMask) {
288         int changes = (_features ^ newMask);
289         if (changes != 0) {
290             _features = newMask;
291             _checkStdFeatureChanges(newMask, changes);
292         }
293         return this;
294     }
295 
296     @Override // since 2.7
overrideStdFeatures(int values, int mask)297     public JsonParser overrideStdFeatures(int values, int mask) {
298         int oldState = _features;
299         int newState = (oldState & ~mask) | (values & mask);
300         int changed = oldState ^ newState;
301         if (changed != 0) {
302             _features = newState;
303             _checkStdFeatureChanges(newState, changed);
304         }
305         return this;
306     }
307 
308     /**
309      * Helper method called to verify changes to standard features.
310      *
311      * @param newFeatureFlags Bitflag of standard features after they were changed
312      * @param changedFeatures Bitflag of standard features for which setting
313      *    did change
314      *
315      * @since 2.7
316      */
_checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)317     protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
318     {
319         int f = Feature.STRICT_DUPLICATE_DETECTION.getMask();
320 
321         if ((changedFeatures & f) != 0) {
322             if ((newFeatureFlags & f) != 0) {
323                 if (_parsingContext.getDupDetector() == null) {
324                     _parsingContext = _parsingContext.withDupDetector(DupDetector.rootDetector(this));
325                 } else { // disabling
326                     _parsingContext = _parsingContext.withDupDetector(null);
327                 }
328             }
329         }
330     }
331 
332     /*
333     /**********************************************************
334     /* JsonParser impl
335     /**********************************************************
336      */
337 
338     /**
339      * Method that can be called to get the name associated with
340      * the current event.
341      */
getCurrentName()342     @Override public String getCurrentName() throws IOException {
343         // [JACKSON-395]: start markers require information from parent
344         if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
345             JsonReadContext parent = _parsingContext.getParent();
346             if (parent != null) {
347                 return parent.getCurrentName();
348             }
349         }
350         return _parsingContext.getCurrentName();
351     }
352 
overrideCurrentName(String name)353     @Override public void overrideCurrentName(String name) {
354         // Simple, but need to look for START_OBJECT/ARRAY's "off-by-one" thing:
355         JsonReadContext ctxt = _parsingContext;
356         if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
357             ctxt = ctxt.getParent();
358         }
359         // 24-Sep-2013, tatu: Unfortunate, but since we did not expose exceptions,
360         //   need to wrap this here
361         try {
362             ctxt.setCurrentName(name);
363         } catch (IOException e) {
364             throw new IllegalStateException(e);
365         }
366     }
367 
close()368     @Override public void close() throws IOException {
369         if (!_closed) {
370             // 19-Jan-2018, tatu: as per [core#440] need to ensure no more data assumed available
371             _inputPtr = Math.max(_inputPtr, _inputEnd);
372             _closed = true;
373             try {
374                 _closeInput();
375             } finally {
376                 // as per [JACKSON-324], do in finally block
377                 // Also, internal buffer(s) can now be released as well
378                 _releaseBuffers();
379             }
380         }
381     }
382 
isClosed()383     @Override public boolean isClosed() { return _closed; }
getParsingContext()384     @Override public JsonReadContext getParsingContext() { return _parsingContext; }
385 
386     /**
387      * Method that return the <b>starting</b> location of the current
388      * token; that is, position of the first character from input
389      * that starts the current token.
390      */
391     @Override
getTokenLocation()392     public JsonLocation getTokenLocation() {
393         return new JsonLocation(_getSourceReference(),
394                 -1L, getTokenCharacterOffset(), // bytes, chars
395                 getTokenLineNr(),
396                 getTokenColumnNr());
397     }
398 
399     /**
400      * Method that returns location of the last processed character;
401      * usually for error reporting purposes
402      */
403     @Override
getCurrentLocation()404     public JsonLocation getCurrentLocation() {
405         int col = _inputPtr - _currInputRowStart + 1; // 1-based
406         return new JsonLocation(_getSourceReference(),
407                 -1L, _currInputProcessed + _inputPtr, // bytes, chars
408                 _currInputRow, col);
409     }
410 
411     /*
412     /**********************************************************
413     /* Public API, access to token information, text and similar
414     /**********************************************************
415      */
416 
417     @Override
hasTextCharacters()418     public boolean hasTextCharacters() {
419         if (_currToken == JsonToken.VALUE_STRING) { return true; } // usually true
420         if (_currToken == JsonToken.FIELD_NAME) { return _nameCopied; }
421         return false;
422     }
423 
424     @SuppressWarnings("resource")
425     @Override // since 2.7
getBinaryValue(Base64Variant variant)426     public byte[] getBinaryValue(Base64Variant variant) throws IOException
427     {
428         if (_binaryValue == null) {
429             if (_currToken != JsonToken.VALUE_STRING) {
430                 _reportError("Current token ("+_currToken+") not VALUE_STRING, can not access as binary");
431             }
432             ByteArrayBuilder builder = _getByteArrayBuilder();
433             _decodeBase64(getText(), builder, variant);
434             _binaryValue = builder.toByteArray();
435         }
436         return _binaryValue;
437     }
438 
439     /*
440     /**********************************************************
441     /* Public low-level accessors
442     /**********************************************************
443      */
444 
getTokenCharacterOffset()445     public long getTokenCharacterOffset() { return _tokenInputTotal; }
getTokenLineNr()446     public int getTokenLineNr() { return _tokenInputRow; }
getTokenColumnNr()447     public int getTokenColumnNr() {
448         // note: value of -1 means "not available"; otherwise convert from 0-based to 1-based
449         int col = _tokenInputCol;
450         return (col < 0) ? col : (col + 1);
451     }
452 
453     /*
454     /**********************************************************
455     /* Abstract methods for sub-classes to implement
456     /**********************************************************
457      */
458 
_closeInput()459     protected abstract void _closeInput() throws IOException;
460 
461     /*
462     /**********************************************************
463     /* Low-level reading, other
464     /**********************************************************
465      */
466 
467     /**
468      * Method called to release internal buffers owned by the base
469      * reader. This may be called along with {@link #_closeInput} (for
470      * example, when explicitly closing this reader instance), or
471      * separately (if need be).
472      */
_releaseBuffers()473     protected void _releaseBuffers() throws IOException {
474         _textBuffer.releaseBuffers();
475         char[] buf = _nameCopyBuffer;
476         if (buf != null) {
477             _nameCopyBuffer = null;
478             _ioContext.releaseNameCopyBuffer(buf);
479         }
480     }
481 
482     /**
483      * Method called when an EOF is encountered between tokens.
484      * If so, it may be a legitimate EOF, but only iff there
485      * is no open non-root context.
486      */
487     @Override
_handleEOF()488     protected void _handleEOF() throws JsonParseException {
489         if (!_parsingContext.inRoot()) {
490             String marker = _parsingContext.inArray() ? "Array" : "Object";
491             _reportInvalidEOF(String.format(
492                     ": expected close marker for %s (start marker at %s)",
493                     marker,
494                     _parsingContext.getStartLocation(_getSourceReference())),
495                     null);
496         }
497     }
498 
499     /**
500      * @since 2.4
501      */
_eofAsNextChar()502     protected final int _eofAsNextChar() throws JsonParseException {
503         _handleEOF();
504         return -1;
505     }
506 
507     /*
508     /**********************************************************
509     /* Internal/package methods: shared/reusable builders
510     /**********************************************************
511      */
512 
_getByteArrayBuilder()513     public ByteArrayBuilder _getByteArrayBuilder()
514     {
515         if (_byteArrayBuilder == null) {
516             _byteArrayBuilder = new ByteArrayBuilder();
517         } else {
518             _byteArrayBuilder.reset();
519         }
520         return _byteArrayBuilder;
521     }
522 
523     /*
524     /**********************************************************
525     /* Methods from former JsonNumericParserBase
526     /**********************************************************
527      */
528 
529     // // // Life-cycle of number-parsing
530 
reset(boolean negative, int intLen, int fractLen, int expLen)531     protected final JsonToken reset(boolean negative, int intLen, int fractLen, int expLen)
532     {
533         if (fractLen < 1 && expLen < 1) { // integer
534             return resetInt(negative, intLen);
535         }
536         return resetFloat(negative, intLen, fractLen, expLen);
537     }
538 
resetInt(boolean negative, int intLen)539     protected final JsonToken resetInt(boolean negative, int intLen)
540     {
541         _numberNegative = negative;
542         _intLength = intLen;
543         _fractLength = 0;
544         _expLength = 0;
545         _numTypesValid = NR_UNKNOWN; // to force parsing
546         return JsonToken.VALUE_NUMBER_INT;
547     }
548 
resetFloat(boolean negative, int intLen, int fractLen, int expLen)549     protected final JsonToken resetFloat(boolean negative, int intLen, int fractLen, int expLen)
550     {
551         _numberNegative = negative;
552         _intLength = intLen;
553         _fractLength = fractLen;
554         _expLength = expLen;
555         _numTypesValid = NR_UNKNOWN; // to force parsing
556         return JsonToken.VALUE_NUMBER_FLOAT;
557     }
558 
resetAsNaN(String valueStr, double value)559     protected final JsonToken resetAsNaN(String valueStr, double value)
560     {
561         _textBuffer.resetWithString(valueStr);
562         _numberDouble = value;
563         _numTypesValid = NR_DOUBLE;
564         return JsonToken.VALUE_NUMBER_FLOAT;
565     }
566 
567     @Override
isNaN()568     public boolean isNaN() {
569         if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) {
570             if ((_numTypesValid & NR_DOUBLE) != 0) {
571                 // 10-Mar-2017, tatu: Alas, `Double.isFinite(d)` only added in JDK 8
572                 double d = _numberDouble;
573                 return Double.isNaN(d) || Double.isInfinite(d);
574             }
575         }
576         return false;
577     }
578 
579     /*
580     /**********************************************************
581     /* Numeric accessors of public API
582     /**********************************************************
583      */
584 
585     @Override
getNumberValue()586     public Number getNumberValue() throws IOException
587     {
588         if (_numTypesValid == NR_UNKNOWN) {
589             _parseNumericValue(NR_UNKNOWN); // will also check event type
590         }
591         // Separate types for int types
592         if (_currToken == JsonToken.VALUE_NUMBER_INT) {
593             if ((_numTypesValid & NR_INT) != 0) {
594                 return _numberInt;
595             }
596             if ((_numTypesValid & NR_LONG) != 0) {
597                 return _numberLong;
598             }
599             if ((_numTypesValid & NR_BIGINT) != 0) {
600                 return _numberBigInt;
601             }
602             _throwInternal();
603         }
604 
605         // And then floating point types. But here optimal type
606         // needs to be big decimal, to avoid losing any data?
607         if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
608             return _numberBigDecimal;
609         }
610         if ((_numTypesValid & NR_DOUBLE) == 0) { // sanity check
611             _throwInternal();
612         }
613         return _numberDouble;
614     }
615 
616     // NOTE: mostly copied from above
617     @Override
getNumberValueExact()618     public Number getNumberValueExact() throws IOException
619     {
620         if (_currToken == JsonToken.VALUE_NUMBER_INT) {
621             if (_numTypesValid == NR_UNKNOWN) {
622                 _parseNumericValue(NR_UNKNOWN);
623             }
624             if ((_numTypesValid & NR_INT) != 0) {
625                 return _numberInt;
626             }
627             if ((_numTypesValid & NR_LONG) != 0) {
628                 return _numberLong;
629             }
630             if ((_numTypesValid & NR_BIGINT) != 0) {
631                 return _numberBigInt;
632             }
633             _throwInternal();
634         }
635         // 09-Jul-2020, tatu: [databind#2644] requires we will retain accuracy, so:
636         if (_numTypesValid == NR_UNKNOWN) {
637             _parseNumericValue(NR_BIGDECIMAL);
638         }
639         if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
640             return _numberBigDecimal;
641         }
642         if ((_numTypesValid & NR_DOUBLE) == 0) { // sanity check
643             _throwInternal();
644         }
645         return _numberDouble;
646     }
647 
648     @Override
getNumberType()649     public NumberType getNumberType() throws IOException
650     {
651         if (_numTypesValid == NR_UNKNOWN) {
652             _parseNumericValue(NR_UNKNOWN); // will also check event type
653         }
654         if (_currToken == JsonToken.VALUE_NUMBER_INT) {
655             if ((_numTypesValid & NR_INT) != 0) {
656                 return NumberType.INT;
657             }
658             if ((_numTypesValid & NR_LONG) != 0) {
659                 return NumberType.LONG;
660             }
661             return NumberType.BIG_INTEGER;
662         }
663 
664         /* And then floating point types. Here optimal type
665          * needs to be big decimal, to avoid losing any data?
666          * However... using BD is slow, so let's allow returning
667          * double as type if no explicit call has been made to access
668          * data as BD?
669          */
670         if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
671             return NumberType.BIG_DECIMAL;
672         }
673         return NumberType.DOUBLE;
674     }
675 
676     @Override
getIntValue()677     public int getIntValue() throws IOException
678     {
679         if ((_numTypesValid & NR_INT) == 0) {
680             if (_numTypesValid == NR_UNKNOWN) { // not parsed at all
681                 return _parseIntValue();
682             }
683             if ((_numTypesValid & NR_INT) == 0) { // wasn't an int natively?
684                 convertNumberToInt(); // let's make it so, if possible
685             }
686         }
687         return _numberInt;
688     }
689 
690     @Override
getLongValue()691     public long getLongValue() throws IOException
692     {
693         if ((_numTypesValid & NR_LONG) == 0) {
694             if (_numTypesValid == NR_UNKNOWN) {
695                 _parseNumericValue(NR_LONG);
696             }
697             if ((_numTypesValid & NR_LONG) == 0) {
698                 convertNumberToLong();
699             }
700         }
701         return _numberLong;
702     }
703 
704     @Override
getBigIntegerValue()705     public BigInteger getBigIntegerValue() throws IOException
706     {
707         if ((_numTypesValid & NR_BIGINT) == 0) {
708             if (_numTypesValid == NR_UNKNOWN) {
709                 _parseNumericValue(NR_BIGINT);
710             }
711             if ((_numTypesValid & NR_BIGINT) == 0) {
712                 convertNumberToBigInteger();
713             }
714         }
715         return _numberBigInt;
716     }
717 
718     @Override
getFloatValue()719     public float getFloatValue() throws IOException
720     {
721         double value = getDoubleValue();
722         /* 22-Jan-2009, tatu: Bounds/range checks would be tricky
723          *   here, so let's not bother even trying...
724          */
725         /*
726         if (value < -Float.MAX_VALUE || value > MAX_FLOAT_D) {
727             _reportError("Numeric value ("+getText()+") out of range of Java float");
728         }
729         */
730         return (float) value;
731     }
732 
733     @Override
getDoubleValue()734     public double getDoubleValue() throws IOException
735     {
736         if ((_numTypesValid & NR_DOUBLE) == 0) {
737             if (_numTypesValid == NR_UNKNOWN) {
738                 _parseNumericValue(NR_DOUBLE);
739             }
740             if ((_numTypesValid & NR_DOUBLE) == 0) {
741                 convertNumberToDouble();
742             }
743         }
744         return _numberDouble;
745     }
746 
747     @Override
getDecimalValue()748     public BigDecimal getDecimalValue() throws IOException
749     {
750         if ((_numTypesValid & NR_BIGDECIMAL) == 0) {
751             if (_numTypesValid == NR_UNKNOWN) {
752                 _parseNumericValue(NR_BIGDECIMAL);
753             }
754             if ((_numTypesValid & NR_BIGDECIMAL) == 0) {
755                 convertNumberToBigDecimal();
756             }
757         }
758         return _numberBigDecimal;
759     }
760 
761     /*
762     /**********************************************************
763     /* Conversion from textual to numeric representation
764     /**********************************************************
765      */
766 
767     /**
768      * Method that will parse actual numeric value out of a syntactically
769      * valid number value. Type it will parse into depends on whether
770      * it is a floating point number, as well as its magnitude: smallest
771      * legal type (of ones available) is used for efficiency.
772      *
773      * @param expType Numeric type that we will immediately need, if any;
774      *   mostly necessary to optimize handling of floating point numbers
775      */
_parseNumericValue(int expType)776     protected void _parseNumericValue(int expType) throws IOException
777     {
778         // 12-Jun-2020, tatu: Sanity check to prevent more cryptic error for this case.
779         //    (note: could alternatively see if TextBuffer has aggregated contents, avoid
780         //    exception -- but that might be more confusing)
781         if (_closed) {
782             _reportError("Internal error: _parseNumericValue called when parser instance closed");
783         }
784 
785         // Int or float?
786         if (_currToken == JsonToken.VALUE_NUMBER_INT) {
787             final int len = _intLength;
788             // First: optimization for simple int
789             if (len <= 9) {
790                 int i = _textBuffer.contentsAsInt(_numberNegative);
791                 _numberInt = i;
792                 _numTypesValid = NR_INT;
793                 return;
794             }
795             if (len <= 18) { // definitely fits AND is easy to parse using 2 int parse calls
796                 long l = _textBuffer.contentsAsLong(_numberNegative);
797                 // Might still fit in int, need to check
798                 if (len == 10) {
799                     if (_numberNegative) {
800                         if (l >= MIN_INT_L) {
801                             _numberInt = (int) l;
802                             _numTypesValid = NR_INT;
803                             return;
804                         }
805                     } else {
806                         if (l <= MAX_INT_L) {
807                             _numberInt = (int) l;
808                             _numTypesValid = NR_INT;
809                             return;
810                         }
811                     }
812                 }
813                 _numberLong = l;
814                 _numTypesValid = NR_LONG;
815                 return;
816             }
817             _parseSlowInt(expType);
818             return;
819         }
820         if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) {
821             _parseSlowFloat(expType);
822             return;
823         }
824         _reportError("Current token (%s) not numeric, can not use numeric value accessors", _currToken);
825     }
826 
827     /**
828      * @since 2.6
829      */
_parseIntValue()830     protected int _parseIntValue() throws IOException
831     {
832         // 12-Jun-2020, tatu: Sanity check to prevent more cryptic error for this case.
833         //    (note: could alternatively see if TextBuffer has aggregated contents, avoid
834         //    exception -- but that might be more confusing)
835         if (_closed) {
836             _reportError("Internal error: _parseNumericValue called when parser instance closed");
837         }
838         // Inlined variant of: _parseNumericValue(NR_INT)
839         if (_currToken == JsonToken.VALUE_NUMBER_INT) {
840             if (_intLength <= 9) {
841                 int i = _textBuffer.contentsAsInt(_numberNegative);
842                 _numberInt = i;
843                 _numTypesValid = NR_INT;
844                 return i;
845             }
846         }
847         // if not optimizable, use more generic
848         _parseNumericValue(NR_INT);
849         if ((_numTypesValid & NR_INT) == 0) {
850             convertNumberToInt();
851         }
852         return _numberInt;
853     }
854 
_parseSlowFloat(int expType)855     private void _parseSlowFloat(int expType) throws IOException
856     {
857         /* Nope: floating point. Here we need to be careful to get
858          * optimal parsing strategy: choice is between accurate but
859          * slow (BigDecimal) and lossy but fast (Double). For now
860          * let's only use BD when explicitly requested -- it can
861          * still be constructed correctly at any point since we do
862          * retain textual representation
863          */
864         try {
865             if (expType == NR_BIGDECIMAL) {
866                 _numberBigDecimal = _textBuffer.contentsAsDecimal();
867                 _numTypesValid = NR_BIGDECIMAL;
868             } else {
869                 // Otherwise double has to do
870                 _numberDouble = _textBuffer.contentsAsDouble();
871                 _numTypesValid = NR_DOUBLE;
872             }
873         } catch (NumberFormatException nex) {
874             // Can this ever occur? Due to overflow, maybe?
875             _wrapError("Malformed numeric value ("+_longNumberDesc(_textBuffer.contentsAsString())+")", nex);
876         }
877     }
878 
_parseSlowInt(int expType)879     private void _parseSlowInt(int expType) throws IOException
880     {
881         String numStr = _textBuffer.contentsAsString();
882         try {
883             int len = _intLength;
884             char[] buf = _textBuffer.getTextBuffer();
885             int offset = _textBuffer.getTextOffset();
886             if (_numberNegative) {
887                 ++offset;
888             }
889             // Some long cases still...
890             if (NumberInput.inLongRange(buf, offset, len, _numberNegative)) {
891                 // Probably faster to construct a String, call parse, than to use BigInteger
892                 _numberLong = Long.parseLong(numStr);
893                 _numTypesValid = NR_LONG;
894             } else {
895                 // 16-Oct-2018, tatu: Need to catch "too big" early due to [jackson-core#488]
896                 if ((expType == NR_INT) || (expType == NR_LONG)) {
897                     _reportTooLongIntegral(expType, numStr);
898                 }
899                 if ((expType == NR_DOUBLE) || (expType == NR_FLOAT)) {
900                     _numberDouble = NumberInput.parseDouble(numStr);
901                     _numTypesValid = NR_DOUBLE;
902                 } else {
903                     // nope, need the heavy guns... (rare case)
904                     _numberBigInt = new BigInteger(numStr);
905                     _numTypesValid = NR_BIGINT;
906                 }
907             }
908         } catch (NumberFormatException nex) {
909             // Can this ever occur? Due to overflow, maybe?
910             _wrapError("Malformed numeric value ("+_longNumberDesc(numStr)+")", nex);
911         }
912     }
913 
914     // @since 2.9.8
_reportTooLongIntegral(int expType, String rawNum)915     protected void _reportTooLongIntegral(int expType, String rawNum) throws IOException
916     {
917         if (expType == NR_INT) {
918             reportOverflowInt(rawNum);
919         } else {
920             reportOverflowLong(rawNum);
921         }
922     }
923 
924     /*
925     /**********************************************************
926     /* Numeric conversions
927     /**********************************************************
928      */
929 
convertNumberToInt()930     protected void convertNumberToInt() throws IOException
931     {
932         // First, converting from long ought to be easy
933         if ((_numTypesValid & NR_LONG) != 0) {
934             // Let's verify it's lossless conversion by simple roundtrip
935             int result = (int) _numberLong;
936             if (((long) result) != _numberLong) {
937                 reportOverflowInt(getText(), currentToken());
938             }
939             _numberInt = result;
940         } else if ((_numTypesValid & NR_BIGINT) != 0) {
941             if (BI_MIN_INT.compareTo(_numberBigInt) > 0
942                     || BI_MAX_INT.compareTo(_numberBigInt) < 0) {
943                 reportOverflowInt();
944             }
945             _numberInt = _numberBigInt.intValue();
946         } else if ((_numTypesValid & NR_DOUBLE) != 0) {
947             // Need to check boundaries
948             if (_numberDouble < MIN_INT_D || _numberDouble > MAX_INT_D) {
949                 reportOverflowInt();
950             }
951             _numberInt = (int) _numberDouble;
952         } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
953             if (BD_MIN_INT.compareTo(_numberBigDecimal) > 0
954                 || BD_MAX_INT.compareTo(_numberBigDecimal) < 0) {
955                 reportOverflowInt();
956             }
957             _numberInt = _numberBigDecimal.intValue();
958         } else {
959             _throwInternal();
960         }
961         _numTypesValid |= NR_INT;
962     }
963 
convertNumberToLong()964     protected void convertNumberToLong() throws IOException
965     {
966         if ((_numTypesValid & NR_INT) != 0) {
967             _numberLong = (long) _numberInt;
968         } else if ((_numTypesValid & NR_BIGINT) != 0) {
969             if (BI_MIN_LONG.compareTo(_numberBigInt) > 0
970                     || BI_MAX_LONG.compareTo(_numberBigInt) < 0) {
971                 reportOverflowLong();
972             }
973             _numberLong = _numberBigInt.longValue();
974         } else if ((_numTypesValid & NR_DOUBLE) != 0) {
975             // Need to check boundaries
976             if (_numberDouble < MIN_LONG_D || _numberDouble > MAX_LONG_D) {
977                 reportOverflowLong();
978             }
979             _numberLong = (long) _numberDouble;
980         } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
981             if (BD_MIN_LONG.compareTo(_numberBigDecimal) > 0
982                 || BD_MAX_LONG.compareTo(_numberBigDecimal) < 0) {
983                 reportOverflowLong();
984             }
985             _numberLong = _numberBigDecimal.longValue();
986         } else {
987             _throwInternal();
988         }
989         _numTypesValid |= NR_LONG;
990     }
991 
convertNumberToBigInteger()992     protected void convertNumberToBigInteger() throws IOException
993     {
994         if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
995             // here it'll just get truncated, no exceptions thrown
996             _numberBigInt = _numberBigDecimal.toBigInteger();
997         } else if ((_numTypesValid & NR_LONG) != 0) {
998             _numberBigInt = BigInteger.valueOf(_numberLong);
999         } else if ((_numTypesValid & NR_INT) != 0) {
1000             _numberBigInt = BigInteger.valueOf(_numberInt);
1001         } else if ((_numTypesValid & NR_DOUBLE) != 0) {
1002             _numberBigInt = BigDecimal.valueOf(_numberDouble).toBigInteger();
1003         } else {
1004             _throwInternal();
1005         }
1006         _numTypesValid |= NR_BIGINT;
1007     }
1008 
convertNumberToDouble()1009     protected void convertNumberToDouble() throws IOException
1010     {
1011         /* 05-Aug-2008, tatus: Important note: this MUST start with
1012          *   more accurate representations, since we don't know which
1013          *   value is the original one (others get generated when
1014          *   requested)
1015          */
1016 
1017         if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
1018             _numberDouble = _numberBigDecimal.doubleValue();
1019         } else if ((_numTypesValid & NR_BIGINT) != 0) {
1020             _numberDouble = _numberBigInt.doubleValue();
1021         } else if ((_numTypesValid & NR_LONG) != 0) {
1022             _numberDouble = (double) _numberLong;
1023         } else if ((_numTypesValid & NR_INT) != 0) {
1024             _numberDouble = (double) _numberInt;
1025         } else {
1026             _throwInternal();
1027         }
1028         _numTypesValid |= NR_DOUBLE;
1029     }
1030 
convertNumberToBigDecimal()1031     protected void convertNumberToBigDecimal() throws IOException
1032     {
1033         /* 05-Aug-2008, tatus: Important note: this MUST start with
1034          *   more accurate representations, since we don't know which
1035          *   value is the original one (others get generated when
1036          *   requested)
1037          */
1038 
1039         if ((_numTypesValid & NR_DOUBLE) != 0) {
1040             /* Let's actually parse from String representation, to avoid
1041              * rounding errors that non-decimal floating operations could incur
1042              */
1043             _numberBigDecimal = NumberInput.parseBigDecimal(getText());
1044         } else if ((_numTypesValid & NR_BIGINT) != 0) {
1045             _numberBigDecimal = new BigDecimal(_numberBigInt);
1046         } else if ((_numTypesValid & NR_LONG) != 0) {
1047             _numberBigDecimal = BigDecimal.valueOf(_numberLong);
1048         } else if ((_numTypesValid & NR_INT) != 0) {
1049             _numberBigDecimal = BigDecimal.valueOf(_numberInt);
1050         } else {
1051             _throwInternal();
1052         }
1053         _numTypesValid |= NR_BIGDECIMAL;
1054     }
1055 
1056     /*
1057     /**********************************************************
1058     /* Internal/package methods: Error reporting
1059     /**********************************************************
1060      */
1061 
_reportMismatchedEndMarker(int actCh, char expCh)1062     protected void _reportMismatchedEndMarker(int actCh, char expCh) throws JsonParseException {
1063         JsonReadContext ctxt = getParsingContext();
1064         _reportError(String.format(
1065                 "Unexpected close marker '%s': expected '%c' (for %s starting at %s)",
1066                 (char) actCh, expCh, ctxt.typeDesc(), ctxt.getStartLocation(_getSourceReference())));
1067     }
1068 
1069     @SuppressWarnings("deprecation")
_handleUnrecognizedCharacterEscape(char ch)1070     protected char _handleUnrecognizedCharacterEscape(char ch) throws JsonProcessingException {
1071         // as per [JACKSON-300]
1072         if (isEnabled(Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)) {
1073             return ch;
1074         }
1075         // and [JACKSON-548]
1076         if (ch == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
1077             return ch;
1078         }
1079         _reportError("Unrecognized character escape "+_getCharDesc(ch));
1080         return ch;
1081     }
1082 
1083     /**
1084      * Method called to report a problem with unquoted control character.
1085      * Note: it is possible to suppress some instances of
1086      * exception by enabling {@link Feature#ALLOW_UNQUOTED_CONTROL_CHARS}.
1087      */
1088     @SuppressWarnings("deprecation")
_throwUnquotedSpace(int i, String ctxtDesc)1089     protected void _throwUnquotedSpace(int i, String ctxtDesc) throws JsonParseException {
1090         // JACKSON-208; possible to allow unquoted control chars:
1091         if (!isEnabled(Feature.ALLOW_UNQUOTED_CONTROL_CHARS) || i > INT_SPACE) {
1092             char c = (char) i;
1093             String msg = "Illegal unquoted character ("+_getCharDesc(c)+"): has to be escaped using backslash to be included in "+ctxtDesc;
1094             _reportError(msg);
1095         }
1096     }
1097 
1098     /**
1099      * @return Description to use as "valid tokens" in an exception message about
1100      *    invalid (unrecognized) JSON token: called when parser finds something that
1101      *    looks like unquoted textual token
1102      *
1103      * @since 2.10
1104      */
_validJsonTokenList()1105     protected String _validJsonTokenList() throws IOException {
1106         return _validJsonValueList();
1107     }
1108 
1109     /**
1110      * @return Description to use as "valid JSON values" in an exception message about
1111      *    invalid (unrecognized) JSON value: called when parser finds something that
1112      *    does not look like a value or separator.
1113      *
1114      * @since 2.10
1115      */
1116     @SuppressWarnings("deprecation")
_validJsonValueList()1117     protected String _validJsonValueList() throws IOException {
1118         if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
1119             return "(JSON String, Number (or 'NaN'/'INF'/'+INF'), Array, Object or token 'null', 'true' or 'false')";
1120         }
1121         return "(JSON String, Number, Array, Object or token 'null', 'true' or 'false')";
1122     }
1123 
1124     /*
1125     /**********************************************************
1126     /* Base64 handling support
1127     /**********************************************************
1128      */
1129 
1130     /**
1131      * Method that sub-classes must implement to support escaped sequences
1132      * in base64-encoded sections.
1133      * Sub-classes that do not need base64 support can leave this as is
1134      */
_decodeEscaped()1135     protected char _decodeEscaped() throws IOException {
1136         throw new UnsupportedOperationException();
1137     }
1138 
_decodeBase64Escape(Base64Variant b64variant, int ch, int index)1139     protected final int _decodeBase64Escape(Base64Variant b64variant, int ch, int index) throws IOException
1140     {
1141         // 17-May-2011, tatu: As per [JACKSON-xxx], need to handle escaped chars
1142         if (ch != '\\') {
1143             throw reportInvalidBase64Char(b64variant, ch, index);
1144         }
1145         int unescaped = _decodeEscaped();
1146         // if white space, skip if first triplet; otherwise errors
1147         if (unescaped <= INT_SPACE) {
1148             if (index == 0) { // whitespace only allowed to be skipped between triplets
1149                 return -1;
1150             }
1151         }
1152         // otherwise try to find actual triplet value
1153         int bits = b64variant.decodeBase64Char(unescaped);
1154         if (bits < 0) {
1155             if (bits != Base64Variant.BASE64_VALUE_PADDING) {
1156                 throw reportInvalidBase64Char(b64variant, unescaped, index);
1157             }
1158         }
1159         return bits;
1160     }
1161 
_decodeBase64Escape(Base64Variant b64variant, char ch, int index)1162     protected final int _decodeBase64Escape(Base64Variant b64variant, char ch, int index) throws IOException
1163     {
1164         if (ch != '\\') {
1165             throw reportInvalidBase64Char(b64variant, ch, index);
1166         }
1167         char unescaped = _decodeEscaped();
1168         // if white space, skip if first triplet; otherwise errors
1169         if (unescaped <= INT_SPACE) {
1170             if (index == 0) { // whitespace only allowed to be skipped between triplets
1171                 return -1;
1172             }
1173         }
1174         // otherwise try to find actual triplet value
1175         int bits = b64variant.decodeBase64Char(unescaped);
1176         if (bits < 0) {
1177             // second check since padding can only be 3rd or 4th byte (index #2 or #3)
1178             if ((bits != Base64Variant.BASE64_VALUE_PADDING) || (index < 2)) {
1179                 throw reportInvalidBase64Char(b64variant, unescaped, index);
1180             }
1181         }
1182         return bits;
1183     }
1184 
reportInvalidBase64Char(Base64Variant b64variant, int ch, int bindex)1185     protected IllegalArgumentException reportInvalidBase64Char(Base64Variant b64variant, int ch, int bindex) throws IllegalArgumentException {
1186         return reportInvalidBase64Char(b64variant, ch, bindex, null);
1187     }
1188 
1189     /**
1190      * @param bindex Relative index within base64 character unit; between 0
1191      *   and 3 (as unit has exactly 4 characters)
1192      */
reportInvalidBase64Char(Base64Variant b64variant, int ch, int bindex, String msg)1193     protected IllegalArgumentException reportInvalidBase64Char(Base64Variant b64variant, int ch, int bindex, String msg) throws IllegalArgumentException {
1194         String base;
1195         if (ch <= INT_SPACE) {
1196             base = String.format("Illegal white space character (code 0x%s) as character #%d of 4-char base64 unit: can only used between units",
1197                     Integer.toHexString(ch), (bindex+1));
1198         } else if (b64variant.usesPaddingChar(ch)) {
1199             base = "Unexpected padding character ('"+b64variant.getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character";
1200         } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) {
1201             // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level)
1202             base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content";
1203         } else {
1204             base = "Illegal character '"+((char)ch)+"' (code 0x"+Integer.toHexString(ch)+") in base64 content";
1205         }
1206         if (msg != null) {
1207             base = base + ": " + msg;
1208         }
1209         return new IllegalArgumentException(base);
1210     }
1211 
1212     // since 2.9.8
_handleBase64MissingPadding(Base64Variant b64variant)1213     protected void _handleBase64MissingPadding(Base64Variant b64variant) throws IOException
1214     {
1215         _reportError(b64variant.missingPaddingMessage());
1216     }
1217 
1218     /*
1219     /**********************************************************
1220     /* Internal/package methods: other
1221     /**********************************************************
1222      */
1223 
1224     /**
1225      * Helper method used to encapsulate logic of including (or not) of
1226      * "source reference" when constructing {@link JsonLocation} instances.
1227      *
1228      * @since 2.9
1229      */
_getSourceReference()1230     protected Object _getSourceReference() {
1231         if (JsonParser.Feature.INCLUDE_SOURCE_IN_LOCATION.enabledIn(_features)) {
1232             return _ioContext.getSourceReference();
1233         }
1234         return null;
1235     }
1236 
growArrayBy(int[] arr, int more)1237     protected static int[] growArrayBy(int[] arr, int more)
1238     {
1239         if (arr == null) {
1240             return new int[more];
1241         }
1242         return Arrays.copyOf(arr, arr.length + more);
1243     }
1244 
1245     /*
1246     /**********************************************************
1247     /* Stuff that was abstract and required before 2.8, but that
1248     /* is not mandatory in 2.8 or above.
1249     /**********************************************************
1250      */
1251 
1252     @Deprecated // since 2.8
loadMoreGuaranteed()1253     protected void loadMoreGuaranteed() throws IOException {
1254         if (!loadMore()) { _reportInvalidEOF(); }
1255     }
1256 
1257     @Deprecated // since 2.8
loadMore()1258     protected boolean loadMore() throws IOException { return false; }
1259 
1260     // Can't declare as deprecated, for now, but shouldn't be needed
_finishString()1261     protected void _finishString() throws IOException { }
1262 }
1263