Пример #1
0
struct json_val *json_parse_value(struct read_state *state)
{
    struct json_val *value;
    char ch;
    
    if (read_state_left(state) < 1) {
        json_error_print(state, "Unexpected end of file parsing generic value\n");
        return 0;
    }
    ch = *state->read;
    
    switch (ch) {
        case 't':
            value = json_parse_true(state);
            break;
        case 'f':
            value = json_parse_false(state);
            break;
        case 'n':
            value = json_parse_null(state);
            break;
        case '\"':
            value = json_parse_string(state);
            break;
        case '{':
            value = json_parse_object(state);
            break;
        case '[':
            value = json_parse_array(state);
            break;
        default:
            value = json_parse_number(state);
    }
    return value;
}
Пример #2
0
/******************************************************************************
 *                                                                            *
 * Function: json_parse_value                                                 *
 *                                                                            *
 * Purpose: Parses JSON object value                                          *
 *                                                                            *
 * Parameters: start - [IN] the JSON data                                     *
 *             error - [OUT] the parsing error message (can be NULL)          *
 *                                                                            *
 * Return value: The number of characters parsed. On error 0 is returned and  *
 *               error parameter (if not NULL) contains allocated error       *
 *               message.                                                     *
 *                                                                            *
 * Author: Andris Zeila                                                       *
 *                                                                            *
 ******************************************************************************/
int	json_parse_value(const char *start, char **error)
{
	const char	*ptr = start;
	int		len;

	SKIP_WHITESPACE(ptr);

	switch (*ptr)
	{
		case '\0':
			return json_error("unexpected end of object value", NULL, error);
		case '"':
			if (0 == (len = json_parse_string(ptr, error)))
				return 0;
			break;
		case '{':
			if (0 == (len = json_parse_object(ptr, error)))
				return 0;
			break;
		case '[':
			if (0 == (len = json_parse_array(ptr, error)))
				return 0;
			break;
		case 't':
			if (0 == (len = json_parse_literal(ptr, "true", error)))
				return 0;
			break;
		case 'f':
			if (0 == (len = json_parse_literal(ptr, "false", error)))
				return 0;
			break;
		case 'n':
			if (0 == (len = json_parse_literal(ptr, "null", error)))
				return 0;
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case '-':
			if (0 == (len = json_parse_number(ptr, error)))
				return 0;
			break;
		default:
			return json_error("invalid JSON object value starting character", ptr, error);
	}

	return ptr - start + len;
}
Пример #3
0
static struct json_node *json_parse_value(json_parser_t p)
{
    int c = look_ch(p);
    if (c == '\"')
        return json_parse_string(p);
    else if (strchr("0123456789-", c))
        return json_parse_number(p);
    else if (c == '{')
        return json_parse_object(p);
    else if (c == '[')
        return json_parse_array(p);
    else if (c == '%')
    {
        struct json_subst_info *sb;
        int idx = 0;
        p->cp++;
        c = *p->cp;
        while (c >= '0' && c <= '9')
        {
            idx = idx*10 + (c - '0');
            p->cp++;
            c = *p->cp;
        }
        for (sb = p->subst; sb; sb = sb->next)
            if (sb->idx == idx)
                return sb->node;
    }
    else if (c == 0)
    {
        return 0;
    }
    else
    {
        char tok[8];
        int i = 0;
        while (c >= 'a' && c <= 'z' && i < 7)
        {
            tok[i++] = c;
            p->cp++;
            c = *p->cp;
        }
        tok[i] = 0;
        if (!strcmp(tok, "true"))
            return json_new_node(p, json_node_true);
        else if (!strcmp(tok, "false"))
            return json_new_node(p, json_node_false);
        else if (!strcmp(tok, "null"))
            return json_new_node(p, json_node_null);
    }
    p->err_msg = "bad token";
    return 0;
}
Пример #4
0
int json_parse(json_parser_t *parser, json_value_t *super, json_value_t *value) {
	int i;
	int c;

	for (i = parser->off; i < parser->len; i++) {
		c = parser->buf[i];
		parser->off = i;

		switch (c) {
		CASE_BLANK:
			break;
		case '{':
			value->off  = i;
			value->len  = parser->len - i;
			value->type = JSON_OBJECT;
			return JSON_PARSER_OK;
		case '[':
			value->off  = i;
			value->len  = parser->len - i;
			value->type = JSON_ARRAY;
			return JSON_PARSER_OK;
		case '\"':
			return json_parse_string(parser, super, value);
		CASE_NUMBER:
			return json_parse_number(parser, super, value);
		case 't':
			return json_parse_true(parser, super, value);
		case 'f':
			return json_parse_false(parser, super, value);
		case 'n':
			return json_parse_null(parser, super, value);
		default: 
			return JSON_PARSER_ERR;
		}
	}
	return JSON_PARSER_ERR;
}
Пример #5
0
int json_parse_value( json_task_t *task, json_object_t *parent ) {
    char ch;
    while(( ch = *(task->str + task->count) )) {
        task->count ++;

        if( ch == '"' ) {
            parent->value_type = JSON_STRING;
            return json_parse_string( task );
        } else if( ch == '-' || ( ch >= '0' && ch <= '9' ) ) {
            task->count --;
            parent->value_type = JSON_LONGLONG;
            return json_parse_number( task, parent );
        } else if( ch == '{' ) {
            parent->value_type = JSON_OBJECT;
            return json_parse_object( task, parent );
        } else if( ch == '[' ) {
            parent->value_type = JSON_ARRAY;
            return json_parse_array( task, parent );
        } else if( ch == 't' ) {
            parent->value_type = JSON_TRUE;
            return json_parse_true( task );
        } else if( ch == 'f' ) {
            parent->value_type = JSON_FALSE;
            return json_parse_false( task );
        } else if( ch == 'n' ) {
            parent->value_type = JSON_NULL;
            return json_parse_null( task );
        } else {
            task->err_msg = "illegal value";
            return -1;
        }
    }

    task->err_msg = "unexpect EOF";
    return -1;
}
Пример #6
0
static int json_parse_value(struct json_parse_state_s* state,
  struct json_value_s* value) {
  if (json_skip_whitespace(state)) {
    // consumed the whole buffer when we expected a value!
    return 1;
  }

  switch (state->src[state->offset]) {
  case '"':
    value->type = json_type_string;
    value->payload = state->dom;
    state->dom += sizeof(struct json_string_s);
    return json_parse_string(state, value->payload);
  case '{':
    value->type = json_type_object;
    value->payload = state->dom;
    state->dom += sizeof(struct json_object_s);
    return json_parse_object(state, value->payload);
  case '[':
    value->type = json_type_array;
    value->payload = state->dom;
    state->dom += sizeof(struct json_array_s);
    return json_parse_array(state, value->payload);
  case '-':
  case '0':
  case '1':
  case '2':
  case '3':
  case '4':
  case '5':
  case '6':
  case '7':
  case '8':
  case '9':
    value->type = json_type_number;
    value->payload = state->dom;
    state->dom += sizeof(struct json_number_s);
    return json_parse_number(state, value->payload);
  default:
    if ((state->offset + 4) < state->size &&
      't' == state->src[state->offset + 0] &&
      'r' == state->src[state->offset + 1] &&
      'u' == state->src[state->offset + 2] &&
      'e' == state->src[state->offset + 3]) {
      value->type = json_type_true;
      value->payload = 0;
      state->offset += 4;
      return 0;
    } else if ((state->offset + 5) < state->size &&
      'f' == state->src[state->offset + 0] &&
      'a' == state->src[state->offset + 1] &&
      'l' == state->src[state->offset + 2] &&
      's' == state->src[state->offset + 3] &&
      'e' == state->src[state->offset + 4]) {
      value->type = json_type_false;
      value->payload = 0;
      state->offset += 5;
      return 0;
    } else if ((state->offset + 4) < state->size &&
      'n' == state->src[state->offset + 0] &&
      'u' == state->src[state->offset + 1] &&
      'l' == state->src[state->offset + 2] &&
      'l' == state->src[state->offset + 3]) {
      value->type = json_type_null;
      value->payload = 0;
      state->offset += 4;
      return 0;
    }

    // invalid value!
    return 1;
  }
}
Пример #7
0
static int
json_try_parse_next(struct json_parser *parser, enum json_type *type_r,
		    const char **value_r)
{
	bool skipping = parser->skipping;
	int ret;

	if (!json_parse_whitespace(parser))
		return -1;

	switch (parser->state) {
	case JSON_STATE_ROOT:
		if (*parser->data != '{') {
			parser->error = "Object doesn't begin with '{'";
			return -1;
		}
		parser->data++;
		parser->state = JSON_STATE_OBJECT_OPEN;
		json_parser_update_input_pos(parser);
		return 0;
	case JSON_STATE_OBJECT_VALUE:
	case JSON_STATE_ARRAY_VALUE:
		if (*parser->data == '{') {
			parser->data++;
			parser->state = JSON_STATE_OBJECT_OPEN;
			array_append(&parser->nesting, &parser->state, 1);
			json_parser_update_input_pos(parser);

			if (parser->skipping) {
				parser->nested_skip_count++;
				return 0;
			}
			*type_r = JSON_TYPE_OBJECT;
			return 1;
		} else if (*parser->data == '[') {
			parser->data++;
			parser->state = JSON_STATE_ARRAY_OPEN;
			array_append(&parser->nesting, &parser->state, 1);
			json_parser_update_input_pos(parser);

			if (parser->skipping) {
				parser->nested_skip_count++;
				return 0;
			}
			*type_r = JSON_TYPE_ARRAY;
			return 1;
		}

		if ((ret = json_parse_string(parser, TRUE, value_r)) >= 0) {
			*type_r = JSON_TYPE_STRING;
		} else if ((ret = json_parse_number(parser, value_r)) >= 0) {
			*type_r = JSON_TYPE_NUMBER;
		} else if ((ret = json_parse_atom(parser, "true")) >= 0) {
			*type_r = JSON_TYPE_TRUE;
			*value_r = "true";
		} else if ((ret = json_parse_atom(parser, "false")) >= 0) {
			*type_r = JSON_TYPE_FALSE;
			*value_r = "false";
		} else if ((ret = json_parse_atom(parser, "null")) >= 0) {
			*type_r = JSON_TYPE_NULL;
			*value_r = NULL;
		} else {
			parser->error = "Invalid data as value";
			return -1;
		}
		if (ret == 0) {
			i_assert(parser->data == parser->end);
			if (parser->skipping && *type_r == JSON_TYPE_STRING) {
				/* a large string that we want to skip over. */
				json_parser_update_input_pos(parser);
				parser->state = parser->state == JSON_STATE_OBJECT_VALUE ?
					JSON_STATE_OBJECT_SKIP_STRING :
					JSON_STATE_ARRAY_SKIP_STRING;
				return 0;
			}
			return -1;
		}
		parser->state = parser->state == JSON_STATE_OBJECT_VALUE ?
			JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
		break;
	case JSON_STATE_OBJECT_OPEN:
		if (*parser->data == '}')
			return json_parse_close_object(parser, type_r);
		parser->state = JSON_STATE_OBJECT_KEY;
		/* fall through */
	case JSON_STATE_OBJECT_KEY:
		if (json_parse_string(parser, FALSE, value_r) <= 0) {
			parser->error = "Expected string as object key";
			return -1;
		}
		*type_r = JSON_TYPE_OBJECT_KEY;
		parser->state = JSON_STATE_OBJECT_COLON;
		break;
	case JSON_STATE_OBJECT_COLON:
		if (*parser->data != ':') {
			parser->error = "Expected ':' after key";
			return -1;
		}
		parser->data++;
		parser->state = JSON_STATE_OBJECT_VALUE;
		json_parser_update_input_pos(parser);
		return 0;
	case JSON_STATE_OBJECT_NEXT:
		if (parser->skipping && parser->nested_skip_count == 0) {
			/* we skipped over the previous value */
			parser->skipping = FALSE;
		}
		if (*parser->data == '}')
			return json_parse_close_object(parser, type_r);
		if (*parser->data != ',') {
			parser->error = "Expected ',' or '}' after object value";
			return -1;
		}
		parser->state = JSON_STATE_OBJECT_KEY;
		parser->data++;
		json_parser_update_input_pos(parser);
		return 0;
	case JSON_STATE_ARRAY_OPEN:
		if (*parser->data == ']')
			return json_parse_close_array(parser, type_r);
		parser->state = JSON_STATE_ARRAY_VALUE;
		return 0;
	case JSON_STATE_ARRAY_NEXT:
		if (parser->skipping && parser->nested_skip_count == 0) {
			/* we skipped over the previous value */
			parser->skipping = FALSE;
		}
		if (*parser->data == ']')
			return json_parse_close_array(parser, type_r);
		if (*parser->data != ',') {
			parser->error = "Expected ',' or '}' after array value";
			return -1;
		}
		parser->state = JSON_STATE_ARRAY_VALUE;
		parser->data++;
		json_parser_update_input_pos(parser);
		return 0;
	case JSON_STATE_OBJECT_SKIP_STRING:
	case JSON_STATE_ARRAY_SKIP_STRING:
		if (json_skip_string(parser) <= 0)
			return -1;
		parser->state = parser->state == JSON_STATE_OBJECT_SKIP_STRING ?
			JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
		return 0;
	case JSON_STATE_DONE:
		parser->error = "Unexpected data at the end";
		return -1;
	}
	json_parser_update_input_pos(parser);
	return skipping ? 0 : 1;
}
Пример #8
0
static void json_parse_value(struct json_parse_state_s *state,
                            int is_global_object, struct json_value_s *value) {
  if (is_global_object) {
    value->type = json_type_object;
    value->payload = state->dom;
    state->dom += sizeof(struct json_object_s);
    json_parse_object(state, /* is_global_object = */ 1, value->payload);
  } else {
    (void)json_skip_all_skippables(state);

    switch (state->src[state->offset]) {
    case '"':
      value->type = json_type_string;
      value->payload = state->dom;
      state->dom += sizeof(struct json_string_s);
      json_parse_string(state, value->payload);
      break;
    case '{':
      value->type = json_type_object;
      value->payload = state->dom;
      state->dom += sizeof(struct json_object_s);
      json_parse_object(state, /* is_global_object = */ 0,
                               value->payload);
      break;
    case '[':
      value->type = json_type_array;
      value->payload = state->dom;
      state->dom += sizeof(struct json_array_s);
      json_parse_array(state, value->payload);
      break;
    case '+':
    case '-':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    case '.':
      value->type = json_type_number;
      value->payload = state->dom;
      state->dom += sizeof(struct json_number_s);
      json_parse_number(state, value->payload);
      break;
    default:
      if ((state->offset + 4) <= state->size &&
          't' == state->src[state->offset + 0] &&
          'r' == state->src[state->offset + 1] &&
          'u' == state->src[state->offset + 2] &&
          'e' == state->src[state->offset + 3]) {
        value->type = json_type_true;
        value->payload = 0;
        state->offset += 4;
      } else if ((state->offset + 5) <= state->size &&
                 'f' == state->src[state->offset + 0] &&
                 'a' == state->src[state->offset + 1] &&
                 'l' == state->src[state->offset + 2] &&
                 's' == state->src[state->offset + 3] &&
                 'e' == state->src[state->offset + 4]) {
        value->type = json_type_false;
        value->payload = 0;
        state->offset += 5;
      } else if ((state->offset + 4) <= state->size &&
                 'n' == state->src[state->offset + 0] &&
                 'u' == state->src[state->offset + 1] &&
                 'l' == state->src[state->offset + 2] &&
                 'l' == state->src[state->offset + 3]) {
        value->type = json_type_null;
        value->payload = 0;
        state->offset += 4;
      }
      break;
    }
  }
}
Пример #9
0
int json_tokenize(
                const char **p,
                char **ret_string,
                union json_value *ret_value,
                void **state,
                unsigned *line) {

        const char *c;
        int t;
        int r;

        assert(p);
        assert(*p);
        assert(ret_string);
        assert(ret_value);
        assert(state);

        t = PTR_TO_INT(*state);
        c = *p;

        if (t == STATE_NULL) {
                if (line)
                        *line = 1;
                t = STATE_VALUE;
        }

        for (;;) {
                const char *b;

                b = c + strspn(c, WHITESPACE);
                if (*b == 0)
                        return JSON_END;

                inc_lines(line, c, b - c);
                c = b;

                switch (t) {

                case STATE_VALUE:

                        if (*c == '{') {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 1;
                                *state = INT_TO_PTR(STATE_VALUE);
                                return JSON_OBJECT_OPEN;

                        } else if (*c == '}') {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 1;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return JSON_OBJECT_CLOSE;

                        } else if (*c == '[') {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 1;
                                *state = INT_TO_PTR(STATE_VALUE);
                                return JSON_ARRAY_OPEN;

                        } else if (*c == ']') {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 1;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return JSON_ARRAY_CLOSE;

                        } else if (*c == '"') {
                                r = json_parse_string(&c, ret_string);
                                if (r < 0)
                                        return r;

                                *ret_value = JSON_VALUE_NULL;
                                *p = c;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return r;

                        } else if (strchr("-0123456789", *c)) {
                                r = json_parse_number(&c, ret_value);
                                if (r < 0)
                                        return r;

                                *ret_string = NULL;
                                *p = c;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return r;

                        } else if (startswith(c, "true")) {
                                *ret_string = NULL;
                                ret_value->boolean = true;
                                *p = c + 4;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return JSON_BOOLEAN;

                        } else if (startswith(c, "false")) {
                                *ret_string = NULL;
                                ret_value->boolean = false;
                                *p = c + 5;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return JSON_BOOLEAN;

                        } else if (startswith(c, "null")) {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 4;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return JSON_NULL;

                        } else
                                return -EINVAL;

                case STATE_VALUE_POST:

                        if (*c == ':') {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 1;
                                *state = INT_TO_PTR(STATE_VALUE);
                                return JSON_COLON;
                        } else if (*c == ',') {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 1;
                                *state = INT_TO_PTR(STATE_VALUE);
                                return JSON_COMMA;
                        } else if (*c == '}') {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 1;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return JSON_OBJECT_CLOSE;
                        } else if (*c == ']') {
                                *ret_string = NULL;
                                *ret_value = JSON_VALUE_NULL;
                                *p = c + 1;
                                *state = INT_TO_PTR(STATE_VALUE_POST);
                                return JSON_ARRAY_CLOSE;
                        } else
                                return -EINVAL;
                }

        }
}
Пример #10
0
/**
   @brief Parse an array.
   @param text The text we're parsing.
   @param arr The token buffer.
   @param maxtoken The length of the token buffer.
   @param p The parser state.
   @returns Parser state after parsing the array.
 */
static struct json_parser json_parse_array(wchar_t *text, struct json_token *arr,
                                           size_t maxtoken, struct json_parser p)
{
  size_t array_tokenidx = p.tokenidx, prev_tokenidx, curr_tokenidx, length=0;
  struct json_token tok = {
    .type = JSON_ARRAY,
    .start = p.textidx,
    .length = 0,
    .end = 0,
    .child = 0,
    .next = 0,
  };
  json_settoken(arr, tok, p, maxtoken);

  // current char is [, so we need to go past it.
  p.textidx++;
  p.tokenidx++;

  // Skip through whitespace.
  p = json_skip_whitespace(text, p);
  while (text[p.textidx] != L']') {

    if (text[p.textidx] == L'\0') {
      p.error = JSONERR_PREMATURE_EOF;
      return p;
    }
    // Parse a value.
    prev_tokenidx = curr_tokenidx;
    curr_tokenidx = p.tokenidx;
    p = json_parse_rec(text, arr, maxtoken, p);
    if (p.error != JSONERR_NO_ERROR) {
      return p;
    }

    // Now set some bookkeeping of previous values.
    if (tok.child == 0) {
      // If this is the first element of the list, set the list's child to point
      // to it.
      tok.child = curr_tokenidx;
      json_setchild(arr, array_tokenidx, curr_tokenidx, maxtoken);
    } else {
      // Otherwise set the previous element's next pointer to point to it.
      json_setnext(arr, prev_tokenidx, curr_tokenidx, maxtoken);
    }

    length++;

    // Skip whitespace.
    p = json_skip_whitespace(text, p);
    if (text[p.textidx] == L',') {
      p.textidx++;
      p = json_skip_whitespace(text, p);
    } else if (text[p.textidx] != L']') {
      // If there was no comma, this better be the end of the object.
      p.error = JSONERR_EXPECTED_TOKEN;
      p.errorarg = L',';
      return p;
    }
  }

  // Set the end of the array token to point to the closing bracket, then move
  // it up.
  json_setend(arr, array_tokenidx, p.textidx, maxtoken);
  json_setlength(arr, array_tokenidx, length, maxtoken);
  p.textidx++;
  return p;
}

/**
   @brief Parse an object.
   @param text The text we're parsing.
   @param arr The token buffer.
   @param maxtoken The length of the token buffer.
   @param p The parser state.
   @returns Parser state after parsing the object.
 */
static struct json_parser json_parse_object(wchar_t *text, struct json_token *arr,
                                            size_t maxtoken, struct json_parser p)
{
  size_t object_tokenidx = p.tokenidx, prev_keyidx, curr_keyidx, length=0;
  struct json_token tok = {
    .type  = JSON_OBJECT,
    .start = p.textidx,
    .length = 0,
    .end   = 0,
    .child = 0,
    .next  = 0,
  };
  json_settoken(arr, tok, p, maxtoken);

  // current char is {, so we need to go past it.
  p.textidx++;
  p.tokenidx++;

  // Skip through whitespace.
  p = json_skip_whitespace(text, p);
  while (text[p.textidx] != L'}') {
    // Make sure the string didn't end.
    if (text[p.textidx] == L'\0') {
      p.error = JSONERR_PREMATURE_EOF;
      return p;
    }

    // Parse a string (key) and value.
    prev_keyidx = curr_keyidx;
    curr_keyidx = p.tokenidx;
    p = json_parse_string(text, arr, maxtoken, p);
    if (p.error != JSONERR_NO_ERROR) {
      return p;
    }
    p = json_skip_whitespace(text, p);
    if (text[p.textidx] != L':') {
      p.error = JSONERR_EXPECTED_TOKEN;
      p.errorarg = L':';
      return p;
    }
    p.textidx++;
    p = json_parse_rec(text, arr, maxtoken, p);
    if (p.error != JSONERR_NO_ERROR) {
      return p;
    }

    // Now set some bookkeeping of previous values.
    if (tok.child == 0) {
      // If this is the first element of the list, set the list's child to point
      // to it.
      tok.child = curr_keyidx;
      json_setchild(arr, object_tokenidx, curr_keyidx, maxtoken);
    } else {
      // Otherwise set the previous element's next pointer to point to it.
      json_setnext(arr, prev_keyidx, curr_keyidx, maxtoken);
    }
    // Set the key's child pointer to point at its value.  Just cause we can.
    json_setchild(arr, curr_keyidx, curr_keyidx + 1, maxtoken);

    length++;

    // Skip whitespace.
    p = json_skip_whitespace(text, p);
    if (text[p.textidx] == L',') {
      p.textidx++;
      p = json_skip_whitespace(text, p);
    } else if (text[p.textidx] != L'}') {
      // If there was no comma, this better be the end of the object.
      p.error = JSONERR_EXPECTED_TOKEN;
      p.errorarg = L',';
      return p;
    }
  }

  // Set the end of the array token to point to the closing bracket, then move
  // it up.
  json_setend(arr, object_tokenidx, p.textidx, maxtoken);
  json_setlength(arr, object_tokenidx, length, maxtoken);
  p.textidx++;
  return p;
}

char *parse_number_state[] = {
  "START", "MINUS", "ZERO", "DIGIT", "DECIMAL", "DECIMAL_ACCEPT", "EXPONENT",
  "EXPONENT_DIGIT", "EXPONENT_DIGIT_ACCEPT", "END"
};

/**
   @brief Parse a string number.
   @param text The text we're parsing.
   @param arr The token buffer.
   @param maxtoken The length of the token buffer.
   @param p The parser state.
   @returns Parser state after parsing the number.
 */
static struct json_parser json_parse_number(wchar_t *text, struct json_token *arr,
                                            size_t maxtoken, struct json_parser p)
{
  struct json_token tok = {
    .type  = JSON_NUMBER,
    .start = p.textidx,
    .length = 0, // not used
    .end   = 0,
    .child = 0,
    .next  = 0
  };
  enum state {
    START, MINUS, ZERO, DIGIT, DECIMAL, DECIMAL_ACCEPT, EXPONENT,
    EXPONENT_DIGIT, EXPONENT_DIGIT_ACCEPT, END
  } state = START;

  /*
    This function is completely described by this FSM.  States marked by
    asterisk are accepting.  Unexpected input at accepting states ends the
    number, and unexpected input at rejecting states causes an error.  This
    state machine is designed to accept any input given by the diagram in the
    ECMA JSON spec.

                         -----START-----
                        /       | (-)   \
                       /        v        \
                   (0) | +----MINUS----+ | (1-9)
                       v v (0)   (1-9) v v
                    *ZERO*            *DIGIT*--------
                     |  \ (.)       (.) / |-\ (0-9)  \
                     |   --->DECIMAL<---              \
                     |          |                      \
                     |          v (0-9)  /----\ (0-9)  |
                     |   *DECIMAL_ACCEPT* ----/        |
                     |          |                     /
                     |(e,E)     v (e,E)   (e,E)      /
                     +-----> EXPONENT <-------------
                           /        \
                      (+,-)v        v (0-9)
              EXPONENT_DIGIT        *EXPONENT_DIGIT_ACCEPT*
                          \-----------/         \    /(0-9)
                                 (0-9)           \--/
   */

  //printf("input: %s\n", text + p.textidx);
  while (state != END) {
    wchar_t c = text[p.textidx];
    //printf("state: %s\n", parse_number_state[state]);
    switch (state) {
    case START:
      if (c == L'0') {
        state = ZERO;
      } else if (c == L'-') {
        state = MINUS;
      } else if (L'1' <= c && c <= L'9') {
        state = DIGIT;
      } else {
        p.error = JSONERR_INVALID_NUMBER;
        state = END; // ERROR
      }
      break;
    case MINUS:
      if (c == L'0') {
        state = ZERO;
      } else if (L'1' <= c && c <= L'9') {
        state = DIGIT;
      } else {
        p.error = JSONERR_INVALID_NUMBER;
        state = END; // ERROR
      }
      break;
    case ZERO:
      if (c == L'.') {
        state = DECIMAL;
      } else if (c == L'e' || c == L'E') {
        state = EXPONENT;
      } else {
        state = END;
      }
      break;
    case DIGIT:
      if (c == L'.') {
        state = DECIMAL;
      } else if (c == L'e' || c == L'E') {
        state = EXPONENT;
      } else if (L'0' <= c && c <= L'9') {
        state = DIGIT;
      } else {
        state = END;
      }
      break;
    case DECIMAL:
      if (L'0' <= c && c <= L'9') {
        state = DECIMAL_ACCEPT;
      } else {
        p.error = JSONERR_INVALID_NUMBER;
        state = END; // ERROR
      }
      break;
    case DECIMAL_ACCEPT:
      if (L'0' <= c && c <= L'9') {
        state = DECIMAL_ACCEPT;
      } else if (c == L'e' || c == L'E') {
        state = EXPONENT;
      } else {
        state = END;
      }
      break;
    case EXPONENT:
      if (c == L'+' || c == L'-') {
        state = EXPONENT_DIGIT;
      } else if (L'0' <= c && c <= L'9') {
        state = EXPONENT_DIGIT_ACCEPT;
      } else {
        p.error = JSONERR_INVALID_NUMBER;
        state = END; // ERROR
      }
      break;
    case EXPONENT_DIGIT:
      if (L'0' <= c && c <= L'9') {
        state = EXPONENT_DIGIT_ACCEPT;
      } else {
        p.error = JSONERR_INVALID_NUMBER;
        state = END; // ERROR
      }
      break;
    case EXPONENT_DIGIT_ACCEPT:
      if (L'0' <= c && c <= L'9') {
        state = EXPONENT_DIGIT_ACCEPT;
      } else {
        state = END;
      }
      break;
    case END:
      // never happens
      assert(false);
    }
    p.textidx++;
  }

  p.textidx--; // the character we failed on
  tok.end = p.textidx - 1; // the previous character
  json_settoken(arr, tok, p, maxtoken);
  p.tokenidx++;
  return p;
}

/**
   @brief Parse any JSON value.
   @param text The text we're parsing.
   @param arr The token buffer.
   @param maxtoken The length of the token buffer.
   @param p The parser state.
   @returns Parser state after parsing the value.
 */
static struct json_parser json_parse_rec(wchar_t *text, struct json_token *arr,
                                         size_t maxtoken, struct json_parser p)
{
  p = json_skip_whitespace(text, p);

  if (text[p.textidx] == '\0') {
    p.error = JSONERR_PREMATURE_EOF;
    return p;
  }

  switch (text[p.textidx]) {
  case L'{':
    return json_parse_object(text, arr, maxtoken, p);
  case L'[':
    return json_parse_array(text, arr, maxtoken, p);
  case L'"':
    return json_parse_string(text, arr, maxtoken, p);
  case L't':
    return json_parse_true(text, arr, maxtoken, p);
  case L'f':
    return json_parse_false(text, arr, maxtoken, p);
  case L'n':
    return json_parse_null(text, arr, maxtoken, p);
  default:
    if (json_isnumber(text[p.textidx])) {
      return json_parse_number(text, arr, maxtoken, p);
    } else {
      p.error = JSONERR_UNEXPECTED_TOKEN;
      return p;
    }
  }
}

char *json_type_str[] = {
  "object",
  "array",
  "number",
  "string",
  "true",
  "false",
  "null"
};

char *json_error_str[] = {
  "no error",
  "encountered an invalid numeric literal",
  "string ended prematurely",
  "unexpected token",
  "invalid surrogate pair",
  "expected token '%c'",
};

struct json_parser json_parse(wchar_t *text, struct json_token *arr, size_t maxtoken)
{
  struct json_parser parser = {
    .textidx = 0,
    .tokenidx = 0,
    .error = JSONERR_NO_ERROR,
    .errorarg = 0
  };
  return json_parse_rec(text, arr, maxtoken, parser);
}

void json_print(struct json_token *arr, size_t n)
{
  size_t i;
  for (i = 0; i < n; i++) {
    printf("%03lu: %6s\t%04lu-%04lu,\tlength=%lu,\tchild=%lu,\tnext=%lu\n", i,
           json_type_str[arr[i].type], arr[i].start, arr[i].end, arr[i].length,
           arr[i].child, arr[i].next);
  }
}

void json_print_error(FILE *f, struct json_parser p)
{
  fprintf(f, "at character %lu: ", p.textidx);
  fprintf(f, json_error_str[p.error], p.errorarg);
  fprintf(f, "\n");
}
Пример #11
0
static int
json_parse(const unsigned char **ucp, const unsigned char *ue,
    size_t *st, size_t lvl)
{
	const unsigned char *uc;
	int rv = 0;
	int t;

	uc = json_skip_space(*ucp, ue);
	if (uc == ue)
		goto out;

	// Avoid recursion
	if (lvl > 20)
		return 0;
#if JSON_COUNT
	/* bail quickly if not counting */
	if (lvl > 1 && (st[JSON_OBJECT] || st[JSON_ARRAY]))
		return 1;
#endif

	DPRINTF("Parse general: ", uc, *ucp);
	switch (*uc++) {
	case '"':
		rv = json_parse_string(&uc, ue);
		t = JSON_STRING;
		break;
	case '[':
		rv = json_parse_array(&uc, ue, st, lvl + 1);
		t = JSON_ARRAY;
		break;
	case '{': /* '}' */
		rv = json_parse_object(&uc, ue, st, lvl + 1);
		t = JSON_OBJECT;
		break;
	case 't':
		rv = json_parse_const(&uc, ue, "true", sizeof("true"));
		t = JSON_CONSTANT;
		break;
	case 'f':
		rv = json_parse_const(&uc, ue, "false", sizeof("false"));
		t = JSON_CONSTANT;
		break;
	case 'n':
		rv = json_parse_const(&uc, ue, "null", sizeof("null"));
		t = JSON_CONSTANT;
		break;
	default:
		--uc;
		rv = json_parse_number(&uc, ue);
		t = JSON_NUMBER;
		break;
	}
	if (rv)
		st[t]++;
	uc = json_skip_space(uc, ue);
out:
	*ucp = uc;
	DPRINTF("End general: ", uc, *ucp);
	if (lvl == 0)
		return rv && (st[JSON_ARRAY] || st[JSON_OBJECT]);
	return rv;
}