Blame json_tokener.c

Packit ea8578
/*
Packit ea8578
 * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $
Packit ea8578
 *
Packit ea8578
 * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
Packit ea8578
 * Michael Clark <michael@metaparadigm.com>
Packit ea8578
 *
Packit ea8578
 * This library is free software; you can redistribute it and/or modify
Packit ea8578
 * it under the terms of the MIT license. See COPYING for details.
Packit ea8578
 *
Packit ea8578
 *
Packit ea8578
 * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.
Packit ea8578
 * The copyrights to the contents of this file are licensed under the MIT License
Packit ea8578
 * (http://www.opensource.org/licenses/mit-license.php)
Packit ea8578
 */
Packit ea8578
Packit ea8578
#include "config.h"
Packit ea8578
Packit ea8578
#include <math.h>
Packit ea8578
#include "math_compat.h"
Packit ea8578
#include <stdio.h>
Packit ea8578
#include <stdlib.h>
Packit ea8578
#include <stddef.h>
Packit ea8578
#include <ctype.h>
Packit ea8578
#include <string.h>
Packit ea8578
#include <limits.h>
Packit ea8578
Packit ea8578
#include "debug.h"
Packit ea8578
#include "printbuf.h"
Packit ea8578
#include "arraylist.h"
Packit ea8578
#include "json_inttypes.h"
Packit ea8578
#include "json_object.h"
Packit ea8578
#include "json_object_private.h"
Packit ea8578
#include "json_tokener.h"
Packit ea8578
#include "json_util.h"
Packit ea8578
#include "strdup_compat.h"
Packit ea8578
Packit ea8578
#ifdef HAVE_LOCALE_H
Packit ea8578
#include <locale.h>
Packit ea8578
#endif /* HAVE_LOCALE_H */
Packit ea8578
#ifdef HAVE_XLOCALE_H
Packit ea8578
#include <xlocale.h>
Packit ea8578
#endif
Packit ea8578
Packit ea8578
#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
Packit ea8578
Packit ea8578
#if !HAVE_STRNCASECMP && defined(_MSC_VER)
Packit ea8578
  /* MSC has the version as _strnicmp */
Packit ea8578
# define strncasecmp _strnicmp
Packit ea8578
#elif !HAVE_STRNCASECMP
Packit ea8578
# error You do not have strncasecmp on your system.
Packit ea8578
#endif /* HAVE_STRNCASECMP */
Packit ea8578
Packit ea8578
/* Use C99 NAN by default; if not available, nan("") should work too. */
Packit ea8578
#ifndef NAN
Packit ea8578
#define NAN nan("")
Packit ea8578
#endif /* !NAN */
Packit ea8578
Packit ea8578
static const char json_null_str[] = "null";
Packit ea8578
static const int json_null_str_len = sizeof(json_null_str) - 1;
Packit ea8578
static const char json_inf_str[] = "Infinity";
Packit ea8578
static const char json_inf_str_lower[] = "infinity";
Packit ea8578
static const unsigned int json_inf_str_len = sizeof(json_inf_str) - 1;
Packit ea8578
static const char json_nan_str[] = "NaN";
Packit ea8578
static const int json_nan_str_len = sizeof(json_nan_str) - 1;
Packit ea8578
static const char json_true_str[] = "true";
Packit ea8578
static const int json_true_str_len = sizeof(json_true_str) - 1;
Packit ea8578
static const char json_false_str[] = "false";
Packit ea8578
static const int json_false_str_len = sizeof(json_false_str) - 1;
Packit ea8578
Packit ea8578
static const char* json_tokener_errors[] = {
Packit ea8578
  "success",
Packit ea8578
  "continue",
Packit ea8578
  "nesting too deep",
Packit ea8578
  "unexpected end of data",
Packit ea8578
  "unexpected character",
Packit ea8578
  "null expected",
Packit ea8578
  "boolean expected",
Packit ea8578
  "number expected",
Packit ea8578
  "array value separator ',' expected",
Packit ea8578
  "quoted object property name expected",
Packit ea8578
  "object property name separator ':' expected",
Packit ea8578
  "object value separator ',' expected",
Packit ea8578
  "invalid string sequence",
Packit ea8578
  "expected comment",
Packit ea8578
  "buffer size overflow"
Packit ea8578
};
Packit ea8578
Packit ea8578
const char *json_tokener_error_desc(enum json_tokener_error jerr)
Packit ea8578
{
Packit ea8578
	int jerr_int = (int) jerr;
Packit ea8578
	if (jerr_int < 0 ||
Packit ea8578
	    jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0])))
Packit ea8578
		return "Unknown error, "
Packit ea8578
		       "invalid json_tokener_error value passed to json_tokener_error_desc()";
Packit ea8578
	return json_tokener_errors[jerr];
Packit ea8578
}
Packit ea8578
Packit ea8578
enum json_tokener_error json_tokener_get_error(struct json_tokener *tok)
Packit ea8578
{
Packit ea8578
	return tok->err;
Packit ea8578
}
Packit ea8578
Packit ea8578
/* Stuff for decoding unicode sequences */
Packit ea8578
#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800)
Packit ea8578
#define IS_LOW_SURROGATE(uc)  (((uc) & 0xFC00) == 0xDC00)
Packit ea8578
#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000)
Packit ea8578
static unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD };
Packit ea8578
Packit ea8578
struct json_tokener* json_tokener_new_ex(int depth)
Packit ea8578
{
Packit ea8578
  struct json_tokener *tok;
Packit ea8578
Packit ea8578
  tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener));
Packit ea8578
  if (!tok) return NULL;
Packit ea8578
  tok->stack = (struct json_tokener_srec *) calloc(depth,
Packit ea8578
						   sizeof(struct json_tokener_srec));
Packit ea8578
  if (!tok->stack) {
Packit ea8578
    free(tok);
Packit ea8578
    return NULL;
Packit ea8578
  }
Packit ea8578
  tok->pb = printbuf_new();
Packit ea8578
  tok->max_depth = depth;
Packit ea8578
  json_tokener_reset(tok);
Packit ea8578
  return tok;
Packit ea8578
}
Packit ea8578
Packit ea8578
struct json_tokener* json_tokener_new(void)
Packit ea8578
{
Packit ea8578
  return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH);
Packit ea8578
}
Packit ea8578
Packit ea8578
void json_tokener_free(struct json_tokener *tok)
Packit ea8578
{
Packit ea8578
  json_tokener_reset(tok);
Packit ea8578
  if (tok->pb) printbuf_free(tok->pb);
Packit ea8578
  free(tok->stack);
Packit ea8578
  free(tok);
Packit ea8578
}
Packit ea8578
Packit ea8578
static void json_tokener_reset_level(struct json_tokener *tok, int depth)
Packit ea8578
{
Packit ea8578
  tok->stack[depth].state = json_tokener_state_eatws;
Packit ea8578
  tok->stack[depth].saved_state = json_tokener_state_start;
Packit ea8578
  json_object_put(tok->stack[depth].current);
Packit ea8578
  tok->stack[depth].current = NULL;
Packit ea8578
  free(tok->stack[depth].obj_field_name);
Packit ea8578
  tok->stack[depth].obj_field_name = NULL;
Packit ea8578
}
Packit ea8578
Packit ea8578
void json_tokener_reset(struct json_tokener *tok)
Packit ea8578
{
Packit ea8578
  int i;
Packit ea8578
  if (!tok)
Packit ea8578
    return;
Packit ea8578
Packit ea8578
  for(i = tok->depth; i >= 0; i--)
Packit ea8578
    json_tokener_reset_level(tok, i);
Packit ea8578
  tok->depth = 0;
Packit ea8578
  tok->err = json_tokener_success;
Packit ea8578
}
Packit ea8578
Packit ea8578
struct json_object* json_tokener_parse(const char *str)
Packit ea8578
{
Packit ea8578
    enum json_tokener_error jerr_ignored;
Packit ea8578
    struct json_object* obj;
Packit ea8578
    obj = json_tokener_parse_verbose(str, &jerr_ignored);
Packit ea8578
    return obj;
Packit ea8578
}
Packit ea8578
Packit ea8578
struct json_object* json_tokener_parse_verbose(const char *str,
Packit ea8578
					       enum json_tokener_error *error)
Packit ea8578
{
Packit ea8578
    struct json_tokener* tok;
Packit ea8578
    struct json_object* obj;
Packit ea8578
Packit ea8578
    tok = json_tokener_new();
Packit ea8578
    if (!tok)
Packit ea8578
      return NULL;
Packit ea8578
    obj = json_tokener_parse_ex(tok, str, -1);
Packit ea8578
    *error = tok->err;
Packit ea8578
    if(tok->err != json_tokener_success) {
Packit ea8578
		if (obj != NULL)
Packit ea8578
			json_object_put(obj);
Packit ea8578
        obj = NULL;
Packit ea8578
    }
Packit ea8578
Packit ea8578
    json_tokener_free(tok);
Packit ea8578
    return obj;
Packit ea8578
}
Packit ea8578
Packit ea8578
#define state  tok->stack[tok->depth].state
Packit ea8578
#define saved_state  tok->stack[tok->depth].saved_state
Packit ea8578
#define current tok->stack[tok->depth].current
Packit ea8578
#define obj_field_name tok->stack[tok->depth].obj_field_name
Packit ea8578
Packit ea8578
/* Optimization:
Packit ea8578
 * json_tokener_parse_ex() consumed a lot of CPU in its main loop,
Packit ea8578
 * iterating character-by character.  A large performance boost is
Packit ea8578
 * achieved by using tighter loops to locally handle units such as
Packit ea8578
 * comments and strings.  Loops that handle an entire token within
Packit ea8578
 * their scope also gather entire strings and pass them to
Packit ea8578
 * printbuf_memappend() in a single call, rather than calling
Packit ea8578
 * printbuf_memappend() one char at a time.
Packit ea8578
 *
Packit ea8578
 * PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is
Packit ea8578
 * common to both the main loop and the tighter loops.
Packit ea8578
 */
Packit ea8578
Packit ea8578
/* PEEK_CHAR(dest, tok) macro:
Packit ea8578
 *   Peeks at the current char and stores it in dest.
Packit ea8578
 *   Returns 1 on success, sets tok->err and returns 0 if no more chars.
Packit ea8578
 *   Implicit inputs:  str, len vars
Packit ea8578
 */
Packit ea8578
#define PEEK_CHAR(dest, tok)			\
Packit ea8578
  (((tok)->char_offset == len) ?		\
Packit ea8578
   (((tok)->depth == 0 &&			\
Packit ea8578
     state == json_tokener_state_eatws &&	\
Packit ea8578
     saved_state == json_tokener_state_finish	\
Packit ea8578
     ) ?					\
Packit ea8578
    (((tok)->err = json_tokener_success), 0)	\
Packit ea8578
    :						\
Packit ea8578
    (((tok)->err = json_tokener_continue), 0)	\
Packit ea8578
    ) :						\
Packit ea8578
   (((dest) = *str), 1)				\
Packit ea8578
   )
Packit ea8578
Packit ea8578
/* ADVANCE_CHAR() macro:
Packit ea8578
 *   Incrementes str & tok->char_offset.
Packit ea8578
 *   For convenience of existing conditionals, returns the old value of c (0 on eof)
Packit ea8578
 *   Implicit inputs:  c var
Packit ea8578
 */
Packit ea8578
#define ADVANCE_CHAR(str, tok) \
Packit ea8578
  ( ++(str), ((tok)->char_offset)++, c)
Packit ea8578
Packit ea8578
Packit ea8578
/* End optimization macro defs */
Packit ea8578
Packit ea8578
Packit ea8578
struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
Packit ea8578
					  const char *str, int len)
Packit ea8578
{
Packit ea8578
  struct json_object *obj = NULL;
Packit ea8578
  char c = '\1';
Packit ea8578
#ifdef HAVE_USELOCALE
Packit ea8578
  locale_t oldlocale = uselocale(NULL);
Packit ea8578
  locale_t newloc;
Packit ea8578
#elif defined(HAVE_SETLOCALE)
Packit ea8578
  char *oldlocale = NULL;
Packit ea8578
#endif
Packit ea8578
Packit ea8578
  tok->char_offset = 0;
Packit ea8578
  tok->err = json_tokener_success;
Packit ea8578
Packit ea8578
  /* this interface is presently not 64-bit clean due to the int len argument
Packit ea8578
     and the internal printbuf interface that takes 32-bit int len arguments
Packit ea8578
     so the function limits the maximum string size to INT32_MAX (2GB).
Packit ea8578
     If the function is called with len == -1 then strlen is called to check
Packit ea8578
     the string length is less than INT32_MAX (2GB) */
Packit ea8578
  if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) {
Packit ea8578
    tok->err = json_tokener_error_size;
Packit ea8578
    return NULL;
Packit ea8578
  }
Packit ea8578
Packit ea8578
#ifdef HAVE_USELOCALE
Packit ea8578
  {
Packit ea8578
    locale_t duploc = duplocale(oldlocale);
Packit ea8578
    newloc = newlocale(LC_NUMERIC, "C", duploc);
Packit ea8578
    // XXX at least Debian 8.4 has a bug in newlocale where it doesn't
Packit ea8578
    //  change the decimal separator unless you set LC_TIME!
Packit ea8578
    if (newloc)
Packit ea8578
    {
Packit ea8578
      duploc = newloc; // original duploc has been freed by newlocale()
Packit ea8578
      newloc = newlocale(LC_TIME, "C", duploc);
Packit ea8578
    }
Packit ea8578
    if (newloc == NULL)
Packit ea8578
    {
Packit ea8578
      freelocale(duploc);
Packit ea8578
      return NULL;
Packit ea8578
    }
Packit ea8578
    uselocale(newloc);
Packit ea8578
  }
Packit ea8578
#elif defined(HAVE_SETLOCALE)
Packit ea8578
  {
Packit ea8578
    char *tmplocale;
Packit ea8578
    tmplocale = setlocale(LC_NUMERIC, NULL);
Packit ea8578
    if (tmplocale) oldlocale = strdup(tmplocale);
Packit ea8578
    setlocale(LC_NUMERIC, "C");
Packit ea8578
  }
Packit ea8578
#endif
Packit ea8578
Packit ea8578
  while (PEEK_CHAR(c, tok)) {
Packit ea8578
Packit ea8578
  redo_char:
Packit ea8578
    switch(state) {
Packit ea8578
Packit ea8578
    case json_tokener_state_eatws:
Packit ea8578
      /* Advance until we change state */
Packit ea8578
      while (isspace((int)c)) {
Packit ea8578
	if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok)))
Packit ea8578
	  goto out;
Packit ea8578
      }
Packit ea8578
      if(c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) {
Packit ea8578
	printbuf_reset(tok->pb);
Packit ea8578
	printbuf_memappend_fast(tok->pb, &c, 1);
Packit ea8578
	state = json_tokener_state_comment_start;
Packit ea8578
      } else {
Packit ea8578
	state = saved_state;
Packit ea8578
	goto redo_char;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_start:
Packit ea8578
      switch(c) {
Packit ea8578
      case '{':
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
	saved_state = json_tokener_state_object_field_start;
Packit ea8578
	current = json_object_new_object();
Packit ea8578
	if(current == NULL)
Packit ea8578
		goto out;
Packit ea8578
	break;
Packit ea8578
      case '[':
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
	saved_state = json_tokener_state_array;
Packit ea8578
	current = json_object_new_array();
Packit ea8578
	if(current == NULL)
Packit ea8578
		goto out;
Packit ea8578
	break;
Packit ea8578
      case 'I':
Packit ea8578
      case 'i':
Packit ea8578
	state = json_tokener_state_inf;
Packit ea8578
	printbuf_reset(tok->pb);
Packit ea8578
	tok->st_pos = 0;
Packit ea8578
	goto redo_char;
Packit ea8578
      case 'N':
Packit ea8578
      case 'n':
Packit ea8578
	state = json_tokener_state_null; // or NaN
Packit ea8578
	printbuf_reset(tok->pb);
Packit ea8578
	tok->st_pos = 0;
Packit ea8578
	goto redo_char;
Packit ea8578
      case '\'':
Packit ea8578
        if (tok->flags & JSON_TOKENER_STRICT) {
Packit ea8578
            /* in STRICT mode only double-quote are allowed */
Packit ea8578
            tok->err = json_tokener_error_parse_unexpected;
Packit ea8578
            goto out;
Packit ea8578
        }
Packit ea8578
	/* FALLTHRU */
Packit ea8578
      case '"':
Packit ea8578
	state = json_tokener_state_string;
Packit ea8578
	printbuf_reset(tok->pb);
Packit ea8578
	tok->quote_char = c;
Packit ea8578
	break;
Packit ea8578
      case 'T':
Packit ea8578
      case 't':
Packit ea8578
      case 'F':
Packit ea8578
      case 'f':
Packit ea8578
	state = json_tokener_state_boolean;
Packit ea8578
	printbuf_reset(tok->pb);
Packit ea8578
	tok->st_pos = 0;
Packit ea8578
	goto redo_char;
Packit ea8578
      case '0':
Packit ea8578
      case '1':
Packit ea8578
      case '2':
Packit ea8578
      case '3':
Packit ea8578
      case '4':
Packit ea8578
      case '5':
Packit ea8578
      case '6':
Packit ea8578
      case '7':
Packit ea8578
      case '8':
Packit ea8578
      case '9':
Packit ea8578
      case '-':
Packit ea8578
	state = json_tokener_state_number;
Packit ea8578
	printbuf_reset(tok->pb);
Packit ea8578
	tok->is_double = 0;
Packit ea8578
	goto redo_char;
Packit ea8578
      default:
Packit ea8578
	tok->err = json_tokener_error_parse_unexpected;
Packit ea8578
	goto out;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_finish:
Packit ea8578
      if(tok->depth == 0) goto out;
Packit ea8578
      obj = json_object_get(current);
Packit ea8578
      json_tokener_reset_level(tok, tok->depth);
Packit ea8578
      tok->depth--;
Packit ea8578
      goto redo_char;
Packit ea8578
Packit ea8578
    case json_tokener_state_inf: /* aka starts with 'i' (or 'I', or "-i", or "-I") */
Packit ea8578
      {
Packit ea8578
	/* If we were guaranteed to have len set, then we could (usually) handle
Packit ea8578
	 * the entire "Infinity" check in a single strncmp (strncasecmp), but
Packit ea8578
	 * since len might be -1 (i.e. "read until \0"), we need to check it
Packit ea8578
	 * a character at a time.
Packit ea8578
	 * Trying to handle it both ways would make this code considerably more
Packit ea8578
	 * complicated with likely little performance benefit.
Packit ea8578
	 */
Packit ea8578
	int is_negative = 0;
Packit ea8578
	const char *_json_inf_str = json_inf_str;
Packit ea8578
	if (!(tok->flags & JSON_TOKENER_STRICT))
Packit ea8578
		_json_inf_str = json_inf_str_lower;
Packit ea8578
Packit ea8578
	/* Note: tok->st_pos must be 0 when state is set to json_tokener_state_inf */
Packit ea8578
	while (tok->st_pos < (int)json_inf_str_len)
Packit ea8578
	{
Packit ea8578
		char inf_char = *str;
Packit ea8578
		if (!(tok->flags & JSON_TOKENER_STRICT))
Packit ea8578
			inf_char = tolower((int)*str);
Packit ea8578
		if (inf_char != _json_inf_str[tok->st_pos])
Packit ea8578
		{
Packit ea8578
			tok->err = json_tokener_error_parse_unexpected;
Packit ea8578
			goto out;
Packit ea8578
		}
Packit ea8578
		tok->st_pos++;
Packit ea8578
		(void)ADVANCE_CHAR(str, tok);
Packit ea8578
		if (!PEEK_CHAR(c, tok))
Packit ea8578
		{
Packit ea8578
			/* out of input chars, for now at least */
Packit ea8578
			goto out;
Packit ea8578
		}
Packit ea8578
	}
Packit ea8578
	/* We checked the full length of "Infinity", so create the object.
Packit ea8578
	 * When handling -Infinity, the number parsing code will have dropped
Packit ea8578
	 * the "-" into tok->pb for us, so check it now.
Packit ea8578
	 */
Packit ea8578
	if (printbuf_length(tok->pb) > 0 && *(tok->pb->buf) == '-')
Packit ea8578
	{
Packit ea8578
		is_negative = 1;
Packit ea8578
	}
Packit ea8578
	current = json_object_new_double(is_negative
Packit ea8578
					 ? -INFINITY : INFINITY);
Packit ea8578
	if (current == NULL)
Packit ea8578
		goto out;
Packit ea8578
	saved_state = json_tokener_state_finish;
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
	goto redo_char;
Packit ea8578
	 
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
    case json_tokener_state_null: /* aka starts with 'n' */
Packit ea8578
      {
Packit ea8578
	int size;
Packit ea8578
	int size_nan;
Packit ea8578
	printbuf_memappend_fast(tok->pb, &c, 1);
Packit ea8578
	size = json_min(tok->st_pos+1, json_null_str_len);
Packit ea8578
	size_nan = json_min(tok->st_pos+1, json_nan_str_len);
Packit ea8578
	if((!(tok->flags & JSON_TOKENER_STRICT) &&
Packit ea8578
	  strncasecmp(json_null_str, tok->pb->buf, size) == 0)
Packit ea8578
	  || (strncmp(json_null_str, tok->pb->buf, size) == 0)
Packit ea8578
	  ) {
Packit ea8578
	  if (tok->st_pos == json_null_str_len) {
Packit ea8578
	    current = NULL;
Packit ea8578
	    saved_state = json_tokener_state_finish;
Packit ea8578
	    state = json_tokener_state_eatws;
Packit ea8578
	    goto redo_char;
Packit ea8578
	  }
Packit ea8578
	}
Packit ea8578
	else if ((!(tok->flags & JSON_TOKENER_STRICT) &&
Packit ea8578
	          strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) ||
Packit ea8578
	         (strncmp(json_nan_str, tok->pb->buf, size_nan) == 0)
Packit ea8578
	        )
Packit ea8578
	{
Packit ea8578
		if (tok->st_pos == json_nan_str_len)
Packit ea8578
		{
Packit ea8578
			current = json_object_new_double(NAN);
Packit ea8578
			if (current == NULL)
Packit ea8578
			    goto out;
Packit ea8578
			saved_state = json_tokener_state_finish;
Packit ea8578
			state = json_tokener_state_eatws;
Packit ea8578
			goto redo_char;
Packit ea8578
		}
Packit ea8578
	} else {
Packit ea8578
	  tok->err = json_tokener_error_parse_null;
Packit ea8578
	  goto out;
Packit ea8578
	}
Packit ea8578
	tok->st_pos++;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_comment_start:
Packit ea8578
      if(c == '*') {
Packit ea8578
	state = json_tokener_state_comment;
Packit ea8578
      } else if(c == '/') {
Packit ea8578
	state = json_tokener_state_comment_eol;
Packit ea8578
      } else {
Packit ea8578
	tok->err = json_tokener_error_parse_comment;
Packit ea8578
	goto out;
Packit ea8578
      }
Packit ea8578
      printbuf_memappend_fast(tok->pb, &c, 1);
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_comment:
Packit ea8578
              {
Packit ea8578
          /* Advance until we change state */
Packit ea8578
          const char *case_start = str;
Packit ea8578
          while(c != '*') {
Packit ea8578
            if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
Packit ea8578
              printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
              goto out;
Packit ea8578
            }
Packit ea8578
          }
Packit ea8578
          printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start);
Packit ea8578
          state = json_tokener_state_comment_end;
Packit ea8578
        }
Packit ea8578
            break;
Packit ea8578
Packit ea8578
    case json_tokener_state_comment_eol:
Packit ea8578
      {
Packit ea8578
	/* Advance until we change state */
Packit ea8578
	const char *case_start = str;
Packit ea8578
	while(c != '\n') {
Packit ea8578
	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
Packit ea8578
	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
	    goto out;
Packit ea8578
	  }
Packit ea8578
	}
Packit ea8578
	printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
	MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_comment_end:
Packit ea8578
      printbuf_memappend_fast(tok->pb, &c, 1);
Packit ea8578
      if(c == '/') {
Packit ea8578
	MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      } else {
Packit ea8578
	state = json_tokener_state_comment;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_string:
Packit ea8578
      {
Packit ea8578
	/* Advance until we change state */
Packit ea8578
	const char *case_start = str;
Packit ea8578
	while(1) {
Packit ea8578
	  if(c == tok->quote_char) {
Packit ea8578
	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
	    current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos);
Packit ea8578
	    if(current == NULL)
Packit ea8578
		goto out;
Packit ea8578
	    saved_state = json_tokener_state_finish;
Packit ea8578
	    state = json_tokener_state_eatws;
Packit ea8578
	    break;
Packit ea8578
	  } else if(c == '\\') {
Packit ea8578
	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
	    saved_state = json_tokener_state_string;
Packit ea8578
	    state = json_tokener_state_string_escape;
Packit ea8578
	    break;
Packit ea8578
	  }
Packit ea8578
	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
Packit ea8578
	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
	    goto out;
Packit ea8578
	  }
Packit ea8578
	}
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_string_escape:
Packit ea8578
      switch(c) {
Packit ea8578
      case '"':
Packit ea8578
      case '\\':
Packit ea8578
      case '/':
Packit ea8578
	printbuf_memappend_fast(tok->pb, &c, 1);
Packit ea8578
	state = saved_state;
Packit ea8578
	break;
Packit ea8578
      case 'b':
Packit ea8578
      case 'n':
Packit ea8578
      case 'r':
Packit ea8578
      case 't':
Packit ea8578
      case 'f':
Packit ea8578
	if(c == 'b') printbuf_memappend_fast(tok->pb, "\b", 1);
Packit ea8578
	else if(c == 'n') printbuf_memappend_fast(tok->pb, "\n", 1);
Packit ea8578
	else if(c == 'r') printbuf_memappend_fast(tok->pb, "\r", 1);
Packit ea8578
	else if(c == 't') printbuf_memappend_fast(tok->pb, "\t", 1);
Packit ea8578
	else if(c == 'f') printbuf_memappend_fast(tok->pb, "\f", 1);
Packit ea8578
	state = saved_state;
Packit ea8578
	break;
Packit ea8578
      case 'u':
Packit ea8578
	tok->ucs_char = 0;
Packit ea8578
	tok->st_pos = 0;
Packit ea8578
	state = json_tokener_state_escape_unicode;
Packit ea8578
	break;
Packit ea8578
      default:
Packit ea8578
	tok->err = json_tokener_error_parse_string;
Packit ea8578
	goto out;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_escape_unicode:
Packit ea8578
	{
Packit ea8578
          unsigned int got_hi_surrogate = 0;
Packit ea8578
Packit ea8578
	  /* Handle a 4-byte sequence, or two sequences if a surrogate pair */
Packit ea8578
	  while(1) {
Packit ea8578
	    if (c && strchr(json_hex_chars, c)) {
Packit ea8578
	      tok->ucs_char += ((unsigned int)jt_hexdigit(c) << ((3-tok->st_pos++)*4));
Packit ea8578
	      if(tok->st_pos == 4) {
Packit ea8578
		unsigned char unescaped_utf[4];
Packit ea8578
Packit ea8578
                if (got_hi_surrogate) {
Packit ea8578
		  if (IS_LOW_SURROGATE(tok->ucs_char)) {
Packit ea8578
                    /* Recalculate the ucs_char, then fall thru to process normally */
Packit ea8578
                    tok->ucs_char = DECODE_SURROGATE_PAIR(got_hi_surrogate, tok->ucs_char);
Packit ea8578
                  } else {
Packit ea8578
                    /* Hi surrogate was not followed by a low surrogate */
Packit ea8578
                    /* Replace the hi and process the rest normally */
Packit ea8578
		    printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
Packit ea8578
                  }
Packit ea8578
                  got_hi_surrogate = 0;
Packit ea8578
                }
Packit ea8578
Packit ea8578
		if (tok->ucs_char < 0x80) {
Packit ea8578
		  unescaped_utf[0] = tok->ucs_char;
Packit ea8578
		  printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1);
Packit ea8578
		} else if (tok->ucs_char < 0x800) {
Packit ea8578
		  unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6);
Packit ea8578
		  unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f);
Packit ea8578
		  printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 2);
Packit ea8578
		} else if (IS_HIGH_SURROGATE(tok->ucs_char)) {
Packit ea8578
                  /* Got a high surrogate.  Remember it and look for the
Packit ea8578
                   * the beginning of another sequence, which should be the
Packit ea8578
                   * low surrogate.
Packit ea8578
                   */
Packit ea8578
                  got_hi_surrogate = tok->ucs_char;
Packit ea8578
                  /* Not at end, and the next two chars should be "\u" */
Packit ea8578
                  if ((len == -1 || len > (tok->char_offset + 2)) &&
Packit ea8578
                      // str[0] != '0' &&  // implied by json_hex_chars, above.
Packit ea8578
                      (str[1] == '\\') &&
Packit ea8578
                      (str[2] == 'u'))
Packit ea8578
                  {
Packit ea8578
                /* Advance through the 16 bit surrogate, and move on to the
Packit ea8578
                 * next sequence. The next step is to process the following
Packit ea8578
                 * characters.
Packit ea8578
                 */
Packit ea8578
	            if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) {
Packit ea8578
                    printbuf_memappend_fast(tok->pb,
Packit ea8578
					    (char*) utf8_replacement_char, 3);
Packit ea8578
		    }
Packit ea8578
                    /* Advance to the first char of the next sequence and
Packit ea8578
                     * continue processing with the next sequence.
Packit ea8578
                     */
Packit ea8578
	            if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
Packit ea8578
	              printbuf_memappend_fast(tok->pb,
Packit ea8578
					      (char*) utf8_replacement_char, 3);
Packit ea8578
	              goto out;
Packit ea8578
                    }
Packit ea8578
	            tok->ucs_char = 0;
Packit ea8578
                    tok->st_pos = 0;
Packit ea8578
                    continue; /* other json_tokener_state_escape_unicode */
Packit ea8578
                  } else {
Packit ea8578
                    /* Got a high surrogate without another sequence following
Packit ea8578
                     * it.  Put a replacement char in for the hi surrogate
Packit ea8578
                     * and pretend we finished.
Packit ea8578
                     */
Packit ea8578
		    printbuf_memappend_fast(tok->pb,
Packit ea8578
					    (char*) utf8_replacement_char, 3);
Packit ea8578
                  }
Packit ea8578
		} else if (IS_LOW_SURROGATE(tok->ucs_char)) {
Packit ea8578
                  /* Got a low surrogate not preceded by a high */
Packit ea8578
		  printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
Packit ea8578
                } else if (tok->ucs_char < 0x10000) {
Packit ea8578
		  unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12);
Packit ea8578
		  unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
Packit ea8578
		  unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f);
Packit ea8578
		  printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 3);
Packit ea8578
		} else if (tok->ucs_char < 0x110000) {
Packit ea8578
		  unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07);
Packit ea8578
		  unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f);
Packit ea8578
		  unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
Packit ea8578
		  unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f);
Packit ea8578
		  printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 4);
Packit ea8578
		} else {
Packit ea8578
                  /* Don't know what we got--insert the replacement char */
Packit ea8578
		  printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
Packit ea8578
                }
Packit ea8578
		state = saved_state;
Packit ea8578
		break;
Packit ea8578
	      }
Packit ea8578
	    } else {
Packit ea8578
	      tok->err = json_tokener_error_parse_string;
Packit ea8578
	      goto out;
Packit ea8578
	    }
Packit ea8578
	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
Packit ea8578
            if (got_hi_surrogate) /* Clean up any pending chars */
Packit ea8578
	      printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
Packit ea8578
	    goto out;
Packit ea8578
	  }
Packit ea8578
	}
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_boolean:
Packit ea8578
      {
Packit ea8578
	int size1, size2;
Packit ea8578
	printbuf_memappend_fast(tok->pb, &c, 1);
Packit ea8578
	size1 = json_min(tok->st_pos+1, json_true_str_len);
Packit ea8578
	size2 = json_min(tok->st_pos+1, json_false_str_len);
Packit ea8578
	if((!(tok->flags & JSON_TOKENER_STRICT) &&
Packit ea8578
	  strncasecmp(json_true_str, tok->pb->buf, size1) == 0)
Packit ea8578
	  || (strncmp(json_true_str, tok->pb->buf, size1) == 0)
Packit ea8578
	  ) {
Packit ea8578
	  if(tok->st_pos == json_true_str_len) {
Packit ea8578
	    current = json_object_new_boolean(1);
Packit ea8578
	    if(current == NULL)
Packit ea8578
		goto out;
Packit ea8578
	    saved_state = json_tokener_state_finish;
Packit ea8578
	    state = json_tokener_state_eatws;
Packit ea8578
	    goto redo_char;
Packit ea8578
	  }
Packit ea8578
	} else if((!(tok->flags & JSON_TOKENER_STRICT) &&
Packit ea8578
	  strncasecmp(json_false_str, tok->pb->buf, size2) == 0)
Packit ea8578
	  || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) {
Packit ea8578
	  if(tok->st_pos == json_false_str_len) {
Packit ea8578
	    current = json_object_new_boolean(0);
Packit ea8578
	    if(current == NULL)
Packit ea8578
		goto out;
Packit ea8578
	    saved_state = json_tokener_state_finish;
Packit ea8578
	    state = json_tokener_state_eatws;
Packit ea8578
	    goto redo_char;
Packit ea8578
	  }
Packit ea8578
	} else {
Packit ea8578
	  tok->err = json_tokener_error_parse_boolean;
Packit ea8578
	  goto out;
Packit ea8578
	}
Packit ea8578
	tok->st_pos++;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_number:
Packit ea8578
      {
Packit ea8578
	/* Advance until we change state */
Packit ea8578
	const char *case_start = str;
Packit ea8578
	int case_len=0;
Packit ea8578
	int is_exponent=0;
Packit ea8578
	int negativesign_next_possible_location=1;
Packit ea8578
	while(c && strchr(json_number_chars, c)) {
Packit ea8578
	  ++case_len;
Packit ea8578
Packit ea8578
	  /* non-digit characters checks */
Packit ea8578
	  /* note: since the main loop condition to get here was
Packit ea8578
	           an input starting with 0-9 or '-', we are
Packit ea8578
	           protected from input starting with '.' or
Packit ea8578
	           e/E. */
Packit ea8578
	  if (c == '.') {
Packit ea8578
	    if (tok->is_double != 0) {
Packit ea8578
	      /* '.' can only be found once, and out of the exponent part.
Packit ea8578
	         Thus, if the input is already flagged as double, it
Packit ea8578
	         is invalid. */
Packit ea8578
	      tok->err = json_tokener_error_parse_number;
Packit ea8578
	      goto out;
Packit ea8578
	    }
Packit ea8578
	    tok->is_double = 1;
Packit ea8578
	  }
Packit ea8578
	  if (c == 'e' || c == 'E') {
Packit ea8578
	    if (is_exponent != 0) {
Packit ea8578
	      /* only one exponent possible */
Packit ea8578
	      tok->err = json_tokener_error_parse_number;
Packit ea8578
	      goto out;
Packit ea8578
	    }
Packit ea8578
	    is_exponent = 1;
Packit ea8578
	    tok->is_double = 1;
Packit ea8578
	    /* the exponent part can begin with a negative sign */
Packit ea8578
	    negativesign_next_possible_location = case_len + 1;
Packit ea8578
	  }
Packit ea8578
	  if (c == '-' && case_len != negativesign_next_possible_location) {
Packit ea8578
	    /* If the negative sign is not where expected (ie
Packit ea8578
	       start of input or start of exponent part), the
Packit ea8578
	       input is invalid. */
Packit ea8578
	    tok->err = json_tokener_error_parse_number;
Packit ea8578
	    goto out;
Packit ea8578
	  }
Packit ea8578
Packit ea8578
	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
Packit ea8578
	    printbuf_memappend_fast(tok->pb, case_start, case_len);
Packit ea8578
	    goto out;
Packit ea8578
	  }
Packit ea8578
	}
Packit ea8578
        if (case_len>0)
Packit ea8578
          printbuf_memappend_fast(tok->pb, case_start, case_len);
Packit ea8578
Packit ea8578
	// Check for -Infinity
Packit ea8578
	if (tok->pb->buf[0] == '-' && case_len <= 1 &&
Packit ea8578
	    (c == 'i' || c == 'I'))
Packit ea8578
	{
Packit ea8578
		state = json_tokener_state_inf;
Packit ea8578
		tok->st_pos = 0;
Packit ea8578
		goto redo_char;
Packit ea8578
	}
Packit ea8578
      }
Packit ea8578
      {
Packit ea8578
	int64_t num64;
Packit ea8578
	double  numd;
Packit ea8578
	if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) {
Packit ea8578
		if (num64 && tok->pb->buf[0]=='0' &&
Packit ea8578
		    (tok->flags & JSON_TOKENER_STRICT)) {
Packit ea8578
			/* in strict mode, number must not start with 0 */
Packit ea8578
			tok->err = json_tokener_error_parse_number;
Packit ea8578
			goto out;
Packit ea8578
		}
Packit ea8578
		current = json_object_new_int64(num64);
Packit ea8578
		if(current == NULL)
Packit ea8578
		    goto out;
Packit ea8578
	}
Packit ea8578
	else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0)
Packit ea8578
	{
Packit ea8578
          current = json_object_new_double_s(numd, tok->pb->buf);
Packit ea8578
	  if(current == NULL)
Packit ea8578
		goto out;
Packit ea8578
        } else {
Packit ea8578
          tok->err = json_tokener_error_parse_number;
Packit ea8578
          goto out;
Packit ea8578
        }
Packit ea8578
        saved_state = json_tokener_state_finish;
Packit ea8578
        state = json_tokener_state_eatws;
Packit ea8578
        goto redo_char;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_array_after_sep:
Packit ea8578
    case json_tokener_state_array:
Packit ea8578
      if(c == ']') {
Packit ea8578
	if (state == json_tokener_state_array_after_sep &&
Packit ea8578
	    (tok->flags & JSON_TOKENER_STRICT))
Packit ea8578
	  {
Packit ea8578
	    tok->err = json_tokener_error_parse_unexpected;
Packit ea8578
	    goto out;
Packit ea8578
	  }
Packit ea8578
	saved_state = json_tokener_state_finish;
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      } else {
Packit ea8578
	if(tok->depth >= tok->max_depth-1) {
Packit ea8578
	  tok->err = json_tokener_error_depth;
Packit ea8578
	  goto out;
Packit ea8578
	}
Packit ea8578
	state = json_tokener_state_array_add;
Packit ea8578
	tok->depth++;
Packit ea8578
	json_tokener_reset_level(tok, tok->depth);
Packit ea8578
	goto redo_char;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_array_add:
Packit ea8578
      if( json_object_array_add(current, obj) != 0 )
Packit ea8578
        goto out;
Packit ea8578
      saved_state = json_tokener_state_array_sep;
Packit ea8578
      state = json_tokener_state_eatws;
Packit ea8578
      goto redo_char;
Packit ea8578
Packit ea8578
    case json_tokener_state_array_sep:
Packit ea8578
      if(c == ']') {
Packit ea8578
	saved_state = json_tokener_state_finish;
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      } else if(c == ',') {
Packit ea8578
	saved_state = json_tokener_state_array_after_sep;
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      } else {
Packit ea8578
	tok->err = json_tokener_error_parse_array;
Packit ea8578
	goto out;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_object_field_start:
Packit ea8578
    case json_tokener_state_object_field_start_after_sep:
Packit ea8578
      if(c == '}') {
Packit ea8578
		if (state == json_tokener_state_object_field_start_after_sep &&
Packit ea8578
		    (tok->flags & JSON_TOKENER_STRICT))
Packit ea8578
		{
Packit ea8578
			tok->err = json_tokener_error_parse_unexpected;
Packit ea8578
			goto out;
Packit ea8578
		}
Packit ea8578
	saved_state = json_tokener_state_finish;
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      } else if (c == '"' || c == '\'') {
Packit ea8578
	tok->quote_char = c;
Packit ea8578
	printbuf_reset(tok->pb);
Packit ea8578
	state = json_tokener_state_object_field;
Packit ea8578
      } else {
Packit ea8578
	tok->err = json_tokener_error_parse_object_key_name;
Packit ea8578
	goto out;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_object_field:
Packit ea8578
      {
Packit ea8578
	/* Advance until we change state */
Packit ea8578
	const char *case_start = str;
Packit ea8578
	while(1) {
Packit ea8578
	  if(c == tok->quote_char) {
Packit ea8578
	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
	    obj_field_name = strdup(tok->pb->buf);
Packit ea8578
	    saved_state = json_tokener_state_object_field_end;
Packit ea8578
	    state = json_tokener_state_eatws;
Packit ea8578
	    break;
Packit ea8578
	  } else if(c == '\\') {
Packit ea8578
	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
	    saved_state = json_tokener_state_object_field;
Packit ea8578
	    state = json_tokener_state_string_escape;
Packit ea8578
	    break;
Packit ea8578
	  }
Packit ea8578
	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
Packit ea8578
	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
Packit ea8578
	    goto out;
Packit ea8578
	  }
Packit ea8578
	}
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_object_field_end:
Packit ea8578
      if(c == ':') {
Packit ea8578
	saved_state = json_tokener_state_object_value;
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      } else {
Packit ea8578
	tok->err = json_tokener_error_parse_object_key_sep;
Packit ea8578
	goto out;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    case json_tokener_state_object_value:
Packit ea8578
      if(tok->depth >= tok->max_depth-1) {
Packit ea8578
	tok->err = json_tokener_error_depth;
Packit ea8578
	goto out;
Packit ea8578
      }
Packit ea8578
      state = json_tokener_state_object_value_add;
Packit ea8578
      tok->depth++;
Packit ea8578
      json_tokener_reset_level(tok, tok->depth);
Packit ea8578
      goto redo_char;
Packit ea8578
Packit ea8578
    case json_tokener_state_object_value_add:
Packit ea8578
      json_object_object_add(current, obj_field_name, obj);
Packit ea8578
      free(obj_field_name);
Packit ea8578
      obj_field_name = NULL;
Packit ea8578
      saved_state = json_tokener_state_object_sep;
Packit ea8578
      state = json_tokener_state_eatws;
Packit ea8578
      goto redo_char;
Packit ea8578
Packit ea8578
    case json_tokener_state_object_sep:
Packit ea8578
      /* { */
Packit ea8578
      if(c == '}') {
Packit ea8578
	saved_state = json_tokener_state_finish;
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      } else if(c == ',') {
Packit ea8578
	saved_state = json_tokener_state_object_field_start_after_sep;
Packit ea8578
	state = json_tokener_state_eatws;
Packit ea8578
      } else {
Packit ea8578
	tok->err = json_tokener_error_parse_object_value_sep;
Packit ea8578
	goto out;
Packit ea8578
      }
Packit ea8578
      break;
Packit ea8578
Packit ea8578
    }
Packit ea8578
    if (!ADVANCE_CHAR(str, tok))
Packit ea8578
      goto out;
Packit ea8578
  } /* while(PEEK_CHAR) */
Packit ea8578
Packit ea8578
 out:
Packit ea8578
  if (c &&
Packit ea8578
     (state == json_tokener_state_finish) &&
Packit ea8578
     (tok->depth == 0) &&
Packit ea8578
     (tok->flags & JSON_TOKENER_STRICT)) {
Packit ea8578
      /* unexpected char after JSON data */
Packit ea8578
      tok->err = json_tokener_error_parse_unexpected;
Packit ea8578
  }
Packit ea8578
  if (!c) { /* We hit an eof char (0) */
Packit ea8578
    if(state != json_tokener_state_finish &&
Packit ea8578
       saved_state != json_tokener_state_finish)
Packit ea8578
      tok->err = json_tokener_error_parse_eof;
Packit ea8578
  }
Packit ea8578
Packit ea8578
#ifdef HAVE_USELOCALE
Packit ea8578
  uselocale(oldlocale);
Packit ea8578
  freelocale(newloc); 
Packit ea8578
#elif defined(HAVE_SETLOCALE)
Packit ea8578
  setlocale(LC_NUMERIC, oldlocale);
Packit ea8578
  free(oldlocale);
Packit ea8578
#endif
Packit ea8578
Packit ea8578
  if (tok->err == json_tokener_success)
Packit ea8578
  {
Packit ea8578
    json_object *ret = json_object_get(current);
Packit ea8578
	int ii;
Packit ea8578
Packit ea8578
	/* Partially reset, so we parse additional objects on subsequent calls. */
Packit ea8578
    for(ii = tok->depth; ii >= 0; ii--)
Packit ea8578
      json_tokener_reset_level(tok, ii);
Packit ea8578
    return ret;
Packit ea8578
  }
Packit ea8578
Packit ea8578
  MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n",
Packit ea8578
	   json_tokener_errors[tok->err], tok->char_offset);
Packit ea8578
  return NULL;
Packit ea8578
}
Packit ea8578
Packit ea8578
void json_tokener_set_flags(struct json_tokener *tok, int flags)
Packit ea8578
{
Packit ea8578
	tok->flags = flags;
Packit ea8578
}