Пример #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
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;
}
Пример #3
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;
}
Пример #4
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");
}