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