QOF 0.7.5
|
00001 /******************************************************************* 00002 * qsf-backend.c 00003 * 00004 * Sat Jan 1 15:07:14 2005 00005 * Copyright 2005, 2006 Neil Williams 00006 * linux@codehelp.co.uk 00007 *******************************************************************/ 00008 /* 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "config.h" 00025 #include <errno.h> 00026 #include <sys/stat.h> 00027 #include <glib.h> 00028 #include <libxml/xmlmemory.h> 00029 #include <libxml/tree.h> 00030 #include <libxml/parser.h> 00031 #include <libxml/xmlschemas.h> 00032 #include "qof.h" 00033 #include "qofobject-p.h" 00034 #include "qof-backend-qsf.h" 00035 #include "qsf-xml.h" 00036 #include "qsf-dir.h" 00037 00038 #define QSF_TYPE_BINARY "binary" 00039 #define QSF_TYPE_GLIST "glist" 00040 #define QSF_TYPE_FRAME "frame" 00041 00042 static QofLogModule log_module = QOF_MOD_QSF; 00043 00044 static void qsf_object_commitCB (gpointer key, gpointer value, 00045 gpointer data); 00046 00047 struct QSFBackend_s 00048 { 00049 QofBackend be; 00050 QsfParam *params; 00051 gchar *fullpath; 00052 }; 00053 00054 typedef struct QSFBackend_s QSFBackend; 00055 00056 static void 00057 option_cb (QofBackendOption * option, gpointer data) 00058 { 00059 QsfParam *params; 00060 00061 params = (QsfParam *) data; 00062 g_return_if_fail (params); 00063 if (0 == safe_strcmp (QSF_COMPRESS, option->option_name)) 00064 { 00065 params->use_gz_level = (*(gint64 *) option->value); 00066 PINFO (" compression=%" G_GINT64_FORMAT, params->use_gz_level); 00067 } 00068 if (0 == safe_strcmp (QSF_MAP_FILES, option->option_name)) 00069 { 00070 params->map_files = g_list_copy ((GList *) option->value); 00071 } 00072 if (0 == safe_strcmp (QSF_ENCODING, option->option_name)) 00073 { 00074 params->encoding = g_strdup (option->value); 00075 PINFO (" encoding=%s", params->encoding); 00076 } 00077 if (0 == safe_strcmp (QSF_DATE_CONVERT, option->option_name)) 00078 { 00079 params->convert = (*(double *) option->value); 00080 if (params->convert > 0) 00081 PINFO (" converting date into time on file write."); 00082 } 00083 } 00084 00085 static void 00086 qsf_load_config (QofBackend * be, KvpFrame * config) 00087 { 00088 QSFBackend *qsf_be; 00089 QsfParam *params; 00090 00091 ENTER (" "); 00092 qsf_be = (QSFBackend *) be; 00093 g_return_if_fail (qsf_be->params); 00094 params = qsf_be->params; 00095 qof_backend_option_foreach (config, option_cb, params); 00096 LEAVE (" "); 00097 } 00098 00099 static KvpFrame * 00100 qsf_get_config (QofBackend * be) 00101 { 00102 QofBackendOption *option; 00103 QSFBackend *qsf_be; 00104 QsfParam *params; 00105 00106 if (!be) 00107 { 00108 return NULL; 00109 } 00110 ENTER (" "); 00111 qsf_be = (QSFBackend *) be; 00112 g_return_val_if_fail (qsf_be->params, NULL); 00113 params = qsf_be->params; 00114 qof_backend_prepare_frame (be); 00115 option = g_new0 (QofBackendOption, 1); 00116 option->option_name = QSF_COMPRESS; 00117 option->description = 00118 _("Level of compression to use: 0 for none, 9 for highest."); 00119 option->tooltip = 00120 _("QOF can compress QSF XML files using gzip. " 00121 "Note that compression is not used when outputting to STDOUT."); 00122 option->type = KVP_TYPE_GINT64; 00123 /* GINT_TO_POINTER can only be used for 32bit values. */ 00124 option->value = (gpointer) & params->use_gz_level; 00125 qof_backend_prepare_option (be, option); 00126 g_free (option); 00127 option = g_new0 (QofBackendOption, 1); 00128 option->option_name = QSF_MAP_FILES; 00129 option->description = 00130 _("List of QSF map files to use for this session."); 00131 option->tooltip = 00132 _("QOF can convert objects within QSF XML files " 00133 "using a map of the changes required."); 00134 option->type = KVP_TYPE_GLIST; 00135 option->value = (gpointer) params->map_files; 00136 qof_backend_prepare_option (be, option); 00137 g_free (option); 00138 option = g_new0 (QofBackendOption, 1); 00139 option->option_name = QSF_ENCODING; 00140 option->description = 00141 _("Encoding string to use when writing the XML file."); 00142 option->tooltip = 00143 _("QSF defaults to UTF-8. Other encodings are supported by " 00144 "passing the encoding string in this option."); 00145 option->type = KVP_TYPE_STRING; 00146 option->value = (gpointer) params->encoding; 00147 qof_backend_prepare_option (be, option); 00148 g_free (option); 00149 option = g_new0 (QofBackendOption, 1); 00150 option->option_name = QSF_DATE_CONVERT; 00151 option->description = 00152 _("Convert deprecated date values to time values."); 00153 option->tooltip = 00154 _("Applications that support the new QOF time format " 00155 "need to enable this option to convert older date values into time. " 00156 "Applications that still use date should not set this option " 00157 "until time values are supported."); 00158 option->type = KVP_TYPE_GINT64; 00159 option->value = ¶ms->convert; 00160 qof_backend_prepare_option (be, option); 00161 g_free (option); 00162 LEAVE (" "); 00163 return qof_backend_complete_frame (be); 00164 } 00165 00166 GList ** 00167 qsf_map_prepare_list (GList ** maps) 00168 { 00169 /* Add new map filenames here. */ 00171 *maps = g_list_prepend (*maps, "pilot-qsf-GnuCashInvoice.xml"); 00172 *maps = g_list_prepend (*maps, "pilot-qsf-gncCustomer.xml"); 00173 return maps; 00174 } 00175 00176 static void 00177 qsf_param_init (QsfParam * params) 00178 { 00179 gchar *qsf_time_string; 00180 gchar *qsf_enquiry_date; 00181 gchar *qsf_time_now; 00182 gchar *qsf_time_precision; 00183 00184 g_return_if_fail (params != NULL); 00185 params->count = 0; 00186 params->convert = 1; 00187 params->use_gz_level = 0; 00188 params->supported_types = NULL; 00189 params->file_type = QSF_UNDEF; 00190 params->qsf_ns = NULL; 00191 params->output_doc = NULL; 00192 params->output_node = NULL; 00193 params->lister = NULL; 00194 params->full_kvp_path = NULL; 00195 params->map_ns = NULL; 00196 params->map_files = NULL; 00197 params->map_path = NULL; 00198 params->encoding = "UTF-8"; 00199 params->qsf_object_list = NULL; 00200 params->qsf_parameter_hash = 00201 g_hash_table_new (g_str_hash, g_str_equal); 00202 params->qsf_default_hash = g_hash_table_new (g_str_hash, g_str_equal); 00203 params->qsf_define_hash = g_hash_table_new (g_str_hash, g_str_equal); 00204 params->qsf_calculate_hash = 00205 g_hash_table_new (g_str_hash, g_str_equal); 00206 params->referenceList = NULL; 00207 params->supported_types = 00208 g_slist_append (params->supported_types, QOF_TYPE_STRING); 00209 params->supported_types = 00210 g_slist_append (params->supported_types, QOF_TYPE_GUID); 00211 params->supported_types = 00212 g_slist_append (params->supported_types, QOF_TYPE_BOOLEAN); 00213 params->supported_types = 00214 g_slist_append (params->supported_types, QOF_TYPE_NUMERIC); 00215 #ifndef QOF_DISABLE_DEPRECATED 00216 /* Support read if built with deprecated code included. 00217 Support write only if convert option is not enabled. */ 00218 params->supported_types = 00219 g_slist_append (params->supported_types, QOF_TYPE_DATE); 00220 #endif 00221 params->supported_types = 00222 g_slist_append (params->supported_types, QOF_TYPE_TIME); 00223 params->supported_types = 00224 g_slist_append (params->supported_types, QOF_TYPE_INT32); 00225 params->supported_types = 00226 g_slist_append (params->supported_types, QOF_TYPE_INT64); 00227 params->supported_types = 00228 g_slist_append (params->supported_types, QOF_TYPE_DOUBLE); 00229 params->supported_types = 00230 g_slist_append (params->supported_types, QOF_TYPE_CHAR); 00231 params->supported_types = 00232 g_slist_append (params->supported_types, QOF_TYPE_KVP); 00233 params->supported_types = 00234 g_slist_append (params->supported_types, QOF_TYPE_COLLECT); 00235 params->supported_types = 00236 g_slist_append (params->supported_types, QOF_TYPE_CHOICE); 00237 qsf_time_precision = "%j"; 00238 qsf_enquiry_date = qof_time_stamp_now (); 00239 qsf_time_string = qof_date_print (qof_date_get_current(), 00240 QOF_DATE_FORMAT_ISO); 00241 qsf_time_now = qof_time_stamp_now (); 00242 00243 g_hash_table_insert (params->qsf_default_hash, "qsf_enquiry_date", 00244 qsf_enquiry_date); 00245 g_hash_table_insert (params->qsf_default_hash, "qsf_time_now", 00246 qof_time_get_current()); 00247 g_hash_table_insert (params->qsf_default_hash, "qsf_time_string", 00248 qsf_time_string); 00249 /* default map files */ 00250 params->map_files = *qsf_map_prepare_list (¶ms->map_files); 00251 params->err_nomap = qof_error_register 00252 (_("The selected QSF Object file '%s' requires a " 00253 "map but it was not provided."), TRUE); 00254 params->err_overflow = qof_error_register 00255 (_("When converting XML strings into numbers, an " 00256 "overflow has been detected. The QSF object file " 00257 "'%s' contains invalid data in a field that is " 00258 "meant to hold a number."), TRUE); 00259 } 00260 00261 static gboolean 00262 qsf_determine_file_type (const gchar * path) 00263 { 00264 struct stat sbuf; 00265 00266 if (!path) 00267 return TRUE; 00268 if (0 == safe_strcmp (path, QOF_STDOUT)) 00269 return TRUE; 00270 if (stat (path, &sbuf) < 0) 00271 { 00272 /* in case the error is that the file does not exist */ 00273 FILE * f; 00274 f = fopen (path, "a+"); 00275 if (f) 00276 { 00277 fclose (f); 00278 return TRUE; 00279 } 00280 return FALSE; 00281 } 00282 if (sbuf.st_size == 0) 00283 return TRUE; 00284 if (is_our_qsf_object (path)) 00285 return TRUE; 00286 else if (is_qsf_object (path)) 00287 return TRUE; 00288 else if (is_qsf_map (path)) 00289 return TRUE; 00290 return FALSE; 00291 } 00292 00293 static void 00294 qsf_session_begin (QofBackend * be, QofSession * session, 00295 const gchar * book_path, gboolean ignore_lock, 00296 gboolean create_if_nonexistent) 00297 { 00298 QSFBackend *qsf_be; 00299 gchar *p, *path; 00300 00301 PINFO (" ignore_lock=%d create_if_nonexistent=%d", ignore_lock, 00302 create_if_nonexistent); 00303 g_return_if_fail (be != NULL); 00304 g_return_if_fail (session); 00305 be->fullpath = g_strdup (book_path); 00306 qsf_be = (QSFBackend *) be; 00307 g_return_if_fail (qsf_be->params != NULL); 00308 qsf_be->fullpath = NULL; 00309 if (book_path == NULL) 00310 { 00311 /* allow use of stdout */ 00312 qof_error_set_be (be, QOF_SUCCESS); 00313 return; 00314 } 00315 p = strchr (book_path, ':'); 00316 if (p) 00317 { 00318 path = g_strdup (book_path); 00319 if (!g_ascii_strncasecmp (path, "file:", 5)) 00320 { 00321 p = g_new0 (gchar, strlen (path) - 5 + 1); 00322 strcpy (p, path + 5); 00323 } 00324 qsf_be->fullpath = g_strdup (p); 00325 g_free (path); 00326 } 00327 else 00328 qsf_be->fullpath = g_strdup (book_path); 00329 if (create_if_nonexistent) 00330 { 00331 FILE *f; 00332 00333 f = fopen (qsf_be->fullpath, "a+"); 00334 if (f) 00335 fclose (f); 00336 else 00337 { 00338 qof_error_set_be (be, qof_error_register 00339 (_("could not write to '%s'. " 00340 "That database may be on a read-only file system, " 00341 "or you may not have write permission for the " 00342 "directory.\n"), TRUE)); 00343 return; 00344 } 00345 } 00346 qof_error_set_be (be, QOF_SUCCESS); 00347 } 00348 00349 static void 00350 qsf_free_params (QsfParam * params) 00351 { 00352 g_hash_table_destroy (params->qsf_calculate_hash); 00353 g_hash_table_destroy (params->qsf_default_hash); 00354 if (params->referenceList) 00355 g_list_free (params->referenceList); 00356 g_slist_free (params->supported_types); 00357 if (params->map_ns) 00358 xmlFreeNs (params->map_ns); 00359 if (params->output_doc) 00360 xmlFreeDoc (params->output_doc); 00361 } 00362 00363 static void 00364 qsf_session_end (QofBackend * be) 00365 { 00366 QSFBackend *qsf_be; 00367 00368 qsf_be = (QSFBackend *) be; 00369 g_return_if_fail (qsf_be != NULL); 00370 qsf_free_params (qsf_be->params); 00371 g_free (qsf_be->fullpath); 00372 qsf_be->fullpath = NULL; 00373 xmlCleanupParser (); 00374 } 00375 00376 static void 00377 qsf_destroy_backend (QofBackend * be) 00378 { 00379 g_free (be); 00380 } 00381 00382 static void 00383 ent_ref_cb (QofEntity * ent, gpointer user_data) 00384 { 00385 QsfParam *params; 00386 QofEntityReference *ref; 00387 void (*reference_setter) (QofEntity *, QofEntity *); 00388 QofEntity *reference; 00389 QofCollection *coll; 00390 QofIdType type; 00391 00392 params = (QsfParam *) user_data; 00393 g_return_if_fail (params); 00394 while (params->referenceList) 00395 { 00396 ref = (QofEntityReference *) params->referenceList->data; 00397 if (qof_object_is_choice (ent->e_type)) 00398 type = ref->choice_type; 00399 else 00400 type = ref->type; 00401 coll = qof_book_get_collection (params->book, type); 00402 reference = qof_collection_lookup_entity (coll, ref->ref_guid); 00403 reference_setter = 00404 (void (*)(QofEntity *, QofEntity *)) ref->param->param_setfcn; 00405 if (reference_setter != NULL) 00406 { 00407 qof_util_param_edit ((QofInstance *) ent, ref->param); 00408 qof_util_param_edit ((QofInstance *) reference, ref->param); 00409 reference_setter (ent, reference); 00410 qof_util_param_commit ((QofInstance *) ent, ref->param); 00411 qof_util_param_commit ((QofInstance *) reference, ref->param); 00412 } 00413 params->referenceList = g_list_next (params->referenceList); 00414 } 00415 } 00416 00417 static void 00418 insert_ref_cb (QofObject * obj, gpointer user_data) 00419 { 00420 QsfParam *params; 00421 00422 params = (QsfParam *) user_data; 00423 g_return_if_fail (params); 00424 qof_object_foreach (obj->e_type, params->book, ent_ref_cb, params); 00425 } 00426 00427 /*================================================ 00428 Load QofEntity into QofBook from XML in memory 00429 ==================================================*/ 00430 00431 static gboolean 00432 qsfdoc_to_qofbook (QsfParam * params) 00433 { 00434 QofInstance *inst; 00435 struct QsfNodeIterate qiter; 00436 QofBook *book; 00437 GList *object_list; 00438 xmlNodePtr qsf_root; 00439 xmlNsPtr qsf_ns; 00440 00441 g_return_val_if_fail (params != NULL, FALSE); 00442 g_return_val_if_fail (params->input_doc != NULL, FALSE); 00443 g_return_val_if_fail (params->book != NULL, FALSE); 00444 g_return_val_if_fail (params->file_type == OUR_QSF_OBJ, FALSE); 00445 qsf_root = xmlDocGetRootElement (params->input_doc); 00446 if (!qsf_root) 00447 return FALSE; 00448 qsf_ns = qsf_root->ns; 00449 qiter.ns = qsf_ns; 00450 book = params->book; 00451 params->referenceList = 00452 (GList *) qof_book_get_data (book, ENTITYREFERENCE); 00453 qsf_node_foreach (qsf_root, qsf_book_node_handler, &qiter, params); 00454 object_list = g_list_copy (params->qsf_object_list); 00455 while (object_list != NULL) 00456 { 00457 params->object_set = object_list->data; 00458 object_list = g_list_next (object_list); 00459 params->qsf_parameter_hash = params->object_set->parameters; 00460 if (!qof_class_is_registered (params->object_set->object_type)) 00461 continue; 00462 inst = 00463 (QofInstance *) qof_object_new_instance (params->object_set-> 00464 object_type, book); 00465 g_return_val_if_fail (inst != NULL, FALSE); 00466 params->qsf_ent = &inst->entity; 00467 g_hash_table_foreach (params->qsf_parameter_hash, 00468 qsf_object_commitCB, params); 00469 } 00470 qof_object_foreach_type (insert_ref_cb, params); 00471 qof_book_set_data (book, ENTITYREFERENCE, params->referenceList); 00472 return TRUE; 00473 } 00474 00475 /* QofBackend routine to load from file - needs a map. 00476 */ 00477 static gboolean 00478 load_qsf_object (QofBook * book, const gchar * fullpath, 00479 QsfParam * params) 00480 { 00481 xmlNodePtr qsf_root, map_root; 00482 xmlDocPtr mapDoc, foreign_doc; 00483 gchar *map_path, *map_file; 00484 00485 map_file = params->map_path; 00486 mapDoc = NULL; 00487 /* use selected map */ 00488 if (!map_file) 00489 { 00490 qof_error_set_be (params->be, params->err_nomap); 00491 return FALSE; 00492 } 00493 foreign_doc = xmlParseFile (fullpath); 00494 if (foreign_doc == NULL) 00495 { 00496 qof_error_set_be (params->be, qof_error_register 00497 (_("There was an error parsing the file '%s'.\n"), TRUE)); 00498 return FALSE; 00499 } 00500 qsf_root = NULL; 00501 qsf_root = xmlDocGetRootElement (foreign_doc); 00502 params->qsf_ns = qsf_root->ns; 00503 params->book = book; 00504 map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file); 00505 if (!map_path) 00506 { 00507 qof_error_set_be (params->be, params->err_nomap); 00508 return FALSE; 00509 } 00510 mapDoc = xmlParseFile (map_path); 00511 if (!mapDoc) 00512 { 00513 qof_error_set_be (params->be, params->err_nomap); 00514 return FALSE; 00515 } 00516 map_root = xmlDocGetRootElement (mapDoc); 00517 params->map_ns = map_root->ns; 00518 params->input_doc = qsf_object_convert (mapDoc, qsf_root, params); 00519 qsfdoc_to_qofbook (params); 00520 return TRUE; 00521 } 00522 00523 static gboolean 00524 load_our_qsf_object (const gchar * fullpath, QsfParam * params) 00525 { 00526 xmlNodePtr qsf_root; 00527 00528 params->input_doc = xmlParseFile (fullpath); 00529 if (params->input_doc == NULL) 00530 { 00531 qof_error_set_be (params->be, qof_error_register 00532 (_("There was an error parsing the file '%s'."), TRUE)); 00533 return FALSE; 00534 } 00535 qsf_root = NULL; 00536 qsf_root = xmlDocGetRootElement (params->input_doc); 00537 params->qsf_ns = qsf_root->ns; 00538 return qsfdoc_to_qofbook (params); 00539 } 00540 00541 /* Determine the type of QSF and load it into the QofBook 00542 00543 - is_our_qsf_object, OUR_QSF_OBJ, QSF object file using only QOF objects known 00544 to the calling process. No map is required. 00545 - is_qsf_object, IS_QSF_OBJ, QSF object file that may or may not have a QSF map 00546 to convert external objects. This temporary type will be set to HAVE_QSF_MAP 00547 if a suitable map exists, or an error value returned: ERR_QSF_NO_MAP, 00548 ERR_QSF_BAD_MAP or ERR_QSF_WRONG_MAP. This allows the calling process to inform 00549 the user that the QSF itself is valid but a suitable map cannot be found. 00550 - is_qsf_map, IS_QSF_MAP, QSF map file. In the backend, this generates 00551 ERR_QSF_MAP_NOT_OBJ but it can be used internally when processing maps to 00552 match a QSF object. 00553 00554 returns NULL on error, otherwise a pointer to the QofBook. Use 00555 the qof_book_merge API to merge the new data into the current 00556 QofBook. 00557 */ 00558 static void 00559 qsf_file_type (QofBackend * be, QofBook * book) 00560 { 00561 QSFBackend *qsf_be; 00562 QofErrorId parse_err; 00563 QsfParam *params; 00564 FILE *f; 00565 gchar *path; 00566 gboolean result; 00567 00568 g_return_if_fail (be != NULL); 00569 g_return_if_fail (book != NULL); 00570 qsf_be = (QSFBackend *) be; 00571 g_return_if_fail (qsf_be != NULL); 00572 g_return_if_fail (qsf_be->fullpath != NULL); 00573 g_return_if_fail (qsf_be->params != NULL); 00574 parse_err = qof_error_register 00575 (_("There was an error parsing the file '%s'."), TRUE); 00576 params = qsf_be->params; 00577 params->book = book; 00578 DEBUG (" qsf_be->fullpath=%s", qsf_be->fullpath); 00579 path = g_strdup (qsf_be->fullpath); 00580 f = fopen (path, "r"); 00581 if (!f) 00582 qof_error_set_be (be, qof_error_register 00583 (_("There was an error reading the file '%s'."), TRUE)); 00584 else 00585 fclose (f); 00586 params->filepath = g_strdup (path); 00587 result = is_our_qsf_object_be (params); 00588 if (result) 00589 { 00590 params->file_type = OUR_QSF_OBJ; 00591 result = load_our_qsf_object (path, params); 00592 if (!result) 00593 qof_error_set_be (be, parse_err); 00594 return; 00595 } 00596 else if (is_qsf_object_be (params)) 00597 { 00598 params->file_type = IS_QSF_OBJ; 00599 result = load_qsf_object (book, path, params); 00600 if (!result) 00601 qof_error_set_be (be, parse_err); 00602 return; 00603 } 00604 if (qof_error_check_be (be) == params->err_nomap) 00605 { 00606 /* usable QSF object but no map available */ 00607 params->file_type = IS_QSF_OBJ; 00608 result = TRUE; 00609 } 00610 if (result == FALSE) 00611 { 00612 if (is_qsf_map_be (params)) 00613 { 00614 params->file_type = IS_QSF_MAP; 00615 qof_error_set_be (be, qof_error_register 00616 (_("The selected file '%s' is a QSF map and cannot " 00617 "be opened as a QSF object."), TRUE)); 00618 } 00619 } 00620 } 00621 00622 static void 00623 qsf_object_sequence (QofParam * qof_param, gpointer data) 00624 { 00625 QsfParam *params; 00626 GSList *checklist, *result; 00627 00628 g_return_if_fail (data != NULL); 00629 params = (QsfParam *) data; 00630 result = NULL; 00631 checklist = NULL; 00632 params->knowntype = FALSE; 00633 checklist = g_slist_copy (params->supported_types); 00634 for (result = checklist; result != NULL; result = result->next) 00635 { 00636 if (0 == 00637 safe_strcmp ((QofIdType) result->data, 00638 qof_param->param_type)) 00639 params->knowntype = TRUE; 00640 } 00641 g_slist_free (checklist); 00642 if (0 == safe_strcmp (qof_param->param_type, params->qof_type)) 00643 { 00644 params->qsf_sequence = 00645 g_slist_append (params->qsf_sequence, qof_param); 00646 params->knowntype = TRUE; 00647 } 00648 /* handle params->qof_type = QOF_TYPE_GUID and qof_param->param_type != known type */ 00649 if (0 == safe_strcmp (params->qof_type, QOF_TYPE_GUID) 00650 && (params->knowntype == FALSE)) 00651 { 00652 params->qsf_sequence = 00653 g_slist_append (params->qsf_sequence, qof_param); 00654 params->knowntype = TRUE; 00655 } 00656 } 00657 00658 /* receives each entry from supported_types in sequence 00659 type = qof data type from supported list 00660 user_data = params. Holds object type 00661 */ 00662 static void 00663 qsf_supported_parameters (gpointer type, gpointer user_data) 00664 { 00665 QsfParam *params; 00666 00667 g_return_if_fail (user_data != NULL); 00668 params = (QsfParam *) user_data; 00669 params->qof_type = (QofIdType) type; 00670 params->knowntype = FALSE; 00671 qof_class_param_foreach (params->qof_obj_type, qsf_object_sequence, 00672 params); 00673 } 00674 00675 static KvpValueType 00676 qsf_to_kvp_helper (const char *type_string) 00677 { 00678 if (0 == safe_strcmp (QOF_TYPE_INT64, type_string)) 00679 return KVP_TYPE_GINT64; 00680 if (0 == safe_strcmp (QOF_TYPE_DOUBLE, type_string)) 00681 return KVP_TYPE_DOUBLE; 00682 if (0 == safe_strcmp (QOF_TYPE_NUMERIC, type_string)) 00683 return KVP_TYPE_NUMERIC; 00684 if (0 == safe_strcmp (QOF_TYPE_STRING, type_string)) 00685 return KVP_TYPE_STRING; 00686 if (0 == safe_strcmp (QOF_TYPE_GUID, type_string)) 00687 return KVP_TYPE_GUID; 00688 #ifndef QOF_DISABLE_DEPRECATED 00689 if (0 == safe_strcmp (QOF_TYPE_DATE, type_string)) 00690 return KVP_TYPE_TIMESPEC; 00691 #endif 00692 if (0 == safe_strcmp (QOF_TYPE_TIME, type_string)) 00693 return KVP_TYPE_TIME; 00694 if (0 == safe_strcmp (QSF_TYPE_BINARY, type_string)) 00695 return KVP_TYPE_BINARY; 00696 if (0 == safe_strcmp (QSF_TYPE_GLIST, type_string)) 00697 return KVP_TYPE_GLIST; 00698 if (0 == safe_strcmp (QSF_TYPE_FRAME, type_string)) 00699 return KVP_TYPE_FRAME; 00700 return 0; 00701 } 00702 00703 static QofIdTypeConst 00704 kvp_value_to_qof_type_helper (KvpValueType n) 00705 { 00706 switch (n) 00707 { 00708 case KVP_TYPE_GINT64: 00709 { 00710 return QOF_TYPE_INT64; 00711 break; 00712 } 00713 case KVP_TYPE_DOUBLE: 00714 { 00715 return QOF_TYPE_DOUBLE; 00716 break; 00717 } 00718 case KVP_TYPE_NUMERIC: 00719 { 00720 return QOF_TYPE_NUMERIC; 00721 break; 00722 } 00723 case KVP_TYPE_STRING: 00724 { 00725 return QOF_TYPE_STRING; 00726 break; 00727 } 00728 case KVP_TYPE_GUID: 00729 { 00730 return QOF_TYPE_GUID; 00731 break; 00732 } 00733 #ifndef QOF_DISABLE_DEPRECATED 00734 case KVP_TYPE_TIMESPEC: 00735 { 00736 return QOF_TYPE_DATE; 00737 break; 00738 } 00739 #endif 00740 case KVP_TYPE_BOOLEAN : 00741 { 00742 return QOF_TYPE_BOOLEAN; 00743 break; 00744 } 00745 case KVP_TYPE_TIME : 00746 { 00747 return QOF_TYPE_TIME; 00748 break; 00749 } 00750 case KVP_TYPE_BINARY: 00751 { 00752 return QSF_TYPE_BINARY; 00753 break; 00754 } 00755 case KVP_TYPE_GLIST: 00756 { 00757 return QSF_TYPE_GLIST; 00758 break; 00759 } 00760 case KVP_TYPE_FRAME: 00761 { 00762 return QSF_TYPE_FRAME; 00763 break; 00764 } 00765 default: 00766 { 00767 return NULL; 00768 } 00769 } 00770 } 00771 00772 00773 static void 00774 qsf_from_kvp_helper (const gchar * path, KvpValue * content, 00775 gpointer data) 00776 { 00777 QsfParam *params; 00778 QofParam *qof_param; 00779 xmlNodePtr node; 00780 KvpValueType n; 00781 gchar *full_path; 00782 00783 params = (QsfParam *) data; 00784 qof_param = params->qof_param; 00785 full_path = NULL; 00786 g_return_if_fail (params && path && content); 00787 n = kvp_value_get_type (content); 00788 switch (n) 00789 { 00790 case KVP_TYPE_GINT64: 00791 case KVP_TYPE_DOUBLE: 00792 case KVP_TYPE_NUMERIC: 00793 case KVP_TYPE_STRING: 00794 case KVP_TYPE_GUID: 00795 case KVP_TYPE_TIME : 00796 case KVP_TYPE_BOOLEAN : 00797 #ifndef QOF_DISABLE_DEPRECATED 00798 case KVP_TYPE_TIMESPEC: 00799 #endif 00800 case KVP_TYPE_BINARY: 00801 case KVP_TYPE_GLIST: 00802 { 00803 node = 00804 xmlAddChild (params->output_node, 00805 xmlNewNode (params->qsf_ns, 00806 BAD_CAST qof_param->param_type)); 00807 xmlNodeAddContent (node, 00808 BAD_CAST kvp_value_to_bare_string (content)); 00809 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, 00810 BAD_CAST qof_param->param_name); 00811 full_path = 00812 g_strconcat (params->full_kvp_path, "/", path, NULL); 00813 xmlNewProp (node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST full_path); 00814 xmlNewProp (node, BAD_CAST QSF_OBJECT_VALUE, 00815 BAD_CAST kvp_value_to_qof_type_helper (n)); 00816 break; 00817 } 00818 case KVP_TYPE_FRAME: 00819 { 00820 if (!params->full_kvp_path) 00821 params->full_kvp_path = g_strdup (path); 00822 else 00823 params->full_kvp_path = g_strconcat (params->full_kvp_path, 00824 "/", path, NULL); 00825 kvp_frame_for_each_slot (kvp_value_get_frame (content), 00826 qsf_from_kvp_helper, params); 00827 g_free (params->full_kvp_path); 00828 params->full_kvp_path = NULL; 00829 break; 00830 } 00831 default: 00832 { 00833 PERR (" unsupported value = %d", kvp_value_get_type (content)); 00834 break; 00835 } 00836 } 00837 } 00838 00839 static void 00840 qsf_from_coll_cb (QofEntity * ent, gpointer user_data) 00841 { 00842 QsfParam *params; 00843 QofParam *qof_param; 00844 xmlNodePtr node; 00845 gchar qsf_guid[GUID_ENCODING_LENGTH + 1]; 00846 00847 params = (QsfParam *) user_data; 00848 if (!ent || !params) 00849 return; 00850 qof_param = params->qof_param; 00851 guid_to_string_buff (qof_entity_get_guid (ent), qsf_guid); 00852 node = xmlAddChild (params->output_node, xmlNewNode (params->qsf_ns, 00853 BAD_CAST qof_param->param_type)); 00854 xmlNodeAddContent (node, BAD_CAST qsf_guid); 00855 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, 00856 BAD_CAST qof_param->param_name); 00857 } 00858 00859 /******* reference handling ***********/ 00860 00861 static gint 00862 qof_reference_list_cb (gconstpointer a, gconstpointer b) 00863 { 00864 const QofEntityReference *aa; 00865 const QofEntityReference *bb; 00866 00867 aa = (QofEntityReference *) a; 00868 bb = (QofEntityReference *) b; 00869 if (aa == NULL) 00870 return 1; 00871 g_return_val_if_fail ((bb != NULL), 1); 00872 g_return_val_if_fail ((aa->type != NULL), 1); 00873 if ((0 == guid_compare (bb->ent_guid, aa->ent_guid)) 00874 && (0 == safe_strcmp (bb->type, aa->type)) 00875 && (0 == safe_strcmp (bb->param->param_name, 00876 aa->param->param_name))) 00877 return 0; 00878 return 1; 00879 } 00880 00881 static QofEntityReference * 00882 qof_reference_lookup (GList * referenceList, QofEntityReference * find) 00883 { 00884 GList *single_ref; 00885 QofEntityReference *ent_ref; 00886 00887 if (referenceList == NULL) 00888 return NULL; 00889 g_return_val_if_fail (find != NULL, NULL); 00890 single_ref = NULL; 00891 ent_ref = NULL; 00892 single_ref = 00893 g_list_find_custom (referenceList, find, qof_reference_list_cb); 00894 if (single_ref == NULL) 00895 return ent_ref; 00896 ent_ref = (QofEntityReference *) single_ref->data; 00897 g_list_free (single_ref); 00898 return ent_ref; 00899 } 00900 00901 static void 00902 reference_list_lookup (gpointer data, gpointer user_data) 00903 { 00904 QofEntity *ent; 00905 QofParam *ref_param; 00906 QofEntityReference *reference, *starter; 00907 QsfParam *params; 00908 const GUID *guid; 00909 xmlNodePtr node, object_node; 00910 xmlNsPtr ns; 00911 GList *copy_list; 00912 gchar qsf_guid[GUID_ENCODING_LENGTH + 1], *ref_name; 00913 00914 params = (QsfParam *) user_data; 00915 ref_param = (QofParam *) data; 00916 object_node = params->output_node; 00917 ent = params->qsf_ent; 00918 ns = params->qsf_ns; 00919 starter = g_new0 (QofEntityReference, 1); 00920 starter->ent_guid = qof_entity_get_guid (ent); 00921 starter->type = g_strdup (ent->e_type); 00922 starter->param = ref_param; 00923 starter->ref_guid = NULL; 00924 copy_list = g_list_copy (params->referenceList); 00925 reference = qof_reference_lookup (copy_list, starter); 00926 g_free (starter); 00927 if (reference != NULL) 00928 { 00929 if ((ref_param->param_getfcn == NULL) 00930 || (ref_param->param_setfcn == NULL)) 00931 return; 00932 ref_name = g_strdup (reference->param->param_name); 00933 node = 00934 xmlAddChild (object_node, 00935 xmlNewNode (ns, BAD_CAST QOF_TYPE_GUID)); 00936 guid_to_string_buff (reference->ref_guid, qsf_guid); 00937 xmlNodeAddContent (node, BAD_CAST qsf_guid); 00938 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ref_name); 00939 g_free (ref_name); 00940 } 00941 else 00942 { 00943 ent = (QofEntity *) ref_param->param_getfcn (ent, ref_param); 00944 if (!ent) 00945 return; 00946 if ((0 == safe_strcmp (ref_param->param_type, QOF_TYPE_COLLECT)) || 00947 (0 == safe_strcmp (ref_param->param_type, QOF_TYPE_CHOICE))) 00948 return; 00949 node = 00950 xmlAddChild (object_node, 00951 xmlNewNode (ns, BAD_CAST QOF_TYPE_GUID)); 00952 guid = qof_entity_get_guid (ent); 00953 guid_to_string_buff (guid, qsf_guid); 00954 xmlNodeAddContent (node, BAD_CAST qsf_guid); 00955 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, 00956 BAD_CAST ref_param->param_name); 00957 } 00958 } 00959 00960 /*===================================== 00961 Convert QofEntity to QSF XML node 00962 qof_param holds the parameter sequence. 00963 =======================================*/ 00964 static void 00965 qsf_entity_foreach (QofEntity * ent, gpointer data) 00966 { 00967 QsfParam *params; 00968 GSList *param_list, *supported; 00969 GList *ref; 00970 xmlNodePtr node, object_node; 00971 xmlNsPtr ns; 00972 gchar *string_buffer; 00973 QofParam *qof_param; 00974 QofEntity *choice_ent; 00975 KvpFrame *qsf_kvp; 00976 QofCollection *qsf_coll; 00977 gint param_count; 00978 gboolean own_guid; 00979 const GUID *cm_guid; 00980 gchar cm_sa[GUID_ENCODING_LENGTH + 1]; 00981 00982 g_return_if_fail (data != NULL); 00983 params = (QsfParam *) data; 00984 param_count = ++params->count; 00985 ns = params->qsf_ns; 00986 qsf_kvp = NULL; 00987 own_guid = FALSE; 00988 choice_ent = NULL; 00989 object_node = xmlNewChild (params->book_node, params->qsf_ns, 00990 BAD_CAST QSF_OBJECT_TAG, NULL); 00991 xmlNewProp (object_node, BAD_CAST QSF_OBJECT_TYPE, 00992 BAD_CAST ent->e_type); 00993 string_buffer = g_strdup_printf ("%i", param_count); 00994 xmlNewProp (object_node, BAD_CAST QSF_OBJECT_COUNT, 00995 BAD_CAST string_buffer); 00996 g_free (string_buffer); 00997 param_list = g_slist_copy (params->qsf_sequence); 00998 while (param_list != NULL) 00999 { 01000 qof_param = (QofParam *) param_list->data; 01001 g_return_if_fail (qof_param != NULL); 01002 if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_GUID)) 01003 { 01004 if (!own_guid) 01005 { 01006 cm_guid = qof_entity_get_guid (ent); 01007 node = xmlAddChild (object_node, xmlNewNode (ns, BAD_CAST 01008 QOF_TYPE_GUID)); 01009 guid_to_string_buff (cm_guid, cm_sa); 01010 string_buffer = g_strdup (cm_sa); 01011 xmlNodeAddContent (node, BAD_CAST string_buffer); 01012 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 01013 QOF_PARAM_GUID); 01014 g_free (string_buffer); 01015 own_guid = TRUE; 01016 } 01017 params->qsf_ent = ent; 01018 params->output_node = object_node; 01019 ref = qof_class_get_referenceList (ent->e_type); 01020 if (ref != NULL) 01021 g_list_foreach (ref, reference_list_lookup, params); 01022 } 01023 if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_COLLECT)) 01024 { 01025 qsf_coll = qof_param->param_getfcn (ent, qof_param); 01026 if (qsf_coll) 01027 { 01028 params->qof_param = qof_param; 01029 params->output_node = object_node; 01030 if (qof_collection_count (qsf_coll) > 0) 01031 qof_collection_foreach (qsf_coll, qsf_from_coll_cb, 01032 params); 01033 } 01034 param_list = g_slist_next (param_list); 01035 continue; 01036 } 01037 if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_CHOICE)) 01038 { 01040 choice_ent = 01041 (QofEntity *) qof_param->param_getfcn (ent, qof_param); 01042 if (!choice_ent) 01043 { 01044 param_list = g_slist_next (param_list); 01045 continue; 01046 } 01047 node = xmlAddChild (object_node, xmlNewNode (ns, BAD_CAST 01048 qof_param->param_type)); 01049 cm_guid = qof_entity_get_guid (choice_ent); 01050 guid_to_string_buff (cm_guid, cm_sa); 01051 string_buffer = g_strdup (cm_sa); 01052 xmlNodeAddContent (node, BAD_CAST string_buffer); 01053 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 01054 qof_param->param_name); 01055 xmlNewProp (node, BAD_CAST "name", 01056 BAD_CAST choice_ent->e_type); 01057 g_free (string_buffer); 01058 param_list = g_slist_next (param_list); 01059 continue; 01060 } 01061 if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_KVP)) 01062 { 01063 qsf_kvp = 01064 (KvpFrame *) qof_param->param_getfcn (ent, qof_param); 01065 if (kvp_frame_is_empty (qsf_kvp)) 01066 return; 01067 params->qof_param = qof_param; 01068 params->output_node = object_node; 01069 kvp_frame_for_each_slot (qsf_kvp, qsf_from_kvp_helper, params); 01070 } 01071 if ((qof_param->param_setfcn != NULL) 01072 && (qof_param->param_getfcn != NULL)) 01073 { 01074 for (supported = g_slist_copy (params->supported_types); 01075 supported != NULL; supported = g_slist_next (supported)) 01076 { 01077 if (0 == safe_strcmp ((const gchar *) supported->data, 01078 (const gchar *) qof_param->param_type)) 01079 { 01080 node = xmlAddChild (object_node, 01081 xmlNewNode (ns, BAD_CAST qof_param->param_type)); 01082 string_buffer = 01083 g_strdup (qof_book_merge_param_as_string 01084 (qof_param, ent)); 01085 xmlNodeAddContent (node, BAD_CAST string_buffer); 01086 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 01087 qof_param->param_name); 01088 g_free (string_buffer); 01089 } 01090 } 01091 } 01092 param_list = g_slist_next (param_list); 01093 } 01094 } 01095 01096 static void 01097 qsf_foreach_obj_type (QofObject * qsf_obj, gpointer data) 01098 { 01099 QsfParam *params; 01100 QofBook *book; 01101 GSList *support; 01102 01103 g_return_if_fail (data != NULL); 01104 params = (QsfParam *) data; 01105 /* Skip unsupported objects */ 01106 if ((qsf_obj->create == NULL) || (qsf_obj->foreach == NULL)) 01107 { 01108 PINFO (" qsf_obj QOF support failed %s", qsf_obj->e_type); 01109 return; 01110 } 01111 params->qof_obj_type = qsf_obj->e_type; 01112 params->qsf_sequence = NULL; 01113 book = params->book; 01114 support = g_slist_copy (params->supported_types); 01115 g_slist_foreach (support, qsf_supported_parameters, params); 01116 qof_object_foreach (qsf_obj->e_type, book, qsf_entity_foreach, params); 01117 } 01118 01119 /*===================================================== 01120 Take a QofBook and prepare a QSF XML doc in memory 01121 =======================================================*/ 01122 /* QSF only uses one QofBook per file - count may be removed later. */ 01123 static xmlDocPtr 01124 qofbook_to_qsf (QofBook * book, QsfParam * params) 01125 { 01126 xmlNodePtr top_node, node; 01127 xmlDocPtr doc; 01128 gchar buffer[GUID_ENCODING_LENGTH + 1]; 01129 const GUID *book_guid; 01130 01131 g_return_val_if_fail (book != NULL, NULL); 01132 params->book = book; 01133 params->referenceList = 01134 g_list_copy ((GList *) qof_book_get_data (book, 01135 ENTITYREFERENCE)); 01136 doc = xmlNewDoc (BAD_CAST QSF_XML_VERSION); 01137 top_node = xmlNewNode (NULL, BAD_CAST QSF_ROOT_TAG); 01138 xmlDocSetRootElement (doc, top_node); 01139 xmlSetNs (top_node, xmlNewNs (top_node, BAD_CAST QSF_DEFAULT_NS, 01140 NULL)); 01141 params->qsf_ns = top_node->ns; 01142 node = 01143 xmlNewChild (top_node, params->qsf_ns, BAD_CAST QSF_BOOK_TAG, 01144 NULL); 01145 params->book_node = node; 01146 xmlNewProp (node, BAD_CAST QSF_BOOK_COUNT, BAD_CAST "1"); 01147 book_guid = qof_entity_get_guid ((QofEntity*)book); 01148 guid_to_string_buff (book_guid, buffer); 01149 xmlNewChild (params->book_node, params->qsf_ns, 01150 BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer); 01151 params->output_doc = doc; 01152 params->book_node = node; 01153 qof_object_foreach_type (qsf_foreach_obj_type, params); 01154 return params->output_doc; 01155 } 01156 01157 static void 01158 write_qsf_from_book (const gchar *path, QofBook * book, 01159 QsfParam * params) 01160 { 01161 xmlDocPtr qsf_doc; 01162 gint write_result; 01163 QofBackend *be; 01164 01165 be = qof_book_get_backend (book); 01166 qsf_doc = qofbook_to_qsf (book, params); 01167 write_result = 0; 01168 PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s", 01169 params->use_gz_level, params->encoding); 01170 if ((params->use_gz_level > 0) && (params->use_gz_level <= 9)) 01171 xmlSetDocCompressMode (qsf_doc, params->use_gz_level); 01172 g_return_if_fail (qsf_is_valid 01173 (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE); 01174 write_result = 01175 xmlSaveFormatFileEnc (path, qsf_doc, params->encoding, 1); 01176 if (write_result < 0) 01177 { 01178 qof_error_set_be (be, qof_error_register 01179 (_("Could not write to '%s'. Check that you have " 01180 "permission to write to this file and that there is " 01181 "sufficient space to create it."), TRUE)); 01182 return; 01183 } 01184 qof_object_mark_clean (book); 01185 } 01186 01187 static void 01188 write_qsf_to_stdout (QofBook * book, QsfParam * params) 01189 { 01190 xmlDocPtr qsf_doc; 01191 01192 qsf_doc = qofbook_to_qsf (book, params); 01193 g_return_if_fail (qsf_is_valid 01194 (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE); 01195 PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s", 01196 params->use_gz_level, params->encoding); 01197 xmlSaveFormatFileEnc ("-", qsf_doc, params->encoding, 1); 01198 fprintf (stdout, "\n"); 01199 qof_object_mark_clean (book); 01200 } 01201 01202 static void 01203 qsf_write_file (QofBackend * be, QofBook * book) 01204 { 01205 QSFBackend *qsf_be; 01206 QsfParam *params; 01207 gchar *path; 01208 01209 qsf_be = (QSFBackend *) be; 01210 params = qsf_be->params; 01211 /* if fullpath is blank, book_id was set to QOF_STDOUT */ 01212 if (!qsf_be->fullpath || (*qsf_be->fullpath == '\0')) 01213 { 01214 write_qsf_to_stdout (book, params); 01215 return; 01216 } 01217 path = strdup (qsf_be->fullpath); 01218 write_qsf_from_book (path, book, params); 01219 g_free (path); 01220 } 01221 01222 KvpValue * 01223 string_to_kvp_value (const gchar * content, KvpValueType type) 01224 { 01225 gchar *tail; 01226 gint64 cm_i64; 01227 gdouble cm_double; 01228 QofNumeric cm_numeric; 01229 GUID *cm_guid; 01230 #ifndef QOF_DISABLE_DEPRECATED 01231 struct tm kvp_time; 01232 time_t kvp_time_t; 01233 Timespec cm_date; 01234 #endif 01235 01236 switch (type) 01237 { 01238 case KVP_TYPE_GINT64: 01239 { 01240 errno = 0; 01241 cm_i64 = strtoll (content, &tail, 0); 01242 if (errno == 0) 01243 { 01244 return kvp_value_new_gint64 (cm_i64); 01245 } 01246 break; 01247 } 01248 case KVP_TYPE_DOUBLE: 01249 { 01250 errno = 0; 01251 cm_double = strtod (content, &tail); 01252 if (errno == 0) 01253 return kvp_value_new_double (cm_double); 01254 break; 01255 } 01256 case KVP_TYPE_NUMERIC: 01257 { 01258 qof_numeric_from_string (content, &cm_numeric); 01259 return kvp_value_new_numeric (cm_numeric); 01260 break; 01261 } 01262 case KVP_TYPE_STRING: 01263 { 01264 return kvp_value_new_string (content); 01265 break; 01266 } 01267 case KVP_TYPE_GUID: 01268 { 01269 cm_guid = g_new0 (GUID, 1); 01270 if (TRUE == string_to_guid (content, cm_guid)) 01271 return kvp_value_new_guid (cm_guid); 01272 break; 01273 } 01274 case KVP_TYPE_TIME : 01275 { 01276 QofDate *qd; 01277 QofTime *qt; 01278 KvpValue *retval; 01279 01280 qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC); 01281 if(qd) 01282 { 01283 qt = qof_date_to_qtime (qd); 01284 retval = kvp_value_new_time (qt); 01285 qof_date_free (qd); 01286 qof_time_free (qt); 01287 return retval; 01288 } 01289 else 01290 PERR (" failed to parse date"); 01291 } 01292 #ifndef QOF_DISABLE_DEPRECATED 01293 case KVP_TYPE_TIMESPEC: 01294 { 01295 strptime (content, QSF_XSD_TIME, &kvp_time); 01296 kvp_time_t = mktime (&kvp_time); 01297 timespecFromTime_t (&cm_date, kvp_time_t); 01298 return kvp_value_new_timespec (cm_date); 01299 break; 01300 } 01301 #endif 01302 case KVP_TYPE_BOOLEAN : 01303 { 01304 gboolean val; 01305 val = qof_util_bool_to_int (content); 01306 return kvp_value_new_boolean (val); 01307 } 01308 case KVP_TYPE_BINARY: 01309 // return kvp_value_new_binary(value->value.binary.data, 01310 // value->value.binary.datasize); 01311 break; 01312 case KVP_TYPE_GLIST: 01313 // return kvp_value_new_glist(value->value.list); 01314 break; 01315 case KVP_TYPE_FRAME: 01316 // return kvp_value_new_frame(value->value.frame); 01317 break; 01318 } 01319 return NULL; 01320 } 01321 01322 /* ====================================================== 01323 Commit XML data from file to QofEntity in a QofBook 01324 ========================================================= */ 01325 void 01326 qsf_object_commitCB (gpointer key, gpointer value, gpointer data) 01327 { 01328 QsfParam *params; 01329 QsfObject *object_set; 01330 xmlNodePtr node; 01331 QofEntityReference *reference; 01332 QofEntity *qsf_ent; 01333 QofBook *targetBook; 01334 const gchar *qof_type, *parameter_name; 01335 QofIdType obj_type, reference_type; 01336 gchar *tail; 01337 /* cm_ prefix used for variables that hold the data to commit */ 01338 QofNumeric cm_numeric; 01339 gdouble cm_double; 01340 gboolean cm_boolean; 01341 gint32 cm_i32; 01342 gint64 cm_i64; 01343 gchar cm_char, (*char_getter) (xmlNodePtr); 01344 GUID *cm_guid; 01345 KvpFrame *cm_kvp; 01346 KvpValue *cm_value; 01347 KvpValueType cm_type; 01348 QofSetterFunc cm_setter; 01349 const QofParam *cm_param; 01350 void (*string_setter) (QofEntity *, const gchar *); 01351 void (*time_setter) (QofEntity *, QofTime *); 01352 void (*numeric_setter) (QofEntity *, QofNumeric); 01353 void (*double_setter) (QofEntity *, gdouble); 01354 void (*boolean_setter) (QofEntity *, gboolean); 01355 void (*i32_setter) (QofEntity *, gint32); 01356 void (*i64_setter) (QofEntity *, gint64); 01357 void (*char_setter) (QofEntity *, gchar); 01358 01359 g_return_if_fail (data && value && key); 01360 params = (QsfParam *) data; 01361 node = (xmlNodePtr) value; 01362 parameter_name = (const gchar *) key; 01363 qof_type = (gchar *) node->name; 01364 qsf_ent = params->qsf_ent; 01365 targetBook = params->book; 01366 obj_type = 01367 (gchar *) xmlGetProp (node->parent, BAD_CAST QSF_OBJECT_TYPE); 01368 if (0 == safe_strcasecmp (obj_type, parameter_name)) 01369 { 01370 return; 01371 } 01372 cm_setter = qof_class_get_parameter_setter (obj_type, parameter_name); 01373 cm_param = qof_class_get_parameter (obj_type, parameter_name); 01374 object_set = params->object_set; 01375 if (safe_strcmp (qof_type, QOF_TYPE_STRING) == 0) 01376 { 01377 string_setter = (void (*)(QofEntity *, const gchar *)) cm_setter; 01378 if (string_setter != NULL) 01379 { 01380 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01381 string_setter (qsf_ent, (gchar *) xmlNodeGetContent (node)); 01382 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01383 } 01384 } 01385 #ifndef QOF_DISABLE_DEPRECATED 01386 /* use convert here to read "date" */ 01387 if ((params->convert != 0) && 01388 ((safe_strcmp (qof_type, QOF_TYPE_DATE) == 0) || 01389 (safe_strcmp (qof_type, QOF_TYPE_TIME) == 0))) 01390 { 01391 /* just reading the same value from a different tag */ 01392 #else 01393 if (safe_strcmp (qof_type, QOF_TYPE_TIME) == 0) 01394 { 01395 #endif 01396 time_setter = (void (*)(QofEntity *, QofTime*)) cm_setter; 01397 if (time_setter != NULL) 01398 { 01399 QofDate *qd; 01400 QofTime *qt; 01401 01402 qd = qof_date_parse ( 01403 (const gchar*) xmlNodeGetContent (node), 01404 QOF_DATE_FORMAT_UTC); 01405 if(qd) 01406 { 01407 qt = qof_date_to_qtime (qd); 01408 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01409 time_setter (qsf_ent, qt); 01410 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01411 qof_date_free (qd); 01412 } 01413 else 01414 PERR (" failed to parse date string"); 01415 } 01416 } 01417 #ifndef QOF_DISABLE_DEPRECATED 01418 if ((params->convert == 0) && 01419 (safe_strcmp (qof_type, QOF_TYPE_DATE) == 0)) 01420 { 01421 void (*date_setter) (QofEntity *, Timespec); 01422 struct tm qsf_time; 01423 time_t qsf_time_t; 01424 Timespec cm_date; 01425 const gchar *timechk; 01426 01427 memset (&qsf_time, '\0', sizeof (qsf_time)); 01428 cm_date.tv_nsec = 0; 01429 cm_date.tv_sec = 0; 01430 date_setter = (void (*)(QofEntity *, Timespec)) cm_setter; 01431 timechk = NULL; 01432 timechk = 01433 strptime ((char *) xmlNodeGetContent (node), QSF_XSD_TIME, 01434 &qsf_time); 01435 g_return_if_fail (timechk != NULL); 01436 qsf_time_t = mktime (&qsf_time); 01437 if (qsf_time_t != -3600) 01438 { 01439 timespecFromTime_t (&cm_date, qsf_time_t); 01440 if (date_setter != NULL) 01441 { 01442 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01443 date_setter (qsf_ent, cm_date); 01444 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01445 } 01446 } 01447 } 01448 #endif 01449 if ((safe_strcmp (qof_type, QOF_TYPE_NUMERIC) == 0) || 01450 (safe_strcmp (qof_type, QOF_TYPE_DEBCRED) == 0)) 01451 { 01452 gchar *tmp; 01453 numeric_setter = (void (*)(QofEntity *, QofNumeric)) cm_setter; 01454 tmp = (char *) xmlNodeGetContent (node); 01455 qof_numeric_from_string (tmp, &cm_numeric); 01456 g_free (tmp); 01457 if (numeric_setter != NULL) 01458 { 01459 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01460 numeric_setter (qsf_ent, cm_numeric); 01461 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01462 } 01463 } 01464 if (safe_strcmp (qof_type, QOF_TYPE_GUID) == 0) 01465 { 01466 cm_guid = g_new0 (GUID, 1); 01467 if (TRUE != 01468 string_to_guid ((gchar *) xmlNodeGetContent (node), cm_guid)) 01469 { 01470 qof_error_set_be (params->be, qof_error_register( 01471 _("The selected QSF object file '%s' contains one or " 01472 "more invalid GUIDs. The file cannot be processed - " 01473 "please check the source of the file and try again."), 01474 TRUE)); 01475 PINFO (" string to guid conversion failed for %s:%s:%s", 01476 xmlNodeGetContent (node), obj_type, qof_type); 01477 return; 01478 } 01479 reference_type = 01480 (gchar *) xmlGetProp (node, BAD_CAST QSF_OBJECT_TYPE); 01481 if (0 == safe_strcmp (QOF_PARAM_GUID, reference_type)) 01482 { 01483 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01484 qof_entity_set_guid (qsf_ent, cm_guid); 01485 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01486 } 01487 else 01488 { 01489 reference = qof_entity_get_reference_from (qsf_ent, cm_param); 01490 if (reference) 01491 { 01492 params->referenceList = 01493 g_list_append (params->referenceList, reference); 01494 } 01495 } 01496 } 01497 if (safe_strcmp (qof_type, QOF_TYPE_INT32) == 0) 01498 { 01499 errno = 0; 01500 cm_i32 = 01501 (gint32) strtol ((char *) xmlNodeGetContent (node), &tail, 0); 01502 if (errno == 0) 01503 { 01504 i32_setter = (void (*)(QofEntity *, gint32)) cm_setter; 01505 if (i32_setter != NULL) 01506 { 01507 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01508 i32_setter (qsf_ent, cm_i32); 01509 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01510 } 01511 } 01512 else 01513 qof_error_set_be (params->be, params->err_overflow); 01514 } 01515 if (safe_strcmp (qof_type, QOF_TYPE_INT64) == 0) 01516 { 01517 errno = 0; 01518 cm_i64 = strtoll ((gchar *) xmlNodeGetContent (node), &tail, 0); 01519 if (errno == 0) 01520 { 01521 i64_setter = (void (*)(QofEntity *, gint64)) cm_setter; 01522 if (i64_setter != NULL) 01523 { 01524 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01525 i64_setter (qsf_ent, cm_i64); 01526 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01527 } 01528 } 01529 else 01530 qof_error_set_be (params->be, params->err_overflow); 01531 } 01532 if (safe_strcmp (qof_type, QOF_TYPE_DOUBLE) == 0) 01533 { 01534 errno = 0; 01535 cm_double = strtod ((gchar *) xmlNodeGetContent (node), &tail); 01536 if (errno == 0) 01537 { 01538 double_setter = (void (*)(QofEntity *, gdouble)) cm_setter; 01539 if (double_setter != NULL) 01540 { 01541 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01542 double_setter (qsf_ent, cm_double); 01543 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01544 } 01545 } 01546 } 01547 if (safe_strcmp (qof_type, QOF_TYPE_BOOLEAN) == 0) 01548 { 01549 if (0 == safe_strcasecmp ((gchar *) xmlNodeGetContent (node), 01550 QSF_XML_BOOLEAN_TEST)) 01551 cm_boolean = TRUE; 01552 else 01553 cm_boolean = FALSE; 01554 boolean_setter = (void (*)(QofEntity *, gboolean)) cm_setter; 01555 if (boolean_setter != NULL) 01556 { 01557 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01558 boolean_setter (qsf_ent, cm_boolean); 01559 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01560 } 01561 } 01562 if (safe_strcmp (qof_type, QOF_TYPE_KVP) == 0) 01563 { 01564 cm_type = 01565 qsf_to_kvp_helper ((gchar *) 01566 xmlGetProp (node, BAD_CAST QSF_OBJECT_VALUE)); 01567 if (!cm_type) 01568 return; 01569 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01570 cm_value = 01571 string_to_kvp_value ((gchar *) xmlNodeGetContent (node), 01572 cm_type); 01573 cm_kvp = (KvpFrame *) cm_param->param_getfcn (qsf_ent, cm_param); 01574 cm_kvp = kvp_frame_set_value (cm_kvp, (gchar *) xmlGetProp (node, 01575 BAD_CAST QSF_OBJECT_KVP), cm_value); 01576 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01577 g_free (cm_value); 01578 } 01579 if (safe_strcmp (qof_type, QOF_TYPE_COLLECT) == 0) 01580 { 01581 QofCollection *qsf_coll; 01582 QofIdType type; 01583 QofEntityReference *reference; 01584 QofParam *copy_param; 01585 /* retrieve the *type* of the collection, ignore any contents. */ 01586 qsf_coll = cm_param->param_getfcn (qsf_ent, cm_param); 01587 type = qof_collection_get_type (qsf_coll); 01588 cm_guid = g_new0 (GUID, 1); 01589 if (TRUE != 01590 string_to_guid ((gchar *) xmlNodeGetContent (node), cm_guid)) 01591 { 01592 qof_error_set_be (params->be, (qof_error_register( 01593 _("The selected QSF object file '%s' contains one or " 01594 "more invalid 'collect' values. The file cannot be processed - " 01595 "please check the source of the file and try again."), 01596 TRUE))); 01597 PINFO (" string to guid collect failed for %s", 01598 xmlNodeGetContent (node)); 01599 return; 01600 } 01601 /* create a QofEntityReference with this type and GUID. 01602 there is only one entity each time. 01603 cm_guid contains the GUID of the reference. 01604 type is the type of the reference. */ 01605 reference = g_new0 (QofEntityReference, 1); 01606 reference->type = g_strdup (qsf_ent->e_type); 01607 reference->ref_guid = cm_guid; 01608 reference->ent_guid = &qsf_ent->guid; 01609 copy_param = g_new0 (QofParam, 1); 01610 copy_param->param_name = g_strdup (cm_param->param_name); 01611 copy_param->param_type = g_strdup (cm_param->param_type); 01612 reference->param = copy_param; 01613 params->referenceList = 01614 g_list_append (params->referenceList, reference); 01615 } 01616 if (safe_strcmp (qof_type, QOF_TYPE_CHAR) == 0) 01617 { 01618 char_getter = (gchar (*)(xmlNodePtr)) xmlNodeGetContent; 01619 cm_char = char_getter (node); 01620 char_setter = (void (*)(QofEntity *, gchar)) cm_setter; 01621 if (char_setter != NULL) 01622 { 01623 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01624 char_setter (qsf_ent, cm_char); 01625 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01626 } 01627 } 01628 } 01629 01630 static QofBackend * 01631 qsf_backend_new (void) 01632 { 01633 QSFBackend *qsf_be; 01634 QofBackend *be; 01635 01636 qsf_be = g_new0 (QSFBackend, 1); 01637 be = (QofBackend *) qsf_be; 01638 qof_backend_init (be); 01639 qsf_be->params = g_new0 (QsfParam, 1); 01640 qsf_be->params->be = be; 01641 qsf_param_init (qsf_be->params); 01642 qsf_be->be.session_begin = qsf_session_begin; 01643 01644 be->session_end = qsf_session_end; 01645 be->destroy_backend = qsf_destroy_backend; 01646 be->load = qsf_file_type; 01647 be->save_may_clobber_data = NULL; 01648 /* The QSF backend will always load and save the entire QSF XML file. */ 01649 be->begin = NULL; 01650 be->commit = NULL; 01651 be->rollback = NULL; 01652 /* QSF uses the built-in SQL, not a dedicated SQL server. */ 01653 be->compile_query = NULL; 01654 be->free_query = NULL; 01655 be->run_query = NULL; 01656 be->counter = NULL; 01657 /* The QSF backend is not multi-user. */ 01658 be->events_pending = NULL; 01659 be->process_events = NULL; 01660 01661 be->sync = qsf_write_file; 01662 /* use for maps, later. */ 01663 be->load_config = qsf_load_config; 01664 be->get_config = qsf_get_config; 01665 01666 qsf_be->fullpath = NULL; 01667 return be; 01668 } 01669 01670 /* The QOF method of loading each backend. 01671 QSF is loaded as a GModule using the QOF method - QofBackendProvider. 01672 */ 01673 static void 01674 qsf_provider_free (QofBackendProvider * prov) 01675 { 01676 prov->provider_name = NULL; 01677 prov->access_method = NULL; 01678 g_free (prov); 01679 } 01680 01681 void 01682 qsf_provider_init (void) 01683 { 01684 QofBackendProvider *prov; 01685 01686 bindtextdomain (PACKAGE, LOCALE_DIR); 01687 prov = g_new0 (QofBackendProvider, 1); 01688 prov->provider_name = "QSF Backend Version 0.4"; 01689 prov->access_method = "file"; 01690 prov->partial_book_supported = TRUE; 01691 prov->backend_new = qsf_backend_new; 01692 prov->check_data_type = qsf_determine_file_type; 01693 prov->provider_free = qsf_provider_free; 01694 qof_backend_register_provider (prov); 01695 }