Annotation of parser3/src/classes/json.C, revision 1.1
1.1 ! misha 1: /** @file
! 2: Parser: @b json parser class.
! 3:
! 4: Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)
! 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
! 6: */
! 7:
! 8: static const char * const IDENT_RESPONSE_C="$Date: 2005-08-09 08:14:48 $";
! 9:
! 10: #include "classes.h"
! 11: #include "pa_vmethod_frame.h"
! 12:
! 13: #include "pa_request.h"
! 14: #include "pa_vbool.h"
! 15:
! 16: #include "pa_charset.h"
! 17: #include "pa_charsets.h"
! 18: #include "JSON_parser.h"
! 19:
! 20: // class
! 21:
! 22: class MJson: public Methoded {
! 23: public:
! 24: MJson();
! 25: public: // Methoded
! 26: bool used_directly() { return true; }
! 27: };
! 28:
! 29: // global variable
! 30:
! 31: DECLARE_CLASS_VAR(json, new MJson, 0);
! 32:
! 33: // methods
! 34: struct Json {
! 35: Stack<Value*> stack;
! 36: Stack<String::Body> key_stack;
! 37:
! 38: String::Body key;
! 39: Value* result;
! 40:
! 41: Junction* hook;
! 42: Charset *charset;
! 43: bool handle_double;
! 44: public:
! 45: Json(Charset* acharset): stack(), key_stack(), key(), result(NULL), hook(NULL), charset(acharset), handle_double(true){}
! 46: };
! 47:
! 48: static void set_json_value(Json *json, Value *value){
! 49: Value *top = json->stack.top_value();
! 50: if(json->key.is_empty()){
! 51: top->put_element(String(format(top->get_hash()->count(), 0)), value, true);
! 52: } else {
! 53: top->put_element(String(json->key, String::L_TAINTED), value, true);
! 54: json->key=String::Body();
! 55: }
! 56: }
! 57:
! 58: String::Body json_string(Json *json, const JSON_value* value){
! 59: return json->charset !=NULL ?
! 60: Charset::transcode(String::Body(value->vu.str.value, value->vu.str.length), UTF8_charset, *json->charset) :
! 61: String::Body(pa_strdup(value->vu.str.value, value->vu.str.length), value->vu.str.length);
! 62: }
! 63:
! 64: static Value *json_hook(Junction *hook, String::Body key, Value* value){
! 65: return value;
! 66: }
! 67:
! 68: static int json_callback(Json *json, int type, const JSON_value* value)
! 69: {
! 70: switch(type) {
! 71: case JSON_T_OBJECT_BEGIN:{
! 72: Value *v = new VHash();
! 73: if (json->hook){
! 74: json->key_stack.push(json->key);
! 75: } else {
! 76: if (json->stack.count()) set_json_value(json, v);
! 77: }
! 78: json->stack.push(v);
! 79: break;
! 80: }
! 81: case JSON_T_OBJECT_END:{
! 82: if (json->hook){
! 83: String::Body key = json->key_stack.pop();
! 84: json->result = json_hook(json->hook, key, json->stack.pop());
! 85:
! 86: if (json->stack.count()){
! 87: json->key = key;
! 88: set_json_value(json, json->result);
! 89: }
! 90: } else {
! 91: json->result = json->stack.pop();
! 92: }
! 93: break;
! 94: }
! 95: case JSON_T_ARRAY_BEGIN:{
! 96: Value *v = new VHash();
! 97: set_json_value(json, v);
! 98: json->stack.push(v);
! 99: break;
! 100: }
! 101: case JSON_T_ARRAY_END:
! 102: json->stack.pop();
! 103: break;
! 104: case JSON_T_KEY:
! 105: json->key = json_string(json, value);
! 106: break;
! 107: case JSON_T_INTEGER:
! 108: set_json_value(json, new VInt((int)value->vu.integer_value));
! 109: break;
! 110: case JSON_T_FLOAT:
! 111: if (json->handle_double){
! 112: set_json_value(json, new VDouble( String(json_string(json, value), String::L_TAINTED).as_double() ));
! 113: break;
! 114: } // else is JSON_T_STRING
! 115: case JSON_T_STRING:
! 116: set_json_value(json, new VString(*new String(json_string(json, value), String::L_TAINTED)));
! 117: break;
! 118: case JSON_T_NULL:
! 119: set_json_value(json, new VVoid());
! 120: break;
! 121: case JSON_T_TRUE:
! 122: set_json_value(json, &VBool::get(true));
! 123: break;
! 124: case JSON_T_FALSE:
! 125: set_json_value(json, &VBool::get(false));
! 126: break;
! 127: }
! 128: return 1;
! 129: }
! 130:
! 131: static char* json_error_message(int error_code){
! 132: static char* error_messages[] = {
! 133: NULL,
! 134: "invalid char",
! 135: "invalid keyword",
! 136: "invalid escape sequence",
! 137: "invalid unicode sequence",
! 138: "invalid number",
! 139: "nesting depth reached",
! 140: "unbalanced collection",
! 141: "expected key",
! 142: "expected colon",
! 143: "out of memory"
! 144: };
! 145: return error_messages[error_code];
! 146: }
! 147:
! 148: static void _parse(Request& r, MethodParams& params) {
! 149: //Json json = Json(r.charsets.source().isUTF8() ? (Charset*)NULL : &(r.charsets.source()));
! 150: Json& json = *new Json(r.charsets.source().isUTF8() ? (Charset*)NULL : &(r.charsets.source()));
! 151:
! 152: JSON_config config;
! 153: init_JSON_config(&config);
! 154:
! 155: config.depth = 19;
! 156: config.callback = (JSON_parser_callback)&json_callback;
! 157: config.allow_comments = 1;
! 158: config.handle_floats_manually = 1;
! 159: config.callback_ctx = &json;
! 160:
! 161: if(params.count() == 2)
! 162: if(HashStringValue* options=params.as_hash(1)) {
! 163: int valid_options=0;
! 164: if(Value* value=options->get("depth")) {
! 165: config.depth=value->as_int();
! 166: valid_options++;
! 167: }
! 168: if(Value* value=options->get("double")) {
! 169: json.handle_double=value->as_bool();
! 170: valid_options++;
! 171: }
! 172: if(Value* value=options->get("object")) {
! 173: json.hook=value->get_junction();
! 174: if (!json.hook || !json.hook->method || !json.hook->method->params_names || !(json.hook->method->params_names->count() == 2)){
! 175: throw Exception(PARSER_RUNTIME, 0, "$.object must be parser method with 2 parameters");
! 176: }
! 177: valid_options++;
! 178: }
! 179: if(valid_options!=options->count())
! 180: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
! 181: }
! 182:
! 183: struct JSON_parser_struct* jc = new_JSON_parser(&config);
! 184:
! 185: const String& json_string=r.process_to_string(params[0]); // we accept both {} and []
! 186: const String::Body json_body = json_string.cstr_to_string_body_untaint(String::L_JS, 0, &(r.charsets));
! 187: const char *json_cstr = json.charset != NULL ? Charset::transcode(json_body, *json.charset, UTF8_charset).cstr() : json_body.cstr();
! 188:
! 189: for (const char *c=json_cstr; *c; c++){
! 190: if (!JSON_parser_char(jc, *((const unsigned char *)c))) {
! 191: throw Exception("json.parse", 0, "%s at byte %d", json_error_message(JSON_parser_get_last_error(jc)), c-json_cstr);
! 192: }
! 193: }
! 194:
! 195: if (!JSON_parser_done(jc)) {
! 196: throw Exception("json.parse", 0, "%s at the end", json_error_message(JSON_parser_get_last_error(jc)));
! 197: }
! 198:
! 199: delete_JSON_parser(jc);
! 200:
! 201: if (json.result) r.write_no_lang(*json.result);
! 202: }
! 203:
! 204: // constructor
! 205:
! 206: MJson::MJson(): Methoded("json") {
! 207: add_native_method("parse", Method::CT_STATIC, _parse, 1, 2);
! 208: }
E-mail: