1 // This file is part of Jiffy released under the MIT license.
2 // See the LICENSE file for more information.
3 
4 #include <assert.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include "erl_nif.h"
11 #include "jiffy.h"
12 
13 #define U(c) ((unsigned char) (c))
14 #define ERROR(i, msg) make_error(st, env, msg)
15 
16 #define STACK_SIZE_INC 64
17 #define NUM_BUF_LEN 32
18 
19 #if WINDOWS || WIN32
20 #define snprintf  _snprintf
21 #endif
22 
23 enum {
24     st_value=0,
25     st_object,
26     st_array,
27     st_key,
28     st_colon,
29     st_comma,
30     st_done,
31     st_invalid
32 } JsonState;
33 
34 enum {
35     nst_init=0,
36     nst_sign,
37     nst_mantissa,
38     nst_frac0,
39     nst_frac1,
40     nst_frac,
41     nst_esign,
42     nst_edigit
43 } JsonNumState;
44 
45 typedef struct {
46     ErlNifEnv*      env;
47     jiffy_st*       atoms;
48 
49     ERL_NIF_TERM    arg;
50     ErlNifBinary    bin;
51 
52     size_t          bytes_per_red;
53     int             is_partial;
54     int             return_maps;
55     int             return_trailer;
56     int             dedupe_keys;
57     int             copy_strings;
58     ERL_NIF_TERM    null_term;
59 
60     unsigned char*  p;
61     int             i;
62     int             len;
63 
64     char*           st_data;
65     int             st_size;
66     int             st_top;
67 } Decoder;
68 
69 Decoder*
dec_new(ErlNifEnv * env)70 dec_new(ErlNifEnv* env)
71 {
72     jiffy_st* st = (jiffy_st*) enif_priv_data(env);
73     Decoder* d = enif_alloc_resource(st->res_dec, sizeof(Decoder));
74     int i;
75 
76     if(d == NULL) {
77         return NULL;
78     }
79 
80     d->atoms = st;
81 
82     d->bytes_per_red = DEFAULT_BYTES_PER_REDUCTION;
83     d->is_partial = 0;
84     d->return_maps = 0;
85     d->return_trailer = 0;
86     d->dedupe_keys = 0;
87     d->copy_strings = 0;
88     d->null_term = d->atoms->atom_null;
89 
90     d->p = NULL;
91     d->len = -1;
92     d->i = 0;
93 
94     d->st_data = (char*) enif_alloc(STACK_SIZE_INC);
95     d->st_size = STACK_SIZE_INC;
96     d->st_top = 0;
97 
98     for(i = 0; i < d->st_size; i++) {
99         d->st_data[i] = st_invalid;
100     }
101 
102     d->st_data[0] = st_value;
103     d->st_top++;
104 
105     return d;
106 }
107 
108 void
dec_init(Decoder * d,ErlNifEnv * env,ERL_NIF_TERM arg,ErlNifBinary * bin)109 dec_init(Decoder* d, ErlNifEnv* env, ERL_NIF_TERM arg, ErlNifBinary* bin)
110 {
111     d->env = env;
112     d->arg = arg;
113 
114     d->p = bin->data;
115     d->len = bin->size;
116 }
117 
118 void
dec_destroy(ErlNifEnv * env,void * obj)119 dec_destroy(ErlNifEnv* env, void* obj)
120 {
121     Decoder* d = (Decoder*) obj;
122 
123     if(d->st_data != NULL) {
124         enif_free(d->st_data);
125     }
126 }
127 
128 ERL_NIF_TERM
dec_error(Decoder * d,const char * atom)129 dec_error(Decoder* d, const char* atom)
130 {
131     ERL_NIF_TERM pos = enif_make_int(d->env, d->i+1);
132     ERL_NIF_TERM msg = make_atom(d->env, atom);
133     ERL_NIF_TERM ret = enif_make_tuple2(d->env, pos, msg);
134     return enif_make_tuple2(d->env, d->atoms->atom_error, ret);
135 }
136 
137 char
dec_curr(Decoder * d)138 dec_curr(Decoder* d)
139 {
140     assert(d->st_top > 0);
141     return d->st_data[d->st_top - 1];
142 }
143 
144 int
dec_top(Decoder * d)145 dec_top(Decoder* d)
146 {
147     return d->st_top;
148 }
149 
150 void
dec_push(Decoder * d,char val)151 dec_push(Decoder* d, char val)
152 {
153     int new_sz;
154     int i;
155 
156     if(d->st_top == d->st_size) {
157         new_sz = d->st_size + STACK_SIZE_INC;
158         d->st_data = (char*) enif_realloc(d->st_data, new_sz);
159         d->st_size = new_sz;
160         for(i = d->st_top; i < d->st_size; i++) {
161             d->st_data[i] = st_invalid;
162         }
163     }
164 
165     assert(d->st_top < d->st_size);
166     d->st_data[d->st_top++] = val;
167 }
168 
169 char
dec_pop(Decoder * d)170 dec_pop(Decoder* d) {
171     char current = st_invalid;
172 
173     if (d->st_top > 0) {
174         current = d->st_data[d->st_top - 1];
175         d->st_data[d->st_top - 1] = st_invalid;
176         d->st_top--;
177     }
178 
179     return current;
180 }
181 
182 void
dec_pop_assert(Decoder * d,char val)183 dec_pop_assert(Decoder* d, char val)
184 {
185     char current = dec_pop(d);
186     assert(current == val && "popped invalid state.");
187     (void)current;
188 }
189 
190 int
dec_string(Decoder * d,ERL_NIF_TERM * value)191 dec_string(Decoder* d, ERL_NIF_TERM* value)
192 {
193     int has_escape = 0;
194     int num_escapes = 0;
195     int st;
196     int ulen;
197     int ui;
198     int hi;
199     int lo;
200     char* chrbuf;
201     int chrpos;
202 
203     if(d->p[d->i] != '\"') {
204         return 0;
205     }
206     d->i++;
207 
208     st = d->i;
209 
210     while(d->i < d->len) {
211         if(d->p[d->i] < 0x20) {
212             return 0;
213         } else if(d->p[d->i] == '\"') {
214             d->i++;
215             goto parse;
216         } else if(d->p[d->i] == '\\') {
217             if(d->i+1 >= d->len) {
218                 return 0;
219             }
220             has_escape = 1;
221             num_escapes += 1;
222             d->i++;
223             switch(d->p[d->i]) {
224                 case '\"':
225                 case '\\':
226                 case '/':
227                 case 'b':
228                 case 'f':
229                 case 'n':
230                 case 'r':
231                 case 't':
232                     d->i++;
233                     break;
234                 case 'u':
235                     hi = 0;
236                     lo = 0;
237                     d->i++;
238                     if(d->i + 4 >= d->len) {
239                         return 0;
240                     }
241                     hi = int_from_hex(&(d->p[d->i]));
242                     if(hi < 0) {
243                         return 0;
244                     }
245                     d->i += 4;
246                     if(hi >= 0xD800 && hi < 0xDC00) {
247                         if(d->i + 6 >= d->len) {
248                             return 0;
249                         }
250                         if(d->p[d->i++] != '\\') {
251                             return 0;
252                         } else if(d->p[d->i++] != 'u') {
253                             return 0;
254                         }
255                         lo = int_from_hex(&(d->p[d->i]));
256                         if(lo < 0) {
257                             return 0;
258                         }
259                         hi = unicode_from_pair(hi, lo);
260                         if(hi < 0) {
261                             return 0;
262                         }
263                     }
264                     hi = utf8_len(hi);
265                     if(hi < 0) {
266                         return 0;
267                     }
268                     if(lo == 0) {
269                         num_escapes += 5 - hi;
270                     } else {
271                         num_escapes += 11 - hi;
272                     }
273                     break;
274                 default:
275                     return 0;
276             }
277         } else if(d->p[d->i] < 0x80) {
278             d->i++;
279         } else {
280             ulen = utf8_validate(&(d->p[d->i]), d->len - d->i);
281             if(ulen < 0) {
282                 return 0;
283             }
284             d->i += ulen;
285         }
286     }
287 
288     // The goto above ensures that we only
289     // hit this when a string is not terminated
290     // correctly.
291     return 0;
292 
293 parse:
294     if(!has_escape && !d->copy_strings) {
295         *value = enif_make_sub_binary(d->env, d->arg, st, (d->i - st - 1));
296         return 1;
297     } else if(!has_escape) {
298         ulen = d->i - 1 - st;
299         chrbuf = (char*) enif_make_new_binary(d->env, ulen, value),
300         memcpy(chrbuf, &(d->p[st]), ulen);
301         return 1;
302     }
303 
304     hi = 0;
305     lo = 0;
306 
307     ulen = (d->i - 1) - st - num_escapes;
308     chrbuf = (char*) enif_make_new_binary(d->env, ulen, value);
309     chrpos = 0;
310     ui = st;
311     while(ui < d->i - 1) {
312         if(d->p[ui] != '\\') {
313             chrbuf[chrpos++] = d->p[ui++];
314             continue;
315         }
316         ui++;
317         switch(d->p[ui]) {
318             case '\"':
319             case '\\':
320             case '/':
321                 chrbuf[chrpos++] = d->p[ui];
322                 ui++;
323                 break;
324             case 'b':
325                 chrbuf[chrpos++] = '\b';
326                 ui++;
327                 break;
328             case 'f':
329                 chrbuf[chrpos++] = '\f';
330                 ui++;
331                 break;
332             case 'n':
333                 chrbuf[chrpos++] = '\n';
334                 ui++;
335                 break;
336             case 'r':
337                 chrbuf[chrpos++] = '\r';
338                 ui++;
339                 break;
340             case 't':
341                 chrbuf[chrpos++] = '\t';
342                 ui++;
343                 break;
344             case 'u':
345                 ui++;
346                 hi = int_from_hex(&(d->p[ui]));
347                 if(hi < 0) {
348                     return 0;
349                 }
350                 if(hi >= 0xD800 && hi < 0xDC00) {
351                     lo = int_from_hex(&(d->p[ui+6]));
352                     if(lo < 0) {
353                         return 0;
354                     }
355                     hi = unicode_from_pair(hi, lo);
356                     ui += 10;
357                 } else {
358                     ui += 4;
359                 }
360                 hi = unicode_to_utf8(hi, (unsigned char*) chrbuf+chrpos);
361                 if(hi < 0) {
362                     return 0;
363                 }
364                 chrpos += hi;
365                 break;
366             default:
367                 return 0;
368         }
369     }
370 
371     return 1;
372 }
373 
374 int
dec_number(Decoder * d,ERL_NIF_TERM * value)375 dec_number(Decoder* d, ERL_NIF_TERM* value)
376 {
377     ERL_NIF_TERM num_type = d->atoms->atom_error;
378     char state = nst_init;
379     char nbuf[NUM_BUF_LEN];
380     int st = d->i;
381     int has_frac = 0;
382     int has_exp = 0;
383     double dval;
384     long lval;
385 
386     while(d->i < d->len) {
387         switch(state) {
388             case nst_init:
389                 switch(d->p[d->i]) {
390                     case '-':
391                         state = nst_sign;
392                         d->i++;
393                         break;
394                     case '0':
395                         state = nst_frac0;
396                         d->i++;
397                         break;
398                     case '1':
399                     case '2':
400                     case '3':
401                     case '4':
402                     case '5':
403                     case '6':
404                     case '7':
405                     case '8':
406                     case '9':
407                         state = nst_mantissa;
408                         d->i++;
409                         break;
410                     default:
411                         return 0;
412                 }
413                 break;
414 
415             case nst_sign:
416                 switch(d->p[d->i]) {
417                     case '0':
418                         state = nst_frac0;
419                         d->i++;
420                         break;
421                     case '1':
422                     case '2':
423                     case '3':
424                     case '4':
425                     case '5':
426                     case '6':
427                     case '7':
428                     case '8':
429                     case '9':
430                         state = nst_mantissa;
431                         d->i++;
432                         break;
433                     default:
434                         return 0;
435                 }
436                 break;
437 
438             case nst_mantissa:
439                 switch(d->p[d->i]) {
440                     case '.':
441                         state = nst_frac1;
442                         d->i++;
443                         break;
444                     case 'e':
445                     case 'E':
446                         state = nst_esign;
447                         d->i++;
448                         break;
449                     case '0':
450                     case '1':
451                     case '2':
452                     case '3':
453                     case '4':
454                     case '5':
455                     case '6':
456                     case '7':
457                     case '8':
458                     case '9':
459                         d->i++;
460                         break;
461                     default:
462                         goto parse;
463                 }
464                 break;
465 
466             case nst_frac0:
467                 switch(d->p[d->i]) {
468                     case '.':
469                         state = nst_frac1;
470                         d->i++;
471                         break;
472                     case 'e':
473                     case 'E':
474                         state = nst_esign;
475                         d->i++;
476                         break;
477                     default:
478                         goto parse;
479                 }
480                 break;
481 
482             case nst_frac1:
483                 has_frac = 1;
484                 switch(d->p[d->i]) {
485                     case '0':
486                     case '1':
487                     case '2':
488                     case '3':
489                     case '4':
490                     case '5':
491                     case '6':
492                     case '7':
493                     case '8':
494                     case '9':
495                         state = nst_frac;
496                         d->i++;
497                         break;
498                     default:
499                         goto parse;
500                 }
501                 break;
502 
503             case nst_frac:
504                 switch(d->p[d->i]) {
505                     case 'e':
506                     case 'E':
507                         state = nst_esign;
508                         d->i++;
509                         break;
510                     case '0':
511                     case '1':
512                     case '2':
513                     case '3':
514                     case '4':
515                     case '5':
516                     case '6':
517                     case '7':
518                     case '8':
519                     case '9':
520                         d->i++;
521                         break;
522                     default:
523                         goto parse;
524                 }
525                 break;
526 
527             case nst_esign:
528                 has_exp = 1;
529                 switch(d->p[d->i]) {
530                     case '-':
531                     case '+':
532                     case '0':
533                     case '1':
534                     case '2':
535                     case '3':
536                     case '4':
537                     case '5':
538                     case '6':
539                     case '7':
540                     case '8':
541                     case '9':
542                         state = nst_edigit;
543                         d->i++;
544                         break;
545                     default:
546                         return 0;
547                 }
548                 break;
549 
550             case nst_edigit:
551                 switch(d->p[d->i]) {
552                     case '0':
553                     case '1':
554                     case '2':
555                     case '3':
556                     case '4':
557                     case '5':
558                     case '6':
559                     case '7':
560                     case '8':
561                     case '9':
562                         d->i++;
563                         break;
564                     default:
565                         goto parse;
566                 }
567                 break;
568 
569             default:
570                 return 0;
571         }
572     }
573 
574 parse:
575 
576     switch(state) {
577         case nst_init:
578         case nst_sign:
579         case nst_frac1:
580         case nst_esign:
581             return 0;
582         default:
583             break;
584     }
585 
586     errno = 0;
587 
588     if(d->i - st < NUM_BUF_LEN) {
589         memset(nbuf, 0, NUM_BUF_LEN);
590         memcpy(nbuf, &(d->p[st]), d->i - st);
591 
592         if(has_frac || has_exp) {
593             dval = strtod(nbuf, NULL);
594             if(errno != ERANGE) {
595                 *value = enif_make_double(d->env, dval);
596                 return 1;
597             }
598         } else {
599             lval = strtol(nbuf, NULL, 10);
600             if(errno != ERANGE) {
601                 *value = enif_make_int64(d->env, lval);
602                 return 1;
603             }
604         }
605     }
606 
607     if(!has_frac && !has_exp) {
608         num_type = d->atoms->atom_bignum;
609     } else if(!has_frac && has_exp) {
610         num_type = d->atoms->atom_bignum_e;
611     } else {
612         num_type = d->atoms->atom_bigdbl;
613     }
614 
615     d->is_partial = 1;
616     *value = enif_make_sub_binary(d->env, d->arg, st, d->i - st);
617     *value = enif_make_tuple2(d->env, num_type, *value);
618     return 1;
619 }
620 
621 ERL_NIF_TERM
make_empty_object(ErlNifEnv * env,int ret_map)622 make_empty_object(ErlNifEnv* env, int ret_map)
623 {
624 #if MAP_TYPE_PRESENT
625     if(ret_map) {
626         return enif_make_new_map(env);
627     }
628 #endif
629 
630     return enif_make_tuple1(env, enif_make_list(env, 0));
631 }
632 
633 ERL_NIF_TERM
make_array(ErlNifEnv * env,ERL_NIF_TERM list)634 make_array(ErlNifEnv* env, ERL_NIF_TERM list)
635 {
636     ERL_NIF_TERM ret = enif_make_list(env, 0);
637     ERL_NIF_TERM item;
638 
639     while(enif_get_list_cell(env, list, &item, &list)) {
640         ret = enif_make_list_cell(env, item, ret);
641     }
642 
643     return ret;
644 }
645 
646 ERL_NIF_TERM
decode_init(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])647 decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
648 {
649     Decoder* d;
650     jiffy_st* st = (jiffy_st*) enif_priv_data(env);
651     ERL_NIF_TERM tmp_argv[5];
652     ERL_NIF_TERM opts;
653     ERL_NIF_TERM val;
654 
655     if(argc != 2) {
656         return enif_make_badarg(env);
657     }
658 
659     d = dec_new(env);
660     if(d == NULL) {
661         return make_error(st, env, "internal_error");
662     }
663 
664     tmp_argv[0] = argv[0];
665     tmp_argv[1] = enif_make_resource(env, d);
666     tmp_argv[2] = st->atom_error;
667     tmp_argv[3] = enif_make_list(env, 0);
668     tmp_argv[4] = enif_make_list(env, 0);
669 
670     enif_release_resource(d);
671 
672     opts = argv[1];
673     if(!enif_is_list(env, opts)) {
674         return enif_make_badarg(env);
675     }
676 
677     while(enif_get_list_cell(env, opts, &val, &opts)) {
678         if(get_bytes_per_iter(env, val, &(d->bytes_per_red))) {
679             continue;
680         } else if(get_bytes_per_red(env, val, &(d->bytes_per_red))) {
681             continue;
682         } else if(enif_is_identical(val, d->atoms->atom_return_maps)) {
683 #if MAP_TYPE_PRESENT
684             d->return_maps = 1;
685 #else
686             return enif_make_badarg(env);
687 #endif
688         } else if(enif_is_identical(val, d->atoms->atom_return_trailer)) {
689             d->return_trailer = 1;
690         } else if(enif_is_identical(val, d->atoms->atom_dedupe_keys)) {
691             d->dedupe_keys = 1;
692         } else if(enif_is_identical(val, d->atoms->atom_copy_strings)) {
693             d->copy_strings = 1;
694         } else if(enif_is_identical(val, d->atoms->atom_use_nil)) {
695             d->null_term = d->atoms->atom_nil;
696         } else if(get_null_term(env, val, &(d->null_term))) {
697             continue;
698         } else {
699             return enif_make_badarg(env);
700         }
701     }
702 
703     return decode_iter(env, 5, tmp_argv);
704 }
705 
706 ERL_NIF_TERM
decode_iter(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])707 decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
708 {
709     Decoder* d;
710     jiffy_st* st = (jiffy_st*) enif_priv_data(env);
711 
712     ErlNifBinary bin;
713 
714     ERL_NIF_TERM objs;
715     ERL_NIF_TERM curr;
716     ERL_NIF_TERM val = argv[2];
717     ERL_NIF_TERM trailer;
718     ERL_NIF_TERM ret;
719     ERL_NIF_TERM tmp_argv[5];
720 
721     void* res;
722 
723     size_t start;
724     size_t bytes_processed = 0;
725 
726     if(!enif_inspect_binary(env, argv[0], &bin)) {
727         return enif_make_badarg(env);
728     } else if(!enif_get_resource(env, argv[1], st->res_dec, &res)) {
729         return enif_make_badarg(env);
730     }
731 
732     d = (Decoder*) res;
733 
734     dec_init(d, env, argv[0], &bin);
735     objs = argv[3];
736     curr = argv[4];
737 
738     start = d->i;
739 
740     while(d->i < bin.size) {
741         bytes_processed = d->i - start;
742 
743         if(should_yield(bytes_processed, d->bytes_per_red)) {
744             assert(enif_is_list(env, objs));
745             assert(enif_is_list(env, curr));
746 
747             tmp_argv[0] = argv[0];
748             tmp_argv[1] = argv[1];
749             tmp_argv[2] = val;
750             tmp_argv[3] = objs;
751             tmp_argv[4] = curr;
752 
753             bump_used_reds(env, bytes_processed, d->bytes_per_red);
754 
755 #if SCHEDULE_NIF_PRESENT
756             return enif_schedule_nif(
757                     env,
758                     "nif_decode_iter",
759                     0,
760                     decode_iter,
761                     5,
762                     tmp_argv
763                 );
764 #else
765             return enif_make_tuple2(
766                     env,
767                     st->atom_iter,
768                     enif_make_tuple_from_array(env, tmp_argv, 5)
769                 );
770 #endif
771         }
772 
773         switch(dec_curr(d)) {
774             case st_value:
775                 switch(d->p[d->i]) {
776                     case ' ':
777                     case '\n':
778                     case '\r':
779                     case '\t':
780                         d->i++;
781                         break;
782                     case 'n':
783                         if(d->i + 3 >= d->len) {
784                             ret = dec_error(d, "invalid_literal");
785                             goto done;
786                         }
787                         if(memcmp(&(d->p[d->i]), "null", 4) != 0) {
788                             ret = dec_error(d, "invalid_literal");
789                             goto done;
790                         }
791                         val = d->null_term;
792                         dec_pop_assert(d, st_value);
793                         d->i += 4;
794                         break;
795                     case 't':
796                         if(d->i + 3 >= d->len) {
797                             ret = dec_error(d, "invalid_literal");
798                             goto done;
799                         }
800                         if(memcmp(&(d->p[d->i]), "true", 4) != 0) {
801                             ret = dec_error(d, "invalid_literal");
802                             goto done;
803                         }
804                         val = d->atoms->atom_true;
805                         dec_pop_assert(d, st_value);
806                         d->i += 4;
807                         break;
808                     case 'f':
809                         if(d->i + 4 >= bin.size) {
810                             ret = dec_error(d, "invalid_literal");
811                             goto done;
812                         }
813                         if(memcmp(&(d->p[d->i]), "false", 5) != 0) {
814                             ret = dec_error(d, "invalid_literal");
815                             goto done;
816                         }
817                         val = d->atoms->atom_false;
818                         dec_pop_assert(d, st_value);
819                         d->i += 5;
820                         break;
821                     case '\"':
822                         if(!dec_string(d, &val)) {
823                             ret = dec_error(d, "invalid_string");
824                             goto done;
825                         }
826                         dec_pop_assert(d, st_value);
827                         break;
828                     case '-':
829                     case '0':
830                     case '1':
831                     case '2':
832                     case '3':
833                     case '4':
834                     case '5':
835                     case '6':
836                     case '7':
837                     case '8':
838                     case '9':
839                         if(!dec_number(d, &val)) {
840                             ret = dec_error(d, "invalid_number");
841                             goto done;
842                         }
843                         dec_pop_assert(d, st_value);
844                         break;
845                     case '{':
846                         dec_push(d, st_object);
847                         dec_push(d, st_key);
848                         objs = enif_make_list_cell(env, curr, objs);
849                         curr = enif_make_list(env, 0);
850                         d->i++;
851                         break;
852                     case '[':
853                         dec_push(d, st_array);
854                         dec_push(d, st_value);
855                         objs = enif_make_list_cell(env, curr, objs);
856                         curr = enif_make_list(env, 0);
857                         d->i++;
858                         break;
859                     case ']':
860                         if(!enif_is_empty_list(env, curr)) {
861                             ret = dec_error(d, "invalid_json");
862                             goto done;
863                         }
864                         dec_pop_assert(d, st_value);
865                         if(dec_pop(d) != st_array) {
866                             ret = dec_error(d, "invalid_json");
867                             goto done;
868                         }
869                         dec_pop_assert(d, st_value);
870                         val = curr; // curr is []
871                         if(!enif_get_list_cell(env, objs, &curr, &objs)) {
872                             ret = dec_error(d, "internal_error");
873                             goto done;
874                         }
875                         d->i++;
876                         break;
877                     default:
878                         ret = dec_error(d, "invalid_json");
879                         goto done;
880                 }
881                 if(dec_top(d) == 0) {
882                     dec_push(d, st_done);
883                 } else if(dec_curr(d) != st_value && dec_curr(d) != st_key) {
884                     dec_push(d, st_comma);
885                     curr = enif_make_list_cell(env, val, curr);
886                 }
887                 break;
888 
889             case st_key:
890                 switch(d->p[d->i]) {
891                     case ' ':
892                     case '\n':
893                     case '\r':
894                     case '\t':
895                         d->i++;
896                         break;
897                     case '\"':
898                         if(!dec_string(d, &val)) {
899                             ret = dec_error(d, "invalid_string");
900                             goto done;
901                         }
902                         dec_pop_assert(d, st_key);
903                         dec_push(d, st_colon);
904                         curr = enif_make_list_cell(env, val, curr);
905                         break;
906                     case '}':
907                         if(!enif_is_empty_list(env, curr)) {
908                             ret = dec_error(d, "invalid_json");
909                             goto done;
910                         }
911                         dec_pop_assert(d, st_key);
912                         dec_pop_assert(d, st_object);
913                         dec_pop_assert(d, st_value);
914                         val = make_empty_object(env, d->return_maps);
915                         if(!enif_get_list_cell(env, objs, &curr, &objs)) {
916                             ret = dec_error(d, "internal_error");
917                             goto done;
918                         }
919                         if(dec_top(d) == 0) {
920                             dec_push(d, st_done);
921                         } else {
922                             dec_push(d, st_comma);
923                             curr = enif_make_list_cell(env, val, curr);
924                         }
925                         d->i++;
926                         break;
927                     default:
928                         ret = dec_error(d, "invalid_json");
929                         goto done;
930                 }
931                 break;
932 
933             case st_colon:
934                 switch(d->p[d->i]) {
935                     case ' ':
936                     case '\n':
937                     case '\r':
938                     case '\t':
939                         d->i++;
940                         break;
941                     case ':':
942                         dec_pop_assert(d, st_colon);
943                         dec_push(d, st_value);
944                         d->i++;
945                         break;
946                     default:
947                         ret = dec_error(d, "invalid_json");
948                         goto done;
949                 }
950                 break;
951 
952             case st_comma:
953                 switch(d->p[d->i]) {
954                     case ' ':
955                     case '\n':
956                     case '\r':
957                     case '\t':
958                         d->i++;
959                         break;
960                     case ',':
961                         dec_pop_assert(d, st_comma);
962                         switch(dec_curr(d)) {
963                             case st_object:
964                                 dec_push(d, st_key);
965                                 break;
966                             case st_array:
967                                 dec_push(d, st_value);
968                                 break;
969                             default:
970                                 ret = dec_error(d, "internal_error");
971                                 goto done;
972                         }
973                         d->i++;
974                         break;
975                     case '}':
976                         dec_pop_assert(d, st_comma);
977                         if(dec_pop(d) != st_object) {
978                             ret = dec_error(d, "invalid_json");
979                             goto done;
980                         }
981                         dec_pop_assert(d, st_value);
982                         if(!make_object(env, curr, &val,
983                                 d->return_maps, d->dedupe_keys)) {
984                             ret = dec_error(d, "internal_object_error");
985                             goto done;
986                         }
987                         if(!enif_get_list_cell(env, objs, &curr, &objs)) {
988                             ret = dec_error(d, "internal_error");
989                             goto done;
990                         }
991                         if(dec_top(d) > 0) {
992                             dec_push(d, st_comma);
993                             curr = enif_make_list_cell(env, val, curr);
994                         } else {
995                             dec_push(d, st_done);
996                         }
997                         d->i++;
998                         break;
999                     case ']':
1000                         dec_pop_assert(d, st_comma);
1001                         if(dec_pop(d) != st_array) {
1002                             ret = dec_error(d, "invalid_json");
1003                             goto done;
1004                         }
1005                         dec_pop_assert(d, st_value);
1006                         val = make_array(env, curr);
1007                         if(!enif_get_list_cell(env, objs, &curr, &objs)) {
1008                             ret = dec_error(d, "internal_error");
1009                             goto done;
1010                         }
1011                         if(dec_top(d) > 0) {
1012                             dec_push(d, st_comma);
1013                             curr = enif_make_list_cell(env, val, curr);
1014                         } else {
1015                             dec_push(d, st_done);
1016                         }
1017                         d->i++;
1018                         break;
1019                     default:
1020                         ret = dec_error(d, "invalid_json");
1021                         goto done;
1022                 }
1023                 break;
1024 
1025             case st_done:
1026                 switch(d->p[d->i]) {
1027                     case ' ':
1028                     case '\n':
1029                     case '\r':
1030                     case '\t':
1031                         d->i++;
1032                         break;
1033                     default:
1034                         goto decode_done;
1035                 }
1036                 break;
1037 
1038             default:
1039                 ret = dec_error(d, "invalid_internal_state");
1040                 goto done;
1041         }
1042     }
1043 
1044 decode_done:
1045 
1046     if(d->i < bin.size && d->return_trailer) {
1047         trailer = enif_make_sub_binary(env, argv[0], d->i, bin.size - d->i);
1048         val = enif_make_tuple3(env, d->atoms->atom_has_trailer, val, trailer);
1049     } else if(d->i < bin.size) {
1050         ret = dec_error(d, "invalid_trailing_data");
1051         goto done;
1052     }
1053 
1054     if(dec_pop(d) != st_done) {
1055         ret = dec_error(d, "truncated_json");
1056     } else if(d->is_partial) {
1057         ret = enif_make_tuple2(env, d->atoms->atom_partial, val);
1058     } else {
1059         ret = val;
1060     }
1061 
1062 done:
1063     bump_used_reds(env, bytes_processed, d->bytes_per_red);
1064 
1065     return ret;
1066 }
1067