]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c
MFC r337227: MFV r337223:
[FreeBSD/FreeBSD.git] / cddl / contrib / opensolaris / lib / libnvpair / nvpair_json.c
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 /*
12  * Copyright (c) 2014, Joyent, Inc.
13  * Copyright (c) 2017 by Delphix. All rights reserved.
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <strings.h>
19 #include <wchar.h>
20 #include <sys/debug.h>
21
22 #include "libnvpair.h"
23
24 #define FPRINTF(fp, ...)                                \
25         do {                                            \
26                 if (fprintf(fp, __VA_ARGS__) < 0)       \
27                         return (-1);                    \
28         } while (0)
29
30 /*
31  * When formatting a string for JSON output we must escape certain characters,
32  * as described in RFC4627.  This applies to both member names and
33  * DATA_TYPE_STRING values.
34  *
35  * This function will only operate correctly if the following conditions are
36  * met:
37  *
38  *       1. The input String is encoded in the current locale.
39  *
40  *       2. The current locale includes the Basic Multilingual Plane (plane 0)
41  *          as defined in the Unicode standard.
42  *
43  * The output will be entirely 7-bit ASCII (as a subset of UTF-8) with all
44  * representable Unicode characters included in their escaped numeric form.
45  */
46 static int
47 nvlist_print_json_string(FILE *fp, const char *input)
48 {
49         mbstate_t mbr;
50         wchar_t c;
51         size_t sz;
52
53         bzero(&mbr, sizeof (mbr));
54
55         FPRINTF(fp, "\"");
56         while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {
57                 switch (c) {
58                 case '"':
59                         FPRINTF(fp, "\\\"");
60                         break;
61                 case '\n':
62                         FPRINTF(fp, "\\n");
63                         break;
64                 case '\r':
65                         FPRINTF(fp, "\\r");
66                         break;
67                 case '\\':
68                         FPRINTF(fp, "\\\\");
69                         break;
70                 case '\f':
71                         FPRINTF(fp, "\\f");
72                         break;
73                 case '\t':
74                         FPRINTF(fp, "\\t");
75                         break;
76                 case '\b':
77                         FPRINTF(fp, "\\b");
78                         break;
79                 default:
80                         if ((c >= 0x00 && c <= 0x1f) ||
81                             (c > 0x7f && c <= 0xffff)) {
82                                 /*
83                                  * Render both Control Characters and Unicode
84                                  * characters in the Basic Multilingual Plane
85                                  * as JSON-escaped multibyte characters.
86                                  */
87                                 FPRINTF(fp, "\\u%04x", (int)(0xffff & c));
88                         } else if (c >= 0x20 && c <= 0x7f) {
89                                 /*
90                                  * Render other 7-bit ASCII characters directly
91                                  * and drop other, unrepresentable characters.
92                                  */
93                                 FPRINTF(fp, "%c", (int)(0xff & c));
94                         }
95                         break;
96                 }
97                 input += sz;
98         }
99
100         if (sz == (size_t)-1 || sz == (size_t)-2) {
101                 /*
102                  * We last read an invalid multibyte character sequence,
103                  * so return an error.
104                  */
105                 return (-1);
106         }
107
108         FPRINTF(fp, "\"");
109         return (0);
110 }
111
112 /*
113  * Dump a JSON-formatted representation of an nvlist to the provided FILE *.
114  * This routine does not output any new-lines or additional whitespace other
115  * than that contained in strings, nor does it call fflush(3C).
116  */
117 int
118 nvlist_print_json(FILE *fp, nvlist_t *nvl)
119 {
120         nvpair_t *curr;
121         boolean_t first = B_TRUE;
122
123         FPRINTF(fp, "{");
124
125         for (curr = nvlist_next_nvpair(nvl, NULL); curr;
126             curr = nvlist_next_nvpair(nvl, curr)) {
127                 data_type_t type = nvpair_type(curr);
128
129                 if (!first)
130                         FPRINTF(fp, ",");
131                 else
132                         first = B_FALSE;
133
134                 if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1)
135                         return (-1);
136                 FPRINTF(fp, ":");
137
138                 switch (type) {
139                 case DATA_TYPE_STRING: {
140                         char *string = fnvpair_value_string(curr);
141                         if (nvlist_print_json_string(fp, string) == -1)
142                                 return (-1);
143                         break;
144                 }
145
146                 case DATA_TYPE_BOOLEAN: {
147                         FPRINTF(fp, "true");
148                         break;
149                 }
150
151                 case DATA_TYPE_BOOLEAN_VALUE: {
152                         FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) ==
153                             B_TRUE ? "true" : "false");
154                         break;
155                 }
156
157                 case DATA_TYPE_BYTE: {
158                         FPRINTF(fp, "%hhu", fnvpair_value_byte(curr));
159                         break;
160                 }
161
162                 case DATA_TYPE_INT8: {
163                         FPRINTF(fp, "%hhd", fnvpair_value_int8(curr));
164                         break;
165                 }
166
167                 case DATA_TYPE_UINT8: {
168                         FPRINTF(fp, "%hhu", fnvpair_value_uint8_t(curr));
169                         break;
170                 }
171
172                 case DATA_TYPE_INT16: {
173                         FPRINTF(fp, "%hd", fnvpair_value_int16(curr));
174                         break;
175                 }
176
177                 case DATA_TYPE_UINT16: {
178                         FPRINTF(fp, "%hu", fnvpair_value_uint16(curr));
179                         break;
180                 }
181
182                 case DATA_TYPE_INT32: {
183                         FPRINTF(fp, "%d", fnvpair_value_int32(curr));
184                         break;
185                 }
186
187                 case DATA_TYPE_UINT32: {
188                         FPRINTF(fp, "%u", fnvpair_value_uint32(curr));
189                         break;
190                 }
191
192                 case DATA_TYPE_INT64: {
193                         FPRINTF(fp, "%lld",
194                             (long long)fnvpair_value_int64(curr));
195                         break;
196                 }
197
198                 case DATA_TYPE_UINT64: {
199                         FPRINTF(fp, "%llu",
200                             (unsigned long long)fnvpair_value_uint64(curr));
201                         break;
202                 }
203
204                 case DATA_TYPE_HRTIME: {
205                         hrtime_t val;
206                         VERIFY0(nvpair_value_hrtime(curr, &val));
207                         FPRINTF(fp, "%llu", (unsigned long long)val);
208                         break;
209                 }
210
211                 case DATA_TYPE_DOUBLE: {
212                         double val;
213                         VERIFY0(nvpair_value_double(curr, &val));
214                         FPRINTF(fp, "%f", val);
215                         break;
216                 }
217
218                 case DATA_TYPE_NVLIST: {
219                         if (nvlist_print_json(fp,
220                             fnvpair_value_nvlist(curr)) == -1)
221                                 return (-1);
222                         break;
223                 }
224
225                 case DATA_TYPE_STRING_ARRAY: {
226                         char **val;
227                         uint_t valsz, i;
228                         VERIFY0(nvpair_value_string_array(curr, &val, &valsz));
229                         FPRINTF(fp, "[");
230                         for (i = 0; i < valsz; i++) {
231                                 if (i > 0)
232                                         FPRINTF(fp, ",");
233                                 if (nvlist_print_json_string(fp, val[i]) == -1)
234                                         return (-1);
235                         }
236                         FPRINTF(fp, "]");
237                         break;
238                 }
239
240                 case DATA_TYPE_NVLIST_ARRAY: {
241                         nvlist_t **val;
242                         uint_t valsz, i;
243                         VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz));
244                         FPRINTF(fp, "[");
245                         for (i = 0; i < valsz; i++) {
246                                 if (i > 0)
247                                         FPRINTF(fp, ",");
248                                 if (nvlist_print_json(fp, val[i]) == -1)
249                                         return (-1);
250                         }
251                         FPRINTF(fp, "]");
252                         break;
253                 }
254
255                 case DATA_TYPE_BOOLEAN_ARRAY: {
256                         boolean_t *val;
257                         uint_t valsz, i;
258                         VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz));
259                         FPRINTF(fp, "[");
260                         for (i = 0; i < valsz; i++) {
261                                 if (i > 0)
262                                         FPRINTF(fp, ",");
263                                 FPRINTF(fp, val[i] == B_TRUE ?
264                                     "true" : "false");
265                         }
266                         FPRINTF(fp, "]");
267                         break;
268                 }
269
270                 case DATA_TYPE_BYTE_ARRAY: {
271                         uchar_t *val;
272                         uint_t valsz, i;
273                         VERIFY0(nvpair_value_byte_array(curr, &val, &valsz));
274                         FPRINTF(fp, "[");
275                         for (i = 0; i < valsz; i++) {
276                                 if (i > 0)
277                                         FPRINTF(fp, ",");
278                                 FPRINTF(fp, "%hhu", val[i]);
279                         }
280                         FPRINTF(fp, "]");
281                         break;
282                 }
283
284                 case DATA_TYPE_UINT8_ARRAY: {
285                         uint8_t *val;
286                         uint_t valsz, i;
287                         VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz));
288                         FPRINTF(fp, "[");
289                         for (i = 0; i < valsz; i++) {
290                                 if (i > 0)
291                                         FPRINTF(fp, ",");
292                                 FPRINTF(fp, "%hhu", val[i]);
293                         }
294                         FPRINTF(fp, "]");
295                         break;
296                 }
297
298                 case DATA_TYPE_INT8_ARRAY: {
299                         int8_t *val;
300                         uint_t valsz, i;
301                         VERIFY0(nvpair_value_int8_array(curr, &val, &valsz));
302                         FPRINTF(fp, "[");
303                         for (i = 0; i < valsz; i++) {
304                                 if (i > 0)
305                                         FPRINTF(fp, ",");
306                                 FPRINTF(fp, "%hhd", val[i]);
307                         }
308                         FPRINTF(fp, "]");
309                         break;
310                 }
311
312                 case DATA_TYPE_UINT16_ARRAY: {
313                         uint16_t *val;
314                         uint_t valsz, i;
315                         VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz));
316                         FPRINTF(fp, "[");
317                         for (i = 0; i < valsz; i++) {
318                                 if (i > 0)
319                                         FPRINTF(fp, ",");
320                                 FPRINTF(fp, "%hu", val[i]);
321                         }
322                         FPRINTF(fp, "]");
323                         break;
324                 }
325
326                 case DATA_TYPE_INT16_ARRAY: {
327                         int16_t *val;
328                         uint_t valsz, i;
329                         VERIFY0(nvpair_value_int16_array(curr, &val, &valsz));
330                         FPRINTF(fp, "[");
331                         for (i = 0; i < valsz; i++) {
332                                 if (i > 0)
333                                         FPRINTF(fp, ",");
334                                 FPRINTF(fp, "%hd", val[i]);
335                         }
336                         FPRINTF(fp, "]");
337                         break;
338                 }
339
340                 case DATA_TYPE_UINT32_ARRAY: {
341                         uint32_t *val;
342                         uint_t valsz, i;
343                         VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz));
344                         FPRINTF(fp, "[");
345                         for (i = 0; i < valsz; i++) {
346                                 if (i > 0)
347                                         FPRINTF(fp, ",");
348                                 FPRINTF(fp, "%u", val[i]);
349                         }
350                         FPRINTF(fp, "]");
351                         break;
352                 }
353
354                 case DATA_TYPE_INT32_ARRAY: {
355                         int32_t *val;
356                         uint_t valsz, i;
357                         VERIFY0(nvpair_value_int32_array(curr, &val, &valsz));
358                         FPRINTF(fp, "[");
359                         for (i = 0; i < valsz; i++) {
360                                 if (i > 0)
361                                         FPRINTF(fp, ",");
362                                 FPRINTF(fp, "%d", val[i]);
363                         }
364                         FPRINTF(fp, "]");
365                         break;
366                 }
367
368                 case DATA_TYPE_UINT64_ARRAY: {
369                         uint64_t *val;
370                         uint_t valsz, i;
371                         VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz));
372                         FPRINTF(fp, "[");
373                         for (i = 0; i < valsz; i++) {
374                                 if (i > 0)
375                                         FPRINTF(fp, ",");
376                                 FPRINTF(fp, "%llu",
377                                     (unsigned long long)val[i]);
378                         }
379                         FPRINTF(fp, "]");
380                         break;
381                 }
382
383                 case DATA_TYPE_INT64_ARRAY: {
384                         int64_t *val;
385                         uint_t valsz, i;
386                         VERIFY0(nvpair_value_int64_array(curr, &val, &valsz));
387                         FPRINTF(fp, "[");
388                         for (i = 0; i < valsz; i++) {
389                                 if (i > 0)
390                                         FPRINTF(fp, ",");
391                                 FPRINTF(fp, "%lld", (long long)val[i]);
392                         }
393                         FPRINTF(fp, "]");
394                         break;
395                 }
396
397                 case DATA_TYPE_UNKNOWN:
398                 case DATA_TYPE_DONTCARE:
399                         return (-1);
400                 }
401
402         }
403
404         FPRINTF(fp, "}");
405         return (0);
406 }