QOF: qsf-xml.c Source File

QOF 0.7.5

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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