diff --git a/CMakeLists.txt b/CMakeLists.txt index bc52b1b7a1f1..9d1b5200c441 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -458,11 +458,9 @@ if(USING_GLES2) find_package(X11) endif() -add_library(vjson STATIC - ext/native/ext/vjson/json.cpp - ext/native/ext/vjson/json.h - ext/native/ext/vjson/block_allocator.cpp - ext/native/ext/vjson/block_allocator.h +add_library(gason STATIC + ext/native/ext/gason/gason.cpp + ext/native/ext/gason/gason.h ) add_library(rg_etc1 STATIC @@ -972,6 +970,8 @@ add_library(native STATIC ext/native/input/keycodes.h ext/native/input/input_state.h ext/native/input/input_state.cpp + ext/native/json/json_reader.h + ext/native/json/json_reader.cpp ext/native/json/json_writer.h ext/native/json/json_writer.cpp ext/native/math/fast/fast_math.c @@ -1060,7 +1060,7 @@ if(ANDROID) SET(ATOMIC_LIB atomic) endif() -target_link_libraries(native ${LIBZIP_LIBRARY} ${PNG_LIBRARY} ${ZLIB_LIBRARY} rg_etc1 vjson udis86 ${RT_LIB} ${nativeExtraLibs} ${ATOMIC_LIB}) +target_link_libraries(native ${LIBZIP_LIBRARY} ${PNG_LIBRARY} ${ZLIB_LIBRARY} rg_etc1 gason udis86 ${RT_LIB} ${nativeExtraLibs} ${ATOMIC_LIB}) if(TARGET Ext::GLEW) target_link_libraries(native Ext::GLEW) endif() diff --git a/Core/Config.cpp b/Core/Config.cpp index e2bde296d9fc..b5b775b8da42 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -22,9 +22,9 @@ #include "base/display.h" #include "base/NativeApp.h" -#include "ext/vjson/json.h" #include "file/ini_file.h" #include "i18n/i18n.h" +#include "json/json_reader.h" #include "gfx_es2/gpu_features.h" #include "net/http_client.h" #include "util/text/parsers.h" @@ -1177,13 +1177,13 @@ void Config::DownloadCompletedCallback(http::Download &download) { } JsonReader reader(data.c_str(), data.size()); - const json_value *root = reader.root(); + const JsonGet root = reader.root(); if (!root) { ERROR_LOG(LOADER, "Failed to parse json"); return; } - std::string version = root->getString("version", ""); + std::string version = root.getString("version", ""); const char *gitVer = PPSSPP_GIT_VERSION; Version installed(gitVer); diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 2767e72761f6..c9d71c6ab80a 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -21,9 +21,9 @@ #include #include "base/timeutil.h" -#include "ext/vjson/json.h" #include "file/fd_util.h" #include "i18n/i18n.h" +#include "json/json_reader.h" #include "net/http_client.h" #include "net/http_server.h" #include "net/resolve.h" @@ -252,16 +252,19 @@ static bool FindServer(std::string &resultHost, int &resultPort) { return false; } - const json_value *entries = reader.root(); - if (!entries) { + const JsonValue entries = reader.rootArray(); + if (entries.getTag() != JSON_ARRAY) { return false; } std::vector servers; - const json_value *entry = entries->first_child; - while (entry && !scanCancelled) { - const char *host = entry->getString("ip", ""); - int port = entry->getInt("p", 0); + for (const auto pentry : entries) { + JsonGet entry = pentry->value; + if (scanCancelled) + return false; + + const char *host = entry.getString("ip", ""); + int port = entry.getInt("p", 0); char url[1024] = {}; snprintf(url, sizeof(url), "http://%s:%d", host, port); @@ -270,8 +273,6 @@ static bool FindServer(std::string &resultHost, int &resultPort) { if (TryServer(host, port)) { return true; } - - entry = entry->next_sibling; } // None of the local IPs were reachable. diff --git a/UI/Store.cpp b/UI/Store.cpp index 99c79d2213d2..da2d2f1a4f17 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -18,7 +18,7 @@ #include #include "base/basictypes.h" -#include "ext/vjson/json.h" +#include "json/json_reader.h" #include "i18n/i18n.h" #include "ui/screen.h" @@ -392,33 +392,32 @@ void StoreScreen::update() { void StoreScreen::ParseListing(std::string json) { JsonReader reader(json.c_str(), json.size()); - if (!reader.ok()) { + if (!reader.ok() || !reader.root()) { ELOG("Error parsing JSON from store"); connectionError_ = true; RecreateViews(); return; } - json_value *root = reader.root(); - const json_value *entries = root->getArray("entries"); + const JsonGet root = reader.root(); + const JsonNode *entries = root.getArray("entries"); if (entries) { entries_.clear(); - const json_value *game = entries->first_child; - while (game) { + for (const JsonNode *pgame : entries->value) { + JsonGet game = pgame->value; StoreEntry e; e.type = ENTRY_PBPZIP; e.name = GetTranslatedString(game, "name"); e.description = GetTranslatedString(game, "description", ""); - e.author = game->getString("author", "?"); - e.size = game->getInt("size"); - e.downloadURL = game->getString("download-url", ""); - e.iconURL = game->getString("icon-url", ""); - e.hidden = game->getBool("hidden", false); - const char *file = game->getString("file", 0); + e.author = game.getString("author", "?"); + e.size = game.getInt("size"); + e.downloadURL = game.getString("download-url", ""); + e.iconURL = game.getString("icon-url", ""); + e.hidden = game.getBool("hidden", false); + const char *file = game.getString("file", nullptr); if (!file) continue; e.file = file; entries_.push_back(e); - game = game->next_sibling; } } } @@ -541,16 +540,16 @@ std::string StoreScreen::GetStoreJsonURL(std::string storePath) const { return path; } -std::string StoreScreen::GetTranslatedString(const json_value *json, std::string key, const char *fallback) const { - const json_value *dict = json->getDict("en_US"); - if (dict && json->hasChild(lang_.c_str(), JSON_OBJECT)) { - if (json->getDict(lang_.c_str())->hasChild(key.c_str(), JSON_STRING)) { - dict = json->getDict(lang_.c_str()); +std::string StoreScreen::GetTranslatedString(const JsonGet json, std::string key, const char *fallback) const { + JsonGet dict = json.getDict("en_US"); + if (dict && json.hasChild(lang_.c_str(), JSON_OBJECT)) { + if (json.getDict(lang_.c_str()).hasChild(key.c_str(), JSON_STRING)) { + dict = json.getDict(lang_.c_str()); } } - const char *str = 0; + const char *str = nullptr; if (dict) { - str = dict->getString(key.c_str(), 0); + str = dict.getString(key.c_str(), nullptr); } if (str) { return std::string(str); diff --git a/UI/Store.h b/UI/Store.h index 1fff85a4c924..e7786c7c9cff 100644 --- a/UI/Store.h +++ b/UI/Store.h @@ -29,7 +29,7 @@ // set game specific settings, etc. // Uses GameInfoCache heavily to implement the functionality. -struct json_value; +struct JsonGet; class ProductItemView; enum EntryType { @@ -79,7 +79,7 @@ class StoreScreen : public UIDialogScreenWithBackground { std::vector FilterEntries(); std::string GetStoreJsonURL(std::string storePath) const; - std::string GetTranslatedString(const json_value *json, std::string key, const char *fallback = 0) const; + std::string GetTranslatedString(const JsonGet json, std::string key, const char *fallback = nullptr) const; std::shared_ptr listing_; std::shared_ptr image_; diff --git a/UWP/NativeUWP/NativeUWP.vcxproj b/UWP/NativeUWP/NativeUWP.vcxproj index e6e8d6a89fbd..da5942bbfbac 100644 --- a/UWP/NativeUWP/NativeUWP.vcxproj +++ b/UWP/NativeUWP/NativeUWP.vcxproj @@ -328,8 +328,6 @@ - - @@ -338,6 +336,8 @@ + + @@ -1160,8 +1160,6 @@ NotUsing NotUsing - - @@ -1169,6 +1167,8 @@ + + diff --git a/UWP/NativeUWP/NativeUWP.vcxproj.filters b/UWP/NativeUWP/NativeUWP.vcxproj.filters index 6b58b4d5c17c..ce9603f3322a 100644 --- a/UWP/NativeUWP/NativeUWP.vcxproj.filters +++ b/UWP/NativeUWP/NativeUWP.vcxproj.filters @@ -37,9 +37,6 @@ {2be24387-0b6a-4253-97fa-b8b6f75a8a4c} - - {7fdd3320-a8e0-42ed-b08b-2d86ba2ff414} - {1a486fc4-bac0-4b33-9139-262272690c74} @@ -214,12 +211,6 @@ i18n - - ext\vjson - - - ext\vjson - ext\libzip @@ -656,12 +647,6 @@ i18n - - ext\vjson - - - ext\vjson - ext\libzip diff --git a/ext/native/Android.mk b/ext/native/Android.mk index 78a75db9d434..bcef6cec25cd 100644 --- a/ext/native/Android.mk +++ b/ext/native/Android.mk @@ -35,8 +35,7 @@ LOCAL_SRC_FILES :=\ ext/jpge/jpgd.cpp \ ext/jpge/jpge.cpp \ ext/sha1/sha1.cpp \ - ext/vjson/json.cpp \ - ext/vjson/block_allocator.cpp \ + ext/gason/gason.cpp \ file/fd_util.cpp \ file/chunk_file.cpp \ file/file_util.cpp \ @@ -44,6 +43,7 @@ LOCAL_SRC_FILES :=\ file/path.cpp \ file/ini_file.cpp \ file/zip_read.cpp \ + json/json_reader.cpp \ json/json_writer.cpp \ i18n/i18n.cpp \ input/gesture_detector.cpp \ diff --git a/ext/native/ext/gason/LICENSE b/ext/native/ext/gason/LICENSE new file mode 100644 index 000000000000..0c4133a47ed3 --- /dev/null +++ b/ext/native/ext/gason/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2015 Ivan Vashchaev + +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. diff --git a/ext/native/ext/gason/gason.cpp b/ext/native/ext/gason/gason.cpp new file mode 100644 index 000000000000..c3ce4efec7ea --- /dev/null +++ b/ext/native/ext/gason/gason.cpp @@ -0,0 +1,334 @@ +#include "gason.h" +#include + +#define JSON_ZONE_SIZE 4096 +#define JSON_STACK_SIZE 32 + +const char *jsonStrError(int err) { + switch (err) { +#define XX(no, str) \ + case JSON_##no: \ + return str; + JSON_ERRNO_MAP(XX) +#undef XX + default: + return "unknown"; + } +} + +void *JsonAllocator::allocate(size_t size) { + size = (size + 7) & ~7; + + if (head && head->used + size <= JSON_ZONE_SIZE) { + char *p = (char *)head + head->used; + head->used += size; + return p; + } + + size_t allocSize = sizeof(Zone) + size; + Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize); + if (zone == nullptr) + return nullptr; + zone->used = allocSize; + if (allocSize <= JSON_ZONE_SIZE || head == nullptr) { + zone->next = head; + head = zone; + } else { + zone->next = head->next; + head->next = zone; + } + return (char *)zone + sizeof(Zone); +} + +void JsonAllocator::deallocate() { + while (head) { + Zone *next = head->next; + free(head); + head = next; + } +} + +static inline bool isspace(char c) { + return c == ' ' || (c >= '\t' && c <= '\r'); +} + +static inline bool isdelim(char c) { + return c == ',' || c == ':' || c == ']' || c == '}' || isspace(c) || !c; +} + +static inline bool isdigit(char c) { + return c >= '0' && c <= '9'; +} + +static inline bool isxdigit(char c) { + return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F'); +} + +static inline int char2int(char c) { + if (c <= '9') + return c - '0'; + return (c & ~' ') - 'A' + 10; +} + +static double string2double(char *s, char **endptr) { + char ch = *s; + if (ch == '-') + ++s; + + double result = 0; + while (isdigit(*s)) + result = (result * 10) + (*s++ - '0'); + + if (*s == '.') { + ++s; + + double fraction = 1; + while (isdigit(*s)) { + fraction *= 0.1; + result += (*s++ - '0') * fraction; + } + } + + if (*s == 'e' || *s == 'E') { + ++s; + + double base = 10; + if (*s == '+') + ++s; + else if (*s == '-') { + ++s; + base = 0.1; + } + + unsigned int exponent = 0; + while (isdigit(*s)) + exponent = (exponent * 10) + (*s++ - '0'); + + double power = 1; + for (; exponent; exponent >>= 1, base *= base) + if (exponent & 1) + power *= base; + + result *= power; + } + + *endptr = s; + return ch == '-' ? -result : result; +} + +static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) { + if (!tail) + return node->next = node; + node->next = tail->next; + tail->next = node; + return node; +} + +static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) { + if (tail) { + auto head = tail->next; + tail->next = nullptr; + return JsonValue(tag, head); + } + return JsonValue(tag, nullptr); +} + +int jsonParse(char *s, char **endptr, JsonValue *value, JsonAllocator &allocator) { + JsonNode *tails[JSON_STACK_SIZE]; + JsonTag tags[JSON_STACK_SIZE]; + char *keys[JSON_STACK_SIZE]; + JsonValue o; + int pos = -1; + bool separator = true; + JsonNode *node; + *endptr = s; + + while (*s) { + while (isspace(*s)) { + ++s; + if (!*s) break; + } + *endptr = s++; + switch (**endptr) { + case '-': + if (!isdigit(*s) && *s != '.') { + *endptr = s; + return JSON_BAD_NUMBER; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + o = JsonValue(string2double(*endptr, &s)); + if (!isdelim(*s)) { + *endptr = s; + return JSON_BAD_NUMBER; + } + break; + case '"': + o = JsonValue(JSON_STRING, s); + for (char *it = s; *s; ++it, ++s) { + int c = *it = *s; + if (c == '\\') { + c = *++s; + switch (c) { + case '\\': + case '"': + case '/': + *it = c; + break; + case 'b': + *it = '\b'; + break; + case 'f': + *it = '\f'; + break; + case 'n': + *it = '\n'; + break; + case 'r': + *it = '\r'; + break; + case 't': + *it = '\t'; + break; + case 'u': + c = 0; + for (int i = 0; i < 4; ++i) { + if (isxdigit(*++s)) { + c = c * 16 + char2int(*s); + } else { + *endptr = s; + return JSON_BAD_STRING; + } + } + if (c < 0x80) { + *it = c; + } else if (c < 0x800) { + *it++ = 0xC0 | (c >> 6); + *it = 0x80 | (c & 0x3F); + } else { + *it++ = 0xE0 | (c >> 12); + *it++ = 0x80 | ((c >> 6) & 0x3F); + *it = 0x80 | (c & 0x3F); + } + break; + default: + *endptr = s; + return JSON_BAD_STRING; + } + } else if ((unsigned int)c < ' ' || c == '\x7F') { + *endptr = s; + return JSON_BAD_STRING; + } else if (c == '"') { + *it = 0; + ++s; + break; + } + } + if (!isdelim(*s)) { + *endptr = s; + return JSON_BAD_STRING; + } + break; + case 't': + if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_TRUE); + s += 3; + break; + case 'f': + if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_FALSE); + s += 4; + break; + case 'n': + if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_NULL); + s += 3; + break; + case ']': + if (pos == -1) + return JSON_STACK_UNDERFLOW; + if (tags[pos] != JSON_ARRAY) + return JSON_MISMATCH_BRACKET; + o = listToValue(JSON_ARRAY, tails[pos--]); + break; + case '}': + if (pos == -1) + return JSON_STACK_UNDERFLOW; + if (tags[pos] != JSON_OBJECT) + return JSON_MISMATCH_BRACKET; + if (keys[pos] != nullptr) + return JSON_UNEXPECTED_CHARACTER; + o = listToValue(JSON_OBJECT, tails[pos--]); + break; + case '[': + if (++pos == JSON_STACK_SIZE) + return JSON_STACK_OVERFLOW; + tails[pos] = nullptr; + tags[pos] = JSON_ARRAY; + keys[pos] = nullptr; + separator = true; + continue; + case '{': + if (++pos == JSON_STACK_SIZE) + return JSON_STACK_OVERFLOW; + tails[pos] = nullptr; + tags[pos] = JSON_OBJECT; + keys[pos] = nullptr; + separator = true; + continue; + case ':': + if (separator || keys[pos] == nullptr) + return JSON_UNEXPECTED_CHARACTER; + separator = true; + continue; + case ',': + if (separator || keys[pos] != nullptr) + return JSON_UNEXPECTED_CHARACTER; + separator = true; + continue; + case '\0': + continue; + default: + return JSON_UNEXPECTED_CHARACTER; + } + + separator = false; + + if (pos == -1) { + *endptr = s; + *value = o; + return JSON_OK; + } + + if (tags[pos] == JSON_OBJECT) { + if (!keys[pos]) { + if (o.getTag() != JSON_STRING) + return JSON_UNQUOTED_KEY; + keys[pos] = o.toString(); + continue; + } + if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode))) == nullptr) + return JSON_ALLOCATION_FAILURE; + tails[pos] = insertAfter(tails[pos], node); + tails[pos]->key = keys[pos]; + keys[pos] = nullptr; + } else { + if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode) - sizeof(char *))) == nullptr) + return JSON_ALLOCATION_FAILURE; + tails[pos] = insertAfter(tails[pos], node); + } + tails[pos]->value = o; + } + return JSON_BREAKING_BAD; +} diff --git a/ext/native/ext/gason/gason.h b/ext/native/ext/gason/gason.h new file mode 100644 index 000000000000..7c3eed96f63f --- /dev/null +++ b/ext/native/ext/gason/gason.h @@ -0,0 +1,135 @@ +#pragma once + +#include +#include +#include + +enum JsonTag { + JSON_NUMBER = 0, + JSON_STRING, + JSON_ARRAY, + JSON_OBJECT, + JSON_TRUE, + JSON_FALSE, + JSON_NULL = 0xF +}; + +struct JsonNode; + +#define JSON_VALUE_PAYLOAD_MASK 0x00007FFFFFFFFFFFULL +#define JSON_VALUE_NAN_MASK 0x7FF8000000000000ULL +#define JSON_VALUE_TAG_MASK 0xF +#define JSON_VALUE_TAG_SHIFT 47 + +union JsonValue { + uint64_t ival; + double fval; + + JsonValue(double x) + : fval(x) { + } + JsonValue(JsonTag tag = JSON_NULL, void *payload = nullptr) { + assert((uintptr_t)payload <= JSON_VALUE_PAYLOAD_MASK); + ival = JSON_VALUE_NAN_MASK | ((uint64_t)tag << JSON_VALUE_TAG_SHIFT) | (uintptr_t)payload; + } + bool isDouble() const { + return (int64_t)ival <= (int64_t)JSON_VALUE_NAN_MASK; + } + JsonTag getTag() const { + return isDouble() ? JSON_NUMBER : JsonTag((ival >> JSON_VALUE_TAG_SHIFT) & JSON_VALUE_TAG_MASK); + } + uint64_t getPayload() const { + assert(!isDouble()); + return ival & JSON_VALUE_PAYLOAD_MASK; + } + double toNumber() const { + assert(getTag() == JSON_NUMBER); + return fval; + } + char *toString() const { + assert(getTag() == JSON_STRING); + return (char *)getPayload(); + } + JsonNode *toNode() const { + assert(getTag() == JSON_ARRAY || getTag() == JSON_OBJECT); + return (JsonNode *)getPayload(); + } +}; + +struct JsonNode { + JsonValue value; + JsonNode *next; + char *key; +}; + +struct JsonIterator { + JsonNode *p; + + void operator++() { + p = p->next; + } + bool operator!=(const JsonIterator &x) const { + return p != x.p; + } + JsonNode *operator*() const { + return p; + } + JsonNode *operator->() const { + return p; + } +}; + +inline JsonIterator begin(JsonValue o) { + return JsonIterator{o.toNode()}; +} +inline JsonIterator end(JsonValue) { + return JsonIterator{nullptr}; +} + +#define JSON_ERRNO_MAP(XX) \ + XX(OK, "ok") \ + XX(BAD_NUMBER, "bad number") \ + XX(BAD_STRING, "bad string") \ + XX(BAD_IDENTIFIER, "bad identifier") \ + XX(STACK_OVERFLOW, "stack overflow") \ + XX(STACK_UNDERFLOW, "stack underflow") \ + XX(MISMATCH_BRACKET, "mismatch bracket") \ + XX(UNEXPECTED_CHARACTER, "unexpected character") \ + XX(UNQUOTED_KEY, "unquoted key") \ + XX(BREAKING_BAD, "breaking bad") \ + XX(ALLOCATION_FAILURE, "allocation failure") + +enum JsonErrno { +#define XX(no, str) JSON_##no, + JSON_ERRNO_MAP(XX) +#undef XX +}; + +const char *jsonStrError(int err); + +class JsonAllocator { + struct Zone { + Zone *next; + size_t used; + } *head; + +public: + JsonAllocator() : head(nullptr) {}; + JsonAllocator(const JsonAllocator &) = delete; + JsonAllocator &operator=(const JsonAllocator &) = delete; + JsonAllocator(JsonAllocator &&x) : head(x.head) { + x.head = nullptr; + } + JsonAllocator &operator=(JsonAllocator &&x) { + head = x.head; + x.head = nullptr; + return *this; + } + ~JsonAllocator() { + deallocate(); + } + void *allocate(size_t size); + void deallocate(); +}; + +int jsonParse(char *str, char **endptr, JsonValue *value, JsonAllocator &allocator); diff --git a/ext/native/ext/vjson/CMakeLists.txt b/ext/native/ext/vjson/CMakeLists.txt deleted file mode 100644 index b8d19dc34f15..000000000000 --- a/ext/native/ext/vjson/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -#if(UNIX) -add_definitions(-fPIC) -add_definitions(-g) -add_definitions(-O2) -add_definitions(-Wall) -#endif(UNIX) - -add_library(vjson json.cpp block_allocator.cpp) diff --git a/ext/native/ext/vjson/block_allocator.cpp b/ext/native/ext/vjson/block_allocator.cpp deleted file mode 100644 index f3a573c6531b..000000000000 --- a/ext/native/ext/vjson/block_allocator.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include "block_allocator.h" - -block_allocator::block_allocator(size_t blocksize) - : m_head(0), m_blocksize(blocksize) -{ -} - -block_allocator::~block_allocator() -{ - while (m_head) - { - block *temp = m_head->next; - ::free(m_head); - m_head = temp; - } -} - -void block_allocator::swap(block_allocator &rhs) -{ - std::swap(m_blocksize, rhs.m_blocksize); - std::swap(m_head, rhs.m_head); -} - -void *block_allocator::Malloc(size_t size) -{ - if ((m_head && m_head->used + size > m_head->size) || !m_head) - { - // calc needed size for allocation - size_t alloc_size = std::max(sizeof(block) + size, m_blocksize); - - // create new block - char *buffer = (char *)::malloc(alloc_size); - block *b = reinterpret_cast(buffer); - b->size = alloc_size; - b->used = sizeof(block); - b->buffer = buffer; - b->next = m_head; - m_head = b; - } - - void *ptr = m_head->buffer + m_head->used; - m_head->used += size; - return ptr; -} - -void block_allocator::Free() -{ - block_allocator(0).swap(*this); -} diff --git a/ext/native/ext/vjson/block_allocator.h b/ext/native/ext/vjson/block_allocator.h deleted file mode 100644 index 9fff7efc5074..000000000000 --- a/ext/native/ext/vjson/block_allocator.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef BLOCK_ALLOCATOR_H -#define BLOCK_ALLOCATOR_H - -class block_allocator -{ -public: - block_allocator(size_t blocksize); - ~block_allocator(); - - // exchange contents with rhs - void swap(block_allocator &rhs); - - // allocate memory - void *Malloc(size_t size); - - // free all allocated blocks - void Free(); - -private: - struct block - { - size_t size; - size_t used; - char *buffer; - block *next; - }; - - block *m_head; - size_t m_blocksize; - - block_allocator(const block_allocator &); - block_allocator &operator=(block_allocator &); -}; - -#endif diff --git a/ext/native/ext/vjson/json.cpp b/ext/native/ext/vjson/json.cpp deleted file mode 100644 index 7203cb577b30..000000000000 --- a/ext/native/ext/vjson/json.cpp +++ /dev/null @@ -1,643 +0,0 @@ -#include -#include -#include -#include "json.h" -#include "file/zip_read.h" -#include "file/vfs.h" - -// true if character represent a digit -#define IS_DIGIT(c) (c >= '0' && c <= '9') - -int json_value::numChildren() const { - int count = 0; - const json_value *c = first_child; - while (c) { - count++; - c = c->next_sibling; - } - return count; -} - -// only works right for first child. includes itself in count. -int json_value::numSiblings() const { - const json_value *s = next_sibling; - int count = 1; - while (s) { - count++; - s = s->next_sibling; - } - return count; -} - -const json_value *json_value::get(const char *child_name) const { - if (!child_name) { - FLOG("JSON: Cannot get from null child name"); - return 0; - } - const json_value *c = first_child; - while (c) { - if (!strcmp(c->name, child_name)) { - return c; - } - c = c->next_sibling; - } - return 0; -} - -const json_value *json_value::get(const char *child_name, json_type type) const { - const json_value *v = get(child_name); - if (v && type == v->type) - return v; - else - return 0; -} - -const char *json_value::getStringOrDie(const char *child_name) const { - const json_value *val = get(child_name, JSON_STRING); - if (val) - return val->string_value; - else - FLOG("String '%s' missing from node '%s'", child_name, this->name); - return 0; -} - -const char *json_value::getString(const char *child_name, const char *default_value) const { - const json_value *val = get(child_name, JSON_STRING); - if (!val) - return default_value; - return val->string_value; -} - -bool json_value::getStringVector(std::vector *vec) const { - vec->clear(); - if (type == JSON_ARRAY) { - json_value *val = first_child; - while (val) { - if (val->type == JSON_STRING) { - vec->push_back(val->string_value); - } - } - return true; - } else { - return false; - } -} - -float json_value::getFloat(const char *child_name) const { - return get(child_name, JSON_FLOAT)->float_value; -} - -float json_value::getFloat(const char *child_name, float default_value) const { - const json_value *val = get(child_name, JSON_FLOAT); - if (!val) { - // Let's try int. - val = get(child_name, JSON_INT); - if (!val) - return default_value; - return val->int_value; - } - return val->float_value; -} - -int json_value::getInt(const char *child_name) const { - return get(child_name, JSON_INT)->int_value; -} - -int json_value::getInt(const char *child_name, int default_value) const { - const json_value *val = get(child_name, JSON_INT); - if (!val) - return default_value; - return val->int_value; -} - -bool json_value::getBool(const char *child_name) const { - return get(child_name, JSON_BOOL)->int_value != 0 ? true : false; -} - -bool json_value::getBool(const char *child_name, bool default_value) const { - const json_value *val = get(child_name, JSON_BOOL); - if (!val) - return default_value; - return val->int_value != 0 ? true : false; -} - - -// convert string to integer -char *atoi(char *first, char *last, int *out) -{ - int sign = 1; - if (first != last) - { - if (*first == '-') - { - sign = -1; - ++first; - } - else if (*first == '+') - { - ++first; - } - } - - int result = 0; - for (; first != last && IS_DIGIT(*first); ++first) - { - result = 10 * result + (*first - '0'); - } - *out = result * sign; - - return first; -} - -// convert hexadecimal string to unsigned integer -char *hatoui(char *first, char *last, unsigned int *out) -{ - unsigned int result = 0; - for (; first != last; ++first) - { - int digit; - if (IS_DIGIT(*first)) - { - digit = *first - '0'; - } - else if (*first >= 'a' && *first <= 'f') - { - digit = *first - 'a' + 10; - } - else if (*first >= 'A' && *first <= 'F') - { - digit = *first - 'A' + 10; - } - else - { - break; - } - result = 16 * result + digit; - } - *out = result; - - return first; -} - -// convert string to floating point -char *atof(char *first, char *last, float *out) -{ - // sign - float sign = 1; - if (first != last) - { - if (*first == '-') - { - sign = -1; - ++first; - } - else if (*first == '+') - { - ++first; - } - } - - // integer part - float result = 0; - for (; first != last && IS_DIGIT(*first); ++first) - { - result = 10 * result + (*first - '0'); - } - - // fraction part - if (first != last && *first == '.') - { - ++first; - - float inv_base = 0.1f; - for (; first != last && IS_DIGIT(*first); ++first) - { - result += (*first - '0') * inv_base; - inv_base *= 0.1f; - } - } - - // result w\o exponent - result *= sign; - - // exponent - bool exponent_negative = false; - int exponent = 0; - if (first != last && (*first == 'e' || *first == 'E')) - { - ++first; - - if (*first == '-') - { - exponent_negative = true; - ++first; - } - else if (*first == '+') - { - ++first; - } - - for (; first != last && IS_DIGIT(*first); ++first) - { - exponent = 10 * exponent + (*first - '0'); - } - } - - if (exponent) - { - float power_of_ten = 10; - for (; exponent > 1; exponent--) - { - power_of_ten *= 10; - } - - if (exponent_negative) - { - result /= power_of_ten; - } - else - { - result *= power_of_ten; - } - } - - *out = result; - - return first; -} - -json_value *json_alloc(block_allocator *allocator) -{ - json_value *value = (json_value *)allocator->Malloc(sizeof(json_value)); - memset(value, 0, sizeof(json_value)); - return value; -} - -void json_append(json_value *lhs, json_value *rhs) -{ - rhs->parent = lhs; - if (lhs->last_child) - { - lhs->last_child = lhs->last_child->next_sibling = rhs; - } - else - { - lhs->first_child = lhs->last_child = rhs; - } -} - -#undef ERROR - -#define ERROR(it, desc)\ - *error_pos = it;\ - *error_desc = (char *)desc;\ - *error_line = 1 - escaped_newlines;\ - for (char *c = it; c != source; --c)\ - if (*c == '\n') ++*error_line;\ - return 0 - -#define CHECK_TOP() if (!top) {ERROR(it, "Unexpected character");} - -json_value *json_parse(char *source, char **error_pos, char **error_desc, int *error_line, block_allocator *allocator) -{ - json_value *root = 0; - json_value *top = 0; - - char *name = 0; - char *it = source; - - int escaped_newlines = 0; - - while (*it) - { - switch (*it) - { - case '{': - case '[': - { - // create new value - json_value *object = json_alloc(allocator); - - // name - object->name = name; - name = 0; - - // type - object->type = (*it == '{') ? JSON_OBJECT : JSON_ARRAY; - - // skip open character - ++it; - - // set top and root - if (top) - { - json_append(top, object); - } - else if (!root) - { - root = object; - } - else - { - ERROR(it, "Second root. Only one root allowed"); - } - top = object; - } - break; - - case '}': - case ']': - { - if (!top || top->type != ((*it == '}') ? JSON_OBJECT : JSON_ARRAY)) - { - ERROR(it, "Mismatch closing brace/bracket"); - } - - // skip close character - ++it; - - // set top - top = top->parent; - } - break; - - case ':': - if (!top || top->type != JSON_OBJECT) - { - ERROR(it, "Unexpected character (no top level)"); - } - ++it; - break; - - case ',': - CHECK_TOP(); - ++it; - break; - - case '"': - { - CHECK_TOP(); - - // skip '"' character - ++it; - - char *first = it; - char *last = it; - while (*it) - { - if ((unsigned char)*it < '\x20') - { - ERROR(first, "Control characters not allowed in strings"); - } - else if (*it == '\\') - { - switch (it[1]) - { - case '"': - *last = '"'; - break; - case '\\': - *last = '\\'; - break; - case '/': - *last = '/'; - break; - case 'b': - *last = '\b'; - break; - case 'f': - *last = '\f'; - break; - case 'n': - *last = '\n'; - ++escaped_newlines; - break; - case 'r': - *last = '\r'; - break; - case 't': - *last = '\t'; - break; - case 'u': - { - unsigned int codepoint; - if (hatoui(it + 2, it + 6, &codepoint) != it + 6) - { - ERROR(it, "Bad unicode codepoint"); - } - - if (codepoint <= 0x7F) - { - *last = (char)codepoint; - } - else if (codepoint <= 0x7FF) - { - *last++ = (char)(0xC0 | (codepoint >> 6)); - *last = (char)(0x80 | (codepoint & 0x3F)); - } - else if (codepoint <= 0xFFFF) - { - *last++ = (char)(0xE0 | (codepoint >> 12)); - *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F)); - *last = (char)(0x80 | (codepoint & 0x3F)); - } - } - it += 4; - break; - default: - ERROR(first, "Unrecognized escape sequence"); - } - - ++last; - it += 2; - } - else if (*it == '"') - { - *last = 0; - ++it; - break; - } - else - { - *last++ = *it++; - } - } - - if (!name && top->type == JSON_OBJECT) - { - // field name in object - name = first; - } - else - { - // new string value - json_value *object = json_alloc(allocator); - - object->name = name; - name = 0; - - object->type = JSON_STRING; - object->string_value = first; - - json_append(top, object); - } - } - break; - - case 'n': - case 't': - case 'f': - { - CHECK_TOP(); - - // new null/bool value - json_value *object = json_alloc(allocator); - - object->name = name; - name = 0; - - // null - if (it[0] == 'n' && it[1] == 'u' && it[2] == 'l' && it[3] == 'l') - { - object->type = JSON_NULL; - it += 4; - } - // true - else if (it[0] == 't' && it[1] == 'r' && it[2] == 'u' && it[3] == 'e') - { - object->type = JSON_BOOL; - object->int_value = 1; - it += 4; - } - // false - else if (it[0] == 'f' && it[1] == 'a' && it[2] == 'l' && it[3] == 's' && it[4] == 'e') - { - object->type = JSON_BOOL; - object->int_value = 0; - it += 5; - } - else - { - ERROR(it, "Unknown identifier"); - } - - json_append(top, object); - } - break; - - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - CHECK_TOP(); - - // new number value - json_value *object = json_alloc(allocator); - - object->name = name; - name = 0; - - object->type = JSON_INT; - - char *first = it; - while (*it != '\x20' && *it != '\x9' && *it != '\xD' && *it != '\xA' && *it != ',' && *it != ']' && *it != '}') - { - if (*it == '.' || *it == 'e' || *it == 'E') - { - object->type = JSON_FLOAT; - } - ++it; - } - - if (object->type == JSON_INT && atoi(first, it, &object->int_value) != it) - { - ERROR(first, "Bad integer number"); - } - - if (object->type == JSON_FLOAT && atof(first, it, &object->float_value) != it) - { - ERROR(first, "Bad float number"); - } - - json_append(top, object); - } - break; - - default: - ERROR(it, "Unexpected character (unknown)"); - } - - // skip white space - while (*it == '\x20' || *it == '\x9' || *it == '\xD' || *it == '\xA') - { - ++it; - } - } - - if (top) - { - ERROR(it, "Not all objects/arrays have been properly closed"); - } - - return root; -} - -#define IDENT(n) for (int i = 0; i < n; ++i) printf(" ") - -void json_print(json_value *value, int ident) -{ - IDENT(ident); - if (value->name) printf("\"%s\" = ", value->name); - switch(value->type) - { - case JSON_NULL: - printf("null\n"); - break; - case JSON_OBJECT: - case JSON_ARRAY: - printf(value->type == JSON_OBJECT ? "{\n" : "[\n"); - for (json_value *it = value->first_child; it; it = it->next_sibling) - { - json_print(it, ident + 1); - } - IDENT(ident); - printf(value->type == JSON_OBJECT ? "}\n" : "]\n"); - break; - case JSON_STRING: - printf("\"%s\"\n", value->string_value); - break; - case JSON_INT: - printf("%d\n", value->int_value); - break; - case JSON_FLOAT: - printf("%f\n", value->float_value); - break; - case JSON_BOOL: - printf(value->int_value ? "true\n" : "false\n"); - break; - } -} - -JsonReader::JsonReader(const std::string &filename) : alloc_(1 << 12), root_(0) { - size_t buf_size; - buffer_ = (char *)VFSReadFile(filename.c_str(), &buf_size); - if (buffer_) { - parse(); - } else { - // Okay, try to read on the local file system - buffer_ = (char *)ReadLocalFile(filename.c_str(), &buf_size); - if (buffer_) { - parse(); - } else { - ELOG("Failed to read json %s", filename.c_str()); - } - } -} diff --git a/ext/native/ext/vjson/json.h b/ext/native/ext/vjson/json.h deleted file mode 100644 index 792ab1cba414..000000000000 --- a/ext/native/ext/vjson/json.h +++ /dev/null @@ -1,113 +0,0 @@ -#pragma once - -#include -#include -#include -#include "base/logging.h" -#include "block_allocator.h" -#include "file/vfs.h" - -enum json_type { - JSON_NULL, - JSON_OBJECT, - JSON_ARRAY, - JSON_STRING, - JSON_INT, - JSON_FLOAT, - JSON_BOOL, -}; - -struct json_value { - json_value() {} - - json_value *parent; - json_value *next_sibling; - json_value *first_child; - json_value *last_child; - - char *name; - union - { - char *string_value; - int int_value; - float float_value; - }; - - json_type type; - - int numChildren() const; - int numSiblings() const; // num siblings *after* this one only - const json_value *get(const char *child_name) const; - const json_value *get(const char *child_name, json_type type) const; - const json_value *getArray(const char *child_name) const { - return get(child_name, JSON_ARRAY); - } - const json_value *getDict(const char *child_name) const { - return get(child_name, JSON_OBJECT); - } - const char *getStringOrDie(const char *child_name) const; - const char *getString(const char *child_name, const char *default_value) const; - bool getStringVector(std::vector *vec) const; - float getFloat(const char *child_name) const; - float getFloat(const char *child_name, float default_value) const; - int getInt(const char *child_name) const; - int getInt(const char *child_name, int default_value) const; - bool getBool(const char *child_name) const; - bool getBool(const char *child_name, bool default_value) const; - - bool hasChild(const char *child_name, json_type child_type) const { - return get(child_name, child_type) != 0; - } - -private: - DISALLOW_COPY_AND_ASSIGN(json_value); -}; - -// low level interface -json_value *json_parse(char *source, char **error_pos, char **error_desc, int *error_line, block_allocator *allocator); -void json_print(json_value *value, int ident = 0); - -// Easy-wrapper -class JsonReader { -public: - JsonReader(const std::string &filename); - JsonReader(const char *data, size_t size) : alloc_(1 << 12) { - buffer_ = (char *)malloc(size + 1); - memcpy(buffer_, data, size); - buffer_[size] = 0; - parse(); - } - - ~JsonReader() { - if (buffer_) - free(buffer_); - } - - bool ok() const { return root_ != 0; } - - json_value *root() { return root_; } - const json_value *root() const { return root_; } - - void print() { - json_print(root_); - } - -private: - bool parse() { - char *error_pos; - char *error_desc; - int error_line; - root_ = json_parse((char *)buffer_, &error_pos, &error_desc, &error_line, &alloc_); - if (!root_) { - ELOG("Error at (%i): %s\n%s\n\n", error_line, error_desc, error_pos); - return false; - } - return true; - } - - char *buffer_; - block_allocator alloc_; - json_value *root_; - - DISALLOW_COPY_AND_ASSIGN(JsonReader); -}; diff --git a/ext/native/ext/vjson/main.cpp b/ext/native/ext/vjson/main.cpp deleted file mode 100644 index 81f72e5c286f..000000000000 --- a/ext/native/ext/vjson/main.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include "json.h" - -void populate_sources(const char *filter, std::vector > &sources) -{ - char filename[256]; - for (int i = 1; i < 64; ++i) - { - sprintf(filename, filter, i); - FILE *fp = fopen(filename, "rb"); - if (fp) - { - fseek(fp, 0, SEEK_END); - int size = ftell(fp); - fseek(fp, 0, SEEK_SET); - std::vector buffer(size + 1); - fread (&buffer[0], 1, size, fp); - fclose(fp); - sources.push_back(buffer); - } - else - { - break; - } - } - - printf("Loaded %d json files\n", (int)sources.size()); -} - -#define IDENT(n) for (int i = 0; i < n; ++i) printf(" ") - -void print(json_value *value, int ident = 0) -{ - IDENT(ident); - if (value->name) printf("\"%s\" = ", value->name); - switch(value->type) - { - case JSON_NULL: - printf("null\n"); - break; - case JSON_OBJECT: - case JSON_ARRAY: - printf(value->type == JSON_OBJECT ? "{\n" : "[\n"); - for (json_value *it = value->first_child; it; it = it->next_sibling) - { - print(it, ident + 1); - } - IDENT(ident); - printf(value->type == JSON_OBJECT ? "}\n" : "]\n"); - break; - case JSON_STRING: - printf("\"%s\"\n", value->string_value); - break; - case JSON_INT: - printf("%d\n", value->int_value); - break; - case JSON_FLOAT: - printf("%f\n", value->float_value); - break; - case JSON_BOOL: - printf(value->int_value ? "true\n" : "false\n"); - break; - } -} - -bool parse(char *source) -{ - char *errorPos = 0; - char *errorDesc = 0; - int errorLine = 0; - block_allocator allocator(1 << 10); - - json_value *root = json_parse(source, &errorPos, &errorDesc, &errorLine, &allocator); - if (root) - { - print(root); - return true; - } - - printf("Error at line %d: %s\n%s\n\n", errorLine, errorDesc, errorPos); - return false; -} - -int main(int argc, char **argv) -{ - // Fail - printf("===FAIL===\n\n"); - std::vector > sources; - populate_sources("test/fail%d.json", sources); - int passed = 0; - for (size_t i = 0; i < sources.size(); ++i) - { - printf("Parsing %d\n", (int)i + 1); - if (parse(&sources[i][0])) - { - ++passed; - } - } - printf("Passed %d from %d tests\n", passed, (int)sources.size()); - - // Pass - sources.clear(); - printf("\n===PASS===\n\n"); - populate_sources("test/pass%d.json", sources); - passed = 0; - for (size_t i = 0; i < sources.size(); ++i) - { - printf("Parsing %d\n", (int)i + 1); - if (parse(&sources[i][0])) - { - ++passed; - } - } - printf("Passed %d from %d tests\n", passed, (int)sources.size()); - - return 0; -} diff --git a/ext/native/json/json_reader.cpp b/ext/native/json/json_reader.cpp new file mode 100644 index 000000000000..83fbe94fa463 --- /dev/null +++ b/ext/native/json/json_reader.cpp @@ -0,0 +1,119 @@ +#include "file/zip_read.h" +#include "file/vfs.h" +#include "json/json_reader.h" + +JsonReader::JsonReader(const std::string &filename) { + size_t buf_size; + buffer_ = (char *)VFSReadFile(filename.c_str(), &buf_size); + if (buffer_) { + parse(); + } else { + // Okay, try to read on the local file system + buffer_ = (char *)ReadLocalFile(filename.c_str(), &buf_size); + if (buffer_) { + parse(); + } else { + ELOG("Failed to read json %s", filename.c_str()); + } + } +} + +int JsonGet::numChildren() const { + int count = 0; + if (value_.getTag() == JSON_OBJECT || value_.getTag() == JSON_ARRAY) { + for (auto it : value_) { + count++; + } + } + return count; +} + +const JsonNode *JsonGet::get(const char *child_name) const { + if (!child_name) { + FLOG("JSON: Cannot get from null child name"); + return nullptr; + } + if (value_.getTag() != JSON_OBJECT) { + return nullptr; + } + for (auto it : value_) { + if (!strcmp(it->key, child_name)) { + return it; + } + } + return nullptr; +} + +const JsonNode *JsonGet::get(const char *child_name, JsonTag type) const { + const JsonNode *v = get(child_name); + if (v && type == v->value.getTag()) + return v; + return nullptr; +} + +const char *JsonGet::getStringOrDie(const char *child_name) const { + const JsonNode *val = get(child_name, JSON_STRING); + if (val) + return val->value.toString(); + FLOG("String '%s' missing from node", child_name); + return nullptr; +} + +const char *JsonGet::getString(const char *child_name, const char *default_value) const { + const JsonNode *val = get(child_name, JSON_STRING); + if (!val) + return default_value; + return val->value.toString(); +} + +bool JsonGet::getStringVector(std::vector *vec) const { + vec->clear(); + if (value_.getTag() == JSON_ARRAY) { + for (auto it : value_) { + if (it->value.getTag() == JSON_STRING) { + vec->push_back(it->value.toString()); + } + } + return true; + } else { + return false; + } +} + +double JsonGet::getFloat(const char *child_name) const { + return get(child_name, JSON_NUMBER)->value.toNumber(); +} + +double JsonGet::getFloat(const char *child_name, double default_value) const { + const JsonNode *val = get(child_name, JSON_NUMBER); + if (!val) + return default_value; + return val->value.toNumber(); +} + +int JsonGet::getInt(const char *child_name) const { + return (int)get(child_name, JSON_NUMBER)->value.toNumber(); +} + +int JsonGet::getInt(const char *child_name, int default_value) const { + const JsonNode *val = get(child_name, JSON_NUMBER); + if (!val) + return default_value; + return (int)val->value.toNumber(); +} + +bool JsonGet::getBool(const char *child_name) const { + return get(child_name)->value.getTag() == JSON_TRUE; +} + +bool JsonGet::getBool(const char *child_name, bool default_value) const { + const JsonNode *val = get(child_name); + if (val) { + JsonTag tag = val->value.getTag(); + if (tag == JSON_TRUE) + return true; + if (tag == JSON_FALSE) + return false; + } + return default_value; +} diff --git a/ext/native/json/json_reader.h b/ext/native/json/json_reader.h new file mode 100644 index 000000000000..b9e8de5e5398 --- /dev/null +++ b/ext/native/json/json_reader.h @@ -0,0 +1,85 @@ +#include +#include +#include "base/basictypes.h" +#include "base/logging.h" +#include "ext/gason/gason.h" + +struct JsonGet { + JsonGet(const JsonValue &value) : value_(value) { + } + + int numChildren() const; + const JsonNode *get(const char *child_name) const; + const JsonNode *get(const char *child_name, JsonTag type) const; + const JsonNode *getArray(const char *child_name) const { + return get(child_name, JSON_ARRAY); + } + const JsonGet getDict(const char *child_name) const { + return JsonGet(get(child_name, JSON_OBJECT)->value); + } + const char *getStringOrDie(const char *child_name) const; + const char *getString(const char *child_name, const char *default_value) const; + bool getStringVector(std::vector *vec) const; + double getFloat(const char *child_name) const; + double getFloat(const char *child_name, double default_value) const; + int getInt(const char *child_name) const; + int getInt(const char *child_name, int default_value) const; + bool getBool(const char *child_name) const; + bool getBool(const char *child_name, bool default_value) const; + + bool hasChild(const char *child_name, JsonTag child_type) const { + return get(child_name, child_type) != nullptr; + } + + operator bool() const { + return value_.getTag() != JSON_NULL; + } + + JsonValue value_; +}; + +// Easy-wrapper +class JsonReader { +public: + JsonReader(const std::string &filename); + JsonReader(const void *data, size_t size) { + buffer_ = (char *)malloc(size + 1); + memcpy(buffer_, data, size); + buffer_[size] = 0; + parse(); + } + JsonReader(const JsonNode *node) { + ok_ = true; + } + + ~JsonReader() { + if (buffer_) + free(buffer_); + } + + bool ok() const { return ok_; } + + JsonGet root() { return root_.getTag() == JSON_OBJECT ? JsonGet(root_) : JsonGet(JSON_NULL); } + const JsonValue rootArray() const { return root_.getTag() == JSON_ARRAY ? root_ : JSON_NULL; } + + const JsonValue rootValue() const { return root_; } + +private: + bool parse() { + char *error_pos; + int status = jsonParse(buffer_, &error_pos, &root_, alloc_); + if (status != JSON_OK) { + ELOG("Error at (%i): %s\n%s\n\n", (int)(error_pos - buffer_), jsonStrError(status), error_pos); + return false; + } + ok_ = true; + return true; + } + + char *buffer_ = nullptr; + JsonAllocator alloc_; + JsonValue root_; + bool ok_ = false; + + DISALLOW_COPY_AND_ASSIGN(JsonReader); +}; diff --git a/ext/native/json/json_writer.cpp b/ext/native/json/json_writer.cpp index 6d4c6905e187..3cc625e13d24 100644 --- a/ext/native/json/json_writer.cpp +++ b/ext/native/json/json_writer.cpp @@ -1,7 +1,7 @@ #include #include #include -#include "ext/vjson/json.h" +#include "json/json_reader.h" #include "json/json_writer.h" JsonWriter::JsonWriter(int flags) { @@ -234,33 +234,33 @@ void JsonWriter::writeEscapedString(const char *str) { } } -static void json_stringify_object(JsonWriter &writer, const json_value *value); -static void json_stringify_array(JsonWriter &writer, const json_value *value); +static void json_stringify_object(JsonWriter &writer, const JsonNode *node); +static void json_stringify_array(JsonWriter &writer, const JsonNode *node); -std::string json_stringify(const json_value *value) { +std::string json_stringify(const JsonNode *node) { JsonWriter writer; // Handle direct values too, not just objects. - switch (value->type) { + switch (node->value.getTag()) { case JSON_NULL: case JSON_STRING: - case JSON_INT: - case JSON_FLOAT: - case JSON_BOOL: + case JSON_NUMBER: + case JSON_TRUE: + case JSON_FALSE: writer.beginRaw(); // It's the same as a one entry array without brackets, so reuse. - json_stringify_array(writer, value); + json_stringify_array(writer, node); break; case JSON_OBJECT: writer.begin(); - for (const json_value *it = value->first_child; it; it = it->next_sibling) { + for (const JsonNode *it : node->value) { json_stringify_object(writer, it); } break; case JSON_ARRAY: writer.beginArray(); - for (const json_value *it = value->first_child; it; it = it->next_sibling) { + for (const JsonNode *it : node->value) { json_stringify_array(writer, it); } break; @@ -270,34 +270,34 @@ std::string json_stringify(const json_value *value) { return writer.str(); } -static void json_stringify_object(JsonWriter &writer, const json_value *value) { - switch (value->type) { +static void json_stringify_object(JsonWriter &writer, const JsonNode *node) { + switch (node->value.getTag()) { case JSON_NULL: - writer.writeRaw(value->name, "null"); + writer.writeRaw(node->key, "null"); break; case JSON_STRING: - writer.writeString(value->name, value->string_value); + writer.writeString(node->key, node->value.toString()); break; - case JSON_INT: - writer.writeInt(value->name, value->int_value); + case JSON_NUMBER: + writer.writeFloat(node->key, node->value.toNumber()); break; - case JSON_FLOAT: - writer.writeFloat(value->name, value->float_value); + case JSON_TRUE: + writer.writeBool(node->key, true); break; - case JSON_BOOL: - writer.writeBool(value->name, value->int_value != 0); + case JSON_FALSE: + writer.writeBool(node->key, false); break; case JSON_OBJECT: - writer.pushDict(value->name); - for (const json_value *it = value->first_child; it; it = it->next_sibling) { + writer.pushDict(node->key); + for (const JsonNode *it : node->value) { json_stringify_object(writer, it); } writer.pop(); break; case JSON_ARRAY: - writer.pushArray(value->name); - for (const json_value *it = value->first_child; it; it = it->next_sibling) { + writer.pushArray(node->key); + for (const JsonNode *it : node->value) { json_stringify_array(writer, it); } writer.pop(); @@ -305,34 +305,34 @@ static void json_stringify_object(JsonWriter &writer, const json_value *value) { } } -static void json_stringify_array(JsonWriter &writer, const json_value *value) { - switch (value->type) { +static void json_stringify_array(JsonWriter &writer, const JsonNode *node) { + switch (node->value.getTag()) { case JSON_NULL: writer.writeRaw("null"); break; case JSON_STRING: - writer.writeString(value->string_value); + writer.writeString(node->value.toString()); break; - case JSON_INT: - writer.writeInt(value->int_value); + case JSON_NUMBER: + writer.writeFloat(node->value.toNumber()); break; - case JSON_FLOAT: - writer.writeFloat(value->float_value); + case JSON_TRUE: + writer.writeBool(true); break; - case JSON_BOOL: - writer.writeBool(value->int_value != 0); + case JSON_FALSE: + writer.writeBool(false); break; case JSON_OBJECT: writer.pushDict(); - for (const json_value *it = value->first_child; it; it = it->next_sibling) { + for (const JsonNode *it : node->value) { json_stringify_object(writer, it); } writer.pop(); break; case JSON_ARRAY: writer.pushArray(); - for (const json_value *it = value->first_child; it; it = it->next_sibling) { + for (const JsonNode *it : node->value) { json_stringify_array(writer, it); } writer.pop(); diff --git a/ext/native/json/json_writer.h b/ext/native/json/json_writer.h index b2f4f30742bb..06afb66bc7a0 100644 --- a/ext/native/json/json_writer.h +++ b/ext/native/json/json_writer.h @@ -87,5 +87,5 @@ class JsonWriter { bool pretty_; }; -struct json_value; -std::string json_stringify(const json_value *json); +struct JsonNode; +std::string json_stringify(const JsonNode *json); diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index 8d43e4329d75..556c328d4fd9 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -206,6 +206,7 @@ + @@ -220,8 +221,6 @@ - - @@ -238,6 +237,7 @@ + @@ -340,6 +340,7 @@ Default Default + @@ -683,8 +684,6 @@ - - @@ -699,6 +698,7 @@ + diff --git a/ext/native/native.vcxproj.filters b/ext/native/native.vcxproj.filters index aecf22367478..999519c3bd0b 100644 --- a/ext/native/native.vcxproj.filters +++ b/ext/native/native.vcxproj.filters @@ -242,12 +242,6 @@ ext\jpge - - ext\vjson - - - ext\vjson - gfx @@ -341,6 +335,12 @@ thin3d + + ext\gason + + + json + @@ -712,12 +712,6 @@ ext\jpge - - ext\vjson - - - ext\vjson - gfx @@ -814,6 +808,12 @@ thin3d + + ext\gason + + + json + @@ -876,14 +876,14 @@ {3721adbc-1a4a-4017-bc1d-893c7e86bc22} - - {c6910d82-73d3-4d97-ac9c-bcc03265b1bc} - {5ce64c0e-98e4-4411-86cc-aacaf2f60b21} {06c6305a-a646-485b-85b9-645a24dd6553} + + {5b740c6f-8dbc-4529-9114-6564b37b3548} + \ No newline at end of file diff --git a/libretro/Makefile.common b/libretro/Makefile.common index c732d9a1e45c..d905f0a57afb 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -125,8 +125,7 @@ SOURCES_CXX += \ SOURCES_CXX += $(EXTDIR)/xbrz/xbrz.cpp SOURCES_CXX += \ - $(NATIVEDIR)/ext/vjson/json.cpp \ - $(NATIVEDIR)/ext/vjson/block_allocator.cpp + $(NATIVEDIR)/ext/gason/gason.cpp SOURCES_CXX += $(NATIVEDIR)/ext/cityhash/city.cpp @@ -203,10 +202,11 @@ SOURCES_CXX += \ $(EXTDIR)/native/base/buffer.cpp \ $(EXTDIR)/native/base/colorutil.cpp \ $(EXTDIR)/native/base/display.cpp \ - $(EXTDIR)/native/base/logging.cpp \ + $(EXTDIR)/native/base/logging.cpp \ $(EXTDIR)/native/base/stringutil.cpp \ $(EXTDIR)/native/base/timeutil.cpp \ $(EXTDIR)/native/data/compression.cpp \ + $(EXTDIR)/native/json/json_reader.cpp \ $(EXTDIR)/glslang/OGLCompilersDLL/InitializeDll.cpp \ $(EXTDIR)/glslang/glslang/GenericCodeGen/CodeGen.cpp \ $(EXTDIR)/glslang/glslang/GenericCodeGen/Link.cpp \