|
Packit Service |
a3c5fa |
/*
|
|
Packit Service |
a3c5fa |
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* SPDX-License-Identifier: LGPL-2.1+
|
|
Packit Service |
a3c5fa |
*/
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
#define G_LOG_DOMAIN "XbSilo"
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
#include "config.h"
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
#include <gio/gio.h>
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
#include "xb-node-private.h"
|
|
Packit Service |
a3c5fa |
#include "xb-silo-export-private.h"
|
|
Packit Service |
a3c5fa |
#include "xb-silo-private.h"
|
|
Packit Service |
a3c5fa |
#include "xb-string-private.h"
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
typedef struct {
|
|
Packit Service |
a3c5fa |
GString *xml;
|
|
Packit Service |
a3c5fa |
XbNodeExportFlags flags;
|
|
Packit Service |
a3c5fa |
guint32 off;
|
|
Packit Service |
a3c5fa |
guint level;
|
|
Packit Service |
a3c5fa |
} XbSiloExportHelper;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
static gboolean
|
|
Packit Service |
a3c5fa |
xb_silo_export_node (XbSilo *self, XbSiloExportHelper *helper, XbSiloNode *sn, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
XbSiloNode *sn2;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
helper->off = xb_silo_get_offset_for_node (self, sn);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* add start of opening tag */
|
|
Packit Service |
a3c5fa |
if (helper->flags & XB_NODE_EXPORT_FLAG_FORMAT_INDENT) {
|
|
Packit Service |
a3c5fa |
for (guint i = 0; i < helper->level; i++)
|
|
Packit Service |
a3c5fa |
g_string_append (helper->xml, " ");
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
g_string_append_printf (helper->xml, "<%s",
|
|
Packit Service |
a3c5fa |
xb_silo_from_strtab (self, sn->element_name));
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* add any attributes */
|
|
Packit Service |
a3c5fa |
for (guint8 i = 0; i < sn->nr_attrs; i++) {
|
|
Packit Service |
a3c5fa |
XbSiloAttr *a = xb_silo_get_attr (self, helper->off, i);
|
|
Packit Service |
a3c5fa |
g_autofree gchar *key = xb_string_xml_escape (xb_silo_from_strtab (self, a->attr_name));
|
|
Packit Service |
a3c5fa |
g_autofree gchar *val = xb_string_xml_escape (xb_silo_from_strtab (self, a->attr_value));
|
|
Packit Service |
a3c5fa |
g_string_append_printf (helper->xml, " %s=\"%s\"", key, val);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* finish the opening tag and add any text if it exists */
|
|
Packit Service |
a3c5fa |
if (sn->text != XB_SILO_UNSET) {
|
|
Packit Service |
a3c5fa |
g_autofree gchar *text = xb_string_xml_escape (xb_silo_from_strtab (self, sn->text));
|
|
Packit Service |
a3c5fa |
g_string_append (helper->xml, ">");
|
|
Packit Service |
a3c5fa |
g_string_append (helper->xml, text);
|
|
Packit Service |
a3c5fa |
} else {
|
|
Packit Service |
a3c5fa |
g_string_append (helper->xml, ">");
|
|
Packit Service |
a3c5fa |
if (helper->flags & XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE)
|
|
Packit Service |
a3c5fa |
g_string_append (helper->xml, "\n");
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
helper->off += xb_silo_node_get_size (sn);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* recurse deeper */
|
|
Packit Service |
a3c5fa |
while (xb_silo_get_node(self, helper->off)->is_node) {
|
|
Packit Service |
a3c5fa |
XbSiloNode *child = xb_silo_get_node (self, helper->off);
|
|
Packit Service |
a3c5fa |
helper->level++;
|
|
Packit Service |
a3c5fa |
if (!xb_silo_export_node (self, helper, child, error))
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
helper->level--;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* check for the single byte sentinel */
|
|
Packit Service |
a3c5fa |
sn2 = xb_silo_get_node (self, helper->off);
|
|
Packit Service |
a3c5fa |
if (sn2->is_node) {
|
|
Packit Service |
a3c5fa |
g_set_error (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_INVALID_DATA,
|
|
Packit Service |
a3c5fa |
"no seninel at %" G_GUINT32_FORMAT,
|
|
Packit Service |
a3c5fa |
helper->off);
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
helper->off += xb_silo_node_get_size (sn2);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* add closing tag */
|
|
Packit Service |
a3c5fa |
if ((helper->flags & XB_NODE_EXPORT_FLAG_FORMAT_INDENT) > 0 &&
|
|
Packit Service |
a3c5fa |
sn->text == XB_SILO_UNSET) {
|
|
Packit Service |
a3c5fa |
for (guint i = 0; i < helper->level; i++)
|
|
Packit Service |
a3c5fa |
g_string_append (helper->xml, " ");
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
g_string_append_printf (helper->xml, "</%s>",
|
|
Packit Service |
a3c5fa |
xb_silo_from_strtab (self, sn->element_name));
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* add any optional tail */
|
|
Packit Service |
a3c5fa |
if (sn->tail != XB_SILO_UNSET) {
|
|
Packit Service |
a3c5fa |
g_autofree gchar *tail = xb_string_xml_escape (xb_silo_from_strtab (self, sn->tail));
|
|
Packit Service |
a3c5fa |
g_string_append (helper->xml, tail);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
if (helper->flags & XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE)
|
|
Packit Service |
a3c5fa |
g_string_append (helper->xml, "\n");
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
return TRUE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* private */
|
|
Packit Service |
a3c5fa |
GString *
|
|
Packit Service |
a3c5fa |
xb_silo_export_with_root (XbSilo *self, XbNode *root, XbNodeExportFlags flags, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
XbSiloNode *sn;
|
|
Packit Service |
a3c5fa |
XbSiloExportHelper helper = {
|
|
Packit Service |
a3c5fa |
.flags = flags,
|
|
Packit Service |
a3c5fa |
.level = 0,
|
|
Packit Service |
a3c5fa |
.off = sizeof(XbSiloHeader),
|
|
Packit Service |
a3c5fa |
};
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (XB_IS_SILO (self), NULL);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* this implies the other */
|
|
Packit Service |
a3c5fa |
if (flags & XB_NODE_EXPORT_FLAG_ONLY_CHILDREN)
|
|
Packit Service |
a3c5fa |
flags |= XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* optional subtree export */
|
|
Packit Service |
a3c5fa |
if (root != NULL) {
|
|
Packit Service |
a3c5fa |
sn = xb_node_get_sn (root);
|
|
Packit Service |
a3c5fa |
if (sn != NULL && flags & XB_NODE_EXPORT_FLAG_ONLY_CHILDREN)
|
|
Packit Service |
a3c5fa |
sn = xb_silo_node_get_child (self, sn);
|
|
Packit Service |
a3c5fa |
} else {
|
|
Packit Service |
a3c5fa |
sn = xb_silo_get_sroot (self);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* no root */
|
|
Packit Service |
a3c5fa |
if (sn == NULL) {
|
|
Packit Service |
a3c5fa |
g_set_error_literal (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_NOT_FOUND,
|
|
Packit Service |
a3c5fa |
"no data to export");
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* root node */
|
|
Packit Service |
a3c5fa |
helper.xml = g_string_new (NULL);
|
|
Packit Service |
a3c5fa |
if ((flags & XB_NODE_EXPORT_FLAG_ADD_HEADER) > 0)
|
|
Packit Service |
a3c5fa |
g_string_append (helper.xml, "\n");
|
|
Packit Service |
a3c5fa |
do {
|
|
Packit Service |
a3c5fa |
if (!xb_silo_export_node (self, &helper, sn, error)) {
|
|
Packit Service |
a3c5fa |
g_string_free (helper.xml, TRUE);
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
if ((flags & XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS) == 0)
|
|
Packit Service |
a3c5fa |
break;
|
|
Packit Service |
a3c5fa |
sn = xb_silo_node_get_next (self, sn);
|
|
Packit Service |
a3c5fa |
} while (sn != NULL);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* success */
|
|
Packit Service |
a3c5fa |
return helper.xml;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_export:
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @flags: some #XbNodeExportFlags, e.g. #XB_NODE_EXPORT_FLAG_NONE
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Exports the silo back to XML.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: XML data, or %NULL for an error
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.0
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
gchar *
|
|
Packit Service |
a3c5fa |
xb_silo_export (XbSilo *self, XbNodeExportFlags flags, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
GString *xml;
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (XB_IS_SILO (self), NULL);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
Packit Service |
a3c5fa |
xml = xb_silo_export_with_root (self, NULL, flags, error);
|
|
Packit Service |
a3c5fa |
if (xml == NULL)
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
return g_string_free (xml, FALSE);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_export_file:
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @file: a #GFile
|
|
Packit Service |
a3c5fa |
* @flags: some #XbNodeExportFlags, e.g. #XB_NODE_EXPORT_FLAG_NONE
|
|
Packit Service |
a3c5fa |
* @cancellable: a #GCancellable, or %NULL
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Exports the silo back to an XML file.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: %TRUE on success
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.2
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
gboolean
|
|
Packit Service |
a3c5fa |
xb_silo_export_file (XbSilo *self,
|
|
Packit Service |
a3c5fa |
GFile *file,
|
|
Packit Service |
a3c5fa |
XbNodeExportFlags flags,
|
|
Packit Service |
a3c5fa |
GCancellable *cancellable,
|
|
Packit Service |
a3c5fa |
GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
g_autoptr(GString) xml = NULL;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (XB_IS_SILO (self), FALSE);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
xml = xb_silo_export_with_root (self, NULL, flags, error);
|
|
Packit Service |
a3c5fa |
if (xml == NULL)
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
return g_file_replace_contents (file,
|
|
Packit Service |
a3c5fa |
xml->str,
|
|
Packit Service |
a3c5fa |
xml->len,
|
|
Packit Service |
a3c5fa |
NULL, /* etag */
|
|
Packit Service |
a3c5fa |
FALSE, /* make-backup */
|
|
Packit Service |
a3c5fa |
G_FILE_CREATE_NONE,
|
|
Packit Service |
a3c5fa |
NULL, /* new etag */
|
|
Packit Service |
a3c5fa |
cancellable,
|
|
Packit Service |
a3c5fa |
error);
|
|
Packit Service |
a3c5fa |
}
|