| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  json.cpp                                                             */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							|  |  |  | /*                    http://www.godotengine.org                         */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-01-01 22:01:57 +01:00
										 |  |  | /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | #include "json.h"
 | 
					
						
							|  |  |  | #include "print_string.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char * JSON::tk_name[TK_MAX] = { | 
					
						
							|  |  |  | 	"'{'", | 
					
						
							|  |  |  | 	"'}'", | 
					
						
							|  |  |  | 	"'['", | 
					
						
							|  |  |  | 	"']'", | 
					
						
							|  |  |  | 	"identifier", | 
					
						
							|  |  |  | 	"string", | 
					
						
							|  |  |  | 	"number", | 
					
						
							|  |  |  | 	"':'", | 
					
						
							|  |  |  | 	"','", | 
					
						
							|  |  |  | 	"EOF", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String JSON::_print_var(const Variant& p_var) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(p_var.get_type()) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case Variant::NIL: return "null"; | 
					
						
							|  |  |  | 		case Variant::BOOL: return p_var.operator bool() ? "true": "false"; | 
					
						
							|  |  |  | 		case Variant::INT: return itos(p_var); | 
					
						
							|  |  |  | 		case Variant::REAL: return rtos(p_var); | 
					
						
							|  |  |  | 		case Variant::INT_ARRAY: | 
					
						
							|  |  |  | 		case Variant::REAL_ARRAY: | 
					
						
							|  |  |  | 		case Variant::STRING_ARRAY: | 
					
						
							|  |  |  | 		case Variant::ARRAY: { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			String s = "["; | 
					
						
							|  |  |  | 			Array a = p_var; | 
					
						
							|  |  |  | 			for(int i=0;i<a.size();i++) { | 
					
						
							|  |  |  | 				if (i>0) | 
					
						
							|  |  |  | 					s+=", "; | 
					
						
							|  |  |  | 				s+=_print_var(a[i]); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s+="]"; | 
					
						
							|  |  |  | 			return s; | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 		case Variant::DICTIONARY: { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			String s = "{"; | 
					
						
							|  |  |  | 			Dictionary d = p_var; | 
					
						
							|  |  |  | 			List<Variant> keys; | 
					
						
							|  |  |  | 			d.get_key_list(&keys); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for (List<Variant>::Element *E=keys.front();E;E=E->next()) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (E!=keys.front()) | 
					
						
							|  |  |  | 					s+=", "; | 
					
						
							|  |  |  | 				s+=_print_var(String(E->get())); | 
					
						
							|  |  |  | 				s+=":"; | 
					
						
							|  |  |  | 				s+=_print_var(d[E->get()]); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			s+="}"; | 
					
						
							|  |  |  | 			return s; | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2016-01-10 15:01:06 -03:00
										 |  |  | 		default: return "\""+String(p_var).json_escape()+"\""; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String JSON::print(const Dictionary& p_dict) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return _print_var(p_dict); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_token,int &line,String &r_err_str) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (true) { | 
					
						
							|  |  |  | 		switch(p_str[idx]) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			case '\n': { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				line++; | 
					
						
							|  |  |  | 				idx++; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			case 0: { | 
					
						
							|  |  |  | 				r_token.type=TK_EOF; | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 			} break; | 
					
						
							|  |  |  | 			case '{': { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_token.type=TK_CURLY_BRACKET_OPEN; | 
					
						
							|  |  |  | 				idx++; | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			case '}': { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_token.type=TK_CURLY_BRACKET_CLOSE; | 
					
						
							|  |  |  | 				idx++; | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			case '[': { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_token.type=TK_BRACKET_OPEN; | 
					
						
							|  |  |  | 				idx++; | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			case ']': { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_token.type=TK_BRACKET_CLOSE; | 
					
						
							|  |  |  | 				idx++; | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			case ':': { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_token.type=TK_COLON; | 
					
						
							|  |  |  | 				idx++; | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			case ',': { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_token.type=TK_COMMA; | 
					
						
							|  |  |  | 				idx++; | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			case '"': { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				idx++; | 
					
						
							|  |  |  | 				String str; | 
					
						
							|  |  |  | 				while(true) { | 
					
						
							|  |  |  | 					if (p_str[idx]==0) { | 
					
						
							|  |  |  | 						r_err_str="Unterminated String"; | 
					
						
							|  |  |  | 						return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 					} else if (p_str[idx]=='"') { | 
					
						
							|  |  |  | 						idx++; | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} else if (p_str[idx]=='\\') { | 
					
						
							|  |  |  | 						//escaped characters...
 | 
					
						
							|  |  |  | 						idx++; | 
					
						
							|  |  |  | 						CharType next = p_str[idx]; | 
					
						
							|  |  |  | 						if (next==0) { | 
					
						
							|  |  |  | 							r_err_str="Unterminated String"; | 
					
						
							|  |  |  | 							return  ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						CharType res=0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						switch(next) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							case 'b': res=8; break; | 
					
						
							|  |  |  | 							case 't': res=9; break; | 
					
						
							|  |  |  | 							case 'n': res=10; break; | 
					
						
							|  |  |  | 							case 'f': res=12; break; | 
					
						
							|  |  |  | 							case 'r': res=13; break; | 
					
						
							|  |  |  | 							case 'u': { | 
					
						
							|  |  |  | 								//hexnumbarh - oct is deprecated
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								for(int j=0;j<4;j++) { | 
					
						
							|  |  |  | 									CharType c = p_str[idx+j+1]; | 
					
						
							|  |  |  | 									if (c==0) { | 
					
						
							|  |  |  | 										r_err_str="Unterminated String"; | 
					
						
							|  |  |  | 										return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 									if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 										r_err_str="Malformed hex constant in string"; | 
					
						
							|  |  |  | 										return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 									CharType v; | 
					
						
							|  |  |  | 									if (c>='0' && c<='9') { | 
					
						
							|  |  |  | 										v=c-'0'; | 
					
						
							|  |  |  | 									} else if (c>='a' && c<='f') { | 
					
						
							|  |  |  | 										v=c-'a'; | 
					
						
							|  |  |  | 										v+=10; | 
					
						
							|  |  |  | 									} else if (c>='A' && c<='F') { | 
					
						
							|  |  |  | 										v=c-'A'; | 
					
						
							|  |  |  | 										v+=10; | 
					
						
							|  |  |  | 									} else { | 
					
						
							|  |  |  | 										ERR_PRINT("BUG"); | 
					
						
							|  |  |  | 										v=0; | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									res<<=4; | 
					
						
							|  |  |  | 									res|=v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 								idx+=4; //will add at the end anyway
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							} break; | 
					
						
							| 
									
										
										
										
											2015-11-16 17:05:39 +02:00
										 |  |  | 							//case '\"': res='\"'; break;
 | 
					
						
							|  |  |  | 							//case '\\': res='\\'; break;
 | 
					
						
							|  |  |  | 							//case '/': res='/'; break;
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 							default: { | 
					
						
							| 
									
										
										
										
											2015-11-16 17:05:39 +02:00
										 |  |  | 								res = next; | 
					
						
							|  |  |  | 								//r_err_str="Invalid escape sequence";
 | 
					
						
							|  |  |  | 								//return ERR_PARSE_ERROR;
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 							} break; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						str+=res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						if (p_str[idx]=='\n') | 
					
						
							|  |  |  | 							line++; | 
					
						
							|  |  |  | 						str+=p_str[idx]; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					idx++; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_token.type=TK_STRING; | 
					
						
							|  |  |  | 				r_token.value=str; | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} break; | 
					
						
							|  |  |  | 			default: { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (p_str[idx]<=32) { | 
					
						
							|  |  |  | 					idx++; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) { | 
					
						
							|  |  |  | 					//a number
 | 
					
						
							|  |  |  | 					const CharType *rptr; | 
					
						
							| 
									
										
										
										
											2015-01-03 11:06:53 -03:00
										 |  |  | 					double number = String::to_double(&p_str[idx],&rptr); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 					idx+=(rptr - &p_str[idx]); | 
					
						
							|  |  |  | 					r_token.type=TK_NUMBER; | 
					
						
							|  |  |  | 					r_token.value=number; | 
					
						
							|  |  |  | 					return OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} else if ((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					String id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					while((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						id+=p_str[idx]; | 
					
						
							|  |  |  | 						idx++; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					r_token.type=TK_IDENTIFIER; | 
					
						
							|  |  |  | 					r_token.value=id; | 
					
						
							|  |  |  | 					return OK; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					r_err_str="Unexpected character."; | 
					
						
							|  |  |  | 					return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error JSON::_parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (token.type==TK_CURLY_BRACKET_OPEN) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 17:56:51 -03:00
										 |  |  | 		Dictionary d(true); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		Error err = _parse_object(d,p_str,index,p_len,line,r_err_str); | 
					
						
							|  |  |  | 		if (err) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 		value=d; | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 	} else if (token.type==TK_BRACKET_OPEN) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 17:56:51 -03:00
										 |  |  | 		Array a(true); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		Error err = _parse_array(a,p_str,index,p_len,line,r_err_str); | 
					
						
							|  |  |  | 		if (err) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 		value=a; | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else if (token.type==TK_IDENTIFIER) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		String id = token.value; | 
					
						
							|  |  |  | 		if (id=="true") | 
					
						
							|  |  |  | 			value=true; | 
					
						
							|  |  |  | 		else if (id=="false") | 
					
						
							|  |  |  | 			value=false; | 
					
						
							|  |  |  | 		else if (id=="null") | 
					
						
							|  |  |  | 			value=Variant(); | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			r_err_str="Expected 'true','false' or 'null', got '"+id+"'."; | 
					
						
							|  |  |  | 			return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else if (token.type==TK_NUMBER) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		value=token.value; | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 	} else if (token.type==TK_STRING) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		value=token.value; | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		r_err_str="Expected value, got "+String(tk_name[token.type])+"."; | 
					
						
							|  |  |  | 		return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error JSON::_parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Token token; | 
					
						
							|  |  |  | 	bool need_comma=false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while(index<p_len) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Error err = _get_token(p_str,index,p_len,token,line,r_err_str); | 
					
						
							|  |  |  | 		if (err!=OK) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (token.type==TK_BRACKET_CLOSE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return OK; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (need_comma) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (token.type!=TK_COMMA) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_err_str="Expected ','"; | 
					
						
							|  |  |  | 				return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				need_comma=false; | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Variant v; | 
					
						
							|  |  |  | 		err = _parse_value(v,token,p_str,index,p_len,line,r_err_str); | 
					
						
							|  |  |  | 		if (err) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		array.push_back(v); | 
					
						
							|  |  |  | 		need_comma=true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error JSON::_parse_object(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool at_key=true; | 
					
						
							|  |  |  | 	String key; | 
					
						
							|  |  |  | 	Token token; | 
					
						
							|  |  |  | 	bool need_comma=false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while(index<p_len) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (at_key) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Error err = _get_token(p_str,index,p_len,token,line,r_err_str); | 
					
						
							|  |  |  | 			if (err!=OK) | 
					
						
							|  |  |  | 				return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (token.type==TK_CURLY_BRACKET_CLOSE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return OK; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (need_comma) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (token.type!=TK_COMMA) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					r_err_str="Expected '}' or ','"; | 
					
						
							|  |  |  | 					return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					need_comma=false; | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (token.type!=TK_STRING) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_err_str="Expected key"; | 
					
						
							|  |  |  | 				return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			key=token.value; | 
					
						
							|  |  |  | 			err = _get_token(p_str,index,p_len,token,line,r_err_str); | 
					
						
							|  |  |  | 			if (err!=OK) | 
					
						
							|  |  |  | 				return err; | 
					
						
							|  |  |  | 			if (token.type!=TK_COLON) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				r_err_str="Expected ':'"; | 
					
						
							|  |  |  | 				return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			at_key=false; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Error err = _get_token(p_str,index,p_len,token,line,r_err_str); | 
					
						
							|  |  |  | 			if (err!=OK) | 
					
						
							|  |  |  | 				return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Variant v; | 
					
						
							|  |  |  | 			err = _parse_value(v,token,p_str,index,p_len,line,r_err_str); | 
					
						
							|  |  |  | 			if (err) | 
					
						
							|  |  |  | 				return err; | 
					
						
							|  |  |  | 			object[key]=v; | 
					
						
							|  |  |  | 			need_comma=true; | 
					
						
							|  |  |  | 			at_key=true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error JSON::parse(const String& p_json,Dictionary& r_ret,String &r_err_str,int &r_err_line) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const CharType *str = p_json.ptr(); | 
					
						
							|  |  |  | 	int idx = 0; | 
					
						
							|  |  |  | 	int len = p_json.length(); | 
					
						
							|  |  |  | 	Token token; | 
					
						
							|  |  |  | 	int line=0; | 
					
						
							|  |  |  | 	String aux_key; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Error err = _get_token(str,idx,len,token,line,r_err_str); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (token.type!=TK_CURLY_BRACKET_OPEN) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		r_err_str="Expected '{'"; | 
					
						
							|  |  |  | 		return ERR_PARSE_ERROR; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return _parse_object(r_ret,str,idx,len,r_err_line,r_err_str); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 |