avro-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dcrea...@apache.org
Subject svn commit: r1175570 [9/13] - in /avro/trunk: ./ lang/c/jansson/ lang/c/jansson/doc/ lang/c/jansson/doc/ext/ lang/c/jansson/src/ lang/c/jansson/test/ lang/c/jansson/test/bin/ lang/c/jansson/test/scripts/ lang/c/jansson/test/suites/ lang/c/jansson/test/...
Date Sun, 25 Sep 2011 20:47:42 GMT
Added: avro/trunk/lang/c/jansson/src/load.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/src/load.c?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/src/load.c (added)
+++ avro/trunk/lang/c/jansson/src/load.c Sun Sep 25 20:47:26 2011
@@ -0,0 +1,960 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <jansson.h>
+#include "jansson_private.h"
+#include "strbuffer.h"
+#include "utf.h"
+
+#define STREAM_STATE_OK        0
+#define STREAM_STATE_EOF      -1
+#define STREAM_STATE_ERROR    -2
+
+#define TOKEN_INVALID         -1
+#define TOKEN_EOF              0
+#define TOKEN_STRING         256
+#define TOKEN_INTEGER        257
+#define TOKEN_REAL           258
+#define TOKEN_TRUE           259
+#define TOKEN_FALSE          260
+#define TOKEN_NULL           261
+
+/* Read one byte from stream, convert to unsigned char, then int, and
+   return. return EOF on end of file. This corresponds to the
+   behaviour of fgetc(). */
+typedef int (*get_func)(void *data);
+
+typedef struct {
+    get_func get;
+    void *data;
+    char buffer[5];
+    int buffer_pos;
+    int state;
+    int line;
+    int column, last_column;
+    size_t position;
+} stream_t;
+
+typedef struct {
+    stream_t stream;
+    strbuffer_t saved_text;
+    int token;
+    union {
+        char *string;
+        json_int_t integer;
+        double real;
+    } value;
+} lex_t;
+
+#define stream_to_lex(stream) container_of(stream, lex_t, stream)
+
+
+/*** error reporting ***/
+
+static void error_set(json_error_t *error, const lex_t *lex,
+                      const char *msg, ...)
+{
+    va_list ap;
+    char msg_text[JSON_ERROR_TEXT_LENGTH];
+
+    int line = -1, col = -1;
+    size_t pos = 0;
+    const char *result = msg_text;
+
+    if(!error)
+        return;
+
+    va_start(ap, msg);
+    vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap);
+    va_end(ap);
+
+    if(lex)
+    {
+        const char *saved_text = strbuffer_value(&lex->saved_text);
+        char msg_with_context[JSON_ERROR_TEXT_LENGTH];
+
+        line = lex->stream.line;
+        col = lex->stream.column;
+        pos = lex->stream.position;
+
+        if(saved_text && saved_text[0])
+        {
+            if(lex->saved_text.length <= 20) {
+                snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH,
+                         "%s near '%s'", msg_text, saved_text);
+                result = msg_with_context;
+            }
+        }
+        else
+        {
+            if(lex->stream.state == STREAM_STATE_ERROR) {
+                /* No context for UTF-8 decoding errors */
+                result = msg_text;
+            }
+            else {
+                snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH,
+                         "%s near end of file", msg_text);
+                result = msg_with_context;
+            }
+        }
+    }
+
+    jsonp_error_set(error, line, col, pos, "%s", result);
+}
+
+
+/*** lexical analyzer ***/
+
+static void
+stream_init(stream_t *stream, get_func get, void *data)
+{
+    stream->get = get;
+    stream->data = data;
+    stream->buffer[0] = '\0';
+    stream->buffer_pos = 0;
+
+    stream->state = STREAM_STATE_OK;
+    stream->line = 1;
+    stream->column = 0;
+    stream->position = 0;
+}
+
+static int stream_get(stream_t *stream, json_error_t *error)
+{
+    int c;
+
+    if(stream->state != STREAM_STATE_OK)
+        return stream->state;
+
+    if(!stream->buffer[stream->buffer_pos])
+    {
+        c = stream->get(stream->data);
+        if(c == EOF) {
+            stream->state = STREAM_STATE_EOF;
+            return STREAM_STATE_EOF;
+        }
+
+        stream->buffer[0] = c;
+        stream->buffer_pos = 0;
+
+        if(0x80 <= c && c <= 0xFF)
+        {
+            /* multi-byte UTF-8 sequence */
+            int i, count;
+
+            count = utf8_check_first(c);
+            if(!count)
+                goto out;
+
+            assert(count >= 2);
+
+            for(i = 1; i < count; i++)
+                stream->buffer[i] = stream->get(stream->data);
+
+            if(!utf8_check_full(stream->buffer, count, NULL))
+                goto out;
+
+            stream->buffer[count] = '\0';
+        }
+        else
+            stream->buffer[1] = '\0';
+    }
+
+    c = stream->buffer[stream->buffer_pos++];
+
+    stream->position++;
+    if(c == '\n') {
+        stream->line++;
+        stream->last_column = stream->column;
+        stream->column = 0;
+    }
+    else if(utf8_check_first(c)) {
+        /* track the Unicode character column, so increment only if
+           this is the first character of a UTF-8 sequence */
+        stream->column++;
+    }
+
+    return c;
+
+out:
+    stream->state = STREAM_STATE_ERROR;
+    error_set(error, stream_to_lex(stream), "unable to decode byte 0x%x", c);
+    return STREAM_STATE_ERROR;
+}
+
+static void stream_unget(stream_t *stream, int c)
+{
+    if(c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR)
+        return;
+
+    stream->position--;
+    if(c == '\n') {
+        stream->line--;
+        stream->column = stream->last_column;
+    }
+    else if(utf8_check_first(c))
+        stream->column--;
+
+    assert(stream->buffer_pos > 0);
+    stream->buffer_pos--;
+    assert(stream->buffer[stream->buffer_pos] == c);
+}
+
+
+static int lex_get(lex_t *lex, json_error_t *error)
+{
+    return stream_get(&lex->stream, error);
+}
+
+static void lex_save(lex_t *lex, int c)
+{
+    strbuffer_append_byte(&lex->saved_text, c);
+}
+
+static int lex_get_save(lex_t *lex, json_error_t *error)
+{
+    int c = stream_get(&lex->stream, error);
+    if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR)
+        lex_save(lex, c);
+    return c;
+}
+
+static void lex_unget(lex_t *lex, int c)
+{
+    stream_unget(&lex->stream, c);
+}
+
+static void lex_unget_unsave(lex_t *lex, int c)
+{
+    if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) {
+        char d;
+        stream_unget(&lex->stream, c);
+        d = strbuffer_pop(&lex->saved_text);
+        assert(c == d);
+    }
+}
+
+static void lex_save_cached(lex_t *lex)
+{
+    while(lex->stream.buffer[lex->stream.buffer_pos] != '\0')
+    {
+        lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]);
+        lex->stream.buffer_pos++;
+        lex->stream.position++;
+    }
+}
+
+/* assumes that str points to 'u' plus at least 4 valid hex digits */
+static int32_t decode_unicode_escape(const char *str)
+{
+    int i;
+    int32_t value = 0;
+
+    assert(str[0] == 'u');
+
+    for(i = 1; i <= 4; i++) {
+        char c = str[i];
+        value <<= 4;
+        if(isdigit(c))
+            value += c - '0';
+        else if(islower(c))
+            value += c - 'a' + 10;
+        else if(isupper(c))
+            value += c - 'A' + 10;
+        else
+            assert(0);
+    }
+
+    return value;
+}
+
+static void lex_scan_string(lex_t *lex, json_error_t *error)
+{
+    int c;
+    const char *p;
+    char *t;
+    int i;
+
+    lex->value.string = NULL;
+    lex->token = TOKEN_INVALID;
+
+    c = lex_get_save(lex, error);
+
+    while(c != '"') {
+        if(c == STREAM_STATE_ERROR)
+            goto out;
+
+        else if(c == STREAM_STATE_EOF) {
+            error_set(error, lex, "premature end of input");
+            goto out;
+        }
+
+        else if(0 <= c && c <= 0x1F) {
+            /* control character */
+            lex_unget_unsave(lex, c);
+            if(c == '\n')
+                error_set(error, lex, "unexpected newline", c);
+            else
+                error_set(error, lex, "control character 0x%x", c);
+            goto out;
+        }
+
+        else if(c == '\\') {
+            c = lex_get_save(lex, error);
+            if(c == 'u') {
+                c = lex_get_save(lex, error);
+                for(i = 0; i < 4; i++) {
+                    if(!isxdigit(c)) {
+                        error_set(error, lex, "invalid escape");
+                        goto out;
+                    }
+                    c = lex_get_save(lex, error);
+                }
+            }
+            else if(c == '"' || c == '\\' || c == '/' || c == 'b' ||
+                    c == 'f' || c == 'n' || c == 'r' || c == 't')
+                c = lex_get_save(lex, error);
+            else {
+                error_set(error, lex, "invalid escape");
+                goto out;
+            }
+        }
+        else
+            c = lex_get_save(lex, error);
+    }
+
+    /* the actual value is at most of the same length as the source
+       string, because:
+         - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte
+         - a single \uXXXX escape (length 6) is converted to at most 3 bytes
+         - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair
+           are converted to 4 bytes
+    */
+    lex->value.string = jsonp_malloc(lex->saved_text.length + 1);
+    if(!lex->value.string) {
+        /* this is not very nice, since TOKEN_INVALID is returned */
+        goto out;
+    }
+
+    /* the target */
+    t = lex->value.string;
+
+    /* + 1 to skip the " */
+    p = strbuffer_value(&lex->saved_text) + 1;
+
+    while(*p != '"') {
+        if(*p == '\\') {
+            p++;
+            if(*p == 'u') {
+                char buffer[4];
+                int length;
+                int32_t value;
+
+                value = decode_unicode_escape(p);
+                p += 5;
+
+                if(0xD800 <= value && value <= 0xDBFF) {
+                    /* surrogate pair */
+                    if(*p == '\\' && *(p + 1) == 'u') {
+                        int32_t value2 = decode_unicode_escape(++p);
+                        p += 5;
+
+                        if(0xDC00 <= value2 && value2 <= 0xDFFF) {
+                            /* valid second surrogate */
+                            value =
+                                ((value - 0xD800) << 10) +
+                                (value2 - 0xDC00) +
+                                0x10000;
+                        }
+                        else {
+                            /* invalid second surrogate */
+                            error_set(error, lex,
+                                      "invalid Unicode '\\u%04X\\u%04X'",
+                                      value, value2);
+                            goto out;
+                        }
+                    }
+                    else {
+                        /* no second surrogate */
+                        error_set(error, lex, "invalid Unicode '\\u%04X'",
+                                  value);
+                        goto out;
+                    }
+                }
+                else if(0xDC00 <= value && value <= 0xDFFF) {
+                    error_set(error, lex, "invalid Unicode '\\u%04X'", value);
+                    goto out;
+                }
+                else if(value == 0)
+                {
+                    error_set(error, lex, "\\u0000 is not allowed");
+                    goto out;
+                }
+
+                if(utf8_encode(value, buffer, &length))
+                    assert(0);
+
+                memcpy(t, buffer, length);
+                t += length;
+            }
+            else {
+                switch(*p) {
+                    case '"': case '\\': case '/':
+                        *t = *p; break;
+                    case 'b': *t = '\b'; break;
+                    case 'f': *t = '\f'; break;
+                    case 'n': *t = '\n'; break;
+                    case 'r': *t = '\r'; break;
+                    case 't': *t = '\t'; break;
+                    default: assert(0);
+                }
+                t++;
+                p++;
+            }
+        }
+        else
+            *(t++) = *(p++);
+    }
+    *t = '\0';
+    lex->token = TOKEN_STRING;
+    return;
+
+out:
+    jsonp_free(lex->value.string);
+}
+
+#if JSON_INTEGER_IS_LONG_LONG
+#define json_strtoint     strtoll
+#else
+#define json_strtoint     strtol
+#endif
+
+static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
+{
+    const char *saved_text;
+    char *end;
+    double value;
+
+    lex->token = TOKEN_INVALID;
+
+    if(c == '-')
+        c = lex_get_save(lex, error);
+
+    if(c == '0') {
+        c = lex_get_save(lex, error);
+        if(isdigit(c)) {
+            lex_unget_unsave(lex, c);
+            goto out;
+        }
+    }
+    else if(isdigit(c)) {
+        c = lex_get_save(lex, error);
+        while(isdigit(c))
+            c = lex_get_save(lex, error);
+    }
+    else {
+        lex_unget_unsave(lex, c);
+        goto out;
+    }
+
+    if(c != '.' && c != 'E' && c != 'e') {
+        json_int_t value;
+
+        lex_unget_unsave(lex, c);
+
+        saved_text = strbuffer_value(&lex->saved_text);
+
+        errno = 0;
+        value = json_strtoint(saved_text, &end, 10);
+        if(errno == ERANGE) {
+            if(value < 0)
+                error_set(error, lex, "too big negative integer");
+            else
+                error_set(error, lex, "too big integer");
+            goto out;
+        }
+
+        assert(end == saved_text + lex->saved_text.length);
+
+        lex->token = TOKEN_INTEGER;
+        lex->value.integer = value;
+        return 0;
+    }
+
+    if(c == '.') {
+        c = lex_get(lex, error);
+        if(!isdigit(c)) {
+            lex_unget(lex, c);
+            goto out;
+        }
+        lex_save(lex, c);
+
+        c = lex_get_save(lex, error);
+        while(isdigit(c))
+            c = lex_get_save(lex, error);
+    }
+
+    if(c == 'E' || c == 'e') {
+        c = lex_get_save(lex, error);
+        if(c == '+' || c == '-')
+            c = lex_get_save(lex, error);
+
+        if(!isdigit(c)) {
+            lex_unget_unsave(lex, c);
+            goto out;
+        }
+
+        c = lex_get_save(lex, error);
+        while(isdigit(c))
+            c = lex_get_save(lex, error);
+    }
+
+    lex_unget_unsave(lex, c);
+
+    saved_text = strbuffer_value(&lex->saved_text);
+    errno = 0;
+    value = strtod(saved_text, &end);
+    assert(end == saved_text + lex->saved_text.length);
+
+    if(errno == ERANGE && value != 0) {
+        error_set(error, lex, "real number overflow");
+        goto out;
+    }
+
+    lex->token = TOKEN_REAL;
+    lex->value.real = value;
+    return 0;
+
+out:
+    return -1;
+}
+
+static int lex_scan(lex_t *lex, json_error_t *error)
+{
+    int c;
+
+    strbuffer_clear(&lex->saved_text);
+
+    if(lex->token == TOKEN_STRING) {
+        jsonp_free(lex->value.string);
+        lex->value.string = NULL;
+    }
+
+    c = lex_get(lex, error);
+    while(c == ' ' || c == '\t' || c == '\n' || c == '\r')
+        c = lex_get(lex, error);
+
+    if(c == STREAM_STATE_EOF) {
+        lex->token = TOKEN_EOF;
+        goto out;
+    }
+
+    if(c == STREAM_STATE_ERROR) {
+        lex->token = TOKEN_INVALID;
+        goto out;
+    }
+
+    lex_save(lex, c);
+
+    if(c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',')
+        lex->token = c;
+
+    else if(c == '"')
+        lex_scan_string(lex, error);
+
+    else if(isdigit(c) || c == '-') {
+        if(lex_scan_number(lex, c, error))
+            goto out;
+    }
+
+    else if(isupper(c) || islower(c)) {
+        /* eat up the whole identifier for clearer error messages */
+        const char *saved_text;
+
+        c = lex_get_save(lex, error);
+        while(isupper(c) || islower(c))
+            c = lex_get_save(lex, error);
+        lex_unget_unsave(lex, c);
+
+        saved_text = strbuffer_value(&lex->saved_text);
+
+        if(strcmp(saved_text, "true") == 0)
+            lex->token = TOKEN_TRUE;
+        else if(strcmp(saved_text, "false") == 0)
+            lex->token = TOKEN_FALSE;
+        else if(strcmp(saved_text, "null") == 0)
+            lex->token = TOKEN_NULL;
+        else
+            lex->token = TOKEN_INVALID;
+    }
+
+    else {
+        /* save the rest of the input UTF-8 sequence to get an error
+           message of valid UTF-8 */
+        lex_save_cached(lex);
+        lex->token = TOKEN_INVALID;
+    }
+
+out:
+    return lex->token;
+}
+
+static char *lex_steal_string(lex_t *lex)
+{
+    char *result = NULL;
+    if(lex->token == TOKEN_STRING)
+    {
+        result = lex->value.string;
+        lex->value.string = NULL;
+    }
+    return result;
+}
+
+static int lex_init(lex_t *lex, get_func get, void *data)
+{
+    stream_init(&lex->stream, get, data);
+    if(strbuffer_init(&lex->saved_text))
+        return -1;
+
+    lex->token = TOKEN_INVALID;
+    return 0;
+}
+
+static void lex_close(lex_t *lex)
+{
+    if(lex->token == TOKEN_STRING)
+        jsonp_free(lex->value.string);
+    strbuffer_close(&lex->saved_text);
+}
+
+
+/*** parser ***/
+
+static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error);
+
+static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
+{
+    json_t *object = json_object();
+    if(!object)
+        return NULL;
+
+    lex_scan(lex, error);
+    if(lex->token == '}')
+        return object;
+
+    while(1) {
+        char *key;
+        json_t *value;
+
+        if(lex->token != TOKEN_STRING) {
+            error_set(error, lex, "string or '}' expected");
+            goto error;
+        }
+
+        key = lex_steal_string(lex);
+        if(!key)
+            return NULL;
+
+        if(flags & JSON_REJECT_DUPLICATES) {
+            if(json_object_get(object, key)) {
+                jsonp_free(key);
+                error_set(error, lex, "duplicate object key");
+                goto error;
+            }
+        }
+
+        lex_scan(lex, error);
+        if(lex->token != ':') {
+            jsonp_free(key);
+            error_set(error, lex, "':' expected");
+            goto error;
+        }
+
+        lex_scan(lex, error);
+        value = parse_value(lex, flags, error);
+        if(!value) {
+            jsonp_free(key);
+            goto error;
+        }
+
+        if(json_object_set_nocheck(object, key, value)) {
+            jsonp_free(key);
+            json_decref(value);
+            goto error;
+        }
+
+        json_decref(value);
+        jsonp_free(key);
+
+        lex_scan(lex, error);
+        if(lex->token != ',')
+            break;
+
+        lex_scan(lex, error);
+    }
+
+    if(lex->token != '}') {
+        error_set(error, lex, "'}' expected");
+        goto error;
+    }
+
+    return object;
+
+error:
+    json_decref(object);
+    return NULL;
+}
+
+static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error)
+{
+    json_t *array = json_array();
+    if(!array)
+        return NULL;
+
+    lex_scan(lex, error);
+    if(lex->token == ']')
+        return array;
+
+    while(lex->token) {
+        json_t *elem = parse_value(lex, flags, error);
+        if(!elem)
+            goto error;
+
+        if(json_array_append(array, elem)) {
+            json_decref(elem);
+            goto error;
+        }
+        json_decref(elem);
+
+        lex_scan(lex, error);
+        if(lex->token != ',')
+            break;
+
+        lex_scan(lex, error);
+    }
+
+    if(lex->token != ']') {
+        error_set(error, lex, "']' expected");
+        goto error;
+    }
+
+    return array;
+
+error:
+    json_decref(array);
+    return NULL;
+}
+
+static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
+{
+    json_t *json;
+
+    switch(lex->token) {
+        case TOKEN_STRING: {
+            json = json_string_nocheck(lex->value.string);
+            break;
+        }
+
+        case TOKEN_INTEGER: {
+            json = json_integer(lex->value.integer);
+            break;
+        }
+
+        case TOKEN_REAL: {
+            json = json_real(lex->value.real);
+            break;
+        }
+
+        case TOKEN_TRUE:
+            json = json_true();
+            break;
+
+        case TOKEN_FALSE:
+            json = json_false();
+            break;
+
+        case TOKEN_NULL:
+            json = json_null();
+            break;
+
+        case '{':
+            json = parse_object(lex, flags, error);
+            break;
+
+        case '[':
+            json = parse_array(lex, flags, error);
+            break;
+
+        case TOKEN_INVALID:
+            error_set(error, lex, "invalid token");
+            return NULL;
+
+        default:
+            error_set(error, lex, "unexpected token");
+            return NULL;
+    }
+
+    if(!json)
+        return NULL;
+
+    return json;
+}
+
+static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error)
+{
+    json_t *result;
+
+    lex_scan(lex, error);
+    if(lex->token != '[' && lex->token != '{') {
+        error_set(error, lex, "'[' or '{' expected");
+        return NULL;
+    }
+
+    result = parse_value(lex, flags, error);
+    if(!result)
+        return NULL;
+
+    if(!(flags & JSON_DISABLE_EOF_CHECK)) {
+        lex_scan(lex, error);
+        if(lex->token != TOKEN_EOF) {
+            error_set(error, lex, "end of file expected");
+            json_decref(result);
+            result = NULL;
+        }
+    }
+
+    return result;
+}
+
+typedef struct
+{
+    const char *data;
+    int pos;
+} string_data_t;
+
+static int string_get(void *data)
+{
+    char c;
+    string_data_t *stream = (string_data_t *)data;
+    c = stream->data[stream->pos];
+    if(c == '\0')
+        return EOF;
+    else
+    {
+        stream->pos++;
+        return (unsigned char)c;
+    }
+}
+
+json_t *json_loads(const char *string, size_t flags, json_error_t *error)
+{
+    lex_t lex;
+    json_t *result;
+    string_data_t stream_data;
+
+    stream_data.data = string;
+    stream_data.pos = 0;
+
+    if(lex_init(&lex, string_get, (void *)&stream_data))
+        return NULL;
+
+    jsonp_error_init(error, "<string>");
+    result = parse_json(&lex, flags, error);
+
+    lex_close(&lex);
+    return result;
+}
+
+typedef struct
+{
+    const char *data;
+    size_t len;
+    size_t pos;
+} buffer_data_t;
+
+static int buffer_get(void *data)
+{
+    char c;
+    buffer_data_t *stream = data;
+    if(stream->pos >= stream->len)
+      return EOF;
+
+    c = stream->data[stream->pos];
+    stream->pos++;
+    return (unsigned char)c;
+}
+
+json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error)
+{
+    lex_t lex;
+    json_t *result;
+    buffer_data_t stream_data;
+
+    stream_data.data = buffer;
+    stream_data.pos = 0;
+    stream_data.len = buflen;
+
+    if(lex_init(&lex, buffer_get, (void *)&stream_data))
+        return NULL;
+
+    jsonp_error_init(error, "<buffer>");
+    result = parse_json(&lex, flags, error);
+
+    lex_close(&lex);
+    return result;
+}
+
+json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
+{
+    lex_t lex;
+    const char *source;
+    json_t *result;
+
+    if(lex_init(&lex, (get_func)fgetc, input))
+        return NULL;
+
+    if(input == stdin)
+        source = "<stdin>";
+    else
+        source = "<stream>";
+
+    jsonp_error_init(error, source);
+    result = parse_json(&lex, flags, error);
+
+    lex_close(&lex);
+    return result;
+}
+
+json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
+{
+    json_t *result;
+    FILE *fp;
+
+    jsonp_error_init(error, path);
+
+    fp = fopen(path, "r");
+    if(!fp)
+    {
+        error_set(error, NULL, "unable to open %s: %s",
+                  path, strerror(errno));
+        return NULL;
+    }
+
+    result = json_loadf(fp, flags, error);
+
+    fclose(fp);
+    return result;
+}

Added: avro/trunk/lang/c/jansson/src/memory.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/src/memory.c?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/src/memory.c (added)
+++ avro/trunk/lang/c/jansson/src/memory.c Sun Sep 25 20:47:26 2011
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2011 Basile Starynkevitch  <basile@starynkevitch.net>
+ *
+ * Jansson is free software; you can redistribute it and/or modify it
+ * under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <jansson.h>
+#include "jansson_private.h"
+
+/* memory function pointers */
+static json_malloc_t do_malloc = malloc;
+static json_free_t do_free = free;
+
+void *jsonp_malloc(size_t size)
+{
+    if(!size)
+        return NULL;
+
+    return (*do_malloc)(size);
+}
+
+void jsonp_free(void *ptr)
+{
+    if(!ptr)
+        return;
+
+    (*do_free)(ptr);
+}
+
+char *jsonp_strdup(const char *str)
+{
+    char *new_str;
+
+    new_str = jsonp_malloc(strlen(str) + 1);
+    if(!new_str)
+        return NULL;
+
+    strcpy(new_str, str);
+    return new_str;
+}
+
+void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn)
+{
+    do_malloc = malloc_fn;
+    do_free = free_fn;
+}

Added: avro/trunk/lang/c/jansson/src/pack_unpack.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/src/pack_unpack.c?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/src/pack_unpack.c (added)
+++ avro/trunk/lang/c/jansson/src/pack_unpack.c Sun Sep 25 20:47:26 2011
@@ -0,0 +1,610 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2011 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <string.h>
+#include <jansson.h>
+#include "jansson_private.h"
+#include "utf.h"
+
+typedef struct {
+    const char *start;
+    const char *fmt;
+    char token;
+    json_error_t *error;
+    size_t flags;
+    int line;
+    int column;
+} scanner_t;
+
+static const char *type_names[] = {
+    "object",
+    "array",
+    "string",
+    "integer",
+    "real",
+    "true",
+    "false",
+    "null"
+};
+
+#define type_name(x) type_names[json_typeof(x)]
+
+static const char *unpack_value_starters = "{[siIbfFOon";
+
+
+static void scanner_init(scanner_t *s, json_error_t *error,
+                         size_t flags, const char *fmt)
+{
+    s->error = error;
+    s->flags = flags;
+    s->fmt = s->start = fmt;
+    s->line = 1;
+    s->column = 0;
+}
+
+static void next_token(scanner_t *s)
+{
+    const char *t = s->fmt;
+    s->column++;
+
+    /* skip space and ignored chars */
+    while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
+        if(*t == '\n') {
+            s->line++;
+            s->column = 1;
+        }
+        else
+            s->column++;
+
+        t++;
+    }
+
+    s->token = *t;
+
+    t++;
+    s->fmt = t;
+}
+
+static void set_error(scanner_t *s, const char *source, const char *fmt, ...)
+{
+    va_list ap;
+    size_t pos;
+    va_start(ap, fmt);
+
+    pos = (size_t)(s->fmt - s->start);
+    jsonp_error_vset(s->error, s->line, s->column, pos, fmt, ap);
+
+    jsonp_error_set_source(s->error, source);
+
+    va_end(ap);
+}
+
+static json_t *pack(scanner_t *s, va_list *ap);
+
+static json_t *pack_object(scanner_t *s, va_list *ap)
+{
+    json_t *object = json_object();
+    next_token(s);
+
+    while(s->token != '}') {
+        const char *key;
+        json_t *value;
+
+        if(!s->token) {
+            set_error(s, "<format>", "Unexpected end of format string");
+            goto error;
+        }
+
+        if(s->token != 's') {
+            set_error(s, "<format>", "Expected format 's', got '%c'", s->token);
+            goto error;
+        }
+
+        key = va_arg(*ap, const char *);
+        if(!key) {
+            set_error(s, "<args>", "NULL object key");
+            goto error;
+        }
+
+        if(!utf8_check_string(key, -1)) {
+            set_error(s, "<args>", "Invalid UTF-8 in object key");
+            goto error;
+        }
+
+        next_token(s);
+
+        value = pack(s, ap);
+        if(!value)
+            goto error;
+
+        if(json_object_set_new_nocheck(object, key, value)) {
+            set_error(s, "<internal>", "Unable to add key \"%s\"", key);
+            goto error;
+        }
+
+        next_token(s);
+    }
+
+    return object;
+
+error:
+    json_decref(object);
+    return NULL;
+}
+
+static json_t *pack_array(scanner_t *s, va_list *ap)
+{
+    json_t *array = json_array();
+    next_token(s);
+
+    while(s->token != ']') {
+        json_t *value;
+
+        if(!s->token) {
+            set_error(s, "<format>", "Unexpected end of format string");
+            goto error;
+        }
+
+        value = pack(s, ap);
+        if(!value)
+            goto error;
+
+        if(json_array_append_new(array, value)) {
+            set_error(s, "<internal>", "Unable to append to array");
+            goto error;
+        }
+
+        next_token(s);
+    }
+    return array;
+
+error:
+    json_decref(array);
+    return NULL;
+}
+
+static json_t *pack(scanner_t *s, va_list *ap)
+{
+    switch(s->token) {
+        case '{':
+            return pack_object(s, ap);
+
+        case '[':
+            return pack_array(s, ap);
+
+        case 's': /* string */
+        {
+            const char *str = va_arg(*ap, const char *);
+            if(!str) {
+                set_error(s, "<args>", "NULL string argument");
+                return NULL;
+            }
+            if(!utf8_check_string(str, -1)) {
+                set_error(s, "<args>", "Invalid UTF-8 string");
+                return NULL;
+            }
+            return json_string_nocheck(str);
+        }
+
+        case 'n': /* null */
+            return json_null();
+
+        case 'b': /* boolean */
+            return va_arg(*ap, int) ? json_true() : json_false();
+
+        case 'i': /* integer from int */
+            return json_integer(va_arg(*ap, int));
+
+        case 'I': /* integer from json_int_t */
+            return json_integer(va_arg(*ap, json_int_t));
+
+        case 'f': /* real */
+            return json_real(va_arg(*ap, double));
+
+        case 'O': /* a json_t object; increments refcount */
+            return json_incref(va_arg(*ap, json_t *));
+
+        case 'o': /* a json_t object; doesn't increment refcount */
+            return va_arg(*ap, json_t *);
+
+        default:
+            set_error(s, "<format>", "Unexpected format character '%c'",
+                      s->token);
+            return NULL;
+    }
+}
+
+static int unpack(scanner_t *s, json_t *root, va_list *ap);
+
+static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
+{
+    int ret = -1;
+    int strict = 0;
+
+    /* Use a set (emulated by a hashtable) to check that all object
+       keys are accessed. Checking that the correct number of keys
+       were accessed is not enough, as the same key can be unpacked
+       multiple times.
+    */
+    hashtable_t key_set;
+
+    if(hashtable_init(&key_set, jsonp_hash_str, jsonp_str_equal, NULL, NULL)) {
+        set_error(s, "<internal>", "Out of memory");
+        return -1;
+    }
+
+    if(!json_is_object(root)) {
+        set_error(s, "<validation>", "Expected object, got %s",
+                  type_name(root));
+        goto out;
+    }
+    next_token(s);
+
+    while(s->token != '}') {
+        const char *key;
+        json_t *value;
+
+        if(strict != 0) {
+            set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
+                      (strict == 1 ? '!' : '*'), s->token);
+            goto out;
+        }
+
+        if(!s->token) {
+            set_error(s, "<format>", "Unexpected end of format string");
+            goto out;
+        }
+
+        if(s->token == '!' || s->token == '*') {
+            strict = (s->token == '!' ? 1 : -1);
+            next_token(s);
+            continue;
+        }
+
+        if(s->token != 's') {
+            set_error(s, "<format>", "Expected format 's', got '%c'", s->token);
+            goto out;
+        }
+
+        key = va_arg(*ap, const char *);
+        if(!key) {
+            set_error(s, "<args>", "NULL object key");
+            goto out;
+        }
+
+        next_token(s);
+
+        value = json_object_get(root, key);
+        if(!value) {
+            set_error(s, "<validation>", "Object item not found: %s", key);
+            goto out;
+        }
+
+        if(unpack(s, value, ap))
+            goto out;
+
+        hashtable_set(&key_set, (void *)key, NULL);
+        next_token(s);
+    }
+
+    if(strict == 0 && (s->flags & JSON_STRICT))
+        strict = 1;
+
+    if(strict == 1 && key_set.size != json_object_size(root)) {
+        long diff = (long)json_object_size(root) - (long)key_set.size;
+        set_error(s, "<validation>", "%li object item(s) left unpacked", diff);
+        goto out;
+    }
+
+    ret = 0;
+
+out:
+    hashtable_close(&key_set);
+    return ret;
+}
+
+static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
+{
+    size_t i = 0;
+    int strict = 0;
+
+    if(!json_is_array(root)) {
+        set_error(s, "<validation>", "Expected array, got %s", type_name(root));
+        return -1;
+    }
+    next_token(s);
+
+    while(s->token != ']') {
+        json_t *value;
+
+        if(strict != 0) {
+            set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
+                      (strict == 1 ? '!' : '*'),
+                      s->token);
+            return -1;
+        }
+
+        if(!s->token) {
+            set_error(s, "<format>", "Unexpected end of format string");
+            return -1;
+        }
+
+        if(s->token == '!' || s->token == '*') {
+            strict = (s->token == '!' ? 1 : -1);
+            next_token(s);
+            continue;
+        }
+
+        if(!strchr(unpack_value_starters, s->token)) {
+            set_error(s, "<format>", "Unexpected format character '%c'",
+                      s->token);
+            return -1;
+        }
+
+        value = json_array_get(root, i);
+        if(!value) {
+            set_error(s, "<validation>", "Array index %lu out of range",
+                      (unsigned long)i);
+            return -1;
+        }
+
+        if(unpack(s, value, ap))
+            return -1;
+
+        next_token(s);
+        i++;
+    }
+
+    if(strict == 0 && (s->flags & JSON_STRICT))
+        strict = 1;
+
+    if(strict == 1 && i != json_array_size(root)) {
+        long diff = (long)json_array_size(root) - (long)i;
+        set_error(s, "<validation>", "%li array item(s) left unpacked", diff);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int unpack(scanner_t *s, json_t *root, va_list *ap)
+{
+    switch(s->token)
+    {
+        case '{':
+            return unpack_object(s, root, ap);
+
+        case '[':
+            return unpack_array(s, root, ap);
+
+        case 's':
+            if(!json_is_string(root)) {
+                set_error(s, "<validation>", "Expected string, got %s",
+                          type_name(root));
+                return -1;
+            }
+
+            if(!(s->flags & JSON_VALIDATE_ONLY)) {
+                const char **str;
+
+                str = va_arg(*ap, const char **);
+                if(!str) {
+                    set_error(s, "<args>", "NULL string argument");
+                    return -1;
+                }
+
+                *str = json_string_value(root);
+            }
+            return 0;
+
+        case 'i':
+            if(!json_is_integer(root)) {
+                set_error(s, "<validation>", "Expected integer, got %s",
+                          type_name(root));
+                return -1;
+            }
+
+            if(!(s->flags & JSON_VALIDATE_ONLY))
+                *va_arg(*ap, int*) = json_integer_value(root);
+
+            return 0;
+
+        case 'I':
+            if(!json_is_integer(root)) {
+                set_error(s, "<validation>", "Expected integer, got %s",
+                          type_name(root));
+                return -1;
+            }
+
+            if(!(s->flags & JSON_VALIDATE_ONLY))
+                *va_arg(*ap, json_int_t*) = json_integer_value(root);
+
+            return 0;
+
+        case 'b':
+            if(!json_is_boolean(root)) {
+                set_error(s, "<validation>", "Expected true or false, got %s",
+                          type_name(root));
+                return -1;
+            }
+
+            if(!(s->flags & JSON_VALIDATE_ONLY))
+                *va_arg(*ap, int*) = json_is_true(root);
+
+            return 0;
+
+        case 'f':
+            if(!json_is_real(root)) {
+                set_error(s, "<validation>", "Expected real, got %s",
+                          type_name(root));
+                return -1;
+            }
+
+            if(!(s->flags & JSON_VALIDATE_ONLY))
+                *va_arg(*ap, double*) = json_real_value(root);
+
+            return 0;
+
+        case 'F':
+            if(!json_is_number(root)) {
+                set_error(s, "<validation>", "Expected real or integer, got %s",
+                          type_name(root));
+                return -1;
+            }
+
+            if(!(s->flags & JSON_VALIDATE_ONLY))
+                *va_arg(*ap, double*) = json_number_value(root);
+
+            return 0;
+
+        case 'O':
+            if(!(s->flags & JSON_VALIDATE_ONLY))
+                json_incref(root);
+            /* Fall through */
+
+        case 'o':
+            if(!(s->flags & JSON_VALIDATE_ONLY))
+                *va_arg(*ap, json_t**) = root;
+
+            return 0;
+
+        case 'n':
+            /* Never assign, just validate */
+            if(!json_is_null(root)) {
+                set_error(s, "<validation>", "Expected null, got %s",
+                          type_name(root));
+                return -1;
+            }
+            return 0;
+
+        default:
+            set_error(s, "<format>", "Unexpected format character '%c'",
+                      s->token);
+            return -1;
+    }
+}
+
+json_t *json_vpack_ex(json_error_t *error, size_t flags,
+                      const char *fmt, va_list ap)
+{
+    scanner_t s;
+    va_list ap_copy;
+    json_t *value;
+
+    if(!fmt || !*fmt) {
+        jsonp_error_init(error, "<format>");
+        jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
+        return NULL;
+    }
+    jsonp_error_init(error, NULL);
+
+    scanner_init(&s, error, flags, fmt);
+    next_token(&s);
+
+    va_copy(ap_copy, ap);
+    value = pack(&s, &ap_copy);
+    va_end(ap_copy);
+
+    if(!value)
+        return NULL;
+
+    next_token(&s);
+    if(s.token) {
+        json_decref(value);
+        set_error(&s, "<format>", "Garbage after format string");
+        return NULL;
+    }
+
+    return value;
+}
+
+json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
+{
+    json_t *value;
+    va_list ap;
+
+    va_start(ap, fmt);
+    value = json_vpack_ex(error, flags, fmt, ap);
+    va_end(ap);
+
+    return value;
+}
+
+json_t *json_pack(const char *fmt, ...)
+{
+    json_t *value;
+    va_list ap;
+
+    va_start(ap, fmt);
+    value = json_vpack_ex(NULL, 0, fmt, ap);
+    va_end(ap);
+
+    return value;
+}
+
+int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
+                    const char *fmt, va_list ap)
+{
+    scanner_t s;
+    va_list ap_copy;
+
+    if(!root) {
+        jsonp_error_init(error, "<root>");
+        jsonp_error_set(error, -1, -1, 0, "NULL root value");
+        return -1;
+    }
+
+    if(!fmt || !*fmt) {
+        jsonp_error_init(error, "<format>");
+        jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
+        return -1;
+    }
+    jsonp_error_init(error, NULL);
+
+    scanner_init(&s, error, flags, fmt);
+    next_token(&s);
+
+    va_copy(ap_copy, ap);
+    if(unpack(&s, root, &ap_copy)) {
+        va_end(ap_copy);
+        return -1;
+    }
+    va_end(ap_copy);
+
+    next_token(&s);
+    if(s.token) {
+        set_error(&s, "<format>", "Garbage after format string");
+        return -1;
+    }
+
+    return 0;
+}
+
+int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...)
+{
+    int ret;
+    va_list ap;
+
+    va_start(ap, fmt);
+    ret = json_vunpack_ex(root, error, flags, fmt, ap);
+    va_end(ap);
+
+    return ret;
+}
+
+int json_unpack(json_t *root, const char *fmt, ...)
+{
+    int ret;
+    va_list ap;
+
+    va_start(ap, fmt);
+    ret = json_vunpack_ex(root, NULL, 0, fmt, ap);
+    va_end(ap);
+
+    return ret;
+}

Added: avro/trunk/lang/c/jansson/src/strbuffer.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/src/strbuffer.c?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/src/strbuffer.c (added)
+++ avro/trunk/lang/c/jansson/src/strbuffer.c Sun Sep 25 20:47:26 2011
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include "jansson_private.h"
+#include "strbuffer.h"
+
+#define STRBUFFER_MIN_SIZE  16
+#define STRBUFFER_FACTOR    2
+
+int strbuffer_init(strbuffer_t *strbuff)
+{
+    strbuff->size = STRBUFFER_MIN_SIZE;
+    strbuff->length = 0;
+
+    strbuff->value = jsonp_malloc(strbuff->size);
+    if(!strbuff->value)
+        return -1;
+
+    /* initialize to empty */
+    strbuff->value[0] = '\0';
+    return 0;
+}
+
+void strbuffer_close(strbuffer_t *strbuff)
+{
+    jsonp_free(strbuff->value);
+    strbuff->size = 0;
+    strbuff->length = 0;
+    strbuff->value = NULL;
+}
+
+void strbuffer_clear(strbuffer_t *strbuff)
+{
+    strbuff->length = 0;
+    strbuff->value[0] = '\0';
+}
+
+const char *strbuffer_value(const strbuffer_t *strbuff)
+{
+    return strbuff->value;
+}
+
+char *strbuffer_steal_value(strbuffer_t *strbuff)
+{
+    char *result = strbuff->value;
+    strbuffer_init(strbuff);
+    return result;
+}
+
+int strbuffer_append(strbuffer_t *strbuff, const char *string)
+{
+    return strbuffer_append_bytes(strbuff, string, strlen(string));
+}
+
+int strbuffer_append_byte(strbuffer_t *strbuff, char byte)
+{
+    return strbuffer_append_bytes(strbuff, &byte, 1);
+}
+
+int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size)
+{
+    if(strbuff->length + size >= strbuff->size)
+    {
+        size_t new_size;
+        char *new_value;
+
+        new_size = max(strbuff->size * STRBUFFER_FACTOR,
+                       strbuff->length + size + 1);
+
+        new_value = jsonp_malloc(new_size);
+        if(!new_value)
+            return -1;
+
+        memcpy(new_value, strbuff->value, strbuff->length);
+
+        jsonp_free(strbuff->value);
+        strbuff->value = new_value;
+        strbuff->size = new_size;
+    }
+
+    memcpy(strbuff->value + strbuff->length, data, size);
+    strbuff->length += size;
+    strbuff->value[strbuff->length] = '\0';
+
+    return 0;
+}
+
+char strbuffer_pop(strbuffer_t *strbuff)
+{
+    if(strbuff->length > 0) {
+        char c = strbuff->value[--strbuff->length];
+        strbuff->value[strbuff->length] = '\0';
+        return c;
+    }
+    else
+        return '\0';
+}

Added: avro/trunk/lang/c/jansson/src/strbuffer.h
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/src/strbuffer.h?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/src/strbuffer.h (added)
+++ avro/trunk/lang/c/jansson/src/strbuffer.h Sun Sep 25 20:47:26 2011
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#ifndef STRBUFFER_H
+#define STRBUFFER_H
+
+typedef struct {
+    char *value;
+    int length;   /* bytes used */
+    int size;     /* bytes allocated */
+} strbuffer_t;
+
+int strbuffer_init(strbuffer_t *strbuff);
+void strbuffer_close(strbuffer_t *strbuff);
+
+void strbuffer_clear(strbuffer_t *strbuff);
+
+const char *strbuffer_value(const strbuffer_t *strbuff);
+char *strbuffer_steal_value(strbuffer_t *strbuff);
+
+int strbuffer_append(strbuffer_t *strbuff, const char *string);
+int strbuffer_append_byte(strbuffer_t *strbuff, char byte);
+int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size);
+
+char strbuffer_pop(strbuffer_t *strbuff);
+
+#endif

Added: avro/trunk/lang/c/jansson/src/utf.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/src/utf.c?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/src/utf.c (added)
+++ avro/trunk/lang/c/jansson/src/utf.c Sun Sep 25 20:47:26 2011
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <string.h>
+#include "utf.h"
+
+int utf8_encode(int32_t codepoint, char *buffer, int *size)
+{
+    if(codepoint < 0)
+        return -1;
+    else if(codepoint < 0x80)
+    {
+        buffer[0] = (char)codepoint;
+        *size = 1;
+    }
+    else if(codepoint < 0x800)
+    {
+        buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6);
+        buffer[1] = 0x80 + ((codepoint & 0x03F));
+        *size = 2;
+    }
+    else if(codepoint < 0x10000)
+    {
+        buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12);
+        buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6);
+        buffer[2] = 0x80 + ((codepoint & 0x003F));
+        *size = 3;
+    }
+    else if(codepoint <= 0x10FFFF)
+    {
+        buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18);
+        buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12);
+        buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6);
+        buffer[3] = 0x80 + ((codepoint & 0x00003F));
+        *size = 4;
+    }
+    else
+        return -1;
+
+    return 0;
+}
+
+int utf8_check_first(char byte)
+{
+    unsigned char u = (unsigned char)byte;
+
+    if(u < 0x80)
+        return 1;
+
+    if(0x80 <= u && u <= 0xBF) {
+        /* second, third or fourth byte of a multi-byte
+           sequence, i.e. a "continuation byte" */
+        return 0;
+    }
+    else if(u == 0xC0 || u == 0xC1) {
+        /* overlong encoding of an ASCII byte */
+        return 0;
+    }
+    else if(0xC2 <= u && u <= 0xDF) {
+        /* 2-byte sequence */
+        return 2;
+    }
+
+    else if(0xE0 <= u && u <= 0xEF) {
+        /* 3-byte sequence */
+        return 3;
+    }
+    else if(0xF0 <= u && u <= 0xF4) {
+        /* 4-byte sequence */
+        return 4;
+    }
+    else { /* u >= 0xF5 */
+        /* Restricted (start of 4-, 5- or 6-byte sequence) or invalid
+           UTF-8 */
+        return 0;
+    }
+}
+
+int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
+{
+    int i;
+    int32_t value = 0;
+    unsigned char u = (unsigned char)buffer[0];
+
+    if(size == 2)
+    {
+        value = u & 0x1F;
+    }
+    else if(size == 3)
+    {
+        value = u & 0xF;
+    }
+    else if(size == 4)
+    {
+        value = u & 0x7;
+    }
+    else
+        return 0;
+
+    for(i = 1; i < size; i++)
+    {
+        u = (unsigned char)buffer[i];
+
+        if(u < 0x80 || u > 0xBF) {
+            /* not a continuation byte */
+            return 0;
+        }
+
+        value = (value << 6) + (u & 0x3F);
+    }
+
+    if(value > 0x10FFFF) {
+        /* not in Unicode range */
+        return 0;
+    }
+
+    else if(0xD800 <= value && value <= 0xDFFF) {
+        /* invalid code point (UTF-16 surrogate halves) */
+        return 0;
+    }
+
+    else if((size == 2 && value < 0x80) ||
+            (size == 3 && value < 0x800) ||
+            (size == 4 && value < 0x10000)) {
+        /* overlong encoding */
+        return 0;
+    }
+
+    if(codepoint)
+        *codepoint = value;
+
+    return 1;
+}
+
+const char *utf8_iterate(const char *buffer, int32_t *codepoint)
+{
+    int count;
+    int32_t value;
+
+    if(!*buffer)
+        return buffer;
+
+    count = utf8_check_first(buffer[0]);
+    if(count <= 0)
+        return NULL;
+
+    if(count == 1)
+        value = (unsigned char)buffer[0];
+    else
+    {
+        if(!utf8_check_full(buffer, count, &value))
+            return NULL;
+    }
+
+    if(codepoint)
+        *codepoint = value;
+
+    return buffer + count;
+}
+
+int utf8_check_string(const char *string, int length)
+{
+    int i;
+
+    if(length == -1)
+        length = strlen(string);
+
+    for(i = 0; i < length; i++)
+    {
+        int count = utf8_check_first(string[i]);
+        if(count == 0)
+            return 0;
+        else if(count > 1)
+        {
+            if(i + count > length)
+                return 0;
+
+            if(!utf8_check_full(&string[i], count, NULL))
+                return 0;
+
+            i += count - 1;
+        }
+    }
+
+    return 1;
+}

Added: avro/trunk/lang/c/jansson/src/utf.h
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/src/utf.h?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/src/utf.h (added)
+++ avro/trunk/lang/c/jansson/src/utf.h Sun Sep 25 20:47:26 2011
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#ifndef UTF_H
+#define UTF_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+
+#ifdef HAVE_INTTYPES_H
+/* inttypes.h includes stdint.h in a standard environment, so there's
+no need to include stdint.h separately. If inttypes.h doesn't define
+int32_t, it's defined in config.h. */
+#include <inttypes.h>
+#endif /* HAVE_INTTYPES_H */
+
+#else /* !HAVE_CONFIG_H */
+#ifdef _WIN32
+typedef int int32_t;
+#else /* !_WIN32 */
+/* Assume a standard environment */
+#include <inttypes.h>
+#endif /* _WIN32 */
+
+#endif /* HAVE_CONFIG_H */
+
+int utf8_encode(int codepoint, char *buffer, int *size);
+
+int utf8_check_first(char byte);
+int utf8_check_full(const char *buffer, int size, int32_t *codepoint);
+const char *utf8_iterate(const char *buffer, int32_t *codepoint);
+
+int utf8_check_string(const char *string, int length);
+
+#endif

Added: avro/trunk/lang/c/jansson/src/value.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/src/value.c?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/src/value.c (added)
+++ avro/trunk/lang/c/jansson/src/value.c Sun Sep 25 20:47:26 2011
@@ -0,0 +1,983 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#define _GNU_SOURCE
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <jansson.h>
+#include "hashtable.h"
+#include "jansson_private.h"
+#include "utf.h"
+
+
+static JSON_INLINE void json_init(json_t *json, json_type type)
+{
+    json->type = type;
+    json->refcount = 1;
+}
+
+
+/*** object ***/
+
+/* From http://www.cse.yorku.ca/~oz/hash.html */
+size_t jsonp_hash_str(const void *ptr)
+{
+    const char *str = (const char *)ptr;
+
+    size_t hash = 5381;
+    size_t c;
+
+    while((c = (size_t)*str))
+    {
+        hash = ((hash << 5) + hash) + c;
+        str++;
+    }
+
+    return hash;
+}
+
+int jsonp_str_equal(const void *ptr1, const void *ptr2)
+{
+    return strcmp((const char *)ptr1, (const char *)ptr2) == 0;
+}
+
+/* This macro just returns a pointer that's a few bytes backwards from
+   string. This makes it possible to pass a pointer to object_key_t
+   when only the string inside it is used, without actually creating
+   an object_key_t instance. */
+#define string_to_key(string)  container_of(string, object_key_t, key)
+
+static size_t hash_key(const void *ptr)
+{
+    return jsonp_hash_str(((const object_key_t *)ptr)->key);
+}
+
+static int key_equal(const void *ptr1, const void *ptr2)
+{
+    return jsonp_str_equal(((const object_key_t *)ptr1)->key,
+                           ((const object_key_t *)ptr2)->key);
+}
+
+static void value_decref(void *value)
+{
+    json_decref((json_t *)value);
+}
+
+json_t *json_object(void)
+{
+    json_object_t *object = jsonp_malloc(sizeof(json_object_t));
+    if(!object)
+        return NULL;
+    json_init(&object->json, JSON_OBJECT);
+
+    if(hashtable_init(&object->hashtable,
+                      hash_key, key_equal,
+                      jsonp_free, value_decref))
+    {
+        jsonp_free(object);
+        return NULL;
+    }
+
+    object->serial = 0;
+    object->visited = 0;
+
+    return &object->json;
+}
+
+static void json_delete_object(json_object_t *object)
+{
+    hashtable_close(&object->hashtable);
+    jsonp_free(object);
+}
+
+size_t json_object_size(const json_t *json)
+{
+    json_object_t *object;
+
+    if(!json_is_object(json))
+        return 0;
+
+    object = json_to_object(json);
+    return object->hashtable.size;
+}
+
+json_t *json_object_get(const json_t *json, const char *key)
+{
+    json_object_t *object;
+
+    if(!json_is_object(json))
+        return NULL;
+
+    object = json_to_object(json);
+    return hashtable_get(&object->hashtable, string_to_key(key));
+}
+
+int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
+{
+    json_object_t *object;
+    object_key_t *k;
+
+    if(!key || !value)
+        return -1;
+
+    if(!json_is_object(json) || json == value)
+    {
+        json_decref(value);
+        return -1;
+    }
+    object = json_to_object(json);
+
+    /* offsetof(...) returns the size of object_key_t without the
+       last, flexible member. This way, the correct amount is
+       allocated. */
+    k = jsonp_malloc(offsetof(object_key_t, key) + strlen(key) + 1);
+    if(!k)
+    {
+        json_decref(value);
+        return -1;
+    }
+
+    k->serial = object->serial++;
+    strcpy(k->key, key);
+
+    if(hashtable_set(&object->hashtable, k, value))
+    {
+        json_decref(value);
+        return -1;
+    }
+
+    return 0;
+}
+
+int json_object_set_new(json_t *json, const char *key, json_t *value)
+{
+    if(!key || !utf8_check_string(key, -1))
+    {
+        json_decref(value);
+        return -1;
+    }
+
+    return json_object_set_new_nocheck(json, key, value);
+}
+
+int json_object_del(json_t *json, const char *key)
+{
+    json_object_t *object;
+
+    if(!json_is_object(json))
+        return -1;
+
+    object = json_to_object(json);
+    return hashtable_del(&object->hashtable, string_to_key(key));
+}
+
+int json_object_clear(json_t *json)
+{
+    json_object_t *object;
+
+    if(!json_is_object(json))
+        return -1;
+
+    object = json_to_object(json);
+    hashtable_clear(&object->hashtable);
+
+    return 0;
+}
+
+int json_object_update(json_t *object, json_t *other)
+{
+    void *iter;
+
+    if(!json_is_object(object) || !json_is_object(other))
+        return -1;
+
+    iter = json_object_iter(other);
+    while(iter) {
+        const char *key;
+        json_t *value;
+
+        key = json_object_iter_key(iter);
+        value = json_object_iter_value(iter);
+
+        if(json_object_set_nocheck(object, key, value))
+            return -1;
+
+        iter = json_object_iter_next(other, iter);
+    }
+
+    return 0;
+}
+
+void *json_object_iter(json_t *json)
+{
+    json_object_t *object;
+
+    if(!json_is_object(json))
+        return NULL;
+
+    object = json_to_object(json);
+    return hashtable_iter(&object->hashtable);
+}
+
+void *json_object_iter_at(json_t *json, const char *key)
+{
+    json_object_t *object;
+
+    if(!key || !json_is_object(json))
+        return NULL;
+
+    object = json_to_object(json);
+    return hashtable_iter_at(&object->hashtable, string_to_key(key));
+}
+
+void *json_object_iter_next(json_t *json, void *iter)
+{
+    json_object_t *object;
+
+    if(!json_is_object(json) || iter == NULL)
+        return NULL;
+
+    object = json_to_object(json);
+    return hashtable_iter_next(&object->hashtable, iter);
+}
+
+const object_key_t *jsonp_object_iter_fullkey(void *iter)
+{
+    if(!iter)
+        return NULL;
+
+    return hashtable_iter_key(iter);
+}
+
+const char *json_object_iter_key(void *iter)
+{
+    if(!iter)
+        return NULL;
+
+    return jsonp_object_iter_fullkey(iter)->key;
+}
+
+json_t *json_object_iter_value(void *iter)
+{
+    if(!iter)
+        return NULL;
+
+    return (json_t *)hashtable_iter_value(iter);
+}
+
+int json_object_iter_set_new(json_t *json, void *iter, json_t *value)
+{
+    json_object_t *object;
+
+    if(!json_is_object(json) || !iter || !value)
+        return -1;
+
+    object = json_to_object(json);
+    hashtable_iter_set(&object->hashtable, iter, value);
+
+    return 0;
+}
+
+static int json_object_equal(json_t *object1, json_t *object2)
+{
+    void *iter;
+
+    if(json_object_size(object1) != json_object_size(object2))
+        return 0;
+
+    iter = json_object_iter(object1);
+    while(iter)
+    {
+        const char *key;
+        json_t *value1, *value2;
+
+        key = json_object_iter_key(iter);
+        value1 = json_object_iter_value(iter);
+        value2 = json_object_get(object2, key);
+
+        if(!json_equal(value1, value2))
+            return 0;
+
+        iter = json_object_iter_next(object1, iter);
+    }
+
+    return 1;
+}
+
+static json_t *json_object_copy(json_t *object)
+{
+    json_t *result;
+    void *iter;
+
+    result = json_object();
+    if(!result)
+        return NULL;
+
+    iter = json_object_iter(object);
+    while(iter)
+    {
+        const char *key;
+        json_t *value;
+
+        key = json_object_iter_key(iter);
+        value = json_object_iter_value(iter);
+        json_object_set_nocheck(result, key, value);
+
+        iter = json_object_iter_next(object, iter);
+    }
+
+    return result;
+}
+
+static json_t *json_object_deep_copy(json_t *object)
+{
+    json_t *result;
+    void *iter;
+
+    result = json_object();
+    if(!result)
+        return NULL;
+
+    iter = json_object_iter(object);
+    while(iter)
+    {
+        const char *key;
+        json_t *value;
+
+        key = json_object_iter_key(iter);
+        value = json_object_iter_value(iter);
+        json_object_set_new_nocheck(result, key, json_deep_copy(value));
+
+        iter = json_object_iter_next(object, iter);
+    }
+
+    return result;
+}
+
+
+/*** array ***/
+
+json_t *json_array(void)
+{
+    json_array_t *array = jsonp_malloc(sizeof(json_array_t));
+    if(!array)
+        return NULL;
+    json_init(&array->json, JSON_ARRAY);
+
+    array->entries = 0;
+    array->size = 8;
+
+    array->table = jsonp_malloc(array->size * sizeof(json_t *));
+    if(!array->table) {
+        jsonp_free(array);
+        return NULL;
+    }
+
+    array->visited = 0;
+
+    return &array->json;
+}
+
+static void json_delete_array(json_array_t *array)
+{
+    size_t i;
+
+    for(i = 0; i < array->entries; i++)
+        json_decref(array->table[i]);
+
+    jsonp_free(array->table);
+    jsonp_free(array);
+}
+
+size_t json_array_size(const json_t *json)
+{
+    if(!json_is_array(json))
+        return 0;
+
+    return json_to_array(json)->entries;
+}
+
+json_t *json_array_get(const json_t *json, size_t index)
+{
+    json_array_t *array;
+    if(!json_is_array(json))
+        return NULL;
+    array = json_to_array(json);
+
+    if(index >= array->entries)
+        return NULL;
+
+    return array->table[index];
+}
+
+int json_array_set_new(json_t *json, size_t index, json_t *value)
+{
+    json_array_t *array;
+
+    if(!value)
+        return -1;
+
+    if(!json_is_array(json) || json == value)
+    {
+        json_decref(value);
+        return -1;
+    }
+    array = json_to_array(json);
+
+    if(index >= array->entries)
+    {
+        json_decref(value);
+        return -1;
+    }
+
+    json_decref(array->table[index]);
+    array->table[index] = value;
+
+    return 0;
+}
+
+static void array_move(json_array_t *array, size_t dest,
+                       size_t src, size_t count)
+{
+    memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *));
+}
+
+static void array_copy(json_t **dest, size_t dpos,
+                       json_t **src, size_t spos,
+                       size_t count)
+{
+    memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *));
+}
+
+static json_t **json_array_grow(json_array_t *array,
+                                size_t amount,
+                                int copy)
+{
+    size_t new_size;
+    json_t **old_table, **new_table;
+
+    if(array->entries + amount <= array->size)
+        return array->table;
+
+    old_table = array->table;
+
+    new_size = max(array->size + amount, array->size * 2);
+    new_table = jsonp_malloc(new_size * sizeof(json_t *));
+    if(!new_table)
+        return NULL;
+
+    array->size = new_size;
+    array->table = new_table;
+
+    if(copy) {
+        array_copy(array->table, 0, old_table, 0, array->entries);
+        jsonp_free(old_table);
+        return array->table;
+    }
+
+    return old_table;
+}
+
+int json_array_append_new(json_t *json, json_t *value)
+{
+    json_array_t *array;
+
+    if(!value)
+        return -1;
+
+    if(!json_is_array(json) || json == value)
+    {
+        json_decref(value);
+        return -1;
+    }
+    array = json_to_array(json);
+
+    if(!json_array_grow(array, 1, 1)) {
+        json_decref(value);
+        return -1;
+    }
+
+    array->table[array->entries] = value;
+    array->entries++;
+
+    return 0;
+}
+
+int json_array_insert_new(json_t *json, size_t index, json_t *value)
+{
+    json_array_t *array;
+    json_t **old_table;
+
+    if(!value)
+        return -1;
+
+    if(!json_is_array(json) || json == value) {
+        json_decref(value);
+        return -1;
+    }
+    array = json_to_array(json);
+
+    if(index > array->entries) {
+        json_decref(value);
+        return -1;
+    }
+
+    old_table = json_array_grow(array, 1, 0);
+    if(!old_table) {
+        json_decref(value);
+        return -1;
+    }
+
+    if(old_table != array->table) {
+        array_copy(array->table, 0, old_table, 0, index);
+        array_copy(array->table, index + 1, old_table, index,
+                   array->entries - index);
+        jsonp_free(old_table);
+    }
+    else
+        array_move(array, index + 1, index, array->entries - index);
+
+    array->table[index] = value;
+    array->entries++;
+
+    return 0;
+}
+
+int json_array_remove(json_t *json, size_t index)
+{
+    json_array_t *array;
+
+    if(!json_is_array(json))
+        return -1;
+    array = json_to_array(json);
+
+    if(index >= array->entries)
+        return -1;
+
+    json_decref(array->table[index]);
+
+    array_move(array, index, index + 1, array->entries - index);
+    array->entries--;
+
+    return 0;
+}
+
+int json_array_clear(json_t *json)
+{
+    json_array_t *array;
+    size_t i;
+
+    if(!json_is_array(json))
+        return -1;
+    array = json_to_array(json);
+
+    for(i = 0; i < array->entries; i++)
+        json_decref(array->table[i]);
+
+    array->entries = 0;
+    return 0;
+}
+
+int json_array_extend(json_t *json, json_t *other_json)
+{
+    json_array_t *array, *other;
+    size_t i;
+
+    if(!json_is_array(json) || !json_is_array(other_json))
+        return -1;
+    array = json_to_array(json);
+    other = json_to_array(other_json);
+
+    if(!json_array_grow(array, other->entries, 1))
+        return -1;
+
+    for(i = 0; i < other->entries; i++)
+        json_incref(other->table[i]);
+
+    array_copy(array->table, array->entries, other->table, 0, other->entries);
+
+    array->entries += other->entries;
+    return 0;
+}
+
+static int json_array_equal(json_t *array1, json_t *array2)
+{
+    size_t i, size;
+
+    size = json_array_size(array1);
+    if(size != json_array_size(array2))
+        return 0;
+
+    for(i = 0; i < size; i++)
+    {
+        json_t *value1, *value2;
+
+        value1 = json_array_get(array1, i);
+        value2 = json_array_get(array2, i);
+
+        if(!json_equal(value1, value2))
+            return 0;
+    }
+
+    return 1;
+}
+
+static json_t *json_array_copy(json_t *array)
+{
+    json_t *result;
+    size_t i;
+
+    result = json_array();
+    if(!result)
+        return NULL;
+
+    for(i = 0; i < json_array_size(array); i++)
+        json_array_append(result, json_array_get(array, i));
+
+    return result;
+}
+
+static json_t *json_array_deep_copy(json_t *array)
+{
+    json_t *result;
+    size_t i;
+
+    result = json_array();
+    if(!result)
+        return NULL;
+
+    for(i = 0; i < json_array_size(array); i++)
+        json_array_append_new(result, json_deep_copy(json_array_get(array, i)));
+
+    return result;
+}
+
+/*** string ***/
+
+json_t *json_string_nocheck(const char *value)
+{
+    json_string_t *string;
+
+    if(!value)
+        return NULL;
+
+    string = jsonp_malloc(sizeof(json_string_t));
+    if(!string)
+        return NULL;
+    json_init(&string->json, JSON_STRING);
+
+    string->value = jsonp_strdup(value);
+    if(!string->value) {
+        jsonp_free(string);
+        return NULL;
+    }
+
+    return &string->json;
+}
+
+json_t *json_string(const char *value)
+{
+    if(!value || !utf8_check_string(value, -1))
+        return NULL;
+
+    return json_string_nocheck(value);
+}
+
+const char *json_string_value(const json_t *json)
+{
+    if(!json_is_string(json))
+        return NULL;
+
+    return json_to_string(json)->value;
+}
+
+int json_string_set_nocheck(json_t *json, const char *value)
+{
+    char *dup;
+    json_string_t *string;
+
+    dup = jsonp_strdup(value);
+    if(!dup)
+        return -1;
+
+    string = json_to_string(json);
+    jsonp_free(string->value);
+    string->value = dup;
+
+    return 0;
+}
+
+int json_string_set(json_t *json, const char *value)
+{
+    if(!value || !utf8_check_string(value, -1))
+        return -1;
+
+    return json_string_set_nocheck(json, value);
+}
+
+static void json_delete_string(json_string_t *string)
+{
+    jsonp_free(string->value);
+    jsonp_free(string);
+}
+
+static int json_string_equal(json_t *string1, json_t *string2)
+{
+    return strcmp(json_string_value(string1), json_string_value(string2)) == 0;
+}
+
+static json_t *json_string_copy(json_t *string)
+{
+    return json_string_nocheck(json_string_value(string));
+}
+
+
+/*** integer ***/
+
+json_t *json_integer(json_int_t value)
+{
+    json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t));
+    if(!integer)
+        return NULL;
+    json_init(&integer->json, JSON_INTEGER);
+
+    integer->value = value;
+    return &integer->json;
+}
+
+json_int_t json_integer_value(const json_t *json)
+{
+    if(!json_is_integer(json))
+        return 0;
+
+    return json_to_integer(json)->value;
+}
+
+int json_integer_set(json_t *json, json_int_t value)
+{
+    if(!json_is_integer(json))
+        return -1;
+
+    json_to_integer(json)->value = value;
+
+    return 0;
+}
+
+static void json_delete_integer(json_integer_t *integer)
+{
+    jsonp_free(integer);
+}
+
+static int json_integer_equal(json_t *integer1, json_t *integer2)
+{
+    return json_integer_value(integer1) == json_integer_value(integer2);
+}
+
+static json_t *json_integer_copy(json_t *integer)
+{
+    return json_integer(json_integer_value(integer));
+}
+
+
+/*** real ***/
+
+json_t *json_real(double value)
+{
+    json_real_t *real = jsonp_malloc(sizeof(json_real_t));
+    if(!real)
+        return NULL;
+    json_init(&real->json, JSON_REAL);
+
+    real->value = value;
+    return &real->json;
+}
+
+double json_real_value(const json_t *json)
+{
+    if(!json_is_real(json))
+        return 0;
+
+    return json_to_real(json)->value;
+}
+
+int json_real_set(json_t *json, double value)
+{
+    if(!json_is_real(json))
+        return 0;
+
+    json_to_real(json)->value = value;
+
+    return 0;
+}
+
+static void json_delete_real(json_real_t *real)
+{
+    jsonp_free(real);
+}
+
+static int json_real_equal(json_t *real1, json_t *real2)
+{
+    return json_real_value(real1) == json_real_value(real2);
+}
+
+static json_t *json_real_copy(json_t *real)
+{
+    return json_real(json_real_value(real));
+}
+
+
+/*** number ***/
+
+double json_number_value(const json_t *json)
+{
+    if(json_is_integer(json))
+        return json_integer_value(json);
+    else if(json_is_real(json))
+        return json_real_value(json);
+    else
+        return 0.0;
+}
+
+
+/*** simple values ***/
+
+json_t *json_true(void)
+{
+    static json_t the_true = {JSON_TRUE, (size_t)-1};
+    return &the_true;
+}
+
+
+json_t *json_false(void)
+{
+    static json_t the_false = {JSON_FALSE, (size_t)-1};
+    return &the_false;
+}
+
+
+json_t *json_null(void)
+{
+    static json_t the_null = {JSON_NULL, (size_t)-1};
+    return &the_null;
+}
+
+
+/*** deletion ***/
+
+void json_delete(json_t *json)
+{
+    if(json_is_object(json))
+        json_delete_object(json_to_object(json));
+
+    else if(json_is_array(json))
+        json_delete_array(json_to_array(json));
+
+    else if(json_is_string(json))
+        json_delete_string(json_to_string(json));
+
+    else if(json_is_integer(json))
+        json_delete_integer(json_to_integer(json));
+
+    else if(json_is_real(json))
+        json_delete_real(json_to_real(json));
+
+    /* json_delete is not called for true, false or null */
+}
+
+
+/*** equality ***/
+
+int json_equal(json_t *json1, json_t *json2)
+{
+    if(!json1 || !json2)
+        return 0;
+
+    if(json_typeof(json1) != json_typeof(json2))
+        return 0;
+
+    /* this covers true, false and null as they are singletons */
+    if(json1 == json2)
+        return 1;
+
+    if(json_is_object(json1))
+        return json_object_equal(json1, json2);
+
+    if(json_is_array(json1))
+        return json_array_equal(json1, json2);
+
+    if(json_is_string(json1))
+        return json_string_equal(json1, json2);
+
+    if(json_is_integer(json1))
+        return json_integer_equal(json1, json2);
+
+    if(json_is_real(json1))
+        return json_real_equal(json1, json2);
+
+    return 0;
+}
+
+
+/*** copying ***/
+
+json_t *json_copy(json_t *json)
+{
+    if(!json)
+        return NULL;
+
+    if(json_is_object(json))
+        return json_object_copy(json);
+
+    if(json_is_array(json))
+        return json_array_copy(json);
+
+    if(json_is_string(json))
+        return json_string_copy(json);
+
+    if(json_is_integer(json))
+        return json_integer_copy(json);
+
+    if(json_is_real(json))
+        return json_real_copy(json);
+
+    if(json_is_true(json) || json_is_false(json) || json_is_null(json))
+        return json;
+
+    return NULL;
+}
+
+json_t *json_deep_copy(json_t *json)
+{
+    if(!json)
+        return NULL;
+
+    if(json_is_object(json))
+        return json_object_deep_copy(json);
+
+    if(json_is_array(json))
+        return json_array_deep_copy(json);
+
+    /* for the rest of the types, deep copying doesn't differ from
+       shallow copying */
+
+    if(json_is_string(json))
+        return json_string_copy(json);
+
+    if(json_is_integer(json))
+        return json_integer_copy(json);
+
+    if(json_is_real(json))
+        return json_real_copy(json);
+
+    if(json_is_true(json) || json_is_false(json) || json_is_null(json))
+        return json;
+
+    return NULL;
+}

Added: avro/trunk/lang/c/jansson/test/.gitignore
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/test/.gitignore?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/test/.gitignore (added)
+++ avro/trunk/lang/c/jansson/test/.gitignore Sun Sep 25 20:47:26 2011
@@ -0,0 +1,13 @@
+bin/json_process
+suites/api/test_array
+suites/api/test_copy
+suites/api/test_dump
+suites/api/test_equal
+suites/api/test_load
+suites/api/test_loadb
+suites/api/test_memory_funcs
+suites/api/test_number
+suites/api/test_object
+suites/api/test_pack
+suites/api/test_simple
+suites/api/test_unpack

Added: avro/trunk/lang/c/jansson/test/Makefile.am
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/test/Makefile.am?rev=1175570&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/test/Makefile.am (added)
+++ avro/trunk/lang/c/jansson/test/Makefile.am Sun Sep 25 20:47:26 2011
@@ -0,0 +1,10 @@
+SUBDIRS = bin suites
+EXTRA_DIST = scripts run-suites
+
+TESTS = run-suites
+TESTS_ENVIRONMENT = \
+	top_srcdir=$(top_srcdir) \
+	top_builddir=$(top_builddir)
+
+clean-local:
+	rm -rf logs



Mime
View raw message