1 /*
2  * Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
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 /**
18  * \file yajl_parse.h
19  * Interface to YAJL's JSON stream parsing facilities.
20  */
21 
22 #include <yajl/yajl_common.h>
23 
24 #ifndef __YAJL_PARSE_H__
25 #define __YAJL_PARSE_H__
26 
27 #include <stddef.h>
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32     /** error codes returned from this interface */
33     typedef enum {
34         /** no error was encountered */
35         yajl_status_ok,
36         /** a client callback returned zero, stopping the parse */
37         yajl_status_client_canceled,
38         /** An error occured during the parse.  Call yajl_get_error for
39          *  more information about the encountered error */
40         yajl_status_error
41     } yajl_status;
42 
43     /** attain a human readable, english, string for an error */
44     YAJL_API const char * yajl_status_to_string(yajl_status code);
45 
46     /** an opaque handle to a parser */
47     typedef struct yajl_handle_t * yajl_handle;
48 
49     /** yajl is an event driven parser.  this means as json elements are
50      *  parsed, you are called back to do something with the data.  The
51      *  functions in this table indicate the various events for which
52      *  you will be called back.  Each callback accepts a "context"
53      *  pointer, this is a void * that is passed into the yajl_parse
54      *  function which the client code may use to pass around context.
55      *
56      *  All callbacks return an integer.  If non-zero, the parse will
57      *  continue.  If zero, the parse will be canceled and
58      *  yajl_status_client_canceled will be returned from the parse.
59      *
60      *  \attention {
61      *    A note about the handling of numbers:
62      *
63      *    yajl will only convert numbers that can be represented in a
64      *    double or a 64 bit (long long) int.  All other numbers will
65      *    be passed to the client in string form using the yajl_number
66      *    callback.  Furthermore, if yajl_number is not NULL, it will
67      *    always be used to return numbers, that is yajl_integer and
68      *    yajl_double will be ignored.  If yajl_number is NULL but one
69      *    of yajl_integer or yajl_double are defined, parsing of a
70      *    number larger than is representable in a double or 64 bit
71      *    integer will result in a parse error.
72      *  }
73      */
74     typedef struct {
75         int (* yajl_null)(void * ctx);
76         int (* yajl_boolean)(void * ctx, int boolVal);
77         int (* yajl_integer)(void * ctx, long long integerVal);
78         int (* yajl_double)(void * ctx, double doubleVal);
79         /** A callback which passes the string representation of the number
80          *  back to the client.  Will be used for all numbers when present */
81         int (* yajl_number)(void * ctx, const char * numberVal,
82                             size_t numberLen);
83 
84         /** strings are returned as pointers into the JSON text when,
85          * possible, as a result, they are _not_ null padded */
86         int (* yajl_string)(void * ctx, const unsigned char * stringVal,
87                             size_t stringLen);
88 
89         int (* yajl_start_map)(void * ctx);
90         int (* yajl_map_key)(void * ctx, const unsigned char * key,
91                              size_t stringLen);
92         int (* yajl_end_map)(void * ctx);
93 
94         int (* yajl_start_array)(void * ctx);
95         int (* yajl_end_array)(void * ctx);
96     } yajl_callbacks;
97 
98     /** allocate a parser handle
99      *  \param callbacks  a yajl callbacks structure specifying the
100      *                    functions to call when different JSON entities
101      *                    are encountered in the input text.  May be NULL,
102      *                    which is only useful for validation.
103      *  \param afs        memory allocation functions, may be NULL for to use
104      *                    C runtime library routines (malloc and friends)
105      *  \param ctx        a context pointer that will be passed to callbacks.
106      */
107     YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks,
108                                     yajl_alloc_funcs * afs,
109                                     void * ctx);
110 
111 
112     /** configuration parameters for the parser, these may be passed to
113      *  yajl_config() along with option specific argument(s).  In general,
114      *  all configuration parameters default to *off*. */
115     typedef enum {
116         /** Ignore javascript style comments present in
117          *  JSON input.  Non-standard, but rather fun
118          *  arguments: toggled off with integer zero, on otherwise.
119          *
120          *  example:
121          *    yajl_config(h, yajl_allow_comments, 1); // turn comment support on
122          */
123         yajl_allow_comments = 0x01,
124         /**
125          * When set the parser will verify that all strings in JSON input are
126          * valid UTF8 and will emit a parse error if this is not so.  When set,
127          * this option makes parsing slightly more expensive (~7% depending
128          * on processor and compiler in use)
129          *
130          * example:
131          *   yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking
132          */
133         yajl_dont_validate_strings     = 0x02,
134         /**
135          * By default, upon calls to yajl_complete_parse(), yajl will
136          * ensure the entire input text was consumed and will raise an error
137          * otherwise.  Enabling this flag will cause yajl to disable this
138          * check.  This can be useful when parsing json out of a that contains more
139          * than a single JSON document.
140          */
141         yajl_allow_trailing_garbage = 0x04,
142         /**
143          * Allow multiple values to be parsed by a single handle.  The
144          * entire text must be valid JSON, and values can be seperated
145          * by any kind of whitespace.  This flag will change the
146          * behavior of the parser, and cause it continue parsing after
147          * a value is parsed, rather than transitioning into a
148          * complete state.  This option can be useful when parsing multiple
149          * values from an input stream.
150          */
151         yajl_allow_multiple_values = 0x08,
152         /**
153          * When yajl_complete_parse() is called the parser will
154          * check that the top level value was completely consumed.  I.E.,
155          * if called whilst in the middle of parsing a value
156          * yajl will enter an error state (premature EOF).  Setting this
157          * flag suppresses that check and the corresponding error.
158          */
159         yajl_allow_partial_values = 0x10,
160         /**
161            By default YAJL unescapes strings before passing them to the
162            string callback function. This options disables that behaviour.
163            Some applications might want the string escaped, and without this
164            option their string callback would have to escape the input string.
165          */
166         yajl_dont_unescape_strings = 0x20
167     } yajl_option;
168 
169     /** allow the modification of parser options subsequent to handle
170      *  allocation (via yajl_alloc)
171      *  \returns zero in case of errors, non-zero otherwise
172      */
173     YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...);
174 
175     /** free a parser handle */
176     YAJL_API void yajl_free(yajl_handle handle);
177 
178     /** Parse some json!
179      *  \param hand - a handle to the json parser allocated with yajl_alloc
180      *  \param jsonText - a pointer to the UTF8 json text to be parsed
181      *  \param jsonTextLength - the length, in bytes, of input text
182      */
183     YAJL_API yajl_status yajl_parse(yajl_handle hand,
184                                     const unsigned char * jsonText,
185                                     size_t jsonTextLength);
186 
187     /** Parse any remaining buffered json.
188      *  Since yajl is a stream-based parser, without an explicit end of
189      *  input, yajl sometimes can't decide if content at the end of the
190      *  stream is valid or not.  For example, if "1" has been fed in,
191      *  yajl can't know whether another digit is next or some character
192      *  that would terminate the integer token.
193      *
194      *  \param hand - a handle to the json parser allocated with yajl_alloc
195      */
196     YAJL_API yajl_status yajl_complete_parse(yajl_handle hand);
197 
198     /** get an error string describing the state of the
199      *  parse.
200      *
201      *  If verbose is non-zero, the message will include the JSON
202      *  text where the error occured, along with an arrow pointing to
203      *  the specific char.
204      *
205      *  \returns A dynamically allocated string will be returned which should
206      *  be freed with yajl_free_error
207      */
208     YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose,
209                                             const unsigned char * jsonText,
210                                             size_t jsonTextLength);
211 
212     /**
213      * get the amount of data consumed from the last chunk passed to YAJL.
214      *
215      * In the case of a successful parse this can help you understand if
216      * the entire buffer was consumed (which will allow you to handle
217      * "junk at end of input").
218      *
219      * In the event an error is encountered during parsing, this function
220      * affords the client a way to get the offset into the most recent
221      * chunk where the error occured.  0 will be returned if no error
222      * was encountered.
223      */
224     YAJL_API size_t yajl_get_bytes_consumed(yajl_handle hand);
225 
226     /** free an error returned from yajl_get_error */
227     YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str);
228 
229 #ifdef __cplusplus
230 }
231 #endif
232 
233 #endif
234