Annotation of parser3/src/classes/json.C, revision 1.3

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

E-mail: