1 | /*
2 | * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #include "yajl/yajl_parse.h"
18 | #include "yajl_lex.h"
19 | #include "yajl_parser.h"
20 | #include "yajl_alloc.h"
21 |
22 | #include <stdlib.h>
23 | #include <string.h>
24 | #include <stdarg.h>
25 | #include <assert.h>
26 |
27 | const char *
28 | yajl_status_to_string(yajl_status stat)
29 | {
30 | const char * statStr = "unknown";
31 | switch (stat) {
32 | case yajl_status_ok:
33 | statStr = "ok, no error";
34 | break;
35 | case yajl_status_client_canceled:
36 | statStr = "client canceled parse";
37 | break;
38 | case yajl_status_error:
39 | statStr = "parse error";
40 | break;
41 | }
42 | return statStr;
43 | }
44 |
45 | /*+
46 | * allocate a parser handle
47 | *
48 | * \param callbacks a yajl callbacks structure specifying the
49 | * functions to call when different JSON entities
50 | * are encountered in the input text. May be NULL,
51 | * which is only useful for validation.
52 | *
53 | * \param afs memory allocation functions, may be NULL for to use
54 | * C runtime library routines (malloc and friends)
55 | *
56 | * \param ctx a context pointer that will be passed to callbacks.
57 | +*/
58 | yajl_handle
59 | yajl_alloc(const yajl_callbacks * callbacks,
60 | yajl_alloc_funcs * afs,
61 | void * ctx)
62 | {
63 | yajl_handle hand = NULL;
64 | yajl_alloc_funcs afsBuffer;
65 |
66 | /* first order of business is to set up memory allocation routines */
67 | if (afs != NULL) {
68 | if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
69 | {
70 | return NULL;
71 | }
72 | } else {
73 | yajl_set_default_alloc_funcs(&afsBuffer);
74 | afs = &afsBuffer;
75 | }
76 |
77 | hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t));
78 |
79 | /* copy in pointers to allocation routines */
80 | hand->alloc = *afs;
81 |
82 | hand->callbacks = callbacks;
83 | hand->ctx = ctx;
84 | hand->lexer = NULL;
85 | hand->bytesConsumed = 0;
86 | hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
87 | hand->flags = 0;
88 | yajl_bs_init(hand->stateStack, &(hand->alloc));
89 | yajl_bs_push(hand->stateStack, yajl_state_start);
90 |
91 | return hand;
92 | }
93 |
94 | /*+
95 | * allow the modification of parser options subsequent to handle allocation (via
96 | * yajl_alloc)
97 | *
98 | * \returns zero in case of errors, non-zero otherwise
99 | +*/
100 | int
101 | yajl_config(yajl_handle h, yajl_option opt, ...)
102 | {
103 | int rv = 1;
104 | va_list ap;
105 | va_start(ap, opt);
106 |
107 | switch(opt) {
108 | case yajl_allow_comments:
109 | case yajl_dont_validate_strings:
110 | case yajl_allow_trailing_garbage:
111 | case yajl_allow_multiple_values:
112 | case yajl_allow_partial_values:
113 | if (va_arg(ap, int)) h->flags |= opt;
114 | else h->flags &= ~opt;
115 | break;
116 | default:
117 | rv = 0;
118 | }
119 | va_end(ap);
120 |
121 | return rv;
122 | }
123 |
124 | /*+ free a parser handle +*/
125 | void
126 | yajl_free(yajl_handle handle)
127 | {
128 | yajl_bs_free(handle->stateStack);
129 | yajl_buf_free(handle->decodeBuf);
130 | if (handle->lexer) {
131 | yajl_lex_free(handle->lexer);
132 | handle->lexer = NULL;
133 | }
134 | YA_FREE(&(handle->alloc), handle);
135 | }
136 |
137 | /*+
138 | * Parse some json!
139 | *
140 | * \param hand - a handle to the json parser allocated with yajl_alloc
141 | *
142 | * \param jsonText - a pointer to the UTF8 json text to be parsed
143 | *
144 | * \param jsonTextLength - the length, in bytes, of input text
145 | +*/
146 | yajl_status
147 | yajl_parse(yajl_handle hand, const unsigned char * jsonText,
148 | size_t jsonTextLen)
149 | {
150 | yajl_status status;
151 |
152 | /* lazy allocation of the lexer */
153 | if (hand->lexer == NULL) {
154 | hand->lexer = yajl_lex_alloc(&(hand->alloc),
155 | (int) hand->flags & yajl_allow_comments,
156 | !(hand->flags & yajl_dont_validate_strings));
157 | }
158 |
159 | status = yajl_do_parse(hand, jsonText, jsonTextLen);
160 | return status;
161 | }
162 |
163 |
164 | /*+
165 | * Parse any remaining buffered json.
166 | *
167 | * Since yajl is a stream-based parser, without an explicit end of input, yajl
168 | * sometimes can't decide if content at the end of the stream is valid or not.
169 | * For example, if "1" has been fed in, yajl can't know whether another digit is
170 | * next or some character that would terminate the integer token.
171 | *
172 | * \param hand - a handle to the json parser allocated with yajl_alloc
173 | +*/
174 | yajl_status
175 | yajl_complete_parse(yajl_handle hand)
176 | {
177 | /* The lexer is lazy allocated in the first call to parse. If parse is
178 | * never called, then no data was provided to parse at all. This is a
179 | * "premature EOF" error unless yajl_allow_partial_values is specified.
180 | * allocating the lexer now is the simplest possible way to handle this
181 | * case while preserving all the other semantics of the parser
182 | * (multiple values, partial values, etc). */
183 | if (hand->lexer == NULL) {
184 | hand->lexer = yajl_lex_alloc(&(hand->alloc),
185 | (int) hand->flags & yajl_allow_comments,
186 | !(hand->flags & yajl_dont_validate_strings));
187 | }
188 |
189 | return yajl_do_finish(hand);
190 | }
191 |
192 | /*+
193 | * get an error string describing the state of the parse.
194 | *
195 | * If verbose is non-zero, the message will include the JSON text where the
196 | * error occurred, along with an arrow pointing to the specific char.
197 | *
198 | * \returns A dynamically allocated string will be returned which should be
199 | * freed with yajl_free_error
200 | +*/
201 | unsigned char *
202 | yajl_get_error(yajl_handle hand, int verbose,
203 | const unsigned char * jsonText, size_t jsonTextLen)
204 | {
205 | return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose);
206 | }
207 |
208 | /*+
209 | * get the amount of data consumed from the last chunk passed to YAJL.
210 | *
211 | * In the case of a successful parse this can help you understand if
212 | * the entire buffer was consumed (which will allow you to handle
213 | * "junk at end of input").
214 | *
215 | * In the event an error is encountered during parsing, this function
216 | * affords the client a way to get the offset into the most recent
217 | * chunk where the error occurred. 0 will be returned if no error
218 | * was encountered.
219 | +*/
220 | size_t
221 | yajl_get_bytes_consumed(yajl_handle hand)
222 | {
223 | if (!hand) return 0;
224 | else return hand->bytesConsumed;
225 | }
226 |
227 |
228 | /*+ free an error returned from yajl_get_error +*/
229 | void
230 | yajl_free_error(yajl_handle hand, unsigned char * str)
231 | {
232 | /* use memory allocation functions if set */
233 | YA_FREE(&(hand->alloc), str);
234 | }
235 |
236 | /* XXX: add utility routines to parse from file */