qsf-xml.c

00001 /***************************************************************************
00002  *            qsf-xml.c
00003  *
00004  *  Fri Nov 26 19:29:47 2004
00005  *  Copyright  2004,2005,2006  Neil Williams  <linux@codehelp.co.uk>
00006  *
00007  ****************************************************************************/
00008 /*
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00022  */
00023 
00024 #define _GNU_SOURCE
00025 
00026 #include "config.h"
00027 #include <glib.h>
00028 #include <libxml/xmlversion.h>
00029 #include <libxml/xmlmemory.h>
00030 #include <libxml/tree.h>
00031 #include <libxml/parser.h>
00032 #include <libxml/xmlschemas.h>
00033 #include "qof.h"
00034 #include "qof-backend-qsf.h"
00035 #include "qsf-dir.h"
00036 #include "qsf-xml.h"
00037 
00038 static QofLogModule log_module = QOF_MOD_QSF;
00039 
00040 gint
00041 qsf_compare_tag_strings(const xmlChar *node_name, gchar *tag_name)
00042 {
00043         return xmlStrcmp(node_name, (const xmlChar *)tag_name);
00044 }
00045 
00046 gint
00047 qsf_strings_equal(const xmlChar *node_name, gchar *tag_name)
00048 {
00049         if(0 == qsf_compare_tag_strings(node_name, tag_name)) { return 1; }
00050         return 0;
00051 }
00052 
00053 gint
00054 qsf_is_element(xmlNodePtr a, xmlNsPtr ns, gchar *c)
00055 {
00056         g_return_val_if_fail(a != NULL, 0);
00057         g_return_val_if_fail(ns != NULL, 0);
00058         g_return_val_if_fail(c != NULL, 0);
00059         if ((a->ns == ns) && (a->type == XML_ELEMENT_NODE) &&
00060                 qsf_strings_equal(a->name, c)) { return 1; }
00061         return 0;
00062 }
00063 
00064 gint
00065 qsf_check_tag(qsf_param *params, gchar *qof_type)
00066 {
00067         return qsf_is_element(params->child_node, params->qsf_ns, qof_type);
00068 }
00069 
00070 gboolean
00071 qsf_is_valid(const gchar *schema_dir, const gchar* schema_filename, xmlDocPtr doc)
00072 {
00073         xmlSchemaParserCtxtPtr qsf_schema_file;
00074         xmlSchemaPtr qsf_schema;
00075         xmlSchemaValidCtxtPtr qsf_context;
00076         gchar *schema_path;
00077         gint result;
00078 
00079         g_return_val_if_fail(doc || schema_filename, FALSE);
00080         schema_path = g_strdup_printf("%s/%s", schema_dir, schema_filename);
00081         qsf_schema_file = xmlSchemaNewParserCtxt(schema_path);
00082         qsf_schema = xmlSchemaParse(qsf_schema_file);
00083         qsf_context = xmlSchemaNewValidCtxt(qsf_schema);
00084         result = xmlSchemaValidateDoc(qsf_context, doc);
00085         xmlSchemaFreeParserCtxt(qsf_schema_file);
00086         xmlSchemaFreeValidCtxt(qsf_context);
00087         xmlSchemaFree(qsf_schema);
00088         if(result == 0) { return TRUE; }
00089         return FALSE;
00090 }
00091 
00092 void
00093 qsf_valid_foreach(xmlNodePtr parent, qsf_validCB cb,
00094         struct qsf_node_iterate *iter, qsf_validator *valid)
00095 {
00096         xmlNodePtr cur_node;
00097 
00098         iter->v_fcn = &cb;
00099         for(cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
00100         {
00101                 cb(cur_node, iter->ns, valid);
00102         }
00103 }
00104 
00105 void
00106 qsf_node_foreach(xmlNodePtr parent, qsf_nodeCB cb,
00107         struct qsf_node_iterate *iter, qsf_param *params)
00108 {
00109         xmlNodePtr cur_node;
00110 
00111         g_return_if_fail(iter->ns);
00112         iter->fcn = &cb;
00113         for(cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
00114         {
00115                 cb(cur_node, iter->ns, params);
00116         }
00117 }
00118 
00119 void
00120 qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid)
00121 {
00122         xmlNodePtr cur_node;
00123         xmlChar *object_declaration;
00124         guint count;
00125         QsfStatus type;
00126         gboolean is_registered;
00127 
00128         count = 0;
00129         type = QSF_NO_OBJECT;
00130         is_registered = FALSE;
00131         for(cur_node = child->children; cur_node != NULL;
00132                 cur_node = cur_node->next)
00133         {
00134                 if(qsf_is_element(cur_node, ns, QSF_OBJECT_TAG)) {
00135                         object_declaration = xmlGetProp(cur_node, BAD_CAST QSF_OBJECT_TYPE);
00136                         is_registered = qof_class_is_registered(object_declaration);
00137                         if(is_registered) { type = QSF_REGISTERED_OBJECT; }
00138                         else { type = QSF_DEFINED_OBJECT; }
00139                         count = g_hash_table_size(valid->object_table);
00140                         g_hash_table_insert(valid->object_table, object_declaration,
00141                                 GINT_TO_POINTER(type));
00142                         /* if insert was successful - i.e. object is unique so far */
00143                         if(g_hash_table_size(valid->object_table) > count)
00144                         {
00145                                 valid->valid_object_count++;
00146                                 if(is_registered) { valid->qof_registered_count++; }
00147                         }
00148                 }
00149         }
00150 }
00151 
00152 gboolean is_our_qsf_object(const gchar *path)
00153 {
00154         xmlDocPtr doc;
00155         struct qsf_node_iterate iter;
00156         xmlNodePtr object_root;
00157         qsf_validator valid;
00158         gint table_count;
00159 
00160         g_return_val_if_fail((path != NULL),FALSE);
00161         doc = xmlParseFile(path);
00162         if(doc == NULL)  { return FALSE; }
00163         if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) { 
00164                 PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR, 
00165                         QSF_OBJECT_SCHEMA, path);
00166                 return FALSE; 
00167         }
00168         object_root = xmlDocGetRootElement(doc);
00169         /* check that all objects in the file are already registered in QOF */
00170         valid.object_table = g_hash_table_new(g_str_hash, g_str_equal);
00171         valid.qof_registered_count = 0;
00172         valid.valid_object_count = 0;
00173         iter.ns = object_root->ns;
00174         qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
00175         table_count = g_hash_table_size(valid.object_table);
00176         g_hash_table_destroy(valid.object_table);
00177         if(table_count == valid.qof_registered_count) { return TRUE; }
00178         return FALSE;
00179 }
00180 
00181 gboolean is_qsf_object(const gchar *path)
00182 {
00183         xmlDocPtr doc;
00184 
00185         g_return_val_if_fail((path != NULL),FALSE);
00186         if(path == NULL) { return FALSE; }
00187         doc = xmlParseFile(path);
00188         if(doc == NULL) { return FALSE; }
00189         if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) { return FALSE; }
00190         /* Note cannot test against a map here, so if the file is valid QSF,
00191         accept it and work out the details later. */
00192         return TRUE;
00193 }
00194 
00195 gboolean is_our_qsf_object_be(qsf_param *params)
00196 {
00197         xmlDocPtr doc;
00198         struct qsf_node_iterate iter;
00199         xmlNodePtr object_root;
00200         qsf_validator valid;
00201         gint table_count;
00202         gchar *path;
00203 
00204         g_return_val_if_fail((params != NULL),FALSE);
00205         path = g_strdup(params->filepath);
00206         if(path == NULL) {
00207                 qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
00208                 return FALSE;
00209         }
00210         if(params->file_type != QSF_UNDEF) { return FALSE; }
00211         doc = xmlParseFile(path);
00212         if(doc == NULL)  {
00213                 qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
00214                 return FALSE;
00215         }
00216         if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00217         {
00218                 qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
00219                 return FALSE;
00220         }
00221         params->file_type = IS_QSF_OBJ;
00222         object_root = xmlDocGetRootElement(doc);
00223         valid.object_table = g_hash_table_new(g_str_hash, g_str_equal);
00224         valid.qof_registered_count = 0;
00225         iter.ns = object_root->ns;
00226         qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
00227         table_count = g_hash_table_size(valid.object_table);
00228         if(table_count == valid.qof_registered_count)
00229         {
00230                 g_hash_table_destroy(valid.object_table);
00231                 qof_backend_set_error(params->be, ERR_BACKEND_NO_ERR);
00232                 return TRUE;
00233         }
00234         g_hash_table_destroy(valid.object_table);
00235         qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
00236         return FALSE;
00237 }
00238 
00239 gboolean is_qsf_object_be(qsf_param *params)
00240 {
00241         gboolean result;
00242         xmlDocPtr doc;
00243         GList *maps;
00244         gchar *path;
00245 
00246         g_return_val_if_fail((params != NULL),FALSE);
00247         path = g_strdup(params->filepath);
00248         if(path == NULL) {
00249                 qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
00250                 return FALSE;
00251         }
00252         /* skip validation if is_our_qsf_object has already been called. */
00253         if(ERR_QSF_INVALID_OBJ == qof_backend_get_error(params->be)) { return FALSE; }
00254         if(params->file_type == QSF_UNDEF)
00255         {
00256                 doc = xmlParseFile(path);
00257                 if(doc == NULL) {
00258                         qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
00259                         return FALSE;
00260                 }
00261                 if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00262                 {
00263                         qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
00264                         return FALSE;
00265                 }
00266         }
00267         result = FALSE;
00268         /* retrieve list of maps from config frame. */
00269         for(maps = params->map_files; maps; maps=maps->next)
00270         {
00271                 QofBackendError err;
00272                 result = is_qsf_object_with_map_be(maps->data, params);
00273                 err = qof_backend_get_error(params->be);
00274                 if((err == ERR_BACKEND_NO_ERR) && result)
00275                 {
00276                         params->map_path = maps->data;
00277                         PINFO ("map chosen = %s", params->map_path);
00278                         break;
00279                 }
00280                 /* pop the error back on the stack. */
00281                 else { qof_backend_set_error(params->be, err); }
00282         }
00283         return result;
00284 }
00285 
00286 static void
00287 qsf_supported_data_types(gpointer type, gpointer user_data)
00288 {
00289         qsf_param *params;
00290 
00291         g_return_if_fail(user_data != NULL);
00292         g_return_if_fail(type != NULL);
00293         params = (qsf_param*) user_data;
00294         if(qsf_is_element(params->param_node, params->qsf_ns, (gchar*)type))
00295         {
00296                 g_hash_table_insert(params->qsf_parameter_hash,
00297                         xmlGetProp(params->param_node, BAD_CAST QSF_OBJECT_TYPE), params->param_node);
00298         }
00299 }
00300 
00301 static void
00302 qsf_parameter_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params)
00303 {
00304         params->param_node = child;
00305         g_slist_foreach(params->supported_types, qsf_supported_data_types, params);
00306 }
00307 
00308 void
00309 qsf_object_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params)
00310 {
00311         struct qsf_node_iterate iter;
00312         qsf_objects *object_set;
00313         gchar *tail, *object_count_s;
00314         gint64 c;
00315 
00316         g_return_if_fail(child != NULL);
00317         g_return_if_fail(qsf_ns != NULL);
00318         params->qsf_ns = qsf_ns;
00319         if(qsf_is_element(child, qsf_ns, QSF_OBJECT_TAG)) {
00320                 params->qsf_parameter_hash = NULL;
00321                 c = 0;
00322                 object_set = g_new(qsf_objects, 1);
00323                 params->object_set = object_set;
00324                 object_set->object_count = 0;
00325                 object_set->parameters = g_hash_table_new(g_str_hash, g_str_equal);
00326                 object_set->object_type = g_strdup((gchar*)xmlGetProp(child, 
00327                         BAD_CAST QSF_OBJECT_TYPE));
00328                 object_count_s = g_strdup((gchar*)xmlGetProp(child, 
00329                         BAD_CAST QSF_OBJECT_COUNT));
00330                 c = (gint64)strtol(object_count_s, &tail, 0);
00331                 object_set->object_count = (gint)c;
00332                 g_free(object_count_s);
00333                 params->qsf_object_list = g_list_prepend(params->qsf_object_list, object_set);
00334                 iter.ns = qsf_ns;
00335                 params->qsf_parameter_hash = object_set->parameters;
00336                 qsf_node_foreach(child, qsf_parameter_handler, &iter, params);
00337         }
00338 }
00339 
00340 void
00341 qsf_book_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
00342 {
00343         gchar *book_count_s, *tail;
00344         gint book_count;
00345         xmlNodePtr child_node;
00346         struct qsf_node_iterate iter;
00347         gchar *buffer;
00348         GUID book_guid;
00349 
00350         g_return_if_fail(child);
00351         g_return_if_fail(params);
00352         ENTER (" child=%s", child->name);
00353         if(qsf_is_element(child, ns, QSF_BOOK_TAG)) {
00354                 book_count_s = (gchar*)xmlGetProp(child, BAD_CAST QSF_BOOK_COUNT);
00355                 if(book_count_s) {
00356                         book_count = (gint)strtol(book_count_s, &tail, 0);
00357                         /* More than one book not currently supported. */
00358                         g_return_if_fail(book_count == 1);
00359                 }
00360                 iter.ns = ns;
00361                 child_node = child->children->next;
00362                 if(qsf_is_element(child_node, ns, QSF_BOOK_GUID)) {
00363                         DEBUG (" trying to set book GUID");
00364                         buffer = g_strdup((gchar*)xmlNodeGetContent(child_node));
00365                         g_return_if_fail(TRUE == string_to_guid(buffer, &book_guid));
00366                         qof_entity_set_guid((QofEntity*)params->book, &book_guid);
00367                         xmlNewChild(params->output_node, params->qsf_ns, 
00368                         BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
00369                         g_free(buffer);
00370                 }
00371                 qsf_node_foreach(child, qsf_object_node_handler, &iter, params);
00372         }
00373         LEAVE (" ");
00374 }

Generated on Fri May 12 18:00:33 2006 for QOF by  doxygen 1.4.4