winlin

add nxjson

@@ -22,3 +22,509 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -22,3 +22,509 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */ 22 */
23 23
24 #include <srs_app_json.hpp> 24 #include <srs_app_json.hpp>
  25 +
  26 +#include <srs_kernel_log.hpp>
  27 +
  28 +// whether use nxjson
  29 +// @see: https://bitbucket.org/yarosla/nxjson
  30 +#undef SRS_JSON_USE_NXJSON
  31 +#define SRS_JSON_USE_NXJSON
  32 +
  33 +#ifdef SRS_JSON_USE_NXJSON
  34 +////////////////////////////////////////////////////////////////////////////////////////////////
  35 +////////////////////////////////////////////////////////////////////////////////////////////////
  36 +////////////////////////////////////////////////////////////////////////////////////////////////
  37 +////////////////////////////////////////////////////////////////////////////////////////////////
  38 +////////////////////////////////////////////////////////////////////////////////////////////////
  39 +////////////////////////////////////////////////////////////////////////////////////////////////
  40 +////////////////////////////////////////////////////////////////////////////////////////////////
  41 +////////////////////////////////////////////////////////////////////////////////////////////////
  42 +////////////////////////////////////////////////////////////////////////////////////////////////
  43 +////////////////////////////////////////////////////////////////////////////////////////////////
  44 +////////////////////////////////////////////////////////////////////////////////////////////////
  45 +////////////////////////////////////////////////////////////////////////////////////////////////
  46 +////////////////////////////////////////////////////////////////////////////////////////////////
  47 +////////////////////////////////////////////////////////////////////////////////////////////////
  48 +////////////////////////////////////////////////////////////////////////////////////////////////
  49 +////////////////////////////////////////////////////////////////////////////////////////////////
  50 +////////////////////////////////////////////////////////////////////////////////////////////////
  51 +////////////////////////////////////////////////////////////////////////////////////////////////
  52 +////////////////////////////////////////////////////////////////////////////////////////////////
  53 +////////////////////////////////////////////////////////////////////////////////////////////////
  54 +/*
  55 + * Copyright (c) 2013 Yaroslav Stavnichiy <yarosla@gmail.com>
  56 + *
  57 + * This file is part of NXJSON.
  58 + *
  59 + * NXJSON is free software: you can redistribute it and/or modify
  60 + * it under the terms of the GNU Lesser General Public License
  61 + * as published by the Free Software Foundation, either version 3
  62 + * of the License, or (at your option) any later version.
  63 + *
  64 + * NXJSON is distributed in the hope that it will be useful,
  65 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  66 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  67 + * GNU Lesser General Public License for more details.
  68 + *
  69 + * You should have received a copy of the GNU Lesser General Public
  70 + * License along with NXJSON. If not, see <http://www.gnu.org/licenses/>.
  71 + */
  72 +
  73 +#ifndef NXJSON_H
  74 +#define NXJSON_H
  75 +
  76 +#ifdef __cplusplus
  77 +extern "C" {
  78 +#endif
  79 +
  80 +
  81 +typedef enum nx_json_type {
  82 + NX_JSON_NULL, // this is null value
  83 + NX_JSON_OBJECT, // this is an object; properties can be found in child nodes
  84 + NX_JSON_ARRAY, // this is an array; items can be found in child nodes
  85 + NX_JSON_STRING, // this is a string; value can be found in text_value field
  86 + NX_JSON_INTEGER, // this is an integer; value can be found in int_value field
  87 + NX_JSON_DOUBLE, // this is a double; value can be found in dbl_value field
  88 + NX_JSON_BOOL // this is a boolean; value can be found in int_value field
  89 +} nx_json_type;
  90 +
  91 +typedef struct nx_json {
  92 + nx_json_type type; // type of json node, see above
  93 + const char* key; // key of the property; for object's children only
  94 + const char* text_value; // text value of STRING node
  95 + long int_value; // the value of INTEGER or BOOL node
  96 + double dbl_value; // the value of DOUBLE node
  97 + int length; // number of children of OBJECT or ARRAY
  98 + struct nx_json* child; // points to first child
  99 + struct nx_json* next; // points to next child
  100 + struct nx_json* last_child;
  101 +} nx_json;
  102 +
  103 +typedef int (*nx_json_unicode_encoder)(unsigned int codepoint, char* p, char** endp);
  104 +
  105 +extern nx_json_unicode_encoder nx_json_unicode_to_utf8;
  106 +
  107 +const nx_json* nx_json_parse(char* text, nx_json_unicode_encoder encoder);
  108 +const nx_json* nx_json_parse_utf8(char* text);
  109 +void nx_json_free(const nx_json* js);
  110 +const nx_json* nx_json_get(const nx_json* json, const char* key); // get object's property by key
  111 +const nx_json* nx_json_item(const nx_json* json, int idx); // get array element by index
  112 +
  113 +
  114 +#ifdef __cplusplus
  115 +}
  116 +#endif
  117 +
  118 +#endif /* NXJSON_H */
  119 +
  120 +/*
  121 + * Copyright (c) 2013 Yaroslav Stavnichiy <yarosla@gmail.com>
  122 + *
  123 + * This file is part of NXJSON.
  124 + *
  125 + * NXJSON is free software: you can redistribute it and/or modify
  126 + * it under the terms of the GNU Lesser General Public License
  127 + * as published by the Free Software Foundation, either version 3
  128 + * of the License, or (at your option) any later version.
  129 + *
  130 + * NXJSON is distributed in the hope that it will be useful,
  131 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  132 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  133 + * GNU Lesser General Public License for more details.
  134 + *
  135 + * You should have received a copy of the GNU Lesser General Public
  136 + * License along with NXJSON. If not, see <http://www.gnu.org/licenses/>.
  137 + */
  138 +
  139 +// this file can be #included in your code
  140 +#ifndef NXJSON_C
  141 +#define NXJSON_C
  142 +
  143 +#ifdef __cplusplus
  144 +extern "C" {
  145 +#endif
  146 +
  147 +
  148 +#include <stdlib.h>
  149 +#include <stdio.h>
  150 +#include <string.h>
  151 +#include <malloc.h>
  152 +#include <assert.h>
  153 +
  154 +//#include "nxjson.h"
  155 +
  156 +// redefine NX_JSON_CALLOC & NX_JSON_FREE to use custom allocator
  157 +#ifndef NX_JSON_CALLOC
  158 +#define NX_JSON_CALLOC() calloc(1, sizeof(nx_json))
  159 +#define NX_JSON_FREE(json) free((void*)(json))
  160 +#endif
  161 +
  162 +// redefine NX_JSON_REPORT_ERROR to use custom error reporting
  163 +#ifndef NX_JSON_REPORT_ERROR
  164 +#define NX_JSON_REPORT_ERROR(msg, p) srs_error("NXJSON PARSE ERROR (%d): " msg " at %s\n", __LINE__, p)
  165 +#endif
  166 +
  167 +#define IS_WHITESPACE(c) ((unsigned char)(c)<=(unsigned char)' ')
  168 +
  169 +static const nx_json dummy={ NX_JSON_NULL };
  170 +
  171 +static nx_json* create_json(nx_json_type type, const char* key, nx_json* parent) {
  172 + nx_json* js=(nx_json*)NX_JSON_CALLOC();
  173 + assert(js);
  174 + js->type=type;
  175 + js->key=key;
  176 + if (!parent->last_child) {
  177 + parent->child=parent->last_child=js;
  178 + }
  179 + else {
  180 + parent->last_child->next=js;
  181 + parent->last_child=js;
  182 + }
  183 + parent->length++;
  184 + return js;
  185 +}
  186 +
  187 +void nx_json_free(const nx_json* js) {
  188 + nx_json* p=js->child;
  189 + nx_json* p1;
  190 + while (p) {
  191 + p1=p->next;
  192 + nx_json_free(p);
  193 + p=p1;
  194 + }
  195 + NX_JSON_FREE(js);
  196 +}
  197 +
  198 +static int unicode_to_utf8(unsigned int codepoint, char* p, char** endp) {
  199 + // code from http://stackoverflow.com/a/4609989/697313
  200 + if (codepoint<0x80) *p++=codepoint;
  201 + else if (codepoint<0x800) *p++=192+codepoint/64, *p++=128+codepoint%64;
  202 + else if (codepoint-0xd800u<0x800) return 0; // surrogate must have been treated earlier
  203 + else if (codepoint<0x10000) *p++=224+codepoint/4096, *p++=128+codepoint/64%64, *p++=128+codepoint%64;
  204 + else if (codepoint<0x110000) *p++=240+codepoint/262144, *p++=128+codepoint/4096%64, *p++=128+codepoint/64%64, *p++=128+codepoint%64;
  205 + else return 0; // error
  206 + *endp=p;
  207 + return 1;
  208 +}
  209 +
  210 +nx_json_unicode_encoder nx_json_unicode_to_utf8=unicode_to_utf8;
  211 +
  212 +static inline int hex_val(char c) {
  213 + if (c>='0' && c<='9') return c-'0';
  214 + if (c>='a' && c<='f') return c-'a'+10;
  215 + if (c>='A' && c<='F') return c-'A'+10;
  216 + return -1;
  217 +}
  218 +
  219 +static char* unescape_string(char* s, char** end, nx_json_unicode_encoder encoder) {
  220 + char* p=s;
  221 + char* d=s;
  222 + char c;
  223 + while ((c=*p++)) {
  224 + if (c=='"') {
  225 + *d='\0';
  226 + *end=p;
  227 + return s;
  228 + }
  229 + else if (c=='\\') {
  230 + switch (*p) {
  231 + case '\\':
  232 + case '/':
  233 + case '"':
  234 + *d++=*p++;
  235 + break;
  236 + case 'b':
  237 + *d++='\b'; p++;
  238 + break;
  239 + case 'f':
  240 + *d++='\f'; p++;
  241 + break;
  242 + case 'n':
  243 + *d++='\n'; p++;
  244 + break;
  245 + case 'r':
  246 + *d++='\r'; p++;
  247 + break;
  248 + case 't':
  249 + *d++='\t'; p++;
  250 + break;
  251 + case 'u': { // unicode
  252 + if (!encoder) {
  253 + // leave untouched
  254 + *d++=c;
  255 + break;
  256 + }
  257 + char* ps=p-1;
  258 + int h1, h2, h3, h4;
  259 + if ((h1=hex_val(p[1]))<0 || (h2=hex_val(p[2]))<0 || (h3=hex_val(p[3]))<0 || (h4=hex_val(p[4]))<0) {
  260 + NX_JSON_REPORT_ERROR("invalid unicode escape", p-1);
  261 + return 0;
  262 + }
  263 + unsigned int codepoint=h1<<12|h2<<8|h3<<4|h4;
  264 + if ((codepoint & 0xfc00)==0xd800) { // high surrogate; need one more unicode to succeed
  265 + p+=6;
  266 + if (p[-1]!='\\' || *p!='u' || (h1=hex_val(p[1]))<0 || (h2=hex_val(p[2]))<0 || (h3=hex_val(p[3]))<0 || (h4=hex_val(p[4]))<0) {
  267 + NX_JSON_REPORT_ERROR("invalid unicode surrogate", ps);
  268 + return 0;
  269 + }
  270 + unsigned int codepoint2=h1<<12|h2<<8|h3<<4|h4;
  271 + if ((codepoint2 & 0xfc00)!=0xdc00) {
  272 + NX_JSON_REPORT_ERROR("invalid unicode surrogate", ps);
  273 + return 0;
  274 + }
  275 + codepoint=0x10000+((codepoint-0xd800)<<10)+(codepoint2-0xdc00);
  276 + }
  277 + if (!encoder(codepoint, d, &d)) {
  278 + NX_JSON_REPORT_ERROR("invalid codepoint", ps);
  279 + return 0;
  280 + }
  281 + p+=5;
  282 + break;
  283 + }
  284 + default: {
  285 + // leave untouched
  286 + *d++=c;
  287 + break;
  288 + }
  289 + }
  290 + }
  291 + else {
  292 + *d++=c;
  293 + }
  294 + }
  295 + NX_JSON_REPORT_ERROR("no closing quote for string", s);
  296 + return 0;
  297 +}
  298 +
  299 +static char* skip_block_comment(char* p) {
  300 + // assume p[-2]=='/' && p[-1]=='*'
  301 + char* ps=p-2;
  302 + if (!*p) {
  303 + NX_JSON_REPORT_ERROR("endless comment", ps);
  304 + return 0;
  305 + }
  306 + REPEAT:
  307 + p=strchr(p+1, '/');
  308 + if (!p) {
  309 + NX_JSON_REPORT_ERROR("endless comment", ps);
  310 + return 0;
  311 + }
  312 + if (p[-1]!='*') goto REPEAT;
  313 + return p+1;
  314 +}
  315 +
  316 +static char* parse_key(const char** key, char* p, nx_json_unicode_encoder encoder) {
  317 + // on '}' return with *p=='}'
  318 + char c;
  319 + while ((c=*p++)) {
  320 + if (c=='"') {
  321 + *key=unescape_string(p, &p, encoder);
  322 + if (!*key) return 0; // propagate error
  323 + while (*p && IS_WHITESPACE(*p)) p++;
  324 + if (*p==':') return p+1;
  325 + NX_JSON_REPORT_ERROR("unexpected chars", p);
  326 + return 0;
  327 + }
  328 + else if (IS_WHITESPACE(c) || c==',') {
  329 + // continue
  330 + }
  331 + else if (c=='}') {
  332 + return p-1;
  333 + }
  334 + else if (c=='/') {
  335 + if (*p=='/') { // line comment
  336 + char* ps=p-1;
  337 + p=strchr(p+1, '\n');
  338 + if (!p) {
  339 + NX_JSON_REPORT_ERROR("endless comment", ps);
  340 + return 0; // error
  341 + }
  342 + p++;
  343 + }
  344 + else if (*p=='*') { // block comment
  345 + p=skip_block_comment(p+1);
  346 + if (!p) return 0;
  347 + }
  348 + else {
  349 + NX_JSON_REPORT_ERROR("unexpected chars", p-1);
  350 + return 0; // error
  351 + }
  352 + }
  353 + else {
  354 + NX_JSON_REPORT_ERROR("unexpected chars", p-1);
  355 + return 0; // error
  356 + }
  357 + }
  358 + NX_JSON_REPORT_ERROR("unexpected chars", p-1);
  359 + return 0; // error
  360 +}
  361 +
  362 +static char* parse_value(nx_json* parent, const char* key, char* p, nx_json_unicode_encoder encoder) {
  363 + nx_json* js;
  364 + while (1) {
  365 + switch (*p) {
  366 + case '\0':
  367 + NX_JSON_REPORT_ERROR("unexpected end of text", p);
  368 + return 0; // error
  369 + case ' ': case '\t': case '\n': case '\r':
  370 + case ',':
  371 + // skip
  372 + p++;
  373 + break;
  374 + case '{':
  375 + js=create_json(NX_JSON_OBJECT, key, parent);
  376 + p++;
  377 + while (1) {
  378 + const char* new_key;
  379 + p=parse_key(&new_key, p, encoder);
  380 + if (!p) return 0; // error
  381 + if (*p=='}') return p+1; // end of object
  382 + p=parse_value(js, new_key, p, encoder);
  383 + if (!p) return 0; // error
  384 + }
  385 + case '[':
  386 + js=create_json(NX_JSON_ARRAY, key, parent);
  387 + p++;
  388 + while (1) {
  389 + p=parse_value(js, 0, p, encoder);
  390 + if (!p) return 0; // error
  391 + if (*p==']') return p+1; // end of array
  392 + }
  393 + case ']':
  394 + return p;
  395 + case '"':
  396 + p++;
  397 + js=create_json(NX_JSON_STRING, key, parent);
  398 + js->text_value=unescape_string(p, &p, encoder);
  399 + if (!js->text_value) return 0; // propagate error
  400 + return p;
  401 + case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
  402 + {
  403 + js=create_json(NX_JSON_INTEGER, key, parent);
  404 + char* pe;
  405 + js->int_value=strtol(p, &pe, 0);
  406 + if (pe==p) {
  407 + NX_JSON_REPORT_ERROR("invalid number", p);
  408 + return 0; // error
  409 + }
  410 + if (*pe=='.' || *pe=='e' || *pe=='E') { // double value
  411 + js->type=NX_JSON_DOUBLE;
  412 + js->dbl_value=strtod(p, &pe);
  413 + if (pe==p) {
  414 + NX_JSON_REPORT_ERROR("invalid number", p);
  415 + return 0; // error
  416 + }
  417 + }
  418 + else {
  419 + js->dbl_value=js->int_value;
  420 + }
  421 + return pe;
  422 + }
  423 + case 't':
  424 + if (!strncmp(p, "true", 4)) {
  425 + js=create_json(NX_JSON_BOOL, key, parent);
  426 + js->int_value=1;
  427 + return p+4;
  428 + }
  429 + NX_JSON_REPORT_ERROR("unexpected chars", p);
  430 + return 0; // error
  431 + case 'f':
  432 + if (!strncmp(p, "false", 5)) {
  433 + js=create_json(NX_JSON_BOOL, key, parent);
  434 + js->int_value=0;
  435 + return p+5;
  436 + }
  437 + NX_JSON_REPORT_ERROR("unexpected chars", p);
  438 + return 0; // error
  439 + case 'n':
  440 + if (!strncmp(p, "null", 4)) {
  441 + create_json(NX_JSON_NULL, key, parent);
  442 + return p+4;
  443 + }
  444 + NX_JSON_REPORT_ERROR("unexpected chars", p);
  445 + return 0; // error
  446 + case '/': // comment
  447 + if (p[1]=='/') { // line comment
  448 + char* ps=p;
  449 + p=strchr(p+2, '\n');
  450 + if (!p) {
  451 + NX_JSON_REPORT_ERROR("endless comment", ps);
  452 + return 0; // error
  453 + }
  454 + p++;
  455 + }
  456 + else if (p[1]=='*') { // block comment
  457 + p=skip_block_comment(p+2);
  458 + if (!p) return 0;
  459 + }
  460 + else {
  461 + NX_JSON_REPORT_ERROR("unexpected chars", p);
  462 + return 0; // error
  463 + }
  464 + break;
  465 + default:
  466 + NX_JSON_REPORT_ERROR("unexpected chars", p);
  467 + return 0; // error
  468 + }
  469 + }
  470 +}
  471 +
  472 +const nx_json* nx_json_parse_utf8(char* text) {
  473 + return nx_json_parse(text, unicode_to_utf8);
  474 +}
  475 +
  476 +const nx_json* nx_json_parse(char* text, nx_json_unicode_encoder encoder) {
  477 + nx_json js;
  478 + if (!parse_value(&js, 0, text, encoder)) {
  479 + if (js.child) nx_json_free(js.child);
  480 + return 0;
  481 + }
  482 + return js.child;
  483 +}
  484 +
  485 +const nx_json* nx_json_get(const nx_json* json, const char* key) {
  486 + if (!json || !key) return &dummy; // never return null
  487 + nx_json* js;
  488 + for (js=json->child; js; js=js->next) {
  489 + if (js->key && !strcmp(js->key, key)) return js;
  490 + }
  491 + return &dummy; // never return null
  492 +}
  493 +
  494 +const nx_json* nx_json_item(const nx_json* json, int idx) {
  495 + if (!json) return &dummy; // never return null
  496 + nx_json* js;
  497 + for (js=json->child; js; js=js->next) {
  498 + if (!idx--) return js;
  499 + }
  500 + return &dummy; // never return null
  501 +}
  502 +
  503 +
  504 +#ifdef __cplusplus
  505 +}
  506 +#endif
  507 +
  508 +#endif /* NXJSON_C */
  509 +////////////////////////////////////////////////////////////////////////////////////////////////
  510 +////////////////////////////////////////////////////////////////////////////////////////////////
  511 +////////////////////////////////////////////////////////////////////////////////////////////////
  512 +////////////////////////////////////////////////////////////////////////////////////////////////
  513 +////////////////////////////////////////////////////////////////////////////////////////////////
  514 +////////////////////////////////////////////////////////////////////////////////////////////////
  515 +////////////////////////////////////////////////////////////////////////////////////////////////
  516 +////////////////////////////////////////////////////////////////////////////////////////////////
  517 +////////////////////////////////////////////////////////////////////////////////////////////////
  518 +////////////////////////////////////////////////////////////////////////////////////////////////
  519 +////////////////////////////////////////////////////////////////////////////////////////////////
  520 +////////////////////////////////////////////////////////////////////////////////////////////////
  521 +////////////////////////////////////////////////////////////////////////////////////////////////
  522 +////////////////////////////////////////////////////////////////////////////////////////////////
  523 +////////////////////////////////////////////////////////////////////////////////////////////////
  524 +////////////////////////////////////////////////////////////////////////////////////////////////
  525 +////////////////////////////////////////////////////////////////////////////////////////////////
  526 +////////////////////////////////////////////////////////////////////////////////////////////////
  527 +////////////////////////////////////////////////////////////////////////////////////////////////
  528 +////////////////////////////////////////////////////////////////////////////////////////////////
  529 +#endif
  530 +
@@ -101,5 +101,7 @@ that is: @@ -101,5 +101,7 @@ that is:
101 //////////////////////////////////////////////////////////////////////// 101 ////////////////////////////////////////////////////////////////////////
102 //////////////////////////////////////////////////////////////////////// 102 ////////////////////////////////////////////////////////////////////////
103 //////////////////////////////////////////////////////////////////////// 103 ////////////////////////////////////////////////////////////////////////
  104 +// @see: https://bitbucket.org/yarosla/nxjson
  105 +// @see: https://github.com/udp/json-parser
104 106
105 #endif 107 #endif