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