4 * Copyright IBM, Corp. 2009
5 * Copyright (c) 2010-2020 Red Hat Inc.
8 * Anthony Liguori <aliguori@us.ibm.com>
9 * Markus Armbruster <armbru@redhat.com>
11 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
12 * See the COPYING.LIB file in the top-level directory.
16 #include "qemu/osdep.h"
17 #include "qapi/qmp/json-writer.h"
18 #include "qemu/unicode.h"
24 GByteArray
*container_is_array
;
27 JSONWriter
*json_writer_new(bool pretty
)
29 JSONWriter
*writer
= g_new(JSONWriter
, 1);
31 writer
->pretty
= pretty
;
32 writer
->need_comma
= false;
33 writer
->contents
= g_string_new(NULL
);
34 writer
->container_is_array
= g_byte_array_new();
38 const char *json_writer_get(JSONWriter
*writer
)
40 g_assert(!writer
->container_is_array
->len
);
41 return writer
->contents
->str
;
44 GString
*json_writer_get_and_free(JSONWriter
*writer
)
46 GString
*contents
= writer
->contents
;
48 writer
->contents
= NULL
;
49 g_byte_array_free(writer
->container_is_array
, true);
54 void json_writer_free(JSONWriter
*writer
)
57 g_string_free(json_writer_get_and_free(writer
), true);
61 static void enter_container(JSONWriter
*writer
, bool is_array
)
63 unsigned depth
= writer
->container_is_array
->len
;
65 g_byte_array_set_size(writer
->container_is_array
, depth
+ 1);
66 writer
->container_is_array
->data
[depth
] = is_array
;
67 writer
->need_comma
= false;
70 static void leave_container(JSONWriter
*writer
, bool is_array
)
72 unsigned depth
= writer
->container_is_array
->len
;
75 assert(writer
->container_is_array
->data
[depth
- 1] == is_array
);
76 g_byte_array_set_size(writer
->container_is_array
, depth
- 1);
77 writer
->need_comma
= true;
80 static bool in_object(JSONWriter
*writer
)
82 unsigned depth
= writer
->container_is_array
->len
;
84 return depth
&& !writer
->container_is_array
->data
[depth
- 1];
87 static void pretty_newline(JSONWriter
*writer
)
90 g_string_append_printf(writer
->contents
, "\n%*s",
91 writer
->container_is_array
->len
* 4, "");
95 static void pretty_newline_or_space(JSONWriter
*writer
)
98 g_string_append_printf(writer
->contents
, "\n%*s",
99 writer
->container_is_array
->len
* 4, "");
101 g_string_append_c(writer
->contents
, ' ');
105 static void quoted_str(JSONWriter
*writer
, const char *str
)
111 g_string_append_c(writer
->contents
, '"');
113 for (ptr
= str
; *ptr
; ptr
= end
) {
114 cp
= mod_utf8_codepoint(ptr
, 6, &end
);
117 g_string_append(writer
->contents
, "\\\"");
120 g_string_append(writer
->contents
, "\\\\");
123 g_string_append(writer
->contents
, "\\b");
126 g_string_append(writer
->contents
, "\\f");
129 g_string_append(writer
->contents
, "\\n");
132 g_string_append(writer
->contents
, "\\r");
135 g_string_append(writer
->contents
, "\\t");
139 cp
= 0xFFFD; /* replacement character */
142 /* beyond BMP; need a surrogate pair */
143 g_string_append_printf(writer
->contents
, "\\u%04X\\u%04X",
144 0xD800 + ((cp
- 0x10000) >> 10),
145 0xDC00 + ((cp
- 0x10000) & 0x3FF));
146 } else if (cp
< 0x20 || cp
>= 0x7F) {
147 g_string_append_printf(writer
->contents
, "\\u%04X", cp
);
149 g_string_append_c(writer
->contents
, cp
);
154 g_string_append_c(writer
->contents
, '"');
157 static void maybe_comma_name(JSONWriter
*writer
, const char *name
)
159 if (writer
->need_comma
) {
160 g_string_append_c(writer
->contents
, ',');
161 pretty_newline_or_space(writer
);
163 if (writer
->contents
->len
) {
164 pretty_newline(writer
);
166 writer
->need_comma
= true;
169 if (in_object(writer
)) {
170 quoted_str(writer
, name
);
171 g_string_append(writer
->contents
, ": ");
175 void json_writer_start_object(JSONWriter
*writer
, const char *name
)
177 maybe_comma_name(writer
, name
);
178 g_string_append_c(writer
->contents
, '{');
179 enter_container(writer
, false);
182 void json_writer_end_object(JSONWriter
*writer
)
184 leave_container(writer
, false);
185 pretty_newline(writer
);
186 g_string_append_c(writer
->contents
, '}');
189 void json_writer_start_array(JSONWriter
*writer
, const char *name
)
191 maybe_comma_name(writer
, name
);
192 g_string_append_c(writer
->contents
, '[');
193 enter_container(writer
, true);
196 void json_writer_end_array(JSONWriter
*writer
)
198 leave_container(writer
, true);
199 pretty_newline(writer
);
200 g_string_append_c(writer
->contents
, ']');
203 void json_writer_bool(JSONWriter
*writer
, const char *name
, bool val
)
205 maybe_comma_name(writer
, name
);
206 g_string_append(writer
->contents
, val
? "true" : "false");
209 void json_writer_null(JSONWriter
*writer
, const char *name
)
211 maybe_comma_name(writer
, name
);
212 g_string_append(writer
->contents
, "null");
215 void json_writer_int64(JSONWriter
*writer
, const char *name
, int64_t val
)
217 maybe_comma_name(writer
, name
);
218 g_string_append_printf(writer
->contents
, "%" PRId64
, val
);
221 void json_writer_uint64(JSONWriter
*writer
, const char *name
, uint64_t val
)
223 maybe_comma_name(writer
, name
);
224 g_string_append_printf(writer
->contents
, "%" PRIu64
, val
);
227 void json_writer_double(JSONWriter
*writer
, const char *name
, double val
)
229 maybe_comma_name(writer
, name
);
232 * FIXME: g_string_append_printf() is locale dependent; but JSON
233 * requires numbers to be formatted as if in the C locale.
234 * Dependence on C locale is a pervasive issue in QEMU.
237 * FIXME: This risks printing Inf or NaN, which are not valid
240 g_string_append_printf(writer
->contents
, "%.17g", val
);
243 void json_writer_str(JSONWriter
*writer
, const char *name
, const char *str
)
245 maybe_comma_name(writer
, name
);
246 quoted_str(writer
, str
);