xref: /spdk/lib/json/json_write.c (revision 588dfe314bb83d86effdf67ec42837b11c2620bf)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2016 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/json.h"
7 
8 #include "spdk_internal/utf.h"
9 
10 struct spdk_json_write_ctx {
11 	spdk_json_write_cb write_cb;
12 	void *cb_ctx;
13 	uint32_t flags;
14 	uint32_t indent;
15 	bool new_indent;
16 	bool first_value;
17 	bool failed;
18 	size_t buf_filled;
19 	uint8_t buf[4096];
20 };
21 
22 static int emit_buf_full(struct spdk_json_write_ctx *w, const void *data, size_t size);
23 
24 static int
25 fail(struct spdk_json_write_ctx *w)
26 {
27 	w->failed = true;
28 	return -1;
29 }
30 
31 static int
32 flush_buf(struct spdk_json_write_ctx *w)
33 {
34 	int rc;
35 
36 	rc = w->write_cb(w->cb_ctx, w->buf, w->buf_filled);
37 	if (rc != 0) {
38 		return fail(w);
39 	}
40 
41 	w->buf_filled = 0;
42 
43 	return 0;
44 }
45 
46 struct spdk_json_write_ctx *
47 spdk_json_write_begin(spdk_json_write_cb write_cb, void *cb_ctx, uint32_t flags)
48 {
49 	struct spdk_json_write_ctx *w;
50 
51 	w = calloc(1, sizeof(*w));
52 	if (w == NULL) {
53 		return w;
54 	}
55 
56 	w->write_cb = write_cb;
57 	w->cb_ctx = cb_ctx;
58 	w->flags = flags;
59 	w->indent = 0;
60 	w->new_indent = false;
61 	w->first_value = true;
62 	w->failed = false;
63 	w->buf_filled = 0;
64 
65 	return w;
66 }
67 
68 int
69 spdk_json_write_end(struct spdk_json_write_ctx *w)
70 {
71 	bool failed;
72 	int rc;
73 
74 	if (w == NULL) {
75 		return 0;
76 	}
77 
78 	failed = w->failed;
79 
80 	rc = flush_buf(w);
81 	if (rc != 0) {
82 		failed = true;
83 	}
84 
85 	free(w);
86 
87 	return failed ? -1 : 0;
88 }
89 
90 static inline int
91 emit(struct spdk_json_write_ctx *w, const void *data, size_t size)
92 {
93 	size_t buf_remain = sizeof(w->buf) - w->buf_filled;
94 
95 	if (spdk_unlikely(size > buf_remain)) {
96 		/* Not enough space in buffer for the new data. */
97 		return emit_buf_full(w, data, size);
98 	}
99 
100 	/* Copy the new data into buf. */
101 	memcpy(w->buf + w->buf_filled, data, size);
102 	w->buf_filled += size;
103 	return 0;
104 }
105 
106 static int
107 emit_buf_full(struct spdk_json_write_ctx *w, const void *data, size_t size)
108 {
109 	size_t buf_remain = sizeof(w->buf) - w->buf_filled;
110 	int rc;
111 
112 	assert(size > buf_remain);
113 
114 	/* Copy as much of the new data as possible into the buffer and flush it. */
115 	memcpy(w->buf + w->buf_filled, data, buf_remain);
116 	w->buf_filled += buf_remain;
117 
118 	rc = flush_buf(w);
119 	if (rc != 0) {
120 		return fail(w);
121 	}
122 
123 	/* Recurse to emit the rest of the data. */
124 	return emit(w, data + buf_remain, size - buf_remain);
125 }
126 
127 static int
128 emit_fmt(struct spdk_json_write_ctx *w, const void *data, size_t size)
129 {
130 	if (w->flags & SPDK_JSON_WRITE_FLAG_FORMATTED) {
131 		return emit(w, data, size);
132 	}
133 	return 0;
134 }
135 
136 static int
137 emit_indent(struct spdk_json_write_ctx *w)
138 {
139 	uint32_t i;
140 
141 	if (w->flags & SPDK_JSON_WRITE_FLAG_FORMATTED) {
142 		for (i = 0; i < w->indent; i++) {
143 			if (emit(w, "  ", 2)) { return fail(w); }
144 		}
145 	}
146 	return 0;
147 }
148 
149 static int
150 begin_value(struct spdk_json_write_ctx *w)
151 {
152 	/* TODO: check for value state */
153 	if (w->new_indent) {
154 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
155 		if (emit_indent(w)) { return fail(w); }
156 	}
157 	if (!w->first_value) {
158 		if (emit(w, ",", 1)) { return fail(w); }
159 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
160 		if (emit_indent(w)) { return fail(w); }
161 	}
162 	w->first_value = false;
163 	w->new_indent = false;
164 	return 0;
165 }
166 
167 int
168 spdk_json_write_val_raw(struct spdk_json_write_ctx *w, const void *data, size_t len)
169 {
170 	if (begin_value(w)) { return fail(w); }
171 	return emit(w, data, len);
172 }
173 
174 int
175 spdk_json_write_null(struct spdk_json_write_ctx *w)
176 {
177 	if (begin_value(w)) { return fail(w); }
178 	return emit(w, "null", 4);
179 }
180 
181 int
182 spdk_json_write_bool(struct spdk_json_write_ctx *w, bool val)
183 {
184 	if (begin_value(w)) { return fail(w); }
185 	if (val) {
186 		return emit(w, "true", 4);
187 	} else {
188 		return emit(w, "false", 5);
189 	}
190 }
191 
192 int
193 spdk_json_write_uint8(struct spdk_json_write_ctx *w, uint8_t val)
194 {
195 	char buf[32];
196 	int count;
197 
198 	if (begin_value(w)) { return fail(w); }
199 	count = snprintf(buf, sizeof(buf), "%" PRIu8, val);
200 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
201 	return emit(w, buf, count);
202 }
203 
204 int
205 spdk_json_write_uint16(struct spdk_json_write_ctx *w, uint16_t val)
206 {
207 	char buf[32];
208 	int count;
209 
210 	if (begin_value(w)) { return fail(w); }
211 	count = snprintf(buf, sizeof(buf), "%" PRIu16, val);
212 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
213 	return emit(w, buf, count);
214 }
215 
216 int
217 spdk_json_write_int32(struct spdk_json_write_ctx *w, int32_t val)
218 {
219 	char buf[32];
220 	int count;
221 
222 	if (begin_value(w)) { return fail(w); }
223 	count = snprintf(buf, sizeof(buf), "%" PRId32, val);
224 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
225 	return emit(w, buf, count);
226 }
227 
228 int
229 spdk_json_write_uint32(struct spdk_json_write_ctx *w, uint32_t val)
230 {
231 	char buf[32];
232 	int count;
233 
234 	if (begin_value(w)) { return fail(w); }
235 	count = snprintf(buf, sizeof(buf), "%" PRIu32, val);
236 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
237 	return emit(w, buf, count);
238 }
239 
240 int
241 spdk_json_write_int64(struct spdk_json_write_ctx *w, int64_t val)
242 {
243 	char buf[32];
244 	int count;
245 
246 	if (begin_value(w)) { return fail(w); }
247 	count = snprintf(buf, sizeof(buf), "%" PRId64, val);
248 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
249 	return emit(w, buf, count);
250 }
251 
252 int
253 spdk_json_write_uint64(struct spdk_json_write_ctx *w, uint64_t val)
254 {
255 	char buf[32];
256 	int count;
257 
258 	if (begin_value(w)) { return fail(w); }
259 	count = snprintf(buf, sizeof(buf), "%" PRIu64, val);
260 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
261 	return emit(w, buf, count);
262 }
263 
264 int
265 spdk_json_write_uint128(struct spdk_json_write_ctx *w, uint64_t low_val, uint64_t high_val)
266 {
267 	char buf[128] = {'\0'};
268 	uint64_t low = low_val, high = high_val;
269 	int count = 0;
270 
271 	if (begin_value(w)) { return fail(w); }
272 
273 	if (high != 0) {
274 		char temp_buf[128] = {'\0'};
275 		uint64_t seg;
276 		unsigned __int128 total = (unsigned __int128)low +
277 					  ((unsigned __int128)high << 64);
278 
279 		while (total) {
280 			seg = total % 10000000000;
281 			total = total / 10000000000;
282 			if (total) {
283 				count = snprintf(temp_buf, 128, "%010" PRIu64 "%s", seg, buf);
284 			} else {
285 				count = snprintf(temp_buf, 128, "%" PRIu64 "%s", seg, buf);
286 			}
287 
288 			if (count <= 0 || (size_t)count >= sizeof(temp_buf)) {
289 				return fail(w);
290 			}
291 
292 			snprintf(buf, 128, "%s", temp_buf);
293 		}
294 	} else {
295 		count = snprintf(buf, sizeof(buf), "%" PRIu64, low);
296 
297 		if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
298 	}
299 
300 	return emit(w, buf, count);
301 }
302 
303 int
304 spdk_json_write_named_uint128(struct spdk_json_write_ctx *w, const char *name,
305 			      uint64_t low_val, uint64_t high_val)
306 {
307 	int rc = spdk_json_write_name(w, name);
308 
309 	return rc ? rc : spdk_json_write_uint128(w, low_val, high_val);
310 }
311 
312 int
313 spdk_json_write_double(struct spdk_json_write_ctx *w, double val)
314 {
315 	char buf[32];
316 	int count;
317 
318 	if (begin_value(w)) { return fail(w); }
319 	count = snprintf(buf, sizeof(buf), "%.20e", val);
320 	if (count <= 0 || (size_t)count >= sizeof(buf)) { return fail(w); }
321 	return emit(w, buf, count);
322 }
323 
324 static void
325 write_hex_2(void *dest, uint8_t val)
326 {
327 	char *p = dest;
328 	char hex[] = "0123456789ABCDEF";
329 
330 	p[0] = hex[val >> 4];
331 	p[1] = hex[val & 0xf];
332 }
333 
334 static void
335 write_hex_4(void *dest, uint16_t val)
336 {
337 	write_hex_2(dest, (uint8_t)(val >> 8));
338 	write_hex_2((char *)dest + 2, (uint8_t)(val & 0xff));
339 }
340 
341 static inline int
342 write_codepoint(struct spdk_json_write_ctx *w, uint32_t codepoint)
343 {
344 	static const uint8_t escapes[] = {
345 		['\b'] = 'b',
346 		['\f'] = 'f',
347 		['\n'] = 'n',
348 		['\r'] = 'r',
349 		['\t'] = 't',
350 		['"'] = '"',
351 		['\\'] = '\\',
352 		/*
353 		 * Forward slash (/) is intentionally not converted to an escape
354 		 *  (it is valid unescaped).
355 		 */
356 	};
357 	uint16_t high, low;
358 	char out[13];
359 	size_t out_len;
360 
361 	if (codepoint < sizeof(escapes) && escapes[codepoint]) {
362 		out[0] = '\\';
363 		out[1] = escapes[codepoint];
364 		out_len = 2;
365 	} else if (codepoint >= 0x20 && codepoint < 0x7F) {
366 		/*
367 		 * Encode plain ASCII directly (except 0x7F, since it is really
368 		 *  a control character, despite the JSON spec not considering it one).
369 		 */
370 		out[0] = (uint8_t)codepoint;
371 		out_len = 1;
372 	} else if (codepoint < 0x10000) {
373 		out[0] = '\\';
374 		out[1] = 'u';
375 		write_hex_4(&out[2], (uint16_t)codepoint);
376 		out_len = 6;
377 	} else {
378 		utf16_encode_surrogate_pair(codepoint, &high, &low);
379 		out[0] = '\\';
380 		out[1] = 'u';
381 		write_hex_4(&out[2], high);
382 		out[6] = '\\';
383 		out[7] = 'u';
384 		write_hex_4(&out[8], low);
385 		out_len = 12;
386 	}
387 
388 	return emit(w, out, out_len);
389 }
390 
391 static int
392 write_string_or_name(struct spdk_json_write_ctx *w, const char *val, size_t len)
393 {
394 	const uint8_t *p = val;
395 	const uint8_t *end = val + len;
396 
397 	if (emit(w, "\"", 1)) { return fail(w); }
398 
399 	while (p != end) {
400 		int codepoint_len;
401 		uint32_t codepoint;
402 
403 		codepoint_len = utf8_valid(p, end);
404 		switch (codepoint_len) {
405 		case 1:
406 			codepoint = utf8_decode_unsafe_1(p);
407 			break;
408 		case 2:
409 			codepoint = utf8_decode_unsafe_2(p);
410 			break;
411 		case 3:
412 			codepoint = utf8_decode_unsafe_3(p);
413 			break;
414 		case 4:
415 			codepoint = utf8_decode_unsafe_4(p);
416 			break;
417 		default:
418 			return fail(w);
419 		}
420 
421 		if (write_codepoint(w, codepoint)) { return fail(w); }
422 		p += codepoint_len;
423 	}
424 
425 	return emit(w, "\"", 1);
426 }
427 
428 static int
429 write_string_or_name_utf16le(struct spdk_json_write_ctx *w, const uint16_t *val, size_t len)
430 {
431 	const uint16_t *p = val;
432 	const uint16_t *end = val + len;
433 
434 	if (emit(w, "\"", 1)) { return fail(w); }
435 
436 	while (p != end) {
437 		int codepoint_len;
438 		uint32_t codepoint;
439 
440 		codepoint_len = utf16le_valid(p, end);
441 		switch (codepoint_len) {
442 		case 1:
443 			codepoint = from_le16(&p[0]);
444 			break;
445 		case 2:
446 			codepoint = utf16_decode_surrogate_pair(from_le16(&p[0]), from_le16(&p[1]));
447 			break;
448 		default:
449 			return fail(w);
450 		}
451 
452 		if (write_codepoint(w, codepoint)) { return fail(w); }
453 		p += codepoint_len;
454 	}
455 
456 	return emit(w, "\"", 1);
457 }
458 
459 int
460 spdk_json_write_string_raw(struct spdk_json_write_ctx *w, const char *val, size_t len)
461 {
462 	if (begin_value(w)) { return fail(w); }
463 	return write_string_or_name(w, val, len);
464 }
465 
466 int
467 spdk_json_write_string(struct spdk_json_write_ctx *w, const char *val)
468 {
469 	return spdk_json_write_string_raw(w, val, strlen(val));
470 }
471 
472 int
473 spdk_json_write_string_utf16le_raw(struct spdk_json_write_ctx *w, const uint16_t *val, size_t len)
474 {
475 	if (begin_value(w)) { return fail(w); }
476 	return write_string_or_name_utf16le(w, val, len);
477 }
478 
479 int
480 spdk_json_write_string_utf16le(struct spdk_json_write_ctx *w, const uint16_t *val)
481 {
482 	const uint16_t *p;
483 	size_t len;
484 
485 	for (len = 0, p = val; *p; p++) {
486 		len++;
487 	}
488 
489 	return spdk_json_write_string_utf16le_raw(w, val, len);
490 }
491 
492 int
493 spdk_json_write_string_fmt(struct spdk_json_write_ctx *w, const char *fmt, ...)
494 {
495 	va_list args;
496 	int rc;
497 
498 	va_start(args, fmt);
499 	rc = spdk_json_write_string_fmt_v(w, fmt, args);
500 	va_end(args);
501 
502 	return rc;
503 }
504 
505 int
506 spdk_json_write_string_fmt_v(struct spdk_json_write_ctx *w, const char *fmt, va_list args)
507 {
508 	char *s;
509 	int rc;
510 
511 	s = spdk_vsprintf_alloc(fmt, args);
512 	if (s == NULL) {
513 		return -1;
514 	}
515 
516 	rc = spdk_json_write_string(w, s);
517 	free(s);
518 	return rc;
519 }
520 
521 int
522 spdk_json_write_bytearray(struct spdk_json_write_ctx *w, const void *val, size_t len)
523 {
524 	const uint8_t *v = val;
525 	size_t i;
526 	char *s;
527 	int rc;
528 
529 	s = malloc(2 * len + 1);
530 	if (s == NULL) {
531 		return -1;
532 	}
533 
534 	for (i = 0; i < len; ++i) {
535 		write_hex_2(&s[2 * i], *v++);
536 	}
537 	s[2 * len] = '\0';
538 
539 	rc = spdk_json_write_string(w, s);
540 	free(s);
541 	return rc;
542 }
543 
544 int
545 spdk_json_write_array_begin(struct spdk_json_write_ctx *w)
546 {
547 	if (begin_value(w)) { return fail(w); }
548 	w->first_value = true;
549 	w->new_indent = true;
550 	w->indent++;
551 	if (emit(w, "[", 1)) { return fail(w); }
552 	return 0;
553 }
554 
555 int
556 spdk_json_write_array_end(struct spdk_json_write_ctx *w)
557 {
558 	w->first_value = false;
559 	if (w->indent == 0) { return fail(w); }
560 	w->indent--;
561 	if (!w->new_indent) {
562 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
563 		if (emit_indent(w)) { return fail(w); }
564 	}
565 	w->new_indent = false;
566 	return emit(w, "]", 1);
567 }
568 
569 int
570 spdk_json_write_object_begin(struct spdk_json_write_ctx *w)
571 {
572 	if (begin_value(w)) { return fail(w); }
573 	w->first_value = true;
574 	w->new_indent = true;
575 	w->indent++;
576 	if (emit(w, "{", 1)) { return fail(w); }
577 	return 0;
578 }
579 
580 int
581 spdk_json_write_object_end(struct spdk_json_write_ctx *w)
582 {
583 	w->first_value = false;
584 	w->indent--;
585 	if (!w->new_indent) {
586 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
587 		if (emit_indent(w)) { return fail(w); }
588 	}
589 	w->new_indent = false;
590 	return emit(w, "}", 1);
591 }
592 
593 int
594 spdk_json_write_name_raw(struct spdk_json_write_ctx *w, const char *name, size_t len)
595 {
596 	/* TODO: check that container is an object */
597 	if (begin_value(w)) { return fail(w); }
598 	if (write_string_or_name(w, name, len)) { return fail(w); }
599 	w->first_value = true;
600 	if (emit(w, ":", 1)) { return fail(w); }
601 	return emit_fmt(w, " ", 1);
602 }
603 
604 int
605 spdk_json_write_name(struct spdk_json_write_ctx *w, const char *name)
606 {
607 	return spdk_json_write_name_raw(w, name, strlen(name));
608 }
609 
610 int
611 spdk_json_write_val(struct spdk_json_write_ctx *w, const struct spdk_json_val *val)
612 {
613 	size_t num_values, i;
614 
615 	switch (val->type) {
616 	case SPDK_JSON_VAL_NUMBER:
617 		return spdk_json_write_val_raw(w, val->start, val->len);
618 
619 	case SPDK_JSON_VAL_STRING:
620 		return spdk_json_write_string_raw(w, val->start, val->len);
621 
622 	case SPDK_JSON_VAL_NAME:
623 		return spdk_json_write_name_raw(w, val->start, val->len);
624 
625 	case SPDK_JSON_VAL_TRUE:
626 		return spdk_json_write_bool(w, true);
627 
628 	case SPDK_JSON_VAL_FALSE:
629 		return spdk_json_write_bool(w, false);
630 
631 	case SPDK_JSON_VAL_NULL:
632 		return spdk_json_write_null(w);
633 
634 	case SPDK_JSON_VAL_ARRAY_BEGIN:
635 	case SPDK_JSON_VAL_OBJECT_BEGIN:
636 		num_values = val[0].len;
637 
638 		if (val[0].type == SPDK_JSON_VAL_OBJECT_BEGIN) {
639 			if (spdk_json_write_object_begin(w)) {
640 				return fail(w);
641 			}
642 		} else {
643 			if (spdk_json_write_array_begin(w)) {
644 				return fail(w);
645 			}
646 		}
647 
648 		/* Loop up to and including the _END value */
649 		for (i = 0; i < num_values + 1;) {
650 			if (spdk_json_write_val(w, &val[i + 1])) {
651 				return fail(w);
652 			}
653 			if (val[i + 1].type == SPDK_JSON_VAL_ARRAY_BEGIN ||
654 			    val[i + 1].type == SPDK_JSON_VAL_OBJECT_BEGIN) {
655 				i += val[i + 1].len + 2;
656 			} else {
657 				i++;
658 			}
659 		}
660 		return 0;
661 
662 	case SPDK_JSON_VAL_ARRAY_END:
663 		return spdk_json_write_array_end(w);
664 
665 	case SPDK_JSON_VAL_OBJECT_END:
666 		return spdk_json_write_object_end(w);
667 
668 	case SPDK_JSON_VAL_INVALID:
669 		/* Handle INVALID to make the compiler happy (and catch other unhandled types) */
670 		return fail(w);
671 	}
672 
673 	return fail(w);
674 }
675 
676 int
677 spdk_json_write_named_null(struct spdk_json_write_ctx *w, const char *name)
678 {
679 	int rc = spdk_json_write_name(w, name);
680 	return rc ? rc : spdk_json_write_null(w);
681 }
682 
683 int
684 spdk_json_write_named_bool(struct spdk_json_write_ctx *w, const char *name, bool val)
685 {
686 	int rc = spdk_json_write_name(w, name);
687 
688 	return rc ? rc : spdk_json_write_bool(w, val);
689 }
690 
691 int
692 spdk_json_write_named_uint8(struct spdk_json_write_ctx *w, const char *name, uint8_t val)
693 {
694 	int rc = spdk_json_write_name(w, name);
695 
696 	return rc ? rc : spdk_json_write_uint8(w, val);
697 }
698 
699 int
700 spdk_json_write_named_uint16(struct spdk_json_write_ctx *w, const char *name, uint16_t val)
701 {
702 	int rc = spdk_json_write_name(w, name);
703 
704 	return rc ? rc : spdk_json_write_uint16(w, val);
705 }
706 
707 int
708 spdk_json_write_named_int32(struct spdk_json_write_ctx *w, const char *name, int32_t val)
709 {
710 	int rc = spdk_json_write_name(w, name);
711 
712 	return rc ? rc : spdk_json_write_int32(w, val);
713 }
714 
715 int
716 spdk_json_write_named_uint32(struct spdk_json_write_ctx *w, const char *name, uint32_t val)
717 {
718 	int rc = spdk_json_write_name(w, name);
719 
720 	return rc ? rc : spdk_json_write_uint32(w, val);
721 }
722 
723 int
724 spdk_json_write_named_int64(struct spdk_json_write_ctx *w, const char *name, int64_t val)
725 {
726 	int rc = spdk_json_write_name(w, name);
727 
728 	return rc ? rc : spdk_json_write_int64(w, val);
729 }
730 
731 int
732 spdk_json_write_named_uint64(struct spdk_json_write_ctx *w, const char *name, uint64_t val)
733 {
734 	int rc = spdk_json_write_name(w, name);
735 
736 	return rc ? rc : spdk_json_write_uint64(w, val);
737 }
738 
739 int
740 spdk_json_write_named_double(struct spdk_json_write_ctx *w, const char *name, double val)
741 {
742 	int rc = spdk_json_write_name(w, name);
743 
744 	return rc ? rc : spdk_json_write_double(w, val);
745 }
746 
747 int
748 spdk_json_write_named_string(struct spdk_json_write_ctx *w, const char *name, const char *val)
749 {
750 	int rc = spdk_json_write_name(w, name);
751 
752 	return rc ? rc : spdk_json_write_string(w, val);
753 }
754 
755 int
756 spdk_json_write_named_string_fmt(struct spdk_json_write_ctx *w, const char *name,
757 				 const char *fmt, ...)
758 {
759 	va_list args;
760 	int rc;
761 
762 	va_start(args, fmt);
763 	rc = spdk_json_write_named_string_fmt_v(w, name, fmt, args);
764 	va_end(args);
765 
766 	return rc;
767 }
768 
769 int
770 spdk_json_write_named_string_fmt_v(struct spdk_json_write_ctx *w, const char *name,
771 				   const char *fmt, va_list args)
772 {
773 	char *s;
774 	int rc;
775 
776 	rc = spdk_json_write_name(w, name);
777 	if (rc) {
778 		return rc;
779 	}
780 
781 	s = spdk_vsprintf_alloc(fmt, args);
782 
783 	if (s == NULL) {
784 		return -1;
785 	}
786 
787 	rc = spdk_json_write_string(w, s);
788 	free(s);
789 	return rc;
790 }
791 
792 int
793 spdk_json_write_named_bytearray(struct spdk_json_write_ctx *w, const char *name, const void *val,
794 				size_t len)
795 {
796 	int rc = spdk_json_write_name(w, name);
797 
798 	return rc ? rc : spdk_json_write_bytearray(w, val, len);
799 }
800 
801 int
802 spdk_json_write_named_array_begin(struct spdk_json_write_ctx *w, const char *name)
803 {
804 	int rc = spdk_json_write_name(w, name);
805 
806 	return rc ? rc : spdk_json_write_array_begin(w);
807 }
808 
809 int
810 spdk_json_write_named_object_begin(struct spdk_json_write_ctx *w, const char *name)
811 {
812 	int rc = spdk_json_write_name(w, name);
813 
814 	return rc ? rc : spdk_json_write_object_begin(w);
815 }
816