From 85a5c5621be9294a5fe0e73fc2921df6f240f26f Mon Sep 17 00:00:00 2001 From: Fawzi Essam Date: Sun, 27 Apr 2025 01:36:52 +0200 Subject: [PATCH 01/10] [CBOR] - Implement RFC compliant binary BigInteger encoding & decoding Signed-off-by: Fawzi Essam --- .../dataformat/cbor/CBORGenerator.java | 23 +++++++- .../jackson/dataformat/cbor/CBORParser.java | 54 ++++++++++++++++--- .../dataformat/cbor/databind/CBORMapper.java | 34 ++++++++++++ .../cbor/gen/GeneratorSimpleTest.java | 38 +++++++++++++ .../cbor/mapper/CBORMapperTest.java | 26 +++++++++ 5 files changed, 166 insertions(+), 9 deletions(-) diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java index e2052d1cc..9ee7703dd 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java @@ -115,6 +115,23 @@ public enum Feature implements FormatFeature { * @since 2.15 */ WRITE_MINIMAL_DOUBLES(false), + + /** + * Feature that determines how binary tagged negative BigInteger values are + * encoded. + * + * When enabled, Ensures proper encoding of negative values + * (e.g., -1 is encoded [0xC3, 0x41, 0x00]) + * + * When disabled, Maintains backwards compatibility with existing implementations + * (e.g., -1 is encoded [0xC3, 0x41, 0x01]) + * + * The default value is false for backwards compatibility. + * + * @since 2.19.1 + */ + + CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING(false) ; protected final boolean _defaultState; @@ -1217,7 +1234,11 @@ protected void _write(BigInteger v) throws IOException { */ if (v.signum() < 0) { _writeByte(BYTE_TAG_BIGNUM_NEG); - v = v.negate(); + if (isEnabled(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING)) { + v = BigInteger.ONE.negate().subtract(v); + } else { + v = v.negate(); + } } else { _writeByte(BYTE_TAG_BIGNUM_POS); } diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java index 5bc01fda4..f187e363a 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java @@ -29,6 +29,24 @@ public class CBORParser extends ParserMinimalBase public enum Feature implements FormatFeature { // BOGUS(false) + + /** + * Feature that determines how binary tagged negative BigInteger values are decoded in CBOR format. + * + * When enabled (true) + * Follows RFC 8949 specification for negative BigIntegers + * Ensures proper decoding of negative values (e.g., [0xC3, 0x41, 0x00] is decoded -1) + * + * When disabled (false): + * Uses legacy incorrect decoding behavior + * Maintains backwards compatibility with existing implementations + * (e.g., [0xC3, 0x41, 0x00] is decoded 0) + * + * The default value is false for backwards compatibility. + * + * @since 2.19.1 + */ + CORRECT_CBOR_NEGATIVE_BIGINT_DECODING(false) ; final boolean _defaultState; @@ -515,6 +533,7 @@ public CBORParser(IOContext ctxt, int parserFeatures, int cborFeatures, boolean bufferRecyclable) { super(parserFeatures, ctxt.streamReadConstraints()); + _formatFeatures = cborFeatures; _ioContext = ctxt; _objectCodec = codec; _symbols = sym; @@ -561,12 +580,22 @@ public Version version() { /********************************************************** */ -// public JsonParser overrideStdFeatures(int values, int mask) + /** + * Bit flag composed of bits that indicate which + * {@link CBORParser.Feature}s are enabled. + *

+ */ + protected int _formatFeatures; @Override - public int getFormatFeatures() { - // No parser features, yet - return 0; + public final JsonParser overrideFormatFeatures(int values, int mask) { + _formatFeatures = (_formatFeatures & ~mask) | (values & mask); + return this; + } + + @Override + public final int getFormatFeatures() { + return _formatFeatures; } @Override // since 2.12 @@ -1123,11 +1152,20 @@ protected JsonToken _handleTaggedBinary(TagList tags) throws IOException _numberBigInt = BigInteger.ZERO; } else { _streamReadConstraints.validateIntegerLength(_binaryValue.length); - BigInteger nr = new BigInteger(_binaryValue); - if (neg) { - nr = nr.negate(); + + if (Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING.enabledIn(_formatFeatures)) { + BigInteger nr = new BigInteger(1, _binaryValue); + if (neg) { + nr = BigInteger.ONE.negate().subtract(nr); // -1 - n + } + _numberBigInt = nr; + } else { + BigInteger nr = new BigInteger(_binaryValue); + if (neg) { + nr = nr.negate(); + } + _numberBigInt = nr; } - _numberBigInt = nr; } _numTypesValid = NR_BIGINT; _tagValues.clear(); diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/databind/CBORMapper.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/databind/CBORMapper.java index c0b7734a9..2173ccde3 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/databind/CBORMapper.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/databind/CBORMapper.java @@ -36,6 +36,40 @@ public Builder(CBORMapper m) { /****************************************************************** */ + /** + * @since 2.19.1 + */ + public Builder enable(CBORParser.Feature... features) { + for (CBORParser.Feature f : features) { + _streamFactory.enable(f); + } + return this; + } + + /** + * @since 2.19.1 + */ + public Builder disable(CBORParser.Feature... features) { + for (CBORParser.Feature f : features) { + _streamFactory.disable(f); + } + return this; + } + + /** + * @since 2.19.1 + */ + public Builder configure(CBORParser.Feature f, boolean state) + { + if (state) { + _streamFactory.enable(f); + } else { + _streamFactory.disable(f); + } + return this; + } + + /** * @since 2.14 */ diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java index a3626f86e..4c9953ba0 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java @@ -259,6 +259,44 @@ public void testBigDecimalValues() throws Exception assertArrayEquals(spec, b); } + // [dataformats-binary#431] + // [https://datatracker.ietf.org/doc/html/rfc8949#section-3.4.3] + @Test + public void testBigIntegerEncoding() throws Exception { + BigInteger minusOne = BigInteger.valueOf(-1); + byte[] expectedBytes = { + (byte) 0xC3, // tag 3 (negative bignum) + (byte) 0x41 // byte string, length 1 + }; + + // Test correct encoding + ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); + CBORFactory factory = new CBORFactory(); + CBORGenerator gen1 = factory.createGenerator(correctOut); + gen1.enable(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING); + gen1.writeNumber(minusOne); + gen1.close(); + + byte[] result1 = correctOut.toByteArray(); + assertEquals(3, result1.length); + assertEquals(expectedBytes[0], result1[0]); + assertEquals(expectedBytes[1], result1[1]); + assertEquals(0x00, result1[2]); + + // Test incorrect encoding for compatibility + ByteArrayOutputStream incorrectOut = new ByteArrayOutputStream(); + CBORGenerator gen2 = cborGenerator(incorrectOut); + gen2.writeNumber(minusOne); + gen2.close(); + + byte[] result2 = incorrectOut.toByteArray(); + assertEquals(3, result2.length); + assertEquals(expectedBytes[0], result2[0]); + assertEquals(expectedBytes[1], result2[1]); + assertEquals(0x01, result2[2]); + } + + @Test public void testEmptyArray() throws Exception { diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java index 4ab56b821..17f2ffd9b 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java @@ -6,6 +6,8 @@ import com.fasterxml.jackson.dataformat.cbor.*; import com.fasterxml.jackson.dataformat.cbor.databind.CBORMapper; +import java.math.BigInteger; + import static org.junit.jupiter.api.Assertions.*; public class CBORMapperTest extends CBORTestBase @@ -54,4 +56,28 @@ public void testMapperCopy() throws Exception assertNotSame(src, m2); assertSame(streamingF, m2.tokenStreamFactory()); } + + // [dataformats-binary#431] + @Test + public void testNegativeBigInteger() throws Exception { + byte[] encodedNegativeOne = { + (byte) 0xC3, // tag 3 (negative big integer) + (byte) 0x41, // byte string, length 1 + (byte) 0x00 // value 0 (become -1 after decoding) + }; + + // Test correct decoding + CBORMapper mapper1 = CBORMapper.builder() + .enable(CBORParser.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING) + .build(); + assertEquals(BigInteger.valueOf(-1), + mapper1.readValue(encodedNegativeOne, BigInteger.class)); + + + // Test incorrect decoding for compatibility + CBORMapper mapper2 = cborMapper(); + assertEquals(BigInteger.ZERO, + mapper2.readValue(encodedNegativeOne, BigInteger.class)); + } + } From 2d42c5ace10841e782e161c7725a53d5222527b2 Mon Sep 17 00:00:00 2001 From: Fawzi Essam Date: Sun, 27 Apr 2025 01:41:32 +0200 Subject: [PATCH 02/10] unify documentation Signed-off-by: Fawzi Essam --- .../jackson/dataformat/cbor/CBORParser.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java index f187e363a..a4331dc25 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java @@ -31,15 +31,13 @@ public enum Feature implements FormatFeature // BOGUS(false) /** - * Feature that determines how binary tagged negative BigInteger values are decoded in CBOR format. + * Feature that determines how binary tagged negative BigInteger values are + * decoded. * - * When enabled (true) - * Follows RFC 8949 specification for negative BigIntegers - * Ensures proper decoding of negative values (e.g., [0xC3, 0x41, 0x00] is decoded -1) + * When enabled, Ensures proper encoding of negative values + * (e.g., [0xC3, 0x41, 0x00] is decoded -1) * - * When disabled (false): - * Uses legacy incorrect decoding behavior - * Maintains backwards compatibility with existing implementations + * When disabled, Maintains backwards compatibility with existing implementations * (e.g., [0xC3, 0x41, 0x00] is decoded 0) * * The default value is false for backwards compatibility. From 4cff9c4b091dab7f10f985cbb24f675e0e730384 Mon Sep 17 00:00:00 2001 From: Fawzi Essam Date: Sun, 27 Apr 2025 13:42:05 +0200 Subject: [PATCH 03/10] update version comment Signed-off-by: Fawzi Essam --- .../fasterxml/jackson/dataformat/cbor/CBORGenerator.java | 2 +- .../com/fasterxml/jackson/dataformat/cbor/CBORParser.java | 2 +- .../jackson/dataformat/cbor/databind/CBORMapper.java | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java index 9ee7703dd..b0e0a3779 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java @@ -128,7 +128,7 @@ public enum Feature implements FormatFeature { * * The default value is false for backwards compatibility. * - * @since 2.19.1 + * @since 2.20.0 */ CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING(false) diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java index a4331dc25..eca2d3bbd 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java @@ -42,7 +42,7 @@ public enum Feature implements FormatFeature * * The default value is false for backwards compatibility. * - * @since 2.19.1 + * @since 2.20.0 */ CORRECT_CBOR_NEGATIVE_BIGINT_DECODING(false) ; diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/databind/CBORMapper.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/databind/CBORMapper.java index 2173ccde3..5117cef64 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/databind/CBORMapper.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/databind/CBORMapper.java @@ -37,7 +37,7 @@ public Builder(CBORMapper m) { */ /** - * @since 2.19.1 + * @since 2.20.0 */ public Builder enable(CBORParser.Feature... features) { for (CBORParser.Feature f : features) { @@ -47,7 +47,7 @@ public Builder enable(CBORParser.Feature... features) { } /** - * @since 2.19.1 + * @since 2.20.0 */ public Builder disable(CBORParser.Feature... features) { for (CBORParser.Feature f : features) { @@ -57,7 +57,7 @@ public Builder disable(CBORParser.Feature... features) { } /** - * @since 2.19.1 + * @since 2.20.0 */ public Builder configure(CBORParser.Feature f, boolean state) { From 76373fb62263a3ae648760a7b50277ad89384cdf Mon Sep 17 00:00:00 2001 From: Fawzi Essam Date: Sun, 27 Apr 2025 16:27:50 +0200 Subject: [PATCH 04/10] simplify conditions and limit it to negative big integers Signed-off-by: Fawzi Essam --- .../jackson/dataformat/cbor/CBORParser.java | 14 +-- .../cbor/gen/GeneratorSimpleTest.java | 95 ++++++++++++++++++- .../cbor/mapper/CBORMapperTest.java | 41 +++++++- 3 files changed, 139 insertions(+), 11 deletions(-) diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java index eca2d3bbd..220e1b7e7 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java @@ -1151,19 +1151,15 @@ protected JsonToken _handleTaggedBinary(TagList tags) throws IOException } else { _streamReadConstraints.validateIntegerLength(_binaryValue.length); - if (Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING.enabledIn(_formatFeatures)) { - BigInteger nr = new BigInteger(1, _binaryValue); - if (neg) { - nr = BigInteger.ONE.negate().subtract(nr); // -1 - n - } - _numberBigInt = nr; - } else { BigInteger nr = new BigInteger(_binaryValue); if (neg) { - nr = nr.negate(); + if (Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING.enabledIn(_formatFeatures)) { + nr = BigInteger.ONE.negate().subtract(new BigInteger(1, _binaryValue)); + } else { + nr = nr.negate(); + } } _numberBigInt = nr; - } } _numTypesValid = NR_BIGINT; _tagValues.clear(); diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java index 4c9953ba0..c58b73d6c 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java @@ -262,7 +262,7 @@ public void testBigDecimalValues() throws Exception // [dataformats-binary#431] // [https://datatracker.ietf.org/doc/html/rfc8949#section-3.4.3] @Test - public void testBigIntegerEncoding() throws Exception { + public void testSimpleBigIntegerEncoding() throws Exception { BigInteger minusOne = BigInteger.valueOf(-1); byte[] expectedBytes = { (byte) 0xC3, // tag 3 (negative bignum) @@ -296,6 +296,99 @@ public void testBigIntegerEncoding() throws Exception { assertEquals(0x01, result2[2]); } + @Test + public void testZeroBigIntegerEncoding() throws Exception { + BigInteger minusOne = BigInteger.valueOf(0); + byte[] expectedBytes = { + (byte) 0xC2, // tag 2 (positive bignum) + (byte) 0x41, // byte string, 1 byte + (byte) 0x00, // 0 + }; + + ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); + CBORFactory factory = new CBORFactory(); + CBORGenerator gen1 = factory.createGenerator(correctOut); + gen1.enable(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING); + gen1.writeNumber(minusOne); + gen1.close(); + + byte[] result = correctOut.toByteArray(); + assertEquals(3, result.length); + assertArrayEquals(expectedBytes, result); + } + + // [dataformats-binary#431] + // [https://datatracker.ietf.org/doc/html/rfc8949#section-3.4.3] + @Test + public void testNgeativeBigIntegerEncoding() throws Exception { + BigInteger negativeBigInteger = new BigInteger("-340282366920938463463374607431768211456"); + // correct encoding: https://cbor.me/?bytes=c350ffffffffffffffffffffffffffffffff + byte[] expectedBytes = { + (byte) 0xC3, + (byte) 0x51, + (byte) 0x00, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF + }; + + // Test correct encoding + ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); + CBORFactory factory = new CBORFactory(); + CBORGenerator gen1 = factory.createGenerator(correctOut); + gen1.enable(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING); + gen1.writeNumber(negativeBigInteger); + gen1.close(); + + byte[] result1 = correctOut.toByteArray(); + assertArrayEquals(expectedBytes, result1); + + + // Test incorrect encoding for compatibility + // incorrect encoding: https://cbor.me/?bytes=c3510100000000000000000000000000000000 + byte[] legacyExpectedBytes = { + (byte) 0xC3, + (byte) 0x51, + (byte) 0x01, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + }; + ByteArrayOutputStream incorrectOut = new ByteArrayOutputStream(); + CBORGenerator gen2 = cborGenerator(incorrectOut); + gen2.writeNumber(negativeBigInteger); + gen2.close(); + + byte[] result2 = incorrectOut.toByteArray(); + assertEquals(19, result2.length); + assertArrayEquals(legacyExpectedBytes, result2); + } @Test public void testEmptyArray() throws Exception diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java index 17f2ffd9b..3c1d02f5a 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java @@ -59,7 +59,7 @@ public void testMapperCopy() throws Exception // [dataformats-binary#431] @Test - public void testNegativeBigInteger() throws Exception { + public void testSimpleNegativeBigInteger() throws Exception { byte[] encodedNegativeOne = { (byte) 0xC3, // tag 3 (negative big integer) (byte) 0x41, // byte string, length 1 @@ -80,4 +80,43 @@ public void testNegativeBigInteger() throws Exception { mapper2.readValue(encodedNegativeOne, BigInteger.class)); } + + // [dataformats-binary#431] + @Test + public void testNegativeBigInteger() throws Exception { + byte[] encodedNegative = { + (byte) 0xC3, + (byte) 0x51, + (byte) 0x00, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF + }; + + // Test correct decoding + CBORMapper mapper1 = CBORMapper.builder() + .enable(CBORParser.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING) + .build(); + assertEquals(new BigInteger("-340282366920938463463374607431768211456"), + mapper1.readValue(encodedNegative, BigInteger.class)); + + + // Test incorrect decoding for compatibility + CBORMapper mapper2 = cborMapper(); + assertEquals(new BigInteger("-340282366920938463463374607431768211455"), + mapper2.readValue(encodedNegative, BigInteger.class)); + } } From b07c95a588426e017f43867e54842a366d962ea4 Mon Sep 17 00:00:00 2001 From: Fawzi Essam Date: Sun, 27 Apr 2025 16:29:09 +0200 Subject: [PATCH 05/10] update referenced decoder to use the variant of leading zero Signed-off-by: Fawzi Essam --- .../jackson/dataformat/cbor/gen/GeneratorSimpleTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java index c58b73d6c..0870c9ddd 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java @@ -322,7 +322,7 @@ public void testZeroBigIntegerEncoding() throws Exception { @Test public void testNgeativeBigIntegerEncoding() throws Exception { BigInteger negativeBigInteger = new BigInteger("-340282366920938463463374607431768211456"); - // correct encoding: https://cbor.me/?bytes=c350ffffffffffffffffffffffffffffffff + // correct encoding: https://cbor.me/?bytes=c35100ffffffffffffffffffffffffffffffff byte[] expectedBytes = { (byte) 0xC3, (byte) 0x51, From 6d0767a7a4150f7f93ec2e464b7b2e666c8c6dac Mon Sep 17 00:00:00 2001 From: Fawzi Essam Date: Sun, 27 Apr 2025 16:41:42 +0200 Subject: [PATCH 06/10] testing we're able to decode with/without leading zeros Signed-off-by: Fawzi Essam --- .../cbor/mapper/CBORMapperTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java index 3c1d02f5a..b26a8538d 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java @@ -119,4 +119,42 @@ public void testNegativeBigInteger() throws Exception { assertEquals(new BigInteger("-340282366920938463463374607431768211455"), mapper2.readValue(encodedNegative, BigInteger.class)); } + + // [dataformats-binary#431] + @Test + public void testNegativeBigIntegerWithoutLeadingZero() throws Exception { + byte[] encodedNegative = { + (byte) 0xC3, + (byte) 0x50, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF + }; + + // Test correct decoding + CBORMapper mapper1 = CBORMapper.builder() + .enable(CBORParser.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING) + .build(); + assertEquals(new BigInteger("-340282366920938463463374607431768211456"), + mapper1.readValue(encodedNegative, BigInteger.class)); + + + // Test incorrect decoding for compatibility + CBORMapper mapper2 = cborMapper(); + assertEquals(BigInteger.ONE, + mapper2.readValue(encodedNegative, BigInteger.class)); + } } From c69c23c6315f23c37082b87fb8149ef1d7711df1 Mon Sep 17 00:00:00 2001 From: Fawzi Essam Date: Sun, 27 Apr 2025 16:45:31 +0200 Subject: [PATCH 07/10] reference cbor.me in tests for clarity Signed-off-by: Fawzi Essam --- .../jackson/dataformat/cbor/mapper/CBORMapperTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java index b26a8538d..64c650dd3 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java @@ -84,10 +84,11 @@ public void testSimpleNegativeBigInteger() throws Exception { // [dataformats-binary#431] @Test public void testNegativeBigInteger() throws Exception { + // correct encoding: https://cbor.me/?bytes=c35100ffffffffffffffffffffffffffffffff byte[] encodedNegative = { (byte) 0xC3, (byte) 0x51, - (byte) 0x00, + (byte) 0x00, // leading zero (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, @@ -123,6 +124,7 @@ public void testNegativeBigInteger() throws Exception { // [dataformats-binary#431] @Test public void testNegativeBigIntegerWithoutLeadingZero() throws Exception { + // correct encoding: https://cbor.me/?bytes=c350ffffffffffffffffffffffffffffffff byte[] encodedNegative = { (byte) 0xC3, (byte) 0x50, From 71f8cdc87bc7e269ff8db1d81820bcc8b6b8fc21 Mon Sep 17 00:00:00 2001 From: Fawzi Essam Date: Sun, 27 Apr 2025 22:55:15 +0200 Subject: [PATCH 08/10] rename variable Signed-off-by: Fawzi Essam --- .../jackson/dataformat/cbor/gen/GeneratorSimpleTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java index 0870c9ddd..10357f8f5 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java @@ -298,7 +298,7 @@ public void testSimpleBigIntegerEncoding() throws Exception { @Test public void testZeroBigIntegerEncoding() throws Exception { - BigInteger minusOne = BigInteger.valueOf(0); + BigInteger zero = BigInteger.valueOf(0); byte[] expectedBytes = { (byte) 0xC2, // tag 2 (positive bignum) (byte) 0x41, // byte string, 1 byte @@ -309,7 +309,7 @@ public void testZeroBigIntegerEncoding() throws Exception { CBORFactory factory = new CBORFactory(); CBORGenerator gen1 = factory.createGenerator(correctOut); gen1.enable(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING); - gen1.writeNumber(minusOne); + gen1.writeNumber(zero); gen1.close(); byte[] result = correctOut.toByteArray(); From 8220346093585468e4ed3b2c4f86b8bbcfdc6849 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Tue, 29 Apr 2025 20:09:24 -0700 Subject: [PATCH 09/10] Add release notes, minor renaming, refactoring --- .../dataformat/cbor/CBORGenerator.java | 22 ++++---- .../jackson/dataformat/cbor/CBORParser.java | 51 ++++++++++--------- .../cbor/gen/GeneratorSimpleTest.java | 6 +-- release-notes/CREDITS-2.x | 9 ++++ release-notes/VERSION-2.x | 3 ++ 5 files changed, 51 insertions(+), 40 deletions(-) diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java index b0e0a3779..53e89e47b 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java @@ -119,19 +119,16 @@ public enum Feature implements FormatFeature { /** * Feature that determines how binary tagged negative BigInteger values are * encoded. - * - * When enabled, Ensures proper encoding of negative values - * (e.g., -1 is encoded [0xC3, 0x41, 0x00]) - * - * When disabled, Maintains backwards compatibility with existing implementations - * (e.g., -1 is encoded [0xC3, 0x41, 0x01]) - * - * The default value is false for backwards compatibility. + * When enabled, ensures proper encoding of negative values + * (e.g., -1 is encoded {@code [0xC3, 0x41, 0x00])} + * When disabled, maintains backwards compatibility with existing implementations + * (e.g., -1 is encoded {@code [0xC3, 0x41, 0x01])} + *

+ * Default value is {@code false} for backwards-compatibility. * * @since 2.20.0 */ - - CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING(false) + ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING(false) ; protected final boolean _defaultState; @@ -1227,14 +1224,13 @@ public void writeNumber(BigInteger v) throws IOException { // Main write method isolated so that it can be called directly // in cases where that is needed (to encode BigDecimal) protected void _write(BigInteger v) throws IOException { - /* - * Supported by using type tags, as per spec: major type for tag '6'; 5 + /* Supported by using type tags, as per spec: major type for tag '6'; 5 * LSB either 2 for positive bignum or 3 for negative bignum. And then * byte sequence that encode variable length integer. */ if (v.signum() < 0) { _writeByte(BYTE_TAG_BIGNUM_NEG); - if (isEnabled(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING)) { + if (isEnabled(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING)) { v = BigInteger.ONE.negate().subtract(v); } else { v = v.negate(); diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java index 220e1b7e7..721449ce0 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java @@ -28,23 +28,21 @@ public class CBORParser extends ParserMinimalBase */ public enum Feature implements FormatFeature { -// BOGUS(false) - /** * Feature that determines how binary tagged negative BigInteger values are * decoded. * - * When enabled, Ensures proper encoding of negative values - * (e.g., [0xC3, 0x41, 0x00] is decoded -1) + * When enabled, ensures proper encoding of negative values + * (e.g., {@code [0xC3, 0x41, 0x00]} is decoded -1) * - * When disabled, Maintains backwards compatibility with existing implementations - * (e.g., [0xC3, 0x41, 0x00] is decoded 0) + * When disabled, maintains backwards compatibility with existing implementations + * (e.g., {@code [0xC3, 0x41, 0x00]} is decoded 0) * - * The default value is false for backwards compatibility. + * The default value is {@code false} for backwards compatibility. * * @since 2.20.0 */ - CORRECT_CBOR_NEGATIVE_BIGINT_DECODING(false) + DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING(false) ; final boolean _defaultState; @@ -163,6 +161,9 @@ public int getFirstTag() { private final static int[] UTF8_UNIT_CODES = CBORConstants.sUtf8UnitLengths; + // @since 2.20 + private final static BigInteger BI_MINUS_ONE = BigInteger.ONE.negate(); + // Constants for handling of 16-bit "mini-floats" private final static double MATH_POW_2_10 = Math.pow(2, 10); private final static double MATH_POW_2_NEG14 = Math.pow(2, -14); @@ -181,6 +182,14 @@ public int getFirstTag() { /********************************************************** */ + /** + * Bit flag composed of bits that indicate which + * {@link CBORParser.Feature}s are enabled. + *

+ * @since 2.20 + */ + protected int _formatFeatures; + /** * Codec used for data binding when (if) requested. */ @@ -578,13 +587,6 @@ public Version version() { /********************************************************** */ - /** - * Bit flag composed of bits that indicate which - * {@link CBORParser.Feature}s are enabled. - *

- */ - protected int _formatFeatures; - @Override public final JsonParser overrideFormatFeatures(int values, int mask) { _formatFeatures = (_formatFeatures & ~mask) | (values & mask); @@ -1150,16 +1152,17 @@ protected JsonToken _handleTaggedBinary(TagList tags) throws IOException _numberBigInt = BigInteger.ZERO; } else { _streamReadConstraints.validateIntegerLength(_binaryValue.length); - - BigInteger nr = new BigInteger(_binaryValue); - if (neg) { - if (Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING.enabledIn(_formatFeatures)) { - nr = BigInteger.ONE.negate().subtract(new BigInteger(1, _binaryValue)); - } else { - nr = nr.negate(); - } + final BigInteger nr; + if (neg) { + if (Feature.DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING.enabledIn(_formatFeatures)) { + nr = BI_MINUS_ONE.subtract(new BigInteger(1, _binaryValue)); + } else { + nr = new BigInteger(_binaryValue).negate(); } - _numberBigInt = nr; + } else { + nr = new BigInteger(_binaryValue); + } + _numberBigInt = nr; } _numTypesValid = NR_BIGINT; _tagValues.clear(); diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java index 10357f8f5..8001406b7 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java @@ -273,7 +273,7 @@ public void testSimpleBigIntegerEncoding() throws Exception { ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); CBORFactory factory = new CBORFactory(); CBORGenerator gen1 = factory.createGenerator(correctOut); - gen1.enable(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING); + gen1.enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING); gen1.writeNumber(minusOne); gen1.close(); @@ -308,7 +308,7 @@ public void testZeroBigIntegerEncoding() throws Exception { ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); CBORFactory factory = new CBORFactory(); CBORGenerator gen1 = factory.createGenerator(correctOut); - gen1.enable(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING); + gen1.enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING); gen1.writeNumber(zero); gen1.close(); @@ -349,7 +349,7 @@ public void testNgeativeBigIntegerEncoding() throws Exception { ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); CBORFactory factory = new CBORFactory(); CBORGenerator gen1 = factory.createGenerator(correctOut); - gen1.enable(CBORGenerator.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_ENCODING); + gen1.enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING); gen1.writeNumber(negativeBigInteger); gen1.close(); diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 8dec9da09..008bf45ac 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -385,3 +385,12 @@ Manuel Sugawara (@sugmanue) Josh Curry (@seadbrane) * Reported, contributed fix for #571: Unable to deserialize a pojo with IonStruct (2.19.0) + +Brian Gruber (@bgruber) + * Reported #431: (cbor) Negative `BigInteger` values not encoded/decoded correctly + (2.20.0) + +Fawzi Essam (@iifawzi) + * Contributed fix for #431: (cbor) Negative `BigInteger` values not encoded/decoded + correctly + (2.20.0) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 750168c00..e36f11800 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -16,6 +16,9 @@ Active maintainers: 2.20.0 (not yet released) +#431: (cbor) Negative `BigInteger` values not encoded/decoded correctly + (reported by Brian G) + (fix contributed by Fawzi E) - Generate SBOMs [JSTEP-14] 2.19.0 (24-Apr-2025) From 4727239d57f33726a1bca4074995f5f4559b9632 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Tue, 29 Apr 2025 20:29:30 -0700 Subject: [PATCH 10/10] Make tests more 3.0-proof (wrt configuration) --- .../dataformat/cbor/CBORGenerator.java | 20 +++++-- .../jackson/dataformat/cbor/CBORParser.java | 17 +++--- .../cbor/gen/GeneratorSimpleTest.java | 60 +++++++++++-------- .../cbor/mapper/CBORMapperTest.java | 19 +++--- 4 files changed, 71 insertions(+), 45 deletions(-) diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java index 53e89e47b..0863ec0ec 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java @@ -25,6 +25,9 @@ public class CBORGenerator extends GeneratorBase { private final static int[] NO_INTS = new int[0]; + // @since 2.20 + private final static BigInteger BI_MINUS_ONE = BigInteger.ONE.negate(); + /** * Let's ensure that we have big enough output buffer because of safety * margins we need for UTF-8 encoding. @@ -118,15 +121,20 @@ public enum Feature implements FormatFeature { /** * Feature that determines how binary tagged negative BigInteger values are - * encoded. - * When enabled, ensures proper encoding of negative values - * (e.g., -1 is encoded {@code [0xC3, 0x41, 0x00])} + * encoded: either using CBOR standard encoding logic (as per spec), + * or using legacy Jackson encoding logic (encoding up to Jackson 2.19). + * When enabled, uses CBOR standard specified encoding of negative values + * (e.g., -1 is encoded {@code [0xC3, 0x41, 0x00]}). * When disabled, maintains backwards compatibility with existing implementations - * (e.g., -1 is encoded {@code [0xC3, 0x41, 0x01])} + * (e.g., -1 is encoded {@code [0xC3, 0x41, 0x01]}) and uses legacy Jackson encoding. + *

+ * Note that there is the counterpart + * {@link CBORParser.Feature#DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING} + * for encoding. *

* Default value is {@code false} for backwards-compatibility. * - * @since 2.20.0 + * @since 2.20 */ ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING(false) ; @@ -1231,7 +1239,7 @@ protected void _write(BigInteger v) throws IOException { if (v.signum() < 0) { _writeByte(BYTE_TAG_BIGNUM_NEG); if (isEnabled(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING)) { - v = BigInteger.ONE.negate().subtract(v); + v = BI_MINUS_ONE.subtract(v); } else { v = v.negate(); } diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java index 721449ce0..01ab6184d 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java @@ -30,17 +30,20 @@ public enum Feature implements FormatFeature { /** * Feature that determines how binary tagged negative BigInteger values are - * decoded. - * + * decoded: either assuming CBOR standard encoding logic (as per spec), + * or the legacy Jackson encoding logic (encoding up to Jackson 2.19). * When enabled, ensures proper encoding of negative values - * (e.g., {@code [0xC3, 0x41, 0x00]} is decoded -1) - * + * (e.g., {@code [0xC3, 0x41, 0x00]} is decoded as -1) * When disabled, maintains backwards compatibility with existing implementations - * (e.g., {@code [0xC3, 0x41, 0x00]} is decoded 0) - * + * (e.g., {@code [0xC3, 0x41, 0x00]} is decoded as 0). + *

+ * Note that there is the counterpart + * {@link CBORGenerator.Feature#ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING} + * for encoding. + *

* The default value is {@code false} for backwards compatibility. * - * @since 2.20.0 + * @since 2.20 */ DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING(false) ; diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java index 8001406b7..e40f052cf 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java @@ -262,7 +262,8 @@ public void testBigDecimalValues() throws Exception // [dataformats-binary#431] // [https://datatracker.ietf.org/doc/html/rfc8949#section-3.4.3] @Test - public void testSimpleBigIntegerEncoding() throws Exception { + public void testSimpleBigIntegerEncoding() throws Exception + { BigInteger minusOne = BigInteger.valueOf(-1); byte[] expectedBytes = { (byte) 0xC3, // tag 3 (negative bignum) @@ -270,12 +271,13 @@ public void testSimpleBigIntegerEncoding() throws Exception { }; // Test correct encoding + CBORFactory factory = CBORFactory.builder() + .enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) + .build(); ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); - CBORFactory factory = new CBORFactory(); - CBORGenerator gen1 = factory.createGenerator(correctOut); - gen1.enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING); - gen1.writeNumber(minusOne); - gen1.close(); + try (CBORGenerator gen1 = factory.createGenerator(correctOut)) { + gen1.writeNumber(minusOne); + } byte[] result1 = correctOut.toByteArray(); assertEquals(3, result1.length); @@ -285,9 +287,12 @@ public void testSimpleBigIntegerEncoding() throws Exception { // Test incorrect encoding for compatibility ByteArrayOutputStream incorrectOut = new ByteArrayOutputStream(); - CBORGenerator gen2 = cborGenerator(incorrectOut); - gen2.writeNumber(minusOne); - gen2.close(); + factory = CBORFactory.builder() + .disable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) + .build(); + try (CBORGenerator gen2 = factory.createGenerator(incorrectOut)) { + gen2.writeNumber(minusOne); + } byte[] result2 = incorrectOut.toByteArray(); assertEquals(3, result2.length); @@ -296,6 +301,8 @@ public void testSimpleBigIntegerEncoding() throws Exception { assertEquals(0x01, result2[2]); } + // [dataformats-binary#431] + // [https://datatracker.ietf.org/doc/html/rfc8949#section-3.4.3] @Test public void testZeroBigIntegerEncoding() throws Exception { BigInteger zero = BigInteger.valueOf(0); @@ -306,11 +313,12 @@ public void testZeroBigIntegerEncoding() throws Exception { }; ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); - CBORFactory factory = new CBORFactory(); - CBORGenerator gen1 = factory.createGenerator(correctOut); - gen1.enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING); - gen1.writeNumber(zero); - gen1.close(); + CBORFactory factory = CBORFactory.builder() + .enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) + .build(); + try (CBORGenerator gen1 = factory.createGenerator(correctOut)) { + gen1.writeNumber(zero); + } byte[] result = correctOut.toByteArray(); assertEquals(3, result.length); @@ -320,7 +328,7 @@ public void testZeroBigIntegerEncoding() throws Exception { // [dataformats-binary#431] // [https://datatracker.ietf.org/doc/html/rfc8949#section-3.4.3] @Test - public void testNgeativeBigIntegerEncoding() throws Exception { + public void testNegativeBigIntegerEncoding() throws Exception { BigInteger negativeBigInteger = new BigInteger("-340282366920938463463374607431768211456"); // correct encoding: https://cbor.me/?bytes=c35100ffffffffffffffffffffffffffffffff byte[] expectedBytes = { @@ -347,16 +355,15 @@ public void testNgeativeBigIntegerEncoding() throws Exception { // Test correct encoding ByteArrayOutputStream correctOut = new ByteArrayOutputStream(); - CBORFactory factory = new CBORFactory(); - CBORGenerator gen1 = factory.createGenerator(correctOut); - gen1.enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING); - gen1.writeNumber(negativeBigInteger); - gen1.close(); - + CBORFactory factory = CBORFactory.builder() + .enable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) + .build(); + try (CBORGenerator gen1 = factory.createGenerator(correctOut)) { + gen1.writeNumber(negativeBigInteger); + } byte[] result1 = correctOut.toByteArray(); assertArrayEquals(expectedBytes, result1); - // Test incorrect encoding for compatibility // incorrect encoding: https://cbor.me/?bytes=c3510100000000000000000000000000000000 byte[] legacyExpectedBytes = { @@ -381,9 +388,12 @@ public void testNgeativeBigIntegerEncoding() throws Exception { (byte) 0x00, }; ByteArrayOutputStream incorrectOut = new ByteArrayOutputStream(); - CBORGenerator gen2 = cborGenerator(incorrectOut); - gen2.writeNumber(negativeBigInteger); - gen2.close(); + factory = CBORFactory.builder() + .disable(CBORGenerator.Feature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) + .build(); + try (CBORGenerator gen2 = factory.createGenerator(incorrectOut)) { + gen2.writeNumber(negativeBigInteger); + } byte[] result2 = incorrectOut.toByteArray(); assertEquals(19, result2.length); diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java index 64c650dd3..5567e4fcd 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/CBORMapperTest.java @@ -68,14 +68,15 @@ public void testSimpleNegativeBigInteger() throws Exception { // Test correct decoding CBORMapper mapper1 = CBORMapper.builder() - .enable(CBORParser.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING) + .enable(CBORParser.Feature.DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) .build(); assertEquals(BigInteger.valueOf(-1), mapper1.readValue(encodedNegativeOne, BigInteger.class)); - // Test incorrect decoding for compatibility - CBORMapper mapper2 = cborMapper(); + CBORMapper mapper2 = CBORMapper.builder() + .disable(CBORParser.Feature.DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) + .build(); assertEquals(BigInteger.ZERO, mapper2.readValue(encodedNegativeOne, BigInteger.class)); } @@ -109,14 +110,16 @@ public void testNegativeBigInteger() throws Exception { // Test correct decoding CBORMapper mapper1 = CBORMapper.builder() - .enable(CBORParser.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING) + .enable(CBORParser.Feature.DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) .build(); assertEquals(new BigInteger("-340282366920938463463374607431768211456"), mapper1.readValue(encodedNegative, BigInteger.class)); // Test incorrect decoding for compatibility - CBORMapper mapper2 = cborMapper(); + CBORMapper mapper2 = CBORMapper.builder() + .disable(CBORParser.Feature.DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) + .build(); assertEquals(new BigInteger("-340282366920938463463374607431768211455"), mapper2.readValue(encodedNegative, BigInteger.class)); } @@ -148,14 +151,16 @@ public void testNegativeBigIntegerWithoutLeadingZero() throws Exception { // Test correct decoding CBORMapper mapper1 = CBORMapper.builder() - .enable(CBORParser.Feature.CORRECT_CBOR_NEGATIVE_BIGINT_DECODING) + .enable(CBORParser.Feature.DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) .build(); assertEquals(new BigInteger("-340282366920938463463374607431768211456"), mapper1.readValue(encodedNegative, BigInteger.class)); // Test incorrect decoding for compatibility - CBORMapper mapper2 = cborMapper(); + CBORMapper mapper2 = CBORMapper.builder() + .disable(CBORParser.Feature.DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING) + .build(); assertEquals(BigInteger.ONE, mapper2.readValue(encodedNegative, BigInteger.class)); }