1 // Copyright (c) 2018-2020 Cesanta Software Limited 2 // All rights reserved 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 // SOFTWARE. 21 22 #ifndef MJSON_H 23 #define MJSON_H 24 25 #include <stdarg.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #ifndef MJSON_ENABLE_PRINT 30 #define MJSON_ENABLE_PRINT 1 31 #endif 32 33 #ifndef MJSON_ENABLE_RPC 34 #define MJSON_ENABLE_RPC 1 35 #endif 36 37 #ifndef MJSON_ENABLE_BASE64 38 #define MJSON_ENABLE_BASE64 1 39 #endif 40 41 #ifndef MJSON_ENABLE_MERGE 42 #define MJSON_ENABLE_MERGE 0 43 #elif MJSON_ENABLE_MERGE 44 #define MJSON_ENABLE_NEXT 1 45 #endif 46 47 #ifndef MJSON_ENABLE_PRETTY 48 #define MJSON_ENABLE_PRETTY 0 49 #elif MJSON_ENABLE_PRETTY 50 #define MJSON_ENABLE_NEXT 1 51 #endif 52 53 #ifndef MJSON_ENABLE_NEXT 54 #define MJSON_ENABLE_NEXT 0 55 #endif 56 57 #ifndef MJSON_RPC_LIST_NAME 58 #define MJSON_RPC_LIST_NAME "rpc.list" 59 #endif 60 61 #ifndef MJSON_DYNBUF_CHUNK 62 #define MJSON_DYNBUF_CHUNK 256 // Allocation granularity for print_dynamic_buf 63 #endif 64 65 #ifdef __cplusplus 66 extern "C" { 67 #endif 68 69 enum { 70 MJSON_ERROR_INVALID_INPUT = -1, 71 MJSON_ERROR_TOO_DEEP = -2, 72 }; 73 74 enum mjson_tok { 75 MJSON_TOK_INVALID = 0, 76 MJSON_TOK_KEY = 1, 77 MJSON_TOK_STRING = 11, 78 MJSON_TOK_NUMBER = 12, 79 MJSON_TOK_TRUE = 13, 80 MJSON_TOK_FALSE = 14, 81 MJSON_TOK_NULL = 15, 82 MJSON_TOK_ARRAY = 91, 83 MJSON_TOK_OBJECT = 123, 84 }; 85 #define MJSON_TOK_IS_VALUE(t) ((t) > 10 && (t) < 20) 86 87 typedef int (*mjson_cb_t)(int ev, const char *s, int off, int len, void *ud); 88 89 #ifndef MJSON_MAX_DEPTH 90 #define MJSON_MAX_DEPTH 20 91 #endif 92 93 int mjson(const char *s, int len, mjson_cb_t cb, void *ud); 94 enum mjson_tok mjson_find(const char *s, int len, const char *jp, 95 const char **tokptr, int *toklen); 96 int mjson_get_number(const char *s, int len, const char *path, double *v); 97 int mjson_get_bool(const char *s, int len, const char *path, int *v); 98 int mjson_get_string(const char *s, int len, const char *path, char *to, int n); 99 int mjson_get_hex(const char *s, int len, const char *path, char *to, int n); 100 101 #if MJSON_ENABLE_NEXT 102 int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff, 103 int *vlen, int *vtype); 104 #endif 105 106 #if MJSON_ENABLE_BASE64 107 int mjson_get_base64(const char *s, int len, const char *path, char *to, int n); 108 int mjson_base64_dec(const char *src, int n, char *dst, int dlen); 109 #endif 110 111 #if MJSON_ENABLE_PRINT 112 typedef int (*mjson_print_fn_t)(const char *buf, int len, void *userdata); 113 typedef int (*mjson_vprint_fn_t)(mjson_print_fn_t, void *, va_list *); 114 115 struct mjson_fixedbuf { 116 char *ptr; 117 int size, len; 118 }; 119 120 int mjson_printf(mjson_print_fn_t, void *, const char *fmt, ...); 121 int mjson_vprintf(mjson_print_fn_t, void *, const char *fmt, va_list ap); 122 int mjson_print_str(mjson_print_fn_t, void *, const char *s, int len); 123 int mjson_print_int(mjson_print_fn_t, void *, int value, int is_signed); 124 int mjson_print_long(mjson_print_fn_t, void *, long value, int is_signed); 125 int mjson_print_buf(mjson_print_fn_t fn, void *, const char *buf, int len); 126 127 int mjson_print_null(const char *ptr, int len, void *userdata); 128 int mjson_print_fixed_buf(const char *ptr, int len, void *userdata); 129 int mjson_print_dynamic_buf(const char *ptr, int len, void *userdata); 130 131 #if MJSON_ENABLE_PRETTY 132 int mjson_pretty(const char *, int, const char *, mjson_print_fn_t, void *); 133 #endif 134 135 #if MJSON_ENABLE_MERGE 136 int mjson_merge(const char *, int, const char *, int, mjson_print_fn_t, void *); 137 #endif 138 139 #endif // MJSON_ENABLE_PRINT 140 141 #if MJSON_ENABLE_RPC 142 143 void jsonrpc_init(mjson_print_fn_t, void *userdata); 144 int mjson_globmatch(const char *s1, int n1, const char *s2, int n2); 145 146 struct jsonrpc_request { 147 struct jsonrpc_ctx *ctx; 148 const char *frame; // Points to the whole frame 149 int frame_len; // Frame length 150 const char *params; // Points to the "params" in the request frame 151 int params_len; // Length of the "params" 152 const char *id; // Points to the "id" in the request frame 153 int id_len; // Length of the "id" 154 const char *method; // Points to the "method" in the request frame 155 int method_len; // Length of the "method" 156 mjson_print_fn_t fn; // Printer function 157 void *fndata; // Printer function data 158 void *userdata; // Callback's user data as specified at export time 159 }; 160 161 struct jsonrpc_method { 162 const char *method; 163 int method_sz; 164 void (*cb)(struct jsonrpc_request *); 165 struct jsonrpc_method *next; 166 }; 167 168 // Main RPC context, stores current request information and a list of 169 // exported RPC methods. 170 struct jsonrpc_ctx { 171 struct jsonrpc_method *methods; 172 mjson_print_fn_t response_cb; 173 void *response_cb_data; 174 }; 175 176 // Registers function fn under the given name within the given RPC context 177 #define jsonrpc_ctx_export(ctx, name, fn) \ 178 do { \ 179 static struct jsonrpc_method m = {(name), sizeof(name) - 1, (fn), 0}; \ 180 m.next = (ctx)->methods; \ 181 (ctx)->methods = &m; \ 182 } while (0) 183 184 void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t, void *); 185 void jsonrpc_return_error(struct jsonrpc_request *r, int code, 186 const char *message, const char *data_fmt, ...); 187 void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt, 188 ...); 189 void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz, 190 mjson_print_fn_t fn, void *fndata, void *userdata); 191 192 extern struct jsonrpc_ctx jsonrpc_default_context; 193 194 #define jsonrpc_export(name, fn) \ 195 jsonrpc_ctx_export(&jsonrpc_default_context, (name), (fn)) 196 197 #define jsonrpc_process(buf, len, fn, fnd, ud) \ 198 jsonrpc_ctx_process(&jsonrpc_default_context, (buf), (len), (fn), (fnd), (ud)) 199 200 #define JSONRPC_ERROR_INVALID -32700 /* Invalid JSON was received */ 201 #define JSONRPC_ERROR_NOT_FOUND -32601 /* The method does not exist */ 202 #define JSONRPC_ERROR_BAD_PARAMS -32602 /* Invalid params passed */ 203 #define JSONRPC_ERROR_INTERNAL -32603 /* Internal JSON-RPC error */ 204 205 #endif // MJSON_ENABLE_RPC 206 #ifdef __cplusplus 207 } 208 #endif 209 #endif // MJSON_H 210