diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a1a1d00..c65c4945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v7.0.0 + +* Removed **rjson** + # v6.5.0 * Added a schema for errors returned by the server diff --git a/README.md b/README.md index 4685e7a1..3453251e 100644 --- a/README.md +++ b/README.md @@ -465,54 +465,6 @@ void rc_format_value(char* buffer, int size, unsigned value, int format); `buffer` receives `value` formatted according to `format`. No more than `size` characters will be written to `buffer`. 32 characters are enough to hold any valid value with any format. -# **rjson** - -**rjson** provides parsing of RetroAchievements JSON files, and provides the results in strongly typed C structures instead of returning a generic dictionary and forcing the caller to check for values and extracting them. - -Similarly to **rcheevos**, **rjson** does *not* allocate any memory. The caller must use the functions that compute the size needed to parse a given JSON, allocate the necessary memory, and call another function that does the parsing. - -## API - -### Return values - -The functions that compute the memory needed for a given JSON return a positive value, which is the number of bytes needed. Errors are negative values taken from the following enumeration: - -```c -enum { - RC_JSON_OK = 0, - RC_JSON_OBJECT_EXPECTED = -1, - RC_JSON_UNKOWN_RECORD = -2, - RC_JSON_EOF_EXPECTED = -3, - RC_JSON_MISSING_KEY = -4, - RC_JSON_UNTERMINATED_KEY = -5, - RC_JSON_MISSING_VALUE = -6, - RC_JSON_UNTERMINATED_OBJECT = -7, - RC_JSON_INVALID_VALUE = -8, - RC_JSON_UNTERMINATED_STRING = -9, - RC_JSON_UNTERMINATED_ARRAY = -10, - RC_JSON_INVALID_ESCAPE = -11 -}; -``` - -### Supported schemas - -**rjson** supports the following JSON schemas. Please see `rjson.h` for the definition of the C structures: - -* `rc_json_gameid_t`: The game identifier returned by the server, given its hash. -* `rc_json_login_t`: The login token for the user, given their user name and password. -* `rc_json_patch_t`: The information about a game, given its identifier. It includes arrays with the achievements and leaderboards for the game. -* `rc_json_unlocks_t`: The list of achievements already awarded for the player, given the game identifier. Used to avoid the emulator awarding achievements more than once. -* `rc_json_error_t`: Error messages returned by the server. - -For each schema there are two functions, for example: - -```c -int rc_json_get_patch_size(const char* json); -const rc_json_patch_t* rc_json_parse_patch(void* buffer, const char* json); -``` - -`rc_json_get_patch_size` returns the number of bytes needed to parse the given JSON as a `rc_json_patch_t`. `rc_json_parse_patch` parses the given JSON into the given `buffer`, returning a pointer that is used to access the decoded information. - # **rurl** **rurl** builds URLs to access many RetroAchievements web services. Its purpose it to just to free the developer from having to URL-encode parameters and build correct URL that are valid for the server. diff --git a/include/rjson.h b/include/rjson.h deleted file mode 100644 index f13f0ef3..00000000 --- a/include/rjson.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef RJSON_H -#define RJSON_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - RC_JSON_OK = 0, - RC_JSON_OBJECT_EXPECTED = -1, - RC_JSON_UNKOWN_RECORD = -2, - RC_JSON_EOF_EXPECTED = -3, - RC_JSON_MISSING_KEY = -4, - RC_JSON_UNTERMINATED_KEY = -5, - RC_JSON_MISSING_VALUE = -6, - RC_JSON_UNTERMINATED_OBJECT = -7, - RC_JSON_INVALID_VALUE = -8, - RC_JSON_UNTERMINATED_STRING = -9, - RC_JSON_UNTERMINATED_ARRAY = -10, - RC_JSON_INVALID_ESCAPE = -11 -}; - -typedef struct { - unsigned int gameid; - char success; -} -rc_json_gameid_t; - -int rc_json_get_gameid_size(const char* json); -const rc_json_gameid_t* rc_json_parse_gameid(void* buffer, const char* json); - -typedef struct { - const char* token; - const char* user; - unsigned int score; - unsigned int messages; - char success; -} -rc_json_login_t; - -int rc_json_get_login_size(const char* json); -const rc_json_login_t* rc_json_parse_login(void* buffer, const char* json); - -typedef struct { - unsigned long long created; - unsigned long long modified; - const char* author; - const char* badge; - const char* description; - const char* memaddr; - const char* title; - unsigned int flags; - unsigned int points; - unsigned int id; -} -rc_json_cheevo_t; - -int rc_json_get_cheevo_size(const char* json); -const rc_json_cheevo_t* rc_json_parse_cheevo(void* buffer, const char* json); - -typedef struct { - const char* description; - const char* title; - const char* format; - const char* mem; - unsigned int id; -} -rc_json_lboard_t; - -int rc_json_get_lboard_size(const char* json); -const rc_json_lboard_t* rc_json_parse_lboard(void* buffer, const char* json); - -typedef struct { - const rc_json_lboard_t* lboards; int lboards_count; - const char* genre; - const char* developer; - const char* publisher; - const char* released; - const char** presence; - const char* console; - const rc_json_cheevo_t* cheevos; int cheevos_count; - const char* image_boxart; - const char* image_title; - const char* image_icon; - const char* title; - const char* image_ingame; - unsigned int consoleid; - unsigned int id; - unsigned int flags; - unsigned int topicid; - char is_final; -} -rc_json_patchdata_t; - -int rc_json_get_patchdata_size(const char* json); -const rc_json_patchdata_t* rc_json_parse_patchdata(void* buffer, const char* json); - -typedef struct { - rc_json_patchdata_t patchdata; - char success; -} -rc_json_patch_t; - -int rc_json_get_patch_size(const char* json); -const rc_json_patch_t* rc_json_parse_patch(void* buffer, const char* json); - -typedef struct { - const unsigned int* ids; int ids_count; - unsigned int gameid; - char success; - char hardcore; -} -rc_json_unlocks_t; - -int rc_json_get_unlocks_size(const char* json); -const rc_json_unlocks_t* rc_json_parse_unlocks(void* buffer, const char* json); - -typedef struct { - const char* error; - char success; -} -rc_json_error_t; - -int rc_json_get_error_size(const char* json); -const rc_json_error_t* rc_json_parse_error(void* buffer, const char* json); - -#ifdef __cplusplus -} -#endif - -#endif /* RJSON_H */ diff --git a/src/rjson/dejson.c b/src/rjson/dejson.c deleted file mode 100644 index e1b628f2..00000000 --- a/src/rjson/dejson.c +++ /dev/null @@ -1,750 +0,0 @@ -#include "rjson.h" -#include "dejson.h" - -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - const uint8_t* json; - uintptr_t buffer; - int counting; - jmp_buf rollback; -} -rc_json_state_t; - -static void* rc_json_alloc(rc_json_state_t* state, size_t size, size_t alignment) { - state->buffer = (state->buffer + alignment - 1) & ~(alignment - 1); - void* ptr = (void*)state->buffer; - state->buffer += size; - return ptr; -} - -static void rc_json_skip_spaces(rc_json_state_t* state) { - if (isspace(*state->json)) { - do { - state->json++; - } - while (isspace(*state->json)); - } -} - -static size_t rc_json_skip_string(rc_json_state_t*); -static void rc_json_skip_value(rc_json_state_t*); - -static void rc_json_skip_object(rc_json_state_t* state) { - state->json++; - rc_json_skip_spaces(state); - - while (*state->json != '}') { - rc_json_skip_string(state); - rc_json_skip_spaces(state); - - if (*state->json != ':') { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - state->json++; - rc_json_skip_spaces(state); - rc_json_skip_value(state); - rc_json_skip_spaces(state); - - if (*state->json != ',') { - break; - } - - state->json++; - rc_json_skip_spaces(state); - } - - if (*state->json != '}') { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - state->json++; -} - -static size_t rc_json_skip_array(rc_json_state_t* state) { - size_t count = 0; - state->json++; - rc_json_skip_spaces(state); - - while (*state->json != ']') { - rc_json_skip_value(state); - rc_json_skip_spaces(state); - - count++; - - if (*state->json != ',') { - break; - } - - state->json++; - rc_json_skip_spaces(state); - } - - if (*state->json != ']') { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - state->json++; - return count; -} - -static void rc_json_skip_number(rc_json_state_t* state) { - errno = 0; - - char* end; - double result = strtod((const char*)state->json, &end); - - if ((result == 0.0 && end == (const char*)state->json) || errno == ERANGE) { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - state->json = (uint8_t*)end; -} - -static void rc_json_skip_boolean(rc_json_state_t* state) { - const uint8_t* json = state->json; - - if (json[0] == 't' && json[1] == 'r' && json[2] == 'u' && json[3] == 'e' && !isalpha(json[4])) { - state->json += 4; - } - else if (json[0] == 'f' && json[1] == 'a' && json[2] == 'l' && json[3] == 's' && json[4] == 'e' && !isalpha(json[5])) { - state->json += 5; - } - else { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } -} - -static size_t rc_json_skip_string(rc_json_state_t* state) { - const uint8_t* aux = state->json + 1; - size_t length = 0; - - if (*aux !='"') { - do { - length++; - - if (*aux++ == '\\') { - char digits[5]; - uint32_t utf32; - - switch (*aux++) { - case '"': - case '\\': - case '/': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - break; - - case 'u': - if (!isxdigit(aux[0] || !isxdigit(aux[1]) || !isxdigit(aux[2]) || !isxdigit(aux[3]))) { - longjmp(state->rollback, RC_JSON_INVALID_ESCAPE); - } - - digits[0] = aux[0]; - digits[1] = aux[1]; - digits[2] = aux[2]; - digits[3] = aux[3]; - digits[4] = 0; - aux += 4; - - utf32 = strtoul(digits, NULL, 16); - - if (utf32 < 0x80U) { - length += 0; - } - else if (utf32 < 0x800U) { - length += 1; - } - else if (utf32 < 0x10000U) { - length += 2; - } - else if (utf32 < 0x200000U) { - length += 3; - } - else { - longjmp(state->rollback, RC_JSON_INVALID_ESCAPE); - } - - break; - - default: - longjmp(state->rollback, RC_JSON_INVALID_ESCAPE); - } - } - } - while (*aux != '"'); - } - - state->json = aux + 1; - return length + 1; -} - -static void rc_json_skip_null(rc_json_state_t* state) { - const uint8_t* json = state->json; - - if (json[0] == 'n' && json[1] == 'u' && json[2] == 'l' && json[3] == 'l' && !isalpha(json[4])) { - state->json += 4; - } - else { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } -} - -static void rc_json_skip_value(rc_json_state_t* state) { - switch (*state->json) { - case '{': - rc_json_skip_object(state); - break; - - case '[': - rc_json_skip_array(state); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - rc_json_skip_number(state); - break; - - case 't': - case 'f': - rc_json_skip_boolean(state); - break; - - case '"': - rc_json_skip_string(state); - break; - - case 'n': - rc_json_skip_null(state); - break; - - default: - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - rc_json_skip_spaces(state); -} - -static int64_t rc_json_get_int64(rc_json_state_t* state, int64_t min, int64_t max) { - errno = 0; - - char* end; - long long result = strtoll((const char*)state->json, &end, 10); - - if ((result == 0 && end == (const char*)state->json) || errno == ERANGE || result < min || result > max) { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - state->json = (uint8_t*)end; - return result; -} - -static uint64_t rc_json_get_uint64(rc_json_state_t* state, uint64_t max) { - errno = 0; - - char* end; - unsigned long long result = strtoull((char*)state->json, &end, 10); - - if ((result == 0 && end == (const char*)state->json) || errno == ERANGE || result > max) { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - state->json = (uint8_t*)end; - return result; -} - -static double rc_json_get_double(rc_json_state_t* state, double min, double max) { - errno = 0; - - char* end; - double result = strtod((const char*)state->json, &end); - - if ((result == 0.0 && end == (const char*)state->json) || errno == ERANGE || result < min || result > max) { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - state->json = (uint8_t*)end; - return result; -} - -static void rc_json_parse_char(rc_json_state_t* state, void* data) { - *(char*)data = rc_json_get_int64(state, CHAR_MIN, CHAR_MAX); -} - -static void rc_json_parse_uchar(rc_json_state_t* state, void* data) { - *(unsigned char*)data = rc_json_get_uint64(state, UCHAR_MAX); -} - -static void rc_json_parse_short(rc_json_state_t* state, void* data) { - *(short*)data = rc_json_get_int64(state, SHRT_MIN, SHRT_MAX); -} - -static void rc_json_parse_ushort(rc_json_state_t* state, void* data) { - *(unsigned short*)data = rc_json_get_uint64(state, USHRT_MAX); -} - -static void rc_json_parse_int(rc_json_state_t* state, void* data) { - *(int*)data = rc_json_get_int64(state, INT_MIN, INT_MAX); -} - -static void rc_json_parse_uint(rc_json_state_t* state, void* data) { - *(unsigned int*)data = rc_json_get_uint64(state, UINT_MAX); -} - -static void rc_json_parse_long(rc_json_state_t* state, void* data) { - *(long*)data = rc_json_get_int64(state, LONG_MIN, LONG_MAX); -} - -static void rc_json_parse_ulong(rc_json_state_t* state, void* data) { - *(unsigned long*)data = rc_json_get_uint64(state, ULONG_MAX); -} - -static void rc_json_parse_longlong(rc_json_state_t* state, void* data) { - *(unsigned long*)data = rc_json_get_int64(state, LLONG_MIN, LLONG_MAX); -} - -static void rc_json_parse_ulonglong(rc_json_state_t* state, void* data) { - *(unsigned long*)data = rc_json_get_uint64(state, ULLONG_MAX); -} - -static void rc_json_parse_int8(rc_json_state_t* state, void* data) { - *(int8_t*)data = rc_json_get_int64(state, INT8_MIN, INT8_MAX); -} - -static void rc_json_parse_int16(rc_json_state_t* state, void* data) { - *(int16_t*)data = rc_json_get_int64(state, INT16_MIN, INT16_MAX); -} - -static void rc_json_parse_int32(rc_json_state_t* state, void* data) { - *(int32_t*)data = rc_json_get_int64(state, INT32_MIN, INT32_MAX); -} - -static void rc_json_parse_int64(rc_json_state_t* state, void* data) { - *(int64_t*)data = rc_json_get_int64(state, INT64_MIN, INT64_MAX); -} - -static void rc_json_parse_uint8(rc_json_state_t* state, void* data) { - *(uint8_t*)data = rc_json_get_uint64(state, UINT8_MAX); -} - -static void rc_json_parse_uint16(rc_json_state_t* state, void* data) { - *(uint16_t*)data = rc_json_get_uint64(state, UINT16_MAX); -} - -static void rc_json_parse_uint32(rc_json_state_t* state, void* data) { - *(uint32_t*)data = rc_json_get_uint64(state, UINT32_MAX); -} - -static void rc_json_parse_uint64(rc_json_state_t* state, void* data) { - *(uint64_t*)data = rc_json_get_uint64(state, UINT64_MAX); -} - -static void rc_json_parse_float(rc_json_state_t* state, void* data) { - *(float*)data = rc_json_get_double(state, FLT_MIN, FLT_MAX); -} - -static void rc_json_parse_double(rc_json_state_t* state, void* data) { - *(double*)data = rc_json_get_double(state, DBL_MIN, DBL_MAX); -} - -static void rc_json_parse_boolean(rc_json_state_t* state, void* data) { - const uint8_t* json = state->json; - - if (json[0] == 't' && json[1] == 'r' && json[2] == 'u' && json[3] == 'e' && !isalpha(json[4])) { - *(char*)data = 1; - state->json += 4; - } - else if (json[0] == 'f' && json[1] == 'a' && json[2] == 'l' && json[3] == 's' && json[4] == 'e' && !isalpha(json[5])) { - *(char*)data = 0; - state->json += 5; - } - else { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } -} - -static void rc_json_parse_string(rc_json_state_t* state, void* data) { - const uint8_t* aux = state->json; - size_t length = rc_json_skip_string(state); - uint8_t* str = (uint8_t*)rc_json_alloc(state, length + 1, RC_JSON_ALIGNOF(char)); - - if (state->counting) { - return; - } - - if (*aux++ != '"') { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - *(char**)data = (char*)str; - - if (*aux !='"') { - do { - if (*aux == '\\') { - char digits[5]; - uint32_t utf32; - - aux++; - - switch (*aux++) { - case '"': *str++ = '"'; break; - case '\\': *str++ = '\\'; break; - case '/': *str++ = '/'; break; - case 'b': *str++ = '\b'; break; - case 'f': *str++ = '\f'; break; - case 'n': *str++ = '\n'; break; - case 'r': *str++ = '\r'; break; - case 't': *str++ = '\t'; break; - - case 'u': - digits[0] = aux[0]; - digits[1] = aux[1]; - digits[2] = aux[2]; - digits[3] = aux[3]; - digits[4] = 0; - aux += 4; - - utf32 = strtoul(digits, NULL, 16); - - if (utf32 < 0x80) { - *str++ = utf32; - } - else if (utf32 < 0x800) { - str[0] = 0xc0 | (utf32 >> 6); - str[1] = 0x80 | (utf32 & 0x3f); - str += 2; - } - else if (utf32 < 0x10000) { - str[0] = 0xe0 | (utf32 >> 12); - str[1] = 0x80 | ((utf32 >> 6) & 0x3f); - str[2] = 0x80 | (utf32 & 0x3f); - str += 3; - } - else { - str[0] = 0xf0 | (utf32 >> 18); - str[1] = 0x80 | ((utf32 >> 12) & 0x3f); - str[2] = 0x80 | ((utf32 >> 6) & 0x3f); - str[3] = 0x80 | (utf32 & 0x3f); - str += 4; - } - - break; - - default: - longjmp(state->rollback, RC_JSON_INVALID_ESCAPE); - } - } - else { - *str++ = *aux++; - } - } - while (*aux != '"'); - } - - *str = 0; -} - -typedef void (*rc_json_parser_t)(rc_json_state_t*, void*); - -static const rc_json_parser_t rc_json_parsers[] = { - rc_json_parse_char, rc_json_parse_uchar, rc_json_parse_short, rc_json_parse_ushort, - rc_json_parse_int, rc_json_parse_uint, rc_json_parse_long, rc_json_parse_ulong, - rc_json_parse_longlong, rc_json_parse_ulonglong, - rc_json_parse_int8, rc_json_parse_int16, rc_json_parse_int32, rc_json_parse_int64, - rc_json_parse_uint8, rc_json_parse_uint16, rc_json_parse_uint32, rc_json_parse_uint64, - rc_json_parse_float, rc_json_parse_double, rc_json_parse_boolean, rc_json_parse_string -}; - -static void rc_json_parse_value(rc_json_state_t*, void*, const rc_json_field_meta_t*); -static void rc_json_parse_object(rc_json_state_t*, void*, const rc_json_struct_meta_t*); - -static void rc_json_parse_array(rc_json_state_t* state, void* value, size_t element_size, size_t element_alignment, const rc_json_field_meta_t* field) { - if (*state->json != '[') { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - const uint8_t* save = state->json; - size_t count = rc_json_skip_array(state); - state->json = save + 1; - - uint8_t* elements = (uint8_t*)rc_json_alloc(state, element_size * count, element_alignment); - - if (!state->counting) { - struct { - void* elements; - int count; - } - *array = value; - - array->elements = elements; - array->count = count; - } - - rc_json_skip_spaces(state); - - rc_json_field_meta_t field_scalar = *field; - field_scalar.flags &= ~RC_JSON_FLAG_ARRAY; - - while (*state->json != ']') { - rc_json_parse_value(state, (void*)elements, &field_scalar); - rc_json_skip_spaces(state); - - elements += element_size; - - if (*state->json != ',') { - break; - } - - state->json++; - rc_json_skip_spaces(state); - } - - if (*state->json != ']') { - longjmp(state->rollback, RC_JSON_UNTERMINATED_ARRAY); - } - - state->json++; -} - -const rc_json_struct_meta_t* rc_json_resolve_struct(uint32_t hash); - -static void rc_json_parse_value(rc_json_state_t* state, void* value, const rc_json_field_meta_t* field) { -#define RC_JSON_TYPE_INFO(t) sizeof(t), RC_JSON_ALIGNOF(t) - - static const size_t rc_json_type_info[] = { - RC_JSON_TYPE_INFO(char), RC_JSON_TYPE_INFO(unsigned char), RC_JSON_TYPE_INFO(short), RC_JSON_TYPE_INFO(unsigned short), - RC_JSON_TYPE_INFO(int), RC_JSON_TYPE_INFO(unsigned int), RC_JSON_TYPE_INFO(long), RC_JSON_TYPE_INFO(unsigned long), - RC_JSON_TYPE_INFO(long long), RC_JSON_TYPE_INFO(unsigned long long), - RC_JSON_TYPE_INFO(int8_t), RC_JSON_TYPE_INFO(int16_t), RC_JSON_TYPE_INFO(int32_t), RC_JSON_TYPE_INFO(int64_t), - RC_JSON_TYPE_INFO(uint8_t), RC_JSON_TYPE_INFO(uint16_t), RC_JSON_TYPE_INFO(uint32_t), RC_JSON_TYPE_INFO(uint64_t), - RC_JSON_TYPE_INFO(float), RC_JSON_TYPE_INFO(double), RC_JSON_TYPE_INFO(char), RC_JSON_TYPE_INFO(const char*) - }; - - const rc_json_struct_meta_t* meta = NULL; - - if ((field->flags & (RC_JSON_FLAG_ARRAY | RC_JSON_FLAG_POINTER)) == 0) { - if (field->type != RC_JSON_TYPE_RECORD) { - char dummy[64]; - - if (state->counting) { - value = (void*)dummy; - } - - rc_json_parsers[field->type](state, value); - } - else { - meta = rc_json_resolve_struct(field->type_hash); - - if (meta == NULL) { - longjmp(state->rollback, RC_JSON_UNKOWN_RECORD); - } - - rc_json_parse_object(state, value, meta); - } - - return; - } - - size_t size, alignment; - - if (field->type != RC_JSON_TYPE_RECORD) { - unsigned ndx = field->type * 2; - size = rc_json_type_info[ndx]; - alignment = rc_json_type_info[ndx + 1]; - } - else { /* field->type == RC_JSON_TYPE_RECORD */ - meta = rc_json_resolve_struct(field->type_hash); - - if (meta == NULL) { - longjmp(state->rollback, RC_JSON_UNKOWN_RECORD); - } - - size = meta->size; - alignment = meta->alignment; - } - - if ((field->flags & RC_JSON_FLAG_ARRAY) != 0) { - rc_json_parse_array(state, value, size, alignment, field); - return; - } - - const uint8_t* json = state->json; - - if (json[0] == 'n' && json[1] == 'u' && json[2] == 'l' && json[3] == 'l' && !isalpha(json[4])) { - if (!state->counting) { - *(void**)value = NULL; - } - - state->json += 4; - return; - } - - void* pointer = rc_json_alloc(state, size, alignment); - - if (!state->counting) { - *(void**)value = pointer; - } - - value = pointer; - - if (field->type != RC_JSON_TYPE_RECORD) { - rc_json_parsers[field->type](state, value); - } - else { - rc_json_parse_object(state, value, meta); - } -} - -static void rc_json_parse_object(rc_json_state_t* state, void* record, const rc_json_struct_meta_t* meta) { - if (*state->json != '{') { - longjmp(state->rollback, RC_JSON_INVALID_VALUE); - } - - if (!state->counting) { - memset((void*)record, 0, meta->size); - } - - state->json++; - rc_json_skip_spaces(state); - - while (*state->json != '}') { - if (*state->json != '"') { - longjmp(state->rollback, RC_JSON_MISSING_KEY); - } - - const char* key = (const char*)++state->json; - const char* quote = key; - - for (;;) { - quote = strchr(quote, '"'); - - if (!quote) { - longjmp(state->rollback, RC_JSON_UNTERMINATED_KEY); - } - - if (quote[-1] != '\\') { - break; - } - } - - state->json = (const uint8_t*)quote + 1; - uint32_t hash = rc_json_hash((const uint8_t*)key, quote - key); - - unsigned i; - const rc_json_field_meta_t* field; - - for (i = 0, field = meta->fields; i < meta->num_fields; i++, field++) { - if (field->name_hash == hash) { - break; - } - } - - rc_json_skip_spaces(state); - - if (*state->json != ':') { - longjmp(state->rollback, RC_JSON_MISSING_VALUE); - } - - state->json++; - rc_json_skip_spaces(state); - - if (i != meta->num_fields) { - rc_json_parse_value(state, (void*)((uint8_t*)record + field->offset), field); - } - else { - rc_json_skip_value(state); - } - - rc_json_skip_spaces(state); - - if (*state->json != ',') { - break; - } - - state->json++; - rc_json_skip_spaces(state); - } - - if (*state->json != '}') { - longjmp(state->rollback, RC_JSON_UNTERMINATED_OBJECT); - } - - state->json++; -} - -static int rc_json_execute(void* buffer, uint32_t hash, const uint8_t* json, int counting) { - const rc_json_struct_meta_t* meta = rc_json_resolve_struct(hash); - - if (!meta) { - return RC_JSON_UNKOWN_RECORD; - } - - rc_json_state_t state; - int res; - - if ((res = setjmp(state.rollback)) != 0) { - return res; - } - - state.json = json; - state.buffer = counting ? 0 : (uintptr_t)*(void**)buffer; - state.counting = counting; - - if (!counting) { - *(void**)buffer = rc_json_alloc(&state, meta->size, meta->alignment); - } - - rc_json_skip_spaces(&state); - rc_json_parse_object(&state, *(void**)buffer, meta); - rc_json_skip_spaces(&state); - - if (counting) { - *(size_t*)buffer = state.buffer; - } - - return *state.json == 0 ? RC_JSON_OK : RC_JSON_EOF_EXPECTED; -} - -void* rc_json_deserialize(void* buffer, uint32_t hash, const uint8_t* json) { - void** record = &buffer; - int res = rc_json_execute(record, hash, json, 0); - return res == RC_JSON_OK ? *record : NULL; -} - -int rc_json_get_size(size_t* size, uint32_t hash, const uint8_t* json) { - return rc_json_execute((void*)size, hash, json, 1); -} - -uint32_t rc_json_hash(const uint8_t* str, size_t length) { - typedef char unsigned_must_have_32_bits_minimum[sizeof(unsigned) >= 4 ? 1 : -1]; - - uint32_t hash = 5381; - - if (length != 0) { - do { - hash = hash * 33 + *str++; - } - while (--length != 0); - } - - return hash & 0xffffffffU; -} diff --git a/src/rjson/dejson.h b/src/rjson/dejson.h deleted file mode 100644 index 406c29ea..00000000 --- a/src/rjson/dejson.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef DEJSON_H -#define DEJSON_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define RC_JSON_OFFSETOF(s, f) ((size_t)(&((s*)0)->f)) -#define RC_JSON_ALIGNOF(t) RC_JSON_OFFSETOF(struct{char c; t d;}, d) - -enum { - RC_JSON_TYPE_CHAR, - RC_JSON_TYPE_UCHAR, - RC_JSON_TYPE_SHORT, - RC_JSON_TYPE_USHORT, - RC_JSON_TYPE_INT, - RC_JSON_TYPE_UINT, - RC_JSON_TYPE_LONG, - RC_JSON_TYPE_LONGLONG, - RC_JSON_TYPE_ULONG, - RC_JSON_TYPE_ULONGLONG, - RC_JSON_TYPE_INT8, - RC_JSON_TYPE_INT16, - RC_JSON_TYPE_INT32, - RC_JSON_TYPE_INT64, - RC_JSON_TYPE_UINT8, - RC_JSON_TYPE_UINT16, - RC_JSON_TYPE_UINT32, - RC_JSON_TYPE_UINT64, - RC_JSON_TYPE_FLOAT, - RC_JSON_TYPE_DOUBLE, - RC_JSON_TYPE_BOOL, - RC_JSON_TYPE_STRING, - RC_JSON_TYPE_RECORD -}; - -enum { - RC_JSON_FLAG_ARRAY = 1 << 0, - RC_JSON_FLAG_POINTER = 1 << 1 -}; - -typedef struct { - uint32_t name_hash; - uint32_t type_hash; - uint16_t offset; - uint8_t type; - uint8_t flags; -} -rc_json_field_meta_t; - -typedef struct { - const rc_json_field_meta_t* fields; - uint32_t name_hash; - uint32_t size; - uint16_t alignment; - uint16_t num_fields; -} -rc_json_struct_meta_t; - -void* rc_json_deserialize(void* buffer, uint32_t hash, const uint8_t* json); -int rc_json_get_size(size_t* size, uint32_t hash, const uint8_t* json); -uint32_t rc_json_hash(const uint8_t* str, size_t length); - -#ifdef __cplusplus -} -#endif - -#endif /* DEJSON_H */ diff --git a/src/rjson/schema.c b/src/rjson/schema.c deleted file mode 100644 index afd2d64f..00000000 --- a/src/rjson/schema.c +++ /dev/null @@ -1,609 +0,0 @@ -#include "rjson.h" -#include "dejson.h" - -static const rc_json_field_meta_t rc_json_field_meta_gameid[] = { - { - /* Metadata for field unsigned int gameid;. */ - /* name_hash */ 0xb4960eecU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_gameid_t, gameid), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field char success;. */ - /* name_hash */ 0x110461deU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_gameid_t, success), - /* type */ RC_JSON_TYPE_BOOL, - /* flags */ 0 - }, -}; - -static const rc_json_struct_meta_t rc_json_struct_meta_gameid = { - /* fields */ rc_json_field_meta_gameid, - /* name_hash */ 0xb4960eecU, - /* size */ sizeof(rc_json_gameid_t), - /* alignment */ RC_JSON_ALIGNOF(rc_json_gameid_t), - /* num_fields */ 2 -}; - -int rc_json_get_gameid_size(const char* json) { - size_t size; - int res = rc_json_get_size(&size, 0xb4960eecU, (const uint8_t*)json); - - if (res == RC_JSON_OK) { - res = (int)size; - } - - return res; -} - -const rc_json_gameid_t* rc_json_parse_gameid(void* buffer, const char* json) { - return (const rc_json_gameid_t*)rc_json_deserialize(buffer, 0xb4960eecU, (const uint8_t*)json); -} - -static const rc_json_field_meta_t rc_json_field_meta_login[] = { - { - /* Metadata for field const char* token;. */ - /* name_hash */ 0x0e2dbd26U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_login_t, token), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* user;. */ - /* name_hash */ 0x7c8da264U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_login_t, user), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int score;. */ - /* name_hash */ 0x0e1522c1U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_login_t, score), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int messages;. */ - /* name_hash */ 0xfed3807dU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_login_t, messages), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field char success;. */ - /* name_hash */ 0x110461deU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_login_t, success), - /* type */ RC_JSON_TYPE_BOOL, - /* flags */ 0 - }, -}; - -static const rc_json_struct_meta_t rc_json_struct_meta_login = { - /* fields */ rc_json_field_meta_login, - /* name_hash */ 0x0d9ce89eU, - /* size */ sizeof(rc_json_login_t), - /* alignment */ RC_JSON_ALIGNOF(rc_json_login_t), - /* num_fields */ 5 -}; - -int rc_json_get_login_size(const char* json) { - size_t size; - int res = rc_json_get_size(&size, 0x0d9ce89eU, (const uint8_t*)json); - - if (res == RC_JSON_OK) { - res = (int)size; - } - - return res; -} - -const rc_json_login_t* rc_json_parse_login(void* buffer, const char* json) { - return (const rc_json_login_t*)rc_json_deserialize(buffer, 0x0d9ce89eU, (const uint8_t*)json); -} - -static const rc_json_field_meta_t rc_json_field_meta_cheevo[] = { - { - /* Metadata for field unsigned long long created;. */ - /* name_hash */ 0x3a84721dU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, created), - /* type */ RC_JSON_TYPE_ULONGLONG, - /* flags */ 0 - }, - { - /* Metadata for field unsigned long long modified;. */ - /* name_hash */ 0xdcea4fe6U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, modified), - /* type */ RC_JSON_TYPE_ULONGLONG, - /* flags */ 0 - }, - { - /* Metadata for field const char* author;. */ - /* name_hash */ 0xa804edb8U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, author), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* badge;. */ - /* name_hash */ 0x887685d9U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, badge), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* description;. */ - /* name_hash */ 0xe61a1f69U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, description), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* memaddr;. */ - /* name_hash */ 0x1e76b53fU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, memaddr), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* title;. */ - /* name_hash */ 0x0e2a9a07U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, title), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int flags;. */ - /* name_hash */ 0x0d2e96b2U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, flags), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int points;. */ - /* name_hash */ 0xca8fce22U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, points), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int id;. */ - /* name_hash */ 0x005973f2U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_cheevo_t, id), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, -}; - -static const rc_json_struct_meta_t rc_json_struct_meta_cheevo = { - /* fields */ rc_json_field_meta_cheevo, - /* name_hash */ 0x0af404aeU, - /* size */ sizeof(rc_json_cheevo_t), - /* alignment */ RC_JSON_ALIGNOF(rc_json_cheevo_t), - /* num_fields */ 10 -}; - -int rc_json_get_cheevo_size(const char* json) { - size_t size; - int res = rc_json_get_size(&size, 0x0af404aeU, (const uint8_t*)json); - - if (res == RC_JSON_OK) { - res = (int)size; - } - - return res; -} - -const rc_json_cheevo_t* rc_json_parse_cheevo(void* buffer, const char* json) { - return (const rc_json_cheevo_t*)rc_json_deserialize(buffer, 0x0af404aeU, (const uint8_t*)json); -} - -static const rc_json_field_meta_t rc_json_field_meta_lboard[] = { - { - /* Metadata for field const char* description;. */ - /* name_hash */ 0xe61a1f69U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_lboard_t, description), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* title;. */ - /* name_hash */ 0x0e2a9a07U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_lboard_t, title), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* format;. */ - /* name_hash */ 0xb341208eU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_lboard_t, format), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* mem;. */ - /* name_hash */ 0x0b8807e4U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_lboard_t, mem), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int id;. */ - /* name_hash */ 0x005973f2U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_lboard_t, id), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, -}; - -static const rc_json_struct_meta_t rc_json_struct_meta_lboard = { - /* fields */ rc_json_field_meta_lboard, - /* name_hash */ 0xf7cacd7aU, - /* size */ sizeof(rc_json_lboard_t), - /* alignment */ RC_JSON_ALIGNOF(rc_json_lboard_t), - /* num_fields */ 5 -}; - -int rc_json_get_lboard_size(const char* json) { - size_t size; - int res = rc_json_get_size(&size, 0xf7cacd7aU, (const uint8_t*)json); - - if (res == RC_JSON_OK) { - res = (int)size; - } - - return res; -} - -const rc_json_lboard_t* rc_json_parse_lboard(void* buffer, const char* json) { - return (const rc_json_lboard_t*)rc_json_deserialize(buffer, 0xf7cacd7aU, (const uint8_t*)json); -} - -static const rc_json_field_meta_t rc_json_field_meta_patchdata[] = { - { - /* Metadata for field const rc_json_lboard_t* lboards; int lboards_count;. */ - /* name_hash */ 0xf1247d2dU, - /* type_hash */ 0xf7cacd7aU, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, lboards), - /* type */ RC_JSON_TYPE_RECORD, - /* flags */ RC_JSON_FLAG_ARRAY - }, - { - /* Metadata for field const char* genre;. */ - /* name_hash */ 0x0d3d1136U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, genre), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* developer;. */ - /* name_hash */ 0x87f5b28bU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, developer), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* publisher;. */ - /* name_hash */ 0xce7b6ff3U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, publisher), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* released;. */ - /* name_hash */ 0x8acb686aU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, released), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char** presence;. */ - /* name_hash */ 0xf18dd230U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, presence), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ RC_JSON_FLAG_POINTER - }, - { - /* Metadata for field const char* console;. */ - /* name_hash */ 0x260aebd9U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, console), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const rc_json_cheevo_t* cheevos; int cheevos_count;. */ - /* name_hash */ 0x69749ae1U, - /* type_hash */ 0x0af404aeU, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, cheevos), - /* type */ RC_JSON_TYPE_RECORD, - /* flags */ RC_JSON_FLAG_ARRAY - }, - { - /* Metadata for field const char* image_boxart;. */ - /* name_hash */ 0xddc6bd18U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, image_boxart), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* image_title;. */ - /* name_hash */ 0x65121b6aU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, image_title), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* image_icon;. */ - /* name_hash */ 0xe4022c11U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, image_icon), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* title;. */ - /* name_hash */ 0x0e2a9a07U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, title), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field const char* image_ingame;. */ - /* name_hash */ 0xedfff5f9U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, image_ingame), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int consoleid;. */ - /* name_hash */ 0x071656e5U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, consoleid), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int id;. */ - /* name_hash */ 0x005973f2U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, id), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int flags;. */ - /* name_hash */ 0x0d2e96b2U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, flags), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field unsigned int topicid;. */ - /* name_hash */ 0x7d2b565aU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, topicid), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field char is_final;. */ - /* name_hash */ 0x088a58abU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patchdata_t, is_final), - /* type */ RC_JSON_TYPE_BOOL, - /* flags */ 0 - }, -}; - -static const rc_json_struct_meta_t rc_json_struct_meta_patchdata = { - /* fields */ rc_json_field_meta_patchdata, - /* name_hash */ 0xadc4ac0fU, - /* size */ sizeof(rc_json_patchdata_t), - /* alignment */ RC_JSON_ALIGNOF(rc_json_patchdata_t), - /* num_fields */ 18 -}; - -int rc_json_get_patchdata_size(const char* json) { - size_t size; - int res = rc_json_get_size(&size, 0xadc4ac0fU, (const uint8_t*)json); - - if (res == RC_JSON_OK) { - res = (int)size; - } - - return res; -} - -const rc_json_patchdata_t* rc_json_parse_patchdata(void* buffer, const char* json) { - return (const rc_json_patchdata_t*)rc_json_deserialize(buffer, 0xadc4ac0fU, (const uint8_t*)json); -} - -static const rc_json_field_meta_t rc_json_field_meta_patch[] = { - { - /* Metadata for field rc_json_patchdata_t patchdata;. */ - /* name_hash */ 0xadc4ac0fU, - /* type_hash */ 0xadc4ac0fU, - /* offset */ RC_JSON_OFFSETOF(rc_json_patch_t, patchdata), - /* type */ RC_JSON_TYPE_RECORD, - /* flags */ 0 - }, - { - /* Metadata for field char success;. */ - /* name_hash */ 0x110461deU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_patch_t, success), - /* type */ RC_JSON_TYPE_BOOL, - /* flags */ 0 - }, -}; - -static const rc_json_struct_meta_t rc_json_struct_meta_patch = { - /* fields */ rc_json_field_meta_patch, - /* name_hash */ 0x0dddd3d5U, - /* size */ sizeof(rc_json_patch_t), - /* alignment */ RC_JSON_ALIGNOF(rc_json_patch_t), - /* num_fields */ 2 -}; - -int rc_json_get_patch_size(const char* json) { - size_t size; - int res = rc_json_get_size(&size, 0x0dddd3d5U, (const uint8_t*)json); - - if (res == RC_JSON_OK) { - res = (int)size; - } - - return res; -} - -const rc_json_patch_t* rc_json_parse_patch(void* buffer, const char* json) { - return (const rc_json_patch_t*)rc_json_deserialize(buffer, 0x0dddd3d5U, (const uint8_t*)json); -} - -static const rc_json_field_meta_t rc_json_field_meta_unlocks[] = { - { - /* Metadata for field const unsigned int* ids; int ids_count;. */ - /* name_hash */ 0xc5e91303U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_unlocks_t, ids), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ RC_JSON_FLAG_ARRAY - }, - { - /* Metadata for field unsigned int gameid;. */ - /* name_hash */ 0xb4960eecU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_unlocks_t, gameid), - /* type */ RC_JSON_TYPE_UINT, - /* flags */ 0 - }, - { - /* Metadata for field char success;. */ - /* name_hash */ 0x110461deU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_unlocks_t, success), - /* type */ RC_JSON_TYPE_BOOL, - /* flags */ 0 - }, - { - /* Metadata for field char hardcore;. */ - /* name_hash */ 0xc1b80672U, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_unlocks_t, hardcore), - /* type */ RC_JSON_TYPE_BOOL, - /* flags */ 0 - }, -}; - -static const rc_json_struct_meta_t rc_json_struct_meta_unlocks = { - /* fields */ rc_json_field_meta_unlocks, - /* name_hash */ 0x9b4e2684U, - /* size */ sizeof(rc_json_unlocks_t), - /* alignment */ RC_JSON_ALIGNOF(rc_json_unlocks_t), - /* num_fields */ 4 -}; - -int rc_json_get_unlocks_size(const char* json) { - size_t size; - int res = rc_json_get_size(&size, 0x9b4e2684U, (const uint8_t*)json); - - if (res == RC_JSON_OK) { - res = (int)size; - } - - return res; -} - -const rc_json_unlocks_t* rc_json_parse_unlocks(void* buffer, const char* json) { - return (const rc_json_unlocks_t*)rc_json_deserialize(buffer, 0x9b4e2684U, (const uint8_t*)json); -} - -static const rc_json_field_meta_t rc_json_field_meta_error[] = { - { - /* Metadata for field const char* error;. */ - /* name_hash */ 0x0d2011cfU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_error_t, error), - /* type */ RC_JSON_TYPE_STRING, - /* flags */ 0 - }, - { - /* Metadata for field char success;. */ - /* name_hash */ 0x110461deU, - /* type_hash */ 0x00000000U, - /* offset */ RC_JSON_OFFSETOF(rc_json_error_t, success), - /* type */ RC_JSON_TYPE_BOOL, - /* flags */ 0 - }, -}; - -static const rc_json_struct_meta_t rc_json_struct_meta_error = { - /* fields */ rc_json_field_meta_error, - /* name_hash */ 0x0d2011cfU, - /* size */ sizeof(rc_json_error_t), - /* alignment */ RC_JSON_ALIGNOF(rc_json_error_t), - /* num_fields */ 2 -}; - -int rc_json_get_error_size(const char* json) { - size_t size; - int res = rc_json_get_size(&size, 0x0d2011cfU, (const uint8_t*)json); - - if (res == RC_JSON_OK) { - res = (int)size; - } - - return res; -} - -const rc_json_error_t* rc_json_parse_error(void* buffer, const char* json) { - return (const rc_json_error_t*)rc_json_deserialize(buffer, 0x0d2011cfU, (const uint8_t*)json); -} - -const rc_json_struct_meta_t* rc_json_resolve_struct(unsigned hash) { - - switch (hash) { - case 0xb4960eecU: return &rc_json_struct_meta_gameid; - case 0x0d9ce89eU: return &rc_json_struct_meta_login; - case 0x0af404aeU: return &rc_json_struct_meta_cheevo; - case 0xf7cacd7aU: return &rc_json_struct_meta_lboard; - case 0xadc4ac0fU: return &rc_json_struct_meta_patchdata; - case 0x0dddd3d5U: return &rc_json_struct_meta_patch; - case 0x9b4e2684U: return &rc_json_struct_meta_unlocks; - case 0x0d2011cfU: return &rc_json_struct_meta_error; - default: return NULL; - } -} diff --git a/src/rjson/schema.dej b/src/rjson/schema.dej deleted file mode 100644 index f11e6a55..00000000 --- a/src/rjson/schema.dej +++ /dev/null @@ -1,82 +0,0 @@ -//---------------------------------------------------------------------------- - -struct gameid/GameID { - bool success/Success; - unsigned gameid/GameID; -}; - -//---------------------------------------------------------------------------- - -struct login/Login { - bool success/Success; - string user/User; - string token/Token; - unsigned score/Score; - unsigned messages/Messages; -}; - -//---------------------------------------------------------------------------- - -struct cheevo/Achievement { - unsigned id/ID; - string memaddr/MemAddr; - string title/Title; - string description/Description; - unsigned points/Points; - string author/Author; - string badge/BadgeName; - unsigned flags/Flags; - - unsigned long long modified/Modified; - unsigned long long created/Created; -}; - -struct lboard/Leaderboard { - unsigned id/ID; - string mem/Mem; - string format/Format; - string title/Title; - string description/Description; -}; - -struct patchdata/PatchData { - unsigned id/ID; - string title/Title; - unsigned consoleid/ConsoleID; - unsigned topicid/ForumTopicID; - unsigned flags/Flags; - string image_icon/ImageIcon; - string image_title/ImageTitle; - string image_ingame/ImageIngame; - string image_boxart/ImageBoxArt; - string publisher/Publisher; - string developer/Developer; - string genre/Genre; - string released/Released; - bool is_final/IsFinal; - string console/ConsoleName; - string* presence/RichPresencePatch; - cheevo cheevos/Achievements[]; - lboard lboards/Leaderboards[]; -}; - -struct patch/Patch { - bool success/Success; - patchdata patchdata/PatchData; -}; - -//---------------------------------------------------------------------------- - -struct unlocks/Unlocks { - bool success/Success; - unsigned ids/UserUnlocks[]; - unsigned gameid/GameID; - bool hardcore/HardcoreMode; -}; - -//---------------------------------------------------------------------------- - -struct error/Error { - bool success/Success; - string error/Error; -}; diff --git a/test/Makefile b/test/Makefile index 32562be5..d8dafce6 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,12 +1,10 @@ RC_SRC=../src/rcheevos -RC_JSON_SRC=../src/rjson RC_URL_SRC=../src/rurl LUA_SRC=lua/src OBJ=$(RC_SRC)/trigger.o $(RC_SRC)/condset.o $(RC_SRC)/condition.o $(RC_SRC)/operand.o \ $(RC_SRC)/term.o $(RC_SRC)/expression.o $(RC_SRC)/value.o $(RC_SRC)/lboard.o \ $(RC_SRC)/alloc.o $(RC_SRC)/format.o \ - $(RC_JSON_SRC)/dejson.o $(RC_JSON_SRC)/schema.o \ $(RC_URL_SRC)/url.o \ $(LUA_SRC)/lapi.o $(LUA_SRC)/lcode.o $(LUA_SRC)/lctype.o $(LUA_SRC)/ldebug.o \ $(LUA_SRC)/ldo.o $(LUA_SRC)/ldump.o $(LUA_SRC)/lfunc.o $(LUA_SRC)/lgc.o $(LUA_SRC)/llex.o \ diff --git a/test/test.c b/test/test.c index c155937e..e9bc770d 100644 --- a/test/test.c +++ b/test/test.c @@ -1,5 +1,4 @@ #include "internal.h" -#include "rjson.h" #include "rurl.h" #include "smw_snes.h" @@ -2091,84 +2090,6 @@ static void test_lua(void) { } } -static void test_json(void) { - { - /*------------------------------------------------------------------------ - TestJson - ------------------------------------------------------------------------*/ - - char json[65536]; - char buffer[65536]; - int res; - const rc_json_patch_t* patch; - - memcpy(json, smw_snes_json, smw_snes_json_len); - json[smw_snes_json_len] = 0; - - res = rc_json_get_patch_size(json); - assert(res >= 0); - patch = rc_json_parse_patch(buffer, json); - - assert(patch->success); - assert(patch->patchdata.id == 228); - assert(!strcmp(patch->patchdata.title, "Super Mario World")); - assert(patch->patchdata.consoleid == 3); - assert(patch->patchdata.topicid == 135); - assert(patch->patchdata.flags == 0); - assert(!strcmp(patch->patchdata.image_icon, "/Images/006972.png")); - assert(!strcmp(patch->patchdata.image_title, "/Images/000021.png")); - assert(!strcmp(patch->patchdata.image_ingame, "/Images/000022.png")); - assert(!strcmp(patch->patchdata.image_boxart, "/Images/000138.png")); - assert(!strcmp(patch->patchdata.publisher, "Nintendo")); - assert(!strcmp(patch->patchdata.developer, "Nintendo EAD")); - assert(!strcmp(patch->patchdata.genre, "Platforming")); - assert(!strcmp(patch->patchdata.released, "JP 1990 , NA 1991 Europe 1992")); - assert(patch->patchdata.is_final == 0); - assert(!strcmp(patch->patchdata.console, "SNES")); - assert(patch->patchdata.presence != NULL); - assert(!strcmp(*patch->patchdata.presence, "Lookup:LevelName\r\n0x0=Title Screen\r\n0x14=Yellow Switch Palace\r\n0x28=Yoshi's House\r\n0x29=Yoshi's Island 1\r\n0x2a=Yoshi's Island 2\r\n0x27=Yoshi's Island 3\r\n0x26=Yoshi's Island 4\r\n0x25=#1 Iggy's Castle\r\n0x15=Donut Plains 1\r\n0x9=Donut Plains 2\r\n0x8=Green Switch Palace\r\n0x4=Donut Ghost House\r\n0x3=Top Secret Area\r\n0x5=Donut Plains 3\r\n0x6=Donut Plains 4\r\n0x7=#2 Morton's Castle\r\n0xa=Donut Secret 1\r\n0x13=Donut Secret House\r\n0x2f=Donut Secret 2\r\n0x3e=Vanilla Dome 1\r\n0x3c=Vanilla Dome 2\r\n0x3f=Red Switch Palace\r\n0x2b=Vanilla Ghost House\r\n0x2e=Vanilla Dome 3\r\n0x3d=Vanilla Dome 4\r\n0x40=#3 Lemmy's Castle\r\n0x2d=Vanilla Secret 1\r\n0x1=Vanilla Secret 2\r\n0x2=Vanilla Secret 3\r\n0xb=Vanilla Fortress\r\n0xc=Butter Bridge 1\r\n0xd=Butter Bridge 2\r\n0xe=#4 Ludwig's Castle\r\n0xf=Cheese Bridge Area\r\n0x10=Cookie Mountain\r\n0x11=Soda Lake\r\n0x41=Forest Ghost House\r\n0x42=Forest of Illusion 1\r\n0x43=Forest of Illusion 4\r\n0x44=Forest of Illusion 2\r\n0x45=Blue Switch Palace\r\n0x46=Forest Secret Area\r\n0x47=Forest of Illusion 3\r\n0x1f=Forest Fortress\r\n0x20=#5 Roy's Castle\r\n0x21=Choco-Ghost House\r\n0x22=Chocolate Island 1\r\n0x23=Chocolate Island 3\r\n0x24=Chocolate Island 2\r\n0x1b=Chocolate Fortress\r\n0x1d=Chocolate Island 4\r\n0x1c=Chocolate Island 5\r\n0x1a=#6 Wendy's Castle\r\n0x18=Sunken Ghost Ship\r\n0x3b=Chocolate Secret\r\n0x3a=Valley of Bowser 1\r\n0x39=Valley of Bowser 2\r\n0x38=Valley Ghost House\r\n0x37=Valley of Bowser 3\r\n0x33=Valley of Bowser 4\r\n0x34=#7 Larry's Castle\r\n0x35=Valley Fortress\r\n0x31=Front Door\r\n0x32=Back Door\r\n0x58=Star World 1\r\n0x54=Star World 2\r\n0x56=Star World 3\r\n0x59=Star World 4\r\n0x5a=Star World 5\r\n0x4e=Gnarly\r\n0x4f=Tubular\r\n0x50=Way Cool\r\n0x51=Awesome\r\n0x4c=Groovy\r\n0x4b=Mondo\r\n0x4a=Outrageous\r\n0x49=Funky\r\n\r\nFormat:Lives\r\nFormatType=VALUE\r\n\r\nDisplay:\r\n@LevelName(0xh0013bf), @Lives(0xh0dbe_v+1) lives")); - assert(patch->patchdata.cheevos_count == 53); - assert(patch->patchdata.lboards_count == 0); - - assert(patch->patchdata.cheevos[0].id == 4874); - assert(!strcmp(patch->patchdata.cheevos[0].memaddr, "0xH000019=2")); - assert(!strcmp(patch->patchdata.cheevos[0].title, "I Believe I Can Fly")); - assert(!strcmp(patch->patchdata.cheevos[0].description, "Collect a feather")); - assert(patch->patchdata.cheevos[0].points == 2); - assert(!strcmp(patch->patchdata.cheevos[0].author, "UNHchabo")); - assert(patch->patchdata.cheevos[0].modified == 1452548368ULL); - assert(patch->patchdata.cheevos[0].created == 1391908064ULL); - assert(!strcmp(patch->patchdata.cheevos[0].badge, "05506")); - assert(patch->patchdata.cheevos[0].flags == 3); - - assert(patch->patchdata.cheevos[52].id == 29667); - assert(!strcmp(patch->patchdata.cheevos[52].memaddr, "0xR001ff5=1_0xH0013bf=58")); - assert(!strcmp(patch->patchdata.cheevos[52].title, "Under A Koopa Moon")); - assert(!strcmp(patch->patchdata.cheevos[52].description, "Collect the 3-Up Moon in the Valley of Bowser")); - assert(patch->patchdata.cheevos[52].points == 2); - assert(!strcmp(patch->patchdata.cheevos[52].author, "Dexterspet")); - assert(patch->patchdata.cheevos[52].modified == 1445783716ULL); - assert(patch->patchdata.cheevos[52].created == 1445754036ULL); - assert(!strcmp(patch->patchdata.cheevos[52].badge, "30351")); - assert(patch->patchdata.cheevos[52].flags == 3); - - memcpy(json, galaga_nes_json, galaga_nes_json_len); - json[galaga_nes_json_len] = 0; - - res = rc_json_get_patch_size(json); - assert(res >= 0); - patch = rc_json_parse_patch(buffer, json); - - assert(patch->patchdata.lboards_count == 1); - - assert(patch->patchdata.lboards[0].id == 310); - assert(!strcmp(patch->patchdata.lboards[0].mem, "STA:0xh0482=1::CAN:0xh0470=0_0xh0471=0::SUB:0xh0485=0_d0xh007a=0_0xh007a=1::VAL:0xh00e5*10_0xh00e4*100_0xh00e3*1000_0xh00e2*10000_0xh00e1*100000_0xh00e0*1000000")); - assert(!strcmp(patch->patchdata.lboards[0].format, "SCORE")); - assert(!strcmp(patch->patchdata.lboards[0].title, "Hi-Score")); - assert(!strcmp(patch->patchdata.lboards[0].description, "Get the highest score possible.")); - } -} - int main(void) { test_operand(); test_condition(); @@ -2177,7 +2098,6 @@ int main(void) { test_value(); test_lboard(); test_lua(); - test_json(); return 0; }