QOF  0.8.7
qsf-xml.c
1 /***************************************************************************
2  * qsf-xml.c
3  *
4  * Fri Nov 26 19:29:47 2004
5  * Copyright 2004,2005,2006 Neil Williams <linux@codehelp.co.uk>
6  *
7  ****************************************************************************/
8 /*
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23 
24 #include "config.h"
25 #include <glib.h>
26 #include <libxml/xmlversion.h>
27 #include <libxml/xmlmemory.h>
28 #include <libxml/tree.h>
29 #include <libxml/parser.h>
30 #include <libxml/xmlschemas.h>
31 #include "qof.h"
32 #include "qof-backend-qsf.h"
33 #include "qsf-xml.h"
34 
35 static QofLogModule log_module = QOF_MOD_QSF;
36 
37 gint
38 qsf_compare_tag_strings (const xmlChar * node_name, gchar * tag_name)
39 {
40  return xmlStrcmp (node_name, (const xmlChar *) tag_name);
41 }
42 
43 gint
44 qsf_strings_equal (const xmlChar * node_name, gchar * tag_name)
45 {
46  if (0 == qsf_compare_tag_strings (node_name, tag_name))
47  {
48  return 1;
49  }
50  return 0;
51 }
52 
53 gint
54 qsf_is_element (xmlNodePtr a, xmlNsPtr ns, gchar * c)
55 {
56  g_return_val_if_fail (a != NULL, 0);
57  g_return_val_if_fail (ns != NULL, 0);
58  g_return_val_if_fail (c != NULL, 0);
59  if ((a->ns == ns) && (a->type == XML_ELEMENT_NODE) &&
60  qsf_strings_equal (a->name, c))
61  {
62  return 1;
63  }
64  return 0;
65 }
66 
67 gint
68 qsf_check_tag (QsfParam * params, gchar * qof_type)
69 {
70  return qsf_is_element (params->child_node, params->qsf_ns, qof_type);
71 }
72 
73 gboolean
74 qsf_is_valid (const gchar * schema_dir, const gchar * schema_filename,
75  xmlDocPtr doc)
76 {
77  xmlSchemaParserCtxtPtr qsf_schema_file;
78  xmlSchemaPtr qsf_schema;
79  xmlSchemaValidCtxtPtr qsf_context;
80  gchar *schema_path;
81  gint result;
82 
83  g_return_val_if_fail (doc || schema_filename, FALSE);
84  schema_path = g_strdup_printf ("%s/%s", schema_dir, schema_filename);
85  qsf_schema_file = xmlSchemaNewParserCtxt (schema_path);
86  qsf_schema = xmlSchemaParse (qsf_schema_file);
87  qsf_context = xmlSchemaNewValidCtxt (qsf_schema);
88  result = xmlSchemaValidateDoc (qsf_context, doc);
89  xmlSchemaFreeParserCtxt (qsf_schema_file);
90  xmlSchemaFreeValidCtxt (qsf_context);
91  xmlSchemaFree (qsf_schema);
92  g_free (schema_path);
93  if (result == 0)
94  {
95  return TRUE;
96  }
97  return FALSE;
98 }
99 
100 void
101 qsf_valid_foreach (xmlNodePtr parent, QsfValidCB cb,
102  struct QsfNodeIterate *qsfiter, QsfValidator * valid)
103 {
104  xmlNodePtr cur_node;
105 
106  qsfiter->v_fcn = &cb;
107  for (cur_node = parent->children; cur_node != NULL;
108  cur_node = cur_node->next)
109  {
110  cb (cur_node, qsfiter->ns, valid);
111  }
112 }
113 
114 void
115 qsf_node_foreach (xmlNodePtr parent, QsfNodeCB cb,
116  struct QsfNodeIterate *qsfiter, QsfParam * params)
117 {
118  xmlNodePtr cur_node;
119 
120  if (!parent)
121  return;
122  g_return_if_fail (params);
123  g_return_if_fail (qsfiter->ns);
124  qsfiter->fcn = &cb;
125  for (cur_node = parent->children; cur_node != NULL;
126  cur_node = cur_node->next)
127  {
128  cb (cur_node, qsfiter->ns, params);
129  }
130 }
131 
132 void
133 qsf_object_validation_handler (xmlNodePtr child, xmlNsPtr ns,
134  QsfValidator * valid)
135 {
136  xmlNodePtr cur_node;
137  xmlChar *object_declaration;
138  guint count;
139  QsfStatus type;
140  gboolean is_registered;
141 
142  count = 0;
143  type = QSF_NO_OBJECT;
144  is_registered = FALSE;
145  for (cur_node = child->children; cur_node != NULL;
146  cur_node = cur_node->next)
147  {
148  if (qsf_is_element (cur_node, ns, QSF_OBJECT_TAG))
149  {
150  object_declaration =
151  xmlGetProp (cur_node, BAD_CAST QSF_OBJECT_TYPE);
152  is_registered = qof_class_is_registered ((gchar*)object_declaration);
153  if (is_registered)
154  {
155  type = QSF_REGISTERED_OBJECT;
156  }
157  else
158  {
159  type = QSF_DEFINED_OBJECT;
160  }
161  xmlFree (object_declaration);
162  count = g_hash_table_size (valid->object_table);
163  g_hash_table_insert (valid->object_table, object_declaration,
164  GINT_TO_POINTER (type));
165  /* if insert was successful - i.e. object is unique so far */
166  if (g_hash_table_size (valid->object_table) > count)
167  {
168  valid->valid_object_count++;
169  if (is_registered)
170  {
171  valid->qof_registered_count++;
172  }
173  }
174  }
175  }
176 }
177 
178 gboolean
179 is_our_qsf_object (const gchar * path)
180 {
181  xmlDocPtr doc;
182  struct QsfNodeIterate qsfiter;
183  xmlNodePtr object_root;
184  QsfValidator valid;
185  gint table_count;
186 
187  g_return_val_if_fail ((path != NULL), FALSE);
188  doc = xmlParseFile (path);
189  if (doc == NULL)
190  {
191  return FALSE;
192  }
193  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
194  {
195  PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR,
196  QSF_OBJECT_SCHEMA, path);
197  return FALSE;
198  }
199  object_root = xmlDocGetRootElement (doc);
200  /* check that all objects in the file are already registered in QOF */
201  valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
202  valid.qof_registered_count = 0;
203  valid.valid_object_count = 0;
204  qsfiter.ns = object_root->ns;
206  &qsfiter, &valid);
207  table_count = g_hash_table_size (valid.object_table);
208  g_hash_table_destroy (valid.object_table);
209  xmlFreeDoc (doc);
210  if (table_count == valid.qof_registered_count)
211  {
212  return TRUE;
213  }
214  return FALSE;
215 }
216 
217 gboolean
218 is_qsf_object (const gchar * path)
219 {
220  xmlDocPtr doc;
221 
222  g_return_val_if_fail ((path != NULL), FALSE);
223  if (path == NULL)
224  {
225  return FALSE;
226  }
227  doc = xmlParseFile (path);
228  if (doc == NULL)
229  {
230  return FALSE;
231  }
232  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
233  {
234  return FALSE;
235  }
236  /* Note cannot test against a map here, so if the file is valid QSF,
237  accept it and work out the details later. */
238  return TRUE;
239 }
240 
241 gboolean
243 {
244  xmlDocPtr doc;
245  struct QsfNodeIterate qsfiter;
246  xmlNodePtr object_root;
247  QsfValidator valid;
248  gint table_count;
249 
250  g_return_val_if_fail ((params != NULL), FALSE);
251  if (params->filepath == NULL)
252  {
253  qof_error_set_be (params->be, qof_error_register
254  (_("The QSF XML file '%s' could not be found."), TRUE));
255  return FALSE;
256  }
257  if (params->file_type != QSF_UNDEF)
258  {
259  return FALSE;
260  }
261  doc = xmlParseFile (params->filepath);
262  if (doc == NULL)
263  {
264  qof_error_set_be (params->be, qof_error_register
265  (_("There was an error parsing the file '%s'."), TRUE));
266  return FALSE;
267  }
268  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
269  {
270  qof_error_set_be (params->be, qof_error_register
271  (_("Invalid QSF Object file! The QSF object file '%s' "
272  " failed to validate against the QSF object schema. "
273  "The XML structure of the file is either not well-formed "
274  "or the file contains illegal data."), TRUE));
275  xmlFreeDoc (doc);
276  return FALSE;
277  }
278  params->file_type = IS_QSF_OBJ;
279  object_root = xmlDocGetRootElement (doc);
280  xmlFreeDoc (doc);
281  valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
282  valid.qof_registered_count = 0;
283  qsfiter.ns = object_root->ns;
285  &qsfiter, &valid);
286  table_count = g_hash_table_size (valid.object_table);
287  if (table_count == valid.qof_registered_count)
288  {
289  g_hash_table_destroy (valid.object_table);
290  return TRUE;
291  }
292  g_hash_table_destroy (valid.object_table);
293  qof_error_set_be (params->be, params->err_nomap);
294  return FALSE;
295 }
296 
297 gboolean
299 {
300  gboolean result;
301  xmlDocPtr doc;
302  GList *maps;
303  gchar *path;
304 
305  g_return_val_if_fail ((params != NULL), FALSE);
306  path = g_strdup (params->filepath);
307  if (path == NULL)
308  {
309  qof_error_set_be (params->be, qof_error_register
310  (_("The QSF XML file '%s' could not be found."), TRUE));
311  return FALSE;
312  }
313  /* skip validation if is_our_qsf_object has already been called. */
314 /* if (ERR_QSF_INVALID_OBJ == qof_backend_get_error (params->be))
315  {
316  return FALSE;
317  }*/
318  if (params->file_type == QSF_UNDEF)
319  {
320  doc = xmlParseFile (path);
321  if (doc == NULL)
322  {
323  qof_error_set_be (params->be, qof_error_register
324  (_("There was an error parsing the file '%s'."), TRUE));
325  return FALSE;
326  }
327  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
328  {
329  qof_error_set_be (params->be, qof_error_register
330  (_("Invalid QSF Object file! The QSF object file '%s' "
331  " failed to validate against the QSF object schema. "
332  "The XML structure of the file is either not well-formed "
333  "or the file contains illegal data."), TRUE));
334  return FALSE;
335  }
336  }
337  result = FALSE;
338  /* retrieve list of maps from config frame. */
339  for (maps = params->map_files; maps; maps = maps->next)
340  {
341  QofErrorId err;
342  result = is_qsf_object_with_map_be (maps->data, params);
343  err = qof_error_check_be (params->be);
344  if ((err == QOF_SUCCESS) && result)
345  {
346  params->map_path = maps->data;
347  PINFO ("map chosen = %s", params->map_path);
348  break;
349  }
350  }
351  return result;
352 }
353 
354 static void
355 qsf_supported_data_types (gpointer type, gpointer user_data)
356 {
357  QsfParam *params;
358 
359  g_return_if_fail (user_data != NULL);
360  g_return_if_fail (type != NULL);
361  params = (QsfParam *) user_data;
362  if (qsf_is_element (params->param_node, params->qsf_ns,
363  (gchar *) type))
364  {
365  g_hash_table_insert (params->qsf_parameter_hash,
366  xmlGetProp (params->param_node,
367  BAD_CAST QSF_OBJECT_TYPE), params->param_node);
368  }
369 }
370 
371 static void
372 qsf_parameter_handler (xmlNodePtr child, xmlNsPtr qsf_ns,
373  QsfParam * params)
374 {
375  /* spurious */
376  if (!qsf_ns)
377  return;
378  params->param_node = child;
379  g_slist_foreach (params->supported_types, qsf_supported_data_types,
380  params);
381 }
382 
383 void
384 qsf_object_node_handler (xmlNodePtr child, xmlNsPtr qsf_ns,
385  QsfParam * params)
386 {
387  struct QsfNodeIterate qsfiter;
388  QsfObject *object_set;
389  gchar *tail, *object_count_s;
390  gint64 c;
391 
392  g_return_if_fail (child != NULL);
393  g_return_if_fail (qsf_ns != NULL);
394  params->qsf_ns = qsf_ns;
395  if (qsf_is_element (child, qsf_ns, QSF_OBJECT_TAG))
396  {
397  params->qsf_parameter_hash = NULL;
398  c = 0;
399  object_set = g_new (QsfObject, 1);
400  params->object_set = object_set;
401  object_set->object_count = 0;
402  object_set->parameters =
403  g_hash_table_new (g_str_hash, g_str_equal);
404  object_set->object_type = ((gchar *) xmlGetProp (child,
405  BAD_CAST QSF_OBJECT_TYPE));
406  object_count_s = ((gchar *) xmlGetProp (child,
407  BAD_CAST QSF_OBJECT_COUNT));
408  if (object_count_s)
409  {
410  c = (gint64) strtol (object_count_s, &tail, 0);
411  object_set->object_count = (gint) c;
412  g_free (object_count_s);
413  }
414  params->qsf_object_list =
415  g_list_prepend (params->qsf_object_list, object_set);
416  qsfiter.ns = qsf_ns;
417  params->qsf_parameter_hash = object_set->parameters;
418  qsf_node_foreach (child, qsf_parameter_handler, &qsfiter, params);
419  }
420 }
421 
422 void
423 qsf_book_node_handler (xmlNodePtr child, xmlNsPtr ns, QsfParam * params)
424 {
425  gchar *book_count_s, *tail;
426  gint book_count;
427  xmlNodePtr child_node;
428  struct QsfNodeIterate qsfiter;
429  gchar *buffer;
430  GUID book_guid;
431 
432  g_return_if_fail (child);
433  g_return_if_fail (params);
434  ENTER (" child=%s", child->name);
435  if (qsf_is_element (child, ns, QSF_BOOK_TAG))
436  {
437  book_count_s =
438  (gchar *) xmlGetProp (child, BAD_CAST QSF_BOOK_COUNT);
439  if (book_count_s)
440  {
441  book_count = (gint) strtol (book_count_s, &tail, 0);
442  /* More than one book not currently supported. */
443  g_free (book_count_s);
444  g_return_if_fail (book_count == 1);
445  }
446  qsfiter.ns = ns;
447  child_node = child->children->next;
448  if (qsf_is_element (child_node, ns, QSF_BOOK_GUID))
449  {
450  DEBUG (" trying to set book GUID");
451  buffer = (gchar*) xmlNodeGetContent (child_node);
452  g_return_if_fail (TRUE == string_to_guid (buffer, &book_guid));
453  qof_entity_set_guid ((QofEntity *) params->book, &book_guid);
454  xmlNewChild (params->output_node, params->qsf_ns,
455  BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
456  xmlFree (buffer);
457  }
458  qsf_node_foreach (child, qsf_object_node_handler, &qsfiter, params);
459  }
460  LEAVE (" ");
461 }
QSF Parameters.
Definition: qsf-xml.h:469
xmlNsPtr qsf_ns
Definition: qsf-xml.h:507
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:73
void qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, QsfValidator *valid)
Checks all incoming objects for QOF registration.
Definition: qsf-xml.c:133
gint qsf_check_tag(QsfParam *params, gchar *qof_type)
shorthand function
Definition: qsf-xml.c:68
#define PINFO(format, args...)
Definition: qoflog.h:199
gboolean qof_class_is_registered(QofIdTypeConst obj_name)
Definition: qofclass.c:133
#define QSF_OBJECT_COUNT
Definition: qsf-xml.h:105
gboolean is_qsf_object(const gchar *path)
Validate a QSF file and identify a suitable QSF map.
Definition: qsf-xml.c:218
Validation metadata.
Definition: qsf-xml.h:558
gboolean string_to_guid(const gchar *string, GUID *guid)
void qsf_valid_foreach(xmlNodePtr parent, QsfValidCB cb, struct QsfNodeIterate *qsfiter, QsfValidator *valid)
Definition: qsf-xml.c:101
QsfType file_type
Definition: qsf-xml.h:472
gboolean qsf_is_valid(const gchar *schema_dir, const gchar *schema_filename, xmlDocPtr doc)
Compares an xmlDoc in memory against the schema file.
Definition: qsf-xml.c:74
gint32 QofErrorId
The ID of this error.
Definition: qofbackend.h:54
gboolean is_qsf_object_be(QsfParam *params)
Validate a QSF file and identify a suitable QSF map.
Definition: qsf-xml.c:298
QofBackend * be
Definition: qsf-xml.h:519
#define QSF_OBJECT_TAG
Definition: qsf-xml.h:101
QofErrorId qof_error_check_be(QofBackend *be)
Check for errors.
Definition: qoferror.c:204
Private QSF header - not for use by applications.
gint qsf_strings_equal(const xmlChar *node_name, gchar *tag_name)
shorthand function
Definition: qsf-xml.c:44
#define QSF_BOOK_COUNT
Definition: qsf-xml.h:99
#define LEAVE(format, args...)
Definition: qoflog.h:227
#define QSF_OBJECT_TYPE
Definition: qsf-xml.h:103
gint qsf_compare_tag_strings(const xmlChar *node_name, gchar *tag_name)
shorthand function
Definition: qsf-xml.c:38
gboolean is_our_qsf_object(const gchar *path)
Validate a QSF file.
Definition: qsf-xml.c:179
One iterator, two typedefs.
Definition: qsf-xml.h:689
gchar * map_path
Definition: qsf-xml.h:535
#define QSF_BOOK_TAG
Definition: qsf-xml.h:94
GList * qsf_object_list
Definition: qsf-xml.h:478
gint qof_registered_count
Definition: qsf-xml.h:578
QsfStatus
Status of various object during mapping.
Definition: qsf-xml.h:446
#define QOF_SUCCESS
Definition: qoferror.h:124
GSList * supported_types
Definition: qsf-xml.h:487
void qsf_node_foreach(xmlNodePtr parent, QsfNodeCB cb, struct QsfNodeIterate *qsfiter, QsfParam *params)
Definition: qsf-xml.c:115
#define DEBUG(format, args...)
Definition: qoflog.h:208
xmlNodePtr child_node
Definition: qsf-xml.h:493
gint valid_object_count
Definition: qsf-xml.h:572
QSF API - Backend, maps, objects and configuration.
xmlNodePtr param_node
Definition: qsf-xml.h:497
gboolean is_qsf_object_with_map_be(gchar *map_path, QsfParam *params)
Validate a QSF file and a selected QSF map.
Definition: qsf-xml-map.c:238
GHashTable * qsf_parameter_hash
Definition: qsf-xml.h:484
void(* QsfNodeCB)(xmlNodePtr, xmlNsPtr, QsfParam *)
map and qsf object callback
Definition: qsf-xml.h:677
QofBook * book
Definition: qsf-xml.h:529
Definition: guid.h:53
GList * map_files
Definition: qsf-xml.h:545
gboolean is_our_qsf_object_be(QsfParam *params)
Validate a QSF file and determine type.
Definition: qsf-xml.c:242
#define QSF_OBJECT_SCHEMA
Definition: qsf-xml.h:420
gint qsf_is_element(xmlNodePtr a, xmlNsPtr ns, gchar *c)
shorthand function
Definition: qsf-xml.c:54
xmlNodePtr output_node
Definition: qsf-xml.h:499
gchar * filepath
Definition: qsf-xml.h:533
Holds a description of the QofObject.
Definition: qsf-xml.h:63
void qof_entity_set_guid(QofEntity *ent, const GUID *guid)
Definition: qofid.c:92
void qsf_book_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, QsfParam *params)
Book and book-guid node handler.
Definition: qsf-xml.c:423
GHashTable * object_table
Definition: qsf-xml.h:565
QsfObject * object_set
Definition: qsf-xml.h:474
#define ENTER(format, args...)
Definition: qoflog.h:217
void qsf_object_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, QsfParam *params)
Definition: qsf-xml.c:384
const gchar * QofLogModule
Definition: qofid.h:85
#define QSF_BOOK_GUID
Definition: qsf-xml.h:97
void(* QsfValidCB)(xmlNodePtr, xmlNsPtr, QsfValidator *)
validator callback
Definition: qsf-xml.h:684