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: