2021-09-24 19:57:15 +02:00
|
|
|
#include <cstdlib>
|
2022-02-03 16:24:36 +01:00
|
|
|
#include <cstring>
|
|
|
|
#include <wups.h>
|
2021-09-24 19:57:15 +02:00
|
|
|
|
|
|
|
#include "utils/base64.h"
|
|
|
|
|
2022-02-03 16:24:36 +01:00
|
|
|
static OpenStorageFunction openfunction_ptr __attribute__((section(".data"))) = nullptr;
|
2021-09-24 19:57:15 +02:00
|
|
|
static CloseStorageFunction closefunction_ptr __attribute__((section(".data"))) = nullptr;
|
2022-02-03 16:24:36 +01:00
|
|
|
static const char *plugin_id __attribute__((section(".data"))) = nullptr;
|
2021-09-24 19:57:15 +02:00
|
|
|
|
|
|
|
static uint32_t storage_initialized __attribute__((section(".data"))) = false;
|
|
|
|
static uint32_t isOpened __attribute__((section(".data")));
|
|
|
|
static uint32_t isDirty __attribute__((section(".data")));
|
|
|
|
static wups_storage_item_t rootItem __attribute__((section(".data")));
|
|
|
|
|
|
|
|
void WUPS_InitStorage(wups_loader_init_storage_args_t args) {
|
2022-02-03 16:24:36 +01:00
|
|
|
openfunction_ptr = args.open_storage_ptr;
|
2021-09-24 19:57:15 +02:00
|
|
|
closefunction_ptr = args.close_storage_ptr;
|
2022-02-03 16:24:36 +01:00
|
|
|
plugin_id = args.plugin_id;
|
2021-09-24 19:57:15 +02:00
|
|
|
|
|
|
|
storage_initialized = true;
|
2022-02-03 16:24:36 +01:00
|
|
|
isOpened = false;
|
|
|
|
isDirty = false;
|
2021-09-24 19:57:15 +02:00
|
|
|
|
2022-02-03 16:24:36 +01:00
|
|
|
rootItem.key = nullptr;
|
|
|
|
rootItem.data = nullptr;
|
|
|
|
rootItem.data_size = 0;
|
2021-09-24 19:57:15 +02:00
|
|
|
rootItem.pending_delete = false;
|
2022-02-03 16:24:36 +01:00
|
|
|
rootItem.type = WUPS_STORAGE_TYPE_ITEM;
|
2021-09-24 19:57:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_OpenStorage(void) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_ALREADY_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t result = openfunction_ptr(plugin_id, &rootItem);
|
|
|
|
|
|
|
|
if (result == WUPS_STORAGE_ERROR_SUCCESS || result == WUPS_STORAGE_ERROR_INVALID_JSON) {
|
|
|
|
isOpened = true;
|
2022-02-03 16:24:36 +01:00
|
|
|
isDirty = false;
|
2021-09-24 19:57:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void closeItem(wups_storage_item_t *item) {
|
|
|
|
if (!item) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto *items = (wups_storage_item_t *) item->data;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < item->data_size; i++) {
|
|
|
|
if (items[i].type == WUPS_STORAGE_TYPE_ITEM) {
|
|
|
|
closeItem(&items[i]);
|
|
|
|
}
|
|
|
|
free(items[i].data);
|
|
|
|
free(items[i].key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_CloseStorage(void) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t result = 0;
|
|
|
|
if (isDirty) {
|
|
|
|
result = closefunction_ptr(plugin_id, &rootItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
isOpened = false;
|
2022-02-03 16:24:36 +01:00
|
|
|
isDirty = false;
|
2021-09-24 19:57:15 +02:00
|
|
|
|
|
|
|
closeItem(&rootItem);
|
|
|
|
free(rootItem.data);
|
|
|
|
rootItem.data_size = 0;
|
2022-02-03 16:24:36 +01:00
|
|
|
rootItem.data = nullptr;
|
2021-09-24 19:57:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_DeleteItem(wups_storage_item_t *parent, const char *key) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
isDirty = true;
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < parent->data_size; i++) {
|
|
|
|
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
|
|
|
|
|
|
|
|
if (item->pending_delete || item->type == WUPS_STORAGE_TYPE_INVALID) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(item->key, key) == 0) {
|
|
|
|
item->pending_delete = true;
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
// int32_t WUPS_GetSize(const char* key) {
|
|
|
|
// if (!storage_initialized) {
|
|
|
|
// return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if (!isOpened) {
|
|
|
|
// return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// for (uint32_t i = 0; i < amount_of_items; i++) {
|
|
|
|
// wups_loader_storage_item_t* item = &items[i];
|
|
|
|
|
|
|
|
// if (item->pending_delete || item->type == WUPS_STORAGE_TYPE_INVALID) {
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if (strcmp(item->key, key) == 0) {
|
|
|
|
// return item->data_size;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// return WUPS_STORAGE_ERROR_NOT_FOUND;
|
|
|
|
// }
|
|
|
|
|
|
|
|
static wups_storage_item_t *addItem(wups_storage_item_t *parent, const char *key, wups_storage_type_t type) {
|
|
|
|
wups_storage_item_t *foundItem = nullptr;
|
|
|
|
for (uint32_t i = 0; i < parent->data_size; i++) {
|
|
|
|
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
|
|
|
|
|
|
|
|
if (strcmp(item->key, key) == 0) {
|
|
|
|
free(item->data);
|
|
|
|
foundItem = item;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item->pending_delete) {
|
|
|
|
free(item->data);
|
|
|
|
free(item->key);
|
|
|
|
|
|
|
|
item->key = (char *) malloc(strlen(key) + 1);
|
|
|
|
strcpy(item->key, key);
|
|
|
|
|
|
|
|
foundItem = item;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foundItem) {
|
|
|
|
parent->data_size++;
|
|
|
|
parent->data = (wups_storage_item_t *) realloc(parent->data, parent->data_size * sizeof(wups_storage_item_t));
|
|
|
|
|
|
|
|
foundItem = &((wups_storage_item_t *) parent->data)[parent->data_size - 1];
|
|
|
|
|
|
|
|
foundItem->key = (char *) malloc(strlen(key) + 1);
|
|
|
|
strcpy(foundItem->key, key);
|
|
|
|
}
|
|
|
|
|
2022-02-03 16:24:36 +01:00
|
|
|
foundItem->type = type;
|
2021-09-24 19:57:15 +02:00
|
|
|
foundItem->pending_delete = false;
|
2022-02-03 16:24:36 +01:00
|
|
|
foundItem->data = nullptr;
|
|
|
|
foundItem->data_size = 0;
|
2021-09-24 19:57:15 +02:00
|
|
|
return foundItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_CreateSubItem(wups_storage_item_t *parent, const char *key, wups_storage_item_t **outItem) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key || !outItem) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
isDirty = true;
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
wups_storage_item_t *item = addItem(parent, key, WUPS_STORAGE_TYPE_ITEM);
|
|
|
|
|
|
|
|
*outItem = item;
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_GetSubItem(wups_storage_item_t *parent, const char *key, wups_storage_item_t **outItem) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key || outItem == nullptr) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < parent->data_size; i++) {
|
|
|
|
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
|
|
|
|
|
|
|
|
if (item->pending_delete || item->type != WUPS_STORAGE_TYPE_ITEM) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(item->key, key) == 0) {
|
|
|
|
*outItem = item;
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_StoreString(wups_storage_item_t *parent, const char *key, const char *string) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key || !string) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
isDirty = true;
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
wups_storage_item_t *item = addItem(parent, key, WUPS_STORAGE_TYPE_STRING);
|
|
|
|
|
2022-02-03 16:24:36 +01:00
|
|
|
uint32_t size = strlen(string) + 1;
|
|
|
|
item->data = malloc(size);
|
2021-09-24 19:57:15 +02:00
|
|
|
item->data_size = size;
|
|
|
|
strcpy((char *) item->data, string);
|
|
|
|
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_StoreBool(wups_storage_item_t *parent, const char *key, bool value) {
|
|
|
|
return WUPS_StoreInt(parent, key, (int32_t) value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_StoreInt(wups_storage_item_t *parent, const char *key, int32_t value) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
isDirty = true;
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
wups_storage_item_t *item = addItem(parent, key, WUPS_STORAGE_TYPE_INT);
|
|
|
|
|
2022-02-03 16:24:36 +01:00
|
|
|
item->data = malloc(sizeof(int32_t));
|
|
|
|
item->data_size = sizeof(int32_t);
|
2021-09-24 19:57:15 +02:00
|
|
|
*(int32_t *) item->data = value;
|
|
|
|
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_StoreBinary(wups_storage_item_t *parent, const char *key, const void *data, uint32_t size) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key || !data || size == 0) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
wups_storage_item_t *item = addItem(parent, key, WUPS_STORAGE_TYPE_STRING);
|
|
|
|
|
2022-02-03 16:24:36 +01:00
|
|
|
item->data = b64_encode((const uint8_t *) data, size);
|
2021-09-24 19:57:15 +02:00
|
|
|
item->data_size = strlen((char *) data) + 1;
|
|
|
|
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_GetString(wups_storage_item_t *parent, const char *key, char *outString, uint32_t maxSize) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key || !outString || maxSize == 0) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < parent->data_size; i++) {
|
|
|
|
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
|
|
|
|
|
|
|
|
if (item->pending_delete || item->type != WUPS_STORAGE_TYPE_STRING) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(item->key, key) == 0) {
|
|
|
|
strncpy(outString, (char *) item->data, maxSize);
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_GetBool(wups_storage_item_t *parent, const char *key, bool *outBool) {
|
|
|
|
int32_t out;
|
|
|
|
int32_t result = WUPS_GetInt(parent, key, &out);
|
|
|
|
if (result != WUPS_STORAGE_ERROR_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
*outBool = out != 0;
|
|
|
|
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_GetInt(wups_storage_item_t *parent, const char *key, int32_t *outInt) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key || !outInt) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < parent->data_size; i++) {
|
|
|
|
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
|
|
|
|
|
|
|
|
if (item->pending_delete || item->type != WUPS_STORAGE_TYPE_INT) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(item->key, key) == 0) {
|
|
|
|
*outInt = *(int32_t *) item->data;
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WUPS_GetBinary(wups_storage_item_t *parent, const char *key, void *outData, uint32_t maxSize) {
|
|
|
|
if (!storage_initialized) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpened) {
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key || !outData || maxSize == 0) {
|
|
|
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
parent = &rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < parent->data_size; i++) {
|
|
|
|
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
|
|
|
|
|
|
|
|
if (item->pending_delete || item->type != WUPS_STORAGE_TYPE_STRING) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(item->key, key) == 0) {
|
|
|
|
if (b64_decoded_size((char *) item->data) > maxSize) {
|
|
|
|
return WUPS_STORAGE_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b64_decode((char *) item->data, (uint8_t *) outData, item->data_size)) {
|
|
|
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
return WUPS_STORAGE_ERROR_B64_DECODE_FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
|
|
|
}
|