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 "api/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 *
yajl_status_to_string(yajl_status stat)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 yajl_handle
yajl_alloc(const yajl_callbacks * callbacks,yajl_alloc_funcs * afs,void * ctx)46 yajl_alloc(const yajl_callbacks * callbacks,
47 yajl_alloc_funcs * afs,
48 void * ctx)
49 {
50 yajl_handle hand = NULL;
51 yajl_alloc_funcs afsBuffer;
52
53 /* first order of business is to set up memory allocation routines */
54 if (afs != NULL) {
55 if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
56 {
57 return NULL;
58 }
59 } else {
60 yajl_set_default_alloc_funcs(&afsBuffer);
61 afs = &afsBuffer;
62 }
63
64 hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t));
65
66 /* copy in pointers to allocation routines */
67 memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
68
69 hand->callbacks = callbacks;
70 hand->ctx = ctx;
71 hand->lexer = NULL;
72 hand->bytesConsumed = 0;
73 hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
74 hand->flags = 0;
75 yajl_bs_init(hand->stateStack, &(hand->alloc));
76 yajl_bs_push(hand->stateStack, yajl_state_start);
77
78 return hand;
79 }
80
81 int
yajl_config(yajl_handle h,yajl_option opt,...)82 yajl_config(yajl_handle h, yajl_option opt, ...)
83 {
84 int rv = 1;
85 va_list ap;
86 va_start(ap, opt);
87
88 switch(opt) {
89 case yajl_allow_comments:
90 case yajl_dont_validate_strings:
91 case yajl_allow_trailing_garbage:
92 case yajl_allow_multiple_values:
93 case yajl_allow_partial_values:
94 if (va_arg(ap, int)) h->flags |= opt;
95 else h->flags &= ~opt;
96 break;
97 default:
98 rv = 0;
99 }
100 va_end(ap);
101
102 return rv;
103 }
104
105 void
yajl_free(yajl_handle handle)106 yajl_free(yajl_handle handle)
107 {
108 yajl_bs_free(handle->stateStack);
109 yajl_buf_free(handle->decodeBuf);
110 if (handle->lexer) {
111 yajl_lex_free(handle->lexer);
112 handle->lexer = NULL;
113 }
114 YA_FREE(&(handle->alloc), handle);
115 }
116
117 yajl_status
yajl_parse(yajl_handle hand,const unsigned char * jsonText,size_t jsonTextLen)118 yajl_parse(yajl_handle hand, const unsigned char * jsonText,
119 size_t jsonTextLen)
120 {
121 yajl_status status;
122
123 /* lazy allocation of the lexer */
124 if (hand->lexer == NULL) {
125 hand->lexer = yajl_lex_alloc(&(hand->alloc),
126 hand->flags & yajl_allow_comments,
127 !(hand->flags & yajl_dont_validate_strings));
128 }
129
130 status = yajl_do_parse(hand, jsonText, jsonTextLen);
131 return status;
132 }
133
134
135 yajl_status
yajl_complete_parse(yajl_handle hand)136 yajl_complete_parse(yajl_handle hand)
137 {
138 /* The lexer is lazy allocated in the first call to parse. if parse is
139 * never called, then no data was provided to parse at all. This is a
140 * "premature EOF" error unless yajl_allow_partial_values is specified.
141 * allocating the lexer now is the simplest possible way to handle this
142 * case while preserving all the other semantics of the parser
143 * (multiple values, partial values, etc). */
144 if (hand->lexer == NULL) {
145 hand->lexer = yajl_lex_alloc(&(hand->alloc),
146 hand->flags & yajl_allow_comments,
147 !(hand->flags & yajl_dont_validate_strings));
148 }
149
150 return yajl_do_finish(hand);
151 }
152
153 unsigned char *
yajl_get_error(yajl_handle hand,int verbose,const unsigned char * jsonText,size_t jsonTextLen)154 yajl_get_error(yajl_handle hand, int verbose,
155 const unsigned char * jsonText, size_t jsonTextLen)
156 {
157 return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose);
158 }
159
160 size_t
yajl_get_bytes_consumed(yajl_handle hand)161 yajl_get_bytes_consumed(yajl_handle hand)
162 {
163 if (!hand) return 0;
164 else return hand->bytesConsumed;
165 }
166
167
168 void
yajl_free_error(yajl_handle hand,unsigned char * str)169 yajl_free_error(yajl_handle hand, unsigned char * str)
170 {
171 /* use memory allocation functions if set */
172 YA_FREE(&(hand->alloc), str);
173 }
174
175 /* XXX: add utility routines to parse from file */
176