Diff for /libelwix/src/json.c between versions 1.1.2.1 and 1.1.2.3

version 1.1.2.1, 2017/11/24 09:53:53 version 1.1.2.3, 2017/11/27 19:37:22
Line 46  SUCH DAMAGE. Line 46  SUCH DAMAGE.
 #include "global.h"  #include "global.h"
   
   
   /* JSON error strings */
   const char *jerrstr[] = {
           "No error",
           "Not enough tokens were provided",
           "Invalid character",
           "JSON string isn't full",
           "Invalid parameter", 
           NULL
   };
   
   
   /*
    * json_init() - Initialize JSON handler
    *
    * @json = JSON handler, if there is NULL then dynamically will be allocated
    * @jstrict = JSON strict mode, when we select strict mode every unquoted value is error
    * return: =NULL error or !=NULL ready for use JSON handler and should be free with json_free()
    */
   json_t *
   json_init(json_t * __restrict json, int jstrict)
   {
           json_t *j = json;
   
           if (!j) {
                   j = e_malloc(sizeof(json_t));
                   if (!j) {
                           LOGERR;
                           return NULL;
                   }
           }
   
           memset(j, 0, sizeof(json_t));
           j->h_parent = -1;
           j->h_strict = jstrict;
   
           /* handler is dynamically allocated! */
           if (!json)
                   j->h_alloc = j;
   
           return j;
   }
   
   /*
    * json_free() - Free JSON handler
    *
    * @json = JSON handler
    * return: none
    */
   void
   json_free(json_t * __restrict json)
   {
           if (json) {
                   if (json->h_alloc)
                           e_free(json);
                   else
                           memset(json, 0, sizeof(json_t));
           }
   }
   
   static jtok_t *
   json_gettoken(json_t * __restrict json, jtok_t * __restrict jtoks, u_int toksnum)
   {
           jtok_t *tok;
   
           assert(json || !(!jtoks && toksnum));
   
           if (json->h_next >= toksnum) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   return NULL;
           } else
                   tok = &jtoks[json->h_next++];
           tok->tok_start = tok->tok_end = tok->tok_parent = -1;
           tok->tok_size = 0;
   
           return tok;
   }
   
   inline void
   json_filltoken(jtok_t * __restrict tok, jtype_t type, long start, long end, long parent)
   {
           assert(tok);
   
           tok->tok_type = type;
           tok->tok_start = start;
           tok->tok_end = end;
           tok->tok_parent = parent;
           tok->tok_size = 0;
   }
   
   static int
   json_parse_string(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
   {
           jtok_t  *tok;
           u_long pos;
           char ch;
           register int i;
   
           assert(json || jstr || !(!jtoks && toksnum));
   
           for (pos = json->h_pos++; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
                   ch = jstr[json->h_pos];
   
                   if (ch == '\"') {
                           if (!jtoks)
                                   return 0;
                           if (!(tok = json_gettoken(json, jtoks, toksnum))) {
                                   json->h_pos = pos;
                                   return -1;
                           } else
                                   json_filltoken(tok, J_STRING, pos + 1, json->h_pos, json->h_parent);
                           return 0;
                   }
   
                   if (ch == '\\' && json->h_pos + 1 < jlen) {
                           switch (jstr[++json->h_pos]) {
                                   case '\"':
                                   case '/':
                                   case '\\':
                                   case 'b':
                                   case 'f':
                                   case 'r':
                                   case 'n':
                                   case 't':
                                           /* Allowed escaped symbols */
                                           break;
                                   case 'u':
                                           /* Allows escaped symbol \uXXXX */
                                           json->h_pos++;
                                           for (i = 0; i < 4 && json->h_pos < jlen && jstr[json->h_pos]; i++, json->h_pos++) {
                                                   /* If it isn't a hex character we have an error */
                                                   if (!((jstr[json->h_pos] >= 48 && jstr[json->h_pos] <= 57) || /* 0-9 */
                                                                   (jstr[json->h_pos] >= 65 && jstr[json->h_pos] <= 70) || /* A-F */
                                                                   (jstr[json->h_pos] >= 97 && jstr[json->h_pos] <= 102))) { /* a-f */
                                                           json->h_pos = pos;
                                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                                           return -1;
                                                   }
                                           }
                                           json->h_pos--;
                                           break;
                                   default:
                                           /* Unexpected symbol */
                                           json->h_pos = pos;
                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                           return -1;
                           }
                   }
           }
   
           json->h_pos = pos;
           elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
           return -1;
   }
   
   static int
   json_parse_value(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
   {
           jtok_t  *tok;
           u_long pos;
   
           assert(json || jstr || !(!jtoks && toksnum));
   
           for (pos = json->h_pos; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
                   switch (jstr[json->h_pos]) {
                           case ':':
                                   if (json->h_strict)
                                           goto found;
                                   break;
                           case '\t':
                           case '\r':
                           case '\n':
                           case ' ':
                           case ',':
                           case ']':
                           case '}':
                                   goto found;
                   }
                   if (jstr[json->h_pos] < 32 || jstr[json->h_pos] > 127) {
                           json->h_pos = pos;
                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                           return -1;
                   }
           }
   
           if (json->h_strict) {
                   json->h_pos = pos;
                   elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
                   return -1;
           }
   found:
           if (jtoks) {
                   if (!(tok = json_gettoken(json, jtoks, toksnum))) {
                           json->h_pos = pos;
                           return -1;
                   } else
                           json_filltoken(tok, J_VALUE, pos, json->h_pos, json->h_parent);
           }
   
           json->h_pos--;
           return 0;
   }
   
   /*
    * json_parse() - Parse JSON string
    *
    * @json = JSON handler
    * @jstr = JSON string
    * @jlen = JSON string length
    * @jtoks = Token array
    * @toksnum = Token array size, return number of allocated tokens in array
    * return: -1 error or number of found tokens 
    */
   u_int
   json_parse(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
   {
           register int i;
           register u_int cx;
           jtype_t type;
           jtok_t *tok;
           char ch;
   
           if (!json || !jstr || (!jtoks && toksnum)) {
                   elwix_SetErr(J_ERR_PARAM, "%s", jerrstr[J_ERR_PARAM]);
                   return (u_int) -1;
           }
   
           for (cx = json->h_next; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
                   switch ((ch = jstr[json->h_pos])) {
                           case '{':
                           case '[':
                                   cx++;   /* start new token */
                                   if (!jtoks)
                                           break;
   
                                   tok = json_gettoken(json, jtoks, toksnum);
                                   if (!tok)
                                           return (u_int) -1;
                                   if (json->h_parent != -1) {
                                           jtoks[json->h_parent].tok_size++;
                                           tok->tok_parent = json->h_parent;
                                   }
                                   tok->tok_type = (ch == '{' ? J_OBJECT : J_ARRAY);
                                   tok->tok_start = json->h_pos;
                                   json->h_parent = json->h_next - 1;
                                   break;
                           case '}':
                           case ']':
                                   if (!jtoks)
                                           break;
   
                                   if (json->h_next < 1) {
                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                           return (u_int) -1;
                                   }
   
                                   type = (ch == '}' ? J_OBJECT : J_ARRAY);
                                   tok = &jtoks[json->h_next - 1];
                                   while (42) {
                                           if (tok->tok_start != -1 && tok->tok_end == -1) {
                                                   if (tok->tok_type != type) {
                                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                                           return (u_int) -1;
                                                   }
                                                   tok->tok_end = json->h_pos + 1;
                                                   json->h_parent = tok->tok_parent;
                                                   break;
                                           }
                                           if (tok->tok_parent == -1) {
                                                   if (tok->tok_type != type || json->h_parent == -1) {
                                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                                           return (u_int) -1;
                                                   }
                                                   break;
                                           }
                                           tok = &jtoks[tok->tok_parent];
                                   }
                                   break;
                           case '\"':
                                   if (json_parse_string(json, jstr, jlen, jtoks, toksnum) == -1) {
                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                           return (u_int) -1;
                                   }
                                   cx++;
                                   if (jtoks && json->h_parent != -1)
                                           jtoks[json->h_parent].tok_size++;
                                   break;
                           case '\t':
                           case '\r':
                           case '\n':
                           case ' ':
                                   /* whitespace, skip */
                                   break;
                           case ':':
                                   json->h_parent = json->h_next - 1;
                                   break;
                           case ',':
                                   if (jtoks && json->h_parent != -1 && 
                                                   jtoks[json->h_parent].tok_type != J_OBJECT && 
                                                   jtoks[json->h_parent].tok_type != J_ARRAY)
                                           json->h_parent = jtoks[json->h_parent].tok_parent;
                                   break;
                           case '-':
                           case '0':
                           case '1':
                           case '2':
                           case '3':
                           case '4':
                           case '5':
                           case '6':
                           case '7':
                           case '8':
                           case '9':
                           case 't':
                           case 'f':
                           case 'n':
                                   if (json->h_strict) {
                                           if (jtoks && json->h_parent != -1) {
                                                   /* they must not be keys of the object */
                                                   if (jtoks[json->h_parent].tok_type == J_OBJECT || 
                                                                   (jtoks[json->h_parent].tok_type == J_STRING && 
                                                                    jtoks[json->h_parent].tok_size)) {
                                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                                           return (u_int) -1;
                                                   }
                                           }
   
                                           if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
                                                   return (u_int) -1;
                                           cx++;
                                           if (jtoks && json->h_parent != -1)
                                                   jtoks[json->h_parent].tok_size++;
                                           break;
                                   }
                           default:
                                   if (json->h_strict) {
                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                           return (u_int) -1;
                                   }
   
                                   if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
                                           return (u_int) -1;
                                   cx++;
                                   if (jtoks && json->h_parent != -1)
                                           jtoks[json->h_parent].tok_size++;
                                   break;
                   }
           }
   
           if (jtoks) {
                   for (i = json->h_next - 1; i >= 0; i--) {
                           /* unmatched opened object or array */
                           if (jtoks[i].tok_start != -1 && jtoks[i].tok_end == -1) {
                                   elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
                                   return (u_int) -1;
                           }
                   }
           }
   
           return cx;
   }

Removed from v.1.1.2.1  
changed lines
  Added in v.1.1.2.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>