233 lines
6.4 KiB
C++
233 lines
6.4 KiB
C++
#include "libwebsockets.h"
|
|
struct lejp_ctx;
|
|
|
|
#ifndef ARRAY_SIZE
|
|
#define ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0]))
|
|
#endif
|
|
#define LEJP_FLAG_WS_KEEP 64
|
|
#define LEJP_FLAG_WS_COMMENTLINE 32
|
|
|
|
enum lejp_states {
|
|
LEJP_IDLE = 0,
|
|
LEJP_MEMBERS = 1,
|
|
LEJP_M_P = 2,
|
|
LEJP_MP_STRING = LEJP_FLAG_WS_KEEP | 3,
|
|
LEJP_MP_STRING_ESC = LEJP_FLAG_WS_KEEP | 4,
|
|
LEJP_MP_STRING_ESC_U1 = LEJP_FLAG_WS_KEEP | 5,
|
|
LEJP_MP_STRING_ESC_U2 = LEJP_FLAG_WS_KEEP | 6,
|
|
LEJP_MP_STRING_ESC_U3 = LEJP_FLAG_WS_KEEP | 7,
|
|
LEJP_MP_STRING_ESC_U4 = LEJP_FLAG_WS_KEEP | 8,
|
|
LEJP_MP_DELIM = 9,
|
|
LEJP_MP_VALUE = 10,
|
|
LEJP_MP_VALUE_NUM_INT = LEJP_FLAG_WS_KEEP | 11,
|
|
LEJP_MP_VALUE_NUM_EXP = LEJP_FLAG_WS_KEEP | 12,
|
|
LEJP_MP_VALUE_TOK = LEJP_FLAG_WS_KEEP | 13,
|
|
LEJP_MP_COMMA_OR_END = 14,
|
|
LEJP_MP_ARRAY_END = 15,
|
|
};
|
|
|
|
enum lejp_reasons {
|
|
LEJP_CONTINUE = -1,
|
|
LEJP_REJECT_IDLE_NO_BRACE = -2,
|
|
LEJP_REJECT_MEMBERS_NO_CLOSE = -3,
|
|
LEJP_REJECT_MP_NO_OPEN_QUOTE = -4,
|
|
LEJP_REJECT_MP_STRING_UNDERRUN = -5,
|
|
LEJP_REJECT_MP_ILLEGAL_CTRL = -6,
|
|
LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC = -7,
|
|
LEJP_REJECT_ILLEGAL_HEX = -8,
|
|
LEJP_REJECT_MP_DELIM_MISSING_COLON = -9,
|
|
LEJP_REJECT_MP_DELIM_BAD_VALUE_START = -10,
|
|
LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC = -11,
|
|
LEJP_REJECT_MP_VAL_NUM_FORMAT = -12,
|
|
LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP = -13,
|
|
LEJP_REJECT_MP_VAL_TOK_UNKNOWN = -14,
|
|
LEJP_REJECT_MP_C_OR_E_UNDERF = -15,
|
|
LEJP_REJECT_MP_C_OR_E_NOTARRAY = -16,
|
|
LEJP_REJECT_MP_ARRAY_END_MISSING = -17,
|
|
LEJP_REJECT_STACK_OVERFLOW = -18,
|
|
LEJP_REJECT_MP_DELIM_ISTACK = -19,
|
|
LEJP_REJECT_NUM_TOO_LONG = -20,
|
|
LEJP_REJECT_MP_C_OR_E_NEITHER = -21,
|
|
LEJP_REJECT_UNKNOWN = -22,
|
|
LEJP_REJECT_CALLBACK = -23
|
|
};
|
|
|
|
#define LEJP_FLAG_CB_IS_VALUE 64
|
|
|
|
enum lejp_callbacks {
|
|
LEJPCB_CONSTRUCTED = 0,
|
|
LEJPCB_DESTRUCTED = 1,
|
|
|
|
LEJPCB_START = 2,
|
|
LEJPCB_COMPLETE = 3,
|
|
LEJPCB_FAILED = 4,
|
|
|
|
LEJPCB_PAIR_NAME = 5,
|
|
|
|
LEJPCB_VAL_TRUE = LEJP_FLAG_CB_IS_VALUE | 6,
|
|
LEJPCB_VAL_FALSE = LEJP_FLAG_CB_IS_VALUE | 7,
|
|
LEJPCB_VAL_NULL = LEJP_FLAG_CB_IS_VALUE | 8,
|
|
LEJPCB_VAL_NUM_INT = LEJP_FLAG_CB_IS_VALUE | 9,
|
|
LEJPCB_VAL_NUM_FLOAT = LEJP_FLAG_CB_IS_VALUE | 10,
|
|
LEJPCB_VAL_STR_START = 11, /* notice handle separately */
|
|
LEJPCB_VAL_STR_CHUNK = LEJP_FLAG_CB_IS_VALUE | 12,
|
|
LEJPCB_VAL_STR_END = LEJP_FLAG_CB_IS_VALUE | 13,
|
|
|
|
LEJPCB_ARRAY_START = 14,
|
|
LEJPCB_ARRAY_END = 15,
|
|
|
|
LEJPCB_OBJECT_START = 16,
|
|
LEJPCB_OBJECT_END = 17
|
|
};
|
|
|
|
/**
|
|
* _lejp_callback() - User parser actions
|
|
* \param ctx: LEJP context
|
|
* \param reason: Callback reason
|
|
*
|
|
* Your user callback is associated with the context at construction time,
|
|
* and receives calls as the parsing progresses.
|
|
*
|
|
* All of the callbacks may be ignored and just return 0.
|
|
*
|
|
* The reasons it might get called, found in @reason, are:
|
|
*
|
|
* LEJPCB_CONSTRUCTED: The context was just constructed... you might want to
|
|
* perform one-time allocation for the life of the context.
|
|
*
|
|
* LEJPCB_DESTRUCTED: The context is being destructed... if you made any
|
|
* allocations at construction-time, you can free them now
|
|
*
|
|
* LEJPCB_START: Parsing is beginning at the first byte of input
|
|
*
|
|
* LEJPCB_COMPLETE: Parsing has completed successfully. You'll get a 0 or
|
|
* positive return code from lejp_parse indicating the
|
|
* amount of unused bytes left in the input buffer
|
|
*
|
|
* LEJPCB_FAILED: Parsing failed. You'll get a negative error code
|
|
* returned from lejp_parse
|
|
*
|
|
* LEJPCB_PAIR_NAME: When a "name":"value" pair has had the name parsed,
|
|
* this callback occurs. You can find the new name at
|
|
* the end of ctx->path[]
|
|
*
|
|
* LEJPCB_VAL_TRUE: The "true" value appeared
|
|
*
|
|
* LEJPCB_VAL_FALSE: The "false" value appeared
|
|
*
|
|
* LEJPCB_VAL_NULL: The "null" value appeared
|
|
*
|
|
* LEJPCB_VAL_NUM_INT: A string representing an integer is in ctx->buf
|
|
*
|
|
* LEJPCB_VAL_NUM_FLOAT: A string representing a float is in ctx->buf
|
|
*
|
|
* LEJPCB_VAL_STR_START: We are starting to parse a string, no data yet
|
|
*
|
|
* LEJPCB_VAL_STR_CHUNK: We parsed LEJP_STRING_CHUNK -1 bytes of string data in
|
|
* ctx->buf, which is as much as we can buffer, so we are
|
|
* spilling it. If all your strings are less than
|
|
* LEJP_STRING_CHUNK - 1 bytes, you will never see this
|
|
* callback.
|
|
*
|
|
* LEJPCB_VAL_STR_END: String parsing has completed, the last chunk of the
|
|
* string is in ctx->buf.
|
|
*
|
|
* LEJPCB_ARRAY_START: An array started
|
|
*
|
|
* LEJPCB_ARRAY_END: An array ended
|
|
*
|
|
* LEJPCB_OBJECT_START: An object started
|
|
*
|
|
* LEJPCB_OBJECT_END: An object ended
|
|
*/
|
|
LWS_EXTERN signed char _lejp_callback(struct lejp_ctx *ctx, char reason);
|
|
|
|
typedef signed char (*lejp_callback)(struct lejp_ctx *ctx, char reason);
|
|
|
|
#ifndef LEJP_MAX_DEPTH
|
|
#define LEJP_MAX_DEPTH 12
|
|
#endif
|
|
#ifndef LEJP_MAX_INDEX_DEPTH
|
|
#define LEJP_MAX_INDEX_DEPTH 5
|
|
#endif
|
|
#ifndef LEJP_MAX_PATH
|
|
#define LEJP_MAX_PATH 128
|
|
#endif
|
|
#ifndef LEJP_STRING_CHUNK
|
|
/* must be >= 30 to assemble floats */
|
|
#define LEJP_STRING_CHUNK 255
|
|
#endif
|
|
|
|
enum num_flags {
|
|
LEJP_SEEN_MINUS = (1 << 0),
|
|
LEJP_SEEN_POINT = (1 << 1),
|
|
LEJP_SEEN_POST_POINT = (1 << 2),
|
|
LEJP_SEEN_EXP = (1 << 3)
|
|
};
|
|
|
|
struct _lejp_stack {
|
|
char s; /* lejp_state stack*/
|
|
char p; /* path length */
|
|
char i; /* index array length */
|
|
char b; /* user bitfield */
|
|
};
|
|
|
|
struct lejp_ctx {
|
|
|
|
/* sorted by type for most compact alignment
|
|
*
|
|
* pointers
|
|
*/
|
|
|
|
signed char (*callback)(struct lejp_ctx *ctx, char reason);
|
|
void *user;
|
|
const char * const *paths;
|
|
|
|
/* arrays */
|
|
|
|
struct _lejp_stack st[LEJP_MAX_DEPTH];
|
|
unsigned short i[LEJP_MAX_INDEX_DEPTH]; /* index array */
|
|
unsigned short wild[LEJP_MAX_INDEX_DEPTH]; /* index array */
|
|
char path[LEJP_MAX_PATH];
|
|
char buf[LEJP_STRING_CHUNK];
|
|
|
|
/* int */
|
|
|
|
unsigned int line;
|
|
|
|
/* short */
|
|
|
|
unsigned short uni;
|
|
|
|
/* char */
|
|
|
|
unsigned char npos;
|
|
unsigned char dcount;
|
|
unsigned char f;
|
|
unsigned char sp; /* stack head */
|
|
unsigned char ipos; /* index stack depth */
|
|
unsigned char ppos;
|
|
unsigned char count_paths;
|
|
unsigned char path_match;
|
|
unsigned char path_match_len;
|
|
unsigned char wildcount;
|
|
};
|
|
|
|
LWS_VISIBLE LWS_EXTERN void
|
|
lejp_construct(struct lejp_ctx *ctx,
|
|
signed char (*callback)(struct lejp_ctx *ctx, char reason),
|
|
void *user, const char * const *paths, unsigned char paths_count);
|
|
|
|
LWS_VISIBLE LWS_EXTERN void
|
|
lejp_destruct(struct lejp_ctx *ctx);
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len);
|
|
|
|
LWS_VISIBLE LWS_EXTERN void
|
|
lejp_change_callback(struct lejp_ctx *ctx,
|
|
signed char (*callback)(struct lejp_ctx *ctx, char reason));
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len);
|