1 package com.fasterxml.jackson.core.json;
2
3 import java.io.*;
4
5 import com.fasterxml.jackson.core.*;
6 import com.fasterxml.jackson.core.base.ParserBase;
7 import com.fasterxml.jackson.core.io.CharTypes;
8 import com.fasterxml.jackson.core.io.IOContext;
9 import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
10 import com.fasterxml.jackson.core.util.*;
11
12 import static com.fasterxml.jackson.core.JsonTokenId.*;
13
14
18 public class UTF8StreamJsonParser
19 extends ParserBase
20 {
21 final static byte BYTE_LF = (byte) '\n';
22
23 @SuppressWarnings("deprecation")
24 private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
25 @SuppressWarnings("deprecation")
26 private final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask();
27 @SuppressWarnings("deprecation")
28 private final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask();
29 @SuppressWarnings("deprecation")
30 private final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask();
31 private final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask();
32 private final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask();
33 private final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask();
34 private final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask();
35
36
37 private final static int[] _icUTF8 = CharTypes.getInputCodeUtf8();
38
39
40
41 protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
42
43
48
49
54 protected ObjectCodec _objectCodec;
55
56
59 final protected ByteQuadsCanonicalizer _symbols;
60
61
66
67
70 protected int[] _quadBuffer = new int[16];
71
72
77 protected boolean _tokenIncomplete;
78
79
82 private int _quad1;
83
84
92 protected int _nameStartOffset;
93
94
97 protected int _nameStartRow;
98
99
102 protected int _nameStartCol;
103
104
109
110 protected InputStream _inputStream;
111
112
117
118
123 protected byte[] _inputBuffer;
124
125
132 protected boolean _bufferRecyclable;
133
134
139
140
143 @Deprecated
144 public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in,
145 ObjectCodec codec, ByteQuadsCanonicalizer sym,
146 byte[] inputBuffer, int start, int end,
147 boolean bufferRecyclable)
148 {
149 this(ctxt, features, in, codec, sym,
150 inputBuffer, start, end, 0, bufferRecyclable);
151 }
152
153 public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in,
154 ObjectCodec codec, ByteQuadsCanonicalizer sym,
155 byte[] inputBuffer, int start, int end, int bytesPreProcessed,
156 boolean bufferRecyclable)
157 {
158 super(ctxt, features);
159 _inputStream = in;
160 _objectCodec = codec;
161 _symbols = sym;
162 _inputBuffer = inputBuffer;
163 _inputPtr = start;
164 _inputEnd = end;
165 _currInputRowStart = start - bytesPreProcessed;
166
167 _currInputProcessed = -start + bytesPreProcessed;
168 _bufferRecyclable = bufferRecyclable;
169 }
170
171 @Override
172 public ObjectCodec getCodec() {
173 return _objectCodec;
174 }
175
176 @Override
177 public void setCodec(ObjectCodec c) {
178 _objectCodec = c;
179 }
180
181
186
187 @Override
188 public int releaseBuffered(OutputStream out) throws IOException
189 {
190 int count = _inputEnd - _inputPtr;
191 if (count < 1) {
192 return 0;
193 }
194
195 int origPtr = _inputPtr;
196 _inputPtr += count;
197 out.write(_inputBuffer, origPtr, count);
198 return count;
199 }
200
201 @Override
202 public Object getInputSource() {
203 return _inputStream;
204 }
205
206
211
212 protected final boolean _loadMore() throws IOException
213 {
214 if (_inputStream != null) {
215 int space = _inputBuffer.length;
216 if (space == 0) {
217 return false;
218 }
219
220 int count = _inputStream.read(_inputBuffer, 0, space);
221 if (count > 0) {
222 final int bufSize = _inputEnd;
223
224 _currInputProcessed += bufSize;
225 _currInputRowStart -= bufSize;
226
227
228
229
230 _nameStartOffset -= bufSize;
231
232 _inputPtr = 0;
233 _inputEnd = count;
234
235 return true;
236 }
237
238 _closeInput();
239
240 if (count == 0) {
241 throw new IOException("InputStream.read() returned 0 characters when trying to read "+_inputBuffer.length+" bytes");
242 }
243 }
244 return false;
245 }
246
247 @Override
248 protected void _closeInput() throws IOException
249 {
250
251
252 if (_inputStream != null) {
253 if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
254 _inputStream.close();
255 }
256 _inputStream = null;
257 }
258 }
259
260
266 @Override
267 protected void _releaseBuffers() throws IOException
268 {
269 super._releaseBuffers();
270
271 _symbols.release();
272 if (_bufferRecyclable) {
273 byte[] buf = _inputBuffer;
274 if (buf != null) {
275
276
277 if (buf != NO_BYTES) {
278 _inputBuffer = NO_BYTES;
279 _ioContext.releaseReadIOBuffer(buf);
280 }
281 }
282 }
283 }
284
285
290
291 @Override
292 public String getText() throws IOException
293 {
294 if (_currToken == JsonToken.VALUE_STRING) {
295 if (_tokenIncomplete) {
296 _tokenIncomplete = false;
297 return _finishAndReturnString();
298 }
299 return _textBuffer.contentsAsString();
300 }
301 return _getText2(_currToken);
302 }
303
304 @Override
305 public int getText(Writer writer) throws IOException
306 {
307 JsonToken t = _currToken;
308 if (t == JsonToken.VALUE_STRING) {
309 if (_tokenIncomplete) {
310 _tokenIncomplete = false;
311 _finishString();
312 }
313 return _textBuffer.contentsToWriter(writer);
314 }
315 if (t == JsonToken.FIELD_NAME) {
316 String n = _parsingContext.getCurrentName();
317 writer.write(n);
318 return n.length();
319 }
320 if (t != null) {
321 if (t.isNumeric()) {
322 return _textBuffer.contentsToWriter(writer);
323 }
324 char[] ch = t.asCharArray();
325 writer.write(ch);
326 return ch.length;
327 }
328 return 0;
329 }
330
331
332
333
334 @Override
335 public String getValueAsString() throws IOException
336 {
337 if (_currToken == JsonToken.VALUE_STRING) {
338 if (_tokenIncomplete) {
339 _tokenIncomplete = false;
340 return _finishAndReturnString();
341 }
342 return _textBuffer.contentsAsString();
343 }
344 if (_currToken == JsonToken.FIELD_NAME) {
345 return getCurrentName();
346 }
347 return super.getValueAsString(null);
348 }
349
350
351 @Override
352 public String getValueAsString(String defValue) throws IOException
353 {
354 if (_currToken == JsonToken.VALUE_STRING) {
355 if (_tokenIncomplete) {
356 _tokenIncomplete = false;
357 return _finishAndReturnString();
358 }
359 return _textBuffer.contentsAsString();
360 }
361 if (_currToken == JsonToken.FIELD_NAME) {
362 return getCurrentName();
363 }
364 return super.getValueAsString(defValue);
365 }
366
367
368 @Override
369 public int getValueAsInt() throws IOException
370 {
371 JsonToken t = _currToken;
372 if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
373
374 if ((_numTypesValid & NR_INT) == 0) {
375 if (_numTypesValid == NR_UNKNOWN) {
376 return _parseIntValue();
377 }
378 if ((_numTypesValid & NR_INT) == 0) {
379 convertNumberToInt();
380 }
381 }
382 return _numberInt;
383 }
384 return super.getValueAsInt(0);
385 }
386
387
388 @Override
389 public int getValueAsInt(int defValue) throws IOException
390 {
391 JsonToken t = _currToken;
392 if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
393
394 if ((_numTypesValid & NR_INT) == 0) {
395 if (_numTypesValid == NR_UNKNOWN) {
396 return _parseIntValue();
397 }
398 if ((_numTypesValid & NR_INT) == 0) {
399 convertNumberToInt();
400 }
401 }
402 return _numberInt;
403 }
404 return super.getValueAsInt(defValue);
405 }
406
407 protected final String _getText2(JsonToken t)
408 {
409 if (t == null) {
410 return null;
411 }
412 switch (t.id()) {
413 case ID_FIELD_NAME:
414 return _parsingContext.getCurrentName();
415
416 case ID_STRING:
417
418 case ID_NUMBER_INT:
419 case ID_NUMBER_FLOAT:
420 return _textBuffer.contentsAsString();
421 default:
422 return t.asString();
423 }
424 }
425
426 @Override
427 public char[] getTextCharacters() throws IOException
428 {
429 if (_currToken != null) {
430 switch (_currToken.id()) {
431
432 case ID_FIELD_NAME:
433 if (!_nameCopied) {
434 String name = _parsingContext.getCurrentName();
435 int nameLen = name.length();
436 if (_nameCopyBuffer == null) {
437 _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
438 } else if (_nameCopyBuffer.length < nameLen) {
439 _nameCopyBuffer = new char[nameLen];
440 }
441 name.getChars(0, nameLen, _nameCopyBuffer, 0);
442 _nameCopied = true;
443 }
444 return _nameCopyBuffer;
445
446 case ID_STRING:
447 if (_tokenIncomplete) {
448 _tokenIncomplete = false;
449 _finishString();
450 }
451
452 case ID_NUMBER_INT:
453 case ID_NUMBER_FLOAT:
454 return _textBuffer.getTextBuffer();
455
456 default:
457 return _currToken.asCharArray();
458 }
459 }
460 return null;
461 }
462
463 @Override
464 public int getTextLength() throws IOException
465 {
466 if (_currToken != null) {
467 switch (_currToken.id()) {
468
469 case ID_FIELD_NAME:
470 return _parsingContext.getCurrentName().length();
471 case ID_STRING:
472 if (_tokenIncomplete) {
473 _tokenIncomplete = false;
474 _finishString();
475 }
476
477 case ID_NUMBER_INT:
478 case ID_NUMBER_FLOAT:
479 return _textBuffer.size();
480
481 default:
482 return _currToken.asCharArray().length;
483 }
484 }
485 return 0;
486 }
487
488 @Override
489 public int getTextOffset() throws IOException
490 {
491
492 if (_currToken != null) {
493 switch (_currToken.id()) {
494 case ID_FIELD_NAME:
495 return 0;
496 case ID_STRING:
497 if (_tokenIncomplete) {
498 _tokenIncomplete = false;
499 _finishString();
500 }
501
502 case ID_NUMBER_INT:
503 case ID_NUMBER_FLOAT:
504 return _textBuffer.getTextOffset();
505 default:
506 }
507 }
508 return 0;
509 }
510
511 @Override
512 public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
513 {
514 if (_currToken != JsonToken.VALUE_STRING &&
515 (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) {
516 _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
517 }
518
519 if (_tokenIncomplete) {
520 try {
521 _binaryValue = _decodeBase64(b64variant);
522 } catch (IllegalArgumentException iae) {
523 throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
524 }
525
526 _tokenIncomplete = false;
527 } else {
528 if (_binaryValue == null) {
529 @SuppressWarnings("resource")
530 ByteArrayBuilder builder = _getByteArrayBuilder();
531 _decodeBase64(getText(), builder, b64variant);
532 _binaryValue = builder.toByteArray();
533 }
534 }
535 return _binaryValue;
536 }
537
538 @Override
539 public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
540 {
541
542 if (!_tokenIncomplete || _currToken != JsonToken.VALUE_STRING) {
543 byte[] b = getBinaryValue(b64variant);
544 out.write(b);
545 return b.length;
546 }
547
548 byte[] buf = _ioContext.allocBase64Buffer();
549 try {
550 return _readBinary(b64variant, out, buf);
551 } finally {
552 _ioContext.releaseBase64Buffer(buf);
553 }
554 }
555
556 protected int _readBinary(Base64Variant b64variant, OutputStream out,
557 byte[] buffer) throws IOException
558 {
559 int outputPtr = 0;
560 final int outputEnd = buffer.length - 3;
561 int outputCount = 0;
562
563 while (true) {
564
565 int ch;
566 do {
567 if (_inputPtr >= _inputEnd) {
568 _loadMoreGuaranteed();
569 }
570 ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
571 } while (ch <= INT_SPACE);
572 int bits = b64variant.decodeBase64Char(ch);
573 if (bits < 0) {
574 if (ch == INT_QUOTE) {
575 break;
576 }
577 bits = _decodeBase64Escape(b64variant, ch, 0);
578 if (bits < 0) {
579 continue;
580 }
581 }
582
583
584 if (outputPtr > outputEnd) {
585 outputCount += outputPtr;
586 out.write(buffer, 0, outputPtr);
587 outputPtr = 0;
588 }
589
590 int decodedData = bits;
591
592
593
594 if (_inputPtr >= _inputEnd) {
595 _loadMoreGuaranteed();
596 }
597 ch = _inputBuffer[_inputPtr++] & 0xFF;
598 bits = b64variant.decodeBase64Char(ch);
599 if (bits < 0) {
600 bits = _decodeBase64Escape(b64variant, ch, 1);
601 }
602 decodedData = (decodedData << 6) | bits;
603
604
605 if (_inputPtr >= _inputEnd) {
606 _loadMoreGuaranteed();
607 }
608 ch = _inputBuffer[_inputPtr++] & 0xFF;
609 bits = b64variant.decodeBase64Char(ch);
610
611
612 if (bits < 0) {
613 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
614
615 if (ch == INT_QUOTE) {
616 decodedData >>= 4;
617 buffer[outputPtr++] = (byte) decodedData;
618 if (b64variant.usesPadding()) {
619 --_inputPtr;
620 _handleBase64MissingPadding(b64variant);
621 }
622 break;
623 }
624 bits = _decodeBase64Escape(b64variant, ch, 2);
625 }
626 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
627
628 if (_inputPtr >= _inputEnd) {
629 _loadMoreGuaranteed();
630 }
631 ch = _inputBuffer[_inputPtr++] & 0xFF;
632 if (!b64variant.usesPaddingChar(ch)) {
633 if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) {
634 throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
635 }
636 }
637
638 decodedData >>= 4;
639 buffer[outputPtr++] = (byte) decodedData;
640 continue;
641 }
642 }
643
644 decodedData = (decodedData << 6) | bits;
645
646 if (_inputPtr >= _inputEnd) {
647 _loadMoreGuaranteed();
648 }
649 ch = _inputBuffer[_inputPtr++] & 0xFF;
650 bits = b64variant.decodeBase64Char(ch);
651 if (bits < 0) {
652 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
653
654 if (ch == INT_QUOTE) {
655 decodedData >>= 2;
656 buffer[outputPtr++] = (byte) (decodedData >> 8);
657 buffer[outputPtr++] = (byte) decodedData;
658 if (b64variant.usesPadding()) {
659 --_inputPtr;
660 _handleBase64MissingPadding(b64variant);
661 }
662 break;
663 }
664 bits = _decodeBase64Escape(b64variant, ch, 3);
665 }
666 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
667
673 decodedData >>= 2;
674 buffer[outputPtr++] = (byte) (decodedData >> 8);
675 buffer[outputPtr++] = (byte) decodedData;
676 continue;
677 }
678 }
679
680 decodedData = (decodedData << 6) | bits;
681 buffer[outputPtr++] = (byte) (decodedData >> 16);
682 buffer[outputPtr++] = (byte) (decodedData >> 8);
683 buffer[outputPtr++] = (byte) decodedData;
684 }
685 _tokenIncomplete = false;
686 if (outputPtr > 0) {
687 outputCount += outputPtr;
688 out.write(buffer, 0, outputPtr);
689 }
690 return outputCount;
691 }
692
693
698
699
703 @Override
704 public JsonToken nextToken() throws IOException
705 {
706
710 if (_currToken == JsonToken.FIELD_NAME) {
711 return _nextAfterName();
712 }
713
714
715 _numTypesValid = NR_UNKNOWN;
716 if (_tokenIncomplete) {
717 _skipString();
718 }
719 int i = _skipWSOrEnd();
720 if (i < 0) {
721
722 close();
723 return (_currToken = null);
724 }
725
726 _binaryValue = null;
727
728
729 if (i == INT_RBRACKET) {
730 _closeArrayScope();
731 return (_currToken = JsonToken.END_ARRAY);
732 }
733 if (i == INT_RCURLY) {
734 _closeObjectScope();
735 return (_currToken = JsonToken.END_OBJECT);
736 }
737
738
739 if (_parsingContext.expectComma()) {
740 if (i != INT_COMMA) {
741 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
742 }
743 i = _skipWS();
744
745 if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
746 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
747 return _closeScope(i);
748 }
749 }
750 }
751
752
755 if (!_parsingContext.inObject()) {
756 _updateLocation();
757 return _nextTokenNotInObject(i);
758 }
759
760 _updateNameLocation();
761 String n = _parseName(i);
762 _parsingContext.setCurrentName(n);
763 _currToken = JsonToken.FIELD_NAME;
764
765 i = _skipColon();
766 _updateLocation();
767
768
769 if (i == INT_QUOTE) {
770 _tokenIncomplete = true;
771 _nextToken = JsonToken.VALUE_STRING;
772 return _currToken;
773 }
774 JsonToken t;
775
776 switch (i) {
777 case '-':
778 t = _parseNegNumber();
779 break;
780
781
782
783 case '.':
784 t = _parseFloatThatStartsWithPeriod();
785 break;
786 case '0':
787 case '1':
788 case '2':
789 case '3':
790 case '4':
791 case '5':
792 case '6':
793 case '7':
794 case '8':
795 case '9':
796 t = _parsePosNumber(i);
797 break;
798 case 'f':
799 _matchFalse();
800 t = JsonToken.VALUE_FALSE;
801 break;
802 case 'n':
803 _matchNull();
804 t = JsonToken.VALUE_NULL;
805 break;
806 case 't':
807 _matchTrue();
808 t = JsonToken.VALUE_TRUE;
809 break;
810 case '[':
811 t = JsonToken.START_ARRAY;
812 break;
813 case '{':
814 t = JsonToken.START_OBJECT;
815 break;
816
817 default:
818 t = _handleUnexpectedValue(i);
819 }
820 _nextToken = t;
821 return _currToken;
822 }
823
824 private final JsonToken _nextTokenNotInObject(int i) throws IOException
825 {
826 if (i == INT_QUOTE) {
827 _tokenIncomplete = true;
828 return (_currToken = JsonToken.VALUE_STRING);
829 }
830 switch (i) {
831 case '[':
832 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
833 return (_currToken = JsonToken.START_ARRAY);
834 case '{':
835 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
836 return (_currToken = JsonToken.START_OBJECT);
837 case 't':
838 _matchTrue();
839 return (_currToken = JsonToken.VALUE_TRUE);
840 case 'f':
841 _matchFalse();
842 return (_currToken = JsonToken.VALUE_FALSE);
843 case 'n':
844 _matchNull();
845 return (_currToken = JsonToken.VALUE_NULL);
846 case '-':
847 return (_currToken = _parseNegNumber());
848
849
850
851 case '.':
852 return (_currToken = _parseFloatThatStartsWithPeriod());
853 case '0':
854 case '1':
855 case '2':
856 case '3':
857 case '4':
858 case '5':
859 case '6':
860 case '7':
861 case '8':
862 case '9':
863 return (_currToken = _parsePosNumber(i));
864 }
865 return (_currToken = _handleUnexpectedValue(i));
866 }
867
868 private final JsonToken _nextAfterName()
869 {
870 _nameCopied = false;
871 JsonToken t = _nextToken;
872 _nextToken = null;
873
874
875
876
877 if (t == JsonToken.START_ARRAY) {
878 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
879 } else if (t == JsonToken.START_OBJECT) {
880 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
881 }
882 return (_currToken = t);
883 }
884
885 @Override
886 public void finishToken() throws IOException {
887 if (_tokenIncomplete) {
888 _tokenIncomplete = false;
889 _finishString();
890 }
891 }
892
893
898
899 @Override
900 public boolean nextFieldName(SerializableString str) throws IOException
901 {
902
903 _numTypesValid = NR_UNKNOWN;
904 if (_currToken == JsonToken.FIELD_NAME) {
905 _nextAfterName();
906 return false;
907 }
908 if (_tokenIncomplete) {
909 _skipString();
910 }
911 int i = _skipWSOrEnd();
912 if (i < 0) {
913 close();
914 _currToken = null;
915 return false;
916 }
917 _binaryValue = null;
918
919
920 if (i == INT_RBRACKET) {
921 _closeArrayScope();
922 _currToken = JsonToken.END_ARRAY;
923 return false;
924 }
925 if (i == INT_RCURLY) {
926 _closeObjectScope();
927 _currToken = JsonToken.END_OBJECT;
928 return false;
929 }
930
931
932 if (_parsingContext.expectComma()) {
933 if (i != INT_COMMA) {
934 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
935 }
936 i = _skipWS();
937
938
939 if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
940 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
941 _closeScope(i);
942 return false;
943 }
944 }
945 }
946 if (!_parsingContext.inObject()) {
947 _updateLocation();
948 _nextTokenNotInObject(i);
949 return false;
950 }
951
952
953 _updateNameLocation();
954 if (i == INT_QUOTE) {
955
956 byte[] nameBytes = str.asQuotedUTF8();
957 final int len = nameBytes.length;
958
959
960 if ((_inputPtr + len + 4) < _inputEnd) {
961
962 final int end = _inputPtr+len;
963 if (_inputBuffer[end] == INT_QUOTE) {
964 int offset = 0;
965 int ptr = _inputPtr;
966 while (true) {
967 if (ptr == end) {
968 _parsingContext.setCurrentName(str.getValue());
969 i = _skipColonFast(ptr+1);
970 _isNextTokenNameYes(i);
971 return true;
972 }
973 if (nameBytes[offset] != _inputBuffer[ptr]) {
974 break;
975 }
976 ++offset;
977 ++ptr;
978 }
979 }
980 }
981 }
982 return _isNextTokenNameMaybe(i, str);
983 }
984
985 @Override
986 public String nextFieldName() throws IOException
987 {
988
989 _numTypesValid = NR_UNKNOWN;
990 if (_currToken == JsonToken.FIELD_NAME) {
991 _nextAfterName();
992 return null;
993 }
994 if (_tokenIncomplete) {
995 _skipString();
996 }
997 int i = _skipWSOrEnd();
998 if (i < 0) {
999 close();
1000 _currToken = null;
1001 return null;
1002 }
1003 _binaryValue = null;
1004
1005 if (i == INT_RBRACKET) {
1006 _closeArrayScope();
1007 _currToken = JsonToken.END_ARRAY;
1008 return null;
1009 }
1010 if (i == INT_RCURLY) {
1011 _closeObjectScope();
1012 _currToken = JsonToken.END_OBJECT;
1013 return null;
1014 }
1015
1016
1017 if (_parsingContext.expectComma()) {
1018 if (i != INT_COMMA) {
1019 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
1020 }
1021 i = _skipWS();
1022
1023 if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
1024 if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
1025 _closeScope(i);
1026 return null;
1027 }
1028 }
1029 }
1030
1031 if (!_parsingContext.inObject()) {
1032 _updateLocation();
1033 _nextTokenNotInObject(i);
1034 return null;
1035 }
1036
1037 _updateNameLocation();
1038 final String nameStr = _parseName(i);
1039 _parsingContext.setCurrentName(nameStr);
1040 _currToken = JsonToken.FIELD_NAME;
1041
1042 i = _skipColon();
1043 _updateLocation();
1044 if (i == INT_QUOTE) {
1045 _tokenIncomplete = true;
1046 _nextToken = JsonToken.VALUE_STRING;
1047 return nameStr;
1048 }
1049 JsonToken t;
1050 switch (i) {
1051 case '-':
1052 t = _parseNegNumber();
1053 break;
1054 case '.':
1055 t = _parseFloatThatStartsWithPeriod();
1056 break;
1057 case '0':
1058 case '1':
1059 case '2':
1060 case '3':
1061 case '4':
1062 case '5':
1063 case '6':
1064 case '7':
1065 case '8':
1066 case '9':
1067 t = _parsePosNumber(i);
1068 break;
1069 case 'f':
1070 _matchFalse();
1071 t = JsonToken.VALUE_FALSE;
1072 break;
1073 case 'n':
1074 _matchNull();
1075 t = JsonToken.VALUE_NULL;
1076 break;
1077 case 't':
1078 _matchTrue();
1079 t = JsonToken.VALUE_TRUE;
1080 break;
1081 case '[':
1082 t = JsonToken.START_ARRAY;
1083 break;
1084 case '{':
1085 t = JsonToken.START_OBJECT;
1086 break;
1087
1088 default:
1089 t = _handleUnexpectedValue(i);
1090 }
1091 _nextToken = t;
1092 return nameStr;
1093 }
1094
1095
1096 private final int _skipColonFast(int ptr) throws IOException
1097 {
1098 int i = _inputBuffer[ptr++];
1099 if (i == INT_COLON) {
1100 i = _inputBuffer[ptr++];
1101 if (i > INT_SPACE) {
1102 if (i != INT_SLASH && i != INT_HASH) {
1103 _inputPtr = ptr;
1104 return i;
1105 }
1106 } else if (i == INT_SPACE || i == INT_TAB) {
1107 i = (int) _inputBuffer[ptr++];
1108 if (i > INT_SPACE) {
1109 if (i != INT_SLASH && i != INT_HASH) {
1110 _inputPtr = ptr;
1111 return i;
1112 }
1113 }
1114 }
1115 _inputPtr = ptr-1;
1116 return _skipColon2(true);
1117 }
1118 if (i == INT_SPACE || i == INT_TAB) {
1119 i = _inputBuffer[ptr++];
1120 }
1121 if (i == INT_COLON) {
1122 i = _inputBuffer[ptr++];
1123 if (i > INT_SPACE) {
1124 if (i != INT_SLASH && i != INT_HASH) {
1125 _inputPtr = ptr;
1126 return i;
1127 }
1128 } else if (i == INT_SPACE || i == INT_TAB) {
1129 i = (int) _inputBuffer[ptr++];
1130 if (i > INT_SPACE) {
1131 if (i != INT_SLASH && i != INT_HASH) {
1132 _inputPtr = ptr;
1133 return i;
1134 }
1135 }
1136 }
1137 _inputPtr = ptr-1;
1138 return _skipColon2(true);
1139 }
1140 _inputPtr = ptr-1;
1141 return _skipColon2(false);
1142 }
1143
1144 private final void _isNextTokenNameYes(int i) throws IOException
1145 {
1146 _currToken = JsonToken.FIELD_NAME;
1147 _updateLocation();
1148
1149 switch (i) {
1150 case '"':
1151 _tokenIncomplete = true;
1152 _nextToken = JsonToken.VALUE_STRING;
1153 return;
1154 case '[':
1155 _nextToken = JsonToken.START_ARRAY;
1156 return;
1157 case '{':
1158 _nextToken = JsonToken.START_OBJECT;
1159 return;
1160 case 't':
1161 _matchTrue();
1162 _nextToken = JsonToken.VALUE_TRUE;
1163 return;
1164 case 'f':
1165 _matchFalse();
1166 _nextToken = JsonToken.VALUE_FALSE;
1167 return;
1168 case 'n':
1169 _matchNull();
1170 _nextToken = JsonToken.VALUE_NULL;
1171 return;
1172 case '-':
1173 _nextToken = _parseNegNumber();
1174 return;
1175 case '.':
1176 _nextToken = _parseFloatThatStartsWithPeriod();
1177 return;
1178 case '0':
1179 case '1':
1180 case '2':
1181 case '3':
1182 case '4':
1183 case '5':
1184 case '6':
1185 case '7':
1186 case '8':
1187 case '9':
1188 _nextToken = _parsePosNumber(i);
1189 return;
1190 }
1191 _nextToken = _handleUnexpectedValue(i);
1192 }
1193
1194 private final boolean _isNextTokenNameMaybe(int i, SerializableString str) throws IOException
1195 {
1196
1197
1198 String n = _parseName(i);
1199 _parsingContext.setCurrentName(n);
1200 final boolean match = n.equals(str.getValue());
1201 _currToken = JsonToken.FIELD_NAME;
1202 i = _skipColon();
1203 _updateLocation();
1204
1205
1206 if (i == INT_QUOTE) {
1207 _tokenIncomplete = true;
1208 _nextToken = JsonToken.VALUE_STRING;
1209 return match;
1210 }
1211 JsonToken t;
1212
1213 switch (i) {
1214 case '[':
1215 t = JsonToken.START_ARRAY;
1216 break;
1217 case '{':
1218 t = JsonToken.START_OBJECT;
1219 break;
1220 case 't':
1221 _matchTrue();
1222 t = JsonToken.VALUE_TRUE;
1223 break;
1224 case 'f':
1225 _matchFalse();
1226 t = JsonToken.VALUE_FALSE;
1227 break;
1228 case 'n':
1229 _matchNull();
1230 t = JsonToken.VALUE_NULL;
1231 break;
1232 case '-':
1233 t = _parseNegNumber();
1234 break;
1235 case '.':
1236 t = _parseFloatThatStartsWithPeriod();
1237 break;
1238 case '0':
1239 case '1':
1240 case '2':
1241 case '3':
1242 case '4':
1243 case '5':
1244 case '6':
1245 case '7':
1246 case '8':
1247 case '9':
1248 t = _parsePosNumber(i);
1249 break;
1250 default:
1251 t = _handleUnexpectedValue(i);
1252 }
1253 _nextToken = t;
1254 return match;
1255 }
1256
1257 @Override
1258 public String nextTextValue() throws IOException
1259 {
1260
1261 if (_currToken == JsonToken.FIELD_NAME) {
1262 _nameCopied = false;
1263 JsonToken t = _nextToken;
1264 _nextToken = null;
1265 _currToken = t;
1266 if (t == JsonToken.VALUE_STRING) {
1267 if (_tokenIncomplete) {
1268 _tokenIncomplete = false;
1269 return _finishAndReturnString();
1270 }
1271 return _textBuffer.contentsAsString();
1272 }
1273 if (t == JsonToken.START_ARRAY) {
1274 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1275 } else if (t == JsonToken.START_OBJECT) {
1276 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1277 }
1278 return null;
1279 }
1280
1281 return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
1282 }
1283
1284 @Override
1285 public int nextIntValue(int defaultValue) throws IOException
1286 {
1287
1288 if (_currToken == JsonToken.FIELD_NAME) {
1289 _nameCopied = false;
1290 JsonToken t = _nextToken;
1291 _nextToken = null;
1292 _currToken = t;
1293 if (t == JsonToken.VALUE_NUMBER_INT) {
1294 return getIntValue();
1295 }
1296 if (t == JsonToken.START_ARRAY) {
1297 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1298 } else if (t == JsonToken.START_OBJECT) {
1299 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1300 }
1301 return defaultValue;
1302 }
1303
1304 return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
1305 }
1306
1307 @Override
1308 public long nextLongValue(long defaultValue) throws IOException
1309 {
1310
1311 if (_currToken == JsonToken.FIELD_NAME) {
1312 _nameCopied = false;
1313 JsonToken t = _nextToken;
1314 _nextToken = null;
1315 _currToken = t;
1316 if (t == JsonToken.VALUE_NUMBER_INT) {
1317 return getLongValue();
1318 }
1319 if (t == JsonToken.START_ARRAY) {
1320 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1321 } else if (t == JsonToken.START_OBJECT) {
1322 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1323 }
1324 return defaultValue;
1325 }
1326
1327 return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
1328 }
1329
1330 @Override
1331 public Boolean nextBooleanValue() throws IOException
1332 {
1333
1334 if (_currToken == JsonToken.FIELD_NAME) {
1335 _nameCopied = false;
1336 JsonToken t = _nextToken;
1337 _nextToken = null;
1338 _currToken = t;
1339 if (t == JsonToken.VALUE_TRUE) {
1340 return Boolean.TRUE;
1341 }
1342 if (t == JsonToken.VALUE_FALSE) {
1343 return Boolean.FALSE;
1344 }
1345 if (t == JsonToken.START_ARRAY) {
1346 _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
1347 } else if (t == JsonToken.START_OBJECT) {
1348 _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
1349 }
1350 return null;
1351 }
1352
1353 JsonToken t = nextToken();
1354 if (t == JsonToken.VALUE_TRUE) {
1355 return Boolean.TRUE;
1356 }
1357 if (t == JsonToken.VALUE_FALSE) {
1358 return Boolean.FALSE;
1359 }
1360 return null;
1361 }
1362
1363
1368
1369
1370 protected final JsonToken _parseFloatThatStartsWithPeriod() throws IOException
1371 {
1372
1373 if (!isEnabled(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1374 return _handleUnexpectedValue(INT_PERIOD);
1375 }
1376 return _parseFloat(_textBuffer.emptyAndGetCurrentSegment(),
1377 0, INT_PERIOD, false, 0);
1378 }
1379
1380
1395 protected JsonToken _parsePosNumber(int c) throws IOException
1396 {
1397 char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
1398
1399 if (c == INT_0) {
1400 c = _verifyNoLeadingZeroes();
1401 }
1402
1403 outBuf[0] = (char) c;
1404 int intLen = 1;
1405 int outPtr = 1;
1406
1407
1408 final int end = Math.min(_inputEnd, _inputPtr + outBuf.length - 1);
1409
1410 while (true) {
1411 if (_inputPtr >= end) {
1412 return _parseNumber2(outBuf, outPtr, false, intLen);
1413 }
1414 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1415 if (c < INT_0 || c > INT_9) {
1416 break;
1417 }
1418 ++intLen;
1419 outBuf[outPtr++] = (char) c;
1420 }
1421 if (c == INT_PERIOD || c == INT_e || c == INT_E) {
1422 return _parseFloat(outBuf, outPtr, c, false, intLen);
1423 }
1424 --_inputPtr;
1425 _textBuffer.setCurrentLength(outPtr);
1426
1427 if (_parsingContext.inRoot()) {
1428 _verifyRootSpace(c);
1429 }
1430
1431 return resetInt(false, intLen);
1432 }
1433
1434 protected JsonToken _parseNegNumber() throws IOException
1435 {
1436 char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
1437 int outPtr = 0;
1438
1439
1440 outBuf[outPtr++] = '-';
1441
1442 if (_inputPtr >= _inputEnd) {
1443 _loadMoreGuaranteed();
1444 }
1445 int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1446
1447 if (c <= INT_0) {
1448
1449 if (c != INT_0) {
1450 return _handleInvalidNumberStart(c, true);
1451 }
1452 c = _verifyNoLeadingZeroes();
1453 } else if (c > INT_9) {
1454 return _handleInvalidNumberStart(c, true);
1455 }
1456
1457
1458 outBuf[outPtr++] = (char) c;
1459 int intLen = 1;
1460
1461
1462
1463 final int end = Math.min(_inputEnd, _inputPtr + outBuf.length - outPtr);
1464
1465 while (true) {
1466 if (_inputPtr >= end) {
1467
1468 return _parseNumber2(outBuf, outPtr, true, intLen);
1469 }
1470 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1471 if (c < INT_0 || c > INT_9) {
1472 break;
1473 }
1474 ++intLen;
1475 outBuf[outPtr++] = (char) c;
1476 }
1477 if (c == INT_PERIOD || c == INT_e || c == INT_E) {
1478 return _parseFloat(outBuf, outPtr, c, true, intLen);
1479 }
1480
1481 --_inputPtr;
1482 _textBuffer.setCurrentLength(outPtr);
1483
1484 if (_parsingContext.inRoot()) {
1485 _verifyRootSpace(c);
1486 }
1487
1488
1489 return resetInt(true, intLen);
1490 }
1491
1492
1496 private final JsonToken _parseNumber2(char[] outBuf, int outPtr, boolean negative,
1497 int intPartLength) throws IOException
1498 {
1499
1500 while (true) {
1501 if (_inputPtr >= _inputEnd && !_loadMore()) {
1502 _textBuffer.setCurrentLength(outPtr);
1503 return resetInt(negative, intPartLength);
1504 }
1505 int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1506 if (c > INT_9 || c < INT_0) {
1507 if (c == INT_PERIOD || c == INT_e || c == INT_E) {
1508 return _parseFloat(outBuf, outPtr, c, negative, intPartLength);
1509 }
1510 break;
1511 }
1512 if (outPtr >= outBuf.length) {
1513 outBuf = _textBuffer.finishCurrentSegment();
1514 outPtr = 0;
1515 }
1516 outBuf[outPtr++] = (char) c;
1517 ++intPartLength;
1518 }
1519 --_inputPtr;
1520 _textBuffer.setCurrentLength(outPtr);
1521
1522 if (_parsingContext.inRoot()) {
1523 _verifyRootSpace(_inputBuffer[_inputPtr] & 0xFF);
1524 }
1525
1526
1527 return resetInt(negative, intPartLength);
1528
1529 }
1530
1531
1535 private final int _verifyNoLeadingZeroes() throws IOException
1536 {
1537
1538 if (_inputPtr >= _inputEnd && !_loadMore()) {
1539 return INT_0;
1540 }
1541 int ch = _inputBuffer[_inputPtr] & 0xFF;
1542
1543 if (ch < INT_0 || ch > INT_9) {
1544 return INT_0;
1545 }
1546
1547 if ((_features & FEAT_MASK_LEADING_ZEROS) == 0) {
1548 reportInvalidNumber("Leading zeroes not allowed");
1549 }
1550
1551 ++_inputPtr;
1552 if (ch == INT_0) {
1553 while (_inputPtr < _inputEnd || _loadMore()) {
1554 ch = _inputBuffer[_inputPtr] & 0xFF;
1555 if (ch < INT_0 || ch > INT_9) {
1556 return INT_0;
1557 }
1558 ++_inputPtr;
1559 if (ch != INT_0) {
1560 break;
1561 }
1562 }
1563 }
1564 return ch;
1565 }
1566
1567 private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
1568 boolean negative, int integerPartLength) throws IOException
1569 {
1570 int fractLen = 0;
1571 boolean eof = false;
1572
1573
1574 if (c == INT_PERIOD) {
1575 if (outPtr >= outBuf.length) {
1576 outBuf = _textBuffer.finishCurrentSegment();
1577 outPtr = 0;
1578 }
1579 outBuf[outPtr++] = (char) c;
1580
1581 fract_loop:
1582 while (true) {
1583 if (_inputPtr >= _inputEnd && !_loadMore()) {
1584 eof = true;
1585 break fract_loop;
1586 }
1587 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1588 if (c < INT_0 || c > INT_9) {
1589 break fract_loop;
1590 }
1591 ++fractLen;
1592 if (outPtr >= outBuf.length) {
1593 outBuf = _textBuffer.finishCurrentSegment();
1594 outPtr = 0;
1595 }
1596 outBuf[outPtr++] = (char) c;
1597 }
1598
1599 if (fractLen == 0) {
1600 reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1601 }
1602 }
1603
1604 int expLen = 0;
1605 if (c == INT_e || c == INT_E) {
1606 if (outPtr >= outBuf.length) {
1607 outBuf = _textBuffer.finishCurrentSegment();
1608 outPtr = 0;
1609 }
1610 outBuf[outPtr++] = (char) c;
1611
1612 if (_inputPtr >= _inputEnd) {
1613 _loadMoreGuaranteed();
1614 }
1615 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1616
1617 if (c == '-' || c == '+') {
1618 if (outPtr >= outBuf.length) {
1619 outBuf = _textBuffer.finishCurrentSegment();
1620 outPtr = 0;
1621 }
1622 outBuf[outPtr++] = (char) c;
1623
1624 if (_inputPtr >= _inputEnd) {
1625 _loadMoreGuaranteed();
1626 }
1627 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1628 }
1629
1630 exp_loop:
1631 while (c >= INT_0 && c <= INT_9) {
1632 ++expLen;
1633 if (outPtr >= outBuf.length) {
1634 outBuf = _textBuffer.finishCurrentSegment();
1635 outPtr = 0;
1636 }
1637 outBuf[outPtr++] = (char) c;
1638 if (_inputPtr >= _inputEnd && !_loadMore()) {
1639 eof = true;
1640 break exp_loop;
1641 }
1642 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
1643 }
1644
1645 if (expLen == 0) {
1646 reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit");
1647 }
1648 }
1649
1650
1651 if (!eof) {
1652 --_inputPtr;
1653
1654 if (_parsingContext.inRoot()) {
1655 _verifyRootSpace(c);
1656 }
1657 }
1658 _textBuffer.setCurrentLength(outPtr);
1659
1660
1661 return resetFloat(negative, integerPartLength, fractLen, expLen);
1662 }
1663
1664
1671 private final void _verifyRootSpace(int ch) throws IOException
1672 {
1673
1674 ++_inputPtr;
1675
1676 switch (ch) {
1677 case ' ':
1678 case '\t':
1679 return;
1680 case '\r':
1681 _skipCR();
1682 return;
1683 case '\n':
1684 ++_currInputRow;
1685 _currInputRowStart = _inputPtr;
1686 return;
1687 }
1688 _reportMissingRootWS(ch);
1689 }
1690
1691
1696
1697 protected final String _parseName(int i) throws IOException
1698 {
1699 if (i != INT_QUOTE) {
1700 return _handleOddName(i);
1701 }
1702
1703 if ((_inputPtr + 13) > _inputEnd) {
1704 return slowParseName();
1705 }
1706
1707
1708
1713 final byte[] input = _inputBuffer;
1714 final int[] codes = _icLatin1;
1715
1716 int q = input[_inputPtr++] & 0xFF;
1717
1718 if (codes[q] == 0) {
1719 i = input[_inputPtr++] & 0xFF;
1720 if (codes[i] == 0) {
1721 q = (q << 8) | i;
1722 i = input[_inputPtr++] & 0xFF;
1723 if (codes[i] == 0) {
1724 q = (q << 8) | i;
1725 i = input[_inputPtr++] & 0xFF;
1726 if (codes[i] == 0) {
1727 q = (q << 8) | i;
1728 i = input[_inputPtr++] & 0xFF;
1729 if (codes[i] == 0) {
1730 _quad1 = q;
1731 return parseMediumName(i);
1732 }
1733 if (i == INT_QUOTE) {
1734 return findName(q, 4);
1735 }
1736 return parseName(q, i, 4);
1737 }
1738 if (i == INT_QUOTE) {
1739 return findName(q, 3);
1740 }
1741 return parseName(q, i, 3);
1742 }
1743 if (i == INT_QUOTE) {
1744 return findName(q, 2);
1745 }
1746 return parseName(q, i, 2);
1747 }
1748 if (i == INT_QUOTE) {
1749 return findName(q, 1);
1750 }
1751 return parseName(q, i, 1);
1752 }
1753 if (q == INT_QUOTE) {
1754 return "";
1755 }
1756 return parseName(0, q, 0);
1757 }
1758
1759 protected final String parseMediumName(int q2) throws IOException
1760 {
1761 final byte[] input = _inputBuffer;
1762 final int[] codes = _icLatin1;
1763
1764
1765 int i = input[_inputPtr++] & 0xFF;
1766 if (codes[i] != 0) {
1767 if (i == INT_QUOTE) {
1768 return findName(_quad1, q2, 1);
1769 }
1770 return parseName(_quad1, q2, i, 1);
1771 }
1772 q2 = (q2 << 8) | i;
1773 i = input[_inputPtr++] & 0xFF;
1774 if (codes[i] != 0) {
1775 if (i == INT_QUOTE) {
1776 return findName(_quad1, q2, 2);
1777 }
1778 return parseName(_quad1, q2, i, 2);
1779 }
1780 q2 = (q2 << 8) | i;
1781 i = input[_inputPtr++] & 0xFF;
1782 if (codes[i] != 0) {
1783 if (i == INT_QUOTE) {
1784 return findName(_quad1, q2, 3);
1785 }
1786 return parseName(_quad1, q2, i, 3);
1787 }
1788 q2 = (q2 << 8) | i;
1789 i = input[_inputPtr++] & 0xFF;
1790 if (codes[i] != 0) {
1791 if (i == INT_QUOTE) {
1792 return findName(_quad1, q2, 4);
1793 }
1794 return parseName(_quad1, q2, i, 4);
1795 }
1796 return parseMediumName2(i, q2);
1797 }
1798
1799
1802 protected final String parseMediumName2(int q3, final int q2) throws IOException
1803 {
1804 final byte[] input = _inputBuffer;
1805 final int[] codes = _icLatin1;
1806
1807
1808 int i = input[_inputPtr++] & 0xFF;
1809 if (codes[i] != 0) {
1810 if (i == INT_QUOTE) {
1811 return findName(_quad1, q2, q3, 1);
1812 }
1813 return parseName(_quad1, q2, q3, i, 1);
1814 }
1815 q3 = (q3 << 8) | i;
1816 i = input[_inputPtr++] & 0xFF;
1817 if (codes[i] != 0) {
1818 if (i == INT_QUOTE) {
1819 return findName(_quad1, q2, q3, 2);
1820 }
1821 return parseName(_quad1, q2, q3, i, 2);
1822 }
1823 q3 = (q3 << 8) | i;
1824 i = input[_inputPtr++] & 0xFF;
1825 if (codes[i] != 0) {
1826 if (i == INT_QUOTE) {
1827 return findName(_quad1, q2, q3, 3);
1828 }
1829 return parseName(_quad1, q2, q3, i, 3);
1830 }
1831 q3 = (q3 << 8) | i;
1832 i = input[_inputPtr++] & 0xFF;
1833 if (codes[i] != 0) {
1834 if (i == INT_QUOTE) {
1835 return findName(_quad1, q2, q3, 4);
1836 }
1837 return parseName(_quad1, q2, q3, i, 4);
1838 }
1839 return parseLongName(i, q2, q3);
1840 }
1841
1842 protected final String parseLongName(int q, final int q2, int q3) throws IOException
1843 {
1844 _quadBuffer[0] = _quad1;
1845 _quadBuffer[1] = q2;
1846 _quadBuffer[2] = q3;
1847
1848
1849 final byte[] input = _inputBuffer;
1850 final int[] codes = _icLatin1;
1851 int qlen = 3;
1852
1853 while ((_inputPtr + 4) <= _inputEnd) {
1854 int i = input[_inputPtr++] & 0xFF;
1855 if (codes[i] != 0) {
1856 if (i == INT_QUOTE) {
1857 return findName(_quadBuffer, qlen, q, 1);
1858 }
1859 return parseEscapedName(_quadBuffer, qlen, q, i, 1);
1860 }
1861
1862 q = (q << 8) | i;
1863 i = input[_inputPtr++] & 0xFF;
1864 if (codes[i] != 0) {
1865 if (i == INT_QUOTE) {
1866 return findName(_quadBuffer, qlen, q, 2);
1867 }
1868 return parseEscapedName(_quadBuffer, qlen, q, i, 2);
1869 }
1870
1871 q = (q << 8) | i;
1872 i = input[_inputPtr++] & 0xFF;
1873 if (codes[i] != 0) {
1874 if (i == INT_QUOTE) {
1875 return findName(_quadBuffer, qlen, q, 3);
1876 }
1877 return parseEscapedName(_quadBuffer, qlen, q, i, 3);
1878 }
1879
1880 q = (q << 8) | i;
1881 i = input[_inputPtr++] & 0xFF;
1882 if (codes[i] != 0) {
1883 if (i == INT_QUOTE) {
1884 return findName(_quadBuffer, qlen, q, 4);
1885 }
1886 return parseEscapedName(_quadBuffer, qlen, q, i, 4);
1887 }
1888
1889
1890 if (qlen >= _quadBuffer.length) {
1891 _quadBuffer = growArrayBy(_quadBuffer, qlen);
1892 }
1893 _quadBuffer[qlen++] = q;
1894 q = i;
1895 }
1896
1897
1901 return parseEscapedName(_quadBuffer, qlen, 0, q, 0);
1902 }
1903
1904
1909 protected String slowParseName() throws IOException
1910 {
1911 if (_inputPtr >= _inputEnd) {
1912 if (!_loadMore()) {
1913 _reportInvalidEOF(": was expecting closing '\"' for name", JsonToken.FIELD_NAME);
1914 }
1915 }
1916 int i = _inputBuffer[_inputPtr++] & 0xFF;
1917 if (i == INT_QUOTE) {
1918 return "";
1919 }
1920 return parseEscapedName(_quadBuffer, 0, 0, i, 0);
1921 }
1922
1923 private final String parseName(int q1, int ch, int lastQuadBytes) throws IOException {
1924 return parseEscapedName(_quadBuffer, 0, q1, ch, lastQuadBytes);
1925 }
1926
1927 private final String parseName(int q1, int q2, int ch, int lastQuadBytes) throws IOException {
1928 _quadBuffer[0] = q1;
1929 return parseEscapedName(_quadBuffer, 1, q2, ch, lastQuadBytes);
1930 }
1931
1932 private final String parseName(int q1, int q2, int q3, int ch, int lastQuadBytes) throws IOException {
1933 _quadBuffer[0] = q1;
1934 _quadBuffer[1] = q2;
1935 return parseEscapedName(_quadBuffer, 2, q3, ch, lastQuadBytes);
1936 }
1937
1938
1944 protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int ch,
1945 int currQuadBytes) throws IOException
1946 {
1947
1948
1949
1950 final int[] codes = _icLatin1;
1951
1952 while (true) {
1953 if (codes[ch] != 0) {
1954 if (ch == INT_QUOTE) {
1955 break;
1956 }
1957
1958 if (ch != INT_BACKSLASH) {
1959
1960 _throwUnquotedSpace(ch, "name");
1961 } else {
1962
1963 ch = _decodeEscaped();
1964 }
1965
1966
1967
1968 if (ch > 127) {
1969
1970 if (currQuadBytes >= 4) {
1971 if (qlen >= quads.length) {
1972 _quadBuffer = quads = growArrayBy(quads, quads.length);
1973 }
1974 quads[qlen++] = currQuad;
1975 currQuad = 0;
1976 currQuadBytes = 0;
1977 }
1978 if (ch < 0x800) {
1979 currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
1980 ++currQuadBytes;
1981
1982 } else {
1983 currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
1984 ++currQuadBytes;
1985
1986 if (currQuadBytes >= 4) {
1987 if (qlen >= quads.length) {
1988 _quadBuffer = quads = growArrayBy(quads, quads.length);
1989 }
1990 quads[qlen++] = currQuad;
1991 currQuad = 0;
1992 currQuadBytes = 0;
1993 }
1994 currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
1995 ++currQuadBytes;
1996 }
1997
1998 ch = 0x80 | (ch & 0x3f);
1999 }
2000 }
2001
2002 if (currQuadBytes < 4) {
2003 ++currQuadBytes;
2004 currQuad = (currQuad << 8) | ch;
2005 } else {
2006 if (qlen >= quads.length) {
2007 _quadBuffer = quads = growArrayBy(quads, quads.length);
2008 }
2009 quads[qlen++] = currQuad;
2010 currQuad = ch;
2011 currQuadBytes = 1;
2012 }
2013 if (_inputPtr >= _inputEnd) {
2014 if (!_loadMore()) {
2015 _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
2016 }
2017 }
2018 ch = _inputBuffer[_inputPtr++] & 0xFF;
2019 }
2020
2021 if (currQuadBytes > 0) {
2022 if (qlen >= quads.length) {
2023 _quadBuffer = quads = growArrayBy(quads, quads.length);
2024 }
2025 quads[qlen++] = _padLastQuad(currQuad, currQuadBytes);
2026 }
2027 String name = _symbols.findName(quads, qlen);
2028 if (name == null) {
2029 name = addName(quads, qlen, currQuadBytes);
2030 }
2031 return name;
2032 }
2033
2034
2040 protected String _handleOddName(int ch) throws IOException
2041 {
2042
2043 if (ch == INT_APOS && (_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) {
2044 return _parseAposName();
2045 }
2046
2047 if ((_features & FEAT_MASK_ALLOW_UNQUOTED_NAMES) == 0) {
2048 char c = (char) _decodeCharForError(ch);
2049 _reportUnexpectedChar(c, "was expecting double-quote to start field name");
2050 }
2051
2055 final int[] codes = CharTypes.getInputCodeUtf8JsNames();
2056
2057 if (codes[ch] != 0) {
2058 _reportUnexpectedChar(ch, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name");
2059 }
2060
2061
2062
2063
2064 int[] quads = _quadBuffer;
2065 int qlen = 0;
2066 int currQuad = 0;
2067 int currQuadBytes = 0;
2068
2069 while (true) {
2070
2071 if (currQuadBytes < 4) {
2072 ++currQuadBytes;
2073 currQuad = (currQuad << 8) | ch;
2074 } else {
2075 if (qlen >= quads.length) {
2076 _quadBuffer = quads = growArrayBy(quads, quads.length);
2077 }
2078 quads[qlen++] = currQuad;
2079 currQuad = ch;
2080 currQuadBytes = 1;
2081 }
2082 if (_inputPtr >= _inputEnd) {
2083 if (!_loadMore()) {
2084 _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
2085 }
2086 }
2087 ch = _inputBuffer[_inputPtr] & 0xFF;
2088 if (codes[ch] != 0) {
2089 break;
2090 }
2091 ++_inputPtr;
2092 }
2093
2094 if (currQuadBytes > 0) {
2095 if (qlen >= quads.length) {
2096 _quadBuffer = quads = growArrayBy(quads, quads.length);
2097 }
2098 quads[qlen++] = currQuad;
2099 }
2100 String name = _symbols.findName(quads, qlen);
2101 if (name == null) {
2102 name = addName(quads, qlen, currQuadBytes);
2103 }
2104 return name;
2105 }
2106
2107
2112 protected String _parseAposName() throws IOException
2113 {
2114 if (_inputPtr >= _inputEnd) {
2115 if (!_loadMore()) {
2116 _reportInvalidEOF(": was expecting closing '\'' for field name", JsonToken.FIELD_NAME);
2117 }
2118 }
2119 int ch = _inputBuffer[_inputPtr++] & 0xFF;
2120 if (ch == INT_APOS) {
2121 return "";
2122 }
2123 int[] quads = _quadBuffer;
2124 int qlen = 0;
2125 int currQuad = 0;
2126 int currQuadBytes = 0;
2127
2128
2129
2130 final int[] codes = _icLatin1;
2131
2132 while (true) {
2133 if (ch == INT_APOS) {
2134 break;
2135 }
2136
2137 if ((codes[ch] != 0) && (ch != '"')) {
2138 if (ch != '\\') {
2139
2140
2141 _throwUnquotedSpace(ch, "name");
2142 } else {
2143
2144 ch = _decodeEscaped();
2145 }
2146
2147 if (ch > 127) {
2148
2149 if (currQuadBytes >= 4) {
2150 if (qlen >= quads.length) {
2151 _quadBuffer = quads = growArrayBy(quads, quads.length);
2152 }
2153 quads[qlen++] = currQuad;
2154 currQuad = 0;
2155 currQuadBytes = 0;
2156 }
2157 if (ch < 0x800) {
2158 currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
2159 ++currQuadBytes;
2160
2161 } else {
2162 currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
2163 ++currQuadBytes;
2164
2165 if (currQuadBytes >= 4) {
2166 if (qlen >= quads.length) {
2167 _quadBuffer = quads = growArrayBy(quads, quads.length);
2168 }
2169 quads[qlen++] = currQuad;
2170 currQuad = 0;
2171 currQuadBytes = 0;
2172 }
2173 currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
2174 ++currQuadBytes;
2175 }
2176
2177 ch = 0x80 | (ch & 0x3f);
2178 }
2179 }
2180
2181 if (currQuadBytes < 4) {
2182 ++currQuadBytes;
2183 currQuad = (currQuad << 8) | ch;
2184 } else {
2185 if (qlen >= quads.length) {
2186 _quadBuffer = quads = growArrayBy(quads, quads.length);
2187 }
2188 quads[qlen++] = currQuad;
2189 currQuad = ch;
2190 currQuadBytes = 1;
2191 }
2192 if (_inputPtr >= _inputEnd) {
2193 if (!_loadMore()) {
2194 _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
2195 }
2196 }
2197 ch = _inputBuffer[_inputPtr++] & 0xFF;
2198 }
2199
2200 if (currQuadBytes > 0) {
2201 if (qlen >= quads.length) {
2202 _quadBuffer = quads = growArrayBy(quads, quads.length);
2203 }
2204 quads[qlen++] = _padLastQuad(currQuad, currQuadBytes);
2205 }
2206 String name = _symbols.findName(quads, qlen);
2207 if (name == null) {
2208 name = addName(quads, qlen, currQuadBytes);
2209 }
2210 return name;
2211 }
2212
2213
2218
2219 private final String findName(int q1, int lastQuadBytes) throws JsonParseException
2220 {
2221 q1 = _padLastQuad(q1, lastQuadBytes);
2222
2223 String name = _symbols.findName(q1);
2224 if (name != null) {
2225 return name;
2226 }
2227
2228 _quadBuffer[0] = q1;
2229 return addName(_quadBuffer, 1, lastQuadBytes);
2230 }
2231
2232 private final String findName(int q1, int q2, int lastQuadBytes) throws JsonParseException
2233 {
2234 q2 = _padLastQuad(q2, lastQuadBytes);
2235
2236 String name = _symbols.findName(q1, q2);
2237 if (name != null) {
2238 return name;
2239 }
2240
2241 _quadBuffer[0] = q1;
2242 _quadBuffer[1] = q2;
2243 return addName(_quadBuffer, 2, lastQuadBytes);
2244 }
2245
2246 private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws JsonParseException
2247 {
2248 q3 = _padLastQuad(q3, lastQuadBytes);
2249 String name = _symbols.findName(q1, q2, q3);
2250 if (name != null) {
2251 return name;
2252 }
2253 int[] quads = _quadBuffer;
2254 quads[0] = q1;
2255 quads[1] = q2;
2256 quads[2] = _padLastQuad(q3, lastQuadBytes);
2257 return addName(quads, 3, lastQuadBytes);
2258 }
2259
2260 private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) throws JsonParseException
2261 {
2262 if (qlen >= quads.length) {
2263 _quadBuffer = quads = growArrayBy(quads, quads.length);
2264 }
2265 quads[qlen++] = _padLastQuad(lastQuad, lastQuadBytes);
2266 String name = _symbols.findName(quads, qlen);
2267 if (name == null) {
2268 return addName(quads, qlen, lastQuadBytes);
2269 }
2270 return name;
2271 }
2272
2273
2279 private final String addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException
2280 {
2281
2285
2286 int byteLen = (qlen << 2) - 4 + lastQuadBytes;
2287
2288
2293 int lastQuad;
2294
2295 if (lastQuadBytes < 4) {
2296 lastQuad = quads[qlen-1];
2297
2298 quads[qlen-1] = (lastQuad << ((4 - lastQuadBytes) << 3));
2299 } else {
2300 lastQuad = 0;
2301 }
2302
2303
2304 char[] cbuf = _textBuffer.emptyAndGetCurrentSegment();
2305 int cix = 0;
2306
2307 for (int ix = 0; ix < byteLen; ) {
2308 int ch = quads[ix >> 2];
2309 int byteIx = (ix & 3);
2310 ch = (ch >> ((3 - byteIx) << 3)) & 0xFF;
2311 ++ix;
2312
2313 if (ch > 127) {
2314 int needed;
2315 if ((ch & 0xE0) == 0xC0) {
2316 ch &= 0x1F;
2317 needed = 1;
2318 } else if ((ch & 0xF0) == 0xE0) {
2319 ch &= 0x0F;
2320 needed = 2;
2321 } else if ((ch & 0xF8) == 0xF0) {
2322 ch &= 0x07;
2323 needed = 3;
2324 } else {
2325 _reportInvalidInitial(ch);
2326 needed = ch = 1;
2327 }
2328 if ((ix + needed) > byteLen) {
2329 _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
2330 }
2331
2332
2333 int ch2 = quads[ix >> 2];
2334 byteIx = (ix & 3);
2335 ch2 = (ch2 >> ((3 - byteIx) << 3));
2336 ++ix;
2337
2338 if ((ch2 & 0xC0) != 0x080) {
2339 _reportInvalidOther(ch2);
2340 }
2341 ch = (ch << 6) | (ch2 & 0x3F);
2342 if (needed > 1) {
2343 ch2 = quads[ix >> 2];
2344 byteIx = (ix & 3);
2345 ch2 = (ch2 >> ((3 - byteIx) << 3));
2346 ++ix;
2347
2348 if ((ch2 & 0xC0) != 0x080) {
2349 _reportInvalidOther(ch2);
2350 }
2351 ch = (ch << 6) | (ch2 & 0x3F);
2352 if (needed > 2) {
2353 ch2 = quads[ix >> 2];
2354 byteIx = (ix & 3);
2355 ch2 = (ch2 >> ((3 - byteIx) << 3));
2356 ++ix;
2357 if ((ch2 & 0xC0) != 0x080) {
2358 _reportInvalidOther(ch2 & 0xFF);
2359 }
2360 ch = (ch << 6) | (ch2 & 0x3F);
2361 }
2362 }
2363 if (needed > 2) {
2364 ch -= 0x10000;
2365 if (cix >= cbuf.length) {
2366 cbuf = _textBuffer.expandCurrentSegment();
2367 }
2368 cbuf[cix++] = (char) (0xD800 + (ch >> 10));
2369 ch = 0xDC00 | (ch & 0x03FF);
2370 }
2371 }
2372 if (cix >= cbuf.length) {
2373 cbuf = _textBuffer.expandCurrentSegment();
2374 }
2375 cbuf[cix++] = (char) ch;
2376 }
2377
2378
2379 String baseName = new String(cbuf, 0, cix);
2380
2381 if (lastQuadBytes < 4) {
2382 quads[qlen-1] = lastQuad;
2383 }
2384 return _symbols.addName(baseName, quads, qlen);
2385 }
2386
2387
2390 private final static int _padLastQuad(int q, int bytes) {
2391 return (bytes == 4) ? q : (q | (-1 << (bytes << 3)));
2392 }
2393
2394
2399
2400 protected void _loadMoreGuaranteed() throws IOException {
2401 if (!_loadMore()) { _reportInvalidEOF(); }
2402 }
2403
2404 @Override
2405 protected void _finishString() throws IOException
2406 {
2407
2408 int ptr = _inputPtr;
2409 if (ptr >= _inputEnd) {
2410 _loadMoreGuaranteed();
2411 ptr = _inputPtr;
2412 }
2413 int outPtr = 0;
2414 char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
2415 final int[] codes = _icUTF8;
2416
2417 final int max = Math.min(_inputEnd, (ptr + outBuf.length));
2418 final byte[] inputBuffer = _inputBuffer;
2419 while (ptr < max) {
2420 int c = (int) inputBuffer[ptr] & 0xFF;
2421 if (codes[c] != 0) {
2422 if (c == INT_QUOTE) {
2423 _inputPtr = ptr+1;
2424 _textBuffer.setCurrentLength(outPtr);
2425 return;
2426 }
2427 break;
2428 }
2429 ++ptr;
2430 outBuf[outPtr++] = (char) c;
2431 }
2432 _inputPtr = ptr;
2433 _finishString2(outBuf, outPtr);
2434 }
2435
2436
2439 protected String _finishAndReturnString() throws IOException
2440 {
2441
2442 int ptr = _inputPtr;
2443 if (ptr >= _inputEnd) {
2444 _loadMoreGuaranteed();
2445 ptr = _inputPtr;
2446 }
2447 int outPtr = 0;
2448 char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
2449 final int[] codes = _icUTF8;
2450
2451 final int max = Math.min(_inputEnd, (ptr + outBuf.length));
2452 final byte[] inputBuffer = _inputBuffer;
2453 while (ptr < max) {
2454 int c = (int) inputBuffer[ptr] & 0xFF;
2455 if (codes[c] != 0) {
2456 if (c == INT_QUOTE) {
2457 _inputPtr = ptr+1;
2458 return _textBuffer.setCurrentAndReturn(outPtr);
2459 }
2460 break;
2461 }
2462 ++ptr;
2463 outBuf[outPtr++] = (char) c;
2464 }
2465 _inputPtr = ptr;
2466 _finishString2(outBuf, outPtr);
2467 return _textBuffer.contentsAsString();
2468 }
2469
2470 private final void _finishString2(char[] outBuf, int outPtr)
2471 throws IOException
2472 {
2473 int c;
2474
2475
2476 final int[] codes = _icUTF8;
2477 final byte[] inputBuffer = _inputBuffer;
2478
2479 main_loop:
2480 while (true) {
2481
2482 ascii_loop:
2483 while (true) {
2484 int ptr = _inputPtr;
2485 if (ptr >= _inputEnd) {
2486 _loadMoreGuaranteed();
2487 ptr = _inputPtr;
2488 }
2489 if (outPtr >= outBuf.length) {
2490 outBuf = _textBuffer.finishCurrentSegment();
2491 outPtr = 0;
2492 }
2493 final int max = Math.min(_inputEnd, (ptr + (outBuf.length - outPtr)));
2494 while (ptr < max) {
2495 c = (int) inputBuffer[ptr++] & 0xFF;
2496 if (codes[c] != 0) {
2497 _inputPtr = ptr;
2498 break ascii_loop;
2499 }
2500 outBuf[outPtr++] = (char) c;
2501 }
2502 _inputPtr = ptr;
2503 }
2504
2505 if (c == INT_QUOTE) {
2506 break main_loop;
2507 }
2508
2509 switch (codes[c]) {
2510 case 1:
2511 c = _decodeEscaped();
2512 break;
2513 case 2:
2514 c = _decodeUtf8_2(c);
2515 break;
2516 case 3:
2517 if ((_inputEnd - _inputPtr) >= 2) {
2518 c = _decodeUtf8_3fast(c);
2519 } else {
2520 c = _decodeUtf8_3(c);
2521 }
2522 break;
2523 case 4:
2524 c = _decodeUtf8_4(c);
2525
2526 outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
2527 if (outPtr >= outBuf.length) {
2528 outBuf = _textBuffer.finishCurrentSegment();
2529 outPtr = 0;
2530 }
2531 c = 0xDC00 | (c & 0x3FF);
2532
2533 break;
2534 default:
2535 if (c < INT_SPACE) {
2536
2537 _throwUnquotedSpace(c, "string value");
2538 } else {
2539
2540 _reportInvalidChar(c);
2541 }
2542 }
2543
2544 if (outPtr >= outBuf.length) {
2545 outBuf = _textBuffer.finishCurrentSegment();
2546 outPtr = 0;
2547 }
2548
2549 outBuf[outPtr++] = (char) c;
2550 }
2551 _textBuffer.setCurrentLength(outPtr);
2552 }
2553
2554
2559 protected void _skipString() throws IOException
2560 {
2561 _tokenIncomplete = false;
2562
2563
2564 final int[] codes = _icUTF8;
2565 final byte[] inputBuffer = _inputBuffer;
2566
2567 main_loop:
2568 while (true) {
2569 int c;
2570
2571 ascii_loop:
2572 while (true) {
2573 int ptr = _inputPtr;
2574 int max = _inputEnd;
2575 if (ptr >= max) {
2576 _loadMoreGuaranteed();
2577 ptr = _inputPtr;
2578 max = _inputEnd;
2579 }
2580 while (ptr < max) {
2581 c = (int) inputBuffer[ptr++] & 0xFF;
2582 if (codes[c] != 0) {
2583 _inputPtr = ptr;
2584 break ascii_loop;
2585 }
2586 }
2587 _inputPtr = ptr;
2588 }
2589
2590 if (c == INT_QUOTE) {
2591 break main_loop;
2592 }
2593
2594 switch (codes[c]) {
2595 case 1:
2596 _decodeEscaped();
2597 break;
2598 case 2:
2599 _skipUtf8_2();
2600 break;
2601 case 3:
2602 _skipUtf8_3();
2603 break;
2604 case 4:
2605 _skipUtf8_4(c);
2606 break;
2607 default:
2608 if (c < INT_SPACE) {
2609 _throwUnquotedSpace(c, "string value");
2610 } else {
2611
2612 _reportInvalidChar(c);
2613 }
2614 }
2615 }
2616 }
2617
2618
2622 protected JsonToken _handleUnexpectedValue(int c) throws IOException
2623 {
2624
2625 switch (c) {
2626
2633 case ']':
2634 if (!_parsingContext.inArray()) {
2635 break;
2636 }
2637
2638 case ',':
2639
2640
2641
2642
2643 if (!_parsingContext.inRoot()) {
2644 if ((_features & FEAT_MASK_ALLOW_MISSING) != 0) {
2645 --_inputPtr;
2646 return JsonToken.VALUE_NULL;
2647 }
2648 }
2649
2650 case '}':
2651
2652
2653 _reportUnexpectedChar(c, "expected a value");
2654 case '\'':
2655 if ((_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) {
2656 return _handleApos();
2657 }
2658 break;
2659 case 'N':
2660 _matchToken("NaN", 1);
2661 if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
2662 return resetAsNaN("NaN", Double.NaN);
2663 }
2664 _reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
2665 break;
2666 case 'I':
2667 _matchToken("Infinity", 1);
2668 if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
2669 return resetAsNaN("Infinity", Double.POSITIVE_INFINITY);
2670 }
2671 _reportError("Non-standard token 'Infinity': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
2672 break;
2673 case '+':
2674 if (_inputPtr >= _inputEnd) {
2675 if (!_loadMore()) {
2676 _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_INT);
2677 }
2678 }
2679 return _handleInvalidNumberStart(_inputBuffer[_inputPtr++] & 0xFF, false);
2680 }
2681
2682 if (Character.isJavaIdentifierStart(c)) {
2683 _reportInvalidToken(""+((char) c), _validJsonTokenList());
2684 }
2685
2686 _reportUnexpectedChar(c, "expected a valid value "+_validJsonValueList());
2687 return null;
2688 }
2689
2690 protected JsonToken _handleApos() throws IOException
2691 {
2692 int c = 0;
2693
2694 int outPtr = 0;
2695 char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
2696
2697
2698 final int[] codes = _icUTF8;
2699 final byte[] inputBuffer = _inputBuffer;
2700
2701 main_loop:
2702 while (true) {
2703
2704 ascii_loop:
2705 while (true) {
2706 if (_inputPtr >= _inputEnd) {
2707 _loadMoreGuaranteed();
2708 }
2709 if (outPtr >= outBuf.length) {
2710 outBuf = _textBuffer.finishCurrentSegment();
2711 outPtr = 0;
2712 }
2713 int max = _inputEnd;
2714 {
2715 int max2 = _inputPtr + (outBuf.length - outPtr);
2716 if (max2 < max) {
2717 max = max2;
2718 }
2719 }
2720 while (_inputPtr < max) {
2721 c = (int) inputBuffer[_inputPtr++] & 0xFF;
2722 if (c == INT_APOS || codes[c] != 0) {
2723 break ascii_loop;
2724 }
2725 outBuf[outPtr++] = (char) c;
2726 }
2727 }
2728
2729
2730 if (c == INT_APOS) {
2731 break main_loop;
2732 }
2733
2734 switch (codes[c]) {
2735 case 1:
2736 c = _decodeEscaped();
2737 break;
2738 case 2:
2739 c = _decodeUtf8_2(c);
2740 break;
2741 case 3:
2742 if ((_inputEnd - _inputPtr) >= 2) {
2743 c = _decodeUtf8_3fast(c);
2744 } else {
2745 c = _decodeUtf8_3(c);
2746 }
2747 break;
2748 case 4:
2749 c = _decodeUtf8_4(c);
2750
2751 outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
2752 if (outPtr >= outBuf.length) {
2753 outBuf = _textBuffer.finishCurrentSegment();
2754 outPtr = 0;
2755 }
2756 c = 0xDC00 | (c & 0x3FF);
2757
2758 break;
2759 default:
2760 if (c < INT_SPACE) {
2761 _throwUnquotedSpace(c, "string value");
2762 }
2763
2764 _reportInvalidChar(c);
2765 }
2766
2767 if (outPtr >= outBuf.length) {
2768 outBuf = _textBuffer.finishCurrentSegment();
2769 outPtr = 0;
2770 }
2771
2772 outBuf[outPtr++] = (char) c;
2773 }
2774 _textBuffer.setCurrentLength(outPtr);
2775
2776 return JsonToken.VALUE_STRING;
2777 }
2778
2779
2784
2785
2789 protected JsonToken _handleInvalidNumberStart(int ch, boolean neg) throws IOException
2790 {
2791 while (ch == 'I') {
2792 if (_inputPtr >= _inputEnd) {
2793 if (!_loadMore()) {
2794 _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_FLOAT);
2795 }
2796 }
2797 ch = _inputBuffer[_inputPtr++];
2798 String match;
2799 if (ch == 'N') {
2800 match = neg ? "-INF" :"+INF";
2801 } else if (ch == 'n') {
2802 match = neg ? "-Infinity" :"+Infinity";
2803 } else {
2804 break;
2805 }
2806 _matchToken(match, 3);
2807 if ((_features & FEAT_MASK_NON_NUM_NUMBERS) != 0) {
2808 return resetAsNaN(match, neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
2809 }
2810 _reportError("Non-standard token '%s': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow",
2811 match);
2812 }
2813 reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value");
2814 return null;
2815 }
2816
2817
2818 protected final void _matchTrue() throws IOException
2819 {
2820 int ptr = _inputPtr;
2821 if ((ptr + 3) < _inputEnd) {
2822 byte[] buf = _inputBuffer;
2823 if ((buf[ptr++] == 'r')
2824 && (buf[ptr++] == 'u')
2825 && (buf[ptr++] == 'e')) {
2826 int ch = buf[ptr] & 0xFF;
2827 if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) {
2828 _inputPtr = ptr;
2829 return;
2830 }
2831 }
2832 }
2833 _matchToken2("true", 1);
2834 }
2835
2836 protected final void _matchFalse() throws IOException
2837 {
2838 int ptr = _inputPtr;
2839 if ((ptr + 4) < _inputEnd) {
2840 byte[] buf = _inputBuffer;
2841 if ((buf[ptr++] == 'a')
2842 && (buf[ptr++] == 'l')
2843 && (buf[ptr++] == 's')
2844 && (buf[ptr++] == 'e')) {
2845 int ch = buf[ptr] & 0xFF;
2846 if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) {
2847 _inputPtr = ptr;
2848 return;
2849 }
2850 }
2851 }
2852 _matchToken2("false", 1);
2853 }
2854
2855 protected final void _matchNull() throws IOException
2856 {
2857 int ptr = _inputPtr;
2858 if ((ptr + 3) < _inputEnd) {
2859 byte[] buf = _inputBuffer;
2860 if ((buf[ptr++] == 'u')
2861 && (buf[ptr++] == 'l')
2862 && (buf[ptr++] == 'l')) {
2863 int ch = buf[ptr] & 0xFF;
2864 if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) {
2865 _inputPtr = ptr;
2866 return;
2867 }
2868 }
2869 }
2870 _matchToken2("null", 1);
2871 }
2872
2873 protected final void _matchToken(String matchStr, int i) throws IOException
2874 {
2875 final int len = matchStr.length();
2876 if ((_inputPtr + len) >= _inputEnd) {
2877 _matchToken2(matchStr, i);
2878 return;
2879 }
2880 do {
2881 if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) {
2882 _reportInvalidToken(matchStr.substring(0, i));
2883 }
2884 ++_inputPtr;
2885 } while (++i < len);
2886
2887 int ch = _inputBuffer[_inputPtr] & 0xFF;
2888 if (ch >= '0' && ch != ']' && ch != '}') {
2889 _checkMatchEnd(matchStr, i, ch);
2890 }
2891 }
2892
2893 private final void _matchToken2(String matchStr, int i) throws IOException
2894 {
2895 final int len = matchStr.length();
2896 do {
2897 if (((_inputPtr >= _inputEnd) && !_loadMore())
2898 || (_inputBuffer[_inputPtr] != matchStr.charAt(i))) {
2899 _reportInvalidToken(matchStr.substring(0, i));
2900 }
2901 ++_inputPtr;
2902 } while (++i < len);
2903
2904
2905 if (_inputPtr >= _inputEnd && !_loadMore()) {
2906 return;
2907 }
2908 int ch = _inputBuffer[_inputPtr] & 0xFF;
2909 if (ch >= '0' && ch != ']' && ch != '}') {
2910 _checkMatchEnd(matchStr, i, ch);
2911 }
2912 }
2913
2914 private final void _checkMatchEnd(String matchStr, int i, int ch) throws IOException {
2915
2916 char c = (char) _decodeCharForError(ch);
2917 if (Character.isJavaIdentifierPart(c)) {
2918 _reportInvalidToken(matchStr.substring(0, i));
2919 }
2920 }
2921
2922
2927
2928 private final int _skipWS() throws IOException
2929 {
2930 while (_inputPtr < _inputEnd) {
2931 int i = _inputBuffer[_inputPtr++] & 0xFF;
2932 if (i > INT_SPACE) {
2933 if (i == INT_SLASH || i == INT_HASH) {
2934 --_inputPtr;
2935 return _skipWS2();
2936 }
2937 return i;
2938 }
2939 if (i != INT_SPACE) {
2940 if (i == INT_LF) {
2941 ++_currInputRow;
2942 _currInputRowStart = _inputPtr;
2943 } else if (i == INT_CR) {
2944 _skipCR();
2945 } else if (i != INT_TAB) {
2946 _throwInvalidSpace(i);
2947 }
2948 }
2949 }
2950 return _skipWS2();
2951 }
2952
2953 private final int _skipWS2() throws IOException
2954 {
2955 while (_inputPtr < _inputEnd || _loadMore()) {
2956 int i = _inputBuffer[_inputPtr++] & 0xFF;
2957 if (i > INT_SPACE) {
2958 if (i == INT_SLASH) {
2959 _skipComment();
2960 continue;
2961 }
2962 if (i == INT_HASH) {
2963 if (_skipYAMLComment()) {
2964 continue;
2965 }
2966 }
2967 return i;
2968 }
2969 if (i != INT_SPACE) {
2970 if (i == INT_LF) {
2971 ++_currInputRow;
2972 _currInputRowStart = _inputPtr;
2973 } else if (i == INT_CR) {
2974 _skipCR();
2975 } else if (i != INT_TAB) {
2976 _throwInvalidSpace(i);
2977 }
2978 }
2979 }
2980 throw _constructError("Unexpected end-of-input within/between "+_parsingContext.typeDesc()+" entries");
2981 }
2982
2983 private final int _skipWSOrEnd() throws IOException
2984 {
2985
2986
2987 if (_inputPtr >= _inputEnd) {
2988 if (!_loadMore()) {
2989 return _eofAsNextChar();
2990 }
2991 }
2992 int i = _inputBuffer[_inputPtr++] & 0xFF;
2993 if (i > INT_SPACE) {
2994 if (i == INT_SLASH || i == INT_HASH) {
2995 --_inputPtr;
2996 return _skipWSOrEnd2();
2997 }
2998 return i;
2999 }
3000 if (i != INT_SPACE) {
3001 if (i == INT_LF) {
3002 ++_currInputRow;
3003 _currInputRowStart = _inputPtr;
3004 } else if (i == INT_CR) {
3005 _skipCR();
3006 } else if (i != INT_TAB) {
3007 _throwInvalidSpace(i);
3008 }
3009 }
3010
3011 while (_inputPtr < _inputEnd) {
3012 i = _inputBuffer[_inputPtr++] & 0xFF;
3013 if (i > INT_SPACE) {
3014 if (i == INT_SLASH || i == INT_HASH) {
3015 --_inputPtr;
3016 return _skipWSOrEnd2();
3017 }
3018 return i;
3019 }
3020 if (i != INT_SPACE) {
3021 if (i == INT_LF) {
3022 ++_currInputRow;
3023 _currInputRowStart = _inputPtr;
3024 } else if (i == INT_CR) {
3025 _skipCR();
3026 } else if (i != INT_TAB) {
3027 _throwInvalidSpace(i);
3028 }
3029 }
3030 }
3031 return _skipWSOrEnd2();
3032 }
3033
3034 private final int _skipWSOrEnd2() throws IOException
3035 {
3036 while ((_inputPtr < _inputEnd) || _loadMore()) {
3037 int i = _inputBuffer[_inputPtr++] & 0xFF;
3038 if (i > INT_SPACE) {
3039 if (i == INT_SLASH) {
3040 _skipComment();
3041 continue;
3042 }
3043 if (i == INT_HASH) {
3044 if (_skipYAMLComment()) {
3045 continue;
3046 }
3047 }
3048 return i;
3049 } else if (i != INT_SPACE) {
3050 if (i == INT_LF) {
3051 ++_currInputRow;
3052 _currInputRowStart = _inputPtr;
3053 } else if (i == INT_CR) {
3054 _skipCR();
3055 } else if (i != INT_TAB) {
3056 _throwInvalidSpace(i);
3057 }
3058 }
3059 }
3060
3061 return _eofAsNextChar();
3062 }
3063
3064 private final int _skipColon() throws IOException
3065 {
3066 if ((_inputPtr + 4) >= _inputEnd) {
3067 return _skipColon2(false);
3068 }
3069
3070 int i = _inputBuffer[_inputPtr];
3071 if (i == INT_COLON) {
3072 i = _inputBuffer[++_inputPtr];
3073 if (i > INT_SPACE) {
3074 if (i == INT_SLASH || i == INT_HASH) {
3075 return _skipColon2(true);
3076 }
3077 ++_inputPtr;
3078 return i;
3079 }
3080 if (i == INT_SPACE || i == INT_TAB) {
3081 i = (int) _inputBuffer[++_inputPtr];
3082 if (i > INT_SPACE) {
3083 if (i == INT_SLASH || i == INT_HASH) {
3084 return _skipColon2(true);
3085 }
3086 ++_inputPtr;
3087 return i;
3088 }
3089 }
3090 return _skipColon2(true);
3091 }
3092 if (i == INT_SPACE || i == INT_TAB) {
3093 i = _inputBuffer[++_inputPtr];
3094 }
3095 if (i == INT_COLON) {
3096 i = _inputBuffer[++_inputPtr];
3097 if (i > INT_SPACE) {
3098 if (i == INT_SLASH || i == INT_HASH) {
3099 return _skipColon2(true);
3100 }
3101 ++_inputPtr;
3102 return i;
3103 }
3104 if (i == INT_SPACE || i == INT_TAB) {
3105 i = (int) _inputBuffer[++_inputPtr];
3106 if (i > INT_SPACE) {
3107 if (i == INT_SLASH || i == INT_HASH) {
3108 return _skipColon2(true);
3109 }
3110 ++_inputPtr;
3111 return i;
3112 }
3113 }
3114 return _skipColon2(true);
3115 }
3116 return _skipColon2(false);
3117 }
3118
3119 private final int _skipColon2(boolean gotColon) throws IOException
3120 {
3121 while (_inputPtr < _inputEnd || _loadMore()) {
3122 int i = _inputBuffer[_inputPtr++] & 0xFF;
3123
3124 if (i > INT_SPACE) {
3125 if (i == INT_SLASH) {
3126 _skipComment();
3127 continue;
3128 }
3129 if (i == INT_HASH) {
3130 if (_skipYAMLComment()) {
3131 continue;
3132 }
3133 }
3134 if (gotColon) {
3135 return i;
3136 }
3137 if (i != INT_COLON) {
3138 _reportUnexpectedChar(i, "was expecting a colon to separate field name and value");
3139 }
3140 gotColon = true;
3141 } else if (i != INT_SPACE) {
3142 if (i == INT_LF) {
3143 ++_currInputRow;
3144 _currInputRowStart = _inputPtr;
3145 } else if (i == INT_CR) {
3146 _skipCR();
3147 } else if (i != INT_TAB) {
3148 _throwInvalidSpace(i);
3149 }
3150 }
3151 }
3152 _reportInvalidEOF(" within/between "+_parsingContext.typeDesc()+" entries",
3153 null);
3154 return -1;
3155 }
3156
3157 private final void _skipComment() throws IOException
3158 {
3159 if ((_features & FEAT_MASK_ALLOW_JAVA_COMMENTS) == 0) {
3160 _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)");
3161 }
3162
3163 if (_inputPtr >= _inputEnd && !_loadMore()) {
3164 _reportInvalidEOF(" in a comment", null);
3165 }
3166 int c = _inputBuffer[_inputPtr++] & 0xFF;
3167 if (c == INT_SLASH) {
3168 _skipLine();
3169 } else if (c == INT_ASTERISK) {
3170 _skipCComment();
3171 } else {
3172 _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment");
3173 }
3174 }
3175
3176 private final void _skipCComment() throws IOException
3177 {
3178
3179 final int[] codes = CharTypes.getInputCodeComment();
3180
3181
3182 main_loop:
3183 while ((_inputPtr < _inputEnd) || _loadMore()) {
3184 int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
3185 int code = codes[i];
3186 if (code != 0) {
3187 switch (code) {
3188 case '*':
3189 if (_inputPtr >= _inputEnd && !_loadMore()) {
3190 break main_loop;
3191 }
3192 if (_inputBuffer[_inputPtr] == INT_SLASH) {
3193 ++_inputPtr;
3194 return;
3195 }
3196 break;
3197 case INT_LF:
3198 ++_currInputRow;
3199 _currInputRowStart = _inputPtr;
3200 break;
3201 case INT_CR:
3202 _skipCR();
3203 break;
3204 case 2:
3205 _skipUtf8_2();
3206 break;
3207 case 3:
3208 _skipUtf8_3();
3209 break;
3210 case 4:
3211 _skipUtf8_4(i);
3212 break;
3213 default:
3214
3215 _reportInvalidChar(i);
3216 }
3217 }
3218 }
3219 _reportInvalidEOF(" in a comment", null);
3220 }
3221
3222 private final boolean _skipYAMLComment() throws IOException
3223 {
3224 if ((_features & FEAT_MASK_ALLOW_YAML_COMMENTS) == 0) {
3225 return false;
3226 }
3227 _skipLine();
3228 return true;
3229 }
3230
3231
3235 private final void _skipLine() throws IOException
3236 {
3237
3238 final int[] codes = CharTypes.getInputCodeComment();
3239 while ((_inputPtr < _inputEnd) || _loadMore()) {
3240 int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
3241 int code = codes[i];
3242 if (code != 0) {
3243 switch (code) {
3244 case INT_LF:
3245 ++_currInputRow;
3246 _currInputRowStart = _inputPtr;
3247 return;
3248 case INT_CR:
3249 _skipCR();
3250 return;
3251 case '*':
3252 break;
3253 case 2:
3254 _skipUtf8_2();
3255 break;
3256 case 3:
3257 _skipUtf8_3();
3258 break;
3259 case 4:
3260 _skipUtf8_4(i);
3261 break;
3262 default:
3263 if (code < 0) {
3264
3265 _reportInvalidChar(i);
3266 }
3267 }
3268 }
3269 }
3270 }
3271
3272 @Override
3273 protected char _decodeEscaped() throws IOException
3274 {
3275 if (_inputPtr >= _inputEnd) {
3276 if (!_loadMore()) {
3277 _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
3278 }
3279 }
3280 int c = (int) _inputBuffer[_inputPtr++];
3281
3282 switch (c) {
3283
3284 case 'b':
3285 return '\b';
3286 case 't':
3287 return '\t';
3288 case 'n':
3289 return '\n';
3290 case 'f':
3291 return '\f';
3292 case 'r':
3293 return '\r';
3294
3295
3296 case '"':
3297 case '/':
3298 case '\\':
3299 return (char) c;
3300
3301 case 'u':
3302 break;
3303
3304 default:
3305 return _handleUnrecognizedCharacterEscape((char) _decodeCharForError(c));
3306 }
3307
3308
3309 int value = 0;
3310 for (int i = 0; i < 4; ++i) {
3311 if (_inputPtr >= _inputEnd) {
3312 if (!_loadMore()) {
3313 _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
3314 }
3315 }
3316 int ch = _inputBuffer[_inputPtr++];
3317 int digit = CharTypes.charToHex(ch);
3318 if (digit < 0) {
3319 _reportUnexpectedChar(ch & 0xFF, "expected a hex-digit for character escape sequence");
3320 }
3321 value = (value << 4) | digit;
3322 }
3323 return (char) value;
3324 }
3325
3326 protected int _decodeCharForError(int firstByte) throws IOException
3327 {
3328 int c = firstByte & 0xFF;
3329 if (c > 0x7F) {
3330 int needed;
3331
3332
3333 if ((c & 0xE0) == 0xC0) {
3334 c &= 0x1F;
3335 needed = 1;
3336 } else if ((c & 0xF0) == 0xE0) {
3337 c &= 0x0F;
3338 needed = 2;
3339 } else if ((c & 0xF8) == 0xF0) {
3340
3341 c &= 0x07;
3342 needed = 3;
3343 } else {
3344 _reportInvalidInitial(c & 0xFF);
3345 needed = 1;
3346 }
3347
3348 int d = nextByte();
3349 if ((d & 0xC0) != 0x080) {
3350 _reportInvalidOther(d & 0xFF);
3351 }
3352 c = (c << 6) | (d & 0x3F);
3353
3354 if (needed > 1) {
3355 d = nextByte();
3356 if ((d & 0xC0) != 0x080) {
3357 _reportInvalidOther(d & 0xFF);
3358 }
3359 c = (c << 6) | (d & 0x3F);
3360 if (needed > 2) {
3361 d = nextByte();
3362 if ((d & 0xC0) != 0x080) {
3363 _reportInvalidOther(d & 0xFF);
3364 }
3365 c = (c << 6) | (d & 0x3F);
3366 }
3367 }
3368 }
3369 return c;
3370 }
3371
3372
3377
3378 private final int _decodeUtf8_2(int c) throws IOException
3379 {
3380 if (_inputPtr >= _inputEnd) {
3381 _loadMoreGuaranteed();
3382 }
3383 int d = (int) _inputBuffer[_inputPtr++];
3384 if ((d & 0xC0) != 0x080) {
3385 _reportInvalidOther(d & 0xFF, _inputPtr);
3386 }
3387 return ((c & 0x1F) << 6) | (d & 0x3F);
3388 }
3389
3390 private final int _decodeUtf8_3(int c1) throws IOException
3391 {
3392 if (_inputPtr >= _inputEnd) {
3393 _loadMoreGuaranteed();
3394 }
3395 c1 &= 0x0F;
3396 int d = (int) _inputBuffer[_inputPtr++];
3397 if ((d & 0xC0) != 0x080) {
3398 _reportInvalidOther(d & 0xFF, _inputPtr);
3399 }
3400 int c = (c1 << 6) | (d & 0x3F);
3401 if (_inputPtr >= _inputEnd) {
3402 _loadMoreGuaranteed();
3403 }
3404 d = (int) _inputBuffer[_inputPtr++];
3405 if ((d & 0xC0) != 0x080) {
3406 _reportInvalidOther(d & 0xFF, _inputPtr);
3407 }
3408 c = (c << 6) | (d & 0x3F);
3409 return c;
3410 }
3411
3412 private final int _decodeUtf8_3fast(int c1) throws IOException
3413 {
3414 c1 &= 0x0F;
3415 int d = (int) _inputBuffer[_inputPtr++];
3416 if ((d & 0xC0) != 0x080) {
3417 _reportInvalidOther(d & 0xFF, _inputPtr);
3418 }
3419 int c = (c1 << 6) | (d & 0x3F);
3420 d = (int) _inputBuffer[_inputPtr++];
3421 if ((d & 0xC0) != 0x080) {
3422 _reportInvalidOther(d & 0xFF, _inputPtr);
3423 }
3424 c = (c << 6) | (d & 0x3F);
3425 return c;
3426 }
3427
3428
3432 private final int _decodeUtf8_4(int c) throws IOException
3433 {
3434 if (_inputPtr >= _inputEnd) {
3435 _loadMoreGuaranteed();
3436 }
3437 int d = (int) _inputBuffer[_inputPtr++];
3438 if ((d & 0xC0) != 0x080) {
3439 _reportInvalidOther(d & 0xFF, _inputPtr);
3440 }
3441 c = ((c & 0x07) << 6) | (d & 0x3F);
3442
3443 if (_inputPtr >= _inputEnd) {
3444 _loadMoreGuaranteed();
3445 }
3446 d = (int) _inputBuffer[_inputPtr++];
3447 if ((d & 0xC0) != 0x080) {
3448 _reportInvalidOther(d & 0xFF, _inputPtr);
3449 }
3450 c = (c << 6) | (d & 0x3F);
3451 if (_inputPtr >= _inputEnd) {
3452 _loadMoreGuaranteed();
3453 }
3454 d = (int) _inputBuffer[_inputPtr++];
3455 if ((d & 0xC0) != 0x080) {
3456 _reportInvalidOther(d & 0xFF, _inputPtr);
3457 }
3458
3459
3462 return ((c << 6) | (d & 0x3F)) - 0x10000;
3463 }
3464
3465 private final void _skipUtf8_2() throws IOException
3466 {
3467 if (_inputPtr >= _inputEnd) {
3468 _loadMoreGuaranteed();
3469 }
3470 int c = (int) _inputBuffer[_inputPtr++];
3471 if ((c & 0xC0) != 0x080) {
3472 _reportInvalidOther(c & 0xFF, _inputPtr);
3473 }
3474 }
3475
3476
3479 private final void _skipUtf8_3() throws IOException
3480 {
3481 if (_inputPtr >= _inputEnd) {
3482 _loadMoreGuaranteed();
3483 }
3484
3485 int c = (int) _inputBuffer[_inputPtr++];
3486 if ((c & 0xC0) != 0x080) {
3487 _reportInvalidOther(c & 0xFF, _inputPtr);
3488 }
3489 if (_inputPtr >= _inputEnd) {
3490 _loadMoreGuaranteed();
3491 }
3492 c = (int) _inputBuffer[_inputPtr++];
3493 if ((c & 0xC0) != 0x080) {
3494 _reportInvalidOther(c & 0xFF, _inputPtr);
3495 }
3496 }
3497
3498 private final void _skipUtf8_4(int c) throws IOException
3499 {
3500 if (_inputPtr >= _inputEnd) {
3501 _loadMoreGuaranteed();
3502 }
3503 int d = (int) _inputBuffer[_inputPtr++];
3504 if ((d & 0xC0) != 0x080) {
3505 _reportInvalidOther(d & 0xFF, _inputPtr);
3506 }
3507 if (_inputPtr >= _inputEnd) {
3508 _loadMoreGuaranteed();
3509 }
3510 d = (int) _inputBuffer[_inputPtr++];
3511 if ((d & 0xC0) != 0x080) {
3512 _reportInvalidOther(d & 0xFF, _inputPtr);
3513 }
3514 if (_inputPtr >= _inputEnd) {
3515 _loadMoreGuaranteed();
3516 }
3517 d = (int) _inputBuffer[_inputPtr++];
3518 if ((d & 0xC0) != 0x080) {
3519 _reportInvalidOther(d & 0xFF, _inputPtr);
3520 }
3521 }
3522
3523
3528
3529
3533 protected final void _skipCR() throws IOException
3534 {
3535 if (_inputPtr < _inputEnd || _loadMore()) {
3536 if (_inputBuffer[_inputPtr] == BYTE_LF) {
3537 ++_inputPtr;
3538 }
3539 }
3540 ++_currInputRow;
3541 _currInputRowStart = _inputPtr;
3542 }
3543
3544 private int nextByte() throws IOException
3545 {
3546 if (_inputPtr >= _inputEnd) {
3547 _loadMoreGuaranteed();
3548 }
3549 return _inputBuffer[_inputPtr++] & 0xFF;
3550 }
3551
3552
3557
3558 protected void _reportInvalidToken(String matchedPart, int ptr) throws IOException {
3559 _inputPtr = ptr;
3560 _reportInvalidToken(matchedPart, _validJsonTokenList());
3561 }
3562
3563 protected void _reportInvalidToken(String matchedPart) throws IOException {
3564 _reportInvalidToken(matchedPart, _validJsonTokenList());
3565 }
3566
3567 protected void _reportInvalidToken(String matchedPart, String msg) throws IOException
3568 {
3569
3573 StringBuilder sb = new StringBuilder(matchedPart);
3574 while ((_inputPtr < _inputEnd) || _loadMore()) {
3575 int i = (int) _inputBuffer[_inputPtr++];
3576 char c = (char) _decodeCharForError(i);
3577 if (!Character.isJavaIdentifierPart(c)) {
3578
3579
3580 break;
3581 }
3582 sb.append(c);
3583 if (sb.length() >= MAX_ERROR_TOKEN_LENGTH) {
3584 sb.append("...");
3585 break;
3586 }
3587 }
3588 _reportError("Unrecognized token '%s': was expecting %s", sb, msg);
3589 }
3590
3591 protected void _reportInvalidChar(int c) throws JsonParseException
3592 {
3593
3594 if (c < INT_SPACE) {
3595 _throwInvalidSpace(c);
3596 }
3597 _reportInvalidInitial(c);
3598 }
3599
3600 protected void _reportInvalidInitial(int mask) throws JsonParseException {
3601 _reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask));
3602 }
3603
3604 protected void _reportInvalidOther(int mask) throws JsonParseException {
3605 _reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask));
3606 }
3607
3608 protected void _reportInvalidOther(int mask, int ptr)
3609 throws JsonParseException
3610 {
3611 _inputPtr = ptr;
3612 _reportInvalidOther(mask);
3613 }
3614
3615
3620
3621
3625 @SuppressWarnings("resource")
3626 protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOException
3627 {
3628 ByteArrayBuilder builder = _getByteArrayBuilder();
3629
3630 while (true) {
3631
3632 int ch;
3633 do {
3634 if (_inputPtr >= _inputEnd) {
3635 _loadMoreGuaranteed();
3636 }
3637 ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
3638 } while (ch <= INT_SPACE);
3639 int bits = b64variant.decodeBase64Char(ch);
3640 if (bits < 0) {
3641 if (ch == INT_QUOTE) {
3642 return builder.toByteArray();
3643 }
3644 bits = _decodeBase64Escape(b64variant, ch, 0);
3645 if (bits < 0) {
3646 continue;
3647 }
3648 }
3649 int decodedData = bits;
3650
3651
3652
3653 if (_inputPtr >= _inputEnd) {
3654 _loadMoreGuaranteed();
3655 }
3656 ch = _inputBuffer[_inputPtr++] & 0xFF;
3657 bits = b64variant.decodeBase64Char(ch);
3658 if (bits < 0) {
3659 bits = _decodeBase64Escape(b64variant, ch, 1);
3660 }
3661 decodedData = (decodedData << 6) | bits;
3662
3663
3664 if (_inputPtr >= _inputEnd) {
3665 _loadMoreGuaranteed();
3666 }
3667 ch = _inputBuffer[_inputPtr++] & 0xFF;
3668 bits = b64variant.decodeBase64Char(ch);
3669
3670
3671 if (bits < 0) {
3672 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
3673
3674 if (ch == INT_QUOTE) {
3675 decodedData >>= 4;
3676 builder.append(decodedData);
3677 if (b64variant.usesPadding()) {
3678 --_inputPtr;
3679 _handleBase64MissingPadding(b64variant);
3680 }
3681 return builder.toByteArray();
3682 }
3683 bits = _decodeBase64Escape(b64variant, ch, 2);
3684 }
3685 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
3686
3687 if (_inputPtr >= _inputEnd) {
3688 _loadMoreGuaranteed();
3689 }
3690 ch = _inputBuffer[_inputPtr++] & 0xFF;
3691 if (!b64variant.usesPaddingChar(ch)) {
3692 if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) {
3693 throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
3694 }
3695 }
3696
3697 decodedData >>= 4;
3698 builder.append(decodedData);
3699 continue;
3700 }
3701 }
3702
3703 decodedData = (decodedData << 6) | bits;
3704
3705 if (_inputPtr >= _inputEnd) {
3706 _loadMoreGuaranteed();
3707 }
3708 ch = _inputBuffer[_inputPtr++] & 0xFF;
3709 bits = b64variant.decodeBase64Char(ch);
3710 if (bits < 0) {
3711 if (bits != Base64Variant.BASE64_VALUE_PADDING) {
3712
3713 if (ch == INT_QUOTE) {
3714 decodedData >>= 2;
3715 builder.appendTwoBytes(decodedData);
3716 if (b64variant.usesPadding()) {
3717 --_inputPtr;
3718 _handleBase64MissingPadding(b64variant);
3719 }
3720 return builder.toByteArray();
3721 }
3722 bits = _decodeBase64Escape(b64variant, ch, 3);
3723 }
3724 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
3725
3726
3727
3728 decodedData >>= 2;
3729 builder.appendTwoBytes(decodedData);
3730 continue;
3731 }
3732 }
3733
3734 decodedData = (decodedData << 6) | bits;
3735 builder.appendThreeBytes(decodedData);
3736 }
3737 }
3738
3739
3744
3745
3746 @Override
3747 public JsonLocation getTokenLocation()
3748 {
3749 if (_currToken == JsonToken.FIELD_NAME) {
3750 long total = _currInputProcessed + (_nameStartOffset-1);
3751 return new JsonLocation(_getSourceReference(),
3752 total, -1L, _nameStartRow, _nameStartCol);
3753 }
3754 return new JsonLocation(_getSourceReference(),
3755 _tokenInputTotal-1, -1L, _tokenInputRow, _tokenInputCol);
3756 }
3757
3758
3759 @Override
3760 public JsonLocation getCurrentLocation()
3761 {
3762 int col = _inputPtr - _currInputRowStart + 1;
3763 return new JsonLocation(_getSourceReference(),
3764 _currInputProcessed + _inputPtr, -1L,
3765 _currInputRow, col);
3766 }
3767
3768
3769 private final void _updateLocation()
3770 {
3771 _tokenInputRow = _currInputRow;
3772 final int ptr = _inputPtr;
3773 _tokenInputTotal = _currInputProcessed + ptr;
3774 _tokenInputCol = ptr - _currInputRowStart;
3775 }
3776
3777
3778 private final void _updateNameLocation()
3779 {
3780 _nameStartRow = _currInputRow;
3781 final int ptr = _inputPtr;
3782 _nameStartOffset = ptr;
3783 _nameStartCol = ptr - _currInputRowStart;
3784 }
3785
3786
3791
3792 private final JsonToken _closeScope(int i) throws JsonParseException {
3793 if (i == INT_RCURLY) {
3794 _closeObjectScope();
3795 return (_currToken = JsonToken.END_OBJECT);
3796 }
3797 _closeArrayScope();
3798 return (_currToken = JsonToken.END_ARRAY);
3799 }
3800
3801 private final void _closeArrayScope() throws JsonParseException {
3802 _updateLocation();
3803 if (!_parsingContext.inArray()) {
3804 _reportMismatchedEndMarker(']', '}');
3805 }
3806 _parsingContext = _parsingContext.clearAndGetParent();
3807 }
3808
3809 private final void _closeObjectScope() throws JsonParseException {
3810 _updateLocation();
3811 if (!_parsingContext.inObject()) {
3812 _reportMismatchedEndMarker('}', ']');
3813 }
3814 _parsingContext = _parsingContext.clearAndGetParent();
3815 }
3816 }
3817