1 /* sdb - MIT - Copyright 2012-2021 - pancake */
2
3 #include <stdarg.h>
4 #include "sdb.h"
5 #include "json/rangstr.c"
6 #include "json/js0n.c"
7 #include "json/path.c"
8 #include "json/api.c"
9 #include "json/indent.c"
10
sdb_json_get_str(const char * json,const char * path)11 SDB_API char *sdb_json_get_str (const char *json, const char *path) {
12 Rangstr rs = json_get (json, path);
13 return rangstr_dup (&rs);
14 }
15
sdb_json_get_bool(const char * json,const char * path)16 SDB_API bool sdb_json_get_bool(const char *json, const char *path) {
17 Rangstr rs = json_get (json, path);
18 const char *p = rs.p + rs.f;
19 return (rangstr_length (&rs) == 4 && !strncmp (p, "true", 4));
20 }
21
sdb_json_get(Sdb * s,const char * k,const char * p,ut32 * cas)22 SDB_API char *sdb_json_get(Sdb *s, const char *k, const char *p, ut32 *cas) {
23 Rangstr rs;
24 char *u, *v = sdb_get (s, k, cas);
25 if (!v) {
26 return NULL;
27 }
28 rs = json_get (v, p);
29 u = rangstr_dup (&rs);
30 free (v);
31 return u;
32 }
33
sdb_json_num_inc(Sdb * s,const char * k,const char * p,int n,ut32 cas)34 SDB_API int sdb_json_num_inc(Sdb *s, const char *k, const char *p, int n, ut32 cas) {
35 ut32 c;
36 int cur = sdb_json_num_get (s, k, p, &c);
37 if (cas && c != cas) {
38 return 0;
39 }
40 sdb_json_num_set (s, k, p, cur + n, cas);
41 return cur + n;
42 }
43
sdb_json_num_dec(Sdb * s,const char * k,const char * p,int n,ut32 cas)44 SDB_API int sdb_json_num_dec(Sdb *s, const char *k, const char *p, int n, ut32 cas) {
45 ut32 c;
46 int cur = sdb_json_num_get (s, k, p, &c);
47 if (cas && c != cas) {
48 return 0;
49 }
50 sdb_json_num_set (s, k, p, cur - n, cas);
51 return cur - n;
52 }
53
sdb_json_num_get(Sdb * s,const char * k,const char * p,ut32 * cas)54 SDB_API int sdb_json_num_get(Sdb *s, const char *k, const char *p, ut32 *cas) {
55 char *v = sdb_get (s, k, cas);
56 if (v) {
57 Rangstr rs = json_get (v, p);
58 int ret = rangstr_int (&rs);
59 free (v);
60 return ret;
61 }
62 return 0;
63 }
64
findkey(Rangstr * rs)65 static int findkey(Rangstr *rs) {
66 int i;
67 for (i = rs->f; i > 0; i--) {
68 // Find the quote after the key
69 if (rs->p[i] == '"') {
70 for (--i; i > 0; i--) {
71 // Find the quote before the key
72 if (rs->p[i] == '"') {
73 return i;
74 }
75 }
76 }
77 }
78 return -1;
79 }
80
isstring(const char * s)81 static bool isstring(const char *s) {
82 if (!strcmp (s, "true")) {
83 return false;
84 }
85 if (!strcmp (s, "false")) {
86 return false;
87 }
88 for (; *s; s++) {
89 if (*s < '0' || *s > '9') {
90 return true;
91 }
92 }
93 return false;
94 }
95
96 // JSON only supports base16 numbers
sdb_json_num_set(Sdb * s,const char * k,const char * p,int v,ut32 cas)97 SDB_API int sdb_json_num_set(Sdb *s, const char *k, const char *p, int v, ut32 cas) {
98 char *_str, str[64];
99 _str = sdb_itoa (v, str, 10);
100 return sdb_json_set (s, k, p, _str, cas);
101 }
102
sdb_json_unset(Sdb * s,const char * k,const char * p,ut32 cas)103 SDB_API int sdb_json_unset(Sdb *s, const char *k, const char *p, ut32 cas) {
104 return sdb_json_set (s, k, p, NULL, cas);
105 }
106
sdb_json_set(Sdb * s,const char * k,const char * p,const char * v,ut32 cas)107 SDB_API bool sdb_json_set(Sdb *s, const char *k, const char *p, const char *v, ut32 cas) {
108 int l, idx, len[3], jslen = 0;
109 char *b, *str = NULL;
110 const char *beg[3];
111 const char *end[3];
112 const char *js;
113 Rangstr rs;
114 ut32 c;
115
116 if (!s || !k || !v) {
117 return false;
118 }
119 js = sdb_const_get_len (s, k, &jslen, &c);
120 if (!js) {
121 const int v_len = strlen (v);
122 const int p_len = strlen (p);
123 b = malloc (p_len + v_len + 8);
124 if (b) {
125 int is_str = isstring (v);
126 const char *q = is_str? "\"": "";
127 sprintf (b, "{\"%s\":%s%s%s}", p, q, v, q);
128 #if 0
129 /* disabled because it memleaks */
130 sdb_set_owned (s, k, b, cas);
131 #else
132 sdb_set (s, k, b, cas);
133 free (b);
134 #endif
135 return true;
136 }
137 return false;
138 }
139 jslen++;
140 if (cas && c != cas) {
141 return false;
142 }
143 rs = json_get (js, p);
144 if (!rs.p) {
145 // jslen already comprehends the NULL-terminator and is
146 // ensured to be positive by sdb_const_get_len
147 // 7 corresponds to the length of '{"":"",'
148 size_t buf_len = jslen + strlen (p) + strlen (v) + 7;
149 char *buf = malloc (buf_len);
150 if (buf) {
151 int curlen, is_str = isstring (v);
152 const char *quote = is_str ? "\"" : "";
153 const char *end = ""; // XX: or comma
154 if (js[0] && js[1] != '}') {
155 end = ",";
156 }
157 curlen = sprintf (buf, "{\"%s\":%s%s%s%s",
158 p, quote, v, quote, end);
159 strcpy (buf + curlen, js + 1);
160 // transfer ownership
161 sdb_set_owned (s, k, buf, cas);
162 return true;
163 }
164 // invalid json?
165 return false;
166 }
167
168 // rs.p and js point to the same memory location
169 beg[0] = js;
170 end[0] = rs.p + rs.f;
171 len[0] = WLEN (0);
172
173 if (*v) {
174 beg[1] = v;
175 end[1] = v + strlen (v);
176 len[1] = WLEN (1);
177 }
178
179 beg[2] = rs.p + rs.t;
180 end[2] = js + jslen;
181 len[2] = WLEN (2);
182
183 // TODO: accelerate with small buffer in stack for small jsons
184 if (*v) {
185 int is_str = isstring (v);
186 // 2 is the maximum amount of quotes that can be inserted
187 int msz = len[0] + len[1] + len[2] + strlen (v) + 2;
188 if (msz < 1) {
189 return false;
190 }
191 str = malloc (msz);
192 if (!str) {
193 return false;
194 }
195 idx = len[0];
196 memcpy (str, beg[0], idx);
197 if (is_str) {
198 if (beg[2][0] != '"') {
199 str[idx] = '"';
200 idx++;
201 }
202 } else {
203 if (beg[2][0] == '"') {
204 beg[2]++;
205 len[2]--;
206 }
207 }
208 l = len[1];
209 memcpy (str + idx, beg[1], l);
210 idx += len[1];
211 if (is_str) {
212 // TODO: add quotes
213 if (beg[2][0] != '"') {
214 str[idx] = '"';
215 idx++;
216 }
217 } else {
218 if (beg[2][0] == '"') {
219 beg[2]++;
220 len[2]--;
221 }
222 }
223 l = len[2];
224 memcpy (str + idx, beg[2], l);
225 str[idx + l] = 0;
226 } else {
227 int kidx;
228 // DELETE KEY
229 rs.f -= 2;
230 kidx = findkey (&rs);
231 len[0] = R_MAX (1, kidx - 1);
232
233 // Delete quote if deleted value was a string
234 if (beg[2][0] == '"') {
235 beg[2]++;
236 len[2]--;
237 }
238
239 // If not the last key, delete comma
240 if (len[2] != 2) {
241 beg[2]++;
242 len[2]--;
243 }
244
245 str = malloc (len[0] + len[2] + 1);
246 if (!str) {
247 return false;
248 }
249
250 memcpy (str, beg[0], len[0]);
251 memcpy (str + len[0], beg[2], len[2]);
252 str[len[0] + len[2]] = 0;
253 }
254 sdb_set_owned (s, k, str, cas);
255 return true;
256 }
257
sdb_json_format(SdbJsonString * s,const char * fmt,...)258 SDB_API const char *sdb_json_format(SdbJsonString *s, const char *fmt, ...) {
259 char *arg_s, *x, tmp[128];
260 ut64 arg_l;
261 int i, arg_i;
262 double arg_f;
263 va_list ap;
264 #define JSONSTR_ALLOCATE(y)\
265 if (s->len + y > s->blen) {\
266 s->blen *= 2;\
267 x = realloc (s->buf, s->blen);\
268 if (!x) {\
269 va_end (ap);\
270 return NULL;\
271 }\
272 s->buf = x;\
273 }
274 if (!s) {
275 return NULL;
276 }
277 if (!s->buf) {
278 s->blen = 1024;
279 s->buf = malloc (s->blen);
280 if (!s->buf) {
281 return NULL;
282 }
283 *s->buf = 0;
284 }
285 if (!fmt || !*fmt) {
286 return s->buf;
287 }
288 va_start (ap, fmt);
289 for (; *fmt; fmt++) {
290 if (*fmt == '%') {
291 fmt++;
292 switch (*fmt) {
293 case 'b':
294 JSONSTR_ALLOCATE (32);
295 arg_i = va_arg (ap, int);
296 arg_i = arg_i? 4: 5;
297 memcpy (s->buf + s->len, (arg_i == 4)? "true": "false", 5);
298 s->len += arg_i;
299 break;
300 case 'f':
301 JSONSTR_ALLOCATE (32);
302 arg_f = va_arg (ap, double);
303 snprintf (tmp, sizeof (tmp), "%f", arg_f);
304 memcpy (s->buf + s->len, tmp, strlen (tmp));
305 s->len += strlen (tmp);
306 break;
307 case 'l':
308 JSONSTR_ALLOCATE (32);
309 arg_l = va_arg (ap, ut64);
310 snprintf (tmp, sizeof (tmp), "0x%"ULLFMT "x", arg_l);
311 memcpy (s->buf + s->len, tmp, strlen (tmp));
312 s->len += strlen (tmp);
313 break;
314 case 'd':
315 case 'i':
316 JSONSTR_ALLOCATE (32);
317 arg_i = va_arg (ap, int);
318 snprintf (tmp, sizeof (tmp), "%d", arg_i);
319 memcpy (s->buf + s->len, tmp, strlen (tmp));
320 s->len += strlen (tmp);
321 break;
322 case 's':
323 arg_s = va_arg (ap, char *);
324 JSONSTR_ALLOCATE (strlen (arg_s) + 3);
325 s->buf[s->len++] = '"';
326 for (i = 0; arg_s[i]; i++) {
327 if (arg_s[i] == '"') {
328 s->buf[s->len++] = '\\';
329 }
330 s->buf[s->len++] = arg_s[i];
331 }
332 s->buf[s->len++] = '"';
333 break;
334 }
335 } else {
336 JSONSTR_ALLOCATE (10);
337 s->buf[s->len++] = *fmt;
338 }
339 s->buf[s->len] = 0;
340 }
341 va_end (ap);
342 return s->buf;
343 }
344
345 #if 0
346 int main () {
347 SdbJsonString s = {
348 0
349 };
350 sdb_json_format (&s, "[{%s:%d},%b]", "Hello \"world\"", 1024, 3);
351 printf ("%s\n", sdb_json_format (&s, 0));
352 sdb_json_format_free (&s);
353 return 0;
354 }
355 #endif
356