load JSON file, returning a value object or nullptr on failure */
| 45 | load JSON file, returning a value object or nullptr on failure |
| 46 | */ |
| 47 | AP_JSON::value *AP_JSON::load_json(const char *filename) |
| 48 | { |
| 49 | struct stat st; |
| 50 | if (AP::FS().stat(filename, &st) != 0) { |
| 51 | ::printf("No such json file %s\n", filename); |
| 52 | return nullptr; |
| 53 | } |
| 54 | int fd = AP::FS().open(filename, O_RDONLY); |
| 55 | if (fd == -1) { |
| 56 | ::printf("failed to open json %s\n", filename); |
| 57 | return nullptr; |
| 58 | } |
| 59 | char *buf = NEW_NOTHROW char[st.st_size+1]; |
| 60 | if (buf == nullptr) { |
| 61 | AP::FS().close(fd); |
| 62 | ::printf("failed to allocate json %s\n", filename); |
| 63 | return nullptr; |
| 64 | } |
| 65 | if (AP::FS().read(fd, buf, st.st_size) != st.st_size) { |
| 66 | ::printf("failed to read json %s\n", filename); |
| 67 | delete[] buf; |
| 68 | AP::FS().close(fd); |
| 69 | return nullptr; |
| 70 | } |
| 71 | AP::FS().close(fd); |
| 72 | |
| 73 | char *start = strchr(buf, '{'); |
| 74 | if (!start) { |
| 75 | ::printf("Invalid json %s\n", filename); |
| 76 | delete[] buf; |
| 77 | return nullptr; |
| 78 | } |
| 79 | |
| 80 | /* |
| 81 | remove comments, as not allowed by the parser |
| 82 | */ |
| 83 | for (char *p = strchr(start,'#'); p; p=strchr(p+1, '#')) { |
| 84 | // clear to end of line |
| 85 | do { |
| 86 | *p++ = ' '; |
| 87 | } while (*p != '\n' && *p != '\r' && *p); |
| 88 | } |
| 89 | |
| 90 | AP_JSON::value *obj = NEW_NOTHROW AP_JSON::value; |
| 91 | if (obj == nullptr) { |
| 92 | ::printf("Invalid allocate json for %s\n", filename); |
| 93 | delete[] buf; |
| 94 | return nullptr; |
| 95 | } |
| 96 | std::string err = AP_JSON::parse(*obj, start); |
| 97 | if (!err.empty()) { |
| 98 | ::printf("parse failed for json %s\n", filename); |
| 99 | delete obj; |
| 100 | delete[] buf; |
| 101 | return nullptr; |
| 102 | } |
| 103 | |
| 104 | delete[] buf; |