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 */