@@ -877,37 +877,227 @@ protected JsonToken _handleTaggedArray(int tag, int len) throws IOException
877877 _reportError ("Unexpected array size (" +len +") for tagged 'bigfloat' value; should have exactly 2 number elements" );
878878 }
879879 // and then use recursion to get values
880- JsonToken t = nextToken ();
881880 // First: exponent, which MUST be a simple integer value
882- if (t != JsonToken . VALUE_NUMBER_INT ) {
883- _reportError ("Unexpected token (" +t +") as the first part of 'bigfloat' value: should get VALUE_NUMBER_INT" );
881+ if (! _checkNextIsIntInArray ( "bigfloat" ) ) {
882+ _reportError ("Unexpected token (" +currentToken () +") as the first part of 'bigfloat' value: should get VALUE_NUMBER_INT" );
884883 }
885884 // 27-Nov-2019, tatu: As per [dataformats-binary#139] need to change sign here
886885 int exp = -getIntValue ();
887886
888- t = nextToken ();
889887 // Should get an integer value; int/long/BigInteger
890- if (t != JsonToken . VALUE_NUMBER_INT ) {
891- _reportError ("Unexpected token (" +t +") as the second part of 'bigfloat' value: should get VALUE_NUMBER_INT" );
888+ if (! _checkNextIsIntInArray ( "bigfloat" ) ) {
889+ _reportError ("Unexpected token (" +currentToken () +") as the second part of 'bigfloat' value: should get VALUE_NUMBER_INT" );
892890 }
893-
894- BigDecimal dec ;
895891
892+ // important: check number type here
893+ BigDecimal dec ;
896894 NumberType numberType = getNumberType ();
897895 if (numberType == NumberType .BIG_INTEGER ) {
898896 dec = new BigDecimal (getBigIntegerValue (), exp );
899897 } else {
900898 dec = BigDecimal .valueOf (getLongValue (), exp );
901899 }
902- t = nextToken ();
903- if (t != JsonToken .END_ARRAY ) {
904- _reportError ("Unexpected token (" +t +") after 2 elements of 'bigfloat' value" );
900+
901+ // but verify closing END_ARRAY here, as this will now override current token
902+ if (!_checkNextIsEndArray ()) {
903+ _reportError ("Unexpected token (" +currentToken ()+") after 2 elements of 'bigfloat' value" );
905904 }
905+
906+ // which needs to be reset here
906907 _numberBigDecimal = dec ;
907908 _numTypesValid = NR_BIGDECIMAL ;
908909 return (_currToken = JsonToken .VALUE_NUMBER_FLOAT );
909910 }
910-
911+
912+ /**
913+ * Heavily simplified method that does a subset of what {@code nextTokendoes to basically
914+ * only (1) determine that we are getting {@code JsonToken.VALUE_NUMBER_INT} (if not,
915+ * return with no processing) and (2) if so, prepare state so that number accessor
916+ * method will work).
917+ *<p>
918+ * Note that in particular this method DOES NOT reset state that {@code nextToken()} would do,
919+ * but will change current token type to allow access.
920+ */
921+ protected final boolean _checkNextIsIntInArray (final String typeDesc ) throws IOException
922+ {
923+ // We know we are in array, with length prefix so:
924+ if (!_parsingContext .expectMoreValues ()) {
925+ _tagValue = -1 ;
926+ _parsingContext = _parsingContext .getParent ();
927+ _currToken = JsonToken .END_ARRAY ;
928+ return false ;
929+ }
930+
931+ if (_inputPtr >= _inputEnd ) {
932+ if (!loadMore ()) {
933+ _handleCBOREOF ();
934+ return false ;
935+ }
936+ }
937+ int ch = _inputBuffer [_inputPtr ++];
938+ int type = (ch >> 5 ) & 0x7 ;
939+
940+ // 01-Nov-2019, tatu: We may actually need tag so decode it, but do not assign
941+ // (that'd override tag we already have)
942+ int tagValue = -1 ;
943+ if (type == 6 ) {
944+ tagValue = _decodeTag (ch & 0x1F );
945+ if ((_inputPtr >= _inputEnd ) && !loadMore ()) {
946+ _handleCBOREOF ();
947+ return false ;
948+ }
949+ ch = _inputBuffer [_inputPtr ++];
950+ type = (ch >> 5 ) & 0x7 ;
951+ }
952+
953+ final int lowBits = ch & 0x1F ;
954+ switch (type ) {
955+ case 0 : // positive int
956+ _numTypesValid = NR_INT ;
957+ if (lowBits <= 23 ) {
958+ _numberInt = lowBits ;
959+ } else {
960+ switch (lowBits - 24 ) {
961+ case 0 :
962+ _numberInt = _decode8Bits ();
963+ break ;
964+ case 1 :
965+ _numberInt = _decode16Bits ();
966+ break ;
967+ case 2 :
968+ {
969+ int v = _decode32Bits ();
970+ if (v >= 0 ) {
971+ _numberInt = v ;
972+ } else {
973+ long l = (long ) v ;
974+ _numberLong = l & 0xFFFFFFFFL ;
975+ _numTypesValid = NR_LONG ;
976+ }
977+ }
978+ break ;
979+ case 3 :
980+ {
981+ long l = _decode64Bits ();
982+ if (l >= 0L ) {
983+ _numberLong = l ;
984+ _numTypesValid = NR_LONG ;
985+ } else {
986+ _numberBigInt = _bigPositive (l );
987+ _numTypesValid = NR_BIGINT ;
988+ }
989+ }
990+ break ;
991+ default :
992+ _invalidToken (ch );
993+ }
994+ }
995+ _currToken = JsonToken .VALUE_NUMBER_INT ;
996+ return true ;
997+ case 1 : // negative int
998+ _numTypesValid = NR_INT ;
999+ if (lowBits <= 23 ) {
1000+ _numberInt = -lowBits - 1 ;
1001+ } else {
1002+ switch (lowBits - 24 ) {
1003+ case 0 :
1004+ _numberInt = -_decode8Bits () - 1 ;
1005+ break ;
1006+ case 1 :
1007+ _numberInt = -_decode16Bits () - 1 ;
1008+ break ;
1009+ case 2 :
1010+ // 15-Oct-2016, as per [dataformats-binary#30], we got an edge case here
1011+ {
1012+ int v = _decode32Bits ();
1013+ if (v < 0 ) {
1014+ long unsignedBase = (long ) v & 0xFFFFFFFFL ;
1015+ _numberLong = -unsignedBase - 1L ;
1016+ _numTypesValid = NR_LONG ;
1017+ } else {
1018+ _numberInt = -v - 1 ;
1019+ }
1020+ }
1021+ break ;
1022+ case 3 :
1023+ // 15-Oct-2016, as per [dataformats-binary#30], we got an edge case here
1024+ {
1025+ long l = _decode64Bits ();
1026+ if (l >= 0L ) {
1027+ _numberLong = -l - 1L ;
1028+ _numTypesValid = NR_LONG ;
1029+ } else {
1030+ _numberBigInt = _bigNegative (l );
1031+ _numTypesValid = NR_BIGINT ;
1032+ }
1033+ }
1034+ break ;
1035+ default :
1036+ _invalidToken (ch );
1037+ }
1038+ }
1039+ _currToken = JsonToken .VALUE_NUMBER_INT ;
1040+ return true ;
1041+
1042+ case 2 : // byte[]
1043+ // ... but we only really care about very specific case of `BigInteger`
1044+ if (tagValue < 0 ) {
1045+ break ;
1046+ }
1047+ _typeByte = ch ;
1048+ _tokenIncomplete = true ;
1049+ _currToken = _handleTaggedBinary (tagValue );
1050+ return (_currToken == JsonToken .VALUE_NUMBER_INT );
1051+
1052+ case 6 : // another tag; not allowed
1053+ _reportError ("Multiple tags not allowed per value (first tag: " +tagValue +")" );
1054+ }
1055+
1056+ // Important! Need to push back the last byte read (but not consumed)
1057+ --_inputPtr ;
1058+ // and now it is safe to decode next token, too
1059+ nextToken ();
1060+ return false ;
1061+ }
1062+
1063+ protected final boolean _checkNextIsEndArray () throws IOException
1064+ {
1065+ // We know we are in array, with length prefix, and this is where we should be:
1066+ if (!_parsingContext .expectMoreValues ()) {
1067+ _tagValue = -1 ;
1068+ _parsingContext = _parsingContext .getParent ();
1069+ _currToken = JsonToken .END_ARRAY ;
1070+ return true ;
1071+ }
1072+
1073+ // But while we otherwise could bail out we should check what follows for better
1074+ // error reporting... yet we ALSO must avoid direct call to `nextToken()` to avoid
1075+ // [dataformats-binary#185]
1076+ int ch = _inputBuffer [_inputPtr ++];
1077+ int type = (ch >> 5 ) & 0x7 ;
1078+
1079+ // No use for tag but removing it is necessary
1080+ int tagValue = -1 ;
1081+ if (type == 6 ) {
1082+ tagValue = _decodeTag (ch & 0x1F );
1083+ if ((_inputPtr >= _inputEnd ) && !loadMore ()) {
1084+ _handleCBOREOF ();
1085+ return false ;
1086+ }
1087+ ch = _inputBuffer [_inputPtr ++];
1088+ type = (ch >> 5 ) & 0x7 ;
1089+ // including but not limited to nested tags (which we do not allow)
1090+ if (type == 6 ) {
1091+ _reportError ("Multiple tags not allowed per value (first tag: " +tagValue +")" );
1092+ }
1093+ }
1094+ // and that's what we need to do for safety; now can drop to generic handling:
1095+
1096+ // Important! Need to push back the last byte read (but not consumed)
1097+ --_inputPtr ;
1098+ return nextToken () == JsonToken .END_ARRAY ; // should never match
1099+ }
1100+
9111101 // base impl is fine:
9121102 //public String getCurrentName() throws IOException
9131103
@@ -1467,7 +1657,7 @@ public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
14671657 }
14681658 if (_currToken != JsonToken .VALUE_EMBEDDED_OBJECT ) {
14691659 // TODO, maybe: support base64 for text?
1470- _reportError ("Current token (" +getCurrentToken ()+") not VALUE_EMBEDDED_OBJECT, can not access as binary" );
1660+ _reportError ("Current token (" +currentToken ()+") not VALUE_EMBEDDED_OBJECT, can not access as binary" );
14711661 }
14721662 return _binaryValue ;
14731663 }
@@ -1489,7 +1679,7 @@ public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IO
14891679 {
14901680 if (_currToken != JsonToken .VALUE_EMBEDDED_OBJECT ) {
14911681 // Todo, maybe: support base64 for text?
1492- _reportError ("Current token (" +getCurrentToken ()+") not VALUE_EMBEDDED_OBJECT, can not access as binary" );
1682+ _reportError ("Current token (" +currentToken ()+") not VALUE_EMBEDDED_OBJECT, can not access as binary" );
14931683 }
14941684 if (!_tokenIncomplete ) { // someone already decoded or read
14951685 if (_binaryValue == null ) { // if this method called twice in a row
@@ -1724,7 +1914,7 @@ protected void _checkNumericValue(int expType) throws IOException
17241914 if (_currToken == JsonToken .VALUE_NUMBER_INT || _currToken == JsonToken .VALUE_NUMBER_FLOAT ) {
17251915 return ;
17261916 }
1727- _reportError ("Current token (" +getCurrentToken ()+") not numeric, can not use numeric value accessors" );
1917+ _reportError ("Current token (" +currentToken ()+") not numeric, can not use numeric value accessors" );
17281918 }
17291919
17301920 protected void convertNumberToInt () throws IOException
@@ -2770,11 +2960,11 @@ private final int _decodeExplicitLength(int lowBits) throws IOException
27702960 case 3 :
27712961 long l = _decode64Bits ();
27722962 if (l < 0 || l > MAX_INT_L ) {
2773- throw _constructError ("Illegal length for " +getCurrentToken ()+": " +l );
2963+ throw _constructError ("Illegal length for " +currentToken ()+": " +l );
27742964 }
27752965 return (int ) l ;
27762966 }
2777- throw _constructError ("Invalid length for " +getCurrentToken ()+": 0x" +Integer .toHexString (lowBits ));
2967+ throw _constructError ("Invalid length for " +currentToken ()+": 0x" +Integer .toHexString (lowBits ));
27782968 }
27792969
27802970 private int _decodeChunkLength (int expType ) throws IOException
0 commit comments