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 #include "config.h"
00025 #include <glib.h>
00026 #include <libxml/xmlversion.h>
00027 #include <libxml/xmlmemory.h>
00028 #include <libxml/tree.h>
00029 #include <libxml/parser.h>
00030 #include <libxml/xmlschemas.h>
00031 #include "qof.h"
00032 #include "qof-backend-qsf.h"
00033 #include "qsf-dir.h"
00034 #include "qsf-xml.h"
00035 
00036 static QofLogModule log_module = QOF_MOD_QSF;
00037 
00038 gint
00039 qsf_compare_tag_strings (const xmlChar * node_name, gchar * tag_name)
00040 {
00041     return xmlStrcmp (node_name, (const xmlChar *) tag_name);
00042 }
00043 
00044 gint
00045 qsf_strings_equal (const xmlChar * node_name, gchar * tag_name)
00046 {
00047     if (0 == qsf_compare_tag_strings (node_name, tag_name))
00048     {
00049         return 1;
00050     }
00051     return 0;
00052 }
00053 
00054 gint
00055 qsf_is_element (xmlNodePtr a, xmlNsPtr ns, gchar * c)
00056 {
00057     g_return_val_if_fail (a != NULL, 0);
00058     g_return_val_if_fail (ns != NULL, 0);
00059     g_return_val_if_fail (c != NULL, 0);
00060     if ((a->ns == ns) && (a->type == XML_ELEMENT_NODE) &&
00061         qsf_strings_equal (a->name, c))
00062     {
00063         return 1;
00064     }
00065     return 0;
00066 }
00067 
00068 gint
00069 qsf_check_tag (qsf_param * params, gchar * qof_type)
00070 {
00071     return qsf_is_element (params->child_node, params->qsf_ns, qof_type);
00072 }
00073 
00074 gboolean
00075 qsf_is_valid (const gchar * schema_dir, const gchar * schema_filename,
00076     xmlDocPtr doc)
00077 {
00078     xmlSchemaParserCtxtPtr qsf_schema_file;
00079     xmlSchemaPtr qsf_schema;
00080     xmlSchemaValidCtxtPtr qsf_context;
00081     gchar *schema_path;
00082     gint result;
00083 
00084     g_return_val_if_fail (doc || schema_filename, FALSE);
00085     schema_path = g_strdup_printf ("%s/%s", schema_dir, schema_filename);
00086     qsf_schema_file = xmlSchemaNewParserCtxt (schema_path);
00087     qsf_schema = xmlSchemaParse (qsf_schema_file);
00088     qsf_context = xmlSchemaNewValidCtxt (qsf_schema);
00089     result = xmlSchemaValidateDoc (qsf_context, doc);
00090     xmlSchemaFreeParserCtxt (qsf_schema_file);
00091     xmlSchemaFreeValidCtxt (qsf_context);
00092     xmlSchemaFree (qsf_schema);
00093     g_free (schema_path);
00094     if (result == 0)
00095     {
00096         return TRUE;
00097     }
00098     return FALSE;
00099 }
00100 
00101 void
00102 qsf_valid_foreach (xmlNodePtr parent, qsf_validCB cb,
00103     struct qsf_node_iterate *iter, qsf_validator * valid)
00104 {
00105     xmlNodePtr cur_node;
00106 
00107     iter->v_fcn = &cb;
00108     for (cur_node = parent->children; cur_node != NULL;
00109         cur_node = cur_node->next)
00110     {
00111         cb (cur_node, iter->ns, valid);
00112     }
00113 }
00114 
00115 void
00116 qsf_node_foreach (xmlNodePtr parent, qsf_nodeCB cb,
00117     struct qsf_node_iterate *iter, qsf_param * params)
00118 {
00119     xmlNodePtr cur_node;
00120 
00121     g_return_if_fail (iter->ns);
00122     iter->fcn = &cb;
00123     for (cur_node = parent->children; cur_node != NULL;
00124         cur_node = cur_node->next)
00125     {
00126         cb (cur_node, iter->ns, params);
00127     }
00128 }
00129 
00130 void
00131 qsf_object_validation_handler (xmlNodePtr child, xmlNsPtr ns,
00132     qsf_validator * valid)
00133 {
00134     xmlNodePtr cur_node;
00135     xmlChar *object_declaration;
00136     guint count;
00137     QsfStatus type;
00138     gboolean is_registered;
00139 
00140     count = 0;
00141     type = QSF_NO_OBJECT;
00142     is_registered = FALSE;
00143     for (cur_node = child->children; cur_node != NULL;
00144         cur_node = cur_node->next)
00145     {
00146         if (qsf_is_element (cur_node, ns, QSF_OBJECT_TAG))
00147         {
00148             object_declaration =
00149                 xmlGetProp (cur_node, BAD_CAST QSF_OBJECT_TYPE);
00150             is_registered = qof_class_is_registered (object_declaration);
00151             if (is_registered)
00152             {
00153                 type = QSF_REGISTERED_OBJECT;
00154             }
00155             else
00156             {
00157                 type = QSF_DEFINED_OBJECT;
00158             }
00159             xmlFree (object_declaration);
00160             count = g_hash_table_size (valid->object_table);
00161             g_hash_table_insert (valid->object_table, object_declaration,
00162                 GINT_TO_POINTER (type));
00163             /* if insert was successful - i.e. object is unique so far */
00164             if (g_hash_table_size (valid->object_table) > count)
00165             {
00166                 valid->valid_object_count++;
00167                 if (is_registered)
00168                 {
00169                     valid->qof_registered_count++;
00170                 }
00171             }
00172         }
00173     }
00174 }
00175 
00176 gboolean
00177 is_our_qsf_object (const gchar * path)
00178 {
00179     xmlDocPtr doc;
00180     struct qsf_node_iterate iter;
00181     xmlNodePtr object_root;
00182     qsf_validator valid;
00183     gint table_count;
00184 
00185     g_return_val_if_fail ((path != NULL), FALSE);
00186     doc = xmlParseFile (path);
00187     if (doc == NULL)
00188     {
00189         return FALSE;
00190     }
00191     if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00192     {
00193         PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR,
00194             QSF_OBJECT_SCHEMA, path);
00195         return FALSE;
00196     }
00197     object_root = xmlDocGetRootElement (doc);
00198     /* check that all objects in the file are already registered in QOF */
00199     valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
00200     valid.qof_registered_count = 0;
00201     valid.valid_object_count = 0;
00202     iter.ns = object_root->ns;
00203     qsf_valid_foreach (object_root, qsf_object_validation_handler, &iter,
00204         &valid);
00205     table_count = g_hash_table_size (valid.object_table);
00206     g_hash_table_destroy (valid.object_table);
00207     xmlFreeDoc (doc);
00208     if (table_count == valid.qof_registered_count)
00209     {
00210         return TRUE;
00211     }
00212     return FALSE;
00213 }
00214 
00215 gboolean
00216 is_qsf_object (const gchar * path)
00217 {
00218     xmlDocPtr doc;
00219 
00220     g_return_val_if_fail ((path != NULL), FALSE);
00221     if (path == NULL)
00222     {
00223         return FALSE;
00224     }
00225     doc = xmlParseFile (path);
00226     if (doc == NULL)
00227     {
00228         return FALSE;
00229     }
00230     if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00231     {
00232         return FALSE;
00233     }
00234     /* Note cannot test against a map here, so if the file is valid QSF,
00235        accept it and work out the details later. */
00236     return TRUE;
00237 }
00238 
00239 gboolean
00240 is_our_qsf_object_be (qsf_param * params)
00241 {
00242     xmlDocPtr doc;
00243     struct qsf_node_iterate iter;
00244     xmlNodePtr object_root;
00245     qsf_validator valid;
00246     gint table_count;
00247 
00248     g_return_val_if_fail ((params != NULL), FALSE);
00249     if (params->filepath == NULL)
00250     {
00251         qof_backend_set_error (params->be, ERR_FILEIO_FILE_NOT_FOUND);
00252         return FALSE;
00253     }
00254     if (params->file_type != QSF_UNDEF)
00255     {
00256         return FALSE;
00257     }
00258     doc = xmlParseFile (params->filepath);
00259     if (doc == NULL)
00260     {
00261         qof_backend_set_error (params->be, ERR_FILEIO_PARSE_ERROR);
00262         return FALSE;
00263     }
00264     if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00265     {
00266         qof_backend_set_error (params->be, ERR_QSF_INVALID_OBJ);
00267         xmlFreeDoc (doc);
00268         return FALSE;
00269     }
00270     params->file_type = IS_QSF_OBJ;
00271     object_root = xmlDocGetRootElement (doc);
00272     xmlFreeDoc (doc);
00273     valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
00274     valid.qof_registered_count = 0;
00275     iter.ns = object_root->ns;
00276     qsf_valid_foreach (object_root, qsf_object_validation_handler, &iter,
00277         &valid);
00278     table_count = g_hash_table_size (valid.object_table);
00279     if (table_count == valid.qof_registered_count)
00280     {
00281         g_hash_table_destroy (valid.object_table);
00282         qof_backend_set_error (params->be, ERR_BACKEND_NO_ERR);
00283         return TRUE;
00284     }
00285     g_hash_table_destroy (valid.object_table);
00286     qof_backend_set_error (params->be, ERR_QSF_NO_MAP);
00287     return FALSE;
00288 }
00289 
00290 gboolean
00291 is_qsf_object_be (qsf_param * params)
00292 {
00293     gboolean result;
00294     xmlDocPtr doc;
00295     GList *maps;
00296     gchar *path;
00297 
00298     g_return_val_if_fail ((params != NULL), FALSE);
00299     path = g_strdup (params->filepath);
00300     if (path == NULL)
00301     {
00302         qof_backend_set_error (params->be, ERR_FILEIO_FILE_NOT_FOUND);
00303         return FALSE;
00304     }
00305     /* skip validation if is_our_qsf_object has already been called. */
00306     if (ERR_QSF_INVALID_OBJ == qof_backend_get_error (params->be))
00307     {
00308         return FALSE;
00309     }
00310     if (params->file_type == QSF_UNDEF)
00311     {
00312         doc = xmlParseFile (path);
00313         if (doc == NULL)
00314         {
00315             qof_backend_set_error (params->be, ERR_FILEIO_PARSE_ERROR);
00316             return FALSE;
00317         }
00318         if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00319         {
00320             qof_backend_set_error (params->be, ERR_QSF_INVALID_OBJ);
00321             return FALSE;
00322         }
00323     }
00324     result = FALSE;
00325     /* retrieve list of maps from config frame. */
00326     for (maps = params->map_files; maps; maps = maps->next)
00327     {
00328         QofBackendError err;
00329         result = is_qsf_object_with_map_be (maps->data, params);
00330         err = qof_backend_get_error (params->be);
00331         if ((err == ERR_BACKEND_NO_ERR) && result)
00332         {
00333             params->map_path = maps->data;
00334             PINFO ("map chosen = %s", params->map_path);
00335             break;
00336         }
00337         /* pop the error back on the stack. */
00338         else
00339         {
00340             qof_backend_set_error (params->be, err);
00341         }
00342     }
00343     return result;
00344 }
00345 
00346 static void
00347 qsf_supported_data_types (gpointer type, gpointer user_data)
00348 {
00349     qsf_param *params;
00350 
00351     g_return_if_fail (user_data != NULL);
00352     g_return_if_fail (type != NULL);
00353     params = (qsf_param *) user_data;
00354     if (qsf_is_element (params->param_node, params->qsf_ns,
00355             (gchar *) type))
00356     {
00357         g_hash_table_insert (params->qsf_parameter_hash,
00358             xmlGetProp (params->param_node,
00359                 BAD_CAST QSF_OBJECT_TYPE), params->param_node);
00360     }
00361 }
00362 
00363 static void
00364 qsf_parameter_handler (xmlNodePtr child, xmlNsPtr qsf_ns,
00365     qsf_param * params)
00366 {
00367     /* spurious */
00368     if (!qsf_ns)
00369         return;
00370     params->param_node = child;
00371     g_slist_foreach (params->supported_types, qsf_supported_data_types,
00372         params);
00373 }
00374 
00375 void
00376 qsf_object_node_handler (xmlNodePtr child, xmlNsPtr qsf_ns,
00377     qsf_param * params)
00378 {
00379     struct qsf_node_iterate iter;
00380     qsf_objects *object_set;
00381     gchar *tail, *object_count_s;
00382     gint64 c;
00383 
00384     g_return_if_fail (child != NULL);
00385     g_return_if_fail (qsf_ns != NULL);
00386     params->qsf_ns = qsf_ns;
00387     if (qsf_is_element (child, qsf_ns, QSF_OBJECT_TAG))
00388     {
00389         params->qsf_parameter_hash = NULL;
00390         c = 0;
00391         object_set = g_new (qsf_objects, 1);
00392         params->object_set = object_set;
00393         object_set->object_count = 0;
00394         object_set->parameters =
00395             g_hash_table_new (g_str_hash, g_str_equal);
00396         object_set->object_type = ((gchar *) xmlGetProp (child,
00397                 BAD_CAST QSF_OBJECT_TYPE));
00398         object_count_s = ((gchar *) xmlGetProp (child,
00399                 BAD_CAST QSF_OBJECT_COUNT));
00400         c = (gint64) strtol (object_count_s, &tail, 0);
00401         object_set->object_count = (gint) c;
00402         g_free (object_count_s);
00403         params->qsf_object_list =
00404             g_list_prepend (params->qsf_object_list, object_set);
00405         iter.ns = qsf_ns;
00406         params->qsf_parameter_hash = object_set->parameters;
00407         qsf_node_foreach (child, qsf_parameter_handler, &iter, params);
00408     }
00409 }
00410 
00411 void
00412 qsf_book_node_handler (xmlNodePtr child, xmlNsPtr ns, qsf_param * params)
00413 {
00414     gchar *book_count_s, *tail;
00415     gint book_count;
00416     xmlNodePtr child_node;
00417     struct qsf_node_iterate iter;
00418     gchar *buffer;
00419     GUID book_guid;
00420 
00421     g_return_if_fail (child);
00422     g_return_if_fail (params);
00423     ENTER (" child=%s", child->name);
00424     if (qsf_is_element (child, ns, QSF_BOOK_TAG))
00425     {
00426         book_count_s =
00427             (gchar *) xmlGetProp (child, BAD_CAST QSF_BOOK_COUNT);
00428         if (book_count_s)
00429         {
00430             book_count = (gint) strtol (book_count_s, &tail, 0);
00431             /* More than one book not currently supported. */
00432             g_free (book_count_s);
00433             g_return_if_fail (book_count == 1);
00434         }
00435         iter.ns = ns;
00436         child_node = child->children->next;
00437         if (qsf_is_element (child_node, ns, QSF_BOOK_GUID))
00438         {
00439             DEBUG (" trying to set book GUID");
00440             buffer = BAD_CAST xmlNodeGetContent (child_node);
00441             g_return_if_fail (TRUE == string_to_guid (buffer, &book_guid));
00442             qof_entity_set_guid ((QofEntity *) params->book, &book_guid);
00443             xmlNewChild (params->output_node, params->qsf_ns,
00444                 BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
00445             xmlFree (buffer);
00446         }
00447         qsf_node_foreach (child, qsf_object_node_handler, &iter, params);
00448     }
00449     LEAVE (" ");
00450 }

Generated on Fri Sep 15 14:24:57 2006 for QOF by  doxygen 1.4.7