QOF
0.8.7
|
00001 /******************************************************************* 00002 * qsf-backend.c 00003 * 00004 * Sat Jan 1 15:07:14 2005 00005 * Copyright 2005-2008 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 "kvputil-p.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 * G_GNUC_UNUSED qsf_time_now; 00182 gchar * G_GNUC_UNUSED 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 params->supported_types = 00216 g_slist_append (params->supported_types, QOF_TYPE_TIME); 00217 params->supported_types = 00218 g_slist_append (params->supported_types, QOF_TYPE_INT32); 00219 params->supported_types = 00220 g_slist_append (params->supported_types, QOF_TYPE_INT64); 00221 params->supported_types = 00222 g_slist_append (params->supported_types, QOF_TYPE_DOUBLE); 00223 params->supported_types = 00224 g_slist_append (params->supported_types, QOF_TYPE_CHAR); 00225 params->supported_types = 00226 g_slist_append (params->supported_types, QOF_TYPE_KVP); 00227 params->supported_types = 00228 g_slist_append (params->supported_types, QOF_TYPE_COLLECT); 00229 params->supported_types = 00230 g_slist_append (params->supported_types, QOF_TYPE_CHOICE); 00231 qsf_time_precision = "%j"; 00232 qsf_enquiry_date = qof_time_stamp_now (); 00233 qsf_time_string = qof_date_print (qof_date_get_current(), 00234 QOF_DATE_FORMAT_ISO); 00235 qsf_time_now = qof_time_stamp_now (); 00236 00237 g_hash_table_insert (params->qsf_default_hash, "qsf_enquiry_date", 00238 qsf_enquiry_date); 00239 g_hash_table_insert (params->qsf_default_hash, "qsf_time_now", 00240 qof_time_get_current()); 00241 g_hash_table_insert (params->qsf_default_hash, "qsf_time_string", 00242 qsf_time_string); 00243 /* default map files */ 00244 params->map_files = *qsf_map_prepare_list (¶ms->map_files); 00245 params->err_nomap = qof_error_register 00246 (_("The selected QSF Object file '%s' requires a " 00247 "map but it was not provided."), TRUE); 00248 params->err_overflow = qof_error_register 00249 (_("When converting XML strings into numbers, an " 00250 "overflow has been detected. The QSF object file " 00251 "'%s' contains invalid data in a field that is " 00252 "meant to hold a number."), TRUE); 00253 } 00254 00255 static gboolean 00256 qsf_determine_file_type (const gchar * path) 00257 { 00258 struct stat sbuf; 00259 00260 if (!path) 00261 return TRUE; 00262 if (0 == safe_strcmp (path, QOF_STDOUT)) 00263 return TRUE; 00264 if (stat (path, &sbuf) < 0) 00265 { 00266 /* in case the error is that the file does not exist */ 00267 FILE * f; 00268 f = fopen (path, "a+"); 00269 if (f) 00270 { 00271 fclose (f); 00272 return TRUE; 00273 } 00274 return FALSE; 00275 } 00276 if (sbuf.st_size == 0) 00277 return TRUE; 00278 if (is_our_qsf_object (path)) 00279 return TRUE; 00280 else if (is_qsf_object (path)) 00281 return TRUE; 00282 else if (is_qsf_map (path)) 00283 return TRUE; 00284 return FALSE; 00285 } 00286 00287 static void 00288 qsf_session_begin (QofBackend * be, QofSession * session, 00289 const gchar * book_path, gboolean ignore_lock, 00290 gboolean create_if_nonexistent) 00291 { 00292 QSFBackend *qsf_be; 00293 gchar *p, *path; 00294 00295 PINFO (" ignore_lock=%d create_if_nonexistent=%d", ignore_lock, 00296 create_if_nonexistent); 00297 g_return_if_fail (be != NULL); 00298 g_return_if_fail (session); 00299 be->fullpath = g_strdup (book_path); 00300 qsf_be = (QSFBackend *) be; 00301 g_return_if_fail (qsf_be->params != NULL); 00302 qsf_be->fullpath = NULL; 00303 if (book_path == NULL) 00304 { 00305 /* allow use of stdout */ 00306 qof_error_set_be (be, QOF_SUCCESS); 00307 return; 00308 } 00309 p = strchr (book_path, ':'); 00310 if (p) 00311 { 00312 path = g_strdup (book_path); 00313 if (!g_ascii_strncasecmp (path, "file:", 5)) 00314 { 00315 p = g_new0 (gchar, strlen (path) - 5 + 1); 00316 strcpy (p, path + 5); 00317 } 00318 qsf_be->fullpath = g_strdup (p); 00319 g_free (path); 00320 } 00321 else 00322 qsf_be->fullpath = g_strdup (book_path); 00323 if (create_if_nonexistent) 00324 { 00325 FILE *f; 00326 00327 f = fopen (qsf_be->fullpath, "a+"); 00328 if (f) 00329 fclose (f); 00330 else 00331 { 00332 qof_error_set_be (be, qof_error_register 00333 (_("could not write to '%s'. " 00334 "That database may be on a read-only file system, " 00335 "or you may not have write permission for the " 00336 "directory.\n"), TRUE)); 00337 return; 00338 } 00339 } 00340 qof_error_set_be (be, QOF_SUCCESS); 00341 } 00342 00343 static void 00344 qsf_free_params (QsfParam * params) 00345 { 00346 g_hash_table_destroy (params->qsf_calculate_hash); 00347 g_hash_table_destroy (params->qsf_default_hash); 00348 if (params->referenceList) 00349 g_list_free (params->referenceList); 00350 g_slist_free (params->supported_types); 00351 if (params->map_ns) 00352 xmlFreeNs (params->map_ns); 00353 if (params->output_doc) 00354 xmlFreeDoc (params->output_doc); 00355 } 00356 00357 static void 00358 qsf_session_end (QofBackend * be) 00359 { 00360 QSFBackend *qsf_be; 00361 00362 qsf_be = (QSFBackend *) be; 00363 g_return_if_fail (qsf_be != NULL); 00364 qsf_free_params (qsf_be->params); 00365 g_free (qsf_be->fullpath); 00366 qsf_be->fullpath = NULL; 00367 xmlCleanupParser (); 00368 } 00369 00370 static void 00371 qsf_destroy_backend (QofBackend * be) 00372 { 00373 g_free (be); 00374 } 00375 00376 static void 00377 ent_ref_cb (QofEntity * ent, gpointer user_data) 00378 { 00379 QsfParam *params; 00380 QofEntityReference *ref; 00381 void (*reference_setter) (QofEntity *, QofEntity *); 00382 QofEntity *reference; 00383 QofCollection *coll; 00384 QofIdType type; 00385 00386 params = (QsfParam *) user_data; 00387 g_return_if_fail (params); 00388 while (params->referenceList) 00389 { 00390 ref = (QofEntityReference *) params->referenceList->data; 00391 if (qof_object_is_choice (ent->e_type)) 00392 type = ref->choice_type; 00393 else 00394 type = ref->type; 00395 coll = qof_book_get_collection (params->book, type); 00396 reference = qof_collection_lookup_entity (coll, ref->ref_guid); 00397 reference_setter = 00398 (void (*)(QofEntity *, QofEntity *)) ref->param->param_setfcn; 00399 if (reference_setter != NULL) 00400 { 00401 qof_util_param_edit ((QofInstance *) ent, ref->param); 00402 qof_util_param_edit ((QofInstance *) reference, ref->param); 00403 reference_setter (ent, reference); 00404 qof_util_param_commit ((QofInstance *) ent, ref->param); 00405 qof_util_param_commit ((QofInstance *) reference, ref->param); 00406 } 00407 params->referenceList = g_list_next (params->referenceList); 00408 } 00409 } 00410 00411 static void 00412 insert_ref_cb (QofObject * obj, gpointer user_data) 00413 { 00414 QsfParam *params; 00415 00416 params = (QsfParam *) user_data; 00417 g_return_if_fail (params); 00418 qof_object_foreach (obj->e_type, params->book, ent_ref_cb, params); 00419 } 00420 00421 /*================================================ 00422 Load QofEntity into QofBook from XML in memory 00423 ==================================================*/ 00424 00425 static gboolean 00426 qsfdoc_to_qofbook (QsfParam * params) 00427 { 00428 QofInstance *inst; 00429 struct QsfNodeIterate qiter; 00430 QofBook *book; 00431 GList *object_list; 00432 xmlNodePtr qsf_root; 00433 xmlNsPtr qsf_ns; 00434 00435 g_return_val_if_fail (params != NULL, FALSE); 00436 g_return_val_if_fail (params->input_doc != NULL, FALSE); 00437 g_return_val_if_fail (params->book != NULL, FALSE); 00438 g_return_val_if_fail (params->file_type == OUR_QSF_OBJ, FALSE); 00439 qsf_root = xmlDocGetRootElement (params->input_doc); 00440 if (!qsf_root) 00441 return FALSE; 00442 qsf_ns = qsf_root->ns; 00443 qiter.ns = qsf_ns; 00444 book = params->book; 00445 params->referenceList = 00446 (GList *) qof_book_get_data (book, ENTITYREFERENCE); 00447 qsf_node_foreach (qsf_root, qsf_book_node_handler, &qiter, params); 00448 object_list = g_list_copy (params->qsf_object_list); 00449 while (object_list != NULL) 00450 { 00451 params->object_set = object_list->data; 00452 object_list = g_list_next (object_list); 00453 params->qsf_parameter_hash = params->object_set->parameters; 00454 if (!qof_class_is_registered (params->object_set->object_type)) 00455 continue; 00456 inst = 00457 (QofInstance *) qof_object_new_instance (params->object_set-> 00458 object_type, book); 00459 g_return_val_if_fail (inst != NULL, FALSE); 00460 params->qsf_ent = &inst->entity; 00461 g_hash_table_foreach (params->qsf_parameter_hash, 00462 qsf_object_commitCB, params); 00463 } 00464 qof_object_foreach_type (insert_ref_cb, params); 00465 qof_book_set_data (book, ENTITYREFERENCE, params->referenceList); 00466 return TRUE; 00467 } 00468 00469 /* QofBackend routine to load from file - needs a map. 00470 */ 00471 static gboolean 00472 load_qsf_object (QofBook * book, const gchar * fullpath, 00473 QsfParam * params) 00474 { 00475 xmlNodePtr qsf_root, map_root; 00476 xmlDocPtr mapDoc, foreign_doc; 00477 gchar *map_path, *map_file; 00478 00479 map_file = params->map_path; 00480 mapDoc = NULL; 00481 /* use selected map */ 00482 if (!map_file) 00483 { 00484 qof_error_set_be (params->be, params->err_nomap); 00485 return FALSE; 00486 } 00487 foreign_doc = xmlParseFile (fullpath); 00488 if (foreign_doc == NULL) 00489 { 00490 qof_error_set_be (params->be, qof_error_register 00491 (_("There was an error parsing the file '%s'.\n"), TRUE)); 00492 return FALSE; 00493 } 00494 qsf_root = NULL; 00495 qsf_root = xmlDocGetRootElement (foreign_doc); 00496 params->qsf_ns = qsf_root->ns; 00497 params->book = book; 00498 map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file); 00499 if (!map_path) 00500 { 00501 qof_error_set_be (params->be, params->err_nomap); 00502 return FALSE; 00503 } 00504 mapDoc = xmlParseFile (map_path); 00505 if (!mapDoc) 00506 { 00507 qof_error_set_be (params->be, params->err_nomap); 00508 return FALSE; 00509 } 00510 map_root = xmlDocGetRootElement (mapDoc); 00511 params->map_ns = map_root->ns; 00512 params->input_doc = qsf_object_convert (mapDoc, qsf_root, params); 00513 qsfdoc_to_qofbook (params); 00514 return TRUE; 00515 } 00516 00517 static gboolean 00518 load_our_qsf_object (const gchar * fullpath, QsfParam * params) 00519 { 00520 xmlNodePtr qsf_root; 00521 00522 params->input_doc = xmlParseFile (fullpath); 00523 if (params->input_doc == NULL) 00524 { 00525 qof_error_set_be (params->be, qof_error_register 00526 (_("There was an error parsing the file '%s'."), TRUE)); 00527 return FALSE; 00528 } 00529 qsf_root = NULL; 00530 qsf_root = xmlDocGetRootElement (params->input_doc); 00531 params->qsf_ns = qsf_root->ns; 00532 return qsfdoc_to_qofbook (params); 00533 } 00534 00535 /* Determine the type of QSF and load it into the QofBook 00536 00537 - is_our_qsf_object, OUR_QSF_OBJ, QSF object file using only QOF objects known 00538 to the calling process. No map is required. 00539 - is_qsf_object, IS_QSF_OBJ, QSF object file that may or may not have a QSF map 00540 to convert external objects. This temporary type will be set to HAVE_QSF_MAP 00541 if a suitable map exists, or an error value returned: ERR_QSF_NO_MAP, 00542 ERR_QSF_BAD_MAP or ERR_QSF_WRONG_MAP. This allows the calling process to inform 00543 the user that the QSF itself is valid but a suitable map cannot be found. 00544 - is_qsf_map, IS_QSF_MAP, QSF map file. In the backend, this generates 00545 ERR_QSF_MAP_NOT_OBJ but it can be used internally when processing maps to 00546 match a QSF object. 00547 00548 returns NULL on error, otherwise a pointer to the QofBook. Use 00549 the qof_book_merge API to merge the new data into the current 00550 QofBook. 00551 */ 00552 static void 00553 qsf_file_type (QofBackend * be, QofBook * book) 00554 { 00555 QSFBackend *qsf_be; 00556 QofErrorId parse_err; 00557 QsfParam *params; 00558 FILE *f; 00559 gchar *path; 00560 gboolean result; 00561 00562 g_return_if_fail (be != NULL); 00563 g_return_if_fail (book != NULL); 00564 qsf_be = (QSFBackend *) be; 00565 g_return_if_fail (qsf_be != NULL); 00566 g_return_if_fail (qsf_be->fullpath != NULL); 00567 g_return_if_fail (qsf_be->params != NULL); 00568 parse_err = qof_error_register 00569 (_("There was an error parsing the file '%s'."), TRUE); 00570 params = qsf_be->params; 00571 params->book = book; 00572 DEBUG (" qsf_be->fullpath=%s", qsf_be->fullpath); 00573 path = g_strdup (qsf_be->fullpath); 00574 f = fopen (path, "r"); 00575 if (!f) 00576 qof_error_set_be (be, qof_error_register 00577 (_("There was an error reading the file '%s'."), TRUE)); 00578 else 00579 fclose (f); 00580 params->filepath = g_strdup (path); 00581 result = is_our_qsf_object_be (params); 00582 if (result) 00583 { 00584 params->file_type = OUR_QSF_OBJ; 00585 result = load_our_qsf_object (path, params); 00586 if (!result) 00587 qof_error_set_be (be, parse_err); 00588 return; 00589 } 00590 else if (is_qsf_object_be (params)) 00591 { 00592 params->file_type = IS_QSF_OBJ; 00593 result = load_qsf_object (book, path, params); 00594 if (!result) 00595 qof_error_set_be (be, parse_err); 00596 return; 00597 } 00598 if (qof_error_check_be (be) == params->err_nomap) 00599 { 00600 /* usable QSF object but no map available */ 00601 params->file_type = IS_QSF_OBJ; 00602 result = TRUE; 00603 } 00604 if (result == FALSE) 00605 { 00606 if (is_qsf_map_be (params)) 00607 { 00608 params->file_type = IS_QSF_MAP; 00609 qof_error_set_be (be, qof_error_register 00610 (_("The selected file '%s' is a QSF map and cannot " 00611 "be opened as a QSF object."), TRUE)); 00612 } 00613 } 00614 } 00615 00616 static void 00617 qsf_object_sequence (QofParam * qof_param, gpointer data) 00618 { 00619 QsfParam *params; 00620 GSList *checklist, *result; 00621 00622 g_return_if_fail (data != NULL); 00623 params = (QsfParam *) data; 00624 result = NULL; 00625 checklist = NULL; 00626 params->knowntype = FALSE; 00627 checklist = g_slist_copy (params->supported_types); 00628 for (result = checklist; result != NULL; result = result->next) 00629 { 00630 if (0 == 00631 safe_strcmp ((QofIdType) result->data, 00632 qof_param->param_type)) 00633 params->knowntype = TRUE; 00634 } 00635 g_slist_free (checklist); 00636 if (0 == safe_strcmp (qof_param->param_type, params->qof_type)) 00637 { 00638 params->qsf_sequence = 00639 g_slist_append (params->qsf_sequence, qof_param); 00640 params->knowntype = TRUE; 00641 } 00642 /* handle params->qof_type = QOF_TYPE_GUID and qof_param->param_type != known type */ 00643 if (0 == safe_strcmp (params->qof_type, QOF_TYPE_GUID) 00644 && (params->knowntype == FALSE)) 00645 { 00646 params->qsf_sequence = 00647 g_slist_append (params->qsf_sequence, qof_param); 00648 params->knowntype = TRUE; 00649 } 00650 } 00651 00652 /* receives each entry from supported_types in sequence 00653 type = qof data type from supported list 00654 user_data = params. Holds object type 00655 */ 00656 static void 00657 qsf_supported_parameters (gpointer type, gpointer user_data) 00658 { 00659 QsfParam *params; 00660 00661 g_return_if_fail (user_data != NULL); 00662 params = (QsfParam *) user_data; 00663 params->qof_type = (QofIdType) type; 00664 params->knowntype = FALSE; 00665 qof_class_param_foreach (params->qof_obj_type, qsf_object_sequence, 00666 params); 00667 } 00668 00669 static KvpValueType 00670 qsf_to_kvp_helper (const char *type_string) 00671 { 00672 KvpValueType kvt; 00673 kvt = qof_id_to_kvp_value_type (type_string); 00674 if (kvt != 0) 00675 return kvt; 00676 if (0 == safe_strcmp (QSF_TYPE_BINARY, type_string)) 00677 return KVP_TYPE_BINARY; 00678 if (0 == safe_strcmp (QSF_TYPE_GLIST, type_string)) 00679 return KVP_TYPE_GLIST; 00680 if (0 == safe_strcmp (QSF_TYPE_FRAME, type_string)) 00681 return KVP_TYPE_FRAME; 00682 return 0; 00683 } 00684 00685 static QofIdTypeConst 00686 kvp_value_to_qof_type_helper (KvpValueType n) 00687 { 00688 QofIdTypeConst qtc; 00689 qtc = kvp_value_type_to_qof_id (n); 00690 if (qtc) 00691 return qtc; 00692 switch (n) 00693 { 00694 case KVP_TYPE_BINARY: 00695 { 00696 return QSF_TYPE_BINARY; 00697 break; 00698 } 00699 case KVP_TYPE_GLIST: 00700 { 00701 return QSF_TYPE_GLIST; 00702 break; 00703 } 00704 case KVP_TYPE_FRAME: 00705 { 00706 return QSF_TYPE_FRAME; 00707 break; 00708 } 00709 default: 00710 { 00711 return NULL; 00712 } 00713 } 00714 } 00715 00716 00717 static void 00718 qsf_from_kvp_helper (const gchar * path, KvpValue * content, 00719 gpointer data) 00720 { 00721 QsfParam *params; 00722 QofParam *qof_param; 00723 xmlNodePtr node; 00724 KvpValueType n; 00725 gchar *full_path; 00726 00727 params = (QsfParam *) data; 00728 qof_param = params->qof_param; 00729 full_path = NULL; 00730 g_return_if_fail (params && path && content); 00731 n = kvp_value_get_type (content); 00732 switch (n) 00733 { 00734 case KVP_TYPE_GINT64: 00735 case KVP_TYPE_DOUBLE: 00736 case KVP_TYPE_NUMERIC: 00737 case KVP_TYPE_STRING: 00738 case KVP_TYPE_GUID: 00739 case KVP_TYPE_TIME : 00740 case KVP_TYPE_BOOLEAN : 00741 case KVP_TYPE_BINARY: 00742 case KVP_TYPE_GLIST: 00743 { 00744 node = 00745 xmlAddChild (params->output_node, 00746 xmlNewNode (params->qsf_ns, 00747 BAD_CAST qof_param->param_type)); 00748 xmlNodeAddContent (node, 00749 BAD_CAST kvp_value_to_bare_string (content)); 00750 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, 00751 BAD_CAST qof_param->param_name); 00752 full_path = 00753 g_strconcat (params->full_kvp_path, "/", path, NULL); 00754 xmlNewProp (node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST full_path); 00755 xmlNewProp (node, BAD_CAST QSF_OBJECT_VALUE, 00756 BAD_CAST kvp_value_to_qof_type_helper (n)); 00757 break; 00758 } 00759 case KVP_TYPE_FRAME: 00760 { 00761 if (!params->full_kvp_path) 00762 params->full_kvp_path = g_strdup (path); 00763 else 00764 params->full_kvp_path = g_strconcat (params->full_kvp_path, 00765 "/", path, NULL); 00766 kvp_frame_for_each_slot (kvp_value_get_frame (content), 00767 qsf_from_kvp_helper, params); 00768 g_free (params->full_kvp_path); 00769 params->full_kvp_path = NULL; 00770 break; 00771 } 00772 default: 00773 { 00774 PERR (" unsupported value = %d", kvp_value_get_type (content)); 00775 break; 00776 } 00777 } 00778 } 00779 00780 static void 00781 qsf_from_coll_cb (QofEntity * ent, gpointer user_data) 00782 { 00783 QsfParam *params; 00784 QofParam *qof_param; 00785 xmlNodePtr node; 00786 gchar qsf_guid[GUID_ENCODING_LENGTH + 1]; 00787 00788 params = (QsfParam *) user_data; 00789 if (!ent || !params) 00790 return; 00791 qof_param = params->qof_param; 00792 guid_to_string_buff (qof_entity_get_guid (ent), qsf_guid); 00793 node = xmlAddChild (params->output_node, xmlNewNode (params->qsf_ns, 00794 BAD_CAST qof_param->param_type)); 00795 xmlNodeAddContent (node, BAD_CAST qsf_guid); 00796 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, 00797 BAD_CAST qof_param->param_name); 00798 } 00799 00800 /******* reference handling ***********/ 00801 00802 static gint 00803 qof_reference_list_cb (gconstpointer a, gconstpointer b) 00804 { 00805 const QofEntityReference *aa; 00806 const QofEntityReference *bb; 00807 00808 aa = (QofEntityReference *) a; 00809 bb = (QofEntityReference *) b; 00810 if (aa == NULL) 00811 return 1; 00812 g_return_val_if_fail ((bb != NULL), 1); 00813 g_return_val_if_fail ((aa->type != NULL), 1); 00814 if ((0 == guid_compare (bb->ent_guid, aa->ent_guid)) 00815 && (0 == safe_strcmp (bb->type, aa->type)) 00816 && (0 == safe_strcmp (bb->param->param_name, 00817 aa->param->param_name))) 00818 return 0; 00819 return 1; 00820 } 00821 00822 static QofEntityReference * 00823 qof_reference_lookup (GList * referenceList, QofEntityReference * find) 00824 { 00825 GList *single_ref; 00826 QofEntityReference *ent_ref; 00827 00828 if (referenceList == NULL) 00829 return NULL; 00830 g_return_val_if_fail (find != NULL, NULL); 00831 single_ref = NULL; 00832 ent_ref = NULL; 00833 single_ref = 00834 g_list_find_custom (referenceList, find, qof_reference_list_cb); 00835 if (single_ref == NULL) 00836 return ent_ref; 00837 ent_ref = (QofEntityReference *) single_ref->data; 00838 g_list_free (single_ref); 00839 return ent_ref; 00840 } 00841 00842 static void 00843 reference_list_lookup (gpointer data, gpointer user_data) 00844 { 00845 QofEntity *ent; 00846 QofParam *ref_param; 00847 QofEntityReference *reference, *starter; 00848 QsfParam *params; 00849 const GUID *guid; 00850 xmlNodePtr node, object_node; 00851 xmlNsPtr ns; 00852 GList *copy_list; 00853 gchar qsf_guid[GUID_ENCODING_LENGTH + 1], *ref_name; 00854 00855 params = (QsfParam *) user_data; 00856 ref_param = (QofParam *) data; 00857 object_node = params->output_node; 00858 ent = params->qsf_ent; 00859 ns = params->qsf_ns; 00860 starter = g_new0 (QofEntityReference, 1); 00861 starter->ent_guid = qof_entity_get_guid (ent); 00862 starter->type = g_strdup (ent->e_type); 00863 starter->param = ref_param; 00864 starter->ref_guid = NULL; 00865 copy_list = g_list_copy (params->referenceList); 00866 reference = qof_reference_lookup (copy_list, starter); 00867 g_free (starter); 00868 if (reference != NULL) 00869 { 00870 if ((ref_param->param_getfcn == NULL) 00871 || (ref_param->param_setfcn == NULL)) 00872 return; 00873 ref_name = g_strdup (reference->param->param_name); 00874 node = 00875 xmlAddChild (object_node, 00876 xmlNewNode (ns, BAD_CAST QOF_TYPE_GUID)); 00877 guid_to_string_buff (reference->ref_guid, qsf_guid); 00878 xmlNodeAddContent (node, BAD_CAST qsf_guid); 00879 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ref_name); 00880 g_free (ref_name); 00881 } 00882 else 00883 { 00884 ent = (QofEntity *) ref_param->param_getfcn (ent, ref_param); 00885 if (!ent) 00886 return; 00887 if ((0 == safe_strcmp (ref_param->param_type, QOF_TYPE_COLLECT)) || 00888 (0 == safe_strcmp (ref_param->param_type, QOF_TYPE_CHOICE))) 00889 return; 00890 node = 00891 xmlAddChild (object_node, 00892 xmlNewNode (ns, BAD_CAST QOF_TYPE_GUID)); 00893 guid = qof_entity_get_guid (ent); 00894 guid_to_string_buff (guid, qsf_guid); 00895 xmlNodeAddContent (node, BAD_CAST qsf_guid); 00896 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, 00897 BAD_CAST ref_param->param_name); 00898 } 00899 } 00900 00901 /*===================================== 00902 Convert QofEntity to QSF XML node 00903 qof_param holds the parameter sequence. 00904 =======================================*/ 00905 static void 00906 qsf_entity_foreach (QofEntity * ent, gpointer data) 00907 { 00908 QsfParam *params; 00909 GSList *param_list, *supported; 00910 GList *ref; 00911 xmlNodePtr node, object_node; 00912 xmlNsPtr ns; 00913 gchar *string_buffer; 00914 QofParam *qof_param; 00915 QofEntity *choice_ent; 00916 KvpFrame *qsf_kvp; 00917 QofCollection *qsf_coll; 00918 gint param_count; 00919 gboolean own_guid; 00920 const GUID *cm_guid; 00921 gchar cm_sa[GUID_ENCODING_LENGTH + 1]; 00922 00923 g_return_if_fail (data != NULL); 00924 params = (QsfParam *) data; 00925 param_count = ++params->count; 00926 ns = params->qsf_ns; 00927 qsf_kvp = NULL; 00928 own_guid = FALSE; 00929 choice_ent = NULL; 00930 object_node = xmlNewChild (params->book_node, params->qsf_ns, 00931 BAD_CAST QSF_OBJECT_TAG, NULL); 00932 xmlNewProp (object_node, BAD_CAST QSF_OBJECT_TYPE, 00933 BAD_CAST ent->e_type); 00934 string_buffer = g_strdup_printf ("%i", param_count); 00935 xmlNewProp (object_node, BAD_CAST QSF_OBJECT_COUNT, 00936 BAD_CAST string_buffer); 00937 g_free (string_buffer); 00938 param_list = g_slist_copy (params->qsf_sequence); 00939 while (param_list != NULL) 00940 { 00941 qof_param = (QofParam *) param_list->data; 00942 g_return_if_fail (qof_param != NULL); 00943 if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_GUID)) 00944 { 00945 if (!own_guid) 00946 { 00947 cm_guid = qof_entity_get_guid (ent); 00948 node = xmlAddChild (object_node, xmlNewNode (ns, BAD_CAST 00949 QOF_TYPE_GUID)); 00950 guid_to_string_buff (cm_guid, cm_sa); 00951 string_buffer = g_strdup (cm_sa); 00952 xmlNodeAddContent (node, BAD_CAST string_buffer); 00953 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 00954 QOF_PARAM_GUID); 00955 g_free (string_buffer); 00956 own_guid = TRUE; 00957 } 00958 params->qsf_ent = ent; 00959 params->output_node = object_node; 00960 ref = qof_class_get_referenceList (ent->e_type); 00961 if (ref != NULL) 00962 g_list_foreach (ref, reference_list_lookup, params); 00963 } 00964 if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_COLLECT)) 00965 { 00966 qsf_coll = qof_param->param_getfcn (ent, qof_param); 00967 if (qsf_coll) 00968 { 00969 params->qof_param = qof_param; 00970 params->output_node = object_node; 00971 if (qof_collection_count (qsf_coll) > 0) 00972 qof_collection_foreach (qsf_coll, qsf_from_coll_cb, 00973 params); 00974 } 00975 param_list = g_slist_next (param_list); 00976 continue; 00977 } 00978 if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_CHOICE)) 00979 { 00981 choice_ent = 00982 (QofEntity *) qof_param->param_getfcn (ent, qof_param); 00983 if (!choice_ent) 00984 { 00985 param_list = g_slist_next (param_list); 00986 continue; 00987 } 00988 node = xmlAddChild (object_node, xmlNewNode (ns, BAD_CAST 00989 qof_param->param_type)); 00990 cm_guid = qof_entity_get_guid (choice_ent); 00991 guid_to_string_buff (cm_guid, cm_sa); 00992 string_buffer = g_strdup (cm_sa); 00993 xmlNodeAddContent (node, BAD_CAST string_buffer); 00994 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 00995 qof_param->param_name); 00996 xmlNewProp (node, BAD_CAST "name", 00997 BAD_CAST choice_ent->e_type); 00998 g_free (string_buffer); 00999 param_list = g_slist_next (param_list); 01000 continue; 01001 } 01002 if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_KVP)) 01003 { 01004 qsf_kvp = 01005 (KvpFrame *) qof_param->param_getfcn (ent, qof_param); 01006 if (kvp_frame_is_empty (qsf_kvp)) 01007 return; 01008 params->qof_param = qof_param; 01009 params->output_node = object_node; 01010 kvp_frame_for_each_slot (qsf_kvp, qsf_from_kvp_helper, params); 01011 } 01012 if ((qof_param->param_setfcn != NULL) 01013 && (qof_param->param_getfcn != NULL)) 01014 { 01015 for (supported = g_slist_copy (params->supported_types); 01016 supported != NULL; supported = g_slist_next (supported)) 01017 { 01018 if (0 == safe_strcmp ((const gchar *) supported->data, 01019 (const gchar *) qof_param->param_type)) 01020 { 01021 node = xmlAddChild (object_node, 01022 xmlNewNode (ns, BAD_CAST qof_param->param_type)); 01023 string_buffer = 01024 g_strdup (qof_util_param_to_string 01025 (ent, qof_param)); 01026 xmlNodeAddContent (node, BAD_CAST string_buffer); 01027 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 01028 qof_param->param_name); 01029 g_free (string_buffer); 01030 } 01031 } 01032 } 01033 param_list = g_slist_next (param_list); 01034 } 01035 } 01036 01037 static void 01038 qsf_foreach_obj_type (QofObject * qsf_obj, gpointer data) 01039 { 01040 QsfParam *params; 01041 QofBook *book; 01042 GSList *support; 01043 01044 g_return_if_fail (data != NULL); 01045 params = (QsfParam *) data; 01046 /* Skip unsupported objects */ 01047 if ((qsf_obj->create == NULL) || (qsf_obj->foreach == NULL)) 01048 { 01049 PINFO (" qsf_obj QOF support failed %s", qsf_obj->e_type); 01050 return; 01051 } 01052 params->qof_obj_type = qsf_obj->e_type; 01053 params->qsf_sequence = NULL; 01054 book = params->book; 01055 support = g_slist_copy (params->supported_types); 01056 g_slist_foreach (support, qsf_supported_parameters, params); 01057 qof_object_foreach (qsf_obj->e_type, book, qsf_entity_foreach, params); 01058 } 01059 01060 /*===================================================== 01061 Take a QofBook and prepare a QSF XML doc in memory 01062 =======================================================*/ 01063 /* QSF only uses one QofBook per file - count may be removed later. */ 01064 static xmlDocPtr 01065 qofbook_to_qsf (QofBook * book, QsfParam * params) 01066 { 01067 xmlNodePtr top_node, node; 01068 xmlDocPtr doc; 01069 gchar buffer[GUID_ENCODING_LENGTH + 1]; 01070 const GUID *book_guid; 01071 01072 g_return_val_if_fail (book != NULL, NULL); 01073 params->book = book; 01074 params->referenceList = 01075 g_list_copy ((GList *) qof_book_get_data (book, 01076 ENTITYREFERENCE)); 01077 doc = xmlNewDoc (BAD_CAST QSF_XML_VERSION); 01078 top_node = xmlNewNode (NULL, BAD_CAST QSF_ROOT_TAG); 01079 xmlDocSetRootElement (doc, top_node); 01080 xmlSetNs (top_node, xmlNewNs (top_node, BAD_CAST QSF_DEFAULT_NS, 01081 NULL)); 01082 params->qsf_ns = top_node->ns; 01083 node = 01084 xmlNewChild (top_node, params->qsf_ns, BAD_CAST QSF_BOOK_TAG, 01085 NULL); 01086 params->book_node = node; 01087 xmlNewProp (node, BAD_CAST QSF_BOOK_COUNT, BAD_CAST "1"); 01088 book_guid = qof_entity_get_guid ((QofEntity*)book); 01089 guid_to_string_buff (book_guid, buffer); 01090 xmlNewChild (params->book_node, params->qsf_ns, 01091 BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer); 01092 params->output_doc = doc; 01093 params->book_node = node; 01094 qof_object_foreach_type (qsf_foreach_obj_type, params); 01095 return params->output_doc; 01096 } 01097 01098 static void 01099 write_qsf_from_book (const gchar *path, QofBook * book, 01100 QsfParam * params) 01101 { 01102 xmlDocPtr qsf_doc; 01103 gint write_result; 01104 QofBackend *be; 01105 01106 be = qof_book_get_backend (book); 01107 qsf_doc = qofbook_to_qsf (book, params); 01108 write_result = 0; 01109 PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s", 01110 params->use_gz_level, params->encoding); 01111 if ((params->use_gz_level > 0) && (params->use_gz_level <= 9)) 01112 xmlSetDocCompressMode (qsf_doc, params->use_gz_level); 01113 g_return_if_fail (qsf_is_valid 01114 (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE); 01115 write_result = 01116 xmlSaveFormatFileEnc (path, qsf_doc, params->encoding, 1); 01117 if (write_result < 0) 01118 { 01119 qof_error_set_be (be, qof_error_register 01120 (_("Could not write to '%s'. Check that you have " 01121 "permission to write to this file and that there is " 01122 "sufficient space to create it."), TRUE)); 01123 return; 01124 } 01125 qof_object_mark_clean (book); 01126 } 01127 01128 static void 01129 write_qsf_to_stdout (QofBook * book, QsfParam * params) 01130 { 01131 xmlDocPtr qsf_doc; 01132 01133 qsf_doc = qofbook_to_qsf (book, params); 01134 g_return_if_fail (qsf_is_valid 01135 (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE); 01136 PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s", 01137 params->use_gz_level, params->encoding); 01138 xmlSaveFormatFileEnc ("-", qsf_doc, params->encoding, 1); 01139 fprintf (stdout, "\n"); 01140 qof_object_mark_clean (book); 01141 } 01142 01143 static void 01144 qsf_write_file (QofBackend * be, QofBook * book) 01145 { 01146 QSFBackend *qsf_be; 01147 QsfParam *params; 01148 gchar *path; 01149 01150 qsf_be = (QSFBackend *) be; 01151 params = qsf_be->params; 01152 /* if fullpath is blank, book_id was set to QOF_STDOUT */ 01153 if (!qsf_be->fullpath || (*qsf_be->fullpath == '\0')) 01154 { 01155 write_qsf_to_stdout (book, params); 01156 return; 01157 } 01158 path = strdup (qsf_be->fullpath); 01159 write_qsf_from_book (path, book, params); 01160 g_free (path); 01161 } 01162 01163 KvpValue * 01164 string_to_kvp_value (const gchar * content, KvpValueType type) 01165 { 01166 gchar *tail; 01167 gint64 cm_i64; 01168 gdouble cm_double; 01169 QofNumeric cm_numeric; 01170 GUID *cm_guid; 01171 01172 switch (type) 01173 { 01174 case KVP_TYPE_GINT64: 01175 { 01176 errno = 0; 01177 cm_i64 = strtoll (content, &tail, 0); 01178 if (errno == 0) 01179 { 01180 return kvp_value_new_gint64 (cm_i64); 01181 } 01182 break; 01183 } 01184 case KVP_TYPE_DOUBLE: 01185 { 01186 errno = 0; 01187 cm_double = strtod (content, &tail); 01188 if (errno == 0) 01189 return kvp_value_new_double (cm_double); 01190 break; 01191 } 01192 case KVP_TYPE_NUMERIC: 01193 { 01194 qof_numeric_from_string (content, &cm_numeric); 01195 return kvp_value_new_numeric (cm_numeric); 01196 break; 01197 } 01198 case KVP_TYPE_STRING: 01199 { 01200 return kvp_value_new_string (content); 01201 break; 01202 } 01203 case KVP_TYPE_GUID: 01204 { 01205 cm_guid = g_new0 (GUID, 1); 01206 if (TRUE == string_to_guid (content, cm_guid)) 01207 return kvp_value_new_guid (cm_guid); 01208 break; 01209 } 01210 case KVP_TYPE_TIME : 01211 { 01212 QofDate *qd; 01213 QofTime *qt; 01214 KvpValue *retval; 01215 01216 qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC); 01217 if(qd) 01218 { 01219 qt = qof_date_to_qtime (qd); 01220 retval = kvp_value_new_time (qt); 01221 qof_date_free (qd); 01222 qof_time_free (qt); 01223 return retval; 01224 } 01225 else 01226 PERR (" failed to parse date"); 01227 } 01228 case KVP_TYPE_BOOLEAN : 01229 { 01230 gboolean val; 01231 val = qof_util_bool_to_int (content); 01232 return kvp_value_new_boolean (val); 01233 } 01234 case KVP_TYPE_BINARY: 01235 // return kvp_value_new_binary(value->value.binary.data, 01236 // value->value.binary.datasize); 01237 break; 01238 case KVP_TYPE_GLIST: 01239 // return kvp_value_new_glist(value->value.list); 01240 break; 01241 case KVP_TYPE_FRAME: 01242 // return kvp_value_new_frame(value->value.frame); 01243 break; 01244 } 01245 return NULL; 01246 } 01247 01248 /* ====================================================== 01249 Commit XML data from file to QofEntity in a QofBook 01250 ========================================================= */ 01251 void 01252 qsf_object_commitCB (gpointer key, gpointer value, gpointer data) 01253 { 01254 QsfParam *params; 01255 QsfObject * G_GNUC_UNUSED object_set; 01256 xmlNodePtr node; 01257 QofEntityReference *reference; 01258 QofEntity *qsf_ent; 01259 QofBook * G_GNUC_UNUSED targetBook; 01260 const gchar *qof_type, *parameter_name; 01261 QofIdType obj_type, reference_type; 01262 gchar *tail; 01263 /* cm_ prefix used for variables that hold the data to commit */ 01264 QofNumeric cm_numeric; 01265 gdouble cm_double; 01266 gboolean cm_boolean; 01267 gint32 cm_i32; 01268 gint64 cm_i64; 01269 gchar cm_char, (*char_getter) (xmlNodePtr); 01270 GUID *cm_guid; 01271 KvpFrame *cm_kvp; 01272 KvpValue *cm_value; 01273 KvpValueType cm_type; 01274 QofSetterFunc cm_setter; 01275 const QofParam *cm_param; 01276 void (*string_setter) (QofEntity *, const gchar *); 01277 void (*time_setter) (QofEntity *, QofTime *); 01278 void (*numeric_setter) (QofEntity *, QofNumeric); 01279 void (*double_setter) (QofEntity *, gdouble); 01280 void (*boolean_setter) (QofEntity *, gboolean); 01281 void (*i32_setter) (QofEntity *, gint32); 01282 void (*i64_setter) (QofEntity *, gint64); 01283 void (*char_setter) (QofEntity *, gchar); 01284 01285 g_return_if_fail (data && value && key); 01286 params = (QsfParam *) data; 01287 node = (xmlNodePtr) value; 01288 parameter_name = (const gchar *) key; 01289 qof_type = (gchar *) node->name; 01290 qsf_ent = params->qsf_ent; 01291 targetBook = params->book; 01292 obj_type = 01293 (gchar *) xmlGetProp (node->parent, BAD_CAST QSF_OBJECT_TYPE); 01294 if (0 == safe_strcasecmp (obj_type, parameter_name)) 01295 { 01296 return; 01297 } 01298 cm_setter = qof_class_get_parameter_setter (obj_type, parameter_name); 01299 cm_param = qof_class_get_parameter (obj_type, parameter_name); 01300 object_set = params->object_set; 01301 if (safe_strcmp (qof_type, QOF_TYPE_STRING) == 0) 01302 { 01303 string_setter = (void (*)(QofEntity *, const gchar *)) cm_setter; 01304 if (string_setter != NULL) 01305 { 01306 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01307 string_setter (qsf_ent, (gchar *) xmlNodeGetContent (node)); 01308 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01309 } 01310 } 01311 if (safe_strcmp (qof_type, QOF_TYPE_TIME) == 0) 01312 { 01313 time_setter = (void (*)(QofEntity *, QofTime*)) cm_setter; 01314 if (time_setter != NULL) 01315 { 01316 QofDate *qd; 01317 QofTime *qt; 01318 01319 qd = qof_date_parse ( 01320 (const gchar*) xmlNodeGetContent (node), 01321 QOF_DATE_FORMAT_UTC); 01322 if(qd) 01323 { 01324 qt = qof_date_to_qtime (qd); 01325 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01326 time_setter (qsf_ent, qt); 01327 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01328 qof_date_free (qd); 01329 } 01330 else 01331 PERR (" failed to parse date string"); 01332 } 01333 } 01334 if ((safe_strcmp (qof_type, QOF_TYPE_NUMERIC) == 0) || 01335 (safe_strcmp (qof_type, QOF_TYPE_DEBCRED) == 0)) 01336 { 01337 gchar *tmp; 01338 numeric_setter = (void (*)(QofEntity *, QofNumeric)) cm_setter; 01339 tmp = (char *) xmlNodeGetContent (node); 01340 qof_numeric_from_string (tmp, &cm_numeric); 01341 g_free (tmp); 01342 if (numeric_setter != NULL) 01343 { 01344 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01345 numeric_setter (qsf_ent, cm_numeric); 01346 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01347 } 01348 } 01349 if (safe_strcmp (qof_type, QOF_TYPE_GUID) == 0) 01350 { 01351 cm_guid = g_new0 (GUID, 1); 01352 if (TRUE != 01353 string_to_guid ((gchar *) xmlNodeGetContent (node), cm_guid)) 01354 { 01355 qof_error_set_be (params->be, qof_error_register( 01356 _("The selected QSF object file '%s' contains one or " 01357 "more invalid GUIDs. The file cannot be processed - " 01358 "please check the source of the file and try again."), 01359 TRUE)); 01360 PINFO (" string to guid conversion failed for %s:%s:%s", 01361 xmlNodeGetContent (node), obj_type, qof_type); 01362 return; 01363 } 01364 reference_type = 01365 (gchar *) xmlGetProp (node, BAD_CAST QSF_OBJECT_TYPE); 01366 if (0 == safe_strcmp (QOF_PARAM_GUID, reference_type)) 01367 { 01368 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01369 qof_entity_set_guid (qsf_ent, cm_guid); 01370 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01371 } 01372 else 01373 { 01374 reference = qof_entity_get_reference_from (qsf_ent, cm_param); 01375 if (reference) 01376 { 01377 params->referenceList = 01378 g_list_append (params->referenceList, reference); 01379 } 01380 } 01381 } 01382 if (safe_strcmp (qof_type, QOF_TYPE_INT32) == 0) 01383 { 01384 errno = 0; 01385 cm_i32 = 01386 (gint32) strtol ((char *) xmlNodeGetContent (node), &tail, 0); 01387 if (errno == 0) 01388 { 01389 i32_setter = (void (*)(QofEntity *, gint32)) cm_setter; 01390 if (i32_setter != NULL) 01391 { 01392 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01393 i32_setter (qsf_ent, cm_i32); 01394 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01395 } 01396 } 01397 else 01398 qof_error_set_be (params->be, params->err_overflow); 01399 } 01400 if (safe_strcmp (qof_type, QOF_TYPE_INT64) == 0) 01401 { 01402 errno = 0; 01403 cm_i64 = strtoll ((gchar *) xmlNodeGetContent (node), &tail, 0); 01404 if (errno == 0) 01405 { 01406 i64_setter = (void (*)(QofEntity *, gint64)) cm_setter; 01407 if (i64_setter != NULL) 01408 { 01409 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01410 i64_setter (qsf_ent, cm_i64); 01411 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01412 } 01413 } 01414 else 01415 qof_error_set_be (params->be, params->err_overflow); 01416 } 01417 if (safe_strcmp (qof_type, QOF_TYPE_DOUBLE) == 0) 01418 { 01419 errno = 0; 01420 cm_double = strtod ((gchar *) xmlNodeGetContent (node), &tail); 01421 if (errno == 0) 01422 { 01423 double_setter = (void (*)(QofEntity *, gdouble)) cm_setter; 01424 if (double_setter != NULL) 01425 { 01426 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01427 double_setter (qsf_ent, cm_double); 01428 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01429 } 01430 } 01431 } 01432 if (safe_strcmp (qof_type, QOF_TYPE_BOOLEAN) == 0) 01433 { 01434 if (0 == safe_strcasecmp ((gchar *) xmlNodeGetContent (node), 01435 QSF_XML_BOOLEAN_TEST)) 01436 cm_boolean = TRUE; 01437 else 01438 cm_boolean = FALSE; 01439 boolean_setter = (void (*)(QofEntity *, gboolean)) cm_setter; 01440 if (boolean_setter != NULL) 01441 { 01442 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01443 boolean_setter (qsf_ent, cm_boolean); 01444 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01445 } 01446 } 01447 if (safe_strcmp (qof_type, QOF_TYPE_KVP) == 0) 01448 { 01449 cm_type = 01450 qsf_to_kvp_helper ((gchar *) 01451 xmlGetProp (node, BAD_CAST QSF_OBJECT_VALUE)); 01452 if (!cm_type) 01453 return; 01454 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01455 cm_value = 01456 string_to_kvp_value ((gchar *) xmlNodeGetContent (node), 01457 cm_type); 01458 cm_kvp = (KvpFrame *) cm_param->param_getfcn (qsf_ent, cm_param); 01459 cm_kvp = kvp_frame_set_value (cm_kvp, (gchar *) xmlGetProp (node, 01460 BAD_CAST QSF_OBJECT_KVP), cm_value); 01461 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01462 g_free (cm_value); 01463 } 01464 if (safe_strcmp (qof_type, QOF_TYPE_COLLECT) == 0) 01465 { 01466 QofCollection *qsf_coll; 01467 QofIdType G_GNUC_UNUSED type; 01468 QofEntityReference *reference; 01469 QofParam *copy_param; 01470 /* retrieve the *type* of the collection, ignore any contents. */ 01471 qsf_coll = cm_param->param_getfcn (qsf_ent, cm_param); 01472 type = qof_collection_get_type (qsf_coll); 01473 cm_guid = g_new0 (GUID, 1); 01474 if (TRUE != 01475 string_to_guid ((gchar *) xmlNodeGetContent (node), cm_guid)) 01476 { 01477 qof_error_set_be (params->be, (qof_error_register( 01478 _("The selected QSF object file '%s' contains one or " 01479 "more invalid 'collect' values. The file cannot be processed - " 01480 "please check the source of the file and try again."), 01481 TRUE))); 01482 PINFO (" string to guid collect failed for %s", 01483 xmlNodeGetContent (node)); 01484 return; 01485 } 01486 /* create a QofEntityReference with this type and GUID. 01487 there is only one entity each time. 01488 cm_guid contains the GUID of the reference. 01489 type is the type of the reference. */ 01490 reference = g_new0 (QofEntityReference, 1); 01491 reference->type = g_strdup (qsf_ent->e_type); 01492 reference->ref_guid = cm_guid; 01493 reference->ent_guid = &qsf_ent->guid; 01494 copy_param = g_new0 (QofParam, 1); 01495 copy_param->param_name = g_strdup (cm_param->param_name); 01496 copy_param->param_type = g_strdup (cm_param->param_type); 01497 reference->param = copy_param; 01498 params->referenceList = 01499 g_list_append (params->referenceList, reference); 01500 } 01501 if (safe_strcmp (qof_type, QOF_TYPE_CHAR) == 0) 01502 { 01503 char_getter = (gchar (*)(xmlNodePtr)) xmlNodeGetContent; 01504 cm_char = char_getter (node); 01505 char_setter = (void (*)(QofEntity *, gchar)) cm_setter; 01506 if (char_setter != NULL) 01507 { 01508 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param); 01509 char_setter (qsf_ent, cm_char); 01510 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param); 01511 } 01512 } 01513 } 01514 01515 static QofBackend * 01516 qsf_backend_new (void) 01517 { 01518 QSFBackend *qsf_be; 01519 QofBackend *be; 01520 01521 qsf_be = g_new0 (QSFBackend, 1); 01522 be = (QofBackend *) qsf_be; 01523 qof_backend_init (be); 01524 qsf_be->params = g_new0 (QsfParam, 1); 01525 qsf_be->params->be = be; 01526 qsf_param_init (qsf_be->params); 01527 qsf_be->be.session_begin = qsf_session_begin; 01528 01529 be->session_end = qsf_session_end; 01530 be->destroy_backend = qsf_destroy_backend; 01531 be->load = qsf_file_type; 01532 be->save_may_clobber_data = NULL; 01533 /* The QSF backend will always load and save the entire QSF XML file. */ 01534 be->begin = NULL; 01535 be->commit = NULL; 01536 be->rollback = NULL; 01537 /* QSF uses the built-in SQL, not a dedicated SQL server. */ 01538 be->compile_query = NULL; 01539 be->free_query = NULL; 01540 be->run_query = NULL; 01541 be->counter = NULL; 01542 /* The QSF backend is not multi-user. */ 01543 be->events_pending = NULL; 01544 be->process_events = NULL; 01545 01546 be->sync = qsf_write_file; 01547 /* use for maps, later. */ 01548 be->load_config = qsf_load_config; 01549 be->get_config = qsf_get_config; 01550 01551 qsf_be->fullpath = NULL; 01552 return be; 01553 } 01554 01555 /* The QOF method of loading each backend. 01556 QSF is loaded as a GModule using the QOF method - QofBackendProvider. 01557 */ 01558 static void 01559 qsf_provider_free (QofBackendProvider * prov) 01560 { 01561 prov->provider_name = NULL; 01562 prov->access_method = NULL; 01563 g_free (prov); 01564 } 01565 01566 void 01567 qsf_provider_init (void) 01568 { 01569 QofBackendProvider *prov; 01570 01571 bindtextdomain (PACKAGE, LOCALE_DIR); 01572 prov = g_new0 (QofBackendProvider, 1); 01573 prov->provider_name = "QSF Backend Version 0.4"; 01574 prov->access_method = "file"; 01575 prov->partial_book_supported = TRUE; 01576 prov->backend_new = qsf_backend_new; 01577 prov->check_data_type = qsf_determine_file_type; 01578 prov->provider_free = qsf_provider_free; 01579 qof_backend_register_provider (prov); 01580 }