├── .Rinstignore ├── inst ├── sampleData │ ├── int.json │ ├── intScalar.json │ ├── array.json │ ├── array2.json │ ├── obj.json │ ├── nestedArray.json │ ├── array3.json │ ├── obj2.json │ ├── nestedObj.json │ ├── obj3.json │ ├── embedded.json │ ├── obj1.json │ ├── menu.json │ ├── glossay.json │ ├── widget.json │ ├── keys.json │ ├── menu1.json │ └── web.json └── doc │ ├── overview.pdf │ ├── timings.docx │ ├── toJSONTimes.rda │ ├── fromJSONTimes.rda │ ├── overview.bib │ ├── GNUmakefile │ ├── biblio.xml │ ├── overview.bbl │ ├── performance.R │ ├── missingValues.Rdb │ └── missingValues.html ├── jsonText.rda ├── tests ├── newsUTF8.rda ├── exp.R ├── con2.R ├── s4.R ├── scalarCollapse.R ├── encoding.R ├── nested.json ├── flat.json ├── empty.R ├── prealloc.R ├── con1.R ├── serialize.R ├── keys.R ├── utf8.R ├── array.R ├── bigInt.R ├── charNULL.R ├── toJSON.R ├── simple.R ├── bigFile.R ├── dataframe.R ├── simplify.R ├── containers.R ├── stringFun.R └── performance.R ├── configure.win ├── utfTest ├── GNUmakefile ├── raw.R ├── json.c ├── news.txt ├── news1.txt └── news2.txt ├── LICENSE ├── src ├── libjson │ ├── README │ ├── copy │ ├── Source │ │ ├── JSONAllocator.cpp │ │ ├── JSONSingleton.h │ │ ├── JSONDefs │ │ │ ├── Unknown_C.h │ │ │ ├── Visual_C.h │ │ │ ├── Strings_Defs.h │ │ │ └── GNU_C.h │ │ ├── JSONPreparse.h │ │ ├── JSON_Base64.h │ │ ├── JSONDebug.cpp │ │ ├── JSONMemoryPool.h │ │ ├── JSONValidator.h │ │ ├── JSONDebug.h │ │ ├── JSONAllocator.h │ │ ├── JSONStream.h │ │ ├── JSONWorker.h │ │ ├── JSONStats.h │ │ ├── JSONGlobals.h │ │ ├── JSONChildren.cpp │ │ ├── JSONStream.cpp │ │ ├── JSONDefs.h │ │ ├── JSONMemory.cpp │ │ ├── JSONMemory.h │ │ └── JSONNode_Mutex.cpp │ ├── bdr │ └── License.txt ├── Makevars.win ├── Makevars.in ├── Rlibjson.h ├── JSON_parser.h ├── ConvertUTF.h └── rparser.c ├── README.libjson ├── Web ├── GNUmakefile └── index.html.in ├── fail.R ├── cleanup.in ├── libjsonFixes ├── cp_libjson ├── leak.R ├── dataframe.R ├── testStream.R ├── GNUmakefile ├── NAMESPACE ├── .Rbuildignore ├── R ├── stream.R ├── isValid.R ├── simpleHandler.R └── asVars.R ├── cleanup ├── purdy.R ├── libjsonNotes ├── tests.R ├── experiments └── stream.R ├── Todo.xml ├── man ├── JSON_T_NULL.Rd ├── basicJSONHandler.Rd ├── isValidJSON.Rd ├── asJSVars.Rd ├── readJSONStream.Rd └── toJSON.Rd ├── README.md ├── DESCRIPTION ├── streaming.R ├── configure.in ├── foo.html └── Changes /.Rinstignore: -------------------------------------------------------------------------------- 1 | overview.tex 2 | -------------------------------------------------------------------------------- /inst/sampleData/int.json: -------------------------------------------------------------------------------- 1 | [1, 2, 3, 4] -------------------------------------------------------------------------------- /inst/sampleData/intScalar.json: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /inst/sampleData/array.json: -------------------------------------------------------------------------------- 1 | [ 1, 2, 3, 4] 2 | -------------------------------------------------------------------------------- /inst/sampleData/array2.json: -------------------------------------------------------------------------------- 1 | [ [1,2,3,4], 2 | [4, 5, 6] 3 | ] -------------------------------------------------------------------------------- /inst/sampleData/obj.json: -------------------------------------------------------------------------------- 1 | {"a1" : "x", 2 | "a2" : "yz" 3 | } -------------------------------------------------------------------------------- /jsonText.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duncantl/RJSONIO/HEAD/jsonText.rda -------------------------------------------------------------------------------- /inst/sampleData/nestedArray.json: -------------------------------------------------------------------------------- 1 | [ 2 | [1, 2], 3 | [3, 4] 4 | , [5, 6] 5 | 6 | ] -------------------------------------------------------------------------------- /tests/newsUTF8.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duncantl/RJSONIO/HEAD/tests/newsUTF8.rda -------------------------------------------------------------------------------- /configure.win: -------------------------------------------------------------------------------- 1 | cp src/libjson/Source/*.cpp src/ 2 | cp src/libjson/JSONOptions.h src/ 3 | 4 | -------------------------------------------------------------------------------- /inst/doc/overview.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duncantl/RJSONIO/HEAD/inst/doc/overview.pdf -------------------------------------------------------------------------------- /inst/doc/timings.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duncantl/RJSONIO/HEAD/inst/doc/timings.docx -------------------------------------------------------------------------------- /inst/sampleData/array3.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ [1,2,3,4], [4, 5, 6, 7] ], 3 | [ "a", "b", "c" ] 4 | ] -------------------------------------------------------------------------------- /inst/doc/toJSONTimes.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duncantl/RJSONIO/HEAD/inst/doc/toJSONTimes.rda -------------------------------------------------------------------------------- /inst/doc/fromJSONTimes.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duncantl/RJSONIO/HEAD/inst/doc/fromJSONTimes.rda -------------------------------------------------------------------------------- /inst/sampleData/obj2.json: -------------------------------------------------------------------------------- 1 | /* JSON syntax error */ 2 | {"a1" : "x", 3 | "a2" : "yz", 4 | [1, 2, 3] 5 | } -------------------------------------------------------------------------------- /tests/exp.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | ans = fromJSON("[3.14e4, 3.14E4]") 3 | stopifnot(ans[[1]] == ans[[2]]) 4 | -------------------------------------------------------------------------------- /inst/sampleData/nestedObj.json: -------------------------------------------------------------------------------- 1 | {"a1" : "x", 2 | "a2" : "yz", 3 | "a3" : { "item": 1, 4 | "item": 2} 5 | } -------------------------------------------------------------------------------- /inst/sampleData/obj3.json: -------------------------------------------------------------------------------- 1 | /* JSON syntax error */ 2 | {"a1" : "x", 3 | "a2" : "yz", 4 | "logical" : true, 5 | "logicalArray" : [true, false] 6 | } -------------------------------------------------------------------------------- /utfTest/GNUmakefile: -------------------------------------------------------------------------------- 1 | 2 | CPPFLAGS=-I../src -g 3 | CC=gcc 4 | 5 | json: json.o ../src/ConvertUTF.o ../src/JSON_parser.o 6 | $(CC) -o $@ $^ 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2001-2014 2 | COPYRIGHT HOLDER: Duncan Temple Lang 3 | ORGANIZATION: R project & University of California at Davis 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /inst/sampleData/embedded.json: -------------------------------------------------------------------------------- 1 | This is text with JSON embedded in it. 2 | [ 3 | [ 1, 2, 3], 4 | [ 4, 5] 5 | ] 6 | and then some more text following it. -------------------------------------------------------------------------------- /tests/con2.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | con = textConnection("[1, 2, 3,\n4]"); fromJSON(con) 3 | 4 | try({con = textConnection("[1, 2, 3,]"); fromJSON(con)}) 5 | 6 | -------------------------------------------------------------------------------- /src/libjson/README: -------------------------------------------------------------------------------- 1 | Copy the .cpp files from libjson/Source/ 2 | Leave the header files in that directory. 3 | Remove the documentation and any files in Objects/ 4 | -------------------------------------------------------------------------------- /tests/s4.R: -------------------------------------------------------------------------------- 1 | setClass("Foo", 2 | representation(a = "integer", b = "character")) 3 | setClass("Bar", 4 | representation(a = "integer", b = "character")) 5 | -------------------------------------------------------------------------------- /inst/sampleData/obj1.json: -------------------------------------------------------------------------------- 1 | /* object with arrays and strings */ 2 | {"a1" : ["x", "y"], 3 | "a2" : [1, 2, 3], 4 | "a3" : "a string", 5 | "a4" : true, 6 | "a 5" : [false, true] 7 | } -------------------------------------------------------------------------------- /tests/scalarCollapse.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | ins = c("[1, 2, 3]", 4 | '[1, "2", 3]', 5 | '[true, 1, 3]', 6 | '[true, false, 3, "xyz"]') 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/libjson/copy: -------------------------------------------------------------------------------- 1 | SRC=/tmp/libjson 2 | cp $SRC/libjson.h $SRC/makefile . 3 | 4 | diff -qr Source $SRC/Source/ | grep 'Only in Source' 5 | # git rm files 6 | 7 | /bin/cp -fr $SRC/Source . 8 | 9 | -------------------------------------------------------------------------------- /tests/encoding.R: -------------------------------------------------------------------------------- 1 | x = "Open Bar $300 \u5564\u9152\u3001\u6C23\u9152 \u4EFB\u98F2" 2 | print(x) 3 | Encoding(x) 4 | library(RJSONIO) 5 | fromJSON(paste('{"tweet":"', x, '"}', sep = '')) 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/nested.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 1, 3 | [ 2, 3], 4 | [ 4, 6], 5 | 10, 20 6 | ] 7 | [ 100, 200, 300 8 | ] 9 | [ "a", "b", "c", 10 | ["wx", "yz"], 11 | true 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /README.libjson: -------------------------------------------------------------------------------- 1 | Install libjson with 2 | 3 | make SHARED=1 install 4 | or 5 | make SHARED=1 6 | make install SHARED=1 7 | 8 | (You need the SHARED=1 on the install as well as the build.) 9 | 10 | -------------------------------------------------------------------------------- /tests/flat.json: -------------------------------------------------------------------------------- 1 | { "a" : 1, 2 | "b" : [true, false] 3 | } 4 | 5 | { "x" : 2, 6 | "y" : ["a", "b", "c"] 7 | } 8 | 9 | { "foo" : true, 10 | "bar" : [ [1, 2], [3, 4]], 11 | "foobar": "a string" 12 | } 13 | -------------------------------------------------------------------------------- /tests/empty.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | str = "[ 1, {}, [1, 3, 5] ]" 4 | v = fromJSON(str) 5 | str1 = toJSON(v, collapse = " ") 6 | 7 | stopifnot( any( duplicated( gsub("[[:space:]]", "", c(str, str1))))) 8 | 9 | 10 | -------------------------------------------------------------------------------- /Web/GNUmakefile: -------------------------------------------------------------------------------- 1 | PACKAGE=RJSONIO 2 | 3 | ifndef ADMIN_TOOLS_DIR 4 | ADMIN_TOOLS_DIR=../../AdminTools 5 | endif 6 | include $(OMEGA_HOME)/R/Config/GNUmakefile.Web 7 | 8 | #include $(ADMIN_TOOLS_DIR)/GNUmakefile 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/prealloc.R: -------------------------------------------------------------------------------- 1 | f = "inst/sampleData/usaPolygons.as" 2 | 3 | # The idea here is to customize the reading by pre-allocating space. 4 | readArray = 5 | function(type, val) { 6 | # if(type) 7 | } 8 | 9 | # fromJSON(f, ) 10 | -------------------------------------------------------------------------------- /tests/con1.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | con = textConnection(c("[[1,2,3,4],", "[5, 6, 7, 8]]")) 4 | fromJSON(con) 5 | 6 | con = file(system.file("sampleData", "usaPolygons.as", package = "RJSONIO")) 7 | o = fromJSON(con) 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /fail.R: -------------------------------------------------------------------------------- 1 | toJSON(list(NA)) # change to make NA represent JSON null 2 | 3 | # now work: 4 | #roundtrip('["A","B","C"]') 5 | # roundtrip('["A",10,"C"]') 6 | 7 | # now work 8 | roundtrip('{"":10,"":13}') 9 | roundtrip('{"":10,"b":13}') 10 | -------------------------------------------------------------------------------- /tests/serialize.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | setClass("A", representation(x = "integer", abc = "character"), 3 | prototype = list(x = 1:10, abc = c("Jan", "Feb", "Mar"))) 4 | a = new("A") 5 | 6 | toJSON(a) 7 | 8 | toJSON(list(a, a)) 9 | 10 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | PKG_CPPFLAGS=-I. -Ilibjson -Ilibjson/Source -DNDEBUG=1 -DJSON_VALIDATE -DJSON_LIBRARY=1 -DJSON_ISO_STRICT -DJSON_READ_PRIORITY=1 2 | # -DJSON_STREAM=1 already defined in JSONOPtions.h 3 | # -DJSON_READ_PRIORITY=1 4 | # -DJSON_NO_EXCEPTIONS=1 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/keys.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | ff = system.file("sampleData", "keys.json", package = "RJSONIO") 4 | print(ff) 5 | z = paste(readLines(ff), collapse = "\n") 6 | 7 | fromJSON(I(z)) 8 | 9 | fromJSON(ff, function(type, val) { cat(names(type), "\n"); TRUE}) 10 | 11 | -------------------------------------------------------------------------------- /cleanup.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CPP="@CPP_FILES@" 4 | 5 | if test -n "$CPP" ; then 6 | echo "Removing the CPP files copied from libjson into src: $CPP" 7 | (cd src ; rm $CPP) 8 | if test -e src/JSONOptions.h ; then 9 | rm src/JSONOptions.h 10 | fi 11 | fi 12 | -------------------------------------------------------------------------------- /libjsonFixes: -------------------------------------------------------------------------------- 1 | libjson/Source/JSONDefs is not readable when installed 2 | 3 | cd libjson 4 | chmod a+rx Source 5 | chmod a+rx Source/JSONDefs 6 | 7 | The makefile doesn't work for SHARED=1 on OS X. 8 | -Wl,-soname,$(libname_shared_major_version) 9 | 10 | ldconfig -------------------------------------------------------------------------------- /tests/utf8.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | if(!is.null(getOption('NYTimesAPI'))) { 3 | news = getForm('http://api.nytimes.com/svc/search/v1/article', 'api-key' = getOption('NYTimesAPI')["Article Search"], query = "climate change") 4 | } else 5 | load("newsUTF8.rda") 6 | 7 | fromJSON(news) 8 | -------------------------------------------------------------------------------- /tests/array.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | a = array(1:(5*7*9), c(5, 7, 9)) 3 | o = toJSON(a) 4 | isValidJSON(I(o)) 5 | b = fromJSON(I(o)) 6 | 7 | toJSON(table(1:3)) 8 | toJSON(table(1:3, 1:3)) 9 | 10 | #z = apply(a, 3, function(x, dim) toJSON(x)) 11 | #toJSON(array(1:8,c(2,2,2))) 12 | -------------------------------------------------------------------------------- /cp_libjson: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if test -z "${JSON_DIR}" ; then 4 | echo "You need to set JSON_DIR" 5 | exit 1; 6 | fi 7 | 8 | cp -r $JSON_DIR/Dependencies . 9 | 10 | cd src/libjson 11 | cp $JSON_DIR/libjson.h . 12 | cp $JSON_DIR/JSONOptions.h . 13 | 14 | cp -r $JSON_DIR/Source . 15 | -------------------------------------------------------------------------------- /leak.R: -------------------------------------------------------------------------------- 1 | library("RJSONIO") 2 | f <- file("inst/sampleData/web.json") 3 | f.lines <- readLines(f) 4 | f.str <- paste(f.lines, collapse = "\n") 5 | ans = vector("list", 1000) 6 | for (x in seq_len(1000)) { 7 | foo <- fromJSON(I(f.str), asText = TRUE) 8 | # ans[[x]] = gc() 9 | } 10 | 11 | -------------------------------------------------------------------------------- /dataframe.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | DF <- head(cars) 3 | DF[1,1] <- NA 4 | cat(toJSON(DF)) 5 | 6 | outDF = toJSON(DF) 7 | tmp <- fromJSON(content = outDF, asText = TRUE, simplify = TRUE, nullValue = NA) 8 | as.data.frame(tmp) 9 | 10 | #origDF <- as.data.frame(lapply(reconstruction, "unlist")) 11 | -------------------------------------------------------------------------------- /tests/bigInt.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | i = fromJSON("[123]")[[1]] 3 | is.integer(i) 4 | i == 123L 5 | 6 | 7 | x = fromJSON("[12345678901]")[[1]] 8 | is.numeric(x[[1]]) 9 | x == 12345678901 10 | 11 | x = fromJSON("[-12345678901]")[[1]] 12 | is.numeric(x[[1]]) 13 | x == -12345678901 14 | 15 | 16 | -------------------------------------------------------------------------------- /inst/doc/overview.bib: -------------------------------------------------------------------------------- 1 | 2 | @misc{bib:libjson, 3 | title = {libjson}, 4 | author = {Wallace, Johnathan}, 5 | url = {http://libjson.sourceforge.net}, 6 | year = 2011 7 | } 8 | 9 | @misc{bib:rjson, 10 | title = {The rjson package}, 11 | author = {Couture-Beil, Alex}, 12 | year = "2011-6-26" 13 | } 14 | -------------------------------------------------------------------------------- /testStream.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | cb = 4 | function(node) 5 | { 6 | cat("in cb", .Call("R_json_node_type", node), "\n") 7 | 8 | TRUE 9 | } 10 | 11 | txt = paste(readLines("inst/sampleData/nestedObj.json"), collapse = "\n") 12 | txt = "[1, 2, 3]" 13 | .Call("R_json_stream_parse", txt, cb) 14 | -------------------------------------------------------------------------------- /inst/sampleData/menu.json: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "id": "file", 3 | "value": "File", 4 | "popup": { 5 | "menuitem": [ 6 | {"value": "New", "onclick": "CreateNewDoc()"}, 7 | {"value": "Open", "onclick": "OpenDoc()"}, 8 | {"value": "Close", "onclick": "CloseDoc()"} 9 | ] 10 | } 11 | }} 12 | -------------------------------------------------------------------------------- /src/Makevars.in: -------------------------------------------------------------------------------- 1 | PKG_CPPFLAGS=@LIBJSON_CFLAGS@ -DNDEBUG=1 -DJSON_VALIDATE -DJSON_STREAM=1 -DJSON_READ_PRIORITY=1 -DJSON_LIBRARY=1 -DJSON_ISO_STRICT -DJSON_STREAM -DJSON_DEBUG 2 | # -DJSON_STREAM=1 already defined in JSONOPtions.h 3 | # -DJSON_NO_EXCEPTIONS=1 4 | # -DJSON_READ_PRIORITY 5 | PKG_LIBS=@LIBJSON_LIBS@ 6 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(OMEGA_HOME)/R/Config/GNUmakefile 2 | 3 | build: Changes.html Changes 4 | -rm src/*.o src/*.so 5 | (cd .. ; R CMD build RJSONIO) 6 | 7 | XSL_DIR=$(OMEGA_HOME)/Docs/XSL 8 | Changes.html: Changes.xml 9 | xsltproc -o $@ $(XSL_DIR)/html/ChangeLog.xsl $< 10 | 11 | Changes: Changes.xml 12 | xsltproc -o $@ $(XSL_DIR)/text/ChangeLog.xsl $< 13 | -------------------------------------------------------------------------------- /inst/doc/GNUmakefile: -------------------------------------------------------------------------------- 1 | ifndef DYN_DOCS 2 | DYN_DOCS=$(HOME)/Classes/StatComputing/XDynDocs/inst 3 | endif 4 | 5 | TEX_XSL_ARGS=--stringparam doc.class '[article]{jss}' --stringparam bibliog.file $* 6 | DB2JSS_XSL=$(DYN_DOCS)/XSL/OmegahatXSL/latex/myRawJSS.xsl 7 | LATEX_STYLE=$(DB2JSS_XSL) 8 | 9 | overview.tex: overview.bib 10 | 11 | include $(DYN_DOCS)/Make/Makefile 12 | -------------------------------------------------------------------------------- /tests/charNULL.R: -------------------------------------------------------------------------------- 1 | # issue spotted by Alexandre Sieira 2 | # and his example code. 3 | library(RJSONIO) 4 | 5 | fromJSON("[ 1, null, 4 ]", asText = TRUE, simplify = TRUE) 6 | fromJSON('[ "a", null, "d" ]', asText = TRUE, simplify = TRUE) 7 | 8 | fromJSON("[ 1, null, 4 ]", asText = TRUE, simplify = TRUE, nullValue = -999L) 9 | fromJSON('[ "a", null, "d" ]', asText = TRUE, simplify = TRUE, nullValue = "999") 10 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONAllocator.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONAllocator.h" 2 | 3 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 4 | #include "JSONMemory.h" 5 | 6 | void * JSONAllocatorRelayer::alloc(size_t bytes) json_nothrow { 7 | return JSONMemory::json_malloc(bytes); 8 | } 9 | 10 | void JSONAllocatorRelayer::dealloc(void * ptr) json_nothrow { 11 | JSONMemory::json_free(ptr); 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | useDynLib(RJSONIO) 2 | import("methods") 3 | 4 | export(toJSON) 5 | exportMethods(toJSON) 6 | 7 | export(emptyNamedList) 8 | 9 | export(fromJSON) 10 | exportMethods(fromJSON) 11 | exportPattern("^JSON_T") 12 | export(asJSVars) 13 | 14 | export(basicJSONHandler) 15 | 16 | export(isValidJSON) 17 | exportMethods(isValidJSON) 18 | 19 | export(Strict, StrictNumeric, StrictCharacter, StrictLogical) 20 | 21 | export(readJSONStream) 22 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | GNUmakefile 2 | .*/autom4te.* 3 | config.log 4 | config.status 5 | Objects.* 6 | purdy.R 7 | .*.bbl 8 | .*.blg 9 | .*.aux 10 | .*.out 11 | .*.log 12 | roebuck.R 13 | json-asIS-withlevel 14 | src/Makevars$ 15 | Changes.xml 16 | intName.R 17 | streaming.R 18 | fail.R 19 | tests.R 20 | testStream.R 21 | dataframe.R 22 | leak.R 23 | jsonText.rda 24 | foo.html 25 | Web 26 | bigFile.R 27 | experiments 28 | utfTest.* 29 | ivan 30 | json-asIS-withlevel 31 | -------------------------------------------------------------------------------- /utfTest/raw.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | x = paste(readLines("utf/news.txt"), collapse = "\n") 4 | r = charToRaw(x) 5 | .Call("R_readFromJSON", r, 20L, TRUE, function(x, ...){}, NULL, c(0L, 5619L)) 6 | 7 | a = readBin("utf/news.txt", "raw", file.info("utf/news.txt")[1, "size"]) 8 | .Call("R_readFromJSON", a, 20L, TRUE, function(x, ...){}, NULL, c(0L, 5619L)) 9 | 10 | i = as.integer(charToRaw(x)) 11 | .Call("R_readFromJSON", i, 20L, TRUE, function(x, ...){}, NULL, c(0L, 5619L)) 12 | -------------------------------------------------------------------------------- /tests/toJSON.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | toJSON(list(1, 2, list(1, NA))) 4 | 5 | toJSON(list(1, 2, list(NA))) # collapses the sub-list into the main vector. 6 | 7 | 8 | e = new.env(); e$a = 1:10; e$bc = letters[1:3] 9 | cat(toJSON(e, pretty = TRUE)) 10 | 11 | 12 | a = list(x=1, y=character(0)) 13 | fromJSON( toJSON( a ) ) 14 | a = list(x=1, y=character(0), b = 1) 15 | fromJSON( toJSON( a ) ) 16 | 17 | 18 | a = list(x = vector(), y = 123, z = "allo") 19 | fromJSON(toJSON(a)) 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/simple.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | x = "[1, 3, 10, 19]" 3 | fromJSON(I(x)) 4 | 5 | h = RJSONIO:::basicJSONHandler() 6 | fromJSON(x, h$update) 7 | 8 | if(!(fromJSON(I("[3.1415]")) == 3.1415)) 9 | stop("Failed for doubles") 10 | 11 | 12 | # From couchdb 13 | 14 | x = '{"total_rows":3,"offset":0,"rows":[{"id":"abc","key":"xyz","value":{"rev":"1-3980939464"}},{"id":"x123","key":"x123","value":{"rev":"1-1794908527"}}]}\n' 15 | 16 | fromJSON(x) 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /R/stream.R: -------------------------------------------------------------------------------- 1 | readJSONStream = 2 | function(con, cb = NULL, 3 | simplify = Strict, nullValue = NULL, simplifyWithNames = TRUE) 4 | { 5 | if(is(con, "connection")) 6 | # e = substitute(readLines(con, n = 1), list(con = con)) 7 | e = substitute(readChar(con, 1024), list(con = con)) 8 | else # Expect an expression or the name of a file 9 | e = con 10 | 11 | .Call("R_json_parser_init_from_con", e, cb, 12 | as.integer(simplify), nullValue, as.logical(simplifyWithNames)) 13 | } 14 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CPP="JSONAllocator.cpp 4 | JSONChildren.cpp 5 | JSONDebug.cpp 6 | JSONIterators.cpp 7 | JSONMemory.cpp 8 | JSONNode.cpp 9 | JSONNode_Mutex.cpp 10 | JSONPreparse.cpp 11 | JSONStream.cpp 12 | JSONValidator.cpp 13 | JSONWorker.cpp 14 | JSONWriter.cpp 15 | internalJSONNode.cpp 16 | libjson.cpp" 17 | 18 | if test -n "$CPP" ; then 19 | echo "Removing the CPP files copied from libjson into src: $CPP" 20 | (cd src ; rm $CPP) 21 | if test -e src/JSONOptions.h ; then 22 | rm src/JSONOptions.h 23 | fi 24 | fi 25 | -------------------------------------------------------------------------------- /purdy.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | x0 = list(sub1 = list(a = 1:10, b = 100, c = 1000), sub2 = list(animal1 = "ape", animal2 = "bear", animal3 = "cat")) 4 | y0 = list(sub1 = list(a = 1:10, b = 100L, c = 1000L), sub2 = list(animal1 = "ape", animal2 = "bear", animal3 = "cat")) 5 | z0 = list(sub1 = list(a = 10, b = 100, c = 1000), sub2 = list(animal1 = "ape", animal2 = "bear", animal3 = "cat")) 6 | 7 | 8 | j0 = toJSON(x0) 9 | x1 = fromJSON(j0, simplify = FALSE) 10 | x2 = fromJSON(j0, simplify = TRUE) 11 | x3 = fromJSON(j0, simplify = Strict) 12 | -------------------------------------------------------------------------------- /libjsonNotes: -------------------------------------------------------------------------------- 1 | Modified 2 | in Source/ 3 | JSONChildren.h - use namespace std; - see BDR's note. 4 | libjson.cpp - change ../../libjson.h to "libjson/libjson.h" 5 | 6 | JSONStats.h - change "../../JSONOptions.h" to "JSONOptions.h". This may not be necessary after changes to configure.in and copying files to src/ 7 | 8 | Then copy to the R package source: 9 | 10 | cd src/libjson 11 | cp -f ~/Downloads/libjson/_internal/Source/[A-Za-z]* Source 12 | cp -f ~/Downloads/libjson/_internal/Source/JSONDefs/* Source/JSONDefs 13 | 14 | configure copies src/libjson/JSONOptions.h to src/ now. 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONSingleton.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONSINGLETON_H 2 | #define JSONSINGLETON_H 3 | 4 | template class JSONSingleton { 5 | public: 6 | static inline T get(void){ 7 | return get_singleton() -> ptr; 8 | } 9 | static inline void set(T p){ 10 | get_singleton() -> ptr = p; 11 | } 12 | private: 13 | inline JSONSingleton() : ptr(NULL) { } 14 | JSONSingleton(const JSONSingleton &); 15 | JSONSingleton operator = (const JSONSingleton &); 16 | static inline JSONSingleton * get_singleton(void){ 17 | static JSONSingleton instance; 18 | return &instance; 19 | } 20 | T ptr; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/libjson/bdr: -------------------------------------------------------------------------------- 1 | Someone is writing C in C++ in libjson, and not declaring it correctly. 2 | 3 | Can you please add 4 | 5 | using namespace std; 6 | 7 | to the top of RJSONIO/src/libjson/Source/JSONChildren.h 8 | 9 | to get memmove etc into scope. 10 | 11 | The remaining problem, 12 | 13 | "libjson/Source/NumberToString.h", line 130: Error: The function "snprintf" must have a prototype. 14 | 15 | is trickier as snprintf is not a C++ and not a C90 function, and indeed the Solaris C++ headers seem to have vsnprintf but not snprintf. So that file needs to have 16 | 17 | #ifdef __SUNPRO_CC 18 | #include 19 | #else 20 | #include 21 | #endif 22 | -------------------------------------------------------------------------------- /tests.R: -------------------------------------------------------------------------------- 1 | str = "[ 1, {}, [1, 3, 5] ]" 2 | fromJSON(str) 3 | 4 | fromJSON('[ "abc", "def"]') 5 | 6 | fromJSON('[ 1, 2, null]', nullValue = 123) 7 | 8 | fromJSON('[ true, false]') 9 | fromJSON('[ true, false, 1]') 10 | 11 | fromJSON('[ 1, 2, true]') 12 | fromJSON('[ 1, 2, 3.4, false]') 13 | 14 | fromJSON('[ 1, 2, 3.4, 1, null]') 15 | 16 | 17 | 18 | fromJSON('{ "a" : 1, "b" : "duncan", "f": [ 1, 2]}') 19 | 20 | toJSON(list(1, 2, list(NA)), .na = -9999) 21 | 22 | 23 | 24 | x = '[ 1, 2, {"a": [ 10, [3, 4] ], "bcd": {"xy": [1, 2], "wy": {"hij": true, "wsd": [true, false]}}}]' 25 | fromJSON(x) 26 | 27 | 28 | toJSON(list(a = pi, b = matrix(c(1:3, pi), 2, 2)), digits = 10) 29 | 30 | -------------------------------------------------------------------------------- /inst/sampleData/glossay.json: -------------------------------------------------------------------------------- 1 | { 2 | "glossary": { 3 | "title": "example glossary", 4 | "GlossDiv": { 5 | "title": "S", 6 | "GlossList": { 7 | "GlossEntry": { 8 | "ID": "SGML", 9 | "SortAs": "SGML", 10 | "GlossTerm": "Standard Generalized Markup Language", 11 | "Acronym": "SGML", 12 | "Abbrev": "ISO 8879:1986", 13 | "GlossDef": { 14 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 15 | "GlossSeeAlso": ["GML", "XML"] 16 | }, 17 | "GlossSee": "markup" 18 | } 19 | } 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONDefs/Unknown_C.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_UNKNOWN_C_HEADER 2 | #define JSON_UNKNOWN_C_HEADER 3 | 4 | #if !defined(__GNUC__) && !defined(_MSC_VER) 5 | 6 | #define json_deprecated(method, warning) method 7 | 8 | #define json_nothrow 9 | #define json_throws(x) 10 | #define json_pure json_nothrow 11 | #define json_read_priority 12 | #define json_write_priority 13 | #define json_malloc_attr json_nothrow 14 | #define json_hot 15 | #define json_cold 16 | #define json_likely(x) x 17 | #define json_unlikely(x) x 18 | 19 | #ifdef JSON_LESS_MEMORY 20 | #define PACKED(x) :x 21 | #define BITS(x) :x 22 | #endif 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONDefs/Visual_C.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_VISUAL_C_HEADER 2 | #define JSON_VISUAL_C_HEADER 3 | 4 | #ifdef _MSC_VER 5 | 6 | #define json_deprecated(method, warning) __declspec(deprecated(warning)) method 7 | 8 | #define json_nothrow 9 | #define json_throws(x) 10 | #define json_pure json_nothrow 11 | #define json_read_priority 12 | #define json_write_priority 13 | #define json_malloc_attr json_nothrow 14 | #define json_hot 15 | #define json_cold 16 | #define json_likely(x) x 17 | #define json_unlikely(x) x 18 | 19 | #ifdef JSON_LESS_MEMORY 20 | #define PACKED(x) :x 21 | #define BITS(x) :x 22 | #endif 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /inst/sampleData/widget.json: -------------------------------------------------------------------------------- 1 | {"widget": { 2 | "debug": "on", 3 | "window": { 4 | "title": "Sample Konfabulator Widget", 5 | "name": "main_window", 6 | "width": 500, 7 | "height": 500 8 | }, 9 | "image": { 10 | "src": "Images/Sun.png", 11 | "name": "sun1", 12 | "hOffset": 250, 13 | "vOffset": 250, 14 | "alignment": "center" 15 | }, 16 | "text": { 17 | "data": "Click Here", 18 | "size": 36, 19 | "style": "bold", 20 | "name": "text1", 21 | "hOffset": 250, 22 | "vOffset": 100, 23 | "alignment": "center", 24 | "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" 25 | } 26 | }} 27 | -------------------------------------------------------------------------------- /inst/doc/biblio.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | libjson 11 | JohnathanWallace 12 | 13 | 14 | 15 | 16 | The <r:pkg>rjson</r:pkg> package 17 | AlexCouture-Beil 18 | 2011-6-26 19 | 20 | 21 | -------------------------------------------------------------------------------- /inst/doc/overview.bbl: -------------------------------------------------------------------------------- 1 | \begin{thebibliography}{2} 2 | \newcommand{\enquote}[1]{``#1''} 3 | \providecommand{\natexlab}[1]{#1} 4 | \providecommand{\url}[1]{\texttt{#1}} 5 | \providecommand{\urlprefix}{URL } 6 | \expandafter\ifx\csname urlstyle\endcsname\relax 7 | \providecommand{\doi}[1]{doi:\discretionary{}{}{}#1}\else 8 | \providecommand{\doi}{doi:\discretionary{}{}{}\begingroup 9 | \urlstyle{rm}\Url}\fi 10 | \providecommand{\eprint}[2][]{\url{#2}} 11 | 12 | \bibitem[{Couture-Beil(2011-6-26)}]{bib:rjson} 13 | Couture-Beil A (2011-6-26). 14 | \newblock \enquote{The rjson package.} 15 | 16 | \bibitem[{Wallace(2011)}]{bib:libjson} 17 | Wallace J (2011). 18 | \newblock \enquote{libjson.} 19 | \newblock \urlprefix\url{http://libjson.sourceforge.net}. 20 | 21 | \end{thebibliography} 22 | -------------------------------------------------------------------------------- /tests/bigFile.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | checkValidity <- function(N, parse = FALSE, short = FALSE) { 4 | l = if(short) 5 | lapply(1:N, function(x) sample(10L, 10, replace = TRUE)) 6 | else 7 | lapply(1:10, function(x) sample(10L, N, replace = TRUE)) 8 | # names(l) <- letters[1:10] 9 | 10 | a <- toJSON(l) 11 | 12 | message("JSON document of size: ", nchar(a)) 13 | if(parse) 14 | fromJSON(a, asText = TRUE) 15 | else 16 | isValidJSON(a, asText = TRUE) 17 | } 18 | 19 | 20 | 21 | if(FALSE) { 22 | checkValidity(1e3L) 23 | 24 | #JSON document of size:31049 25 | 26 | #[1] TRUE 27 | 28 | checkValidity(1e6L) 29 | 30 | #JSON document of size:31002696 31 | 32 | #[1] TRUE 33 | 34 | checkValidity(2e6L) 35 | 36 | #JSON document of size:61999858 37 | #[1] FALSE 38 | } 39 | -------------------------------------------------------------------------------- /tests/dataframe.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | empty = data.frame(a = integer(), b = numeric()) 4 | r = data.frame(fromJSON(toJSON(empty))) 5 | identical(dim(r), dim(empty)) 6 | identical(names(r), names(empty)) 7 | 8 | # The columns are of different types as the fromJSON version 9 | # are just list() 10 | 11 | oneRow = data.frame(a = integer(1), b = numeric(1)) 12 | r = data.frame(fromJSON(toJSON(oneRow))) 13 | stopifnot(identical(dim(r), dim(oneRow))) 14 | stopifnot(identical(names(r), names(oneRow))) 15 | 16 | 17 | twoRows = data.frame(a = 1:2, b = as.numeric(1:2)) 18 | r = data.frame(fromJSON(toJSON(twoRows))) 19 | stopifnot(all.equal(r, twoRows)) 20 | 21 | 22 | j = toJSON(twoRows, byrow = TRUE) 23 | r = data.frame(do.call(rbind, fromJSON(j))) 24 | 25 | j = toJSON(twoRows, byrow = TRUE, colNames = TRUE) 26 | r = data.frame(do.call(rbind, fromJSON(j))) 27 | all.equal(twoRows, r) 28 | -------------------------------------------------------------------------------- /experiments/stream.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | if(FALSE) { 3 | jtxt = "[1,\n 2,\n 3,\n 4]" 4 | con = textConnection(jtxt) 5 | } else { 6 | # con = file("inst/sampleData/array2.json", "r") 7 | f = "inst/sampleData/web.json" 8 | # f = "inst/sampleData/widget.json" 9 | 10 | con = file(f, "r") 11 | } 12 | 13 | streamJSON = 14 | function(con, cb =function(obj) { cat("Called cb\n"); print(obj)}) 15 | { 16 | getData = function() { 17 | x = readLines(con, n = 1) 18 | cat("R: ", sQuote(x), "\n", sep = "") 19 | if(length(x)) 20 | sprintf("%s\n", x) 21 | else 22 | character() 23 | } 24 | # conCall = substitute({x = readLines(con, n = 1); cat(x, "\n"); if(length(x)) sprintf("%s\n", x) else character()}, list(con = con)) 25 | cbCall = substitute(foo(val), list(foo = cb)) 26 | 27 | .Call("R_json_parser_init_from_con", getData, cbCall) 28 | } 29 | 30 | streamJSON(con) 31 | -------------------------------------------------------------------------------- /Todo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Swap in the latest version of libjson (e.g. 7.0) 10 |
11 | We should allow the package to be built against 12 | an existing installed libjson. 13 |
14 | 15 | 16 | Perhaps allow objects with homogeneous elements to be converted 17 | to named vectors, e.g. servlet-mapping in web.json 18 | 19 | 20 | 21 | 22 | fromJSON("inst/sampleData/menu.json") 23 | 24 | takes the elements in menuitem and condenses them into a matrix 25 | and discards the names. 26 |
27 | Put in a check on names in condense 28 |
29 | 30 | 31 | Put in a pure C routine to read the content. 32 | Mimic the R basicJSONHandler$update function. 33 | 34 |
-------------------------------------------------------------------------------- /src/Rlibjson.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef enum { NATIVE_STR_ROUTINE, SEXP_STR_ROUTINE, R_FUNCTION, GARBAGE} StringFunctionType; 6 | 7 | typedef SEXP (*SEXPStringRoutine)(const char *, cetype_t encoding); 8 | typedef char * (*StringRoutine)(const char *); 9 | 10 | SEXP processJSONNode(JSONNODE *node, int parentType, int simplify, SEXP nullValue, 11 | int simplifyWithNames, cetype_t, SEXP strFun, StringFunctionType str_fun_type); 12 | 13 | 14 | typedef enum {NONE, ALL, STRICT_LOGICAL = 2, STRICT_NUMERIC = 4, STRICT_CHARACTER = 8, STRICT = 14} SimplifyStyle; 15 | 16 | 17 | 18 | 19 | 20 | #ifndef PROBLEM 21 | 22 | #define R_PROBLEM_BUFSIZE 4096 23 | #define PROBLEM {char R_problem_buf[R_PROBLEM_BUFSIZE];(snprintf)(R_problem_buf, R_PROBLEM_BUFSIZE, 24 | #define ERROR ),Rf_error(R_problem_buf);} 25 | #define WARNING(x) ),Rf_warning(R_problem_buf);} 26 | #define WARN WARNING(NULL) 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /inst/sampleData/keys.json: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "header": "SVG Viewer", 3 | "items": [ 4 | {"id": "Open"}, 5 | {"id": "OpenNew", "label": "Open New"}, 6 | null, 7 | {"id": "ZoomIn", "label": "Zoom In"}, 8 | {"id": "ZoomOut", "label": "Zoom Out"}, 9 | {"id": "OriginalView", "label": "Original View"}, 10 | null, 11 | {"id": "Quality"}, 12 | {"id": "Pause"}, 13 | {"id": "Mute"}, 14 | null, 15 | {"id": "Find", "label": "Find..."}, 16 | {"id": "FindAgain", "label": "Find Again"}, 17 | {"id": "Copy"}, 18 | {"id": "CopyAgain", "label": "Copy Again"}, 19 | {"id": "CopySVG", "label": "Copy SVG"}, 20 | {"id": "ViewSVG", "label": "View SVG"}, 21 | {"id": "ViewSource", "label": "View Source"}, 22 | {"id": "SaveAs", "label": "Save As"}, 23 | null, 24 | {"id": "Help"}, 25 | {"id": "About", "label": "About Adobe CVG Viewer..."} 26 | ] 27 | }} 28 | -------------------------------------------------------------------------------- /inst/sampleData/menu1.json: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "header": "SVG Viewer", 3 | "items": [ 4 | {"id": "Open"}, 5 | {"id": "OpenNew", "label": "Open New"}, 6 | null, 7 | {"id": "ZoomIn", "label": "Zoom In"}, 8 | {"id": "ZoomOut", "label": "Zoom Out"}, 9 | {"id": "OriginalView", "label": "Original View"}, 10 | null, 11 | {"id": "Quality"}, 12 | {"id": "Pause"}, 13 | {"id": "Mute"}, 14 | null, 15 | {"id": "Find", "label": "Find..."}, 16 | {"id": "FindAgain", "label": "Find Again"}, 17 | {"id": "Copy"}, 18 | {"id": "CopyAgain", "label": "Copy Again"}, 19 | {"id": "CopySVG", "label": "Copy SVG"}, 20 | {"id": "ViewSVG", "label": "View SVG"}, 21 | {"id": "ViewSource", "label": "View Source"}, 22 | {"id": "SaveAs", "label": "Save As"}, 23 | null, 24 | {"id": "Help"}, 25 | {"id": "About", "label": "About Adobe CVG Viewer..."} 26 | ] 27 | }} 28 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONDefs/Strings_Defs.h: -------------------------------------------------------------------------------- 1 | #ifndef STRINGS_DEFS_HEADER 2 | #define STRINGS_DEFS_HEADER 3 | 4 | #include "../../../JSONOptions.h" 5 | 6 | #ifdef JSON_UNICODE 7 | #define json_char wchar_t 8 | #define json_uchar wchar_t 9 | #ifdef __cplusplus 10 | #include /* need wide characters */ 11 | #ifndef JSON_STRING_HEADER 12 | #include 13 | #endif 14 | #else 15 | #include /* need wide characters */ 16 | #endif 17 | #define JSON_TEXT(s) L ## s 18 | #define json_strlen wcslen 19 | #define json_strcmp wcscmp 20 | #else 21 | #define json_char char 22 | #define json_uchar unsigned char 23 | #ifdef __cplusplus 24 | #ifndef JSON_STRING_HEADER 25 | #include 26 | #endif 27 | #else 28 | #include /* still need it for strlen and such */ 29 | #endif 30 | #define JSON_TEXT(s) s 31 | #define json_strlen strlen 32 | #define json_strcmp strcmp 33 | #endif 34 | 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /R/isValid.R: -------------------------------------------------------------------------------- 1 | setGeneric("isValidJSON", 2 | function(content, asText = inherits(content, "AsIs"), ...) 3 | standardGeneric("isValidJSON")) 4 | 5 | setMethod("isValidJSON", "AsIs", 6 | function(content, asText = inherits(content, "AsIs"), ...) { 7 | .Call("R_isValidJSON", as.character(content)) 8 | }) 9 | 10 | setMethod("isValidJSON", "character", 11 | function(content, asText = inherits(content, "AsIs"), ...) { 12 | 13 | if(!asText) { 14 | content = I(suppressWarnings(paste(readLines(content), collapse = "\n"))) 15 | } else 16 | content = I(content) 17 | 18 | isValidJSON(content, asText = TRUE) 19 | }) 20 | 21 | setMethod("isValidJSON", "connection", 22 | function(content, asText = inherits(content, "AsIs"), ...) { 23 | content = I(suppressWarnings(paste(readLines(content), collapse = "\n"))) 24 | isValidJSON(content, asText = TRUE) 25 | }) 26 | -------------------------------------------------------------------------------- /man/JSON_T_NULL.Rd: -------------------------------------------------------------------------------- 1 | \name{Bob} 2 | %\Rdversion{1.1} 3 | \alias{JSON_T_ARRAY_BEGIN} 4 | \alias{JSON_T_ARRAY_END} 5 | \alias{JSON_T_FALSE} 6 | \alias{JSON_T_FLOAT} 7 | \alias{JSON_T_INTEGER} 8 | \alias{JSON_T_KEY} 9 | \alias{JSON_T_MAX} 10 | \alias{JSON_T_NONE} 11 | \alias{JSON_T_NULL} 12 | \alias{JSON_T_OBJECT_BEGIN} 13 | \alias{JSON_T_OBJECT_END} 14 | \alias{JSON_T_STRING} 15 | \alias{JSON_T_TRUE} 16 | \docType{data} 17 | \title{ 18 | Symbolic constants identifying the type of a JSON value. 19 | } 20 | \description{ 21 | These constants are used by handler functions that 22 | are called when a JSON value is encountered by the 23 | JSON parser. These identify the type of the JSON value. 24 | The values will already have been converted, but 25 | the start and end array and object events won't have 26 | a type. 27 | } 28 | %\usage{} 29 | \format{ 30 | A collection of integer values. 31 | } 32 | \source{ 33 | \code{JSON_parser.h} code from \url{http://www.json.org}. 34 | } 35 | \references{ 36 | \url{http://www.json.org}. 37 | } 38 | %\examples{} 39 | \keyword{datasets} 40 | -------------------------------------------------------------------------------- /tests/simplify.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | stopifnot(is.list(fromJSON('[1, "2.3", "abc"]', simplify = Strict))) 4 | 5 | stopifnot(is.character(fromJSON('[1, "2.3", "abc"]', simplify = TRUE))) 6 | 7 | stopifnot(is.character(fromJSON('[1, true, "2.3", "abc"]', simplify = TRUE))) 8 | 9 | stopifnot(is.list(fromJSON('[1, true, "2.3", "abc"]', simplify = Strict))) 10 | 11 | stopifnot(is.list(fromJSON('[1, true]', simplify = Strict))) 12 | stopifnot(is.numeric(fromJSON('[1, true]', simplify = TRUE))) 13 | 14 | stopifnot(is.character(fromJSON('["1", true]', simplify = TRUE))) 15 | 16 | 17 | stopifnot(is.character(fromJSON('{ "a": "1", "b": true}', simplify = TRUE))) 18 | stopifnot(is.list(fromJSON('{ "a": "1", "b": true}', simplify = Strict))) 19 | 20 | stopifnot(is.character(fromJSON('{ "a": "1", "b": "true"}', simplify = Strict))) 21 | 22 | stopifnot(is.numeric(fromJSON('{ "a": 1, "b": 2}', simplify = Strict))) 23 | 24 | stopifnot(is.list(fromJSON('{ "a": 1, "b": 2}', simplify = FALSE))) 25 | 26 | 27 | is.na(fromJSON(toJSON( c("a", NA, "b", "c")), nullValue = NA, simplify = TRUE)) 28 | is.na(fromJSON(toJSON( c(1, NA, 3, 4)), nullValue = NA, simplify = TRUE)) 29 | 30 | is.na(fromJSON(toJSON( c(TRUE, NA, FALSE, TRUE)), nullValue = NA, simplify = TRUE)) 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This RJSONIO package uses the libjson C library from 2 | libjson.sourceforge.net. A version of that C++ code is included in 3 | this package and can be used. Alternatively, one can use a different 4 | version of libjson, e.g. a more recent version. To do this, 5 | you install that version of libjson with 6 | ``` 7 | make SHARED=1 install 8 | ``` 9 | The key thing is to make this a shared library so we can link against 10 | it as position independent code (PIC). 11 | 12 | By default, this will be installed in /usr/local. 13 | You can control this with 14 | ``` 15 | make SHARED=1 install prefix="/my/directory" 16 | ``` 17 | 18 | The configuration script will attempt to find libjson on your system, 19 | looking in /usr/local. If this is not the location you installed 20 | libjson to, you can specify the prefix via the --with-prefix=/my/directory, 21 | e.g. 22 | ``` 23 | R CMD INSTALL --configure-args="--with-prefix=/my/directory" RJSONIO 24 | ``` 25 | 26 | If you want to force using the version of libjson contained in this package, 27 | you can use 28 | ``` 29 | R CMD INSTALL --configure-args="--with-local-libjson=yes" RJSONIO 30 | ``` 31 | 32 | If you do use a version of libjson installed into a non-standard place, 33 | you will probably need to modify your LD_LIBRARY_PATH (or DYLD_LIBRARY_PATH on OS X) 34 | environment variable. 35 | 36 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONPreparse.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_PREPARSE_H 2 | #define LIBJSON_GUARD_PREPARSE_H 3 | 4 | #include "JSONDebug.h" 5 | #include "JSONNode.h" 6 | 7 | #if (defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)) 8 | 9 | #ifdef JSON_COMMENTS 10 | #define COMMENT_PARAM(name) ,const json_string & name 11 | #else 12 | #define COMMENT_PARAM(name) 13 | #endif 14 | 15 | class JSONPreparse { 16 | public: 17 | static JSONNode isValidNumber(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 18 | static JSONNode isValidMember(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 19 | static json_string isValidString(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 20 | static void isValidNamedObject(json_string::const_iterator & ptr, json_string::const_iterator & end, JSONNode & parent COMMENT_PARAM(comment)) json_read_priority; 21 | static JSONNode isValidObject(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 22 | static JSONNode isValidArray(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 23 | static JSONNode isValidRoot(const json_string & json) json_throws(std::invalid_argument) json_read_priority; 24 | }; 25 | 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/libjson/Source/JSON_Base64.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_BASE64_H 2 | #define LIBJSON_GUARD_BASE64_H 3 | 4 | #include "JSONDebug.h" 5 | #if defined(JSON_BINARY) || defined(JSON_EXPOSE_BASE64) //if this is not needed, don't waste space compiling it 6 | 7 | #include "../Dependencies/libbase64++/libbase64++.h" 8 | 9 | class JSONBase64 { 10 | public: 11 | inline static json_string json_encode64(const unsigned char * binary, size_t bytes) json_nothrow json_cold; 12 | inline static std::string json_decode64(const json_string & encoded) json_nothrow json_cold; 13 | private: 14 | JSONBase64(void); 15 | }; 16 | 17 | json_string JSONBase64::json_encode64(const unsigned char * binary, size_t bytes) json_nothrow { 18 | #if defined JSON_DEBUG || defined JSON_SAFE 19 | return libbase64::encode(binary, bytes); 20 | #else 21 | return libbase64::encode(binary, bytes); 22 | #endif 23 | } 24 | 25 | std::string JSONBase64::json_decode64(const json_string & encoded) json_nothrow { 26 | #if defined JSON_DEBUG || defined JSON_SAFE 27 | return libbase64::decode(encoded); 28 | #else 29 | return libbase64::decode(encoded); 30 | #endif 31 | } 32 | 33 | 34 | #endif 35 | #endif 36 | -------------------------------------------------------------------------------- /man/basicJSONHandler.Rd: -------------------------------------------------------------------------------- 1 | \name{basicJSONHandler} 2 | \alias{basicJSONHandler} 3 | \title{Create handler for processing JSON elements from a parser} 4 | \description{ 5 | This function creates a handler object that is used to 6 | consume tokens/elements from a JSON parser and combine 7 | them into R objects. 8 | 9 | This is slow relative to using C code because this is done 10 | in R and also we don't know the length of each object until 11 | we have consumed all its elements. 12 | } 13 | \usage{ 14 | basicJSONHandler(default.size = 100, simplify = FALSE) 15 | } 16 | \arguments{ 17 | \item{default.size}{the best guess as to the sizes of the different elements. This is used 18 | for preallocating space for elements} 19 | \item{simplify}{a logical value indicating whether to simplify arrays 20 | from lists to vectors if the elements are of compatible types.} 21 | } 22 | \value{ 23 | \item{update}{a function called with a JSON element and used to process that element and add it to the relevant R object} 24 | \item{value}{a function to retrieve the result after processing the JSON} 25 | } 26 | %\references{} 27 | \author{ 28 | Duncan Temple Lang 29 | } 30 | 31 | \seealso{ 32 | \code{\link{fromJSON}} and the handler argument. 33 | } 34 | \examples{ 35 | h = basicJSONHandler() 36 | x = fromJSON("[1, 2, 3]", h) 37 | x 38 | h$value() 39 | } 40 | \keyword{IO} 41 | \keyword{programming} 42 | -------------------------------------------------------------------------------- /tests/containers.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | 3 | roundTrip = 4 | # compare can be all.equal 5 | function(x, y = x, simplify = TRUE, asIs = NA, compare = identical) { 6 | ans <- fromJSON(toJSON(x, asIs = asIs), simplify = simplify) 7 | compare(ans, y) 8 | } 9 | 10 | stopifnot(roundTrip(c(TRUE, FALSE))) 11 | stopifnot(roundTrip(TRUE)) 12 | try(stopifnot(roundTrip(1L))) # fails since 1L becomes a numeric 13 | stopifnot(roundTrip(1)) 14 | stopifnot(roundTrip("xyz")) 15 | 16 | stopifnot(roundTrip(c(TRUE, FALSE))) 17 | stopifnot(roundTrip(1:2, as.numeric(1:2))) 18 | stopifnot(roundTrip(c(1, 2, 3))) 19 | stopifnot(roundTrip(c("abc", "xyz"))) 20 | 21 | # with names 22 | stopifnot(roundTrip(c(a = TRUE))) 23 | stopifnot(roundTrip(c(a = 1))) 24 | stopifnot(roundTrip(c(a = "xyz"))) 25 | stopifnot(roundTrip(c(a = 1L), c(a = 1))) 26 | 27 | 28 | # lists 29 | 30 | stopifnot(roundTrip(list(1L), asIs = FALSE, simplify = FALSE, list(1))) 31 | 32 | # 33 | stopifnot(roundTrip(list(1, 2), asIs = FALSE, simplify = FALSE, list(1, 2))) 34 | stopifnot(roundTrip(list(1, 2), asIs = TRUE, simplify = FALSE, list(list(1), list(2)))) 35 | 36 | stopifnot(roundTrip(list(a= 1, b = 2), asIs = TRUE, simplify = FALSE, list(a = list(1), b = list(2)))) 37 | 38 | 39 | # 40 | tmp = list(a = 1, b = c(1, 2), c = list(1:3, x = c(TRUE, FALSE, FALSE), list(c("a", "b", "c", "d")))) 41 | tmp1 = fromJSON(toJSON(tmp)) 42 | all.equal(tmp, tmp1) 43 | 44 | roundTrip(tmp, compare = all.equal) 45 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONDebug.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONDebug.h" 2 | #ifdef JSON_DEBUG 3 | 4 | #ifdef JSON_STDERROR 5 | #include //need std::cerr 6 | #else 7 | #include "JSONSingleton.h" 8 | //otherwise, use a callback to tell the end user what happened 9 | json_error_callback_t JSONDebug::register_callback(json_error_callback_t callback) json_nothrow { 10 | json_error_callback_t res = JSONSingleton::get(); 11 | JSONSingleton::set(callback); 12 | return res; 13 | } 14 | #endif 15 | 16 | //Something went wrong or an assert failed 17 | void JSONDebug::_JSON_FAIL(const json_string & msg) json_nothrow { 18 | #ifdef JSON_STDERROR //no callback, just use stderror 19 | #ifndef JSON_UNICODE 20 | std::cerr << msg << std::endl; 21 | #else 22 | std::cerr << std::string(msg.begin(), msg.end()) << std::endl; 23 | #endif 24 | #else 25 | if (json_error_callback_t ErrorCallback = JSONSingleton::get()){ //only do anything if the callback is registered 26 | #ifdef JSON_LIBRARY 27 | ErrorCallback(msg.c_str()); 28 | #else 29 | ErrorCallback(msg); 30 | #endif 31 | } 32 | #endif 33 | } 34 | 35 | //asserts that condition is true, more useful than cassert because it lets you keep going 36 | void JSONDebug::_JSON_ASSERT(bool condition, const json_string & msg) json_nothrow { 37 | if (json_unlikely(!condition)){ 38 | _JSON_FAIL(msg); 39 | } 40 | } 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONMemoryPool.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_MEMORY_POOL_H 2 | #define LIBJSON_GUARD_MEMORY_POOL_H 3 | 4 | #ifdef JSON_MEMORY_POOL 5 | 6 | #include "../Dependencies/mempool++/mempool.h" 7 | 8 | //this macro expands to the number of bytes a pool gets based on block size and number of 32s of the total pool it gets 9 | #define jsonPoolPart(bytes_per_block, thirty_seconds_of_mem) bytes_per_block, ((thirty_seconds_of_mem * JSON_MEMORY_POOL / 32) / bytes_per_block) 10 | 11 | #ifdef JSON_PREPARSE 12 | #define NODEPOOL jsonPoolPart(sizeof(JSONNode), 1) 13 | #define INTERNALNODEPOOL jsonPoolPart(sizeof(internalJSONNode), 3) 14 | #define MEMPOOL_1 jsonPoolPart(8, 2) 15 | #define MEMPOOL_2 jsonPoolPart(16, 2) 16 | #define MEMPOOL_3 jsonPoolPart(32, 2) 17 | #define MEMPOOL_4 jsonPoolPart(64, 2) 18 | #define MEMPOOL_5 jsonPoolPart(128, 3) 19 | #define MEMPOOL_6 jsonPoolPart(256, 4) 20 | #define MEMPOOL_7 jsonPoolPart(512, 5) 21 | #define MEMPOOL_8 jsonPoolPart(4096, 8) 22 | #else 23 | #define NODEPOOL jsonPoolPart(sizeof(JSONNode), 2) 24 | #define INTERNALNODEPOOL jsonPoolPart(sizeof(internalJSONNode), 7) 25 | #define MEMPOOL_1 jsonPoolPart(8, 1) 26 | #define MEMPOOL_2 jsonPoolPart(16, 1) 27 | #define MEMPOOL_3 jsonPoolPart(32, 1) 28 | #define MEMPOOL_4 jsonPoolPart(64, 1) 29 | #define MEMPOOL_5 jsonPoolPart(128, 3) 30 | #define MEMPOOL_6 jsonPoolPart(256, 3) 31 | #define MEMPOOL_7 jsonPoolPart(512, 5) 32 | #define MEMPOOL_8 jsonPoolPart(4096, 8) 33 | #endif 34 | 35 | #endif 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /R/simpleHandler.R: -------------------------------------------------------------------------------- 1 | simpleJSONHandler = 2 | # 3 | # A handler to read generic JSON content 4 | # 5 | function() 6 | { 7 | stack = NULL 8 | cur = NULL 9 | curKey = character() 10 | 11 | update = function(type, val) { 12 | 13 | if(type == JSON_T_KEY) { 14 | # a key for a hash table. 15 | curKey <<- c(val, curKey) 16 | } else if(type == JSON_T_ARRAY_BEGIN || type == JSON_T_OBJECT_BEGIN) { 17 | stack <<- list(cur, stack) 18 | cur <<- list() 19 | } else if(type == JSON_T_ARRAY_END || type == JSON_T_OBJECT_END) { 20 | obj = if(type == JSON_T_ARRAY_END) condense(cur) else cur 21 | if(type == JSON_T_OBJECT_END) { 22 | i = seq(along = obj) 23 | names(obj) = rev(curKey[i]) 24 | curKey <<- curKey[-i] 25 | } 26 | 27 | cur <<- stack[[1]] 28 | if(length(stack) > 1) 29 | stack <<- stack[[2]] 30 | 31 | cur[[ length(cur) + 1 ]] <<- obj 32 | } else if(type > JSON_T_OBJECT_END && type < JSON_T_KEY) { 33 | # The actual atomic values 34 | cur[[length(cur) + 1]] <<- val 35 | } 36 | 37 | TRUE 38 | } 39 | 40 | getValue = 41 | function(simplify = TRUE) { 42 | if(simplify && length(cur) == 1) 43 | cur[[1]] 44 | else 45 | cur 46 | } 47 | 48 | structure(list(update = update, 49 | value = getValue), 50 | class = "JSONParserHandler") 51 | } 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONValidator.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_VALIDATOR_H 2 | #define JSON_VALIDATOR_H 3 | 4 | #include "JSONDebug.h" 5 | 6 | #ifdef JSON_VALIDATE 7 | 8 | #ifdef JSON_SECURITY_MAX_NEST_LEVEL 9 | #define DEPTH_PARAM ,size_t depth_param 10 | #define DEPTH_ARG(arg) ,arg 11 | #define INC_DEPTH()\ 12 | if (++depth_param > JSON_SECURITY_MAX_NEST_LEVEL){\ 13 | JSON_FAIL(JSON_TEXT("Exceeded JSON_SECURITY_MAX_NEST_LEVEL"));\ 14 | return false;\ 15 | } 16 | #else 17 | #define DEPTH_PARAM 18 | #define DEPTH_ARG(arg) 19 | #define INC_DEPTH() (void)0 20 | #endif 21 | 22 | class JSONValidator { 23 | public: 24 | static bool isValidNumber(const json_char * & ptr) json_nothrow json_read_priority; 25 | static bool isValidMember(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority; 26 | static bool isValidString(const json_char * & ptr) json_nothrow json_read_priority; 27 | static bool isValidNamedObject(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority; 28 | static bool isValidObject(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority; 29 | static bool isValidArray(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority; 30 | static bool isValidRoot(const json_char * json) json_nothrow json_read_priority; 31 | #ifdef JSON_STREAM 32 | static bool isValidPartialRoot(const json_char * json) json_nothrow json_read_priority; 33 | #endif 34 | private: 35 | JSONValidator(void); 36 | }; 37 | 38 | #endif 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/libjson/License.txt: -------------------------------------------------------------------------------- 1 | This license is also available in Documentation.pdf 2 | 3 | Copyright 2010 Jonathan Wallace. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | 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. 10 | 11 | THIS SOFTWARE IS PROVIDED BY JONATHAN WALLACE ``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 JONATHAN WALLACE OR CONTRIBUTORS 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. 12 | 13 | The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Jonathan Wallace. -------------------------------------------------------------------------------- /man/isValidJSON.Rd: -------------------------------------------------------------------------------- 1 | \name{isValidJSON} 2 | \alias{isValidJSON} 3 | \alias{isValidJSON,AsIs-method} 4 | \alias{isValidJSON,character-method} 5 | \alias{isValidJSON,connection-method} 6 | \title{Test if JSON content is valid} 7 | \description{ 8 | This function and its methods allows the caller to verify if the 9 | JSON content is strictly valid. Even if the content is invalid, 10 | the parser may still be able to make sense of it or at least 11 | get it partially correct and yield a result. 12 | So this function allows the caller to verify that the input is 13 | legitimate and not just rely on the parser not failing. 14 | } 15 | \usage{ 16 | isValidJSON(content, asText = inherits(content, "AsIs"), ...) 17 | } 18 | %- maybe also 'usage' for other objects documented here. 19 | \arguments{ 20 | \item{content}{the JSON input either as a string, the name of a file 21 | or URL, or a connection object.} 22 | \item{asText}{a logical value that specifies whether the value in 23 | \code{content} is actually the JSON content or the name of a file} 24 | \item{\dots}{additional parameters for the methods} 25 | } 26 | \value{ 27 | A logical value indicating whether the content is valid JSON 28 | (\code{TRUE}) or invalid (\code{FALSE}). 29 | } 30 | \references{ 31 | libjson 32 | } 33 | \author{ 34 | Duncan Temple Lang. 35 | Functionality suggested by Jeroen Ooms. 36 | } 37 | 38 | \seealso{ 39 | \code{\link{fromJSON}} 40 | } 41 | \examples{ 42 | isValidJSON(I('{"foo" : "bar"}')) 43 | 44 | isValidJSON(I('{foo : "bar"}')) 45 | isValidJSON('{foo : "bar"}', TRUE) 46 | } 47 | \keyword{programming} 48 | \keyword{IO} 49 | 50 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONDebug.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_DEBUG_H 2 | #define LIBJSON_GUARD_DEBUG_H 3 | 4 | #include "JSONDefs.h" 5 | #include "JSONStats.h" 6 | 7 | #ifdef JSON_DEBUG 8 | #ifdef JSON_SAFE 9 | #define JSON_ASSERT_SAFE(condition, msg, code)\ 10 | {\ 11 | if (json_unlikely(!(condition))){\ 12 | JSON_FAIL(msg);\ 13 | code\ 14 | }\ 15 | } 16 | #define JSON_FAIL_SAFE(msg, code)\ 17 | {\ 18 | JSON_FAIL(msg);\ 19 | code\ 20 | } 21 | #else 22 | #define JSON_ASSERT_SAFE(condition, msg, code) JSON_ASSERT(condition, msg) 23 | #define JSON_FAIL_SAFE(msg, code) JSON_FAIL(msg) 24 | #endif 25 | 26 | #define JSON_FAIL(msg) JSONDebug::_JSON_FAIL(msg) 27 | #define JSON_ASSERT(bo, msg) JSONDebug::_JSON_ASSERT(bo, msg) 28 | 29 | class JSONDebug { 30 | public: 31 | #ifndef JSON_STDERROR 32 | static json_error_callback_t register_callback(json_error_callback_t callback) json_nothrow json_cold; 33 | #endif 34 | static void _JSON_FAIL(const json_string & msg) json_nothrow json_cold; 35 | static void _JSON_ASSERT(bool condition, const json_string & msg) json_nothrow json_cold; 36 | }; 37 | #else 38 | #ifdef JSON_SAFE 39 | #define JSON_ASSERT_SAFE(condition, msg, code)\ 40 | {\ 41 | if (json_unlikely(!(condition))){\ 42 | code\ 43 | }\ 44 | } 45 | #define JSON_FAIL_SAFE(msg, code)\ 46 | {\ 47 | code\ 48 | } 49 | #else 50 | #define JSON_ASSERT_SAFE(condition, msg, code) 51 | #define JSON_FAIL_SAFE(msg, code) 52 | #endif 53 | 54 | #define JSON_ASSERT(condition, msg) 55 | #define JSON_FAIL(msg) 56 | #endif 57 | 58 | #endif 59 | 60 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: RJSONIO 2 | Version: 1.3-2 3 | Title: Serialize R objects to JSON, JavaScript Object Notation 4 | Description: This is a package that allows conversion to and from 5 | data in Javascript object notation (JSON) format. 6 | This allows R objects to be inserted into Javascript/ECMAScript/ActionScript code 7 | and allows R programmers to read and convert JSON content to R objects. 8 | This is an alternative to rjson package. Originally, that was too slow for converting large R objects to JSON 9 | and was not extensible. rjson's performance is now similar to this package, and perhaps slightly faster in some cases. 10 | This package uses methods and is readily extensible by defining methods for different classes, 11 | vectorized operations, and C code and callbacks to R functions for deserializing JSON objects to R. 12 | The two packages intentionally share the same basic interface. This package (RJSONIO) has many additional 13 | options to allow customizing the generation and processing of JSON content. 14 | This package uses libjson rather than implementing yet another JSON parser. The aim is to support 15 | other general projects by building on their work, providing feedback and benefit from their ongoing development. 16 | Note: The C code for parsing JSON comes from www.json.org and is licensed under essentially the BSD license. 17 | See the notice in src/JSON_parser.c 18 | The libjson code is on sourceforge.net, but does not yet have a license. 19 | libjson was written and is maintained and developed by Johnathan Wallace. 20 | Note: See http://www.json.org/JSON_checker/test.zip for tests. 21 | We now use code from the libjson project (http://libjson.sourceforge.net). 22 | License: BSD_3_clause + file LICENSE 23 | Imports: methods 24 | Author: Duncan Temple Lang 25 | Maintainer: Duncan Temple Lang 26 | Collate: readJSON.R asVars.R isValid.R json.R simpleHandler.R stream.R 27 | Biarch: true 28 | 29 | 30 | -------------------------------------------------------------------------------- /R/asVars.R: -------------------------------------------------------------------------------- 1 | asJSVars = 2 | # 3 | # For action script, we often want to declare the variables 4 | # as public/protected and also to put the variables 5 | # 6 | function(..., .vars = list(...), 7 | qualifier = character(), types = character()) 8 | { 9 | # Add in suitable indentation 10 | vals = paste(sapply(.vars, toJSON), ";") 11 | 12 | if(length(types)) { 13 | if(is.logical(types)) 14 | if(types) 15 | types = sapply(.vars, jsType) 16 | else # Should never happen. Caller should leave the default! 17 | types = character() 18 | 19 | if(length(types)) 20 | ids = paste(names(.vars), types, sep = " : ") 21 | else 22 | ids = names(.vars) 23 | } else 24 | ids = names(.vars) 25 | 26 | if(length(qualifier)) 27 | ids = paste(qualifier, ids) 28 | 29 | # Indent the object initialization with the number of characters involved in the 30 | # variable declaration. 31 | len = nchar(ids) 32 | vals = sapply(seq(along = ids), 33 | function(i) { 34 | gsub("\\\n", paste("\\\n", paste(rep(" ", len[i] + 3), collapse = ""), sep = ""), vals[i]) 35 | }) 36 | 37 | invisible(paste(ids, vals, sep = " = ", collapse = "\n\n")) 38 | } 39 | 40 | setGeneric("jsType", function(x, ...) standardGeneric("jsType")) 41 | 42 | setMethod("jsType", "matrix", 43 | function(x){ 44 | "Array" 45 | }) 46 | 47 | jsTypes = c("integer" = "int", 48 | "numeric" = "Number", 49 | "logical" = "Boolean", 50 | "character" = "String" 51 | ) 52 | 53 | setMethod("jsType", "vector", 54 | function(x){ 55 | if(length(x) == 1 && is.atomic(x) && length(names(x)) == 0) { 56 | jsTypes[typeof(x)] 57 | } else { 58 | if(length(names(x))) 59 | "Object" 60 | else 61 | "Array" 62 | } 63 | }) 64 | 65 | -------------------------------------------------------------------------------- /man/asJSVars.Rd: -------------------------------------------------------------------------------- 1 | \name{asJSVars} 2 | \alias{asJSVars} 3 | \title{Serialize R objects as Javsscript/ActionScript variables} 4 | \description{ 5 | This function takes R objects and serializes them as 6 | Javascript/ActionScript values. 7 | It uses the specified names in the R call as 8 | Javascript variable names. One can also specify 9 | qualifiers (\sQuote{public}, \sQuote{protected}, \sQuote{private}) 10 | and also types. These are optional, but useful, in ActionScript. 11 | } 12 | \usage{ 13 | asJSVars(..., .vars = list(...), qualifier = character(), types = character()) 14 | } 15 | %- maybe also 'usage' for other objects documented here. 16 | \arguments{ 17 | \item{\dots}{\code{name = value} pairs where the \code{value} is an R object 18 | that is converted to JSON format and \code{name} is the name of the corresponding 19 | Javascript variable.} 20 | \item{.vars}{this is an alternative to \dots as a way to specify a collection of 21 | \code{name = value} pairs that is already in a list.} 22 | \item{qualifier}{a character vector (recycled as necessary) which is 23 | used as qualifiers for the individual ActionScript variables. 24 | The values should be public, protected or private. 25 | } 26 | \item{types}{either a logical value or a character vector (which is 27 | recycled if necessary). If this is \code{TRUE}, then we compute the 28 | Javascript type for each of the R objects (using the non-exported 29 | function \code{jsType})} 30 | } 31 | \value{ 32 | A character vector of length 1 giving the variable declarations and 33 | initializations. 34 | } 35 | \author{Duncan Temple Lang } 36 | 37 | \seealso{ 38 | \code{\link{toJSON}} 39 | } 40 | \examples{ 41 | cat(asJSVars( a = 1:10, myMatrix = matrix(1:15, 3, 5))) 42 | cat(asJSVars( a = 1:10, myMatrix = matrix(1:15, 3, 5), types = TRUE)) 43 | cat(asJSVars( a = 1:10, myMatrix = matrix(1:15, 3, 5), 44 | qualifier = "protected", types = TRUE)) 45 | } 46 | \keyword{IO} 47 | \keyword{programming} 48 | 49 | -------------------------------------------------------------------------------- /tests/stringFun.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO) 2 | jtxt = '[ 1, "abc", "xyz"]' 3 | jdate = '[ 1, "/Date(1335746208)/", "xyz"]' 4 | jnewdate = '[ 1, "/new Date(1335746208)/", "xyz"]' 5 | 6 | 7 | 8 | a = fromJSON(jtxt, stringFun = I(getNativeSymbolInfo("dummyStringOperation")$address)) 9 | b = fromJSON(jtxt, stringFun = I(getNativeSymbolInfo("dummyStringOperation"))) 10 | c = fromJSON(jtxt, stringFun = I("dummyStringOperation")) 11 | d = fromJSON(jtxt, stringFun = structure("dummyStringOperation", class = "NativeStringRoutine")) 12 | 13 | e = fromJSON(jtxt, stringFun = I("dummyStringOperation"), simplify = TRUE) 14 | 15 | 16 | ans = fromJSON(jtxt, stringFun = structure("R_json_dateStringOp", class = "SEXPRoutine")) 17 | sapply(ans, class) == c("numeric", "character", "character") 18 | ans = fromJSON(jtxt, stringFun = "R_json_dateStringOp") 19 | 20 | ans = fromJSON(jtxt, stringFun = structure("R_json_dateStringOp", class = "SEXPRoutine"), simplify = TRUE) 21 | 22 | # process jdate 23 | ans = fromJSON(jdate, stringFun = structure("R_json_dateStringOp", class = "SEXPRoutine")) 24 | ans = fromJSON(jdate, stringFun = "R_json_dateStringOp") 25 | 26 | 27 | # process strings by just returning them. 28 | fromJSON(jtxt, stringFun = function(val) val) 29 | 30 | # process strings by prefixing them with xxx_ 31 | fromJSON(jtxt, stringFun = function(val) sprintf("xxx_%s", val)) 32 | 33 | jtxt = '[ "1", "2.3", "3.1415"]' # all numeric but in "" 34 | ans = fromJSON(jtxt) 35 | stopifnot(is.character(ans)) 36 | 37 | # convert all of the strings to numeric! 38 | ans = fromJSON(jtxt, stringFun = function(val) as.numeric(val)) 39 | stopifnot(is.numeric(ans)) 40 | 41 | # Now convert them all to TRUE as logicals 42 | ans = fromJSON(jtxt, stringFun = function(val) TRUE) 43 | stopifnot(is.logical(ans)) 44 | 45 | 46 | # 47 | jtxt = '[ 1, "/new Date(12312313)", "/Date(12312313)"]' 48 | ans = fromJSON(jtxt) 49 | 50 | ans = fromJSON(jtxt, stringFun = "R_json_dateStringOp", simplify = FALSE) 51 | stopifnot(all(mapply(is, ans, c("numeric", "POSIXct", "POSIXct")))) 52 | 53 | 54 | -------------------------------------------------------------------------------- /inst/doc/performance.R: -------------------------------------------------------------------------------- 1 | n = seq(1000, 100000, by = 5000) 2 | new.times = sapply(n, function(n) system.time(invisible(toJSON(rpois(n, 4))))) 3 | 4 | library(rjson) 5 | new.times = sapply(n, function(n) system.time(invisible(toJSON(rpois(n, 4))))) 6 | 7 | ################### 8 | 9 | json = sapply(n, function(n) toJSON(rpois(n, 2))) 10 | fromJSON.new.times = sapply(json, function(v) system.time(fromJSON(v, asText = TRUE))) 11 | 12 | fromJSON.new.times.10000 = sapply(json, function(v) system.time(fromJSON(v, default.size = 10000, asText = TRUE))) 13 | 14 | 15 | library(rjson) 16 | fromJSON.old.times = sapply(json, function(v) system.time(fromJSON(v))) 17 | 18 | colnames(fromJSON.old.times) = colnames(fromJSON.new.times) = n 19 | save(fromJSON.new.times, fromJSON.new.times.10000, fromJSON.old.times, n, file = "inst/doc/fromJSONTimes.rda") 20 | 21 | 22 | ############################### 23 | 24 | n = seq(1000, by = 1000, 10000) 25 | v = sapply(n, function(n) toJSON(rpois(n, 4))) 26 | 27 | a = sapply(v, function(x) system.time(fromJSON(x)), USE.NAMES = FALSE) 28 | 29 | b = sapply(v, function(x) system.time(fromJSON(x, RJSONIO:::simpleJSONHandler())), USE.NAMES = FALSE) 30 | 31 | f = get("fromJSON", "package:rjson") 32 | 33 | c = sapply(v, function(x) system.time(f(x)), USE.NAMES = FALSE) 34 | 35 | d = sapply(v, function(x) { 36 | system.time({ 37 | buf = rep(as.integer(NA), 100000) 38 | fromJSON(v,getNativeSymbolInfo("R_json_IntegerArrayCallback", PACKAGE = "RJSONIO"), 39 | data = buf) 40 | buf[!is.na(buf)] 41 | }) 42 | }, USE.NAMES = FALSE) 43 | 44 | matplot(n, cbind(a[3,], b[3,], c[3,], d[3,]), type = "l") 45 | 46 | D = data.frame(n = rep(n, 4), 47 | elapsed = c(a[3,], b[3,], c[3,], d[3,]), 48 | type = rep(c("default", "simple", "rjson", "C"), each = ncol(a))) 49 | 50 | xyplot(elapsed ~ n, D, group = type, type = "l", auto.key = list(columns = length(levels(D$type)))) 51 | 52 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONDefs/GNU_C.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_GNU_C_HEADER 2 | #define JSON_GNU_C_HEADER 3 | 4 | #ifdef __GNUC__ 5 | 6 | #define json_deprecated(method, warning) method __attribute__((deprecated)) 7 | 8 | #if (__GNUC__ >= 3) 9 | #define JSON_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 10 | #else 11 | #define JSON_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) 12 | #endif 13 | 14 | #if (JSON_GCC_VERSION >= 40300) 15 | #define json_hot __attribute__ ((hot)) 16 | #define json_cold __attribute__ ((cold)) 17 | #define json_pure json_nothrow __attribute__ ((pure, hot)) 18 | #define json_malloc_attr json_nothrow __attribute__ ((malloc, hot)) 19 | 20 | /* Can do priorities */ 21 | #if (JSON_WRITE_PRIORITY == HIGH) 22 | #define json_write_priority __attribute__ ((hot)) 23 | #elif (JSON_WRITE_PRIORITY == LOW) 24 | #define json_write_priority __attribute__ ((cold)) 25 | #else 26 | #define json_write_priority 27 | #endif 28 | 29 | #if (JSON_READ_PRIORITY == HIGH) 30 | #define json_read_priority __attribute__ ((hot)) 31 | #elif (JSON_READ_PRIORITY == LOW) 32 | #define json_read_priority __attribute__ ((cold)) 33 | #else 34 | #define json_read_priority 35 | #endif 36 | 37 | #define json_likely(x) __builtin_expect((long)((bool)(x)),1) 38 | #define json_unlikely(x) __builtin_expect((long)((bool)(x)),0) 39 | #else 40 | #if (JSON_GCC_VERSION >= 29600) 41 | #define json_pure json_nothrow __attribute__ ((pure)) 42 | #define json_likely(x) __builtin_expect((long)((bool)(x)),1) 43 | #define json_unlikely(x) __builtin_expect((long)((bool)(x)),0) 44 | #else 45 | #define json_pure json_nothrow 46 | #define json_likely(x) x 47 | #define json_unlikely(x) x 48 | #endif 49 | 50 | #define json_malloc_attr json_nothrow __attribute__ ((malloc)) 51 | #define json_write_priority 52 | #define json_read_priority 53 | #define json_hot 54 | #define json_cold 55 | #endif 56 | 57 | #define json_nothrow throw() 58 | #define json_throws(x) throw(x) 59 | 60 | #ifdef JSON_LESS_MEMORY 61 | #define PACKED(x) :x __attribute__ ((packed)) 62 | #define BITS(x) :x 63 | #endif 64 | 65 | #endif 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /Web/index.html.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @PKG_NAME@ 5 | 6 | 7 | 8 |

The @PKG_NAME@ Package

9 |

Last Release: 10 | @VERSION@ (@DATE@)

11 | 12 |

13 | This package provides facilities for reading and writing 14 | data in JSON - Javascript Object 15 | Notation - format. 16 | This allows us to read data in this format, e.g. from Web service 17 | applications, 18 | and also to export objects from R for use in 19 | Javascript/ECMAScript/ActionScript code. 20 | This is useful when generating dynamic plots with SVG (Scalable Vector 21 | Graphics), or Flash and ActionScript. 22 | 23 |

24 | 25 |

26 | The primary functions in the package are 27 |

    28 |
  • fromJSON 29 |
  • toJSON 30 |
  • asJSVars 31 |
32 |

33 | 34 |

35 | The package is extensible, allowing others to 36 | define S4 methods for toJSON 37 | for different R classes/types. 38 | Similarly, the fromJSON function allows 39 | the caller to specify a different callback handler 40 | which is invoked each time an element (e.g. number, 41 | string, key, start or end of an array or object) is found 42 | in the JSON content. 43 |

44 | 45 |

This package was motivated by the need to export R objects for use 46 | in creating dynamic graphics for the Web via SVG and Flash/FLEX. 47 | Since then, JSON has become a prominent format with many uses. 48 | Alex Couture-Beil's rjson 50 | package is another mechanism in R for reading and writing JSON 51 | content. However, that does not use S4/S3 methods and so is not 52 | readily extensible, but still useful. 53 |

54 | 55 |

Documentation

56 | 57 | 61 | 62 | 63 | 64 |
65 |
Duncan Temple Lang 66 | <duncan@r-project.org>
67 | 68 | Last modified: Mon May 19 09:26:38 PDT 2014 69 | 70 | 71 | -------------------------------------------------------------------------------- /streaming.R: -------------------------------------------------------------------------------- 1 | library(RJSONIO); f= "inst/sampleData/web.json"; .Call("R_json_parser_test_stream", f) 2 | 3 | library(RJSONIO); f= "inst/sampleData/web.json"; .Call("R_json_parser_test_stream_str", '[1,2, 3]{"a": [true, false]}') 4 | 5 | library(RJSONIO); f= "inst/sampleData/web.json"; .Call("R_json_parser_test_stream_str", paste(readLines("inst/sampleData/web.json"), collapse = "\n")) 6 | 7 | 8 | library(RJSONIO) 9 | val = list(a = 1:100, b = 100:1, c = rnorm(1000)) 10 | xx = toJSON(val, digits = 16) 11 | ans = .Call("R_json_parser_test_stream_str", xx) 12 | 13 | # in chunks 14 | ans = .Call("R_json_parser_test_stream_chunk", xx) 15 | all.equal(val, ans) 16 | 17 | z = replicate(400, {ans = .Call("R_json_parser_test_stream_chunk", xx); all.equal(val, ans)}) 18 | 19 | 20 | 21 | 22 | library(RJSONIO) 23 | val = list(a = 1:100, b = 100:1, c = rnorm(1000)) 24 | xx = toJSON(val, digits = 16) 25 | 26 | con = textConnection(xx) 27 | getData = function() readLines(con, n = 1) 28 | 29 | ans = .Call("R_json_parser_test_stream_chunk_con", quote(getData())) 30 | all.equal(ans, val) 31 | 32 | 33 | 34 | 35 | library(RJSONIO) 36 | val = list(a = 1:100, b = 100:1, c = rnorm(1000)) 37 | xx = toJSON(val, digits = 16) 38 | 39 | con = textConnection(xx) 40 | e = substitute(readLines(con, n = 1), list(con = con)) 41 | 42 | ans = .Call("R_json_parser_test_stream_chunk_con", e) 43 | all.equal(ans, val) 44 | 45 | 46 | #################### 47 | 48 | library(RJSONIO) 49 | val = list(a = 1:100, b = 100:1, c = rnorm(1000)) 50 | xx = toJSON(val, digits = 16) 51 | 52 | z = replicate(40, { 53 | con = textConnection(xx) 54 | e = substitute(readLines(con, n = 1), list(con = con)) 55 | ans = .Call("R_json_parser_init_from_con", e, NULL, 14L, NULL, TRUE) 56 | all.equal(ans, val) 57 | }) 58 | 59 | table(z) 60 | 61 | # With a callback 62 | library(RJSONIO) 63 | val = list(a = 1:100, b = 100:1, c = rnorm(1000)) 64 | xx = toJSON(val, digits = 16) 65 | 66 | con = textConnection(xx) 67 | e = substitute(readLines(con, n = 1), list(con = con)) 68 | 69 | f = function(x) 70 | print(x) 71 | 72 | ans = .Call("R_json_parser_init_from_con", e, f, 14L, NULL, TRUE) 73 | all.equal(ans, val) 74 | 75 | 76 | library(RJSONIO) 77 | xx = '[1,2, 3]{"a": [true, false]}' 78 | con = textConnection(xx) 79 | e = substitute(readLines(con, n = 1), list(con = con)) 80 | 81 | f = function(x) 82 | print(sum(unlist(x))) 83 | 84 | ans = .Call("R_json_parser_init_from_con", e, f) 85 | 86 | -------------------------------------------------------------------------------- /tests/performance.R: -------------------------------------------------------------------------------- 1 | if(FALSE) { # This works but takes a lot of time. So leave this out 2 | # for default runs. 3 | library(RJSONIO) 4 | 5 | v = rpois(100000, 4) 6 | x = toJSON(v) 7 | 8 | # 0.054 seconds 9 | system.time({ val = fromJSON(x, getNativeSymbolInfo("R_json_IntegerArrayCallback"), 10 | data = rep(as.integer(NA), 100000))}) 11 | 12 | all(v == val) 13 | 14 | # 89.981 So a factor of 1666 15 | system.time({v1 = fromJSON(x)}) 16 | 17 | 18 | # Now if we preallocate a vector with the size of the result 19 | # and fill it with an R callback, we get 1.050. 20 | # This is a factor of 20 relative to the specialized C code. 21 | gen = 22 | function(n = 100000, ans = integer(n)) 23 | { 24 | pos = 1 25 | update = 26 | function(type, val) { 27 | if(type == JSON_T_INTEGER) { 28 | ans[pos] <<- val 29 | pos <<- pos + 1 30 | } 31 | TRUE 32 | } 33 | list(update = update, value = function() ans) 34 | } 35 | h = gen() 36 | system.time({v1 = fromJSON(x, h$update)}) 37 | 38 | 39 | # Now let's use the generic list 40 | # We get 1.130 41 | 42 | gen.list = 43 | function(n = 100000, ans = vector("list", n)) 44 | { 45 | pos = 1 46 | update = 47 | function(type, val) { 48 | if(type == JSON_T_INTEGER) { 49 | ans[pos] <<- val 50 | pos <<- pos + 1 51 | } 52 | TRUE 53 | } 54 | structure(list(update = update, value = function() unlist(ans[1:pos])), 55 | class = "JSONParserHandler") 56 | } 57 | h = gen.list() 58 | system.time({v1 = fromJSON(x, h)}) 59 | 60 | 61 | # 62 | gen.list = 63 | function(n = 100000, ans = vector("list", n)) 64 | { 65 | pos = 1 66 | update = 67 | function(type, val) { 68 | if(type == JSON_T_INTEGER) { 69 | if(length(ans) == pos) 70 | length(ans) <<- 2*pos 71 | ans[pos] <<- val 72 | pos <<- pos + 1 73 | } 74 | TRUE 75 | } 76 | structure(list(update = update, value = function() unlist(ans[1:pos])), 77 | class = "JSONParserHandler") 78 | } 79 | h = gen.list() 80 | system.time({v1 = fromJSON(x, h)}) 81 | 82 | 83 | 84 | ############################################ 85 | 86 | v = rpois(100000, 4) 87 | x = toJSON(v) 88 | 89 | h = RJSONIO:::simpleJSONHandler() 90 | system.time({a = fromJSON(x, h)}) 91 | # user system elapsed 92 | # 59.470 21.693 91.442 93 | system.time({a = fromJSON(x)}) 94 | # user system elapsed 95 | # 3.899 0.117 4.415 96 | system.time({a = fromJSON(x, default.size = 10000)}) 97 | # user system elapsed 98 | # 3.957 0.116 4.465 99 | system.time({a = fromJSON(x, default.size = 100000)}) 100 | } 101 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONAllocator.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_ALLOCATOR_H 2 | #define JSON_ALLOCATOR_H 3 | 4 | #include "JSONStats.h" 5 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 6 | 7 | #include 8 | 9 | //need these for the json_nothrow 10 | #include "JSONDefs/Visual_C.h" 11 | #include "JSONDefs/GNU_C.h" 12 | #include "JSONDefs/Unknown_C.h" 13 | 14 | class JSONAllocatorRelayer { 15 | public: 16 | static void * alloc(size_t bytes) json_nothrow json_hot; 17 | static void dealloc(void * ptr) json_nothrow json_hot; 18 | }; 19 | 20 | template class json_allocator; 21 | 22 | // specialize for void: 23 | template <> class json_allocator { 24 | public: 25 | typedef void* pointer; 26 | typedef const void* const_pointer; 27 | // reference to void members are impossible. 28 | typedef void value_type; 29 | template struct rebind { typedef json_allocator other; }; 30 | }; 31 | 32 | template class json_allocator { 33 | public: 34 | typedef size_t size_type; 35 | typedef ptrdiff_t difference_type; 36 | typedef T* pointer; 37 | typedef const T* const_pointer; 38 | typedef T& reference; 39 | typedef const T& const_reference; 40 | typedef T value_type; 41 | template struct rebind { typedef json_allocator other; }; 42 | 43 | //LIBJSON_OBJECT(json_allocator); 44 | 45 | inline json_allocator() json_nothrow { 46 | //LIBJSON_CTOR; 47 | } 48 | inline json_allocator(const json_allocator&) json_nothrow { 49 | //LIBJSON_COPY_CTOR; 50 | } 51 | template inline json_allocator(const json_allocator&) json_nothrow { 52 | //LIBJSON_COPY_CTOR; 53 | } 54 | inline ~json_allocator() json_nothrow { 55 | //LIBJSON_DTOR; 56 | } 57 | 58 | inline pointer address(reference x) const { return &x; } 59 | inline const_pointer address(const_reference x) const { return &x; } 60 | 61 | inline pointer allocate(size_type n, json_allocator::const_pointer = 0) json_hot { 62 | return (pointer)JSONAllocatorRelayer::alloc(n * sizeof(T)); 63 | } 64 | inline void deallocate(pointer p, size_type) json_hot { 65 | JSONAllocatorRelayer::dealloc(p); 66 | } 67 | 68 | inline size_type max_size() const json_nothrow { return 0xEFFFFFFF; } 69 | 70 | inline void construct(pointer p, const T& val){ 71 | new(p)T(val); 72 | }; 73 | inline void destroy(pointer p){ 74 | ((T*)p) -> ~T(); 75 | } 76 | }; 77 | 78 | template inline bool operator==(const json_allocator&, const json_allocator&) json_nothrow { return true; } 79 | template inline bool operator!=(const json_allocator&, const json_allocator&) json_nothrow { return false; } 80 | 81 | #endif 82 | #endif 83 | -------------------------------------------------------------------------------- /man/readJSONStream.Rd: -------------------------------------------------------------------------------- 1 | \name{readJSONStream} 2 | \alias{readJSONStream} 3 | \title{Read JSON from a Connection/Stream} 4 | \description{ 5 | This function is capable of reading and processing 6 | JSON content from a "stream". This is most likely 7 | to be from an R connection, but can be an arbitrary 8 | source of JSON content. 9 | The idea is that the parser will pull partial data from the 10 | source and process it immediately, and then return to 11 | retrieve more data. This allows the parser to work on 12 | the JSON content without it all being in memory at one 13 | time. This can save a significant amount of memory 14 | and make some computations feasible which would not 15 | be if we had to first read all of the JSON and then 16 | process it. 17 | } 18 | \usage{ 19 | readJSONStream(con, cb = NULL, simplify = Strict, nullValue = NULL, 20 | simplifyWithNames = TRUE) 21 | } 22 | \arguments{ 23 | \item{con}{a connection object from which we will read the JSON 24 | content. This can also be any R expression that returns 25 | a string. This allows a caller to get content from any source, 26 | not just a connection. 27 | } 28 | \item{cb}{ 29 | an optional callback function that is invoked 30 | for each top-level JSON object in the stream. Typically there 31 | will only be one such top-level object and so the callback 32 | is not really needed as the default is to return that top-level 33 | object from \code{readJSONStream}. 34 | However, if there are multiple top-level JSON objects in the stream, 35 | this callback function can process them, e.g. merge them, collapse 36 | the contents. 37 | } 38 | \item{simplify}{same as for \code{\link{fromJSON}}.} 39 | \item{nullValue}{same as for \code{\link{fromJSON}}.} 40 | \item{simplifyWithNames}{same as for \code{\link{fromJSON}}.} 41 | } 42 | \value{ 43 | By default, this returns the top-level JSON object in the stream. 44 | } 45 | \references{ 46 | libjson and the \code{JSONSTREAM} facilities. 47 | } 48 | \author{Duncan Temple Lang} 49 | 50 | \seealso{ 51 | \code{\link{fromJSON}} and its methods, 52 | specifically the method for a connection. 53 | } 54 | \examples{ 55 | \dontrun{ 56 | xx = '[1,2, 3]{"a": [true, false]}' 57 | con = textConnection(xx) 58 | 59 | f = function(x) 60 | print(sum(unlist(x))) 61 | 62 | readJSONStream(con, f) 63 | 64 | # The callback function can be anonymous 65 | con = textConnection(xx) 66 | readJSONStream(con, function(x) 67 | print(sum(unlist(x)))) 68 | 69 | 70 | 71 | gen = 72 | function() { 73 | ans <- 0 74 | list(update = function(x) ans <<- ans + sum(unlist(x)), 75 | value = function() ans) 76 | } 77 | g = gen() 78 | con = textConnection(xx) 79 | readJSONStream(con, g$update) 80 | } 81 | } 82 | \keyword{IO} 83 | 84 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONStream.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_STREAM_H 2 | #define LIBJSON_GUARD_STREAM_H 3 | 4 | #include "JSONDebug.h" 5 | 6 | #ifdef JSON_STREAM 7 | 8 | #ifdef JSON_LESS_MEMORY 9 | #ifdef __GNUC__ 10 | #pragma pack(push, 1) 11 | #elif _MSC_VER 12 | #pragma pack(push, JSONStream_pack, 1) 13 | #endif 14 | #endif 15 | 16 | #ifdef JSON_MEMORY_CALLBACKS 17 | #include "JSONMemory.h" 18 | #endif 19 | 20 | #ifndef JSON_LIBRARY 21 | class JSONNode; //foreward declaration 22 | typedef void (*json_stream_callback_t)(JSONNode &, void *); 23 | #endif 24 | 25 | class JSONStream { 26 | public: 27 | LIBJSON_OBJECT(JSONStream); 28 | JSONStream(json_stream_callback_t call_p, json_stream_e_callback_t call_e = NULL, void * callbackIdentifier = JSONSTREAM_SELF) json_nothrow; 29 | JSONStream(const JSONStream & orig) json_nothrow; 30 | JSONStream & operator =(const JSONStream & orig) json_nothrow; 31 | ~JSONStream(void) json_nothrow { LIBJSON_DTOR; } 32 | #ifdef JSON_LIBRARY 33 | JSONStream & operator << (const json_char * str) json_nothrow; 34 | #else 35 | JSONStream & operator << (const json_string & str) json_nothrow; 36 | #endif 37 | 38 | static void deleteJSONStream(JSONStream * stream) json_nothrow { 39 | #ifdef JSON_MEMORY_CALLBACKS 40 | stream -> ~JSONStream(); 41 | libjson_free(stream); 42 | #else 43 | delete stream; 44 | #endif 45 | } 46 | 47 | static JSONStream * newJSONStream(json_stream_callback_t callback, json_stream_e_callback_t call_e, void * callbackIdentifier) json_nothrow { 48 | #ifdef JSON_MEMORY_CALLBACKS 49 | return new(json_malloc(1)) JSONStream(callback, call_e, callbackIdentifier); 50 | #else 51 | return new JSONStream(callback, call_e, callbackIdentifier); 52 | #endif 53 | } 54 | 55 | inline void reset() json_nothrow { 56 | state = true; 57 | buffer.clear(); 58 | } 59 | JSON_PRIVATE 60 | inline void * getIdentifier(void) json_nothrow { 61 | if (callback_identifier == JSONSTREAM_SELF){ 62 | return (void*)this; 63 | } 64 | return callback_identifier; 65 | } 66 | 67 | #if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY))) 68 | template 69 | static size_t FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow json_read_priority; 70 | #else 71 | static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow json_read_priority; 72 | #endif 73 | 74 | void parse(void) json_nothrow; 75 | json_string buffer; 76 | json_stream_callback_t call; 77 | json_stream_e_callback_t err_call; 78 | void * callback_identifier; 79 | bool state BITS(1); 80 | }; 81 | 82 | #ifdef JSON_LESS_MEMORY 83 | #ifdef __GNUC__ 84 | #pragma pack(pop) 85 | #elif _MSC_VER 86 | #pragma pack(pop, JSONStream_pack) 87 | #endif 88 | #endif 89 | 90 | #endif 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /configure.in: -------------------------------------------------------------------------------- 1 | AC_INIT(src/rlibjson.c) 2 | 3 | AC_ARG_WITH(local-libjson, [use the libjson code that comes with this package rather than 4 | looking for an installed version on the system], 5 | USE_LOCAL=$withval) 6 | 7 | AC_ARG_WITH(prefix, [the name of the directory into which the libjson include files and library were installed], 8 | [ LIBJSON_PREFIX=$withval; if test -z "$USE_LOCAL" ; then USE_LOCAL="never" ; fi], 9 | [ LIBJSON_PREFIX="/usr/local" ; 10 | ]) 11 | 12 | ORIG_USE_LOCAL="$USE_LOCAL" 13 | 14 | if test -z "$USE_LOCAL" || test "$USE_LOCAL" = "no" ; then 15 | echo "Trying to find libjson.h header file" 16 | CPPFLAGS="$CPPFLAGS -I$LIBJSON_PREFIX/include" 17 | AC_TRY_COMPILE( 18 | [#include ], 19 | [JSONNODE *ptr = json_parse("[1, 3]");], 20 | [USE_LOCAL=1; echo "Found system libjson header file libjson.h"], [] 21 | ) 22 | 23 | 24 | if test -n "$USE_LOCAL" && ! test "$USE_LOCAL" = "no"; then 25 | echo "Trying to link against libjson" 26 | LIBS="$LIBS -L$LIBJSON_PREFIX/lib -ljson" 27 | AC_TRY_LINK( 28 | [#include ], 29 | [JSONNODE *ptr = json_parse("[1, 3]");], 30 | [USE_LOCAL=1; echo "linked against libjson"], 31 | [USE_LOCAL=""; echo "Failed to link against system libjson"] 32 | ) 33 | fi 34 | 35 | fi 36 | 37 | echo "USE_LOCAL = \"$USE_LOCAL\"" 38 | 39 | 40 | if test -n "$USE_LOCAL" && ! test "$USE_LOCAL" = "" && ! test "$USE_LOCAL" = "yes" && test -n "$LIBJSON_PREFIX" ; then 41 | LIBJSON_CFLAGS="-I${LIBJSON_PREFIX}/include -I." # -I${LIBJSON_PREFIX}/Source 42 | LIBJSON_LIBS="-L${LIBJSON_PREFIX}/lib -ljson" 43 | CPP_FILES="" 44 | else 45 | if test "$ORIG_USE_LOCAL" = "never" ; then 46 | echo " ****************" 47 | echo "Couldn't find libjson on system so would use the local version of libjson in this package but you asked not to" 48 | echo " ****************" 49 | exit 1; 50 | fi 51 | if test -z "${LIBJSON_SRC}" ; then 52 | LIBJSON_SRC="src/libjson/Source" 53 | LIBJSON_CFLAGS="-I. -Ilibjson -Ilibjson/Source" 54 | else 55 | LIBJSON_CFLAGS="-I${LIBJSON_SRC}/.. -I${LIBJSON_SRC}" 56 | fi 57 | MINOR_VERSION=`grep 'define __LIBJSON_MINOR__' $LIBJSON_SRC/JSONDefs.h | sed -e 's/.* __LIBJSON_MINOR__ //'` 58 | if test "$MINOR_VERSION" = "0" ; then 59 | LIBJSON_CFLAGS="${LIBJSON_CFLAGS} -DJSON_NO_EXCEPTIONS=1" 60 | else 61 | LIBJSON_CFLAGS="${LIBJSON_CFLAGS} -DNEW_JSON_NEW_STREAM" 62 | fi 63 | echo "Minor Version: $MINOR_VERSION" 64 | echo "Using local libjson code. Copying files from ${LIBJSON_SRC}" 65 | echo "`pwd`" 66 | CPP_FILES="`(cd ${LIBJSON_SRC}; ls *.cpp)`" 67 | echo "$CPP_FILES" 68 | cp ${LIBJSON_SRC}/*.cpp src/ 69 | cp src/libjson/JSONOptions.h src/ 70 | fi 71 | 72 | AC_SUBST(CPP_FILES) 73 | AC_SUBST(LIBJSON_CFLAGS) 74 | AC_SUBST(LIBJSON_LIBS) 75 | 76 | AC_OUTPUT(src/Makevars cleanup) 77 | chmod +x cleanup 78 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONWorker.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_WORKER_H 2 | #define JSON_WORKER_H 3 | 4 | #include "JSONNode.h" 5 | #include "JSONSharedString.h" 6 | 7 | class JSONWorker { 8 | public: 9 | static json_string RemoveWhiteSpaceAndComments(const json_string & value_t, bool escapeQuotes) json_nothrow json_read_priority; 10 | static json_char * RemoveWhiteSpaceAndCommentsC(const json_string & value_t, bool escapeQuotes) json_nothrow json_read_priority; 11 | 12 | #ifdef JSON_READ_PRIORITY 13 | static JSONNode parse(const json_string & json) json_throws(std::invalid_argument) json_read_priority; 14 | static JSONNode parse_unformatted(const json_string & json) json_throws(std::invalid_argument) json_read_priority; 15 | 16 | static JSONNode _parse_unformatted(const json_char * json, const json_char * const end) json_throws(std::invalid_argument) json_read_priority; 17 | 18 | static json_char * RemoveWhiteSpace(const json_string & value_t, size_t & len, bool escapeQuotes) json_nothrow json_read_priority; 19 | 20 | static void DoArray(const internalJSONNode * parent, const json_string & value_t) json_nothrow json_read_priority; 21 | static void DoNode(const internalJSONNode * parent, const json_string & value_t) json_nothrow json_read_priority; 22 | 23 | #ifdef JSON_LESS_MEMORY 24 | #define NAME_ENCODED this, true 25 | #define STRING_ENCODED this, false 26 | static json_string FixString(const json_string & value_t, const internalJSONNode * flag, bool which) json_nothrow json_read_priority; 27 | #else 28 | #define NAME_ENCODED _name_encoded 29 | #define STRING_ENCODED _string_encoded 30 | static json_string FixString(const json_string & value_t, bool & flag) json_nothrow json_read_priority; 31 | #endif 32 | #endif 33 | 34 | #if defined(JSON_READ_PRIORITY) || defined(JSON_STREAM) 35 | #if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY))) 36 | template 37 | static size_t FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow json_read_priority; 38 | #else 39 | static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow json_read_priority; 40 | #endif 41 | #endif 42 | static void UnfixString(const json_string & value_t, bool flag, json_string & res) json_nothrow; 43 | JSON_PRIVATE 44 | #ifdef JSON_READ_PRIORITY 45 | static json_char Hex(const json_char * & pos) json_nothrow; 46 | static json_uchar UTF8(const json_char * & pos, const json_char * const end) json_nothrow; 47 | #endif 48 | #ifdef JSON_ESCAPE_WRITES 49 | static json_string toUTF8(json_uchar p) json_nothrow; 50 | #endif 51 | #ifdef JSON_UNICODE 52 | static void UTF(const json_char * & pos, json_string & result, const json_char * const end) json_nothrow; 53 | #ifdef JSON_ESCAPE_WRITES 54 | static json_string toSurrogatePair(json_uchar pos) json_nothrow; 55 | #endif 56 | #endif 57 | #ifdef JSON_READ_PRIORITY 58 | static void SpecialChar(const json_char * & pos, const json_char * const end, json_string & res) json_nothrow; 59 | static void NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, bool array) json_nothrow; 60 | #endif 61 | private: 62 | JSONWorker(void); 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONStats.h: -------------------------------------------------------------------------------- 1 | #ifndef TestSuite_JSONStats_h 2 | #define TestSuite_JSONStats_h 3 | 4 | #include "../../JSONOptions.h" 5 | 6 | #if defined(JSON_UNIT_TEST) || defined(JSON_DEBUG) 7 | #define LIBJSON_OBJECT(name)\ 8 | static size_t & getCtorCounter(void){\ 9 | static size_t count = 0;\ 10 | static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\ 11 | return count;\ 12 | }\ 13 | static size_t & getCopyCtorCounter(void){\ 14 | static size_t count = 0;\ 15 | static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\ 16 | return count;\ 17 | }\ 18 | static size_t & getAssignmentCounter(void){\ 19 | static size_t count = 0;\ 20 | static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\ 21 | return count;\ 22 | }\ 23 | static size_t & getDtorCounter(void){\ 24 | static size_t count = 0;\ 25 | static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\ 26 | return count;\ 27 | } 28 | #define LIBJSON_CTOR getCtorCounter() += 1 29 | #define LIBJSON_COPY_CTOR getCopyCtorCounter() += 1 30 | #define LIBJSON_ASSIGNMENT getAssignmentCounter() += 1 31 | #define LIBJSON_DTOR getDtorCounter() += 1 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | class JSONStats { 38 | public: 39 | ~JSONStats(void){ 40 | std::map & mymap = getMapper(); 41 | std::map::iterator b = mymap.begin(); 42 | std::map::iterator e = mymap.end(); 43 | std::cout << "Counters for libjson:" << std::endl; 44 | for(; b != e; ++b){ 45 | std::cout << " " << b -> second -> _name << std::endl; 46 | std::cout << " Constructor: " << b -> second -> _cTor() << std::endl; 47 | std::cout << " Copy Constructor: " << b -> second -> _ccTor() << std::endl; 48 | std::cout << " Assignment: " << b -> second -> _assign() << std::endl; 49 | std::cout << " Destructor: " << b -> second -> _dTor() << std::endl; 50 | delete b -> second; 51 | } 52 | } 53 | 54 | typedef size_t & (*getCounter_m)(void); 55 | struct objectStructure { 56 | objectStructure(getCounter_m cTor, getCounter_m ccTor, getCounter_m assign, getCounter_m dTor, const std::string & name): 57 | _cTor(cTor), _ccTor(ccTor), _assign(assign), _dTor(dTor), _name(name){} 58 | std::string _name; 59 | getCounter_m _cTor; 60 | getCounter_m _ccTor; 61 | getCounter_m _assign; 62 | getCounter_m _dTor; 63 | }; 64 | static int setCallbacks(getCounter_m cTor, getCounter_m ccTor, getCounter_m assign, getCounter_m dtor, const std::string & name){ 65 | getMapper()[cTor] = new objectStructure (cTor, ccTor, assign, dtor, name); 66 | return 0; 67 | } 68 | 69 | static std::map & getMapper(void) { 70 | static std::map mymap; 71 | return mymap; 72 | } 73 | }; 74 | #else 75 | #define LIBJSON_OBJECT(name) 76 | #define LIBJSON_CTOR (void)0 77 | #define LIBJSON_DTOR (void)0 78 | #define LIBJSON_COPY_CTOR (void)0 79 | #define LIBJSON_ASSIGNMENT (void)0 80 | typedef int JSONStats; 81 | #endif 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /inst/sampleData/web.json: -------------------------------------------------------------------------------- 1 | {"web-app": { 2 | "servlet": [ 3 | { 4 | "servlet-name": "cofaxCDS", 5 | "servlet-class": "org.cofax.cds.CDSServlet", 6 | "init-param": { 7 | "configGlossary:installationAt": "Philadelphia, PA", 8 | "configGlossary:adminEmail": "ksm@pobox.com", 9 | "configGlossary:poweredBy": "Cofax", 10 | "configGlossary:poweredByIcon": "/images/cofax.gif", 11 | "configGlossary:staticPath": "/content/static", 12 | "templateProcessorClass": "org.cofax.WysiwygTemplate", 13 | "templateLoaderClass": "org.cofax.FilesTemplateLoader", 14 | "templatePath": "templates", 15 | "templateOverridePath": "", 16 | "defaultListTemplate": "listTemplate.htm", 17 | "defaultFileTemplate": "articleTemplate.htm", 18 | "useJSP": false, 19 | "jspListTemplate": "listTemplate.jsp", 20 | "jspFileTemplate": "articleTemplate.jsp", 21 | "cachePackageTagsTrack": 200, 22 | "cachePackageTagsStore": 200, 23 | "cachePackageTagsRefresh": 60, 24 | "cacheTemplatesTrack": 100, 25 | "cacheTemplatesStore": 50, 26 | "cacheTemplatesRefresh": 15, 27 | "cachePagesTrack": 200, 28 | "cachePagesStore": 100, 29 | "cachePagesRefresh": 10, 30 | "cachePagesDirtyRead": 10, 31 | "searchEngineListTemplate": "forSearchEnginesList.htm", 32 | "searchEngineFileTemplate": "forSearchEngines.htm", 33 | "searchEngineRobotsDb": "WEB-INF/robots.db", 34 | "useDataStore": true, 35 | "dataStoreClass": "org.cofax.SqlDataStore", 36 | "redirectionClass": "org.cofax.SqlRedirection", 37 | "dataStoreName": "cofax", 38 | "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", 39 | "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", 40 | "dataStoreUser": "sa", 41 | "dataStorePassword": "dataStoreTestQuery", 42 | "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", 43 | "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", 44 | "dataStoreInitConns": 10, 45 | "dataStoreMaxConns": 100, 46 | "dataStoreConnUsageLimit": 100, 47 | "dataStoreLogLevel": "debug", 48 | "maxUrlLength": 500}}, 49 | { 50 | "servlet-name": "cofaxEmail", 51 | "servlet-class": "org.cofax.cds.EmailServlet", 52 | "init-param": { 53 | "mailHost": "mail1", 54 | "mailHostOverride": "mail2"}}, 55 | { 56 | "servlet-name": "cofaxAdmin", 57 | "servlet-class": "org.cofax.cds.AdminServlet"}, 58 | 59 | { 60 | "servlet-name": "fileServlet", 61 | "servlet-class": "org.cofax.cds.FileServlet"}, 62 | { 63 | "servlet-name": "cofaxTools", 64 | "servlet-class": "org.cofax.cms.CofaxToolsServlet", 65 | "init-param": { 66 | "templatePath": "toolstemplates/", 67 | "log": 1, 68 | "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", 69 | "logMaxSize": "", 70 | "dataLog": 1, 71 | "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", 72 | "dataLogMaxSize": "", 73 | "removePageCache": "/content/admin/remove?cache=pages&id=", 74 | "removeTemplateCache": "/content/admin/remove?cache=templates&id=", 75 | "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", 76 | "lookInContext": 1, 77 | "adminGroupID": 4, 78 | "betaServer": true}}], 79 | "servlet-mapping": { 80 | "cofaxCDS": "/", 81 | "cofaxEmail": "/cofaxutil/aemail/*", 82 | "cofaxAdmin": "/admin/*", 83 | "fileServlet": "/static/*", 84 | "cofaxTools": "/tools/*"}, 85 | 86 | "taglib": { 87 | "taglib-uri": "cofax.tld", 88 | "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} 89 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONGlobals.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_GLOBALS_H 2 | #define JSON_GLOBALS_H 3 | 4 | #include "JSONDefs.h" 5 | 6 | /* 7 | * The use of singletons for globals makes globals not 8 | * actually be initialized until it is first needed, this 9 | * makes the library faster to load, and have a smaller 10 | * memory footprint 11 | */ 12 | 13 | #define json_global_decl(TYPE, NAME, VALUE) \ 14 | class jsonSingleton ## NAME { \ 15 | public: \ 16 | inline static TYPE & getValue() json_nothrow { \ 17 | static jsonSingleton ## NAME single; \ 18 | return single.val; \ 19 | } \ 20 | protected: \ 21 | inline jsonSingleton ## NAME() json_nothrow : val(VALUE) {} \ 22 | TYPE val; \ 23 | } 24 | 25 | #define json_global_decl_strconfig(TYPE, NAME, VALUE) \ 26 | class jsonSingleton ## NAME { \ 27 | public: \ 28 | inline static TYPE & getValue() json_nothrow { \ 29 | static jsonSingleton ## NAME single; \ 30 | return single.val; \ 31 | } \ 32 | protected: \ 33 | inline jsonSingleton ## NAME() json_nothrow { \ 34 | const std::string tmp = std::string(VALUE); \ 35 | val = json_string(tmp.begin(), tmp.end()); \ 36 | } \ 37 | TYPE val; \ 38 | } 39 | 40 | #define json_global(NAME) jsonSingleton ## NAME::getValue() 41 | 42 | #include 43 | json_global_decl(json_string, EMPTY_JSON_STRING, ); 44 | json_global_decl(std::string, EMPTY_STD_STRING, ); 45 | 46 | json_global_decl(json_string, CONST_TRUE, JSON_TEXT("true")); 47 | json_global_decl(json_string, CONST_FALSE, JSON_TEXT("false")); 48 | json_global_decl(json_string, CONST_NULL, JSON_TEXT("null")); 49 | 50 | #ifndef JSON_NEWLINE 51 | json_global_decl(json_string, NEW_LINE, JSON_TEXT("\n")); 52 | #else 53 | json_global_decl_strconfig(json_string, NEW_LINE, JSON_NEWLINE); 54 | #endif 55 | 56 | #ifdef JSON_WRITE_BASH_COMMENTS 57 | json_global_decl(json_string, SINGLELINE_COMMENT, JSON_TEXT("#")); 58 | #else 59 | json_global_decl(json_string, SINGLELINE_COMMENT, JSON_TEXT("//")); 60 | #endif 61 | 62 | #ifdef JSON_INDENT 63 | json_global_decl_strconfig(json_string, INDENT, JSON_INDENT); 64 | #endif 65 | 66 | #ifdef JSON_MUTEX_CALLBACKS 67 | #include 68 | json_global_decl(JSON_MAP(void *, unsigned int), MUTEX_MANAGER, ); 69 | json_global_decl(JSON_MAP(int, JSON_MAP(void *, unsigned int) ), THREAD_LOCKS, ); 70 | #endif 71 | 72 | #ifdef JSON_LIBRARY 73 | #ifdef JSON_MEMORY_MANAGE 74 | #include "JSONMemory.h" 75 | json_global_decl(auto_expand, STRING_HANDLER, ); 76 | json_global_decl(auto_expand_node, NODE_HANDLER, ); 77 | #ifdef JSON_STREAM 78 | json_global_decl(auto_expand_stream, STREAM_HANDLER, ); 79 | #endif 80 | #endif 81 | #endif 82 | 83 | //These are common error responses 84 | json_global_decl(json_string, ERROR_TOO_LONG, JSON_TEXT("Exceeding JSON_SECURITY_MAX_STRING_LENGTH")); 85 | json_global_decl(json_string, ERROR_UNKNOWN_LITERAL, JSON_TEXT("Unknown JSON literal: ")); 86 | json_global_decl(json_string, ERROR_NON_CONTAINER, JSON_TEXT("Calling container method on non-container: ")); 87 | json_global_decl(json_string, ERROR_NON_ITERATABLE, JSON_TEXT("Calling iterator method on non-iteratable: ")); 88 | json_global_decl(json_string, ERROR_NULL_IN_CHILDREN, JSON_TEXT("a null pointer within the children")); 89 | json_global_decl(json_string, ERROR_UNDEFINED, JSON_TEXT("Undefined results: ")); 90 | json_global_decl(json_string, ERROR_LOWER_RANGE, JSON_TEXT(" is outside the lower range of ")); 91 | json_global_decl(json_string, ERROR_UPPER_RANGE, JSON_TEXT(" is outside the upper range of ")); 92 | json_global_decl(json_string, ERROR_NOT_BASE64, JSON_TEXT("Not base64")); 93 | json_global_decl(json_string, ERROR_OUT_OF_MEMORY, JSON_TEXT("Out of memory")); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONChildren.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONChildren.h" 2 | #include "JSONNode.h" 3 | 4 | /* 5 | * reserves a certain number of bytes, in memory saving mode it creates a special 6 | * type of child container that will not autoshrink 7 | */ 8 | void jsonChildren::reserve2(jsonChildren *& mine, json_index_t amount) json_nothrow { 9 | if (mine -> array != 0){ 10 | if (mine -> mycapacity < amount){ 11 | mine -> inc(amount - mine -> mycapacity); 12 | #ifdef JSON_LESS_MEMORY 13 | mine = jsonChildren_Reserved::newChildren_Reserved(mine, amount); 14 | #endif 15 | } 16 | } else { 17 | mine -> reserve(amount); 18 | } 19 | } 20 | 21 | void jsonChildren::inc(void) json_nothrow { 22 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null inc")); 23 | if (json_unlikely(mysize == mycapacity)){ //it's full 24 | if (json_unlikely(mycapacity == 0)){ //the array hasn't been created yet 25 | JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); 26 | #ifdef JSON_LESS_MEMORY 27 | array = json_malloc(1); 28 | mycapacity = 1; 29 | #else 30 | array = json_malloc(8); //8 seems average for JSON, and it's only 64 bytes 31 | mycapacity = 8; 32 | #endif 33 | } else { 34 | #ifdef JSON_LESS_MEMORY 35 | mycapacity += 1; //increment the size of the array 36 | #else 37 | mycapacity <<= 1; //double the size of the array 38 | #endif 39 | array = json_realloc(array, mycapacity); 40 | } 41 | } 42 | } 43 | 44 | 45 | void jsonChildren::inc(json_index_t amount) json_nothrow { 46 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null inc(amount)")); 47 | if (json_unlikely(amount == 0)) return; 48 | if (json_likely(mysize + amount >= mycapacity)){ //it's full 49 | if (json_unlikely(mycapacity == 0)){ //the array hasn't been created yet 50 | JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); 51 | #ifdef JSON_LESS_MEMORY 52 | array = json_malloc(amount); 53 | mycapacity = amount; 54 | #else 55 | array = json_malloc(amount > 8 ? amount : 8); //8 seems average for JSON, and it's only 64 bytes 56 | mycapacity = amount > 8 ? amount : 8; 57 | #endif 58 | } else { 59 | #ifdef JSON_LESS_MEMORY 60 | mycapacity = mysize + amount; //increment the size of the array 61 | #else 62 | while(mysize + amount > mycapacity){ 63 | mycapacity <<= 1; //double the size of the array 64 | } 65 | #endif 66 | array = json_realloc(array, mycapacity); 67 | } 68 | } 69 | } 70 | 71 | //actually deletes everything within the vector, this is safe to do on an empty or even a null array 72 | void jsonChildren::deleteAll(void) json_nothrow { 73 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null deleteAll")); 74 | json_foreach(this, runner){ 75 | JSON_ASSERT(*runner != (JSONNode *) JSON_TEXT('\0'), JSON_TEXT("a null pointer within the children")); 76 | JSONNode::deleteJSONNode(*runner); //this is why I can't do forward declaration 77 | } 78 | } 79 | 80 | void jsonChildren::doerase(JSONNode ** position, json_index_t number) json_nothrow { 81 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null doerase")); 82 | JSON_ASSERT(array != 0, JSON_TEXT("erasing something from a null array 2")); 83 | JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 2")); 84 | JSON_ASSERT(position + number <= array + mysize, JSON_TEXT("erasing out of bounds 2")); 85 | if (position + number >= array + mysize){ 86 | mysize = (json_index_t)(position - array); 87 | #ifndef JSON_ISO_STRICT 88 | JSON_ASSERT((long long)position - (long long)array >= 0, JSON_TEXT("doing negative allocation")); 89 | #endif 90 | } else { 91 | std::memmove(position, position + number, (mysize - (position - array) - number) * sizeof(JSONNode *)); 92 | mysize -= number; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /inst/doc/missingValues.Rdb: -------------------------------------------------------------------------------- 1 | 2 |
4 | 5 | 6 | 7 | JSON, null and <r:na/> 8 | 9 | DuncanTemple Lang 10 | University of California at Davis 11 | Department of Statistics 12 | 13 | 14 | 15 | 16 |
17 | Limitations of JSON regarding the meaning of null 18 | 19 | 20 | JavaScript Object Notation (JSON) is a convenient format for 21 | representing data and facilitates transferring data between 22 | applications. It is widely used in different applications, Web 23 | services and other contexts. As such, it is useful for R to be able 24 | to import and export data in this format. Unfortunately, JSON is a 25 | little too simple and cannot faithfully represent all of the types and 26 | values in R. Most specifically, there is no way to support , 27 | Inf or NaN. Typically, these 28 | values are represented in JSON as "null". However, that is also used 29 | to represent a null object. So there is ambiguity in how we interpret 30 | null in JSON. 31 | We don't know whether it is , NaN, Inf or in R. 32 | This many-to-one mapping results in a loss of information. 33 | 34 | 35 | In spite of the shortcomings of the format, we can still work with 36 | JSON. However, how we convert null values to R and how we 37 | convert values from R is not automatic and uniquely defined. 38 | For that reason, the caller must control how these are mapped. 39 | We provide some mechanisms to do this in the 40 | fromJSON and toJSON functions. 41 | 42 | 43 | When converting R objects to JSON via toJSON, 44 | one can specify how to map values to JSON. 45 | One provides a value for the parameter .na 46 | to control this. 47 | For example, suppose we want to transform the R list 48 | 49 | x = list(1, 2, NA, c(TRUE, NA, FALSE)) 50 | 51 | to JSON and want values to map to null. 52 | We can achieve this with 53 | 54 | toJSON(x, .na = "null") 55 | 56 | 57 | 58 | In some applications, we represent a missing value with a fixed number that is unlikely 59 | to occur in actual data, e.g. -99999. 60 | We can map values to such a number with 61 | 62 | toJSON(list(1, 2, list(NA)), .na = -99999) 63 | 64 | 65 | 66 | Now consider round-tripping , e.g. 67 | 68 | o = toJSON ( NA ) 69 | 70 | [1] "[ null ]" 71 | 72 | fromJSON( o ) 73 | 77 | 78 | So we have lost information. 79 | 80 | 81 | 82 | 83 | We can correct this loss of information by 84 | specifying how to map null values in JSON 85 | to R values. We use the nullValue 86 | 87 | fromJSON( toJSON ( NA ), nullValue = NA) 88 | 89 | Again, here we as the caller of fromJSON 90 | (and also toJSON) we are providing 91 | information about how to transfer the null value from JSON to R. 92 | Only we know what it means in this case. 93 | If we knew that the null corresponded to Inf, 94 | we could specify that: 95 | 96 | fromJSON( "[null]", nullValue = Inf) 97 | 98 | 99 | 100 | Where this mechanism breaks down is when we have multiple 101 | null values in our JSON content and they map to different 102 | R values, e.g. , and NaN. 103 | The nullValue parameter is a global replacement for 104 | null entries in the JSON. To adaptively process these null 105 | entries in a context specific manner, we have to use a customized 106 | parser. We can do this by providing an R function as the 107 | callback handler for the JSON parser. 108 | 109 | 110 | 111 |
112 |
-------------------------------------------------------------------------------- /utfTest/json.c: -------------------------------------------------------------------------------- 1 | /* main.c */ 2 | 3 | /* 4 | This program demonstrates a simple application of JSON_parser. It reads 5 | a JSON text from STDIN, producing an error message if the text is rejected. 6 | 7 | % JSON_parser 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "JSON_parser.h" 17 | 18 | static int print(void* ctx, int type, const JSON_value* value); 19 | 20 | int main(int argc, char* argv[]) { 21 | int count = 0; 22 | FILE* input; 23 | 24 | JSON_config config; 25 | 26 | struct JSON_parser_struct* jc = NULL; 27 | 28 | init_JSON_config(&config); 29 | 30 | config.depth = 20; 31 | config.callback = &print; 32 | config.allow_comments = 1; 33 | config.handle_floats_manually = 0; 34 | 35 | /* Important! Set locale before parser is created.*/ 36 | if (argc >= 2) { 37 | if (!setlocale(LC_ALL, argv[1])) { 38 | fprintf(stderr, "Failed to set locale to '%s'\n", argv[1]); 39 | } 40 | } else { 41 | fprintf(stderr, "No locale provided, C locale is used\n"); 42 | } 43 | 44 | jc = new_JSON_parser(&config); 45 | 46 | input = stdin; 47 | for (; input ; ++count) { 48 | int next_char = fgetc(input); 49 | if(count == 1601) 50 | fprintf(stderr, "1061\n"); 51 | if (next_char <= 0) { 52 | break; 53 | } 54 | fprintf(stderr, "%d) %c %u\n", count, next_char, (unsigned int) next_char);fflush(stderr); 55 | if (!JSON_parser_char(jc, next_char)) { 56 | delete_JSON_parser(jc); 57 | fprintf(stderr, "JSON_parser_char: syntax error, byte %d\n", count); 58 | return 1; 59 | } 60 | } 61 | if (!JSON_parser_done(jc)) { 62 | delete_JSON_parser(jc); 63 | fprintf(stderr, "JSON_parser_end: syntax error\n"); 64 | return 1; 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | static size_t s_Level = 0; 71 | 72 | static const char* s_pIndention = " "; 73 | 74 | static int s_IsKey = 0; 75 | 76 | static void print_indention() 77 | { 78 | size_t i; 79 | 80 | for (i = 0; i < s_Level; ++i) { 81 | printf(s_pIndention); 82 | } 83 | } 84 | 85 | 86 | static int print(void* ctx, int type, const JSON_value* value) 87 | { 88 | switch(type) { 89 | case JSON_T_ARRAY_BEGIN: 90 | if (!s_IsKey) print_indention(); 91 | s_IsKey = 0; 92 | printf("[\n"); 93 | ++s_Level; 94 | break; 95 | case JSON_T_ARRAY_END: 96 | assert(!s_IsKey); 97 | if (s_Level > 0) --s_Level; 98 | print_indention(); 99 | printf("]\n"); 100 | break; 101 | case JSON_T_OBJECT_BEGIN: 102 | if (!s_IsKey) print_indention(); 103 | s_IsKey = 0; 104 | printf("{\n"); 105 | ++s_Level; 106 | break; 107 | case JSON_T_OBJECT_END: 108 | assert(!s_IsKey); 109 | if (s_Level > 0) --s_Level; 110 | print_indention(); 111 | printf("}\n"); 112 | break; 113 | case JSON_T_INTEGER: 114 | if (!s_IsKey) print_indention(); 115 | s_IsKey = 0; 116 | printf("integer: "JSON_PARSER_INTEGER_SPRINTF_TOKEN"\n", value->vu.integer_value); 117 | break; 118 | case JSON_T_FLOAT: 119 | if (!s_IsKey) print_indention(); 120 | s_IsKey = 0; 121 | printf("float: %f\n", value->vu.float_value); /* We wanted stringified floats */ 122 | break; 123 | case JSON_T_NULL: 124 | if (!s_IsKey) print_indention(); 125 | s_IsKey = 0; 126 | printf("null\n"); 127 | break; 128 | case JSON_T_TRUE: 129 | if (!s_IsKey) print_indention(); 130 | s_IsKey = 0; 131 | printf("true\n"); 132 | break; 133 | case JSON_T_FALSE: 134 | if (!s_IsKey) print_indention(); 135 | s_IsKey = 0; 136 | printf("false\n"); 137 | break; 138 | case JSON_T_KEY: 139 | s_IsKey = 1; 140 | print_indention(); 141 | printf("key = '%s', value = ", value->vu.str.value); 142 | break; 143 | case JSON_T_STRING: 144 | if (!s_IsKey) print_indention(); 145 | s_IsKey = 0; 146 | printf("string: '%s'\n", value->vu.str.value); 147 | break; 148 | default: 149 | assert(0); 150 | break; 151 | } 152 | 153 | return 1; 154 | } 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONStream.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONStream.h" 2 | 3 | #ifdef JSON_STREAM 4 | #include "JSONWorker.h" 5 | #include "JSONValidator.h" 6 | 7 | 8 | JSONStream::JSONStream(json_stream_callback_t call_p, json_stream_e_callback_t call_e, void * callbackIdentifier) json_nothrow : state(true), call(call_p), err_call(call_e), buffer(), callback_identifier(callbackIdentifier) { 9 | LIBJSON_CTOR; 10 | } 11 | 12 | JSONStream::JSONStream(const JSONStream & orig) json_nothrow : state(orig.state), call(orig.call), err_call(orig.err_call), buffer(orig.buffer), callback_identifier(orig.callback_identifier){ 13 | LIBJSON_COPY_CTOR; 14 | } 15 | 16 | JSONStream & JSONStream::operator =(const JSONStream & orig) json_nothrow { 17 | LIBJSON_ASSIGNMENT; 18 | err_call = orig.err_call; 19 | call = orig.call; 20 | state = orig.state; 21 | buffer = orig.buffer; 22 | callback_identifier = orig.callback_identifier; 23 | return *this; 24 | } 25 | 26 | #ifdef JSON_LIBRARY 27 | JSONStream & JSONStream::operator << (const json_char * str) json_nothrow { 28 | #else 29 | JSONStream & JSONStream::operator << (const json_string & str) json_nothrow { 30 | #endif 31 | if (state){ 32 | buffer += str; 33 | parse(); 34 | } 35 | return *this; 36 | } 37 | 38 | 39 | #define QUOTECASE_STREAM()\ 40 | case JSON_TEXT('\"'):\ 41 | while (*(++p) != JSON_TEXT('\"')){\ 42 | if (json_unlikely(*p == JSON_TEXT('\0'))) return json_string::npos;\ 43 | }\ 44 | break; 45 | 46 | 47 | #define NULLCASE_STREAM()\ 48 | case JSON_TEXT('\0'):\ 49 | return json_string::npos;\ 50 | 51 | 52 | #define BRACKET_STREAM(left, right)\ 53 | case left: {\ 54 | size_t brac = 1;\ 55 | while (brac){\ 56 | switch (*(++p)){\ 57 | case right:\ 58 | --brac;\ 59 | break;\ 60 | case left:\ 61 | ++brac;\ 62 | break;\ 63 | QUOTECASE_STREAM()\ 64 | NULLCASE_STREAM()\ 65 | }\ 66 | }\ 67 | break;}\ 68 | case right:\ 69 | return json_string::npos; 70 | 71 | #if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY))) 72 | #define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant(vt, po) 73 | template 74 | size_t JSONStream::FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow { 75 | #else 76 | #define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant(ch, vt, po) 77 | size_t JSONStream::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow { 78 | #endif 79 | const json_char * start = value_t.c_str(); 80 | for (const json_char * p = start + pos; *p; ++p){ 81 | if (json_unlikely(*p == ch)) return p - start; 82 | switch (*p){ 83 | BRACKET_STREAM(JSON_TEXT('['), JSON_TEXT(']')) 84 | BRACKET_STREAM(JSON_TEXT('{'), JSON_TEXT('}')) 85 | QUOTECASE_STREAM() 86 | } 87 | }; 88 | return json_string::npos; 89 | } 90 | 91 | void JSONStream::parse(void) json_nothrow { 92 | #ifdef JSON_SECURITY_MAX_STREAM_OBJECTS 93 | size_t objects = 0; 94 | #endif 95 | for(;;){ 96 | size_t pos = buffer.find_first_of(JSON_TEXT("{[")); 97 | if (json_likely(pos != json_string::npos)){ 98 | size_t end = (buffer[pos] == JSON_TEXT('[')) ? STREAM_FIND_NEXT_RELEVANT(JSON_TEXT(']'), buffer, pos + 1) : STREAM_FIND_NEXT_RELEVANT(JSON_TEXT('}'), buffer, pos + 1); 99 | if (end != json_string::npos){ 100 | #ifdef JSON_SECURITY_MAX_STREAM_OBJECTS 101 | if (++objects > JSON_SECURITY_MAX_STREAM_OBJECTS){ 102 | JSON_FAIL(JSON_TEXT("Maximum number of json objects for a stream at once has been reached")); 103 | if (err_call) err_call(getIdentifier()); 104 | state = false; 105 | return; 106 | } 107 | #endif 108 | START_MEM_SCOPE 109 | JSONNode temp(JSONWorker::parse(buffer.substr(pos, end - pos + 1))); 110 | #ifndef JSON_LIBRARY 111 | call(temp, getIdentifier()); 112 | #else 113 | call(&temp, getIdentifier()); 114 | #endif 115 | END_MEM_SCOPE 116 | json_string::iterator beginning = buffer.begin(); 117 | buffer.erase(beginning, beginning + end); 118 | continue; //parse(); //parse the next object too 119 | } 120 | #ifdef JSON_SAFE 121 | else { 122 | //verify that what's in there is at least valid so far 123 | #ifndef JSON_VALIDATE 124 | #error In order to use safe mode and streams, JSON_VALIDATE needs to be defined 125 | #endif 126 | 127 | json_auto s; 128 | size_t len; 129 | s.set(JSONWorker::RemoveWhiteSpace(json_string(buffer.c_str() + pos), len, false)); 130 | 131 | 132 | if (!JSONValidator::isValidPartialRoot(s.ptr)){ 133 | if (err_call) err_call(getIdentifier()); 134 | state = false; 135 | } 136 | } 137 | #endif 138 | } 139 | break; 140 | } 141 | } 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /foo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Change Log for RJSONIO 6 | 7 | 8 |

Change Log for RJSONIO 9 |

10 | RJSONIO 11 | 12 |

Version 0.6-0

13 |
14 |
  • 15 | Updated the libjson source code in the package to libjson 7.0.1. 16 | This removes a bug in parsing numbers of the form 3.14E4. Found 17 | by Jeroen Ooms. 18 |
  • 19 |
    20 |
  • 21 | Added configuration so that we can use a libjson installed on the system. 22 | This avoids issues of using older versions of libjson shipped with this package. 23 |
  • 24 |
    25 |
    26 |
    27 | 28 |

    Version 0.5-0

    29 |
    30 |
  • Enhancements to disambiguate serializing empty lists from as empty arrays or associative 31 | arrays. See also emptyNamedList to map to {}. 32 |
  • 33 |
    34 |
  • Method for identifying an R scalar that should be mapped to a JSON array via the 35 | AsIs class and I() function. 36 |
  • 37 |
    38 |
  • toJSON() honors these also ensuring transformation from JSON to R to JSON 39 | preserves the same structure. 40 |
  • 41 |
    42 |
  • 43 | Both changes thanks to suggestions by Keith Bonawitz. 44 |
  • 45 |
    46 |
    47 |
    48 | 49 |

    Version 0.4-2

    50 |
    51 |
  • Fixed significant memory leaks found by Keith Bonawitz
  • 52 |
    53 |
    54 |
    55 | 56 |

    Version 0.4-1

    57 |
    58 |
  • Tidied up C++ code from libjsonio to avoid a warning about no 59 | argument to initializeFetch() when compiling the C++ code. 60 |
  • 61 |
    62 |
  • Fixed a C routine (R_fromJSON) that did not return a value.
  • 63 |
    64 |
    65 |
    66 | 67 |

    Version 0.4-0

    68 |
    69 |
  • 70 | fromJSON() now uses libjson for the native parsing 71 | and a C routine to transform the resulting tree into R. 72 | This leads to a considerable speedup in parsing documents, 73 | approximately a factor of 200 over the customizable, event 74 | driven mechanism in earlier versions and still available 75 | in this package via the basicJSONHandler() 76 | function and fromJSON(). 77 |
  • 78 |
    79 |
    80 |
    81 | 82 |

    Version 0.3-4

    83 |
    84 |
  • Refinement of handling large integers that do not fit into a 4 byte int. 85 | Tested on Windows. 86 |
  • 87 |
    88 |
    89 |
    90 | 91 |

    Version 0.3-3

    92 |
    93 |
  • Handle large integers that do not fit into a 4 byte int. Return as numeric values.
  • 94 |
    95 |
    96 |
    97 | 98 |

    Version 0.3-1

    99 |
    100 |
  • Convert factors to character vectors in toJSON() and then serialize.
  • 101 |
    102 |
    103 |
    104 | 105 |

    Version 0.2-4

    106 |
    107 |
  • Handles UTF-8 content as input. We convert the text to raw and then integer 108 | values. 109 |
  • 110 |
    111 |
    112 |
    113 | 114 |

    Version 0.2-3

    115 |
    116 |
  • (Minor) Change to the C code to make it compile on Windows.
  • 117 |
    118 |
    119 |
    120 | 121 |

    Version 0.2-2

    122 |
    123 |
  • 124 | named atomic/primitive vectors serialized as associative arrays rather 125 | than simple arrays. 126 |
  • 127 |
    128 |
    129 |
    130 | 131 |

    Version 0.2-1

    132 |
    133 |
  • 134 | names on R objects from associative arrays from JSON were in reverse order. 135 |
  • 136 |
    137 |
    138 |
    139 | 140 |

    Version 0.2-0

    141 |
    142 |
  • 143 | Scalar, by default, values are represented in JSON as scalars and not 144 | arrays of length 1. One can control this via the 145 | container parameter in toJSON(). 146 |
  • 147 |
    148 |
    149 |
    150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /utfTest/news.txt: -------------------------------------------------------------------------------- 1 | {"offset" : "0" , "results" : [{"body" : "Whenever modern humans reached a new continent in the expansion from their African homeland 50,000 years ago, whether Australia, Europe or the Americas, all the large fauna quickly disappeared. This circumstantial evidence from the fossil record suggests that people’s first accomplishment upon reaching new territory was to hunt all its all" , "byline" : "By NICHOLAS WADE" , "date" : "20091124" , "title" : "New Data Shed Light on Large-Animal Extinction" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/science\/24fauna.html"} , {"body" : "Perhaps by living on another planet, you might have missed the popular conclusion that Asia must increase consumption and let its exchange rates climb to help put the world economy on a more even keel. But, until recently, another part of the policy prescription for stronger Asian demand to reduce global imbalances has received far less attention:" , "byline" : "By ALAN WHEATLEY" , "date" : "20091124" , "title" : "INSIDE ASIA; Asia Could Benefit From Cooperating on Infrastructure" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/business\/global\/24inside.html"} , {"body" : "BRASÍLIA — As leaders from Brazil and Iran prepared to meet here on Monday, the Brazilian president, Luiz Inacio Lula da Silva , defended his decision to play host to the Iranian president at a moment of rising tension over Iran’s nuclear ambitions. In his national radio show, Mr. da Silva said that “you don’t move" , "byline" : "By ALEXEI BARRIONUEVO" , "date" : "20091124" , "title" : "Brazil’s President Defends Visit of Iranian Leader" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/world\/americas\/24brazil.html"} , {"body" : "Let’s stipulate: Lloyd Blankfein and Jamie Dimon are enlightened, broad-gauge chief executive officers, among the finest in the world. Their firms, Goldman Sachs and JPMorgan Chase, are indispensable in raising capital for companies, creating wealth. They’ve repaid the government assistance money received in the financial crisis and are" , "byline" : "By ALBERT R. HUNT" , "date" : "20091124" , "title" : "LETTER FROM WASHINGTON; No Lessons Learned on Wall Street" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/us\/24iht-letter.html"} , {"body" : "Joe Witte, a meteorologist for News Channel 8 in Virginia and Maryland, hopes that people watching his television forecasts will think about more than just the weather. Two years ago, Mr. Witte started to include phenomena linked with climate change in his reports, like how warmer conditions affect life in Chesapeake Bay and prospects for" , "byline" : "By JAMES KANTER" , "date" : "20091123" , "title" : "GREEN INC. COLUMN; New Voices on Climate Change" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/business\/energy-environment\/23iht-green23.html"} , {"body" : "BUSINESS DAY An article on Friday about a House committee’s approval of a measure that would expand Congressional oversight of the Federal Reserve misidentified the state represented by Paul E. Kanjorski, who offered an amendment that would expand government power over large financial institutions. It is Pennsylvania, not Ohio. ( Go to" , "date" : "20091123" , "title" : "Corrections" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/pageoneplus\/corrections.html"} , {"body" : "An article on Thursday about turmoil within the United States Chamber of Commerce over its opposition to climate change legislation erroneously included one company among those that have resigned from the chamber over the climate policy. A spokeswoman for Levi Strauss & Company said that although the company had differed with the chamber over" , "date" : "20091123" , "title" : "Corrections" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/pageoneplus\/23corrections-003.html"} , {"body" : "WASHINGTON — On the House floor during a debate over health care reform , he taunted a colleague who had been calling for his ouster. At a recent fund-raiser, he complained that the House speaker had made an end run around him and his committee. Confronted by a persistent conservative activist in a hallway, he let loose an expletive, telling" , "byline" : "By RAYMOND HERNANDEZ and JIM RUTENBERG" , "date" : "20091123" , "title" : "His Ethics Under Scrutiny, Rangel Is Frayed but Defiant" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/nyregion\/23rangel.html"} , {"body" : "BRASÍLIA — Brazil ’s ambitions to be a more important player on the global diplomatic stage are crashing headlong into the efforts of the United States and other Western powers to rein in Iran ’s nuclear arms program. Luiz Inácio Lula da Silva , Brazil’s president, is set to receive Iran’s president, Mahmoud" , "byline" : "By ALEXEI BARRIONUEVO" , "date" : "20091123" , "title" : "Brazil Elbows U.S. on the Diplomatic Stage" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/world\/americas\/23brazil.html"} , {"body" : "PORTLAND, Ore. — For decades, the world’s supercomputers have been the tightly guarded property of universities and governments. But what would happen if regular folks could get their hands on one? The price of supercomputers is dropping quickly, in part because they are often built with the same off-the-shelf parts found in PCs, as a" , "byline" : "By ASHLEE VANCE" , "date" : "20091123" , "title" : "Shared Supercomputing and Everyday Research" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/technology\/23compute.html"}] , "tokens" : ["climate" , "change"] , "total" : 10492} -------------------------------------------------------------------------------- /utfTest/news1.txt: -------------------------------------------------------------------------------- 1 | {"offset" : "0" , "results" : [{"body" : "Whenever modern humans reached a new continent in the expansion from their African homeland 50,000 years ago, whether Australia, Europe or the Americas, all the large fauna quickly disappeared. This circumstantial evidence from the fossil record suggests that people’s first accomplishment upon reaching new territory was to hunt all its all" , "byline" : "By NICHOLAS WADE" , "date" : "20091124" , "title" : "New Data Shed Light on Large-Animal Extinction" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/science\/24fauna.html"} , {"body" : "Perhaps by living on another planet, you might have missed the popular conclusion that Asia must increase consumption and let its exchange rates climb to help put the world economy on a more even keel. But, until recently, another part of the policy prescription for stronger Asian demand to reduce global imbalances has received far less attention:" , "byline" : "By ALAN WHEATLEY" , "date" : "20091124" , "title" : "INSIDE ASIA; Asia Could Benefit From Cooperating on Infrastructure" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/business\/global\/24inside.html"} , {"body" : "BRASÍLIA — As leaders from Brazil and Iran prepared to meet here on Monday, the Brazilian president, Luiz Inacio Lula da Silva , defended his decision to play host to the Iranian president at a moment of rising tension over Iran’s nuclear ambitions. In his national radio show, Mr. da Silva said that “you don’t move" , "byline" : "By ALEXEI BARRIONUEVO" , "date" : "20091124" , "title" : "Brazil's President Defends Visit of Iranian Leader" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/world\/americas\/24brazil.html"} , {"body" : "Let’s stipulate: Lloyd Blankfein and Jamie Dimon are enlightened, broad-gauge chief executive officers, among the finest in the world. Their firms, Goldman Sachs and JPMorgan Chase, are indispensable in raising capital for companies, creating wealth. They’ve repaid the government assistance money received in the financial crisis and are" , "byline" : "By ALBERT R. HUNT" , "date" : "20091124" , "title" : "LETTER FROM WASHINGTON; No Lessons Learned on Wall Street" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/us\/24iht-letter.html"} , {"body" : "Joe Witte, a meteorologist for News Channel 8 in Virginia and Maryland, hopes that people watching his television forecasts will think about more than just the weather. Two years ago, Mr. Witte started to include phenomena linked with climate change in his reports, like how warmer conditions affect life in Chesapeake Bay and prospects for" , "byline" : "By JAMES KANTER" , "date" : "20091123" , "title" : "GREEN INC. COLUMN; New Voices on Climate Change" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/business\/energy-environment\/23iht-green23.html"} , {"body" : "BUSINESS DAY An article on Friday about a House committee’s approval of a measure that would expand Congressional oversight of the Federal Reserve misidentified the state represented by Paul E. Kanjorski, who offered an amendment that would expand government power over large financial institutions. It is Pennsylvania, not Ohio. ( Go to" , "date" : "20091123" , "title" : "Corrections" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/pageoneplus\/corrections.html"} , {"body" : "An article on Thursday about turmoil within the United States Chamber of Commerce over its opposition to climate change legislation erroneously included one company among those that have resigned from the chamber over the climate policy. A spokeswoman for Levi Strauss & Company said that although the company had differed with the chamber over" , "date" : "20091123" , "title" : "Corrections" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/pageoneplus\/23corrections-003.html"} , {"body" : "WASHINGTON — On the House floor during a debate over health care reform , he taunted a colleague who had been calling for his ouster. At a recent fund-raiser, he complained that the House speaker had made an end run around him and his committee. Confronted by a persistent conservative activist in a hallway, he let loose an expletive, telling" , "byline" : "By RAYMOND HERNANDEZ and JIM RUTENBERG" , "date" : "20091123" , "title" : "His Ethics Under Scrutiny, Rangel Is Frayed but Defiant" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/nyregion\/23rangel.html"} , {"body" : "BRASÍLIA — Brazil ’s ambitions to be a more important player on the global diplomatic stage are crashing headlong into the efforts of the United States and other Western powers to rein in Iran ’s nuclear arms program. Luiz Inácio Lula da Silva , Brazil’s president, is set to receive Iran’s president, Mahmoud" , "byline" : "By ALEXEI BARRIONUEVO" , "date" : "20091123" , "title" : "Brazil Elbows U.S. on the Diplomatic Stage" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/world\/americas\/23brazil.html"} , {"body" : "PORTLAND, Ore. — For decades, the world’s supercomputers have been the tightly guarded property of universities and governments. But what would happen if regular folks could get their hands on one? The price of supercomputers is dropping quickly, in part because they are often built with the same off-the-shelf parts found in PCs, as a" , "byline" : "By ASHLEE VANCE" , "date" : "20091123" , "title" : "Shared Supercomputing and Everyday Research" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/technology\/23compute.html"}] , "tokens" : ["climate" , "change"] , "total" : 10492} 2 | -------------------------------------------------------------------------------- /utfTest/news2.txt: -------------------------------------------------------------------------------- 1 | {"offset" : "0" , "results" : [{"body" : "Whenever modern humans reached a new continent in the expansion from their African homeland 50,000 years ago, whether Australia, Europe or the Americas, all the large fauna quickly disappeared. This circumstantial evidence from the fossil record suggests that people’s first accomplishment upon reaching new territory was to hunt all its all" , "byline" : "By NICHOLAS WADE" , "date" : "20091124" , "title" : "New Data Shed Light on Large-Animal Extinction" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/science\/24fauna.html"} , {"body" : "Perhaps by living on another planet, you might have missed the popular conclusion that Asia must increase consumption and let its exchange rates climb to help put the world economy on a more even keel. But, until recently, another part of the policy prescription for stronger Asian demand to reduce global imbalances has received far less attention:" , "byline" : "By ALAN WHEATLEY" , "date" : "20091124" , "title" : "INSIDE ASIA; Asia Could Benefit From Cooperating on Infrastructure" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/business\/global\/24inside.html"} , {"body" : "BRASÍLIA — As leaders from Brazil and Iran prepared to meet here on Monday, the Brazilian president, Luiz Inacio Lula da Silva , defended his decision to play host to the Iranian president at a moment of rising tension over Iran’s nuclear ambitions. In his national radio show, Mr. da Silva said that “you don’t move" , "byline" : "By ALEXEI BARRIONUEVO" , "date" : "20091124" , "title" : "Brazil’s President Defends Visit of Iranian Leader" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/world\/americas\/24brazil.html"} , {"body" : "Let’s stipulate: Lloyd Blankfein and Jamie Dimon are enlightened, broad-gauge chief executive officers, among the finest in the world. Their firms, Goldman Sachs and JPMorgan Chase, are indispensable in raising capital for companies, creating wealth. They’ve repaid the government assistance money received in the financial crisis and are" , "byline" : "By ALBERT R. HUNT" , "date" : "20091124" , "title" : "LETTER FROM WASHINGTON; No Lessons Learned on Wall Street" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/24\/us\/24iht-letter.html"} , {"body" : "Joe Witte, a meteorologist for News Channel 8 in Virginia and Maryland, hopes that people watching his television forecasts will think about more than just the weather. Two years ago, Mr. Witte started to include phenomena linked with climate change in his reports, like how warmer conditions affect life in Chesapeake Bay and prospects for" , "byline" : "By JAMES KANTER" , "date" : "20091123" , "title" : "GREEN INC. COLUMN; New Voices on Climate Change" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/business\/energy-environment\/23iht-green23.html"} , {"body" : "BUSINESS DAY An article on Friday about a House committee’s approval of a measure that would expand Congressional oversight of the Federal Reserve misidentified the state represented by Paul E. Kanjorski, who offered an amendment that would expand government power over large financial institutions. It is Pennsylvania, not Ohio. ( Go to" , "date" : "20091123" , "title" : "Corrections" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/pageoneplus\/corrections.html"} , {"body" : "An article on Thursday about turmoil within the United States Chamber of Commerce over its opposition to climate change legislation erroneously included one company among those that have resigned from the chamber over the climate policy. A spokeswoman for Levi Strauss & Company said that although the company had differed with the chamber over" , "date" : "20091123" , "title" : "Corrections" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/pageoneplus\/23corrections-003.html"} , {"body" : "WASHINGTON — On the House floor during a debate over health care reform , he taunted a colleague who had been calling for his ouster. At a recent fund-raiser, he complained that the House speaker had made an end run around him and his committee. Confronted by a persistent conservative activist in a hallway, he let loose an expletive, telling" , "byline" : "By RAYMOND HERNANDEZ and JIM RUTENBERG" , "date" : "20091123" , "title" : "His Ethics Under Scrutiny, Rangel Is Frayed but Defiant" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/nyregion\/23rangel.html"} , {"body" : "BRASÍLIA — Brazil ’s ambitions to be a more important player on the global diplomatic stage are crashing headlong into the efforts of the United States and other Western powers to rein in Iran ’s nuclear arms program. Luiz Inácio Lula da Silva , Brazil’s president, is set to receive Iran’s president, Mahmoud" , "byline" : "By ALEXEI BARRIONUEVO" , "date" : "20091123" , "title" : "Brazil Elbows U.S. on the Diplomatic Stage" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/world\/americas\/23brazil.html"} , {"body" : "PORTLAND, Ore. — For decades, the world’s supercomputers have been the tightly guarded property of universities and governments. But what would happen if regular folks could get their hands on one? The price of supercomputers is dropping quickly, in part because they are often built with the same off-the-shelf parts found in PCs, as a" , "byline" : "By ASHLEE VANCE" , "date" : "20091123" , "title" : "Shared Supercomputing and Everyday Research" , "url" : "http:\/\/www.nytimes.com\/2009\/11\/23\/technology\/23compute.html"}] , "tokens" : ["climate" , "change"] , "total" : 10492} 2 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONDefs.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONDEFS_H 2 | #define JSONDEFS_H 3 | 4 | /* 5 | Defines all of the types of functions and various other definitions 6 | that are used in C applications, this is very useful if dynamically loading 7 | the library instead of linking. 8 | */ 9 | 10 | #include "../../JSONOptions.h" 11 | #include "JSONDefs/Unknown_C.h" 12 | #include "JSONDefs/GNU_C.h" 13 | #include "JSONDefs/Visual_C.h" 14 | #include "JSONDefs/Strings_Defs.h" 15 | 16 | #define __LIBJSON_MAJOR__ 7 17 | #define __LIBJSON_MINOR__ 6 18 | #define __LIBJSON_PATCH__ 1 19 | #define __LIBJSON_VERSION__ (__LIBJSON_MAJOR__ * 10000 + __LIBJSON_MINOR__ * 100 + __LIBJSON_PATCH__) 20 | 21 | #define JSON_NULL '\0' 22 | #define JSON_STRING '\1' 23 | #define JSON_NUMBER '\2' 24 | #define JSON_BOOL '\3' 25 | #define JSON_ARRAY '\4' 26 | #define JSON_NODE '\5' 27 | 28 | #ifdef __cplusplus 29 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 30 | #include "JSONAllocator.h" 31 | #else 32 | #define json_allocator std::allocator 33 | #endif 34 | 35 | #ifdef JSON_STRING_HEADER 36 | #include JSON_STRING_HEADER 37 | #else 38 | typedef std::basic_string, json_allocator > json_string; 39 | #endif 40 | #endif 41 | #define JSON_MAP(x, y) std::map, json_allocator > > 42 | 43 | #ifdef JSON_NO_EXCEPTIONS 44 | #define json_throw(x) 45 | #define json_try 46 | #define json_catch(exception, code) 47 | #else 48 | #define json_throw(x) throw(x) 49 | #define json_try try 50 | #define json_catch(exception, code) catch(exception){ code } 51 | #endif 52 | 53 | #ifdef JSON_STRICT 54 | #ifndef JSON_UNICODE 55 | #error, JSON_UNICODE is required for JSON_STRICT 56 | #endif 57 | #ifdef JSON_COMMENTS 58 | #error, JSON_COMMENTS is required to be off for JSON_STRICT 59 | #endif 60 | #endif 61 | 62 | #ifdef JSON_ISO_STRICT 63 | #ifdef JSON_UNICODE 64 | #error, You can not use unicode under ANSI Strict C++ 65 | #endif 66 | #else 67 | #ifdef __GNUC__ 68 | #ifdef __STRICT_ANSI__ 69 | #warning, Using -ansi GCC option, but JSON_ISO_STRICT not on, turning it on for you 70 | #define JSON_ISO_STRICT 71 | #endif 72 | #endif 73 | #endif 74 | 75 | 76 | #ifdef JSON_NUMBER_TYPE 77 | typedef JSON_NUMBER_TYPE json_number; 78 | #define JSON_FLOAT_THRESHHOLD 0.00001 79 | #else 80 | #ifdef JSON_LESS_MEMORY 81 | typedef float json_number; 82 | #define JSON_FLOAT_THRESHHOLD 0.00001f 83 | #else 84 | typedef double json_number; 85 | #define JSON_FLOAT_THRESHHOLD 0.00001 86 | #endif 87 | #endif 88 | 89 | 90 | #ifdef JSON_LESS_MEMORY 91 | /* PACKED and BITS stored in compiler specific headers */ 92 | #define START_MEM_SCOPE { 93 | #define END_MEM_SCOPE } 94 | #else 95 | #define PACKED(x) 96 | #define BITS(x) 97 | #define START_MEM_SCOPE 98 | #define END_MEM_SCOPE 99 | #endif 100 | 101 | #if defined JSON_DEBUG || defined JSON_SAFE 102 | #ifdef JSON_LIBRARY 103 | typedef void (*json_error_callback_t)(const json_char *); 104 | #else 105 | typedef void (*json_error_callback_t)(const json_string &); 106 | #endif 107 | #endif 108 | 109 | #ifdef JSON_INDEX_TYPE 110 | typedef JSON_INDEX_TYPE json_index_t; 111 | #else 112 | typedef unsigned int json_index_t; 113 | #endif 114 | 115 | #ifdef JSON_BOOL_TYPE 116 | typedef JSON_BOOL_TYPE json_bool_t; 117 | #else 118 | typedef int json_bool_t; 119 | #endif 120 | 121 | #ifdef JSON_INT_TYPE 122 | typedef JSON_INT_TYPE json_int_t; 123 | #else 124 | typedef long json_int_t; 125 | #endif 126 | 127 | #define JSONSTREAM_SELF (void*)-1 128 | typedef void (*json_stream_e_callback_t)(void * identifier); 129 | 130 | typedef void (*json_mutex_callback_t)(void *); 131 | typedef void (*json_free_t)(void *); 132 | #ifndef JSON_LIBRARY 133 | typedef void * (*json_malloc_t)(size_t); 134 | typedef void * (*json_realloc_t)(void *, size_t); 135 | #else 136 | #define JSONNODE void /* so that JSONNODE* is void* */ 137 | typedef JSONNODE** JSONNODE_ITERATOR; 138 | #ifdef JSON_STREAM 139 | #define JSONSTREAM void 140 | typedef void (*json_stream_callback_t)(JSONNODE *, void * identifier); 141 | #endif 142 | typedef void * (*json_malloc_t)(unsigned long); 143 | typedef void * (*json_realloc_t)(void *, unsigned long); 144 | #endif 145 | 146 | #ifdef JSON_DEBUG 147 | #ifdef NDEBUG 148 | #ifdef __GNUC__ 149 | #warning, Have JSON_DEBUG on in a release build 150 | #else 151 | #error, Have JSON_DEBUG on in a release build 152 | #endif 153 | #endif 154 | #else 155 | #ifndef NDEBUG 156 | #ifdef __GNUC__ 157 | #warning, Release build of libjson, but NDEBUG is not on 158 | #else 159 | #error, Release build of libjson, but NDEBUG is not on 160 | #endif 161 | #endif 162 | #endif 163 | 164 | #ifdef JSON_UNIT_TEST 165 | #define JSON_PRIVATE public: 166 | #define JSON_PROTECTED public: 167 | #else 168 | #define JSON_PRIVATE private: 169 | #define JSON_PROTECTED protected: 170 | #endif 171 | #ifdef JSON_STREAM 172 | #ifndef JSON_READ_PRIORITY 173 | #error, JSON_STREAM also requires JSON_READ_PRIORITY 174 | #endif 175 | #endif 176 | #ifdef JSON_VALIDATE 177 | #ifndef JSON_READ_PRIORITY 178 | #error, JSON_VALIDATE also requires JSON_READ_PRIORITY 179 | #endif 180 | #endif 181 | 182 | #define JSON_TEMP_COMMENT_IDENTIFIER JSON_TEXT('#') 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /src/JSON_parser.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_PARSER_H 2 | #define JSON_PARSER_H 3 | 4 | /* JSON_parser.h */ 5 | 6 | 7 | #include 8 | 9 | #if 0 10 | 11 | /* Windows DLL stuff */ 12 | #ifdef _WIN32 13 | # ifdef JSON_PARSER_DLL_EXPORTS 14 | # define JSON_PARSER_DLL_API __declspec(dllexport) 15 | # else 16 | # define JSON_PARSER_DLL_API __declspec(dllimport) 17 | # endif 18 | #else 19 | # define JSON_PARSER_DLL_API 20 | #endif 21 | 22 | #else 23 | 24 | #define JSON_PARSER_DLL_API 25 | 26 | #endif /* #if 0 */ 27 | 28 | 29 | /* Determine the integer type use to parse non-floating point numbers */ 30 | #if __STDC_VERSION__ >= 199901L || HAVE_LONG_LONG == 1 31 | typedef long long JSON_int_t; 32 | //#warning "using long long" 33 | #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%lld" 34 | #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%lld" 35 | #else 36 | typedef long JSON_int_t; 37 | #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%ld" 38 | #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%ld" 39 | #endif 40 | 41 | #define MAX_INT 2147483647L 42 | 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | typedef enum 49 | { 50 | JSON_T_NONE = 0, 51 | JSON_T_ARRAY_BEGIN, 52 | JSON_T_ARRAY_END, 53 | JSON_T_OBJECT_BEGIN, 54 | JSON_T_OBJECT_END, 55 | JSON_T_INTEGER, 56 | JSON_T_FLOAT, 57 | JSON_T_NULL, 58 | JSON_T_TRUE, 59 | JSON_T_FALSE, 60 | JSON_T_STRING, 61 | JSON_T_KEY, 62 | JSON_T_MAX 63 | } JSON_type; 64 | 65 | #ifndef WIN32 66 | typedef long double DoubleType; 67 | #define DoubleScanFormat "%Lf" 68 | #else 69 | typedef double DoubleType; 70 | #define DoubleScanFormat "%lf" 71 | #endif 72 | 73 | typedef struct JSON_value_struct { 74 | union { 75 | JSON_int_t integer_value; 76 | 77 | DoubleType float_value; 78 | 79 | struct { 80 | const char* value; 81 | size_t length; 82 | } str; 83 | } vu; 84 | } JSON_value; 85 | 86 | /*! \brief JSON parser callback 87 | 88 | \param ctx The pointer passed to new_JSON_parser. 89 | \param type An element of JSON_type but not JSON_T_NONE. 90 | \param value A representation of the parsed value. This parameter is NULL for 91 | JSON_T_ARRAY_BEGIN, JSON_T_ARRAY_END, JSON_T_OBJECT_BEGIN, JSON_T_OBJECT_END, 92 | JSON_T_NULL, JSON_T_TRUE, and SON_T_FALSE. String values are always returned 93 | as zero-terminated C strings. 94 | 95 | \return Non-zero if parsing should continue, else zero. 96 | */ 97 | typedef int (*JSON_parser_callback)(void* ctx, int type, const struct JSON_value_struct* value); 98 | 99 | 100 | /*! \brief The structure used to configure a JSON parser object 101 | 102 | \param depth If negative, the parser can parse arbitrary levels of JSON, otherwise 103 | the depth is the limit 104 | \param Pointer to a callback. This parameter may be NULL. In this case the input is merely checked for validity. 105 | \param Callback context. This parameter may be NULL. 106 | \param depth. Specifies the levels of nested JSON to allow. Negative numbers yield unlimited nesting. 107 | \param allowComments. To allow C style comments in JSON, set to non-zero. 108 | \param handleFloatsManually. To decode floating point numbers manually set this parameter to non-zero. 109 | 110 | \return The parser object. 111 | */ 112 | typedef struct JSON_config_struct { 113 | JSON_parser_callback callback; 114 | void* callback_ctx; 115 | int depth; 116 | int allow_comments; 117 | int handle_floats_manually; 118 | } JSON_config; 119 | 120 | 121 | /*! \brief Initializes the JSON parser configuration structure to default values. 122 | 123 | The default configuration is 124 | - 127 levels of nested JSON (depends on JSON_PARSER_STACK_SIZE, see json_parser.c) 125 | - no parsing, just checking for JSON syntax 126 | - no comments 127 | 128 | \param config. Used to configure the parser. 129 | */ 130 | JSON_PARSER_DLL_API void init_JSON_config(JSON_config* config); 131 | 132 | /*! \brief Create a JSON parser object 133 | 134 | \param config. Used to configure the parser. Set to NULL to use the default configuration. 135 | See init_JSON_config 136 | 137 | \return The parser object. 138 | */ 139 | JSON_PARSER_DLL_API extern struct JSON_parser_struct* new_JSON_parser(JSON_config* config); 140 | 141 | /*! \brief Destroy a previously created JSON parser object. */ 142 | JSON_PARSER_DLL_API extern void delete_JSON_parser(struct JSON_parser_struct* jc); 143 | 144 | /*! \brief Parse a character. 145 | 146 | \return Non-zero, if all characters passed to this function are part of are valid JSON. 147 | */ 148 | JSON_PARSER_DLL_API extern int JSON_parser_char(struct JSON_parser_struct* jc, int next_char); 149 | 150 | /*! \brief Finalize parsing. 151 | 152 | Call this method once after all input characters have been consumed. 153 | 154 | \return Non-zero, if all parsed characters are valid JSON, zero otherwise. 155 | */ 156 | JSON_PARSER_DLL_API extern int JSON_parser_done(struct JSON_parser_struct* jc); 157 | 158 | /*! \brief Determine if a given string is valid JSON white space 159 | 160 | \return Non-zero if the string is valid, zero otherwise. 161 | */ 162 | JSON_PARSER_DLL_API extern int JSON_parser_is_legal_white_space_string(const char* s); 163 | 164 | 165 | #ifdef __cplusplus 166 | } 167 | #endif 168 | 169 | 170 | #endif /* JSON_PARSER_H */ 171 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONMemory.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONMemory.h" 2 | 3 | #ifdef JSON_MEMORY_MANAGE 4 | #include "JSONNode.h" 5 | void auto_expand::purge(void) json_nothrow { 6 | for(JSON_MAP(void *, void *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ 7 | #if defined(JSON_DEBUG) || defined(JSON_SAFE) 8 | void * temp = (void*)i -> first; //because its pass by reference 9 | libjson_free(temp); 10 | #else 11 | libjson_free((void*)i -> first); 12 | #endif 13 | } 14 | } 15 | 16 | void auto_expand_node::purge(void) json_nothrow { 17 | for(JSON_MAP(void *, JSONNode *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ 18 | JSONNode::deleteJSONNode((JSONNode *)i -> second); 19 | } 20 | } 21 | 22 | #ifdef JSON_STREAM 23 | #include "JSONStream.h" 24 | void auto_expand_stream::purge(void) json_nothrow { 25 | for(JSON_MAP(void *, JSONStream *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ 26 | JSONStream::deleteJSONStream((JSONStream *)i -> second); 27 | } 28 | } 29 | #endif 30 | #endif 31 | 32 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 33 | 34 | #ifdef JSON_MEMORY_POOL 35 | #include "JSONMemoryPool.h" 36 | static bucket_pool_8 json_generic_mempool; 37 | 38 | //This class is only meant to initiate the mempool to start out using std::malloc/realloc/free 39 | class mempool_callback_setter { 40 | public: 41 | LIBJSON_OBJECT(mempool_callback_setter); 42 | inline mempool_callback_setter(void) json_nothrow { 43 | ` LIBJSON_CTOR; 44 | mempool_callbacks::set(std::malloc, std::realloc, std::free); 45 | } 46 | private: 47 | inline mempool_callback_setter(const mempool_callback_setter & o); 48 | inline mempool_callback_setter & operator = (const mempool_callback_setter & o); 49 | }; 50 | static mempool_callback_setter __mempoolcallbacksetter; 51 | #endif 52 | 53 | #include "JSONSingleton.h" 54 | 55 | void * JSONMemory::json_malloc(size_t siz) json_nothrow { 56 | #ifdef JSON_MEMORY_POOL 57 | return json_generic_mempool.allocate(siz); 58 | #else 59 | if (json_malloc_t callback = JSONSingleton::get()){ 60 | #if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful 61 | void * result = callback(siz); 62 | JSON_ASSERT(result, JSON_TEXT("Out of memory")); 63 | return result; 64 | #else 65 | return callback(siz); 66 | #endif 67 | } 68 | #if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful 69 | void * result = std::malloc(siz); 70 | JSON_ASSERT(result, JSON_TEXT("Out of memory")); 71 | return result; 72 | #else 73 | return std::malloc(siz); 74 | #endif 75 | #endif 76 | } 77 | 78 | void JSONMemory::json_free(void * ptr) json_nothrow { 79 | #ifdef JSON_MEMORY_POOL 80 | json_generic_mempool.deallocate(ptr); 81 | #else 82 | if (json_free_t callback = JSONSingleton::get()){ 83 | callback(ptr); 84 | } else { 85 | std::free(ptr); 86 | } 87 | #endif 88 | } 89 | 90 | void * JSONMemory::json_realloc(void * ptr, size_t siz) json_nothrow { 91 | #ifdef JSON_MEMORY_POOL 92 | return json_generic_mempool.reallocate(ptr, siz); 93 | #else 94 | if (json_realloc_t callback = JSONSingleton::get()){ 95 | #if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful 96 | void * result = callback(ptr, siz); 97 | JSON_ASSERT(result, JSON_TEXT("Out of memory")); 98 | return result; 99 | #else 100 | return callback(ptr, siz); 101 | #endif 102 | } 103 | #if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful 104 | void * result = std::realloc(ptr, siz); 105 | JSON_ASSERT(result, JSON_TEXT("Out of memory")); 106 | return result; 107 | #else 108 | return std::realloc(ptr, siz); 109 | #endif 110 | #endif 111 | } 112 | 113 | #ifdef JSON_MEMORY_POOL 114 | //it is okay to pass null to these callbacks, no make sure they function exists 115 | static void * malloc_proxy(size_t siz) json_nothrow { 116 | if (json_malloc_t callback = JSONSingleton::get()){ 117 | return callback(siz); 118 | } 119 | return std::malloc(siz); 120 | } 121 | 122 | static void * realloc_proxy(void * ptr, size_t siz) json_nothrow { 123 | if (json_realloc_t callback = JSONSingleton::get()){ 124 | return callback(ptr, siz); 125 | } 126 | return std::realloc(ptr, siz); 127 | } 128 | 129 | static void free_proxy(void * ptr){ 130 | if (json_free_t callback = JSONSingleton::get()){ 131 | callback(ptr); 132 | } else { 133 | std::free(ptr); 134 | } 135 | } 136 | #endif 137 | 138 | 139 | void JSONMemory::registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre) json_nothrow { 140 | JSONSingleton::set(mal); 141 | JSONSingleton::set(real); 142 | JSONSingleton::set(fre); 143 | #ifdef JSON_MEMORY_POOL 144 | mempool_callbacks::set(malloc_proxy, realloc_proxy, free_proxy); 145 | #endif 146 | } 147 | 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /src/ConvertUTF.h: -------------------------------------------------------------------------------- 1 | #ifndef CONVERT_UNICODE_H 2 | #define CONVERT_UNICODE_H 3 | 4 | /* 5 | * Copyright 2001-2004 Unicode, Inc. 6 | * 7 | * Disclaimer 8 | * 9 | * This source code is provided as is by Unicode, Inc. No claims are 10 | * made as to fitness for any particular purpose. No warranties of any 11 | * kind are expressed or implied. The recipient agrees to determine 12 | * applicability of information provided. If this file has been 13 | * purchased on magnetic or optical media from Unicode, Inc., the 14 | * sole remedy for any claim will be exchange of defective media 15 | * within 90 days of receipt. 16 | * 17 | * Limitations on Rights to Redistribute This Code 18 | * 19 | * Unicode, Inc. hereby grants the right to freely use the information 20 | * supplied in this file in the creation of products supporting the 21 | * Unicode Standard, and to make copies of this file in any form 22 | * for internal or external distribution as long as this notice 23 | * remains attached. 24 | */ 25 | 26 | /* --------------------------------------------------------------------- 27 | 28 | Conversions between UTF32, UTF-16, and UTF-8. Header file. 29 | 30 | Several funtions are included here, forming a complete set of 31 | conversions between the three formats. UTF-7 is not included 32 | here, but is handled in a separate source file. 33 | 34 | Each of these routines takes pointers to input buffers and output 35 | buffers. The input buffers are const. 36 | 37 | Each routine converts the text between *sourceStart and sourceEnd, 38 | putting the result into the buffer between *targetStart and 39 | targetEnd. Note: the end pointers are *after* the last item: e.g. 40 | *(sourceEnd - 1) is the last item. 41 | 42 | The return result indicates whether the conversion was successful, 43 | and if not, whether the problem was in the source or target buffers. 44 | (Only the first encountered problem is indicated.) 45 | 46 | After the conversion, *sourceStart and *targetStart are both 47 | updated to point to the end of last text successfully converted in 48 | the respective buffers. 49 | 50 | Input parameters: 51 | sourceStart - pointer to a pointer to the source buffer. 52 | The contents of this are modified on return so that 53 | it points at the next thing to be converted. 54 | targetStart - similarly, pointer to pointer to the target buffer. 55 | sourceEnd, targetEnd - respectively pointers to the ends of the 56 | two buffers, for overflow checking only. 57 | 58 | These conversion functions take a ConversionFlags argument. When this 59 | flag is set to strict, both irregular sequences and isolated surrogates 60 | will cause an error. When the flag is set to lenient, both irregular 61 | sequences and isolated surrogates are converted. 62 | 63 | Whether the flag is strict or lenient, all illegal sequences will cause 64 | an error return. This includes sequences such as: , , 65 | or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code 66 | must check for illegal sequences. 67 | 68 | When the flag is set to lenient, characters over 0x10FFFF are converted 69 | to the replacement character; otherwise (when the flag is set to strict) 70 | they constitute an error. 71 | 72 | Output parameters: 73 | The value "sourceIllegal" is returned from some routines if the input 74 | sequence is malformed. When "sourceIllegal" is returned, the source 75 | value will point to the illegal value that caused the problem. E.g., 76 | in UTF-8 when a sequence is malformed, it points to the start of the 77 | malformed sequence. 78 | 79 | Author: Mark E. Davis, 1994. 80 | Rev History: Rick McGowan, fixes & updates May 2001. 81 | Fixes & updates, Sept 2001. 82 | 83 | ------------------------------------------------------------------------ */ 84 | 85 | /* --------------------------------------------------------------------- 86 | The following 4 definitions are compiler-specific. 87 | The C standard does not guarantee that wchar_t has at least 88 | 16 bits, so wchar_t is no less portable than unsigned short! 89 | All should be unsigned values to avoid sign extension during 90 | bit mask & shift operations. 91 | ------------------------------------------------------------------------ */ 92 | 93 | 94 | typedef unsigned int UTF32; /* at least 32 bits */ 95 | typedef unsigned short UTF16; /* at least 16 bits */ 96 | typedef unsigned char UTF8; /* typically 8 bits */ 97 | typedef unsigned char Boolean; /* 0 or 1 */ 98 | 99 | /* Some fundamental constants */ 100 | #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD 101 | #define UNI_MAX_BMP (UTF32)0x0000FFFF 102 | #define UNI_MAX_UTF16 (UTF32)0x0010FFFF 103 | #define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF 104 | #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF 105 | 106 | typedef enum { 107 | conversionOK, /* conversion successful */ 108 | sourceExhausted, /* partial character in source, but hit end */ 109 | targetExhausted, /* insuff. room in target for conversion */ 110 | sourceIllegal /* source sequence is illegal/malformed */ 111 | } ConversionResult; 112 | 113 | typedef enum { 114 | strictConversion = 0, 115 | lenientConversion 116 | } ConversionFlags; 117 | 118 | /* This is for C++ and does no harm in C */ 119 | #ifdef __cplusplus 120 | extern "C" { 121 | #endif 122 | 123 | ConversionResult ConvertUTF8toUTF16 ( 124 | const UTF8** sourceStart, const UTF8* sourceEnd, 125 | UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); 126 | 127 | ConversionResult ConvertUTF16toUTF8 ( 128 | const UTF16** sourceStart, const UTF16* sourceEnd, 129 | UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); 130 | 131 | ConversionResult ConvertUTF8toUTF32 ( 132 | const UTF8** sourceStart, const UTF8* sourceEnd, 133 | UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); 134 | 135 | ConversionResult ConvertUTF32toUTF8 ( 136 | const UTF32** sourceStart, const UTF32* sourceEnd, 137 | UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); 138 | 139 | ConversionResult ConvertUTF16toUTF32 ( 140 | const UTF16** sourceStart, const UTF16* sourceEnd, 141 | UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); 142 | 143 | ConversionResult ConvertUTF32toUTF16 ( 144 | const UTF32** sourceStart, const UTF32* sourceEnd, 145 | UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); 146 | 147 | Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); 148 | 149 | #ifdef __cplusplus 150 | } 151 | #endif 152 | 153 | /* --------------------------------------------------------------------- */ 154 | 155 | #endif // CONVERT_UNICODE_H 156 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONMemory.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_MEMORY_H 2 | #define JSON_MEMORY_H 3 | 4 | #include //for malloc, realloc, and free 5 | #include //for memmove 6 | #include "JSONDebug.h" 7 | 8 | #if defined(JSON_DEBUG) || defined(JSON_SAFE) 9 | #define JSON_FREE_PASSTYPE & 10 | #else 11 | #define JSON_FREE_PASSTYPE 12 | #endif 13 | 14 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 15 | class JSONMemory { 16 | public: 17 | static void * json_malloc(size_t siz) json_malloc_attr; 18 | static void * json_realloc(void * ptr, size_t siz) json_malloc_attr; 19 | static void json_free(void * ptr) json_nothrow; 20 | static void registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre) json_nothrow json_cold; 21 | private: 22 | JSONMemory(void); 23 | }; 24 | 25 | template static inline T * json_malloc(size_t count) json_malloc_attr; 26 | template static inline T * json_malloc(size_t count) json_nothrow { 27 | return (T *)JSONMemory::json_malloc(sizeof(T) * count); 28 | } 29 | 30 | template static inline T * json_realloc(T * ptr, size_t count) json_malloc_attr; 31 | template static inline T * json_realloc(T * ptr, size_t count) json_nothrow { 32 | return (T *)JSONMemory::json_realloc(ptr, sizeof(T) * count); 33 | } 34 | 35 | template static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr) json_nothrow { 36 | JSONMemory::json_free(ptr); 37 | #if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again 38 | ptr = 0; 39 | #endif 40 | } 41 | #else 42 | 43 | template static inline T * json_malloc(size_t count) json_malloc_attr; 44 | template static inline T * json_malloc(size_t count) json_nothrow { 45 | #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful 46 | void * result = std::malloc(count * sizeof(T)); 47 | JSON_ASSERT(result != 0, JSON_TEXT("Out of memory")); 48 | #ifdef JSON_NULL_MEMORY 49 | std::memset(result, '\0', count * sizeof(T)); 50 | #endif 51 | return (T *)result; 52 | #else 53 | return (T *)std::malloc(count * sizeof(T)); 54 | #endif 55 | } 56 | 57 | template static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr) json_nothrow { 58 | std::free(ptr); 59 | #if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again 60 | ptr = 0; 61 | #endif 62 | } 63 | 64 | template static inline T * json_realloc(T * ptr, size_t count) json_malloc_attr; 65 | template static inline T * json_realloc(T * ptr, size_t count) json_nothrow { 66 | #ifdef JSON_DEBUG //in debug mode, check the results of realloc to be sure it was successful 67 | void * result = std::realloc(ptr, count * sizeof(T)); 68 | JSON_ASSERT(result != 0, JSON_TEXT("Out of memory")); 69 | return (T *)result; 70 | #else 71 | return (T *)std::realloc(ptr, count * sizeof(T)); 72 | #endif 73 | } 74 | #endif 75 | 76 | #ifdef JSON_MEMORY_MANAGE 77 | #include 78 | class JSONNode; 79 | struct auto_expand { 80 | public: 81 | LIBJSON_OBJECT(auto_expand); 82 | auto_expand(void) json_nothrow : mymap(){ LIBJSON_CTOR;} 83 | ~auto_expand(void) json_nothrow { purge(); LIBJSON_DTOR; } 84 | void purge(void) json_nothrow; 85 | inline void clear(void) json_nothrow { purge(); mymap.clear(); } 86 | inline void * insert(void * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; } 87 | inline void remove(void * ptr) json_nothrow { 88 | JSON_MAP(void *, void *)::iterator i = mymap.find(ptr); 89 | JSON_ASSERT(i != mymap.end(), JSON_TEXT("Removing a non-managed item")); 90 | mymap.erase(i); 91 | } 92 | JSON_MAP(void *, void *) mymap; 93 | private: 94 | auto_expand(const auto_expand &); 95 | auto_expand & operator = (const auto_expand &); 96 | }; 97 | 98 | struct auto_expand_node { 99 | public: 100 | LIBJSON_OBJECT(auto_expand_node); 101 | auto_expand_node(void) json_nothrow : mymap(){ LIBJSON_CTOR; } 102 | ~auto_expand_node(void) json_nothrow { purge(); LIBJSON_DTOR; } 103 | void purge(void) json_nothrow ; 104 | inline void clear(void) json_nothrow { purge(); mymap.clear(); } 105 | inline JSONNode * insert(JSONNode * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; } 106 | inline void remove(void * ptr) json_nothrow { 107 | JSON_MAP(void *, JSONNode *)::iterator i = mymap.find(ptr); 108 | if(json_likely(i != mymap.end())) mymap.erase(i); 109 | } 110 | JSON_MAP(void *, JSONNode *) mymap; 111 | private: 112 | auto_expand_node(const auto_expand_node &); 113 | auto_expand_node & operator = (const auto_expand_node &); 114 | }; 115 | 116 | #ifdef JSON_STREAM 117 | class JSONStream; 118 | struct auto_expand_stream { 119 | public: 120 | LIBJSON_OBJECT(auto_expand_stream); 121 | auto_expand_stream(void) json_nothrow : mymap(){ LIBJSON_CTOR; } 122 | ~auto_expand_stream(void) json_nothrow { purge(); LIBJSON_DTOR; } 123 | void purge(void) json_nothrow ; 124 | inline void clear(void) json_nothrow { purge(); mymap.clear(); } 125 | inline JSONStream * insert(JSONStream * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; } 126 | inline void remove(void * ptr) json_nothrow { 127 | JSON_MAP(void *, JSONStream *)::iterator i = mymap.find(ptr); 128 | if(json_likely(i != mymap.end())) mymap.erase(i); 129 | } 130 | JSON_MAP(void *, JSONStream *) mymap; 131 | private: 132 | auto_expand_stream(const auto_expand_stream &); 133 | auto_expand_stream & operator = (const auto_expand_stream &); 134 | }; 135 | #endif 136 | #endif 137 | 138 | //The C++ way, use an self-deleting pointer and let the optimizer decide when it gets destroyed 139 | template 140 | class json_auto { 141 | public: 142 | LIBJSON_OBJECT(json_auto); 143 | json_auto(void) json_nothrow : ptr(0){ LIBJSON_CTOR; } 144 | json_auto(size_t count) json_nothrow : ptr(json_malloc(count)){ LIBJSON_CTOR; } 145 | json_auto(T * arg) json_nothrow : ptr(arg){ LIBJSON_CTOR; } 146 | ~json_auto(void) json_nothrow { 147 | libjson_free(ptr); 148 | LIBJSON_DTOR; 149 | } 150 | inline void set(T * p) json_nothrow{ 151 | ptr = p; 152 | } 153 | T * ptr; 154 | private: 155 | json_auto(const json_auto &); 156 | json_auto & operator =(const json_auto &); 157 | }; 158 | 159 | //Clears a string, if required, frees the memory 160 | static inline void clearString(json_string & str) json_nothrow { 161 | #ifdef JSON_LESS_MEMORY 162 | json_string().swap(str); 163 | #else 164 | str.clear(); 165 | #endif 166 | } 167 | 168 | //Shrinks a string 169 | static inline void shrinkString(json_string & str) json_nothrow { 170 | #ifdef JSON_LESS_MEMORY 171 | if (str.capacity() != str.length()) str = json_string(str.begin(), str.end()); 172 | #endif 173 | } 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /src/libjson/Source/JSONNode_Mutex.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONNode.h" 2 | #include "JSONGlobals.h" 3 | 4 | #ifdef JSON_MUTEX_CALLBACKS 5 | 6 | json_mutex_callback_t json_lock_callback = 0; 7 | json_mutex_callback_t json_unlock_callback = 0; 8 | void * global_mutex = 0; 9 | void * manager_mutex = 0; 10 | 11 | struct AutoLock { 12 | public: 13 | LIBJSON_OBJECT(AutoLock); 14 | AutoLock(void) json_nothrow { 15 | LIBJSON_CTOR; 16 | json_lock_callback(manager_mutex); 17 | } 18 | ~AutoLock(void) json_nothrow { 19 | LIBJSON_DTOR; 20 | json_unlock_callback(manager_mutex); 21 | } 22 | private: 23 | AutoLock(const AutoLock &); 24 | AutoLock & operator = (const AutoLock &); 25 | }; 26 | 27 | #ifdef JSON_MUTEX_MANAGE 28 | json_mutex_callback_t json_destroy = 0; 29 | 30 | //make sure that the global mutex is taken care of too 31 | struct auto_global { 32 | public: 33 | LIBJSON_OBJECT(auto_global;) 34 | auto_global(void) json_nothrow { LIBJSON_CTOR; } 35 | ~auto_global(void) json_nothrow { 36 | LIBJSON_DTOR; 37 | if (global_mutex){ 38 | JSON_ASSERT_SAFE(json_destroy != 0, JSON_TEXT("No json_destroy in mutex managed mode"), return;); 39 | json_destroy(global_mutex); 40 | } 41 | } 42 | private: 43 | auto_global(const auto_global &); 44 | auto_global & operator = (const auto_global &); 45 | }; 46 | auto_global cleanupGlobal; 47 | #endif 48 | 49 | void JSONNode::register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock) json_nothrow { 50 | json_lock_callback = lock; 51 | json_unlock_callback = unlock; 52 | manager_mutex = manager_lock; 53 | } 54 | 55 | void JSONNode::set_global_mutex(void * mutex) json_nothrow { 56 | global_mutex = mutex; 57 | } 58 | 59 | void JSONNode::set_mutex(void * mutex) json_nothrow { 60 | makeUniqueInternal(); 61 | internal -> _set_mutex(mutex); 62 | } 63 | 64 | void * JSONNode::getThisLock(JSONNode * pthis) json_nothrow { 65 | if (pthis -> internal -> mylock != 0){ 66 | return pthis -> internal -> mylock; 67 | } 68 | JSON_ASSERT(global_mutex != 0, JSON_TEXT("No global_mutex")); //this is safe, because it's just goingi to return 0 anyway 69 | return global_mutex; 70 | } 71 | 72 | void JSONNode::lock(int thread) json_nothrow { 73 | JSON_ASSERT_SAFE(json_lock_callback != 0, JSON_TEXT("No locking callback"), return;); 74 | 75 | AutoLock lockControl; 76 | 77 | //first, figure out what needs to be locked 78 | void * thislock = getThisLock(this); 79 | #ifdef JSON_SAFE 80 | if (json_unlikely(thislock == 0)) return; 81 | #endif 82 | 83 | //make sure that the same thread isn't locking it more than once (possible due to complex ref counting) 84 | JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread); 85 | if (it == json_global(THREAD_LOCKS).end()){ 86 | JSON_MAP(void *, unsigned int) newthread; 87 | newthread[thislock] = 1; 88 | json_global(THREAD_LOCKS).insert(std::pair(thread, newthread)); 89 | } else { //this thread already has some things locked, check if the current mutex is 90 | JSON_MAP(void *, unsigned int) & newthread = it -> second; 91 | JSON_MAP(void *, unsigned int)::iterator locker(newthread.find(thislock)); 92 | if (locker == newthread.end()){ //current mutex is not locked, set it to locked 93 | newthread.insert(std::pair(thislock, 1)); 94 | } else { //it's already locked, don't relock it 95 | ++(locker -> second); 96 | return; //don't try to relock, it will deadlock the program 97 | } 98 | } 99 | 100 | //if I need to, lock it 101 | json_lock_callback(thislock); 102 | } 103 | 104 | void JSONNode::unlock(int thread) json_nothrow{ 105 | JSON_ASSERT_SAFE(json_unlock_callback != 0, JSON_TEXT("No unlocking callback"), return;); 106 | 107 | AutoLock lockControl; 108 | 109 | //first, figure out what needs to be locked 110 | void * thislock = getThisLock(this); 111 | #ifdef JSON_SAFE 112 | if (thislock == 0) return; 113 | #endif 114 | 115 | //get it out of the map 116 | JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread); 117 | JSON_ASSERT_SAFE(it != json_global(THREAD_LOCKS).end(), JSON_TEXT("thread unlocking something it didn't lock"), return;); 118 | 119 | //get the mutex out of the thread 120 | JSON_MAP(void *, unsigned int) & newthread = it -> second; 121 | JSON_MAP(void *, unsigned int)::iterator locker = newthread.find(thislock); 122 | JSON_ASSERT_SAFE(locker != newthread.end(), JSON_TEXT("thread unlocking mutex it didn't lock"), return;); 123 | 124 | //unlock it 125 | if (--(locker -> second)) return; //other nodes is this same thread still have a lock on it 126 | 127 | //if I need to, unlock it 128 | newthread.erase(locker); 129 | json_unlock_callback(thislock); 130 | 131 | } 132 | 133 | #ifdef JSON_MUTEX_MANAGE 134 | void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy) json_nothrow { 135 | json_destroy = destroy; 136 | } 137 | #endif 138 | 139 | 140 | void internalJSONNode::_set_mutex(void * mutex, bool unset) json_nothrow { 141 | if (unset) _unset_mutex(); //for reference counting 142 | mylock = mutex; 143 | if (mutex != 0){ 144 | #ifdef JSON_MUTEX_MANAGE 145 | JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mutex); 146 | if (it == json_global(MUTEX_MANAGER).end()){ 147 | json_global(MUTEX_MANAGER).insert(std::pair(mutex, 1)); 148 | } else { 149 | ++it -> second; 150 | } 151 | #endif 152 | if (isContainer()){ 153 | json_foreach(CHILDREN, myrunner){ 154 | (*myrunner) -> set_mutex(mutex); 155 | } 156 | } 157 | } 158 | } 159 | 160 | void internalJSONNode::_unset_mutex(void) json_nothrow { 161 | #ifdef JSON_MUTEX_MANAGE 162 | if (mylock != 0){ 163 | JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock); 164 | JSON_ASSERT_SAFE(it != json_global(MUTEX_MANAGER).end(), JSON_TEXT("Mutex not managed"), return;); 165 | --it -> second; 166 | if (it -> second == 0){ 167 | JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("You didn't register a destructor for mutexes"), return;); 168 | json_global(MUTEX_MANAGER).erase(it); 169 | } 170 | } 171 | #endif 172 | } 173 | 174 | #ifdef JSON_DEBUG 175 | #ifndef JSON_LIBRARY 176 | JSONNode internalJSONNode::DumpMutex(void) const json_nothrow { 177 | JSONNode mut(JSON_NODE); 178 | mut.set_name(JSON_TEXT("mylock")); 179 | #ifdef JSON_MUTEX_MANAGE 180 | if (mylock != 0){ 181 | mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)mylock))); 182 | JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock); 183 | if (it == json_global(MUTEX_MANAGER).end()){ 184 | mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), JSON_TEXT("error")))); 185 | } else { 186 | mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), it -> second))); 187 | } 188 | } else { 189 | mut = (long)mylock; 190 | } 191 | #else 192 | mut = (long)mylock; 193 | #endif 194 | return mut; 195 | } 196 | #endif 197 | #endif 198 | 199 | #else 200 | #ifdef JSON_MUTEX_MANAGE 201 | #error You can not have JSON_MUTEX_MANAGE on without JSON_MUTEX_CALLBACKS 202 | #endif 203 | #endif 204 | -------------------------------------------------------------------------------- /man/toJSON.Rd: -------------------------------------------------------------------------------- 1 | \name{toJSON} 2 | \alias{toJSON} 3 | \alias{toJSON,list-method} 4 | \alias{toJSON,ANY-method} 5 | \alias{toJSON,numeric-method} 6 | \alias{toJSON,integer-method} 7 | \alias{toJSON,integer,missing-method} 8 | \alias{toJSON,character-method} 9 | \alias{toJSON,logical-method} 10 | \alias{toJSON,hexmode-method} 11 | \alias{toJSON,matrix-method} 12 | \alias{toJSON,ANY-method} 13 | \alias{toJSON,name-method} 14 | \alias{toJSON,list-method} 15 | \alias{toJSON,NULL-method} 16 | \alias{toJSON,factor-method} 17 | \alias{toJSON,AsIs-method} 18 | \alias{toJSON,environment-method} 19 | \alias{toJSON,data.frame-method} 20 | \alias{toJSON,array-method} 21 | \alias{toJSON,function-method} 22 | 23 | 24 | \alias{emptyNamedList} 25 | 26 | \title{Convert an R object to a string in Javascript Object Notation} 27 | \description{ 28 | This function and its methods convert an R object into a string 29 | that represents the object in Javascript Object Notation (JSON). 30 | 31 | The different methods try to map R's vectors to JSON arrays and 32 | associative arrays. There is ambiguity here as an R vector of length 1 33 | can be a JSON scalar or an array with one element. When there are 34 | names on the R vector, the descision is clearer. 35 | We have introduced the \code{emptyNamedList} variable to identify 36 | an empty list that has an empty names character vector and so 37 | maps to an associative array in JSON, albeit an empty one. 38 | 39 | Objects of class \code{AsIs} in R, i.e. that are enclosed in a call to 40 | \code{I()} are treated as containers even if they are of length 1. 41 | This allows callers to indicate the desired representation of an R "scalar" 42 | as an array of length 1 in JSON 43 | } 44 | \usage{ 45 | toJSON(x, container = isContainer(x, asIs, .level), 46 | collapse = "\n", ..., .level = 1L, 47 | .withNames = length(x) > 0 && length(names(x)) > 0, .na = "null", 48 | .escapeEscapes = TRUE, pretty = FALSE, asIs = NA, .inf = " Infinity") 49 | } 50 | %- maybe also 'usage' for other objects documented here. 51 | \arguments{ 52 | \item{x}{the R object to be converted to JSON format} 53 | \item{\dots}{additional arguments controlling the formatting of the 54 | JSON. 55 | } 56 | \item{container}{a logical value indicating whether to treat the 57 | object as a vector/container or a scalar and so represent it as an 58 | array or primitive in JavaScript.} 59 | \item{collapse}{a string that is used as the separator when combining the individual lines of the 60 | generated JSON content} 61 | \item{.level}{an integer value. This is not a parameter the caller is supposed to supply. It is a 62 | value that is passed in recursive calls to identify the top-level and sub-level serialization to JSON 63 | and so help to identify when a scalar needs to be in a container and when it is legitimate to 64 | output a scalar value directly.} 65 | \item{.withNames}{a logical value. If we are dealing with a named 66 | vector/list, we typically generate a JSON associative 67 | array/dictionary. If there are no names, we create a simple array. 68 | This argument allows us to explicitly control whether we use a 69 | dictionary or to ignore the names and use an array. 70 | } 71 | \item{.na}{a value to use when we encounter an \code{NA} value in the R 72 | objects. This allows the caller to convert these to whatever makes 73 | sense to them. For example, we might specify this as \code{"null"} 74 | and then the \code{NA} values will appear as \code{null} in the JSON 75 | output. One can also specify an unusual numeric value, e.g. -9999999 76 | to indicate a missing value! 77 | } 78 | \item{.escapeEscapes}{a logical value that controls how 79 | new line and tab characters are serialized. If this is \code{TRUE}, 80 | we preserve them symbolically by escaping the \\. 81 | Otherwise, we replace them with their literal value. 82 | } 83 | \item{pretty}{a logical value that controls if extra processing is done 84 | on the result to make it indented for easier human-readability. 85 | At present, this reparses the generated JSON content and 86 | re-formats it (using libjson). This means that there 87 | can be three copies of the data in memory simultaneously - 88 | the original data, the JSON text and the pretty-printed 89 | version of the JSON text. For large objects, this can 90 | require a lot of memory. 91 | } 92 | \item{asIs}{a logical value that, if \code{TRUE} causes 93 | R vectors of length 1 to be represented as arrays in JSON, 94 | but if \code{FALSE} to be represented as scalars, where appropriate 95 | (i.e. not the top level of the JSON content). This avoids having 96 | to explicitly mark sub-elements in an R object as being of class 97 | \code{AsIs}. 98 | } 99 | \item{.inf}{how to represent infinity in JSON. This should be a string.} 100 | } 101 | 102 | \value{ 103 | A string containing the JSON content. 104 | } 105 | \references{ 106 | \url{http://www.json.org} 107 | } 108 | \author{Duncan Temple Lang } 109 | 110 | \seealso{ 111 | \code{\link{fromJSON}} 112 | } 113 | \examples{ 114 | toJSON(1:10) 115 | toJSON(rnorm(3)) 116 | toJSON(rnorm(3), digits = 4) 117 | 118 | toJSON(c("Duncan", "Temple Lang")) 119 | 120 | toJSON(c(FALSE, FALSE, TRUE)) 121 | 122 | # List of elements 123 | toJSON(list(1L, c("a", "b"), c(FALSE, FALSE, TRUE), rnorm(3))) 124 | # with digits controlling formatting of sub-elements 125 | toJSON(list(1L, c("a", "b"), c(FALSE, FALSE, TRUE), rnorm(3)), 126 | digits = 10) 127 | 128 | # nested lists 129 | toJSON(list(1L, c("a", "b"), list(c(FALSE, FALSE, TRUE), rnorm(3)))) 130 | 131 | # with names 132 | toJSON(list(a = 1L, c("a", "b"), c(FALSE, FALSE, TRUE), rnorm(3))) 133 | 134 | setClass("TEMP", representation(a = "integer", xyz = "logical")) 135 | setClass("TEMP1", representation(one = "integer", two = "TEMP")) 136 | 137 | new("TEMP1", one = 1:10, two = new("TEMP", a = 4L, xyz = c(TRUE, FALSE))) 138 | 139 | 140 | toJSON(list()) 141 | toJSON(emptyNamedList) 142 | toJSON(I(list("hi"))) 143 | toJSON(I("hi")) 144 | 145 | 146 | x = list(list(), 147 | emptyNamedList, 148 | I(list("hi")), 149 | "hi", 150 | I("hi")) 151 | toJSON(x) 152 | 153 | # examples of specifying .withNames 154 | toJSON(structure(1:3, names = letters[1:3])) 155 | toJSON(structure(1:3, names = letters[1:3]), .withNames = FALSE) 156 | 157 | 158 | # Controlling NAs and mapping them to whatever we want. 159 | toJSON(c(1L, 2L, NA), .na = "null") 160 | toJSON(c(1L, 2L, NA), .na = -9999) 161 | 162 | toJSON(c(1, 2, pi, NA), .na = "null") 163 | 164 | toJSON(c(TRUE, FALSE, NA), .na = "null") 165 | 166 | toJSON(c("A", "BCD", NA), .na = "null") 167 | 168 | toJSON( factor(c("A", "B", "A", NA, "A")), .na = "null" ) 169 | 170 | toJSON(list(TRUE, list(1, NA), NA), .na = "null") 171 | 172 | 173 | 174 | setClass("Foo", representation(a = "integer", b = "character")) 175 | obj = new("Foo", a = c(1L, 2L, NA, 4L), b = c("abc", NA, "def")) 176 | toJSON(obj) 177 | toJSON(obj, .na = "null") 178 | 179 | # hexmode example with .na ? 180 | 181 | toJSON(matrix(c(1, 2, NA, 4), 2, 2), .na = "null") 182 | toJSON(matrix(c(1, 2, NA, 4), 2, 2), .na = -9999999) 183 | 184 | 185 | x = '"foo\tbar\n\tagain"' 186 | cat(toJSON(x)) 187 | cat(toJSON(list(x))) 188 | 189 | # if we want to expand the new lines and tab characters 190 | cat(toJSON(x), .escapeEscapes = FALSE) 191 | 192 | 193 | # illustration of the asIs argument 194 | cat(toJSON(list(a = 1, b = 2L, c = TRUE, 195 | d = c(1, 3), 196 | e = "abc"), asIs = TRUE)) 197 | 198 | cat(toJSON(list(a = 1, b = 2L, c = TRUE, 199 | d = c(1, 3), 200 | e = "abc"), asIs = FALSE)) 201 | 202 | # extra level 203 | cat(toJSON(list(a = c(x = 1), b = 2L, c = TRUE, 204 | d = list(1, 3), 205 | e = "abc"), asIs = FALSE, pretty = TRUE)) 206 | 207 | 208 | # data frame by row as arrays 209 | twoRows = data.frame(a = 1:2, b = as.numeric(1:2)) 210 | j = toJSON(twoRows, byrow = TRUE) 211 | r = data.frame(do.call(rbind, fromJSON(j))) 212 | 213 | # here we keep the names of the columns on each row 214 | # which allows us to round-trip the object back to R 215 | j = toJSON(twoRows, byrow = TRUE, colNames = TRUE) 216 | r = data.frame(do.call(rbind, fromJSON(j))) 217 | } 218 | 219 | \keyword{IO} 220 | \keyword{programming} 221 | -------------------------------------------------------------------------------- /src/rparser.c: -------------------------------------------------------------------------------- 1 | #include "Rlibjson.h" 2 | 3 | typedef struct { 4 | int cumBytes; 5 | SEXP call; 6 | JSONSTREAM *stream; 7 | SEXP result; 8 | 9 | int simplify; 10 | int simplifyWithNames; 11 | SEXP nullValue; 12 | 13 | FILE *file; 14 | } RCallback; 15 | 16 | //#define R_DEBUG_STREAM 1 17 | //#define CHECK_CONTENT 1 18 | #ifdef CHECK_CONTENT 19 | static FILE *out = NULL; 20 | #endif 21 | 22 | void 23 | errorCB(void *ptr) 24 | { 25 | RCallback *data = (RCallback *) ptr; 26 | int num = 0; 27 | if(data) 28 | num = data->cumBytes; 29 | 30 | if(data->file) 31 | fclose(data->file); 32 | 33 | // if(data->stream) 34 | // json_delete_stream(data->stream); 35 | #ifdef CHECK_CONTENT 36 | if(out) { 37 | fclose(out); out = NULL; 38 | } 39 | #endif 40 | 41 | PROBLEM "failed to parse json at %d", num 42 | ERROR; 43 | } 44 | 45 | 46 | SEXP 47 | R_makeJSONRef(JSONNODE *node) 48 | { 49 | return(processJSONNode(node, json_type(node), 1, R_NilValue, 1, CE_NATIVE, NULL, GARBAGE)); 50 | } 51 | 52 | void 53 | R_json_parser_callback(JSONNODE *node, void *userdata) 54 | { 55 | SEXP ans; 56 | RCallback *data = (RCallback*)userdata; 57 | 58 | SEXP tmp; 59 | 60 | 61 | tmp = processJSONNode(node, json_type(node), data->simplify, data->nullValue, data->simplifyWithNames, 62 | CE_NATIVE, NULL, GARBAGE); 63 | 64 | if(data->call == R_NilValue) { 65 | ans = tmp; 66 | } else { 67 | // SETCAR( CDR(e), ScalarInteger(json_type(node))); 68 | PROTECT(tmp); 69 | PROTECT(ans = tmp); // R_makeJSONRef(node)); 70 | SETCAR( CDR(data->call), ans); 71 | 72 | ans = Rf_eval(data->call, R_GlobalEnv); 73 | UNPROTECT(2); 74 | } 75 | data->result = ans; 76 | R_PreserveObject(data->result); 77 | } 78 | 79 | 80 | 81 | static int 82 | getData(SEXP call, JSONSTREAM *stream, int *numBytes) 83 | { 84 | SEXP r_str; 85 | int num; 86 | 87 | 88 | PROTECT(r_str = Rf_eval(call, R_GlobalEnv)); 89 | if( (num = Rf_length(r_str)) ) { 90 | const char *ptr = CHAR(STRING_ELT(r_str, 0)); 91 | int len = strlen(ptr); 92 | 93 | *numBytes += len; 94 | ptr = strdup(ptr); //xxx 95 | #ifdef CHECK_CONTENT 96 | if(!out) 97 | out = fopen("/tmp/check.json", "w"); 98 | #endif 99 | 100 | 101 | #if R_DEBUG_STREAM 102 | fprintf(stderr, "# %d to %d\n '%s'\n", (int) strlen(ptr), *numBytes, ptr); 103 | #endif 104 | 105 | #ifdef CHECK_CONTENT 106 | fprintf(out, "%s", ptr); 107 | #endif 108 | 109 | json_stream_push(stream, ptr); 110 | 111 | } else { 112 | #if 0 113 | fprintf(stderr, "finished reading data with %d bytes\n", *numBytes); 114 | #endif 115 | } 116 | UNPROTECT(1); 117 | 118 | return(num > 0); 119 | } 120 | 121 | 122 | int 123 | readFileData(FILE *f, JSONSTREAM *stream, int *numBytes) 124 | { 125 | char buffer[1024]; 126 | size_t num; 127 | int len = sizeof(buffer)/sizeof(buffer[0]) - 1; 128 | num = fread(buffer, 1, len - 2, f); 129 | *numBytes += num; 130 | buffer[num] = '\0'; 131 | 132 | json_stream_push(stream, strdup(buffer)); 133 | #ifdef R_DEBUG_STREAM 134 | fprintf(stderr, "Read (%d) %d/%d bytes\n'%s'\n", (int) strlen(buffer), (int) num, *numBytes, buffer); 135 | #endif 136 | return(num == len - 2); 137 | } 138 | 139 | 140 | typedef void (*ParserCallback)(JSONNODE *, void *); 141 | 142 | SEXP 143 | R_json_parser_init_from_con(SEXP conCall, SEXP cbCall, 144 | SEXP simplify, SEXP nullValue, SEXP simplifyWithNames) 145 | { 146 | JSONSTREAM *stream; 147 | RCallback cb; 148 | int nprotect = 0; 149 | ParserCallback callback; 150 | 151 | /* If the callback is an external pointer, use that as the callback for the top-level JSONNODE objects */ 152 | if(TYPEOF(cbCall) == EXTPTRSXP) 153 | callback = R_ExternalPtrAddr(cbCall); 154 | else /* otherwise use our own callback to process the JSONNODE */ 155 | callback = R_json_parser_callback; 156 | 157 | stream = json_new_stream(callback, errorCB, &cb); 158 | if(!stream) { 159 | PROBLEM "Couldn't create json stream" 160 | ERROR; 161 | } 162 | 163 | cb.stream = stream; 164 | cb.cumBytes = 0; 165 | cb.result = NULL; 166 | cb.simplify = INTEGER(simplify)[0]; 167 | cb.simplifyWithNames = INTEGER(simplifyWithNames)[0]; 168 | cb.nullValue = nullValue; 169 | cb.file = NULL; 170 | 171 | if(TYPEOF(cbCall) == CLOSXP) { 172 | PROTECT(cb.call = allocVector(LANGSXP, 2)); 173 | SETCAR(cb.call, cbCall); 174 | nprotect++; 175 | } else 176 | cb.call = cbCall; // expression. 177 | 178 | if(TYPEOF(conCall) == STRSXP) { 179 | FILE *f; 180 | f = fopen(CHAR(STRING_ELT(conCall, 0)), "r"); 181 | if(!f) { 182 | json_delete_stream(stream); 183 | PROBLEM "cannot open JSON file %s", CHAR(STRING_ELT(conCall, 0)) 184 | ERROR; 185 | } 186 | cb.file = f; 187 | 188 | while(readFileData(f, stream, &(cb.cumBytes))) { } 189 | fclose(f); 190 | } else { 191 | while(getData(conCall, stream, &(cb.cumBytes))) { } 192 | } 193 | 194 | if(nprotect) 195 | UNPROTECT(nprotect); 196 | 197 | #ifdef CHECK_CONTENT 198 | if(out) { 199 | fclose(out); out = NULL; 200 | } 201 | #endif 202 | 203 | json_delete_stream(stream); 204 | 205 | return(cb.result ? cb.result : R_NilValue); 206 | } 207 | 208 | 209 | 210 | 211 | #if 1 212 | 213 | SEXP top = NULL; 214 | 215 | void 216 | R_json_cb_test_stream(JSONNODE *node, void *userdata) 217 | { 218 | // fprintf(stderr, "Finished parsing\n"); 219 | top = processJSONNode(node, 0, 1, R_NilValue, 1, CE_NATIVE, NULL, GARBAGE); 220 | R_PreserveObject(top); 221 | } 222 | 223 | static int total = 0; 224 | int 225 | test_get_data(FILE *f, JSONSTREAM *stream) 226 | { 227 | char buffer[1024]; 228 | size_t num; 229 | int len = sizeof(buffer)/sizeof(buffer[0]) - 1; 230 | num = fread(buffer, 1, len - 2, f); 231 | total += num; 232 | buffer[num] = '\0'; 233 | 234 | json_stream_push(stream, strdup(buffer)); 235 | #ifdef R_DEBUG_STREAM 236 | fprintf(stderr, "Read (%d) %d/%d bytes\n'%s'\n", (int) strlen(buffer), (int) num, total, buffer); 237 | #endif 238 | return(num == len - 2); 239 | } 240 | 241 | SEXP 242 | R_json_parser_test_stream(SEXP r_filename) 243 | { 244 | JSONSTREAM *stream; 245 | FILE *fileptr; 246 | 247 | fileptr = fopen(CHAR(STRING_ELT(r_filename, 0)), "r"); 248 | if(!fileptr) { 249 | PROBLEM "cannot open file" 250 | ERROR; 251 | } 252 | 253 | stream = json_new_stream(R_json_cb_test_stream, errorCB, NULL); 254 | if(!stream) { 255 | PROBLEM "Couldn't create json stream" 256 | ERROR; 257 | } 258 | 259 | json_stream_push(stream, "{ \"a\": [1, 2, 3]}[true, false]"); 260 | 261 | while(test_get_data(fileptr, stream)) { } 262 | json_stream_push(stream, ""); 263 | 264 | fclose(fileptr); 265 | json_delete_stream(stream); 266 | 267 | return(R_NilValue); 268 | } 269 | 270 | 271 | SEXP 272 | R_json_parser_test_stream_str(SEXP r_filename) 273 | { 274 | JSONSTREAM *stream; 275 | const char *str = CHAR(STRING_ELT(r_filename, 0)); 276 | 277 | stream = json_new_stream(R_json_cb_test_stream, errorCB, NULL); 278 | if(!stream) { 279 | PROBLEM "Couldn't create json stream" 280 | ERROR; 281 | } 282 | 283 | json_stream_push(stream, str); 284 | 285 | R_ReleaseObject(top); 286 | return(top); 287 | // return(R_NilValue); 288 | } 289 | 290 | 291 | SEXP 292 | R_json_parser_test_stream_chunk(SEXP r_filename) 293 | { 294 | JSONSTREAM *stream; 295 | const char *str = CHAR(STRING_ELT(r_filename, 0)); 296 | 297 | stream = json_new_stream(R_json_cb_test_stream, errorCB, NULL); 298 | if(!stream) { 299 | PROBLEM "Couldn't create json stream" 300 | ERROR; 301 | } 302 | 303 | int len = strlen(str), cur = 0, blocksize = 100; 304 | int count = 0; 305 | char tmp[blocksize + 1]; 306 | tmp[blocksize] = '\0'; 307 | while(cur < len) { 308 | strncpy(tmp, str + cur, blocksize); 309 | 310 | #ifdef R_DEBUG_STREAM 311 | fprintf(stderr, "%d) %s\n", count++, tmp); 312 | #endif 313 | json_stream_push(stream, strdup(tmp)); 314 | cur += blocksize; 315 | } 316 | 317 | json_delete_stream(stream); 318 | R_ReleaseObject(top); 319 | return(top); 320 | } 321 | 322 | 323 | 324 | SEXP 325 | R_json_parser_test_stream_chunk_con(SEXP r_getData) 326 | { 327 | JSONSTREAM *stream; 328 | 329 | stream = json_new_stream(R_json_cb_test_stream, errorCB, NULL); 330 | if(!stream) { 331 | PROBLEM "Couldn't create json stream" 332 | ERROR; 333 | } 334 | 335 | int n = 0; 336 | while(getData(r_getData, stream, &n)) {} 337 | 338 | json_delete_stream(stream); 339 | 340 | R_ReleaseObject(top); 341 | return(top); 342 | } 343 | 344 | 345 | #endif 346 | -------------------------------------------------------------------------------- /inst/doc/missingValues.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | JSON, null and NA 4 | 5 |

    16 |

    JSON, null and NA

    Duncan Temple Lang

    University of California at Davis

    Department of Statistics


    Limitations of JSON regarding the meaning of null

    17 | JavaScript Object Notation (JSON) is a convenient format for 18 | representing data and facilitates transferring data between 19 | applications. It is widely used in different applications, Web 20 | services and other contexts. As such, it is useful for R to be able 21 | to import and export data in this format. Unfortunately, JSON is a 22 | little too simple and cannot faithfully represent all of the types and 23 | values in R. Most specifically, there is no way to support NA, 24 | Inf or NaN. Typically, these 25 | values are represented in JSON as "null". However, that is also used 26 | to represent a null object. So there is ambiguity in how we interpret 27 | null in JSON. 28 | We don't know whether it is NA, NaN, Inf or NULL in R. 29 | This many-to-one mapping results in a loss of information. 30 |

    31 | In spite of the shortcomings of the format, we can still work with 32 | JSON. However, how we convert null values to R and how we 33 | convert NA values from R is not automatic and uniquely defined. 34 | For that reason, the caller must control how these are mapped. 35 | We provide some mechanisms to do this in the 36 | fromJSON() and toJSON() functions. 37 |

    38 | When converting R objects to JSON via toJSON(), 39 | one can specify how to map NA values to JSON. 40 | One provides a value for the parameter .na 41 | to control this. 42 | For example, suppose we want to transform the R list 43 |

     44 | x = list(1, 2, NA, c(TRUE, NA, FALSE))
     45 | 
    46 |
    47 |

    48 | to JSON and want NA values to map to null. 49 | We can achieve this with 50 |

     51 | toJSON(x, .na = "null")
     52 | 
    53 |
    54 |

    55 |

    56 | In some applications, we represent a missing value with a fixed number that is unlikely 57 | to occur in actual data, e.g. -99999. 58 | We can map NA values to such a number with 59 |

     60 | toJSON(list(1, 2, list(NA)), .na = -99999)
     61 | 
    62 |
    63 |

    64 |

    65 | Now consider round-tripping NA, e.g. 66 |

     67 | o = toJSON ( NA )
     68 | 
     69 | [1] "[ null ]"
     70 | 
    71 | fromJSON( o ) 72 |
     73 | [[1]]
     74 | NULL
     75 | 
    76 |
    77 |
    78 |

    79 | So we have lost information. 80 |

    81 | We can correct this loss of information by 82 | specifying how to map null values in JSON 83 | to R values. We use the nullValue 84 |

     85 | fromJSON( toJSON ( NA ), nullValue = NA)
     86 | 
    87 |
    88 |

    89 | Again, here we as the caller of fromJSON() 90 | (and also toJSON()) we are providing 91 | information about how to transfer the null value from JSON to R. 92 | Only we know what it means in this case. 93 | If we knew that the null corresponded to Inf, 94 | we could specify that: 95 |

     96 |  fromJSON( "[null]", nullValue = Inf)
     97 | 
    98 |
    99 |

    100 |

    101 | Where this mechanism breaks down is when we have multiple 102 | null values in our JSON content and they map to different 103 | R values, e.g. NULL, NA and NaN. 104 | The nullValue parameter is a global replacement for 105 | null entries in the JSON. To adaptively process these null 106 | entries in a context specific manner, we have to use a customized 107 | parser. We can do this by providing an R function as the 108 | callback handler for the JSON parser. 109 |

    110 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | 2 | RJSONIO 3 | 4 | 5 | Version 1.3-1 6 | 7 | * Fix for simplify = TRUE and getting the correct element type. Problem identified by Ivan Yevshin 8 | 9 | 10 | 11 | Version 1.3-0 12 | 13 | 14 | 15 | Version 1.2-1 16 | 17 | * Fix for toJSON(character(0)) in a hierarchy. Found by Kevin Ushey. 18 | 19 | * Method for toJSON() for function. 20 | 21 | 22 | 23 | Version 1.2-0 24 | 25 | * Included updated code from libjson which is used if one does not have libjson installed. 26 | 27 | * Method for toJSON() for function. 28 | 29 | 30 | 31 | Version 1.1-0 32 | 33 | * Inf in R mapped to Infinity in JSON. This is customizable. 34 | 35 | * Fixed dQuote() to handle empty vectors and not create a vector of length 1. This allows toJSON() to work correctly. Thanks to Murat Tasan for identifying the larger problem. 36 | 37 | * Added toJSON() method for data.frame that allows output by row and also handles the cases where the number of rows is 1. Fix from Joe Cheng. 38 | 39 | 40 | 41 | Version 1.0-4 42 | 43 | * Updates for toJSON() for handling array, table and function objects. These don't fail (with infinite recursion) but may not be what is desired for a particular application. Identified by Stavros Macrakis 44 | 45 | * Added a warning about +/- Inf values in a vector. 46 | 47 | 48 | 49 | 50 | Version 1.0-3 51 | 52 | * Removed the limit on the size of the string that was on by default in libjson (via JSON_SECURITY_MAX_STRING_LENGTH in JSONOptions.h). Issue identified by Adrian Alexa. 53 | 54 | 55 | 56 | Version 1.1-0 57 | 58 | * Escape \b \r and \f when exporting strings from R to JSON. Thanks to Joe Cheng. 59 | 60 | * Fix use of snprintf in libjson code to remove the std:: qualifier. 61 | 62 | * 63 | 64 | 65 | 66 | Version 1.0-1 67 | 68 | * Fixes to the libjson code to make it compile on different machines. 69 | 70 | 71 | 72 | Version 1.0-0 73 | 74 | * toJSON() for S4 objects adds , separating slots that was omitted. 75 | 76 | * Force the values of container and .withNames in the toJSON() generic to fix a bug that caused vectors of length 1 with names to appear as scalars and so lose the names. Thanks to Igor Elbert. 77 | 78 | * Added stringFun as parameter in fromJSON() to allow processing of each string value as it is encountered. This can be used to convert strings to arbitrary R objects. 79 | 80 | * Initial implementation of parsing streaming data from a file or connection. Unreliable at present. 81 | 82 | * Changes to libjson source for missing arguments in C++ macros. 83 | 84 | 85 | 86 | 87 | Version 0.99-0 88 | 89 | * Implemented reading JSON from a connection using a "pull" mechanism which reads from the connection as more content is needed by the parser. This avoids having all the content in memory before parsing. 90 | 91 | * Incorporated libjson_7.6.0 which has support for escaped content (e.g. \x). 92 | 93 | 94 | 95 | Version 0.98-1 96 | 97 | * Compilation issues fixed for new libjson code on Solaris and Windows. Thanks to Brian Ripley for Solaris corrections. 98 | 99 | 100 | 101 | Version 0.98-0 102 | 103 | * Update default libjson code to version 7.4.0. 104 | 105 | * Changes to configuration to allow the use of a version of libjson that is not installed but not in the RJSONIO package directory itself. Use the environment variable LIBJSON_SRC. 106 | 107 | * Configuration determines version of libjson and adapts compilation flags accordingly. 108 | 109 | 110 | 111 | Version 0.97-0 112 | 113 | * Add isValidJSON() to test whether the JSON content is valid. Suggested by Jeroen Ooms. 114 | 115 | 116 | 117 | Version 0.96-0 118 | 119 | * Added encoding argument for fromJSON() and that encoding is preserved on the resulting strings. Thanks to Tony Breyal for pointing out the issue. 120 | 121 | 122 | 123 | Version 0.95-0 124 | 125 | * In fromJSON(), when nullValue is (the logical NA) we attempt to simplify vectors with JSON null values. 126 | 127 | 128 | 129 | Version 0.94-0 130 | 131 | * Added simplifyWithNames to fromJSON() for controlling whether we attempt to collapse collections of values read from JSON if they have names. This can be used to collapse unnamed vectors, but leave named lists that would otherwise be collapsed to vectors. 132 | 133 | 134 | 135 | Version 0.93-0 136 | 137 | * Added support in fromJSON() for collapsing particular types of elements, i.e. logicals, numbers or characters via StrictLogical, StrictNumeric and StrictCharacter. This allows "strict" collapsing, but for different types, while leaving others as lists. These can be combined. 138 | 139 | 140 | 141 | Version 0.92-0 142 | 143 | * Added to the ability to control whether we simplify the content using simplify = Strict or or . 144 | 145 | 146 | 147 | Version 0.91-0 148 | 149 | * Added .escapeEscapes to toJSON() to allow the caller to preserve new lines and tabs symbolically or not. Thanks to Antonio Piccolboni for the report about the issue. 150 | 151 | 152 | 153 | Version 0.9-0 154 | 155 | * Added .na parameter to the toJSON() function and methods so that the caller can control how values are mapped to JSON. This defaults to "null" so that the resulting JSON is well-formed. However, users should explicitly think about how values (and Inf and NaN) are mapped to JSON in order to avoid ambiguity and faithfully serialize their data in a meaningful manner. 156 | 157 | * Added a nullValue parameter to fromJSON() to allow the caller to provide an R object that will be used when we encounter a JSON null value. This can be used for example to map null to in R. 158 | 159 | * Added more support for simplifying lists to vectors of different types. In the future, I might add a simplify = "strict" mode that would only collapse vectors if all the elements were of the same type, not just compatible types. In other words, [true, 1 ] would not collapse to c(1, 1) in R. 160 | 161 | 162 | 163 | Version 0.8-2 164 | 165 | * Corrected what toJSON() does with new lines (\n) and avoid the escaping of the \. Thanks to Antonio Piccolboni for the report. 166 | 167 | 168 | 169 | Version 0.8-1 170 | 171 | * Corrections to the libjson C/C++ code from Brian Ripley. 172 | 173 | 174 | 175 | Version 0.8-0 176 | 177 | * Added a .withNames parameter to toJSON() so that the caller can explicitly control whether an R object with names is written as an associative array or as a simple array. 178 | 179 | 180 | * Added a simplify parameter to fromJSON() that controls whether we collapse lists of homogeneous element types to an R vector. 181 | 182 | 183 | 184 | Version 0.7-3 185 | 186 | * Added .withNames parameter for toJSON() which allows the caller to control whether we ignore or use any names. Defaults to use the names if they are present. 187 | 188 | 189 | 190 | Version 0.7-3 191 | 192 | * Honor the collapse argument in more places to allow avoiding new line characters being inserted. 193 | 194 | 195 | 196 | Version 0.7-2 197 | 198 | * Copied compiler flags for libjson code into Makevars.win 199 | 200 | 201 | 202 | Version 0.7-1 203 | 204 | * Correction for toJSON() method for handling of \ in strings so that they round-trip and work in other JSON tools. Thanks to Patrick Perry. 205 | 206 | 207 | 208 | Version 0.7-0 209 | 210 | * Round-tripping from JSON to R and back behaves a lot more consistently. Thanks to Kevin Coombes for the examples/tests. Next, we will add functionality to customize serialization of . 211 | 212 | * Change to the default value of container of toJSON() so that this is when at the top-level or initial call to toJSON(). 213 | 214 | * We now know the type of the top-most node so can correctly handle empty associative arrays, etc. 215 | 216 | 217 | 218 | Version 0.6-0 219 | 220 | * Updated the libjson source code in the package to libjson 7.0.1. This removes a bug in parsing numbers of the form 3.14E4. Found by Jeroen Ooms. 221 | 222 | * Added configuration so that we can use a libjson installed on the system. This avoids issues of using older versions of libjson shipped with this package. 223 | 224 | 225 | 226 | Version 0.5-0 227 | 228 | * Enhancements to disambiguate serializing empty lists from as empty arrays or associative arrays. See also emptyNamedList to map to {}. 229 | 230 | * Method for identifying an R scalar that should be mapped to a JSON array via the AsIs class and I() function. 231 | 232 | * toJSON() honors these also ensuring transformation from JSON to R to JSON preserves the same structure. 233 | 234 | * Both changes thanks to suggestions by Keith Bonawitz. 235 | 236 | 237 | 238 | Version 0.4-2 239 | 240 | * Fixed significant memory leaks found by Keith Bonawitz 241 | 242 | 243 | 244 | Version 0.4-1 245 | 246 | * Tidied up C++ code from libjsonio to avoid a warning about no argument to initializeFetch() when compiling the C++ code. 247 | 248 | * Fixed a C routine (R_fromJSON) that did not return a value. 249 | 250 | 251 | 252 | Version 0.4-0 253 | 254 | * fromJSON() now uses libjson for the native parsing and a C routine to transform the resulting tree into R. This leads to a considerable speedup in parsing documents, approximately a factor of 200 over the customizable, event driven mechanism in earlier versions and still available in this package via the basicJSONHandler() function and fromJSON(). 255 | 256 | 257 | 258 | Version 0.3-4 259 | 260 | * Refinement of handling large integers that do not fit into a 4 byte int. Tested on Windows. 261 | 262 | 263 | 264 | Version 0.3-3 265 | 266 | * Handle large integers that do not fit into a 4 byte int. Return as numeric values. 267 | 268 | 269 | 270 | Version 0.3-1 271 | 272 | * Convert factors to character vectors in toJSON() and then serialize. 273 | 274 | 275 | 276 | Version 0.2-4 277 | 278 | * Handles UTF-8 content as input. We convert the text to raw and then integer values. 279 | 280 | 281 | 282 | Version 0.2-3 283 | 284 | * (Minor) Change to the C code to make it compile on Windows. 285 | 286 | 287 | 288 | Version 0.2-2 289 | 290 | * named atomic/primitive vectors serialized as associative arrays rather than simple arrays. 291 | 292 | 293 | 294 | Version 0.2-1 295 | 296 | * names on R objects from associative arrays from JSON were in reverse order. 297 | 298 | 299 | 300 | Version 0.2-0 301 | 302 | * Scalar, by default, values are represented in JSON as scalars and not arrays of length 1. One can control this via the container parameter in toJSON(). 303 | 304 | 305 | --------------------------------------------------------------------------------