json: Switch to gason instead of vjson.

From the same author.  Most importantly, reads numbers as doubles rather
than as signed ints and floats.  This allows us to actually read 32 bit
unsigned int parameters.

Moved all the native customization to a separate json_reader.cpp.
This commit is contained in:
Unknown W. Brackets 2018-04-15 11:24:10 -07:00
parent b56249eec1
commit 082ddf5120
24 changed files with 799 additions and 1092 deletions

View File

@ -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()

View File

@ -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"
@ -1181,13 +1181,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);

View File

@ -21,9 +21,9 @@
#include <condition_variable>
#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<std::string> 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.

View File

@ -18,7 +18,7 @@
#include <functional>
#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);

View File

@ -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 @@ private:
std::vector<StoreEntry> 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<http::Download> listing_;
std::shared_ptr<http::Download> image_;

View File

@ -328,8 +328,6 @@
<ClInclude Include="..\..\ext\native\ext\libzip\config.h" />
<ClInclude Include="..\..\ext\native\ext\libzip\zip.h" />
<ClInclude Include="..\..\ext\native\ext\libzip\zipint.h" />
<ClInclude Include="..\..\ext\native\ext\vjson\block_allocator.h" />
<ClInclude Include="..\..\ext\native\ext\vjson\json.h" />
<ClInclude Include="..\..\ext\native\file\chunk_file.h" />
<ClInclude Include="..\..\ext\native\file\fd_util.h" />
<ClInclude Include="..\..\ext\native\file\file_util.h" />
@ -338,6 +336,8 @@
<ClInclude Include="..\..\ext\native\file\path.h" />
<ClInclude Include="..\..\ext\native\file\vfs.h" />
<ClInclude Include="..\..\ext\native\file\zip_read.h" />
<ClInclude Include="..\..\ext\native\json\json_reader.h" />
<ClInclude Include="..\..\ext\native\json\json_writer.h" />
<ClInclude Include="..\..\ext\native\gfx\texture_atlas.h" />
<ClInclude Include="..\..\ext\native\gfx_es2\draw_buffer.h" />
<ClInclude Include="..\..\ext\native\gfx_es2\draw_text.h" />
@ -1160,8 +1160,6 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\..\ext\native\ext\vjson\block_allocator.cpp" />
<ClCompile Include="..\..\ext\native\ext\vjson\json.cpp" />
<ClCompile Include="..\..\ext\native\file\chunk_file.cpp" />
<ClCompile Include="..\..\ext\native\file\fd_util.cpp" />
<ClCompile Include="..\..\ext\native\file\file_util.cpp" />
@ -1169,6 +1167,8 @@
<ClCompile Include="..\..\ext\native\file\ini_file.cpp" />
<ClCompile Include="..\..\ext\native\file\path.cpp" />
<ClCompile Include="..\..\ext\native\file\zip_read.cpp" />
<ClCompile Include="..\..\ext\native\json\json_reader.cpp" />
<ClCompile Include="..\..\ext\native\json\json_writer.cpp" />
<ClCompile Include="..\..\ext\native\gfx\texture_atlas.cpp" />
<ClCompile Include="..\..\ext\native\gfx_es2\draw_buffer.cpp" />
<ClCompile Include="..\..\ext\native\gfx_es2\draw_text.cpp" />

View File

@ -37,9 +37,6 @@
<Filter Include="ext">
<UniqueIdentifier>{2be24387-0b6a-4253-97fa-b8b6f75a8a4c}</UniqueIdentifier>
</Filter>
<Filter Include="ext\vjson">
<UniqueIdentifier>{7fdd3320-a8e0-42ed-b08b-2d86ba2ff414}</UniqueIdentifier>
</Filter>
<Filter Include="ext\libzip">
<UniqueIdentifier>{1a486fc4-bac0-4b33-9139-262272690c74}</UniqueIdentifier>
</Filter>
@ -214,12 +211,6 @@
<ClCompile Include="..\..\ext\native\i18n\i18n.cpp">
<Filter>i18n</Filter>
</ClCompile>
<ClCompile Include="..\..\ext\native\ext\vjson\block_allocator.cpp">
<Filter>ext\vjson</Filter>
</ClCompile>
<ClCompile Include="..\..\ext\native\ext\vjson\json.cpp">
<Filter>ext\vjson</Filter>
</ClCompile>
<ClCompile Include="..\..\ext\native\ext\libzip\mkstemp.c">
<Filter>ext\libzip</Filter>
</ClCompile>
@ -656,12 +647,6 @@
<ClInclude Include="..\..\ext\native\i18n\i18n.h">
<Filter>i18n</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\native\ext\vjson\block_allocator.h">
<Filter>ext\vjson</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\native\ext\vjson\json.h">
<Filter>ext\vjson</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\native\ext\libzip\config.h">
<Filter>ext\libzip</Filter>
</ClInclude>

View File

@ -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 \

View File

@ -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.

View File

@ -0,0 +1,334 @@
#include "gason.h"
#include <stdlib.h>
#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;
}

View File

@ -0,0 +1,135 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
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);

View File

@ -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)

View File

@ -1,52 +0,0 @@
#include <memory.h>
#include <algorithm>
#include <stdlib.h>
#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<block *>(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);
}

View File

@ -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

View File

@ -1,643 +0,0 @@
#include <memory.h>
#include <stdio.h>
#include <string.h>
#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<std::string> *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());
}
}
}

View File

@ -1,113 +0,0 @@
#pragma once
#include <string.h>
#include <string>
#include <vector>
#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<std::string> *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);
};

View File

@ -1,118 +0,0 @@
#include <vector>
#include <stdio.h>
#include "json.h"
void populate_sources(const char *filter, std::vector<std::vector<char> > &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<char> 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<std::vector<char> > 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;
}

View File

@ -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<std::string> *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;
}

View File

@ -0,0 +1,85 @@
#include <string>
#include <vector>
#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<std::string> *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);
};

View File

@ -1,7 +1,7 @@
#include <iomanip>
#include <cmath>
#include <cstring>
#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();

View File

@ -87,5 +87,5 @@ private:
bool pretty_;
};
struct json_value;
std::string json_stringify(const json_value *json);
struct JsonNode;
std::string json_stringify(const JsonNode *json);

View File

@ -206,6 +206,7 @@
<ClInclude Include="data\listable.h" />
<ClInclude Include="ext\cityhash\city.h" />
<ClInclude Include="ext\cityhash\citycrc.h" />
<ClInclude Include="ext\gason\gason.h" />
<ClInclude Include="ext\jpge\jpgd.h" />
<ClInclude Include="ext\jpge\jpge.h" />
<ClInclude Include="ext\libpng17\png.h" />
@ -220,8 +221,6 @@
<ClInclude Include="ext\libzip\zipint.h" />
<ClInclude Include="ext\rg_etc1\rg_etc1.h" />
<ClInclude Include="ext\sha1\sha1.h" />
<ClInclude Include="ext\vjson\block_allocator.h" />
<ClInclude Include="ext\vjson\json.h" />
<ClInclude Include="file\chunk_file.h" />
<ClInclude Include="file\fd_util.h" />
<ClInclude Include="file\file_util.h" />
@ -238,6 +237,7 @@
<ClInclude Include="gfx_es2\draw_text_android.h" />
<ClInclude Include="gfx_es2\draw_text_qt.h" />
<ClInclude Include="gfx_es2\draw_text_win.h" />
<ClInclude Include="json\json_reader.h" />
<ClInclude Include="thin3d\d3d11_loader.h" />
<ClInclude Include="thin3d\DataFormat.h" />
<ClInclude Include="thin3d\DataFormatGL.h" />
@ -340,6 +340,7 @@
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="ext\gason\gason.cpp" />
<ClCompile Include="ext\jpge\jpgd.cpp" />
<ClCompile Include="ext\jpge\jpge.cpp" />
<ClCompile Include="ext\libpng17\png.c" />
@ -683,8 +684,6 @@
</ClCompile>
<ClCompile Include="ext\rg_etc1\rg_etc1.cpp" />
<ClCompile Include="ext\sha1\sha1.cpp" />
<ClCompile Include="ext\vjson\block_allocator.cpp" />
<ClCompile Include="ext\vjson\json.cpp" />
<ClCompile Include="file\chunk_file.cpp" />
<ClCompile Include="file\fd_util.cpp" />
<ClCompile Include="file\file_util.cpp" />
@ -699,6 +698,7 @@
<ClCompile Include="gfx_es2\draw_text_android.cpp" />
<ClCompile Include="gfx_es2\draw_text_qt.cpp" />
<ClCompile Include="gfx_es2\draw_text_win.cpp" />
<ClCompile Include="json\json_reader.cpp" />
<ClCompile Include="math\dataconv.cpp" />
<ClCompile Include="thin3d\d3d11_loader.cpp" />
<ClCompile Include="thin3d\DataFormatGL.cpp" />

View File

@ -242,12 +242,6 @@
<ClInclude Include="ext\jpge\jpge.h">
<Filter>ext\jpge</Filter>
</ClInclude>
<ClInclude Include="ext\vjson\block_allocator.h">
<Filter>ext\vjson</Filter>
</ClInclude>
<ClInclude Include="ext\vjson\json.h">
<Filter>ext\vjson</Filter>
</ClInclude>
<ClInclude Include="gfx_es2\gl3stub.h">
<Filter>gfx</Filter>
</ClInclude>
@ -341,6 +335,12 @@
<ClInclude Include="thin3d\thin3d_create.h">
<Filter>thin3d</Filter>
</ClInclude>
<ClInclude Include="ext\gason\gason.h">
<Filter>ext\gason</Filter>
</ClInclude>
<ClInclude Include="json\json_reader.h">
<Filter>json</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="gfx\gl_debug_log.cpp">
@ -712,12 +712,6 @@
<ClCompile Include="ext\jpge\jpge.cpp">
<Filter>ext\jpge</Filter>
</ClCompile>
<ClCompile Include="ext\vjson\block_allocator.cpp">
<Filter>ext\vjson</Filter>
</ClCompile>
<ClCompile Include="ext\vjson\json.cpp">
<Filter>ext\vjson</Filter>
</ClCompile>
<ClCompile Include="gfx_es2\gl3stub.c">
<Filter>gfx</Filter>
</ClCompile>
@ -814,6 +808,12 @@
<ClCompile Include="thin3d\DataFormatGL.cpp">
<Filter>thin3d</Filter>
</ClCompile>
<ClCompile Include="ext\gason\gason.cpp">
<Filter>ext\gason</Filter>
</ClCompile>
<ClCompile Include="json\json_reader.cpp">
<Filter>json</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="gfx">
@ -876,14 +876,14 @@
<Filter Include="ext\jpge">
<UniqueIdentifier>{3721adbc-1a4a-4017-bc1d-893c7e86bc22}</UniqueIdentifier>
</Filter>
<Filter Include="ext\vjson">
<UniqueIdentifier>{c6910d82-73d3-4d97-ac9c-bcc03265b1bc}</UniqueIdentifier>
</Filter>
<Filter Include="math\fast">
<UniqueIdentifier>{5ce64c0e-98e4-4411-86cc-aacaf2f60b21}</UniqueIdentifier>
</Filter>
<Filter Include="thin3d">
<UniqueIdentifier>{06c6305a-a646-485b-85b9-645a24dd6553}</UniqueIdentifier>
</Filter>
<Filter Include="ext\gason">
<UniqueIdentifier>{5b740c6f-8dbc-4529-9114-6564b37b3548}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@ -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 \