Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tpruvot
GitHub Repository: tpruvot/cpuminer-multi
Path: blob/linux/compat/jansson/pack_unpack.c
1201 views
1
/*
2
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
3
* Copyright (c) 2011-2012 Graeme Smecher <[email protected]>
4
*
5
* Jansson is free software; you can redistribute it and/or modify
6
* it under the terms of the MIT license. See LICENSE for details.
7
*/
8
9
#include <string.h>
10
#include "jansson.h"
11
#include "jansson_private.h"
12
#include "utf.h"
13
14
typedef struct {
15
int line;
16
int column;
17
size_t pos;
18
char token;
19
} token_t;
20
21
typedef struct {
22
const char *start;
23
const char *fmt;
24
token_t prev_token;
25
token_t token;
26
token_t next_token;
27
json_error_t *error;
28
size_t flags;
29
int line;
30
int column;
31
size_t pos;
32
} scanner_t;
33
34
#define token(scanner) ((scanner)->token.token)
35
36
static const char * const type_names[] = {
37
"object",
38
"array",
39
"string",
40
"integer",
41
"real",
42
"true",
43
"false",
44
"null"
45
};
46
47
#define type_name(x) type_names[json_typeof(x)]
48
49
static const char unpack_value_starters[] = "{[siIbfFOon";
50
51
52
static void scanner_init(scanner_t *s, json_error_t *error,
53
size_t flags, const char *fmt)
54
{
55
s->error = error;
56
s->flags = flags;
57
s->fmt = s->start = fmt;
58
memset(&s->prev_token, 0, sizeof(token_t));
59
memset(&s->token, 0, sizeof(token_t));
60
memset(&s->next_token, 0, sizeof(token_t));
61
s->line = 1;
62
s->column = 0;
63
s->pos = 0;
64
}
65
66
static void next_token(scanner_t *s)
67
{
68
const char *t;
69
s->prev_token = s->token;
70
71
if(s->next_token.line) {
72
s->token = s->next_token;
73
s->next_token.line = 0;
74
return;
75
}
76
77
t = s->fmt;
78
s->column++;
79
s->pos++;
80
81
/* skip space and ignored chars */
82
while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
83
if(*t == '\n') {
84
s->line++;
85
s->column = 1;
86
}
87
else
88
s->column++;
89
90
s->pos++;
91
t++;
92
}
93
94
s->token.token = *t;
95
s->token.line = s->line;
96
s->token.column = s->column;
97
s->token.pos = s->pos;
98
99
t++;
100
s->fmt = t;
101
}
102
103
static void prev_token(scanner_t *s)
104
{
105
s->next_token = s->token;
106
s->token = s->prev_token;
107
}
108
109
static void set_error(scanner_t *s, const char *source, const char *fmt, ...)
110
{
111
va_list ap;
112
va_start(ap, fmt);
113
114
jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos,
115
fmt, ap);
116
117
jsonp_error_set_source(s->error, source);
118
119
va_end(ap);
120
}
121
122
static json_t *pack(scanner_t *s, va_list *ap);
123
124
125
/* ours will be set to 1 if jsonp_free() must be called for the result
126
afterwards */
127
static char *read_string(scanner_t *s, va_list *ap,
128
const char *purpose, int *ours)
129
{
130
char t;
131
strbuffer_t strbuff;
132
const char *str;
133
size_t length;
134
char *result;
135
136
next_token(s);
137
t = token(s);
138
prev_token(s);
139
140
if(t != '#' && t != '+') {
141
/* Optimize the simple case */
142
str = va_arg(*ap, const char *);
143
144
if(!str) {
145
set_error(s, "<args>", "NULL string argument");
146
return NULL;
147
}
148
149
if(!utf8_check_string(str, -1)) {
150
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
151
return NULL;
152
}
153
154
*ours = 0;
155
return (char *)str;
156
}
157
158
strbuffer_init(&strbuff);
159
160
while(1) {
161
str = va_arg(*ap, const char *);
162
if(!str) {
163
set_error(s, "<args>", "NULL string argument");
164
strbuffer_close(&strbuff);
165
return NULL;
166
}
167
168
next_token(s);
169
170
if(token(s) == '#') {
171
length = va_arg(*ap, int);
172
}
173
else {
174
prev_token(s);
175
length = strlen(str);
176
}
177
178
if(strbuffer_append_bytes(&strbuff, str, length) == -1) {
179
set_error(s, "<internal>", "Out of memory");
180
strbuffer_close(&strbuff);
181
return NULL;
182
}
183
184
next_token(s);
185
if(token(s) != '+') {
186
prev_token(s);
187
break;
188
}
189
}
190
191
result = strbuffer_steal_value(&strbuff);
192
193
if(!utf8_check_string(result, -1)) {
194
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
195
return NULL;
196
}
197
198
*ours = 1;
199
return result;
200
}
201
202
static json_t *pack_object(scanner_t *s, va_list *ap)
203
{
204
json_t *object = json_object();
205
next_token(s);
206
207
while(token(s) != '}') {
208
char *key;
209
int ours;
210
json_t *value;
211
212
if(!token(s)) {
213
set_error(s, "<format>", "Unexpected end of format string");
214
goto error;
215
}
216
217
if(token(s) != 's') {
218
set_error(s, "<format>", "Expected format 's', got '%c'", token(s));
219
goto error;
220
}
221
222
key = read_string(s, ap, "object key", &ours);
223
if(!key)
224
goto error;
225
226
next_token(s);
227
228
value = pack(s, ap);
229
if(!value)
230
goto error;
231
232
if(json_object_set_new_nocheck(object, key, value)) {
233
if(ours)
234
jsonp_free(key);
235
236
set_error(s, "<internal>", "Unable to add key \"%s\"", key);
237
goto error;
238
}
239
240
if(ours)
241
jsonp_free(key);
242
243
next_token(s);
244
}
245
246
return object;
247
248
error:
249
json_decref(object);
250
return NULL;
251
}
252
253
static json_t *pack_array(scanner_t *s, va_list *ap)
254
{
255
json_t *array = json_array();
256
next_token(s);
257
258
while(token(s) != ']') {
259
json_t *value;
260
261
if(!token(s)) {
262
set_error(s, "<format>", "Unexpected end of format string");
263
goto error;
264
}
265
266
value = pack(s, ap);
267
if(!value)
268
goto error;
269
270
if(json_array_append_new(array, value)) {
271
set_error(s, "<internal>", "Unable to append to array");
272
goto error;
273
}
274
275
next_token(s);
276
}
277
return array;
278
279
error:
280
json_decref(array);
281
return NULL;
282
}
283
284
static json_t *pack(scanner_t *s, va_list *ap)
285
{
286
switch(token(s)) {
287
case '{':
288
return pack_object(s, ap);
289
290
case '[':
291
return pack_array(s, ap);
292
293
case 's': { /* string */
294
char *str;
295
int ours;
296
json_t *result;
297
298
str = read_string(s, ap, "string", &ours);
299
if(!str)
300
return NULL;
301
302
result = json_string_nocheck(str);
303
if(ours)
304
jsonp_free(str);
305
306
return result;
307
}
308
309
case 'n': /* null */
310
return json_null();
311
312
case 'b': /* boolean */
313
return va_arg(*ap, int) ? json_true() : json_false();
314
315
case 'i': /* integer from int */
316
return json_integer(va_arg(*ap, int));
317
318
case 'I': /* integer from json_int_t */
319
return json_integer(va_arg(*ap, json_int_t));
320
321
case 'f': /* real */
322
return json_real(va_arg(*ap, double));
323
324
case 'O': /* a json_t object; increments refcount */
325
return json_incref(va_arg(*ap, json_t *));
326
327
case 'o': /* a json_t object; doesn't increment refcount */
328
return va_arg(*ap, json_t *);
329
330
default:
331
set_error(s, "<format>", "Unexpected format character '%c'",
332
token(s));
333
return NULL;
334
}
335
}
336
337
static int unpack(scanner_t *s, json_t *root, va_list *ap);
338
339
static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
340
{
341
int ret = -1;
342
int strict = 0;
343
344
/* Use a set (emulated by a hashtable) to check that all object
345
keys are accessed. Checking that the correct number of keys
346
were accessed is not enough, as the same key can be unpacked
347
multiple times.
348
*/
349
hashtable_t key_set;
350
351
if(hashtable_init(&key_set)) {
352
set_error(s, "<internal>", "Out of memory");
353
return -1;
354
}
355
356
if(root && !json_is_object(root)) {
357
set_error(s, "<validation>", "Expected object, got %s",
358
type_name(root));
359
goto out;
360
}
361
next_token(s);
362
363
while(token(s) != '}') {
364
const char *key;
365
json_t *value;
366
int opt = 0;
367
368
if(strict != 0) {
369
set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
370
(strict == 1 ? '!' : '*'), token(s));
371
goto out;
372
}
373
374
if(!token(s)) {
375
set_error(s, "<format>", "Unexpected end of format string");
376
goto out;
377
}
378
379
if(token(s) == '!' || token(s) == '*') {
380
strict = (token(s) == '!' ? 1 : -1);
381
next_token(s);
382
continue;
383
}
384
385
if(token(s) != 's') {
386
set_error(s, "<format>", "Expected format 's', got '%c'", token(s));
387
goto out;
388
}
389
390
key = va_arg(*ap, const char *);
391
if(!key) {
392
set_error(s, "<args>", "NULL object key");
393
goto out;
394
}
395
396
next_token(s);
397
398
if(token(s) == '?') {
399
opt = 1;
400
next_token(s);
401
}
402
403
if(!root) {
404
/* skipping */
405
value = NULL;
406
}
407
else {
408
value = json_object_get(root, key);
409
if(!value && !opt) {
410
set_error(s, "<validation>", "Object item not found: %s", key);
411
goto out;
412
}
413
}
414
415
if(unpack(s, value, ap))
416
goto out;
417
418
hashtable_set(&key_set, key, 0, json_null());
419
next_token(s);
420
}
421
422
if(strict == 0 && (s->flags & JSON_STRICT))
423
strict = 1;
424
425
if(root && strict == 1 && key_set.size != json_object_size(root)) {
426
long diff = (long)json_object_size(root) - (long)key_set.size;
427
set_error(s, "<validation>", "%li object item(s) left unpacked", diff);
428
goto out;
429
}
430
431
ret = 0;
432
433
out:
434
hashtable_close(&key_set);
435
return ret;
436
}
437
438
static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
439
{
440
size_t i = 0;
441
int strict = 0;
442
443
if(root && !json_is_array(root)) {
444
set_error(s, "<validation>", "Expected array, got %s", type_name(root));
445
return -1;
446
}
447
next_token(s);
448
449
while(token(s) != ']') {
450
json_t *value;
451
452
if(strict != 0) {
453
set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
454
(strict == 1 ? '!' : '*'),
455
token(s));
456
return -1;
457
}
458
459
if(!token(s)) {
460
set_error(s, "<format>", "Unexpected end of format string");
461
return -1;
462
}
463
464
if(token(s) == '!' || token(s) == '*') {
465
strict = (token(s) == '!' ? 1 : -1);
466
next_token(s);
467
continue;
468
}
469
470
if(!strchr(unpack_value_starters, token(s))) {
471
set_error(s, "<format>", "Unexpected format character '%c'",
472
token(s));
473
return -1;
474
}
475
476
if(!root) {
477
/* skipping */
478
value = NULL;
479
}
480
else {
481
value = json_array_get(root, i);
482
if(!value) {
483
set_error(s, "<validation>", "Array index %lu out of range",
484
(unsigned long)i);
485
return -1;
486
}
487
}
488
489
if(unpack(s, value, ap))
490
return -1;
491
492
next_token(s);
493
i++;
494
}
495
496
if(strict == 0 && (s->flags & JSON_STRICT))
497
strict = 1;
498
499
if(root && strict == 1 && i != json_array_size(root)) {
500
long diff = (long)json_array_size(root) - (long)i;
501
set_error(s, "<validation>", "%li array item(s) left unpacked", diff);
502
return -1;
503
}
504
505
return 0;
506
}
507
508
static int unpack(scanner_t *s, json_t *root, va_list *ap)
509
{
510
switch(token(s))
511
{
512
case '{':
513
return unpack_object(s, root, ap);
514
515
case '[':
516
return unpack_array(s, root, ap);
517
518
case 's':
519
if(root && !json_is_string(root)) {
520
set_error(s, "<validation>", "Expected string, got %s",
521
type_name(root));
522
return -1;
523
}
524
525
if(!(s->flags & JSON_VALIDATE_ONLY)) {
526
const char **target;
527
528
target = va_arg(*ap, const char **);
529
if(!target) {
530
set_error(s, "<args>", "NULL string argument");
531
return -1;
532
}
533
534
if(root)
535
*target = json_string_value(root);
536
}
537
return 0;
538
539
case 'i':
540
if(root && !json_is_integer(root)) {
541
set_error(s, "<validation>", "Expected integer, got %s",
542
type_name(root));
543
return -1;
544
}
545
546
if(!(s->flags & JSON_VALIDATE_ONLY)) {
547
int *target = va_arg(*ap, int*);
548
if(root)
549
*target = (int)json_integer_value(root);
550
}
551
552
return 0;
553
554
case 'I':
555
if(root && !json_is_integer(root)) {
556
set_error(s, "<validation>", "Expected integer, got %s",
557
type_name(root));
558
return -1;
559
}
560
561
if(!(s->flags & JSON_VALIDATE_ONLY)) {
562
json_int_t *target = va_arg(*ap, json_int_t*);
563
if(root)
564
*target = json_integer_value(root);
565
}
566
567
return 0;
568
569
case 'b':
570
if(root && !json_is_boolean(root)) {
571
set_error(s, "<validation>", "Expected true or false, got %s",
572
type_name(root));
573
return -1;
574
}
575
576
if(!(s->flags & JSON_VALIDATE_ONLY)) {
577
int *target = va_arg(*ap, int*);
578
if(root)
579
*target = json_is_true(root);
580
}
581
582
return 0;
583
584
case 'f':
585
if(root && !json_is_real(root)) {
586
set_error(s, "<validation>", "Expected real, got %s",
587
type_name(root));
588
return -1;
589
}
590
591
if(!(s->flags & JSON_VALIDATE_ONLY)) {
592
double *target = va_arg(*ap, double*);
593
if(root)
594
*target = json_real_value(root);
595
}
596
597
return 0;
598
599
case 'F':
600
if(root && !json_is_number(root)) {
601
set_error(s, "<validation>", "Expected real or integer, got %s",
602
type_name(root));
603
return -1;
604
}
605
606
if(!(s->flags & JSON_VALIDATE_ONLY)) {
607
double *target = va_arg(*ap, double*);
608
if(root)
609
*target = json_number_value(root);
610
}
611
612
return 0;
613
614
case 'O':
615
if(root && !(s->flags & JSON_VALIDATE_ONLY))
616
json_incref(root);
617
/* Fall through */
618
619
case 'o':
620
if(!(s->flags & JSON_VALIDATE_ONLY)) {
621
json_t **target = va_arg(*ap, json_t**);
622
if(root)
623
*target = root;
624
}
625
626
return 0;
627
628
case 'n':
629
/* Never assign, just validate */
630
if(root && !json_is_null(root)) {
631
set_error(s, "<validation>", "Expected null, got %s",
632
type_name(root));
633
return -1;
634
}
635
return 0;
636
637
default:
638
set_error(s, "<format>", "Unexpected format character '%c'",
639
token(s));
640
return -1;
641
}
642
}
643
644
json_t *json_vpack_ex(json_error_t *error, size_t flags,
645
const char *fmt, va_list ap)
646
{
647
scanner_t s;
648
va_list ap_copy;
649
json_t *value;
650
651
if(!fmt || !*fmt) {
652
jsonp_error_init(error, "<format>");
653
jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
654
return NULL;
655
}
656
jsonp_error_init(error, NULL);
657
658
scanner_init(&s, error, flags, fmt);
659
next_token(&s);
660
661
va_copy(ap_copy, ap);
662
value = pack(&s, &ap_copy);
663
va_end(ap_copy);
664
665
if(!value)
666
return NULL;
667
668
next_token(&s);
669
if(token(&s)) {
670
json_decref(value);
671
set_error(&s, "<format>", "Garbage after format string");
672
return NULL;
673
}
674
675
return value;
676
}
677
678
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
679
{
680
json_t *value;
681
va_list ap;
682
683
va_start(ap, fmt);
684
value = json_vpack_ex(error, flags, fmt, ap);
685
va_end(ap);
686
687
return value;
688
}
689
690
json_t *json_pack(const char *fmt, ...)
691
{
692
json_t *value;
693
va_list ap;
694
695
va_start(ap, fmt);
696
value = json_vpack_ex(NULL, 0, fmt, ap);
697
va_end(ap);
698
699
return value;
700
}
701
702
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
703
const char *fmt, va_list ap)
704
{
705
scanner_t s;
706
va_list ap_copy;
707
708
if(!root) {
709
jsonp_error_init(error, "<root>");
710
jsonp_error_set(error, -1, -1, 0, "NULL root value");
711
return -1;
712
}
713
714
if(!fmt || !*fmt) {
715
jsonp_error_init(error, "<format>");
716
jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
717
return -1;
718
}
719
jsonp_error_init(error, NULL);
720
721
scanner_init(&s, error, flags, fmt);
722
next_token(&s);
723
724
va_copy(ap_copy, ap);
725
if(unpack(&s, root, &ap_copy)) {
726
va_end(ap_copy);
727
return -1;
728
}
729
va_end(ap_copy);
730
731
next_token(&s);
732
if(token(&s)) {
733
set_error(&s, "<format>", "Garbage after format string");
734
return -1;
735
}
736
737
return 0;
738
}
739
740
int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...)
741
{
742
int ret;
743
va_list ap;
744
745
va_start(ap, fmt);
746
ret = json_vunpack_ex(root, error, flags, fmt, ap);
747
va_end(ap);
748
749
return ret;
750
}
751
752
int json_unpack(json_t *root, const char *fmt, ...)
753
{
754
int ret;
755
va_list ap;
756
757
va_start(ap, fmt);
758
ret = json_vunpack_ex(root, NULL, 0, fmt, ap);
759
va_end(ap);
760
761
return ret;
762
}
763
764