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

1.1       misha       1: /** @file
                      2:        Parser: @b json parser class.
                      3: 
1.17      moko        4:        Copyright (c) 2000-2012 Art. Lebedev Studio (http://www.artlebedev.com)
1.1       misha       5: */
                      6: 
                      7: #include "classes.h"
                      8: #include "pa_vmethod_frame.h"
                      9: 
                     10: #include "pa_request.h"
                     11: #include "pa_vbool.h"
                     12: 
                     13: #include "pa_charset.h"
                     14: #include "pa_charsets.h"
1.29      moko       15: #include "pa_json.h"
1.1       misha      16: 
1.14      misha      17: #ifdef XML
                     18: #include "pa_vxdoc.h"
                     19: #endif
                     20: 
1.36    ! moko       21: volatile const char * IDENT_JSON_C="$Id: json.C,v 1.35 2015/07/22 18:29:09 moko Exp $";
1.17      moko       22: 
1.1       misha      23: // class
                     24: 
                     25: class MJson: public Methoded {
                     26: public:
                     27:        MJson();
                     28: };
                     29: 
                     30: // global variable
                     31: 
                     32: DECLARE_CLASS_VAR(json, new MJson, 0);
                     33: 
                     34: // methods
                     35: struct Json {
1.4       moko       36:        Stack<VHash*> stack;
1.3       moko       37:        Stack<String*> key_stack;
1.1       misha      38: 
1.3       moko       39:        String* key;
1.1       misha      40:        Value* result;
                     41: 
1.16      misha      42:        Junction* hook_object;
                     43:        Junction* hook_array;
1.3       moko       44:        Request* request;
                     45: 
1.1       misha      46:        Charset *charset;
1.23      moko       47:        String::Language taint;
                     48: 
1.1       misha      49:        bool handle_double;
1.30      misha      50:        bool handle_int;
1.4       moko       51:        enum Distinct { D_EXCEPTION, D_FIRST, D_LAST, D_ALL } distinct;
1.3       moko       52: 
1.23      moko       53:        Json(Charset* acharset): stack(), key_stack(), key(NULL), result(NULL), hook_object(NULL), hook_array(NULL), 
1.30      misha      54:                request(NULL), charset(acharset), taint(String::L_TAINTED), handle_double(true), handle_int(true), 
                     55:                distinct(D_EXCEPTION){}
1.4       moko       56: 
                     57:        bool set_distinct(const String &value){
                     58:                if (value == "first") distinct = D_FIRST;
                     59:                else if (value == "last") distinct = D_LAST;
                     60:                else if (value == "all") distinct = D_ALL;
                     61:                else return false;
                     62:                return true;
                     63:        }
1.1       misha      64: };
                     65: 
                     66: static void set_json_value(Json *json, Value *value){
1.4       moko       67:        VHash *top = json->stack.top_value();
1.3       moko       68:        if(json->key == NULL){
1.4       moko       69:                top->hash().put(String(format(top->get_hash()->count(), 0)), value);
1.1       misha      70:        } else {
1.4       moko       71:                switch (json->distinct){
                     72:                        case Json::D_EXCEPTION:
                     73:                                if (top->hash().put_dont_replace(*json->key, value))
                     74:                                        throw Exception(PARSER_RUNTIME, json->key, "duplicate key");
                     75:                                break;
                     76:                        case Json::D_FIRST:
                     77:                                top->hash().put_dont_replace(*json->key, value);
                     78:                                break;
                     79:                        case Json::D_LAST:
                     80:                                top->hash().put(*json->key, value);
                     81:                                break;
                     82:                        case Json::D_ALL:
                     83:                                if (top->hash().put_dont_replace(*json->key, value)){
                     84:                                        for(int i=2;;i++){
                     85:                                                String key;
                     86:                                                key << *json->key << "_" << format(i, 0);
                     87:                                                if (!top->hash().put_dont_replace(key, value)) break;
                     88:                                        }
                     89:                                }
                     90:                                break;
                     91:                }
1.3       moko       92:                json->key=NULL;
1.1       misha      93:        }
                     94: }
                     95: 
1.25      moko       96: String* json_string(Json *json, const char *value, uint32_t length){
1.3       moko       97:        String::C result = json->charset !=NULL ? 
1.25      moko       98:                Charset::transcode(String::C(value, length), UTF8_charset, *json->charset) :
                     99:                String::C(pa_strdup(value, length), length);
1.23      moko      100:        return new String(result.str, json->taint, result.length);
1.1       misha     101: }
                    102: 
1.3       moko      103: static Value *json_hook(Request &r, Junction *hook, String* key, Value* value){
                    104:        VMethodFrame frame(*hook->method, r.method_frame, hook->self);
1.10      moko      105:        Value *params[]={new VString(key ? *key : String::Empty), value};
1.3       moko      106: 
                    107:        frame.store_params(params, 2);
                    108:        r.execute_method(frame);
                    109: 
                    110:        return &frame.result().as_value();
1.1       misha     111: }
                    112: 
1.25      moko      113: static int json_callback(Json *json, int type, const char *value, uint32_t length)
1.1       misha     114: {
                    115:        switch(type) {
1.25      moko      116:                case JSON_OBJECT_BEGIN:{
1.4       moko      117:                        VHash *v = new VHash();
1.16      misha     118:                        if (json->hook_object){
1.1       misha     119:                                json->key_stack.push(json->key);
1.16      misha     120:                                json->key=NULL;
1.1       misha     121:                        } else {
                    122:                                if (json->stack.count()) set_json_value(json, v);
                    123:                        }
                    124:                        json->stack.push(v);
                    125:                        break;
                    126:                }
1.25      moko      127:                case JSON_OBJECT_END:{
1.16      misha     128:                        if (json->hook_object){
1.3       moko      129:                                String* key = json->key_stack.pop();
1.16      misha     130:                                json->result = json_hook(*json->request, json->hook_object, key, json->stack.pop());
1.1       misha     131:                                
                    132:                                if (json->stack.count()){
                    133:                                        json->key = key;
                    134:                                        set_json_value(json, json->result);
                    135:                                }
                    136:                        } else {
                    137:                                json->result = json->stack.pop();
                    138:                        }
                    139:                        break;
                    140:                }
1.25      moko      141:                case JSON_ARRAY_BEGIN:{
1.4       moko      142:                        VHash *v = new VHash();
1.16      misha     143:                        if (json->hook_array){
                    144:                                json->key_stack.push(json->key);
                    145:                                json->key=NULL;
                    146:                        } else {
                    147:                                if (json->stack.count()) set_json_value(json, v);
                    148:                        }
1.1       misha     149:                        json->stack.push(v);
                    150:                        break;
                    151:                }
1.25      moko      152:                case JSON_ARRAY_END:
1.12      moko      153:                        // libjson supports array at top level, we too
1.16      misha     154:                        if (json->hook_array){
                    155:                                String* key = json->key_stack.pop();
                    156:                                json->result = json_hook(*json->request, json->hook_array, key, json->stack.pop());
                    157:                                
                    158:                                if (json->stack.count()){
                    159:                                        json->key = key;
                    160:                                        set_json_value(json, json->result);
                    161:                                }
                    162:                        } else {
                    163:                                json->result = json->stack.pop();
                    164:                        }
1.1       misha     165:                        break;
1.25      moko      166:                case JSON_KEY:
                    167:                        json->key = json_string(json, value, length);
1.16      misha     168:                        break;
1.25      moko      169:                case JSON_INT:
1.30      misha     170:                        if (json->handle_int){
                    171:                                set_json_value(json, new VDouble( json_string(json, value, length)->as_double() ));
                    172:                        } else {
                    173:                                // JSON_STRING
                    174:                                set_json_value(json, new VString(*json_string(json, value, length)));
                    175:                        }
1.1       misha     176:                        break;
1.25      moko      177:                case JSON_FLOAT:
1.1       misha     178:                        if (json->handle_double){
1.25      moko      179:                                set_json_value(json, new VDouble( json_string(json, value, length)->as_double() ));
1.1       misha     180:                                break;
1.25      moko      181:                        } // else is JSON_STRING
                    182:                case JSON_STRING:
                    183:                        set_json_value(json, new VString(*json_string(json, value, length)));
1.1       misha     184:                        break;
1.25      moko      185:                case JSON_NULL:
1.18      moko      186:                        set_json_value(json, VVoid::get());
1.1       misha     187:                        break;
1.25      moko      188:                case JSON_TRUE:
1.1       misha     189:                        set_json_value(json, &VBool::get(true));
                    190:                        break;
1.25      moko      191:                case JSON_FALSE:
1.1       misha     192:                        set_json_value(json, &VBool::get(false));
1.25      moko      193:                        break;
1.1       misha     194:        }
1.25      moko      195:        return 0;
1.1       misha     196: }
                    197: 
1.5       moko      198: static const char* json_error_message(int error_code){
                    199:        static const char* error_messages[] = {
1.1       misha     200:                NULL,
1.25      moko      201:                "out of memory",
                    202:                "bad character",
                    203:                "stack empty",
                    204:                "pop unexpected mode",
                    205:                "nesting limit",
                    206:                "data limit",
                    207:                "comment not allowed by config",
1.35      moko      208:                "unexpected character",
1.25      moko      209:                "missing unicode low surrogate",
                    210:                "unexpected unicode low surrogate",
                    211:                "error comma out of structure",
                    212:                "error in a callback"
1.1       misha     213:        };
                    214:        return error_messages[error_code];
                    215: }
                    216: 
1.23      moko      217: extern String::Language get_untaint_lang(const String& lang_name);
                    218: 
1.35      moko      219: #define SOURCE_MAX_LEN 60
                    220: 
                    221: void json_exception_with_source(Request& r, const char* msg, const char* json, int offset){
                    222:        int i;
                    223: 
                    224:        int line=0;
                    225:        int start=0;
                    226:        int end=strlen(json);
                    227: 
                    228:        if(offset>end)
                    229:                offset=end;
                    230: 
                    231:        for(i = 0; i < offset; i++){
                    232:                if(json[i]=='\n'){
                    233:                        line++;
                    234:                }
                    235:        }
                    236: 
                    237:        if(offset > SOURCE_MAX_LEN/2)
                    238:                start = offset - SOURCE_MAX_LEN/2;
                    239: 
                    240:        for(i = offset-1; i>=start; i--){
                    241:                if(json[i]=='\n'){
                    242:                        start=i+1;
                    243:                        break;
                    244:                }
                    245:        }
                    246: 
                    247:        if(start+SOURCE_MAX_LEN < end)
                    248:                end=start+SOURCE_MAX_LEN;
                    249: 
                    250:        for(i = offset+1; i<end; i++){
                    251:                if(json[i]=='\n'){
                    252:                        end=i;
                    253:                        break;
                    254:                }
                    255:        }
                    256: 
                    257:        char *source = pa_strdup(json+start, end-start);
                    258:        int source_offset = offset-start;
                    259: 
                    260:        if(source[source_offset]=='\n')
                    261:                source[source_offset]=' ';
                    262: 
                    263:        for(i = 0; i < source_offset; i++){
                    264:                if(source[i]=='\t'){
                    265:                        source[i]=' ';
                    266:                }
                    267:        }
                    268: 
                    269:        if(r.charsets.source().isUTF8()){
                    270:                source=(char *)fixUTF8(source);
                    271:                if(source_offset>0){
                    272:                        String s_source(pa_strdup(source,source_offset));
                    273:                        source_offset=s_source.length(r.charsets.source());
                    274:                }
                    275:        }
                    276: 
                    277:        throw Exception("json.parse", 0, "%s at line %d\n%s\n%*s", msg, line+1, source, source_offset+1, "^");
                    278: }
                    279: 
1.1       misha     280: static void _parse(Request& r, MethodParams& params) {
1.3       moko      281:        const String& json_string=params.as_string(0, "json must be string");
                    282: 
                    283:        Json json(r.charsets.source().isUTF8() ? NULL : &(r.charsets.source()));
1.1       misha     284: 
1.25      moko      285:        json_config config = {
                    286:                0,              // buffer_initial_size
1.26      moko      287:                128,            // max_nesting
1.25      moko      288:                0,              // max_data
                    289:                1,              // allow_c_comments
                    290:                1,              // allow_yaml_comments
                    291:                pa_malloc,
                    292:                pa_realloc,
                    293:                pa_free
                    294:        };
1.1       misha     295: 
                    296:        if(params.count() == 2)
                    297:                if(HashStringValue* options=params.as_hash(1)) {
                    298:                        int valid_options=0;
                    299:                        if(Value* value=options->get("depth")) {
1.25      moko      300:                                config.max_nesting=r.process_to_value(*value).as_int();
1.1       misha     301:                                valid_options++;
                    302:                        }
                    303:                        if(Value* value=options->get("double")) {
1.4       moko      304:                                json.handle_double=r.process_to_value(*value).as_bool();
                    305:                                valid_options++;
                    306:                        }
1.30      misha     307:                        if(Value* value=options->get("int")) {
                    308:                                json.handle_int=r.process_to_value(*value).as_bool();
                    309:                                valid_options++;
                    310:                        }
1.4       moko      311:                        if(Value* value=options->get("distinct")) {
                    312:                                const String& sdistinct=value->as_string();
                    313:                                if (!json.set_distinct(sdistinct))
                    314:                                        throw Exception(PARSER_RUNTIME, &sdistinct, "must be 'first', 'last' or 'all'");
1.1       misha     315:                                valid_options++;
                    316:                        }
1.23      moko      317:                        if(Value* value=options->get("taint")) {
                    318:                                json.taint=get_untaint_lang(value->as_string());
                    319:                                valid_options++;
                    320:                        }
1.1       misha     321:                        if(Value* value=options->get("object")) {
1.16      misha     322:                                json.hook_object=value->get_junction();
1.3       moko      323:                                json.request=&r;
1.16      misha     324:                                if (!json.hook_object || !json.hook_object->method || !json.hook_object->method->params_names || !(json.hook_object->method->params_names->count() == 2))
1.1       misha     325:                                        throw Exception(PARSER_RUNTIME, 0, "$.object must be parser method with 2 parameters");
                    326:                                valid_options++;
                    327:                        }
1.16      misha     328:                        if(Value* value=options->get("array")) {
                    329:                                json.hook_array=value->get_junction();
                    330:                                json.request=&r;
                    331:                                if (!json.hook_array || !json.hook_array->method || !json.hook_array->method->params_names || !(json.hook_array->method->params_names->count() == 2))
                    332:                                        throw Exception(PARSER_RUNTIME, 0, "$.array must be parser method with 2 parameters");
                    333:                                valid_options++;
                    334:                        }
1.1       misha     335:                        if(valid_options!=options->count())
                    336:                                throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
                    337:                }
                    338: 
1.28      moko      339:        const String::Body json_body = json_string.cstr_to_string_body_untaint(String::L_JSON, r.connection(false), &r.charsets);
1.1       misha     340:        const char *json_cstr = json.charset != NULL ? Charset::transcode(json_body, *json.charset, UTF8_charset).cstr() : json_body.cstr();
                    341: 
1.25      moko      342:        json_parser parser;
                    343:        if(int result = json_parser_init(&parser, &config, (json_parser_callback)&json_callback, &json))
                    344:                throw Exception("json.parse", 0, "%s", json_error_message(result));
                    345: 
1.36    ! moko      346:        if(!*json_cstr)
        !           347:                throw Exception("json.parse", 0, "empty string is not valid json");
        !           348: 
        !           349:        const char *first_quote=strchr(json_cstr,'"');
        !           350:        if(first_quote && first_quote>json_cstr && *(--first_quote) == '\\')
        !           351:                json_exception_with_source(r, "illegal quote escape, json may be tainted", json_cstr, first_quote-json_cstr);
        !           352: 
1.25      moko      353:        uint32_t processed;
                    354:        if(int result = json_parser_string(&parser, json_cstr, strlen(json_cstr), &processed))
1.35      moko      355:                json_exception_with_source(r, json_error_message(result), json_cstr, processed);
1.3       moko      356: 
1.25      moko      357:        if (!json_parser_is_done(&parser))
1.35      moko      358:                json_exception_with_source(r, "unexpected end of json data", json_cstr, processed);
                    359: 
1.25      moko      360:        json_parser_free(&parser);
1.1       misha     361: 
                    362:        if (json.result) r.write_no_lang(*json.result);
                    363: }
                    364: 
1.26      moko      365: const uint ANTI_ENDLESS_JSON_STRING_RECOURSION=128;
                    366: 
1.8       moko      367: char *get_indent(uint level){
                    368:        static char* cache[ANTI_ENDLESS_JSON_STRING_RECOURSION]={};
                    369:        if (!cache[level]){
                    370:                char *result =  static_cast<char*>(pa_gc_malloc_atomic(level+1));
                    371:                memset(result, '\t', level);
1.9       moko      372:                result[level]='\0';
1.8       moko      373:                return cache[level]=result;
                    374:        }
                    375:        return cache[level];
                    376: }
                    377: 
1.26      moko      378: class Json_string_recoursion {
                    379:        Json_options& foptions;
                    380: public:
                    381:        Json_string_recoursion(Json_options& aoptions) : foptions(aoptions) {
                    382:                if(++foptions.json_string_recoursion==ANTI_ENDLESS_JSON_STRING_RECOURSION)
                    383:                        throw Exception(PARSER_RUNTIME, 0, "call canceled - endless json recursion detected");
                    384:        }
                    385:        ~Json_string_recoursion() {
                    386:                if(foptions.json_string_recoursion)
                    387:                        foptions.json_string_recoursion--;
                    388:        }
                    389: };
                    390: 
1.21      moko      391: const String& value_json_string(String::Body key, Value& v, Json_options& options);
1.6       misha     392: 
1.21      moko      393: const String* Json_options::hash_json_string(HashStringValue &hash) {
1.6       misha     394:        if(!hash.count())
1.21      moko      395:                return new String("{}", String::L_AS_IS);
1.8       moko      396: 
1.26      moko      397:        Json_string_recoursion go_down(*this);
1.8       moko      398: 
                    399:        String& result = *new String("{\n", String::L_AS_IS);
                    400: 
1.21      moko      401:        if (indent){
1.8       moko      402: 
                    403:                String *delim=NULL;
1.26      moko      404:                indent=get_indent(json_string_recoursion);
1.8       moko      405:                for(HashStringValue::Iterator i(hash); i; i.next() ){
                    406:                        if (delim){
                    407:                                result << *delim;
                    408:                        } else {
1.21      moko      409:                                result << indent << "\"";
                    410:                                delim = new String(",\n", String::L_AS_IS); *delim << indent << "\"";
1.8       moko      411:                        }
1.21      moko      412:                        result << String(i.key(), String::L_JSON) << "\":" << value_json_string(i.key(), *i.value(), *this);
1.8       moko      413:                }
1.26      moko      414:                result << "\n" << (indent=get_indent(json_string_recoursion-1)) << "}";
1.6       misha     415: 
1.8       moko      416:        } else {
                    417: 
                    418:                bool need_delim=false;
                    419:                for(HashStringValue::Iterator i(hash); i; i.next() ){
                    420:                        result << (need_delim ? ",\n\"" : "\"");
1.21      moko      421:                        result << String(i.key(), String::L_JSON) << "\":" << value_json_string(i.key(), *i.value(), *this);
1.8       moko      422:                        need_delim=true;
                    423:                }
                    424:                result << "\n}";
1.6       misha     425: 
                    426:        }
                    427: 
1.21      moko      428:        return &result;
1.6       misha     429: }
                    430: 
1.21      moko      431: static bool based_on(HashStringValue::key_type key, HashStringValue::value_type /*value*/, Value* v) {
1.15      misha     432:        return v->is(key.cstr());
                    433: }
1.26      moko      434: 
1.21      moko      435: const String& value_json_string(String::Body key, Value& v, Json_options& options) {
                    436:        if(options.methods) {
                    437:                Value* method=options.methods->get(v.type());
                    438:                if(!method){
                    439:                        method=options.methods->first_that<Value*>(based_on, &v);
1.31      misha     440:                        options.methods->put(v.type(), method ? method : VVoid::get());
1.21      moko      441:                }
                    442:                if(method && !method->is_void()) {
1.6       misha     443:                        Junction* junction=method->get_junction();
1.21      moko      444:                        VMethodFrame frame(*junction->method, options.r->method_frame, junction->self);
1.6       misha     445: 
1.26      moko      446:                        HashStringValue* params_hash=options.params && options.indent ? options.params->get_hash() : NULL;
1.27      moko      447:                        Temp_hash_value<HashStringValue, Value*> indent(params_hash, "indent", new VString(*new String(options.indent, String::L_AS_IS)));
1.26      moko      448: 
1.21      moko      449:                        Value *params[]={new VString(*new String(key, String::L_JSON)), &v, options.params ? options.params : VVoid::get()};
1.13      moko      450:                        frame.store_params(params, 3);
1.6       misha     451: 
1.21      moko      452:                        options.r->execute_method(frame);
1.6       misha     453: 
                    454:                        return frame.result().as_string();
                    455:                }
1.15      misha     456:        }
1.6       misha     457: 
1.21      moko      458:        options.key=key;
1.6       misha     459:        return *v.get_json_string(options);
                    460: }
                    461: 
                    462: static void _string(Request& r, MethodParams& params) {
                    463:        Json_options json(&r);
                    464: 
                    465:        if(params.count() == 2)
                    466:                if(HashStringValue* options=params.as_hash(1)) {
                    467:                        json.params=params.get(1);
                    468:                        HashStringValue* methods=new HashStringValue();
                    469:                        int valid_options=0;
1.14      misha     470:                        HashStringValue* vvalue;
1.6       misha     471:                        for(HashStringValue::Iterator i(*options); i; i.next() ){
                    472:                                String::Body key=i.key();
                    473:                                Value* value=i.value();
                    474:                                if(key == "skip-unknown"){
                    475:                                        json.skip_unknown=r.process_to_value(*value).as_bool();
                    476:                                        valid_options++;
                    477:                                } else if(key == "date" && value->is_string()){
                    478:                                        const String& svalue=value->as_string();
                    479:                                        if(!json.set_date_format(svalue))
                    480:                                                throw Exception(PARSER_RUNTIME, &svalue, "must be 'sql-string', 'gmt-string' or 'unix-timestamp'");
                    481:                                        valid_options++;
1.8       moko      482:                                } else if(key == "indent"){
1.26      moko      483:                                        if(value->is_string()){
                    484:                                                json.indent=value->as_string().cstr();
                    485:                                                json.json_string_recoursion=strlen(json.indent);
                    486:                                        } else json.indent=r.process_to_value(*value).as_bool() ? "" : NULL;
1.8       moko      487:                                        valid_options++;
1.6       misha     488:                                } else if(key == "table" && value->is_string()){
                    489:                                        const String& svalue=value->as_string();
                    490:                                        if(!json.set_table_format(svalue))
1.13      moko      491:                                                throw Exception(PARSER_RUNTIME, &svalue, "must be 'array', 'object' or 'compact'");
1.6       misha     492:                                        valid_options++;
                    493:                                } else if(key == "file" && value->is_string()){
                    494:                                        const String& svalue=value->as_string();
                    495:                                        if(!json.set_file_format(svalue))
1.19      misha     496:                                                throw Exception(PARSER_RUNTIME, &svalue, "must be 'base64', 'text' or 'stat'");
1.6       misha     497:                                        valid_options++;
1.32      misha     498:                                } else if(key == "void" && value->is_string()){
                    499:                                        const String& svalue=value->as_string();
                    500:                                        if(!json.set_void_format(svalue))
                    501:                                                throw Exception(PARSER_RUNTIME, &svalue, "must be 'string' or 'null'");
                    502:                                        valid_options++;
1.14      misha     503: #ifdef XML
                    504:                                } else if(key == "xdoc" && (vvalue = value->get_hash())){
1.24      moko      505:                                        json.xdoc_options=new XDocOutputOptions();
                    506:                                        json.xdoc_options->append(r, vvalue);
1.14      misha     507:                                        valid_options++;
                    508: #endif
1.6       misha     509:                                } else if(Junction* junction=value->get_junction()){
1.13      moko      510:                                        if(!junction->method || !junction->method->params_names || junction->method->params_names->count() != 3)
                    511:                                                throw Exception(PARSER_RUNTIME, 0, "$.%s must be parser method with 3 parameters", key.cstr());
1.6       misha     512:                                        methods->put(key, value);
                    513:                                        valid_options++;
                    514:                                }
                    515:                        }
1.22      moko      516: 
1.6       misha     517:                        if(valid_options!=options->count())
                    518:                                throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
1.22      moko      519: 
                    520:                        // special handling for $._default 
                    521:                        if(VHash* vhash=static_cast<VHash*>(params[1].as(VHASH_TYPE)))
                    522:                                if(Value* value=vhash->get_default()) {
1.34      misha     523:                                        if(!value->is_string()){
1.22      moko      524:                                        Junction* junction=value->get_junction();
                    525:                                        if(!junction || !junction->method || !junction->method->params_names || junction->method->params_names->count() != 3)
1.34      misha     526:                                                        throw Exception(PARSER_RUNTIME, 0, "$.%s must be string or parser method with 3 parameters", HASH_DEFAULT_ELEMENT_NAME);
                    527:                                        }
1.22      moko      528:                                        json.default_method=value;
                    529:                                }
                    530: 
1.6       misha     531:                        if(methods->count())
                    532:                                json.methods=methods;
                    533:                }
1.14      misha     534: 
1.33      misha     535:        const String& result_string=value_json_string(String::Body(), r.process_to_value(params[0]), json);
1.28      moko      536:        String::Body result_body=result_string.cstr_to_string_body_untaint(String::L_JSON, r.connection(false), &r.charsets);
1.13      moko      537:        r.write_pass_lang(*new String(result_body, String::L_AS_IS));
1.6       misha     538:  }
                    539: 
1.1       misha     540: // constructor
                    541: 
                    542: MJson::MJson(): Methoded("json") {
                    543:        add_native_method("parse", Method::CT_STATIC, _parse, 1, 2);
1.6       misha     544: 
                    545:        add_native_method("string", Method::CT_ANY, _string, 1, 2);
1.1       misha     546: }

E-mail: