]> git.ipfire.org Git - thirdparty/openssl.git/blame - ssl/quic/json_enc.c
Copyright year updates
[thirdparty/openssl.git] / ssl / quic / json_enc.c
CommitLineData
9c89b9fe 1/*
b6461792 2 * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
9c89b9fe
HL
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include "internal/json_enc.h"
11#include "internal/nelem.h"
a19553cd 12#include "internal/numbers.h"
9c89b9fe
HL
13#include <string.h>
14#include <math.h>
15
16/*
17 * wbuf
18 * ====
19 */
5fd1f46f 20static int wbuf_flush(struct json_write_buf *wbuf, int full);
9c89b9fe
HL
21
22static int wbuf_init(struct json_write_buf *wbuf, BIO *bio, size_t alloc)
23{
24 wbuf->buf = OPENSSL_malloc(alloc);
25 if (wbuf->buf == NULL)
26 return 0;
27
28 wbuf->cur = 0;
29 wbuf->alloc = alloc;
30 wbuf->bio = bio;
31 return 1;
32}
33
34static void wbuf_cleanup(struct json_write_buf *wbuf)
35{
36 OPENSSL_free(wbuf->buf);
37 wbuf->buf = NULL;
38 wbuf->alloc = 0;
39}
40
39b93452 41static void wbuf_set0_bio(struct json_write_buf *wbuf, BIO *bio)
9c89b9fe
HL
42{
43 wbuf->bio = bio;
44}
45
46/* Empty write buffer. */
47static ossl_inline void wbuf_clean(struct json_write_buf *wbuf)
48{
49 wbuf->cur = 0;
50}
51
52/* Available data remaining in buffer. */
53static ossl_inline size_t wbuf_avail(struct json_write_buf *wbuf)
54{
55 return wbuf->alloc - wbuf->cur;
56}
57
58/* Add character to write buffer, returning 0 on flush failure. */
59static ossl_inline int wbuf_write_char(struct json_write_buf *wbuf, char c)
60{
61 if (wbuf_avail(wbuf) == 0) {
5fd1f46f 62 if (!wbuf_flush(wbuf, /*full=*/0))
9c89b9fe
HL
63 return 0;
64 }
65
66 wbuf->buf[wbuf->cur++] = c;
67 return 1;
68}
69
70/*
71 * Write zero-terminated string to write buffer, returning 0 on flush failure.
72 */
73static int wbuf_write_str(struct json_write_buf *wbuf, const char *s)
74{
75 char c;
76
77 while ((c = *s++) != 0)
78 if (!wbuf_write_char(wbuf, c))
79 return 0;
80
81 return 1;
82}
83
84/* Flush write buffer, returning 0 on I/O failure. */
5fd1f46f 85static int wbuf_flush(struct json_write_buf *wbuf, int full)
9c89b9fe
HL
86{
87 size_t written = 0, total_written = 0;
88
89 while (total_written < wbuf->cur) {
90 if (!BIO_write_ex(wbuf->bio,
91 wbuf->buf + total_written,
92 wbuf->cur - total_written,
93 &written)) {
94 memmove(wbuf->buf,
95 wbuf->buf + total_written,
96 wbuf->cur - total_written);
97 wbuf->cur = 0;
98 return 0;
99 }
100
101 total_written += written;
102 }
103
104 wbuf->cur = 0;
5fd1f46f
HL
105
106 if (full)
107 (void)BIO_flush(wbuf->bio); /* best effort */
108
9c89b9fe
HL
109 return 1;
110}
111
112/*
b3706fd7
HL
113 * OSSL_JSON_ENC: Stack Management
114 * ===============================
9c89b9fe
HL
115 */
116
b3706fd7 117static int json_ensure_stack_size(OSSL_JSON_ENC *json, size_t num_bytes)
9c89b9fe
HL
118{
119 unsigned char *stack;
120
121 if (json->stack_bytes >= num_bytes)
122 return 1;
123
124 if (num_bytes <= OSSL_NELEM(json->stack_small)) {
125 stack = json->stack_small;
126 } else {
127 if (json->stack == json->stack_small)
128 json->stack = NULL;
129
130 stack = OPENSSL_realloc(json->stack, num_bytes);
131 if (stack == NULL)
132 return 0;
133 }
134
135 json->stack = stack;
136 json->stack_bytes = num_bytes;
137 return 1;
138}
139
140/* Push one bit onto the stack. Returns 0 on allocation failure. */
b3706fd7 141static int json_push(OSSL_JSON_ENC *json, unsigned int v)
9c89b9fe
HL
142{
143 if (v > 1)
144 return 0;
145
146 if (json->stack_end_byte >= json->stack_bytes) {
147 size_t new_size
148 = (json->stack_bytes == 0)
149 ? OSSL_NELEM(json->stack_small)
150 : (json->stack_bytes * 2);
151
152 if (!json_ensure_stack_size(json, new_size))
153 return 0;
154
155 json->stack_bytes = new_size;
156 }
157
158 if (v > 0)
159 json->stack[json->stack_end_byte] |= (v << json->stack_end_bit);
160 else
161 json->stack[json->stack_end_byte] &= ~(1U << json->stack_end_bit);
162
163 json->stack_end_bit = (json->stack_end_bit + 1) % CHAR_BIT;
164 if (json->stack_end_bit == 0)
165 ++json->stack_end_byte;
166
167 return 1;
168}
169
170/*
171 * Pop a bit from the stack. Returns 0 if stack is empty. Use json_peek() to get
172 * the value before calling this.
173 */
b3706fd7 174static int json_pop(OSSL_JSON_ENC *json)
9c89b9fe
HL
175{
176 if (json->stack_end_byte == 0 && json->stack_end_bit == 0)
177 return 0;
178
179 if (json->stack_end_bit == 0) {
180 --json->stack_end_byte;
181 json->stack_end_bit = CHAR_BIT - 1;
182 } else {
183 --json->stack_end_bit;
184 }
185
186 return 1;
187}
188
189/*
190 * Returns the bit on the top of the stack, or -1 if the stack is empty.
191 */
b3706fd7 192static int json_peek(OSSL_JSON_ENC *json)
9c89b9fe
HL
193{
194 size_t obyte, obit;
195
196 obyte = json->stack_end_byte;
197 obit = json->stack_end_bit;
198 if (obit == 0) {
199 if (obyte == 0)
200 return -1;
201
202 --obyte;
203 obit = CHAR_BIT - 1;
204 } else {
205 --obit;
206 }
207
208 return (json->stack[obyte] & (1U << obit)) != 0;
209}
210
211/*
b3706fd7
HL
212 * OSSL_JSON_ENC: Initialisation
213 * =============================
9c89b9fe
HL
214 */
215
216enum {
217 STATE_PRE_KEY,
218 STATE_PRE_ITEM,
219 STATE_PRE_COMMA
220};
221
b3706fd7 222static ossl_inline int in_ijson(const OSSL_JSON_ENC *json)
9c89b9fe 223{
b3706fd7 224 return (json->flags & OSSL_JSON_FLAG_IJSON) != 0;
9c89b9fe
HL
225}
226
b3706fd7 227static ossl_inline int in_seq(const OSSL_JSON_ENC *json)
9c89b9fe 228{
b3706fd7 229 return (json->flags & OSSL_JSON_FLAG_SEQ) != 0;
9c89b9fe
HL
230}
231
b3706fd7 232static ossl_inline int in_pretty(const OSSL_JSON_ENC *json)
9c89b9fe 233{
b3706fd7 234 return (json->flags & OSSL_JSON_FLAG_PRETTY) != 0;
9c89b9fe
HL
235}
236
b3706fd7 237int ossl_json_init(OSSL_JSON_ENC *json, BIO *bio, uint32_t flags)
9c89b9fe
HL
238{
239 memset(json, 0, sizeof(*json));
240 json->flags = flags;
67f99769 241 json->error = 0;
9c89b9fe
HL
242 if (!wbuf_init(&json->wbuf, bio, 4096))
243 return 0;
244
245 json->state = STATE_PRE_COMMA;
39b93452 246 return 1;
9c89b9fe
HL
247}
248
b3706fd7 249void ossl_json_cleanup(OSSL_JSON_ENC *json)
9c89b9fe
HL
250{
251 wbuf_cleanup(&json->wbuf);
252
253 if (json->stack != json->stack_small)
254 OPENSSL_free(json->stack);
255
256 json->stack = NULL;
257}
258
b3706fd7 259int ossl_json_flush_cleanup(OSSL_JSON_ENC *json)
9c89b9fe
HL
260{
261 int ok = ossl_json_flush(json);
262
263 ossl_json_cleanup(json);
264 return ok;
265}
266
b3706fd7 267int ossl_json_reset(OSSL_JSON_ENC *json)
9c89b9fe
HL
268{
269 wbuf_clean(&json->wbuf);
270 json->stack_end_byte = 0;
271 json->stack_end_bit = 0;
272 json->error = 0;
273 return 1;
274}
275
b3706fd7 276int ossl_json_flush(OSSL_JSON_ENC *json)
9c89b9fe 277{
5fd1f46f 278 return wbuf_flush(&json->wbuf, /*full=*/1);
9c89b9fe
HL
279}
280
39b93452 281int ossl_json_set0_sink(OSSL_JSON_ENC *json, BIO *bio)
9c89b9fe 282{
39b93452 283 wbuf_set0_bio(&json->wbuf, bio);
9c89b9fe
HL
284 return 1;
285}
286
b3706fd7 287int ossl_json_in_error(OSSL_JSON_ENC *json)
9c89b9fe
HL
288{
289 return json->error;
290}
291
292/*
293 * JSON Builder Calls
294 * ==================
295 */
296
b3706fd7
HL
297static void json_write_qstring(OSSL_JSON_ENC *json, const char *str);
298static void json_indent(OSSL_JSON_ENC *json);
9c89b9fe 299
b3706fd7 300static void json_raise_error(OSSL_JSON_ENC *json)
9c89b9fe
HL
301{
302 json->error = 1;
303}
304
b3706fd7 305static void json_undefer(OSSL_JSON_ENC *json)
9c89b9fe
HL
306{
307 if (!json->defer_indent)
308 return;
309
310 json_indent(json);
311}
312
b3706fd7 313static void json_write_char(OSSL_JSON_ENC *json, char ch)
9c89b9fe 314{
29bd1e2d 315 if (ossl_json_in_error(json))
9c89b9fe
HL
316 return;
317
318 json_undefer(json);
319 if (!wbuf_write_char(&json->wbuf, ch))
320 json_raise_error(json);
321}
322
b3706fd7 323static void json_write_str(OSSL_JSON_ENC *json, const char *s)
9c89b9fe 324{
29bd1e2d 325 if (ossl_json_in_error(json))
9c89b9fe
HL
326 return;
327
328 json_undefer(json);
329 if (!wbuf_write_str(&json->wbuf, s))
330 json_raise_error(json);
331}
332
b3706fd7 333static void json_indent(OSSL_JSON_ENC *json)
9c89b9fe
HL
334{
335 size_t i, depth;
336
337 json->defer_indent = 0;
338
339 if (!in_pretty(json))
340 return;
341
342 json_write_char(json, '\n');
343
344 depth = json->stack_end_byte * 8 + json->stack_end_bit;
345 for (i = 0; i < depth * 4; ++i)
346 json_write_str(json, " ");
347}
348
b3706fd7 349static int json_pre_item(OSSL_JSON_ENC *json)
9c89b9fe
HL
350{
351 int s;
352
29bd1e2d 353 if (ossl_json_in_error(json))
9c89b9fe
HL
354 return 0;
355
356 switch (json->state) {
357 case STATE_PRE_COMMA:
358 s = json_peek(json);
359
360 if (s == 0) {
361 json_raise_error(json);
362 return 0;
363 }
364
365 if (s == 1) {
366 json_write_char(json, ',');
29bd1e2d 367 if (ossl_json_in_error(json))
9c89b9fe
HL
368 return 0;
369
370 json_indent(json);
371 }
372
373 if (s < 0 && in_seq(json))
374 json_write_char(json, '\x1E');
375
376 json->state = STATE_PRE_ITEM;
377 break;
378
379 case STATE_PRE_ITEM:
380 break;
381
382 case STATE_PRE_KEY:
383 default:
384 json_raise_error(json);
385 return 0;
386 }
387
388 return 1;
389}
390
b3706fd7 391static void json_post_item(OSSL_JSON_ENC *json)
9c89b9fe
HL
392{
393 int s = json_peek(json);
394
395 json->state = STATE_PRE_COMMA;
396
397 if (s < 0 && in_seq(json))
398 json_write_char(json, '\n');
399}
400
401/*
402 * Begin a composite structure (object or array).
403 *
404 * type: 0=object, 1=array.
405 */
b3706fd7 406static void composite_begin(OSSL_JSON_ENC *json, int type, char ch)
9c89b9fe
HL
407{
408 if (!json_pre_item(json)
409 || !json_push(json, type))
410 json_raise_error(json);
411
412 json_write_char(json, ch);
413 json->defer_indent = 1;
414}
415
416/*
417 * End a composite structure (object or array).
418 *
419 * type: 0=object, 1=array. Errors on mismatch.
420 */
b3706fd7 421static void composite_end(OSSL_JSON_ENC *json, int type, char ch)
9c89b9fe
HL
422{
423 int was_defer = json->defer_indent;
424
29bd1e2d 425 if (ossl_json_in_error(json))
9c89b9fe
HL
426 return;
427
428 json->defer_indent = 0;
429
29bd1e2d
HL
430 if (json_peek(json) != type) {
431 json_raise_error(json);
9c89b9fe 432 return;
29bd1e2d 433 }
9c89b9fe
HL
434
435 if (type == 0 && json->state == STATE_PRE_ITEM) {
436 json_raise_error(json);
437 return;
438 }
439
29bd1e2d
HL
440 if (!json_pop(json)) {
441 json_raise_error(json);
9c89b9fe 442 return;
29bd1e2d 443 }
9c89b9fe
HL
444
445 if (!was_defer)
446 json_indent(json);
447
448 json_write_char(json, ch);
449 json_post_item(json);
450}
451
452/* Begin a new JSON object. */
b3706fd7 453void ossl_json_object_begin(OSSL_JSON_ENC *json)
9c89b9fe
HL
454{
455 composite_begin(json, 0, '{');
456 json->state = STATE_PRE_KEY;
457}
458
ae300c0d 459/* End a JSON object. Must be matched with a call to ossl_json_object_begin(). */
b3706fd7 460void ossl_json_object_end(OSSL_JSON_ENC *json)
9c89b9fe
HL
461{
462 composite_end(json, 0, '}');
463}
464
465/* Begin a new JSON array. */
b3706fd7 466void ossl_json_array_begin(OSSL_JSON_ENC *json)
9c89b9fe
HL
467{
468 composite_begin(json, 1, '[');
469 json->state = STATE_PRE_ITEM;
470}
471
ae300c0d 472/* End a JSON array. Must be matched with a call to ossl_json_array_begin(). */
b3706fd7 473void ossl_json_array_end(OSSL_JSON_ENC *json)
9c89b9fe
HL
474{
475 composite_end(json, 1, ']');
476}
477
478/*
479 * Encode a JSON key within an object. Pass a zero-terminated string, which can
480 * be freed immediately following the call to this function.
481 */
b3706fd7 482void ossl_json_key(OSSL_JSON_ENC *json, const char *key)
9c89b9fe 483{
29bd1e2d 484 if (ossl_json_in_error(json))
9c89b9fe
HL
485 return;
486
487 if (json_peek(json) != 0) {
488 /* Not in object */
489 json_raise_error(json);
490 return;
491 }
492
493 if (json->state == STATE_PRE_COMMA) {
494 json_write_char(json, ',');
495 json->state = STATE_PRE_KEY;
496 }
497
498 json_indent(json);
499 if (json->state != STATE_PRE_KEY) {
500 json_raise_error(json);
501 return;
502 }
503
504 json_write_qstring(json, key);
29bd1e2d 505 if (ossl_json_in_error(json))
9c89b9fe
HL
506 return;
507
508 json_write_char(json, ':');
509 if (in_pretty(json))
510 json_write_char(json, ' ');
511
512 json->state = STATE_PRE_ITEM;
513}
514
515/* Encode a JSON 'null' value. */
b3706fd7 516void ossl_json_null(OSSL_JSON_ENC *json)
9c89b9fe
HL
517{
518 if (!json_pre_item(json))
519 return;
520
521 json_write_str(json, "null");
522 json_post_item(json);
523}
524
b3706fd7 525void ossl_json_bool(OSSL_JSON_ENC *json, int v)
9c89b9fe
HL
526{
527 if (!json_pre_item(json))
528 return;
529
530 json_write_str(json, v > 0 ? "true" : "false");
531 json_post_item(json);
532}
533
534#define POW_53 (((int64_t)1) << 53)
535
536/* Encode a JSON integer from a uint64_t. */
b3706fd7 537static void json_u64(OSSL_JSON_ENC *json, uint64_t v, int noquote)
9c89b9fe
HL
538{
539 char buf[22], *p = buf + sizeof(buf) - 1;
540 int quote = !noquote && in_ijson(json) && v > (uint64_t)(POW_53 - 1);
541
542 if (!json_pre_item(json))
543 return;
544
545 if (quote)
546 json_write_char(json, '"');
547
548 if (v == 0)
549 p = "0";
550 else
551 for (*p = '\0'; v > 0; v /= 10)
552 *--p = '0' + v % 10;
553
554 json_write_str(json, p);
555
556 if (quote)
557 json_write_char(json, '"');
558
559 json_post_item(json);
560}
561
b3706fd7 562void ossl_json_u64(OSSL_JSON_ENC *json, uint64_t v)
9c89b9fe
HL
563{
564 json_u64(json, v, 0);
565}
566
567/* Encode a JSON integer from an int64_t. */
b3706fd7 568void ossl_json_i64(OSSL_JSON_ENC *json, int64_t value)
9c89b9fe
HL
569{
570 uint64_t uv;
571 int quote;
572
573 if (value >= 0) {
574 ossl_json_u64(json, (uint64_t)value);
575 return;
576 }
577
578 if (!json_pre_item(json))
579 return;
580
581 quote = in_ijson(json)
582 && (value > POW_53 - 1 || value < -POW_53 + 1);
583
584 if (quote)
585 json_write_char(json, '"');
586
587 json_write_char(json, '-');
588
589 uv = (value == INT64_MIN)
590 ? ((uint64_t)-(INT64_MIN + 1)) + 1
591 : (uint64_t)-value;
592 json_u64(json, uv, /*noquote=*/1);
593
29bd1e2d 594 if (quote && !ossl_json_in_error(json))
9c89b9fe
HL
595 json_write_char(json, '"');
596}
597
598/* Encode a JSON number from a 64-bit floating point value. */
b3706fd7 599void ossl_json_f64(OSSL_JSON_ENC *json, double value)
9c89b9fe
HL
600{
601 char buf[32];
602
603 if (!json_pre_item(json))
604 return;
605
a19553cd
RL
606#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
607 {
608 int checks = isnan(value);
609# if !defined(OPENSSL_SYS_VMS)
610 checks |= isinf(value);
611# endif
612
613 if (checks) {
614 json_raise_error(json);
615 return;
616 }
9c89b9fe 617 }
a19553cd 618#endif
9c89b9fe 619
c71bde1e 620 BIO_snprintf(buf, sizeof(buf), "%1.17g", value);
9c89b9fe
HL
621 json_write_str(json, buf);
622 json_post_item(json);
623}
624
625/*
626 * Encode a JSON UTF-8 string from a zero-terminated string. The string passed
627 * can be freed immediately following the call to this function.
628 */
629static ossl_inline int hex_digit(int v)
630{
631 return v >= 10 ? 'a' + (v - 10) : '0' + v;
632}
633
634static ossl_inline void
b3706fd7 635json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,
9c89b9fe
HL
636 int nul_term)
637{
638 char c, *o, obuf[7];
bc3eb7b5 639 unsigned char *u_str;
9c89b9fe
HL
640 int i;
641 size_t j;
642
29bd1e2d 643 if (ossl_json_in_error(json))
9c89b9fe
HL
644 return;
645
646 json_write_char(json, '"');
647
bc3eb7b5 648 for (j = nul_term ? strlen(str) : str_len; j > 0; str++, j--) {
9c89b9fe 649 c = *str;
bc3eb7b5 650 u_str = (unsigned char*)str;
9c89b9fe
HL
651 switch (c) {
652 case '\n': o = "\\n"; break;
653 case '\r': o = "\\r"; break;
654 case '\t': o = "\\t"; break;
655 case '\b': o = "\\b"; break;
656 case '\f': o = "\\f"; break;
657 case '"': o = "\\\""; break;
658 case '\\': o = "\\\\"; break;
659 default:
bc3eb7b5
BE
660 /* valid UTF-8 sequences according to RFC-3629 */
661 if (u_str[0] >= 0xc2 && u_str[0] <= 0xdf && j >= 2
662 && u_str[1] >= 0x80 && u_str[1] <= 0xbf) {
663 memcpy(obuf, str, 2);
664 obuf[2] = '\0';
665 str++, j--;
666 o = obuf;
667 break;
668 }
669 if (u_str[0] >= 0xe0 && u_str[0] <= 0xef && j >= 3
670 && u_str[1] >= 0x80 && u_str[1] <= 0xbf
671 && u_str[2] >= 0x80 && u_str[2] <= 0xbf
672 && !(u_str[0] == 0xe0 && u_str[1] <= 0x9f)
673 && !(u_str[0] == 0xed && u_str[1] >= 0xa0)) {
674 memcpy(obuf, str, 3);
675 obuf[3] = '\0';
676 str += 2;
677 j -= 2;
678 o = obuf;
679 break;
680 }
681 if (u_str[0] >= 0xf0 && u_str[0] <= 0xf4 && j >= 4
682 && u_str[1] >= 0x80 && u_str[1] <= 0xbf
683 && u_str[2] >= 0x80 && u_str[2] <= 0xbf
684 && u_str[3] >= 0x80 && u_str[3] <= 0xbf
685 && !(u_str[0] == 0xf0 && u_str[1] <= 0x8f)
686 && !(u_str[0] == 0xf4 && u_str[1] >= 0x90)) {
687 memcpy(obuf, str, 4);
688 obuf[4] = '\0';
689 str += 3;
690 j -= 3;
691 o = obuf;
692 break;
9c89b9fe 693 }
bc3eb7b5 694 if (u_str[0] < 0x20 || u_str[0] >= 0x7f) {
9c89b9fe
HL
695 obuf[0] = '\\';
696 obuf[1] = 'u';
697 for (i = 0; i < 4; ++i)
bc3eb7b5 698 obuf[2 + i] = hex_digit((u_str[0] >> ((3 - i) * 4)) & 0x0F);
9c89b9fe
HL
699 obuf[6] = '\0';
700 o = obuf;
701 } else {
702 json_write_char(json, c);
703 continue;
704 }
705 break;
706 }
707
708 json_write_str(json, o);
709 }
710
711 json_write_char(json, '"');
712}
713
714static void
b3706fd7 715json_write_qstring(OSSL_JSON_ENC *json, const char *str)
9c89b9fe
HL
716{
717 json_write_qstring_inner(json, str, 0, 1);
718}
719
720static void
b3706fd7 721json_write_qstring_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
9c89b9fe
HL
722{
723 json_write_qstring_inner(json, str, str_len, 0);
724}
725
b3706fd7 726void ossl_json_str(OSSL_JSON_ENC *json, const char *str)
9c89b9fe
HL
727{
728 if (!json_pre_item(json))
729 return;
730
731 json_write_qstring(json, str);
732 json_post_item(json);
733}
734
b3706fd7 735void ossl_json_str_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
9c89b9fe
HL
736{
737 if (!json_pre_item(json))
738 return;
739
740 json_write_qstring_len(json, str, str_len);
741 json_post_item(json);
742}
743
744/*
745 * Encode binary data as a lowercase hex string. data_len is the data length in
746 * bytes.
747 */
b3706fd7 748void ossl_json_str_hex(OSSL_JSON_ENC *json, const void *data, size_t data_len)
9c89b9fe
HL
749{
750 const unsigned char *b = data, *end = b + data_len;
751 unsigned char c;
752
753 if (!json_pre_item(json))
754 return;
755
756 json_write_char(json, '"');
757
758 for (; b < end; ++b) {
759 c = *b;
760 json_write_char(json, hex_digit(c >> 4));
761 json_write_char(json, hex_digit(c & 0x0F));
762 }
763
764 json_write_char(json, '"');
765 json_post_item(json);
766}