xref: /openbmc/qemu/qobject/json-lexer.c (revision d2ca7c0b0d876cf0e219ae7a92252626b0913a28)
1a372823aSPaolo Bonzini /*
2a372823aSPaolo Bonzini  * JSON lexer
3a372823aSPaolo Bonzini  *
4a372823aSPaolo Bonzini  * Copyright IBM, Corp. 2009
5a372823aSPaolo Bonzini  *
6a372823aSPaolo Bonzini  * Authors:
7a372823aSPaolo Bonzini  *  Anthony Liguori   <aliguori@us.ibm.com>
8a372823aSPaolo Bonzini  *
9a372823aSPaolo Bonzini  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10a372823aSPaolo Bonzini  * See the COPYING.LIB file in the top-level directory.
11a372823aSPaolo Bonzini  *
12a372823aSPaolo Bonzini  */
13a372823aSPaolo Bonzini 
14a372823aSPaolo Bonzini #include "qemu-common.h"
15a372823aSPaolo Bonzini #include "qapi/qmp/json-lexer.h"
16*d2ca7c0bSPaolo Bonzini #include <stdint.h>
17a372823aSPaolo Bonzini 
18a372823aSPaolo Bonzini #define MAX_TOKEN_SIZE (64ULL << 20)
19a372823aSPaolo Bonzini 
20a372823aSPaolo Bonzini /*
21a372823aSPaolo Bonzini  * \"([^\\\"]|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*\"
22a372823aSPaolo Bonzini  * '([^\\']|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*'
23a372823aSPaolo Bonzini  * 0|([1-9][0-9]*(.[0-9]+)?([eE]([-+])?[0-9]+))
24a372823aSPaolo Bonzini  * [{}\[\],:]
25a372823aSPaolo Bonzini  * [a-z]+
26a372823aSPaolo Bonzini  *
27a372823aSPaolo Bonzini  */
28a372823aSPaolo Bonzini 
29a372823aSPaolo Bonzini enum json_lexer_state {
30b8d3b1daSMarkus Armbruster     IN_ERROR = 0,               /* must really be 0, see json_lexer[] */
31a372823aSPaolo Bonzini     IN_DQ_UCODE3,
32a372823aSPaolo Bonzini     IN_DQ_UCODE2,
33a372823aSPaolo Bonzini     IN_DQ_UCODE1,
34a372823aSPaolo Bonzini     IN_DQ_UCODE0,
35a372823aSPaolo Bonzini     IN_DQ_STRING_ESCAPE,
36a372823aSPaolo Bonzini     IN_DQ_STRING,
37a372823aSPaolo Bonzini     IN_SQ_UCODE3,
38a372823aSPaolo Bonzini     IN_SQ_UCODE2,
39a372823aSPaolo Bonzini     IN_SQ_UCODE1,
40a372823aSPaolo Bonzini     IN_SQ_UCODE0,
41a372823aSPaolo Bonzini     IN_SQ_STRING_ESCAPE,
42a372823aSPaolo Bonzini     IN_SQ_STRING,
43a372823aSPaolo Bonzini     IN_ZERO,
44a372823aSPaolo Bonzini     IN_DIGITS,
45a372823aSPaolo Bonzini     IN_DIGIT,
46a372823aSPaolo Bonzini     IN_EXP_E,
47a372823aSPaolo Bonzini     IN_MANTISSA,
48a372823aSPaolo Bonzini     IN_MANTISSA_DIGITS,
49a372823aSPaolo Bonzini     IN_NONZERO_NUMBER,
50a372823aSPaolo Bonzini     IN_NEG_NONZERO_NUMBER,
51a372823aSPaolo Bonzini     IN_KEYWORD,
52a372823aSPaolo Bonzini     IN_ESCAPE,
53a372823aSPaolo Bonzini     IN_ESCAPE_L,
54a372823aSPaolo Bonzini     IN_ESCAPE_LL,
55a372823aSPaolo Bonzini     IN_ESCAPE_I,
56a372823aSPaolo Bonzini     IN_ESCAPE_I6,
57a372823aSPaolo Bonzini     IN_ESCAPE_I64,
58a372823aSPaolo Bonzini     IN_WHITESPACE,
59a372823aSPaolo Bonzini     IN_START,
60a372823aSPaolo Bonzini };
61a372823aSPaolo Bonzini 
62b8d3b1daSMarkus Armbruster QEMU_BUILD_BUG_ON((int)JSON_MIN <= (int)IN_START);
63b8d3b1daSMarkus Armbruster 
64a372823aSPaolo Bonzini #define TERMINAL(state) [0 ... 0x7F] = (state)
65a372823aSPaolo Bonzini 
66a372823aSPaolo Bonzini /* Return whether TERMINAL is a terminal state and the transition to it
67a372823aSPaolo Bonzini    from OLD_STATE required lookahead.  This happens whenever the table
68a372823aSPaolo Bonzini    below uses the TERMINAL macro.  */
69a372823aSPaolo Bonzini #define TERMINAL_NEEDED_LOOKAHEAD(old_state, terminal) \
70a372823aSPaolo Bonzini             (json_lexer[(old_state)][0] == (terminal))
71a372823aSPaolo Bonzini 
72a372823aSPaolo Bonzini static const uint8_t json_lexer[][256] =  {
73b8d3b1daSMarkus Armbruster     /* Relies on default initialization to IN_ERROR! */
74b8d3b1daSMarkus Armbruster 
75a372823aSPaolo Bonzini     /* double quote string */
76a372823aSPaolo Bonzini     [IN_DQ_UCODE3] = {
77a372823aSPaolo Bonzini         ['0' ... '9'] = IN_DQ_STRING,
78a372823aSPaolo Bonzini         ['a' ... 'f'] = IN_DQ_STRING,
79a372823aSPaolo Bonzini         ['A' ... 'F'] = IN_DQ_STRING,
80a372823aSPaolo Bonzini     },
81a372823aSPaolo Bonzini     [IN_DQ_UCODE2] = {
82a372823aSPaolo Bonzini         ['0' ... '9'] = IN_DQ_UCODE3,
83a372823aSPaolo Bonzini         ['a' ... 'f'] = IN_DQ_UCODE3,
84a372823aSPaolo Bonzini         ['A' ... 'F'] = IN_DQ_UCODE3,
85a372823aSPaolo Bonzini     },
86a372823aSPaolo Bonzini     [IN_DQ_UCODE1] = {
87a372823aSPaolo Bonzini         ['0' ... '9'] = IN_DQ_UCODE2,
88a372823aSPaolo Bonzini         ['a' ... 'f'] = IN_DQ_UCODE2,
89a372823aSPaolo Bonzini         ['A' ... 'F'] = IN_DQ_UCODE2,
90a372823aSPaolo Bonzini     },
91a372823aSPaolo Bonzini     [IN_DQ_UCODE0] = {
92a372823aSPaolo Bonzini         ['0' ... '9'] = IN_DQ_UCODE1,
93a372823aSPaolo Bonzini         ['a' ... 'f'] = IN_DQ_UCODE1,
94a372823aSPaolo Bonzini         ['A' ... 'F'] = IN_DQ_UCODE1,
95a372823aSPaolo Bonzini     },
96a372823aSPaolo Bonzini     [IN_DQ_STRING_ESCAPE] = {
97a372823aSPaolo Bonzini         ['b'] = IN_DQ_STRING,
98a372823aSPaolo Bonzini         ['f'] =  IN_DQ_STRING,
99a372823aSPaolo Bonzini         ['n'] =  IN_DQ_STRING,
100a372823aSPaolo Bonzini         ['r'] =  IN_DQ_STRING,
101a372823aSPaolo Bonzini         ['t'] =  IN_DQ_STRING,
102a372823aSPaolo Bonzini         ['/'] = IN_DQ_STRING,
103a372823aSPaolo Bonzini         ['\\'] = IN_DQ_STRING,
104a372823aSPaolo Bonzini         ['\''] = IN_DQ_STRING,
105a372823aSPaolo Bonzini         ['\"'] = IN_DQ_STRING,
106a372823aSPaolo Bonzini         ['u'] = IN_DQ_UCODE0,
107a372823aSPaolo Bonzini     },
108a372823aSPaolo Bonzini     [IN_DQ_STRING] = {
109a372823aSPaolo Bonzini         [1 ... 0xBF] = IN_DQ_STRING,
110a372823aSPaolo Bonzini         [0xC2 ... 0xF4] = IN_DQ_STRING,
111a372823aSPaolo Bonzini         ['\\'] = IN_DQ_STRING_ESCAPE,
112a372823aSPaolo Bonzini         ['"'] = JSON_STRING,
113a372823aSPaolo Bonzini     },
114a372823aSPaolo Bonzini 
115a372823aSPaolo Bonzini     /* single quote string */
116a372823aSPaolo Bonzini     [IN_SQ_UCODE3] = {
117a372823aSPaolo Bonzini         ['0' ... '9'] = IN_SQ_STRING,
118a372823aSPaolo Bonzini         ['a' ... 'f'] = IN_SQ_STRING,
119a372823aSPaolo Bonzini         ['A' ... 'F'] = IN_SQ_STRING,
120a372823aSPaolo Bonzini     },
121a372823aSPaolo Bonzini     [IN_SQ_UCODE2] = {
122a372823aSPaolo Bonzini         ['0' ... '9'] = IN_SQ_UCODE3,
123a372823aSPaolo Bonzini         ['a' ... 'f'] = IN_SQ_UCODE3,
124a372823aSPaolo Bonzini         ['A' ... 'F'] = IN_SQ_UCODE3,
125a372823aSPaolo Bonzini     },
126a372823aSPaolo Bonzini     [IN_SQ_UCODE1] = {
127a372823aSPaolo Bonzini         ['0' ... '9'] = IN_SQ_UCODE2,
128a372823aSPaolo Bonzini         ['a' ... 'f'] = IN_SQ_UCODE2,
129a372823aSPaolo Bonzini         ['A' ... 'F'] = IN_SQ_UCODE2,
130a372823aSPaolo Bonzini     },
131a372823aSPaolo Bonzini     [IN_SQ_UCODE0] = {
132a372823aSPaolo Bonzini         ['0' ... '9'] = IN_SQ_UCODE1,
133a372823aSPaolo Bonzini         ['a' ... 'f'] = IN_SQ_UCODE1,
134a372823aSPaolo Bonzini         ['A' ... 'F'] = IN_SQ_UCODE1,
135a372823aSPaolo Bonzini     },
136a372823aSPaolo Bonzini     [IN_SQ_STRING_ESCAPE] = {
137a372823aSPaolo Bonzini         ['b'] = IN_SQ_STRING,
138a372823aSPaolo Bonzini         ['f'] =  IN_SQ_STRING,
139a372823aSPaolo Bonzini         ['n'] =  IN_SQ_STRING,
140a372823aSPaolo Bonzini         ['r'] =  IN_SQ_STRING,
141a372823aSPaolo Bonzini         ['t'] =  IN_SQ_STRING,
142d5932334SPaolo Bonzini         ['/'] = IN_SQ_STRING,
143d5932334SPaolo Bonzini         ['\\'] = IN_SQ_STRING,
144a372823aSPaolo Bonzini         ['\''] = IN_SQ_STRING,
145a372823aSPaolo Bonzini         ['\"'] = IN_SQ_STRING,
146a372823aSPaolo Bonzini         ['u'] = IN_SQ_UCODE0,
147a372823aSPaolo Bonzini     },
148a372823aSPaolo Bonzini     [IN_SQ_STRING] = {
149a372823aSPaolo Bonzini         [1 ... 0xBF] = IN_SQ_STRING,
150a372823aSPaolo Bonzini         [0xC2 ... 0xF4] = IN_SQ_STRING,
151a372823aSPaolo Bonzini         ['\\'] = IN_SQ_STRING_ESCAPE,
152a372823aSPaolo Bonzini         ['\''] = JSON_STRING,
153a372823aSPaolo Bonzini     },
154a372823aSPaolo Bonzini 
155a372823aSPaolo Bonzini     /* Zero */
156a372823aSPaolo Bonzini     [IN_ZERO] = {
157a372823aSPaolo Bonzini         TERMINAL(JSON_INTEGER),
158a372823aSPaolo Bonzini         ['0' ... '9'] = IN_ERROR,
159a372823aSPaolo Bonzini         ['.'] = IN_MANTISSA,
160a372823aSPaolo Bonzini     },
161a372823aSPaolo Bonzini 
162a372823aSPaolo Bonzini     /* Float */
163a372823aSPaolo Bonzini     [IN_DIGITS] = {
164a372823aSPaolo Bonzini         TERMINAL(JSON_FLOAT),
165a372823aSPaolo Bonzini         ['0' ... '9'] = IN_DIGITS,
166a372823aSPaolo Bonzini     },
167a372823aSPaolo Bonzini 
168a372823aSPaolo Bonzini     [IN_DIGIT] = {
169a372823aSPaolo Bonzini         ['0' ... '9'] = IN_DIGITS,
170a372823aSPaolo Bonzini     },
171a372823aSPaolo Bonzini 
172a372823aSPaolo Bonzini     [IN_EXP_E] = {
173a372823aSPaolo Bonzini         ['-'] = IN_DIGIT,
174a372823aSPaolo Bonzini         ['+'] = IN_DIGIT,
175a372823aSPaolo Bonzini         ['0' ... '9'] = IN_DIGITS,
176a372823aSPaolo Bonzini     },
177a372823aSPaolo Bonzini 
178a372823aSPaolo Bonzini     [IN_MANTISSA_DIGITS] = {
179a372823aSPaolo Bonzini         TERMINAL(JSON_FLOAT),
180a372823aSPaolo Bonzini         ['0' ... '9'] = IN_MANTISSA_DIGITS,
181a372823aSPaolo Bonzini         ['e'] = IN_EXP_E,
182a372823aSPaolo Bonzini         ['E'] = IN_EXP_E,
183a372823aSPaolo Bonzini     },
184a372823aSPaolo Bonzini 
185a372823aSPaolo Bonzini     [IN_MANTISSA] = {
186a372823aSPaolo Bonzini         ['0' ... '9'] = IN_MANTISSA_DIGITS,
187a372823aSPaolo Bonzini     },
188a372823aSPaolo Bonzini 
189a372823aSPaolo Bonzini     /* Number */
190a372823aSPaolo Bonzini     [IN_NONZERO_NUMBER] = {
191a372823aSPaolo Bonzini         TERMINAL(JSON_INTEGER),
192a372823aSPaolo Bonzini         ['0' ... '9'] = IN_NONZERO_NUMBER,
193a372823aSPaolo Bonzini         ['e'] = IN_EXP_E,
194a372823aSPaolo Bonzini         ['E'] = IN_EXP_E,
195a372823aSPaolo Bonzini         ['.'] = IN_MANTISSA,
196a372823aSPaolo Bonzini     },
197a372823aSPaolo Bonzini 
198a372823aSPaolo Bonzini     [IN_NEG_NONZERO_NUMBER] = {
199a372823aSPaolo Bonzini         ['0'] = IN_ZERO,
200a372823aSPaolo Bonzini         ['1' ... '9'] = IN_NONZERO_NUMBER,
201a372823aSPaolo Bonzini     },
202a372823aSPaolo Bonzini 
203a372823aSPaolo Bonzini     /* keywords */
204a372823aSPaolo Bonzini     [IN_KEYWORD] = {
205a372823aSPaolo Bonzini         TERMINAL(JSON_KEYWORD),
206a372823aSPaolo Bonzini         ['a' ... 'z'] = IN_KEYWORD,
207a372823aSPaolo Bonzini     },
208a372823aSPaolo Bonzini 
209a372823aSPaolo Bonzini     /* whitespace */
210a372823aSPaolo Bonzini     [IN_WHITESPACE] = {
211a372823aSPaolo Bonzini         TERMINAL(JSON_SKIP),
212a372823aSPaolo Bonzini         [' '] = IN_WHITESPACE,
213a372823aSPaolo Bonzini         ['\t'] = IN_WHITESPACE,
214a372823aSPaolo Bonzini         ['\r'] = IN_WHITESPACE,
215a372823aSPaolo Bonzini         ['\n'] = IN_WHITESPACE,
216a372823aSPaolo Bonzini     },
217a372823aSPaolo Bonzini 
218a372823aSPaolo Bonzini     /* escape */
219a372823aSPaolo Bonzini     [IN_ESCAPE_LL] = {
220a372823aSPaolo Bonzini         ['d'] = JSON_ESCAPE,
221a372823aSPaolo Bonzini     },
222a372823aSPaolo Bonzini 
223a372823aSPaolo Bonzini     [IN_ESCAPE_L] = {
224a372823aSPaolo Bonzini         ['d'] = JSON_ESCAPE,
225a372823aSPaolo Bonzini         ['l'] = IN_ESCAPE_LL,
226a372823aSPaolo Bonzini     },
227a372823aSPaolo Bonzini 
228a372823aSPaolo Bonzini     [IN_ESCAPE_I64] = {
229a372823aSPaolo Bonzini         ['d'] = JSON_ESCAPE,
230a372823aSPaolo Bonzini     },
231a372823aSPaolo Bonzini 
232a372823aSPaolo Bonzini     [IN_ESCAPE_I6] = {
233a372823aSPaolo Bonzini         ['4'] = IN_ESCAPE_I64,
234a372823aSPaolo Bonzini     },
235a372823aSPaolo Bonzini 
236a372823aSPaolo Bonzini     [IN_ESCAPE_I] = {
237a372823aSPaolo Bonzini         ['6'] = IN_ESCAPE_I6,
238a372823aSPaolo Bonzini     },
239a372823aSPaolo Bonzini 
240a372823aSPaolo Bonzini     [IN_ESCAPE] = {
241a372823aSPaolo Bonzini         ['d'] = JSON_ESCAPE,
242a372823aSPaolo Bonzini         ['i'] = JSON_ESCAPE,
243a372823aSPaolo Bonzini         ['p'] = JSON_ESCAPE,
244a372823aSPaolo Bonzini         ['s'] = JSON_ESCAPE,
245a372823aSPaolo Bonzini         ['f'] = JSON_ESCAPE,
246a372823aSPaolo Bonzini         ['l'] = IN_ESCAPE_L,
247a372823aSPaolo Bonzini         ['I'] = IN_ESCAPE_I,
248a372823aSPaolo Bonzini     },
249a372823aSPaolo Bonzini 
250a372823aSPaolo Bonzini     /* top level rule */
251a372823aSPaolo Bonzini     [IN_START] = {
252a372823aSPaolo Bonzini         ['"'] = IN_DQ_STRING,
253a372823aSPaolo Bonzini         ['\''] = IN_SQ_STRING,
254a372823aSPaolo Bonzini         ['0'] = IN_ZERO,
255a372823aSPaolo Bonzini         ['1' ... '9'] = IN_NONZERO_NUMBER,
256a372823aSPaolo Bonzini         ['-'] = IN_NEG_NONZERO_NUMBER,
257c5461660SMarkus Armbruster         ['{'] = JSON_LCURLY,
258c5461660SMarkus Armbruster         ['}'] = JSON_RCURLY,
259c5461660SMarkus Armbruster         ['['] = JSON_LSQUARE,
260c5461660SMarkus Armbruster         [']'] = JSON_RSQUARE,
261c5461660SMarkus Armbruster         [','] = JSON_COMMA,
262c5461660SMarkus Armbruster         [':'] = JSON_COLON,
263a372823aSPaolo Bonzini         ['a' ... 'z'] = IN_KEYWORD,
264a372823aSPaolo Bonzini         ['%'] = IN_ESCAPE,
265a372823aSPaolo Bonzini         [' '] = IN_WHITESPACE,
266a372823aSPaolo Bonzini         ['\t'] = IN_WHITESPACE,
267a372823aSPaolo Bonzini         ['\r'] = IN_WHITESPACE,
268a372823aSPaolo Bonzini         ['\n'] = IN_WHITESPACE,
269a372823aSPaolo Bonzini     },
270a372823aSPaolo Bonzini };
271a372823aSPaolo Bonzini 
272a372823aSPaolo Bonzini void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
273a372823aSPaolo Bonzini {
274a372823aSPaolo Bonzini     lexer->emit = func;
275a372823aSPaolo Bonzini     lexer->state = IN_START;
276*d2ca7c0bSPaolo Bonzini     lexer->token = g_string_sized_new(3);
277a372823aSPaolo Bonzini     lexer->x = lexer->y = 0;
278a372823aSPaolo Bonzini }
279a372823aSPaolo Bonzini 
280a372823aSPaolo Bonzini static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
281a372823aSPaolo Bonzini {
282a372823aSPaolo Bonzini     int char_consumed, new_state;
283a372823aSPaolo Bonzini 
284a372823aSPaolo Bonzini     lexer->x++;
285a372823aSPaolo Bonzini     if (ch == '\n') {
286a372823aSPaolo Bonzini         lexer->x = 0;
287a372823aSPaolo Bonzini         lexer->y++;
288a372823aSPaolo Bonzini     }
289a372823aSPaolo Bonzini 
290a372823aSPaolo Bonzini     do {
291b8d3b1daSMarkus Armbruster         assert(lexer->state <= ARRAY_SIZE(json_lexer));
292a372823aSPaolo Bonzini         new_state = json_lexer[lexer->state][(uint8_t)ch];
293a372823aSPaolo Bonzini         char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state);
294a372823aSPaolo Bonzini         if (char_consumed) {
295*d2ca7c0bSPaolo Bonzini             g_string_append_c(lexer->token, ch);
296a372823aSPaolo Bonzini         }
297a372823aSPaolo Bonzini 
298a372823aSPaolo Bonzini         switch (new_state) {
299c5461660SMarkus Armbruster         case JSON_LCURLY:
300c5461660SMarkus Armbruster         case JSON_RCURLY:
301c5461660SMarkus Armbruster         case JSON_LSQUARE:
302c5461660SMarkus Armbruster         case JSON_RSQUARE:
303c5461660SMarkus Armbruster         case JSON_COLON:
304c5461660SMarkus Armbruster         case JSON_COMMA:
305a372823aSPaolo Bonzini         case JSON_ESCAPE:
306a372823aSPaolo Bonzini         case JSON_INTEGER:
307a372823aSPaolo Bonzini         case JSON_FLOAT:
308a372823aSPaolo Bonzini         case JSON_KEYWORD:
309a372823aSPaolo Bonzini         case JSON_STRING:
310a372823aSPaolo Bonzini             lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y);
311a372823aSPaolo Bonzini             /* fall through */
312a372823aSPaolo Bonzini         case JSON_SKIP:
313*d2ca7c0bSPaolo Bonzini             g_string_truncate(lexer->token, 0);
314a372823aSPaolo Bonzini             new_state = IN_START;
315a372823aSPaolo Bonzini             break;
316a372823aSPaolo Bonzini         case IN_ERROR:
317a372823aSPaolo Bonzini             /* XXX: To avoid having previous bad input leaving the parser in an
318a372823aSPaolo Bonzini              * unresponsive state where we consume unpredictable amounts of
319a372823aSPaolo Bonzini              * subsequent "good" input, percolate this error state up to the
320a372823aSPaolo Bonzini              * tokenizer/parser by forcing a NULL object to be emitted, then
321a372823aSPaolo Bonzini              * reset state.
322a372823aSPaolo Bonzini              *
323a372823aSPaolo Bonzini              * Also note that this handling is required for reliable channel
324a372823aSPaolo Bonzini              * negotiation between QMP and the guest agent, since chr(0xFF)
325a372823aSPaolo Bonzini              * is placed at the beginning of certain events to ensure proper
326a372823aSPaolo Bonzini              * delivery when the channel is in an unknown state. chr(0xFF) is
327a372823aSPaolo Bonzini              * never a valid ASCII/UTF-8 sequence, so this should reliably
328a372823aSPaolo Bonzini              * induce an error/flush state.
329a372823aSPaolo Bonzini              */
330a372823aSPaolo Bonzini             lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y);
331*d2ca7c0bSPaolo Bonzini             g_string_truncate(lexer->token, 0);
332a372823aSPaolo Bonzini             new_state = IN_START;
333a372823aSPaolo Bonzini             lexer->state = new_state;
334a372823aSPaolo Bonzini             return 0;
335a372823aSPaolo Bonzini         default:
336a372823aSPaolo Bonzini             break;
337a372823aSPaolo Bonzini         }
338a372823aSPaolo Bonzini         lexer->state = new_state;
339a372823aSPaolo Bonzini     } while (!char_consumed && !flush);
340a372823aSPaolo Bonzini 
341a372823aSPaolo Bonzini     /* Do not let a single token grow to an arbitrarily large size,
342a372823aSPaolo Bonzini      * this is a security consideration.
343a372823aSPaolo Bonzini      */
344*d2ca7c0bSPaolo Bonzini     if (lexer->token->len > MAX_TOKEN_SIZE) {
345a372823aSPaolo Bonzini         lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
346*d2ca7c0bSPaolo Bonzini         g_string_truncate(lexer->token, 0);
347a372823aSPaolo Bonzini         lexer->state = IN_START;
348a372823aSPaolo Bonzini     }
349a372823aSPaolo Bonzini 
350a372823aSPaolo Bonzini     return 0;
351a372823aSPaolo Bonzini }
352a372823aSPaolo Bonzini 
353a372823aSPaolo Bonzini int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
354a372823aSPaolo Bonzini {
355a372823aSPaolo Bonzini     size_t i;
356a372823aSPaolo Bonzini 
357a372823aSPaolo Bonzini     for (i = 0; i < size; i++) {
358a372823aSPaolo Bonzini         int err;
359a372823aSPaolo Bonzini 
360a372823aSPaolo Bonzini         err = json_lexer_feed_char(lexer, buffer[i], false);
361a372823aSPaolo Bonzini         if (err < 0) {
362a372823aSPaolo Bonzini             return err;
363a372823aSPaolo Bonzini         }
364a372823aSPaolo Bonzini     }
365a372823aSPaolo Bonzini 
366a372823aSPaolo Bonzini     return 0;
367a372823aSPaolo Bonzini }
368a372823aSPaolo Bonzini 
369a372823aSPaolo Bonzini int json_lexer_flush(JSONLexer *lexer)
370a372823aSPaolo Bonzini {
371a372823aSPaolo Bonzini     return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0, true);
372a372823aSPaolo Bonzini }
373a372823aSPaolo Bonzini 
374a372823aSPaolo Bonzini void json_lexer_destroy(JSONLexer *lexer)
375a372823aSPaolo Bonzini {
376*d2ca7c0bSPaolo Bonzini     g_string_free(lexer->token, true);
377a372823aSPaolo Bonzini }
378