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"
28 #include "math_support_p.h"
37 static int hexDump(FILE *out, const uint8_t *buffer, size_t n)
40 int r = fprintf(out, "%02" PRIx8, *buffer++);
44 return 0; // should be n * 2, but we don't have the original n anymore
47 /* This function decodes buffer as UTF-8 and prints as escaped UTF-16.
48 * On UTF-8 decoding error, it returns CborErrorInvalidUtf8TextString */
49 static int utf8EscapedDump(FILE *out, const char *buffer, size_t n)
53 uc = (uint8_t)*buffer++;
56 if (uc < 0x7f && uc >= 0x20 && uc != '\\' && uc != '"') {
57 if (fprintf(out, "%c", (char)uc) < 0)
62 // print as an escape sequence
63 char escaped = (char)uc;
86 if (fprintf(out, "\\%c", escaped) < 0)
91 // multi-byte UTF-8, decode it
94 if (unlikely(uc <= 0xC1))
95 return CborErrorInvalidUtf8TextString;
101 } else if (uc < 0xF0) {
102 /* three-byte UTF-8 */
106 } else if (uc < 0xF5) {
107 /* four-byte UTF-8 */
112 return CborErrorInvalidUtf8TextString;
115 if (n < charsNeeded - 1)
116 return CborErrorInvalidUtf8TextString;
118 // first continuation character
119 uint8_t b = (uint8_t)*buffer++;
120 if ((b & 0xc0) != 0x80)
121 return CborErrorInvalidUtf8TextString;
125 if (charsNeeded > 2) {
126 // second continuation character
127 b = (uint8_t)*buffer++;
128 if ((b & 0xc0) != 0x80)
129 return CborErrorInvalidUtf8TextString;
133 if (charsNeeded > 3) {
134 // third continuation character
135 b = (uint8_t)*buffer++;
136 if ((b & 0xc0) != 0x80)
137 return CborErrorInvalidUtf8TextString;
143 // overlong sequence? surrogate pair? out or range?
144 if (uc < min_uc || uc - 0xd800U < 2048U || uc > 0x10ffff)
145 return CborErrorInvalidUtf8TextString;
147 // now print the sequence
148 if (charsNeeded > 3) {
149 // needs surrogate pairs
150 if (fprintf(out, "\\u%04" PRIX32 "\\u%04" PRIX32,
151 (uc >> 10) + 0xd7c0, // high surrogate
152 (uc % 0x0400) + 0xdc00) < 0)
156 // no surrogate pair needed
157 if (fprintf(out, "\\u%04" PRIX32, uc) < 0)
164 static CborError value_to_pretty(FILE *out, CborValue *it);
165 static CborError container_to_pretty(FILE *out, CborValue *it, CborType containerType)
167 const char *comma = "";
168 while (!cbor_value_at_end(it)) {
169 if (fprintf(out, "%s", comma) < 0)
173 CborError err = value_to_pretty(out, it);
177 if (containerType == CborArrayType)
180 // map: that was the key, so get the value
181 if (fprintf(out, ": ") < 0)
183 err = value_to_pretty(out, it);
190 static CborError value_to_pretty(FILE *out, CborValue *it)
193 CborType type = cbor_value_get_type(it);
200 if (fprintf(out, type == CborArrayType ? "[" : "{") < 0)
202 if (!cbor_value_is_length_known(it)) {
203 if (fprintf(out, "_ ") < 0)
207 err = cbor_value_enter_container(it, &recursed);
209 it->ptr = recursed.ptr;
210 return err; // parse error
212 err = container_to_pretty(out, &recursed, type);
214 it->ptr = recursed.ptr;
215 return err; // parse error
217 err = cbor_value_leave_container(it, &recursed);
219 return err; // parse error
221 if (fprintf(out, type == CborArrayType ? "]" : "}") < 0)
226 case CborIntegerType: {
228 cbor_value_get_raw_integer(it, &val); // can't fail
230 if (cbor_value_is_unsigned_integer(it)) {
231 if (fprintf(out, "%" PRIu64, val) < 0)
234 // CBOR stores the negative number X as -1 - X
235 // (that is, -1 is stored as 0, -2 as 1 and so forth)
236 if (++val) { // unsigned overflow may happen
237 if (fprintf(out, "-%" PRIu64, val) < 0)
241 // 0xffff`ffff`ffff`ffff + 1 =
242 // 0x1`0000`0000`0000`0000 = 18446744073709551616 (2^64)
243 if (fprintf(out, "-18446744073709551616") < 0)
250 case CborByteStringType:{
253 err = cbor_value_dup_byte_string(it, &buffer, &n, it);
257 bool failed = fprintf(out, "h'") < 0 || hexDump(out, buffer, n) < 0 || fprintf(out, "'") < 0;
259 return failed ? CborErrorIO : CborNoError;
262 case CborTextStringType: {
265 err = cbor_value_dup_text_string(it, &buffer, &n, it);
270 bool failed = fprintf(out, "\"") < 0
271 || (err = utf8EscapedDump(out, buffer, n)) != CborNoError
272 || fprintf(out, "\"") < 0;
274 return err != CborNoError ? err :
275 failed ? CborErrorIO : CborNoError;
280 cbor_value_get_tag(it, &tag); // can't fail
281 if (fprintf(out, "%" PRIu64 "(", tag) < 0)
283 err = cbor_value_advance_fixed(it);
286 err = value_to_pretty(out, it);
289 if (fprintf(out, ")") < 0)
294 case CborSimpleType: {
296 cbor_value_get_simple_type(it, &simple_type); // can't fail
297 if (fprintf(out, "simple(%" PRIu8 ")", simple_type) < 0)
303 if (fprintf(out, "null") < 0)
307 case CborUndefinedType:
308 if (fprintf(out, "undefined") < 0)
312 case CborBooleanType: {
314 cbor_value_get_boolean(it, &val); // can't fail
315 if (fprintf(out, val ? "true" : "false") < 0)
320 case CborDoubleType: {
326 cbor_value_get_float(it, &f);
331 case CborHalfFloatType:
332 cbor_value_get_half_float(it, &f16);
333 val = decode_half(f16);
336 cbor_value_get_double(it, &val);
340 int r = fpclassify(val);
341 if (r == FP_NAN || r == FP_INFINITE)
344 uint64_t ival = (uint64_t)fabs(val);
345 if (ival == fabs(val)) {
346 // this double value fits in a 64-bit integer, so show it as such
347 // (followed by a floating point suffix, to disambiguate)
348 r = fprintf(out, "%s%" PRIu64 ".%s", val < 0 ? "-" : "", ival, suffix);
350 // this number is definitely not a 64-bit integer
351 r = fprintf(out, "%." DBL_DECIMAL_DIG_STR "g%s", val, suffix);
358 case CborInvalidType:
359 if (fprintf(out, "invalid") < 0)
361 return CborErrorUnknownType;
364 err = cbor_value_advance_fixed(it);
368 CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value)
370 return value_to_pretty(out, value);