--- parser3/src/classes/json.C 2016/07/20 13:57:04 1.43 +++ parser3/src/classes/json.C 2021/01/15 16:28:36 1.56 @@ -1,7 +1,7 @@ /** @file Parser: @b json parser class. - Copyright (c) 2000-2015 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2000-2020 Art. Lebedev Studio (http://www.artlebedev.com) */ #include "classes.h" @@ -18,7 +18,7 @@ #include "pa_vxdoc.h" #endif -volatile const char * IDENT_JSON_C="$Id: json.C,v 1.43 2016/07/20 13:57:04 moko Exp $"; +volatile const char * IDENT_JSON_C="$Id: json.C,v 1.56 2021/01/15 16:28:36 moko Exp $"; // class @@ -32,7 +32,7 @@ public: DECLARE_CLASS_VAR(json, new MJson); // methods -struct Json { +struct Json : public PA_Allocated { Stack stack; Stack key_stack; @@ -66,7 +66,7 @@ struct Json { static void set_json_value(Json *json, Value *value){ VHash *top = json->stack.top_value(); if(json->key == NULL){ - top->hash().put(String(format(top->get_hash()->count(), 0)), value); + top->hash().put(format(top->get_hash()->count(), 0), value); } else { switch (json->distinct){ case Json::D_EXCEPTION: @@ -95,19 +95,18 @@ static void set_json_value(Json *json, V String* json_string(Json *json, const char *value, uint32_t length){ String::C result = json->charset !=NULL ? - Charset::transcode(String::C(value, length), UTF8_charset, *json->charset) : + Charset::transcode(String::C(value, length), pa_UTF8_charset, *json->charset) : String::C(pa_strdup(value, length), length); return new String(result, json->taint); } static Value *json_hook(Request &r, Junction *hook, String* key, Value* value){ - VMethodFrame frame(*hook->method, r.method_frame, hook->self); Value *params[]={new VString(key ? *key : String::Empty), value}; - - frame.store_params(params, 2); - r.execute_method(frame); - - return &frame.result().as_value(); + METHOD_FRAME_ACTION(*hook->method, r.method_frame, hook->self, { + frame.store_params(params, 2); + r.call(frame); + return &frame.result(); + }); } static int json_callback(Json *json, int type, const char *value, uint32_t length) @@ -297,15 +296,15 @@ static void _parse(Request& r, MethodPar if(HashStringValue* options=params.as_hash(1)) { int valid_options=0; if(Value* value=options->get("depth")) { - config.max_nesting=r.process_to_value(*value).as_int(); + config.max_nesting=r.process(*value).as_int(); valid_options++; } if(Value* value=options->get("double")) { - json.handle_double=r.process_to_value(*value).as_bool(); + json.handle_double=r.process(*value).as_bool(); valid_options++; } if(Value* value=options->get("int")) { - json.handle_int=r.process_to_value(*value).as_bool(); + json.handle_int=r.process(*value).as_bool(); valid_options++; } if(Value* value=options->get("distinct")) { @@ -321,14 +320,14 @@ static void _parse(Request& r, MethodPar if(Value* value=options->get("object")) { json.hook_object=value->get_junction(); json.request=&r; - if (!json.hook_object || !json.hook_object->method || !json.hook_object->method->params_names || !(json.hook_object->method->params_names->count() == 2)) + if (!json.hook_object || !json.hook_object->method || !json.hook_object->method->params_names || !(json.hook_object->method->params_count == 2)) throw Exception(PARSER_RUNTIME, 0, "$.object must be parser method with 2 parameters"); valid_options++; } if(Value* value=options->get("array")) { json.hook_array=value->get_junction(); json.request=&r; - if (!json.hook_array || !json.hook_array->method || !json.hook_array->method->params_names || !(json.hook_array->method->params_names->count() == 2)) + if (!json.hook_array || !json.hook_array->method || !json.hook_array->method->params_names || !(json.hook_array->method->params_count == 2)) throw Exception(PARSER_RUNTIME, 0, "$.array must be parser method with 2 parameters"); valid_options++; } @@ -337,7 +336,7 @@ static void _parse(Request& r, MethodPar } const String::Body json_body = json_string.cstr_to_string_body_untaint(String::L_JSON, r.connection(false), &r.charsets); - const char *json_cstr = json.charset != NULL ? Charset::transcode(json_body, *json.charset, UTF8_charset).cstr() : json_body.cstr(); + const char *json_cstr = json.charset != NULL ? Charset::transcode(json_body, *json.charset, pa_UTF8_charset).cstr() : json_body.cstr(); json_parser parser; if(int result = json_parser_init(&parser, &config, (json_parser_callback)&json_callback, &json)) @@ -359,7 +358,7 @@ static void _parse(Request& r, MethodPar json_parser_free(&parser); - if (json.result) r.write_no_lang(*json.result); + if (json.result) r.write(*json.result); } const uint ANTI_ENDLESS_JSON_STRING_RECOURSION=128; @@ -367,7 +366,7 @@ const uint ANTI_ENDLESS_JSON_STRING_RECO char *get_indent(uint level){ static char* cache[ANTI_ENDLESS_JSON_STRING_RECOURSION]={}; if (!cache[level]){ - char *result = static_cast(pa_gc_malloc_atomic(level+1)); + char *result = static_cast(pa_malloc_atomic(level+1)); memset(result, '\t', level); result[level]='\0'; return cache[level]=result; @@ -375,6 +374,21 @@ char *get_indent(uint level){ return cache[level]; } +String *get_delim(uint level){ + static String* cache[ANTI_ENDLESS_JSON_STRING_RECOURSION]={}; + + if (!cache[level]){ + char *result = static_cast(pa_malloc_atomic(level+2+1+1)); + result[0]=','; + result[1]='\n'; + memset(result+2, '\t', level); + result[level+2]='"'; + result[level+3]='\0'; + return cache[level] = new String(result, String::L_AS_IS); + } + return cache[level]; +} + class Json_string_recoursion { Json_options& foptions; public: @@ -407,7 +421,7 @@ const String* Json_options::hash_json_st result << *delim; } else { result << indent << "\""; - delim = new String(",\n", String::L_AS_IS); *delim << indent << "\""; + delim = get_delim(json_string_recoursion); } result << String(i.key(), String::L_JSON) << "\":" << value_json_string(i.key(), *i.value(), *this); } @@ -441,17 +455,16 @@ const String& value_json_string(String:: } if(method && !method->is_void()) { Junction* junction=method->get_junction(); - VMethodFrame frame(*junction->method, options.r->method_frame, junction->self); - HashStringValue* params_hash=options.params && options.indent ? options.params->get_hash() : NULL; Temp_hash_value indent(params_hash, "indent", new VString(*new String(options.indent, String::L_AS_IS))); Value *params[]={new VString(*new String(key, String::L_JSON)), &v, options.params ? options.params : VVoid::get()}; - frame.store_params(params, 3); - - options.r->execute_method(frame); - return frame.result().as_string(); + METHOD_FRAME_ACTION(*junction->method, options.r->method_frame, junction->self, { + frame.store_params(params, 3); + options.r->call(frame); + return frame.result().as_string(); + }); } } @@ -464,7 +477,7 @@ static void _string(Request& r, MethodPa if(params.count() == 2) if(HashStringValue* options=params.as_hash(1)) { - json.params=params.get(1); + json.params=¶ms[1]; HashStringValue* methods=new HashStringValue(); int valid_options=0; HashStringValue* vvalue; @@ -472,7 +485,10 @@ static void _string(Request& r, MethodPa String::Body key=i.key(); Value* value=i.value(); if(key == "skip-unknown"){ - json.skip_unknown=r.process_to_value(*value).as_bool(); + json.skip_unknown=r.process(*value).as_bool(); + valid_options++; + } else if(key == "one-line"){ + json.one_line=r.process(*value).as_bool(); valid_options++; } else if(key == "date" && value->is_string()){ const String& svalue=value->as_string(); @@ -483,7 +499,7 @@ static void _string(Request& r, MethodPa if(value->is_string()){ json.indent=value->as_string().cstr(); json.json_string_recoursion=strlen(json.indent); - } else json.indent=r.process_to_value(*value).as_bool() ? "" : NULL; + } else json.indent=r.process(*value).as_bool() ? "" : NULL; valid_options++; } else if(key == "table" && value->is_string()){ const String& svalue=value->as_string(); @@ -507,7 +523,7 @@ static void _string(Request& r, MethodPa valid_options++; #endif } else if(Junction* junction=value->get_junction()){ - if(!junction->method || !junction->method->params_names || junction->method->params_names->count() != 3) + if(!junction->method || !junction->method->params_names || junction->method->params_count != 3) throw Exception(PARSER_RUNTIME, 0, "$.%s must be parser method with 3 parameters", key.cstr()); methods->put(key, value); valid_options++; @@ -522,7 +538,7 @@ static void _string(Request& r, MethodPa if(Value* value=vhash->get_default()) { if(!value->is_string()){ Junction* junction=value->get_junction(); - if(!junction || !junction->method || !junction->method->params_names || junction->method->params_names->count() != 3) + if(!junction || !junction->method || !junction->method->params_names || junction->method->params_count != 3) throw Exception(PARSER_RUNTIME, 0, "$._default must be string or parser method with 3 parameters"); } json.default_method=value; @@ -532,10 +548,17 @@ static void _string(Request& r, MethodPa json.methods=methods; } - const String& result_string=value_json_string(String::Body(), r.process_to_value(params[0]), json); + const String& result_string=value_json_string(String::Body(), r.process(params[0]), json); String::Body result_body=result_string.cstr_to_string_body_untaint(String::L_JSON, r.connection(false), &r.charsets); - r.write_pass_lang(*new String(result_body, String::L_AS_IS)); - } + if(json.one_line){ + char *result=result_body.cstrm(); + for(char *c=result;*c;c++) + if(*c=='\n') + *c=' '; + result_body=result; + } + r.write(*new String(result_body, String::L_AS_IS)); +} // constructor