fix cjson bugs and reduce mem usage

This commit is contained in:
funshine 2015-03-16 23:59:57 +08:00
parent c0d690ce7e
commit 54004a4beb
10 changed files with 188 additions and 350 deletions

View File

@ -1,44 +0,0 @@
Version 2.1.0 (Mar 1 2012)
* Added cjson.safe module interface which returns nil after an error
* Improved Makefile compatibility with Solaris make
Version 2.0.0 (Jan 22 2012)
* Improved platform compatibility for strtod/sprintf locale workaround
* Added option to build with David Gay's dtoa.c for improved performance
* Added support for Lua 5.2
* Added option to encode infinity/NaN as JSON null
* Fixed encode bug with a raised default limit and deeply nested tables
* Updated Makefile for compatibility with non-GNU make implementations
* Added CMake build support
* Added HTML manual
* Increased default nesting limit to 1000
* Added support for re-entrant use of encode and decode
* Added support for installing lua2json and json2lua utilities
* Added encode_invalid_numbers() and decode_invalid_numbers()
* Added decode_max_depth()
* Removed registration of global cjson module table
* Removed refuse_invalid_numbers()
Version 1.0.4 (Nov 30 2011)
* Fixed numeric conversion under locales with a comma decimal separator
Version 1.0.3 (Sep 15 2011)
* Fixed detection of objects with numeric string keys
* Provided work around for missing isinf() on Solaris
Version 1.0.2 (May 30 2011)
* Portability improvements for Windows
- No longer links with -lm
- Use "socket" instead of "posix" for sub-second timing
* Removed UTF-8 test dependency on Perl Text::Iconv
* Added simple CLI commands for testing Lua <-> JSON conversions
* Added cjson.encode_number_precision()
Version 1.0.1 (May 10 2011)
* Added build support for OSX
* Removed unnecessary whitespace from JSON output
* Added cjson.encode_keep_buffer()
* Fixed memory leak on Lua stack overflow exception
Version 1.0 (May 9 2011)
* Initial release

View File

@ -184,7 +184,7 @@
* a decimal expansion to decide close cases. This logic is only
* used for input more than STRTOD_DIGLIM digits long (default 40).
*/
#if 0
#include "dtoa_config.h"
#ifndef Long
@ -4356,3 +4356,4 @@ dtoa
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,6 +1,6 @@
#ifndef _DTOA_CONFIG_H
#define _DTOA_CONFIG_H
#if 0
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@ -67,7 +67,7 @@ static pthread_mutex_t private_dtoa_lock[2] = {
} while (0)
#endif /* MULTIPLE_THREADS */
#endif
#endif /* _DTOA_CONFIG_H */
/* vi:ai et sw=4 ts=4:

View File

@ -21,7 +21,7 @@
* it suffices to declare buf
* char buf[32];
*/
#if 0
#ifdef __cplusplus
extern "C" {
#endif
@ -109,3 +109,4 @@ fpconv_g_fmt(char *b, double x, int precision)
#endif
return b - b0;
}
#endif

View File

@ -1,56 +0,0 @@
package = "lua-cjson"
version = "2.1devel-1"
source = {
url = "http://www.kyne.com.au/~mark/software/download/lua-cjson-2.1devel.zip",
}
description = {
summary = "A fast JSON encoding/parsing module",
detailed = [[
The Lua CJSON module provides JSON support for Lua. It features:
- Fast, standards compliant encoding/parsing routines
- Full support for JSON with UTF-8, including decoding surrogate pairs
- Optional run-time support for common exceptions to the JSON specification
(infinity, NaN,..)
- No dependencies on other libraries
]],
homepage = "http://www.kyne.com.au/~mark/software/lua-cjson.php",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = {
cjson = {
sources = { "lua_cjson.c", "strbuf.c", "fpconv.c" },
defines = {
-- LuaRocks does not support platform specific configuration for Solaris.
-- Uncomment the line below on Solaris platforms if required.
-- "USE_INTERNAL_ISINF"
}
}
},
install = {
lua = {
["cjson.util"] = "lua/cjson/util.lua"
},
bin = {
json2lua = "lua/json2lua.lua",
lua2json = "lua/lua2json.lua"
}
},
-- Override default build options (per platform)
platforms = {
win32 = { modules = { cjson = { defines = {
"DISABLE_INVALID_NUMBERS"
} } } }
},
copy_directories = { "tests" }
}
-- vi:ai et sw=4 ts=4:

View File

@ -1,80 +0,0 @@
%define luaver 5.1
%define lualibdir %{_libdir}/lua/%{luaver}
%define luadatadir %{_datadir}/lua/%{luaver}
Name: lua-cjson
Version: 2.1devel
Release: 1%{?dist}
Summary: A fast JSON encoding/parsing module for Lua
Group: Development/Libraries
License: MIT
URL: http://www.kyne.com.au/~mark/software/lua-cjson/
Source0: http://www.kyne.com.au/~mark/software/lua-cjson/download/lua-cjson-%{version}.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
BuildRequires: lua >= %{luaver}, lua-devel >= %{luaver}
Requires: lua >= %{luaver}
%description
The Lua CJSON module provides JSON support for Lua. It features:
- Fast, standards compliant encoding/parsing routines
- Full support for JSON with UTF-8, including decoding surrogate pairs
- Optional run-time support for common exceptions to the JSON specification
(infinity, NaN,..)
- No dependencies on other libraries
%prep
%setup -q
%build
make %{?_smp_mflags} CFLAGS="%{optflags}" LUA_INCLUDE_DIR="%{_includedir}"
%install
rm -rf "$RPM_BUILD_ROOT"
make install DESTDIR="$RPM_BUILD_ROOT" LUA_CMODULE_DIR="%{lualibdir}"
make install-extra DESTDIR="$RPM_BUILD_ROOT" LUA_MODULE_DIR="%{luadatadir}" \
LUA_BIN_DIR="%{_bindir}"
%clean
rm -rf "$RPM_BUILD_ROOT"
%preun
/bin/rm -f "%{luadatadir}/cjson/tests/utf8.dat"
%files
%defattr(-,root,root,-)
%doc LICENSE NEWS performance.html performance.txt manual.html manual.txt rfc4627.txt THANKS
%{lualibdir}/*
%{luadatadir}/*
%{_bindir}/*
%changelog
* Thu Mar 1 2012 Mark Pulford <mark@kyne.com.au> - 2.1.0-1
- Update for 2.1.0
* Sun Jan 22 2012 Mark Pulford <mark@kyne.com.au> - 2.0.0-1
- Update for 2.0.0
- Install lua2json / json2lua utilities
* Wed Nov 27 2011 Mark Pulford <mark@kyne.com.au> - 1.0.4-1
- Update for 1.0.4
* Wed Sep 15 2011 Mark Pulford <mark@kyne.com.au> - 1.0.3-1
- Update for 1.0.3
* Sun May 29 2011 Mark Pulford <mark@kyne.com.au> - 1.0.2-1
- Update for 1.0.2
* Sun May 10 2011 Mark Pulford <mark@kyne.com.au> - 1.0.1-1
- Update for 1.0.1
* Sun May 1 2011 Mark Pulford <mark@kyne.com.au> - 1.0-1
- Initial package

View File

@ -1,89 +0,0 @@
JSON module performance comparison under Lua
============================================
Mark Pulford <mark@kyne.com.au>
:revdate: January 22, 2012
This performance comparison aims to provide a guide of relative
performance between several fast and popular JSON modules.
The examples used in this comparison were mostly sourced from the
http://json.org[JSON website] and
http://tools.ietf.org/html/rfc4627[RFC 4627].
Performance will vary widely between platforms and data sets. These
results should only be used as an approximation.
Modules
-------
The following JSON modules for Lua were tested:
http://chiselapp.com/user/dhkolf/repository/dkjson/[DKJSON 2.1]::
- Lua implementation with no dependencies on other libraries
- Supports LPeg to improve decode performance
https://github.com/brimworks/lua-yajl[Lua YAJL 2.0]::
- C wrapper for the YAJL library
http://www.kyne.com.au/%7Emark/software/lua-cjson.php[Lua CSJON 2.0.0]::
- C implementation with no dependencies on other libraries
Summary
-------
All modules were built and tested as follows:
DKJSON:: Tested with/without LPeg 10.2.
Lua YAJL:: Tested with YAJL 2.0.4.
Lua CJSON:: Tested with Libc and internal floating point conversion
routines.
The following Lua implementations were used for this comparison:
- http://www.lua.org[Lua 5.1.4] (_Lua_)
- http://www.luajit.org[LuaJIT 2.0.0-beta9] (_JIT_)
These results show the number of JSON operations per second sustained by
each module. All results have been normalised against the pure Lua
DKJSON implementation.
.Decoding performance
............................................................................
| DKJSON | Lua YAJL | Lua CJSON
| No LPeg With LPeg | | Libc Internal
| Lua JIT Lua JIT | Lua JIT | Lua JIT Lua JIT
example1 | 1x 2x 2.6x 3.4x | 7.1x 10x | 14x 20x 14x 20x
example2 | 1x 2.2x 2.9x 4.4x | 6.7x 9.9x | 14x 22x 14x 22x
example3 | 1x 2.1x 3x 4.3x | 6.9x 9.3x | 14x 21x 15x 22x
example4 | 1x 2x 2.5x 3.7x | 7.3x 10x | 12x 19x 12x 20x
example5 | 1x 2.2x 3x 4.5x | 7.8x 11x | 16x 24x 16x 24x
numbers | 1x 2.2x 2.3x 4x | 4.6x 5.5x | 8.9x 10x 13x 17x
rfc-example1 | 1x 2.1x 2.8x 4.3x | 6.1x 8.1x | 13x 19x 14x 21x
rfc-example2 | 1x 2.1x 3.1x 4.2x | 7.1x 9.2x | 15x 21x 17x 24x
types | 1x 2.2x 2.6x 4.3x | 5.3x 7.4x | 12x 20x 13x 21x
-------------|-------------------------|------------|-----------------------
= Average => | 1x 2.1x 2.7x 4.1x | 6.5x 9x | 13x 20x 14x 21x
............................................................................
.Encoding performance
.............................................................................
| DKJSON | Lua YAJL | Lua CJSON
| No LPeg With LPeg | | Libc Internal
| Lua JIT Lua JIT | Lua JIT | Lua JIT Lua JIT
example1 | 1x 1.8x 0.97x 1.6x | 3.1x 5.2x | 23x 29x 23x 29x
example2 | 1x 2x 0.97x 1.7x | 2.6x 4.3x | 22x 28x 22x 28x
example3 | 1x 1.9x 0.98x 1.6x | 2.8x 4.3x | 13x 15x 16x 18x
example4 | 1x 1.7x 0.96x 1.3x | 3.9x 6.1x | 15x 19x 17x 21x
example5 | 1x 2x 0.98x 1.7x | 2.7x 4.5x | 20x 23x 20x 23x
numbers | 1x 2.3x 1x 2.2x | 1.3x 1.9x | 3.8x 4.1x 4.2x 4.6x
rfc-example1 | 1x 1.9x 0.97x 1.6x | 2.2x 3.2x | 8.5x 9.3x 11x 12x
rfc-example2 | 1x 1.9x 0.98x 1.6x | 2.6x 3.9x | 10x 11x 17x 19x
types | 1x 2.2x 0.97x 2x | 1.2x 1.9x | 11x 13x 12x 14x
-------------|-------------------------|------------|-----------------------
= Average => | 1x 1.9x 0.98x 1.7x | 2.5x 3.9x | 14x 17x 16x 19x
.............................................................................
// vi:ft=asciidoc tw=72:

View File

@ -41,7 +41,7 @@
// exit(-1);
// }
void strbuf_init(strbuf_t *s, int len)
int strbuf_init(strbuf_t *s, int len)
{
int size;
@ -61,10 +61,11 @@ void strbuf_init(strbuf_t *s, int len)
s->buf = c_malloc(size);
if (!s->buf){
NODE_ERR("not enough memory\n");
return;
return -1;
}
strbuf_ensure_null(s);
return 0;
}
strbuf_t *strbuf_new(int len)
@ -74,7 +75,7 @@ strbuf_t *strbuf_new(int len)
s = c_malloc(sizeof(strbuf_t));
if (!s){
NODE_ERR("not enough memory\n");
return;
return NULL;
}
strbuf_init(s, len);
@ -85,16 +86,17 @@ strbuf_t *strbuf_new(int len)
return s;
}
void strbuf_set_increment(strbuf_t *s, int increment)
int strbuf_set_increment(strbuf_t *s, int increment)
{
/* Increment > 0: Linear buffer growth rate
* Increment < -1: Exponential buffer growth rate */
if (increment == 0 || increment == -1){
NODE_ERR("BUG: Invalid string increment");
return;
return -1;
}
s->increment = increment;
return 0;
}
static inline void debug_stats(strbuf_t *s)
@ -169,7 +171,7 @@ static int calculate_new_size(strbuf_t *s, int len)
/* Ensure strbuf can handle a string length bytes long (ignoring NULL
* optional termination). */
void strbuf_resize(strbuf_t *s, int len)
int strbuf_resize(strbuf_t *s, int len)
{
int newsize;
@ -180,13 +182,14 @@ void strbuf_resize(strbuf_t *s, int len)
(long)s, s->size, newsize);
}
s->size = newsize;
s->buf = (char *)c_realloc(s->buf, s->size);
s->buf = (char *)c_realloc(s->buf, newsize);
if (!s->buf){
NODE_ERR("not enough memory");
return;
return -1;
}
s->size = newsize;
s->reallocs++;
return 0;
}
void strbuf_append_string(strbuf_t *s, const char *str)

View File

@ -50,15 +50,15 @@ typedef struct {
/* Initialise */
extern strbuf_t *strbuf_new(int len);
extern void strbuf_init(strbuf_t *s, int len);
extern void strbuf_set_increment(strbuf_t *s, int increment);
extern int strbuf_init(strbuf_t *s, int len);
extern int strbuf_set_increment(strbuf_t *s, int increment);
/* Release */
extern void strbuf_free(strbuf_t *s);
extern char *strbuf_free_to_string(strbuf_t *s, int *len);
/* Management */
extern void strbuf_resize(strbuf_t *s, int len);
extern int strbuf_resize(strbuf_t *s, int len);
static int strbuf_empty_length(strbuf_t *s);
static int strbuf_length(strbuf_t *s);
static char *strbuf_string(strbuf_t *s, int *len);
@ -127,13 +127,13 @@ static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
{
strbuf_ensure_empty_length(s, len);
memcpy(s->buf + s->length, c, len);
c_memcpy(s->buf + s->length, c, len);
s->length += len;
}
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
{
memcpy(s->buf + s->length, c, len);
c_memcpy(s->buf + s->length, c, len);
s->length += len;
}

View File

@ -42,6 +42,7 @@
#include "c_limits.h"
#include "lua.h"
#include "lauxlib.h"
#include "flash_api.h"
#include "strbuf.h"
#ifdef LUA_NUMBER_INTEGRAL
@ -50,7 +51,6 @@
#define FPCONV_G_FMT_BUFSIZE 32
#define fpconv_strtod c_strtod
#define fpconv_init() ((void)0)
#define fpconv_g_fmt fpconv_g_fmt
#endif
#ifndef CJSON_MODNAME
@ -73,7 +73,7 @@
#define DEFAULT_DECODE_MAX_DEPTH 1000
#define DEFAULT_ENCODE_INVALID_NUMBERS 0
#define DEFAULT_DECODE_INVALID_NUMBERS 1
#define DEFAULT_ENCODE_KEEP_BUFFER 1
#define DEFAULT_ENCODE_KEEP_BUFFER 0
#define DEFAULT_ENCODE_NUMBER_PRECISION 14
#ifdef DISABLE_INVALID_NUMBERS
@ -97,7 +97,7 @@ typedef enum {
T_ERROR,
T_UNKNOWN
} json_token_type_t;
#if 0
static const char *json_token_type_name[] = {
"T_OBJ_BEGIN",
"T_OBJ_END",
@ -115,10 +115,27 @@ static const char *json_token_type_name[] = {
"T_UNKNOWN",
NULL
};
#endif
static const char json_token_type_name[14][16] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = {
{'T','_','O','B','J','_','B','E','G','I','N',0},
{'T','_','O','B','J','_','E','N','D',0},
{'T','_','A','R','R','_','B','E','G','I','N',0},
{'T','_','A','R','R','_','E','N','D',0},
{'T','_','S','T','R','I','N','G',0},
{'T','_','N','U','M','B','E','R',0},
{'T','_','B','O','O','L','E','A','N',0},
{'T','_','N','U','L','L',0},
{'T','_','C','O','L','O','N',0},
{'T','_','C','O','M','M','A',0},
{'T','_','E','N','D',0},
{'T','_','W','H','I','T','E','S','P','A','C','E',0},
{'T','_','E','R','R','O','R',0},
{'T','_','U','N','K','N','O','W','N',0}
};
typedef struct {
json_token_type_t ch2token[256];
char escape2char[256]; /* Decoding */
// json_token_type_t ch2token[256]; // 256*4 = 1024 byte
// char escape2char[256]; /* Decoding */
/* encode_buf is only allocated and used when
* encode_keep_buffer is set */
@ -155,6 +172,7 @@ typedef struct {
int string_len;
} json_token_t;
#if 0
static const char *char2escape[256] = {
"\\u0000", "\\u0001", "\\u0002", "\\u0003",
"\\u0004", "\\u0005", "\\u0006", "\\u0007",
@ -193,6 +211,99 @@ static const char *char2escape[256] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
#endif
/* ===== HELPER FUNCTION ===== */
static const char escape_array[36][8] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = {
{'\\','u','0','0','0','0','\0','\0'},
{'\\','u','0','0','0','1','\0','\0'},
{'\\','u','0','0','0','2','\0','\0'},
{'\\','u','0','0','0','3','\0','\0'},
{'\\','u','0','0','0','4','\0','\0'},
{'\\','u','0','0','0','5','\0','\0'},
{'\\','u','0','0','0','6','\0','\0'},
{'\\','u','0','0','0','7','\0','\0'},
{'\\','b','\0','\0','\0','\0','\0','\0'},
{'\\','t','\0','\0','\0','\0','\0','\0'},
{'\\','n','\0','\0','\0','\0','\0','\0'},
{'\\','u','0','0','0','b','\0','\0'},
{'\\','f','\0','\0','\0','\0','\0','\0'},
{'\\','r','\0','\0','\0','\0','\0','\0'},
{'\\','u','0','0','0','e','\0','\0'},
{'\\','u','0','0','0','f','\0','\0'},
{'\\','u','0','0','1','0','\0','\0'},
{'\\','u','0','0','1','1','\0','\0'},
{'\\','u','0','0','1','2','\0','\0'},
{'\\','u','0','0','1','3','\0','\0'},
{'\\','u','0','0','1','4','\0','\0'},
{'\\','u','0','0','1','5','\0','\0'},
{'\\','u','0','0','1','6','\0','\0'},
{'\\','u','0','0','1','7','\0','\0'},
{'\\','u','0','0','1','8','\0','\0'},
{'\\','u','0','0','1','9','\0','\0'},
{'\\','u','0','0','1','a','\0','\0'},
{'\\','u','0','0','1','b','\0','\0'},
{'\\','u','0','0','1','c','\0','\0'},
{'\\','u','0','0','1','d','\0','\0'},
{'\\','u','0','0','1','e','\0','\0'},
{'\\','u','0','0','1','f','\0','\0'},
{'\\','\"','\0','\0','\0','\0','\0','\0'},
{'\\','/','\0','\0','\0','\0','\0','\0'},
{'\\','\\','\0','\0','\0','\0','\0','\0'},
{'\\','u','0','0','7','f','\0','\0'}
};
static const char *char2escape(unsigned char c){
if(c<32) return escape_array[c];
switch(c){
case 34: return escape_array[32];
case 47: return escape_array[33];
case 92: return escape_array[34];
case 127: return escape_array[35];
default:
return NULL;
}
}
static json_token_type_t ch2token(unsigned char c){
switch(c){
case '{': return T_OBJ_BEGIN;
case '}': return T_OBJ_END;
case '[': return T_ARR_BEGIN;
case ']': return T_ARR_END;
case ',': return T_COMMA;
case ':': return T_COLON;
case '\0': return T_END;
case ' ': return T_WHITESPACE;
case '\t': return T_WHITESPACE;
case '\n': return T_WHITESPACE;
case '\r': return T_WHITESPACE;
/* Update characters that require further processing */
case 'f': case 'i': case 'I': case 'n': case 'N': case 't': case '"': case '+': case '-':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
return T_UNKNOWN;
default:
return T_ERROR;
}
}
static char escape2char(unsigned char c){
switch(c){
case '"': return '"';
case '\\': return '\\';
case '/': return '/';
case 'b': return '\b';
case 't': return '\t';
case 'n': return '\n';
case 'f': return '\f';
case 'r': return '\r';
case 'u': return 'u';
default:
return 0;
}
}
/* ===== CONFIGURATION ===== */
#if 0
@ -319,8 +430,10 @@ static int json_cfg_encode_keep_buffer(lua_State *l)
/* Init / free the buffer if the setting has changed */
if (old_value ^ cfg->encode_keep_buffer) {
if (cfg->encode_keep_buffer)
strbuf_init(&cfg->encode_buf, 0);
if (cfg->encode_keep_buffer){
if(-1==strbuf_init(&cfg->encode_buf, 0))
return luaL_error(l, "not enough memory");
}
else
strbuf_free(&cfg->encode_buf);
}
@ -456,9 +569,7 @@ static json_config_t *json_fetch_config(lua_State *l)
return &_cfg;
}
static void cfg_init(json_config_t *cfg){
int i;
static int cfg_init(json_config_t *cfg){
cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT;
cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO;
cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE;
@ -470,53 +581,13 @@ static void cfg_init(json_config_t *cfg){
cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION;
#if DEFAULT_ENCODE_KEEP_BUFFER > 0
strbuf_init(&cfg->encode_buf, 0);
if(-1==strbuf_init(&cfg->encode_buf, 0)){
NODE_ERR("not enough memory\n");
return -1;
}
#endif
/* Decoding init */
/* Tag all characters as an error */
for (i = 0; i < 256; i++)
cfg->ch2token[i] = T_ERROR;
/* Set tokens that require no further processing */
cfg->ch2token['{'] = T_OBJ_BEGIN;
cfg->ch2token['}'] = T_OBJ_END;
cfg->ch2token['['] = T_ARR_BEGIN;
cfg->ch2token[']'] = T_ARR_END;
cfg->ch2token[','] = T_COMMA;
cfg->ch2token[':'] = T_COLON;
cfg->ch2token['\0'] = T_END;
cfg->ch2token[' '] = T_WHITESPACE;
cfg->ch2token['\t'] = T_WHITESPACE;
cfg->ch2token['\n'] = T_WHITESPACE;
cfg->ch2token['\r'] = T_WHITESPACE;
/* Update characters that require further processing */
cfg->ch2token['f'] = T_UNKNOWN; /* false? */
cfg->ch2token['i'] = T_UNKNOWN; /* inf, ininity? */
cfg->ch2token['I'] = T_UNKNOWN;
cfg->ch2token['n'] = T_UNKNOWN; /* null, nan? */
cfg->ch2token['N'] = T_UNKNOWN;
cfg->ch2token['t'] = T_UNKNOWN; /* true? */
cfg->ch2token['"'] = T_UNKNOWN; /* string? */
cfg->ch2token['+'] = T_UNKNOWN; /* number? */
cfg->ch2token['-'] = T_UNKNOWN;
for (i = 0; i < 10; i++)
cfg->ch2token['0' + i] = T_UNKNOWN;
/* Lookup table for parsing escape characters */
for (i = 0; i < 256; i++)
cfg->escape2char[i] = 0; /* String error */
cfg->escape2char['"'] = '"';
cfg->escape2char['\\'] = '\\';
cfg->escape2char['/'] = '/';
cfg->escape2char['b'] = '\b';
cfg->escape2char['t'] = '\t';
cfg->escape2char['n'] = '\n';
cfg->escape2char['f'] = '\f';
cfg->escape2char['r'] = '\r';
cfg->escape2char['u'] = 'u'; /* Unicode parsing required */
return 0;
}
/* ===== ENCODING ===== */
@ -552,9 +623,18 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
strbuf_append_char_unsafe(json, '\"');
for (i = 0; i < len; i++) {
escstr = char2escape[(unsigned char)str[i]];
if (escstr)
escstr = char2escape((unsigned char)str[i]);
if (escstr){
int i;
char temp[8]; // for now, 8-bytes is enough.
for (i=0; i < 8; ++i)
{
temp[i] = byte_of_aligned_array(escstr, i);
if(temp[i]==0) break;
}
escstr = temp;
strbuf_append_string(json, escstr);
}
else
strbuf_append_char_unsafe(json, str[i]);
}
@ -694,7 +774,12 @@ static void json_append_number(lua_State *l, json_config_t *cfg,
}
strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE);
#ifdef LUA_NUMBER_INTEGRAL
len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision);
#else
c_sprintf(strbuf_empty_ptr(json), "%.14g", num);
len = c_strlen(strbuf_empty_ptr(json));
#endif
strbuf_extend_length(json, len);
}
@ -796,7 +881,8 @@ static int json_encode(lua_State *l)
if (!cfg->encode_keep_buffer) {
/* Use private buffer */
encode_buf = &local_encode_buf;
strbuf_init(encode_buf, 0);
if(-1==strbuf_init(encode_buf, 0))
return luaL_error(l, "not enough memory");
} else {
/* Reuse existing buffer */
encode_buf = &cfg->encode_buf;
@ -967,7 +1053,7 @@ static void json_set_token_error(json_token_t *token, json_parse_t *json,
static void json_next_string_token(json_parse_t *json, json_token_t *token)
{
char *escape2char = json->cfg->escape2char;
// char *escape2char = json->cfg->escape2char;
char ch;
/* Caller must ensure a string is next */
@ -995,7 +1081,7 @@ static void json_next_string_token(json_parse_t *json, json_token_t *token)
ch = *(json->ptr + 1);
/* Translate escape code and append to tmp string */
ch = escape2char[(unsigned char)ch];
ch = escape2char((unsigned char)ch);
if (ch == 'u') {
if (json_append_unicode_escape(json) == 0)
continue;
@ -1107,13 +1193,13 @@ static void json_next_number_token(json_parse_t *json, json_token_t *token)
*/
static void json_next_token(json_parse_t *json, json_token_t *token)
{
const json_token_type_t *ch2token = json->cfg->ch2token;
// const json_token_type_t *ch2token = json->cfg->ch2token;
int ch;
/* Eat whitespace. */
while (1) {
ch = (unsigned char)*(json->ptr);
token->type = ch2token[ch];
token->type = ch2token(ch);
if (token->type != T_WHITESPACE)
break;
json->ptr++;
@ -1194,13 +1280,23 @@ static void json_throw_parse_error(lua_State *l, json_parse_t *json,
const char *exp, json_token_t *token)
{
const char *found;
char temp[16]; // for now, 16-bytes is enough.
strbuf_free(json->tmp);
if (token->type == T_ERROR)
found = token->value.string;
else
{
found = json_token_type_name[token->type];
int i;
for (i=0; i < 16; ++i)
{
temp[i] = byte_of_aligned_array(found, i);
if(temp[i]==0) break;
}
found = temp;
}
/* Note: token->index is 0 based, display starting from 1 */
luaL_error(l, "Expected %s but found %s at character %d",
@ -1369,6 +1465,9 @@ static int json_decode(lua_State *l)
* This means we no longer need to do length checks since the decoded
* string must be smaller than the entire json string */
json.tmp = strbuf_new(json_len);
if(json.tmp == NULL){
return luaL_error(l, "not enought memory");
}
json_next_token(&json, &token);
json_process_value(l, &json, &token);
@ -1434,6 +1533,7 @@ static int json_protect_conversion(lua_State *l)
return luaL_error(l, "Memory allocation error in CJSON protected call");
}
#endif
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
@ -1459,7 +1559,9 @@ LUALIB_API int luaopen_cjson( lua_State *L )
{
/* Initialise number conversions */
fpconv_init();
cfg_init(&_cfg);
if(-1==cfg_init(&_cfg)){
return luaL_error(L, "BUG: Unable to init config for cjson");;
}
#if LUA_OPTIMIZE_MEMORY > 0
return 0;
#else // #if LUA_OPTIMIZE_MEMORY > 0