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_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