xref: /spdk/lib/json/json_write.c (revision 488570ebd418ba07c9e69e65106dcc964f3bb41b)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 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 static void
313 write_hex_2(void *dest, uint8_t val)
314 {
315 	char *p = dest;
316 	char hex[] = "0123456789ABCDEF";
317 
318 	p[0] = hex[val >> 4];
319 	p[1] = hex[val & 0xf];
320 }
321 
322 static void
323 write_hex_4(void *dest, uint16_t val)
324 {
325 	write_hex_2(dest, (uint8_t)(val >> 8));
326 	write_hex_2((char *)dest + 2, (uint8_t)(val & 0xff));
327 }
328 
329 static inline int
330 write_codepoint(struct spdk_json_write_ctx *w, uint32_t codepoint)
331 {
332 	static const uint8_t escapes[] = {
333 		['\b'] = 'b',
334 		['\f'] = 'f',
335 		['\n'] = 'n',
336 		['\r'] = 'r',
337 		['\t'] = 't',
338 		['"'] = '"',
339 		['\\'] = '\\',
340 		/*
341 		 * Forward slash (/) is intentionally not converted to an escape
342 		 *  (it is valid unescaped).
343 		 */
344 	};
345 	uint16_t high, low;
346 	char out[13];
347 	size_t out_len;
348 
349 	if (codepoint < sizeof(escapes) && escapes[codepoint]) {
350 		out[0] = '\\';
351 		out[1] = escapes[codepoint];
352 		out_len = 2;
353 	} else if (codepoint >= 0x20 && codepoint < 0x7F) {
354 		/*
355 		 * Encode plain ASCII directly (except 0x7F, since it is really
356 		 *  a control character, despite the JSON spec not considering it one).
357 		 */
358 		out[0] = (uint8_t)codepoint;
359 		out_len = 1;
360 	} else if (codepoint < 0x10000) {
361 		out[0] = '\\';
362 		out[1] = 'u';
363 		write_hex_4(&out[2], (uint16_t)codepoint);
364 		out_len = 6;
365 	} else {
366 		utf16_encode_surrogate_pair(codepoint, &high, &low);
367 		out[0] = '\\';
368 		out[1] = 'u';
369 		write_hex_4(&out[2], high);
370 		out[6] = '\\';
371 		out[7] = 'u';
372 		write_hex_4(&out[8], low);
373 		out_len = 12;
374 	}
375 
376 	return emit(w, out, out_len);
377 }
378 
379 static int
380 write_string_or_name(struct spdk_json_write_ctx *w, const char *val, size_t len)
381 {
382 	const uint8_t *p = val;
383 	const uint8_t *end = val + len;
384 
385 	if (emit(w, "\"", 1)) { return fail(w); }
386 
387 	while (p != end) {
388 		int codepoint_len;
389 		uint32_t codepoint;
390 
391 		codepoint_len = utf8_valid(p, end);
392 		switch (codepoint_len) {
393 		case 1:
394 			codepoint = utf8_decode_unsafe_1(p);
395 			break;
396 		case 2:
397 			codepoint = utf8_decode_unsafe_2(p);
398 			break;
399 		case 3:
400 			codepoint = utf8_decode_unsafe_3(p);
401 			break;
402 		case 4:
403 			codepoint = utf8_decode_unsafe_4(p);
404 			break;
405 		default:
406 			return fail(w);
407 		}
408 
409 		if (write_codepoint(w, codepoint)) { return fail(w); }
410 		p += codepoint_len;
411 	}
412 
413 	return emit(w, "\"", 1);
414 }
415 
416 static int
417 write_string_or_name_utf16le(struct spdk_json_write_ctx *w, const uint16_t *val, size_t len)
418 {
419 	const uint16_t *p = val;
420 	const uint16_t *end = val + len;
421 
422 	if (emit(w, "\"", 1)) { return fail(w); }
423 
424 	while (p != end) {
425 		int codepoint_len;
426 		uint32_t codepoint;
427 
428 		codepoint_len = utf16le_valid(p, end);
429 		switch (codepoint_len) {
430 		case 1:
431 			codepoint = from_le16(&p[0]);
432 			break;
433 		case 2:
434 			codepoint = utf16_decode_surrogate_pair(from_le16(&p[0]), from_le16(&p[1]));
435 			break;
436 		default:
437 			return fail(w);
438 		}
439 
440 		if (write_codepoint(w, codepoint)) { return fail(w); }
441 		p += codepoint_len;
442 	}
443 
444 	return emit(w, "\"", 1);
445 }
446 
447 int
448 spdk_json_write_string_raw(struct spdk_json_write_ctx *w, const char *val, size_t len)
449 {
450 	if (begin_value(w)) { return fail(w); }
451 	return write_string_or_name(w, val, len);
452 }
453 
454 int
455 spdk_json_write_string(struct spdk_json_write_ctx *w, const char *val)
456 {
457 	return spdk_json_write_string_raw(w, val, strlen(val));
458 }
459 
460 int
461 spdk_json_write_string_utf16le_raw(struct spdk_json_write_ctx *w, const uint16_t *val, size_t len)
462 {
463 	if (begin_value(w)) { return fail(w); }
464 	return write_string_or_name_utf16le(w, val, len);
465 }
466 
467 int
468 spdk_json_write_string_utf16le(struct spdk_json_write_ctx *w, const uint16_t *val)
469 {
470 	const uint16_t *p;
471 	size_t len;
472 
473 	for (len = 0, p = val; *p; p++) {
474 		len++;
475 	}
476 
477 	return spdk_json_write_string_utf16le_raw(w, val, len);
478 }
479 
480 int
481 spdk_json_write_string_fmt(struct spdk_json_write_ctx *w, const char *fmt, ...)
482 {
483 	va_list args;
484 	int rc;
485 
486 	va_start(args, fmt);
487 	rc = spdk_json_write_string_fmt_v(w, fmt, args);
488 	va_end(args);
489 
490 	return rc;
491 }
492 
493 int
494 spdk_json_write_string_fmt_v(struct spdk_json_write_ctx *w, const char *fmt, va_list args)
495 {
496 	char *s;
497 	int rc;
498 
499 	s = spdk_vsprintf_alloc(fmt, args);
500 	if (s == NULL) {
501 		return -1;
502 	}
503 
504 	rc = spdk_json_write_string(w, s);
505 	free(s);
506 	return rc;
507 }
508 
509 int
510 spdk_json_write_bytearray(struct spdk_json_write_ctx *w, const void *val, size_t len)
511 {
512 	const uint8_t *v = val;
513 	size_t i;
514 	char *s;
515 	int rc;
516 
517 	s = malloc(2 * len + 1);
518 	if (s == NULL) {
519 		return -1;
520 	}
521 
522 	for (i = 0; i < len; ++i) {
523 		write_hex_2(&s[2 * i], *v++);
524 	}
525 	s[2 * len] = '\0';
526 
527 	rc = spdk_json_write_string(w, s);
528 	free(s);
529 	return rc;
530 }
531 
532 int
533 spdk_json_write_array_begin(struct spdk_json_write_ctx *w)
534 {
535 	if (begin_value(w)) { return fail(w); }
536 	w->first_value = true;
537 	w->new_indent = true;
538 	w->indent++;
539 	if (emit(w, "[", 1)) { return fail(w); }
540 	return 0;
541 }
542 
543 int
544 spdk_json_write_array_end(struct spdk_json_write_ctx *w)
545 {
546 	w->first_value = false;
547 	if (w->indent == 0) { return fail(w); }
548 	w->indent--;
549 	if (!w->new_indent) {
550 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
551 		if (emit_indent(w)) { return fail(w); }
552 	}
553 	w->new_indent = false;
554 	return emit(w, "]", 1);
555 }
556 
557 int
558 spdk_json_write_object_begin(struct spdk_json_write_ctx *w)
559 {
560 	if (begin_value(w)) { return fail(w); }
561 	w->first_value = true;
562 	w->new_indent = true;
563 	w->indent++;
564 	if (emit(w, "{", 1)) { return fail(w); }
565 	return 0;
566 }
567 
568 int
569 spdk_json_write_object_end(struct spdk_json_write_ctx *w)
570 {
571 	w->first_value = false;
572 	w->indent--;
573 	if (!w->new_indent) {
574 		if (emit_fmt(w, "\n", 1)) { return fail(w); }
575 		if (emit_indent(w)) { return fail(w); }
576 	}
577 	w->new_indent = false;
578 	return emit(w, "}", 1);
579 }
580 
581 int
582 spdk_json_write_name_raw(struct spdk_json_write_ctx *w, const char *name, size_t len)
583 {
584 	/* TODO: check that container is an object */
585 	if (begin_value(w)) { return fail(w); }
586 	if (write_string_or_name(w, name, len)) { return fail(w); }
587 	w->first_value = true;
588 	if (emit(w, ":", 1)) { return fail(w); }
589 	return emit_fmt(w, " ", 1);
590 }
591 
592 int
593 spdk_json_write_name(struct spdk_json_write_ctx *w, const char *name)
594 {
595 	return spdk_json_write_name_raw(w, name, strlen(name));
596 }
597 
598 int
599 spdk_json_write_val(struct spdk_json_write_ctx *w, const struct spdk_json_val *val)
600 {
601 	size_t num_values, i;
602 
603 	switch (val->type) {
604 	case SPDK_JSON_VAL_NUMBER:
605 		return spdk_json_write_val_raw(w, val->start, val->len);
606 
607 	case SPDK_JSON_VAL_STRING:
608 		return spdk_json_write_string_raw(w, val->start, val->len);
609 
610 	case SPDK_JSON_VAL_NAME:
611 		return spdk_json_write_name_raw(w, val->start, val->len);
612 
613 	case SPDK_JSON_VAL_TRUE:
614 		return spdk_json_write_bool(w, true);
615 
616 	case SPDK_JSON_VAL_FALSE:
617 		return spdk_json_write_bool(w, false);
618 
619 	case SPDK_JSON_VAL_NULL:
620 		return spdk_json_write_null(w);
621 
622 	case SPDK_JSON_VAL_ARRAY_BEGIN:
623 	case SPDK_JSON_VAL_OBJECT_BEGIN:
624 		num_values = val[0].len;
625 
626 		if (val[0].type == SPDK_JSON_VAL_OBJECT_BEGIN) {
627 			if (spdk_json_write_object_begin(w)) {
628 				return fail(w);
629 			}
630 		} else {
631 			if (spdk_json_write_array_begin(w)) {
632 				return fail(w);
633 			}
634 		}
635 
636 		/* Loop up to and including the _END value */
637 		for (i = 0; i < num_values + 1;) {
638 			if (spdk_json_write_val(w, &val[i + 1])) {
639 				return fail(w);
640 			}
641 			if (val[i + 1].type == SPDK_JSON_VAL_ARRAY_BEGIN ||
642 			    val[i + 1].type == SPDK_JSON_VAL_OBJECT_BEGIN) {
643 				i += val[i + 1].len + 2;
644 			} else {
645 				i++;
646 			}
647 		}
648 		return 0;
649 
650 	case SPDK_JSON_VAL_ARRAY_END:
651 		return spdk_json_write_array_end(w);
652 
653 	case SPDK_JSON_VAL_OBJECT_END:
654 		return spdk_json_write_object_end(w);
655 
656 	case SPDK_JSON_VAL_INVALID:
657 		/* Handle INVALID to make the compiler happy (and catch other unhandled types) */
658 		return fail(w);
659 	}
660 
661 	return fail(w);
662 }
663 
664 int spdk_json_write_named_null(struct spdk_json_write_ctx *w, const char *name)
665 {
666 	int rc = spdk_json_write_name(w, name);
667 	return rc ? rc : spdk_json_write_null(w);
668 }
669 
670 int spdk_json_write_named_bool(struct spdk_json_write_ctx *w, const char *name, bool val)
671 {
672 	int rc = spdk_json_write_name(w, name);
673 
674 	return rc ? rc : spdk_json_write_bool(w, val);
675 }
676 
677 int spdk_json_write_named_uint8(struct spdk_json_write_ctx *w, const char *name, uint8_t val)
678 {
679 	int rc = spdk_json_write_name(w, name);
680 
681 	return rc ? rc : spdk_json_write_uint8(w, val);
682 }
683 
684 int spdk_json_write_named_uint16(struct spdk_json_write_ctx *w, const char *name, uint16_t val)
685 {
686 	int rc = spdk_json_write_name(w, name);
687 
688 	return rc ? rc : spdk_json_write_uint16(w, val);
689 }
690 
691 int spdk_json_write_named_int32(struct spdk_json_write_ctx *w, const char *name, int32_t val)
692 {
693 	int rc = spdk_json_write_name(w, name);
694 
695 	return rc ? rc : spdk_json_write_int32(w, val);
696 }
697 
698 int spdk_json_write_named_uint32(struct spdk_json_write_ctx *w, const char *name, uint32_t val)
699 {
700 	int rc = spdk_json_write_name(w, name);
701 
702 	return rc ? rc : spdk_json_write_uint32(w, val);
703 }
704 
705 int spdk_json_write_named_int64(struct spdk_json_write_ctx *w, const char *name, int64_t val)
706 {
707 	int rc = spdk_json_write_name(w, name);
708 
709 	return rc ? rc : spdk_json_write_int64(w, val);
710 }
711 
712 int spdk_json_write_named_uint64(struct spdk_json_write_ctx *w, const char *name, uint64_t val)
713 {
714 	int rc = spdk_json_write_name(w, name);
715 
716 	return rc ? rc : spdk_json_write_uint64(w, val);
717 }
718 
719 int spdk_json_write_named_string(struct spdk_json_write_ctx *w, const char *name, const char *val)
720 {
721 	int rc = spdk_json_write_name(w, name);
722 
723 	return rc ? rc : spdk_json_write_string(w, val);
724 }
725 
726 int spdk_json_write_named_string_fmt(struct spdk_json_write_ctx *w, const char *name,
727 				     const char *fmt, ...)
728 {
729 	va_list args;
730 	int rc;
731 
732 	va_start(args, fmt);
733 	rc = spdk_json_write_named_string_fmt_v(w, name, fmt, args);
734 	va_end(args);
735 
736 	return rc;
737 }
738 
739 int spdk_json_write_named_string_fmt_v(struct spdk_json_write_ctx *w, const char *name,
740 				       const char *fmt, va_list args)
741 {
742 	char *s;
743 	int rc;
744 
745 	rc = spdk_json_write_name(w, name);
746 	if (rc) {
747 		return rc;
748 	}
749 
750 	s = spdk_vsprintf_alloc(fmt, args);
751 
752 	if (s == NULL) {
753 		return -1;
754 	}
755 
756 	rc = spdk_json_write_string(w, s);
757 	free(s);
758 	return rc;
759 }
760 
761 int
762 spdk_json_write_named_bytearray(struct spdk_json_write_ctx *w, const char *name, const void *val,
763 				size_t len)
764 {
765 	int rc = spdk_json_write_name(w, name);
766 
767 	return rc ? rc : spdk_json_write_bytearray(w, val, len);
768 }
769 
770 int spdk_json_write_named_array_begin(struct spdk_json_write_ctx *w, const char *name)
771 {
772 	int rc = spdk_json_write_name(w, name);
773 
774 	return rc ? rc : spdk_json_write_array_begin(w);
775 }
776 
777 int spdk_json_write_named_object_begin(struct spdk_json_write_ctx *w, const char *name)
778 {
779 	int rc = spdk_json_write_name(w, name);
780 
781 	return rc ? rc : spdk_json_write_object_begin(w);
782 }
783