2 * JSON parsing functions.
4 * Copyright 2016, Dario Lombardo
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
20 #include <wsutil/jsmn.h>
21 #include <wsutil/str_util.h>
22 #include <wsutil/unicode-utils.h>
23 #include <wsutil/wslog.h>
26 json_validate(const uint8_t *buf
, const size_t len
)
29 /* We expect no more than 1024 tokens */
30 unsigned max_tokens
= 1024;
36 * Make sure the buffer isn't empty and the first octet isn't a NUL;
37 * otherwise, the parser will immediately stop parsing and not validate
38 * anything after that, so it'll just think it was handed an empty string.
40 * XXX - should we check for NULs anywhere in the buffer?
43 ws_debug("JSON string is empty");
47 ws_debug("invalid character inside JSON string");
51 t
= g_new0(jsmntok_t
, max_tokens
);
57 rcode
= jsmn_parse(&p
, buf
, len
, t
, max_tokens
);
60 case JSMN_ERROR_NOMEM
:
61 ws_debug("not enough tokens were provided");
63 case JSMN_ERROR_INVAL
:
64 ws_debug("invalid character inside JSON string");
67 ws_debug("the string is not a full JSON packet, "
68 "more bytes expected");
71 ws_debug("unexpected error");
82 json_parse(const char *buf
, jsmntok_t
*tokens
, unsigned int max_tokens
)
87 return jsmn_parse(&p
, buf
, strlen(buf
), tokens
, max_tokens
);
91 jsmntok_t
*json_get_next_object(jsmntok_t
*cur
)
94 jsmntok_t
*next
= cur
+1;
96 for (i
= 0; i
< cur
->size
; i
++) {
97 next
= json_get_next_object(next
);
102 jsmntok_t
*json_get_object(const char *buf
, jsmntok_t
*parent
, const char *name
)
105 jsmntok_t
*cur
= parent
+1;
107 for (i
= 0; i
< parent
->size
; i
++) {
108 if (cur
->type
== JSMN_STRING
&&
109 !strncmp(&buf
[cur
->start
], name
, cur
->end
- cur
->start
)
110 && strlen(name
) == (size_t)(cur
->end
- cur
->start
) &&
111 cur
->size
== 1 && (cur
+1)->type
== JSMN_OBJECT
) {
114 cur
= json_get_next_object(cur
);
119 jsmntok_t
*json_get_array(const char *buf
, jsmntok_t
*parent
, const char *name
)
122 jsmntok_t
*cur
= parent
+1;
124 for (i
= 0; i
< parent
->size
; i
++) {
125 if (cur
->type
== JSMN_STRING
&&
126 !strncmp(&buf
[cur
->start
], name
, cur
->end
- cur
->start
)
127 && strlen(name
) == (size_t)(cur
->end
- cur
->start
) &&
128 cur
->size
== 1 && (cur
+1)->type
== JSMN_ARRAY
) {
131 cur
= json_get_next_object(cur
);
136 int json_get_array_len(jsmntok_t
*array
)
138 if (array
->type
!= JSMN_ARRAY
)
143 jsmntok_t
*json_get_array_index(jsmntok_t
*array
, int idx
)
146 jsmntok_t
*cur
= array
+1;
149 if (array
->type
!= JSMN_ARRAY
|| idx
< 0 || idx
>= array
->size
)
151 for (i
= 0; i
< idx
; i
++)
152 cur
= json_get_next_object(cur
);
156 char *json_get_string(char *buf
, jsmntok_t
*parent
, const char *name
)
159 jsmntok_t
*cur
= parent
+1;
161 for (i
= 0; i
< parent
->size
; i
++) {
162 if (cur
->type
== JSMN_STRING
&&
163 !strncmp(&buf
[cur
->start
], name
, cur
->end
- cur
->start
)
164 && strlen(name
) == (size_t)(cur
->end
- cur
->start
) &&
165 cur
->size
== 1 && (cur
+1)->type
== JSMN_STRING
) {
166 buf
[(cur
+1)->end
] = '\0';
167 if (!json_decode_string_inplace(&buf
[(cur
+1)->start
]))
169 return &buf
[(cur
+1)->start
];
171 cur
= json_get_next_object(cur
);
176 bool json_get_double(char *buf
, jsmntok_t
*parent
, const char *name
, double *val
)
179 jsmntok_t
*cur
= parent
+1;
181 for (i
= 0; i
< parent
->size
; i
++) {
182 if (cur
->type
== JSMN_STRING
&&
183 !strncmp(&buf
[cur
->start
], name
, cur
->end
- cur
->start
)
184 && strlen(name
) == (size_t)(cur
->end
- cur
->start
) &&
185 cur
->size
== 1 && (cur
+1)->type
== JSMN_PRIMITIVE
) {
186 buf
[(cur
+1)->end
] = '\0';
187 *val
= g_ascii_strtod(&buf
[(cur
+1)->start
], NULL
);
192 cur
= json_get_next_object(cur
);
197 bool json_get_boolean(char *buf
, jsmntok_t
*parent
, const char *name
, bool *val
)
201 jsmntok_t
*cur
= parent
+1;
203 for (i
= 0; i
< parent
->size
; i
++) {
204 if (cur
->type
== JSMN_STRING
&&
205 !strncmp(&buf
[cur
->start
], name
, cur
->end
- cur
->start
)
206 && strlen(name
) == (size_t)(cur
->end
- cur
->start
) &&
207 cur
->size
== 1 && (cur
+1)->type
== JSMN_PRIMITIVE
) {
208 /* JSMN_STRICT guarantees that a primitive starts with the
211 tok_len
= (cur
+1)->end
- (cur
+1)->start
;
212 switch (buf
[(cur
+1)->start
]) {
214 if (tok_len
== 4 && strncmp(&buf
[(cur
+1)->start
], "true", tok_len
) == 0) {
220 if (tok_len
== 5 && strncmp(&buf
[(cur
+1)->start
], "false", tok_len
) == 0) {
229 cur
= json_get_next_object(cur
);
235 json_decode_string_inplace(char *text
)
237 const char *input
= text
;
270 uint32_t unicode_hex
= 0;
274 for (k
= 0; k
< 4; k
++) {
284 if ((IS_LEAD_SURROGATE(unicode_hex
))) {
285 uint16_t lead_surrogate
= unicode_hex
;
286 uint16_t trail_surrogate
= 0;
288 if (input
[0] != '\\' || input
[1] != 'u')
292 for (k
= 0; k
< 4; k
++) {
293 trail_surrogate
<<= 4;
299 trail_surrogate
|= bin
;
302 if ((!IS_TRAIL_SURROGATE(trail_surrogate
)))
305 unicode_hex
= SURROGATE_VALUE(lead_surrogate
,trail_surrogate
);
307 } else if ((IS_TRAIL_SURROGATE(unicode_hex
))) {
311 if (!g_unichar_validate(unicode_hex
))
314 /* Don't allow NUL byte injection. */
315 if (unicode_hex
== 0)
318 /* \uXXXX => 6 bytes, and g_unichar_to_utf8() requires to have output buffer at least 6 bytes -> OK. */
319 k
= g_unichar_to_utf8(unicode_hex
, output
);
339 * Editor modelines - https://www.wireshark.org/tools/modelines.html
344 * indent-tabs-mode: nil
347 * vi: set shiftwidth=4 tabstop=8 expandtab:
348 * :indentSize=4:tabSize=8:noTabs=true: