1
0
mirror of https://github.com/libretro/RetroArch synced 2025-03-26 20:37:10 +00:00

Updated rcheevos to 7.0.0

This commit is contained in:
Andre Leiradella 2018-09-02 14:32:08 +01:00
parent 613a3e8479
commit 720ecaff17
9 changed files with 4 additions and 1773 deletions

@ -1,3 +1,7 @@
# v7.0.0
* Removed **rjson**
# v6.5.0
* Added a schema for errors returned by the server

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

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

@ -1,750 +0,0 @@
#include "rjson.h"
#include "dejson.h"
#include <setjmp.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <float.h>
#include <errno.h>
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;
}

@ -1,71 +0,0 @@
#ifndef DEJSON_H
#define DEJSON_H
#include <stddef.h>
#include <stdint.h>
#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 */

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

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

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

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