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: