fix one too small
[RRG-proxmark3.git] / client / src / jansson_path.c
blob1f21cb3431cd21dcdb3a21d57d4ebe1e65249af8
1 //-----------------------------------------------------------------------------
2 // Borrowed initially from
3 // https://github.com/rogerz/jansson/blob/json_path/src/path.c
4 // Copyright (c) 2012 Rogerz Zhang <rogerz.zhang@gmail.com>
5 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // See LICENSE.txt for the text of the license.
18 //-----------------------------------------------------------------------------
20 #include <string.h>
21 #include <assert.h>
23 #include "jansson.h"
24 #include "jansson_path.h"
26 ////// memory.c private functions
28 /* C89 allows these to be macros */
29 #undef malloc
30 #undef free
32 /* memory function pointers */
33 static json_malloc_t do_malloc = malloc;
34 static json_free_t do_free = free;
36 static void *jsonp_malloc(size_t size) {
37 if (!size)
38 return NULL;
40 return (*do_malloc)(size);
43 static void jsonp_free(void *ptr) {
44 if (!ptr)
45 return;
47 (*do_free)(ptr);
50 static char *jsonp_strndup(const char *str, size_t len) {
51 char *new_str = jsonp_malloc(len + 1);
52 if (!new_str)
53 return NULL;
55 memcpy(new_str, str, len);
56 new_str[len] = '\0';
57 return new_str;
60 static char *jsonp_strdup(const char *str) {
61 return jsonp_strndup(str, strlen(str));
64 ////// error.c private functions
66 static void jsonp_error_set_source(json_error_t *error, const char *source) {
67 size_t length;
69 if (!error || !source)
70 return;
72 length = strlen(source);
73 if (length < JSON_ERROR_SOURCE_LENGTH) {
74 strncpy(error->source, source, JSON_ERROR_SOURCE_LENGTH - 1);
75 } else {
76 size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4;
77 memcpy(error->source, "...", 3);
78 strncpy(error->source + 3, source + extra, length - extra + 1);
82 static void jsonp_error_init(json_error_t *error, const char *source) {
83 if (error) {
84 error->text[0] = '\0';
85 error->line = -1;
86 error->column = -1;
87 error->position = 0;
88 if (source)
89 jsonp_error_set_source(error, source);
90 else
91 error->source[0] = '\0';
95 static void jsonp_error_vset(json_error_t *error, int line, int column,
96 size_t position, enum json_error_code code,
97 const char *msg, va_list ap) {
98 if (!error)
99 return;
101 if (error->text[0] != '\0') {
102 /* error already set */
103 return;
106 error->line = line;
107 error->column = column;
108 error->position = (int)position;
110 vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap);
111 error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0';
112 error->text[JSON_ERROR_TEXT_LENGTH - 1] = code;
115 static void jsonp_error_set(json_error_t *error, int line, int column,
116 size_t position, enum json_error_code code,
117 const char *msg, ...) {
118 va_list ap;
119 va_start(ap, msg);
120 jsonp_error_vset(error, line, column, position, code, msg, ap);
121 va_end(ap);
125 // original path.c from jansson fork
127 json_t *json_path_get(const json_t *json, const char *path) {
128 static const char root_chr = '$', array_open = '[';
129 static const char *path_delims = ".[", *array_close = "]";
130 const json_t *cursor;
131 char *token, *buf, *peek, *endptr, delim = '\0';
132 const char *expect;
134 if (!json || !path || path[0] != root_chr)
135 return NULL;
136 else
137 buf = jsonp_strdup(path);
139 peek = buf + 1;
140 cursor = json;
141 token = NULL;
142 expect = path_delims;
144 while (peek && *peek && cursor) {
145 char *last_peek = peek;
146 peek = strpbrk(peek, expect);
147 if (peek) {
148 if (!token && peek != last_peek)
149 goto fail;
150 delim = *peek;
151 *peek++ = '\0';
152 } else if (expect != path_delims || !token) {
153 goto fail;
156 if (expect == path_delims) {
157 if (token) {
158 cursor = json_object_get(cursor, token);
160 expect = (delim == array_open ? array_close : path_delims);
161 token = peek;
162 } else if (expect == array_close) {
163 size_t index = strtol(token, &endptr, 0);
164 if (*endptr)
165 goto fail;
166 cursor = json_array_get(cursor, index);
167 token = NULL;
168 expect = path_delims;
169 } else {
170 goto fail;
174 jsonp_free(buf);
175 return (json_t *)cursor;
176 fail:
177 jsonp_free(buf);
178 return NULL;
181 int json_path_set_new(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error) {
182 static const char root_chr = '$', array_open = '[', object_delim = '.';
183 static const char *const path_delims = ".[", *array_close = "]";
185 json_t *cursor, *parent = NULL;
186 char *token, *buf = NULL, *peek, delim = '\0';
187 const char *expect;
188 int index_saved = -1;
190 jsonp_error_init(error, "<path>");
192 if (!json || !path || flags || !value) {
193 jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "invalid argument");
194 goto fail;
195 } else {
196 buf = jsonp_strdup(path);
199 if (buf[0] != root_chr) {
200 jsonp_error_set(error, -1, -1, 0, json_error_invalid_format, "path should start with $");
201 goto fail;
204 peek = buf + 1;
205 cursor = json;
206 token = NULL;
207 expect = path_delims;
209 while (peek && *peek && cursor) {
210 char *last_peek = peek;
211 peek = strpbrk(last_peek, expect);
213 if (peek) {
214 if (!token && peek != last_peek) {
215 jsonp_error_set(error, -1, -1, last_peek - buf, json_error_invalid_format, "unexpected trailing chars");
216 goto fail;
218 delim = *peek;
219 *peek++ = '\0';
220 } else { // end of path
221 if (expect == path_delims) {
222 break;
223 } else {
224 jsonp_error_set(error, -1, -1, last_peek - buf, json_error_invalid_format, "missing ']'?");
225 goto fail;
229 if (expect == path_delims) {
230 if (token) {
231 if (token[0] == '\0') {
232 jsonp_error_set(error, -1, -1, peek - buf, json_error_invalid_format, "empty token");
233 goto fail;
236 parent = cursor;
237 cursor = json_object_get(parent, token);
239 if (!cursor) {
240 if (!json_is_object(parent)) {
241 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "object expected");
242 goto fail;
244 if (delim == object_delim) {
245 cursor = json_object();
246 json_object_set_new(parent, token, cursor);
247 } else {
248 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "new array is not allowed");
249 goto fail;
253 expect = (delim == array_open ? array_close : path_delims);
254 token = peek;
255 } else if (expect == array_close) {
256 char *endptr;
257 size_t index;
259 parent = cursor;
260 if (!json_is_array(parent)) {
261 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "array expected");
262 goto fail;
264 index = strtol(token, &endptr, 0);
265 if (*endptr) {
266 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "invalid array index");
267 goto fail;
269 cursor = json_array_get(parent, index);
270 if (!cursor) {
271 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "array index out of bound");
272 goto fail;
274 index_saved = index;
275 token = NULL;
276 expect = path_delims;
277 } else {
278 assert(1);
279 jsonp_error_set(error, -1, -1, peek - buf, json_error_unknown, "unexpected error in path move");
280 goto fail;
284 if (token) {
285 if (json_is_object(cursor)) {
286 json_object_set(cursor, token, value);
287 } else {
288 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "object expected");
289 goto fail;
291 cursor = json_object_get(cursor, token);
292 } else if (index_saved != -1 && json_is_array(parent)) {
293 json_array_set(parent, index_saved, value);
294 cursor = json_array_get(parent, index_saved);
295 } else {
296 jsonp_error_set(error, -1, -1, 0, json_error_item_not_found, "invalid path");
297 goto fail;
300 json_decref(value);
301 jsonp_free(buf);
302 return 0;
304 fail:
305 json_decref(value);
306 jsonp_free(buf);
307 return -1;