Skip to content

Commit 40fc2bd

Browse files
authored
Add support for writing unsigned numbers to CBOR (#603)
1 parent 37c10ae commit 40fc2bd

File tree

2 files changed

+248
-0
lines changed

2 files changed

+248
-0
lines changed

cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,21 @@ public void writeNull() throws IOException {
11421142
_writeByte(BYTE_NULL);
11431143
}
11441144

1145+
/**
1146+
* Method for outputting given value as an unsigned integer.
1147+
* Can be called in any context where a value is expected
1148+
* (Array value, Object field value, root-level value).
1149+
*
1150+
* @param i Number value to write
1151+
* @throws IOException if there is either an underlying I/O problem or encoding
1152+
* issue at format layer
1153+
* @since 2.20
1154+
*/
1155+
public void writeNumberUnsigned(int i) throws IOException {
1156+
_verifyValueWrite("write number unsigned");
1157+
_writeIntMinimal(PREFIX_TYPE_INT_POS, i);
1158+
}
1159+
11451160
@Override
11461161
public void writeNumber(int i) throws IOException {
11471162
_verifyValueWrite("write number");
@@ -1183,6 +1198,34 @@ public void writeNumber(int i) throws IOException {
11831198
_outputBuffer[_outputTail++] = b0;
11841199
}
11851200

1201+
/**
1202+
* Method for outputting given value as an unsigned integer.
1203+
* Can be called in any context where a value is expected
1204+
* (Array value, Object field value, root-level value).
1205+
*
1206+
* @param l Number value to write
1207+
* @throws IOException if there is either an underlying I/O problem or encoding
1208+
* issue at format layer
1209+
* @since 2.20
1210+
*/
1211+
public void writeNumberUnsigned(long l) throws IOException {
1212+
if (_cfgMinimalInts && l >= 0 && l < 0x100000000L) {
1213+
writeNumberUnsigned((int) l);
1214+
return;
1215+
}
1216+
_verifyValueWrite("write number unsigned");
1217+
_ensureRoomForOutput(9);
1218+
_outputBuffer[_outputTail++] = (byte) (PREFIX_TYPE_INT_POS + SUFFIX_UINT64_ELEMENTS);
1219+
_outputBuffer[_outputTail++] = (byte) (l >> 56);
1220+
_outputBuffer[_outputTail++] = (byte) (l >> 48);
1221+
_outputBuffer[_outputTail++] = (byte) (l >> 40);
1222+
_outputBuffer[_outputTail++] = (byte) (l >> 32);
1223+
_outputBuffer[_outputTail++] = (byte) (l >> 24);
1224+
_outputBuffer[_outputTail++] = (byte) (l >> 16);
1225+
_outputBuffer[_outputTail++] = (byte) (l >> 8);
1226+
_outputBuffer[_outputTail++] = (byte) l;
1227+
}
1228+
11861229
@Override
11871230
public void writeNumber(long l) throws IOException {
11881231
_verifyValueWrite("write number");

cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/gen/GeneratorSimpleTest.java

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,98 @@ public void testIntValues() throws Exception
181181
(byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF);
182182
}
183183

184+
@Test
185+
public void testUnsignedIntValues() throws Exception
186+
{
187+
// uint32 max
188+
ByteArrayOutputStream out = new ByteArrayOutputStream();
189+
CBORGenerator gen = cborGenerator(out);
190+
gen.writeNumberUnsigned(-1);
191+
gen.close();
192+
_verifyBytes(out.toByteArray(),
193+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT32_ELEMENTS),
194+
(byte) 0xFF,
195+
(byte) 0xFF,
196+
(byte) 0xFF,
197+
(byte) 0xFF);
198+
199+
// Min int
200+
out = new ByteArrayOutputStream();
201+
gen = cborGenerator(out);
202+
gen.writeNumberUnsigned(Integer.MIN_VALUE);
203+
gen.close();
204+
_verifyBytes(out.toByteArray(),
205+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT32_ELEMENTS),
206+
(byte) 0x80,
207+
(byte) 0x00,
208+
(byte) 0x00,
209+
(byte) 0x00);
210+
211+
// Truncated to 2 bytes
212+
out = new ByteArrayOutputStream();
213+
gen = cborGenerator(out);
214+
gen.writeNumberUnsigned(1000);
215+
gen.close();
216+
_verifyBytes(out.toByteArray(),
217+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT16_ELEMENTS),
218+
(byte) 0x03,
219+
(byte) 0xE8);
220+
221+
// Truncated to 1 byte
222+
out = new ByteArrayOutputStream();
223+
gen = cborGenerator(out);
224+
gen.writeNumberUnsigned(100);
225+
gen.close();
226+
_verifyBytes(out.toByteArray(),
227+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT8_ELEMENTS),
228+
(byte) 0x64);
229+
230+
out = new ByteArrayOutputStream();
231+
gen = cborGenerator(out);
232+
gen.writeNumberUnsigned(25);
233+
gen.close();
234+
_verifyBytes(out.toByteArray(),
235+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT8_ELEMENTS),
236+
(byte) 0x19);
237+
238+
out = new ByteArrayOutputStream();
239+
gen = cborGenerator(out);
240+
gen.writeNumberUnsigned(24);
241+
gen.close();
242+
_verifyBytes(out.toByteArray(),
243+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT8_ELEMENTS),
244+
(byte) 0x18);
245+
246+
// Truncated to not take any extra bytes
247+
out = new ByteArrayOutputStream();
248+
gen = cborGenerator(out);
249+
gen.writeNumberUnsigned(23);
250+
gen.close();
251+
_verifyBytes(out.toByteArray(),
252+
(byte) 0x17);
253+
254+
out = new ByteArrayOutputStream();
255+
gen = cborGenerator(out);
256+
gen.writeNumberUnsigned(10);
257+
gen.close();
258+
_verifyBytes(out.toByteArray(),
259+
(byte) 0x0A);
260+
261+
out = new ByteArrayOutputStream();
262+
gen = cborGenerator(out);
263+
gen.writeNumberUnsigned(1);
264+
gen.close();
265+
_verifyBytes(out.toByteArray(),
266+
(byte) 0x01);
267+
268+
out = new ByteArrayOutputStream();
269+
gen = cborGenerator(out);
270+
gen.writeNumberUnsigned(0);
271+
gen.close();
272+
_verifyBytes(out.toByteArray(),
273+
(byte) 0x00);
274+
}
275+
184276
@Test
185277
public void testLongValues() throws Exception
186278
{
@@ -201,6 +293,119 @@ public void testLongValues() throws Exception
201293
assertEquals(0, b[3]);
202294
}
203295

296+
@Test
297+
public void testUnsignedLongValues() throws Exception
298+
{
299+
ByteArrayOutputStream out = new ByteArrayOutputStream();
300+
CBORGenerator gen = cborGenerator(out);
301+
302+
// uint64 max
303+
gen.writeNumberUnsigned(-1L);
304+
gen.close();
305+
_verifyBytes(out.toByteArray(),
306+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT64_ELEMENTS),
307+
(byte) 0xFF,
308+
(byte) 0xFF,
309+
(byte) 0xFF,
310+
(byte) 0xFF,
311+
(byte) 0xFF,
312+
(byte) 0xFF,
313+
(byte) 0xFF,
314+
(byte) 0xFF);
315+
316+
// Min long
317+
out = new ByteArrayOutputStream();
318+
gen = cborGenerator(out);
319+
gen.writeNumberUnsigned(Long.MIN_VALUE);
320+
gen.close();
321+
_verifyBytes(out.toByteArray(),
322+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT64_ELEMENTS),
323+
(byte) 0x80,
324+
(byte) 0x00,
325+
(byte) 0x00,
326+
(byte) 0x00,
327+
(byte) 0x00,
328+
(byte) 0x00,
329+
(byte) 0x00,
330+
(byte) 0x00);
331+
332+
// Truncated to 4 bytes
333+
out = new ByteArrayOutputStream();
334+
gen = cborGenerator(out);
335+
gen.writeNumberUnsigned(1000000L);
336+
gen.close();
337+
_verifyBytes(out.toByteArray(),
338+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT32_ELEMENTS),
339+
(byte) 0x00,
340+
(byte) 0x0F,
341+
(byte) 0x42,
342+
(byte) 0x40);
343+
344+
// Truncated to 2 bytes
345+
out = new ByteArrayOutputStream();
346+
gen = cborGenerator(out);
347+
gen.writeNumberUnsigned(1000L);
348+
gen.close();
349+
_verifyBytes(out.toByteArray(),
350+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT16_ELEMENTS),
351+
(byte) 0x03,
352+
(byte) 0xE8);
353+
354+
// Truncated to 1 byte
355+
out = new ByteArrayOutputStream();
356+
gen = cborGenerator(out);
357+
gen.writeNumberUnsigned(100L);
358+
gen.close();
359+
_verifyBytes(out.toByteArray(),
360+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT8_ELEMENTS),
361+
(byte) 0x64);
362+
363+
out = new ByteArrayOutputStream();
364+
gen = cborGenerator(out);
365+
gen.writeNumberUnsigned(25L);
366+
gen.close();
367+
_verifyBytes(out.toByteArray(),
368+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT8_ELEMENTS),
369+
(byte) 0x19);
370+
371+
out = new ByteArrayOutputStream();
372+
gen = cborGenerator(out);
373+
gen.writeNumberUnsigned(24L);
374+
gen.close();
375+
_verifyBytes(out.toByteArray(),
376+
(byte) (CBORConstants.PREFIX_TYPE_INT_POS + CBORConstants.SUFFIX_UINT8_ELEMENTS),
377+
(byte) 0x18);
378+
379+
// Truncated to not take any extra bytes
380+
out = new ByteArrayOutputStream();
381+
gen = cborGenerator(out);
382+
gen.writeNumberUnsigned(23L);
383+
gen.close();
384+
_verifyBytes(out.toByteArray(),
385+
(byte) 0x17);
386+
387+
out = new ByteArrayOutputStream();
388+
gen = cborGenerator(out);
389+
gen.writeNumberUnsigned(10L);
390+
gen.close();
391+
_verifyBytes(out.toByteArray(),
392+
(byte) 0x0A);
393+
394+
out = new ByteArrayOutputStream();
395+
gen = cborGenerator(out);
396+
gen.writeNumberUnsigned(1L);
397+
gen.close();
398+
_verifyBytes(out.toByteArray(),
399+
(byte) 0x01);
400+
401+
out = new ByteArrayOutputStream();
402+
gen = cborGenerator(out);
403+
gen.writeNumberUnsigned(0L);
404+
gen.close();
405+
_verifyBytes(out.toByteArray(),
406+
(byte) 0x00);
407+
}
408+
204409
@Test
205410
public void testFloatValues() throws Exception
206411
{

0 commit comments

Comments
 (0)