QOF  0.8.7
qsf-xml-map.c
1 /***************************************************************************
2  * qsf-xml-map.c
3  *
4  * Sat Jan 1 07:31:55 2005
5  * Copyright 2005-2006 Neil Williams
6  * linux@codehelp.co.uk
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 static void
38 qsf_date_default_handler (const gchar * default_name,
39  GHashTable * qsf_default_hash,
40  xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns)
41 {
42  xmlNodePtr output_parent;
43  time_t *qsf_time;
44  gchar date_as_string[QSF_DATE_LENGTH];
45 
46  output_parent = xmlAddChild (parent_tag, xmlNewNode (ns,
47  xmlGetProp (import_node, BAD_CAST QSF_OBJECT_TYPE)));
48  xmlNewProp (output_parent, BAD_CAST QSF_OBJECT_TYPE,
49  xmlGetProp (import_node, BAD_CAST MAP_VALUE_ATTR));
50  qsf_time =
51  (time_t *) g_hash_table_lookup (qsf_default_hash, default_name);
52  strftime (date_as_string, QSF_DATE_LENGTH, QSF_XSD_TIME,
53  gmtime (qsf_time));
54  xmlNodeAddContent (output_parent, BAD_CAST date_as_string);
55 }
56 
57 static void
58 qsf_string_default_handler (const gchar * default_name,
59  GHashTable * qsf_default_hash,
60  xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns)
61 {
62  xmlNodePtr node;
63  xmlChar *output;
64 
65  node = xmlAddChild (parent_tag,
66  xmlNewNode (ns,
67  xmlGetProp (import_node, BAD_CAST QSF_OBJECT_TYPE)));
68  xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE,
69  xmlGetProp (import_node, BAD_CAST MAP_VALUE_ATTR));
70  output =
71  (xmlChar *) g_hash_table_lookup (qsf_default_hash, default_name);
72  xmlNodeAddContent (node, output);
73 }
74 
75 static void
76 qsf_map_validation_handler (xmlNodePtr child, xmlNsPtr ns,
77  QsfValidator * valid)
78 {
79  xmlChar *qof_version, *obj_type;
80  gboolean is_registered;
81  gchar *buff;
82  xmlNodePtr child_node;
83  QsfStatus type, incoming_type;
84 
85  buff = NULL;
86  is_registered = FALSE;
87  type = QSF_NO_OBJECT;
88  if (qsf_is_element (child, ns, MAP_DEFINITION_TAG))
89  {
90  qof_version = xmlGetProp (child, BAD_CAST MAP_QOF_VERSION);
91  buff = g_strdup_printf ("%i", QSF_QOF_VERSION);
92  if (xmlStrcmp (qof_version, BAD_CAST buff) != 0)
93  {
94  PERR (" Wrong QOF_VERSION in map '%s', should be %s",
95  qof_version, buff);
96  valid->error_state = QOF_FATAL;
97  g_free (buff);
98  return;
99  }
100  g_free (buff);
101  for (child_node = child->children; child_node != NULL;
102  child_node = child_node->next)
103  {
104  if (qsf_is_element (child_node, ns, MAP_DEFINE_TAG))
105  {
106  obj_type = xmlGetProp (child_node, BAD_CAST MAP_E_TYPE);
107  type = QSF_DEFINED_OBJECT;
108  is_registered = qof_class_is_registered ((gchar*)obj_type);
109  if (is_registered)
110  {
111  type = QSF_REGISTERED_OBJECT;
112  }
113  g_hash_table_insert (valid->map_table, obj_type,
114  GINT_TO_POINTER (type));
115  }
116  }
117  }
118  if (qsf_is_element (child, ns, MAP_OBJECT_TAG))
119  {
120  obj_type = xmlGetProp (child, BAD_CAST MAP_TYPE_ATTR);
121  /* check each listed object is either registered or calculated. */
122  type =
123  GPOINTER_TO_INT (g_hash_table_lookup
124  (valid->map_table, obj_type));
125  switch (type)
126  {
127  case QSF_DEFINED_OBJECT:
128  /* we have a calculation for an unregistered object. */
129  /* Ignore the calculation that exists to support bidirectional maps. */
130  /* Check that the incoming QSF contains data for this object */
131  {
132  /* lookup the same object in QSF object_table */
133  incoming_type =
134  GPOINTER_TO_INT (g_hash_table_lookup
135  (valid->object_table, obj_type));
136  switch (incoming_type)
137  {
138  case QSF_DEFINED_OBJECT:
139  {
140  valid->incoming_count++;
141  g_hash_table_insert (valid->map_table, obj_type,
142  GINT_TO_POINTER (type));
143  break; /* good, proceed. */
144  }
145  default:
146  {
147  PERR (" Missing data: %s", obj_type);
148  type = QSF_INVALID_OBJECT;
149  break;
150  }
151  }
152  break;
153  }
154  case QSF_REGISTERED_OBJECT: /* use this calculation. */
155  {
156  type = QSF_CALCULATED_OBJECT;
157  valid->map_calculated_count++;
158  valid->qof_registered_count++;
159  /* store the result */
160  g_hash_table_insert (valid->map_table, obj_type,
161  GINT_TO_POINTER (type));
162  break;
163  }
164  default:
165  {
166  type = QSF_INVALID_OBJECT;
167  break;
168  }
169  }
170  PINFO (" final type=%s result=%d", obj_type, type);
171  if (type == QSF_INVALID_OBJECT)
172  {
173  valid->error_state = QOF_FATAL;
174  }
175  }
176 }
177 
178 static QofErrorId
179 check_qsf_object_with_map_internal (xmlDocPtr map_doc, xmlDocPtr doc)
180 {
181  xmlNodePtr map_root, object_root;
182  struct QsfNodeIterate qsfiter;
183  QsfValidator valid;
184  xmlNsPtr map_ns;
185 
186  valid.map_table = g_hash_table_new (g_str_hash, g_str_equal);
187  valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
188  map_root = xmlDocGetRootElement (map_doc);
189  object_root = xmlDocGetRootElement (doc);
190  valid.map_calculated_count = 0;
191  valid.valid_object_count = 0;
192  valid.qof_registered_count = 0;
193  valid.incoming_count = 0;
194  valid.error_state = QOF_SUCCESS;
195  map_ns = map_root->ns;
196  qsfiter.ns = object_root->ns;
198  &qsfiter, &valid);
199  qsfiter.ns = map_ns;
200  qsf_valid_foreach (map_root, qsf_map_validation_handler, &qsfiter,
201  &valid);
202  if (valid.error_state != QOF_SUCCESS)
203  {
204  PINFO (" Map is wrong. Trying the next map.");
205  g_hash_table_destroy (valid.object_table);
206  g_hash_table_destroy (valid.map_table);
207  return valid.error_state;
208  }
209  /* check all counted objects are valid:
210  Objects to be calculated must also be registered
211  so that new objects can be created and populated
212  from the incoming data: qof_registered_count > 0
213  The incoming data must contain valid objects -
214  not an empty QofBook: valid_object_count > 0
215  The map must contain at least some calculations:
216  map_calculated_count > 0
217  */
218  if ((valid.qof_registered_count < 1)
219  || (valid.map_calculated_count < 1)
220  || (valid.valid_object_count < 1)
221  || (valid.incoming_count < g_hash_table_size (valid.object_table)))
222  {
223  PINFO
224  (" Map is wrong. map:%d object:%d reg:%d incoming:%d size:%d",
225  valid.map_calculated_count, valid.valid_object_count,
226  valid.qof_registered_count, valid.incoming_count,
227  g_hash_table_size (valid.object_table));
228  g_hash_table_destroy (valid.object_table);
229  g_hash_table_destroy (valid.map_table);
230  return valid.error_state;
231  }
232  g_hash_table_destroy (valid.object_table);
233  g_hash_table_destroy (valid.map_table);
234  return QOF_SUCCESS;
235 }
236 
237 gboolean
238 is_qsf_object_with_map_be (gchar * map_file, QsfParam * params)
239 {
240  xmlDocPtr doc, map_doc;
241  QofErrorId result;
242  gchar *path, *map_path;
243 
244  g_return_val_if_fail ((params != NULL), FALSE);
245  path = g_strdup (params->filepath);
246  map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file);
247  PINFO (" checking map file '%s'", map_path);
248  if (path == NULL)
249  {
250  qof_error_set_be (params->be, qof_error_register
251  (_("The QSF XML file '%s' could not be found."), TRUE));
252  return FALSE;
253  }
254  doc = xmlParseFile (path);
255  if (doc == NULL)
256  {
257  qof_error_set_be (params->be, qof_error_register
258  (_("There was an error parsing the file '%s'."), TRUE));
259  return FALSE;
260  }
261  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
262  {
263  qof_error_set_be (params->be, qof_error_register
264  (_("Invalid QSF Object file! The QSF object file '%s' "
265  " failed to validate against the QSF object schema. "
266  "The XML structure of the file is either not well-formed "
267  "or the file contains illegal data."), TRUE));
268  return FALSE;
269  }
270  if (map_path == NULL)
271  {
272  qof_error_set_be (params->be, qof_error_register
273  (_("The QSF map file '%s' could not be found."), TRUE));
274  return FALSE;
275  }
276  map_doc = xmlParseFile (map_path);
277  if (map_doc == NULL)
278  {
279  qof_error_set_be (params->be, qof_error_register
280  (_("There was an error parsing the file '%s'."), TRUE));
281  return FALSE;
282  }
283  result = check_qsf_object_with_map_internal (map_doc, doc);
284  return (result == QOF_SUCCESS) ? TRUE : FALSE;
285 }
286 
287 gboolean
288 is_qsf_object_with_map (const gchar * path, gchar * map_file)
289 {
290  xmlDocPtr doc, map_doc;
291  QofErrorId result;
292  gchar *map_path;
293 
294  map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file);
295  if (path == NULL)
296  {
297  return FALSE;
298  }
299  doc = xmlParseFile (path);
300  if (doc == NULL)
301  {
302  return FALSE;
303  }
304  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
305  {
306  return FALSE;
307  }
308  if (map_path == NULL)
309  {
310  return FALSE;
311  }
312  map_doc = xmlParseFile (map_path);
313  result = check_qsf_object_with_map_internal (map_doc, doc);
314  return (result == QOF_SUCCESS) ? TRUE : FALSE;
315 }
316 
317 gboolean
319 {
320  xmlDocPtr doc;
321  struct QsfNodeIterate qsfiter;
322  QsfValidator valid;
323  xmlNodePtr map_root;
324  xmlNsPtr map_ns;
325  gchar *path;
326 
327  g_return_val_if_fail ((params != NULL), FALSE);
328  path = g_strdup (params->filepath);
329  if (path == NULL)
330  {
331  qof_error_set_be (params->be, qof_error_register
332  (_("The QSF XML file '%s' could not be found."), TRUE));
333  return FALSE;
334  }
335  doc = xmlParseFile (path);
336  if (doc == NULL)
337  {
338  qof_error_set_be (params->be, qof_error_register
339  (_("There was an error parsing the file '%s'."), TRUE));
340  return FALSE;
341  }
342  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc))
343  {
344  qof_error_set_be (params->be,
346  _("Invalid QSF Map file! The QSF map file "
347  "failed to validate against the QSF map schema. "
348  "The XML structure of the file is either not well-formed "
349  "or the file contains illegal data."), FALSE));
350  return FALSE;
351  }
352  map_root = xmlDocGetRootElement (doc);
353  map_ns = map_root->ns;
354  qsfiter.ns = map_ns;
355  valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
356  valid.map_table = g_hash_table_new (g_str_hash, g_str_equal);
357  valid.error_state = QOF_SUCCESS;
358  qsf_valid_foreach (map_root, qsf_map_validation_handler,
359  &qsfiter, &valid);
360  if (valid.error_state != QOF_SUCCESS)
361  {
362  g_hash_table_destroy (valid.object_table);
363  return FALSE;
364  }
365  g_hash_table_destroy (valid.object_table);
366  return TRUE;
367 }
368 
369 gboolean
370 is_qsf_map (const gchar * path)
371 {
372  xmlDocPtr doc;
373  struct QsfNodeIterate qsfiter;
374  QsfValidator valid;
375  xmlNodePtr map_root;
376  xmlNsPtr map_ns;
377 
378  g_return_val_if_fail ((path != NULL), FALSE);
379  if (path == NULL)
380  {
381  return FALSE;
382  }
383  doc = xmlParseFile (path);
384  if (doc == NULL)
385  {
386  return FALSE;
387  }
388  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc))
389  {
390  return FALSE;
391  }
392  map_root = xmlDocGetRootElement (doc);
393  map_ns = map_root->ns;
394  qsfiter.ns = map_ns;
395  valid.error_state = QOF_SUCCESS;
396  valid.map_table = g_hash_table_new (g_str_hash, g_str_equal);
397  qsf_valid_foreach (map_root, qsf_map_validation_handler,
398  &qsfiter, &valid);
399  if (valid.error_state != QOF_SUCCESS)
400  {
401  g_hash_table_destroy (valid.map_table);
402  return FALSE;
403  }
404  g_hash_table_destroy (valid.map_table);
405  return TRUE;
406 }
407 
408 static void
409 qsf_map_default_handler (xmlNodePtr child, xmlNsPtr ns, QsfParam * params)
410 {
411  xmlChar * G_GNUC_UNUSED qsf_enum;
412  gchar *iterate;
413  QofErrorId bad_map;
414 
415  g_return_if_fail (params->qsf_define_hash != NULL);
416  iterate = NULL;
417  bad_map = qof_error_register
418  (_("The selected QSF map '%s' contains unusable or "
419  "missing data. This is usually because not all the "
420  "required parameters for the defined objects have "
421  "calculations described in the map."), TRUE);
422  if (qsf_is_element (child, ns, MAP_DEFINE_TAG))
423  {
424  iterate = (gchar*) xmlGetProp (child, BAD_CAST MAP_ITERATE_ATTR);
425  if ((qof_util_bool_to_int (iterate) == 1) &&
427  ((gchar*) xmlGetProp (child, BAD_CAST MAP_E_TYPE))))
428  {
429  params->qof_foreach = (gchar*) xmlGetProp (child, BAD_CAST MAP_E_TYPE);
430  PINFO (" iterating over '%s' objects", params->qof_foreach);
431  }
432  if (NULL == g_hash_table_lookup (params->qsf_define_hash,
433  xmlGetProp (child, BAD_CAST MAP_E_TYPE)))
434  {
435  g_hash_table_insert (params->qsf_define_hash,
436  xmlGetProp (child, BAD_CAST MAP_E_TYPE),
437  params->child_node);
438  }
439  else
440  {
441  qof_error_set_be (params->be, bad_map);
442  PERR (" ERR_QSF_BAD_MAP set");
443  return;
444  }
445  }
446  if (qsf_is_element (child, ns, MAP_DEFAULT_TAG))
447  {
449  (xmlGetProp (child, BAD_CAST MAP_TYPE_ATTR), MAP_ENUM_TYPE))
450  {
451  qsf_enum = xmlNodeGetContent (child);
453  PERR (" enum todo incomplete");
457  if (NULL == g_hash_table_lookup (params->qsf_default_hash,
458  xmlNodeGetContent (child)))
459  {
460  g_hash_table_insert (params->qsf_default_hash,
461  xmlNodeGetContent (child), child);
462  }
463  else
464  {
465  qof_error_set_be (params->be, bad_map);
466  PERR (" ERR_QSF_BAD_MAP set");
467  return;
468  }
469  }
471  else
472  {
473  if (NULL == g_hash_table_lookup (params->qsf_default_hash,
474  xmlGetProp (child, BAD_CAST MAP_NAME_ATTR)))
475  {
476  g_hash_table_insert (params->qsf_default_hash,
477  xmlGetProp (child, BAD_CAST MAP_NAME_ATTR), child);
478  }
479  else
480 /* if(0 != xmlHashAddEntry(params->default_map,
481  xmlGetProp(child_node, MAP_NAME_ATTR), child_node))*/
482  {
483  qof_error_set_be (params->be, bad_map);
484  PERR (" ERR_QSF_BAD_MAP set");
485  return;
486  }
487  }
488  }
489 }
490 
491 static void
492 qsf_map_top_node_handler (xmlNodePtr child, xmlNsPtr ns,
493  QsfParam * params)
494 {
495  xmlChar *qof_version;
496  gchar *buff;
497  struct QsfNodeIterate qsfiter;
498 
499  if (!params->qsf_define_hash)
500  return;
501  if (!params->qsf_default_hash)
502  return;
503  ENTER (" map top node child=%s", child->name);
504  buff = NULL;
505  if (qsf_is_element (child, ns, MAP_DEFINITION_TAG))
506  {
507  qof_version = xmlGetProp (child, BAD_CAST MAP_QOF_VERSION);
508  buff = g_strdup_printf ("%i", QSF_QOF_VERSION);
509  if (xmlStrcmp (qof_version, BAD_CAST buff) != 0)
510  {
511  qof_error_set_be (params->be, qof_error_register(
512  _("The QSF Map file '%s' was written for a different "
513  "version of QOF. It may need to be modified to work with "
514  "your current QOF installation."), TRUE));
515  LEAVE (" BAD QOF VERSION");
516  return;
517  }
518  qsfiter.ns = ns;
519  qsf_node_foreach (child, qsf_map_default_handler, &qsfiter, params);
520  }
521  LEAVE (" ");
522 }
523 
524 static char *
525 qsf_else_set_value (xmlNodePtr parent, gchar * content,
526  xmlNsPtr map_ns)
527 {
528  xmlNodePtr cur_node;
529 
530  content = NULL;
531  for (cur_node = parent->children; cur_node != NULL;
532  cur_node = cur_node->next)
533  {
534  if (qsf_is_element (cur_node, map_ns, QSF_CONDITIONAL_SET))
535  {
536  content = (gchar *) xmlNodeGetContent (cur_node);
537  return content;
538  }
539  }
540  return NULL;
541 }
542 
543 /* Handles the set tag in the map.
544 This function will be overhauled once inside QOF
545 QOF hook required for "Lookup in the receiving application"
546 */
547 static gchar *
548 qsf_set_handler (xmlNodePtr parent, GHashTable * default_hash,
549  gchar * content, QsfParam * params)
550 {
551  xmlNodePtr cur_node, lookup_node;
552 
553  ENTER (" lookup problem");
554  content = NULL;
555  for (cur_node = parent->children; cur_node != NULL;
556  cur_node = cur_node->next)
557  {
558  if (qsf_is_element (cur_node, params->map_ns, QSF_CONDITIONAL_SET))
559  {
560  content = (gchar *) xmlGetProp (cur_node, BAD_CAST QSF_OPTION);
561  if (qsf_strings_equal (xmlGetProp (cur_node,
562  BAD_CAST QSF_OPTION), "qsf_lookup_string"))
563  {
564  lookup_node =
565  (xmlNodePtr) g_hash_table_lookup (default_hash,
566  xmlNodeGetContent (cur_node));
567  content =
568  (gchar *) xmlGetProp (lookup_node,
569  BAD_CAST MAP_VALUE_ATTR);
571  /* Find by name, get GUID, return GUID as string. */
572  g_message ("Lookup %s in the receiving application\n",
573  content);
574  LEAVE (" todo");
575  return content;
576  }
577  if (content)
578  {
579  lookup_node =
580  (xmlNodePtr) g_hash_table_lookup (default_hash,
581  xmlNodeGetContent (cur_node));
582  content =
583  (gchar *) xmlGetProp (lookup_node, BAD_CAST "value");
584  return content;
585  }
586  content = (gchar *) xmlGetProp (parent, BAD_CAST "boolean");
587  if (!content)
588  {
590  lookup_node =
591  (xmlNodePtr) g_hash_table_lookup (params->
592  qsf_parameter_hash,
593  xmlGetProp (parent->parent, BAD_CAST MAP_TYPE_ATTR));
594  if (lookup_node)
595  {
596  return (gchar *) xmlNodeGetContent (lookup_node);
597  }
598  LEAVE (" check arguments");
599  return (gchar *) xmlNodeGetContent (cur_node);
600  }
601  }
602  }
603  LEAVE (" null");
604  return NULL;
605 }
606 
607 static void
608 qsf_calculate_else (xmlNodePtr param_node, xmlNodePtr child,
609  QsfParam * params)
610 {
611  xmlNodePtr export_node;
612  xmlChar *output_content, *object_data;
613 
614  if (qsf_is_element (param_node, params->map_ns, QSF_CONDITIONAL_ELSE))
615  {
616  if (params->boolean_calculation_done == 0)
617  {
618  output_content = object_data = NULL;
619  output_content = BAD_CAST qsf_set_handler (param_node,
620  params->
621  qsf_default_hash, (gchar *) output_content, params);
622  if (output_content == NULL)
623  {
624  output_content =
625  xmlGetProp (param_node, BAD_CAST MAP_TYPE_ATTR);
626  object_data =
627  BAD_CAST qsf_else_set_value (param_node,
628  (gchar *) output_content, params->map_ns);
629  output_content =
630  BAD_CAST xmlGetProp ((xmlNodePtr)
631  g_hash_table_lookup (params->
632  qsf_default_hash,
633  object_data), BAD_CAST MAP_VALUE_ATTR);
634  }
635  if (object_data != NULL)
636  {
637  export_node =
638  (xmlNodePtr) g_hash_table_lookup (params->
639  qsf_parameter_hash,
640  xmlGetProp (params->
641  child_node, BAD_CAST QSF_OBJECT_TYPE));
642  object_data = xmlNodeGetContent (export_node);
643  }
644  if (output_content != NULL)
645  {
646  object_data = output_content;
647  }
648  export_node =
649  xmlAddChild (params->lister,
650  xmlNewNode (params->qsf_ns,
651  xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
652  xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
653  xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
654  xmlNodeAddContent (export_node, object_data);
655  params->boolean_calculation_done = 1;
656  }
657  }
658 }
659 
660 static void
661 qsf_set_format_value (xmlChar * format, gchar * qsf_time_now_as_string,
662  xmlNodePtr cur_node, QsfParam * params)
663 {
664  gint result;
665  xmlChar *content;
666  time_t *output;
667  struct tm *tmp;
668  time_t tester;
669  xmlNodePtr kl;
670  regex_t reg;
671 
674  result = 0;
675  if (format == NULL)
676  {
677  return;
678  }
679  ENTER (" ");
680  content = xmlNodeGetContent (cur_node);
681  output =
682  (time_t *) g_hash_table_lookup (params->qsf_default_hash, content);
683  if (!output)
684  {
687  tester = time (NULL);
688  tmp = gmtime (&tester);
691  kl = (xmlNodePtr) g_hash_table_lookup (params->qsf_parameter_hash,
692  content);
693  if (!kl)
694  {
695  LEAVE (" no suitable date set.");
696  return;
697  }
699  strptime ((char *) xmlNodeGetContent (kl), QSF_XSD_TIME, tmp);
700  if (!tmp)
701  {
702  LEAVE (" empty date field in QSF object.\n");
703  return;
704  }
705  tester = mktime (tmp);
706  output = &tester;
707  }
708  result = regcomp (&reg, "%[a-zA-Z]", REG_EXTENDED | REG_NOSUB);
709  result = regexec (&reg, (gchar *) format, (size_t) 0, NULL, 0);
710  if (result == REG_NOMATCH)
711  {
712  format = BAD_CAST "%F";
713  }
714  regfree (&reg);
715  /* QSF_DATE_LENGTH preset for all internal and QSF_XSD_TIME string formats. */
716  strftime (qsf_time_now_as_string, QSF_DATE_LENGTH, (char *) format,
717  gmtime (output));
718  LEAVE (" ok");
719 }
720 
721 static void
722 qsf_boolean_set_value (xmlNodePtr parent, QsfParam * params,
723  gchar * content, xmlNsPtr map_ns)
724 {
725  xmlNodePtr cur_node;
726  xmlChar *boolean_name;
727 
728  boolean_name = NULL;
729  for (cur_node = parent->children; cur_node != NULL;
730  cur_node = cur_node->next)
731  {
732  if (qsf_is_element (cur_node, map_ns, QSF_CONDITIONAL_SET))
733  {
734  boolean_name =
735  xmlGetProp (cur_node, BAD_CAST QSF_FORMATTING_OPTION);
736  qsf_set_format_value (boolean_name, content, cur_node, params);
737  }
738  }
739 }
740 
741 static void
742 qsf_calculate_conditional (xmlNodePtr param_node, xmlNodePtr child,
743  QsfParam * params)
744 {
745  xmlNodePtr export_node;
746  xmlChar *output_content;
747 
748  output_content = NULL;
749  if (qsf_is_element (param_node, params->map_ns, QSF_CONDITIONAL))
750  {
751  if (params->boolean_calculation_done == 0)
752  {
753  /* set handler */
754  output_content =
755  BAD_CAST qsf_set_handler (param_node,
756  params->qsf_default_hash,
757  (gchar *) output_content, params);
758  /* If the 'if' contains a boolean that has a default value */
759  if (output_content == NULL)
760  {
761  if (NULL !=
762  xmlGetProp (param_node, BAD_CAST QSF_BOOLEAN_DEFAULT))
763  {
764  output_content =
765  xmlGetProp ((xmlNodePtr)
766  g_hash_table_lookup (params->
767  qsf_default_hash,
768  xmlGetProp
769  (param_node,
770  BAD_CAST
771  QSF_BOOLEAN_DEFAULT)),
772  BAD_CAST MAP_VALUE_ATTR);
773  }
774  /* Is the default set to true? */
775  if (0 ==
776  qsf_compare_tag_strings (output_content,
778  {
779  qsf_boolean_set_value (param_node, params,
780  (gchar *) output_content, params->map_ns);
781  export_node =
782  xmlAddChild (params->lister,
783  xmlNewNode (params->qsf_ns,
784  xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
785  xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
786  xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
787  xmlNodeAddContent (export_node, output_content);
788  params->boolean_calculation_done = 1;
789  }
790  }
791  }
792  }
793 }
794 
795 static void
796 qsf_add_object_tag (QsfParam * params, gint count)
797 {
798  xmlNodePtr extra_node;
799  GString *str;
800  xmlChar *property;
801 
802  str = g_string_new (" ");
803  g_string_printf (str, "%i", count);
804  extra_node = NULL;
805  extra_node = xmlAddChild (params->output_node,
806  xmlNewNode (params->qsf_ns, BAD_CAST QSF_OBJECT_TAG));
807  xmlNewProp (extra_node, BAD_CAST QSF_OBJECT_TYPE,
808  xmlGetProp (params->convert_node, BAD_CAST QSF_OBJECT_TYPE));
809  property = xmlCharStrdup (str->str);
810  xmlNewProp (extra_node, BAD_CAST QSF_OBJECT_COUNT, property);
811  params->lister = extra_node;
812 }
813 
814 static gint
815 identify_source_func (gconstpointer qsf_object, gconstpointer map)
816 {
817  PINFO (" qsf_object=%s, map=%s",
818  ((QsfObject *) qsf_object)->object_type, (QofIdType) map);
819  return safe_strcmp (((QsfObject *) qsf_object)->object_type,
820  (QofIdType) map);
821 }
822 
823 static void
824 qsf_map_calculate_output (xmlNodePtr param_node, xmlNodePtr child,
825  QsfParam * params)
826 {
827  xmlNodePtr export_node;
828  xmlChar *output_content;
829  xmlNodePtr input_node;
830  GList *source;
831 
832  output_content = xmlNodeGetContent (param_node);
833  DEBUG (" %s", output_content);
834  /* source refers to the source object that provides the data */
835  source = g_list_find_custom (params->qsf_object_list,
836  BAD_CAST xmlGetProp (param_node,
837  BAD_CAST MAP_OBJECT_ATTR), identify_source_func);
838  PINFO (" checking %s", BAD_CAST xmlGetProp (param_node,
839  BAD_CAST MAP_OBJECT_ATTR));
840  if (!source)
841  {
842  DEBUG (" no source found in list.");
843  return;
844  }
845  params->object_set = source->data;
846  input_node = g_hash_table_lookup (params->object_set->parameters,
847  output_content);
848  DEBUG (" node_value=%s, content=%s",
849  xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR),
850  xmlNodeGetContent (input_node));
851  export_node = xmlAddChild (params->lister, xmlNewNode (params->qsf_ns,
852  xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
853  xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
854  xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
855  xmlNodeAddContent (export_node, xmlNodeGetContent (input_node));
856 }
857 
858 static void
859 qsf_map_object_handler (xmlNodePtr child, xmlNsPtr ns, QsfParam * params)
860 {
861  xmlNodePtr param_node;
862  xmlNsPtr map_ns, qsf_ns;
863  gint G_GNUC_UNUSED result;
864 
865  map_ns = ns;
866  qsf_ns = params->qsf_ns;
867  param_node = NULL;
868  result = 0;
869  if (child == NULL)
870  {
871  return;
872  }
873  if (ns == NULL)
874  {
875  return;
876  }
877  params->boolean_calculation_done = 0;
878 
879  if (qsf_is_element (child, map_ns, MAP_CALCULATE_TAG))
880  {
881  params->boolean_calculation_done = 0;
882  /* read the child nodes to prepare the calculation. */
883  for (param_node = child->children; param_node != NULL;
884  param_node = param_node->next)
885  {
886  if (qsf_is_element (param_node, map_ns, QSF_CONDITIONAL_SET))
887  {
888  /* Map the pre-defined defaults */
889  if (0 ==
890  qsf_compare_tag_strings (xmlNodeGetContent
891  (param_node), "qsf_enquiry_date"))
892  {
893  qsf_string_default_handler ("qsf_enquiry_date",
894  params->qsf_default_hash,
895  params->lister, child, qsf_ns);
896  }
897  if (0 ==
898  qsf_compare_tag_strings (xmlNodeGetContent
899  (param_node), "qsf_time_now"))
900  {
901  qsf_date_default_handler ("qsf_time_now",
902  params->qsf_default_hash,
903  params->lister, child, qsf_ns);
904  }
905  if (0 ==
906  qsf_compare_tag_strings (xmlNodeGetContent
907  (param_node), "qsf_time_string"))
908  {
909  qsf_string_default_handler ("qsf_time_string",
910  params->qsf_default_hash,
911  params->lister, child, qsf_ns);
912  }
913  qsf_map_calculate_output (param_node, child, params);
914  }
915  qsf_calculate_conditional (param_node, child, params);
916  qsf_calculate_else (param_node, child, params);
917  }
918  /* calculate_map currently not in use */
919  /* ensure uniqueness of the key before re-instating */
920 /* result = xmlHashAddEntry2(calculate_map,
921  xmlGetProp(child_node, MAP_TYPE_ATTR),
922  xmlGetProp(child_node, MAP_VALUE_ATTR), child_node);
923  if(result != 0) {
924  printf("add entry to calculate hash failed. %s\t%s\t%s.\n",
925  xmlGetProp(child_node, MAP_TYPE_ATTR),
926  xmlGetProp(child_node, MAP_VALUE_ATTR), child_node->name);
927  return;
928  }
929 
930  is_qsf_object_with_map(path, map_path);
931 */
932  }
933 }
934 
935 static void
936 iterator_cb (xmlNodePtr child, xmlNsPtr ns, QsfParam * params)
937 {
938  gchar *object_name;
939 
940  /* count the number of iterators in the QSF file */
941  if (qsf_is_element (child, ns, QSF_OBJECT_TAG))
942  {
943  object_name = (gchar*) xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE);
944  if (0 == safe_strcmp (object_name, params->qof_foreach))
945  {
946  params->foreach_limit++;
947  }
948  }
949 }
950 
951 xmlDocPtr
952 qsf_object_convert (xmlDocPtr mapDoc, xmlNodePtr qsf_root,
953  QsfParam * params)
954 {
955  /* mapDoc : map document. qsf_root: incoming QSF root node. */
956  struct QsfNodeIterate qsfiter;
957  xmlDocPtr output_doc;
958  xmlNode *cur_node;
959  xmlNode *map_root, *output_root;
960 
961  g_return_val_if_fail ((mapDoc && qsf_root && params), NULL);
962  ENTER (" root=%s", qsf_root->name);
963  /* prepare the intermediary document */
964  qsfiter.ns = params->qsf_ns;
965  output_doc = xmlNewDoc (BAD_CAST QSF_XML_VERSION);
966  output_root = xmlNewNode (NULL, BAD_CAST QSF_ROOT_TAG);
967  xmlDocSetRootElement (output_doc, output_root);
968  xmlSetNs (output_root, params->qsf_ns);
969  params->output_node = xmlNewChild (output_root, params->qsf_ns,
970  BAD_CAST QSF_BOOK_TAG, NULL);
971  xmlNewProp (params->output_node, BAD_CAST QSF_BOOK_COUNT,
972  BAD_CAST "1");
973  /* parse the incoming QSF */
974  qsf_book_node_handler (qsf_root->children->next, params->qsf_ns,
975  params);
976  /* parse the map and calculate the values */
977  map_root = xmlDocGetRootElement (mapDoc);
978  params->foreach_limit = 0;
979  qsfiter.ns = params->map_ns;
980  /* sets qof_foreach iterator, defines and defaults. */
981  qsf_node_foreach (map_root, qsf_map_top_node_handler, &qsfiter, params);
982  /* identify the entities of iterator type. */
983  qsfiter.ns = params->qsf_ns;
984  qsf_node_foreach (qsf_root->children->next, iterator_cb, &qsfiter,
985  params);
986  PINFO (" counted %d records", params->foreach_limit);
987  params->count = 0;
988  for (cur_node = map_root->children; cur_node != NULL;
989  cur_node = cur_node->next)
990  {
991  params->convert_node = cur_node;
992  if (qsf_is_element (cur_node, params->map_ns, MAP_OBJECT_TAG))
993  {
994  gint i;
995 
996  params->lister = NULL;
997  PINFO (" found an object tag. starting calculation");
998  /* cur_node describes the target object */
999  if (!qof_class_is_registered ((gchar*)
1000  xmlGetProp (cur_node, BAD_CAST MAP_TYPE_ATTR)))
1001  {
1002  continue;
1003  }
1004  qsf_add_object_tag (params, params->count);
1005  params->count++;
1006  qsfiter.ns = params->map_ns;
1007  PINFO (" params->foreach_limit=%d", params->foreach_limit);
1008  for (i = -1; i < params->foreach_limit; i++)
1009  {
1010  qsf_node_foreach (cur_node, qsf_map_object_handler,
1011  &qsfiter, params);
1012  params->qsf_object_list =
1013  g_list_next (params->qsf_object_list);
1014  params->count++;
1015  }
1016  }
1017  }
1018  params->file_type = OUR_QSF_OBJ;
1019  /* use for debugging */
1020  xmlSaveFormatFileEnc ("-", output_doc, "UTF-8", 1);
1021  LEAVE (" ");
1022  return output_doc;
1023 }
QSF Parameters.
Definition: qsf-xml.h:469
xmlNsPtr qsf_ns
Definition: qsf-xml.h:507
gint map_calculated_count
Definition: qsf-xml.h:575
#define MAP_E_TYPE
Definition: qsf-xml.h:303
#define MAP_ITERATE_ATTR
Definition: qsf-xml.h:158
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:73
#define PERR(format, args...)
Definition: qoflog.h:183
void qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, QsfValidator *valid)
Checks all incoming objects for QOF registration.
Definition: qsf-xml.c:133
const gchar * QofIdType
Definition: qofid.h:81
#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
#define MAP_DEFINE_TAG
Definition: qsf-xml.h:154
#define QSF_ROOT_TAG
Definition: qsf-xml.h:81
gboolean is_qsf_object_with_map(const gchar *path, gchar *map_file)
Validate a QSF file and a selected QSF map.
Definition: qsf-xml-map.c:288
Validation metadata.
Definition: qsf-xml.h:558
GHashTable * map_table
Definition: qsf-xml.h:568
gint count
Definition: qsf-xml.h:476
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
#define MAP_DEFINITION_TAG
Definition: qsf-xml.h:147
#define MAP_VALUE_ATTR
Definition: qsf-xml.h:289
#define MAP_OBJECT_ATTR
Definition: qsf-xml.h:293
gint boolean_calculation_done
Definition: qsf-xml.h:531
#define MAP_TYPE_ATTR
Definition: qsf-xml.h:279
QofBackend * be
Definition: qsf-xml.h:519
#define QSF_OBJECT_TAG
Definition: qsf-xml.h:101
#define MAP_ENUM_TYPE
Definition: qsf-xml.h:307
Private QSF header - not for use by applications.
gint qof_util_bool_to_int(const gchar *val)
Definition: qofutil.c:252
gint foreach_limit
Definition: qsf-xml.h:515
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
#define QSF_CONDITIONAL_SET
Definition: qsf-xml.h:334
#define MAP_QOF_VERSION
Definition: qsf-xml.h:260
One iterator, two typedefs.
Definition: qsf-xml.h:689
QofIdType qof_foreach
Definition: qsf-xml.h:513
#define QSF_FORMATTING_OPTION
Definition: qsf-xml.h:376
#define QSF_BOOK_TAG
Definition: qsf-xml.h:94
#define QSF_XML_BOOLEAN_TEST
Definition: qsf-xml.h:417
#define MAP_DEFAULT_TAG
Definition: qsf-xml.h:229
GList * qsf_object_list
Definition: qsf-xml.h:478
#define QSF_BOOLEAN_DEFAULT
A specific boolean default for this map.
Definition: qsf-xml.h:310
gint qof_registered_count
Definition: qsf-xml.h:578
xmlNodePtr convert_node
Definition: qsf-xml.h:495
QsfStatus
Status of various object during mapping.
Definition: qsf-xml.h:446
#define QOF_SUCCESS
Definition: qoferror.h:124
void qsf_node_foreach(xmlNodePtr parent, QsfNodeCB cb, struct QsfNodeIterate *qsfiter, QsfParam *params)
Definition: qsf-xml.c:115
xmlNodePtr lister
Definition: qsf-xml.h:505
#define DEBUG(format, args...)
Definition: qoflog.h:208
xmlNodePtr child_node
Definition: qsf-xml.h:493
QSF API - Backend, maps, objects and configuration.
#define MAP_CALCULATE_TAG
Definition: qsf-xml.h:251
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
gboolean is_qsf_map_be(QsfParam *params)
Validate a QSF map file.
Definition: qsf-xml-map.c:318
gboolean is_qsf_map(const gchar *path)
Validate a QSF map file.
Definition: qsf-xml-map.c:370
#define QSF_XSD_TIME
Definition: qsf-xml.h:414
guint incoming_count
Definition: qsf-xml.h:581
#define QSF_CONDITIONAL_ELSE
Definition: qsf-xml.h:358
#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
#define QSF_QOF_VERSION
Definition: qsf-xml.h:70
gchar * filepath
Definition: qsf-xml.h:533
Holds a description of the QofObject.
Definition: qsf-xml.h:63
#define QOF_FATAL
general error value
Definition: qoferror.h:131
#define QSF_CONDITIONAL
Definition: qsf-xml.h:322
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:75
#define QSF_MAP_SCHEMA
Definition: qsf-xml.h:423
xmlDocPtr qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, QsfParam *params)
Convert between QSF objects.
Definition: qsf-xml-map.c:952
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 MAP_OBJECT_TAG
Definition: qsf-xml.h:240
#define QSF_DATE_LENGTH
Definition: qsf-xml.h:91
#define ENTER(format, args...)
Definition: qoflog.h:217
#define QSF_OPTION
Definition: qsf-xml.h:366
const gchar * QofLogModule
Definition: qofid.h:85
#define QSF_XML_VERSION
Definition: qsf-xml.h:107
#define MAP_NAME_ATTR
Definition: qsf-xml.h:270