Files
djhackersdev_bemanitools/src/main/core/property-mxml.c
T
icex2 e3c97801ed feat: Property (node) API impl with mxml
To provide a unified backend for all games, no
matter if they have AVS 2 available or now, use the
property (node) abstraction for any means of
configuration. This is somewhat annoying and a pain
because the property API isn't amazing. However,
the past has shown that having different means of
providing and handling (structured) configuration
data isn't great either.

Thus, have a non AVS implementation that allows
AVS independent applications/old games to use
the same core bemanitools API.
Summary:

Test Plan:
Summary:

Test Plan:
2024-08-15 11:34:33 +02:00

241 lines
6.6 KiB
C

#define LOG_MODULE "core-property-mxml"
#include <windows.h>
#include <errno.h>
#include <stdio.h>
#include <mxml/mxml.h>
#include "core/property-mxml-internal.h"
#include "core/property-node-mxml.h"
#include "core/property-mxml.h"
#include "iface-core/log.h"
#include "util/fs.h"
#include "util/mem.h"
static core_property_result_t
_core_property_mxml_create(size_t size, core_property_t **property_)
{
mxml_node_t *node;
core_property_mxml_internal_property_t *property;
// There is no need to use the size parameter here as everything's allocated
// dynamically on the heap and no initial fixed size is needed
node = mxmlNewXML(NULL);
if (!node) {
return CORE_PROPERTY_RESULT_ERROR_ALLOC;
}
property = xmalloc(sizeof(core_property_mxml_internal_property_t));
property->document = node;
*property_ = (core_property_t *) property;
return CORE_PROPERTY_RESULT_SUCCESS;
}
static core_property_result_t
_core_property_mxml_file_load(const char *path, core_property_t **property_)
{
mxml_node_t *node;
core_property_mxml_internal_property_t *property;
// The return value NULL of the loading function
// doesn't distinguish file not found and loading error =|
if (!path_exists(path)) {
return CORE_PROPERTY_RESULT_NOT_FOUND;
}
node = mxmlLoadFilename(NULL, NULL, path);
if (!node) {
return CORE_PROPERTY_RESULT_ERROR_READ;
}
property = xmalloc(sizeof(core_property_mxml_internal_property_t));
property->document = node;
*property_ = (core_property_t *) property;
return CORE_PROPERTY_RESULT_SUCCESS;
}
static core_property_result_t
_core_property_mxml_str_load(const char *str, core_property_t **property_)
{
mxml_node_t *node;
core_property_mxml_internal_property_t *property;
node = mxmlLoadString(NULL, NULL, str);
if (!node) {
return CORE_PROPERTY_RESULT_ERROR_READ;
}
property = xmalloc(sizeof(core_property_mxml_internal_property_t));
property->document = node;
*property_ = (core_property_t *) property;
return CORE_PROPERTY_RESULT_SUCCESS;
}
static core_property_result_t
_core_property_mxml_size(const core_property_t *property_, size_t *size)
{
*size = CORE_PROPERTY_MXML_INTERNAL_FIXED_SIZE_DUMMY;
return CORE_PROPERTY_RESULT_SUCCESS;
}
static core_property_result_t _core_property_mxml_clone(
const core_property_t *property_, core_property_t **property_cloned_)
{
const core_property_mxml_internal_property_t *property;
core_property_mxml_internal_property_t **property_cloned;
char *str_copy;
mxml_node_t *node_cloned;
property = (const core_property_mxml_internal_property_t*) property_;
property_cloned = (core_property_mxml_internal_property_t**) property_cloned_;
// Ensure actual cloning by storing and loading this
// Just "adding it" to the other tree with mxml creates a reference only
str_copy = mxmlSaveAllocString(property->document, NULL);
if (str_copy == NULL) {
return CORE_PROPERTY_RESULT_ERROR_READ;
}
node_cloned = mxmlLoadString(NULL, NULL, str_copy);
if (node_cloned == NULL) {
return CORE_PROPERTY_RESULT_ERROR_WRITE;
}
*property_cloned = xmalloc(sizeof(core_property_mxml_internal_property_t));
(*property_cloned)->document = node_cloned;
return CORE_PROPERTY_RESULT_SUCCESS;
}
static core_property_result_t _core_property_mxml_root_node_get(
const core_property_t *property_, core_property_node_t *node_)
{
core_property_mxml_internal_property_t *property;
core_property_mxml_internal_property_node_t *node;
mxml_node_t *mxml_node;
mxml_type_t type;
property = (core_property_mxml_internal_property_t *) property_;
node = (core_property_mxml_internal_property_node_t *) node_;
memset(node, 0, sizeof(core_property_mxml_internal_property_node_t));
// Walk the nodes as the loaded xml node is the document root
// which can be the xml directive, or if missing, the first root
// element
for (mxml_node = property->document;
mxml_node != NULL;
mxml_node = mxmlWalkNext(mxml_node, property->document, MXML_DESCEND_FIRST))
{
type = mxmlGetType(mxml_node);
// Consider the first element to be found the root element of the
// document. Having multiple roots isn't a valid XML document
// anyway
if (type == MXML_TYPE_ELEMENT) {
break;
}
}
if (mxml_node == NULL) {
return CORE_PROPERTY_RESULT_NOT_FOUND;
}
node->property = property;
// No difference for property vs. property_node
node->node = mxml_node;
return CORE_PROPERTY_RESULT_SUCCESS;
}
static core_property_result_t _core_property_mxml_other_node_insert(
core_property_t *property_, const core_property_node_t *node_)
{
core_property_mxml_internal_property_t *property;
core_property_mxml_internal_property_node_t *node;
char *str_copy;
mxml_node_t *node_cloned;
property = (core_property_mxml_internal_property_t *) property_;
node = (core_property_mxml_internal_property_node_t *) node_;
// Ensure actual cloning by storing and loading this
// Just "adding it" to the other tree with mxml creates a reference only
str_copy = mxmlSaveAllocString(node->node, NULL);
if (str_copy == NULL) {
return CORE_PROPERTY_RESULT_ERROR_READ;
}
node_cloned = mxmlLoadString(NULL, NULL, str_copy);
if (node_cloned == NULL) {
return CORE_PROPERTY_RESULT_ERROR_WRITE;
}
// Hook the new node into the existing tree
mxmlAdd(property->document, MXML_ADD_AFTER, NULL, node_cloned);
return CORE_PROPERTY_NODE_RESULT_SUCCESS;
}
static void _core_property_mxml_free(core_property_t **property_)
{
core_property_mxml_internal_property_t *property;
property = (core_property_mxml_internal_property_t *) (*property_);
mxmlDelete(property->document);
free(*property_);
*property_ = NULL;
}
static void _core_property_mxml_core_api_get(core_property_api_t *api)
{
log_assert(api);
api->version = 1;
api->v1.create = _core_property_mxml_create;
api->v1.file_load = _core_property_mxml_file_load;
api->v1.str_load = _core_property_mxml_str_load;
api->v1.size = _core_property_mxml_size;
api->v1.clone = _core_property_mxml_clone;
api->v1.root_node_get = _core_property_mxml_root_node_get;
api->v1.other_node_insert = _core_property_mxml_other_node_insert;
api->v1.free = _core_property_mxml_free;
}
void core_property_mxml_core_api_set()
{
core_property_api_t api;
_core_property_mxml_core_api_get(&api);
core_property_api_set(&api);
}