28 #include <libxml/xmlmemory.h>
29 #include <libxml/tree.h>
30 #include <libxml/parser.h>
31 #include <libxml/xmlschemas.h>
38 #define QSF_TYPE_BINARY "binary"
39 #define QSF_TYPE_GLIST "glist"
40 #define QSF_TYPE_FRAME "frame"
44 static void qsf_object_commitCB (gpointer key, gpointer value,
54 typedef struct QSFBackend_s QSFBackend;
62 g_return_if_fail (params);
81 PINFO (
" converting date into time on file write.");
92 qsf_be = (QSFBackend *) be;
93 g_return_if_fail (qsf_be->params);
94 params = qsf_be->params;
111 qsf_be = (QSFBackend *) be;
112 g_return_val_if_fail (qsf_be->params, NULL);
113 params = qsf_be->params;
118 _(
"Level of compression to use: 0 for none, 9 for highest.");
120 _(
"QOF can compress QSF XML files using gzip. "
121 "Note that compression is not used when outputting to STDOUT.");
130 _(
"List of QSF map files to use for this session.");
132 _(
"QOF can convert objects within QSF XML files "
133 "using a map of the changes required.");
141 _(
"Encoding string to use when writing the XML file.");
143 _(
"QSF defaults to UTF-8. Other encodings are supported by "
144 "passing the encoding string in this option.");
152 _(
"Convert deprecated date values to time values.");
154 _(
"Applications that support the new QOF time format "
155 "need to enable this option to convert older date values into time. "
156 "Applications that still use date should not set this option "
157 "until time values are supported.");
167 qsf_map_prepare_list (GList ** maps)
171 *maps = g_list_prepend (*maps,
"pilot-qsf-GnuCashInvoice.xml");
172 *maps = g_list_prepend (*maps,
"pilot-qsf-gncCustomer.xml");
179 gchar *qsf_time_string;
180 gchar *qsf_enquiry_date;
182 gchar *qsf_time_precision;
184 g_return_if_fail (params != NULL);
195 params->map_ns = NULL;
201 g_hash_table_new (g_str_hash, g_str_equal);
202 params->qsf_default_hash = g_hash_table_new (g_str_hash, g_str_equal);
203 params->qsf_define_hash = g_hash_table_new (g_str_hash, g_str_equal);
204 params->qsf_calculate_hash =
205 g_hash_table_new (g_str_hash, g_str_equal);
215 #ifndef QOF_DISABLE_DEPRECATED
237 qsf_time_precision =
"%j";
243 g_hash_table_insert (params->qsf_default_hash,
"qsf_enquiry_date",
245 g_hash_table_insert (params->qsf_default_hash,
"qsf_time_now",
247 g_hash_table_insert (params->qsf_default_hash,
"qsf_time_string",
252 (_(
"The selected QSF Object file '%s' requires a "
253 "map but it was not provided."), TRUE);
255 (_(
"When converting XML strings into numbers, an "
256 "overflow has been detected. The QSF object file "
257 "'%s' contains invalid data in a field that is "
258 "meant to hold a number."), TRUE);
262 qsf_determine_file_type (
const gchar * path)
270 if (stat (path, &sbuf) < 0)
274 f = fopen (path,
"a+");
282 if (sbuf.st_size == 0)
284 if (is_our_qsf_object (path))
286 else if (is_qsf_object (path))
288 else if (is_qsf_map (path))
295 const gchar * book_path, gboolean ignore_lock,
296 gboolean create_if_nonexistent)
301 PINFO (
" ignore_lock=%d create_if_nonexistent=%d", ignore_lock,
302 create_if_nonexistent);
303 g_return_if_fail (be != NULL);
304 g_return_if_fail (session);
305 be->
fullpath = g_strdup (book_path);
306 qsf_be = (QSFBackend *) be;
307 g_return_if_fail (qsf_be->params != NULL);
308 qsf_be->fullpath = NULL;
309 if (book_path == NULL)
315 p = strchr (book_path,
':');
318 path = g_strdup (book_path);
319 if (!g_ascii_strncasecmp (path,
"file:", 5))
321 p = g_new0 (gchar, strlen (path) - 5 + 1);
322 strcpy (p, path + 5);
324 qsf_be->fullpath = g_strdup (p);
328 qsf_be->fullpath = g_strdup (book_path);
329 if (create_if_nonexistent)
333 f = fopen (qsf_be->fullpath,
"a+");
339 (_(
"could not write to '%s'. "
340 "That database may be on a read-only file system, "
341 "or you may not have write permission for the "
342 "directory.\n"), TRUE));
352 g_hash_table_destroy (params->qsf_calculate_hash);
353 g_hash_table_destroy (params->qsf_default_hash);
358 xmlFreeNs (params->map_ns);
368 qsf_be = (QSFBackend *) be;
369 g_return_if_fail (qsf_be != NULL);
370 qsf_free_params (qsf_be->params);
371 g_free (qsf_be->fullpath);
372 qsf_be->fullpath = NULL;
383 ent_ref_cb (
QofEntity * ent, gpointer user_data)
393 g_return_if_fail (params);
405 if (reference_setter != NULL)
409 reference_setter (ent, reference);
418 insert_ref_cb (
QofObject * obj, gpointer user_data)
423 g_return_if_fail (params);
432 qsfdoc_to_qofbook (
QsfParam * params)
441 g_return_val_if_fail (params != NULL, FALSE);
442 g_return_val_if_fail (params->
input_doc != NULL, FALSE);
443 g_return_val_if_fail (params->
book != NULL, FALSE);
445 qsf_root = xmlDocGetRootElement (params->
input_doc);
448 qsf_ns = qsf_root->ns;
453 qsf_node_foreach (qsf_root, qsf_book_node_handler, &qiter, params);
455 while (object_list != NULL)
458 object_list = g_list_next (object_list);
465 g_return_val_if_fail (inst != NULL, FALSE);
468 qsf_object_commitCB, params);
478 load_qsf_object (
QofBook * book,
const gchar * fullpath,
481 xmlNodePtr qsf_root, map_root;
482 xmlDocPtr mapDoc, foreign_doc;
483 gchar *map_path, *map_file;
490 qof_error_set_be (params->
be, params->err_nomap);
493 foreign_doc = xmlParseFile (fullpath);
494 if (foreign_doc == NULL)
497 (_(
"There was an error parsing the file '%s'.\n"), TRUE));
501 qsf_root = xmlDocGetRootElement (foreign_doc);
502 params->
qsf_ns = qsf_root->ns;
504 map_path = g_strdup_printf (
"%s/%s", QSF_SCHEMA_DIR, map_file);
507 qof_error_set_be (params->
be, params->err_nomap);
510 mapDoc = xmlParseFile (map_path);
513 qof_error_set_be (params->
be, params->err_nomap);
516 map_root = xmlDocGetRootElement (mapDoc);
517 params->map_ns = map_root->ns;
518 params->
input_doc = qsf_object_convert (mapDoc, qsf_root, params);
519 qsfdoc_to_qofbook (params);
524 load_our_qsf_object (
const gchar * fullpath,
QsfParam * params)
528 params->
input_doc = xmlParseFile (fullpath);
532 (_(
"There was an error parsing the file '%s'."), TRUE));
536 qsf_root = xmlDocGetRootElement (params->
input_doc);
537 params->
qsf_ns = qsf_root->ns;
538 return qsfdoc_to_qofbook (params);
568 g_return_if_fail (be != NULL);
569 g_return_if_fail (book != NULL);
570 qsf_be = (QSFBackend *) be;
571 g_return_if_fail (qsf_be != NULL);
572 g_return_if_fail (qsf_be->fullpath != NULL);
573 g_return_if_fail (qsf_be->params != NULL);
575 (_(
"There was an error parsing the file '%s'."), TRUE);
576 params = qsf_be->params;
578 DEBUG (
" qsf_be->fullpath=%s", qsf_be->fullpath);
579 path = g_strdup (qsf_be->fullpath);
580 f = fopen (path,
"r");
583 (_(
"There was an error reading the file '%s'."), TRUE));
587 result = is_our_qsf_object_be (params);
591 result = load_our_qsf_object (path, params);
593 qof_error_set_be (be, parse_err);
596 else if (is_qsf_object_be (params))
599 result = load_qsf_object (book, path, params);
601 qof_error_set_be (be, parse_err);
612 if (is_qsf_map_be (params))
616 (_(
"The selected file '%s' is a QSF map and cannot "
617 "be opened as a QSF object."), TRUE));
623 qsf_object_sequence (
QofParam * qof_param, gpointer data)
626 GSList *checklist, *result;
628 g_return_if_fail (data != NULL);
634 for (result = checklist; result != NULL; result = result->next)
638 qof_param->param_type))
641 g_slist_free (checklist);
663 qsf_supported_parameters (gpointer type, gpointer user_data)
667 g_return_if_fail (user_data != NULL);
676 qsf_to_kvp_helper (
const char *type_string)
678 if (0 ==
safe_strcmp (QOF_TYPE_INT64, type_string))
680 if (0 ==
safe_strcmp (QOF_TYPE_DOUBLE, type_string))
682 if (0 ==
safe_strcmp (QOF_TYPE_NUMERIC, type_string))
684 if (0 ==
safe_strcmp (QOF_TYPE_STRING, type_string))
688 #ifndef QOF_DISABLE_DEPRECATED
694 if (0 ==
safe_strcmp (QSF_TYPE_BINARY, type_string))
696 if (0 ==
safe_strcmp (QSF_TYPE_GLIST, type_string))
698 if (0 ==
safe_strcmp (QSF_TYPE_FRAME, type_string))
710 return QOF_TYPE_INT64;
715 return QOF_TYPE_DOUBLE;
720 return QOF_TYPE_NUMERIC;
725 return QOF_TYPE_STRING;
730 return QOF_TYPE_GUID;
733 #ifndef QOF_DISABLE_DEPRECATED
742 return QOF_TYPE_BOOLEAN;
747 return QOF_TYPE_TIME;
752 return QSF_TYPE_BINARY;
757 return QSF_TYPE_GLIST;
762 return QSF_TYPE_FRAME;
774 qsf_from_kvp_helper (
const gchar * path,
KvpValue * content,
786 g_return_if_fail (params && path && content);
787 n = kvp_value_get_type (content);
797 #ifndef QOF_DISABLE_DEPRECATED
805 xmlNewNode (params->
qsf_ns,
806 BAD_CAST qof_param->param_type));
807 xmlNodeAddContent (node,
810 BAD_CAST qof_param->param_name);
826 qsf_from_kvp_helper, params);
833 PERR (
" unsupported value = %d", kvp_value_get_type (content));
840 qsf_from_coll_cb (
QofEntity * ent, gpointer user_data)
853 BAD_CAST qof_param->param_type));
854 xmlNodeAddContent (node, BAD_CAST qsf_guid);
856 BAD_CAST qof_param->param_name);
862 qof_reference_list_cb (gconstpointer a, gconstpointer b)
871 g_return_val_if_fail ((bb != NULL), 1);
872 g_return_val_if_fail ((aa->
type != NULL), 1);
876 aa->
param->param_name)))
887 if (referenceList == NULL)
889 g_return_val_if_fail (find != NULL, NULL);
893 g_list_find_custom (referenceList, find, qof_reference_list_cb);
894 if (single_ref == NULL)
897 g_list_free (single_ref);
902 reference_list_lookup (gpointer data, gpointer user_data)
909 xmlNodePtr node, object_node;
921 starter->
type = g_strdup (ent->e_type);
922 starter->
param = ref_param;
925 reference = qof_reference_lookup (copy_list, starter);
927 if (reference != NULL)
929 if ((ref_param->param_getfcn == NULL)
930 || (ref_param->param_setfcn == NULL))
932 ref_name = g_strdup (reference->
param->param_name);
934 xmlAddChild (object_node,
935 xmlNewNode (ns, BAD_CAST QOF_TYPE_GUID));
937 xmlNodeAddContent (node, BAD_CAST qsf_guid);
943 ent = (
QofEntity *) ref_param->param_getfcn (ent, ref_param);
950 xmlAddChild (object_node,
951 xmlNewNode (ns, BAD_CAST QOF_TYPE_GUID));
954 xmlNodeAddContent (node, BAD_CAST qsf_guid);
956 BAD_CAST ref_param->param_name);
965 qsf_entity_foreach (
QofEntity * ent, gpointer data)
968 GSList *param_list, *supported;
970 xmlNodePtr node, object_node;
972 gchar *string_buffer;
982 g_return_if_fail (data != NULL);
984 param_count = ++params->
count;
992 BAD_CAST ent->e_type);
993 string_buffer = g_strdup_printf (
"%i", param_count);
995 BAD_CAST string_buffer);
996 g_free (string_buffer);
998 while (param_list != NULL)
1000 qof_param = (
QofParam *) param_list->data;
1001 g_return_if_fail (qof_param != NULL);
1002 if (0 ==
safe_strcmp (qof_param->param_type, QOF_TYPE_GUID))
1007 node = xmlAddChild (object_node, xmlNewNode (ns, BAD_CAST
1010 string_buffer = g_strdup (cm_sa);
1011 xmlNodeAddContent (node, BAD_CAST string_buffer);
1014 g_free (string_buffer);
1021 g_list_foreach (ref, reference_list_lookup, params);
1025 qsf_coll = qof_param->param_getfcn (ent, qof_param);
1034 param_list = g_slist_next (param_list);
1041 (
QofEntity *) qof_param->param_getfcn (ent, qof_param);
1044 param_list = g_slist_next (param_list);
1047 node = xmlAddChild (object_node, xmlNewNode (ns, BAD_CAST
1048 qof_param->param_type));
1051 string_buffer = g_strdup (cm_sa);
1052 xmlNodeAddContent (node, BAD_CAST string_buffer);
1054 qof_param->param_name);
1055 xmlNewProp (node, BAD_CAST
"name",
1056 BAD_CAST choice_ent->e_type);
1057 g_free (string_buffer);
1058 param_list = g_slist_next (param_list);
1061 if (0 ==
safe_strcmp (qof_param->param_type, QOF_TYPE_KVP))
1064 (
KvpFrame *) qof_param->param_getfcn (ent, qof_param);
1071 if ((qof_param->param_setfcn != NULL)
1072 && (qof_param->param_getfcn != NULL))
1075 supported != NULL; supported = g_slist_next (supported))
1077 if (0 ==
safe_strcmp ((
const gchar *) supported->data,
1078 (
const gchar *) qof_param->param_type))
1080 node = xmlAddChild (object_node,
1081 xmlNewNode (ns, BAD_CAST qof_param->param_type));
1085 xmlNodeAddContent (node, BAD_CAST string_buffer);
1087 qof_param->param_name);
1088 g_free (string_buffer);
1092 param_list = g_slist_next (param_list);
1097 qsf_foreach_obj_type (
QofObject * qsf_obj, gpointer data)
1103 g_return_if_fail (data != NULL);
1106 if ((qsf_obj->
create == NULL) || (qsf_obj->
foreach == NULL))
1108 PINFO (
" qsf_obj QOF support failed %s", qsf_obj->e_type);
1113 book = params->
book;
1115 g_slist_foreach (support, qsf_supported_parameters, params);
1126 xmlNodePtr top_node, node;
1129 const GUID *book_guid;
1131 g_return_val_if_fail (book != NULL, NULL);
1132 params->
book = book;
1138 xmlDocSetRootElement (doc, top_node);
1141 params->
qsf_ns = top_node->ns;
1158 write_qsf_from_book (
const gchar *path,
QofBook * book,
1166 qsf_doc = qofbook_to_qsf (book, params);
1168 PINFO (
" use_gz_level=%" G_GINT64_FORMAT
" encoding=%s",
1172 g_return_if_fail (qsf_is_valid
1175 xmlSaveFormatFileEnc (path, qsf_doc, params->
encoding, 1);
1176 if (write_result < 0)
1179 (_(
"Could not write to '%s'. Check that you have "
1180 "permission to write to this file and that there is "
1181 "sufficient space to create it."), TRUE));
1184 qof_object_mark_clean (book);
1192 qsf_doc = qofbook_to_qsf (book, params);
1193 g_return_if_fail (qsf_is_valid
1195 PINFO (
" use_gz_level=%" G_GINT64_FORMAT
" encoding=%s",
1197 xmlSaveFormatFileEnc (
"-", qsf_doc, params->
encoding, 1);
1198 fprintf (stdout,
"\n");
1199 qof_object_mark_clean (book);
1209 qsf_be = (QSFBackend *) be;
1210 params = qsf_be->params;
1212 if (!qsf_be->fullpath || (*qsf_be->fullpath ==
'\0'))
1214 write_qsf_to_stdout (book, params);
1217 path = strdup (qsf_be->fullpath);
1218 write_qsf_from_book (path, book, params);
1230 #ifndef QOF_DISABLE_DEPRECATED
1241 cm_i64 = strtoll (content, &tail, 0);
1244 return kvp_value_new_gint64 (cm_i64);
1251 cm_double = strtod (content, &tail);
1253 return kvp_value_new_double (cm_double);
1259 return kvp_value_new_numeric (cm_numeric);
1264 return kvp_value_new_string (content);
1269 cm_guid = g_new0 (
GUID, 1);
1271 return kvp_value_new_guid (cm_guid);
1284 retval = kvp_value_new_time (qt);
1290 PERR (
" failed to parse date");
1292 #ifndef QOF_DISABLE_DEPRECATED
1296 kvp_time_t = mktime (&kvp_time);
1297 timespecFromTime_t (&cm_date, kvp_time_t);
1298 return kvp_value_new_timespec (cm_date);
1326 qsf_object_commitCB (gpointer key, gpointer value, gpointer data)
1334 const gchar *qof_type, *parameter_name;
1340 gboolean cm_boolean;
1343 gchar cm_char, (*char_getter) (xmlNodePtr);
1350 void (*string_setter) (
QofEntity *,
const gchar *);
1353 void (*double_setter) (
QofEntity *, gdouble);
1354 void (*boolean_setter) (
QofEntity *, gboolean);
1355 void (*i32_setter) (
QofEntity *, gint32);
1356 void (*i64_setter) (
QofEntity *, gint64);
1357 void (*char_setter) (
QofEntity *, gchar);
1359 g_return_if_fail (data && value && key);
1361 node = (xmlNodePtr) value;
1362 parameter_name = (
const gchar *) key;
1363 qof_type = (gchar *) node->name;
1365 targetBook = params->
book;
1377 string_setter = (void (*)(
QofEntity *,
const gchar *)) cm_setter;
1378 if (string_setter != NULL)
1381 string_setter (qsf_ent, (gchar *) xmlNodeGetContent (node));
1385 #ifndef QOF_DISABLE_DEPRECATED
1397 if (time_setter != NULL)
1403 (
const gchar*) xmlNodeGetContent (node),
1409 time_setter (qsf_ent, qt);
1414 PERR (
" failed to parse date string");
1417 #ifndef QOF_DISABLE_DEPRECATED
1425 const gchar *timechk;
1427 memset (&qsf_time,
'\0',
sizeof (qsf_time));
1428 cm_date.tv_nsec = 0;
1433 strptime ((
char *) xmlNodeGetContent (node),
QSF_XSD_TIME,
1435 g_return_if_fail (timechk != NULL);
1436 qsf_time_t = mktime (&qsf_time);
1437 if (qsf_time_t != -3600)
1439 timespecFromTime_t (&cm_date, qsf_time_t);
1440 if (date_setter != NULL)
1443 date_setter (qsf_ent, cm_date);
1449 if ((
safe_strcmp (qof_type, QOF_TYPE_NUMERIC) == 0) ||
1454 tmp = (
char *) xmlNodeGetContent (node);
1457 if (numeric_setter != NULL)
1460 numeric_setter (qsf_ent, cm_numeric);
1466 cm_guid = g_new0 (
GUID, 1);
1471 _(
"The selected QSF object file '%s' contains one or "
1472 "more invalid GUIDs. The file cannot be processed - "
1473 "please check the source of the file and try again."),
1475 PINFO (
" string to guid conversion failed for %s:%s:%s",
1476 xmlNodeGetContent (node), obj_type, qof_type);
1481 if (0 ==
safe_strcmp (QOF_PARAM_GUID, reference_type))
1501 (gint32) strtol ((
char *) xmlNodeGetContent (node), &tail, 0);
1504 i32_setter = (void (*)(
QofEntity *, gint32)) cm_setter;
1505 if (i32_setter != NULL)
1508 i32_setter (qsf_ent, cm_i32);
1513 qof_error_set_be (params->
be, params->err_overflow);
1518 cm_i64 = strtoll ((gchar *) xmlNodeGetContent (node), &tail, 0);
1521 i64_setter = (void (*)(
QofEntity *, gint64)) cm_setter;
1522 if (i64_setter != NULL)
1525 i64_setter (qsf_ent, cm_i64);
1530 qof_error_set_be (params->
be, params->err_overflow);
1535 cm_double = strtod ((gchar *) xmlNodeGetContent (node), &tail);
1538 double_setter = (void (*)(
QofEntity *, gdouble)) cm_setter;
1539 if (double_setter != NULL)
1542 double_setter (qsf_ent, cm_double);
1547 if (
safe_strcmp (qof_type, QOF_TYPE_BOOLEAN) == 0)
1554 boolean_setter = (void (*)(
QofEntity *, gboolean)) cm_setter;
1555 if (boolean_setter != NULL)
1558 boolean_setter (qsf_ent, cm_boolean);
1565 qsf_to_kvp_helper ((gchar *)
1571 string_to_kvp_value ((gchar *) xmlNodeGetContent (node),
1573 cm_kvp = (
KvpFrame *) cm_param->param_getfcn (qsf_ent, cm_param);
1586 qsf_coll = cm_param->param_getfcn (qsf_ent, cm_param);
1588 cm_guid = g_new0 (
GUID, 1);
1593 _(
"The selected QSF object file '%s' contains one or "
1594 "more invalid 'collect' values. The file cannot be processed - "
1595 "please check the source of the file and try again."),
1597 PINFO (
" string to guid collect failed for %s",
1598 xmlNodeGetContent (node));
1606 reference->
type = g_strdup (qsf_ent->e_type);
1608 reference->
ent_guid = &qsf_ent->guid;
1610 copy_param->param_name = g_strdup (cm_param->param_name);
1611 copy_param->param_type = g_strdup (cm_param->param_type);
1612 reference->
param = copy_param;
1618 char_getter = (gchar (*)(xmlNodePtr)) xmlNodeGetContent;
1619 cm_char = char_getter (node);
1620 char_setter = (void (*)(
QofEntity *, gchar)) cm_setter;
1621 if (char_setter != NULL)
1624 char_setter (qsf_ent, cm_char);
1631 qsf_backend_new (
void)
1636 qsf_be = g_new0 (QSFBackend, 1);
1639 qsf_be->params = g_new0 (
QsfParam, 1);
1640 qsf_be->params->be = be;
1641 qsf_param_init (qsf_be->params);
1642 qsf_be->be.session_begin = qsf_session_begin;
1644 be->session_end = qsf_session_end;
1645 be->destroy_backend = qsf_destroy_backend;
1646 be->load = qsf_file_type;
1651 be->rollback = NULL;
1653 be->compile_query = NULL;
1654 be->free_query = NULL;
1655 be->run_query = NULL;
1658 be->events_pending = NULL;
1659 be->process_events = NULL;
1661 be->sync = qsf_write_file;
1663 be->load_config = qsf_load_config;
1664 be->get_config = qsf_get_config;
1666 qsf_be->fullpath = NULL;
1686 bindtextdomain (PACKAGE, LOCALE_DIR);