1b8af0d5eSTrond Norbye/* JSON_checker.c */
2b8af0d5eSTrond Norbye
3b8af0d5eSTrond Norbye/* 2007-08-24 */
4b8af0d5eSTrond Norbye
5b8af0d5eSTrond Norbye/*
6b8af0d5eSTrond NorbyeCopyright (c) 2005 JSON.org
7b8af0d5eSTrond Norbye
8b8af0d5eSTrond NorbyePermission is hereby granted, free of charge, to any person obtaining a copy
9b8af0d5eSTrond Norbyeof this software and associated documentation files (the "Software"), to deal
10b8af0d5eSTrond Norbyein the Software without restriction, including without limitation the rights
11b8af0d5eSTrond Norbyeto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12b8af0d5eSTrond Norbyecopies of the Software, and to permit persons to whom the Software is
13b8af0d5eSTrond Norbyefurnished to do so, subject to the following conditions:
14b8af0d5eSTrond Norbye
15b8af0d5eSTrond NorbyeThe above copyright notice and this permission notice shall be included in all
16b8af0d5eSTrond Norbyecopies or substantial portions of the Software.
17b8af0d5eSTrond Norbye
18b8af0d5eSTrond NorbyeThe Software shall be used for Good, not Evil.
19b8af0d5eSTrond Norbye
20b8af0d5eSTrond NorbyeTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21b8af0d5eSTrond NorbyeIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22b8af0d5eSTrond NorbyeFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23b8af0d5eSTrond NorbyeAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24b8af0d5eSTrond NorbyeLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25b8af0d5eSTrond NorbyeOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26b8af0d5eSTrond NorbyeSOFTWARE.
27b8af0d5eSTrond Norbye*/
28b8af0d5eSTrond Norbye
29b8af0d5eSTrond Norbye#include <stdlib.h>
30b8af0d5eSTrond Norbye#include "JSON_checker.h"
31b8af0d5eSTrond Norbye
32b8af0d5eSTrond Norbyetypedef struct JSON_checker_struct {
33b8af0d5eSTrond Norbye    int state;
34b8af0d5eSTrond Norbye    int depth;
35b8af0d5eSTrond Norbye    int top;
36b8af0d5eSTrond Norbye    int* stack;
37b8af0d5eSTrond Norbye} * JSON_checker;
38b8af0d5eSTrond Norbye
39b8af0d5eSTrond Norbye
40b8af0d5eSTrond Norbye#define true  1
41b8af0d5eSTrond Norbye#define false 0
42b8af0d5eSTrond Norbye#define __   -1     /* the universal error code */
43b8af0d5eSTrond Norbye
44b8af0d5eSTrond Norbye/*
45b8af0d5eSTrond Norbye    Characters are mapped into these 31 character classes. This allows for
46b8af0d5eSTrond Norbye    a significant reduction in the size of the state transition table.
47b8af0d5eSTrond Norbye*/
48b8af0d5eSTrond Norbye
49b8af0d5eSTrond Norbyeenum classes {
50b8af0d5eSTrond Norbye    C_SPACE,  /* space */
51b8af0d5eSTrond Norbye    C_WHITE,  /* other whitespace */
52b8af0d5eSTrond Norbye    C_LCURB,  /* {  */
53b8af0d5eSTrond Norbye    C_RCURB,  /* } */
54b8af0d5eSTrond Norbye    C_LSQRB,  /* [ */
55b8af0d5eSTrond Norbye    C_RSQRB,  /* ] */
56b8af0d5eSTrond Norbye    C_COLON,  /* : */
57b8af0d5eSTrond Norbye    C_COMMA,  /* , */
58b8af0d5eSTrond Norbye    C_QUOTE,  /* " */
59b8af0d5eSTrond Norbye    C_BACKS,  /* \ */
60b8af0d5eSTrond Norbye    C_SLASH,  /* / */
61b8af0d5eSTrond Norbye    C_PLUS,   /* + */
62b8af0d5eSTrond Norbye    C_MINUS,  /* - */
63b8af0d5eSTrond Norbye    C_POINT,  /* . */
64b8af0d5eSTrond Norbye    C_ZERO ,  /* 0 */
65b8af0d5eSTrond Norbye    C_DIGIT,  /* 123456789 */
66b8af0d5eSTrond Norbye    C_LOW_A,  /* a */
67b8af0d5eSTrond Norbye    C_LOW_B,  /* b */
68b8af0d5eSTrond Norbye    C_LOW_C,  /* c */
69b8af0d5eSTrond Norbye    C_LOW_D,  /* d */
70b8af0d5eSTrond Norbye    C_LOW_E,  /* e */
71b8af0d5eSTrond Norbye    C_LOW_F,  /* f */
72b8af0d5eSTrond Norbye    C_LOW_L,  /* l */
73b8af0d5eSTrond Norbye    C_LOW_N,  /* n */
74b8af0d5eSTrond Norbye    C_LOW_R,  /* r */
75b8af0d5eSTrond Norbye    C_LOW_S,  /* s */
76b8af0d5eSTrond Norbye    C_LOW_T,  /* t */
77b8af0d5eSTrond Norbye    C_LOW_U,  /* u */
78b8af0d5eSTrond Norbye    C_ABCDF,  /* ABCDF */
79b8af0d5eSTrond Norbye    C_E,      /* E */
80b8af0d5eSTrond Norbye    C_ETC,    /* everything else */
81b8af0d5eSTrond Norbye    NR_CLASSES
82b8af0d5eSTrond Norbye};
83b8af0d5eSTrond Norbye
84b8af0d5eSTrond Norbyestatic int ascii_class[128] = {
85b8af0d5eSTrond Norbye/*
86b8af0d5eSTrond Norbye    This array maps the 128 ASCII characters into character classes.
87b8af0d5eSTrond Norbye    The remaining Unicode characters should be mapped to C_ETC.
88b8af0d5eSTrond Norbye    Non-whitespace control characters are errors.
89b8af0d5eSTrond Norbye*/
90b8af0d5eSTrond Norbye    __,      __,      __,      __,      __,      __,      __,      __,
91b8af0d5eSTrond Norbye    __,      C_WHITE, C_WHITE, __,      __,      C_WHITE, __,      __,
92b8af0d5eSTrond Norbye    __,      __,      __,      __,      __,      __,      __,      __,
93b8af0d5eSTrond Norbye    __,      __,      __,      __,      __,      __,      __,      __,
94b8af0d5eSTrond Norbye
95b8af0d5eSTrond Norbye    C_SPACE, C_ETC,   C_QUOTE, C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,
96b8af0d5eSTrond Norbye    C_ETC,   C_ETC,   C_ETC,   C_PLUS,  C_COMMA, C_MINUS, C_POINT, C_SLASH,
97b8af0d5eSTrond Norbye    C_ZERO,  C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT,
98b8af0d5eSTrond Norbye    C_DIGIT, C_DIGIT, C_COLON, C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,
99b8af0d5eSTrond Norbye
100b8af0d5eSTrond Norbye    C_ETC,   C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E,     C_ABCDF, C_ETC,
101b8af0d5eSTrond Norbye    C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,
102b8af0d5eSTrond Norbye    C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,
103b8af0d5eSTrond Norbye    C_ETC,   C_ETC,   C_ETC,   C_LSQRB, C_BACKS, C_RSQRB, C_ETC,   C_ETC,
104b8af0d5eSTrond Norbye
105b8af0d5eSTrond Norbye    C_ETC,   C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC,
106b8af0d5eSTrond Norbye    C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_LOW_L, C_ETC,   C_LOW_N, C_ETC,
107b8af0d5eSTrond Norbye    C_ETC,   C_ETC,   C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC,   C_ETC,
108b8af0d5eSTrond Norbye    C_ETC,   C_ETC,   C_ETC,   C_LCURB, C_ETC,   C_RCURB, C_ETC,   C_ETC
109b8af0d5eSTrond Norbye};
110b8af0d5eSTrond Norbye
111b8af0d5eSTrond Norbye
112b8af0d5eSTrond Norbye/*
113b8af0d5eSTrond Norbye    The state codes.
114b8af0d5eSTrond Norbye*/
115b8af0d5eSTrond Norbyeenum states {
116b8af0d5eSTrond Norbye    GO,  /* start    */
117b8af0d5eSTrond Norbye    OK,  /* ok       */
118b8af0d5eSTrond Norbye    OB,  /* object   */
119b8af0d5eSTrond Norbye    KE,  /* key      */
120b8af0d5eSTrond Norbye    CO,  /* colon    */
121b8af0d5eSTrond Norbye    VA,  /* value    */
122b8af0d5eSTrond Norbye    AR,  /* array    */
123b8af0d5eSTrond Norbye    ST,  /* string   */
124b8af0d5eSTrond Norbye    ES,  /* escape   */
125b8af0d5eSTrond Norbye    U1,  /* u1       */
126b8af0d5eSTrond Norbye    U2,  /* u2       */
127b8af0d5eSTrond Norbye    U3,  /* u3       */
128b8af0d5eSTrond Norbye    U4,  /* u4       */
129b8af0d5eSTrond Norbye    MI,  /* minus    */
130b8af0d5eSTrond Norbye    ZE,  /* zero     */
131b8af0d5eSTrond Norbye    IN,  /* integer  */
132b8af0d5eSTrond Norbye    FR,  /* fraction */
133b8af0d5eSTrond Norbye    E1,  /* e        */
134b8af0d5eSTrond Norbye    E2,  /* ex       */
135b8af0d5eSTrond Norbye    E3,  /* exp      */
136b8af0d5eSTrond Norbye    T1,  /* tr       */
137b8af0d5eSTrond Norbye    T2,  /* tru      */
138b8af0d5eSTrond Norbye    T3,  /* true     */
139b8af0d5eSTrond Norbye    F1,  /* fa       */
140b8af0d5eSTrond Norbye    F2,  /* fal      */
141b8af0d5eSTrond Norbye    F3,  /* fals     */
142b8af0d5eSTrond Norbye    F4,  /* false    */
143b8af0d5eSTrond Norbye    N1,  /* nu       */
144b8af0d5eSTrond Norbye    N2,  /* nul      */
145b8af0d5eSTrond Norbye    N3,  /* null     */
146b8af0d5eSTrond Norbye    NR_STATES
147b8af0d5eSTrond Norbye};
148b8af0d5eSTrond Norbye
149b8af0d5eSTrond Norbye
150b8af0d5eSTrond Norbyestatic int state_transition_table[NR_STATES][NR_CLASSES] = {
151b8af0d5eSTrond Norbye/*
152b8af0d5eSTrond Norbye    The state transition table takes the current state and the current symbol,
153b8af0d5eSTrond Norbye    and returns either a new state or an action. An action is represented as a
154b8af0d5eSTrond Norbye    negative number. A JSON text is accepted if at the end of the text the
155b8af0d5eSTrond Norbye    state is OK and if the mode is MODE_DONE.
156b8af0d5eSTrond Norbye
157b8af0d5eSTrond Norbye                 white                                      1-9                                   ABCDF  etc
158b8af0d5eSTrond Norbye             space |  {  }  [  ]  :  ,  "  \  /  +  -  .  0  |  a  b  c  d  e  f  l  n  r  s  t  u  |  E  |*/
159b8af0d5eSTrond Norbye/*start  GO*/ {GO,GO,-6,__,-5,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
160b8af0d5eSTrond Norbye/*ok     OK*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
161b8af0d5eSTrond Norbye/*object OB*/ {OB,OB,__,-9,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
162b8af0d5eSTrond Norbye/*key    KE*/ {KE,KE,__,__,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
163b8af0d5eSTrond Norbye/*colon  CO*/ {CO,CO,__,__,__,__,-2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
164b8af0d5eSTrond Norbye/*value  VA*/ {VA,VA,-6,__,-5,__,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
165b8af0d5eSTrond Norbye/*array  AR*/ {AR,AR,-6,__,-5,-7,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
166b8af0d5eSTrond Norbye/*string ST*/ {ST,__,ST,ST,ST,ST,ST,ST,-4,ES,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST},
167b8af0d5eSTrond Norbye/*escape ES*/ {__,__,__,__,__,__,__,__,ST,ST,ST,__,__,__,__,__,__,ST,__,__,__,ST,__,ST,ST,__,ST,U1,__,__,__},
168b8af0d5eSTrond Norbye/*u1     U1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__},
169b8af0d5eSTrond Norbye/*u2     U2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__},
170b8af0d5eSTrond Norbye/*u3     U3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__},
171b8af0d5eSTrond Norbye/*u4     U4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ST,ST,ST,ST,ST,ST,ST,ST,__,__,__,__,__,__,ST,ST,__},
172b8af0d5eSTrond Norbye/*minus  MI*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ZE,IN,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
173b8af0d5eSTrond Norbye/*zero   ZE*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
174b8af0d5eSTrond Norbye/*int    IN*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,IN,IN,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
175b8af0d5eSTrond Norbye/*frac   FR*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
176b8af0d5eSTrond Norbye/*e      E1*/ {__,__,__,__,__,__,__,__,__,__,__,E2,E2,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
177b8af0d5eSTrond Norbye/*ex     E2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
178b8af0d5eSTrond Norbye/*exp    E3*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
179b8af0d5eSTrond Norbye/*tr     T1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__},
180b8af0d5eSTrond Norbye/*tru    T2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__},
181b8af0d5eSTrond Norbye/*true   T3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
182b8af0d5eSTrond Norbye/*fa     F1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
183b8af0d5eSTrond Norbye/*fal    F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__},
184b8af0d5eSTrond Norbye/*fals   F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__},
185b8af0d5eSTrond Norbye/*false  F4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
186b8af0d5eSTrond Norbye/*nu     N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__},
187b8af0d5eSTrond Norbye/*nul    N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__},
188b8af0d5eSTrond Norbye/*null   N3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__},
189b8af0d5eSTrond Norbye};
190b8af0d5eSTrond Norbye
191b8af0d5eSTrond Norbye
192b8af0d5eSTrond Norbye/*
193b8af0d5eSTrond Norbye    These modes can be pushed on the stack.
194b8af0d5eSTrond Norbye*/
195b8af0d5eSTrond Norbyeenum modes {
196b8af0d5eSTrond Norbye    MODE_ARRAY,
197b8af0d5eSTrond Norbye    MODE_DONE,
198b8af0d5eSTrond Norbye    MODE_KEY,
199b8af0d5eSTrond Norbye    MODE_OBJECT
200b8af0d5eSTrond Norbye};
201b8af0d5eSTrond Norbye
202b8af0d5eSTrond Norbyestatic int
203b8af0d5eSTrond Norbyereject(JSON_checker jc)
204b8af0d5eSTrond Norbye{
205b8af0d5eSTrond Norbye/*
206b8af0d5eSTrond Norbye    Delete the JSON_checker object.
207b8af0d5eSTrond Norbye*/
208b8af0d5eSTrond Norbye    free((void*)jc->stack);
209b8af0d5eSTrond Norbye    free((void*)jc);
210b8af0d5eSTrond Norbye    return false;
211b8af0d5eSTrond Norbye}
212b8af0d5eSTrond Norbye
213b8af0d5eSTrond Norbye
214b8af0d5eSTrond Norbyestatic int
215b8af0d5eSTrond Norbyepush(JSON_checker jc, int mode)
216b8af0d5eSTrond Norbye{
217b8af0d5eSTrond Norbye/*
218b8af0d5eSTrond Norbye    Push a mode onto the stack. Return false if there is overflow.
219b8af0d5eSTrond Norbye*/
220b8af0d5eSTrond Norbye    jc->top += 1;
221b8af0d5eSTrond Norbye    if (jc->top >= jc->depth) {
222b8af0d5eSTrond Norbye        return false;
223b8af0d5eSTrond Norbye    }
224b8af0d5eSTrond Norbye    jc->stack[jc->top] = mode;
225b8af0d5eSTrond Norbye    return true;
226b8af0d5eSTrond Norbye}
227b8af0d5eSTrond Norbye
228b8af0d5eSTrond Norbye
229b8af0d5eSTrond Norbyestatic int
230b8af0d5eSTrond Norbyepop(JSON_checker jc, int mode)
231b8af0d5eSTrond Norbye{
232b8af0d5eSTrond Norbye/*
233b8af0d5eSTrond Norbye    Pop the stack, assuring that the current mode matches the expectation.
234b8af0d5eSTrond Norbye    Return false if there is underflow or if the modes mismatch.
235b8af0d5eSTrond Norbye*/
236b8af0d5eSTrond Norbye    if (jc->top < 0 || jc->stack[jc->top] != mode) {
237b8af0d5eSTrond Norbye        return false;
238b8af0d5eSTrond Norbye    }
239b8af0d5eSTrond Norbye    jc->top -= 1;
240b8af0d5eSTrond Norbye    return true;
241b8af0d5eSTrond Norbye}
242b8af0d5eSTrond Norbye
243b8af0d5eSTrond Norbye
244b8af0d5eSTrond Norbyestatic JSON_checker
245b8af0d5eSTrond Norbyenew_JSON_checker(int depth)
246b8af0d5eSTrond Norbye{
247b8af0d5eSTrond Norbye/*
248b8af0d5eSTrond Norbye    new_JSON_checker starts the checking process by constructing a JSON_checker
249b8af0d5eSTrond Norbye    object. It takes a depth parameter that restricts the level of maximum
250b8af0d5eSTrond Norbye    nesting.
251b8af0d5eSTrond Norbye
252b8af0d5eSTrond Norbye    To continue the process, call JSON_checker_char for each character in the
253b8af0d5eSTrond Norbye    JSON text, and then call JSON_checker_done to obtain the final result.
254b8af0d5eSTrond Norbye    These functions are fully reentrant.
255b8af0d5eSTrond Norbye
256b8af0d5eSTrond Norbye    The JSON_checker object will be deleted by JSON_checker_done.
257b8af0d5eSTrond Norbye    JSON_checker_char will delete the JSON_checker object if it sees an error.
258b8af0d5eSTrond Norbye*/
259b8af0d5eSTrond Norbye    JSON_checker jc = (JSON_checker)malloc(sizeof(struct JSON_checker_struct));
260b8af0d5eSTrond Norbye    /* Modified- we want to accept JSON values, not just JSON-Texts */
261b8af0d5eSTrond Norbye    jc->state = VA;
262b8af0d5eSTrond Norbye    jc->depth = depth;
263b8af0d5eSTrond Norbye    jc->top = -1;
264b8af0d5eSTrond Norbye    jc->stack = (int*)calloc(depth, sizeof(int));
265b8af0d5eSTrond Norbye    push(jc, MODE_DONE);
266b8af0d5eSTrond Norbye    return jc;
267b8af0d5eSTrond Norbye}
268b8af0d5eSTrond Norbye
269b8af0d5eSTrond Norbye
270b8af0d5eSTrond Norbyestatic int
271b8af0d5eSTrond NorbyeJSON_checker_char(JSON_checker jc, int next_char)
272b8af0d5eSTrond Norbye{
273b8af0d5eSTrond Norbye/*
274b8af0d5eSTrond Norbye    After calling new_JSON_checker, call this function for each character (or
275b8af0d5eSTrond Norbye    partial character) in your JSON text. It can accept UTF-8, UTF-16, or
276b8af0d5eSTrond Norbye    UTF-32. It returns true if things are looking ok so far. If it rejects the
277b8af0d5eSTrond Norbye    text, it deletes the JSON_checker object and returns false.
278b8af0d5eSTrond Norbye*/
279b8af0d5eSTrond Norbye    int next_class, next_state;
280b8af0d5eSTrond Norbye/*
281b8af0d5eSTrond Norbye    Determine the character's class.
282b8af0d5eSTrond Norbye*/
283b8af0d5eSTrond Norbye    if (next_char < 0) {
284b8af0d5eSTrond Norbye        return reject(jc);
285b8af0d5eSTrond Norbye    }
286b8af0d5eSTrond Norbye    if (next_char >= 128) {
287b8af0d5eSTrond Norbye        next_class = C_ETC;
288b8af0d5eSTrond Norbye    } else {
289b8af0d5eSTrond Norbye        next_class = ascii_class[next_char];
290b8af0d5eSTrond Norbye        if (next_class <= __) {
291b8af0d5eSTrond Norbye            return reject(jc);
292b8af0d5eSTrond Norbye        }
293b8af0d5eSTrond Norbye    }
294b8af0d5eSTrond Norbye/*
295b8af0d5eSTrond Norbye    Get the next state from the state transition table.
296b8af0d5eSTrond Norbye*/
297b8af0d5eSTrond Norbye    next_state = state_transition_table[jc->state][next_class];
298b8af0d5eSTrond Norbye    if (next_state >= 0) {
299b8af0d5eSTrond Norbye/*
300b8af0d5eSTrond Norbye    Change the state.
301b8af0d5eSTrond Norbye*/
302b8af0d5eSTrond Norbye        jc->state = next_state;
303b8af0d5eSTrond Norbye    } else {
304b8af0d5eSTrond Norbye/*
305b8af0d5eSTrond Norbye    Or perform one of the actions.
306b8af0d5eSTrond Norbye*/
307b8af0d5eSTrond Norbye        switch (next_state) {
308b8af0d5eSTrond Norbye/* empty } */
309b8af0d5eSTrond Norbye        case -9:
310b8af0d5eSTrond Norbye            if (!pop(jc, MODE_KEY)) {
311b8af0d5eSTrond Norbye                return reject(jc);
312b8af0d5eSTrond Norbye            }
313b8af0d5eSTrond Norbye            jc->state = OK;
314b8af0d5eSTrond Norbye            break;
315b8af0d5eSTrond Norbye
316b8af0d5eSTrond Norbye/* } */ case -8:
317b8af0d5eSTrond Norbye            if (!pop(jc, MODE_OBJECT)) {
318b8af0d5eSTrond Norbye                return reject(jc);
319b8af0d5eSTrond Norbye            }
320b8af0d5eSTrond Norbye            jc->state = OK;
321b8af0d5eSTrond Norbye            break;
322b8af0d5eSTrond Norbye
323b8af0d5eSTrond Norbye/* ] */ case -7:
324b8af0d5eSTrond Norbye            if (!pop(jc, MODE_ARRAY)) {
325b8af0d5eSTrond Norbye                return reject(jc);
326b8af0d5eSTrond Norbye            }
327b8af0d5eSTrond Norbye            jc->state = OK;
328b8af0d5eSTrond Norbye            break;
329b8af0d5eSTrond Norbye
330b8af0d5eSTrond Norbye/* { */ case -6:
331b8af0d5eSTrond Norbye            if (!push(jc, MODE_KEY)) {
332b8af0d5eSTrond Norbye                return reject(jc);
333b8af0d5eSTrond Norbye            }
334b8af0d5eSTrond Norbye            jc->state = OB;
335b8af0d5eSTrond Norbye            break;
336b8af0d5eSTrond Norbye
337b8af0d5eSTrond Norbye/* [ */ case -5:
338b8af0d5eSTrond Norbye            if (!push(jc, MODE_ARRAY)) {
339b8af0d5eSTrond Norbye                return reject(jc);
340b8af0d5eSTrond Norbye            }
341b8af0d5eSTrond Norbye            jc->state = AR;
342b8af0d5eSTrond Norbye            break;
343b8af0d5eSTrond Norbye
344b8af0d5eSTrond Norbye/* " */ case -4:
345b8af0d5eSTrond Norbye            switch (jc->stack[jc->top]) {
346b8af0d5eSTrond Norbye            case MODE_KEY:
347b8af0d5eSTrond Norbye                jc->state = CO;
348b8af0d5eSTrond Norbye                break;
349b8af0d5eSTrond Norbye            case MODE_ARRAY:
350b8af0d5eSTrond Norbye            case MODE_OBJECT:
351b8af0d5eSTrond Norbye            /*
352b8af0d5eSTrond Norbye              Modified- we want to accept JSON values, not just JSON-Texts, this
353b8af0d5eSTrond Norbye              allows us to accept bare strings.
354b8af0d5eSTrond Norbye            */
355b8af0d5eSTrond Norbye            case MODE_DONE:
356b8af0d5eSTrond Norbye                jc->state = OK;
357b8af0d5eSTrond Norbye                break;
358b8af0d5eSTrond Norbye            default:
359b8af0d5eSTrond Norbye                return reject(jc);
360b8af0d5eSTrond Norbye            }
361b8af0d5eSTrond Norbye            break;
362b8af0d5eSTrond Norbye
363b8af0d5eSTrond Norbye/* , */ case -3:
364b8af0d5eSTrond Norbye            switch (jc->stack[jc->top]) {
365b8af0d5eSTrond Norbye            case MODE_OBJECT:
366b8af0d5eSTrond Norbye/*
367b8af0d5eSTrond Norbye    A comma causes a flip from object mode to key mode.
368b8af0d5eSTrond Norbye*/
369b8af0d5eSTrond Norbye                if (!pop(jc, MODE_OBJECT) || !push(jc, MODE_KEY)) {
370b8af0d5eSTrond Norbye                    return reject(jc);
371b8af0d5eSTrond Norbye                }
372b8af0d5eSTrond Norbye                jc->state = KE;
373b8af0d5eSTrond Norbye                break;
374b8af0d5eSTrond Norbye            case MODE_ARRAY:
375b8af0d5eSTrond Norbye                jc->state = VA;
376b8af0d5eSTrond Norbye                break;
377b8af0d5eSTrond Norbye            default:
378b8af0d5eSTrond Norbye                return reject(jc);
379b8af0d5eSTrond Norbye            }
380b8af0d5eSTrond Norbye            break;
381b8af0d5eSTrond Norbye
382b8af0d5eSTrond Norbye/* : */ case -2:
383b8af0d5eSTrond Norbye/*
384b8af0d5eSTrond Norbye    A colon causes a flip from key mode to object mode.
385b8af0d5eSTrond Norbye*/
386b8af0d5eSTrond Norbye            if (!pop(jc, MODE_KEY) || !push(jc, MODE_OBJECT)) {
387b8af0d5eSTrond Norbye                return reject(jc);
388b8af0d5eSTrond Norbye            }
389b8af0d5eSTrond Norbye            jc->state = VA;
390b8af0d5eSTrond Norbye            break;
391b8af0d5eSTrond Norbye/*
392b8af0d5eSTrond Norbye    Bad action.
393b8af0d5eSTrond Norbye*/
394b8af0d5eSTrond Norbye        default:
395b8af0d5eSTrond Norbye            return reject(jc);
396b8af0d5eSTrond Norbye        }
397b8af0d5eSTrond Norbye    }
398b8af0d5eSTrond Norbye    return true;
399b8af0d5eSTrond Norbye}
400b8af0d5eSTrond Norbye
401b8af0d5eSTrond Norbye
402b8af0d5eSTrond Norbyestatic int
403b8af0d5eSTrond NorbyeJSON_checker_done(JSON_checker jc)
404b8af0d5eSTrond Norbye{
405b8af0d5eSTrond Norbye/*
406b8af0d5eSTrond Norbye    The JSON_checker_done function should be called after all of the characters
407b8af0d5eSTrond Norbye    have been processed, but only if every call to JSON_checker_char returned
408b8af0d5eSTrond Norbye    true. This function deletes the JSON_checker and returns true if the JSON
409b8af0d5eSTrond Norbye    text was accepted.
410b8af0d5eSTrond Norbye*/
411b8af0d5eSTrond Norbye    int result = (jc->state == OK) && pop(jc, MODE_DONE);
412b8af0d5eSTrond Norbye    reject(jc);
413b8af0d5eSTrond Norbye    return result;
414b8af0d5eSTrond Norbye}
415b8af0d5eSTrond Norbye
416b8af0d5eSTrond Norbye/* Check for both UTF-8ness and JSONness in one pass */
417b8af0d5eSTrond Norbyeint
418b8af0d5eSTrond NorbyecheckUTF8JSON(const unsigned char* data, size_t size) {
419b8af0d5eSTrond Norbye    int expect = 0; /* Expect UTF code point to extend this many bytes */
420b8af0d5eSTrond Norbye    int badjson = 0;
421b8af0d5eSTrond Norbye    int badutf = 0;
422b8af0d5eSTrond Norbye    const unsigned char *end = data + size;
423b8af0d5eSTrond Norbye    JSON_checker jc = new_JSON_checker((int)(size/2) + 1);
424b8af0d5eSTrond Norbye    for(;data < end; data++) {
425b8af0d5eSTrond Norbye        if(!JSON_checker_char(jc, *data)) {
426b8af0d5eSTrond Norbye            badjson = 1;
427b8af0d5eSTrond Norbye            break;
428b8af0d5eSTrond Norbye        }
429b8af0d5eSTrond Norbye
430b8af0d5eSTrond Norbye        if(*data <= 0x7F) {
431b8af0d5eSTrond Norbye            if(expect != 0) {
432b8af0d5eSTrond Norbye                /* Must not be expecting >0x7F. */
433b8af0d5eSTrond Norbye                badutf = 1;
434b8af0d5eSTrond Norbye                break;
435b8af0d5eSTrond Norbye            }
436b8af0d5eSTrond Norbye            continue;
437b8af0d5eSTrond Norbye        }
438b8af0d5eSTrond Norbye
439b8af0d5eSTrond Norbye        if((*data & 0xC0) == 0xC0) {
440b8af0d5eSTrond Norbye            if(expect != 0) {
441b8af0d5eSTrond Norbye               /* Beginning of UTF-8 multi-byte sequence inside of another one. */
442b8af0d5eSTrond Norbye                badutf = 1;
443b8af0d5eSTrond Norbye                break;
444b8af0d5eSTrond Norbye            }
445b8af0d5eSTrond Norbye            expect++;
446b8af0d5eSTrond Norbye            if(*data & 0x20) expect++;
447b8af0d5eSTrond Norbye            if((*data & 0x10) && expect == 2) expect++;
448b8af0d5eSTrond Norbye            /* Verify zero bit separates count bits and codepoint bits */
449b8af0d5eSTrond Norbye            if(expect == 3 && (*data & 0x8)) return false;
450b8af0d5eSTrond Norbye            continue;
451b8af0d5eSTrond Norbye        }
452b8af0d5eSTrond Norbye
453b8af0d5eSTrond Norbye        if(expect) {
454b8af0d5eSTrond Norbye            expect--;
455b8af0d5eSTrond Norbye        } else {
456b8af0d5eSTrond Norbye           /* Got > 0x7F when not expecting it */
457b8af0d5eSTrond Norbye            badutf = 1;
458b8af0d5eSTrond Norbye            break;
459b8af0d5eSTrond Norbye        }
460b8af0d5eSTrond Norbye    }
461b8af0d5eSTrond Norbye    if(!badjson) {
462b8af0d5eSTrond Norbye        /* Feed fake space to the validator to force it to finish validating */
463b8af0d5eSTrond Norbye        /* numerical values, iff it hasn't marked the current stream as valid */
464b8af0d5eSTrond Norbye        if(jc->state != OK) {
465b8af0d5eSTrond Norbye            badjson = !JSON_checker_char(jc, 32);
466b8af0d5eSTrond Norbye        }
467b8af0d5eSTrond Norbye        if(!badjson) {
468b8af0d5eSTrond Norbye            badjson = !JSON_checker_done(jc);
469b8af0d5eSTrond Norbye        }
470b8af0d5eSTrond Norbye    }
471b8af0d5eSTrond Norbye    return (!badjson && !badutf);
472b8af0d5eSTrond Norbye}
473