diff options
author | Paul J. Davis <paul.joseph.davis@gmail.com> | 2014-02-04 17:40:42 -0600 |
---|---|---|
committer | Paul J. Davis <paul.joseph.davis@gmail.com> | 2014-02-04 17:40:42 -0600 |
commit | 191a9b41f2f67d16472e0ace293bf1dc0fe4cece (patch) | |
tree | 3f84f890a9c49a9045f42bd65d1afe8be8b00b57 | |
parent | 572ee3ce4603be89d8545b50142a183ded001d27 (diff) | |
download | couchdb-191a9b41f2f67d16472e0ace293bf1dc0fe4cece.tar.gz |
Remove src/ejson
24 files changed, 0 insertions, 5021 deletions
diff --git a/src/ejson/c_src/decode.c b/src/ejson/c_src/decode.c deleted file mode 100644 index 68f131764..000000000 --- a/src/ejson/c_src/decode.c +++ /dev/null @@ -1,308 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -#include <assert.h> -#include <stdio.h> -#include <string.h> - -#include "erl_nif.h" -#include "erl_nif_compat.h" -#include "yajl/yajl_parse.h" -#include "yajl/yajl_parser.h" -#include "yajl/yajl_lex.h" - -typedef struct { - ERL_NIF_TERM head; - ErlNifEnv* env; -} decode_ctx; - -#define ENV(ctxarg) (((decode_ctx*)ctxarg)->env) - -#define CONTINUE 1 -#define CANCEL 0 - - -static ERL_NIF_TERM -make_error(yajl_handle handle, ErlNifEnv* env) -{ - char* yajlError = (char*) yajl_get_error(handle, 0, NULL, 0); - ERL_NIF_TERM errMsg; - - if(yajlError != NULL) - { - errMsg = enif_make_string(env, yajlError, ERL_NIF_LATIN1); - yajl_free_error(handle, (unsigned char*) yajlError); - } - else - { - errMsg = enif_make_string(env, "unknown parse error", ERL_NIF_LATIN1); - } - - return enif_make_tuple(env, 2, - enif_make_atom(env, "error"), - enif_make_tuple(env, 2, - enif_make_uint(env, handle->bytesConsumed), - errMsg - ) - ); -} - - -static void -add_to_head(void* vctx, ERL_NIF_TERM newhead) -{ - decode_ctx* ctx = (decode_ctx*)vctx; - ctx->head = enif_make_list_cell(ctx->env, newhead, ctx->head); -} - -static int -decode_null(void* ctx) -{ - add_to_head(ctx, enif_make_atom(ENV(ctx), "null")); - return CONTINUE; -} - -static int -decode_boolean(void* ctx, int val) -{ - add_to_head(ctx, enif_make_atom(ENV(ctx), val ? "true" : "false")); - return CONTINUE; -} - -static int -decode_number(void * ctx, const char * numberVal, unsigned int numberLen) -{ - // scan in the input to see if it's a float or int - - int numberType = 0; // 0 means integer, 1 means float - unsigned int i; - ErlNifBinary bin; - int missingDot = 1; - unsigned int expPos; - - for(i=0; i<numberLen; i++) { - switch (numberVal[i]) { - case '.': - missingDot = 0; - numberType = 1; // it's a float - goto loopend; - case 'E': - case 'e': - expPos = i; - numberType = 1; // it's a float - goto loopend; - } - } -loopend: - if ((numberType == 1) && missingDot) - { - if(!enif_alloc_binary_compat(ENV(ctx), numberLen + 2, &bin)) - { - return CANCEL; - } - memcpy(bin.data, numberVal, expPos); - bin.data[expPos] = '.'; - bin.data[expPos + 1] = '0'; - memcpy(bin.data + expPos + 2, numberVal + expPos, numberLen - expPos); - } - else - { - if(!enif_alloc_binary_compat(ENV(ctx), numberLen, &bin)) - { - return CANCEL; - } - memcpy(bin.data, numberVal, numberLen); - } - add_to_head(ctx, enif_make_tuple(ENV(ctx), 2, - enif_make_int(ENV(ctx), numberType), - enif_make_binary(ENV(ctx), &bin))); - return CONTINUE; -} - - - -static int -decode_string(void* ctx, const unsigned char* data, unsigned int size) -{ - ErlNifBinary bin; - if(!enif_alloc_binary_compat(ENV(ctx), size, &bin)) - { - return CANCEL; - } - memcpy(bin.data, data, size); - add_to_head(ctx, enif_make_binary(ENV(ctx), &bin)); - return CONTINUE; -} - -static int -decode_start_array(void* ctx) -{ - add_to_head(ctx, enif_make_int(ENV(ctx), 0)); - return CONTINUE; -} - - -static int -decode_end_array(void* ctx) -{ - add_to_head(ctx, enif_make_int(ENV(ctx), 1)); - return CONTINUE; -} - - -static int -decode_start_map(void* ctx) -{ - add_to_head(ctx, enif_make_int(ENV(ctx), 2)); - return CONTINUE; -} - - -static int -decode_end_map(void* ctx) -{ - add_to_head(ctx, enif_make_int(ENV(ctx), 3)); - return CONTINUE; -} - - -static int -decode_map_key(void* ctx, const unsigned char* data, unsigned int size) -{ - ErlNifBinary bin; - if(!enif_alloc_binary_compat(ENV(ctx), size, &bin)) - { - return CANCEL; - } - memcpy(bin.data, data, size); - add_to_head(ctx, enif_make_tuple(ENV(ctx), 2, - enif_make_int(ENV(ctx), 3), - enif_make_binary(ENV(ctx), &bin))); - return CONTINUE; -} - -static yajl_callbacks -decoder_callbacks = { - decode_null, - decode_boolean, - NULL, - NULL, - decode_number, - decode_string, - decode_start_map, - decode_map_key, - decode_end_map, - decode_start_array, - decode_end_array -}; - -static int -check_rest(unsigned char* data, unsigned int size, unsigned int used) -{ - unsigned int i = 0; - for(i = used; i < size; i++) - { - switch(data[i]) - { - case ' ': - case '\t': - case '\r': - case '\n': - continue; - default: - return CANCEL; - } - } - - return CONTINUE; -} - -ERL_NIF_TERM -reverse_tokens(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - decode_ctx ctx; - yajl_parser_config conf = {0, 1}; // No comments, check utf8 - yajl_handle handle = yajl_alloc(&decoder_callbacks, &conf, NULL, &ctx); - yajl_status status; - unsigned int used; - ErlNifBinary bin; - ERL_NIF_TERM ret; - - ctx.env = env; - ctx.head = enif_make_list_from_array(env, NULL, 0); - - if(!enif_inspect_iolist_as_binary(env, argv[0], &bin)) - { - ret = enif_make_badarg(env); - goto done; - } - - status = yajl_parse(handle, bin.data, bin.size); - used = handle->bytesConsumed; - - // Parsing something like "2.0" (without quotes) will - // cause a spurious semi-error. We add the extra size - // check so that "2008-20-10" doesn't pass. - if(status == yajl_status_insufficient_data && used == bin.size) - { - status = yajl_parse_complete(handle); - } - - if(status == yajl_status_ok && used != bin.size) - { - if(check_rest(bin.data, bin.size, used) == CANCEL) - { - ret = enif_make_tuple(env, 2, - enif_make_atom(env, "error"), - enif_make_atom(env, "garbage_after_value") - ); - goto done; - } - } - - switch(status) - { - case yajl_status_ok: - ret = enif_make_tuple(env, 2, enif_make_atom(env, "ok"), ctx.head); - goto done; - - case yajl_status_error: - ret = make_error(handle, env); - goto done; - - case yajl_status_insufficient_data: - ret = enif_make_tuple(env, 2, - enif_make_atom(env, "error"), - enif_make_atom(env, "insufficient_data") - ); - goto done; - - case yajl_status_client_canceled: - /* the only time we do this is when we can't allocate a binary. */ - ret = enif_make_tuple(env, 2, - enif_make_atom(env, "error"), - enif_make_atom(env, "insufficient_memory") - ); - goto done; - - default: - ret = enif_make_tuple(env, 2, - enif_make_atom(env, "error"), - enif_make_atom(env, "unknown") - ); - goto done; - } - -done: - if(handle != NULL) yajl_free(handle); - return ret; -} diff --git a/src/ejson/c_src/ejson.c b/src/ejson/c_src/ejson.c deleted file mode 100644 index 390f762f7..000000000 --- a/src/ejson/c_src/ejson.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "erl_nif.h" - -ERL_NIF_TERM final_encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -ERL_NIF_TERM reverse_tokens(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - -int -on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM info) -{ - return 0; -} - -int -on_reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM info) -{ - return 0; -} - -int -on_upgrade(ErlNifEnv* env, void** priv_data, void** old_data, ERL_NIF_TERM info) -{ - return 0; -} - -static ErlNifFunc nif_funcs[] = -{ - {"final_encode", 1, final_encode}, - {"reverse_tokens", 1, reverse_tokens} -}; - -ERL_NIF_INIT(ejson, nif_funcs, &on_load, &on_reload, &on_upgrade, NULL); diff --git a/src/ejson/c_src/encode.c b/src/ejson/c_src/encode.c deleted file mode 100644 index 1dbd1dfbf..000000000 --- a/src/ejson/c_src/encode.c +++ /dev/null @@ -1,200 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include "erl_nif.h" -#include "erl_nif_compat.h" -#include "yajl/yajl_encode.h" - -#if defined(_WIN32) || defined(WIN32) || defined(__WIN32__) -#include <float.h> -#define isnan _isnan -#define isinf !_finite -#define snprintf _snprintf -#endif - -#define SUCCESS 0 -#define NOMEM 1 -#define BADARG 2 - - -typedef struct { - ErlNifEnv* env; - ErlNifBinary bin; - size_t fill_offset; - int error; -} encode_ctx; - - -static int -ensure_buffer(void* vctx, unsigned int len) { - encode_ctx* ctx = (encode_ctx*)vctx; - if ((ctx->bin.size - ctx->fill_offset) < len) { - if(!enif_realloc_binary_compat(ctx->env, &(ctx->bin), (ctx->bin.size * 2) + len)) { - return NOMEM; - } - } - return SUCCESS; -} - -static void -fill_buffer(void* vctx, const char* str, unsigned int len) -{ - encode_ctx* ctx = (encode_ctx*)vctx; - - if (ctx->error || (ctx->error = ensure_buffer(vctx, len))) { - return; - } - memcpy(ctx->bin.data + ctx->fill_offset, str, len); - ctx->fill_offset += len; -} - -/* Json encode the string binary into the ctx.bin, - with surrounding quotes and all */ -static int -encode_string(void* vctx, ERL_NIF_TERM binary) -{ - encode_ctx* ctx = (encode_ctx*)vctx; - ErlNifBinary bin; - - if(!enif_inspect_binary(ctx->env, binary, &bin)) { - return NOMEM; - } - fill_buffer(ctx, "\"", 1); - if (ctx->error) { - return ctx->error; - } - yajl_string_encode2(fill_buffer, ctx, bin.data, bin.size); - fill_buffer(ctx, "\"", 1); - - return ctx->error; -} - -static ERL_NIF_TERM -no_mem_error(ErlNifEnv* env) -{ - return enif_make_tuple(env, 2, - enif_make_atom(env, "error"), - enif_make_atom(env, "insufficient_memory")); -} - -ERL_NIF_TERM -final_encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - ERL_NIF_TERM head = argv[0]; - ERL_NIF_TERM term; - double number; - encode_ctx ctx; - char* start; - size_t len; - size_t i; - - ctx.env = env; - ctx.fill_offset = 0; - ctx.error = 0; - - if (!enif_alloc_binary_compat(env, 100, &ctx.bin)) { - return no_mem_error(env); - } - - while(enif_get_list_cell(env, head, &term, &head)) { - ErlNifBinary termbin; - const ERL_NIF_TERM* array; - int arity; - int code; - - // We scan the list, looking for things to write into the binary, or - // encode and then write into the binary. We encode values that are - // tuples tagged with a type and a value: {Type, Value} where Type - // is a an Integer and Value is what is to be encoded - - if (enif_get_tuple(env, term, &arity, &array)) { - // It's a tuple to encode and copy - if (arity != 2 || !enif_get_int(env, array[0], &code)) { - // not arity 2 or the first element isn't an int - ctx.error = BADARG; - goto done; - } - if (code == 0) { - // {0, String} - if (encode_string(&ctx, array[1]) != SUCCESS) { - goto done; - } - } - else { - // {1, Double} - if(!enif_get_double(env, array[1], &number)) { - ctx.error = BADARG; - goto done; - } - // We can't encode these. - if (isnan(number) || isinf(number)) { - ctx.error = BADARG; - goto done; - } - if ((ctx.error = ensure_buffer(&ctx, 32)) != SUCCESS) { - goto done; - } - // write the string into the buffer - start = (char*) (ctx.bin.data + ctx.fill_offset); - snprintf(start, 32, "%0.20g", number); - len = strlen(start); - for(i = 0; i < len; i++) { - if(start[i] == '.' || start[i] == 'e' || start[i] == 'E') { - break; - } - } - if(i == len) { - if(i > 29) { - ctx.error = BADARG; - goto done; - } - start[len++] = '.'; - start[len++] = '0'; - } - // increment the length - ctx.fill_offset += len; - } - } else if (enif_inspect_binary(env, term, &termbin)) { - // this is a regular binary, copy the contents into the buffer - fill_buffer(&ctx, (char*)termbin.data, termbin.size); - if (ctx.error) { - goto done; - } - } - else { - //not a binary, not a tuple, wtf! - ctx.error = BADARG; - goto done; - } - } -done: - if (ctx.error == NOMEM) { - enif_release_binary_compat(env, &ctx.bin); - return no_mem_error(env); - } else if (ctx.error == BADARG) { - enif_release_binary_compat(env, &ctx.bin); - return enif_make_badarg(env); - } - - // Resize the binary to our exact final size - if(!enif_realloc_binary_compat(env, &(ctx.bin), ctx.fill_offset)) { - enif_release_binary_compat(env, &ctx.bin); - return no_mem_error(env); - } - // make the binary term which transfers ownership - return enif_make_binary(env, &ctx.bin); -} - diff --git a/src/ejson/c_src/erl_nif_compat.h b/src/ejson/c_src/erl_nif_compat.h deleted file mode 100644 index 548ea7aa7..000000000 --- a/src/ejson/c_src/erl_nif_compat.h +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (c) 2010-2011 Basho Technologies, Inc. - * With some minor modifications for Apache CouchDB. - * - * This file is provided to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. -*/ - -#ifndef ERL_NIF_COMPAT_H_ -#define ERL_NIF_COMPAT_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include "erl_nif.h" - - -#if ERL_NIF_MAJOR_VERSION == 0 && ERL_NIF_MINOR_VERSION == 1 -#define OTP_R13B03 -#elif ERL_NIF_MAJOR_VERSION == 1 && ERL_NIF_MINOR_VERSION == 0 -#define OTP_R13B04 -#elif ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION == 0 -#define OTP_R14A -#define OTP_R14B -#define OTP_R14B01 -#elif ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION == 1 -#define OTP_R14B02 -#endif - - -#ifdef OTP_R13B03 - -#define enif_open_resource_type_compat enif_open_resource_type -#define enif_alloc_resource_compat enif_alloc_resource -#define enif_release_resource_compat enif_release_resource -#define enif_alloc_binary_compat enif_alloc_binary -#define enif_alloc_compat enif_alloc -#define enif_release_binary_compat enif_release_binary -#define enif_free_compat enif_free -#define enif_get_atom_compat enif_get_atom -#define enif_priv_data_compat enif_get_data -#define enif_make_uint_compat enif_make_ulong - -#define enif_make_string_compat(E, B, Enc) \ - enif_make_string(E, B) - -#endif /* R13B03 */ - - -#ifdef OTP_R13B04 - -#define enif_open_resource_type_compat enif_open_resource_type -#define enif_alloc_resource_compat enif_alloc_resource -#define enif_release_resource_compat enif_release_resource -#define enif_alloc_binary_compat enif_alloc_binary -#define enif_realloc_binary_compat enif_realloc_binary -#define enif_release_binary_compat enif_release_binary -#define enif_alloc_compat enif_alloc -#define enif_free_compat enif_free -#define enif_get_atom_compat enif_get_atom -#define enif_priv_data_compat enif_priv_data -#define enif_make_string_compat enif_make_string -#define enif_make_uint_compat enif_make_uint - -#endif /* R13B04 */ - - -/* OTP R14 and future releases */ -#if !defined(OTP_R13B03) && !defined(OTP_R13B04) - -#define enif_open_resource_type_compat(E, N, D, F, T) \ - enif_open_resource_type(E, NULL, N, D, F, T) - -#define enif_alloc_resource_compat(E, T, S) \ - enif_alloc_resource(T, S) - -#define enif_release_resource_compat(E, H) \ - enif_release_resource(H) - -#define enif_alloc_binary_compat(E, S, B) \ - enif_alloc_binary(S, B) - -#define enif_realloc_binary_compat(E, S, B) \ - enif_realloc_binary(S, B) - -#define enif_release_binary_compat(E, B) \ - enif_release_binary(B) - -#define enif_alloc_compat(E, S) \ - enif_alloc(S) - -#define enif_free_compat(E, P) \ - enif_free(P) - -#define enif_get_atom_compat(E, T, B, S) \ - enif_get_atom(E, T, B, S, ERL_NIF_LATIN1) - -#define enif_priv_data_compat enif_priv_data -#define enif_make_string_compat enif_make_string -#define enif_make_uint_compat enif_make_uint - -#endif /* R14 and future releases */ - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* ERL_NIF_COMPAT_H_ */ diff --git a/src/ejson/c_src/yajl/yajl.c b/src/ejson/c_src/yajl/yajl.c deleted file mode 100644 index 39d8b9f78..000000000 --- a/src/ejson/c_src/yajl/yajl.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yajl_parse.h" -#include "yajl_lex.h" -#include "yajl_parser.h" -#include "yajl_alloc.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -const char * -yajl_status_to_string(yajl_status stat) -{ - const char * statStr = "unknown"; - switch (stat) { - case yajl_status_ok: - statStr = "ok, no error"; - break; - case yajl_status_client_canceled: - statStr = "client canceled parse"; - break; - case yajl_status_insufficient_data: - statStr = "eof was met before the parse could complete"; - break; - case yajl_status_error: - statStr = "parse error"; - break; - } - return statStr; -} - -yajl_handle -yajl_alloc(const yajl_callbacks * callbacks, - const yajl_parser_config * config, - const yajl_alloc_funcs * afs, - void * ctx) -{ - unsigned int allowComments = 0; - unsigned int validateUTF8 = 0; - yajl_handle hand = NULL; - yajl_alloc_funcs afsBuffer; - - /* first order of business is to set up memory allocation routines */ - if (afs != NULL) { - if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) - { - return NULL; - } - } else { - yajl_set_default_alloc_funcs(&afsBuffer); - afs = &afsBuffer; - } - - hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t)); - - /* copy in pointers to allocation routines */ - memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); - - if (config != NULL) { - allowComments = config->allowComments; - validateUTF8 = config->checkUTF8; - } - - hand->callbacks = callbacks; - hand->ctx = ctx; - hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8); - hand->bytesConsumed = 0; - hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); - yajl_bs_init(hand->stateStack, &(hand->alloc)); - - yajl_bs_push(hand->stateStack, yajl_state_start); - - return hand; -} - -void -yajl_free(yajl_handle handle) -{ - yajl_bs_free(handle->stateStack); - yajl_buf_free(handle->decodeBuf); - yajl_lex_free(handle->lexer); - YA_FREE(&(handle->alloc), handle); -} - -yajl_status -yajl_parse(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLen) -{ - yajl_status status; - status = yajl_do_parse(hand, jsonText, jsonTextLen); - return status; -} - -yajl_status -yajl_parse_complete(yajl_handle hand) -{ - /* The particular case we want to handle is a trailing number. - * Further input consisting of digits could cause our interpretation - * of the number to change (buffered "1" but "2" comes in). - * A very simple approach to this is to inject whitespace to terminate - * any number in the lex buffer. - */ - return yajl_parse(hand, (const unsigned char *)" ", 1); -} - -unsigned char * -yajl_get_error(yajl_handle hand, int verbose, - const unsigned char * jsonText, unsigned int jsonTextLen) -{ - return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose); -} - -unsigned int -yajl_get_bytes_consumed(yajl_handle hand) -{ - if (!hand) return 0; - else return hand->bytesConsumed; -} - - -void -yajl_free_error(yajl_handle hand, unsigned char * str) -{ - /* use memory allocation functions if set */ - YA_FREE(&(hand->alloc), str); -} - -/* XXX: add utility routines to parse from file */ diff --git a/src/ejson/c_src/yajl/yajl_alloc.c b/src/ejson/c_src/yajl/yajl_alloc.c deleted file mode 100644 index ccfb7c3dd..000000000 --- a/src/ejson/c_src/yajl/yajl_alloc.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file yajl_alloc.h - * default memory allocation routines for yajl which use malloc/realloc and - * free - */ - -#include "yajl_alloc.h" -#include <stdlib.h> - -static void * yajl_internal_malloc(void *ctx, unsigned int sz) -{ - return malloc(sz); -} - -static void * yajl_internal_realloc(void *ctx, void * previous, - unsigned int sz) -{ - return realloc(previous, sz); -} - -static void yajl_internal_free(void *ctx, void * ptr) -{ - free(ptr); -} - -void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) -{ - yaf->malloc = yajl_internal_malloc; - yaf->free = yajl_internal_free; - yaf->realloc = yajl_internal_realloc; - yaf->ctx = NULL; -} - diff --git a/src/ejson/c_src/yajl/yajl_alloc.h b/src/ejson/c_src/yajl/yajl_alloc.h deleted file mode 100644 index cc1e5cf43..000000000 --- a/src/ejson/c_src/yajl/yajl_alloc.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file yajl_alloc.h - * default memory allocation routines for yajl which use malloc/realloc and - * free - */ - -#ifndef __YAJL_ALLOC_H__ -#define __YAJL_ALLOC_H__ - -#include "yajl_common.h" - -#define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) -#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) -#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)) - -void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); - -#endif diff --git a/src/ejson/c_src/yajl/yajl_buf.c b/src/ejson/c_src/yajl/yajl_buf.c deleted file mode 100644 index 04e608a3e..000000000 --- a/src/ejson/c_src/yajl/yajl_buf.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yajl_buf.h" - -#include <assert.h> -#include <stdlib.h> -#include <string.h> - -#define YAJL_BUF_INIT_SIZE 2048 - -struct yajl_buf_t { - unsigned int len; - unsigned int used; - unsigned char * data; - yajl_alloc_funcs * alloc; -}; - -static -void yajl_buf_ensure_available(yajl_buf buf, unsigned int want) -{ - unsigned int need; - - assert(buf != NULL); - - /* first call */ - if (buf->data == NULL) { - buf->len = YAJL_BUF_INIT_SIZE; - buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len); - buf->data[0] = 0; - } - - need = buf->len; - - while (want >= (need - buf->used)) need <<= 1; - - if (need != buf->len) { - buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need); - buf->len = need; - } -} - -yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc) -{ - yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t)); - memset((void *) b, 0, sizeof(struct yajl_buf_t)); - b->alloc = alloc; - return b; -} - -void yajl_buf_free(yajl_buf buf) -{ - assert(buf != NULL); - if (buf->data) YA_FREE(buf->alloc, buf->data); - YA_FREE(buf->alloc, buf); -} - -void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len) -{ - yajl_buf_ensure_available(buf, len); - if (len > 0) { - assert(data != NULL); - memcpy(buf->data + buf->used, data, len); - buf->used += len; - buf->data[buf->used] = 0; - } -} - -void yajl_buf_clear(yajl_buf buf) -{ - buf->used = 0; - if (buf->data) buf->data[buf->used] = 0; -} - -const unsigned char * yajl_buf_data(yajl_buf buf) -{ - return buf->data; -} - -unsigned int yajl_buf_len(yajl_buf buf) -{ - return buf->used; -} - -void -yajl_buf_truncate(yajl_buf buf, unsigned int len) -{ - assert(len <= buf->used); - buf->used = len; -} diff --git a/src/ejson/c_src/yajl/yajl_buf.h b/src/ejson/c_src/yajl/yajl_buf.h deleted file mode 100644 index a6dcbe9a5..000000000 --- a/src/ejson/c_src/yajl/yajl_buf.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __YAJL_BUF_H__ -#define __YAJL_BUF_H__ - -#include "yajl_common.h" -#include "yajl_alloc.h" - -/* - * Implementation/performance notes. If this were moved to a header - * only implementation using #define's where possible we might be - * able to sqeeze a little performance out of the guy by killing function - * call overhead. YMMV. - */ - -/** - * yajl_buf is a buffer with exponential growth. the buffer ensures that - * you are always null padded. - */ -typedef struct yajl_buf_t * yajl_buf; - -/* allocate a new buffer */ -yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc); - -/* free the buffer */ -void yajl_buf_free(yajl_buf buf); - -/* append a number of bytes to the buffer */ -void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len); - -/* empty the buffer */ -void yajl_buf_clear(yajl_buf buf); - -/* get a pointer to the beginning of the buffer */ -const unsigned char * yajl_buf_data(yajl_buf buf); - -/* get the length of the buffer */ -unsigned int yajl_buf_len(yajl_buf buf); - -/* truncate the buffer */ -void yajl_buf_truncate(yajl_buf buf, unsigned int len); - -#endif diff --git a/src/ejson/c_src/yajl/yajl_bytestack.h b/src/ejson/c_src/yajl/yajl_bytestack.h deleted file mode 100644 index 3b49d17f9..000000000 --- a/src/ejson/c_src/yajl/yajl_bytestack.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * A header only implementation of a simple stack of bytes, used in YAJL - * to maintain parse state. - */ - -#ifndef __YAJL_BYTESTACK_H__ -#define __YAJL_BYTESTACK_H__ - -#include "yajl_common.h" - -#define YAJL_BS_INC 128 - -typedef struct yajl_bytestack_t -{ - unsigned char * stack; - unsigned int size; - unsigned int used; - yajl_alloc_funcs * yaf; -} yajl_bytestack; - -/* initialize a bytestack */ -#define yajl_bs_init(obs, _yaf) { \ - (obs).stack = NULL; \ - (obs).size = 0; \ - (obs).used = 0; \ - (obs).yaf = (_yaf); \ - } \ - - -/* initialize a bytestack */ -#define yajl_bs_free(obs) \ - if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack); - -#define yajl_bs_current(obs) \ - (assert((obs).used > 0), (obs).stack[(obs).used - 1]) - -#define yajl_bs_push(obs, byte) { \ - if (((obs).size - (obs).used) == 0) { \ - (obs).size += YAJL_BS_INC; \ - (obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\ - (void *) (obs).stack, (obs).size);\ - } \ - (obs).stack[((obs).used)++] = (byte); \ -} - -/* removes the top item of the stack, returns nothing */ -#define yajl_bs_pop(obs) { ((obs).used)--; } - -#define yajl_bs_set(obs, byte) \ - (obs).stack[((obs).used) - 1] = (byte); - - -#endif diff --git a/src/ejson/c_src/yajl/yajl_common.h b/src/ejson/c_src/yajl/yajl_common.h deleted file mode 100644 index a227debbd..000000000 --- a/src/ejson/c_src/yajl/yajl_common.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __YAJL_COMMON_H__ -#define __YAJL_COMMON_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define YAJL_MAX_DEPTH 128 - -/* msft dll export gunk. To build a DLL on windows, you - * must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared - * DLL, you must define YAJL_SHARED and WIN32 */ -#if defined(WIN32) && defined(YAJL_SHARED) -# ifdef YAJL_BUILD -# define YAJL_API __declspec(dllexport) -# else -# define YAJL_API __declspec(dllimport) -# endif -#else -# define YAJL_API -#endif - -/** pointer to a malloc function, supporting client overriding memory - * allocation routines */ -typedef void * (*yajl_malloc_func)(void *ctx, unsigned int sz); - -/** pointer to a free function, supporting client overriding memory - * allocation routines */ -typedef void (*yajl_free_func)(void *ctx, void * ptr); - -/** pointer to a realloc function which can resize an allocation. */ -typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, unsigned int sz); - -/** A structure which can be passed to yajl_*_alloc routines to allow the - * client to specify memory allocation functions to be used. */ -typedef struct -{ - /** pointer to a function that can allocate uninitialized memory */ - yajl_malloc_func malloc; - /** pointer to a function that can resize memory allocations */ - yajl_realloc_func realloc; - /** pointer to a function that can free memory allocated using - * reallocFunction or mallocFunction */ - yajl_free_func free; - /** a context pointer that will be passed to above allocation routines */ - void * ctx; -} yajl_alloc_funcs; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/ejson/c_src/yajl/yajl_encode.c b/src/ejson/c_src/yajl/yajl_encode.c deleted file mode 100644 index ad5b1c591..000000000 --- a/src/ejson/c_src/yajl/yajl_encode.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yajl_encode.h" - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> - -static void CharToHex(unsigned char c, char * hexBuf) -{ - const char * hexchar = "0123456789ABCDEF"; - hexBuf[0] = hexchar[c >> 4]; - hexBuf[1] = hexchar[c & 0x0F]; -} - -void -yajl_string_encode(yajl_buf buf, const unsigned char * str, - unsigned int len) -{ - yajl_string_encode2((const yajl_print_t) &yajl_buf_append, buf, str, len); -} - -void -yajl_string_encode2(const yajl_print_t print, - void * ctx, - const unsigned char * str, - unsigned int len) -{ - unsigned int beg = 0; - unsigned int end = 0; - char hexBuf[7]; - hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0'; - hexBuf[6] = 0; - - while (end < len) { - const char * escaped = NULL; - switch (str[end]) { - case '\r': escaped = "\\r"; break; - case '\n': escaped = "\\n"; break; - case '\\': escaped = "\\\\"; break; - /* case '/': escaped = "\\/"; break; */ - case '"': escaped = "\\\""; break; - case '\f': escaped = "\\f"; break; - case '\b': escaped = "\\b"; break; - case '\t': escaped = "\\t"; break; - default: - if ((unsigned char) str[end] < 32) { - CharToHex(str[end], hexBuf + 4); - escaped = hexBuf; - } - break; - } - if (escaped != NULL) { - print(ctx, (const char *) (str + beg), end - beg); - print(ctx, escaped, strlen(escaped)); - beg = ++end; - } else { - ++end; - } - } - print(ctx, (const char *) (str + beg), end - beg); -} - -static void hexToDigit(unsigned int * val, const unsigned char * hex) -{ - unsigned int i; - for (i=0;i<4;i++) { - unsigned char c = hex[i]; - if (c >= 'A') c = (c & ~0x20) - 7; - c -= '0'; - assert(!(c & 0xF0)); - *val = (*val << 4) | c; - } -} - -static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) -{ - if (codepoint < 0x80) { - utf8Buf[0] = (char) codepoint; - utf8Buf[1] = 0; - } else if (codepoint < 0x0800) { - utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0); - utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80); - utf8Buf[2] = 0; - } else if (codepoint < 0x10000) { - utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0); - utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80); - utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80); - utf8Buf[3] = 0; - } else if (codepoint < 0x200000) { - utf8Buf[0] =(char)((codepoint >> 18) | 0xF0); - utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80); - utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80); - utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80); - utf8Buf[4] = 0; - } else { - utf8Buf[0] = '?'; - utf8Buf[1] = 0; - } -} - -void yajl_string_decode(yajl_buf buf, const unsigned char * str, - unsigned int len) -{ - unsigned int beg = 0; - unsigned int end = 0; - - while (end < len) { - if (str[end] == '\\') { - char utf8Buf[5]; - const char * unescaped = "?"; - yajl_buf_append(buf, str + beg, end - beg); - switch (str[++end]) { - case 'r': unescaped = "\r"; break; - case 'n': unescaped = "\n"; break; - case '\\': unescaped = "\\"; break; - case '/': unescaped = "/"; break; - case '"': unescaped = "\""; break; - case 'f': unescaped = "\f"; break; - case 'b': unescaped = "\b"; break; - case 't': unescaped = "\t"; break; - case 'u': { - unsigned int codepoint = 0; - hexToDigit(&codepoint, str + ++end); - end+=3; - /* check if this is a surrogate */ - if ((codepoint & 0xFC00) == 0xD800) { - end++; - if (str[end] == '\\' && str[end + 1] == 'u') { - unsigned int surrogate = 0; - hexToDigit(&surrogate, str + end + 2); - codepoint = - (((codepoint & 0x3F) << 10) | - ((((codepoint >> 6) & 0xF) + 1) << 16) | - (surrogate & 0x3FF)); - end += 5; - } else { - unescaped = "?"; - break; - } - } - - Utf32toUtf8(codepoint, utf8Buf); - unescaped = utf8Buf; - break; - } - default: - assert("this should never happen" == NULL); - } - yajl_buf_append(buf, unescaped, strlen(unescaped)); - beg = ++end; - } else { - end++; - } - } - yajl_buf_append(buf, str + beg, end - beg); -} diff --git a/src/ejson/c_src/yajl/yajl_encode.h b/src/ejson/c_src/yajl/yajl_encode.h deleted file mode 100644 index 3e3b0923d..000000000 --- a/src/ejson/c_src/yajl/yajl_encode.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __YAJL_ENCODE_H__ -#define __YAJL_ENCODE_H__ - -#include "yajl_buf.h" -#include "yajl_gen.h" - -void yajl_string_encode2(const yajl_print_t printer, - void * ctx, - const unsigned char * str, - unsigned int length); - -void yajl_string_encode(yajl_buf buf, const unsigned char * str, - unsigned int length); - -void yajl_string_decode(yajl_buf buf, const unsigned char * str, - unsigned int length); - -#endif diff --git a/src/ejson/c_src/yajl/yajl_gen.c b/src/ejson/c_src/yajl/yajl_gen.c deleted file mode 100644 index 6cfda0a4c..000000000 --- a/src/ejson/c_src/yajl/yajl_gen.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yajl_gen.h" -#include "yajl_buf.h" -#include "yajl_encode.h" - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <math.h> - -typedef enum { - yajl_gen_start, - yajl_gen_map_start, - yajl_gen_map_key, - yajl_gen_map_val, - yajl_gen_array_start, - yajl_gen_in_array, - yajl_gen_complete, - yajl_gen_error -} yajl_gen_state; - -struct yajl_gen_t -{ - unsigned int depth; - unsigned int pretty; - const char * indentString; - yajl_gen_state state[YAJL_MAX_DEPTH]; - yajl_print_t print; - void * ctx; /* yajl_buf */ - /* memory allocation routines */ - yajl_alloc_funcs alloc; -}; - -yajl_gen -yajl_gen_alloc(const yajl_gen_config * config, - const yajl_alloc_funcs * afs) -{ - return yajl_gen_alloc2(NULL, config, afs, NULL); -} - -yajl_gen -yajl_gen_alloc2(const yajl_print_t callback, - const yajl_gen_config * config, - const yajl_alloc_funcs * afs, - void * ctx) -{ - yajl_gen g = NULL; - yajl_alloc_funcs afsBuffer; - - /* first order of business is to set up memory allocation routines */ - if (afs != NULL) { - if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) - { - return NULL; - } - } else { - yajl_set_default_alloc_funcs(&afsBuffer); - afs = &afsBuffer; - } - - g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t)); - memset((void *) g, 0, sizeof(struct yajl_gen_t)); - /* copy in pointers to allocation routines */ - memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); - - if (config) { - g->pretty = config->beautify; - g->indentString = config->indentString ? config->indentString : " "; - } - - if (callback) { - g->print = callback; - g->ctx = ctx; - } else { - g->print = (yajl_print_t)&yajl_buf_append; - g->ctx = yajl_buf_alloc(&(g->alloc)); - } - - return g; -} - -void -yajl_gen_free(yajl_gen g) -{ - if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_free((yajl_buf)g->ctx); - YA_FREE(&(g->alloc), g); -} - -#define INSERT_SEP \ - if (g->state[g->depth] == yajl_gen_map_key || \ - g->state[g->depth] == yajl_gen_in_array) { \ - g->print(g->ctx, ",", 1); \ - if (g->pretty) g->print(g->ctx, "\n", 1); \ - } else if (g->state[g->depth] == yajl_gen_map_val) { \ - g->print(g->ctx, ":", 1); \ - if (g->pretty) g->print(g->ctx, " ", 1); \ - } - -#define INSERT_WHITESPACE \ - if (g->pretty) { \ - if (g->state[g->depth] != yajl_gen_map_val) { \ - unsigned int _i; \ - for (_i=0;_i<g->depth;_i++) \ - g->print(g->ctx, g->indentString, \ - strlen(g->indentString)); \ - } \ - } - -#define ENSURE_NOT_KEY \ - if (g->state[g->depth] == yajl_gen_map_key) { \ - return yajl_gen_keys_must_be_strings; \ - } \ - -/* check that we're not complete, or in error state. in a valid state - * to be generating */ -#define ENSURE_VALID_STATE \ - if (g->state[g->depth] == yajl_gen_error) { \ - return yajl_gen_in_error_state;\ - } else if (g->state[g->depth] == yajl_gen_complete) { \ - return yajl_gen_generation_complete; \ - } - -#define INCREMENT_DEPTH \ - if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded; - -#define APPENDED_ATOM \ - switch (g->state[g->depth]) { \ - case yajl_gen_start: \ - g->state[g->depth] = yajl_gen_complete; \ - break; \ - case yajl_gen_map_start: \ - case yajl_gen_map_key: \ - g->state[g->depth] = yajl_gen_map_val; \ - break; \ - case yajl_gen_array_start: \ - g->state[g->depth] = yajl_gen_in_array; \ - break; \ - case yajl_gen_map_val: \ - g->state[g->depth] = yajl_gen_map_key; \ - break; \ - default: \ - break; \ - } \ - -#define FINAL_NEWLINE \ - if (g->pretty && g->state[g->depth] == yajl_gen_complete) \ - g->print(g->ctx, "\n", 1); - -yajl_gen_status -yajl_gen_integer(yajl_gen g, long int number) -{ - char i[32]; - ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - sprintf(i, "%ld", number); - g->print(g->ctx, i, strlen(i)); - APPENDED_ATOM; - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -#if defined(_WIN32) || defined(WIN32) || defined(__WIN32__) -#include <float.h> -#define isnan _isnan -#define isinf !_finite -#endif - -yajl_gen_status -yajl_gen_double(yajl_gen g, double number) -{ - char i[32]; - ENSURE_VALID_STATE; ENSURE_NOT_KEY; - if (isnan(number) || isinf(number)) return yajl_gen_invalid_number; - INSERT_SEP; INSERT_WHITESPACE; - sprintf(i, "%g", number); - g->print(g->ctx, i, strlen(i)); - APPENDED_ATOM; - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_number(yajl_gen g, const char * s, unsigned int l) -{ - ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - g->print(g->ctx, s, l); - APPENDED_ATOM; - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_string(yajl_gen g, const unsigned char * str, - unsigned int len) -{ - ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE; - g->print(g->ctx, "\"", 1); - yajl_string_encode2(g->print, g->ctx, str, len); - g->print(g->ctx, "\"", 1); - APPENDED_ATOM; - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_null(yajl_gen g) -{ - ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - g->print(g->ctx, "null", strlen("null")); - APPENDED_ATOM; - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_bool(yajl_gen g, int boolean) -{ - const char * val = boolean ? "true" : "false"; - - ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - g->print(g->ctx, val, strlen(val)); - APPENDED_ATOM; - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_map_open(yajl_gen g) -{ - ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - INCREMENT_DEPTH; - - g->state[g->depth] = yajl_gen_map_start; - g->print(g->ctx, "{", 1); - if (g->pretty) g->print(g->ctx, "\n", 1); - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_map_close(yajl_gen g) -{ - ENSURE_VALID_STATE; - (g->depth)--; - if (g->pretty) g->print(g->ctx, "\n", 1); - APPENDED_ATOM; - INSERT_WHITESPACE; - g->print(g->ctx, "}", 1); - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_array_open(yajl_gen g) -{ - ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - INCREMENT_DEPTH; - g->state[g->depth] = yajl_gen_array_start; - g->print(g->ctx, "[", 1); - if (g->pretty) g->print(g->ctx, "\n", 1); - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_array_close(yajl_gen g) -{ - ENSURE_VALID_STATE; - if (g->pretty) g->print(g->ctx, "\n", 1); - (g->depth)--; - APPENDED_ATOM; - INSERT_WHITESPACE; - g->print(g->ctx, "]", 1); - FINAL_NEWLINE; - return yajl_gen_status_ok; -} - -yajl_gen_status -yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf, - unsigned int * len) -{ - if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf; - *buf = yajl_buf_data((yajl_buf)g->ctx); - *len = yajl_buf_len((yajl_buf)g->ctx); - return yajl_gen_status_ok; -} - -void -yajl_gen_clear(yajl_gen g) -{ - if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_clear((yajl_buf)g->ctx); -} diff --git a/src/ejson/c_src/yajl/yajl_gen.h b/src/ejson/c_src/yajl/yajl_gen.h deleted file mode 100644 index 97c20426c..000000000 --- a/src/ejson/c_src/yajl/yajl_gen.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file yajl_gen.h - * Interface to YAJL's JSON generation facilities. - */ - -#include "yajl_common.h" - -#ifndef __YAJL_GEN_H__ -#define __YAJL_GEN_H__ - -#ifdef __cplusplus -extern "C" { -#endif - /** generator status codes */ - typedef enum { - /** no error */ - yajl_gen_status_ok = 0, - /** at a point where a map key is generated, a function other than - * yajl_gen_string was called */ - yajl_gen_keys_must_be_strings, - /** YAJL's maximum generation depth was exceeded. see - * YAJL_MAX_DEPTH */ - yajl_max_depth_exceeded, - /** A generator function (yajl_gen_XXX) was called while in an error - * state */ - yajl_gen_in_error_state, - /** A complete JSON document has been generated */ - yajl_gen_generation_complete, - /** yajl_gen_double was passed an invalid floating point value - * (infinity or NaN). */ - yajl_gen_invalid_number, - /** A print callback was passed in, so there is no internal - * buffer to get from */ - yajl_gen_no_buf - } yajl_gen_status; - - /** an opaque handle to a generator */ - typedef struct yajl_gen_t * yajl_gen; - - /** a callback used for "printing" the results. */ - typedef void (*yajl_print_t)(void * ctx, - const char * str, - unsigned int len); - - /** configuration structure for the generator */ - typedef struct { - /** generate indented (beautiful) output */ - unsigned int beautify; - /** an opportunity to define an indent string. such as \\t or - * some number of spaces. default is four spaces ' '. This - * member is only relevant when beautify is true */ - const char * indentString; - } yajl_gen_config; - - /** allocate a generator handle - * \param config a pointer to a structure containing parameters which - * configure the behavior of the json generator - * \param allocFuncs an optional pointer to a structure which allows - * the client to overide the memory allocation - * used by yajl. May be NULL, in which case - * malloc/free/realloc will be used. - * - * \returns an allocated handle on success, NULL on failure (bad params) - */ - YAJL_API yajl_gen yajl_gen_alloc(const yajl_gen_config * config, - const yajl_alloc_funcs * allocFuncs); - - /** allocate a generator handle that will print to the specified - * callback rather than storing the results in an internal buffer. - * \param callback a pointer to a printer function. May be NULL - * in which case, the results will be store in an - * internal buffer. - * \param config a pointer to a structure containing parameters - * which configure the behavior of the json - * generator. - * \param allocFuncs an optional pointer to a structure which allows - * the client to overide the memory allocation - * used by yajl. May be NULL, in which case - * malloc/free/realloc will be used. - * \param ctx a context pointer that will be passed to the - * printer callback. - * - * \returns an allocated handle on success, NULL on failure (bad params) - */ - YAJL_API yajl_gen yajl_gen_alloc2(const yajl_print_t callback, - const yajl_gen_config * config, - const yajl_alloc_funcs * allocFuncs, - void * ctx); - - /** free a generator handle */ - YAJL_API void yajl_gen_free(yajl_gen handle); - - YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long int number); - /** generate a floating point number. number may not be infinity or - * NaN, as these have no representation in JSON. In these cases the - * generator will return 'yajl_gen_invalid_number' */ - YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number); - YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand, - const char * num, - unsigned int len); - YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand, - const unsigned char * str, - unsigned int len); - YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand); - YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean); - YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand); - YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand); - YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand); - YAJL_API yajl_gen_status yajl_gen_array_close(yajl_gen hand); - - /** access the null terminated generator buffer. If incrementally - * outputing JSON, one should call yajl_gen_clear to clear the - * buffer. This allows stream generation. */ - YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand, - const unsigned char ** buf, - unsigned int * len); - - /** clear yajl's output buffer, but maintain all internal generation - * state. This function will not "reset" the generator state, and is - * intended to enable incremental JSON outputing. */ - YAJL_API void yajl_gen_clear(yajl_gen hand); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/ejson/c_src/yajl/yajl_lex.c b/src/ejson/c_src/yajl/yajl_lex.c deleted file mode 100644 index 11e5f7bca..000000000 --- a/src/ejson/c_src/yajl/yajl_lex.c +++ /dev/null @@ -1,737 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yajl_lex.h" -#include "yajl_buf.h" - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <string.h> - -#ifdef YAJL_LEXER_DEBUG -static const char * -tokToStr(yajl_tok tok) -{ - switch (tok) { - case yajl_tok_bool: return "bool"; - case yajl_tok_colon: return "colon"; - case yajl_tok_comma: return "comma"; - case yajl_tok_eof: return "eof"; - case yajl_tok_error: return "error"; - case yajl_tok_left_brace: return "brace"; - case yajl_tok_left_bracket: return "bracket"; - case yajl_tok_null: return "null"; - case yajl_tok_integer: return "integer"; - case yajl_tok_double: return "double"; - case yajl_tok_right_brace: return "brace"; - case yajl_tok_right_bracket: return "bracket"; - case yajl_tok_string: return "string"; - case yajl_tok_string_with_escapes: return "string_with_escapes"; - } - return "unknown"; -} -#endif - -/* Impact of the stream parsing feature on the lexer: - * - * YAJL support stream parsing. That is, the ability to parse the first - * bits of a chunk of JSON before the last bits are available (still on - * the network or disk). This makes the lexer more complex. The - * responsibility of the lexer is to handle transparently the case where - * a chunk boundary falls in the middle of a token. This is - * accomplished is via a buffer and a character reading abstraction. - * - * Overview of implementation - * - * When we lex to end of input string before end of token is hit, we - * copy all of the input text composing the token into our lexBuf. - * - * Every time we read a character, we do so through the readChar function. - * readChar's responsibility is to handle pulling all chars from the buffer - * before pulling chars from input text - */ - -struct yajl_lexer_t { - /* the overal line and char offset into the data */ - unsigned int lineOff; - unsigned int charOff; - - /* error */ - yajl_lex_error error; - - /* a input buffer to handle the case where a token is spread over - * multiple chunks */ - yajl_buf buf; - - /* in the case where we have data in the lexBuf, bufOff holds - * the current offset into the lexBuf. */ - unsigned int bufOff; - - /* are we using the lex buf? */ - unsigned int bufInUse; - - /* shall we allow comments? */ - unsigned int allowComments; - - /* shall we validate utf8 inside strings? */ - unsigned int validateUTF8; - - yajl_alloc_funcs * alloc; -}; - -#define readChar(lxr, txt, off) \ - (((lxr)->bufInUse && yajl_buf_len((lxr)->buf) && lxr->bufOff < yajl_buf_len((lxr)->buf)) ? \ - (*((const unsigned char *) yajl_buf_data((lxr)->buf) + ((lxr)->bufOff)++)) : \ - ((txt)[(*(off))++])) - -#define unreadChar(lxr, off) ((*(off) > 0) ? (*(off))-- : ((lxr)->bufOff--)) - -yajl_lexer -yajl_lex_alloc(yajl_alloc_funcs * alloc, - unsigned int allowComments, unsigned int validateUTF8) -{ - yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t)); - memset((void *) lxr, 0, sizeof(struct yajl_lexer_t)); - lxr->buf = yajl_buf_alloc(alloc); - lxr->allowComments = allowComments; - lxr->validateUTF8 = validateUTF8; - lxr->alloc = alloc; - return lxr; -} - -void -yajl_lex_free(yajl_lexer lxr) -{ - yajl_buf_free(lxr->buf); - YA_FREE(lxr->alloc, lxr); - return; -} - -/* a lookup table which lets us quickly determine three things: - * VEC - valid escaped conrol char - * IJC - invalid json char - * VHC - valid hex char - * note. the solidus '/' may be escaped or not. - * note. the - */ -#define VEC 1 -#define IJC 2 -#define VHC 4 -static const char charLookupTable[256] = -{ -/*00*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , -/*08*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , -/*10*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , -/*18*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , - -/*20*/ 0 , 0 , VEC|IJC, 0 , 0 , 0 , 0 , 0 , -/*28*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , VEC , -/*30*/ VHC , VHC , VHC , VHC , VHC , VHC , VHC , VHC , -/*38*/ VHC , VHC , 0 , 0 , 0 , 0 , 0 , 0 , - -/*40*/ 0 , VHC , VHC , VHC , VHC , VHC , VHC , 0 , -/*48*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , -/*50*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , -/*58*/ 0 , 0 , 0 , 0 , VEC|IJC, 0 , 0 , 0 , - -/*60*/ 0 , VHC , VEC|VHC, VHC , VHC , VHC , VEC|VHC, 0 , -/*68*/ 0 , 0 , 0 , 0 , 0 , 0 , VEC , 0 , -/*70*/ 0 , 0 , VEC , 0 , VEC , 0 , 0 , 0 , -/*78*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - -/* include these so we don't have to always check the range of the char */ - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 -}; - -/** process a variable length utf8 encoded codepoint. - * - * returns: - * yajl_tok_string - if valid utf8 char was parsed and offset was - * advanced - * yajl_tok_eof - if end of input was hit before validation could - * complete - * yajl_tok_error - if invalid utf8 was encountered - * - * NOTE: on error the offset will point to the first char of the - * invalid utf8 */ -#define UTF8_CHECK_EOF if (*offset >= jsonTextLen) { return yajl_tok_eof; } - -static yajl_tok -yajl_lex_utf8_char(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset, - unsigned char curChar) -{ - if (curChar <= 0x7f) { - /* single byte */ - return yajl_tok_string; - } else if ((curChar >> 5) == 0x6) { - /* two byte */ - UTF8_CHECK_EOF; - curChar = readChar(lexer, jsonText, offset); - if ((curChar >> 6) == 0x2) return yajl_tok_string; - } else if ((curChar >> 4) == 0x0e) { - /* three byte */ - UTF8_CHECK_EOF; - curChar = readChar(lexer, jsonText, offset); - if ((curChar >> 6) == 0x2) { - UTF8_CHECK_EOF; - curChar = readChar(lexer, jsonText, offset); - if ((curChar >> 6) == 0x2) return yajl_tok_string; - } - } else if ((curChar >> 3) == 0x1e) { - /* four byte */ - UTF8_CHECK_EOF; - curChar = readChar(lexer, jsonText, offset); - if ((curChar >> 6) == 0x2) { - UTF8_CHECK_EOF; - curChar = readChar(lexer, jsonText, offset); - if ((curChar >> 6) == 0x2) { - UTF8_CHECK_EOF; - curChar = readChar(lexer, jsonText, offset); - if ((curChar >> 6) == 0x2) return yajl_tok_string; - } - } - } - - return yajl_tok_error; -} - -/* lex a string. input is the lexer, pointer to beginning of - * json text, and start of string (offset). - * a token is returned which has the following meanings: - * yajl_tok_string: lex of string was successful. offset points to - * terminating '"'. - * yajl_tok_eof: end of text was encountered before we could complete - * the lex. - * yajl_tok_error: embedded in the string were unallowable chars. offset - * points to the offending char - */ -#define STR_CHECK_EOF \ -if (*offset >= jsonTextLen) { \ - tok = yajl_tok_eof; \ - goto finish_string_lex; \ -} - -static yajl_tok -yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset) -{ - yajl_tok tok = yajl_tok_error; - int hasEscapes = 0; - - for (;;) { - unsigned char curChar; - - STR_CHECK_EOF; - - curChar = readChar(lexer, jsonText, offset); - - /* quote terminates */ - if (curChar == '"') { - tok = yajl_tok_string; - break; - } - /* backslash escapes a set of control chars, */ - else if (curChar == '\\') { - hasEscapes = 1; - STR_CHECK_EOF; - - /* special case \u */ - curChar = readChar(lexer, jsonText, offset); - if (curChar == 'u') { - unsigned int i = 0; - - for (i=0;i<4;i++) { - STR_CHECK_EOF; - curChar = readChar(lexer, jsonText, offset); - if (!(charLookupTable[curChar] & VHC)) { - /* back up to offending char */ - unreadChar(lexer, offset); - lexer->error = yajl_lex_string_invalid_hex_char; - goto finish_string_lex; - } - } - } else if (!(charLookupTable[curChar] & VEC)) { - /* back up to offending char */ - unreadChar(lexer, offset); - lexer->error = yajl_lex_string_invalid_escaped_char; - goto finish_string_lex; - } - } - /* when not validating UTF8 it's a simple table lookup to determine - * if the present character is invalid */ - else if(charLookupTable[curChar] & IJC) { - /* back up to offending char */ - unreadChar(lexer, offset); - lexer->error = yajl_lex_string_invalid_json_char; - goto finish_string_lex; - } - /* when in validate UTF8 mode we need to do some extra work */ - else if (lexer->validateUTF8) { - yajl_tok t = yajl_lex_utf8_char(lexer, jsonText, jsonTextLen, - offset, curChar); - - if (t == yajl_tok_eof) { - tok = yajl_tok_eof; - goto finish_string_lex; - } else if (t == yajl_tok_error) { - lexer->error = yajl_lex_string_invalid_utf8; - goto finish_string_lex; - } - } - /* accept it, and move on */ - } - finish_string_lex: - /* tell our buddy, the parser, wether he needs to process this string - * again */ - if (hasEscapes && tok == yajl_tok_string) { - tok = yajl_tok_string_with_escapes; - } - - return tok; -} - -#define RETURN_IF_EOF if (*offset >= jsonTextLen) return yajl_tok_eof; - -static yajl_tok -yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset) -{ - /** XXX: numbers are the only entities in json that we must lex - * _beyond_ in order to know that they are complete. There - * is an ambiguous case for integers at EOF. */ - - unsigned char c; - - yajl_tok tok = yajl_tok_integer; - - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - - /* optional leading minus */ - if (c == '-') { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - } - - /* a single zero, or a series of integers */ - if (c == '0') { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - } else if (c >= '1' && c <= '9') { - do { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - } while (c >= '0' && c <= '9'); - } else { - unreadChar(lexer, offset); - lexer->error = yajl_lex_missing_integer_after_minus; - return yajl_tok_error; - } - - /* optional fraction (indicates this is floating point) */ - if (c == '.') { - int numRd = 0; - - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - - while (c >= '0' && c <= '9') { - numRd++; - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - } - - if (!numRd) { - unreadChar(lexer, offset); - lexer->error = yajl_lex_missing_integer_after_decimal; - return yajl_tok_error; - } - tok = yajl_tok_double; - } - - /* optional exponent (indicates this is floating point) */ - if (c == 'e' || c == 'E') { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - - /* optional sign */ - if (c == '+' || c == '-') { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - } - - if (c >= '0' && c <= '9') { - do { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - } while (c >= '0' && c <= '9'); - } else { - unreadChar(lexer, offset); - lexer->error = yajl_lex_missing_integer_after_exponent; - return yajl_tok_error; - } - tok = yajl_tok_double; - } - - /* we always go "one too far" */ - unreadChar(lexer, offset); - - return tok; -} - -static yajl_tok -yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset) -{ - unsigned char c; - - yajl_tok tok = yajl_tok_comment; - - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - - /* either slash or star expected */ - if (c == '/') { - /* now we throw away until end of line */ - do { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - } while (c != '\n'); - } else if (c == '*') { - /* now we throw away until end of comment */ - for (;;) { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - if (c == '*') { - RETURN_IF_EOF; - c = readChar(lexer, jsonText, offset); - if (c == '/') { - break; - } else { - unreadChar(lexer, offset); - } - } - } - } else { - lexer->error = yajl_lex_invalid_char; - tok = yajl_tok_error; - } - - return tok; -} - -yajl_tok -yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset, - const unsigned char ** outBuf, unsigned int * outLen) -{ - yajl_tok tok = yajl_tok_error; - unsigned char c; - unsigned int startOffset = *offset; - - *outBuf = NULL; - *outLen = 0; - - for (;;) { - assert(*offset <= jsonTextLen); - - if (*offset >= jsonTextLen) { - tok = yajl_tok_eof; - goto lexed; - } - - c = readChar(lexer, jsonText, offset); - - switch (c) { - case '{': - tok = yajl_tok_left_bracket; - goto lexed; - case '}': - tok = yajl_tok_right_bracket; - goto lexed; - case '[': - tok = yajl_tok_left_brace; - goto lexed; - case ']': - tok = yajl_tok_right_brace; - goto lexed; - case ',': - tok = yajl_tok_comma; - goto lexed; - case ':': - tok = yajl_tok_colon; - goto lexed; - case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': - startOffset++; - break; - case 't': { - const char * want = "rue"; - do { - if (*offset >= jsonTextLen) { - tok = yajl_tok_eof; - goto lexed; - } - c = readChar(lexer, jsonText, offset); - if (c != *want) { - unreadChar(lexer, offset); - lexer->error = yajl_lex_invalid_string; - tok = yajl_tok_error; - goto lexed; - } - } while (*(++want)); - tok = yajl_tok_bool; - goto lexed; - } - case 'f': { - const char * want = "alse"; - do { - if (*offset >= jsonTextLen) { - tok = yajl_tok_eof; - goto lexed; - } - c = readChar(lexer, jsonText, offset); - if (c != *want) { - unreadChar(lexer, offset); - lexer->error = yajl_lex_invalid_string; - tok = yajl_tok_error; - goto lexed; - } - } while (*(++want)); - tok = yajl_tok_bool; - goto lexed; - } - case 'n': { - const char * want = "ull"; - do { - if (*offset >= jsonTextLen) { - tok = yajl_tok_eof; - goto lexed; - } - c = readChar(lexer, jsonText, offset); - if (c != *want) { - unreadChar(lexer, offset); - lexer->error = yajl_lex_invalid_string; - tok = yajl_tok_error; - goto lexed; - } - } while (*(++want)); - tok = yajl_tok_null; - goto lexed; - } - case '"': { - tok = yajl_lex_string(lexer, (const unsigned char *) jsonText, - jsonTextLen, offset); - goto lexed; - } - case '-': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - /* integer parsing wants to start from the beginning */ - unreadChar(lexer, offset); - tok = yajl_lex_number(lexer, (const unsigned char *) jsonText, - jsonTextLen, offset); - goto lexed; - } - case '/': - /* hey, look, a probable comment! If comments are disabled - * it's an error. */ - if (!lexer->allowComments) { - unreadChar(lexer, offset); - lexer->error = yajl_lex_unallowed_comment; - tok = yajl_tok_error; - goto lexed; - } - /* if comments are enabled, then we should try to lex - * the thing. possible outcomes are - * - successful lex (tok_comment, which means continue), - * - malformed comment opening (slash not followed by - * '*' or '/') (tok_error) - * - eof hit. (tok_eof) */ - tok = yajl_lex_comment(lexer, (const unsigned char *) jsonText, - jsonTextLen, offset); - if (tok == yajl_tok_comment) { - /* "error" is silly, but that's the initial - * state of tok. guilty until proven innocent. */ - tok = yajl_tok_error; - yajl_buf_clear(lexer->buf); - lexer->bufInUse = 0; - startOffset = *offset; - break; - } - /* hit error or eof, bail */ - goto lexed; - default: - lexer->error = yajl_lex_invalid_char; - tok = yajl_tok_error; - goto lexed; - } - } - - - lexed: - /* need to append to buffer if the buffer is in use or - * if it's an EOF token */ - if (tok == yajl_tok_eof || lexer->bufInUse) { - if (!lexer->bufInUse) yajl_buf_clear(lexer->buf); - lexer->bufInUse = 1; - yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset); - lexer->bufOff = 0; - - if (tok != yajl_tok_eof) { - *outBuf = yajl_buf_data(lexer->buf); - *outLen = yajl_buf_len(lexer->buf); - lexer->bufInUse = 0; - } - } else if (tok != yajl_tok_error) { - *outBuf = jsonText + startOffset; - *outLen = *offset - startOffset; - } - - /* special case for strings. skip the quotes. */ - if (tok == yajl_tok_string || tok == yajl_tok_string_with_escapes) - { - assert(*outLen >= 2); - (*outBuf)++; - *outLen -= 2; - } - - -#ifdef YAJL_LEXER_DEBUG - if (tok == yajl_tok_error) { - printf("lexical error: %s\n", - yajl_lex_error_to_string(yajl_lex_get_error(lexer))); - } else if (tok == yajl_tok_eof) { - printf("EOF hit\n"); - } else { - printf("lexed %s: '", tokToStr(tok)); - fwrite(*outBuf, 1, *outLen, stdout); - printf("'\n"); - } -#endif - - return tok; -} - -const char * -yajl_lex_error_to_string(yajl_lex_error error) -{ - switch (error) { - case yajl_lex_e_ok: - return "ok, no error"; - case yajl_lex_string_invalid_utf8: - return "invalid bytes in UTF8 string."; - case yajl_lex_string_invalid_escaped_char: - return "inside a string, '\\' occurs before a character " - "which it may not."; - case yajl_lex_string_invalid_json_char: - return "invalid character inside string."; - case yajl_lex_string_invalid_hex_char: - return "invalid (non-hex) character occurs after '\\u' inside " - "string."; - case yajl_lex_invalid_char: - return "invalid char in json text."; - case yajl_lex_invalid_string: - return "invalid string in json text."; - case yajl_lex_missing_integer_after_exponent: - return "malformed number, a digit is required after the exponent."; - case yajl_lex_missing_integer_after_decimal: - return "malformed number, a digit is required after the " - "decimal point."; - case yajl_lex_missing_integer_after_minus: - return "malformed number, a digit is required after the " - "minus sign."; - case yajl_lex_unallowed_comment: - return "probable comment found in input text, comments are " - "not enabled."; - } - return "unknown error code"; -} - - -/** allows access to more specific information about the lexical - * error when yajl_lex_lex returns yajl_tok_error. */ -yajl_lex_error -yajl_lex_get_error(yajl_lexer lexer) -{ - if (lexer == NULL) return (yajl_lex_error) -1; - return lexer->error; -} - -unsigned int yajl_lex_current_line(yajl_lexer lexer) -{ - return lexer->lineOff; -} - -unsigned int yajl_lex_current_char(yajl_lexer lexer) -{ - return lexer->charOff; -} - -yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int offset) -{ - const unsigned char * outBuf; - unsigned int outLen; - unsigned int bufLen = yajl_buf_len(lexer->buf); - unsigned int bufOff = lexer->bufOff; - unsigned int bufInUse = lexer->bufInUse; - yajl_tok tok; - - tok = yajl_lex_lex(lexer, jsonText, jsonTextLen, &offset, - &outBuf, &outLen); - - lexer->bufOff = bufOff; - lexer->bufInUse = bufInUse; - yajl_buf_truncate(lexer->buf, bufLen); - - return tok; -} diff --git a/src/ejson/c_src/yajl/yajl_lex.h b/src/ejson/c_src/yajl/yajl_lex.h deleted file mode 100644 index 559e54dba..000000000 --- a/src/ejson/c_src/yajl/yajl_lex.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __YAJL_LEX_H__ -#define __YAJL_LEX_H__ - -#include "yajl_common.h" - -typedef enum { - yajl_tok_bool, - yajl_tok_colon, - yajl_tok_comma, - yajl_tok_eof, - yajl_tok_error, - yajl_tok_left_brace, - yajl_tok_left_bracket, - yajl_tok_null, - yajl_tok_right_brace, - yajl_tok_right_bracket, - - /* we differentiate between integers and doubles to allow the - * parser to interpret the number without re-scanning */ - yajl_tok_integer, - yajl_tok_double, - - /* we differentiate between strings which require further processing, - * and strings that do not */ - yajl_tok_string, - yajl_tok_string_with_escapes, - - /* comment tokens are not currently returned to the parser, ever */ - yajl_tok_comment -} yajl_tok; - -typedef struct yajl_lexer_t * yajl_lexer; - -yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc, - unsigned int allowComments, - unsigned int validateUTF8); - -void yajl_lex_free(yajl_lexer lexer); - -/** - * run/continue a lex. "offset" is an input/output parameter. - * It should be initialized to zero for a - * new chunk of target text, and upon subsetquent calls with the same - * target text should passed with the value of the previous invocation. - * - * the client may be interested in the value of offset when an error is - * returned from the lexer. This allows the client to render useful -n * error messages. - * - * When you pass the next chunk of data, context should be reinitialized - * to zero. - * - * Finally, the output buffer is usually just a pointer into the jsonText, - * however in cases where the entity being lexed spans multiple chunks, - * the lexer will buffer the entity and the data returned will be - * a pointer into that buffer. - * - * This behavior is abstracted from client code except for the performance - * implications which require that the client choose a reasonable chunk - * size to get adequate performance. - */ -yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset, - const unsigned char ** outBuf, unsigned int * outLen); - -/** have a peek at the next token, but don't move the lexer forward */ -yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int offset); - - -typedef enum { - yajl_lex_e_ok = 0, - yajl_lex_string_invalid_utf8, - yajl_lex_string_invalid_escaped_char, - yajl_lex_string_invalid_json_char, - yajl_lex_string_invalid_hex_char, - yajl_lex_invalid_char, - yajl_lex_invalid_string, - yajl_lex_missing_integer_after_decimal, - yajl_lex_missing_integer_after_exponent, - yajl_lex_missing_integer_after_minus, - yajl_lex_unallowed_comment -} yajl_lex_error; - -const char * yajl_lex_error_to_string(yajl_lex_error error); - -/** allows access to more specific information about the lexical - * error when yajl_lex_lex returns yajl_tok_error. */ -yajl_lex_error yajl_lex_get_error(yajl_lexer lexer); - -/** get the current offset into the most recently lexed json string. */ -unsigned int yajl_lex_current_offset(yajl_lexer lexer); - -/** get the number of lines lexed by this lexer instance */ -unsigned int yajl_lex_current_line(yajl_lexer lexer); - -/** get the number of chars lexed by this lexer instance since the last - * \n or \r */ -unsigned int yajl_lex_current_char(yajl_lexer lexer); - -#endif diff --git a/src/ejson/c_src/yajl/yajl_parse.h b/src/ejson/c_src/yajl/yajl_parse.h deleted file mode 100644 index a3dcffcef..000000000 --- a/src/ejson/c_src/yajl/yajl_parse.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file yajl_parse.h - * Interface to YAJL's JSON parsing facilities. - */ - -#include "yajl_common.h" - -#ifndef __YAJL_PARSE_H__ -#define __YAJL_PARSE_H__ - -#ifdef __cplusplus -extern "C" { -#endif - /** error codes returned from this interface */ - typedef enum { - /** no error was encountered */ - yajl_status_ok, - /** a client callback returned zero, stopping the parse */ - yajl_status_client_canceled, - /** The parse cannot yet complete because more json input text - * is required, call yajl_parse with the next buffer of input text. - * (pertinent only when stream parsing) */ - yajl_status_insufficient_data, - /** An error occured during the parse. Call yajl_get_error for - * more information about the encountered error */ - yajl_status_error - } yajl_status; - - /** attain a human readable, english, string for an error */ - YAJL_API const char * yajl_status_to_string(yajl_status code); - - /** an opaque handle to a parser */ - typedef struct yajl_handle_t * yajl_handle; - - /** yajl is an event driven parser. this means as json elements are - * parsed, you are called back to do something with the data. The - * functions in this table indicate the various events for which - * you will be called back. Each callback accepts a "context" - * pointer, this is a void * that is passed into the yajl_parse - * function which the client code may use to pass around context. - * - * All callbacks return an integer. If non-zero, the parse will - * continue. If zero, the parse will be canceled and - * yajl_status_client_canceled will be returned from the parse. - * - * Note about handling of numbers: - * yajl will only convert numbers that can be represented in a double - * or a long int. All other numbers will be passed to the client - * in string form using the yajl_number callback. Furthermore, if - * yajl_number is not NULL, it will always be used to return numbers, - * that is yajl_integer and yajl_double will be ignored. If - * yajl_number is NULL but one of yajl_integer or yajl_double are - * defined, parsing of a number larger than is representable - * in a double or long int will result in a parse error. - */ - typedef struct { - int (* yajl_null)(void * ctx); - int (* yajl_boolean)(void * ctx, int boolVal); - int (* yajl_integer)(void * ctx, long integerVal); - int (* yajl_double)(void * ctx, double doubleVal); - /** A callback which passes the string representation of the number - * back to the client. Will be used for all numbers when present */ - int (* yajl_number)(void * ctx, const char * numberVal, - unsigned int numberLen); - - /** strings are returned as pointers into the JSON text when, - * possible, as a result, they are _not_ null padded */ - int (* yajl_string)(void * ctx, const unsigned char * stringVal, - unsigned int stringLen); - - int (* yajl_start_map)(void * ctx); - int (* yajl_map_key)(void * ctx, const unsigned char * key, - unsigned int stringLen); - int (* yajl_end_map)(void * ctx); - - int (* yajl_start_array)(void * ctx); - int (* yajl_end_array)(void * ctx); - } yajl_callbacks; - - /** configuration structure for the generator */ - typedef struct { - /** if nonzero, javascript style comments will be allowed in - * the json input, both slash star and slash slash */ - unsigned int allowComments; - /** if nonzero, invalid UTF8 strings will cause a parse - * error */ - unsigned int checkUTF8; - } yajl_parser_config; - - /** allocate a parser handle - * \param callbacks a yajl callbacks structure specifying the - * functions to call when different JSON entities - * are encountered in the input text. May be NULL, - * which is only useful for validation. - * \param config configuration parameters for the parse. - * \param ctx a context pointer that will be passed to callbacks. - */ - YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks, - const yajl_parser_config * config, - const yajl_alloc_funcs * allocFuncs, - void * ctx); - - /** free a parser handle */ - YAJL_API void yajl_free(yajl_handle handle); - - /** Parse some json! - * \param hand - a handle to the json parser allocated with yajl_alloc - * \param jsonText - a pointer to the UTF8 json text to be parsed - * \param jsonTextLength - the length, in bytes, of input text - */ - YAJL_API yajl_status yajl_parse(yajl_handle hand, - const unsigned char * jsonText, - unsigned int jsonTextLength); - - /** Parse any remaining buffered json. - * Since yajl is a stream-based parser, without an explicit end of - * input, yajl sometimes can't decide if content at the end of the - * stream is valid or not. For example, if "1" has been fed in, - * yajl can't know whether another digit is next or some character - * that would terminate the integer token. - * - * \param hand - a handle to the json parser allocated with yajl_alloc - */ - YAJL_API yajl_status yajl_parse_complete(yajl_handle hand); - - /** get an error string describing the state of the - * parse. - * - * If verbose is non-zero, the message will include the JSON - * text where the error occured, along with an arrow pointing to - * the specific char. - * - * \returns A dynamically allocated string will be returned which should - * be freed with yajl_free_error - */ - YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose, - const unsigned char * jsonText, - unsigned int jsonTextLength); - - /** - * get the amount of data consumed from the last chunk passed to YAJL. - * - * In the case of a successful parse this can help you understand if - * the entire buffer was consumed (which will allow you to handle - * "junk at end of input". - * - * In the event an error is encountered during parsing, this function - * affords the client a way to get the offset into the most recent - * chunk where the error occured. 0 will be returned if no error - * was encountered. - */ - YAJL_API unsigned int yajl_get_bytes_consumed(yajl_handle hand); - - /** free an error returned from yajl_get_error */ - YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/ejson/c_src/yajl/yajl_parser.c b/src/ejson/c_src/yajl/yajl_parser.c deleted file mode 100644 index 990c860ba..000000000 --- a/src/ejson/c_src/yajl/yajl_parser.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yajl_lex.h" -#include "yajl_parser.h" -#include "yajl_encode.h" -#include "yajl_bytestack.h" - -#include <stdlib.h> -#include <limits.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <assert.h> -#include <math.h> - -const char * -yajl_parser_error_to_string(yajl_parser_error error) -{ - switch (error) { - case yajl_parser_e_ok: - return "ok, no error"; - case yajl_parser_client_cancelled: - return "client cancelled parse via callback return value"; - case yajl_parser_integer_overflow: - return "integer overflow"; - case yajl_parser_numeric_overflow: - return "numeric (floating point) overflow"; - case yajl_parser_invalid_token: - return "unallowed token at this point in JSON text"; - case yajl_parser_internal_invalid_token: - return "invalid token, internal error"; - case yajl_parser_key_must_be_string: - return "invalid object key (must be a string)"; - case yajl_parser_pair_missing_colon: - return "object key and value must be separated by a colon (':')"; - case yajl_parser_bad_token_after_map_value: - return "after key and value, inside map, I expect ',' or '}'"; - case yajl_parser_bad_token_after_array_value: - return "after array element, I expect ',' or ']'"; - } - return "unknown error code"; -} - - -unsigned char * -yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLen, int verbose) -{ - unsigned int offset = hand->bytesConsumed; - unsigned char * str; - const char * errorType = NULL; - const char * errorText = NULL; - char text[72]; - const char * arrow = " (right here) ------^\n"; - - if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) { - errorType = "parse"; - errorText = yajl_parser_error_to_string(hand->parserError); - } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) { - errorType = "lexical"; - errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer)); - } else { - errorType = "unknown"; - } - - { - unsigned int memneeded = 0; - memneeded += strlen(errorType); - memneeded += strlen(" error"); - if (errorText != NULL) { - memneeded += strlen(": "); - memneeded += strlen(errorText); - } - str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2); - str[0] = 0; - strcat((char *) str, errorType); - strcat((char *) str, " error"); - if (errorText != NULL) { - strcat((char *) str, ": "); - strcat((char *) str, errorText); - } - strcat((char *) str, "\n"); - } - - /* now we append as many spaces as needed to make sure the error - * falls at char 41, if verbose was specified */ - if (verbose) { - unsigned int start, end, i; - unsigned int spacesNeeded; - - spacesNeeded = (offset < 30 ? 40 - offset : 10); - start = (offset >= 30 ? offset - 30 : 0); - end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30); - - for (i=0;i<spacesNeeded;i++) text[i] = ' '; - - for (;start < end;start++, i++) { - if (jsonText[start] != '\n' && jsonText[start] != '\r') - { - text[i] = jsonText[start]; - } - else - { - text[i] = ' '; - } - } - assert(i <= 71); - text[i++] = '\n'; - text[i] = 0; - { - char * newStr = (char *) - YA_MALLOC(&(hand->alloc), (strlen((char *) str) + - strlen((char *) text) + - strlen(arrow) + 1)); - newStr[0] = 0; - strcat((char *) newStr, (char *) str); - strcat((char *) newStr, text); - strcat((char *) newStr, arrow); - YA_FREE(&(hand->alloc), str); - str = (unsigned char *) newStr; - } - } - return str; -} - -/* check for client cancelation */ -#define _CC_CHK(x) \ - if (!(x)) { \ - yajl_bs_set(hand->stateStack, yajl_state_parse_error); \ - hand->parserError = yajl_parser_client_cancelled; \ - return yajl_status_client_canceled; \ - } - - -yajl_status -yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLen) -{ - yajl_tok tok; - const unsigned char * buf; - unsigned int bufLen; - unsigned int * offset = &(hand->bytesConsumed); - - *offset = 0; - - - around_again: - switch (yajl_bs_current(hand->stateStack)) { - case yajl_state_parse_complete: - return yajl_status_ok; - case yajl_state_lexical_error: - case yajl_state_parse_error: - return yajl_status_error; - case yajl_state_start: - case yajl_state_map_need_val: - case yajl_state_array_need_val: - case yajl_state_array_start: { - /* for arrays and maps, we advance the state for this - * depth, then push the state of the next depth. - * If an error occurs during the parsing of the nesting - * enitity, the state at this level will not matter. - * a state that needs pushing will be anything other - * than state_start */ - yajl_state stateToPush = yajl_state_start; - - tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, - offset, &buf, &bufLen); - - switch (tok) { - case yajl_tok_eof: - return yajl_status_insufficient_data; - case yajl_tok_error: - yajl_bs_set(hand->stateStack, yajl_state_lexical_error); - goto around_again; - case yajl_tok_string: - if (hand->callbacks && hand->callbacks->yajl_string) { - _CC_CHK(hand->callbacks->yajl_string(hand->ctx, - buf, bufLen)); - } - break; - case yajl_tok_string_with_escapes: - if (hand->callbacks && hand->callbacks->yajl_string) { - yajl_buf_clear(hand->decodeBuf); - yajl_string_decode(hand->decodeBuf, buf, bufLen); - _CC_CHK(hand->callbacks->yajl_string( - hand->ctx, yajl_buf_data(hand->decodeBuf), - yajl_buf_len(hand->decodeBuf))); - } - break; - case yajl_tok_bool: - if (hand->callbacks && hand->callbacks->yajl_boolean) { - _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx, - *buf == 't')); - } - break; - case yajl_tok_null: - if (hand->callbacks && hand->callbacks->yajl_null) { - _CC_CHK(hand->callbacks->yajl_null(hand->ctx)); - } - break; - case yajl_tok_left_bracket: - if (hand->callbacks && hand->callbacks->yajl_start_map) { - _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx)); - } - stateToPush = yajl_state_map_start; - break; - case yajl_tok_left_brace: - if (hand->callbacks && hand->callbacks->yajl_start_array) { - _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx)); - } - stateToPush = yajl_state_array_start; - break; - case yajl_tok_integer: - /* - * note. strtol does not respect the length of - * the lexical token. in a corner case where the - * lexed number is a integer with a trailing zero, - * immediately followed by the end of buffer, - * sscanf could run off into oblivion and cause a - * crash. for this reason we copy the integer - * (and doubles), into our parse buffer (the same - * one used for unescaping strings), before - * calling strtol. yajl_buf ensures null padding, - * so we're safe. - */ - if (hand->callbacks) { - if (hand->callbacks->yajl_number) { - _CC_CHK(hand->callbacks->yajl_number( - hand->ctx,(const char *) buf, bufLen)); - } else if (hand->callbacks->yajl_integer) { - long int i = 0; - yajl_buf_clear(hand->decodeBuf); - yajl_buf_append(hand->decodeBuf, buf, bufLen); - buf = yajl_buf_data(hand->decodeBuf); - i = strtol((const char *) buf, NULL, 10); - if ((i == LONG_MIN || i == LONG_MAX) && - errno == ERANGE) - { - yajl_bs_set(hand->stateStack, - yajl_state_parse_error); - hand->parserError = yajl_parser_integer_overflow; - /* try to restore error offset */ - if (*offset >= bufLen) *offset -= bufLen; - else *offset = 0; - goto around_again; - } - _CC_CHK(hand->callbacks->yajl_integer(hand->ctx, - i)); - } - } - break; - case yajl_tok_double: - if (hand->callbacks) { - if (hand->callbacks->yajl_number) { - _CC_CHK(hand->callbacks->yajl_number( - hand->ctx, (const char *) buf, bufLen)); - } else if (hand->callbacks->yajl_double) { - double d = 0.0; - yajl_buf_clear(hand->decodeBuf); - yajl_buf_append(hand->decodeBuf, buf, bufLen); - buf = yajl_buf_data(hand->decodeBuf); - d = strtod((char *) buf, NULL); - if ((d == HUGE_VAL || d == -HUGE_VAL) && - errno == ERANGE) - { - yajl_bs_set(hand->stateStack, - yajl_state_parse_error); - hand->parserError = yajl_parser_numeric_overflow; - /* try to restore error offset */ - if (*offset >= bufLen) *offset -= bufLen; - else *offset = 0; - goto around_again; - } - _CC_CHK(hand->callbacks->yajl_double(hand->ctx, - d)); - } - } - break; - case yajl_tok_right_brace: { - if (yajl_bs_current(hand->stateStack) == - yajl_state_array_start) - { - if (hand->callbacks && - hand->callbacks->yajl_end_array) - { - _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); - } - yajl_bs_pop(hand->stateStack); - goto around_again; - } - /* intentional fall-through */ - } - case yajl_tok_colon: - case yajl_tok_comma: - case yajl_tok_right_bracket: - yajl_bs_set(hand->stateStack, yajl_state_parse_error); - hand->parserError = yajl_parser_invalid_token; - goto around_again; - default: - yajl_bs_set(hand->stateStack, yajl_state_parse_error); - hand->parserError = yajl_parser_invalid_token; - goto around_again; - } - /* got a value. transition depends on the state we're in. */ - { - yajl_state s = yajl_bs_current(hand->stateStack); - if (s == yajl_state_start) { - yajl_bs_set(hand->stateStack, yajl_state_parse_complete); - } else if (s == yajl_state_map_need_val) { - yajl_bs_set(hand->stateStack, yajl_state_map_got_val); - } else { - yajl_bs_set(hand->stateStack, yajl_state_array_got_val); - } - } - if (stateToPush != yajl_state_start) { - yajl_bs_push(hand->stateStack, stateToPush); - } - - goto around_again; - } - case yajl_state_map_start: - case yajl_state_map_need_key: { - /* only difference between these two states is that in - * start '}' is valid, whereas in need_key, we've parsed - * a comma, and a string key _must_ follow */ - tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, - offset, &buf, &bufLen); - switch (tok) { - case yajl_tok_eof: - return yajl_status_insufficient_data; - case yajl_tok_error: - yajl_bs_set(hand->stateStack, yajl_state_lexical_error); - goto around_again; - case yajl_tok_string_with_escapes: - if (hand->callbacks && hand->callbacks->yajl_map_key) { - yajl_buf_clear(hand->decodeBuf); - yajl_string_decode(hand->decodeBuf, buf, bufLen); - buf = yajl_buf_data(hand->decodeBuf); - bufLen = yajl_buf_len(hand->decodeBuf); - } - /* intentional fall-through */ - case yajl_tok_string: - if (hand->callbacks && hand->callbacks->yajl_map_key) { - _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf, - bufLen)); - } - yajl_bs_set(hand->stateStack, yajl_state_map_sep); - goto around_again; - case yajl_tok_right_bracket: - if (yajl_bs_current(hand->stateStack) == - yajl_state_map_start) - { - if (hand->callbacks && hand->callbacks->yajl_end_map) { - _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); - } - yajl_bs_pop(hand->stateStack); - goto around_again; - } - default: - yajl_bs_set(hand->stateStack, yajl_state_parse_error); - hand->parserError = yajl_parser_key_must_be_string; - goto around_again; - } - } - case yajl_state_map_sep: { - tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, - offset, &buf, &bufLen); - switch (tok) { - case yajl_tok_colon: - yajl_bs_set(hand->stateStack, yajl_state_map_need_val); - goto around_again; - case yajl_tok_eof: - return yajl_status_insufficient_data; - case yajl_tok_error: - yajl_bs_set(hand->stateStack, yajl_state_lexical_error); - goto around_again; - default: - yajl_bs_set(hand->stateStack, yajl_state_parse_error); - hand->parserError = yajl_parser_pair_missing_colon; - goto around_again; - } - } - case yajl_state_map_got_val: { - tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, - offset, &buf, &bufLen); - switch (tok) { - case yajl_tok_right_bracket: - if (hand->callbacks && hand->callbacks->yajl_end_map) { - _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); - } - yajl_bs_pop(hand->stateStack); - goto around_again; - case yajl_tok_comma: - yajl_bs_set(hand->stateStack, yajl_state_map_need_key); - goto around_again; - case yajl_tok_eof: - return yajl_status_insufficient_data; - case yajl_tok_error: - yajl_bs_set(hand->stateStack, yajl_state_lexical_error); - goto around_again; - default: - yajl_bs_set(hand->stateStack, yajl_state_parse_error); - hand->parserError = yajl_parser_bad_token_after_map_value; - /* try to restore error offset */ - if (*offset >= bufLen) *offset -= bufLen; - else *offset = 0; - goto around_again; - } - } - case yajl_state_array_got_val: { - tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, - offset, &buf, &bufLen); - switch (tok) { - case yajl_tok_right_brace: - if (hand->callbacks && hand->callbacks->yajl_end_array) { - _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); - } - yajl_bs_pop(hand->stateStack); - goto around_again; - case yajl_tok_comma: - yajl_bs_set(hand->stateStack, yajl_state_array_need_val); - goto around_again; - case yajl_tok_eof: - return yajl_status_insufficient_data; - case yajl_tok_error: - yajl_bs_set(hand->stateStack, yajl_state_lexical_error); - goto around_again; - default: - yajl_bs_set(hand->stateStack, yajl_state_parse_error); - hand->parserError = yajl_parser_bad_token_after_array_value; - goto around_again; - } - } - } - - abort(); - return yajl_status_error; -} - diff --git a/src/ejson/c_src/yajl/yajl_parser.h b/src/ejson/c_src/yajl/yajl_parser.h deleted file mode 100644 index f359b456d..000000000 --- a/src/ejson/c_src/yajl/yajl_parser.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __YAJL_PARSER_H__ -#define __YAJL_PARSER_H__ - -#include "yajl_parse.h" -#include "yajl_bytestack.h" -#include "yajl_buf.h" -#include "yajl_lex.h" - -typedef enum { - yajl_state_start = 0, - yajl_state_parse_complete, - yajl_state_parse_error, - yajl_state_lexical_error, - yajl_state_map_start, - yajl_state_map_sep, - yajl_state_map_need_val, - yajl_state_map_got_val, - yajl_state_map_need_key, - yajl_state_array_start, - yajl_state_array_got_val, - yajl_state_array_need_val -} yajl_state; - -typedef enum { - yajl_parser_e_ok = 0, - yajl_parser_client_cancelled, - yajl_parser_integer_overflow, - yajl_parser_numeric_overflow, - yajl_parser_invalid_token, - yajl_parser_internal_invalid_token, - yajl_parser_key_must_be_string, - yajl_parser_pair_missing_colon, - yajl_parser_bad_token_after_map_value, - yajl_parser_bad_token_after_array_value -} yajl_parser_error; - -struct yajl_handle_t { - const yajl_callbacks * callbacks; - void * ctx; - yajl_lexer lexer; - yajl_parser_error parserError; - /* the number of bytes consumed from the last client buffer, - * in the case of an error this will be an error offset, in the - * case of an error this can be used as the error offset */ - unsigned int bytesConsumed; - /* temporary storage for decoded strings */ - yajl_buf decodeBuf; - /* a stack of states. access with yajl_state_XXX routines */ - yajl_bytestack stateStack; - /* memory allocation routines */ - yajl_alloc_funcs alloc; -}; - -yajl_status -yajl_do_parse(yajl_handle handle, const unsigned char * jsonText, - unsigned int jsonTextLen); - -unsigned char * -yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLen, int verbose); - - -#endif diff --git a/src/ejson/src/ejson.app.src b/src/ejson/src/ejson.app.src deleted file mode 100644 index 7180b81cf..000000000 --- a/src/ejson/src/ejson.app.src +++ /dev/null @@ -1,9 +0,0 @@ -{application, ejson, [ - {description, "EJSON - decode and encode JSON into/from Erlang terms"}, - {vsn, git}, - {modules, [ejson]}, - {registered, []}, - {applications, [kernel, stdlib]}, - {env, []} -]}. - diff --git a/src/ejson/src/ejson.erl b/src/ejson/src/ejson.erl deleted file mode 100644 index 72bb6c157..000000000 --- a/src/ejson/src/ejson.erl +++ /dev/null @@ -1,168 +0,0 @@ -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - --module(ejson). --export([encode/1, decode/1]). --on_load(init/0). - -init() -> - SoName = case code:priv_dir(ejson) of - {error, bad_name} -> - case filelib:is_dir(filename:join(["..", priv])) of - true -> - filename:join(["..", priv, ejson]); - false -> - filename:join([priv, ejson]) - end; - Dir -> - filename:join(Dir, ejson) - end, - (catch erlang:load_nif(SoName, 0)), - case erlang:system_info(otp_release) of - "R13B03" -> true; - _ -> ok - end. - - -decode(undefined) -> - throw({invalid_json, undefined}); -decode(IoList) -> - try - nif_decode(IoList) - catch exit:ejson_nif_not_loaded -> - erl_decode(IoList) - end. - -encode(EJson) -> - try - nif_encode(EJson) - catch exit:ejson_nif_not_loaded -> - erl_encode(EJson) - end. - - -nif_decode(IoList) -> - case reverse_tokens(IoList) of - {ok, ReverseTokens} -> - [[EJson]] = make_ejson(ReverseTokens, [[]]), - EJson; - Error -> - throw({invalid_json, {Error, IoList}}) - end. - - -erl_decode(IoList) -> - try - (mochijson2:decoder([{object_hook, fun({struct, L}) -> {L} end}]))(IoList) - catch _Type:Error -> - throw({invalid_json, {Error, IoList}}) - end. - - -nif_encode(EJson) -> - RevList = encode_rev(EJson), - final_encode(lists:reverse(lists:flatten([RevList]))). - - -erl_encode(EJson) -> - Opts = [{handler, fun mochi_encode_handler/1}], - iolist_to_binary((mochijson2:encoder(Opts))(EJson)). - -mochi_encode_handler({L}) when is_list(L) -> - {struct, L}; -mochi_encode_handler(Bad) -> - exit({json_encode, {bad_term, Bad}}). - - -% Encode the json into a reverse list that's almost an iolist -% everything in the list is the final output except for tuples with -% {0, Strings} and {1, Floats}, which are to be converted to strings -% inside the NIF. -encode_rev(true) -> - <<"true">>; -encode_rev(false) -> - <<"false">>; -encode_rev(null) -> - <<"null">>; -encode_rev(I) when is_integer(I) -> - list_to_binary(integer_to_list(I)); -encode_rev(S) when is_binary(S) -> - {0, S}; -encode_rev(S) when is_atom(S) -> - {0, list_to_binary(atom_to_list(S))}; -encode_rev(F) when is_float(F) -> - {1, F}; -encode_rev({Props}) when is_list(Props) -> - encode_proplist_rev(Props, [<<"{">>]); -encode_rev(Array) when is_list(Array) -> - encode_array_rev(Array, [<<"[">>]); -encode_rev(Bad) -> - throw({json_encode, {bad_term, Bad}}). - - -encode_array_rev([], Acc) -> - [<<"]">> | Acc]; -encode_array_rev([Val | Rest], [<<"[">>]) -> - encode_array_rev(Rest, [encode_rev(Val), <<"[">>]); -encode_array_rev([Val | Rest], Acc) -> - encode_array_rev(Rest, [encode_rev(Val), <<",">> | Acc]). - - -encode_proplist_rev([], Acc) -> - [<<"}">> | Acc]; -encode_proplist_rev([{Key,Val} | Rest], [<<"{">>]) -> - encode_proplist_rev( - Rest, [encode_rev(Val), <<":">>, {0, as_binary(Key)}, <<"{">>]); -encode_proplist_rev([{Key,Val} | Rest], Acc) -> - encode_proplist_rev( - Rest, [encode_rev(Val), <<":">>, {0, as_binary(Key)}, <<",">> | Acc]). - -as_binary(B) when is_binary(B) -> - B; -as_binary(A) when is_atom(A) -> - list_to_binary(atom_to_list(A)); -as_binary(L) when is_list(L) -> - list_to_binary(L). - - -make_ejson([], Stack) -> - Stack; -make_ejson([0 | RevEvs], [ArrayValues, PrevValues | RestStack]) -> - % 0 ArrayStart - make_ejson(RevEvs, [[ArrayValues | PrevValues] | RestStack]); -make_ejson([1 | RevEvs], Stack) -> - % 1 ArrayEnd - make_ejson(RevEvs, [[] | Stack]); -make_ejson([2 | RevEvs], [ObjValues, PrevValues | RestStack]) -> - % 2 ObjectStart - make_ejson(RevEvs, [[{ObjValues} | PrevValues] | RestStack]); -make_ejson([3 | RevEvs], Stack) -> - % 3 ObjectEnd - make_ejson(RevEvs, [[] | Stack]); -make_ejson([{0, Value} | RevEvs], [Vals | RestStack] = _Stack) -> - % {0, IntegerString} - make_ejson(RevEvs, [[list_to_integer(binary_to_list(Value)) | Vals] | RestStack]); -make_ejson([{1, Value} | RevEvs], [Vals | RestStack] = _Stack) -> - % {1, FloatString} - make_ejson(RevEvs, [[list_to_float(binary_to_list(Value)) | Vals] | RestStack]); -make_ejson([{3, String} | RevEvs], [[PrevValue|RestObject] | RestStack] = _Stack) -> - % {3 , ObjectKey} - make_ejson(RevEvs, [[{String, PrevValue}|RestObject] | RestStack]); -make_ejson([Value | RevEvs], [Vals | RestStack] = _Stack) -> - make_ejson(RevEvs, [[Value | Vals] | RestStack]). - - -reverse_tokens(_) -> - exit(ejson_nif_not_loaded). - -final_encode(_) -> - exit(ejson_nif_not_loaded). diff --git a/src/ejson/src/mochijson2.erl b/src/ejson/src/mochijson2.erl deleted file mode 100644 index 954a07dc9..000000000 --- a/src/ejson/src/mochijson2.erl +++ /dev/null @@ -1,849 +0,0 @@ -%% @author Bob Ippolito <bob@mochimedia.com> -%% @copyright 2007 Mochi Media, Inc. - -%% @doc Yet another JSON (RFC 4627) library for Erlang. mochijson2 works -%% with binaries as strings, arrays as lists (without an {array, _}) -%% wrapper and it only knows how to decode UTF-8 (and ASCII). -%% -%% JSON terms are decoded as follows (javascript -> erlang): -%% <ul> -%% <li>{"key": "value"} -> -%% {struct, [{<<"key">>, <<"value">>}]}</li> -%% <li>["array", 123, 12.34, true, false, null] -> -%% [<<"array">>, 123, 12.34, true, false, null] -%% </li> -%% </ul> -%% <ul> -%% <li>Strings in JSON decode to UTF-8 binaries in Erlang</li> -%% <li>Objects decode to {struct, PropList}</li> -%% <li>Numbers decode to integer or float</li> -%% <li>true, false, null decode to their respective terms.</li> -%% </ul> -%% The encoder will accept the same format that the decoder will produce, -%% but will also allow additional cases for leniency: -%% <ul> -%% <li>atoms other than true, false, null will be considered UTF-8 -%% strings (even as a proplist key) -%% </li> -%% <li>{json, IoList} will insert IoList directly into the output -%% with no validation -%% </li> -%% <li>{array, Array} will be encoded as Array -%% (legacy mochijson style) -%% </li> -%% <li>A non-empty raw proplist will be encoded as an object as long -%% as the first pair does not have an atom key of json, struct, -%% or array -%% </li> -%% </ul> - --module(mochijson2). --author('bob@mochimedia.com'). --export([encoder/1, encode/1]). --export([decoder/1, decode/1]). - -% This is a macro to placate syntax highlighters.. --define(Q, $\"). --define(ADV_COL(S, N), S#decoder{offset=N+S#decoder.offset, - column=N+S#decoder.column}). --define(INC_COL(S), S#decoder{offset=1+S#decoder.offset, - column=1+S#decoder.column}). --define(INC_LINE(S), S#decoder{offset=1+S#decoder.offset, - column=1, - line=1+S#decoder.line}). --define(INC_CHAR(S, C), - case C of - $\n -> - S#decoder{column=1, - line=1+S#decoder.line, - offset=1+S#decoder.offset}; - _ -> - S#decoder{column=1+S#decoder.column, - offset=1+S#decoder.offset} - end). --define(IS_WHITESPACE(C), - (C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)). - -%% @type iolist() = [char() | binary() | iolist()] -%% @type iodata() = iolist() | binary() -%% @type json_string() = atom | binary() -%% @type json_number() = integer() | float() -%% @type json_array() = [json_term()] -%% @type json_object() = {struct, [{json_string(), json_term()}]} -%% @type json_iolist() = {json, iolist()} -%% @type json_term() = json_string() | json_number() | json_array() | -%% json_object() | json_iolist() - --record(encoder, {handler=null, - utf8=false}). - --record(decoder, {object_hook=null, - offset=0, - line=1, - column=1, - state=null}). - -%% @spec encoder([encoder_option()]) -> function() -%% @doc Create an encoder/1 with the given options. -%% @type encoder_option() = handler_option() | utf8_option() -%% @type utf8_option() = boolean(). Emit unicode as utf8 (default - false) -encoder(Options) -> - State = parse_encoder_options(Options, #encoder{}), - fun (O) -> json_encode(O, State) end. - -%% @spec encode(json_term()) -> iolist() -%% @doc Encode the given as JSON to an iolist. -encode(Any) -> - json_encode(Any, #encoder{}). - -%% @spec decoder([decoder_option()]) -> function() -%% @doc Create a decoder/1 with the given options. -decoder(Options) -> - State = parse_decoder_options(Options, #decoder{}), - fun (O) -> json_decode(O, State) end. - -%% @spec decode(iolist()) -> json_term() -%% @doc Decode the given iolist to Erlang terms. -decode(S) -> - json_decode(S, #decoder{}). - -%% Internal API - -parse_encoder_options([], State) -> - State; -parse_encoder_options([{handler, Handler} | Rest], State) -> - parse_encoder_options(Rest, State#encoder{handler=Handler}); -parse_encoder_options([{utf8, Switch} | Rest], State) -> - parse_encoder_options(Rest, State#encoder{utf8=Switch}). - -parse_decoder_options([], State) -> - State; -parse_decoder_options([{object_hook, Hook} | Rest], State) -> - parse_decoder_options(Rest, State#decoder{object_hook=Hook}). - -json_encode(true, _State) -> - <<"true">>; -json_encode(false, _State) -> - <<"false">>; -json_encode(null, _State) -> - <<"null">>; -json_encode(I, _State) when is_integer(I) -> - integer_to_list(I); -json_encode(F, _State) when is_float(F) -> - mochinum:digits(F); -json_encode(S, State) when is_binary(S); is_atom(S) -> - json_encode_string(S, State); -json_encode([{K, _}|_] = Props, State) when (K =/= struct andalso - K =/= array andalso - K =/= json) -> - json_encode_proplist(Props, State); -json_encode({struct, Props}, State) when is_list(Props) -> - json_encode_proplist(Props, State); -json_encode(Array, State) when is_list(Array) -> - json_encode_array(Array, State); -json_encode({array, Array}, State) when is_list(Array) -> - json_encode_array(Array, State); -json_encode({json, IoList}, _State) -> - IoList; -json_encode(Bad, #encoder{handler=null}) -> - exit({json_encode, {bad_term, Bad}}); -json_encode(Bad, State=#encoder{handler=Handler}) -> - json_encode(Handler(Bad), State). - -json_encode_array([], _State) -> - <<"[]">>; -json_encode_array(L, State) -> - F = fun (O, Acc) -> - [$,, json_encode(O, State) | Acc] - end, - [$, | Acc1] = lists:foldl(F, "[", L), - lists:reverse([$\] | Acc1]). - -json_encode_proplist([], _State) -> - <<"{}">>; -json_encode_proplist(Props, State) -> - F = fun ({K, V}, Acc) -> - KS = json_encode_string(K, State), - VS = json_encode(V, State), - [$,, VS, $:, KS | Acc] - end, - [$, | Acc1] = lists:foldl(F, "{", Props), - lists:reverse([$\} | Acc1]). - -json_encode_string(A, State) when is_atom(A) -> - L = atom_to_list(A), - case json_string_is_safe(L) of - true -> - [?Q, L, ?Q]; - false -> - json_encode_string_unicode(xmerl_ucs:from_utf8(L), State, [?Q]) - end; -json_encode_string(B, State) when is_binary(B) -> - case json_bin_is_safe(B) of - true -> - [?Q, B, ?Q]; - false -> - json_encode_string_unicode(xmerl_ucs:from_utf8(B), State, [?Q]) - end; -json_encode_string(I, _State) when is_integer(I) -> - [?Q, integer_to_list(I), ?Q]; -json_encode_string(L, State) when is_list(L) -> - case json_string_is_safe(L) of - true -> - [?Q, L, ?Q]; - false -> - json_encode_string_unicode(L, State, [?Q]) - end. - -json_string_is_safe([]) -> - true; -json_string_is_safe([C | Rest]) -> - case C of - ?Q -> - false; - $\\ -> - false; - $\b -> - false; - $\f -> - false; - $\n -> - false; - $\r -> - false; - $\t -> - false; - C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF -> - false; - C when C < 16#7f -> - json_string_is_safe(Rest); - _ -> - false - end. - -json_bin_is_safe(<<>>) -> - true; -json_bin_is_safe(<<C, Rest/binary>>) -> - case C of - ?Q -> - false; - $\\ -> - false; - $\b -> - false; - $\f -> - false; - $\n -> - false; - $\r -> - false; - $\t -> - false; - C when C >= 0, C < $\s; C >= 16#7f -> - false; - C when C < 16#7f -> - json_bin_is_safe(Rest) - end. - -json_encode_string_unicode([], _State, Acc) -> - lists:reverse([$\" | Acc]); -json_encode_string_unicode([C | Cs], State, Acc) -> - Acc1 = case C of - ?Q -> - [?Q, $\\ | Acc]; - %% Escaping solidus is only useful when trying to protect - %% against "</script>" injection attacks which are only - %% possible when JSON is inserted into a HTML document - %% in-line. mochijson2 does not protect you from this, so - %% if you do insert directly into HTML then you need to - %% uncomment the following case or escape the output of encode. - %% - %% $/ -> - %% [$/, $\\ | Acc]; - %% - $\\ -> - [$\\, $\\ | Acc]; - $\b -> - [$b, $\\ | Acc]; - $\f -> - [$f, $\\ | Acc]; - $\n -> - [$n, $\\ | Acc]; - $\r -> - [$r, $\\ | Acc]; - $\t -> - [$t, $\\ | Acc]; - C when C >= 0, C < $\s -> - [unihex(C) | Acc]; - C when C >= 16#7f, C =< 16#10FFFF, State#encoder.utf8 -> - [xmerl_ucs:to_utf8(C) | Acc]; - C when C >= 16#7f, C =< 16#10FFFF, not State#encoder.utf8 -> - [unihex(C) | Acc]; - C when C < 16#7f -> - [C | Acc]; - _ -> - exit({json_encode, {bad_char, C}}) - end, - json_encode_string_unicode(Cs, State, Acc1). - -hexdigit(C) when C >= 0, C =< 9 -> - C + $0; -hexdigit(C) when C =< 15 -> - C + $a - 10. - -unihex(C) when C < 16#10000 -> - <<D3:4, D2:4, D1:4, D0:4>> = <<C:16>>, - Digits = [hexdigit(D) || D <- [D3, D2, D1, D0]], - [$\\, $u | Digits]; -unihex(C) when C =< 16#10FFFF -> - N = C - 16#10000, - S1 = 16#d800 bor ((N bsr 10) band 16#3ff), - S2 = 16#dc00 bor (N band 16#3ff), - [unihex(S1), unihex(S2)]. - -json_decode(L, S) when is_list(L) -> - json_decode(iolist_to_binary(L), S); -json_decode(B, S) -> - {Res, S1} = decode1(B, S), - {eof, _} = tokenize(B, S1#decoder{state=trim}), - Res. - -decode1(B, S=#decoder{state=null}) -> - case tokenize(B, S#decoder{state=any}) of - {{const, C}, S1} -> - {C, S1}; - {start_array, S1} -> - decode_array(B, S1); - {start_object, S1} -> - decode_object(B, S1) - end. - -make_object(V, #decoder{object_hook=null}) -> - V; -make_object(V, #decoder{object_hook=Hook}) -> - Hook(V). - -decode_object(B, S) -> - decode_object(B, S#decoder{state=key}, []). - -decode_object(B, S=#decoder{state=key}, Acc) -> - case tokenize(B, S) of - {end_object, S1} -> - V = make_object({struct, lists:reverse(Acc)}, S1), - {V, S1#decoder{state=null}}; - {{const, K}, S1} -> - {colon, S2} = tokenize(B, S1), - {V, S3} = decode1(B, S2#decoder{state=null}), - decode_object(B, S3#decoder{state=comma}, [{K, V} | Acc]) - end; -decode_object(B, S=#decoder{state=comma}, Acc) -> - case tokenize(B, S) of - {end_object, S1} -> - V = make_object({struct, lists:reverse(Acc)}, S1), - {V, S1#decoder{state=null}}; - {comma, S1} -> - decode_object(B, S1#decoder{state=key}, Acc) - end. - -decode_array(B, S) -> - decode_array(B, S#decoder{state=any}, []). - -decode_array(B, S=#decoder{state=any}, Acc) -> - case tokenize(B, S) of - {end_array, S1} -> - {lists:reverse(Acc), S1#decoder{state=null}}; - {start_array, S1} -> - {Array, S2} = decode_array(B, S1), - decode_array(B, S2#decoder{state=comma}, [Array | Acc]); - {start_object, S1} -> - {Array, S2} = decode_object(B, S1), - decode_array(B, S2#decoder{state=comma}, [Array | Acc]); - {{const, Const}, S1} -> - decode_array(B, S1#decoder{state=comma}, [Const | Acc]) - end; -decode_array(B, S=#decoder{state=comma}, Acc) -> - case tokenize(B, S) of - {end_array, S1} -> - {lists:reverse(Acc), S1#decoder{state=null}}; - {comma, S1} -> - decode_array(B, S1#decoder{state=any}, Acc) - end. - -tokenize_string(B, S=#decoder{offset=O}) -> - case tokenize_string_fast(B, O) of - {escape, O1} -> - Length = O1 - O, - S1 = ?ADV_COL(S, Length), - <<_:O/binary, Head:Length/binary, _/binary>> = B, - tokenize_string(B, S1, lists:reverse(binary_to_list(Head))); - O1 -> - Length = O1 - O, - <<_:O/binary, String:Length/binary, ?Q, _/binary>> = B, - {{const, String}, ?ADV_COL(S, Length + 1)} - end. - -tokenize_string_fast(B, O) -> - case B of - <<_:O/binary, ?Q, _/binary>> -> - O; - <<_:O/binary, $\\, _/binary>> -> - {escape, O}; - <<_:O/binary, C1, _/binary>> when C1 < 128 -> - tokenize_string_fast(B, 1 + O); - <<_:O/binary, C1, C2, _/binary>> when C1 >= 194, C1 =< 223, - C2 >= 128, C2 =< 191 -> - tokenize_string_fast(B, 2 + O); - <<_:O/binary, C1, C2, C3, _/binary>> when C1 >= 224, C1 =< 239, - C2 >= 128, C2 =< 191, - C3 >= 128, C3 =< 191 -> - tokenize_string_fast(B, 3 + O); - <<_:O/binary, C1, C2, C3, C4, _/binary>> when C1 >= 240, C1 =< 244, - C2 >= 128, C2 =< 191, - C3 >= 128, C3 =< 191, - C4 >= 128, C4 =< 191 -> - tokenize_string_fast(B, 4 + O); - _ -> - throw(invalid_utf8) - end. - -tokenize_string(B, S=#decoder{offset=O}, Acc) -> - case B of - <<_:O/binary, ?Q, _/binary>> -> - {{const, iolist_to_binary(lists:reverse(Acc))}, ?INC_COL(S)}; - <<_:O/binary, "\\\"", _/binary>> -> - tokenize_string(B, ?ADV_COL(S, 2), [$\" | Acc]); - <<_:O/binary, "\\\\", _/binary>> -> - tokenize_string(B, ?ADV_COL(S, 2), [$\\ | Acc]); - <<_:O/binary, "\\/", _/binary>> -> - tokenize_string(B, ?ADV_COL(S, 2), [$/ | Acc]); - <<_:O/binary, "\\b", _/binary>> -> - tokenize_string(B, ?ADV_COL(S, 2), [$\b | Acc]); - <<_:O/binary, "\\f", _/binary>> -> - tokenize_string(B, ?ADV_COL(S, 2), [$\f | Acc]); - <<_:O/binary, "\\n", _/binary>> -> - tokenize_string(B, ?ADV_COL(S, 2), [$\n | Acc]); - <<_:O/binary, "\\r", _/binary>> -> - tokenize_string(B, ?ADV_COL(S, 2), [$\r | Acc]); - <<_:O/binary, "\\t", _/binary>> -> - tokenize_string(B, ?ADV_COL(S, 2), [$\t | Acc]); - <<_:O/binary, "\\u", C3, C2, C1, C0, Rest/binary>> -> - C = erlang:list_to_integer([C3, C2, C1, C0], 16), - if C > 16#D7FF, C < 16#DC00 -> - %% coalesce UTF-16 surrogate pair - <<"\\u", D3, D2, D1, D0, _/binary>> = Rest, - D = erlang:list_to_integer([D3,D2,D1,D0], 16), - [CodePoint] = xmerl_ucs:from_utf16be(<<C:16/big-unsigned-integer, - D:16/big-unsigned-integer>>), - Acc1 = lists:reverse(xmerl_ucs:to_utf8(CodePoint), Acc), - tokenize_string(B, ?ADV_COL(S, 12), Acc1); - true -> - Acc1 = lists:reverse(xmerl_ucs:to_utf8(C), Acc), - tokenize_string(B, ?ADV_COL(S, 6), Acc1) - end; - <<_:O/binary, C1, _/binary>> when C1 < 128 -> - tokenize_string(B, ?INC_CHAR(S, C1), [C1 | Acc]); - <<_:O/binary, C1, C2, _/binary>> when C1 >= 194, C1 =< 223, - C2 >= 128, C2 =< 191 -> - tokenize_string(B, ?ADV_COL(S, 2), [C2, C1 | Acc]); - <<_:O/binary, C1, C2, C3, _/binary>> when C1 >= 224, C1 =< 239, - C2 >= 128, C2 =< 191, - C3 >= 128, C3 =< 191 -> - tokenize_string(B, ?ADV_COL(S, 3), [C3, C2, C1 | Acc]); - <<_:O/binary, C1, C2, C3, C4, _/binary>> when C1 >= 240, C1 =< 244, - C2 >= 128, C2 =< 191, - C3 >= 128, C3 =< 191, - C4 >= 128, C4 =< 191 -> - tokenize_string(B, ?ADV_COL(S, 4), [C4, C3, C2, C1 | Acc]); - _ -> - throw(invalid_utf8) - end. - -tokenize_number(B, S) -> - case tokenize_number(B, sign, S, []) of - {{int, Int}, S1} -> - {{const, list_to_integer(Int)}, S1}; - {{float, Float}, S1} -> - {{const, list_to_float(Float)}, S1} - end. - -tokenize_number(B, sign, S=#decoder{offset=O}, []) -> - case B of - <<_:O/binary, $-, _/binary>> -> - tokenize_number(B, int, ?INC_COL(S), [$-]); - _ -> - tokenize_number(B, int, S, []) - end; -tokenize_number(B, int, S=#decoder{offset=O}, Acc) -> - case B of - <<_:O/binary, $0, _/binary>> -> - tokenize_number(B, frac, ?INC_COL(S), [$0 | Acc]); - <<_:O/binary, C, _/binary>> when C >= $1 andalso C =< $9 -> - tokenize_number(B, int1, ?INC_COL(S), [C | Acc]) - end; -tokenize_number(B, int1, S=#decoder{offset=O}, Acc) -> - case B of - <<_:O/binary, C, _/binary>> when C >= $0 andalso C =< $9 -> - tokenize_number(B, int1, ?INC_COL(S), [C | Acc]); - _ -> - tokenize_number(B, frac, S, Acc) - end; -tokenize_number(B, frac, S=#decoder{offset=O}, Acc) -> - case B of - <<_:O/binary, $., C, _/binary>> when C >= $0, C =< $9 -> - tokenize_number(B, frac1, ?ADV_COL(S, 2), [C, $. | Acc]); - <<_:O/binary, E, _/binary>> when E =:= $e orelse E =:= $E -> - tokenize_number(B, esign, ?INC_COL(S), [$e, $0, $. | Acc]); - _ -> - {{int, lists:reverse(Acc)}, S} - end; -tokenize_number(B, frac1, S=#decoder{offset=O}, Acc) -> - case B of - <<_:O/binary, C, _/binary>> when C >= $0 andalso C =< $9 -> - tokenize_number(B, frac1, ?INC_COL(S), [C | Acc]); - <<_:O/binary, E, _/binary>> when E =:= $e orelse E =:= $E -> - tokenize_number(B, esign, ?INC_COL(S), [$e | Acc]); - _ -> - {{float, lists:reverse(Acc)}, S} - end; -tokenize_number(B, esign, S=#decoder{offset=O}, Acc) -> - case B of - <<_:O/binary, C, _/binary>> when C =:= $- orelse C=:= $+ -> - tokenize_number(B, eint, ?INC_COL(S), [C | Acc]); - _ -> - tokenize_number(B, eint, S, Acc) - end; -tokenize_number(B, eint, S=#decoder{offset=O}, Acc) -> - case B of - <<_:O/binary, C, _/binary>> when C >= $0 andalso C =< $9 -> - tokenize_number(B, eint1, ?INC_COL(S), [C | Acc]) - end; -tokenize_number(B, eint1, S=#decoder{offset=O}, Acc) -> - case B of - <<_:O/binary, C, _/binary>> when C >= $0 andalso C =< $9 -> - tokenize_number(B, eint1, ?INC_COL(S), [C | Acc]); - _ -> - {{float, lists:reverse(Acc)}, S} - end. - -tokenize(B, S=#decoder{offset=O}) -> - case B of - <<_:O/binary, C, _/binary>> when ?IS_WHITESPACE(C) -> - tokenize(B, ?INC_CHAR(S, C)); - <<_:O/binary, "{", _/binary>> -> - {start_object, ?INC_COL(S)}; - <<_:O/binary, "}", _/binary>> -> - {end_object, ?INC_COL(S)}; - <<_:O/binary, "[", _/binary>> -> - {start_array, ?INC_COL(S)}; - <<_:O/binary, "]", _/binary>> -> - {end_array, ?INC_COL(S)}; - <<_:O/binary, ",", _/binary>> -> - {comma, ?INC_COL(S)}; - <<_:O/binary, ":", _/binary>> -> - {colon, ?INC_COL(S)}; - <<_:O/binary, "null", _/binary>> -> - {{const, null}, ?ADV_COL(S, 4)}; - <<_:O/binary, "true", _/binary>> -> - {{const, true}, ?ADV_COL(S, 4)}; - <<_:O/binary, "false", _/binary>> -> - {{const, false}, ?ADV_COL(S, 5)}; - <<_:O/binary, "\"", _/binary>> -> - tokenize_string(B, ?INC_COL(S)); - <<_:O/binary, C, _/binary>> when (C >= $0 andalso C =< $9) - orelse C =:= $- -> - tokenize_number(B, S); - <<_:O/binary>> -> - trim = S#decoder.state, - {eof, S} - end. -%% -%% Tests -%% --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). - - -%% testing constructs borrowed from the Yaws JSON implementation. - -%% Create an object from a list of Key/Value pairs. - -obj_new() -> - {struct, []}. - -is_obj({struct, Props}) -> - F = fun ({K, _}) when is_binary(K) -> true end, - lists:all(F, Props). - -obj_from_list(Props) -> - Obj = {struct, Props}, - ?assert(is_obj(Obj)), - Obj. - -%% Test for equivalence of Erlang terms. -%% Due to arbitrary order of construction, equivalent objects might -%% compare unequal as erlang terms, so we need to carefully recurse -%% through aggregates (tuples and objects). - -equiv({struct, Props1}, {struct, Props2}) -> - equiv_object(Props1, Props2); -equiv(L1, L2) when is_list(L1), is_list(L2) -> - equiv_list(L1, L2); -equiv(N1, N2) when is_number(N1), is_number(N2) -> N1 == N2; -equiv(B1, B2) when is_binary(B1), is_binary(B2) -> B1 == B2; -equiv(A, A) when A =:= true orelse A =:= false orelse A =:= null -> true. - -%% Object representation and traversal order is unknown. -%% Use the sledgehammer and sort property lists. - -equiv_object(Props1, Props2) -> - L1 = lists:keysort(1, Props1), - L2 = lists:keysort(1, Props2), - Pairs = lists:zip(L1, L2), - true = lists:all(fun({{K1, V1}, {K2, V2}}) -> - equiv(K1, K2) and equiv(V1, V2) - end, Pairs). - -%% Recursively compare tuple elements for equivalence. - -equiv_list([], []) -> - true; -equiv_list([V1 | L1], [V2 | L2]) -> - equiv(V1, V2) andalso equiv_list(L1, L2). - -decode_test() -> - [1199344435545.0, 1] = decode(<<"[1199344435545.0,1]">>), - <<16#F0,16#9D,16#9C,16#95>> = decode([34,"\\ud835","\\udf15",34]). - -e2j_vec_test() -> - test_one(e2j_test_vec(utf8), 1). - -test_one([], _N) -> - %% io:format("~p tests passed~n", [N-1]), - ok; -test_one([{E, J} | Rest], N) -> - %% io:format("[~p] ~p ~p~n", [N, E, J]), - true = equiv(E, decode(J)), - true = equiv(E, decode(encode(E))), - test_one(Rest, 1+N). - -e2j_test_vec(utf8) -> - [ - {1, "1"}, - {3.1416, "3.14160"}, %% text representation may truncate, trail zeroes - {-1, "-1"}, - {-3.1416, "-3.14160"}, - {12.0e10, "1.20000e+11"}, - {1.234E+10, "1.23400e+10"}, - {-1.234E-10, "-1.23400e-10"}, - {10.0, "1.0e+01"}, - {123.456, "1.23456E+2"}, - {10.0, "1e1"}, - {<<"foo">>, "\"foo\""}, - {<<"foo", 5, "bar">>, "\"foo\\u0005bar\""}, - {<<"">>, "\"\""}, - {<<"\n\n\n">>, "\"\\n\\n\\n\""}, - {<<"\" \b\f\r\n\t\"">>, "\"\\\" \\b\\f\\r\\n\\t\\\"\""}, - {obj_new(), "{}"}, - {obj_from_list([{<<"foo">>, <<"bar">>}]), "{\"foo\":\"bar\"}"}, - {obj_from_list([{<<"foo">>, <<"bar">>}, {<<"baz">>, 123}]), - "{\"foo\":\"bar\",\"baz\":123}"}, - {[], "[]"}, - {[[]], "[[]]"}, - {[1, <<"foo">>], "[1,\"foo\"]"}, - - %% json array in a json object - {obj_from_list([{<<"foo">>, [123]}]), - "{\"foo\":[123]}"}, - - %% json object in a json object - {obj_from_list([{<<"foo">>, obj_from_list([{<<"bar">>, true}])}]), - "{\"foo\":{\"bar\":true}}"}, - - %% fold evaluation order - {obj_from_list([{<<"foo">>, []}, - {<<"bar">>, obj_from_list([{<<"baz">>, true}])}, - {<<"alice">>, <<"bob">>}]), - "{\"foo\":[],\"bar\":{\"baz\":true},\"alice\":\"bob\"}"}, - - %% json object in a json array - {[-123, <<"foo">>, obj_from_list([{<<"bar">>, []}]), null], - "[-123,\"foo\",{\"bar\":[]},null]"} - ]. - -%% test utf8 encoding -encoder_utf8_test() -> - %% safe conversion case (default) - [34,"\\u0001","\\u0442","\\u0435","\\u0441","\\u0442",34] = - encode(<<1,"\321\202\320\265\321\201\321\202">>), - - %% raw utf8 output (optional) - Enc = mochijson2:encoder([{utf8, true}]), - [34,"\\u0001",[209,130],[208,181],[209,129],[209,130],34] = - Enc(<<1,"\321\202\320\265\321\201\321\202">>). - -input_validation_test() -> - Good = [ - {16#00A3, <<?Q, 16#C2, 16#A3, ?Q>>}, %% pound - {16#20AC, <<?Q, 16#E2, 16#82, 16#AC, ?Q>>}, %% euro - {16#10196, <<?Q, 16#F0, 16#90, 16#86, 16#96, ?Q>>} %% denarius - ], - lists:foreach(fun({CodePoint, UTF8}) -> - Expect = list_to_binary(xmerl_ucs:to_utf8(CodePoint)), - Expect = decode(UTF8) - end, Good), - - Bad = [ - %% 2nd, 3rd, or 4th byte of a multi-byte sequence w/o leading byte - <<?Q, 16#80, ?Q>>, - %% missing continuations, last byte in each should be 80-BF - <<?Q, 16#C2, 16#7F, ?Q>>, - <<?Q, 16#E0, 16#80,16#7F, ?Q>>, - <<?Q, 16#F0, 16#80, 16#80, 16#7F, ?Q>>, - %% we don't support code points > 10FFFF per RFC 3629 - <<?Q, 16#F5, 16#80, 16#80, 16#80, ?Q>>, - %% escape characters trigger a different code path - <<?Q, $\\, $\n, 16#80, ?Q>> - ], - lists:foreach( - fun(X) -> - ok = try decode(X) catch invalid_utf8 -> ok end, - %% could be {ucs,{bad_utf8_character_code}} or - %% {json_encode,{bad_char,_}} - {'EXIT', _} = (catch encode(X)) - end, Bad). - -inline_json_test() -> - ?assertEqual(<<"\"iodata iodata\"">>, - iolist_to_binary( - encode({json, [<<"\"iodata">>, " iodata\""]}))), - ?assertEqual({struct, [{<<"key">>, <<"iodata iodata">>}]}, - decode( - encode({struct, - [{key, {json, [<<"\"iodata">>, " iodata\""]}}]}))), - ok. - -big_unicode_test() -> - UTF8Seq = list_to_binary(xmerl_ucs:to_utf8(16#0001d120)), - ?assertEqual( - <<"\"\\ud834\\udd20\"">>, - iolist_to_binary(encode(UTF8Seq))), - ?assertEqual( - UTF8Seq, - decode(iolist_to_binary(encode(UTF8Seq)))), - ok. - -custom_decoder_test() -> - ?assertEqual( - {struct, [{<<"key">>, <<"value">>}]}, - (decoder([]))("{\"key\": \"value\"}")), - F = fun ({struct, [{<<"key">>, <<"value">>}]}) -> win end, - ?assertEqual( - win, - (decoder([{object_hook, F}]))("{\"key\": \"value\"}")), - ok. - -atom_test() -> - %% JSON native atoms - [begin - ?assertEqual(A, decode(atom_to_list(A))), - ?assertEqual(iolist_to_binary(atom_to_list(A)), - iolist_to_binary(encode(A))) - end || A <- [true, false, null]], - %% Atom to string - ?assertEqual( - <<"\"foo\"">>, - iolist_to_binary(encode(foo))), - ?assertEqual( - <<"\"\\ud834\\udd20\"">>, - iolist_to_binary(encode(list_to_atom(xmerl_ucs:to_utf8(16#0001d120))))), - ok. - -key_encode_test() -> - %% Some forms are accepted as keys that would not be strings in other - %% cases - ?assertEqual( - <<"{\"foo\":1}">>, - iolist_to_binary(encode({struct, [{foo, 1}]}))), - ?assertEqual( - <<"{\"foo\":1}">>, - iolist_to_binary(encode({struct, [{<<"foo">>, 1}]}))), - ?assertEqual( - <<"{\"foo\":1}">>, - iolist_to_binary(encode({struct, [{"foo", 1}]}))), - ?assertEqual( - <<"{\"foo\":1}">>, - iolist_to_binary(encode([{foo, 1}]))), - ?assertEqual( - <<"{\"foo\":1}">>, - iolist_to_binary(encode([{<<"foo">>, 1}]))), - ?assertEqual( - <<"{\"foo\":1}">>, - iolist_to_binary(encode([{"foo", 1}]))), - ?assertEqual( - <<"{\"\\ud834\\udd20\":1}">>, - iolist_to_binary( - encode({struct, [{[16#0001d120], 1}]}))), - ?assertEqual( - <<"{\"1\":1}">>, - iolist_to_binary(encode({struct, [{1, 1}]}))), - ok. - -unsafe_chars_test() -> - Chars = "\"\\\b\f\n\r\t", - [begin - ?assertEqual(false, json_string_is_safe([C])), - ?assertEqual(false, json_bin_is_safe(<<C>>)), - ?assertEqual(<<C>>, decode(encode(<<C>>))) - end || C <- Chars], - ?assertEqual( - false, - json_string_is_safe([16#0001d120])), - ?assertEqual( - false, - json_bin_is_safe(list_to_binary(xmerl_ucs:to_utf8(16#0001d120)))), - ?assertEqual( - [16#0001d120], - xmerl_ucs:from_utf8( - binary_to_list( - decode(encode(list_to_atom(xmerl_ucs:to_utf8(16#0001d120))))))), - ?assertEqual( - false, - json_string_is_safe([16#110000])), - ?assertEqual( - false, - json_bin_is_safe(list_to_binary(xmerl_ucs:to_utf8([16#110000])))), - %% solidus can be escaped but isn't unsafe by default - ?assertEqual( - <<"/">>, - decode(<<"\"\\/\"">>)), - ok. - -int_test() -> - ?assertEqual(0, decode("0")), - ?assertEqual(1, decode("1")), - ?assertEqual(11, decode("11")), - ok. - -large_int_test() -> - ?assertEqual(<<"-2147483649214748364921474836492147483649">>, - iolist_to_binary(encode(-2147483649214748364921474836492147483649))), - ?assertEqual(<<"2147483649214748364921474836492147483649">>, - iolist_to_binary(encode(2147483649214748364921474836492147483649))), - ok. - -float_test() -> - ?assertEqual(<<"-2147483649.0">>, iolist_to_binary(encode(-2147483649.0))), - ?assertEqual(<<"2147483648.0">>, iolist_to_binary(encode(2147483648.0))), - ok. - -handler_test() -> - ?assertEqual( - {'EXIT',{json_encode,{bad_term,{}}}}, - catch encode({})), - F = fun ({}) -> [] end, - ?assertEqual( - <<"[]">>, - iolist_to_binary((encoder([{handler, F}]))({}))), - ok. - --endif. diff --git a/src/ejson/src/mochinum.erl b/src/ejson/src/mochinum.erl deleted file mode 100644 index c52b15ca5..000000000 --- a/src/ejson/src/mochinum.erl +++ /dev/null @@ -1,354 +0,0 @@ -%% @copyright 2007 Mochi Media, Inc. -%% @author Bob Ippolito <bob@mochimedia.com> - -%% @doc Useful numeric algorithms for floats that cover some deficiencies -%% in the math module. More interesting is digits/1, which implements -%% the algorithm from: -%% http://www.cs.indiana.edu/~burger/fp/index.html -%% See also "Printing Floating-Point Numbers Quickly and Accurately" -%% in Proceedings of the SIGPLAN '96 Conference on Programming Language -%% Design and Implementation. - --module(mochinum). --author("Bob Ippolito <bob@mochimedia.com>"). --export([digits/1, frexp/1, int_pow/2, int_ceil/1]). - -%% IEEE 754 Float exponent bias --define(FLOAT_BIAS, 1022). --define(MIN_EXP, -1074). --define(BIG_POW, 4503599627370496). - -%% External API - -%% @spec digits(number()) -> string() -%% @doc Returns a string that accurately represents the given integer or float -%% using a conservative amount of digits. Great for generating -%% human-readable output, or compact ASCII serializations for floats. -digits(N) when is_integer(N) -> - integer_to_list(N); -digits(0.0) -> - "0.0"; -digits(Float) -> - {Frac1, Exp1} = frexp_int(Float), - [Place0 | Digits0] = digits1(Float, Exp1, Frac1), - {Place, Digits} = transform_digits(Place0, Digits0), - R = insert_decimal(Place, Digits), - case Float < 0 of - true -> - [$- | R]; - _ -> - R - end. - -%% @spec frexp(F::float()) -> {Frac::float(), Exp::float()} -%% @doc Return the fractional and exponent part of an IEEE 754 double, -%% equivalent to the libc function of the same name. -%% F = Frac * pow(2, Exp). -frexp(F) -> - frexp1(unpack(F)). - -%% @spec int_pow(X::integer(), N::integer()) -> Y::integer() -%% @doc Moderately efficient way to exponentiate integers. -%% int_pow(10, 2) = 100. -int_pow(_X, 0) -> - 1; -int_pow(X, N) when N > 0 -> - int_pow(X, N, 1). - -%% @spec int_ceil(F::float()) -> integer() -%% @doc Return the ceiling of F as an integer. The ceiling is defined as -%% F when F == trunc(F); -%% trunc(F) when F < 0; -%% trunc(F) + 1 when F > 0. -int_ceil(X) -> - T = trunc(X), - case (X - T) of - Pos when Pos > 0 -> T + 1; - _ -> T - end. - - -%% Internal API - -int_pow(X, N, R) when N < 2 -> - R * X; -int_pow(X, N, R) -> - int_pow(X * X, N bsr 1, case N band 1 of 1 -> R * X; 0 -> R end). - -insert_decimal(0, S) -> - "0." ++ S; -insert_decimal(Place, S) when Place > 0 -> - L = length(S), - case Place - L of - 0 -> - S ++ ".0"; - N when N < 0 -> - {S0, S1} = lists:split(L + N, S), - S0 ++ "." ++ S1; - N when N < 6 -> - %% More places than digits - S ++ lists:duplicate(N, $0) ++ ".0"; - _ -> - insert_decimal_exp(Place, S) - end; -insert_decimal(Place, S) when Place > -6 -> - "0." ++ lists:duplicate(abs(Place), $0) ++ S; -insert_decimal(Place, S) -> - insert_decimal_exp(Place, S). - -insert_decimal_exp(Place, S) -> - [C | S0] = S, - S1 = case S0 of - [] -> - "0"; - _ -> - S0 - end, - Exp = case Place < 0 of - true -> - "e-"; - false -> - "e+" - end, - [C] ++ "." ++ S1 ++ Exp ++ integer_to_list(abs(Place - 1)). - - -digits1(Float, Exp, Frac) -> - Round = ((Frac band 1) =:= 0), - case Exp >= 0 of - true -> - BExp = 1 bsl Exp, - case (Frac =/= ?BIG_POW) of - true -> - scale((Frac * BExp * 2), 2, BExp, BExp, - Round, Round, Float); - false -> - scale((Frac * BExp * 4), 4, (BExp * 2), BExp, - Round, Round, Float) - end; - false -> - case (Exp =:= ?MIN_EXP) orelse (Frac =/= ?BIG_POW) of - true -> - scale((Frac * 2), 1 bsl (1 - Exp), 1, 1, - Round, Round, Float); - false -> - scale((Frac * 4), 1 bsl (2 - Exp), 2, 1, - Round, Round, Float) - end - end. - -scale(R, S, MPlus, MMinus, LowOk, HighOk, Float) -> - Est = int_ceil(math:log10(abs(Float)) - 1.0e-10), - %% Note that the scheme implementation uses a 326 element look-up table - %% for int_pow(10, N) where we do not. - case Est >= 0 of - true -> - fixup(R, S * int_pow(10, Est), MPlus, MMinus, Est, - LowOk, HighOk); - false -> - Scale = int_pow(10, -Est), - fixup(R * Scale, S, MPlus * Scale, MMinus * Scale, Est, - LowOk, HighOk) - end. - -fixup(R, S, MPlus, MMinus, K, LowOk, HighOk) -> - TooLow = case HighOk of - true -> - (R + MPlus) >= S; - false -> - (R + MPlus) > S - end, - case TooLow of - true -> - [(K + 1) | generate(R, S, MPlus, MMinus, LowOk, HighOk)]; - false -> - [K | generate(R * 10, S, MPlus * 10, MMinus * 10, LowOk, HighOk)] - end. - -generate(R0, S, MPlus, MMinus, LowOk, HighOk) -> - D = R0 div S, - R = R0 rem S, - TC1 = case LowOk of - true -> - R =< MMinus; - false -> - R < MMinus - end, - TC2 = case HighOk of - true -> - (R + MPlus) >= S; - false -> - (R + MPlus) > S - end, - case TC1 of - false -> - case TC2 of - false -> - [D | generate(R * 10, S, MPlus * 10, MMinus * 10, - LowOk, HighOk)]; - true -> - [D + 1] - end; - true -> - case TC2 of - false -> - [D]; - true -> - case R * 2 < S of - true -> - [D]; - false -> - [D + 1] - end - end - end. - -unpack(Float) -> - <<Sign:1, Exp:11, Frac:52>> = <<Float:64/float>>, - {Sign, Exp, Frac}. - -frexp1({_Sign, 0, 0}) -> - {0.0, 0}; -frexp1({Sign, 0, Frac}) -> - Exp = log2floor(Frac), - <<Frac1:64/float>> = <<Sign:1, ?FLOAT_BIAS:11, (Frac-1):52>>, - {Frac1, -(?FLOAT_BIAS) - 52 + Exp}; -frexp1({Sign, Exp, Frac}) -> - <<Frac1:64/float>> = <<Sign:1, ?FLOAT_BIAS:11, Frac:52>>, - {Frac1, Exp - ?FLOAT_BIAS}. - -log2floor(Int) -> - log2floor(Int, 0). - -log2floor(0, N) -> - N; -log2floor(Int, N) -> - log2floor(Int bsr 1, 1 + N). - - -transform_digits(Place, [0 | Rest]) -> - transform_digits(Place, Rest); -transform_digits(Place, Digits) -> - {Place, [$0 + D || D <- Digits]}. - - -frexp_int(F) -> - case unpack(F) of - {_Sign, 0, Frac} -> - {Frac, ?MIN_EXP}; - {_Sign, Exp, Frac} -> - {Frac + (1 bsl 52), Exp - 53 - ?FLOAT_BIAS} - end. - -%% -%% Tests -%% --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). - -int_ceil_test() -> - ?assertEqual(1, int_ceil(0.0001)), - ?assertEqual(0, int_ceil(0.0)), - ?assertEqual(1, int_ceil(0.99)), - ?assertEqual(1, int_ceil(1.0)), - ?assertEqual(-1, int_ceil(-1.5)), - ?assertEqual(-2, int_ceil(-2.0)), - ok. - -int_pow_test() -> - ?assertEqual(1, int_pow(1, 1)), - ?assertEqual(1, int_pow(1, 0)), - ?assertEqual(1, int_pow(10, 0)), - ?assertEqual(10, int_pow(10, 1)), - ?assertEqual(100, int_pow(10, 2)), - ?assertEqual(1000, int_pow(10, 3)), - ok. - -digits_test() -> - ?assertEqual("0", - digits(0)), - ?assertEqual("0.0", - digits(0.0)), - ?assertEqual("1.0", - digits(1.0)), - ?assertEqual("-1.0", - digits(-1.0)), - ?assertEqual("0.1", - digits(0.1)), - ?assertEqual("0.01", - digits(0.01)), - ?assertEqual("0.001", - digits(0.001)), - ?assertEqual("1.0e+6", - digits(1000000.0)), - ?assertEqual("0.5", - digits(0.5)), - ?assertEqual("4503599627370496.0", - digits(4503599627370496.0)), - %% small denormalized number - %% 4.94065645841246544177e-324 =:= 5.0e-324 - <<SmallDenorm/float>> = <<0,0,0,0,0,0,0,1>>, - ?assertEqual("5.0e-324", - digits(SmallDenorm)), - ?assertEqual(SmallDenorm, - list_to_float(digits(SmallDenorm))), - %% large denormalized number - %% 2.22507385850720088902e-308 - <<BigDenorm/float>> = <<0,15,255,255,255,255,255,255>>, - ?assertEqual("2.225073858507201e-308", - digits(BigDenorm)), - ?assertEqual(BigDenorm, - list_to_float(digits(BigDenorm))), - %% small normalized number - %% 2.22507385850720138309e-308 - <<SmallNorm/float>> = <<0,16,0,0,0,0,0,0>>, - ?assertEqual("2.2250738585072014e-308", - digits(SmallNorm)), - ?assertEqual(SmallNorm, - list_to_float(digits(SmallNorm))), - %% large normalized number - %% 1.79769313486231570815e+308 - <<LargeNorm/float>> = <<127,239,255,255,255,255,255,255>>, - ?assertEqual("1.7976931348623157e+308", - digits(LargeNorm)), - ?assertEqual(LargeNorm, - list_to_float(digits(LargeNorm))), - %% issue #10 - mochinum:frexp(math:pow(2, -1074)). - ?assertEqual("5.0e-324", - digits(math:pow(2, -1074))), - ok. - -frexp_test() -> - %% zero - ?assertEqual({0.0, 0}, frexp(0.0)), - %% one - ?assertEqual({0.5, 1}, frexp(1.0)), - %% negative one - ?assertEqual({-0.5, 1}, frexp(-1.0)), - %% small denormalized number - %% 4.94065645841246544177e-324 - <<SmallDenorm/float>> = <<0,0,0,0,0,0,0,1>>, - ?assertEqual({0.5, -1073}, frexp(SmallDenorm)), - %% large denormalized number - %% 2.22507385850720088902e-308 - <<BigDenorm/float>> = <<0,15,255,255,255,255,255,255>>, - ?assertEqual( - {0.99999999999999978, -1022}, - frexp(BigDenorm)), - %% small normalized number - %% 2.22507385850720138309e-308 - <<SmallNorm/float>> = <<0,16,0,0,0,0,0,0>>, - ?assertEqual({0.5, -1021}, frexp(SmallNorm)), - %% large normalized number - %% 1.79769313486231570815e+308 - <<LargeNorm/float>> = <<127,239,255,255,255,255,255,255>>, - ?assertEqual( - {0.99999999999999989, 1024}, - frexp(LargeNorm)), - %% issue #10 - mochinum:frexp(math:pow(2, -1074)). - ?assertEqual( - {0.5, -1073}, - frexp(math:pow(2, -1074))), - ok. - --endif. |