JsonParser.cpp
1 #include "JsonParser.hpp" 2 3 static void _errorExit(std::string const& msg); 4 5 /* *************************************************************************** * 6 * Constructor & Destructor * 7 * ****************************************************************************/ 8 9 JsonParser::JsonParser(void) {} 10 11 JsonParser::~JsonParser(void) {} 12 13 /* *************************************************************************** * 14 * Public Member Functions * 15 * ****************************************************************************/ 16 17 JsonData const& JsonParser::getJson(void) const 18 { 19 return this->_json; 20 } 21 22 JsonData JsonParser::parseJson(std::string const& filepath) 23 { 24 std::string text; 25 std::string::iterator start; 26 27 readFile(filepath, text); 28 start = text.begin(); 29 this->_json = parseObject(text, start); 30 return this->_json; 31 } 32 33 /* *************************************************************************** * 34 * Private Member Functions * 35 * ****************************************************************************/ 36 37 void JsonParser::readFile 38 (std::string const& filepath, std::string& output) 39 { 40 std::ifstream file(filepath.c_str()); 41 std::string line; 42 43 if (!file.is_open()) 44 { 45 _errorExit("Error: cannot open file " + filepath); 46 } 47 48 while (std::getline(file, line, '\0')) 49 { 50 output.append(line); 51 } 52 } 53 54 std::pair<std::string, JsonData> JsonParser::retriveKeyValuePair 55 (std::string const& text, std::string::iterator& it) 56 { 57 std::string key; 58 JsonData data; 59 60 if (it == text.end()) 61 { 62 _errorExit("Error: Incomplete object"); 63 } 64 65 while (std::isspace(*it)) 66 it++; 67 68 if (*it == '\"') 69 { 70 key = parseStringKey(text, it); 71 } 72 else if (*it == '}') 73 { 74 return std::make_pair(key, data); 75 } 76 else 77 { 78 _errorExit("Error: Invalid object key"); 79 } 80 81 while (std::isspace(*it)) 82 it++; 83 84 if (*it == '{') 85 { 86 data = parseObject(text, it); 87 } 88 else if (*it == '\"') 89 { 90 data._type = TYPE_STRING; 91 data._str = parseStringValue(text, it); 92 } 93 else if (*it == '[') 94 { 95 data._type = TYPE_ARRAY; 96 data._arr = parseArray(text, it); 97 } 98 else if (std::isalnum(*it)) 99 { 100 data._str = parsePrimitive(it, data._type); 101 } 102 else 103 { 104 _errorExit("Error: Invalid object value"); 105 } 106 107 if (checkKeyValueEnd(text, it) == false) 108 { 109 _errorExit("Error: Malformed object format"); 110 } 111 112 it++; 113 while (*it == ',' || std::isspace(*it)) 114 it++; 115 116 return std::make_pair(key, data); 117 } 118 119 std::vector<JsonData> JsonParser::parseArray 120 (std::string const& text, std::string::iterator& it) 121 { 122 std::vector<JsonData> arr; 123 std::string::iterator nxt; 124 125 it++; 126 while (it != text.end()) 127 { 128 JsonData data; 129 130 while (std::isspace(*it)) 131 it++; 132 if (*it == '{') 133 { 134 data = parseObject(text, it); 135 } 136 else if (*it == '\"') 137 { 138 data._type = TYPE_STRING; 139 data._str = parseStringValue(text, it); 140 } 141 else if (*it == '[') 142 { 143 data._type = TYPE_ARRAY; 144 data._arr = parseArray(text, it); 145 } 146 else if (*it == ']') 147 { 148 break; 149 } 150 else if (std::isalnum(*it)) 151 { 152 data._str = parsePrimitive(it, data._type); 153 } 154 else 155 { 156 _errorExit("Error: Invalid array element"); 157 } 158 159 if (checkElementEnd(text, it) == false) 160 { 161 _errorExit("Error: Malformed array format"); 162 } 163 164 it++; 165 while (*it == ',' || std::isspace(*it)) 166 it++; 167 168 arr.push_back(data); 169 } 170 171 return arr; 172 } 173 174 JsonData JsonParser::parseObject 175 (std::string const& text, std::string::iterator& it) 176 { 177 JsonData jsonData; 178 std::vector<std::pair< std::string, JsonData> > jsonObject; 179 180 while (std::isspace(*it)) 181 ++it; 182 183 if (*it != '{') 184 { 185 _errorExit("Error: Object must start with open curly bracket"); 186 } 187 it++; 188 189 do { 190 std::pair<std::string, JsonData> keyValuePair 191 = retriveKeyValuePair(text, it); 192 193 jsonObject.push_back(keyValuePair); 194 195 while (std::isspace(*it)) 196 it++; 197 198 } while (*it != '}'); 199 200 jsonData._type = TYPE_OBJECT; 201 jsonData._obj = jsonObject; 202 203 return jsonData; 204 } 205 206 bool JsonParser::checkElementEnd 207 (std::string const& text, std::string::iterator& it) 208 { 209 std::string::iterator cur; 210 bool comma = false; 211 212 if (it == text.end()) 213 { 214 _errorExit("Error: Incomplete array"); 215 } 216 217 cur = it + 1; 218 while (*cur == ',' || std::isspace(*cur)) 219 { 220 if (*cur == ',') 221 { 222 if (comma == false) 223 { 224 comma = true; 225 } 226 else 227 { 228 _errorExit("Error: Duplicate comma"); 229 } 230 } 231 cur++; 232 } 233 234 if (*cur == '\"') 235 { 236 if (comma == true) 237 { 238 return true; 239 } 240 else 241 { 242 _errorExit("Error: Missing comma before element"); 243 } 244 } 245 else if (*cur == '{') 246 { 247 if (comma == true) 248 { 249 return true; 250 } 251 else 252 { 253 _errorExit("Error: Missing comma before element"); 254 } 255 } 256 else if (*cur == '[') 257 { 258 if (comma == true) 259 { 260 return true; 261 } 262 else 263 { 264 _errorExit("Error: Missing comma before element"); 265 } 266 } 267 else if (std::isalnum(*cur)) 268 { 269 if (comma == true) 270 { 271 return true; 272 } 273 else 274 { 275 _errorExit("Error: Missing comma before element"); 276 } 277 } 278 else if (*cur == ']') 279 { 280 if (comma == false) 281 { 282 return true; 283 } 284 else 285 { 286 _errorExit("Error: Found comma before end of array"); 287 } 288 } 289 290 return false; 291 } 292 293 bool JsonParser::checkKeyValueEnd 294 (std::string const& text, std::string::iterator& it) 295 { 296 std::string::iterator cur; 297 bool comma = false; 298 299 if (it == text.end()) 300 { 301 _errorExit("Error: Incomplete object"); 302 } 303 304 cur = it + 1; 305 while (*cur == ',' || std::isspace(*cur)) 306 { 307 if (*cur == ',') 308 { 309 if (comma == false) 310 { 311 comma = true; 312 } 313 else 314 { 315 _errorExit("Error: Duplicate comma"); 316 } 317 } 318 cur++; 319 } 320 321 if (*cur == '\"') 322 { 323 if (comma == true) 324 { 325 return true; 326 } 327 else 328 { 329 _errorExit("Error: Missing comma before key"); 330 } 331 } 332 else if (*cur == '}') 333 { 334 if (comma == false) 335 { 336 return true; 337 } 338 else 339 { 340 _errorExit("Error: Found comma before end of object"); 341 } 342 } 343 344 return false; 345 } 346 347 std::string JsonParser::parsePrimitive 348 (std::string::iterator& it, jsonType& type) 349 { 350 std::string value; 351 352 while (*it != ',' && *it != '}' && *it != ']' && !std::isspace(*it)) 353 { 354 if (*it == '\"') 355 { 356 _errorExit("Error: Malformed primitive format"); 357 } 358 value += *it; 359 it++; 360 } 361 it--; 362 363 type = getPrimitiveType(value); 364 if (type == TYPE_ERROR) 365 { 366 _errorExit("Error: Invalid primitive"); 367 } 368 369 return value; 370 } 371 372 std::string JsonParser::parseStringKey 373 (std::string const& text, std::string::iterator& it) 374 { 375 std::string key; 376 377 key = getStringData(text, it); 378 379 it++; 380 while (std::isspace(*it)) 381 it++; 382 383 if (*it != ':') 384 { 385 _errorExit("Error: Missing colon after key"); 386 } 387 it++; 388 389 return key; 390 } 391 392 std::string JsonParser::parseStringValue 393 (std::string const& text, std::string::iterator& it) 394 { 395 return getStringData(text, it); 396 } 397 398 std::string JsonParser::getStringData 399 (std::string const& text, std::string::iterator& it) 400 { 401 std::string str; 402 bool insideQuote = false; 403 bool escape = false; 404 char ch; 405 406 while (it != text.end()) 407 { 408 ch = *it; 409 if (insideQuote) 410 { 411 if (ch == '\n') 412 { 413 _errorExit("Error: Malformed String Data type"); 414 } 415 if (escape) 416 { 417 str += ch; 418 escape = false; 419 } 420 else if (ch == '\\') 421 { 422 escape = true; 423 } 424 else if (ch == '\"') 425 { 426 insideQuote = false; 427 break; 428 } 429 else 430 { 431 str += ch; 432 } 433 } 434 else if (ch == '\"') 435 { 436 insideQuote = true; 437 } 438 else if (ch == '\\') 439 { 440 escape = true; 441 } 442 else 443 { 444 _errorExit("Error: Malformed String Data type"); 445 } 446 it++; 447 } 448 449 if ((it == text.end()) || insideQuote) 450 { 451 _errorExit("Error: Malformed String Data type"); 452 } 453 454 return str; 455 } 456 457 jsonType JsonParser::getPrimitiveType(std::string const& str) 458 { 459 char* endptr; 460 461 static_cast<void>(strtol(str.c_str(), &endptr, 10)); 462 if (*endptr == '\0') 463 return TYPE_INTEGER; 464 static_cast<void>(strtod(str.c_str(), &endptr)); 465 if (*endptr == '\0') 466 return TYPE_FLOAT; 467 if (str == "true" || str == "false") 468 return TYPE_BOOLEAN; 469 if (str == "null") 470 return TYPE_NULL; 471 return TYPE_ERROR; 472 } 473 474 /* *************************************************************************** * 475 * Helper Functions * 476 * ****************************************************************************/ 477 478 static void _errorExit(std::string const& msg) 479 { 480 std::cerr << msg << std::endl; 481 std::exit(1); 482 }