Rev 8301 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#include "JSON_parser.h"#include <Rinternals.h>#include <Rdefines.h>#include "ConvertUTF.h"#include <stdlib.h>/* A structure which we use to store information that is used within callsto the R callback function. The */typedef struct {SEXP func; /* The R expression to call the user-specified function */SEXP names; /* the names vector of the type (first argument) which we set on each call.*/int encoding; /* The user-specified encoding. XXX fix */} RJSONParserInfo;/* Names for the types which we use on R type identifiers in the callback. */const char *jsonTypeNames[] = {"NONE","ARRAY_BEGIN","ARRAY_END","OBJECT_BEGIN","OBJECT_END","INTEGER","FLOAT","NULL","TRUE","FALSE","STRING","KEY"};int R_json_basicCallback(void* ctx, int type, const struct JSON_value_struct* value);SEXP convertJSONValueToR(int type, const struct JSON_value_struct *value, cetype_t encoding);void R_json_parse_character(SEXP r_input, SEXP maxChar, struct JSON_parser_struct *parser);void R_json_parse_connection(SEXP r_input, SEXP numLines, struct JSON_parser_struct *parser);SEXPR_readFromJSON(SEXP r_input, SEXP depth, SEXP allowComments, SEXP func, SEXP data, SEXP maxChar){JSON_config conf;struct JSON_parser_struct *parser;SEXP ans = R_NilValue;int do_unprotect = 1;RJSONParserInfo info = {NULL, NULL, CE_NATIVE};init_JSON_config(&conf);conf.depth = INTEGER(depth)[0];conf.allow_comments = LOGICAL(allowComments)[0];/* Handle the callback function and data here. First the C routines and data context.*/if(Rf_length(data)) {SEXP tmp = VECTOR_ELT(data, 1);void *ptr;switch(TYPEOF(tmp)) {case NILSXP:ptr = NULL;break;case INTSXP:case LGLSXP:ptr = INTEGER(tmp);break;case REALSXP:ptr = REAL(tmp);break;case VECSXP:ptr = (void *) VECTOR_PTR_RO(tmp);break;default:ptr = NULL;}conf.callback = (JSON_parser_callback) R_ExternalPtrAddr(VECTOR_ELT(data, 0));conf.callback_ctx = ptr;do_unprotect = 0;} else if(func != R_NilValue && TYPEOF(func) == CLOSXP) {/* we have a function*/SEXP e;PROTECT(e = allocVector(LANGSXP, 3));SETCAR(e, func);SETCAR(CDR(e), allocVector(INTSXP, 1));SET_NAMES(CAR(CDR(e)), info.names = NEW_CHARACTER(1));SETCAR(CDR(CDR(e)), R_NilValue);info.func = e;ans = R_NilValue;conf.callback = R_json_basicCallback;conf.callback_ctx = &info;} else if(func == R_NilValue)PROTECT(ans = NEW_LIST(1));else { /* You what? */Rf_error("unhandled type of R object as handler function %d", TYPEOF(func));}parser = new_JSON_parser(&conf);if(inherits(r_input, "connection")) {R_json_parse_connection(r_input, maxChar, parser);} else {R_json_parse_character(r_input, maxChar, parser);}if(do_unprotect)UNPROTECT(1);return(ans);}voidR_json_parse_character(SEXP r_input, SEXP maxChar, struct JSON_parser_struct *parser){const char *input = NULL;int *ivals = NULL;unsigned int count = 0, len;int next_char;count = INTEGER(maxChar)[0];len = INTEGER(maxChar)[1];if(TYPEOF(r_input) == RAWSXP)input = (char *) RAW(r_input);else if(TYPEOF(r_input) == INTSXP) {ivals = INTEGER(r_input);} elseinput = CHAR(STRING_ELT(r_input, 0));for (; count < len ; ++count) {if(ivals)next_char = ivals[count];elsenext_char = input[count];if (next_char <= 0) {break;}/* fprintf(stderr, "%d) %c %u\n", count, next_char, (unsigned int) next_char);fflush(stderr); */if (!JSON_parser_char(parser, next_char)) {delete_JSON_parser(parser);if(ivals) {Rf_error("JSON parser error: syntax error, int %d (%d)\n", count, ivals[count]);} else {Rf_error("JSON parser error: syntax error, byte %d (%c)\n", count, input[count]);}}}if (!JSON_parser_done(parser)) {delete_JSON_parser(parser);Rf_error("JSON parser error: syntax error, byte %d\n", count);}}voidR_json_parse_connection(SEXP r_input, SEXP numLines, struct JSON_parser_struct *parser){const char *input;unsigned int count = 0, len, totalCount = 0, lineCount = 0;SEXP call, ans;int n, i, maxNumLines;PROTECT(call = allocVector(LANGSXP, 3));SETCAR(call, Rf_install("readLines"));SETCAR(CDR(call), r_input);SETCAR(CDR(CDR(call)), ScalarInteger(1));maxNumLines = INTEGER(numLines)[0];while(1) {PROTECT(ans = Rf_eval(call, R_GlobalEnv));n = Rf_length(ans);lineCount += n;if(n == 0) {UNPROTECT(1);break;}for(i = 0 ; i < n ; i++) {input = CHAR(STRING_ELT(ans, i));len = (int)strlen(input);for (count = 0; count < len ; ++count, ++totalCount) {int next_char = input[count];if (next_char <= 0) {break;}if (!JSON_parser_char(parser, next_char)) {delete_JSON_parser(parser);Rf_error("JSON parser error: syntax error, byte %d (%c)", totalCount, input[count]);}}}UNPROTECT(1);if(maxNumLines > 0 && lineCount == maxNumLines)break;}UNPROTECT(1);if (!JSON_parser_done(parser)) {delete_JSON_parser(parser);Rf_error("JSON parser error: syntax error, incomplete content");}}/*The "simple"/standard callback to an R function.*/intR_json_basicCallback(void* ctx, int type, const struct JSON_value_struct* value){RJSONParserInfo *info = ( RJSONParserInfo *) ctx;if(info->func != NULL) {SEXP result, tmp;tmp = CAR(CDR(info->func));INTEGER(tmp)[0] = type; /* Names too */SET_STRING_ELT(info->names, 0, mkChar(jsonTypeNames[type]));if(value)SETCAR(CDR(CDR(info->func)), convertJSONValueToR(type, value, info->encoding));else if(type == JSON_T_TRUE)SETCAR(CDR(CDR(info->func)), ScalarLogical(1));else if(type == JSON_T_FALSE)SETCAR(CDR(CDR(info->func)), ScalarLogical(0));elseSETCAR(CDR(CDR(info->func)), R_NilValue);result = Rf_eval(info->func, R_GlobalEnv);if(isLogical(result))return(LOGICAL(result)[0]);else if(isInteger(result))return(INTEGER(result)[0]);else if(isNumeric(result))return((int)REAL(result)[0]);elsereturn(1);}return(1);}/*Convert a JSON object to an R object.*/SEXPconvertJSONValueToR(int type, const struct JSON_value_struct *value, cetype_t encoding){SEXP ans = R_NilValue;switch(type) {case JSON_T_INTEGER:ans = ScalarInteger((int) ((long) value->vu.integer_value));break;case JSON_T_FLOAT:ans = ScalarReal((double)value->vu.float_value);break;case JSON_T_NULL:ans = R_NilValue;break;case JSON_T_FALSE:ans = ScalarLogical(0);break;case JSON_T_TRUE:ans = ScalarLogical(1);break;case JSON_T_STRING:case JSON_T_KEY:ans = ScalarString(mkCharLenCE(value->vu.str.value,(int)value->vu.str.length, encoding));break;}return(ans);}/*An example native/C callback that just prints the type of the elements "passing" through.*/intR_json_testNativeCallback(void* ctx, int type, const struct JSON_value_struct* value){REprintf("%d (ctx = %p, value = %p)\n", type, ctx, (void *)value);return(1);}intR_json_degenerateNativeCallback(void* ctx, int type, const struct JSON_value_struct* value){return(1);}/*A callback that handles integers (and only integers)*/static int int_cb_counter;intR_json_IntegerArrayCallback(void* ctx, int type, const struct JSON_value_struct* value){int *p = (int *) ctx;if(type == JSON_T_ARRAY_BEGIN)int_cb_counter = 0;else if(type == JSON_T_INTEGER)p[int_cb_counter++] = (int)value->vu.integer_value;return(1);}static int real_cb_counter;/*A callback that handles reals (and only integers)*/intR_json_RealArrayCallback(void* ctx, int type, const struct JSON_value_struct* value){double *p = (double *) ctx;if(type == JSON_T_ARRAY_BEGIN)real_cb_counter = 0;else if(type == JSON_T_FLOAT)p[real_cb_counter++] = (double)value->vu.float_value;return(1);}static int logical_cb_counter;/*A callback that handles logicals (and only logicals)*/intR_json_LogicalArrayCallback(void* ctx, int type, const struct JSON_value_struct* value){int *p = (int *) ctx;if(type == JSON_T_ARRAY_BEGIN)logical_cb_counter = 0;else if(type == JSON_T_FLOAT)p[logical_cb_counter++] = 1;else if(type == JSON_T_FLOAT)p[logical_cb_counter++] = 1;return(1);}