105
105
* A dot is always present.
106
106
* \par Arrays:
107
107
* Comma-separated list of elements, enclosed in square brackets ("[" and "]").
108
- * If the array length is indeterminate, an underscore ("_") appears immediately after the opening bracket.
109
108
* \par Maps:
110
109
* Comma-separated list of key-value pairs, with the key and value separated
111
110
* by a colon (":"), enclosed in curly braces ("{" and "}").
112
- * If the map length is indeterminate, an underscore ("_") appears immediately after the opening brace.
111
+ *
112
+ * The CborPrettyFlags enumerator contains flags to control some aspects of the
113
+ * encoding:
114
+ * \par String fragmentation
115
+ * When the CborPrettyShowStringFragments option is active, text and byte
116
+ * strings that are transmitted in fragments are shown instead inside
117
+ * parentheses ("(" and ")") with no preceding number and each fragment is
118
+ * displayed individually. If a tag precedes the string, then the output
119
+ * will contain a double set of parentheses. If the option is not active,
120
+ * the fragments are merged together and the display will not show any
121
+ * difference from a string transmitted with determinate length.
122
+ * \par Encoding indicators
123
+ * Numbers and lengths in CBOR can be encoded in multiple representations.
124
+ * If the CborPrettyIndicateOverlongNumbers option is active, numbers
125
+ * and lengths that are transmitted in a longer encoding than necessary
126
+ * will be indicated, by appending an underscore ("_") to either the
127
+ * number or the opening bracket or brace, followed by a number
128
+ * indicating the CBOR additional information: 0 for 1 byte, 1 for 2
129
+ * bytes, 2 for 4 bytes and 3 for 8 bytes.
130
+ * If the CborPrettyIndicateIndetermineLength option is active, maps,
131
+ * arrays and strings encoded with indeterminate length will be marked by
132
+ * an underscore after the opening bracket or brace or the string (if not
133
+ * showing fragments), without a number after it.
113
134
*/
114
135
115
136
/**
118
139
*
119
140
* \value CborPrettyNumericEncodingIndicators Use numeric encoding indicators instead of textual for float and half-float.
120
141
* \value CborPrettyTextualEncodingIndicators Use textual encoding indicators for float ("f") and half-float ("f16").
142
+ * \value CborPrettyIndicateIndetermineLength Indicate when a map or array has indeterminate length.
143
+ * \value CborPrettyIndicateOverlongNumbers Indicate when a number or length was encoded with more bytes than needed.
121
144
* \value CborPrettyShowStringFragments If the byte or text string is transmitted in chunks, show each individually.
122
145
* \value CborPrettyMergeStringFragment Merge all chunked byte or text strings and display them in a single entry.
123
146
* \value CborPrettyDefaultFlags Default conversion flags.
@@ -253,6 +276,56 @@ static CborError utf8EscapedDump(FILE *out, const void *ptr, size_t n)
253
276
return CborNoError ;
254
277
}
255
278
279
+ static const char * resolve_indicator (const uint8_t * ptr , const uint8_t * end , int flags )
280
+ {
281
+ static const char indicators [8 ][3 ] = {
282
+ "_0" , "_1" , "_2" , "_3" ,
283
+ "" , "" , "" , /* these are not possible */
284
+ "_"
285
+ };
286
+ const char * no_indicator = indicators [5 ]; /* empty string */
287
+ uint8_t additional_information ;
288
+ uint8_t expected_information ;
289
+ uint64_t value ;
290
+ CborError err ;
291
+
292
+ if (ptr == end )
293
+ return NULL ; /* CborErrorUnexpectedEOF */
294
+
295
+ additional_information = (* ptr & SmallValueMask );
296
+ if (additional_information < Value8Bit )
297
+ return no_indicator ;
298
+
299
+ /* determine whether to show anything */
300
+ if ((flags & CborPrettyIndicateIndetermineLength ) &&
301
+ additional_information == IndefiniteLength )
302
+ return indicators [IndefiniteLength - Value8Bit ];
303
+ if ((flags & CborPrettyIndicateOverlongNumbers ) == 0 )
304
+ return no_indicator ;
305
+
306
+ err = _cbor_value_extract_number (& ptr , end , & value );
307
+ if (err )
308
+ return NULL ; /* CborErrorUnexpectedEOF */
309
+
310
+ expected_information = Value8Bit - 1 ;
311
+ if (value >= Value8Bit )
312
+ ++ expected_information ;
313
+ if (value > 0xffU )
314
+ ++ expected_information ;
315
+ if (value > 0xffffU )
316
+ ++ expected_information ;
317
+ if (value > 0xffffffffU )
318
+ ++ expected_information ;
319
+ return expected_information == additional_information ?
320
+ no_indicator :
321
+ indicators [additional_information - Value8Bit ];
322
+ }
323
+
324
+ static const char * get_indicator (const CborValue * it , int flags )
325
+ {
326
+ return resolve_indicator (it -> ptr , it -> parser -> end , flags );
327
+ }
328
+
256
329
static CborError value_to_pretty (FILE * out , CborValue * it , int flags );
257
330
static CborError container_to_pretty (FILE * out , CborValue * it , CborType containerType , int flags )
258
331
{
@@ -288,13 +361,11 @@ static CborError value_to_pretty(FILE *out, CborValue *it, int flags)
288
361
case CborMapType : {
289
362
/* recursive type */
290
363
CborValue recursed ;
364
+ const char * indicator = get_indicator (it , flags );
365
+ const char * space = * indicator ? " " : indicator ;
291
366
292
- if (fprintf (out , type == CborArrayType ? "[" : "{" ) < 0 )
367
+ if (fprintf (out , "%c%s%s" , type == CborArrayType ? '[' : '{' , indicator , space ) < 0 )
293
368
return CborErrorIO ;
294
- if (!cbor_value_is_length_known (it )) {
295
- if (fprintf (out , "_ " ) < 0 )
296
- return CborErrorIO ;
297
- }
298
369
299
370
err = cbor_value_enter_container (it , & recursed );
300
371
if (err ) {
@@ -336,6 +407,8 @@ static CborError value_to_pretty(FILE *out, CborValue *it, int flags)
336
407
return CborErrorIO ;
337
408
}
338
409
}
410
+ if (fprintf (out , "%s" , get_indicator (it , flags )) < 0 )
411
+ return CborErrorIO ;
339
412
break ;
340
413
}
341
414
@@ -347,16 +420,30 @@ static CborError value_to_pretty(FILE *out, CborValue *it, int flags)
347
420
const char * separator = "" ;
348
421
char close = '\'' ;
349
422
char open [3 ] = "h'" ;
423
+ const char * indicator = NULL ;
350
424
351
425
if (type == CborTextStringType ) {
352
426
close = open [0 ] = '"' ;
353
427
open [1 ] = '\0' ;
354
428
}
355
429
356
- if (fputs (showingFragments ? "(_ " : open , out ) < 0 )
357
- return CborErrorIO ;
430
+ if (showingFragments ) {
431
+ if (fputs ("(_ " , out ) < 0 )
432
+ return CborErrorIO ;
433
+ err = _cbor_value_prepare_string_iteration (it );
434
+ if (err )
435
+ return err ;
436
+ } else {
437
+ if (fputs (open , out ) < 0 )
438
+ return CborErrorIO ;
439
+ }
358
440
359
441
while (1 ) {
442
+ if (showingFragments || indicator == NULL ) {
443
+ /* any iteration, except the second for a non-chunked string */
444
+ indicator = resolve_indicator (it -> ptr , it -> parser -> end , flags );
445
+ }
446
+
360
447
err = _cbor_value_get_string_chunk (it , & ptr , & n , it );
361
448
if (err )
362
449
return err ;
@@ -369,21 +456,23 @@ static CborError value_to_pretty(FILE *out, CborValue *it, int flags)
369
456
if (err )
370
457
return err ;
371
458
if (showingFragments ) {
372
- if (fputc ( close , out ) < 0 )
459
+ if (fprintf ( out , "%c%s" , close , indicator ) < 0 )
373
460
return CborErrorIO ;
374
461
separator = ", " ;
375
462
}
376
463
}
377
464
378
- if (fputc (showingFragments ? ')' : close , out ) < 0 )
465
+ if (showingFragments && fputc (')' , out ) < 0 )
466
+ return CborErrorIO ;
467
+ if (!showingFragments && fprintf (out , "%c%s" , close , indicator ) < 0 )
379
468
return CborErrorIO ;
380
469
return CborNoError ;
381
470
}
382
471
383
472
case CborTagType : {
384
473
CborTag tag ;
385
474
cbor_value_get_tag (it , & tag ); /* can't fail */
386
- if (fprintf (out , "%" PRIu64 "(" , tag ) < 0 )
475
+ if (fprintf (out , "%" PRIu64 "%s (" , tag , get_indicator ( it , flags ) ) < 0 )
387
476
return CborErrorIO ;
388
477
err = cbor_value_advance_fixed (it );
389
478
if (err )
@@ -397,8 +486,9 @@ static CborError value_to_pretty(FILE *out, CborValue *it, int flags)
397
486
}
398
487
399
488
case CborSimpleType : {
489
+ /* simple types can't fail and can't have overlong encoding */
400
490
uint8_t simple_type ;
401
- cbor_value_get_simple_type (it , & simple_type ); /* can't fail */
491
+ cbor_value_get_simple_type (it , & simple_type );
402
492
if (fprintf (out , "simple(%" PRIu8 ")" , simple_type ) < 0 )
403
493
return CborErrorIO ;
404
494
break ;
0 commit comments