1 /****************************************************************************
3 ** Copyright (C) 2015 Intel Corporation
5 ** Permission is hereby granted, free of charge, to any person obtaining a copy
6 ** of this software and associated documentation files (the "Software"), to deal
7 ** in the Software without restriction, including without limitation the rights
8 ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 ** copies of the Software, and to permit persons to whom the Software is
10 ** furnished to do so, subject to the following conditions:
12 ** The above copyright notice and this permission notice shall be included in
13 ** all copies or substantial portions of the Software.
15 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 ****************************************************************************/
27 #include "compilersupport_p.h"
36 static int hexDump(FILE *out, const uint8_t *buffer, size_t n)
39 int r = fprintf(out, "%02" PRIx8, *buffer++);
43 return 0; // should be n * 2, but we don't have the original n anymore
46 /* This function decodes buffer as UTF-8 and prints as escaped UTF-16.
47 * On UTF-8 decoding error, it returns CborErrorInvalidUtf8TextString */
48 static int utf8EscapedDump(FILE *out, const char *buffer, size_t n)
52 uc = (uint8_t)*buffer++;
55 if (uc < 0x7f && uc >= 0x20 && uc != '\\' && uc != '"') {
56 if (fprintf(out, "%c", (char)uc) < 0)
61 // print as an escape sequence
62 char escaped = (char)uc;
85 if (fprintf(out, "\\%c", escaped) < 0)
90 // multi-byte UTF-8, decode it
93 if (unlikely(uc <= 0xC1))
94 return CborErrorInvalidUtf8TextString;
100 } else if (uc < 0xF0) {
101 /* three-byte UTF-8 */
105 } else if (uc < 0xF5) {
106 /* four-byte UTF-8 */
111 return CborErrorInvalidUtf8TextString;
114 if (n < charsNeeded - 1)
115 return CborErrorInvalidUtf8TextString;
117 // first continuation character
118 uint8_t b = (uint8_t)*buffer++;
119 if ((b & 0xc0) != 0x80)
120 return CborErrorInvalidUtf8TextString;
124 if (charsNeeded > 2) {
125 // second continuation character
126 b = (uint8_t)*buffer++;
127 if ((b & 0xc0) != 0x80)
128 return CborErrorInvalidUtf8TextString;
132 if (charsNeeded > 3) {
133 // third continuation character
134 b = (uint8_t)*buffer++;
135 if ((b & 0xc0) != 0x80)
136 return CborErrorInvalidUtf8TextString;
142 // overlong sequence? surrogate pair? out or range?
143 if (uc < min_uc || uc - 0xd800U < 2048U || uc > 0x10ffff)
144 return CborErrorInvalidUtf8TextString;
146 // now print the sequence
147 if (charsNeeded > 3) {
148 // needs surrogate pairs
149 if (fprintf(out, "\\u%04" PRIX32 "\\u%04" PRIX32,
150 (uc >> 10) + 0xd7c0, // high surrogate
151 (uc % 0x0400) + 0xdc00) < 0)
155 // no surrogate pair needed
156 if (fprintf(out, "\\u%04" PRIX32, uc) < 0)
163 static CborError value_to_pretty(FILE *out, CborValue *it);
164 static CborError container_to_pretty(FILE *out, CborValue *it, CborType containerType)
166 const char *comma = "";
167 while (!cbor_value_at_end(it)) {
168 if (fprintf(out, "%s", comma) < 0)
172 CborError err = value_to_pretty(out, it);
176 if (containerType == CborArrayType)
179 // map: that was the key, so get the value
180 if (fprintf(out, ": ") < 0)
182 err = value_to_pretty(out, it);
189 static CborError value_to_pretty(FILE *out, CborValue *it)
192 CborType type = cbor_value_get_type(it);
199 if (fprintf(out, type == CborArrayType ? "[" : "{") < 0)
201 if (!cbor_value_is_length_known(it)) {
202 if (fprintf(out, "_ ") < 0)
206 err = cbor_value_enter_container(it, &recursed);
208 it->ptr = recursed.ptr;
209 return err; // parse error
211 err = container_to_pretty(out, &recursed, type);
213 it->ptr = recursed.ptr;
214 return err; // parse error
216 err = cbor_value_leave_container(it, &recursed);
218 return err; // parse error
220 if (fprintf(out, type == CborArrayType ? "]" : "}") < 0)
225 case CborIntegerType: {
227 cbor_value_get_raw_integer(it, &val); // can't fail
229 if (cbor_value_is_unsigned_integer(it)) {
230 if (fprintf(out, "%" PRIu64, val) < 0)
233 // CBOR stores the negative number X as -1 - X
234 // (that is, -1 is stored as 0, -2 as 1 and so forth)
235 if (++val) { // unsigned overflow may happen
236 if (fprintf(out, "-%" PRIu64, val) < 0)
240 // 0xffff`ffff`ffff`ffff + 1 =
241 // 0x1`0000`0000`0000`0000 = 18446744073709551616 (2^64)
242 if (fprintf(out, "-18446744073709551616") < 0)
249 case CborByteStringType:{
252 err = cbor_value_dup_byte_string(it, &buffer, &n, it);
256 bool failed = fprintf(out, "h'") < 0 || hexDump(out, buffer, n) < 0 || fprintf(out, "'") < 0;
258 return failed ? CborErrorIO : CborNoError;
261 case CborTextStringType: {
264 err = cbor_value_dup_text_string(it, &buffer, &n, it);
269 bool failed = fprintf(out, "\"") < 0
270 || (err = utf8EscapedDump(out, buffer, n)) != CborNoError
271 || fprintf(out, "\"") < 0;
273 return err != CborNoError ? err :
274 failed ? CborErrorIO : CborNoError;
279 cbor_value_get_tag(it, &tag); // can't fail
280 if (fprintf(out, "%" PRIu64 "(", tag) < 0)
282 err = cbor_value_advance_fixed(it);
285 err = value_to_pretty(out, it);
288 if (fprintf(out, ")") < 0)
293 case CborSimpleType: {
295 cbor_value_get_simple_type(it, &simple_type); // can't fail
296 if (fprintf(out, "simple(%" PRIu8 ")", simple_type) < 0)
302 if (fprintf(out, "null") < 0)
306 case CborUndefinedType:
307 if (fprintf(out, "undefined") < 0)
311 case CborBooleanType: {
313 cbor_value_get_boolean(it, &val); // can't fail
314 if (fprintf(out, val ? "true" : "false") < 0)
319 case CborDoubleType: {
325 cbor_value_get_float(it, &f);
330 case CborHalfFloatType:
331 cbor_value_get_half_float(it, &f16);
332 val = decode_half(f16);
335 cbor_value_get_double(it, &val);
339 int r = fpclassify(val);
340 if (r == FP_NAN || r == FP_INFINITE)
343 uint64_t ival = (uint64_t)fabs(val);
344 if (ival == fabs(val)) {
345 // this double value fits in a 64-bit integer, so show it as such
346 // (followed by a floating point suffix, to disambiguate)
347 r = fprintf(out, "%s%" PRIu64 ".%s", val < 0 ? "-" : "", ival, suffix);
349 // this number is definitely not a 64-bit integer
350 r = fprintf(out, "%." DBL_DECIMAL_DIG_STR "g%s", val, suffix);
357 case CborInvalidType:
358 if (fprintf(out, "invalid") < 0)
360 return CborErrorUnknownType;
363 err = cbor_value_advance_fixed(it);
367 CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value)
369 return value_to_pretty(out, value);