/*
 * Copyright (C) 2009 Vincent Hanquez <vincent@snarc.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; version 2.1 or version 3.0 only.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/*
 * the class, states and state transition tables has been inspired by the JSON_parser.c
 * available at http://json.org, but are quite different on the way that the
 * parser handles its parse buffer and contains significant differences that affect
 * the JSON compliance.
 */

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "json.h"

#ifdef TRACING_ENABLE
#include <stdio.h>
#define TRACING(fmt, ...)	fprintf(stderr, "tracing: " fmt, ##__VA_ARGS__)
#else
#define TRACING(fmt, ...)	((void) 0)
#endif

enum classes {
	C_SPACE, /* space */
	C_NL,    /* newline */
	C_WHITE, /* tab, CR */
	C_LCURB, C_RCURB, /* object opening/closing */
	C_LSQRB, C_RSQRB, /* array opening/closing */
	/* syntax symbols */
	C_COLON,
	C_COMMA,
	C_QUOTE, /* " */
	C_BACKS, /* \ */
	C_SLASH, /* / */
	C_PLUS,
	C_MINUS,
	C_DOT,
	C_ZERO, C_DIGIT, /* digits */
	C_a, C_b, C_c, C_d, C_e, C_f, C_l, C_n, C_r, C_s, C_t, C_u, /* nocaps letters */
	C_ABCDF, C_E, /* caps letters */
	C_OTHER, /* all other */
	C_STAR, /* star in C style comment */
	C_HASH, /* # for YAML comment */
	C_ERROR = 0xfe,
};

/* map from character < 128 to classes. from 128 to 256 all C_OTHER */
static uint8_t character_class[128] = {
	C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR,
	C_ERROR, C_WHITE, C_NL,    C_ERROR, C_ERROR, C_WHITE, C_ERROR, C_ERROR,
	C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR,
	C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR, C_ERROR,

	C_SPACE, C_OTHER, C_QUOTE, C_HASH,  C_OTHER, C_OTHER, C_OTHER, C_OTHER,
	C_OTHER, C_OTHER, C_STAR,  C_PLUS,  C_COMMA, C_MINUS, C_DOT,   C_SLASH,
	C_ZERO,  C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT,
	C_DIGIT, C_DIGIT, C_COLON, C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER,

	C_OTHER, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E,     C_ABCDF, C_OTHER,
	C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER,
	C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_OTHER,
	C_OTHER, C_OTHER, C_OTHER, C_LSQRB, C_BACKS, C_RSQRB, C_OTHER, C_OTHER,

	C_OTHER, C_a,     C_b,     C_c,     C_d,     C_e,     C_f,     C_OTHER,
	C_OTHER, C_OTHER, C_OTHER, C_OTHER, C_l,     C_OTHER, C_n,     C_OTHER,
	C_OTHER, C_OTHER, C_r,     C_s,     C_t,     C_u,     C_OTHER, C_OTHER,
	C_OTHER, C_OTHER, C_OTHER, C_LCURB, C_OTHER, C_RCURB, C_OTHER, C_OTHER
};

/* only the first 36 ascii characters need an escape */
static char *character_escape[36] = {
	"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", /*  0-7  */
	"\\b"    ,     "\\t",     "\\n", "\\u000b",     "\\f",     "\\r", "\\u000e", "\\u000f", /*  8-f  */
	"\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", /* 10-17 */
	"\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f", /* 18-1f */
	" "      , "!"      , "\\\""   , "#",
};

/* define all states and actions that will be taken on each transition.
 *
 * states are defined first because of the fact they are use as index in the
 * transitions table. they usually contains either a number or a prefix _ 
 * for simple state like string, object, value ...
 *
 * actions are defined starting from 0x80. state error is defined as 0xff
 */

enum states {
	STATE_GO, /* start  */
	STATE_OK, /* ok     */
	STATE__O, /* object */
	STATE__K, /* key    */
	STATE_CO, /* colon  */
	STATE__V, /* value  */
	STATE__A, /* array  */
	STATE__S, /* string */
	STATE_E0, /* escape */
	STATE_U1, STATE_U2, STATE_U3, STATE_U4, /* unicode states */
	STATE_M0, STATE_Z0, STATE_I0, /* number states */
	STATE_R1, STATE_R2, /* real states (after-dot digits) */
	STATE_X1, STATE_X2, STATE_X3, /* exponant states */
	STATE_T1, STATE_T2, STATE_T3, /* true constant states */
	STATE_F1, STATE_F2, STATE_F3, STATE_F4, /* false constant states */
	STATE_N1, STATE_N2, STATE_N3, /* null constant states */
	STATE_C1, STATE_C2, STATE_C3, /* C-comment states */
	STATE_Y1, /* YAML-comment state */
	STATE_D1, STATE_D2, /* multi unicode states */
};

/* the following are actions that need to be taken */
enum actions {
	STATE_KS = 0x80, /* key separator */
	STATE_SP, /* comma separator */
	STATE_AB, /* array begin */
	STATE_AE, /* array ending */
	STATE_OB, /* object begin */
	STATE_OE, /* object end */
	STATE_CB, /* C-comment begin */
	STATE_YB, /* YAML-comment begin */
	STATE_CE, /* YAML/C comment end */
	STATE_FA, /* false */
	STATE_TR, /* true */
	STATE_NU, /* null */
	STATE_DE, /* double detected by exponent */
	STATE_DF, /* double detected by . */
	STATE_SE, /* string end */
	STATE_MX, /* integer detected by minus */
	STATE_ZX, /* integer detected by zero */
	STATE_IX, /* integer detected by 1-9 */
	STATE_UC, /* Unicode character read */
};

/* error state */
#define STATE___ 	0xff

#define NR_STATES 	(STATE_D2 + 1)
#define NR_CLASSES	(C_HASH + 1)

#define IS_STATE_ACTION(s) ((s) & 0x80)
#define S(x) STATE_##x
#define PT_(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,a1,b1,c1,d1,e1,f1,g1,h1)	\
	{ S(a),S(b),S(c),S(d),S(e),S(f),S(g),S(h),S(i),S(j),S(k),S(l),S(m),S(n),		\
	  S(o),S(p),S(q),S(r),S(s),S(t),S(u),S(v),S(w),S(x),S(y),S(z),S(a1),S(b1),		\
	  S(c1),S(d1),S(e1),S(f1),S(g1),S(h1) }

/* map from the (previous state+new character class) to the next parser transition */
static const uint8_t state_transition_table[NR_STATES][NR_CLASSES] = {
/*             white                                                                            ABCDF  other    */
/*         sp nl |  {  }  [  ]  :  ,  "  \  /  +  -  .  0  19 a  b  c  d  e  f  l  n  r  s  t  u  |  E  |  *  # */
/*GO*/ PT_(GO,GO,GO,OB,__,AB,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,YB),
/*OK*/ PT_(OK,OK,OK,__,OE,__,AE,__,SP,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,YB),
/*_O*/ PT_(_O,_O,_O,__,OE,__,__,__,__,_S,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,YB),
/*_K*/ PT_(_K,_K,_K,__,__,__,__,__,__,_S,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,YB),
/*CO*/ PT_(CO,CO,CO,__,__,__,__,KS,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,YB),
/*_V*/ PT_(_V,_V,_V,OB,__,AB,__,__,__,_S,__,CB,__,MX,__,ZX,IX,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__,__,YB),
/*_A*/ PT_(_A,_A,_A,OB,__,AB,AE,__,__,_S,__,CB,__,MX,__,ZX,IX,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__,__,YB),
/****************************************************************************************************************/
/*_S*/ PT_(_S,__,__,_S,_S,_S,_S,_S,_S,SE,E0,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S,_S),
/*E0*/ PT_(__,__,__,__,__,__,__,__,__,_S,_S,_S,__,__,__,__,__,__,_S,__,__,__,_S,__,_S,_S,__,_S,U1,__,__,__,__,__),
/*U1*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__,__,__),
/*U2*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__,__,__),
/*U3*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__,__,__),
/*U4*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,UC,UC,UC,UC,UC,UC,UC,UC,__,__,__,__,__,__,UC,UC,__,__,__),
/****************************************************************************************************************/
/*M0*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,Z0,I0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__),
/*Z0*/ PT_(OK,OK,OK,__,OE,__,AE,__,SP,__,__,CB,__,__,DF,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,YB),
/*I0*/ PT_(OK,OK,OK,__,OE,__,AE,__,SP,__,__,CB,__,__,DF,I0,I0,__,__,__,__,DE,__,__,__,__,__,__,__,__,DE,__,__,YB),
/*R1*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,R2,R2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__),
/*R2*/ PT_(OK,OK,OK,__,OE,__,AE,__,SP,__,__,CB,__,__,__,R2,R2,__,__,__,__,X1,__,__,__,__,__,__,__,__,X1,__,__,YB),
/*X1*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,X2,X2,__,X3,X3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__),
/*X2*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,X3,X3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__),
/*X3*/ PT_(OK,OK,OK,__,OE,__,AE,__,SP,__,__,__,__,__,__,X3,X3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__),
/****************************************************************************************************************/
/*T1*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__,__,__),
/*T2*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__,__,__),
/*T3*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,TR,__,__,__,__,__,__,__,__,__,__,__,__),
/*F1*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__),
/*F2*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__,__,__),
/*F3*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__,__,__),
/*F4*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,FA,__,__,__,__,__,__,__,__,__,__,__,__),
/*N1*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__,__,__),
/*N2*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__,__,__),
/*N3*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,NU,__,__,__,__,__,__,__,__,__,__),
/****************************************************************************************************************/
/*C1*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,C2,__),
/*C2*/ PT_(C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3,C2),
/*C3*/ PT_(C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,CE,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3,C2),
/*Y1*/ PT_(Y1,CE,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1,Y1),
/*D1*/ PT_(__,__,__,__,__,__,__,__,__,__,D2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__),
/*D2*/ PT_(__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,U1,__,__,__,__,__),
};
#undef S
#undef PT_

/* map from (previous state+new character class) to the buffer policy. ignore=0/append=1/escape=2 */
static const uint8_t buffer_policy_table[NR_STATES][NR_CLASSES] = {
/*          white                                                                            ABCDF  other     */
/*      sp nl  |  {  }  [  ]  :  ,  "  \  /  +  -  .  0  19 a  b  c  d  e  f  l  n  r  s  t  u  |  E  |  *  # */
/*GO*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*OK*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*_O*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*_K*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*CO*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*_V*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*_A*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/**************************************************************************************************************/
/*_S*/ { 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
/*E0*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0 },
/*U1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 },
/*U2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 },
/*U3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 },
/*U4*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 },
/**************************************************************************************************************/
/*M0*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*Z0*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*I0*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
/*R1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*R2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
/*X1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*X2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*X3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/**************************************************************************************************************/
/*T1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*T2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*T3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*F1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*F2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*F3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*F4*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*N1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*N2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*N3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/**************************************************************************************************************/
/*C1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*C2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*C3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*Y1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*D1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/*D2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};

#define MODE_ARRAY 0
#define MODE_OBJECT 1

static inline void *memory_realloc(void *(*realloc_fct)(void *, size_t), void *ptr, size_t size)
{
	return (realloc_fct) ? realloc_fct(ptr, size) : realloc(ptr, size);
}

static inline void *memory_calloc(void *(*calloc_fct)(size_t, size_t), size_t nmemb, size_t size)
{
	return (calloc_fct) ? calloc_fct(nmemb, size) : calloc(nmemb, size);
}

#define parser_calloc(parser, n, s) memory_calloc(parser->config.user_calloc, n, s)
#define parser_realloc(parser, n, s) memory_realloc(parser->config.user_realloc, n, s)

static int state_grow(json_parser *parser)
{
	uint32_t newsize = parser->stack_size * 2;
	void *ptr;

	if (parser->config.max_nesting != 0)
		return JSON_ERROR_NESTING_LIMIT;

	ptr = parser_realloc(parser, parser->stack, newsize * sizeof(uint8_t));
	if (!ptr)
		return JSON_ERROR_NO_MEMORY;
	parser->stack = ptr;
	parser->stack_size = newsize;
	return 0;
}

static int state_push(json_parser *parser, int mode)
{
	if (parser->stack_offset >= parser->stack_size) {
		int ret = state_grow(parser);
		if (ret)
			return ret;
	}
	parser->stack[parser->stack_offset++] = mode;
	return 0;
}

static int state_pop(json_parser *parser, int mode)
{
	if (parser->stack_offset == 0)
		return JSON_ERROR_POP_EMPTY;
	parser->stack_offset--;
	if (parser->stack[parser->stack_offset] != mode)
		return JSON_ERROR_POP_UNEXPECTED_MODE;
	return 0;
}

static int buffer_grow(json_parser *parser)
{
	uint32_t newsize;
	void *ptr;
	int max = parser->config.max_data;

	if (max > 0 && parser->buffer_size == max)
		return JSON_ERROR_DATA_LIMIT;
	newsize = parser->buffer_size * 2;
	if (max > 0 && newsize > max)
		newsize = max;

	ptr = parser_realloc(parser, parser->buffer, newsize * sizeof(char));
	if (!ptr)
		return JSON_ERROR_NO_MEMORY;
	parser->buffer = ptr;
	parser->buffer_size = newsize;
	return 0;
}

static int buffer_push(json_parser *parser, unsigned char c)
{
	int ret;

	if (parser->buffer_offset + 1 >= parser->buffer_size) {
		ret = buffer_grow(parser);
		if (ret)
			return ret;
	}
	parser->buffer[parser->buffer_offset++] = c;
	return 0;
}

static int do_callback_withbuf(json_parser *parser, int type)
{
	if (!parser->callback)
		return 0;
	parser->buffer[parser->buffer_offset] = '\0';
	return (*parser->callback)(parser->userdata, type, parser->buffer, parser->buffer_offset);
}

static int do_callback(json_parser *parser, int type)
{
	if (!parser->callback)
		return 0;
	return (*parser->callback)(parser->userdata, type, NULL, 0);
}

static int do_buffer(json_parser *parser)
{
	int ret = 0;

	switch (parser->type) {
	case JSON_KEY: case JSON_STRING:
	case JSON_FLOAT: case JSON_INT:
	case JSON_NULL: case JSON_TRUE: case JSON_FALSE:
		ret = do_callback_withbuf(parser, parser->type);
		if (ret)
			return ret;
		break;
	default:
		break;
	}
	parser->buffer_offset = 0;
	return ret;
}

static const uint8_t hextable[] = {
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
	-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};

#define hex(c) (hextable[(uint8_t) c])

/* high surrogate range from d800 to dbff */
/* low surrogate range dc00 to dfff */
#define IS_HIGH_SURROGATE(uc) (((uc) & 0xfc00) == 0xd800)
#define IS_LOW_SURROGATE(uc)  (((uc) & 0xfc00) == 0xdc00)

/* transform an unicode [0-9A-Fa-f]{4} sequence into a proper value */
static int decode_unicode_char(json_parser *parser)
{
	uint32_t uval;
	char *b = parser->buffer;
	int offset = parser->buffer_offset;

	uval = (hex(b[offset - 4]) << 12) | (hex(b[offset - 3]) << 8)
	     | (hex(b[offset - 2]) << 4) | hex(b[offset - 1]);

	parser->buffer_offset -= 4;

	/* fast case */
	if (!parser->unicode_multi && uval < 0x80) {
		b[parser->buffer_offset++] = (char) uval;
		return 0;
	}

	if (parser->unicode_multi) {
		if (!IS_LOW_SURROGATE(uval))
			return JSON_ERROR_UNICODE_MISSING_LOW_SURROGATE;

		uval = 0x10000 + ((parser->unicode_multi & 0x3ff) << 10) + (uval & 0x3ff);
		b[parser->buffer_offset++] = (char) ((uval >> 18) | 0xf0);
		b[parser->buffer_offset++] = (char) (((uval >> 12) & 0x3f) | 0x80);
		b[parser->buffer_offset++] = (char) (((uval >> 6) & 0x3f) | 0x80);
		b[parser->buffer_offset++] = (char) ((uval & 0x3f) | 0x80);
		parser->unicode_multi = 0;
		return 0;
	}

	if (IS_LOW_SURROGATE(uval))
		return JSON_ERROR_UNICODE_UNEXPECTED_LOW_SURROGATE;
	if (IS_HIGH_SURROGATE(uval)) {
		parser->unicode_multi = uval;
		return 0;
	}

	if (uval < 0x800) {
		b[parser->buffer_offset++] = (char) ((uval >> 6) | 0xc0);
		b[parser->buffer_offset++] = (char) ((uval & 0x3f) | 0x80);
	} else {
		b[parser->buffer_offset++] = (char) ((uval >> 12) | 0xe0);
		b[parser->buffer_offset++] = (char) (((uval >> 6) & 0x3f) | 0x80);
		b[parser->buffer_offset++] = (char) (((uval >> 0) & 0x3f) | 0x80);
	}
	return 0;
}

static int buffer_push_escape(json_parser *parser, unsigned char next)
{
	char c = '\0';

	switch (next) {
	case 'b': c = '\b'; break;
	case 'f': c = '\f'; break;
	case 'n': c = '\n'; break;
	case 'r': c = '\r'; break;
	case 't': c = '\t'; break;
	case '"': c = '"'; break;
	case '/': c = '/'; break;
	case '\\': c = '\\'; break;
	}
	/* push the escaped character */
	return buffer_push(parser, c);
}

#define CHK(f) ({ ret = f; if (ret) return ret; })

int act_uc(json_parser *parser)
{
	int ret;
	CHK(decode_unicode_char(parser));
	parser->state = (parser->unicode_multi) ? STATE_D1 : STATE__S;
	return 0;
}

int act_yb(json_parser *parser)
{
	if (!parser->config.allow_yaml_comments)
		return JSON_ERROR_COMMENT_NOT_ALLOWED;
	parser->save_state = parser->state;
	return 0;
}

int act_cb(json_parser *parser)
{
	if (!parser->config.allow_c_comments)
		return JSON_ERROR_COMMENT_NOT_ALLOWED;
	parser->save_state = parser->state;
	return 0;
}

int act_ce(json_parser *parser)
{
	parser->state = (parser->save_state > STATE__A) ? STATE_OK : parser->save_state;
	return 0;
}

int act_ob(json_parser *parser)
{
	int ret;
	CHK(do_callback(parser, JSON_OBJECT_BEGIN));
	CHK(state_push(parser, MODE_OBJECT));
	parser->expecting_key = 1;
	return 0;
}

int act_oe(json_parser *parser)
{
	int ret;
	CHK(do_callback(parser, JSON_OBJECT_END));
	CHK(state_pop(parser, MODE_OBJECT));
	parser->expecting_key = 0;
	return 0;
}

int act_ab(json_parser *parser)
{
	int ret;
	CHK(do_callback(parser, JSON_ARRAY_BEGIN));
	CHK(state_push(parser, MODE_ARRAY));
	return 0;
}
int act_ae(json_parser *parser)
{
	int ret;
	CHK(do_callback(parser, JSON_ARRAY_END));
	CHK(state_pop(parser, MODE_ARRAY));
	return 0;
}

int act_se(json_parser *parser)
{
	int ret;
	CHK(do_callback_withbuf(parser, (parser->expecting_key) ? JSON_KEY : JSON_STRING));
	parser->buffer_offset = 0;
	parser->state = (parser->expecting_key) ? STATE_CO : STATE_OK;
	parser->expecting_key = 0;
	return 0;
}

int act_sp(json_parser *parser)
{
	if (parser->stack_offset == 0)
		return JSON_ERROR_COMMA_OUT_OF_STRUCTURE;
	if (parser->stack[parser->stack_offset - 1] == MODE_OBJECT) {
		parser->expecting_key = 1;
		parser->state = STATE__K;
	} else
		parser->state = STATE__V;
	return 0;
}

struct action_descr
{
	int (*call)(json_parser *parser);
	uint8_t type;
	uint8_t state; /* 0 if we let the callback set the value it want */
	uint8_t dobuffer;
};

static struct action_descr actions_map[] = {
	[STATE_MX & ~0x80] = { NULL,   JSON_INT,   STATE_M0, 0 },
	[STATE_ZX & ~0x80] = { NULL,   JSON_INT,   STATE_Z0, 0 },
	[STATE_IX & ~0x80] = { NULL,   JSON_INT,   STATE_I0, 0 },
	[STATE_DE & ~0x80] = { NULL,   JSON_FLOAT, STATE_X1, 0 },
	[STATE_DF & ~0x80] = { NULL,   JSON_FLOAT, STATE_R1, 0 },
	[STATE_NU & ~0x80] = { NULL,   JSON_NULL,  STATE_OK, 0 },
	[STATE_FA & ~0x80] = { NULL,   JSON_FALSE, STATE_OK, 0 },
	[STATE_TR & ~0x80] = { NULL,   JSON_TRUE,  STATE_OK, 0 },
	[STATE_KS & ~0x80] = { NULL,   JSON_NONE,  STATE__V, 0 },
	[STATE_UC & ~0x80] = { act_uc, JSON_NONE,  0,        0 },
	[STATE_YB & ~0x80] = { act_yb, JSON_NONE,  STATE_Y1, 1 },
	[STATE_CB & ~0x80] = { act_cb, JSON_NONE,  STATE_C1, 1 },
	[STATE_CE & ~0x80] = { act_ce, JSON_NONE,  0,        0 },
	[STATE_OB & ~0x80] = { act_ob, JSON_NONE,  STATE__O, 0 },
	[STATE_OE & ~0x80] = { act_oe, JSON_NONE,  STATE_OK, 1 },
	[STATE_AB & ~0x80] = { act_ab, JSON_NONE,  STATE__A, 0 },
	[STATE_AE & ~0x80] = { act_ae, JSON_NONE,  STATE_OK, 1 },
	[STATE_SE & ~0x80] = { act_se, JSON_NONE,  0,        0 },
	[STATE_SP & ~0x80] = { act_sp, JSON_NONE,  0,        1 },
};

static int do_action(json_parser *parser, int next_state)
{
	struct action_descr *descr = &actions_map[next_state & ~0x80];
	int ret;

	if (descr->call) {
		if (descr->dobuffer)
			CHK(do_buffer(parser));
		CHK((descr->call)(parser));
	}
	if (descr->state)	
		parser->state = descr->state;
	parser->type = descr->type;
	return ret;
}

/** json_parser_init initialize a parser structure taking a config,
 * a config and its userdata.
 * return JSON_ERROR_NO_MEMORY if memory allocation failed or SUCCESS.
 */
int json_parser_init(json_parser *parser, json_config *config,
                     json_parser_callback callback, void *userdata)
{
	memset(parser, 0, sizeof(*parser));

	if (config)
		memcpy(&parser->config, config, sizeof(json_config));
	parser->callback = callback;
	parser->userdata = userdata;

	/* initialise parsing stack and state */
	parser->stack_offset = 0;
	parser->state = STATE_GO;

	/* initialize the parse stack */
	parser->stack_size = (parser->config.max_nesting > 0)
		? parser->config.max_nesting
		: LIBJSON_DEFAULT_STACK_SIZE;

	parser->stack = parser_calloc(parser, parser->stack_size, sizeof(parser->stack[0]));
	if (!parser->stack)
		return JSON_ERROR_NO_MEMORY;

	/* initialize the parse buffer */
	parser->buffer_size = (parser->config.buffer_initial_size > 0)
		? parser->config.buffer_initial_size
		: LIBJSON_DEFAULT_BUFFER_SIZE;

	if (parser->config.max_data > 0 && parser->buffer_size > parser->config.max_data)
		parser->buffer_size = parser->config.max_data;

	parser->buffer = parser_calloc(parser, parser->buffer_size, sizeof(char));
	if (!parser->buffer) {
		free(parser->stack);
		return JSON_ERROR_NO_MEMORY;
	}
	return 0;
}

/** json_parser_free freed memory structure allocated by the parser */
int json_parser_free(json_parser *parser)
{
	if (!parser)
		return 0;
	free(parser->stack);
	free(parser->buffer);
	parser->stack = NULL;
	parser->buffer = NULL;
	return 0;
}

/** json_parser_is_done return 0 is the parser isn't in a finish state. !0 if it is */
int json_parser_is_done(json_parser *parser)
{
	/* need to compare the state to !GO to not accept empty document */
	return parser->stack_offset == 0 && parser->state != STATE_GO;
}

/** json_parser_string append a string s with a specific length to the parser
 * return 0 if everything went ok, a JSON_ERROR_* otherwise.
 * the user can supplied a valid processed pointer that will
 * be fill with the number of processed characters before returning */
int json_parser_string(json_parser *parser, const char *s,
                       uint32_t length, uint32_t *processed)
{
	int ret;
	int next_class, next_state;
	int buffer_policy;
	uint32_t i;

	ret = 0;
	for (i = 0; i < length; i++) {
		unsigned char ch = s[i];

		ret = 0;
		next_class = (ch >= 128) ? C_OTHER : character_class[ch];
		if (next_class == C_ERROR) {
			ret = JSON_ERROR_BAD_CHAR;
			break;
		}

		next_state = state_transition_table[parser->state][next_class];
		buffer_policy = buffer_policy_table[parser->state][next_class];
		TRACING("addchar %d (current-state=%d, next-state=%d, buf-policy=%d)\n",
			ch, parser->state, next_state, buffer_policy);
		if (next_state == STATE___) {
			ret = JSON_ERROR_UNEXPECTED_CHAR;
			break;
		}

		/* add char to buffer */
		if (buffer_policy) {
			ret = (buffer_policy == 2)
				? buffer_push_escape(parser, ch)
				: buffer_push(parser, ch);
			if (ret)
				break;
		}

		/* move to the next level */
		if (IS_STATE_ACTION(next_state))
			ret = do_action(parser, next_state);
		else
			parser->state = next_state;
		if (ret)
			break;
	}
	if (processed)
		*processed = i;
	return ret;
}

/** json_parser_char append one single char to the parser
 * return 0 if everything went ok, a JSON_ERROR_* otherwise */
int json_parser_char(json_parser *parser, unsigned char ch)
{
	return json_parser_string(parser, (char *) &ch, 1, NULL);
}

/** json_print_init initialize a printer context. always succeed */
int json_print_init(json_printer *printer, json_printer_callback callback, void *userdata)
{
	memset(printer, '\0', sizeof(*printer));
	printer->callback = callback;
	printer->userdata = userdata;

	printer->indentstr = "\t";
	printer->indentlevel = 0;
	printer->enter_object = 1;
	printer->first = 1;
	return 0;
}

/** json_print_free free a printer a context
 * doesn't do anything now, but in future print_init could allocate memory */
int json_print_free(json_printer *printer)
{
	return 0;
}

/* escape a C string to be a JSON valid string on the wire.
 * XXX: it doesn't do unicode verification. yet?. */
static int print_string(json_printer *printer, const char *data, uint32_t length)
{
	int i;

	printer->callback(printer->userdata, "\"", 1);
	for (i = 0; i < length; i++) {
		unsigned char c = data[i];
		if (c < 36) {
			char *esc = character_escape[c];
			printer->callback(printer->userdata, esc, strlen(esc));
		} else if (c == '\\') {
			printer->callback(printer->userdata, "\\\\", 2);
		} else
			printer->callback(printer->userdata, data + i, 1);
	}
	printer->callback(printer->userdata, "\"", 1);
	return 0;
}

static int print_indent(json_printer *printer)
{
	int i;
	printer->callback(printer->userdata, "\n", 1);
	for (i = 0; i < printer->indentlevel; i++)
		printer->callback(printer->userdata, printer->indentstr, strlen(printer->indentstr));
	return 0;
}

int json_print_mode(json_printer *printer, int type, const char *data, uint32_t length, int pretty)
{
	int enterobj = printer->enter_object;

	if (!enterobj && !printer->afterkey && (type != JSON_ARRAY_END && type != JSON_OBJECT_END)) {
		printer->callback(printer->userdata, ",", 1);
		if (pretty) print_indent(printer);
	}

	if (pretty && (enterobj && !printer->first && (type != JSON_ARRAY_END && type != JSON_OBJECT_END))) {
		print_indent(printer);
	}

	printer->first = 0;
	printer->enter_object = 0;
	printer->afterkey = 0;
	switch (type) {
	case JSON_ARRAY_BEGIN:
		printer->callback(printer->userdata, "[", 1);
		printer->indentlevel++;
		printer->enter_object = 1;
		break;
	case JSON_OBJECT_BEGIN:
		printer->callback(printer->userdata, "{", 1);
		printer->indentlevel++;
		printer->enter_object = 1;
		break;
	case JSON_ARRAY_END:
	case JSON_OBJECT_END:
		printer->indentlevel--;
		if (pretty && !enterobj) print_indent(printer);
		printer->callback(printer->userdata, (type == JSON_OBJECT_END) ? "}" : "]", 1);
		break;
	case JSON_INT: printer->callback(printer->userdata, data, length); break;
	case JSON_FLOAT: printer->callback(printer->userdata, data, length); break;
	case JSON_NULL: printer->callback(printer->userdata, "null", 4); break;
	case JSON_TRUE: printer->callback(printer->userdata, "true", 4); break;
	case JSON_FALSE: printer->callback(printer->userdata, "false", 5); break;
	case JSON_KEY:
		print_string(printer, data, length);
		printer->callback(printer->userdata, ": ", (pretty) ? 2 : 1);
		printer->afterkey = 1;
		break;
	case JSON_STRING:
		print_string(printer, data, length);
		break;
	default:
		break;
	}

	return 0;
}

/** json_print_pretty pretty print the passed argument (type/data/length). */
int json_print_pretty(json_printer *printer, int type, const char *data, uint32_t length)
{
	return json_print_mode(printer, type, data, length, 1);
}

/** json_print_raw prints without eye candy the passed argument (type/data/length). */
int json_print_raw(json_printer *printer, int type, const char *data, uint32_t length)
{
	return json_print_mode(printer, type, data, length, 0);
}

/** json_print_args takes multiple types and pass them to the printer function */
int json_print_args(json_printer *printer,
                    int (*f)(json_printer *, int, const char *, uint32_t),
                    ...)
{
	va_list ap;
	char *data;
	uint32_t length;
	int type, ret;

	ret = 0;
	va_start(ap, f);
	while ((type = va_arg(ap, int)) != -1) {
		switch (type) {
		case JSON_ARRAY_BEGIN:
		case JSON_ARRAY_END:
		case JSON_OBJECT_BEGIN:
		case JSON_OBJECT_END:
		case JSON_NULL:
		case JSON_TRUE:
		case JSON_FALSE:
			ret = (*f)(printer, type, NULL, 0);
			break;
		case JSON_INT:
		case JSON_FLOAT:
		case JSON_KEY:
		case JSON_STRING:
			data = va_arg(ap, char *);
			length = va_arg(ap, uint32_t);
			if (length == -1)
				length = strlen(data);
			ret = (*f)(printer, type, data, length);
			break;
		}
		if (ret)
			break;
	}
	va_end(ap);
	return ret;
}

static int dom_push(struct json_parser_dom *ctx, void *val)
{
	if (ctx->stack_offset == ctx->stack_size) {
		void *ptr;
		uint32_t newsize = ctx->stack_size * 2;
		ptr = memory_realloc(ctx->user_realloc, ctx->stack, newsize);
		if (!ptr)
			return JSON_ERROR_NO_MEMORY;
		ctx->stack = ptr;
		ctx->stack_size = newsize;
	}
	ctx->stack[ctx->stack_offset].val = val;
	ctx->stack[ctx->stack_offset].key = NULL;
	ctx->stack[ctx->stack_offset].key_length = 0;
	ctx->stack_offset++;
	return 0;
}

static int dom_pop(struct json_parser_dom *ctx, void **val)
{
	ctx->stack_offset--;
	*val = ctx->stack[ctx->stack_offset].val;
	return 0;
}

int json_parser_dom_init(json_parser_dom *dom,
                         json_parser_dom_create_structure create_structure,
                         json_parser_dom_create_data create_data,
                         json_parser_dom_append append)
{
	memset(dom, 0, sizeof(*dom));
	dom->stack_size = 1024;
	dom->stack_offset = 0;
	dom->stack = memory_calloc(dom->user_calloc, dom->stack_size, sizeof(*(dom->stack)));
	if (!dom->stack)
		return JSON_ERROR_NO_MEMORY;
	dom->append = append;
	dom->create_structure = create_structure;
	dom->create_data = create_data;
	return 0;
}

int json_parser_dom_free(json_parser_dom *dom)
{
	free(dom->stack);
	return 0;
}

int json_parser_dom_callback(void *userdata, int type, const char *data, uint32_t length)
{
	struct json_parser_dom *ctx = userdata;
	void *v;
	struct stack_elem *stack = NULL;

	switch (type) {
	case JSON_ARRAY_BEGIN:
	case JSON_OBJECT_BEGIN:
		v = ctx->create_structure(ctx->stack_offset, type == JSON_OBJECT_BEGIN);
		if (!v)
			return JSON_ERROR_CALLBACK;
		dom_push(ctx, v);
		break;
	case JSON_OBJECT_END:
	case JSON_ARRAY_END:
		dom_pop(ctx, &v);
		if (ctx->stack_offset > 0) {
			stack = &(ctx->stack[ctx->stack_offset - 1]);
			ctx->append(stack->val, stack->key, stack->key_length, v);
			free(stack->key);
		} else
			ctx->root_structure = v;
		break;
	case JSON_KEY:
		stack = &(ctx->stack[ctx->stack_offset - 1]);
		stack->key = memory_calloc(ctx->user_calloc, length + 1, sizeof(char));
		stack->key_length = length;
		if (!stack->key)
			return JSON_ERROR_NO_MEMORY;
		memcpy(stack->key, data, length);
		break;
	case JSON_STRING:
	case JSON_INT:
	case JSON_FLOAT:
	case JSON_NULL:
	case JSON_TRUE:
	case JSON_FALSE:
		stack = &(ctx->stack[ctx->stack_offset - 1]);
		v = ctx->create_data(type, data, length);
		ctx->append(stack->val, stack->key, stack->key_length, v);
		free(stack->key);
		break;
	}
	return 0;
}
