Network conn and disconn
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
|
#include "network/http/networkhttprequest.h"
|
||||||
#include "system/system.h"
|
#include "system/system.h"
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
#include "save/save.h"
|
#include "save/save.h"
|
||||||
@@ -45,6 +46,13 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
|||||||
errorChain(networkInit());
|
errorChain(networkInit());
|
||||||
errorChain(sceneInit());
|
errorChain(sceneInit());
|
||||||
|
|
||||||
|
networkRequestConnection(
|
||||||
|
engineNetworkOnConnected,
|
||||||
|
engineNetworkOnFailed,
|
||||||
|
engineNetworkOnDisconnect,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
consolePrint("Engine initialized");
|
consolePrint("Engine initialized");
|
||||||
|
|
||||||
#ifdef DUSK_ASSERTIONS_FAKED
|
#ifdef DUSK_ASSERTIONS_FAKED
|
||||||
@@ -55,7 +63,6 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
|||||||
|
|
||||||
sceneSet(SCENE_TYPE_OVERWORLD);
|
sceneSet(SCENE_TYPE_OVERWORLD);
|
||||||
|
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +70,15 @@ errorret_t engineUpdate(void) {
|
|||||||
// Order here is important.
|
// Order here is important.
|
||||||
errorChain(networkUpdate());
|
errorChain(networkUpdate());
|
||||||
timeUpdate();
|
timeUpdate();
|
||||||
|
|
||||||
|
if(
|
||||||
|
ENGINE.networkDisconnectTestPending &&
|
||||||
|
TIME.time >= ENGINE.networkDisconnectTestAt
|
||||||
|
) {
|
||||||
|
ENGINE.networkDisconnectTestPending = false;
|
||||||
|
networkRequestDisconnection(engineNetworkDisconnectTestOnComplete, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
inputUpdate();
|
inputUpdate();
|
||||||
consoleUpdate();
|
consoleUpdate();
|
||||||
errorChain(rpgUpdate());
|
errorChain(rpgUpdate());
|
||||||
@@ -93,3 +109,63 @@ errorret_t engineDispose(void) {
|
|||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void engineHttpTestOnComplete(void *params, void *user) {
|
||||||
|
networkhttprequest_t *request = (networkhttprequest_t *)params;
|
||||||
|
const networkhttpresponse_t *response = &request->response;
|
||||||
|
|
||||||
|
consolePrint("frogfind.com response status: %d", response->status);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < response->headers.count; i++) {
|
||||||
|
const networkhttpheader_t *header = &response->headers.headers[i];
|
||||||
|
consolePrint("frogfind.com header: %s: %s", header->name, header->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
consolePrint("frogfind.com body length: %d", (int32_t)response->bodyLength);
|
||||||
|
|
||||||
|
const size_t chunkMax = CONSOLE_LINE_MAX - 32;
|
||||||
|
for(size_t offset = 0; offset < response->bodyLength; offset += chunkMax) {
|
||||||
|
size_t chunkLength = response->bodyLength - offset;
|
||||||
|
if(chunkLength > chunkMax) chunkLength = chunkMax;
|
||||||
|
|
||||||
|
consolePrint("frogfind.com body: %.*s",
|
||||||
|
(int32_t)chunkLength, (const char_t *)response->body + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void engineHttpTestOnError(void *params, void *user) {
|
||||||
|
consolePrint("frogfind.com request failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void engineNetworkOnConnected(void *user) {
|
||||||
|
consolePrint("Network connected");
|
||||||
|
|
||||||
|
errorret_t ret = networkHttpRequest(
|
||||||
|
NETWORK_HTTP_METHOD_GET,
|
||||||
|
"http://frogfind.com",
|
||||||
|
NULL, 0,
|
||||||
|
NULL, 0,
|
||||||
|
NULL, 0,
|
||||||
|
engineHttpTestOnComplete,
|
||||||
|
engineHttpTestOnError,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
errorCatch(errorPrint(ret));
|
||||||
|
|
||||||
|
ENGINE.networkDisconnectTestAt = TIME.time + 10.0f;
|
||||||
|
ENGINE.networkDisconnectTestPending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void engineNetworkOnFailed(errorret_t error, void *user) {
|
||||||
|
consolePrint("Network connection failed");
|
||||||
|
errorCatch(errorPrint(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void engineNetworkOnDisconnect(errorret_t error, void *user) {
|
||||||
|
consolePrint("Network disconnected");
|
||||||
|
errorCatch(errorPrint(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void engineNetworkDisconnectTestOnComplete(void *user) {
|
||||||
|
consolePrint("Network disconnect test complete");
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ typedef struct {
|
|||||||
int32_t argc;
|
int32_t argc;
|
||||||
const char_t **argv;
|
const char_t **argv;
|
||||||
const char_t *version;
|
const char_t *version;
|
||||||
|
|
||||||
|
// Test: disconnects the network 10 seconds after it connects.
|
||||||
|
bool_t networkDisconnectTestPending;
|
||||||
|
float_t networkDisconnectTestAt;
|
||||||
} engine_t;
|
} engine_t;
|
||||||
|
|
||||||
extern engine_t ENGINE;
|
extern engine_t ENGINE;
|
||||||
@@ -38,3 +42,51 @@ errorret_t engineUpdate(void);
|
|||||||
*/
|
*/
|
||||||
errorret_t engineDispose(void);
|
errorret_t engineDispose(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the response status, headers and body of the frogfind.com test
|
||||||
|
* request to the console.
|
||||||
|
*
|
||||||
|
* @param params The completed networkhttprequest_t.
|
||||||
|
* @param user Unused.
|
||||||
|
*/
|
||||||
|
void engineHttpTestOnComplete(void *params, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs that the frogfind.com test request failed.
|
||||||
|
*
|
||||||
|
* @param params The failed networkhttprequest_t.
|
||||||
|
* @param user Unused.
|
||||||
|
*/
|
||||||
|
void engineHttpTestOnError(void *params, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires the frogfind.com test request once the network connection is
|
||||||
|
* up (some platforms, such as PSP, only bring the network stack up
|
||||||
|
* asynchronously after networkRequestConnection is called).
|
||||||
|
*
|
||||||
|
* @param user Unused.
|
||||||
|
*/
|
||||||
|
void engineNetworkOnConnected(void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs that the network connection could not be established.
|
||||||
|
*
|
||||||
|
* @param error The error describing why the connection failed.
|
||||||
|
* @param user Unused.
|
||||||
|
*/
|
||||||
|
void engineNetworkOnFailed(errorret_t error, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs that the network connection was lost after having connected.
|
||||||
|
*
|
||||||
|
* @param error The error describing why the connection was lost.
|
||||||
|
* @param user Unused.
|
||||||
|
*/
|
||||||
|
void engineNetworkOnDisconnect(errorret_t error, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs that the 10-second test disconnect completed.
|
||||||
|
*
|
||||||
|
* @param user Unused.
|
||||||
|
*/
|
||||||
|
void engineNetworkDisconnectTestOnComplete(void *user);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "util/math.h"
|
#include "util/math.h"
|
||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
#include "event/event.h"
|
#include "event/event.h"
|
||||||
|
#include "save/save.h"
|
||||||
|
|
||||||
input_t INPUT;
|
input_t INPUT;
|
||||||
|
|
||||||
@@ -46,6 +47,43 @@ errorret_t inputInit(void) {
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errorret_t inputSaveSettings(void) {
|
||||||
|
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
|
||||||
|
yyjson_mut_val *root = yyjson_mut_obj(doc);
|
||||||
|
yyjson_mut_doc_set_root(doc, root);
|
||||||
|
|
||||||
|
yyjson_mut_val *settings = yyjson_mut_obj(doc);
|
||||||
|
yyjson_mut_obj_add_val(doc, root, "settings", settings);
|
||||||
|
|
||||||
|
yyjson_mut_val *inputSettings = yyjson_mut_obj(doc);
|
||||||
|
yyjson_mut_obj_add_val(doc, settings, "input", inputSettings);
|
||||||
|
|
||||||
|
yyjson_mut_obj_add_real(doc, inputSettings, "deadzone", INPUT.deadzone);
|
||||||
|
|
||||||
|
errorret_t ret = saveWrite(SAVE_SETTINGS_SLOT, doc);
|
||||||
|
yyjson_mut_doc_free(doc);
|
||||||
|
|
||||||
|
if(errorIsNotOk(ret)) return ret;
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t inputLoadSettings(void) {
|
||||||
|
yyjson_doc *doc = NULL;
|
||||||
|
errorChain(saveLoad(SAVE_SETTINGS_SLOT, &doc));
|
||||||
|
|
||||||
|
if(!doc) errorOk();
|
||||||
|
|
||||||
|
yyjson_val *root = yyjson_doc_get_root(doc);
|
||||||
|
yyjson_val *settings = yyjson_obj_get(root, "settings");
|
||||||
|
yyjson_val *inputSettings = yyjson_obj_get(settings, "input");
|
||||||
|
yyjson_val *deadzone = yyjson_obj_get(inputSettings, "deadzone");
|
||||||
|
|
||||||
|
if(deadzone) INPUT.deadzone = (float_t)yyjson_get_num(deadzone);
|
||||||
|
|
||||||
|
yyjson_doc_free(doc);
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
void inputUpdate(void) {
|
void inputUpdate(void) {
|
||||||
#ifdef inputUpdatePlatform
|
#ifdef inputUpdatePlatform
|
||||||
inputUpdatePlatform();
|
inputUpdatePlatform();
|
||||||
|
|||||||
@@ -37,6 +37,23 @@ errorret_t inputInit(void);
|
|||||||
*/
|
*/
|
||||||
void inputUpdate(void);
|
void inputUpdate(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists the current input settings (currently just the gamepad
|
||||||
|
* deadzone) to the save system as JSON, under settings.input.
|
||||||
|
*
|
||||||
|
* @return An error code if serialization or the write fails.
|
||||||
|
*/
|
||||||
|
errorret_t inputSaveSettings(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads input settings (currently just the gamepad deadzone) from the
|
||||||
|
* save system's JSON payload under settings.input and applies them to
|
||||||
|
* INPUT. Leaves INPUT unchanged if no settings file exists yet.
|
||||||
|
*
|
||||||
|
* @return An error code if the load or parse fails.
|
||||||
|
*/
|
||||||
|
errorret_t inputLoadSettings(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current value of a specific input action.
|
* Gets the current value of a specific input action.
|
||||||
*
|
*
|
||||||
|
|||||||
+10
-10
@@ -29,8 +29,11 @@ errorret_t saveDispose(void) {
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveLoad(const uint8_t slot) {
|
errorret_t saveLoad(const uint8_t slot, yyjson_doc **outDoc) {
|
||||||
assertTrue(slot < SAVE_FILE_COUNT_MAX, "slot exceeds SAVE_FILE_COUNT_MAX");
|
assertTrue(slot < SAVE_FILE_COUNT_MAX, "slot exceeds SAVE_FILE_COUNT_MAX");
|
||||||
|
assertNotNull(outDoc, "outDoc must not be NULL");
|
||||||
|
|
||||||
|
*outDoc = NULL;
|
||||||
|
|
||||||
savefile_t *file = &SAVE.files[slot];
|
savefile_t *file = &SAVE.files[slot];
|
||||||
file->exists = false;
|
file->exists = false;
|
||||||
@@ -44,7 +47,8 @@ errorret_t saveLoad(const uint8_t slot) {
|
|||||||
|
|
||||||
if(!stream.found) errorOk();
|
if(!stream.found) errorOk();
|
||||||
|
|
||||||
errorret_t ret = saveFileLoad(&stream, file);
|
yyjson_doc *doc = NULL;
|
||||||
|
errorret_t ret = saveFileLoad(&stream, file, &doc);
|
||||||
|
|
||||||
#ifdef saveStreamClosePlatform
|
#ifdef saveStreamClosePlatform
|
||||||
saveStreamClosePlatform(&stream);
|
saveStreamClosePlatform(&stream);
|
||||||
@@ -52,14 +56,14 @@ errorret_t saveLoad(const uint8_t slot) {
|
|||||||
|
|
||||||
if(errorIsNotOk(ret)) return ret;
|
if(errorIsNotOk(ret)) return ret;
|
||||||
|
|
||||||
errorChain(saveStreamVerifyChecksumImpl(&stream, slot));
|
*outDoc = doc;
|
||||||
|
|
||||||
file->exists = true;
|
file->exists = true;
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveWrite(const uint8_t slot) {
|
errorret_t saveWrite(const uint8_t slot, yyjson_mut_doc *doc) {
|
||||||
assertTrue(slot < SAVE_FILE_COUNT_MAX, "slot exceeds SAVE_FILE_COUNT_MAX");
|
assertTrue(slot < SAVE_FILE_COUNT_MAX, "slot exceeds SAVE_FILE_COUNT_MAX");
|
||||||
|
assertNotNull(doc, "doc must not be NULL");
|
||||||
|
|
||||||
savefile_t *file = &SAVE.files[slot];
|
savefile_t *file = &SAVE.files[slot];
|
||||||
|
|
||||||
@@ -70,11 +74,7 @@ errorret_t saveWrite(const uint8_t slot) {
|
|||||||
errorChain(saveStreamOpenWritePlatform(&stream, slot));
|
errorChain(saveStreamOpenWritePlatform(&stream, slot));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
errorret_t ret = saveFileWrite(&stream, file);
|
errorret_t ret = saveFileWrite(&stream, file, doc);
|
||||||
|
|
||||||
if(errorIsOk(ret)) {
|
|
||||||
ret = saveStreamFinalizeWriteImpl(&stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef saveStreamClosePlatform
|
#ifdef saveStreamClosePlatform
|
||||||
saveStreamClosePlatform(&stream);
|
saveStreamClosePlatform(&stream);
|
||||||
|
|||||||
+21
-9
@@ -9,9 +9,10 @@
|
|||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "savefile.h"
|
#include "savefile.h"
|
||||||
#include "save/saveplatform.h"
|
#include "save/saveplatform.h"
|
||||||
|
#include "yyjson.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** Per-slot save file data; indexed 0 to SAVE_FILE_COUNT_MAX - 1. */
|
/** Per-slot save file metadata; indexed 0 to SAVE_FILE_COUNT_MAX - 1. */
|
||||||
savefile_t files[SAVE_FILE_COUNT_MAX];
|
savefile_t files[SAVE_FILE_COUNT_MAX];
|
||||||
/** Platform-specific save system state (paths, card handles, etc.). */
|
/** Platform-specific save system state (paths, card handles, etc.). */
|
||||||
saveplatform_t platform;
|
saveplatform_t platform;
|
||||||
@@ -34,20 +35,30 @@ errorret_t saveInit(void);
|
|||||||
errorret_t saveDispose(void);
|
errorret_t saveDispose(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the save file for a given slot from persistent storage.
|
* Loads the save file for a given slot from persistent storage and parses
|
||||||
|
* its JSON payload. The payload is read and parsed fresh on every call and
|
||||||
|
* is not retained anywhere else - the caller owns the returned document
|
||||||
|
* and must release it with yyjson_doc_free() once done reading from it.
|
||||||
*
|
*
|
||||||
* @param slot The save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
* @param slot The save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
||||||
* @return An error code if the load fails.
|
* @param outDoc Receives the parsed JSON document, or NULL if the slot has
|
||||||
|
* no save file on disk.
|
||||||
|
* @return An error code if the load or checksum validation fails.
|
||||||
*/
|
*/
|
||||||
errorret_t saveLoad(const uint8_t slot);
|
errorret_t saveLoad(const uint8_t slot, yyjson_doc **outDoc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the save file for a given slot to persistent storage.
|
* Serializes the given JSON document and writes it to persistent storage
|
||||||
|
* for a given slot, alongside its byte size and CRC32 checksum. The
|
||||||
|
* document is serialized to bytes fresh on every call and is not retained
|
||||||
|
* anywhere else - the caller keeps ownership of doc and must dispose of it
|
||||||
|
* with yyjson_mut_doc_free() once done.
|
||||||
*
|
*
|
||||||
* @param slot The save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
* @param slot The save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
||||||
* @return An error code if the write fails.
|
* @param doc The JSON document to serialize and write.
|
||||||
|
* @return An error code if serialization or the write fails.
|
||||||
*/
|
*/
|
||||||
errorret_t saveWrite(const uint8_t slot);
|
errorret_t saveWrite(const uint8_t slot, yyjson_mut_doc *doc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the save file for a given slot from persistent storage.
|
* Deletes the save file for a given slot from persistent storage.
|
||||||
@@ -66,7 +77,8 @@ errorret_t saveDelete(const uint8_t slot);
|
|||||||
bool_t saveExists(const uint8_t slot);
|
bool_t saveExists(const uint8_t slot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a pointer to the save file data for a given slot.
|
* Gets a pointer to the save file metadata for a given slot. This does
|
||||||
|
* not include the JSON payload itself - see saveLoad().
|
||||||
*
|
*
|
||||||
* @param slot The save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
* @param slot The save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
||||||
* @return A pointer to the savefile_t for the given slot.
|
* @return A pointer to the savefile_t for the given slot.
|
||||||
|
|||||||
@@ -20,11 +20,21 @@
|
|||||||
/** Maximum number of independent save slots supported. */
|
/** Maximum number of independent save slots supported. */
|
||||||
#define SAVE_FILE_COUNT_MAX 3
|
#define SAVE_FILE_COUNT_MAX 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slot used to persist game settings. Shares the save slot range with
|
||||||
|
* game saves for now, until settings get a dedicated file of their own.
|
||||||
|
*/
|
||||||
|
#define SAVE_SETTINGS_SLOT 0
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** Magic header bytes read from the file; must equal SAVE_FILE_HEADER. */
|
/** Magic header bytes read from the file; must equal SAVE_FILE_HEADER. */
|
||||||
char_t header[SAVE_FILE_HEADER_SIZE];
|
char_t header[SAVE_FILE_HEADER_SIZE];
|
||||||
/** Format version read from the file; used to branch on older layouts. */
|
/** Format version read from the file; used to branch on older layouts. */
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
|
/** Byte length of the serialized JSON payload. */
|
||||||
|
uint32_t size;
|
||||||
|
/** CRC32 checksum of the serialized JSON payload, for validation. */
|
||||||
|
uint32_t checksum;
|
||||||
/** Runtime flag - true if this slot was successfully loaded or written. */
|
/** Runtime flag - true if this slot was successfully loaded or written. */
|
||||||
bool_t exists;
|
bool_t exists;
|
||||||
} savefile_t;
|
} savefile_t;
|
||||||
|
|||||||
+75
-251
@@ -8,10 +8,10 @@
|
|||||||
#include "save/savestream.h"
|
#include "save/savestream.h"
|
||||||
#include "util/crypt.h"
|
#include "util/crypt.h"
|
||||||
#include "util/endian.h"
|
#include "util/endian.h"
|
||||||
#include "util/string.h"
|
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
errorret_t saveStreamReadBytesRawImpl(
|
errorret_t saveStreamReadBytesImpl(
|
||||||
savestream_t *stream, void *buf, const size_t len
|
savestream_t *stream, void *buf, const size_t len
|
||||||
) {
|
) {
|
||||||
#ifdef saveStreamReadBytesPlatform
|
#ifdef saveStreamReadBytesPlatform
|
||||||
@@ -20,7 +20,7 @@ errorret_t saveStreamReadBytesRawImpl(
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveStreamWriteBytesRawImpl(
|
errorret_t saveStreamWriteBytesImpl(
|
||||||
savestream_t *stream, const void *buf, const size_t len
|
savestream_t *stream, const void *buf, const size_t len
|
||||||
) {
|
) {
|
||||||
#ifdef saveStreamWriteBytesPlatform
|
#ifdef saveStreamWriteBytesPlatform
|
||||||
@@ -29,51 +29,10 @@ errorret_t saveStreamWriteBytesRawImpl(
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveStreamReadBytesImpl(
|
|
||||||
savestream_t *stream, void *buf, const size_t len
|
|
||||||
) {
|
|
||||||
errorChain(saveStreamReadBytesRawImpl(stream, buf, len));
|
|
||||||
cryptCRC32Update(&stream->checksum, buf, len);
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteBytesImpl(
|
|
||||||
savestream_t *stream, const void *buf, const size_t len
|
|
||||||
) {
|
|
||||||
cryptCRC32Update(&stream->checksum, buf, len);
|
|
||||||
errorChain(saveStreamWriteBytesRawImpl(stream, buf, len));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamFinalizeWriteImpl(savestream_t *stream) {
|
|
||||||
uint32_t finalCRC = cryptCRC32End(stream->checksum);
|
|
||||||
uint32_t leChecksum = endianLittleToHost32(finalCRC);
|
|
||||||
|
|
||||||
#ifdef saveStreamSeekPlatform
|
|
||||||
errorChain(saveStreamSeekPlatform(stream, SAVE_FILE_HEADER_SIZE));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
errorChain(saveStreamWriteBytesRawImpl(
|
|
||||||
stream, &leChecksum, sizeof(uint32_t)
|
|
||||||
));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamVerifyChecksumImpl(
|
|
||||||
savestream_t *stream, const uint8_t slot
|
|
||||||
) {
|
|
||||||
uint32_t computed = cryptCRC32End(stream->checksum);
|
|
||||||
if(computed != stream->expectedChecksum) {
|
|
||||||
errorThrow("Save slot %u has invalid checksum", (uint32_t)slot);
|
|
||||||
}
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
errorret_t saveStreamReadHeaderImpl(
|
errorret_t saveStreamReadHeaderImpl(
|
||||||
savestream_t *stream, char_t header[SAVE_FILE_HEADER_SIZE]
|
savestream_t *stream, char_t header[SAVE_FILE_HEADER_SIZE]
|
||||||
) {
|
) {
|
||||||
errorChain(saveStreamReadBytesRawImpl(stream, header, SAVE_FILE_HEADER_SIZE));
|
errorChain(saveStreamReadBytesImpl(stream, header, SAVE_FILE_HEADER_SIZE));
|
||||||
|
|
||||||
if(
|
if(
|
||||||
header[0] != SAVE_FILE_HEADER[0] ||
|
header[0] != SAVE_FILE_HEADER[0] ||
|
||||||
@@ -83,25 +42,13 @@ errorret_t saveStreamReadHeaderImpl(
|
|||||||
errorThrow("Save file has invalid header");
|
errorThrow("Save file has invalid header");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t leChecksum;
|
|
||||||
errorChain(saveStreamReadBytesRawImpl(stream, &leChecksum, sizeof(uint32_t)));
|
|
||||||
stream->expectedChecksum = endianLittleToHost32(leChecksum);
|
|
||||||
stream->checksum = cryptCRC32Begin();
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveStreamWriteHeaderImpl(
|
errorret_t saveStreamWriteHeaderImpl(
|
||||||
savestream_t *stream, const char_t header[SAVE_FILE_HEADER_SIZE]
|
savestream_t *stream, const char_t header[SAVE_FILE_HEADER_SIZE]
|
||||||
) {
|
) {
|
||||||
errorChain(saveStreamWriteBytesRawImpl(
|
errorChain(saveStreamWriteBytesImpl(stream, header, SAVE_FILE_HEADER_SIZE));
|
||||||
stream, header, SAVE_FILE_HEADER_SIZE
|
|
||||||
));
|
|
||||||
|
|
||||||
uint32_t placeholder = 0;
|
|
||||||
errorChain(saveStreamWriteBytesRawImpl(
|
|
||||||
stream, &placeholder, sizeof(uint32_t)
|
|
||||||
));
|
|
||||||
stream->checksum = cryptCRC32Begin();
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,100 +67,14 @@ errorret_t saveStreamWriteVersionImpl(
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveStreamReadBoolImpl(savestream_t *stream, bool_t *out) {
|
errorret_t saveStreamReadSizeImpl(savestream_t *stream, uint32_t *out) {
|
||||||
uint8_t raw;
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint8_t)));
|
|
||||||
*out = (bool_t)(raw != 0);
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteBoolImpl(savestream_t *stream, const bool_t *input) {
|
|
||||||
uint8_t raw = *input ? 1 : 0;
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint8_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadInt8Impl(savestream_t *stream, int8_t *out) {
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, out, sizeof(int8_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteInt8Impl(savestream_t *stream, const int8_t *input) {
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, input, sizeof(int8_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadUInt8Impl(savestream_t *stream, uint8_t *out) {
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, out, sizeof(uint8_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteUInt8Impl(
|
|
||||||
savestream_t *stream, const uint8_t *input
|
|
||||||
) {
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, input, sizeof(uint8_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadInt16Impl(savestream_t *stream, int16_t *out) {
|
|
||||||
uint16_t raw;
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint16_t)));
|
|
||||||
uint16_t host = endianLittleToHost16(raw);
|
|
||||||
memoryCopy(out, &host, sizeof(int16_t));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteInt16Impl(
|
|
||||||
savestream_t *stream, const int16_t *input
|
|
||||||
) {
|
|
||||||
uint16_t raw;
|
|
||||||
memoryCopy(&raw, input, sizeof(int16_t));
|
|
||||||
raw = endianLittleToHost16(raw);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint16_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadUInt16Impl(savestream_t *stream, uint16_t *out) {
|
|
||||||
uint16_t raw;
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint16_t)));
|
|
||||||
*out = endianLittleToHost16(raw);
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteUInt16Impl(
|
|
||||||
savestream_t *stream, const uint16_t *input
|
|
||||||
) {
|
|
||||||
uint16_t raw = endianLittleToHost16(*input);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint16_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadInt32Impl(savestream_t *stream, int32_t *out) {
|
|
||||||
uint32_t raw;
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint32_t)));
|
|
||||||
uint32_t host = endianLittleToHost32(raw);
|
|
||||||
memoryCopy(out, &host, sizeof(int32_t));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteInt32Impl(
|
|
||||||
savestream_t *stream, const int32_t *input
|
|
||||||
) {
|
|
||||||
uint32_t raw;
|
|
||||||
memoryCopy(&raw, input, sizeof(int32_t));
|
|
||||||
raw = endianLittleToHost32(raw);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint32_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadUInt32Impl(savestream_t *stream, uint32_t *out) {
|
|
||||||
uint32_t raw;
|
uint32_t raw;
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint32_t)));
|
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint32_t)));
|
||||||
*out = endianLittleToHost32(raw);
|
*out = endianLittleToHost32(raw);
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveStreamWriteUInt32Impl(
|
errorret_t saveStreamWriteSizeImpl(
|
||||||
savestream_t *stream, const uint32_t *input
|
savestream_t *stream, const uint32_t *input
|
||||||
) {
|
) {
|
||||||
uint32_t raw = endianLittleToHost32(*input);
|
uint32_t raw = endianLittleToHost32(*input);
|
||||||
@@ -221,120 +82,83 @@ errorret_t saveStreamWriteUInt32Impl(
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveStreamReadInt64Impl(savestream_t *stream, int64_t *out) {
|
errorret_t saveStreamReadChecksumImpl(savestream_t *stream, uint32_t *out) {
|
||||||
uint64_t raw;
|
uint32_t raw;
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint64_t)));
|
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint32_t)));
|
||||||
uint64_t host = endianLittleToHost64(raw);
|
*out = endianLittleToHost32(raw);
|
||||||
memoryCopy(out, &host, sizeof(int64_t));
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveStreamWriteInt64Impl(
|
errorret_t saveStreamWriteChecksumImpl(
|
||||||
savestream_t *stream, const int64_t *input
|
savestream_t *stream, const uint32_t *input
|
||||||
) {
|
) {
|
||||||
uint64_t raw;
|
uint32_t raw = endianLittleToHost32(*input);
|
||||||
memoryCopy(&raw, input, sizeof(int64_t));
|
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint32_t)));
|
||||||
raw = endianLittleToHost64(raw);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint64_t)));
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t saveStreamReadUInt64Impl(savestream_t *stream, uint64_t *out) {
|
errorret_t saveFileWritePayloadImpl(
|
||||||
uint64_t raw;
|
savestream_t *stream,
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint64_t)));
|
const savefile_t *file,
|
||||||
*out = endianLittleToHost64(raw);
|
const char_t *json,
|
||||||
errorOk();
|
const size_t len
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteUInt64Impl(
|
|
||||||
savestream_t *stream, const uint64_t *input
|
|
||||||
) {
|
) {
|
||||||
uint64_t raw = endianLittleToHost64(*input);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint64_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadFloatImpl(savestream_t *stream, float_t *out) {
|
|
||||||
float_t raw;
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(float_t)));
|
|
||||||
*out = endianLittleToHostFloat(raw);
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteFloatImpl(
|
|
||||||
savestream_t *stream, const float_t *input
|
|
||||||
) {
|
|
||||||
float_t raw = endianLittleToHostFloat(*input);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(float_t)));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadStringImpl(
|
|
||||||
savestream_t *stream, char_t *out, const size_t maxLen
|
|
||||||
) {
|
|
||||||
for(size_t i = 0; i < maxLen; i++) {
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &out[i], sizeof(char_t)));
|
|
||||||
if(out[i] == '\0') errorOk();
|
|
||||||
}
|
|
||||||
out[maxLen - 1] = '\0';
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteStringImpl(
|
|
||||||
savestream_t *stream, const char_t *input, const size_t maxLen
|
|
||||||
) {
|
|
||||||
size_t len = strlen(input);
|
|
||||||
if(len >= maxLen) len = maxLen - 1;
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, input, len + 1));
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamReadDateImpl(savestream_t *stream, dusktimeepoch_t *out) {
|
|
||||||
uint64_t raw;
|
|
||||||
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint64_t)));
|
|
||||||
raw = endianLittleToHost64(raw);
|
|
||||||
memoryCopy(&out->time, &raw, sizeof(double_t));
|
|
||||||
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint64_t)));
|
|
||||||
raw = endianLittleToHost64(raw);
|
|
||||||
memoryCopy(&out->timeZone, &raw, sizeof(double_t));
|
|
||||||
|
|
||||||
errorChain(saveStreamReadBytesImpl(stream, &raw, sizeof(uint64_t)));
|
|
||||||
raw = endianLittleToHost64(raw);
|
|
||||||
memoryCopy(&out->offsetTime, &raw, sizeof(double_t));
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveStreamWriteDateImpl(
|
|
||||||
savestream_t *stream, const dusktimeepoch_t *input
|
|
||||||
) {
|
|
||||||
uint64_t raw;
|
|
||||||
|
|
||||||
memoryCopy(&raw, &input->time, sizeof(double_t));
|
|
||||||
raw = endianLittleToHost64(raw);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint64_t)));
|
|
||||||
|
|
||||||
memoryCopy(&raw, &input->timeZone, sizeof(double_t));
|
|
||||||
raw = endianLittleToHost64(raw);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint64_t)));
|
|
||||||
|
|
||||||
memoryCopy(&raw, &input->offsetTime, sizeof(double_t));
|
|
||||||
raw = endianLittleToHost64(raw);
|
|
||||||
errorChain(saveStreamWriteBytesImpl(stream, &raw, sizeof(uint64_t)));
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveFileLoad(savestream_t *stream, savefile_t *file) {
|
|
||||||
saveFileReadHeader(stream, file->header);
|
|
||||||
saveFileReadVersion(stream, &file->version);
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t saveFileWrite(savestream_t *stream, savefile_t *file) {
|
|
||||||
saveFileWriteHeader(stream, file->header);
|
saveFileWriteHeader(stream, file->header);
|
||||||
saveFileWriteVersion(stream, &file->version);
|
saveFileWriteVersion(stream, &file->version);
|
||||||
|
saveFileWriteSize(stream, &file->size);
|
||||||
|
saveFileWriteChecksum(stream, &file->checksum);
|
||||||
|
errorChain(saveStreamWriteBytesImpl(stream, json, len));
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t saveFileLoad(
|
||||||
|
savestream_t *stream, savefile_t *file, yyjson_doc **outDoc
|
||||||
|
) {
|
||||||
|
saveFileReadHeader(stream, file->header);
|
||||||
|
saveFileReadVersion(stream, &file->version);
|
||||||
|
saveFileReadSize(stream, &file->size);
|
||||||
|
saveFileReadChecksum(stream, &file->checksum);
|
||||||
|
|
||||||
|
uint8_t *buf = memoryAllocate(file->size);
|
||||||
|
errorret_t ret = saveStreamReadBytesImpl(stream, buf, file->size);
|
||||||
|
|
||||||
|
if(errorIsNotOk(ret)) {
|
||||||
|
memoryFree(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cryptCRC32(buf, file->size) != file->checksum) {
|
||||||
|
memoryFree(buf);
|
||||||
|
errorThrow("Save file has invalid checksum");
|
||||||
|
}
|
||||||
|
|
||||||
|
yyjson_doc *doc = yyjson_read((const char_t *)buf, file->size, 0);
|
||||||
|
memoryFree(buf);
|
||||||
|
|
||||||
|
if(!doc) errorThrow("Failed to parse save file JSON");
|
||||||
|
|
||||||
|
*outDoc = doc;
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t saveFileWrite(
|
||||||
|
savestream_t *stream, savefile_t *file, yyjson_mut_doc *doc
|
||||||
|
) {
|
||||||
|
size_t len = 0;
|
||||||
|
char_t *json = yyjson_mut_write(doc, 0, &len);
|
||||||
|
if(!json) errorThrow("Failed to serialize save data to JSON");
|
||||||
|
|
||||||
|
memoryCopy(file->header, SAVE_FILE_HEADER, SAVE_FILE_HEADER_SIZE);
|
||||||
|
file->version = SAVE_FILE_VERSION;
|
||||||
|
file->size = (uint32_t)len;
|
||||||
|
file->checksum = cryptCRC32(json, len);
|
||||||
|
|
||||||
|
errorret_t ret = saveFileWritePayloadImpl(stream, file, json, len);
|
||||||
|
|
||||||
|
// json comes from yyjson's own allocator (malloc), not the project
|
||||||
|
// allocator, so it must be released with free() rather than memoryFree().
|
||||||
|
free(json);
|
||||||
|
|
||||||
|
if(errorIsNotOk(ret)) return ret;
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
+69
-341
@@ -9,41 +9,17 @@
|
|||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "savefile.h"
|
#include "savefile.h"
|
||||||
#include "save/saveplatform.h"
|
#include "save/saveplatform.h"
|
||||||
#include "time/timeepoch.h"
|
#include "yyjson.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/** True if the platform found and opened an existing save file. */
|
||||||
bool_t found;
|
bool_t found;
|
||||||
uint32_t checksum;
|
/** Platform-specific stream handle (file handle, card slot, etc.). */
|
||||||
uint32_t expectedChecksum;
|
|
||||||
saveplatformstream_t platform;
|
saveplatformstream_t platform;
|
||||||
} savestream_t;
|
} savestream_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads bytes from the platform stream without updating the CRC.
|
* Reads raw bytes from the platform stream.
|
||||||
*
|
|
||||||
* @param stream Active stream.
|
|
||||||
* @param buf Destination buffer.
|
|
||||||
* @param len Number of bytes to read.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadBytesRawImpl(
|
|
||||||
savestream_t *stream, void *buf, const size_t len
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes bytes to the platform stream without updating the CRC.
|
|
||||||
*
|
|
||||||
* @param stream Active stream.
|
|
||||||
* @param buf Source buffer.
|
|
||||||
* @param len Number of bytes to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteBytesRawImpl(
|
|
||||||
savestream_t *stream, const void *buf, const size_t len
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads bytes from the platform stream and accumulates them into the CRC.
|
|
||||||
*
|
*
|
||||||
* @param stream Active stream.
|
* @param stream Active stream.
|
||||||
* @param buf Destination buffer.
|
* @param buf Destination buffer.
|
||||||
@@ -55,7 +31,7 @@ errorret_t saveStreamReadBytesImpl(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the CRC then writes bytes to the platform stream.
|
* Writes raw bytes to the platform stream.
|
||||||
*
|
*
|
||||||
* @param stream Active stream.
|
* @param stream Active stream.
|
||||||
* @param buf Source buffer.
|
* @param buf Source buffer.
|
||||||
@@ -67,29 +43,7 @@ errorret_t saveStreamWriteBytesImpl(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finalizes a write stream: computes the final CRC32, seeks to the
|
* Reads and validates the magic header from the stream.
|
||||||
* checksum field in the header, and writes it in little-endian order.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @return An error if the seek or write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamFinalizeWriteImpl(savestream_t *stream);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies that the CRC32 accumulated during loading matches the value
|
|
||||||
* stored in the file header.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream (loading must be complete).
|
|
||||||
* @param slot Slot index used in the error message on mismatch.
|
|
||||||
* @return An error if the checksum does not match.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamVerifyChecksumImpl(
|
|
||||||
savestream_t *stream, const uint8_t slot
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and validates the magic header, then reads the stored CRC32 and
|
|
||||||
* resets the running accumulator.
|
|
||||||
*
|
*
|
||||||
* @param stream Active read stream.
|
* @param stream Active read stream.
|
||||||
* @param header Buffer of SAVE_FILE_HEADER_SIZE bytes to receive the header.
|
* @param header Buffer of SAVE_FILE_HEADER_SIZE bytes to receive the header.
|
||||||
@@ -100,8 +54,7 @@ errorret_t saveStreamReadHeaderImpl(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the magic header and a zero CRC32 placeholder, then resets the
|
* Writes the magic header to the stream.
|
||||||
* running accumulator.
|
|
||||||
*
|
*
|
||||||
* @param stream Active write stream.
|
* @param stream Active write stream.
|
||||||
* @param header Buffer of SAVE_FILE_HEADER_SIZE bytes to write.
|
* @param header Buffer of SAVE_FILE_HEADER_SIZE bytes to write.
|
||||||
@@ -133,268 +86,94 @@ errorret_t saveStreamWriteVersionImpl(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a single byte as a boolean (0 = false, non-zero = true).
|
* Reads a little-endian uint32 JSON payload size field from the stream.
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Receives the boolean value.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadBoolImpl(savestream_t *stream, bool_t *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a boolean as a single byte (true = 1, false = 0).
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteBoolImpl(savestream_t *stream, const bool_t *input);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a signed 8-bit integer from the stream.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Receives the value.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadInt8Impl(savestream_t *stream, int8_t *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a signed 8-bit integer to the stream.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteInt8Impl(savestream_t *stream, const int8_t *input);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads an unsigned 8-bit integer from the stream.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Receives the value.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadUInt8Impl(savestream_t *stream, uint8_t *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an unsigned 8-bit integer to the stream.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteUInt8Impl(savestream_t *stream, const uint8_t *input);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a little-endian signed 16-bit integer from the stream.
|
|
||||||
*
|
*
|
||||||
* @param stream Active read stream.
|
* @param stream Active read stream.
|
||||||
* @param out Receives the host-order value.
|
* @param out Receives the host-order value.
|
||||||
* @return An error if the read fails.
|
* @return An error if the read fails.
|
||||||
*/
|
*/
|
||||||
errorret_t saveStreamReadInt16Impl(savestream_t *stream, int16_t *out);
|
errorret_t saveStreamReadSizeImpl(savestream_t *stream, uint32_t *out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a signed 16-bit integer to the stream in little-endian order.
|
* Writes a uint32 JSON payload size field to the stream in little-endian
|
||||||
|
* order.
|
||||||
*
|
*
|
||||||
* @param stream Active write stream.
|
* @param stream Active write stream.
|
||||||
* @param input Value to write.
|
* @param input Value to write.
|
||||||
* @return An error if the write fails.
|
* @return An error if the write fails.
|
||||||
*/
|
*/
|
||||||
errorret_t saveStreamWriteInt16Impl(
|
errorret_t saveStreamWriteSizeImpl(
|
||||||
savestream_t *stream, const int16_t *input
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a little-endian unsigned 16-bit integer from the stream.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Receives the host-order value.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadUInt16Impl(savestream_t *stream, uint16_t *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an unsigned 16-bit integer to the stream in little-endian order.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteUInt16Impl(
|
|
||||||
savestream_t *stream, const uint16_t *input
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a little-endian signed 32-bit integer from the stream.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Receives the host-order value.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadInt32Impl(savestream_t *stream, int32_t *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a signed 32-bit integer to the stream in little-endian order.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteInt32Impl(
|
|
||||||
savestream_t *stream, const int32_t *input
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a little-endian unsigned 32-bit integer from the stream.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Receives the host-order value.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadUInt32Impl(savestream_t *stream, uint32_t *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an unsigned 32-bit integer to the stream in little-endian order.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteUInt32Impl(
|
|
||||||
savestream_t *stream, const uint32_t *input
|
savestream_t *stream, const uint32_t *input
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a little-endian signed 64-bit integer from the stream.
|
* Reads a little-endian uint32 CRC32 checksum field from the stream.
|
||||||
*
|
*
|
||||||
* @param stream Active read stream.
|
* @param stream Active read stream.
|
||||||
* @param out Receives the host-order value.
|
* @param out Receives the host-order value.
|
||||||
* @return An error if the read fails.
|
* @return An error if the read fails.
|
||||||
*/
|
*/
|
||||||
errorret_t saveStreamReadInt64Impl(savestream_t *stream, int64_t *out);
|
errorret_t saveStreamReadChecksumImpl(savestream_t *stream, uint32_t *out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a signed 64-bit integer to the stream in little-endian order.
|
* Writes a uint32 CRC32 checksum field to the stream in little-endian
|
||||||
|
* order.
|
||||||
*
|
*
|
||||||
* @param stream Active write stream.
|
* @param stream Active write stream.
|
||||||
* @param input Value to write.
|
* @param input Value to write.
|
||||||
* @return An error if the write fails.
|
* @return An error if the write fails.
|
||||||
*/
|
*/
|
||||||
errorret_t saveStreamWriteInt64Impl(
|
errorret_t saveStreamWriteChecksumImpl(
|
||||||
savestream_t *stream, const int64_t *input
|
savestream_t *stream, const uint32_t *input
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a little-endian unsigned 64-bit integer from the stream.
|
* Writes the header, version, size and checksum fields already populated
|
||||||
*
|
* on file, followed by the raw JSON payload bytes. Split out of
|
||||||
* @param stream Active read stream.
|
* saveFileWrite so the caller can free its serialized JSON buffer exactly
|
||||||
* @param out Receives the host-order value.
|
* once regardless of which step fails.
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadUInt64Impl(savestream_t *stream, uint64_t *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an unsigned 64-bit integer to the stream in little-endian order.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteUInt64Impl(
|
|
||||||
savestream_t *stream, const uint64_t *input
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a little-endian float from the stream.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Receives the host-order value.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadFloatImpl(savestream_t *stream, float_t *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a float to the stream in little-endian order.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteFloatImpl(
|
|
||||||
savestream_t *stream, const float_t *input
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a null-terminated string from the stream up to maxLen bytes
|
|
||||||
* (including the terminator). Always null-terminates the output buffer.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Destination buffer of at least maxLen bytes.
|
|
||||||
* @param maxLen Maximum bytes to read, including the null terminator.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadStringImpl(
|
|
||||||
savestream_t *stream, char_t *out, const size_t maxLen
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a null-terminated string to the stream, truncating to maxLen-1
|
|
||||||
* characters and always appending a null terminator.
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Source string.
|
|
||||||
* @param maxLen Maximum bytes to write, including the null terminator.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteStringImpl(
|
|
||||||
savestream_t *stream, const char_t *input, const size_t maxLen
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a dusktimeepoch_t as three little-endian 64-bit IEEE 754 doubles
|
|
||||||
* (time, timeZone, offsetTime).
|
|
||||||
*
|
|
||||||
* @param stream Active read stream.
|
|
||||||
* @param out Receives the epoch value.
|
|
||||||
* @return An error if the read fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamReadDateImpl(
|
|
||||||
savestream_t *stream, dusktimeepoch_t *out
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a dusktimeepoch_t as three little-endian 64-bit IEEE 754 doubles
|
|
||||||
* (time, timeZone, offsetTime).
|
|
||||||
*
|
|
||||||
* @param stream Active write stream.
|
|
||||||
* @param input Epoch value to write.
|
|
||||||
* @return An error if the write fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveStreamWriteDateImpl(
|
|
||||||
savestream_t *stream, const dusktimeepoch_t *input
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the contents of a save slot from the stream into the save file
|
|
||||||
* struct. Use saveFileRead* macros to deserialize fields one at a time.
|
|
||||||
*
|
|
||||||
* @param stream Active read stream for this slot.
|
|
||||||
* @param file Save file struct to populate.
|
|
||||||
* @return An error code if loading fails.
|
|
||||||
*/
|
|
||||||
errorret_t saveFileLoad(savestream_t *stream, savefile_t *file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the contents of the save file struct into the stream.
|
|
||||||
* Use saveFileWrite* macros to serialize fields one at a time.
|
|
||||||
*
|
*
|
||||||
* @param stream Active write stream for this slot.
|
* @param stream Active write stream for this slot.
|
||||||
* @param file Save file struct to serialize.
|
* @param file Save file metadata with header/version/size/checksum set.
|
||||||
* @return An error code if writing fails.
|
* @param json Serialized JSON payload bytes.
|
||||||
|
* @param len Byte length of json.
|
||||||
|
* @return An error code if any write fails.
|
||||||
*/
|
*/
|
||||||
errorret_t saveFileWrite(savestream_t *stream, savefile_t *file);
|
errorret_t saveFileWritePayloadImpl(
|
||||||
|
savestream_t *stream,
|
||||||
|
const savefile_t *file,
|
||||||
|
const char_t *json,
|
||||||
|
const size_t len
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a save slot's header, version and JSON payload from the stream,
|
||||||
|
* validating the payload against its stored size and CRC32 checksum. The
|
||||||
|
* JSON is parsed fresh into a new document each call; no payload bytes are
|
||||||
|
* kept resident beyond this call.
|
||||||
|
*
|
||||||
|
* @param stream Active read stream for this slot.
|
||||||
|
* @param file Save file metadata struct to populate.
|
||||||
|
* @param outDoc Receives the parsed JSON document, owned by the caller.
|
||||||
|
* @return An error code if loading, validation or parsing fails.
|
||||||
|
*/
|
||||||
|
errorret_t saveFileLoad(
|
||||||
|
savestream_t *stream, savefile_t *file, yyjson_doc **outDoc
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the given JSON document and writes the header, version,
|
||||||
|
* size, checksum and payload to the stream. The serialized bytes are not
|
||||||
|
* kept resident beyond this call.
|
||||||
|
*
|
||||||
|
* @param stream Active write stream for this slot.
|
||||||
|
* @param file Save file metadata struct to populate and serialize.
|
||||||
|
* @param doc The JSON document to serialize and write.
|
||||||
|
* @return An error code if serialization or writing fails.
|
||||||
|
*/
|
||||||
|
errorret_t saveFileWrite(
|
||||||
|
savestream_t *stream, savefile_t *file, yyjson_mut_doc *doc
|
||||||
|
);
|
||||||
|
|
||||||
#define saveFileReadHeader(stream, header) \
|
#define saveFileReadHeader(stream, header) \
|
||||||
errorChain(saveStreamReadHeaderImpl(stream, header))
|
errorChain(saveStreamReadHeaderImpl(stream, header))
|
||||||
@@ -406,63 +185,12 @@ errorret_t saveFileWrite(savestream_t *stream, savefile_t *file);
|
|||||||
#define saveFileWriteVersion(stream, input) \
|
#define saveFileWriteVersion(stream, input) \
|
||||||
errorChain(saveStreamWriteVersionImpl(stream, input))
|
errorChain(saveStreamWriteVersionImpl(stream, input))
|
||||||
|
|
||||||
#define saveFileReadBool(stream, out) \
|
#define saveFileReadSize(stream, out) \
|
||||||
errorChain(saveStreamReadBoolImpl(stream, out))
|
errorChain(saveStreamReadSizeImpl(stream, out))
|
||||||
#define saveFileWriteBool(stream, input) \
|
#define saveFileWriteSize(stream, input) \
|
||||||
errorChain(saveStreamWriteBoolImpl(stream, input))
|
errorChain(saveStreamWriteSizeImpl(stream, input))
|
||||||
|
|
||||||
#define saveFileReadInt8(stream, out) \
|
|
||||||
errorChain(saveStreamReadInt8Impl(stream, out))
|
|
||||||
#define saveFileWriteInt8(stream, input) \
|
|
||||||
errorChain(saveStreamWriteInt8Impl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadUInt8(stream, out) \
|
|
||||||
errorChain(saveStreamReadUInt8Impl(stream, out))
|
|
||||||
#define saveFileWriteUInt8(stream, input) \
|
|
||||||
errorChain(saveStreamWriteUInt8Impl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadInt16(stream, out) \
|
|
||||||
errorChain(saveStreamReadInt16Impl(stream, out))
|
|
||||||
#define saveFileWriteInt16(stream, input) \
|
|
||||||
errorChain(saveStreamWriteInt16Impl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadUInt16(stream, out) \
|
|
||||||
errorChain(saveStreamReadUInt16Impl(stream, out))
|
|
||||||
#define saveFileWriteUInt16(stream, input) \
|
|
||||||
errorChain(saveStreamWriteUInt16Impl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadInt32(stream, out) \
|
|
||||||
errorChain(saveStreamReadInt32Impl(stream, out))
|
|
||||||
#define saveFileWriteInt32(stream, input) \
|
|
||||||
errorChain(saveStreamWriteInt32Impl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadUInt32(stream, out) \
|
|
||||||
errorChain(saveStreamReadUInt32Impl(stream, out))
|
|
||||||
#define saveFileWriteUInt32(stream, input) \
|
|
||||||
errorChain(saveStreamWriteUInt32Impl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadInt64(stream, out) \
|
|
||||||
errorChain(saveStreamReadInt64Impl(stream, out))
|
|
||||||
#define saveFileWriteInt64(stream, input) \
|
|
||||||
errorChain(saveStreamWriteInt64Impl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadUInt64(stream, out) \
|
|
||||||
errorChain(saveStreamReadUInt64Impl(stream, out))
|
|
||||||
#define saveFileWriteUInt64(stream, input) \
|
|
||||||
errorChain(saveStreamWriteUInt64Impl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadFloat(stream, out) \
|
|
||||||
errorChain(saveStreamReadFloatImpl(stream, out))
|
|
||||||
#define saveFileWriteFloat(stream, input) \
|
|
||||||
errorChain(saveStreamWriteFloatImpl(stream, input))
|
|
||||||
|
|
||||||
#define saveFileReadString(stream, out, maxLen) \
|
|
||||||
errorChain(saveStreamReadStringImpl(stream, out, maxLen))
|
|
||||||
#define saveFileWriteString(stream, input, maxLen) \
|
|
||||||
errorChain(saveStreamWriteStringImpl(stream, input, maxLen))
|
|
||||||
|
|
||||||
#define saveFileReadDate(stream, out) \
|
|
||||||
errorChain(saveStreamReadDateImpl(stream, out))
|
|
||||||
#define saveFileWriteDate(stream, input) \
|
|
||||||
errorChain(saveStreamWriteDateImpl(stream, input))
|
|
||||||
|
|
||||||
|
#define saveFileReadChecksum(stream, out) \
|
||||||
|
errorChain(saveStreamReadChecksumImpl(stream, out))
|
||||||
|
#define saveFileWriteChecksum(stream, input) \
|
||||||
|
errorChain(saveStreamWriteChecksumImpl(stream, input))
|
||||||
|
|||||||
Reference in New Issue
Block a user