fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / jansson_path.c
blob8bc224fcdc3247ec8a39a3f1d12e4cc26dad363a
1 /*
2 * Copyright (c) 2012 Rogerz Zhang <rogerz.zhang@gmail.com>
4 * Jansson is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
7 * source here https://github.com/rogerz/jansson/blob/json_path/src/path.c
8 */
10 #include <string.h>
11 #include <assert.h>
13 #include "jansson.h"
14 #include "jansson_path.h"
16 ////// memory.c private functions
18 /* C89 allows these to be macros */
19 #undef malloc
20 #undef free
22 /* memory function pointers */
23 static json_malloc_t do_malloc = malloc;
24 static json_free_t do_free = free;
26 static void *jsonp_malloc(size_t size) {
27 if (!size)
28 return NULL;
30 return (*do_malloc)(size);
33 static void jsonp_free(void *ptr) {
34 if (!ptr)
35 return;
37 (*do_free)(ptr);
40 static char *jsonp_strndup(const char *str, size_t len) {
41 char *new_str = jsonp_malloc(len + 1);
42 if (!new_str)
43 return NULL;
45 memcpy(new_str, str, len);
46 new_str[len] = '\0';
47 return new_str;
50 static char *jsonp_strdup(const char *str) {
51 return jsonp_strndup(str, strlen(str));
54 ////// error.c private functions
56 static void jsonp_error_set_source(json_error_t *error, const char *source) {
57 size_t length;
59 if (!error || !source)
60 return;
62 length = strlen(source);
63 if (length < JSON_ERROR_SOURCE_LENGTH) {
64 strncpy(error->source, source, JSON_ERROR_SOURCE_LENGTH - 1);
65 } else {
66 size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4;
67 memcpy(error->source, "...", 3);
68 strncpy(error->source + 3, source + extra, length - extra + 1);
72 static void jsonp_error_init(json_error_t *error, const char *source) {
73 if (error) {
74 error->text[0] = '\0';
75 error->line = -1;
76 error->column = -1;
77 error->position = 0;
78 if (source)
79 jsonp_error_set_source(error, source);
80 else
81 error->source[0] = '\0';
85 static void jsonp_error_vset(json_error_t *error, int line, int column,
86 size_t position, enum json_error_code code,
87 const char *msg, va_list ap) {
88 if (!error)
89 return;
91 if (error->text[0] != '\0') {
92 /* error already set */
93 return;
96 error->line = line;
97 error->column = column;
98 error->position = (int)position;
100 vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap);
101 error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0';
102 error->text[JSON_ERROR_TEXT_LENGTH - 1] = code;
105 static void jsonp_error_set(json_error_t *error, int line, int column,
106 size_t position, enum json_error_code code,
107 const char *msg, ...) {
108 va_list ap;
109 va_start(ap, msg);
110 jsonp_error_vset(error, line, column, position, code, msg, ap);
111 va_end(ap);
115 // original path.c from jansson fork
117 json_t *json_path_get(const json_t *json, const char *path) {
118 static const char root_chr = '$', array_open = '[';
119 static const char *path_delims = ".[", *array_close = "]";
120 const json_t *cursor;
121 char *token, *buf, *peek, *endptr, delim = '\0';
122 const char *expect;
124 if (!json || !path || path[0] != root_chr)
125 return NULL;
126 else
127 buf = jsonp_strdup(path);
129 peek = buf + 1;
130 cursor = json;
131 token = NULL;
132 expect = path_delims;
134 while (peek && *peek && cursor) {
135 char *last_peek = peek;
136 peek = strpbrk(peek, expect);
137 if (peek) {
138 if (!token && peek != last_peek)
139 goto fail;
140 delim = *peek;
141 *peek++ = '\0';
142 } else if (expect != path_delims || !token) {
143 goto fail;
146 if (expect == path_delims) {
147 if (token) {
148 cursor = json_object_get(cursor, token);
150 expect = (delim == array_open ? array_close : path_delims);
151 token = peek;
152 } else if (expect == array_close) {
153 size_t index = strtol(token, &endptr, 0);
154 if (*endptr)
155 goto fail;
156 cursor = json_array_get(cursor, index);
157 token = NULL;
158 expect = path_delims;
159 } else {
160 goto fail;
164 jsonp_free(buf);
165 return (json_t *)cursor;
166 fail:
167 jsonp_free(buf);
168 return NULL;
171 int json_path_set_new(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error) {
172 static const char root_chr = '$', array_open = '[', object_delim = '.';
173 static const char *const path_delims = ".[", *array_close = "]";
175 json_t *cursor, *parent = NULL;
176 char *token, *buf = NULL, *peek, delim = '\0';
177 const char *expect;
178 int index_saved = -1;
180 jsonp_error_init(error, "<path>");
182 if (!json || !path || flags || !value) {
183 jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "invalid argument");
184 goto fail;
185 } else {
186 buf = jsonp_strdup(path);
189 if (buf[0] != root_chr) {
190 jsonp_error_set(error, -1, -1, 0, json_error_invalid_format, "path should start with $");
191 goto fail;
194 peek = buf + 1;
195 cursor = json;
196 token = NULL;
197 expect = path_delims;
199 while (peek && *peek && cursor) {
200 char *last_peek = peek;
201 peek = strpbrk(last_peek, expect);
203 if (peek) {
204 if (!token && peek != last_peek) {
205 jsonp_error_set(error, -1, -1, last_peek - buf, json_error_invalid_format, "unexpected trailing chars");
206 goto fail;
208 delim = *peek;
209 *peek++ = '\0';
210 } else { // end of path
211 if (expect == path_delims) {
212 break;
213 } else {
214 jsonp_error_set(error, -1, -1, last_peek - buf, json_error_invalid_format, "missing ']'?");
215 goto fail;
219 if (expect == path_delims) {
220 if (token) {
221 if (token[0] == '\0') {
222 jsonp_error_set(error, -1, -1, peek - buf, json_error_invalid_format, "empty token");
223 goto fail;
226 parent = cursor;
227 cursor = json_object_get(parent, token);
229 if (!cursor) {
230 if (!json_is_object(parent)) {
231 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "object expected");
232 goto fail;
234 if (delim == object_delim) {
235 cursor = json_object();
236 json_object_set_new(parent, token, cursor);
237 } else {
238 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "new array is not allowed");
239 goto fail;
243 expect = (delim == array_open ? array_close : path_delims);
244 token = peek;
245 } else if (expect == array_close) {
246 char *endptr;
247 size_t index;
249 parent = cursor;
250 if (!json_is_array(parent)) {
251 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "array expected");
252 goto fail;
254 index = strtol(token, &endptr, 0);
255 if (*endptr) {
256 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "invalid array index");
257 goto fail;
259 cursor = json_array_get(parent, index);
260 if (!cursor) {
261 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "array index out of bound");
262 goto fail;
264 index_saved = index;
265 token = NULL;
266 expect = path_delims;
267 } else {
268 assert(1);
269 jsonp_error_set(error, -1, -1, peek - buf, json_error_unknown, "unexpected error in path move");
270 goto fail;
274 if (token) {
275 if (json_is_object(cursor)) {
276 json_object_set(cursor, token, value);
277 } else {
278 jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "object expected");
279 goto fail;
281 cursor = json_object_get(cursor, token);
282 } else if (index_saved != -1 && json_is_array(parent)) {
283 json_array_set(parent, index_saved, value);
284 cursor = json_array_get(parent, index_saved);
285 } else {
286 jsonp_error_set(error, -1, -1, 0, json_error_item_not_found, "invalid path");
287 goto fail;
290 json_decref(value);
291 jsonp_free(buf);
292 return 0;
294 fail:
295 json_decref(value);
296 jsonp_free(buf);
297 return -1;