|
| 1 | +#include <iostream> |
| 2 | +#include <vector> |
| 3 | +#include <map> |
| 4 | +#include <string> |
| 5 | +#include <sstream> |
| 6 | +#include <fstream> |
| 7 | +#include <cstring> |
| 8 | +#include "jute.h" |
| 9 | +using namespace std; |
| 10 | +using namespace jute; |
| 11 | + |
| 12 | +string deserialize(const string& ref) { |
| 13 | + string out = ""; |
| 14 | + for (size_t i=0;i<ref.length();i++) { |
| 15 | + if (ref[i] == '\\' && i+1 < ref.length()) { |
| 16 | + int plus = 2; |
| 17 | + if (ref[i+1] == '\"') { |
| 18 | + out += '"'; |
| 19 | + }else if (ref[i+1] == '\\') { |
| 20 | + out += '\\'; |
| 21 | + }else if (ref[i+1] == '/') { |
| 22 | + out += '/'; |
| 23 | + }else if (ref[i+1] == 'b') { |
| 24 | + out += '\b'; |
| 25 | + }else if (ref[i+1] == 'f') { |
| 26 | + out += '\f'; |
| 27 | + }else if (ref[i+1] == 'n') { |
| 28 | + out += '\n'; |
| 29 | + }else if (ref[i+1] == 'r') { |
| 30 | + out += '\r'; |
| 31 | + }else if (ref[i+1] == 't') { |
| 32 | + out += '\t'; |
| 33 | + }else if(ref[i+1] == 'u' && i+5 < ref.length()) { |
| 34 | + unsigned long long v = 0; |
| 35 | + for (int j=0;j<4;j++) { |
| 36 | + v *= 16; |
| 37 | + if (ref[i+2+j] <= '9' && ref[i+2+j] >= '0') v += ref[i+2+j]-'0'; |
| 38 | + if (ref[i+2+j] <= 'f' && ref[i+2+j] >= 'a') v += ref[i+2+j]-'a'+10; |
| 39 | + } |
| 40 | + out += (char)v; |
| 41 | + plus = 6; |
| 42 | + } |
| 43 | + i += plus-1; |
| 44 | + continue; |
| 45 | + } |
| 46 | + out += ref[i]; |
| 47 | + } |
| 48 | + return out; |
| 49 | +} |
| 50 | + |
| 51 | +string jValue::makesp(int d) { |
| 52 | + string s = ""; |
| 53 | + while (d--) s += " "; |
| 54 | + return s; |
| 55 | +} |
| 56 | +string jValue::to_string_d(int d) { |
| 57 | + if (type == JSTRING) return string("\"") + svalue + string("\""); |
| 58 | + if (type == JNUMBER) return svalue; |
| 59 | + if (type == JBOOLEAN) return svalue; |
| 60 | + if (type == JNULL) return "null"; |
| 61 | + if (type == JOBJECT) { |
| 62 | + string s = string("{\n"); |
| 63 | + for (size_t i=0;i<properties.size();i++) { |
| 64 | + s += makesp(d) + string("\"") + properties[i].first + string("\": ") + properties[i].second.to_string_d(d+1) + string(i==properties.size()-1?"":",") + string("\n"); |
| 65 | + } |
| 66 | + s += makesp(d-1) + string("}"); |
| 67 | + return s; |
| 68 | + } |
| 69 | + if (type == JARRAY) { |
| 70 | + string s = "["; |
| 71 | + for (size_t i=0;i<arr.size();i++) { |
| 72 | + if (i) s += ", "; |
| 73 | + s += arr[i].to_string_d(d+1); |
| 74 | + } |
| 75 | + s += "]"; |
| 76 | + return s; |
| 77 | + } |
| 78 | + return "##"; |
| 79 | +} |
| 80 | +jValue::jValue() { |
| 81 | + this->type = JUNKNOWN; |
| 82 | +} |
| 83 | +jValue::jValue(jType tp) { |
| 84 | + this->type = tp; |
| 85 | +} |
| 86 | + |
| 87 | +string jValue::to_string() { |
| 88 | + return to_string_d(1); |
| 89 | +} |
| 90 | +jType jValue::get_type() { |
| 91 | + return type; |
| 92 | +} |
| 93 | +void jValue::set_type(jType tp) { |
| 94 | + type = tp; |
| 95 | +} |
| 96 | +void jValue::add_property(string key, jValue v) { |
| 97 | + mpindex[key] = properties.size(); |
| 98 | + properties.push_back(make_pair(key, v)); |
| 99 | +} |
| 100 | +void jValue::add_element(jValue v) { |
| 101 | + arr.push_back(v); |
| 102 | +} |
| 103 | +void jValue::set_string(string s) { |
| 104 | + svalue = s; |
| 105 | +} |
| 106 | +int jValue::as_int() { |
| 107 | + stringstream ss; |
| 108 | + ss << svalue; |
| 109 | + int k; |
| 110 | + ss >> k; |
| 111 | + return k; |
| 112 | +} |
| 113 | +double jValue::as_double() { |
| 114 | + stringstream ss; |
| 115 | + ss << svalue; |
| 116 | + double k; |
| 117 | + ss >> k; |
| 118 | + return k; |
| 119 | +} |
| 120 | +bool jValue::as_bool() { |
| 121 | + if (svalue == "true") return true; |
| 122 | + return false; |
| 123 | +} |
| 124 | +void* jValue::as_null() { |
| 125 | + return NULL; |
| 126 | +} |
| 127 | +string jValue::as_string() { |
| 128 | + return deserialize(svalue); |
| 129 | +} |
| 130 | +int jValue::size() { |
| 131 | + if (type == JARRAY) { |
| 132 | + return (int)arr.size(); |
| 133 | + } |
| 134 | + if (type == JOBJECT) { |
| 135 | + return (int)properties.size();; |
| 136 | + } |
| 137 | + return 0; |
| 138 | +} |
| 139 | +jValue jValue::operator[](int i) { |
| 140 | + if (type == JARRAY) { |
| 141 | + return arr[i]; |
| 142 | + } |
| 143 | + if (type == JOBJECT) { |
| 144 | + return properties[i].second; |
| 145 | + } |
| 146 | + return jValue(); |
| 147 | +} |
| 148 | +jValue jValue::operator[](string s) { |
| 149 | + if (mpindex.find(s) == mpindex.end()) return jValue(); |
| 150 | + return properties[mpindex[s]].second; |
| 151 | +} |
| 152 | + |
| 153 | +struct parser::token { |
| 154 | + string value; |
| 155 | + token_type type; |
| 156 | + token(string value="",token_type type=UNKNOWN): value(value), type(type) {} |
| 157 | +}; |
| 158 | +bool parser::is_whitespace(const char c) { |
| 159 | + return isspace(c); |
| 160 | +} |
| 161 | +int parser::next_whitespace(const string& source, int i) { |
| 162 | + while (i < (int)source.length()) { |
| 163 | + if (source[i] == '"') { |
| 164 | + i++; |
| 165 | + while (i < (int)source.length() && (source[i] != '"' || source[i-1] == '\\')) i++; |
| 166 | + } |
| 167 | + if (source[i] == '\'') { |
| 168 | + i++; |
| 169 | + while (i < (int)source.length() && (source[i] != '\'' || source[i-1] == '\\')) i++; |
| 170 | + } |
| 171 | + if (is_whitespace(source[i])) return i; |
| 172 | + i++; |
| 173 | + } |
| 174 | + return (int)source.length(); |
| 175 | +} |
| 176 | +int parser::skip_whitespaces(const string& source, int i) { |
| 177 | + while (i < (int)source.length()) { |
| 178 | + if (!is_whitespace(source[i])) return i; |
| 179 | + i++; |
| 180 | + } |
| 181 | + return -1; |
| 182 | +} |
| 183 | + |
| 184 | +vector<parser::token> parser::tokenize(string source) { |
| 185 | + source += " "; |
| 186 | + vector<token> tokens; |
| 187 | + int index = skip_whitespaces(source, 0); |
| 188 | + while (index >= 0) { |
| 189 | + int next = next_whitespace(source, index); |
| 190 | + string str = source.substr(index, next-index); |
| 191 | + |
| 192 | + size_t k = 0; |
| 193 | + while (k < str.length()) { |
| 194 | + if (str[k] == '"') { |
| 195 | + size_t tmp_k = k+1; |
| 196 | + while (tmp_k < str.length() && (str[tmp_k] != '"' || str[tmp_k-1] == '\\')) tmp_k++; |
| 197 | + tokens.push_back(token(str.substr(k+1, tmp_k-k-1), STRING)); |
| 198 | + k = tmp_k+1; |
| 199 | + continue; |
| 200 | + } |
| 201 | + if (str[k] == '\'') { |
| 202 | + size_t tmp_k = k+1; |
| 203 | + while (tmp_k < str.length() && (str[tmp_k] != '\'' || str[tmp_k-1] == '\\')) tmp_k++; |
| 204 | + tokens.push_back(token(str.substr(k+1, tmp_k-k-1), STRING)); |
| 205 | + k = tmp_k+1; |
| 206 | + continue; |
| 207 | + } |
| 208 | + if (str[k] == ',') { |
| 209 | + tokens.push_back(token(",", COMMA)); |
| 210 | + k++; |
| 211 | + continue; |
| 212 | + } |
| 213 | + if (str[k] == 't' && k+3 < str.length() && str.substr(k, 4) == "true") { |
| 214 | + tokens.push_back(token("true", BOOLEAN)); |
| 215 | + k += 4; |
| 216 | + continue; |
| 217 | + } |
| 218 | + if (str[k] == 'f' && k+4 < str.length() && str.substr(k, 5) == "false") { |
| 219 | + tokens.push_back(token("false", BOOLEAN)); |
| 220 | + k += 5; |
| 221 | + continue; |
| 222 | + } |
| 223 | + if (str[k] == 'n' && k+3 < str.length() && str.substr(k, 4) == "null") { |
| 224 | + tokens.push_back(token("null", NUL)); |
| 225 | + k += 4; |
| 226 | + continue; |
| 227 | + } |
| 228 | + if (str[k] == '}') { |
| 229 | + tokens.push_back(token("}", CROUSH_CLOSE)); |
| 230 | + k++; |
| 231 | + continue; |
| 232 | + } |
| 233 | + if (str[k] == '{') { |
| 234 | + tokens.push_back(token("{", CROUSH_OPEN)); |
| 235 | + k++; |
| 236 | + continue; |
| 237 | + } |
| 238 | + if (str[k] == ']') { |
| 239 | + tokens.push_back(token("]", BRACKET_CLOSE)); |
| 240 | + k++; |
| 241 | + continue; |
| 242 | + } |
| 243 | + if (str[k] == '[') { |
| 244 | + tokens.push_back(token("[", BRACKET_OPEN)); |
| 245 | + k++; |
| 246 | + continue; |
| 247 | + } |
| 248 | + if (str[k] == ':') { |
| 249 | + tokens.push_back(token(":", COLON)); |
| 250 | + k++; |
| 251 | + continue; |
| 252 | + } |
| 253 | + if (str[k] == '-' || (str[k] <= '9' && str[k] >= '0')) { |
| 254 | + size_t tmp_k = k; |
| 255 | + if (str[tmp_k] == '-') tmp_k++; |
| 256 | + while (tmp_k < str.size() && ((str[tmp_k] <= '9' && str[tmp_k] >= '0') || str[tmp_k] == '.')) tmp_k++; |
| 257 | + tokens.push_back(token(str.substr(k, tmp_k-k), NUMBER)); |
| 258 | + k = tmp_k; |
| 259 | + continue; |
| 260 | + } |
| 261 | + tokens.push_back(token(str.substr(k), UNKNOWN)); |
| 262 | + k = str.length(); |
| 263 | + } |
| 264 | + |
| 265 | + index = skip_whitespaces(source, next); |
| 266 | + } |
| 267 | + // for (int i=0;i<tokens.size();i++) { |
| 268 | + // cout << i << " " << tokens[i].value << endl; |
| 269 | + // } |
| 270 | + return tokens; |
| 271 | +} |
| 272 | + |
| 273 | + |
| 274 | +jValue parser::json_parse(vector<token> v, int i, int& r) { |
| 275 | + jValue current; |
| 276 | + if (v[i].type == CROUSH_OPEN) { |
| 277 | + current.set_type(JOBJECT); |
| 278 | + int k = i+1; |
| 279 | + while (v[k].type != CROUSH_CLOSE) { |
| 280 | + string key = v[k].value; |
| 281 | + k+=2; // k+1 should be ':' |
| 282 | + int j = k; |
| 283 | + jValue vv = json_parse(v, k, j); |
| 284 | + current.add_property(key, vv); |
| 285 | + k = j; |
| 286 | + if (v[k].type == COMMA) k++; |
| 287 | + } |
| 288 | + r = k+1; |
| 289 | + return current; |
| 290 | + } |
| 291 | + if (v[i].type == BRACKET_OPEN) { |
| 292 | + current.set_type(JARRAY); |
| 293 | + int k = i+1; |
| 294 | + while (v[k].type != BRACKET_CLOSE) { |
| 295 | + int j = k; |
| 296 | + jValue vv = json_parse(v, k, j); |
| 297 | + current.add_element(vv); |
| 298 | + k = j; |
| 299 | + if (v[k].type == COMMA) k++; |
| 300 | + } |
| 301 | + r = k+1; |
| 302 | + return current; |
| 303 | + } |
| 304 | + if (v[i].type == NUMBER) { |
| 305 | + current.set_type(JNUMBER); |
| 306 | + current.set_string(v[i].value); |
| 307 | + r = i+1; |
| 308 | + return current; |
| 309 | + } |
| 310 | + if (v[i].type == STRING) { |
| 311 | + current.set_type(JSTRING); |
| 312 | + current.set_string(v[i].value); |
| 313 | + r = i+1; |
| 314 | + return current; |
| 315 | + } |
| 316 | + if (v[i].type == BOOLEAN) { |
| 317 | + current.set_type(JBOOLEAN); |
| 318 | + current.set_string(v[i].value); |
| 319 | + r = i+1; |
| 320 | + return current; |
| 321 | + } |
| 322 | + if (v[i].type == NUL) { |
| 323 | + current.set_type(JNULL); |
| 324 | + current.set_string("null"); |
| 325 | + r = i+1; |
| 326 | + return current; |
| 327 | + } |
| 328 | + return current; |
| 329 | +} |
| 330 | + |
| 331 | +jValue parser::parse(const string& str) { |
| 332 | + int k; |
| 333 | + return json_parse(tokenize(str), 0, k); |
| 334 | +} |
| 335 | +jValue parser::parse_file(const string& filename) { |
| 336 | + ifstream in(filename.c_str()); |
| 337 | + string str = ""; |
| 338 | + string tmp; |
| 339 | + while (getline(in, tmp)) str += tmp; |
| 340 | + in.close(); |
| 341 | + return parser::parse(str); |
| 342 | +} |
| 343 | + |
0 commit comments