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.CharsToNameCanonicalizer;
10 import com.fasterxml.jackson.core.util.*;
11
12 import static com.fasterxml.jackson.core.JsonTokenId.*;
13
14
19 public class ReaderBasedJsonParser
20 extends ParserBase
21 {
22 @SuppressWarnings("deprecation")
23 private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
24
25 @SuppressWarnings("deprecation")
26 private final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask();
27
28 @SuppressWarnings("deprecation")
29 private final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask();
30
31 @SuppressWarnings("deprecation")
32 private final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask();
33 private final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask();
34 private final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask();
35
36 private final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask();
37 private final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask();
38
39
40
41 protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
42
43
48
49
54 protected Reader _reader;
55
56
60 protected char[] _inputBuffer;
61
62
69 protected boolean _bufferRecyclable;
70
71
76
77 protected ObjectCodec _objectCodec;
78
79 final protected CharsToNameCanonicalizer _symbols;
80
81 final protected int _hashSeed;
82
83
88
89
94 protected boolean _tokenIncomplete;
95
96
104 protected long _nameStartOffset;
105
106
109 protected int _nameStartRow;
110
111
114 protected int _nameStartCol;
115
116
121
122
128 public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
129 ObjectCodec codec, CharsToNameCanonicalizer st,
130 char[] inputBuffer, int start, int end,
131 boolean bufferRecyclable)
132 {
133 super(ctxt, features);
134 _reader = r;
135 _inputBuffer = inputBuffer;
136 _inputPtr = start;
137 _inputEnd = end;
138 _objectCodec = codec;
139 _symbols = st;
140 _hashSeed = st.hashSeed();
141 _bufferRecyclable = bufferRecyclable;
142 }
143
144
148 public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
149 ObjectCodec codec, CharsToNameCanonicalizer st)
150 {
151 super(ctxt, features);
152 _reader = r;
153 _inputBuffer = ctxt.allocTokenBuffer();
154 _inputPtr = 0;
155 _inputEnd = 0;
156 _objectCodec = codec;
157 _symbols = st;
158 _hashSeed = st.hashSeed();
159 _bufferRecyclable = true;
160 }
161
162
167
168 @Override public ObjectCodec getCodec() { return _objectCodec; }
169 @Override public void setCodec(ObjectCodec c) { _objectCodec = c; }
170
171 @Override
172 public int releaseBuffered(Writer w) throws IOException {
173 int count = _inputEnd - _inputPtr;
174 if (count < 1) { return 0; }
175
176 int origPtr = _inputPtr;
177 _inputPtr += count;
178 w.write(_inputBuffer, origPtr, count);
179 return count;
180 }
181
182 @Override public Object getInputSource() { return _reader; }
183
184 @Deprecated
185 protected char getNextChar(String eofMsg) throws IOException {
186 return getNextChar(eofMsg, null);
187 }
188
189 protected char getNextChar(String eofMsg, JsonToken forToken) throws IOException {
190 if (_inputPtr >= _inputEnd) {
191 if (!_loadMore()) {
192 _reportInvalidEOF(eofMsg, forToken);
193 }
194 }
195 return _inputBuffer[_inputPtr++];
196 }
197
198 @Override
199 protected void _closeInput() throws IOException {
200
207 if (_reader != null) {
208 if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
209 _reader.close();
210 }
211 _reader = null;
212 }
213 }
214
215
221 @Override
222 protected void _releaseBuffers() throws IOException
223 {
224 super._releaseBuffers();
225
226 _symbols.release();
227
228 if (_bufferRecyclable) {
229 char[] buf = _inputBuffer;
230 if (buf != null) {
231 _inputBuffer = null;
232 _ioContext.releaseTokenBuffer(buf);
233 }
234 }
235 }
236
237
242
243 protected void _loadMoreGuaranteed() throws IOException {
244 if (!_loadMore()) { _reportInvalidEOF(); }
245 }
246
247 protected boolean _loadMore() throws IOException
248 {
249 if (_reader != null) {
250 int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
251 if (count > 0) {
252 final int bufSize = _inputEnd;
253 _currInputProcessed += bufSize;
254 _currInputRowStart -= bufSize;
255
256
257
258
259 _nameStartOffset -= bufSize;
260
261 _inputPtr = 0;
262 _inputEnd = count;
263
264 return true;
265 }
266
267 _closeInput();
268
269 if (count == 0) {
270 throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd);
271 }
272 }
273 return false;
274 }
275
276
281
282
288 @Override
289 public final String getText() throws IOException
290 {
291 if (_currToken == JsonToken.VALUE_STRING) {
292 if (_tokenIncomplete) {
293 _tokenIncomplete = false;
294 _finishString();
295 }
296 return _textBuffer.contentsAsString();
297 }
298 return _getText2(_currToken);
299 }
300
301 @Override
302 public int getText(Writer writer) throws IOException
303 {
304 JsonToken t = _currToken;
305 if (t == JsonToken.VALUE_STRING) {
306 if (_tokenIncomplete) {
307 _tokenIncomplete = false;
308 _finishString();
309 }
310 return _textBuffer.contentsToWriter(writer);
311 }
312 if (t == JsonToken.FIELD_NAME) {
313 String n = _parsingContext.getCurrentName();
314 writer.write(n);
315 return n.length();
316 }
317 if (t != null) {
318 if (t.isNumeric()) {
319 return _textBuffer.contentsToWriter(writer);
320 }
321 char[] ch = t.asCharArray();
322 writer.write(ch);
323 return ch.length;
324 }
325 return 0;
326 }
327
328
329
330
331 @Override
332 public final String getValueAsString() throws IOException
333 {
334 if (_currToken == JsonToken.VALUE_STRING) {
335 if (_tokenIncomplete) {
336 _tokenIncomplete = false;
337 _finishString();
338 }
339 return _textBuffer.contentsAsString();
340 }
341 if (_currToken == JsonToken.FIELD_NAME) {
342 return getCurrentName();
343 }
344 return super.getValueAsString(null);
345 }
346
347
348 @Override
349 public final String getValueAsString(String defValue) throws IOException {
350 if (_currToken == JsonToken.VALUE_STRING) {
351 if (_tokenIncomplete) {
352 _tokenIncomplete = false;
353 _finishString();
354 }
355 return _textBuffer.contentsAsString();
356 }
357 if (_currToken == JsonToken.FIELD_NAME) {
358 return getCurrentName();
359 }
360 return super.getValueAsString(defValue);
361 }
362
363 protected final String _getText2(JsonToken t) {
364 if (t == null) {
365 return null;
366 }
367 switch (t.id()) {
368 case ID_FIELD_NAME:
369 return _parsingContext.getCurrentName();
370
371 case ID_STRING:
372
373 case ID_NUMBER_INT:
374 case ID_NUMBER_FLOAT:
375 return _textBuffer.contentsAsString();
376 default:
377 return t.asString();
378 }
379 }
380
381 @Override
382 public final char[] getTextCharacters() throws IOException
383 {
384 if (_currToken != null) {
385 switch (_currToken.id()) {
386 case ID_FIELD_NAME:
387 if (!_nameCopied) {
388 String name = _parsingContext.getCurrentName();
389 int nameLen = name.length();
390 if (_nameCopyBuffer == null) {
391 _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
392 } else if (_nameCopyBuffer.length < nameLen) {
393 _nameCopyBuffer = new char[nameLen];
394 }
395 name.getChars(0, nameLen, _nameCopyBuffer, 0);
396 _nameCopied = true;
397 }
398 return _nameCopyBuffer;
399 case ID_STRING:
400 if (_tokenIncomplete) {
401 _tokenIncomplete = false;
402 _finishString();
403 }
404
405 case ID_NUMBER_INT:
406 case ID_NUMBER_FLOAT:
407 return _textBuffer.getTextBuffer();
408 default:
409 return _currToken.asCharArray();
410 }
411 }
412 return null;
413 }
414
415 @Override
416 public final int getTextLength() throws IOException
417 {
418 if (_currToken != null) {
419 switch (_currToken.id()) {
420 case ID_FIELD_NAME:
421 return _parsingContext.getCurrentName().length();
422 case ID_STRING:
423 if (_tokenIncomplete) {
424 _tokenIncomplete = false;
425 _finishString();
426 }
427
428 case ID_NUMBER_INT:
429 case ID_NUMBER_FLOAT:
430 return _textBuffer.size();
431 default:
432 return _currToken.asCharArray().length;
433 }
434 }
435 return 0;
436 }
437
438 @Override
439 public final int getTextOffset() throws IOException
440 {
441
442 if (_currToken != null) {
443 switch (_currToken.id()) {
444 case ID_FIELD_NAME:
445 return 0;
446 case ID_STRING:
447 if (_tokenIncomplete) {
448 _tokenIncomplete = false;
449 _finishString();
450 }
451
452 case ID_NUMBER_INT:
453 case ID_NUMBER_FLOAT:
454 return _textBuffer.getTextOffset();
455 default:
456 }
457 }
458 return 0;
459 }
460
461 @Override
462 public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
463 {
464 if ((_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) && (_binaryValue != null)) {
465 return _binaryValue;
466 }
467 if (_currToken != JsonToken.VALUE_STRING) {
468 _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
469 }
470
471 if (_tokenIncomplete) {
472 try {
473 _binaryValue = _decodeBase64(b64variant);
474 } catch (IllegalArgumentException iae) {
475 throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
476 }
477
480 _tokenIncomplete = false;
481 } else {
482 if (_binaryValue == null) {
483 @SuppressWarnings("resource")
484 ByteArrayBuilder builder = _getByteArrayBuilder();
485 _decodeBase64(getText(), builder, b64variant);
486 _binaryValue = builder.toByteArray();
487 }
488 }
489 return _binaryValue;
490 }
491
492 @Override
493 public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
494 {
495
496 if (!_tokenIncomplete || _currToken != JsonToken.VALUE_STRING) {
497 byte[] b = getBinaryValue(b64variant);
498 out.write(b);
499 return b.length;
500 }
501
502 byte[] buf = _ioContext.allocBase64Buffer();
503 try {
504 return _readBinary(b64variant, out, buf);
505 } finally {
506 _ioContext.releaseBase64Buffer(buf);
507 }
508 }
509
510 protected int _readBinary(Base64Variant b64variant, OutputStream out, byte[] buffer) throws IOException
511 {
512 int outputPtr = 0;
513 final int outputEnd = buffer.length - 3;
514 int outputCount = 0;
515
516 while (true) {
517
518 char ch;
519 do {
520 if (_inputPtr >= _inputEnd) {
521 _loadMoreGuaranteed();
522 }
523 ch = _inputBuffer[_inputPtr++];
524 } while (ch <= INT_SPACE);
525 int bits = b64variant.decodeBase64Char(ch);
526 if (bits < 0) {
527 if (ch == '"') {
528 break;
529 }
530 bits = _decodeBase64Escape(b64variant, ch, 0);
531 if (bits < 0) {
532 continue;
533 }
534 }
535
536
537 if (outputPtr > outputEnd) {
538 outputCount += outputPtr;
539 out.write(buffer, 0, outputPtr);
540 outputPtr = 0;
541 }
542
543 int decodedData = bits;
544
545
546
547 if (_inputPtr >= _inputEnd) {
548 _loadMoreGuaranteed();
549 }
550 ch = _inputBuffer[_inputPtr++];
551 bits = b64variant.decodeBase64Char(ch);
552 if (bits < 0) {
553 bits = _decodeBase64Escape(b64variant, ch, 1);
554 }
555 decodedData = (decodedData << 6) | bits;
556
557
558 if (_inputPtr >= _inputEnd) {
559 _loadMoreGuaranteed();
560 }
561 ch = _inputBuffer[_inputPtr++];
562 bits = b64variant.decodeBase64Char(ch);
563
564
565 if (bits < 0) {
566 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
567
568 if (ch == '"') {
569 decodedData >>= 4;
570 buffer[outputPtr++] = (byte) decodedData;
571 if (b64variant.usesPadding()) {
572 --_inputPtr;
573 _handleBase64MissingPadding(b64variant);
574 }
575 break;
576 }
577 bits = _decodeBase64Escape(b64variant, ch, 2);
578 }
579 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
580
581 if (_inputPtr >= _inputEnd) {
582 _loadMoreGuaranteed();
583 }
584 ch = _inputBuffer[_inputPtr++];
585 if (!b64variant.usesPaddingChar(ch)) {
586 if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) {
587 throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
588 }
589 }
590
591 decodedData >>= 4;
592 buffer[outputPtr++] = (byte) decodedData;
593 continue;
594 }
595 }
596
597 decodedData = (decodedData << 6) | bits;
598
599 if (_inputPtr >= _inputEnd) {
600 _loadMoreGuaranteed();
601 }
602 ch = _inputBuffer[_inputPtr++];
603 bits = b64variant.decodeBase64Char(ch);
604 if (bits < 0) {
605 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
606
607 if (ch == '"') {
608 decodedData >>= 2;
609 buffer[outputPtr++] = (byte) (decodedData >> 8);
610 buffer[outputPtr++] = (byte) decodedData;
611 if (b64variant.usesPadding()) {
612 --_inputPtr;
613 _handleBase64MissingPadding(b64variant);
614 }
615 break;
616 }
617 bits = _decodeBase64Escape(b64variant, ch, 3);
618 }
619 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
620
626 decodedData >>= 2;
627 buffer[outputPtr++] = (byte) (decodedData >> 8);
628 buffer[outputPtr++] = (byte) decodedData;
629 continue;
630 }
631 }
632
633 decodedData = (decodedData << 6) | bits;
634 buffer[outputPtr++] = (byte) (decodedData >> 16);
635 buffer[outputPtr++] = (byte) (decodedData >> 8);
636 buffer[outputPtr++] = (byte) decodedData;
637 }
638 _tokenIncomplete = false;
639 if (outputPtr > 0) {
640 outputCount += outputPtr;
641 out.write(buffer, 0, outputPtr);
642 }
643 return outputCount;
644 }
645
646
651
652
656 @Override
657 public final JsonToken nextToken() throws IOException
658 {
659
663 if (_currToken == JsonToken.FIELD_NAME) {
664 return _nextAfterName();
665 }
666
667
668 _numTypesValid = NR_UNKNOWN;
669 if (_tokenIncomplete) {
670 _skipString();
671 }
672 int i = _skipWSOrEnd();
673 if (i < 0) {
674
675
676 close();
677 return (_currToken = null);
678 }
679
680 _binaryValue = null;
681
682
683 if (i == INT_RBRACKET || i == INT_RCURLY) {
684 _closeScope(i);
685 return _currToken;
686 }
687
688
689 if (_parsingContext.expectComma()) {
690 i = _skipComma(i);
691
692
693 if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
694 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
695 _closeScope(i);
696 return _currToken;
697 }
698 }
699 }
700
701
704 boolean inObject = _parsingContext.inObject();
705 if (inObject) {
706
707 _updateNameLocation();
708 String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
709 _parsingContext.setCurrentName(name);
710 _currToken = JsonToken.FIELD_NAME;
711 i = _skipColon();
712 }
713 _updateLocation();
714
715
716
717 JsonToken t;
718
719 switch (i) {
720 case '"':
721 _tokenIncomplete = true;
722 t = JsonToken.VALUE_STRING;
723 break;
724 case '[':
725 if (!inObject) {
726 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
727 }
728 t = JsonToken.START_ARRAY;
729 break;
730 case '{':
731 if (!inObject) {
732 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
733 }
734 t = JsonToken.START_OBJECT;
735 break;
736 case '}':
737
738
739 _reportUnexpectedChar(i, "expected a value");
740 case 't':
741 _matchTrue();
742 t = JsonToken.VALUE_TRUE;
743 break;
744 case 'f':
745 _matchFalse();
746 t = JsonToken.VALUE_FALSE;
747 break;
748 case 'n':
749 _matchNull();
750 t = JsonToken.VALUE_NULL;
751 break;
752
753 case '-':
754
758 t = _parseNegNumber();
759 break;
760 case '.':
761 t = _parseFloatThatStartsWithPeriod();
762 break;
763 case '0':
764 case '1':
765 case '2':
766 case '3':
767 case '4':
768 case '5':
769 case '6':
770 case '7':
771 case '8':
772 case '9':
773 t = _parsePosNumber(i);
774 break;
775 default:
776 t = _handleOddValue(i);
777 break;
778 }
779
780 if (inObject) {
781 _nextToken = t;
782 return _currToken;
783 }
784 _currToken = t;
785 return t;
786 }
787
788 private final JsonToken _nextAfterName()
789 {
790 _nameCopied = false;
791 JsonToken t = _nextToken;
792 _nextToken = null;
793
794
795
796
797 if (t == JsonToken.START_ARRAY) {
798 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
799 } else if (t == JsonToken.START_OBJECT) {
800 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
801 }
802 return (_currToken = t);
803 }
804
805 @Override
806 public void finishToken() throws IOException {
807 if (_tokenIncomplete) {
808 _tokenIncomplete = false;
809 _finishString();
810 }
811 }
812
813
818
819
820 @Override
821 public boolean nextFieldName(SerializableString sstr) throws IOException
822 {
823
824
825 _numTypesValid = NR_UNKNOWN;
826 if (_currToken == JsonToken.FIELD_NAME) {
827 _nextAfterName();
828 return false;
829 }
830 if (_tokenIncomplete) {
831 _skipString();
832 }
833 int i = _skipWSOrEnd();
834 if (i < 0) {
835 close();
836 _currToken = null;
837 return false;
838 }
839 _binaryValue = null;
840
841
842 if (i == INT_RBRACKET || i == INT_RCURLY) {
843 _closeScope(i);
844 return false;
845 }
846
847 if (_parsingContext.expectComma()) {
848 i = _skipComma(i);
849
850
851 if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
852 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
853 _closeScope(i);
854 return false;
855 }
856 }
857 }
858
859 if (!_parsingContext.inObject()) {
860 _updateLocation();
861 _nextTokenNotInObject(i);
862 return false;
863 }
864
865 _updateNameLocation();
866 if (i == INT_QUOTE) {
867
868 char[] nameChars = sstr.asQuotedChars();
869 final int len = nameChars.length;
870
871
872 if ((_inputPtr + len + 4) < _inputEnd) {
873
874 final int end = _inputPtr+len;
875 if (_inputBuffer[end] == '"') {
876 int offset = 0;
877 int ptr = _inputPtr;
878 while (true) {
879 if (ptr == end) {
880 _parsingContext.setCurrentName(sstr.getValue());
881 _isNextTokenNameYes(_skipColonFast(ptr+1));
882 return true;
883 }
884 if (nameChars[offset] != _inputBuffer[ptr]) {
885 break;
886 }
887 ++offset;
888 ++ptr;
889 }
890 }
891 }
892 }
893 return _isNextTokenNameMaybe(i, sstr.getValue());
894 }
895
896 @Override
897 public String nextFieldName() throws IOException
898 {
899
900
901 _numTypesValid = NR_UNKNOWN;
902 if (_currToken == JsonToken.FIELD_NAME) {
903 _nextAfterName();
904 return null;
905 }
906 if (_tokenIncomplete) {
907 _skipString();
908 }
909 int i = _skipWSOrEnd();
910 if (i < 0) {
911 close();
912 _currToken = null;
913 return null;
914 }
915 _binaryValue = null;
916 if (i == INT_RBRACKET || i == INT_RCURLY) {
917 _closeScope(i);
918 return null;
919 }
920 if (_parsingContext.expectComma()) {
921 i = _skipComma(i);
922 if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
923 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
924 _closeScope(i);
925 return null;
926 }
927 }
928 }
929 if (!_parsingContext.inObject()) {
930 _updateLocation();
931 _nextTokenNotInObject(i);
932 return null;
933 }
934
935 _updateNameLocation();
936 String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
937 _parsingContext.setCurrentName(name);
938 _currToken = JsonToken.FIELD_NAME;
939 i = _skipColon();
940
941 _updateLocation();
942 if (i == INT_QUOTE) {
943 _tokenIncomplete = true;
944 _nextToken = JsonToken.VALUE_STRING;
945 return name;
946 }
947
948
949
950 JsonToken t;
951
952 switch (i) {
953 case '-':
954 t = _parseNegNumber();
955 break;
956 case '.':
957 t = _parseFloatThatStartsWithPeriod();
958 break;
959 case '0':
960 case '1':
961 case '2':
962 case '3':
963 case '4':
964 case '5':
965 case '6':
966 case '7':
967 case '8':
968 case '9':
969 t = _parsePosNumber(i);
970 break;
971 case 'f':
972 _matchFalse();
973 t = JsonToken.VALUE_FALSE;
974 break;
975 case 'n':
976 _matchNull();
977 t = JsonToken.VALUE_NULL;
978 break;
979 case 't':
980 _matchTrue();
981 t = JsonToken.VALUE_TRUE;
982 break;
983 case '[':
984 t = JsonToken.START_ARRAY;
985 break;
986 case '{':
987 t = JsonToken.START_OBJECT;
988 break;
989 default:
990 t = _handleOddValue(i);
991 break;
992 }
993 _nextToken = t;
994 return name;
995 }
996
997 private final void _isNextTokenNameYes(int i) throws IOException
998 {
999 _currToken = JsonToken.FIELD_NAME;
1000 _updateLocation();
1001
1002 switch (i) {
1003 case '"':
1004 _tokenIncomplete = true;
1005 _nextToken = JsonToken.VALUE_STRING;
1006 return;
1007 case '[':
1008 _nextToken = JsonToken.START_ARRAY;
1009 return;
1010 case '{':
1011 _nextToken = JsonToken.START_OBJECT;
1012 return;
1013 case 't':
1014 _matchToken("true", 1);
1015 _nextToken = JsonToken.VALUE_TRUE;
1016 return;
1017 case 'f':
1018 _matchToken("false", 1);
1019 _nextToken = JsonToken.VALUE_FALSE;
1020 return;
1021 case 'n':
1022 _matchToken("null", 1);
1023 _nextToken = JsonToken.VALUE_NULL;
1024 return;
1025 case '-':
1026 _nextToken = _parseNegNumber();
1027 return;
1028 case '.':
1029 _nextToken = _parseFloatThatStartsWithPeriod();
1030 return;
1031 case '0':
1032 case '1':
1033 case '2':
1034 case '3':
1035 case '4':
1036 case '5':
1037 case '6':
1038 case '7':
1039 case '8':
1040 case '9':
1041 _nextToken = _parsePosNumber(i);
1042 return;
1043 }
1044 _nextToken = _handleOddValue(i);
1045 }
1046
1047 protected boolean _isNextTokenNameMaybe(int i, String nameToMatch) throws IOException
1048 {
1049
1050 String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
1051 _parsingContext.setCurrentName(name);
1052 _currToken = JsonToken.FIELD_NAME;
1053 i = _skipColon();
1054 _updateLocation();
1055 if (i == INT_QUOTE) {
1056 _tokenIncomplete = true;
1057 _nextToken = JsonToken.VALUE_STRING;
1058 return nameToMatch.equals(name);
1059 }
1060
1061 JsonToken t;
1062 switch (i) {
1063 case '-':
1064 t = _parseNegNumber();
1065 break;
1066 case '.':
1067 t = _parseFloatThatStartsWithPeriod();
1068 break;
1069 case '0':
1070 case '1':
1071 case '2':
1072 case '3':
1073 case '4':
1074 case '5':
1075 case '6':
1076 case '7':
1077 case '8':
1078 case '9':
1079 t = _parsePosNumber(i);
1080 break;
1081 case 'f':
1082 _matchFalse();
1083 t = JsonToken.VALUE_FALSE;
1084 break;
1085 case 'n':
1086 _matchNull();
1087 t = JsonToken.VALUE_NULL;
1088 break;
1089 case 't':
1090 _matchTrue();
1091 t = JsonToken.VALUE_TRUE;
1092 break;
1093 case '[':
1094 t = JsonToken.START_ARRAY;
1095 break;
1096 case '{':
1097 t = JsonToken.START_OBJECT;
1098 break;
1099 default:
1100 t = _handleOddValue(i);
1101 break;
1102 }
1103 _nextToken = t;
1104 return nameToMatch.equals(name);
1105 }
1106
1107 private final JsonToken _nextTokenNotInObject(int i) throws IOException
1108 {
1109 if (i == INT_QUOTE) {
1110 _tokenIncomplete = true;
1111 return (_currToken = JsonToken.VALUE_STRING);
1112 }
1113 switch (i) {
1114 case '[':
1115 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1116 return (_currToken = JsonToken.START_ARRAY);
1117 case '{':
1118 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1119 return (_currToken = JsonToken.START_OBJECT);
1120 case 't':
1121 _matchToken("true", 1);
1122 return (_currToken = JsonToken.VALUE_TRUE);
1123 case 'f':
1124 _matchToken("false", 1);
1125 return (_currToken = JsonToken.VALUE_FALSE);
1126 case 'n':
1127 _matchToken("null", 1);
1128 return (_currToken = JsonToken.VALUE_NULL);
1129 case '-':
1130 return (_currToken = _parseNegNumber());
1131
1135 case '.':
1136 return (_currToken = _parseFloatThatStartsWithPeriod());
1137 case '0':
1138 case '1':
1139 case '2':
1140 case '3':
1141 case '4':
1142 case '5':
1143 case '6':
1144 case '7':
1145 case '8':
1146 case '9':
1147 return (_currToken = _parsePosNumber(i));
1148
1156
1157 case ',':
1158
1159 if (!_parsingContext.inRoot()) {
1160 if ((_features & FEAT_MASK_ALLOW_MISSING) != 0) {
1161 --_inputPtr;
1162 return (_currToken = JsonToken.VALUE_NULL);
1163 }
1164 }
1165 }
1166 return (_currToken = _handleOddValue(i));
1167 }
1168
1169 @Override
1170 public final String nextTextValue() throws IOException
1171 {
1172 if (_currToken == JsonToken.FIELD_NAME) {
1173 _nameCopied = false;
1174 JsonToken t = _nextToken;
1175 _nextToken = null;
1176 _currToken = t;
1177 if (t == JsonToken.VALUE_STRING) {
1178 if (_tokenIncomplete) {
1179 _tokenIncomplete = false;
1180 _finishString();
1181 }
1182 return _textBuffer.contentsAsString();
1183 }
1184 if (t == JsonToken.START_ARRAY) {
1185 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1186 } else if (t == JsonToken.START_OBJECT) {
1187 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1188 }
1189 return null;
1190 }
1191
1192 return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
1193 }
1194
1195
1196 @Override
1197 public final int nextIntValue(int defaultValue) throws IOException
1198 {
1199 if (_currToken == JsonToken.FIELD_NAME) {
1200 _nameCopied = false;
1201 JsonToken t = _nextToken;
1202 _nextToken = null;
1203 _currToken = t;
1204 if (t == JsonToken.VALUE_NUMBER_INT) {
1205 return getIntValue();
1206 }
1207 if (t == JsonToken.START_ARRAY) {
1208 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1209 } else if (t == JsonToken.START_OBJECT) {
1210 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1211 }
1212 return defaultValue;
1213 }
1214
1215 return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
1216 }
1217
1218
1219 @Override
1220 public final long nextLongValue(long defaultValue) throws IOException
1221 {
1222 if (_currToken == JsonToken.FIELD_NAME) {
1223 _nameCopied = false;
1224 JsonToken t = _nextToken;
1225 _nextToken = null;
1226 _currToken = t;
1227 if (t == JsonToken.VALUE_NUMBER_INT) {
1228 return getLongValue();
1229 }
1230 if (t == JsonToken.START_ARRAY) {
1231 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1232 } else if (t == JsonToken.START_OBJECT) {
1233 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1234 }
1235 return defaultValue;
1236 }
1237
1238 return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
1239 }
1240
1241
1242 @Override
1243 public final Boolean nextBooleanValue() throws IOException
1244 {
1245 if (_currToken == JsonToken.FIELD_NAME) {
1246 _nameCopied = false;
1247 JsonToken t = _nextToken;
1248 _nextToken = null;
1249 _currToken = t;
1250 if (t == JsonToken.VALUE_TRUE) {
1251 return Boolean.TRUE;
1252 }
1253 if (t == JsonToken.VALUE_FALSE) {
1254 return Boolean.FALSE;
1255 }
1256 if (t == JsonToken.START_ARRAY) {
1257 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1258 } else if (t == JsonToken.START_OBJECT) {
1259 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1260 }
1261 return null;
1262 }
1263 JsonToken t = nextToken();
1264 if (t != null) {
1265 int id = t.id();
1266 if (id == ID_TRUE) return Boolean.TRUE;
1267 if (id == ID_FALSE) return Boolean.FALSE;
1268 }
1269 return null;
1270 }
1271
1272
1277
1278
1279 protected final JsonToken _parseFloatThatStartsWithPeriod() throws IOException
1280 {
1281
1282 if (!isEnabled(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1283 return _handleOddValue('.');
1284 }
1285 return _parseFloat(INT_PERIOD, _inputPtr-1, _inputPtr, false, 0);
1286 }
1287
1288
1303 protected final JsonToken _parsePosNumber(int ch) throws IOException
1304 {
1305
1310 int ptr = _inputPtr;
1311 int startPtr = ptr-1;
1312 final int inputLen = _inputEnd;
1313
1314
1315 if (ch == INT_0) {
1316 return _parseNumber2(false, startPtr);
1317 }
1318
1319
1324
1325 int intLen = 1;
1326
1327
1328 int_loop:
1329 while (true) {
1330 if (ptr >= inputLen) {
1331 _inputPtr = startPtr;
1332 return _parseNumber2(false, startPtr);
1333 }
1334 ch = (int) _inputBuffer[ptr++];
1335 if (ch < INT_0 || ch > INT_9) {
1336 break int_loop;
1337 }
1338 ++intLen;
1339 }
1340 if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) {
1341 _inputPtr = ptr;
1342 return _parseFloat(ch, startPtr, ptr, false, intLen);
1343 }
1344
1345 --ptr;
1346 _inputPtr = ptr;
1347
1348 if (_parsingContext.inRoot()) {
1349 _verifyRootSpace(ch);
1350 }
1351 int len = ptr-startPtr;
1352 _textBuffer.resetWithShared(_inputBuffer, startPtr, len);
1353 return resetInt(false, intLen);
1354 }
1355
1356 private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg, int intLen)
1357 throws IOException
1358 {
1359 final int inputLen = _inputEnd;
1360 int fractLen = 0;
1361
1362
1363 if (ch == '.') {
1364 fract_loop:
1365 while (true) {
1366 if (ptr >= inputLen) {
1367 return _parseNumber2(neg, startPtr);
1368 }
1369 ch = (int) _inputBuffer[ptr++];
1370 if (ch < INT_0 || ch > INT_9) {
1371 break fract_loop;
1372 }
1373 ++fractLen;
1374 }
1375
1376 if (fractLen == 0) {
1377 reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
1378 }
1379 }
1380 int expLen = 0;
1381 if (ch == 'e' || ch == 'E') {
1382 if (ptr >= inputLen) {
1383 _inputPtr = startPtr;
1384 return _parseNumber2(neg, startPtr);
1385 }
1386
1387 ch = (int) _inputBuffer[ptr++];
1388 if (ch == INT_MINUS || ch == INT_PLUS) {
1389 if (ptr >= inputLen) {
1390 _inputPtr = startPtr;
1391 return _parseNumber2(neg, startPtr);
1392 }
1393 ch = (int) _inputBuffer[ptr++];
1394 }
1395 while (ch <= INT_9 && ch >= INT_0) {
1396 ++expLen;
1397 if (ptr >= inputLen) {
1398 _inputPtr = startPtr;
1399 return _parseNumber2(neg, startPtr);
1400 }
1401 ch = (int) _inputBuffer[ptr++];
1402 }
1403
1404 if (expLen == 0) {
1405 reportUnexpectedNumberChar(ch, "Exponent indicator not followed by a digit");
1406 }
1407 }
1408 --ptr;
1409 _inputPtr = ptr;
1410
1411 if (_parsingContext.inRoot()) {
1412 _verifyRootSpace(ch);
1413 }
1414 int len = ptr-startPtr;
1415 _textBuffer.resetWithShared(_inputBuffer, startPtr, len);
1416
1417 return resetFloat(neg, intLen, fractLen, expLen);
1418 }
1419
1420 protected final JsonToken _parseNegNumber() throws IOException
1421 {
1422 int ptr = _inputPtr;
1423 int startPtr = ptr-1;
1424 final int inputLen = _inputEnd;
1425
1426 if (ptr >= inputLen) {
1427 return _parseNumber2(true, startPtr);
1428 }
1429 int ch = _inputBuffer[ptr++];
1430
1431 if (ch > INT_9 || ch < INT_0) {
1432 _inputPtr = ptr;
1433 return _handleInvalidNumberStart(ch, true);
1434 }
1435
1436 if (ch == INT_0) {
1437 return _parseNumber2(true, startPtr);
1438 }
1439 int intLen = 1;
1440
1441
1442 int_loop:
1443 while (true) {
1444 if (ptr >= inputLen) {
1445 return _parseNumber2(true, startPtr);
1446 }
1447 ch = (int) _inputBuffer[ptr++];
1448 if (ch < INT_0 || ch > INT_9) {
1449 break int_loop;
1450 }
1451 ++intLen;
1452 }
1453
1454 if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) {
1455 _inputPtr = ptr;
1456 return _parseFloat(ch, startPtr, ptr, true, intLen);
1457 }
1458 --ptr;
1459 _inputPtr = ptr;
1460 if (_parsingContext.inRoot()) {
1461 _verifyRootSpace(ch);
1462 }
1463 int len = ptr-startPtr;
1464 _textBuffer.resetWithShared(_inputBuffer, startPtr, len);
1465 return resetInt(true, intLen);
1466 }
1467
1468
1475 private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOException
1476 {
1477 _inputPtr = neg ? (startPtr+1) : startPtr;
1478 char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
1479 int outPtr = 0;
1480
1481
1482 if (neg) {
1483 outBuf[outPtr++] = '-';
1484 }
1485
1486
1487 int intLen = 0;
1488 char c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
1489 : getNextChar("No digit following minus sign", JsonToken.VALUE_NUMBER_INT);
1490 if (c == '0') {
1491 c = _verifyNoLeadingZeroes();
1492 }
1493 boolean eof = false;
1494
1495
1496 int_loop:
1497 while (c >= '0' && c <= '9') {
1498 ++intLen;
1499 if (outPtr >= outBuf.length) {
1500 outBuf = _textBuffer.finishCurrentSegment();
1501 outPtr = 0;
1502 }
1503 outBuf[outPtr++] = c;
1504 if (_inputPtr >= _inputEnd && !_loadMore()) {
1505
1506 c = CHAR_NULL;
1507 eof = true;
1508 break int_loop;
1509 }
1510 c = _inputBuffer[_inputPtr++];
1511 }
1512
1513 if (intLen == 0) {
1514 return _handleInvalidNumberStart(c, neg);
1515 }
1516
1517 int fractLen = 0;
1518
1519 if (c == '.') {
1520 if (outPtr >= outBuf.length) {
1521 outBuf = _textBuffer.finishCurrentSegment();
1522 outPtr = 0;
1523 }
1524 outBuf[outPtr++] = c;
1525
1526 fract_loop:
1527 while (true) {
1528 if (_inputPtr >= _inputEnd && !_loadMore()) {
1529 eof = true;
1530 break fract_loop;
1531 }
1532 c = _inputBuffer[_inputPtr++];
1533 if (c < INT_0 || c > INT_9) {
1534 break fract_loop;
1535 }
1536 ++fractLen;
1537 if (outPtr >= outBuf.length) {
1538 outBuf = _textBuffer.finishCurrentSegment();
1539 outPtr = 0;
1540 }
1541 outBuf[outPtr++] = c;
1542 }
1543
1544 if (fractLen == 0) {
1545 reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1546 }
1547 }
1548
1549 int expLen = 0;
1550 if (c == 'e' || c == 'E') {
1551 if (outPtr >= outBuf.length) {
1552 outBuf = _textBuffer.finishCurrentSegment();
1553 outPtr = 0;
1554 }
1555 outBuf[outPtr++] = c;
1556
1557 c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
1558 : getNextChar("expected a digit for number exponent");
1559
1560 if (c == '-' || c == '+') {
1561 if (outPtr >= outBuf.length) {
1562 outBuf = _textBuffer.finishCurrentSegment();
1563 outPtr = 0;
1564 }
1565 outBuf[outPtr++] = c;
1566
1567 c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
1568 : getNextChar("expected a digit for number exponent");
1569 }
1570
1571 exp_loop:
1572 while (c <= INT_9 && c >= INT_0) {
1573 ++expLen;
1574 if (outPtr >= outBuf.length) {
1575 outBuf = _textBuffer.finishCurrentSegment();
1576 outPtr = 0;
1577 }
1578 outBuf[outPtr++] = c;
1579 if (_inputPtr >= _inputEnd && !_loadMore()) {
1580 eof = true;
1581 break exp_loop;
1582 }
1583 c = _inputBuffer[_inputPtr++];
1584 }
1585
1586 if (expLen == 0) {
1587 reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit");
1588 }
1589 }
1590
1591
1592 if (!eof) {
1593 --_inputPtr;
1594 if (_parsingContext.inRoot()) {
1595 _verifyRootSpace(c);
1596 }
1597 }
1598 _textBuffer.setCurrentLength(outPtr);
1599
1600 return reset(neg, intLen, fractLen, expLen);
1601 }
1602
1603
1607 private final char _verifyNoLeadingZeroes() throws IOException
1608 {
1609
1610 if (_inputPtr < _inputEnd) {
1611 char ch = _inputBuffer[_inputPtr];
1612
1613 if (ch < '0' || ch > '9') {
1614 return '0';
1615 }
1616 }
1617
1618 return _verifyNLZ2();
1619 }
1620
1621 private char _verifyNLZ2() throws IOException
1622 {
1623 if (_inputPtr >= _inputEnd && !_loadMore()) {
1624 return '0';
1625 }
1626 char ch = _inputBuffer[_inputPtr];
1627 if (ch < '0' || ch > '9') {
1628 return '0';
1629 }
1630 if ((_features & FEAT_MASK_LEADING_ZEROS) == 0) {
1631 reportInvalidNumber("Leading zeroes not allowed");
1632 }
1633
1634 ++_inputPtr;
1635 if (ch == INT_0) {
1636 while (_inputPtr < _inputEnd || _loadMore()) {
1637 ch = _inputBuffer[_inputPtr];
1638 if (ch < '0' || ch > '9') {
1639 return '0';
1640 }
1641 ++_inputPtr;
1642 if (ch != '0') {
1643 break;
1644 }
1645 }
1646 }
1647 return ch;
1648 }
1649
1650
1654 protected JsonToken _handleInvalidNumberStart(int ch, boolean negative) throws IOException
1655 {
1656 if (ch == 'I') {
1657 if (_inputPtr >= _inputEnd) {
1658 if (!_loadMore()) {
1659 _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_INT);
1660 }
1661 }
1662 ch = _inputBuffer[_inputPtr++];
1663 if (ch == 'N') {
1664 String match = negative ? "-INF" :"+INF";
1665 _matchToken(match, 3);
1666 if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
1667 return resetAsNaN(match, negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
1668 }
1669 _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
1670 } else if (ch == 'n') {
1671 String match = negative ? "-Infinity" :"+Infinity";
1672 _matchToken(match, 3);
1673 if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
1674 return resetAsNaN(match, negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
1675 }
1676 _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
1677 }
1678 }
1679 reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value");
1680 return null;
1681 }
1682
1683
1690 private final void _verifyRootSpace(int ch) throws IOException
1691 {
1692
1693 ++_inputPtr;
1694 switch (ch) {
1695 case ' ':
1696 case '\t':
1697 return;
1698 case '\r':
1699 _skipCR();
1700 return;
1701 case '\n':
1702 ++_currInputRow;
1703 _currInputRowStart = _inputPtr;
1704 return;
1705 }
1706 _reportMissingRootWS(ch);
1707 }
1708
1709
1714
1715 protected final String _parseName() throws IOException
1716 {
1717
1718
1719 int ptr = _inputPtr;
1720 int hash = _hashSeed;
1721 final int[] codes = _icLatin1;
1722
1723 while (ptr < _inputEnd) {
1724 int ch = _inputBuffer[ptr];
1725 if (ch < codes.length && codes[ch] != 0) {
1726 if (ch == '"') {
1727 int start = _inputPtr;
1728 _inputPtr = ptr+1;
1729 return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
1730 }
1731 break;
1732 }
1733 hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
1734 ++ptr;
1735 }
1736 int start = _inputPtr;
1737 _inputPtr = ptr;
1738 return _parseName2(start, hash, INT_QUOTE);
1739 }
1740
1741 private String _parseName2(int startPtr, int hash, int endChar) throws IOException
1742 {
1743 _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr));
1744
1745
1748 char[] outBuf = _textBuffer.getCurrentSegment();
1749 int outPtr = _textBuffer.getCurrentSegmentSize();
1750
1751 while (true) {
1752 if (_inputPtr >= _inputEnd) {
1753 if (!_loadMore()) {
1754 _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
1755 }
1756 }
1757 char c = _inputBuffer[_inputPtr++];
1758 int i = (int) c;
1759 if (i <= INT_BACKSLASH) {
1760 if (i == INT_BACKSLASH) {
1761
1765 c = _decodeEscaped();
1766 } else if (i <= endChar) {
1767 if (i == endChar) {
1768 break;
1769 }
1770 if (i < INT_SPACE) {
1771 _throwUnquotedSpace(i, "name");
1772 }
1773 }
1774 }
1775 hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + c;
1776
1777 outBuf[outPtr++] = c;
1778
1779
1780 if (outPtr >= outBuf.length) {
1781 outBuf = _textBuffer.finishCurrentSegment();
1782 outPtr = 0;
1783 }
1784 }
1785 _textBuffer.setCurrentLength(outPtr);
1786 {
1787 TextBuffer tb = _textBuffer;
1788 char[] buf = tb.getTextBuffer();
1789 int start = tb.getTextOffset();
1790 int len = tb.size();
1791 return _symbols.findSymbol(buf, start, len, hash);
1792 }
1793 }
1794
1795
1801 protected String _handleOddName(int i) throws IOException
1802 {
1803
1804 if (i == '\'' && (_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) {
1805 return _parseAposName();
1806 }
1807
1808 if ((_features & FEAT_MASK_ALLOW_UNQUOTED_NAMES) == 0) {
1809 _reportUnexpectedChar(i, "was expecting double-quote to start field name");
1810 }
1811 final int[] codes = CharTypes.getInputCodeLatin1JsNames();
1812 final int maxCode = codes.length;
1813
1814
1815 boolean firstOk;
1816
1817 if (i < maxCode) {
1818 firstOk = (codes[i] == 0);
1819 } else {
1820 firstOk = Character.isJavaIdentifierPart((char) i);
1821 }
1822 if (!firstOk) {
1823 _reportUnexpectedChar(i, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name");
1824 }
1825 int ptr = _inputPtr;
1826 int hash = _hashSeed;
1827 final int inputLen = _inputEnd;
1828
1829 if (ptr < inputLen) {
1830 do {
1831 int ch = _inputBuffer[ptr];
1832 if (ch < maxCode) {
1833 if (codes[ch] != 0) {
1834 int start = _inputPtr-1;
1835 _inputPtr = ptr;
1836 return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
1837 }
1838 } else if (!Character.isJavaIdentifierPart((char) ch)) {
1839 int start = _inputPtr-1;
1840 _inputPtr = ptr;
1841 return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
1842 }
1843 hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
1844 ++ptr;
1845 } while (ptr < inputLen);
1846 }
1847 int start = _inputPtr-1;
1848 _inputPtr = ptr;
1849 return _handleOddName2(start, hash, codes);
1850 }
1851
1852 protected String _parseAposName() throws IOException
1853 {
1854
1855 int ptr = _inputPtr;
1856 int hash = _hashSeed;
1857 final int inputLen = _inputEnd;
1858
1859 if (ptr < inputLen) {
1860 final int[] codes = _icLatin1;
1861 final int maxCode = codes.length;
1862
1863 do {
1864 int ch = _inputBuffer[ptr];
1865 if (ch == '\'') {
1866 int start = _inputPtr;
1867 _inputPtr = ptr+1;
1868 return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
1869 }
1870 if (ch < maxCode && codes[ch] != 0) {
1871 break;
1872 }
1873 hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
1874 ++ptr;
1875 } while (ptr < inputLen);
1876 }
1877
1878 int start = _inputPtr;
1879 _inputPtr = ptr;
1880
1881 return _parseName2(start, hash, '\'');
1882 }
1883
1884
1888 protected JsonToken _handleOddValue(int i) throws IOException
1889 {
1890
1891 switch (i) {
1892 case '\'':
1893
1898 if ((_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) {
1899 return _handleApos();
1900 }
1901 break;
1902 case ']':
1903
1907 if (!_parsingContext.inArray()) {
1908 break;
1909 }
1910
1911 case ',':
1912
1913 if (!_parsingContext.inRoot()) {
1914 if ((_features & FEAT_MASK_ALLOW_MISSING) != 0) {
1915 --_inputPtr;
1916 return JsonToken.VALUE_NULL;
1917 }
1918 }
1919 break;
1920 case 'N':
1921 _matchToken("NaN", 1);
1922 if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
1923 return resetAsNaN("NaN", Double.NaN);
1924 }
1925 _reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
1926 break;
1927 case 'I':
1928 _matchToken("Infinity", 1);
1929 if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
1930 return resetAsNaN("Infinity", Double.POSITIVE_INFINITY);
1931 }
1932 _reportError("Non-standard token 'Infinity': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
1933 break;
1934 case '+':
1935 if (_inputPtr >= _inputEnd) {
1936 if (!_loadMore()) {
1937 _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_INT);
1938 }
1939 }
1940 return _handleInvalidNumberStart(_inputBuffer[_inputPtr++], false);
1941 }
1942
1943 if (Character.isJavaIdentifierStart(i)) {
1944 _reportInvalidToken(""+((char) i), _validJsonTokenList());
1945 }
1946
1947 _reportUnexpectedChar(i, "expected a valid value "+_validJsonValueList());
1948 return null;
1949 }
1950
1951 protected JsonToken _handleApos() throws IOException
1952 {
1953 char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
1954 int outPtr = _textBuffer.getCurrentSegmentSize();
1955
1956 while (true) {
1957 if (_inputPtr >= _inputEnd) {
1958 if (!_loadMore()) {
1959 _reportInvalidEOF(": was expecting closing quote for a string value",
1960 JsonToken.VALUE_STRING);
1961 }
1962 }
1963 char c = _inputBuffer[_inputPtr++];
1964 int i = (int) c;
1965 if (i <= '\\') {
1966 if (i == '\\') {
1967
1971 c = _decodeEscaped();
1972 } else if (i <= '\'') {
1973 if (i == '\'') {
1974 break;
1975 }
1976 if (i < INT_SPACE) {
1977 _throwUnquotedSpace(i, "string value");
1978 }
1979 }
1980 }
1981
1982 if (outPtr >= outBuf.length) {
1983 outBuf = _textBuffer.finishCurrentSegment();
1984 outPtr = 0;
1985 }
1986
1987 outBuf[outPtr++] = c;
1988 }
1989 _textBuffer.setCurrentLength(outPtr);
1990 return JsonToken.VALUE_STRING;
1991 }
1992
1993 private String _handleOddName2(int startPtr, int hash, int[] codes) throws IOException
1994 {
1995 _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr));
1996 char[] outBuf = _textBuffer.getCurrentSegment();
1997 int outPtr = _textBuffer.getCurrentSegmentSize();
1998 final int maxCode = codes.length;
1999
2000 while (true) {
2001 if (_inputPtr >= _inputEnd) {
2002 if (!_loadMore()) {
2003 break;
2004 }
2005 }
2006 char c = _inputBuffer[_inputPtr];
2007 int i = (int) c;
2008 if (i < maxCode) {
2009 if (codes[i] != 0) {
2010 break;
2011 }
2012 } else if (!Character.isJavaIdentifierPart(c)) {
2013 break;
2014 }
2015 ++_inputPtr;
2016 hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + i;
2017
2018 outBuf[outPtr++] = c;
2019
2020
2021 if (outPtr >= outBuf.length) {
2022 outBuf = _textBuffer.finishCurrentSegment();
2023 outPtr = 0;
2024 }
2025 }
2026 _textBuffer.setCurrentLength(outPtr);
2027 {
2028 TextBuffer tb = _textBuffer;
2029 char[] buf = tb.getTextBuffer();
2030 int start = tb.getTextOffset();
2031 int len = tb.size();
2032
2033 return _symbols.findSymbol(buf, start, len, hash);
2034 }
2035 }
2036
2037 @Override
2038 protected final void _finishString() throws IOException
2039 {
2040
2044 int ptr = _inputPtr;
2045 final int inputLen = _inputEnd;
2046
2047 if (ptr < inputLen) {
2048 final int[] codes = _icLatin1;
2049 final int maxCode = codes.length;
2050
2051 do {
2052 int ch = _inputBuffer[ptr];
2053 if (ch < maxCode && codes[ch] != 0) {
2054 if (ch == '"') {
2055 _textBuffer.resetWithShared(_inputBuffer, _inputPtr, (ptr-_inputPtr));
2056 _inputPtr = ptr+1;
2057
2058 return;
2059 }
2060 break;
2061 }
2062 ++ptr;
2063 } while (ptr < inputLen);
2064 }
2065
2066
2067 _textBuffer.resetWithCopy(_inputBuffer, _inputPtr, (ptr-_inputPtr));
2068 _inputPtr = ptr;
2069 _finishString2();
2070 }
2071
2072 protected void _finishString2() throws IOException
2073 {
2074 char[] outBuf = _textBuffer.getCurrentSegment();
2075 int outPtr = _textBuffer.getCurrentSegmentSize();
2076 final int[] codes = _icLatin1;
2077 final int maxCode = codes.length;
2078
2079 while (true) {
2080 if (_inputPtr >= _inputEnd) {
2081 if (!_loadMore()) {
2082 _reportInvalidEOF(": was expecting closing quote for a string value",
2083 JsonToken.VALUE_STRING);
2084 }
2085 }
2086 char c = _inputBuffer[_inputPtr++];
2087 int i = (int) c;
2088 if (i < maxCode && codes[i] != 0) {
2089 if (i == INT_QUOTE) {
2090 break;
2091 } else if (i == INT_BACKSLASH) {
2092
2096 c = _decodeEscaped();
2097 } else if (i < INT_SPACE) {
2098 _throwUnquotedSpace(i, "string value");
2099 }
2100 }
2101
2102 if (outPtr >= outBuf.length) {
2103 outBuf = _textBuffer.finishCurrentSegment();
2104 outPtr = 0;
2105 }
2106
2107 outBuf[outPtr++] = c;
2108 }
2109 _textBuffer.setCurrentLength(outPtr);
2110 }
2111
2112
2117 protected final void _skipString() throws IOException
2118 {
2119 _tokenIncomplete = false;
2120
2121 int inPtr = _inputPtr;
2122 int inLen = _inputEnd;
2123 char[] inBuf = _inputBuffer;
2124
2125 while (true) {
2126 if (inPtr >= inLen) {
2127 _inputPtr = inPtr;
2128 if (!_loadMore()) {
2129 _reportInvalidEOF(": was expecting closing quote for a string value",
2130 JsonToken.VALUE_STRING);
2131 }
2132 inPtr = _inputPtr;
2133 inLen = _inputEnd;
2134 }
2135 char c = inBuf[inPtr++];
2136 int i = (int) c;
2137 if (i <= INT_BACKSLASH) {
2138 if (i == INT_BACKSLASH) {
2139
2140
2141 _inputPtr = inPtr;
2142 _decodeEscaped();
2143 inPtr = _inputPtr;
2144 inLen = _inputEnd;
2145 } else if (i <= INT_QUOTE) {
2146 if (i == INT_QUOTE) {
2147 _inputPtr = inPtr;
2148 break;
2149 }
2150 if (i < INT_SPACE) {
2151 _inputPtr = inPtr;
2152 _throwUnquotedSpace(i, "string value");
2153 }
2154 }
2155 }
2156 }
2157 }
2158
2159
2164
2165
2169 protected final void _skipCR() throws IOException {
2170 if (_inputPtr < _inputEnd || _loadMore()) {
2171 if (_inputBuffer[_inputPtr] == '\n') {
2172 ++_inputPtr;
2173 }
2174 }
2175 ++_currInputRow;
2176 _currInputRowStart = _inputPtr;
2177 }
2178
2179 private final int _skipColon() throws IOException
2180 {
2181 if ((_inputPtr + 4) >= _inputEnd) {
2182 return _skipColon2(false);
2183 }
2184 char c = _inputBuffer[_inputPtr];
2185 if (c == ':') {
2186 int i = _inputBuffer[++_inputPtr];
2187 if (i > INT_SPACE) {
2188 if (i == INT_SLASH || i == INT_HASH) {
2189 return _skipColon2(true);
2190 }
2191 ++_inputPtr;
2192 return i;
2193 }
2194 if (i == INT_SPACE || i == INT_TAB) {
2195 i = (int) _inputBuffer[++_inputPtr];
2196 if (i > INT_SPACE) {
2197 if (i == INT_SLASH || i == INT_HASH) {
2198 return _skipColon2(true);
2199 }
2200 ++_inputPtr;
2201 return i;
2202 }
2203 }
2204 return _skipColon2(true);
2205 }
2206 if (c == ' ' || c == '\t') {
2207 c = _inputBuffer[++_inputPtr];
2208 }
2209 if (c == ':') {
2210 int i = _inputBuffer[++_inputPtr];
2211 if (i > INT_SPACE) {
2212 if (i == INT_SLASH || i == INT_HASH) {
2213 return _skipColon2(true);
2214 }
2215 ++_inputPtr;
2216 return i;
2217 }
2218 if (i == INT_SPACE || i == INT_TAB) {
2219 i = (int) _inputBuffer[++_inputPtr];
2220 if (i > INT_SPACE) {
2221 if (i == INT_SLASH || i == INT_HASH) {
2222 return _skipColon2(true);
2223 }
2224 ++_inputPtr;
2225 return i;
2226 }
2227 }
2228 return _skipColon2(true);
2229 }
2230 return _skipColon2(false);
2231 }
2232
2233 private final int _skipColon2(boolean gotColon) throws IOException
2234 {
2235 while (_inputPtr < _inputEnd || _loadMore()) {
2236 int i = (int) _inputBuffer[_inputPtr++];
2237 if (i > INT_SPACE) {
2238 if (i == INT_SLASH) {
2239 _skipComment();
2240 continue;
2241 }
2242 if (i == INT_HASH) {
2243 if (_skipYAMLComment()) {
2244 continue;
2245 }
2246 }
2247 if (gotColon) {
2248 return i;
2249 }
2250 if (i != INT_COLON) {
2251 _reportUnexpectedChar(i, "was expecting a colon to separate field name and value");
2252 }
2253 gotColon = true;
2254 continue;
2255 }
2256 if (i < INT_SPACE) {
2257 if (i == INT_LF) {
2258 ++_currInputRow;
2259 _currInputRowStart = _inputPtr;
2260 } else if (i == INT_CR) {
2261 _skipCR();
2262 } else if (i != INT_TAB) {
2263 _throwInvalidSpace(i);
2264 }
2265 }
2266 }
2267 _reportInvalidEOF(" within/between "+_parsingContext.typeDesc()+" entries",
2268 null);
2269 return -1;
2270 }
2271
2272
2273 private final int _skipColonFast(int ptr) throws IOException
2274 {
2275 int i = (int) _inputBuffer[ptr++];
2276 if (i == INT_COLON) {
2277 i = _inputBuffer[ptr++];
2278 if (i > INT_SPACE) {
2279 if (i != INT_SLASH && i != INT_HASH) {
2280 _inputPtr = ptr;
2281 return i;
2282 }
2283 } else if (i == INT_SPACE || i == INT_TAB) {
2284 i = (int) _inputBuffer[ptr++];
2285 if (i > INT_SPACE) {
2286 if (i != INT_SLASH && i != INT_HASH) {
2287 _inputPtr = ptr;
2288 return i;
2289 }
2290 }
2291 }
2292 _inputPtr = ptr-1;
2293 return _skipColon2(true);
2294 }
2295 if (i == INT_SPACE || i == INT_TAB) {
2296 i = _inputBuffer[ptr++];
2297 }
2298 boolean gotColon = (i == INT_COLON);
2299 if (gotColon) {
2300 i = _inputBuffer[ptr++];
2301 if (i > INT_SPACE) {
2302 if (i != INT_SLASH && i != INT_HASH) {
2303 _inputPtr = ptr;
2304 return i;
2305 }
2306 } else if (i == INT_SPACE || i == INT_TAB) {
2307 i = (int) _inputBuffer[ptr++];
2308 if (i > INT_SPACE) {
2309 if (i != INT_SLASH && i != INT_HASH) {
2310 _inputPtr = ptr;
2311 return i;
2312 }
2313 }
2314 }
2315 }
2316 _inputPtr = ptr-1;
2317 return _skipColon2(gotColon);
2318 }
2319
2320
2321 private final int _skipComma(int i) throws IOException
2322 {
2323 if (i != INT_COMMA) {
2324 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
2325 }
2326 while (_inputPtr < _inputEnd) {
2327 i = (int) _inputBuffer[_inputPtr++];
2328 if (i > INT_SPACE) {
2329 if (i == INT_SLASH || i == INT_HASH) {
2330 --_inputPtr;
2331 return _skipAfterComma2();
2332 }
2333 return i;
2334 }
2335 if (i < INT_SPACE) {
2336 if (i == INT_LF) {
2337 ++_currInputRow;
2338 _currInputRowStart = _inputPtr;
2339 } else if (i == INT_CR) {
2340 _skipCR();
2341 } else if (i != INT_TAB) {
2342 _throwInvalidSpace(i);
2343 }
2344 }
2345 }
2346 return _skipAfterComma2();
2347 }
2348
2349 private final int _skipAfterComma2() throws IOException
2350 {
2351 while (_inputPtr < _inputEnd || _loadMore()) {
2352 int i = (int) _inputBuffer[_inputPtr++];
2353 if (i > INT_SPACE) {
2354 if (i == INT_SLASH) {
2355 _skipComment();
2356 continue;
2357 }
2358 if (i == INT_HASH) {
2359 if (_skipYAMLComment()) {
2360 continue;
2361 }
2362 }
2363 return i;
2364 }
2365 if (i < INT_SPACE) {
2366 if (i == INT_LF) {
2367 ++_currInputRow;
2368 _currInputRowStart = _inputPtr;
2369 } else if (i == INT_CR) {
2370 _skipCR();
2371 } else if (i != INT_TAB) {
2372 _throwInvalidSpace(i);
2373 }
2374 }
2375 }
2376 throw _constructError("Unexpected end-of-input within/between "+_parsingContext.typeDesc()+" entries");
2377 }
2378
2379 private final int _skipWSOrEnd() throws IOException
2380 {
2381
2382
2383 if (_inputPtr >= _inputEnd) {
2384 if (!_loadMore()) {
2385 return _eofAsNextChar();
2386 }
2387 }
2388 int i = _inputBuffer[_inputPtr++];
2389 if (i > INT_SPACE) {
2390 if (i == INT_SLASH || i == INT_HASH) {
2391 --_inputPtr;
2392 return _skipWSOrEnd2();
2393 }
2394 return i;
2395 }
2396 if (i != INT_SPACE) {
2397 if (i == INT_LF) {
2398 ++_currInputRow;
2399 _currInputRowStart = _inputPtr;
2400 } else if (i == INT_CR) {
2401 _skipCR();
2402 } else if (i != INT_TAB) {
2403 _throwInvalidSpace(i);
2404 }
2405 }
2406
2407 while (_inputPtr < _inputEnd) {
2408 i = (int) _inputBuffer[_inputPtr++];
2409 if (i > INT_SPACE) {
2410 if (i == INT_SLASH || i == INT_HASH) {
2411 --_inputPtr;
2412 return _skipWSOrEnd2();
2413 }
2414 return i;
2415 }
2416 if (i != INT_SPACE) {
2417 if (i == INT_LF) {
2418 ++_currInputRow;
2419 _currInputRowStart = _inputPtr;
2420 } else if (i == INT_CR) {
2421 _skipCR();
2422 } else if (i != INT_TAB) {
2423 _throwInvalidSpace(i);
2424 }
2425 }
2426 }
2427 return _skipWSOrEnd2();
2428 }
2429
2430 private int _skipWSOrEnd2() throws IOException
2431 {
2432 while (true) {
2433 if (_inputPtr >= _inputEnd) {
2434 if (!_loadMore()) {
2435 return _eofAsNextChar();
2436 }
2437 }
2438 int i = (int) _inputBuffer[_inputPtr++];
2439 if (i > INT_SPACE) {
2440 if (i == INT_SLASH) {
2441 _skipComment();
2442 continue;
2443 }
2444 if (i == INT_HASH) {
2445 if (_skipYAMLComment()) {
2446 continue;
2447 }
2448 }
2449 return i;
2450 } else if (i != INT_SPACE) {
2451 if (i == INT_LF) {
2452 ++_currInputRow;
2453 _currInputRowStart = _inputPtr;
2454 } else if (i == INT_CR) {
2455 _skipCR();
2456 } else if (i != INT_TAB) {
2457 _throwInvalidSpace(i);
2458 }
2459 }
2460 }
2461 }
2462
2463 private void _skipComment() throws IOException
2464 {
2465 if ((_features & FEAT_MASK_ALLOW_JAVA_COMMENTS) == 0) {
2466 _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)");
2467 }
2468
2469 if (_inputPtr >= _inputEnd && !_loadMore()) {
2470 _reportInvalidEOF(" in a comment", null);
2471 }
2472 char c = _inputBuffer[_inputPtr++];
2473 if (c == '/') {
2474 _skipLine();
2475 } else if (c == '*') {
2476 _skipCComment();
2477 } else {
2478 _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment");
2479 }
2480 }
2481
2482 private void _skipCComment() throws IOException
2483 {
2484
2485 while ((_inputPtr < _inputEnd) || _loadMore()) {
2486 int i = (int) _inputBuffer[_inputPtr++];
2487 if (i <= '*') {
2488 if (i == '*') {
2489 if ((_inputPtr >= _inputEnd) && !_loadMore()) {
2490 break;
2491 }
2492 if (_inputBuffer[_inputPtr] == INT_SLASH) {
2493 ++_inputPtr;
2494 return;
2495 }
2496 continue;
2497 }
2498 if (i < INT_SPACE) {
2499 if (i == INT_LF) {
2500 ++_currInputRow;
2501 _currInputRowStart = _inputPtr;
2502 } else if (i == INT_CR) {
2503 _skipCR();
2504 } else if (i != INT_TAB) {
2505 _throwInvalidSpace(i);
2506 }
2507 }
2508 }
2509 }
2510 _reportInvalidEOF(" in a comment", null);
2511 }
2512
2513 private boolean _skipYAMLComment() throws IOException
2514 {
2515 if ((_features & FEAT_MASK_ALLOW_YAML_COMMENTS) == 0) {
2516 return false;
2517 }
2518 _skipLine();
2519 return true;
2520 }
2521
2522 private void _skipLine() throws IOException
2523 {
2524
2525 while ((_inputPtr < _inputEnd) || _loadMore()) {
2526 int i = (int) _inputBuffer[_inputPtr++];
2527 if (i < INT_SPACE) {
2528 if (i == INT_LF) {
2529 ++_currInputRow;
2530 _currInputRowStart = _inputPtr;
2531 break;
2532 } else if (i == INT_CR) {
2533 _skipCR();
2534 break;
2535 } else if (i != INT_TAB) {
2536 _throwInvalidSpace(i);
2537 }
2538 }
2539 }
2540 }
2541
2542 @Override
2543 protected char _decodeEscaped() throws IOException
2544 {
2545 if (_inputPtr >= _inputEnd) {
2546 if (!_loadMore()) {
2547 _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
2548 }
2549 }
2550 char c = _inputBuffer[_inputPtr++];
2551
2552 switch ((int) c) {
2553
2554 case 'b':
2555 return '\b';
2556 case 't':
2557 return '\t';
2558 case 'n':
2559 return '\n';
2560 case 'f':
2561 return '\f';
2562 case 'r':
2563 return '\r';
2564
2565
2566 case '"':
2567 case '/':
2568 case '\\':
2569 return c;
2570
2571 case 'u':
2572 break;
2573
2574 default:
2575 return _handleUnrecognizedCharacterEscape(c);
2576 }
2577
2578
2579 int value = 0;
2580 for (int i = 0; i < 4; ++i) {
2581 if (_inputPtr >= _inputEnd) {
2582 if (!_loadMore()) {
2583 _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
2584 }
2585 }
2586 int ch = (int) _inputBuffer[_inputPtr++];
2587 int digit = CharTypes.charToHex(ch);
2588 if (digit < 0) {
2589 _reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence");
2590 }
2591 value = (value << 4) | digit;
2592 }
2593 return (char) value;
2594 }
2595
2596 private final void _matchTrue() throws IOException {
2597 int ptr = _inputPtr;
2598 if ((ptr + 3) < _inputEnd) {
2599 final char[] b = _inputBuffer;
2600 if (b[ptr] == 'r' && b[++ptr] == 'u' && b[++ptr] == 'e') {
2601 char c = b[++ptr];
2602 if (c < '0' || c == ']' || c == '}') {
2603 _inputPtr = ptr;
2604 return;
2605 }
2606 }
2607 }
2608
2609 _matchToken("true", 1);
2610 }
2611
2612 private final void _matchFalse() throws IOException {
2613 int ptr = _inputPtr;
2614 if ((ptr + 4) < _inputEnd) {
2615 final char[] b = _inputBuffer;
2616 if (b[ptr] == 'a' && b[++ptr] == 'l' && b[++ptr] == 's' && b[++ptr] == 'e') {
2617 char c = b[++ptr];
2618 if (c < '0' || c == ']' || c == '}') {
2619 _inputPtr = ptr;
2620 return;
2621 }
2622 }
2623 }
2624
2625 _matchToken("false", 1);
2626 }
2627
2628 private final void _matchNull() throws IOException {
2629 int ptr = _inputPtr;
2630 if ((ptr + 3) < _inputEnd) {
2631 final char[] b = _inputBuffer;
2632 if (b[ptr] == 'u' && b[++ptr] == 'l' && b[++ptr] == 'l') {
2633 char c = b[++ptr];
2634 if (c < '0' || c == ']' || c == '}') {
2635 _inputPtr = ptr;
2636 return;
2637 }
2638 }
2639 }
2640
2641 _matchToken("null", 1);
2642 }
2643
2644
2647 protected final void _matchToken(String matchStr, int i) throws IOException
2648 {
2649 final int len = matchStr.length();
2650 if ((_inputPtr + len) >= _inputEnd) {
2651 _matchToken2(matchStr, i);
2652 return;
2653 }
2654
2655 do {
2656 if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) {
2657 _reportInvalidToken(matchStr.substring(0, i));
2658 }
2659 ++_inputPtr;
2660 } while (++i < len);
2661 int ch = _inputBuffer[_inputPtr];
2662 if (ch >= '0' && ch != ']' && ch != '}') {
2663 _checkMatchEnd(matchStr, i, ch);
2664 }
2665 }
2666
2667 private final void _matchToken2(String matchStr, int i) throws IOException
2668 {
2669 final int len = matchStr.length();
2670 do {
2671 if (((_inputPtr >= _inputEnd) && !_loadMore())
2672 || (_inputBuffer[_inputPtr] != matchStr.charAt(i))) {
2673 _reportInvalidToken(matchStr.substring(0, i));
2674 }
2675 ++_inputPtr;
2676 } while (++i < len);
2677
2678
2679 if (_inputPtr >= _inputEnd && !_loadMore()) {
2680 return;
2681 }
2682 int ch = _inputBuffer[_inputPtr];
2683 if (ch >= '0' && ch != ']' && ch != '}') {
2684 _checkMatchEnd(matchStr, i, ch);
2685 }
2686 }
2687
2688 private final void _checkMatchEnd(String matchStr, int i, int c) throws IOException {
2689
2690 char ch = (char) c;
2691 if (Character.isJavaIdentifierPart(ch)) {
2692 _reportInvalidToken(matchStr.substring(0, i));
2693 }
2694 }
2695
2696
2701
2702
2706 @SuppressWarnings("resource")
2707 protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException
2708 {
2709 ByteArrayBuilder builder = _getByteArrayBuilder();
2710
2711
2712 while (true) {
2713
2714 char ch;
2715 do {
2716 if (_inputPtr >= _inputEnd) {
2717 _loadMoreGuaranteed();
2718 }
2719 ch = _inputBuffer[_inputPtr++];
2720 } while (ch <= INT_SPACE);
2721 int bits = b64variant.decodeBase64Char(ch);
2722 if (bits < 0) {
2723 if (ch == '"') {
2724 return builder.toByteArray();
2725 }
2726 bits = _decodeBase64Escape(b64variant, ch, 0);
2727 if (bits < 0) {
2728 continue;
2729 }
2730 }
2731 int decodedData = bits;
2732
2733
2734
2735 if (_inputPtr >= _inputEnd) {
2736 _loadMoreGuaranteed();
2737 }
2738 ch = _inputBuffer[_inputPtr++];
2739 bits = b64variant.decodeBase64Char(ch);
2740 if (bits < 0) {
2741 bits = _decodeBase64Escape(b64variant, ch, 1);
2742 }
2743 decodedData = (decodedData << 6) | bits;
2744
2745
2746 if (_inputPtr >= _inputEnd) {
2747 _loadMoreGuaranteed();
2748 }
2749 ch = _inputBuffer[_inputPtr++];
2750 bits = b64variant.decodeBase64Char(ch);
2751
2752
2753 if (bits < 0) {
2754 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
2755
2756 if (ch == '"') {
2757 decodedData >>= 4;
2758 builder.append(decodedData);
2759 if (b64variant.usesPadding()) {
2760 --_inputPtr;
2761 _handleBase64MissingPadding(b64variant);
2762 }
2763 return builder.toByteArray();
2764 }
2765 bits = _decodeBase64Escape(b64variant, ch, 2);
2766 }
2767 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
2768
2769 if (_inputPtr >= _inputEnd) {
2770 _loadMoreGuaranteed();
2771 }
2772 ch = _inputBuffer[_inputPtr++];
2773 if (!b64variant.usesPaddingChar(ch)) {
2774 if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) {
2775 throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
2776 }
2777 }
2778
2779 decodedData >>= 4;
2780 builder.append(decodedData);
2781 continue;
2782 }
2783
2784 }
2785
2786 decodedData = (decodedData << 6) | bits;
2787
2788 if (_inputPtr >= _inputEnd) {
2789 _loadMoreGuaranteed();
2790 }
2791 ch = _inputBuffer[_inputPtr++];
2792 bits = b64variant.decodeBase64Char(ch);
2793 if (bits < 0) {
2794 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
2795
2796 if (ch == '"') {
2797 decodedData >>= 2;
2798 builder.appendTwoBytes(decodedData);
2799 if (b64variant.usesPadding()) {
2800 --_inputPtr;
2801 _handleBase64MissingPadding(b64variant);
2802 }
2803 return builder.toByteArray();
2804 }
2805 bits = _decodeBase64Escape(b64variant, ch, 3);
2806 }
2807 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
2808
2809
2810
2811
2812
2813 decodedData >>= 2;
2814 builder.appendTwoBytes(decodedData);
2815 continue;
2816 }
2817
2818 }
2819
2820 decodedData = (decodedData << 6) | bits;
2821 builder.appendThreeBytes(decodedData);
2822 }
2823 }
2824
2825
2830
2831 @Override
2832 public JsonLocation getTokenLocation()
2833 {
2834 if (_currToken == JsonToken.FIELD_NAME) {
2835 long total = _currInputProcessed + (_nameStartOffset-1);
2836 return new JsonLocation(_getSourceReference(),
2837 -1L, total, _nameStartRow, _nameStartCol);
2838 }
2839 return new JsonLocation(_getSourceReference(),
2840 -1L, _tokenInputTotal-1, _tokenInputRow, _tokenInputCol);
2841 }
2842
2843 @Override
2844 public JsonLocation getCurrentLocation() {
2845 final int col = _inputPtr - _currInputRowStart + 1;
2846 return new JsonLocation(_getSourceReference(),
2847 -1L, _currInputProcessed + _inputPtr,
2848 _currInputRow, col);
2849 }
2850
2851
2852 private final void _updateLocation()
2853 {
2854 int ptr = _inputPtr;
2855 _tokenInputTotal = _currInputProcessed + ptr;
2856 _tokenInputRow = _currInputRow;
2857 _tokenInputCol = ptr - _currInputRowStart;
2858 }
2859
2860
2861 private final void _updateNameLocation()
2862 {
2863 int ptr = _inputPtr;
2864 _nameStartOffset = ptr;
2865 _nameStartRow = _currInputRow;
2866 _nameStartCol = ptr - _currInputRowStart;
2867 }
2868
2869
2874
2875 protected void _reportInvalidToken(String matchedPart) throws IOException {
2876 _reportInvalidToken(matchedPart, _validJsonTokenList());
2877 }
2878
2879 protected void _reportInvalidToken(String matchedPart, String msg) throws IOException
2880 {
2881
2885 StringBuilder sb = new StringBuilder(matchedPart);
2886 while ((_inputPtr < _inputEnd) || _loadMore()) {
2887 char c = _inputBuffer[_inputPtr];
2888 if (!Character.isJavaIdentifierPart(c)) {
2889 break;
2890 }
2891 ++_inputPtr;
2892 sb.append(c);
2893 if (sb.length() >= MAX_ERROR_TOKEN_LENGTH) {
2894 sb.append("...");
2895 break;
2896 }
2897 }
2898 _reportError("Unrecognized token '%s': was expecting %s", sb, msg);
2899 }
2900
2901
2906
2907 private void _closeScope(int i) throws JsonParseException {
2908 if (i == INT_RBRACKET) {
2909 _updateLocation();
2910 if (!_parsingContext.inArray()) {
2911 _reportMismatchedEndMarker(i, '}');
2912 }
2913 _parsingContext = _parsingContext.clearAndGetParent();
2914 _currToken = JsonToken.END_ARRAY;
2915 }
2916 if (i == INT_RCURLY) {
2917 _updateLocation();
2918 if (!_parsingContext.inObject()) {
2919 _reportMismatchedEndMarker(i, ']');
2920 }
2921 _parsingContext = _parsingContext.clearAndGetParent();
2922 _currToken = JsonToken.END_OBJECT;
2923 }
2924 }
2925 }
2926