Blame src/json.cpp

Packit bfcc33
/*
Packit bfcc33
  Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
Packit bfcc33
  All rights reserved.
Packit bfcc33
Packit bfcc33
  Permission is hereby granted, free of charge, to any person obtaining a copy
Packit bfcc33
  of this software and associated documentation files (the "Software"), to deal
Packit bfcc33
  in the Software without restriction, including without limitation the rights
Packit bfcc33
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Packit bfcc33
  copies of the Software, and to permit persons to whom the Software is
Packit bfcc33
  furnished to do so, subject to the following conditions:
Packit bfcc33
Packit bfcc33
  The above copyright notice and this permission notice shall be included in
Packit bfcc33
  all copies or substantial portions of the Software.
Packit bfcc33
Packit bfcc33
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit bfcc33
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit bfcc33
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit bfcc33
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit bfcc33
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Packit bfcc33
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Packit bfcc33
  THE SOFTWARE.
Packit bfcc33
*/
Packit bfcc33
Packit bfcc33
#ifdef _MSC_VER
Packit bfcc33
#define _CRT_SECURE_NO_WARNINGS
Packit bfcc33
#define _CRT_NONSTDC_NO_DEPRECATE
Packit bfcc33
#endif
Packit bfcc33
Packit bfcc33
#include "json.hpp"
Packit bfcc33
Packit bfcc33
// include utf8 library used by libsass
Packit bfcc33
// ToDo: replace internal json utf8 code
Packit bfcc33
#include "utf8.h"
Packit bfcc33
Packit bfcc33
#include <assert.h>
Packit bfcc33
#include <stdint.h>
Packit bfcc33
#include <stdio.h>
Packit bfcc33
#include <stdlib.h>
Packit bfcc33
#include <string.h>
Packit bfcc33
Packit bfcc33
#if defined(_MSC_VER) && _MSC_VER < 1900
Packit bfcc33
#include <stdarg.h>
Packit bfcc33
#ifdef snprintf
Packit bfcc33
#undef snprintf
Packit bfcc33
#endif
Packit bfcc33
extern "C" int snprintf(char *, size_t, const char *, ...);
Packit bfcc33
#endif
Packit bfcc33
Packit bfcc33
#define out_of_memory() do {                    \
Packit bfcc33
    fprintf(stderr, "Out of memory.\n");    \
Packit bfcc33
    exit(EXIT_FAILURE);                     \
Packit bfcc33
  } while (0)
Packit bfcc33
Packit bfcc33
/* Sadly, strdup is not portable. */
Packit bfcc33
static char *json_strdup(const char *str)
Packit bfcc33
{
Packit bfcc33
  char *ret = (char*) malloc(strlen(str) + 1);
Packit bfcc33
  if (ret == NULL)
Packit bfcc33
    out_of_memory();
Packit bfcc33
  strcpy(ret, str);
Packit bfcc33
  return ret;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/* String buffer */
Packit bfcc33
Packit bfcc33
typedef struct
Packit bfcc33
{
Packit bfcc33
  char *cur;
Packit bfcc33
  char *end;
Packit bfcc33
  char *start;
Packit bfcc33
} SB;
Packit bfcc33
Packit bfcc33
static void sb_init(SB *sb)
Packit bfcc33
{
Packit bfcc33
  sb->start = (char*) malloc(17);
Packit bfcc33
  if (sb->start == NULL)
Packit bfcc33
    out_of_memory();
Packit bfcc33
  sb->cur = sb->start;
Packit bfcc33
  sb->end = sb->start + 16;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/* sb and need may be evaluated multiple times. */
Packit bfcc33
#define sb_need(sb, need) do {                  \
Packit bfcc33
    if ((sb)->end - (sb)->cur < (need))     \
Packit bfcc33
      sb_grow(sb, need);                  \
Packit bfcc33
  } while (0)
Packit bfcc33
Packit bfcc33
static void sb_grow(SB *sb, int need)
Packit bfcc33
{
Packit bfcc33
  size_t length = sb->cur - sb->start;
Packit bfcc33
  size_t alloc = sb->end - sb->start;
Packit bfcc33
Packit bfcc33
  do {
Packit bfcc33
    alloc *= 2;
Packit bfcc33
  } while (alloc < length + need);
Packit bfcc33
Packit bfcc33
  sb->start = (char*) realloc(sb->start, alloc + 1);
Packit bfcc33
  if (sb->start == NULL)
Packit bfcc33
    out_of_memory();
Packit bfcc33
  sb->cur = sb->start + length;
Packit bfcc33
  sb->end = sb->start + alloc;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void sb_put(SB *sb, const char *bytes, int count)
Packit bfcc33
{
Packit bfcc33
  sb_need(sb, count);
Packit bfcc33
  memcpy(sb->cur, bytes, count);
Packit bfcc33
  sb->cur += count;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
#define sb_putc(sb, c) do {         \
Packit bfcc33
    if ((sb)->cur >= (sb)->end) \
Packit bfcc33
      sb_grow(sb, 1);         \
Packit bfcc33
    *(sb)->cur++ = (c);         \
Packit bfcc33
  } while (0)
Packit bfcc33
Packit bfcc33
static void sb_puts(SB *sb, const char *str)
Packit bfcc33
{
Packit bfcc33
  sb_put(sb, str, (int)strlen(str));
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static char *sb_finish(SB *sb)
Packit bfcc33
{
Packit bfcc33
  *sb->cur = 0;
Packit bfcc33
  assert(sb->start <= sb->cur && strlen(sb->start) == (size_t)(sb->cur - sb->start));
Packit bfcc33
  return sb->start;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void sb_free(SB *sb)
Packit bfcc33
{
Packit bfcc33
  free(sb->start);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * Unicode helper functions
Packit bfcc33
 *
Packit bfcc33
 * These are taken from the ccan/charset module and customized a bit.
Packit bfcc33
 * Putting them here means the compiler can (choose to) inline them,
Packit bfcc33
 * and it keeps ccan/json from having a dependency.
Packit bfcc33
 *
Packit bfcc33
 * We use uint32_t Type for Unicode codepoints.
Packit bfcc33
 * We need our own because wchar_t might be 16 bits.
Packit bfcc33
 */
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * Validate a single UTF-8 character starting at @s.
Packit bfcc33
 * The string must be null-terminated.
Packit bfcc33
 *
Packit bfcc33
 * If it's valid, return its length (1 thru 4).
Packit bfcc33
 * If it's invalid or clipped, return 0.
Packit bfcc33
 *
Packit bfcc33
 * This function implements the syntax given in RFC3629, which is
Packit bfcc33
 * the same as that given in The Unicode Standard, Version 6.0.
Packit bfcc33
 *
Packit bfcc33
 * It has the following properties:
Packit bfcc33
 *
Packit bfcc33
 *  * All codepoints U+0000..U+10FFFF may be encoded,
Packit bfcc33
 *    except for U+D800..U+DFFF, which are reserved
Packit bfcc33
 *    for UTF-16 surrogate pair encoding.
Packit bfcc33
 *  * UTF-8 byte sequences longer than 4 bytes are not permitted,
Packit bfcc33
 *    as they exceed the range of Unicode.
Packit bfcc33
 *  * The sixty-six Unicode "non-characters" are permitted
Packit bfcc33
 *    (namely, U+FDD0..U+FDEF, U+xxFFFE, and U+xxFFFF).
Packit bfcc33
 */
Packit bfcc33
static int utf8_validate_cz(const char *s)
Packit bfcc33
{
Packit bfcc33
  unsigned char c = *s++;
Packit bfcc33
Packit bfcc33
  if (c <= 0x7F) {        /* 00..7F */
Packit bfcc33
    return 1;
Packit bfcc33
  } else if (c <= 0xC1) { /* 80..C1 */
Packit bfcc33
    /* Disallow overlong 2-byte sequence. */
Packit bfcc33
    return 0;
Packit bfcc33
  } else if (c <= 0xDF) { /* C2..DF */
Packit bfcc33
    /* Make sure subsequent byte is in the range 0x80..0xBF. */
Packit bfcc33
    if (((unsigned char)*s++ & 0xC0) != 0x80)
Packit bfcc33
      return 0;
Packit bfcc33
Packit bfcc33
    return 2;
Packit bfcc33
  } else if (c <= 0xEF) { /* E0..EF */
Packit bfcc33
    /* Disallow overlong 3-byte sequence. */
Packit bfcc33
    if (c == 0xE0 && (unsigned char)*s < 0xA0)
Packit bfcc33
      return 0;
Packit bfcc33
Packit bfcc33
    /* Disallow U+D800..U+DFFF. */
Packit bfcc33
    if (c == 0xED && (unsigned char)*s > 0x9F)
Packit bfcc33
      return 0;
Packit bfcc33
Packit bfcc33
    /* Make sure subsequent bytes are in the range 0x80..0xBF. */
Packit bfcc33
    if (((unsigned char)*s++ & 0xC0) != 0x80)
Packit bfcc33
      return 0;
Packit bfcc33
    if (((unsigned char)*s++ & 0xC0) != 0x80)
Packit bfcc33
      return 0;
Packit bfcc33
Packit bfcc33
    return 3;
Packit bfcc33
  } else if (c <= 0xF4) { /* F0..F4 */
Packit bfcc33
    /* Disallow overlong 4-byte sequence. */
Packit bfcc33
    if (c == 0xF0 && (unsigned char)*s < 0x90)
Packit bfcc33
      return 0;
Packit bfcc33
Packit bfcc33
    /* Disallow codepoints beyond U+10FFFF. */
Packit bfcc33
    if (c == 0xF4 && (unsigned char)*s > 0x8F)
Packit bfcc33
      return 0;
Packit bfcc33
Packit bfcc33
    /* Make sure subsequent bytes are in the range 0x80..0xBF. */
Packit bfcc33
    if (((unsigned char)*s++ & 0xC0) != 0x80)
Packit bfcc33
      return 0;
Packit bfcc33
    if (((unsigned char)*s++ & 0xC0) != 0x80)
Packit bfcc33
      return 0;
Packit bfcc33
    if (((unsigned char)*s++ & 0xC0) != 0x80)
Packit bfcc33
      return 0;
Packit bfcc33
Packit bfcc33
    return 4;
Packit bfcc33
  } else {                /* F5..FF */
Packit bfcc33
    return 0;
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/* Validate a null-terminated UTF-8 string. */
Packit bfcc33
static bool utf8_validate(const char *s)
Packit bfcc33
{
Packit bfcc33
  int len;
Packit bfcc33
Packit bfcc33
  for (; *s != 0; s += len) {
Packit bfcc33
    len = utf8_validate_cz(s);
Packit bfcc33
    if (len == 0)
Packit bfcc33
      return false;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  return true;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * Read a single UTF-8 character starting at @s,
Packit bfcc33
 * returning the length, in bytes, of the character read.
Packit bfcc33
 *
Packit bfcc33
 * This function assumes input is valid UTF-8,
Packit bfcc33
 * and that there are enough characters in front of @s.
Packit bfcc33
 */
Packit bfcc33
static int utf8_read_char(const char *s, uint32_t *out)
Packit bfcc33
{
Packit bfcc33
  const unsigned char *c = (const unsigned char*) s;
Packit bfcc33
Packit bfcc33
  assert(utf8_validate_cz(s));
Packit bfcc33
Packit bfcc33
  if (c[0] <= 0x7F) {
Packit bfcc33
    /* 00..7F */
Packit bfcc33
    *out = c[0];
Packit bfcc33
    return 1;
Packit bfcc33
  } else if (c[0] <= 0xDF) {
Packit bfcc33
    /* C2..DF (unless input is invalid) */
Packit bfcc33
    *out = ((uint32_t)c[0] & 0x1F) << 6 |
Packit bfcc33
           ((uint32_t)c[1] & 0x3F);
Packit bfcc33
    return 2;
Packit bfcc33
  } else if (c[0] <= 0xEF) {
Packit bfcc33
    /* E0..EF */
Packit bfcc33
    *out = ((uint32_t)c[0] &  0xF) << 12 |
Packit bfcc33
           ((uint32_t)c[1] & 0x3F) << 6  |
Packit bfcc33
           ((uint32_t)c[2] & 0x3F);
Packit bfcc33
    return 3;
Packit bfcc33
  } else {
Packit bfcc33
    /* F0..F4 (unless input is invalid) */
Packit bfcc33
    *out = ((uint32_t)c[0] &  0x7) << 18 |
Packit bfcc33
           ((uint32_t)c[1] & 0x3F) << 12 |
Packit bfcc33
           ((uint32_t)c[2] & 0x3F) << 6  |
Packit bfcc33
           ((uint32_t)c[3] & 0x3F);
Packit bfcc33
    return 4;
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * Write a single UTF-8 character to @s,
Packit bfcc33
 * returning the length, in bytes, of the character written.
Packit bfcc33
 *
Packit bfcc33
 * @unicode must be U+0000..U+10FFFF, but not U+D800..U+DFFF.
Packit bfcc33
 *
Packit bfcc33
 * This function will write up to 4 bytes to @out.
Packit bfcc33
 */
Packit bfcc33
static int utf8_write_char(uint32_t unicode, char *out)
Packit bfcc33
{
Packit bfcc33
  unsigned char *o = (unsigned char*) out;
Packit bfcc33
Packit bfcc33
  assert(unicode <= 0x10FFFF && !(unicode >= 0xD800 && unicode <= 0xDFFF));
Packit bfcc33
Packit bfcc33
  if (unicode <= 0x7F) {
Packit bfcc33
    /* U+0000..U+007F */
Packit bfcc33
    *o++ = unicode;
Packit bfcc33
    return 1;
Packit bfcc33
  } else if (unicode <= 0x7FF) {
Packit bfcc33
    /* U+0080..U+07FF */
Packit bfcc33
    *o++ = 0xC0 | unicode >> 6;
Packit bfcc33
    *o++ = 0x80 | (unicode & 0x3F);
Packit bfcc33
    return 2;
Packit bfcc33
  } else if (unicode <= 0xFFFF) {
Packit bfcc33
    /* U+0800..U+FFFF */
Packit bfcc33
    *o++ = 0xE0 | unicode >> 12;
Packit bfcc33
    *o++ = 0x80 | (unicode >> 6 & 0x3F);
Packit bfcc33
    *o++ = 0x80 | (unicode & 0x3F);
Packit bfcc33
    return 3;
Packit bfcc33
  } else {
Packit bfcc33
    /* U+10000..U+10FFFF */
Packit bfcc33
    *o++ = 0xF0 | unicode >> 18;
Packit bfcc33
    *o++ = 0x80 | (unicode >> 12 & 0x3F);
Packit bfcc33
    *o++ = 0x80 | (unicode >> 6 & 0x3F);
Packit bfcc33
    *o++ = 0x80 | (unicode & 0x3F);
Packit bfcc33
    return 4;
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * Compute the Unicode codepoint of a UTF-16 surrogate pair.
Packit bfcc33
 *
Packit bfcc33
 * @uc should be 0xD800..0xDBFF, and @lc should be 0xDC00..0xDFFF.
Packit bfcc33
 * If they aren't, this function returns false.
Packit bfcc33
 */
Packit bfcc33
static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uint32_t *unicode)
Packit bfcc33
{
Packit bfcc33
  if (uc >= 0xD800 && uc <= 0xDBFF && lc >= 0xDC00 && lc <= 0xDFFF) {
Packit bfcc33
    *unicode = 0x10000 + ((((uint32_t)uc & 0x3FF) << 10) | (lc & 0x3FF));
Packit bfcc33
    return true;
Packit bfcc33
  } else {
Packit bfcc33
    return false;
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * Construct a UTF-16 surrogate pair given a Unicode codepoint.
Packit bfcc33
 *
Packit bfcc33
 * @unicode must be U+10000..U+10FFFF.
Packit bfcc33
 */
Packit bfcc33
static void to_surrogate_pair(uint32_t unicode, uint16_t *uc, uint16_t *lc)
Packit bfcc33
{
Packit bfcc33
  uint32_t n;
Packit bfcc33
Packit bfcc33
  assert(unicode >= 0x10000 && unicode <= 0x10FFFF);
Packit bfcc33
Packit bfcc33
  n = unicode - 0x10000;
Packit bfcc33
  *uc = ((n >> 10) & 0x3FF) | 0xD800;
Packit bfcc33
  *lc = (n & 0x3FF) | 0xDC00;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static bool is_space        (const char *c);
Packit bfcc33
static bool is_digit        (const char *c);
Packit bfcc33
static bool parse_value     (const char **sp, JsonNode        **out);
Packit bfcc33
static bool parse_string    (const char **sp, char            **out);
Packit bfcc33
static bool parse_number    (const char **sp, double           *out);
Packit bfcc33
static bool parse_array     (const char **sp, JsonNode        **out);
Packit bfcc33
static bool parse_object    (const char **sp, JsonNode        **out);
Packit bfcc33
static bool parse_hex16     (const char **sp, uint16_t         *out);
Packit bfcc33
Packit bfcc33
static bool expect_literal  (const char **sp, const char *str);
Packit bfcc33
static void skip_space      (const char **sp);
Packit bfcc33
Packit bfcc33
static void emit_value              (SB *out, const JsonNode *node);
Packit bfcc33
static void emit_value_indented     (SB *out, const JsonNode *node, const char *space, int indent_level);
Packit bfcc33
static void emit_string             (SB *out, const char *str);
Packit bfcc33
static void emit_number             (SB *out, double num);
Packit bfcc33
static void emit_array              (SB *out, const JsonNode *array);
Packit bfcc33
static void emit_array_indented     (SB *out, const JsonNode *array, const char *space, int indent_level);
Packit bfcc33
static void emit_object             (SB *out, const JsonNode *object);
Packit bfcc33
static void emit_object_indented    (SB *out, const JsonNode *object, const char *space, int indent_level);
Packit bfcc33
Packit bfcc33
static int write_hex16(char *out, uint16_t val);
Packit bfcc33
Packit bfcc33
static JsonNode *mknode(JsonTag tag);
Packit bfcc33
static void append_node(JsonNode *parent, JsonNode *child);
Packit bfcc33
static void prepend_node(JsonNode *parent, JsonNode *child);
Packit bfcc33
static void append_member(JsonNode *object, char *key, JsonNode *value);
Packit bfcc33
Packit bfcc33
/* Assertion-friendly validity checks */
Packit bfcc33
static bool tag_is_valid(unsigned int tag);
Packit bfcc33
static bool number_is_valid(const char *num);
Packit bfcc33
Packit bfcc33
JsonNode *json_decode(const char *json)
Packit bfcc33
{
Packit bfcc33
  const char *s = json;
Packit bfcc33
  JsonNode *ret;
Packit bfcc33
Packit bfcc33
  skip_space(&s);
Packit bfcc33
  if (!parse_value(&s, &ret))
Packit bfcc33
    return NULL;
Packit bfcc33
Packit bfcc33
  skip_space(&s);
Packit bfcc33
  if (*s != 0) {
Packit bfcc33
    json_delete(ret);
Packit bfcc33
    return NULL;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  return ret;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
char *json_encode(const JsonNode *node)
Packit bfcc33
{
Packit bfcc33
  return json_stringify(node, NULL);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
char *json_encode_string(const char *str)
Packit bfcc33
{
Packit bfcc33
  SB sb;
Packit bfcc33
  sb_init(&sb);
Packit bfcc33
Packit bfcc33
  try {
Packit bfcc33
    emit_string(&sb, str);
Packit bfcc33
  }
Packit bfcc33
  catch (std::exception) {
Packit bfcc33
    sb_free(&sb);
Packit bfcc33
    throw;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  return sb_finish(&sb);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
char *json_stringify(const JsonNode *node, const char *space)
Packit bfcc33
{
Packit bfcc33
  SB sb;
Packit bfcc33
  sb_init(&sb);
Packit bfcc33
Packit bfcc33
  try {
Packit bfcc33
    if (space != NULL)
Packit bfcc33
      emit_value_indented(&sb, node, space, 0);
Packit bfcc33
    else
Packit bfcc33
      emit_value(&sb, node);
Packit bfcc33
  }
Packit bfcc33
  catch (std::exception) {
Packit bfcc33
    sb_free(&sb);
Packit bfcc33
    throw;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  return sb_finish(&sb);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
void json_delete(JsonNode *node)
Packit bfcc33
{
Packit bfcc33
  if (node != NULL) {
Packit bfcc33
    json_remove_from_parent(node);
Packit bfcc33
Packit bfcc33
    switch (node->tag) {
Packit bfcc33
      case JSON_STRING:
Packit bfcc33
        free(node->string_);
Packit bfcc33
        break;
Packit bfcc33
      case JSON_ARRAY:
Packit bfcc33
      case JSON_OBJECT:
Packit bfcc33
      {
Packit bfcc33
        JsonNode *child, *next;
Packit bfcc33
        for (child = node->children.head; child != NULL; child = next) {
Packit bfcc33
          next = child->next;
Packit bfcc33
          json_delete(child);
Packit bfcc33
        }
Packit bfcc33
        break;
Packit bfcc33
      }
Packit bfcc33
      default:;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    free(node);
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
bool json_validate(const char *json)
Packit bfcc33
{
Packit bfcc33
  const char *s = json;
Packit bfcc33
Packit bfcc33
  skip_space(&s);
Packit bfcc33
  if (!parse_value(&s, NULL))
Packit bfcc33
    return false;
Packit bfcc33
Packit bfcc33
  skip_space(&s);
Packit bfcc33
  if (*s != 0)
Packit bfcc33
    return false;
Packit bfcc33
Packit bfcc33
  return true;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_find_element(JsonNode *array, int index)
Packit bfcc33
{
Packit bfcc33
  JsonNode *element;
Packit bfcc33
  int i = 0;
Packit bfcc33
Packit bfcc33
  if (array == NULL || array->tag != JSON_ARRAY)
Packit bfcc33
    return NULL;
Packit bfcc33
Packit bfcc33
  json_foreach(element, array) {
Packit bfcc33
    if (i == index)
Packit bfcc33
      return element;
Packit bfcc33
    i++;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  return NULL;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_find_member(JsonNode *object, const char *name)
Packit bfcc33
{
Packit bfcc33
  JsonNode *member;
Packit bfcc33
Packit bfcc33
  if (object == NULL || object->tag != JSON_OBJECT)
Packit bfcc33
    return NULL;
Packit bfcc33
Packit bfcc33
  json_foreach(member, object)
Packit bfcc33
    if (strcmp(member->key, name) == 0)
Packit bfcc33
      return member;
Packit bfcc33
Packit bfcc33
  return NULL;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_first_child(const JsonNode *node)
Packit bfcc33
{
Packit bfcc33
  if (node != NULL && (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT))
Packit bfcc33
    return node->children.head;
Packit bfcc33
  return NULL;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static JsonNode *mknode(JsonTag tag)
Packit bfcc33
{
Packit bfcc33
  JsonNode *ret = (JsonNode*) calloc(1, sizeof(JsonNode));
Packit bfcc33
  if (ret == NULL)
Packit bfcc33
    out_of_memory();
Packit bfcc33
  ret->tag = tag;
Packit bfcc33
  return ret;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_mknull(void)
Packit bfcc33
{
Packit bfcc33
  return mknode(JSON_NULL);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_mkbool(bool b)
Packit bfcc33
{
Packit bfcc33
  JsonNode *ret = mknode(JSON_BOOL);
Packit bfcc33
  ret->bool_ = b;
Packit bfcc33
  return ret;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static JsonNode *mkstring(char *s)
Packit bfcc33
{
Packit bfcc33
  JsonNode *ret = mknode(JSON_STRING);
Packit bfcc33
  ret->string_ = s;
Packit bfcc33
  return ret;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_mkstring(const char *s)
Packit bfcc33
{
Packit bfcc33
  return mkstring(json_strdup(s));
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_mknumber(double n)
Packit bfcc33
{
Packit bfcc33
  JsonNode *node = mknode(JSON_NUMBER);
Packit bfcc33
  node->number_ = n;
Packit bfcc33
  return node;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_mkarray(void)
Packit bfcc33
{
Packit bfcc33
  return mknode(JSON_ARRAY);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
JsonNode *json_mkobject(void)
Packit bfcc33
{
Packit bfcc33
  return mknode(JSON_OBJECT);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void append_node(JsonNode *parent, JsonNode *child)
Packit bfcc33
{
Packit bfcc33
  if (child != NULL && parent != NULL) {
Packit bfcc33
      child->parent = parent;
Packit bfcc33
      child->prev = parent->children.tail;
Packit bfcc33
      child->next = NULL;
Packit bfcc33
Packit bfcc33
      if (parent->children.tail != NULL)
Packit bfcc33
          parent->children.tail->next = child;
Packit bfcc33
      else
Packit bfcc33
          parent->children.head = child;
Packit bfcc33
      parent->children.tail = child;
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void prepend_node(JsonNode *parent, JsonNode *child)
Packit bfcc33
{
Packit bfcc33
  if (child != NULL && parent != NULL) {
Packit bfcc33
      child->parent = parent;
Packit bfcc33
      child->prev = NULL;
Packit bfcc33
      child->next = parent->children.head;
Packit bfcc33
Packit bfcc33
      if (parent->children.head != NULL)
Packit bfcc33
          parent->children.head->prev = child;
Packit bfcc33
      else
Packit bfcc33
          parent->children.tail = child;
Packit bfcc33
      parent->children.head = child;
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void append_member(JsonNode *object, char *key, JsonNode *value)
Packit bfcc33
{
Packit bfcc33
  if (value != NULL && object != NULL) {
Packit bfcc33
      value->key = key;
Packit bfcc33
      append_node(object, value);
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
void json_append_element(JsonNode *array, JsonNode *element)
Packit bfcc33
{
Packit bfcc33
  if (array != NULL && element !=NULL) {
Packit bfcc33
      assert(array->tag == JSON_ARRAY);
Packit bfcc33
      assert(element->parent == NULL);
Packit bfcc33
Packit bfcc33
      append_node(array, element);
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
void json_prepend_element(JsonNode *array, JsonNode *element)
Packit bfcc33
{
Packit bfcc33
  assert(array->tag == JSON_ARRAY);
Packit bfcc33
  assert(element->parent == NULL);
Packit bfcc33
Packit bfcc33
  prepend_node(array, element);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
void json_append_member(JsonNode *object, const char *key, JsonNode *value)
Packit bfcc33
{
Packit bfcc33
  if (object != NULL && key != NULL && value != NULL) {
Packit bfcc33
      assert(object->tag == JSON_OBJECT);
Packit bfcc33
      assert(value->parent == NULL);
Packit bfcc33
Packit bfcc33
      append_member(object, json_strdup(key), value);
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
void json_prepend_member(JsonNode *object, const char *key, JsonNode *value)
Packit bfcc33
{
Packit bfcc33
  if (object != NULL && key != NULL && value != NULL) {
Packit bfcc33
      assert(object->tag == JSON_OBJECT);
Packit bfcc33
      assert(value->parent == NULL);
Packit bfcc33
Packit bfcc33
      value->key = json_strdup(key);
Packit bfcc33
      prepend_node(object, value);
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
void json_remove_from_parent(JsonNode *node)
Packit bfcc33
{
Packit bfcc33
  if (node != NULL) {
Packit bfcc33
      JsonNode *parent = node->parent;
Packit bfcc33
Packit bfcc33
      if (parent != NULL) {
Packit bfcc33
          if (node->prev != NULL)
Packit bfcc33
              node->prev->next = node->next;
Packit bfcc33
          else
Packit bfcc33
              parent->children.head = node->next;
Packit bfcc33
Packit bfcc33
          if (node->next != NULL)
Packit bfcc33
              node->next->prev = node->prev;
Packit bfcc33
          else
Packit bfcc33
              parent->children.tail = node->prev;
Packit bfcc33
Packit bfcc33
          free(node->key);
Packit bfcc33
Packit bfcc33
          node->parent = NULL;
Packit bfcc33
          node->prev = node->next = NULL;
Packit bfcc33
          node->key = NULL;
Packit bfcc33
      }
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static bool parse_value(const char **sp, JsonNode **out)
Packit bfcc33
{
Packit bfcc33
  const char *s = *sp;
Packit bfcc33
Packit bfcc33
  switch (*s) {
Packit bfcc33
    case 'n':
Packit bfcc33
      if (expect_literal(&s, "null")) {
Packit bfcc33
        if (out)
Packit bfcc33
          *out = json_mknull();
Packit bfcc33
        *sp = s;
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
Packit bfcc33
    case 'f':
Packit bfcc33
      if (expect_literal(&s, "false")) {
Packit bfcc33
        if (out)
Packit bfcc33
          *out = json_mkbool(false);
Packit bfcc33
        *sp = s;
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
Packit bfcc33
    case 't':
Packit bfcc33
      if (expect_literal(&s, "true")) {
Packit bfcc33
        if (out)
Packit bfcc33
          *out = json_mkbool(true);
Packit bfcc33
        *sp = s;
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
Packit bfcc33
    case '"': {
Packit bfcc33
      char *str = NULL;
Packit bfcc33
      if (parse_string(&s, out ? &str : NULL)) {
Packit bfcc33
        if (out)
Packit bfcc33
          *out = mkstring(str);
Packit bfcc33
        *sp = s;
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    case '[':
Packit bfcc33
      if (parse_array(&s, out)) {
Packit bfcc33
        *sp = s;
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
Packit bfcc33
    case '{':
Packit bfcc33
      if (parse_object(&s, out)) {
Packit bfcc33
        *sp = s;
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
Packit bfcc33
    default: {
Packit bfcc33
      double num;
Packit bfcc33
      if (parse_number(&s, out ? &num : NULL)) {
Packit bfcc33
        if (out)
Packit bfcc33
          *out = json_mknumber(num);
Packit bfcc33
        *sp = s;
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static bool parse_array(const char **sp, JsonNode **out)
Packit bfcc33
{
Packit bfcc33
  const char *s = *sp;
Packit bfcc33
  JsonNode *ret = out ? json_mkarray() : NULL;
Packit bfcc33
  JsonNode *element = NULL;
Packit bfcc33
Packit bfcc33
  if (*s++ != '[')
Packit bfcc33
    goto failure;
Packit bfcc33
  skip_space(&s);
Packit bfcc33
Packit bfcc33
  if (*s == ']') {
Packit bfcc33
    s++;
Packit bfcc33
    goto success;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  for (;;) {
Packit bfcc33
    if (!parse_value(&s, out ? &element : NULL))
Packit bfcc33
      goto failure;
Packit bfcc33
    skip_space(&s);
Packit bfcc33
Packit bfcc33
    if (out)
Packit bfcc33
      json_append_element(ret, element);
Packit bfcc33
Packit bfcc33
    if (*s == ']') {
Packit bfcc33
      s++;
Packit bfcc33
      goto success;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    if (*s++ != ',')
Packit bfcc33
      goto failure;
Packit bfcc33
    skip_space(&s);
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
success:
Packit bfcc33
  *sp = s;
Packit bfcc33
  if (out)
Packit bfcc33
    *out = ret;
Packit bfcc33
  return true;
Packit bfcc33
Packit bfcc33
failure:
Packit bfcc33
  json_delete(ret);
Packit bfcc33
  return false;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static bool parse_object(const char **sp, JsonNode **out)
Packit bfcc33
{
Packit bfcc33
  const char *s = *sp;
Packit bfcc33
  JsonNode *ret = out ? json_mkobject() : NULL;
Packit bfcc33
  char *key = NULL;
Packit bfcc33
  JsonNode *value = NULL;
Packit bfcc33
Packit bfcc33
  if (*s++ != '{')
Packit bfcc33
    goto failure;
Packit bfcc33
  skip_space(&s);
Packit bfcc33
Packit bfcc33
  if (*s == '}') {
Packit bfcc33
    s++;
Packit bfcc33
    goto success;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  for (;;) {
Packit bfcc33
    if (!parse_string(&s, out ? &key : NULL))
Packit bfcc33
      goto failure;
Packit bfcc33
    skip_space(&s);
Packit bfcc33
Packit bfcc33
    if (*s++ != ':')
Packit bfcc33
      goto failure_free_key;
Packit bfcc33
    skip_space(&s);
Packit bfcc33
Packit bfcc33
    if (!parse_value(&s, out ? &value : NULL))
Packit bfcc33
      goto failure_free_key;
Packit bfcc33
    skip_space(&s);
Packit bfcc33
Packit bfcc33
    if (out)
Packit bfcc33
      append_member(ret, key, value);
Packit bfcc33
Packit bfcc33
    if (*s == '}') {
Packit bfcc33
      s++;
Packit bfcc33
      goto success;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    if (*s++ != ',')
Packit bfcc33
      goto failure;
Packit bfcc33
    skip_space(&s);
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
success:
Packit bfcc33
  *sp = s;
Packit bfcc33
  if (out)
Packit bfcc33
    *out = ret;
Packit bfcc33
  return true;
Packit bfcc33
Packit bfcc33
failure_free_key:
Packit bfcc33
  if (out)
Packit bfcc33
    free(key);
Packit bfcc33
failure:
Packit bfcc33
  json_delete(ret);
Packit bfcc33
  return false;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
bool parse_string(const char **sp, char **out)
Packit bfcc33
{
Packit bfcc33
  const char *s = *sp;
Packit bfcc33
  SB sb = { 0, 0, 0 };
Packit bfcc33
  char throwaway_buffer[4];
Packit bfcc33
    /* enough space for a UTF-8 character */
Packit bfcc33
  char *b;
Packit bfcc33
Packit bfcc33
  if (*s++ != '"')
Packit bfcc33
    return false;
Packit bfcc33
Packit bfcc33
  if (out) {
Packit bfcc33
    sb_init(&sb);
Packit bfcc33
    sb_need(&sb, 4);
Packit bfcc33
    b = sb.cur;
Packit bfcc33
  } else {
Packit bfcc33
    b = throwaway_buffer;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  while (*s != '"') {
Packit bfcc33
    unsigned char c = *s++;
Packit bfcc33
Packit bfcc33
    /* Parse next character, and write it to b. */
Packit bfcc33
    if (c == '\\') {
Packit bfcc33
      c = *s++;
Packit bfcc33
      switch (c) {
Packit bfcc33
        case '"':
Packit bfcc33
        case '\\':
Packit bfcc33
        case '/':
Packit bfcc33
          *b++ = c;
Packit bfcc33
          break;
Packit bfcc33
        case 'b':
Packit bfcc33
          *b++ = '\b';
Packit bfcc33
          break;
Packit bfcc33
        case 'f':
Packit bfcc33
          *b++ = '\f';
Packit bfcc33
          break;
Packit bfcc33
        case 'n':
Packit bfcc33
          *b++ = '\n';
Packit bfcc33
          break;
Packit bfcc33
        case 'r':
Packit bfcc33
          *b++ = '\r';
Packit bfcc33
          break;
Packit bfcc33
        case 't':
Packit bfcc33
          *b++ = '\t';
Packit bfcc33
          break;
Packit bfcc33
        case 'u':
Packit bfcc33
        {
Packit bfcc33
          uint16_t uc, lc;
Packit bfcc33
          uint32_t unicode;
Packit bfcc33
Packit bfcc33
          if (!parse_hex16(&s, &uc))
Packit bfcc33
            goto failed;
Packit bfcc33
Packit bfcc33
          if (uc >= 0xD800 && uc <= 0xDFFF) {
Packit bfcc33
            /* Handle UTF-16 surrogate pair. */
Packit bfcc33
            if (*s++ != '\\' || *s++ != 'u' || !parse_hex16(&s, &lc))
Packit bfcc33
              goto failed; /* Incomplete surrogate pair. */
Packit bfcc33
            if (!from_surrogate_pair(uc, lc, &unicode))
Packit bfcc33
              goto failed; /* Invalid surrogate pair. */
Packit bfcc33
          } else if (uc == 0) {
Packit bfcc33
            /* Disallow "\u0000". */
Packit bfcc33
            goto failed;
Packit bfcc33
          } else {
Packit bfcc33
            unicode = uc;
Packit bfcc33
          }
Packit bfcc33
Packit bfcc33
          b += utf8_write_char(unicode, b);
Packit bfcc33
          break;
Packit bfcc33
        }
Packit bfcc33
        default:
Packit bfcc33
          /* Invalid escape */
Packit bfcc33
          goto failed;
Packit bfcc33
      }
Packit bfcc33
    } else if (c <= 0x1F) {
Packit bfcc33
      /* Control characters are not allowed in string literals. */
Packit bfcc33
      goto failed;
Packit bfcc33
    } else {
Packit bfcc33
      /* Validate and echo a UTF-8 character. */
Packit bfcc33
      int len;
Packit bfcc33
Packit bfcc33
      s--;
Packit bfcc33
      len = utf8_validate_cz(s);
Packit bfcc33
      if (len == 0)
Packit bfcc33
        goto failed; /* Invalid UTF-8 character. */
Packit bfcc33
Packit bfcc33
      while (len--)
Packit bfcc33
        *b++ = *s++;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    /*
Packit bfcc33
     * Update sb to know about the new bytes,
Packit bfcc33
     * and set up b to write another character.
Packit bfcc33
     */
Packit bfcc33
    if (out) {
Packit bfcc33
      sb.cur = b;
Packit bfcc33
      sb_need(&sb, 4);
Packit bfcc33
      b = sb.cur;
Packit bfcc33
    } else {
Packit bfcc33
      b = throwaway_buffer;
Packit bfcc33
    }
Packit bfcc33
  }
Packit bfcc33
  s++;
Packit bfcc33
Packit bfcc33
  if (out)
Packit bfcc33
    *out = sb_finish(&sb);
Packit bfcc33
  *sp = s;
Packit bfcc33
  return true;
Packit bfcc33
Packit bfcc33
failed:
Packit bfcc33
  if (out)
Packit bfcc33
    sb_free(&sb);
Packit bfcc33
  return false;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
bool is_space(const char *c) {
Packit bfcc33
  return ((*c) == '\t' || (*c) == '\n' || (*c) == '\r' || (*c) == ' ');
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
bool is_digit(const char *c){
Packit bfcc33
  return ((*c) >= '0' && (*c) <= '9');
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * The JSON spec says that a number shall follow this precise pattern
Packit bfcc33
 * (spaces and quotes added for readability):
Packit bfcc33
 *   '-'? (0 | [1-9][0-9]*) ('.' [0-9]+)? ([Ee] [+-]? [0-9]+)?
Packit bfcc33
 *
Packit bfcc33
 * However, some JSON parsers are more liberal.  For instance, PHP accepts
Packit bfcc33
 * '.5' and '1.'.  JSON.parse accepts '+3'.
Packit bfcc33
 *
Packit bfcc33
 * This function takes the strict approach.
Packit bfcc33
 */
Packit bfcc33
bool parse_number(const char **sp, double *out)
Packit bfcc33
{
Packit bfcc33
  const char *s = *sp;
Packit bfcc33
Packit bfcc33
  /* '-'? */
Packit bfcc33
  if (*s == '-')
Packit bfcc33
    s++;
Packit bfcc33
Packit bfcc33
  /* (0 | [1-9][0-9]*) */
Packit bfcc33
  if (*s == '0') {
Packit bfcc33
    s++;
Packit bfcc33
  } else {
Packit bfcc33
    if (!is_digit(s))
Packit bfcc33
      return false;
Packit bfcc33
    do {
Packit bfcc33
      s++;
Packit bfcc33
    } while (is_digit(s));
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  /* ('.' [0-9]+)? */
Packit bfcc33
  if (*s == '.') {
Packit bfcc33
    s++;
Packit bfcc33
    if (!is_digit(s))
Packit bfcc33
      return false;
Packit bfcc33
    do {
Packit bfcc33
      s++;
Packit bfcc33
    } while (is_digit(s));
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  /* ([Ee] [+-]? [0-9]+)? */
Packit bfcc33
  if (*s == 'E' || *s == 'e') {
Packit bfcc33
    s++;
Packit bfcc33
    if (*s == '+' || *s == '-')
Packit bfcc33
      s++;
Packit bfcc33
    if (!is_digit(s))
Packit bfcc33
      return false;
Packit bfcc33
    do {
Packit bfcc33
      s++;
Packit bfcc33
    } while (is_digit(s));
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  if (out)
Packit bfcc33
    *out = strtod(*sp, NULL);
Packit bfcc33
Packit bfcc33
  *sp = s;
Packit bfcc33
  return true;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void skip_space(const char **sp)
Packit bfcc33
{
Packit bfcc33
  const char *s = *sp;
Packit bfcc33
  while (is_space(s))
Packit bfcc33
    s++;
Packit bfcc33
  *sp = s;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void emit_value(SB *out, const JsonNode *node)
Packit bfcc33
{
Packit bfcc33
  assert(tag_is_valid(node->tag));
Packit bfcc33
  switch (node->tag) {
Packit bfcc33
    case JSON_NULL:
Packit bfcc33
      sb_puts(out, "null");
Packit bfcc33
      break;
Packit bfcc33
    case JSON_BOOL:
Packit bfcc33
      sb_puts(out, node->bool_ ? "true" : "false");
Packit bfcc33
      break;
Packit bfcc33
    case JSON_STRING:
Packit bfcc33
      emit_string(out, node->string_);
Packit bfcc33
      break;
Packit bfcc33
    case JSON_NUMBER:
Packit bfcc33
      emit_number(out, node->number_);
Packit bfcc33
      break;
Packit bfcc33
    case JSON_ARRAY:
Packit bfcc33
      emit_array(out, node);
Packit bfcc33
      break;
Packit bfcc33
    case JSON_OBJECT:
Packit bfcc33
      emit_object(out, node);
Packit bfcc33
      break;
Packit bfcc33
    default:
Packit bfcc33
      assert(false);
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
void emit_value_indented(SB *out, const JsonNode *node, const char *space, int indent_level)
Packit bfcc33
{
Packit bfcc33
  assert(tag_is_valid(node->tag));
Packit bfcc33
  switch (node->tag) {
Packit bfcc33
    case JSON_NULL:
Packit bfcc33
      sb_puts(out, "null");
Packit bfcc33
      break;
Packit bfcc33
    case JSON_BOOL:
Packit bfcc33
      sb_puts(out, node->bool_ ? "true" : "false");
Packit bfcc33
      break;
Packit bfcc33
    case JSON_STRING:
Packit bfcc33
      emit_string(out, node->string_);
Packit bfcc33
      break;
Packit bfcc33
    case JSON_NUMBER:
Packit bfcc33
      emit_number(out, node->number_);
Packit bfcc33
      break;
Packit bfcc33
    case JSON_ARRAY:
Packit bfcc33
      emit_array_indented(out, node, space, indent_level);
Packit bfcc33
      break;
Packit bfcc33
    case JSON_OBJECT:
Packit bfcc33
      emit_object_indented(out, node, space, indent_level);
Packit bfcc33
      break;
Packit bfcc33
    default:
Packit bfcc33
      assert(false);
Packit bfcc33
  }
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void emit_array(SB *out, const JsonNode *array)
Packit bfcc33
{
Packit bfcc33
  const JsonNode *element;
Packit bfcc33
Packit bfcc33
  sb_putc(out, '[');
Packit bfcc33
  json_foreach(element, array) {
Packit bfcc33
    emit_value(out, element);
Packit bfcc33
    if (element->next != NULL)
Packit bfcc33
      sb_putc(out, ',');
Packit bfcc33
  }
Packit bfcc33
  sb_putc(out, ']');
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void emit_array_indented(SB *out, const JsonNode *array, const char *space, int indent_level)
Packit bfcc33
{
Packit bfcc33
  const JsonNode *element = array->children.head;
Packit bfcc33
  int i;
Packit bfcc33
Packit bfcc33
  if (element == NULL) {
Packit bfcc33
    sb_puts(out, "[]");
Packit bfcc33
    return;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  sb_puts(out, "[\n");
Packit bfcc33
  while (element != NULL) {
Packit bfcc33
    for (i = 0; i < indent_level + 1; i++)
Packit bfcc33
      sb_puts(out, space);
Packit bfcc33
    emit_value_indented(out, element, space, indent_level + 1);
Packit bfcc33
Packit bfcc33
    element = element->next;
Packit bfcc33
    sb_puts(out, element != NULL ? ",\n" : "\n");
Packit bfcc33
  }
Packit bfcc33
  for (i = 0; i < indent_level; i++)
Packit bfcc33
    sb_puts(out, space);
Packit bfcc33
  sb_putc(out, ']');
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void emit_object(SB *out, const JsonNode *object)
Packit bfcc33
{
Packit bfcc33
  const JsonNode *member;
Packit bfcc33
Packit bfcc33
  sb_putc(out, '{');
Packit bfcc33
  json_foreach(member, object) {
Packit bfcc33
    emit_string(out, member->key);
Packit bfcc33
    sb_putc(out, ':');
Packit bfcc33
    emit_value(out, member);
Packit bfcc33
    if (member->next != NULL)
Packit bfcc33
      sb_putc(out, ',');
Packit bfcc33
  }
Packit bfcc33
  sb_putc(out, '}');
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void emit_object_indented(SB *out, const JsonNode *object, const char *space, int indent_level)
Packit bfcc33
{
Packit bfcc33
  const JsonNode *member = object->children.head;
Packit bfcc33
  int i;
Packit bfcc33
Packit bfcc33
  if (member == NULL) {
Packit bfcc33
    sb_puts(out, "{}");
Packit bfcc33
    return;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  sb_puts(out, "{\n");
Packit bfcc33
  while (member != NULL) {
Packit bfcc33
    for (i = 0; i < indent_level + 1; i++)
Packit bfcc33
      sb_puts(out, space);
Packit bfcc33
    emit_string(out, member->key);
Packit bfcc33
    sb_puts(out, ": ");
Packit bfcc33
    emit_value_indented(out, member, space, indent_level + 1);
Packit bfcc33
Packit bfcc33
    member = member->next;
Packit bfcc33
    sb_puts(out, member != NULL ? ",\n" : "\n");
Packit bfcc33
  }
Packit bfcc33
  for (i = 0; i < indent_level; i++)
Packit bfcc33
    sb_puts(out, space);
Packit bfcc33
  sb_putc(out, '}');
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
void emit_string(SB *out, const char *str)
Packit bfcc33
{
Packit bfcc33
  bool escape_unicode = false;
Packit bfcc33
  const char *s = str;
Packit bfcc33
  char *b;
Packit bfcc33
Packit bfcc33
// make assertion catchable
Packit bfcc33
#ifndef NDEBUG
Packit bfcc33
  if (!utf8_validate(str)) {
Packit bfcc33
    throw utf8::invalid_utf8(0);
Packit bfcc33
  }
Packit bfcc33
#endif
Packit bfcc33
Packit bfcc33
  assert(utf8_validate(str));
Packit bfcc33
Packit bfcc33
  /*
Packit bfcc33
   * 14 bytes is enough space to write up to two
Packit bfcc33
   * \uXXXX escapes and two quotation marks.
Packit bfcc33
   */
Packit bfcc33
  sb_need(out, 14);
Packit bfcc33
  b = out->cur;
Packit bfcc33
Packit bfcc33
  *b++ = '"';
Packit bfcc33
  while (*s != 0) {
Packit bfcc33
    unsigned char c = *s++;
Packit bfcc33
Packit bfcc33
    /* Encode the next character, and write it to b. */
Packit bfcc33
    switch (c) {
Packit bfcc33
      case '"':
Packit bfcc33
        *b++ = '\\';
Packit bfcc33
        *b++ = '"';
Packit bfcc33
        break;
Packit bfcc33
      case '\\':
Packit bfcc33
        *b++ = '\\';
Packit bfcc33
        *b++ = '\\';
Packit bfcc33
        break;
Packit bfcc33
      case '\b':
Packit bfcc33
        *b++ = '\\';
Packit bfcc33
        *b++ = 'b';
Packit bfcc33
        break;
Packit bfcc33
      case '\f':
Packit bfcc33
        *b++ = '\\';
Packit bfcc33
        *b++ = 'f';
Packit bfcc33
        break;
Packit bfcc33
      case '\n':
Packit bfcc33
        *b++ = '\\';
Packit bfcc33
        *b++ = 'n';
Packit bfcc33
        break;
Packit bfcc33
      case '\r':
Packit bfcc33
        *b++ = '\\';
Packit bfcc33
        *b++ = 'r';
Packit bfcc33
        break;
Packit bfcc33
      case '\t':
Packit bfcc33
        *b++ = '\\';
Packit bfcc33
        *b++ = 't';
Packit bfcc33
        break;
Packit bfcc33
      default: {
Packit bfcc33
        int len;
Packit bfcc33
Packit bfcc33
        s--;
Packit bfcc33
        len = utf8_validate_cz(s);
Packit bfcc33
Packit bfcc33
        if (len == 0) {
Packit bfcc33
          /*
Packit bfcc33
           * Handle invalid UTF-8 character gracefully in production
Packit bfcc33
           * by writing a replacement character (U+FFFD)
Packit bfcc33
           * and skipping a single byte.
Packit bfcc33
           *
Packit bfcc33
           * This should never happen when assertions are enabled
Packit bfcc33
           * due to the assertion at the beginning of this function.
Packit bfcc33
           */
Packit bfcc33
          assert(false);
Packit bfcc33
          if (escape_unicode) {
Packit bfcc33
            strcpy(b, "\\uFFFD");
Packit bfcc33
            b += 6;
Packit bfcc33
          } else {
Packit bfcc33
            *b++ = 0xEFu;
Packit bfcc33
            *b++ = 0xBFu;
Packit bfcc33
            *b++ = 0xBDu;
Packit bfcc33
          }
Packit bfcc33
          s++;
Packit bfcc33
        } else if (c < 0x1F || (c >= 0x80 && escape_unicode)) {
Packit bfcc33
          /* Encode using \u.... */
Packit bfcc33
          uint32_t unicode;
Packit bfcc33
Packit bfcc33
          s += utf8_read_char(s, &unicode);
Packit bfcc33
Packit bfcc33
          if (unicode <= 0xFFFF) {
Packit bfcc33
            *b++ = '\\';
Packit bfcc33
            *b++ = 'u';
Packit bfcc33
            b += write_hex16(b, unicode);
Packit bfcc33
          } else {
Packit bfcc33
            /* Produce a surrogate pair. */
Packit bfcc33
            uint16_t uc, lc;
Packit bfcc33
            assert(unicode <= 0x10FFFF);
Packit bfcc33
            to_surrogate_pair(unicode, &uc, &lc);
Packit bfcc33
            *b++ = '\\';
Packit bfcc33
            *b++ = 'u';
Packit bfcc33
            b += write_hex16(b, uc);
Packit bfcc33
            *b++ = '\\';
Packit bfcc33
            *b++ = 'u';
Packit bfcc33
            b += write_hex16(b, lc);
Packit bfcc33
          }
Packit bfcc33
        } else {
Packit bfcc33
          /* Write the character directly. */
Packit bfcc33
          while (len--)
Packit bfcc33
            *b++ = *s++;
Packit bfcc33
        }
Packit bfcc33
Packit bfcc33
        break;
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    /*
Packit bfcc33
     * Update *out to know about the new bytes,
Packit bfcc33
     * and set up b to write another encoded character.
Packit bfcc33
     */
Packit bfcc33
    out->cur = b;
Packit bfcc33
    sb_need(out, 14);
Packit bfcc33
    b = out->cur;
Packit bfcc33
  }
Packit bfcc33
  *b++ = '"';
Packit bfcc33
Packit bfcc33
  out->cur = b;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static void emit_number(SB *out, double num)
Packit bfcc33
{
Packit bfcc33
  /*
Packit bfcc33
   * This isn't exactly how JavaScript renders numbers,
Packit bfcc33
   * but it should produce valid JSON for reasonable numbers
Packit bfcc33
   * preserve precision well enough, and avoid some oddities
Packit bfcc33
   * like 0.3 -> 0.299999999999999988898 .
Packit bfcc33
   */
Packit bfcc33
  char buf[64];
Packit bfcc33
  sprintf(buf, "%.16g", num);
Packit bfcc33
Packit bfcc33
  if (number_is_valid(buf))
Packit bfcc33
    sb_puts(out, buf);
Packit bfcc33
  else
Packit bfcc33
    sb_puts(out, "null");
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static bool tag_is_valid(unsigned int tag)
Packit bfcc33
{
Packit bfcc33
  return (/* tag >= JSON_NULL && */ tag <= JSON_OBJECT);
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static bool number_is_valid(const char *num)
Packit bfcc33
{
Packit bfcc33
  return (parse_number(&num, NULL) && *num == '\0');
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
static bool expect_literal(const char **sp, const char *str)
Packit bfcc33
{
Packit bfcc33
  const char *s = *sp;
Packit bfcc33
Packit bfcc33
  while (*str != '\0')
Packit bfcc33
    if (*s++ != *str++)
Packit bfcc33
      return false;
Packit bfcc33
Packit bfcc33
  *sp = s;
Packit bfcc33
  return true;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * Parses exactly 4 hex characters (capital or lowercase).
Packit bfcc33
 * Fails if any input chars are not [0-9A-Fa-f].
Packit bfcc33
 */
Packit bfcc33
static bool parse_hex16(const char **sp, uint16_t *out)
Packit bfcc33
{
Packit bfcc33
  const char *s = *sp;
Packit bfcc33
  uint16_t ret = 0;
Packit bfcc33
  uint16_t i;
Packit bfcc33
  uint16_t tmp;
Packit bfcc33
  char c;
Packit bfcc33
Packit bfcc33
  for (i = 0; i < 4; i++) {
Packit bfcc33
    c = *s++;
Packit bfcc33
    if (c >= '0' && c <= '9')
Packit bfcc33
      tmp = c - '0';
Packit bfcc33
    else if (c >= 'A' && c <= 'F')
Packit bfcc33
      tmp = c - 'A' + 10;
Packit bfcc33
    else if (c >= 'a' && c <= 'f')
Packit bfcc33
      tmp = c - 'a' + 10;
Packit bfcc33
    else
Packit bfcc33
      return false;
Packit bfcc33
Packit bfcc33
    ret <<= 4;
Packit bfcc33
    ret += tmp;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  if (out)
Packit bfcc33
    *out = ret;
Packit bfcc33
  *sp = s;
Packit bfcc33
  return true;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * Encodes a 16-bit number into hexadecimal,
Packit bfcc33
 * writing exactly 4 hex chars.
Packit bfcc33
 */
Packit bfcc33
static int write_hex16(char *out, uint16_t val)
Packit bfcc33
{
Packit bfcc33
  const char *hex = "0123456789ABCDEF";
Packit bfcc33
Packit bfcc33
  *out++ = hex[(val >> 12) & 0xF];
Packit bfcc33
  *out++ = hex[(val >> 8)  & 0xF];
Packit bfcc33
  *out++ = hex[(val >> 4)  & 0xF];
Packit bfcc33
  *out++ = hex[ val        & 0xF];
Packit bfcc33
Packit bfcc33
  return 4;
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
bool json_check(const JsonNode *node, char errmsg[256])
Packit bfcc33
{
Packit bfcc33
  #define problem(...) do { \
Packit bfcc33
      if (errmsg != NULL) \
Packit bfcc33
        snprintf(errmsg, 256, __VA_ARGS__); \
Packit bfcc33
      return false; \
Packit bfcc33
    } while (0)
Packit bfcc33
Packit bfcc33
  if (node->key != NULL && !utf8_validate(node->key))
Packit bfcc33
    problem("key contains invalid UTF-8");
Packit bfcc33
Packit bfcc33
  if (!tag_is_valid(node->tag))
Packit bfcc33
    problem("tag is invalid (%u)", node->tag);
Packit bfcc33
Packit bfcc33
  if (node->tag == JSON_BOOL) {
Packit bfcc33
    if (node->bool_ != false && node->bool_ != true)
Packit bfcc33
      problem("bool_ is neither false (%d) nor true (%d)", (int)false, (int)true);
Packit bfcc33
  } else if (node->tag == JSON_STRING) {
Packit bfcc33
    if (node->string_ == NULL)
Packit bfcc33
      problem("string_ is NULL");
Packit bfcc33
    if (!utf8_validate(node->string_))
Packit bfcc33
      problem("string_ contains invalid UTF-8");
Packit bfcc33
  } else if (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT) {
Packit bfcc33
    JsonNode *head = node->children.head;
Packit bfcc33
    JsonNode *tail = node->children.tail;
Packit bfcc33
Packit bfcc33
    if (head == NULL || tail == NULL) {
Packit bfcc33
      if (head != NULL)
Packit bfcc33
        problem("tail is NULL, but head is not");
Packit bfcc33
      if (tail != NULL)
Packit bfcc33
        problem("head is NULL, but tail is not");
Packit bfcc33
    } else {
Packit bfcc33
      JsonNode *child;
Packit bfcc33
      JsonNode *last = NULL;
Packit bfcc33
Packit bfcc33
      if (head->prev != NULL)
Packit bfcc33
        problem("First child's prev pointer is not NULL");
Packit bfcc33
Packit bfcc33
      for (child = head; child != NULL; last = child, child = child->next) {
Packit bfcc33
        if (child == node)
Packit bfcc33
          problem("node is its own child");
Packit bfcc33
        if (child->next == child)
Packit bfcc33
          problem("child->next == child (cycle)");
Packit bfcc33
        if (child->next == head)
Packit bfcc33
          problem("child->next == head (cycle)");
Packit bfcc33
Packit bfcc33
        if (child->parent != node)
Packit bfcc33
          problem("child does not point back to parent");
Packit bfcc33
        if (child->next != NULL && child->next->prev != child)
Packit bfcc33
          problem("child->next does not point back to child");
Packit bfcc33
Packit bfcc33
        if (node->tag == JSON_ARRAY && child->key != NULL)
Packit bfcc33
          problem("Array element's key is not NULL");
Packit bfcc33
        if (node->tag == JSON_OBJECT && child->key == NULL)
Packit bfcc33
          problem("Object member's key is NULL");
Packit bfcc33
Packit bfcc33
        if (!json_check(child, errmsg))
Packit bfcc33
          return false;
Packit bfcc33
      }
Packit bfcc33
Packit bfcc33
      if (last != tail)
Packit bfcc33
        problem("tail does not match pointer found by starting at head and following next links");
Packit bfcc33
    }
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  return true;
Packit bfcc33
Packit bfcc33
  #undef problem
Packit bfcc33
}