source: trunk/libtransmission/jsonsl.h @ 13614

Last change on this file since 13614 was 13614, checked in by jordan, 8 years ago

(trunk libT) #5131: replace JSON_parser with jsonsl to resolve licensing issue.

File size: 25.6 KB
Line 
1/*
2 * jsonsl
3 * https://github.com/mnunberg/jsonsl
4 *
5 * Copyright (c) 2012 M. Nunberg, mnunberg@haskalah.org
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27/**
28 * JSON Simple/Stacked/Stateful Lexer.
29 * - Does not buffer data
30 * - Maintains state
31 * - Callback oriented
32 * - Lightweight and fast. One source file and one header file
33 */
34
35#ifndef JSONSL_H_
36#define JSONSL_H_
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <sys/types.h>
42#include <wchar.h>
43
44#ifdef __cplusplus
45extern "C" {
46#endif /* __cplusplus */
47
48#ifdef JSONSL_USE_WCHAR
49typedef jsonsl_char_t wchar_t;
50typedef jsonsl_uchar_t unsigned wchar_t;
51#else
52typedef char jsonsl_char_t;
53typedef unsigned char jsonsl_uchar_t;
54#endif /* JSONSL_USE_WCHAR */
55
56/* Stolen from http-parser.h, and possibly others */
57#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
58typedef __int8 int8_t;
59typedef unsigned __int8 uint8_t;
60typedef __int16 int16_t;
61typedef unsigned __int16 uint16_t;
62typedef __int32 int32_t;
63typedef unsigned __int32 uint32_t;
64typedef __int64 int64_t;
65typedef unsigned __int64 uint64_t;
66
67typedef unsigned int size_t;
68typedef int ssize_t;
69#else
70#include <stdint.h>
71#endif
72
73
74#if (!defined(JSONSL_STATE_GENERIC)) && (!defined(JSONSL_STATE_USER_FIELDS))
75#warning "JSONSL_STATE_USER_FIELDS not defined. Define this for extra structure fields"
76#warning "or define JSONSL_STATE_GENERIC"
77#define JSONSL_STATE_GENERIC
78#endif /* !defined JSONSL_STATE_GENERIC */
79
80#ifdef JSONSL_STATE_GENERIC
81#define JSONSL_STATE_USER_FIELDS
82#endif /* JSONSL_STATE_GENERIC */
83
84#ifndef JSONSL_API
85#define JSONSL_API
86#endif /* JSONSL_API */
87
88#define JSONSL_MAX_LEVELS 512
89
90struct jsonsl_st;
91typedef struct jsonsl_st *jsonsl_t;
92
93typedef struct jsonsl_jpr_st* jsonsl_jpr_t;
94
95/**
96 * This flag is true when AND'd against a type whose value
97 * must be in "quoutes" i.e. T_HKEY and T_STRING
98 */
99#define JSONSL_Tf_STRINGY 0xffff00
100
101/**
102 * Constant representing the special JSON types.
103 * The values are special and aid in speed (the OBJECT and LIST
104 * values are the char literals of their openings).
105 *
106 * Their actual value is a character which attempts to resemble
107 * some mnemonic reference to the actual type.
108 *
109 * If new types are added, they must fit into the ASCII printable
110 * range (so they should be AND'd with 0x7f and yield something
111 * meaningful)
112 */
113#define JSONSL_XTYPE \
114    X(STRING,   '"'|JSONSL_Tf_STRINGY) \
115    X(HKEY,     '#'|JSONSL_Tf_STRINGY) \
116    X(OBJECT,   '{') \
117    X(LIST,     '[') \
118    X(SPECIAL,  '^') \
119    X(UESCAPE,  'u')
120typedef enum {
121#define X(o, c) \
122    JSONSL_T_##o = c,
123    JSONSL_XTYPE
124    JSONSL_T_UNKNOWN = '?',
125    /* Abstract 'root' object */
126    JSONSL_T_ROOT = 0
127#undef X
128} jsonsl_type_t;
129
130/**
131 * Subtypes for T_SPECIAL. We define them as flags
132 * because more than one type can be applied to a
133 * given object.
134 */
135
136#define JSONSL_XSPECIAL \
137    X(NONE, 0) \
138    X(SIGNED,       1<<0) \
139    X(UNSIGNED,     1<<1) \
140    X(TRUE,         1<<2) \
141    X(FALSE,        1<<3) \
142    X(NULL,         1<<4) \
143    X(FLOAT,        1<<5) \
144    X(EXPONENT,     1<<6) \
145    X(NONASCII,     1<<7)
146typedef enum {
147#define X(o,b) \
148    JSONSL_SPECIALf_##o = b,
149    JSONSL_XSPECIAL
150#undef X
151    /* Handy flags for checking */
152    JSONSL_SPECIALf_UNKNOWN = 1 << 8,
153    JSONSL_SPECIALf_NUMERIC = (JSONSL_SPECIALf_SIGNED|JSONSL_SPECIALf_UNSIGNED),
154    JSONSL_SPECIALf_BOOLEAN = (JSONSL_SPECIALf_TRUE|JSONSL_SPECIALf_FALSE),
155    /* For non-simple numeric types */
156    JSONSL_SPECIALf_NUMNOINT = (JSONSL_SPECIALf_FLOAT|JSONSL_SPECIALf_EXPONENT)
157} jsonsl_special_t;
158
159
160/**
161 * These are the various types of stack (or other) events
162 * which will trigger a callback.
163 * Like the type constants, this are also mnemonic
164 */
165#define JSONSL_XACTION \
166    X(PUSH, '+') \
167    X(POP, '-') \
168    X(UESCAPE, 'U') \
169    X(ERROR, '!')
170typedef enum {
171#define X(a,c) \
172    JSONSL_ACTION_##a = c,
173    JSONSL_XACTION
174    JSONSL_ACTION_UNKNOWN = '?'
175#undef X
176} jsonsl_action_t;
177
178
179/**
180 * Various errors which may be thrown while parsing JSON
181 */
182#define JSONSL_XERR \
183    X(SUCCESS) \
184/* Trailing garbage characters */ \
185    X(GARBAGE_TRAILING) \
186/* We were expecting a 'special' (numeric, true, false, null) */ \
187    X(SPECIAL_EXPECTED) \
188/* Found a stray token */ \
189    X(STRAY_TOKEN) \
190/* We were expecting a token before this one */ \
191    X(MISSING_TOKEN) \
192/* Cannot insert because the container is not ready */ \
193    X(CANT_INSERT) \
194/* Found a '\' outside a string */ \
195    X(ESCAPE_OUTSIDE_STRING) \
196/* Found a ':' outside of a hash */ \
197    X(KEY_OUTSIDE_OBJECT) \
198/* found a string outside of a container */ \
199    X(STRING_OUTSIDE_CONTAINER) \
200/* Found a null byte in middle of string */ \
201    X(FOUND_NULL_BYTE) \
202/* Current level exceeds limit specified in constructor */ \
203    X(LEVELS_EXCEEDED) \
204/* Got a } as a result of an opening [ or vice versa */ \
205    X(BRACKET_MISMATCH) \
206/* We expected a key, but got something else instead */ \
207    X(HKEY_EXPECTED) \
208/* We got an illegal control character (bad whitespace or something) */ \
209    X(WEIRD_WHITESPACE) \
210/* Found a \u-escape, but there were less than 4 following hex digits */ \
211    X(UESCAPE_TOOSHORT) \
212/* Invalid two-character escape */ \
213    X(ESCAPE_INVALID) \
214/* Trailing comma */ \
215    X(TRAILING_COMMA) \
216/* An invalid number was passed in a numeric field */ \
217    X(INVALID_NUMBER) \
218/* The following are for JPR Stuff */ \
219    \
220/* Found a literal '%' but it was only followed by a single valid hex digit */ \
221    X(PERCENT_BADHEX) \
222/* jsonpointer URI is malformed '/' */ \
223    X(JPR_BADPATH) \
224/* Duplicate slash */ \
225    X(JPR_DUPSLASH) \
226/* No leading root */ \
227    X(JPR_NOROOT)
228
229typedef enum {
230#define X(e) \
231    JSONSL_ERROR_##e,
232    JSONSL_XERR
233#undef X
234    JSONSL_ERROR_GENERIC
235} jsonsl_error_t;
236
237
238/**
239 * A state is a single level of the stack
240 */
241struct jsonsl_state_st {
242    /**
243     * The JSON object type
244     */
245    jsonsl_type_t type;
246
247    /** If this element is special, then its extended type is here */
248    jsonsl_special_t special_flags;
249
250    /**
251     * Position offset variables. These are relative to jsn->pos.
252     * pos_begin is the position at which this state was first pushed
253     * to the stack. pos_cur is the position at which return last controlled
254     * to this state (i.e. an immediate child state was popped from it).
255     */
256
257    /**
258     * The position at which this state was first PUSHed
259     */
260    size_t pos_begin;
261
262    /**
263     * The position at which any immediate child was last POPped
264     */
265    size_t pos_cur;
266
267
268    /**
269     * Level of recursion into nesting. This is mainly a convenience
270     * variable, as this can technically be deduced from the lexer's
271     * level parameter (though the logic is not that simple)
272     */
273    size_t level;
274
275
276    /**
277     * how many elements in the object/list.
278     * For objects (hashes), an element is either
279     * a key or a value. Thus for one complete pair,
280     * nelem will be 2.
281     *
282     * For special types, this will hold the sum of the digits.
283     * This only holds true for values which are simple signed/unsigned
284     * numbers. Otherwise a special flag is set, and extra handling is not
285     * performed.
286     */
287    uint64_t nelem;
288
289
290
291    /*TODO: merge this and special_flags into a union */
292
293
294    /**
295     * Useful for an opening nest, this will prevent a callback from being
296     * invoked on this item or any of its children
297     */
298    int ignore_callback;
299
300    /**
301     * Counter which is incremented each time an escape ('\') is encountered.
302     */
303    unsigned int nescapes;
304
305    /**
306     * Put anything you want here. if JSONSL_STATE_USER_FIELDS is here, then
307     * the macro expansion happens here
308     */
309#ifndef JSONSL_STATE_GENERIC
310    JSONSL_STATE_USER_FIELDS
311#else
312
313    /**
314     * Otherwise, this is a simple void * pointer for anything you want
315     */
316    void *data;
317#endif /* JSONSL_STATE_USER_FIELDS */
318};
319
320/*
321 * So now we need some special structure for keeping the
322 * JPR info in sync. Preferrably all in a single block
323 * of memory (there's no need for separate allocations.
324 * So we will define a 'table' with the following layout
325 *
326 * Level    nPosbl  JPR1_last   JPR2_last   JPR3_last
327 *
328 * 0        1       NOMATCH     POSSIBLE    POSSIBLE
329 * 1        0       NOMATCH     NOMATCH     COMPLETE
330 * [ table ends here because no further path is possible]
331 *
332 * Where the JPR..n corresponds to the number of JPRs
333 * requested, and nPosble is a quick flag to determine
334 *
335 * the number of possibilities. In the future this might
336 * be made into a proper 'jump' table,
337 *
338 * Since we always mark JPRs from the higher levels descending
339 * into the lower ones, a prospective child match would first
340 * look at the parent table to check the possibilities, and then
341 * see which ones were possible..
342 *
343 * Thus, the size of this blob would be (and these are all ints here)
344 * nLevels * nJPR * 2.
345 *
346 * the 'Width' of the table would be nJPR*2, and the 'height' would be
347 * nlevels
348 */
349
350/**
351 * This is called when a stack change ocurs.
352 *
353 * @param jsn The lexer
354 * @param action The type of action, this can be PUSH or POP
355 * @param state A pointer to the stack currently affected by the action
356 * @param at A pointer to the position of the input buffer which triggered
357 * this action.
358 */
359typedef void (*jsonsl_stack_callback)(
360        jsonsl_t jsn,
361        jsonsl_action_t action,
362        struct jsonsl_state_st* state,
363        const jsonsl_char_t *at);
364
365
366/**
367 * This is called when an error is encountered.
368 * Sometimes it's possible to 'erase' characters (by replacing them
369 * with whitespace). If you think you have corrected the error, you
370 * can return a true value, in which case the parser will backtrack
371 * and try again.
372 *
373 * @param jsn The lexer
374 * @param error The error which was thrown
375 * @param state the current state
376 * @param a pointer to the position of the input buffer which triggered
377 * the error. Note that this is not const, this is because you have the
378 * possibility of modifying the character in an attempt to correct the
379 * error
380 *
381 * @return zero to bail, nonzero to try again (this only makes sense if
382 * the input buffer has been modified by this callback)
383 */
384typedef int (*jsonsl_error_callback)(
385        jsonsl_t jsn,
386        jsonsl_error_t error,
387        struct jsonsl_state_st* state,
388        jsonsl_char_t *at);
389
390struct jsonsl_st {
391    /** Public, read-only */
392
393    /** This is the current level of the stack */
394    size_t level;
395
396    /**
397     * This is the current position, relative to the beginning
398     * of the stream.
399     */
400    size_t pos;
401
402    /** This is the 'bytes' variable passed to feed() */
403    const jsonsl_char_t *base;
404
405    /** Callback invoked for PUSH actions */
406    jsonsl_stack_callback action_callback_PUSH;
407
408    /** Callback invoked for POP actions */
409    jsonsl_stack_callback action_callback_POP;
410
411    /** Default callback for any action, if neither PUSH or POP callbacks are defined */
412    jsonsl_stack_callback action_callback;
413
414    /** Do not invoke callbacks for objects deeper than this level */
415    unsigned int max_callback_level;
416
417    /** The error callback. Invoked when an error happens. Should not be NULL */
418    jsonsl_error_callback error_callback;
419
420    /* these are boolean flags you can modify. You will be called
421     * about notification for each of these types if the corresponding
422     * variable is true.
423     */
424
425    /**
426     * @name Callback Booleans.
427     * These determine whether a callback is to be invoked for certain types of objects
428     * @{*/
429
430    /** Boolean flag to enable or disable the invokcation for events on this type*/
431    int call_SPECIAL;
432    int call_OBJECT;
433    int call_LIST;
434    int call_STRING;
435    int call_HKEY;
436    /*@}*/
437
438    /**
439     * @name u-Escape handling
440     * Special handling for the \\u-f00d type sequences. These are meant
441     * to be translated back into the corresponding octet(s).
442     * A special callback (if set) is invoked with *at=='u'. An application
443     * may wish to temporarily suspend parsing and handle the 'u-' sequence
444     * internally (or not).
445     */
446
447     /*@{*/
448
449    /** Callback to be invoked for a u-escape */
450    jsonsl_stack_callback action_callback_UESCAPE;
451
452    /** Boolean flag, whether to invoke the callback */
453    int call_UESCAPE;
454
455    /** Boolean flag, whether we should return after encountering a u-escape:
456     * the callback is invoked and then we return if this is true
457     */
458    int return_UESCAPE;
459    /*@}*/
460
461    struct {
462        int allow_trailing_comma;
463    } options;
464
465    /** Put anything here */
466    void *data;
467
468    /*@{*/
469    /** Private */
470    int in_escape;
471    char expecting;
472    char tok_last;
473    int can_insert;
474    size_t levels_max;
475
476#ifndef JSONSL_NO_JPR
477    unsigned int jpr_count;
478    jsonsl_jpr_t *jprs;
479
480    /* Root pointer for JPR matching information */
481    size_t *jpr_root;
482#endif /* JSONSL_NO_JPR */
483    /*@}*/
484
485    /**
486     * This is the stack. Its upper bound is levels_max, or the
487     * nlevels argument passed to jsonsl_new. If you modify this structure,
488     * make sure that this member is last.
489     */
490    struct jsonsl_state_st stack[1];
491};
492
493
494/**
495 * Creates a new lexer object, with capacity for recursion up to nlevels
496 *
497 * @param nlevels maximum recursion depth
498 */
499JSONSL_API
500jsonsl_t jsonsl_new(size_t nlevels);
501
502/**
503 * Feeds data into the lexer.
504 *
505 * @param jsn the lexer object
506 * @param bytes new data to be fed
507 * @param nbytes size of new data
508 */
509JSONSL_API
510void jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes);
511
512/**
513 * Resets the internal parser state. This does not free the parser
514 * but does clean it internally, so that the next time feed() is called,
515 * it will be treated as a new stream
516 *
517 * @param jsn the lexer
518 */
519JSONSL_API
520void jsonsl_reset(jsonsl_t jsn);
521
522/**
523 * Frees the lexer, cleaning any allocated memory taken
524 *
525 * @param jsn the lexer
526 */
527JSONSL_API
528void jsonsl_destroy(jsonsl_t jsn);
529
530/**
531 * Gets the 'parent' element, given the current one
532 *
533 * @param jsn the lexer
534 * @param cur the current nest, which should be a struct jsonsl_nest_st
535 */
536#define jsonsl_last_state(jsn, cur) \
537    (cur->level > 1 ) \
538    ? (jsn->stack + (cur->level-1)) \
539    : NULL
540
541
542/**
543 * This enables receiving callbacks on all events. Doesn't do
544 * anything special but helps avoid some boilerplate.
545 * This does not touch the UESCAPE callbacks or flags.
546 */
547#define jsonsl_enable_all_callbacks(jsn) \
548    jsn->call_HKEY = 1; \
549    jsn->call_STRING = 1; \
550    jsn->call_OBJECT = 1; \
551    jsn->call_SPECIAL = 1; \
552    jsn->call_LIST = 1;
553
554/**
555 * A macro which returns true if the current state object can
556 * have children. This means a list type or an object type.
557 */
558#define JSONSL_STATE_IS_CONTAINER(state) \
559        (state->type == JSONSL_T_OBJECT || state->type == JSONSL_T_LIST)
560
561/**
562 * These two functions, dump a string representation
563 * of the error or type, respectively. They will never
564 * return NULL
565 */
566JSONSL_API
567const char* jsonsl_strerror(jsonsl_error_t err);
568JSONSL_API
569const char* jsonsl_strtype(jsonsl_type_t jt);
570
571/**
572 * Dumps global metrics to the screen. This is a noop unless
573 * jsonsl was compiled with JSONSL_USE_METRICS
574 */
575JSONSL_API
576void jsonsl_dump_global_metrics(void);
577
578/* This macro just here for editors to do code folding */
579#ifndef JSONSL_NO_JPR
580
581/**
582 * @name JSON Pointer API
583 *
584 * JSONPointer API. This isn't really related to the lexer (at least not yet)
585 * JSONPointer provides an extremely simple specification for providing
586 * locations within JSON objects. We will extend it a bit and allow for
587 * providing 'wildcard' characters by which to be able to 'query' the stream.
588 *
589 * See http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00
590 *
591 * Currently I'm implementing the 'single query' API which can only use a single
592 * query component. In the future I will integrate my yet-to-be-published
593 * Boyer-Moore-esque prefix searching implementation, in order to allow
594 * multiple paths to be merged into one for quick and efficient searching.
595 *
596 *
597 * JPR (as we'll refer to it within the source) can be used by splitting
598 * the components into mutliple sections, and incrementally 'track' each
599 * component. When JSONSL delivers a 'pop' callback for a string, or a 'push'
600 * callback for an object, we will check to see whether the index matching
601 * the component corresponding to the current level contains a match
602 * for our path.
603 *
604 * In order to do this properly, a structure must be maintained within the
605 * parent indicating whether its children are possible matches. This flag
606 * will be 'inherited' by call children which may conform to the match
607 * specification, and discarded by all which do not (thereby eliminating
608 * their children from inheriting it).
609 *
610 * A successful match is a complete one. One can provide multiple paths with
611 * multiple levels of matches e.g.
612 *  /foo/bar/baz/^/blah
613 *
614 *  @{
615 */
616
617/** The wildcard character */
618#ifndef JSONSL_PATH_WILDCARD_CHAR
619#define JSONSL_PATH_WILDCARD_CHAR '^'
620#endif /* WILDCARD_CHAR */
621
622#define JSONSL_XMATCH \
623    X(COMPLETE,1) \
624    X(POSSIBLE,0) \
625    X(NOMATCH,-1)
626
627typedef enum {
628
629#define X(T,v) \
630    JSONSL_MATCH_##T = v,
631    JSONSL_XMATCH
632
633#undef X
634    JSONSL_MATCH_UNKNOWN
635} jsonsl_jpr_match_t;
636
637typedef enum {
638    JSONSL_PATH_STRING = 1,
639    JSONSL_PATH_WILDCARD,
640    JSONSL_PATH_NUMERIC,
641    JSONSL_PATH_ROOT,
642
643    /* Special */
644    JSONSL_PATH_INVALID = -1,
645    JSONSL_PATH_NONE = 0
646} jsonsl_jpr_type_t;
647
648struct jsonsl_jpr_component_st {
649    char *pstr;
650    /** if this is a numeric type, the number is 'cached' here */
651    unsigned long idx;
652    size_t len;
653    jsonsl_jpr_type_t ptype;
654};
655
656struct jsonsl_jpr_st {
657    /** Path components */
658    struct jsonsl_jpr_component_st *components;
659    size_t ncomponents;
660
661    /** Base of allocated string for components */
662    char *basestr;
663
664    /** The original match string. Useful for returning to the user */
665    char *orig;
666    size_t norig;
667};
668
669
670
671/**
672 * Create a new JPR object.
673 *
674 * @param path the JSONPointer path specification.
675 * @param errp a pointer to a jsonsl_error_t. If this function returns NULL,
676 * then more details will be in this variable.
677 *
678 * @return a new jsonsl_jpr_t object, or NULL on error.
679 */
680JSONSL_API
681jsonsl_jpr_t jsonsl_jpr_new(const char *path, jsonsl_error_t *errp);
682
683/**
684 * Destroy a JPR object
685 */
686JSONSL_API
687void jsonsl_jpr_destroy(jsonsl_jpr_t jpr);
688
689/**
690 * Match a JSON object against a type and specific level
691 *
692 * @param jpr the JPR object
693 * @param parent_type the type of the parent (should be T_LIST or T_OBJECT)
694 * @param parent_level the level of the parent
695 * @param key the 'key' of the child. If the parent is an array, this should be
696 * empty.
697 * @param nkey - the length of the key. If the parent is an array (T_LIST), then
698 * this should be the current index.
699 *
700 * @return a status constant. This indicates whether a match was excluded, possible,
701 * or successful.
702 */
703JSONSL_API
704jsonsl_jpr_match_t jsonsl_jpr_match(jsonsl_jpr_t jpr,
705                                    jsonsl_type_t parent_type,
706                                    size_t parent_level,
707                                    const char *key, size_t nkey);
708
709
710/**
711 * Associate a set of JPR objects with a lexer instance.
712 * This should be called before the lexer has been fed any data (and
713 * behavior is undefined if you don't adhere to this).
714 *
715 * After using this function, you may subsequently call match_state() on
716 * given states (presumably from within the callbacks).
717 *
718 * Note that currently the first JPR is the quickest and comes
719 * pre-allocated with the state structure. Further JPR objects
720 * are chained.
721 *
722 * @param jsn The lexer
723 * @param jprs An array of jsonsl_jpr_t objects
724 * @param njprs How many elements in the jprs array.
725 */
726JSONSL_API
727void jsonsl_jpr_match_state_init(jsonsl_t jsn,
728                                 jsonsl_jpr_t *jprs,
729                                 size_t njprs);
730
731/**
732 * This follows the same semantics as the normal match,
733 * except we infer parent and type information from the relevant state objects.
734 * The match status (for all possible JPR objects) is set in the *out parameter.
735 *
736 * If a match has succeeded, then its JPR object will be returned. In all other
737 * instances, NULL is returned;
738 *
739 * @param jpr The jsonsl_jpr_t handle
740 * @param state The jsonsl_state_st which is a candidate
741 * @param key The hash key (if applicable, can be NULL if parent is list)
742 * @param nkey Length of hash key (if applicable, can be zero if parent is list)
743 * @param out A pointer to a jsonsl_jpr_match_t. This will be populated with
744 * the match result
745 *
746 * @return If a match was completed in full, then the JPR object containing
747 * the matching path will be returned. Otherwise, the return is NULL (note, this
748 * does not mean matching has failed, it can still be part of the match: check
749 * the out parameter).
750 */
751JSONSL_API
752jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn,
753                                    struct jsonsl_state_st *state,
754                                    const char *key,
755                                    size_t nkey,
756                                    jsonsl_jpr_match_t *out);
757
758
759/**
760 * Cleanup any memory allocated and any states set by
761 * match_state_init() and match_state()
762 * @param jsn The lexer
763 */
764JSONSL_API
765void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn);
766
767/**
768 * Return a string representation of the match result returned by match()
769 */
770JSONSL_API
771const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match);
772
773/* @}*/
774
775/**
776 * Utility function to convert escape sequences into their original form.
777 *
778 * The decoders I've sampled do not seem to specify a standard behavior of what
779 * to escape/unescape.
780 *
781 * RFC 4627 Mandates only that the quoute, backslash, and ASCII control
782 * characters (0x00-0x1f) be escaped. It is often common for applications
783 * to escape a '/' - however this may also be desired behavior. the JSON
784 * spec is not clear on this, and therefore jsonsl leaves it up to you.
785 *
786 * @param in The input string.
787 * @param out An allocated output (should be the same size as in)
788 * @param len the size of the buffer
789 * @param toEscape - A sparse array of characters to unescape. Characters
790 * which are not present in this array, e.g. toEscape['c'] == 0 will be
791 * ignored and passed to the output in their original form.
792 * @param oflags If not null, and a \uXXXX escape expands to a non-ascii byte,
793 * then this variable will have the SPECIALf_NONASCII flag on.
794 *
795 * @param err A pointer to an error variable. If an error ocurrs, it will be
796 * set in this variable
797 * @param errat If not null and an error occurs, this will be set to point
798 * to the position within the string at which the offending character was
799 * encountered.
800 *
801 * @return The effective size of the output buffer.
802 */
803JSONSL_API
804size_t jsonsl_util_unescape_ex(const char *in,
805                               char *out,
806                               size_t len,
807                               const int toEscape[128],
808                               jsonsl_special_t *oflags,
809                               jsonsl_error_t *err,
810                               const char **errat);
811
812/**
813 * Convenience macro to avoid passing too many parameters
814 */
815#define jsonsl_util_unescape(in, out, len, toEscape, err) \
816    jsonsl_util_unescape_ex(in, out, len, toEscape, NULL, err, NULL)
817
818#endif /* JSONSL_NO_JPR */
819
820/**
821 * HERE BE CHARACTER TABLES!
822 */
823#define JSONSL_CHARTABLE_string_nopass \
824/* 0x00 */ 1 /* <NUL> */, /* 0x00 */  \
825/* 0x01 */ 1 /* <SOH> */, /* 0x01 */  \
826/* 0x02 */ 1 /* <STX> */, /* 0x02 */  \
827/* 0x03 */ 1 /* <ETX> */, /* 0x03 */  \
828/* 0x04 */ 1 /* <EOT> */, /* 0x04 */  \
829/* 0x05 */ 1 /* <ENQ> */, /* 0x05 */  \
830/* 0x06 */ 1 /* <ACK> */, /* 0x06 */  \
831/* 0x07 */ 1 /* <BEL> */, /* 0x07 */  \
832/* 0x08 */ 1 /* <BS> */, /* 0x08 */  \
833/* 0x09 */ 1 /* <HT> */, /* 0x09 */  \
834/* 0x0a */ 1 /* <LF> */, /* 0x0a */  \
835/* 0x0b */ 1 /* <VT> */, /* 0x0b */  \
836/* 0x0c */ 1 /* <FF> */, /* 0x0c */  \
837/* 0x0d */ 1 /* <CR> */, /* 0x0d */  \
838/* 0x0e */ 1 /* <SO> */, /* 0x0e */  \
839/* 0x0f */ 1 /* <SI> */, /* 0x0f */  \
840/* 0x10 */ 1 /* <DLE> */, /* 0x10 */  \
841/* 0x11 */ 1 /* <DC1> */, /* 0x11 */  \
842/* 0x12 */ 1 /* <DC2> */, /* 0x12 */  \
843/* 0x13 */ 1 /* <DC3> */, /* 0x13 */  \
844/* 0x14 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x21 */  \
845/* 0x22 */ 1 /* <"> */, /* 0x22 */  \
846/* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x42 */  \
847/* 0x43 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */  \
848/* 0x5c */ 1 /* <\> */, /* 0x5c */  \
849/* 0x5d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7c */  \
850/* 0x7d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9c */  \
851/* 0x9d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbc */  \
852/* 0xbd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdc */  \
853/* 0xdd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfc */  \
854/* 0xfd */ 0,0 /* 0xfe */  \
855
856
857
858#ifdef __cplusplus
859}
860#endif /* __cplusplus */
861
862#endif /* JSONSL_H_ */
Note: See TracBrowser for help on using the repository browser.