Files
gnucash/lib/libqof/backend/file/qsf-xml.c
David Hampton 4b04137e7d Never include "config.h" from a header file. Doing so makes it nigh
impossible to override configuration settings.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@13549 57a11ea4-9604-0410-9ed3-97b8803252fd
2006-03-09 05:51:07 +00:00

352 lines
10 KiB
C

/***************************************************************************
* qsf-xml.c
*
* Fri Nov 26 19:29:47 2004
* Copyright 2004-2005 Neil Williams <linux@codehelp.co.uk>
*
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define _GNU_SOURCE
#include "config.h"
#include <libxml/xmlversion.h>
#include "qof.h"
#include "qof-backend-qsf.h"
#include "qsf-dir.h"
#include "qsf-xml.h"
static QofLogModule log_module = QOF_MOD_QSF;
int
qsf_compare_tag_strings(const xmlChar *node_name, char *tag_name)
{
return xmlStrcmp(node_name, (const xmlChar *)tag_name);
}
int
qsf_strings_equal(const xmlChar *node_name, char *tag_name)
{
if(0 == qsf_compare_tag_strings(node_name, tag_name)) { return 1; }
return 0;
}
int
qsf_is_element(xmlNodePtr a, xmlNsPtr ns, char *c)
{
g_return_val_if_fail(a != NULL, 0);
g_return_val_if_fail(ns != NULL, 0);
g_return_val_if_fail(c != NULL, 0);
if ((a->ns == ns) && (a->type == XML_ELEMENT_NODE) &&
qsf_strings_equal(a->name, c)) { return 1; }
return 0;
}
int
qsf_check_tag(qsf_param *params, char *qof_type)
{
return qsf_is_element(params->child_node, params->qsf_ns, qof_type);
}
gboolean
qsf_is_valid(const char *schema_dir, const char* schema_filename, xmlDocPtr doc)
{
xmlSchemaParserCtxtPtr qsf_schema_file;
xmlSchemaPtr qsf_schema;
xmlSchemaValidCtxtPtr qsf_context;
gchar *schema_path;
gint result;
g_return_val_if_fail(doc || schema_filename, FALSE);
schema_path = g_strdup_printf("%s/%s", schema_dir, schema_filename);
qsf_schema_file = xmlSchemaNewParserCtxt(schema_path);
qsf_schema = xmlSchemaParse(qsf_schema_file);
qsf_context = xmlSchemaNewValidCtxt(qsf_schema);
result = xmlSchemaValidateDoc(qsf_context, doc);
xmlSchemaFreeParserCtxt(qsf_schema_file);
xmlSchemaFreeValidCtxt(qsf_context);
xmlSchemaFree(qsf_schema);
if(result == 0) { return TRUE; }
return FALSE;
}
void
qsf_valid_foreach(xmlNodePtr parent, qsf_validCB cb,
struct qsf_node_iterate *iter, qsf_validator *valid)
{
xmlNodePtr cur_node;
iter->v_fcn = &cb;
for(cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
{
cb(cur_node, iter->ns, valid);
}
}
void
qsf_node_foreach(xmlNodePtr parent, qsf_nodeCB cb,
struct qsf_node_iterate *iter, qsf_param *params)
{
xmlNodePtr cur_node;
iter->fcn = &cb;
for(cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
{
cb(cur_node, iter->ns, params);
}
}
void
qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid)
{
xmlNodePtr cur_node;
xmlChar *object_declaration;
guint count;
count = 0;
for(cur_node = child->children; cur_node != NULL;
cur_node = cur_node->next)
{
if(qsf_is_element(cur_node, ns, QSF_OBJECT_TAG)) {
object_declaration = xmlGetProp(cur_node, BAD_CAST QSF_OBJECT_TYPE);
count = g_hash_table_size(valid->validation_table);
g_hash_table_insert(valid->validation_table, object_declaration, xmlNodeGetContent(cur_node));
if(g_hash_table_size(valid->validation_table) > count)
{
valid->valid_object_count++;
if(TRUE == qof_class_is_registered((QofIdTypeConst) object_declaration))
{
valid->qof_registered_count++;
}
}
}
}
}
gboolean is_our_qsf_object(const char *path)
{
xmlDocPtr doc;
struct qsf_node_iterate iter;
xmlNodePtr object_root;
qsf_validator valid;
gint table_count;
g_return_val_if_fail((path != NULL),FALSE);
doc = xmlParseFile(path);
if(doc == NULL) { return FALSE; }
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) {
PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR,
QSF_OBJECT_SCHEMA, path);
return FALSE;
}
object_root = xmlDocGetRootElement(doc);
/* check that all objects in the file are already registered in QOF */
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.qof_registered_count = 0;
valid.valid_object_count = 0;
iter.ns = object_root->ns;
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
table_count = g_hash_table_size(valid.validation_table);
g_hash_table_destroy(valid.validation_table);
if(table_count == valid.qof_registered_count) { return TRUE; }
return FALSE;
}
gboolean is_qsf_object(const char *path)
{
xmlDocPtr doc;
g_return_val_if_fail((path != NULL),FALSE);
if(path == NULL) { return FALSE; }
doc = xmlParseFile(path);
if(doc == NULL) { return FALSE; }
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) { return FALSE; }
/* Note cannot test against a map here, so if the file is valid QSF,
accept it and work out the details later. */
return TRUE;
}
gboolean is_our_qsf_object_be(qsf_param *params)
{
xmlDocPtr doc;
struct qsf_node_iterate iter;
xmlNodePtr object_root;
qsf_validator valid;
gint table_count;
char *path;
g_return_val_if_fail((params != NULL),FALSE);
path = g_strdup(params->filepath);
if(path == NULL) {
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
return FALSE;
}
if(params->file_type != QSF_UNDEF) { return FALSE; }
doc = xmlParseFile(path);
if(doc == NULL) {
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
return FALSE;
}
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
{
qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
return FALSE;
}
params->file_type = IS_QSF_OBJ;
object_root = xmlDocGetRootElement(doc);
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.qof_registered_count = 0;
iter.ns = object_root->ns;
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
table_count = g_hash_table_size(valid.validation_table);
if(table_count == valid.qof_registered_count)
{
g_hash_table_destroy(valid.validation_table);
qof_backend_set_error(params->be, ERR_BACKEND_NO_ERR);
return TRUE;
}
g_hash_table_destroy(valid.validation_table);
qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
return FALSE;
}
gboolean is_qsf_object_be(qsf_param *params)
{
gboolean result;
xmlDocPtr doc;
GList *maps;
char *path;
g_return_val_if_fail((params != NULL),FALSE);
path = g_strdup(params->filepath);
if(path == NULL) {
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
return FALSE;
}
/* skip validation if is_our_qsf_object has already been called. */
if(ERR_QSF_INVALID_OBJ == qof_backend_get_error(params->be)) { return FALSE; }
if(params->file_type == QSF_UNDEF)
{
doc = xmlParseFile(path);
if(doc == NULL) {
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
return FALSE;
}
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
{
qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
return FALSE;
}
}
result = FALSE;
/* retrieve list of maps from config frame. */
for(maps = params->map_files; maps; maps=maps->next)
{
result = is_qsf_object_with_map_be(maps->data, params);
if(result) { break;}
}
return result;
}
static void
qsf_supported_data_types(gpointer type, gpointer user_data)
{
qsf_param *params;
g_return_if_fail(user_data != NULL);
g_return_if_fail(type != NULL);
params = (qsf_param*) user_data;
if(qsf_is_element(params->param_node, params->qsf_ns, (char*)type))
{
g_hash_table_insert(params->qsf_parameter_hash,
xmlGetProp(params->param_node, BAD_CAST QSF_OBJECT_TYPE), params->param_node);
}
}
static void
qsf_parameter_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params)
{
params->param_node = child;
g_slist_foreach(params->supported_types, qsf_supported_data_types, params);
}
/* Despite the name, this function handles the QSF object book tag
AND the object tags. */
void
qsf_object_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params)
{
struct qsf_node_iterate iter;
qsf_objects *object_set;
char *tail, *object_count_s;
int c;
g_return_if_fail(child != NULL);
g_return_if_fail(qsf_ns != NULL);
params->qsf_ns = qsf_ns;
if(qsf_is_element(child, qsf_ns, QSF_OBJECT_TAG)) {
params->qsf_parameter_hash = NULL;
object_set = g_new(qsf_objects, 1);
params->object_set = object_set;
object_set->parameters = g_hash_table_new(g_str_hash, g_str_equal);
object_set->object_type = g_strdup((char*)xmlGetProp(child, BAD_CAST QSF_OBJECT_TYPE));
object_count_s = g_strdup((char*)xmlGetProp(child, BAD_CAST QSF_OBJECT_COUNT));
c = (int)strtol(object_count_s, &tail, 0);
g_free(object_count_s);
params->qsf_object_list = g_list_prepend(params->qsf_object_list, object_set);
iter.ns = qsf_ns;
params->qsf_parameter_hash = object_set->parameters;
qsf_node_foreach(child, qsf_parameter_handler, &iter, params);
}
}
void
qsf_book_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
{
char *book_count_s, *tail;
int book_count;
xmlNodePtr child_node;
struct qsf_node_iterate iter;
gchar *buffer;
GUID book_guid;
if(qsf_is_element(child, ns, QSF_BOOK_TAG)) {
book_count_s = (char*)xmlGetProp(child, BAD_CAST QSF_BOOK_COUNT);
if(book_count_s) {
book_count = (int)strtol(book_count_s, &tail, 0);
/* More than one book not currently supported. */
g_return_if_fail(book_count == 1);
}
iter.ns = ns;
qsf_node_foreach(child, qsf_object_node_handler, &iter, params);
}
for(child_node = child->children; child_node != NULL;
child_node = child_node->next)
{
if(qsf_is_element(child_node, ns, QSF_BOOK_GUID)) {
buffer = g_strdup((char*)xmlNodeGetContent(child_node));
g_return_if_fail(TRUE == string_to_guid(buffer, &book_guid));
qof_entity_set_guid((QofEntity*)params->book, &book_guid);
g_free(buffer);
}
if(qsf_is_element(child_node, ns, QSF_OBJECT_TAG)) {
iter.ns = ns;
qsf_node_foreach(child_node, qsf_object_node_handler, &iter, params);
}
}
}