Diff for /parser3/src/classes/json.C between versions 1.46 and 1.69

version 1.46, 2016/10/04 13:23:46 version 1.69, 2025/12/17 20:34:20
Line 1 Line 1
 /** @file  /** @file
         Parser: @b json parser class.          Parser: @b json parser class.
   
         Copyright (c) 2000-2015 Art. Lebedev Studio (http://www.artlebedev.com)          Copyright (c) 2000-2024 Art. Lebedev Studio (http://www.artlebedev.com)
           Authors: Konstantin Morshnev <moko@design.ru>
 */  */
   
 #include "classes.h"  #include "classes.h"
Line 9 Line 10
   
 #include "pa_request.h"  #include "pa_request.h"
 #include "pa_vbool.h"  #include "pa_vbool.h"
   #include "pa_varray.h"
   
 #include "pa_charset.h"  #include "pa_charset.h"
 #include "pa_charsets.h"  #include "pa_charsets.h"
Line 25  volatile const char * IDENT_JSON_C="$Id$ Line 27  volatile const char * IDENT_JSON_C="$Id$
 class MJson: public Methoded {  class MJson: public Methoded {
 public:  public:
         MJson();          MJson();
   
           override Value* get_element(const String&);
           override const VJunction* put_element(const String&, Value*);
 };  };
   
 // global variable  // global variable
   
 DECLARE_CLASS_VAR(json, new MJson);  DECLARE_CLASS_VAR(json, new MJson);
   
   bool handle_array_default=true;
   
 // methods  // methods
 struct Json {  struct Json : public PA_Allocated {
         Stack<VHash*> stack;          Stack<VHashBase*> stack;
         Stack<String*> key_stack;          Stack<String*> key_stack;
   
         String* key;          String* key;
Line 48  struct Json { Line 55  struct Json {
   
         bool handle_double;          bool handle_double;
         bool handle_int;          bool handle_int;
           bool handle_array;
         enum Distinct { D_EXCEPTION, D_FIRST, D_LAST, D_ALL } distinct;          enum Distinct { D_EXCEPTION, D_FIRST, D_LAST, D_ALL } distinct;
   
         Json(Charset* acharset): stack(), key_stack(), key(NULL), result(NULL), hook_object(NULL), hook_array(NULL),           Json(Charset* acharset): stack(), key_stack(), key(NULL), result(NULL), hook_object(NULL), hook_array(NULL), 
                 request(NULL), charset(acharset), taint(String::L_TAINTED), handle_double(true), handle_int(true),                   request(NULL), charset(acharset), taint(String::L_TAINTED), handle_double(true), handle_int(true), 
                 distinct(D_EXCEPTION){}                  handle_array(handle_array_default), distinct(D_EXCEPTION){}
   
         bool set_distinct(const String &value){          bool set_distinct(const String &value){
                 if (value == "first") distinct = D_FIRST;                  if (value == "first") distinct = D_FIRST;
Line 61  struct Json { Line 69  struct Json {
                 else return false;                  else return false;
                 return true;                  return true;
         }          }
   
           bool set_handle_array(const String &value){
                   if (value == "array") handle_array = true;
                   else if (value == "hash") handle_array = false;
                   else return false;
                   return true;
           }
 };  };
   
   
   Value* MJson::get_element(const String& aname) {
           if (aname=="array"){
                   return new VString(*new String(handle_array_default ? "array" : "hash"));
           }
           return Methoded::get_element(aname);
   }
   
   const VJunction* MJson::put_element(const String& aname, Value* avalue) {
           if (aname=="array"){
                   Json json(NULL);
                   if (avalue->get_string()){
                           const String& sarray=avalue->as_string();
                           if (json.set_handle_array(sarray)){
                                   handle_array_default=json.handle_array;
                                   return 0;
                           }
                           throw Exception(PARSER_RUNTIME, &sarray, "$json:array must be 'array' or 'hash'");
                   }
                   throw Exception(PARSER_RUNTIME, 0, "$json:array must be 'array' or 'hash'");
           }
           return Methoded::put_element(aname, avalue);
   }
   
   
 static void set_json_value(Json *json, Value *value){  static void set_json_value(Json *json, Value *value){
         VHash *top = json->stack.top_value();          VHashBase *top = json->stack.top_value();
         if(json->key == NULL){          if(json->key == NULL){
                 top->hash().put(String(format(top->get_hash()->count(), 0)), value);                  top->add(value);
         } else {          } else {
                 switch (json->distinct){                  switch (json->distinct){
                         case Json::D_EXCEPTION:                          case Json::D_EXCEPTION:
Line 83  static void set_json_value(Json *json, V Line 123  static void set_json_value(Json *json, V
                                 if (top->hash().put_dont_replace(*json->key, value)){                                  if (top->hash().put_dont_replace(*json->key, value)){
                                         for(int i=2;;i++){                                          for(int i=2;;i++){
                                                 String key;                                                  String key;
                                                 key << *json->key << "_" << format(i, 0);                                                  key << *json->key << "_" << pa_uitoa(i);
                                                 if (!top->hash().put_dont_replace(key, value)) break;                                                  if (!top->hash().put_dont_replace(key, value)) break;
                                         }                                          }
                                 }                                  }
Line 93  static void set_json_value(Json *json, V Line 133  static void set_json_value(Json *json, V
         }          }
 }  }
   
 String* json_string(Json *json, const char *value, uint32_t length){  String* json_string(Json *json, const char *value){
         String::C result = json->charset !=NULL ?           /* do_callback_withbuf guarantees a null-terminated value */
                 Charset::transcode(String::C(value, length), pa_UTF8_charset, *json->charset) :          if (size_t length = strlen(value)){
                 String::C(pa_strdup(value, length), length);                  String::C result = json->charset !=NULL ?
         return new String(result, json->taint);                          Charset::transcode(String::C(value, length), pa_UTF8_charset, *json->charset) :
                           String::C(pa_strdup(value, length), length);
                   return new String(result, json->taint);
           }
           return (String*)&String::Empty;
 }  }
   
 static Value *json_hook(Request &r, Junction *hook, String* key, Value* value){  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};          Value *params[]={new VString(key ? *key : String::Empty), value};
           METHOD_FRAME_ACTION(*hook->method, r.method_frame, hook->self, {
         frame.store_params(params, 2);                  frame.store_params(params, 2);
         r.execute_method(frame);                  r.call(frame);
                   return &frame.result();
         return &frame.result();          });
 }  }
   
 static int json_callback(Json *json, int type, const char *value, uint32_t length)  static int json_callback(Json *json, int type, const char *value, uint32_t)
 {  {
         switch(type) {          switch(type) {
                 case JSON_OBJECT_BEGIN:{                  case JSON_OBJECT_BEGIN:{
Line 139  static int json_callback(Json *json, int Line 182  static int json_callback(Json *json, int
                         break;                          break;
                 }                  }
                 case JSON_ARRAY_BEGIN:{                  case JSON_ARRAY_BEGIN:{
                         VHash *v = new VHash();  
                         if (json->hook_array){                          if (json->hook_array){
                                 json->key_stack.push(json->key);                                  json->key_stack.push(json->key);
                                 json->key=NULL;                                  json->key=NULL;
                                   json->stack.push(new VHash);
                         } else {                          } else {
                                   VHashBase *v = json->handle_array ? (VHashBase *)new VArray : (VHashBase *)new VHash;
                                 if (json->stack.count()) set_json_value(json, v);                                  if (json->stack.count()) set_json_value(json, v);
                                   json->stack.push(v);
                         }                          }
                         json->stack.push(v);  
                         break;                          break;
                 }                  }
                 case JSON_ARRAY_END:                  case JSON_ARRAY_END:
Line 164  static int json_callback(Json *json, int Line 208  static int json_callback(Json *json, int
                         }                          }
                         break;                          break;
                 case JSON_KEY:                  case JSON_KEY:
                         json->key = json_string(json, value, length);                          json->key = json_string(json, value);
                         break;                          break;
                 case JSON_INT:                  case JSON_INT:
                         if (json->handle_int){                          if (json->handle_int){
                                 set_json_value(json, new VDouble( json_string(json, value, length)->as_double() ));                                  set_json_value(json, new VDouble( json_string(json, value)->as_double() ));
                         } else {                          } else {
                                 // JSON_STRING                                  // JSON_STRING
                                 set_json_value(json, new VString(*json_string(json, value, length)));                                  set_json_value(json, new VString(*json_string(json, value)));
                         }                          }
                         break;                          break;
                 case JSON_FLOAT:                  case JSON_FLOAT:
                         if (json->handle_double){                          if (json->handle_double){
                                 set_json_value(json, new VDouble( json_string(json, value, length)->as_double() ));                                  set_json_value(json, new VDouble( json_string(json, value)->as_double() ));
                                 break;                                  break;
                         } // else is JSON_STRING                          } // else is JSON_STRING
                 case JSON_STRING:                  case JSON_STRING:
                         set_json_value(json, new VString(*json_string(json, value, length)));                          set_json_value(json, new VString(*json_string(json, value)));
                         break;                          break;
                 case JSON_NULL:                  case JSON_NULL:
                         set_json_value(json, VVoid::get());                          set_json_value(json, VVoid::get());
Line 321  static void _parse(Request& r, MethodPar Line 365  static void _parse(Request& r, MethodPar
                         if(Value* value=options->get("object")) {                          if(Value* value=options->get("object")) {
                                 json.hook_object=value->get_junction();                                  json.hook_object=value->get_junction();
                                 json.request=&r;                                  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");                                          throw Exception(PARSER_RUNTIME, 0, "$.object must be parser method with 2 parameters");
                                 valid_options++;                                  valid_options++;
                         }                          }
                         if(Value* value=options->get("array")) {                          if(Value* value=options->get("array")) {
                                 json.hook_array=value->get_junction();                                  if(value->get_string()){
                                 json.request=&r;                                          const String& sarray=value->as_string();
                                 if (!json.hook_array || !json.hook_array->method || !json.hook_array->method->params_names || !(json.hook_array->method->params_names->count() == 2))                                          if (!json.set_handle_array(sarray))
                                         throw Exception(PARSER_RUNTIME, 0, "$.array must be parser method with 2 parameters");                                                  throw Exception(PARSER_RUNTIME, &sarray, "$.array must be parser method with 2 parameters or 'array' or 'hash'");
                                   } else {
                                           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_count == 2))
                                                   throw Exception(PARSER_RUNTIME, 0, "$.array must be parser method with 2 parameters or 'array' or 'hash'");
                                   }
                                 valid_options++;                                  valid_options++;
                         }                          }
                         if(valid_options!=options->count())                          if(valid_options!=options->count())
Line 359  static void _parse(Request& r, MethodPar Line 409  static void _parse(Request& r, MethodPar
   
         json_parser_free(&parser);          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;  const uint ANTI_ENDLESS_JSON_STRING_RECURSION=128;
   
 char *get_indent(uint level){  char *get_indent(uint level){
         static char* cache[ANTI_ENDLESS_JSON_STRING_RECOURSION]={};          static char* cache[ANTI_ENDLESS_JSON_STRING_RECURSION]={};
         if (!cache[level]){          if (!cache[level]){
                 char *result =  static_cast<char*>(pa_gc_malloc_atomic(level+1));                  char *result = static_cast<char*>(pa_malloc_atomic(level+1));
                 memset(result, '\t', level);                  memset(result, '\t', level);
                 result[level]='\0';                  result[level]='\0';
                 return cache[level]=result;                  return cache[level]=result;
Line 375  char *get_indent(uint level){ Line 425  char *get_indent(uint level){
         return cache[level];          return cache[level];
 }  }
   
 class Json_string_recoursion {  String *get_delim(uint level){
           static String* cache[ANTI_ENDLESS_JSON_STRING_RECURSION]={};
   
           if (!cache[level]){
                   char *result = static_cast<char*>(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];
   }
   
   String *get_array_delim(uint level){
           static String* cache[ANTI_ENDLESS_JSON_STRING_RECURSION]={};
   
           if (!cache[level]){
                   char *result = static_cast<char*>(pa_malloc_atomic(level+2+1));
                   result[0]=',';
                   result[1]='\n';
                   memset(result+2, '\t', level);
                   result[level+2]='\0';
                   return cache[level] = new String(result, String::L_AS_IS);
           }
           return cache[level];
   }
   
   class Json_string_recursion {
         Json_options& foptions;          Json_options& foptions;
 public:  public:
         Json_string_recoursion(Json_options& aoptions) : foptions(aoptions) {          Json_string_recursion(Json_options& aoptions) : foptions(aoptions) {
                 if(++foptions.json_string_recoursion==ANTI_ENDLESS_JSON_STRING_RECOURSION)                  if(++foptions.json_string_recursion==ANTI_ENDLESS_JSON_STRING_RECURSION)
                         throw Exception(PARSER_RUNTIME, 0, "call canceled - endless json recursion detected");                          throw Exception(PARSER_RUNTIME, 0, "call canceled - endless json recursion detected");
         }          }
         ~Json_string_recoursion() {          ~Json_string_recursion() {
                 if(foptions.json_string_recoursion)                  if(foptions.json_string_recursion)
                         foptions.json_string_recoursion--;                          foptions.json_string_recursion--;
         }          }
 };  };
   
Line 394  const String* Json_options::hash_json_st Line 473  const String* Json_options::hash_json_st
         if(!hash || !hash->count())          if(!hash || !hash->count())
                 return new String("{}", String::L_AS_IS);                  return new String("{}", String::L_AS_IS);
   
         Json_string_recoursion go_down(*this);          Json_string_recursion go_down(*this);
   
         String& result = *new String("{\n", String::L_AS_IS);          String& result = *new String("{\n", String::L_AS_IS);
   
         if (indent){          if (indent){
   
                 String *delim=NULL;                  String *delim=NULL;
                 indent=get_indent(json_string_recoursion);                  indent=get_indent(json_string_recursion);
                 for(HashStringValue::Iterator i(*hash); i; i.next() ){                  for(HashStringValue::Iterator i(*hash); i; i.next() ){
                         if (delim){                          if (delim){
                                 result << *delim;                                  result << *delim;
                         } else {                          } else {
                                 result << indent << "\"";                                  result << indent << "\"";
                                 delim = new String(",\n", String::L_AS_IS); *delim << indent << "\"";                                  delim = get_delim(json_string_recursion);
                         }                          }
                         result << String(i.key(), String::L_JSON) << "\":" << value_json_string(i.key(), *i.value(), *this);                          result << String(i.key(), String::L_JSON) << "\":" << value_json_string(i.key(), *i.value(), *this);
                 }                  }
                 result << "\n" << (indent=get_indent(json_string_recoursion-1)) << "}";                  result << "\n" << (indent=get_indent(json_string_recursion-1)) << "}";
   
         } else {          } else {
   
Line 428  const String* Json_options::hash_json_st Line 507  const String* Json_options::hash_json_st
         return &result;          return &result;
 }  }
   
   const String* Json_options::array_json_string(ArrayValue *array) {
           if(!array || !array->count())
                   return new String("[]", String::L_AS_IS);
   
           Json_string_recursion go_down(*this);
   
           String& result = *new String("[\n", String::L_AS_IS);
   
           if (indent){
   
                   String *delim=NULL;
                   indent=get_indent(json_string_recursion);
                   for(ArrayValue::Iterator i(*array); i; i.next() ){
                           if (delim){
                                   result << *delim;
                           } else {
                                   result << indent;
                                   delim = get_array_delim(json_string_recursion);
                           }
                           result << value_json_string(String::Body::uitoa(i.index()), i.value() ? *i.value() : static_cast<Value&>(*VVoid::get()), *this);
                   }
                   result << "\n" << (indent=get_indent(json_string_recursion-1)) << "]";
   
           } else {
   
                   bool need_delim=false;
                   for(ArrayValue::Iterator i(*array); i; i.next() ){
                           if(need_delim) result << ",\n";
                           result << value_json_string(String::Body::uitoa(i.index()), i.value() ? *i.value() : static_cast<Value&>(*VVoid::get()), *this);
                           need_delim=true;
                   }
                   result << "\n]";
   
           }
   
           return &result;
   }
   
   const String* Json_options::array_compact_json_string(ArrayValue *array) {
           if(!array || !array->count())
                   return new String("[]", String::L_AS_IS);
   
           Json_string_recursion go_down(*this);
   
           String& result = *new String("[\n", String::L_AS_IS);
   
           if (indent){
   
                   String *delim=NULL;
                   indent=get_indent(json_string_recursion);
                   for(ArrayValue::Iterator i(*array); i; i.next() ){
                           if (i.value()){
                                   if (delim){
                                           result << *delim;
                                   } else {
                                           result << indent;
                                           delim = get_array_delim(json_string_recursion);
                                   }
                                   result << value_json_string(String::Body::uitoa(i.index()), *i.value(), *this);
                           }
                   }
                   result << "\n" << (indent=get_indent(json_string_recursion-1)) << "]";
   
           } else {
   
                   bool need_delim=false;
                   for(ArrayValue::Iterator i(*array); i; i.next() ){
                           if (i.value()){
                                   if(need_delim) result << ",\n";
                                   result << value_json_string(String::Body::uitoa(i.index()), *i.value(), *this);
                                   need_delim=true;
                           }
                   }
                   result << "\n]";
   
           }
   
           return &result;
   }
   
 static bool based_on(HashStringValue::key_type key, HashStringValue::value_type /*value*/, Value* v) {  static bool based_on(HashStringValue::key_type key, HashStringValue::value_type /*value*/, Value* v) {
         return v->is(key.cstr());          return v->is(key.cstr());
 }  }
Line 440  const String& value_json_string(String:: Line 599  const String& value_json_string(String::
                         options.methods->put(v.type(), method ? method : VVoid::get());                          options.methods->put(v.type(), method ? method : VVoid::get());
                 }                  }
                 if(method && !method->is_void()) {                  if(method && !method->is_void()) {
                           static const String::Body sindent("indent");
                         Junction* junction=method->get_junction();                          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;                          HashStringValue* params_hash=options.params && options.indent ? options.params->get_hash() : NULL;
                         Temp_hash_value<HashStringValue, Value*> indent(params_hash, "indent", new VString(*new String(options.indent, String::L_AS_IS)));                          Temp_hash_value<HashStringValue, Value*> indent(params_hash, sindent, 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()};                          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();
                           });
                 }                  }
         }          }
   
Line 464  static void _string(Request& r, MethodPa Line 623  static void _string(Request& r, MethodPa
   
         if(params.count() == 2)          if(params.count() == 2)
                 if(HashStringValue* options=params.as_hash(1)) {                  if(HashStringValue* options=params.as_hash(1)) {
                         json.params=params.get(1);                          json.params=&params[1];
                         HashStringValue* methods=new HashStringValue();                          HashStringValue* methods=new HashStringValue();
                         int valid_options=0;  
                         HashStringValue* vvalue;                          HashStringValue* vvalue;
                         for(HashStringValue::Iterator i(*options); i; i.next() ){                          for(HashStringValue::Iterator i(*options); i; i.next() ){
                                 String::Body key=i.key();                                  String::Body key=i.key();
                                 Value* value=i.value();                                  Value* value=i.value();
                                 if(key == "skip-unknown"){                                  if(key == "skip-unknown"){
                                         json.skip_unknown=r.process(*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();
                                 } else if(key == "date" && value->is_string()){                                  } else if(key == "date" && value->is_string()){
                                         const String& svalue=value->as_string();                                          const String& svalue=value->as_string();
                                         if(!json.set_date_format(svalue))                                          if(!json.set_date_format(svalue))
                                                 throw Exception(PARSER_RUNTIME, &svalue, "must be 'sql-string', 'gmt-string', 'iso-string' or 'unix-timestamp'");                                                  throw Exception(PARSER_RUNTIME, &svalue, "must be 'sql-string', 'gmt-string', 'iso-string' or 'unix-timestamp'");
                                         valid_options++;  
                                 } else if(key == "indent"){                                  } else if(key == "indent"){
                                         if(value->is_string()){                                          if(value->is_string()){
                                                 json.indent=value->as_string().cstr();                                                  json.indent=value->as_string().cstr();
                                                 json.json_string_recoursion=strlen(json.indent);                                                  json.json_string_recursion=strlen(json.indent);
                                         } else json.indent=r.process(*value).as_bool() ? "" : NULL;                                          } else json.indent=r.process(*value).as_bool() ? "" : NULL;
                                         valid_options++;  
                                 } else if(key == "table" && value->is_string()){                                  } else if(key == "table" && value->is_string()){
                                         const String& svalue=value->as_string();                                          const String& svalue=value->as_string();
                                         if(!json.set_table_format(svalue))                                          if(!json.set_table_format(svalue))
                                                 throw Exception(PARSER_RUNTIME, &svalue, "must be 'array', 'object' or 'compact'");                                                  throw Exception(PARSER_RUNTIME, &svalue, "must be 'array', 'object' or 'compact'");
                                         valid_options++;                                  } else if(key == "array" && value->is_string()){
                                           const String& svalue=value->as_string();
                                           if(!json.set_array_format(svalue))
                                                   throw Exception(PARSER_RUNTIME, &svalue, "must be 'array', 'object' or 'compact'");
                                 } else if(key == "file" && value->is_string()){                                  } else if(key == "file" && value->is_string()){
                                         const String& svalue=value->as_string();                                          const String& svalue=value->as_string();
                                         if(!json.set_file_format(svalue))                                          if(!json.set_file_format(svalue))
                                                 throw Exception(PARSER_RUNTIME, &svalue, "must be 'base64', 'text' or 'stat'");                                                  throw Exception(PARSER_RUNTIME, &svalue, "must be 'base64', 'text' or 'stat'");
                                         valid_options++;  
                                 } else if(key == "void" && value->is_string()){                                  } else if(key == "void" && value->is_string()){
                                         const String& svalue=value->as_string();                                          const String& svalue=value->as_string();
                                         if(!json.set_void_format(svalue))                                          if(!json.set_void_format(svalue))
                                                 throw Exception(PARSER_RUNTIME, &svalue, "must be 'string' or 'null'");                                                  throw Exception(PARSER_RUNTIME, &svalue, "must be 'string' or 'null'");
                                         valid_options++;  
 #ifdef XML  #ifdef XML
                                 } else if(key == "xdoc" && (vvalue = value->get_hash())){                                  } else if(key == "xdoc" && (vvalue = value->get_hash())){
                                         json.xdoc_options=new XDocOutputOptions();                                          json.xdoc_options=new XDocOutputOptions();
                                         json.xdoc_options->append(r, vvalue);                                          json.xdoc_options->append(r, vvalue);
                                         valid_options++;  
 #endif  #endif
                                 } else if(Junction* junction=value->get_junction()){                                  } 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());                                                  throw Exception(PARSER_RUNTIME, 0, "$.%s must be parser method with 3 parameters", key.cstr());
                                         methods->put(key, value);                                          methods->put(key, value);
                                         valid_options++;                                  } else
                                 }                                          throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
                         }                          }
   
                         if(valid_options!=options->count())  
                                 throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);  
   
                         // special handling for $._default                           // special handling for $._default 
                         if(VHashBase* vhash=static_cast<VHashBase*>(params[1].as(VHASH_TYPE)))                          if(VHashBase* vhash=dynamic_cast<VHashBase*>(&params[1]))
                                 if(Value* value=vhash->get_default()) {                                  if(Value* value=vhash->get_default()) {
                                         if(!value->is_string()){                                          if(!value->is_string()){
                                                 Junction* junction=value->get_junction();                                                  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");                                                          throw Exception(PARSER_RUNTIME, 0, "$._default must be string or parser method with 3 parameters");
                                         }                                          }
                                         json.default_method=value;                                          json.default_method=value;
Line 534  static void _string(Request& r, MethodPa Line 688  static void _string(Request& r, MethodPa
   
         const String& result_string=value_json_string(String::Body(), r.process(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);          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=String::Body(result);
           }
           r.write(*new String(result_body, String::L_AS_IS));
   }
   
 // constructor  // constructor
   
 MJson::MJson(): Methoded("json") {  MJson::MJson(): Methoded("json") {
         add_native_method("parse", Method::CT_STATIC, _parse, 1, 2);          add_native_method("parse", Method::CT_STATIC, _parse, 1, 2);
   
         add_native_method("string", Method::CT_ANY, _string, 1, 2);          add_native_method("string", Method::CT_STATIC, _string, 1, 2);
 }  }

Removed from v.1.46  
changed lines
  Added in v.1.69


E-mail: