qsf-backend.c

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 #define _GNU_SOURCE
00025 
00026 #include "config.h"
00027 #include <errno.h>
00028 #include <sys/stat.h>
00029 #include <glib.h>
00030 #include <libxml/xmlmemory.h>
00031 #include <libxml/tree.h>
00032 #include <libxml/parser.h>
00033 #include <libxml/xmlschemas.h>
00034 #include "qof.h"
00035 #include "qof-backend-qsf.h"
00036 #include "qsf-xml.h"
00037 #include "qsf-dir.h"
00038 
00039 #define QSF_TYPE_BINARY "binary"
00040 #define QSF_TYPE_GLIST  "glist"
00041 #define QSF_TYPE_FRAME  "frame"
00042 
00043 static QofLogModule log_module = QOF_MOD_QSF;
00044 
00045 static void qsf_object_commitCB(gpointer key, gpointer value, gpointer data);
00046 
00047 struct QSFBackend_s
00048 {
00049         QofBackend be;
00050         qsf_param *params;
00051         gchar *fullpath;
00052 };
00053 
00054 typedef struct QSFBackend_s QSFBackend;
00055 
00056 static void option_cb (QofBackendOption *option, gpointer data)
00057 {
00058         qsf_param *params;
00059 
00060         params = (qsf_param*)data;
00061         g_return_if_fail(params);
00062         if(0 == safe_strcmp(QSF_COMPRESS, option->option_name)) {
00063                 params->use_gz_level = (*(gint64*)option->value);
00064                 PINFO (" compression=%" G_GINT64_FORMAT,params->use_gz_level);
00065         }
00066         if (0 == safe_strcmp(QSF_MAP_FILES, option->option_name)) {
00067                 params->map_files = g_list_copy((GList*)option->value);
00068         }
00069         if (0 == safe_strcmp(QSF_ENCODING, option->option_name)) {
00070                 params->encoding = g_strdup(option->value);
00071                 PINFO (" encoding=%s", params->encoding);
00072         }
00073 }
00074 
00075 static void
00076 qsf_load_config(QofBackend *be, KvpFrame *config)
00077 {
00078         QSFBackend *qsf_be;
00079         qsf_param  *params;
00080 
00081         ENTER (" ");
00082         qsf_be = (QSFBackend*)be;
00083         g_return_if_fail(qsf_be->params);
00084         params = qsf_be->params;
00085         qof_backend_option_foreach(config, option_cb, params);
00086         LEAVE (" ");
00087 }
00088 
00089 static KvpFrame*
00090 qsf_get_config(QofBackend *be)
00091 {
00092         QofBackendOption *option;
00093         QSFBackend *qsf_be;
00094         qsf_param *params;
00095 
00096         if(!be) { return NULL; }
00097         ENTER (" ");
00098         qsf_be = (QSFBackend*)be;
00099         g_return_val_if_fail(qsf_be->params, NULL);
00100         params = qsf_be->params;
00101         qof_backend_prepare_frame(be);
00102         option = g_new0(QofBackendOption, 1);
00103         option->option_name = QSF_COMPRESS;
00104         option->description = _("Level of compression to use: 0 for none, 9 for highest.");
00105         option->tooltip = _("QOF can compress QSF XML files using gzip. "
00106                 "Note that compression is not used when outputting to STDOUT.");
00107         option->type = KVP_TYPE_GINT64;
00108         /* GINT_TO_POINTER can only be used for 32bit values. */
00109         option->value = (gpointer)&params->use_gz_level;
00110         qof_backend_prepare_option(be, option);
00111         g_free(option);
00112         option = g_new0(QofBackendOption, 1);
00113         option->option_name = QSF_MAP_FILES;
00114         option->description = _("List of QSF map files to use for this session.");
00115         option->tooltip = _("QOF can convert objects within QSF XML files "
00116                 "using a map of the changes required.");
00117         option->type = KVP_TYPE_GLIST;
00118         option->value = (gpointer)params->map_files;
00119         qof_backend_prepare_option(be, option);
00120         g_free(option);
00121         option = g_new0(QofBackendOption, 1);
00122         option->option_name = QSF_ENCODING;
00123         option->description = _("Encoding string to use when writing the XML file.");
00124         option->tooltip = _("QSF defaults to UTF-8. Other encodings are supported by "
00125                         "passing the encoding string in this option.");
00126         option->type = KVP_TYPE_STRING;
00127         option->value = (gpointer)params->encoding;
00128         qof_backend_prepare_option(be, option);
00129         g_free(option);
00130         LEAVE (" ");
00131         return qof_backend_complete_frame(be);
00132 }
00133 
00134 GList**
00135 qsf_map_prepare_list(GList **maps)
00136 {
00137         /* Add new map filenames here. */
00139         *maps = g_list_prepend(*maps, "pilot-qsf-GnuCashInvoice.xml");
00140         *maps = g_list_prepend(*maps, "pilot-qsf-gncCustomer.xml");
00141         return maps;
00142 }
00143 
00144 static void
00145 qsf_param_init(qsf_param *params)
00146 {
00147         Timespec *qsf_ts;
00148         gchar qsf_time_string[QSF_DATE_LENGTH];
00149         gchar qsf_enquiry_date[QSF_DATE_LENGTH];
00150         gchar qsf_time_match[QSF_DATE_LENGTH];
00151         gchar qsf_time_now[QSF_DATE_LENGTH];
00152         time_t qsf_time_now_t;
00153         gchar *qsf_time_precision;
00154 
00155         g_return_if_fail(params != NULL);
00156         params->count = 0;
00157         params->use_gz_level = 0;
00158         params->supported_types = NULL;
00159         params->file_type = QSF_UNDEF;
00160         params->qsf_ns = NULL;
00161         params->output_doc = NULL;
00162         params->output_node = NULL;
00163         params->lister = NULL;
00164         params->full_kvp_path = NULL;
00165         params->map_ns = NULL;
00166         params->map_files = NULL;
00167         params->map_path = NULL;
00168         params->encoding = "UTF-8";
00169         params->qsf_object_list = NULL;
00170         params->qsf_parameter_hash = g_hash_table_new(g_str_hash, g_str_equal);
00171         params->qsf_default_hash = g_hash_table_new(g_str_hash, g_str_equal);
00172         params->qsf_define_hash = g_hash_table_new(g_str_hash, g_str_equal);
00173         params->qsf_calculate_hash = g_hash_table_new(g_str_hash, g_str_equal);
00174         params->referenceList = NULL;
00175         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_STRING);
00176         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_GUID);
00177         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_BOOLEAN);
00178         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_NUMERIC);
00179         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_DATE);
00180         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_INT32);
00181         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_INT64);
00182         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_DOUBLE);
00183         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_CHAR);
00184         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_KVP);
00185         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_COLLECT);
00186         params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_CHOICE);
00187         qsf_time_precision = "%j";
00188         qsf_time_now_t = time(NULL);
00189         qsf_ts = g_new(Timespec, 1);
00190         timespecFromTime_t(qsf_ts, qsf_time_now_t);
00191         strftime(qsf_enquiry_date, QSF_DATE_LENGTH, QSF_XSD_TIME, gmtime(&qsf_time_now_t));
00192         strftime(qsf_time_match, QSF_DATE_LENGTH, qsf_time_precision, gmtime(&qsf_time_now_t));
00193         strftime(qsf_time_string, QSF_DATE_LENGTH, "%F", gmtime(&qsf_time_now_t));
00194         strftime(qsf_time_now, QSF_DATE_LENGTH, QSF_XSD_TIME, gmtime(&qsf_time_now_t));
00195         g_hash_table_insert(params->qsf_default_hash, "qsf_enquiry_date", qsf_enquiry_date);
00196         g_hash_table_insert(params->qsf_default_hash, "qsf_time_now", &qsf_time_now_t);
00197         g_hash_table_insert(params->qsf_default_hash, "qsf_time_string", qsf_time_string);
00198         /* default map files */
00199         params->map_files = *qsf_map_prepare_list(&params->map_files);
00200 }
00201 
00202 static gboolean 
00203 qsf_determine_file_type(const gchar *path)
00204 {
00205         struct stat sbuf;
00206 
00207         if (!path) { return TRUE; }
00208         if (0 == safe_strcmp(path, QOF_STDOUT)) { return TRUE; }
00209         if (stat(path, &sbuf) <0)    { return FALSE; }
00210         if (sbuf.st_size == 0)       { return TRUE; }
00211         if(is_our_qsf_object(path))  { return TRUE; }
00212         else if(is_qsf_object(path)) { return TRUE; }
00213         else if(is_qsf_map(path))    { return TRUE; }
00214         return FALSE;
00215 }
00216 
00217 /* GnuCash does LOTS of filesystem work, QSF is going to leave most of it to libxml2. :-)
00218 Just strip the file: from the start of the book_path URL. Locks are not implemented.
00219 */
00220 static void
00221 qsf_session_begin(QofBackend *be, QofSession *session, const gchar *book_path,
00222                    gboolean ignore_lock, gboolean create_if_nonexistent)
00223 {
00224         QSFBackend *qsf_be;
00225         gchar *p, *path;
00226 
00227         PINFO (" ignore_lock=%d create_if_nonexistent=%d", ignore_lock, create_if_nonexistent);
00228         g_return_if_fail(be != NULL);
00229         qsf_be = (QSFBackend*)be;
00230         g_return_if_fail(qsf_be->params != NULL);
00231         qsf_be->fullpath = NULL;
00232         if(book_path == NULL)
00233         {
00234                 /* use stdout */
00235                 qof_backend_set_error(be, ERR_BACKEND_NO_ERR);
00236                 return;
00237         }
00238         p = strchr (book_path, ':');
00239         if (p) {
00240                 path = g_strdup (book_path);
00241                 if (!g_ascii_strncasecmp(path, "file:", 5)) {
00242                         p = g_new(gchar, strlen(path) - 5 + 1);
00243                         strcpy(p, path + 5);
00244                 }
00245                 qsf_be->fullpath = g_strdup(p);
00246                 g_free (path);
00247         }
00248         else {
00249                 qsf_be->fullpath = g_strdup(book_path);
00250         }
00251         if(create_if_nonexistent)
00252         {
00253                 FILE *f;
00254                 
00255                 f = fopen(qsf_be->fullpath, "a+");
00256                 if(f) {fclose(f); }
00257                 else
00258                 {
00259                         qof_backend_set_error(be, ERR_BACKEND_READONLY);
00260                         return;
00261                 }
00262         }
00263         qof_backend_set_error(be, ERR_BACKEND_NO_ERR);
00264 }
00265 
00266 static void 
00267 qsf_free_params(qsf_param *params)
00268 {
00269         g_hash_table_destroy(params->qsf_calculate_hash);
00270         g_hash_table_destroy(params->qsf_default_hash);
00271         if(params->referenceList) {
00272                 g_list_free(params->referenceList);
00273         }
00274         g_slist_free(params->supported_types);
00275         if(params->map_ns) { xmlFreeNs(params->map_ns); }
00276 }
00277 
00278 static void
00279 qsf_session_end( QofBackend *be)
00280 {
00281         QSFBackend *qsf_be;
00282 
00283         qsf_be = (QSFBackend*)be;
00284         g_return_if_fail(qsf_be != NULL);
00285         qsf_free_params(qsf_be->params);
00286         g_free(qsf_be->fullpath);
00287         qsf_be->fullpath = NULL;
00288         xmlCleanupParser();
00289 }
00290 
00291 static void
00292 qsf_destroy_backend (QofBackend *be)
00293 {
00294         g_free(be);
00295 }
00296 
00297 static void
00298 ent_ref_cb (QofEntity* ent, gpointer user_data)
00299 {
00300         qsf_param *params;
00301         QofEntityReference *ref;
00302         void (*reference_setter) (QofEntity*, QofEntity*);
00303         QofEntity *reference;
00304         QofCollection *coll;
00305         QofIdType type;
00306 
00307         params = (qsf_param*)user_data;
00308         g_return_if_fail(params);
00309         while(params->referenceList)
00310         {
00311                 ref = (QofEntityReference*)params->referenceList->data;
00312                 if(qof_object_is_choice(ent->e_type)) { type = ref->choice_type; }
00313                 else { type = ref->type; }
00314                 coll = qof_book_get_collection(params->book, type);
00315                 reference = qof_collection_lookup_entity(coll, ref->ref_guid);
00316                 reference_setter = (void(*)(QofEntity*, QofEntity*))ref->param->param_setfcn;
00317                 if(reference_setter != NULL)
00318                 {
00319                         qof_begin_edit((QofInstance*)ent);
00320                         qof_begin_edit((QofInstance*)reference);
00321                         reference_setter(ent, reference);
00322                         qof_commit_edit((QofInstance*)ent);
00323                         qof_commit_edit((QofInstance*)reference);
00324                 }
00325                 params->referenceList = g_list_next(params->referenceList);
00326         }
00327 }
00328 
00329 static void
00330 insert_ref_cb(QofObject *obj, gpointer user_data)
00331 {
00332         qsf_param *params;
00333 
00334         params = (qsf_param*)user_data;
00335         g_return_if_fail(params);
00336         qof_object_foreach(obj->e_type, params->book, ent_ref_cb, params);
00337 }
00338 
00339 /*================================================
00340         Load QofEntity into QofBook from XML in memory
00341 ==================================================*/
00342 
00343 static gboolean
00344 qsfdoc_to_qofbook(xmlDocPtr doc, qsf_param *params)
00345 {
00346         QofInstance *inst;
00347         struct qsf_node_iterate iter;
00348         QofBook *book;
00349         GList *object_list;
00350         xmlNodePtr qsf_root;
00351         xmlNsPtr qsf_ns;
00352 
00353         g_return_val_if_fail(params != NULL, FALSE);
00354         g_return_val_if_fail(params->input_doc != NULL, FALSE);
00355         g_return_val_if_fail(params->book != NULL, FALSE);
00356         g_return_val_if_fail(params->file_type == OUR_QSF_OBJ, FALSE);
00357         qsf_root = xmlDocGetRootElement(params->input_doc);
00358         if(!qsf_root) { return FALSE; }
00359         qsf_ns = qsf_root->ns;
00360         iter.ns = qsf_ns;
00361         book = params->book;
00362         params->referenceList = (GList*)qof_book_get_data(book, ENTITYREFERENCE);
00363         qsf_node_foreach(qsf_root, qsf_book_node_handler, &iter, params);
00364         object_list = g_list_copy(params->qsf_object_list);
00365         while(object_list != NULL)
00366         {
00367                 params->object_set = object_list->data;
00368                 object_list = g_list_next(object_list);
00369                 params->qsf_parameter_hash = params->object_set->parameters;
00370                 if(!qof_class_is_registered(params->object_set->object_type)) { continue; }
00371                 inst = (QofInstance*)qof_object_new_instance(params->object_set->object_type, 
00372                         book);
00373                 g_return_val_if_fail(inst != NULL, FALSE);
00374                 params->qsf_ent = &inst->entity;
00375                 qof_begin_edit(inst);
00376                 g_hash_table_foreach(params->qsf_parameter_hash, qsf_object_commitCB, 
00377                         params);
00378                 qof_commit_edit(inst);
00379         }
00380         qof_object_foreach_type(insert_ref_cb, params);
00381         qof_book_set_data(book, ENTITYREFERENCE, params->referenceList);
00382         return TRUE;
00383 }
00384 
00385 /* QofBackend routine to load from file - needs a map.
00386 */
00387 static gboolean
00388 load_qsf_object(QofBook *book, const gchar *fullpath, qsf_param *params)
00389 {
00390         xmlNodePtr qsf_root, map_root;
00391         xmlDocPtr mapDoc, foreign_doc;
00392         gchar *map_path, *map_file;
00393 
00394         map_file = params->map_path;
00395         mapDoc = NULL;
00396         /* use selected map */
00397         if(!map_file) {
00398                 qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
00399                 return FALSE; 
00400         }
00401         foreign_doc = xmlParseFile(fullpath);
00402         if (foreign_doc == NULL) {
00403                 qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
00404                 return FALSE;
00405         }
00406         qsf_root = NULL;
00407         qsf_root = xmlDocGetRootElement(foreign_doc);
00408         params->qsf_ns = qsf_root->ns;
00409         params->book = book;
00410         map_path = g_strdup_printf("%s/%s", QSF_SCHEMA_DIR, map_file);
00411         if(!map_path) {
00412                 qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
00413                 return FALSE; 
00414         }
00415         mapDoc = xmlParseFile(map_path);
00416         if(!mapDoc) {
00417                 qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
00418                 return FALSE;
00419         }
00420         map_root = xmlDocGetRootElement(mapDoc);
00421         params->map_ns = map_root->ns;
00422         params->input_doc = qsf_object_convert(mapDoc, qsf_root, params);
00423         qsfdoc_to_qofbook(params->input_doc, params);
00424         return TRUE;
00425 }
00426 
00427 static gboolean
00428 load_our_qsf_object(QofBook *book, const gchar *fullpath, qsf_param *params)
00429 {
00430         xmlNodePtr qsf_root;
00431 
00432         params->input_doc = xmlParseFile(fullpath);
00433         if (params->input_doc == NULL) {
00434                 qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
00435                 return FALSE;
00436         }
00437         qsf_root = NULL;
00438         qsf_root = xmlDocGetRootElement(params->input_doc);
00439         params->qsf_ns = qsf_root->ns;
00440         return qsfdoc_to_qofbook(params->input_doc, params);
00441 }
00442 
00443 /* Determine the type of QSF and load it into the QofBook
00444 
00445 - is_our_qsf_object, OUR_QSF_OBJ, QSF object file using only QOF objects known
00446         to the calling process. No map is required.
00447 - is_qsf_object, IS_QSF_OBJ, QSF object file that may or may not have a QSF map
00448         to convert external objects. This temporary type will be set to HAVE_QSF_MAP 
00449         if a suitable map exists, or an error value returned: ERR_QSF_NO_MAP, 
00450         ERR_QSF_BAD_MAP or ERR_QSF_WRONG_MAP. This allows the calling process to inform 
00451         the user that the QSF itself is valid but a suitable map cannot be found.
00452 - is_qsf_map, IS_QSF_MAP, QSF map file. In the backend, this generates 
00453         ERR_QSF_MAP_NOT_OBJ but it can be used internally when processing maps to 
00454         match a QSF object.
00455 
00456 returns NULL on error, otherwise a pointer to the QofBook. Use
00457 the qof_book_merge API to merge the new data into the current
00458 QofBook. 
00459 */
00460 static void
00461 qsf_file_type(QofBackend *be, QofBook *book)
00462 {
00463         QSFBackend *qsf_be;
00464         QofBackendError err;
00465         qsf_param *params;
00466         FILE *f;
00467         gchar *path;
00468         gboolean result;
00469 
00470         g_return_if_fail(be != NULL);
00471         g_return_if_fail(book != NULL);
00472         qsf_be = (QSFBackend*) be;
00473         g_return_if_fail(qsf_be != NULL);
00474         g_return_if_fail(qsf_be->fullpath != NULL);
00475         g_return_if_fail(qsf_be->params != NULL);
00476         params = qsf_be->params;
00477         params->book = book;
00478         path = g_strdup(qsf_be->fullpath);
00479         f = fopen(path, "r");
00480         if(!f) { qof_backend_set_error(be, ERR_FILEIO_READ_ERROR); }
00481         fclose(f);
00482         params->filepath = g_strdup(path);
00483         qof_backend_get_error(be);
00484         result = is_our_qsf_object_be(params);
00485         if(result) {
00486                 params->file_type = OUR_QSF_OBJ;
00487                 result = load_our_qsf_object(book, path, params);
00488                 if(!result) { qof_backend_set_error(be, ERR_FILEIO_PARSE_ERROR); }
00489                 return;
00490         }
00491         else if(is_qsf_object_be(params)) {
00492                 params->file_type = IS_QSF_OBJ;
00493                 result = load_qsf_object(book, path, params);
00494                 if(!result) { qof_backend_set_error(be, ERR_FILEIO_PARSE_ERROR); }
00495                 return;
00496         }
00497         err = qof_backend_get_error(be);
00498         if(err == ERR_QSF_WRONG_MAP)
00499         {
00500                 /* usable QSF object but no map available */
00501                 params->file_type = IS_QSF_OBJ;
00502                 result = TRUE;
00503         }
00504         /* pop the error back on the stack. */
00505         qof_backend_set_error(params->be, err);
00506         if(result == FALSE){
00507                 if(is_qsf_map_be(params)) {
00508                 params->file_type = IS_QSF_MAP;
00509                 qof_backend_set_error(be, ERR_QSF_MAP_NOT_OBJ);
00510                 }
00511         }
00512 }
00513 
00514 static void
00515 qsf_object_sequence(QofParam *qof_param, gpointer data)
00516 {
00517         qsf_param *params;
00518         GSList *checklist, *result;
00519 
00520         g_return_if_fail(data != NULL);
00521         params = (qsf_param*) data;
00522         result = NULL;
00523         checklist = NULL;
00524         params->knowntype = FALSE;
00525         checklist = g_slist_copy(params->supported_types);
00526         for(result = checklist; result != NULL; result = result->next)
00527         {
00528                 if(0 == safe_strcmp((QofIdType)result->data, qof_param->param_type))
00529                 {
00530                         params->knowntype = TRUE;
00531                 }
00532         }
00533         g_slist_free(checklist);
00534         if(0 == safe_strcmp(qof_param->param_type, params->qof_type))
00535         {
00536                 params->qsf_sequence = g_slist_append(params->qsf_sequence, qof_param);
00537                 params->knowntype = TRUE;
00538         }
00539         /* handle params->qof_type = QOF_TYPE_GUID and qof_param->param_type != known type */
00540         if(0 == safe_strcmp(params->qof_type, QOF_TYPE_GUID)
00541                 && (params->knowntype == FALSE))
00542         {
00543                 params->qsf_sequence = g_slist_append(params->qsf_sequence, qof_param);
00544                 params->knowntype = TRUE;
00545         }
00546 }
00547 
00548 /* receives each entry from supported_types in sequence
00549         type = qof data type from supported list
00550         user_data = params. Holds object type
00551 */
00552 static void
00553 qsf_supported_parameters(gpointer type, gpointer user_data)
00554 {
00555         qsf_param *params;
00556 
00557         g_return_if_fail(user_data != NULL);
00558         params = (qsf_param*) user_data;
00559         params->qof_type = (QofIdType)type;
00560         params->knowntype = FALSE;
00561         qof_class_param_foreach(params->qof_obj_type, qsf_object_sequence, params);
00562 }
00563 
00564 static KvpValueType
00565 qsf_to_kvp_helper(const char *type_string)
00566 {
00567         if(0 == safe_strcmp(QOF_TYPE_INT64,   type_string)) { return KVP_TYPE_GINT64;   }
00568         if(0 == safe_strcmp(QOF_TYPE_DOUBLE,  type_string)) { return KVP_TYPE_DOUBLE;   }
00569         if(0 == safe_strcmp(QOF_TYPE_NUMERIC, type_string)) { return KVP_TYPE_NUMERIC;  }
00570         if(0 == safe_strcmp(QOF_TYPE_STRING,  type_string)) { return KVP_TYPE_STRING;   }
00571         if(0 == safe_strcmp(QOF_TYPE_GUID,    type_string)) { return KVP_TYPE_GUID;     }
00572         if(0 == safe_strcmp(QOF_TYPE_DATE,    type_string)) { return KVP_TYPE_TIMESPEC; }
00573         if(0 == safe_strcmp(QSF_TYPE_BINARY,  type_string)) { return KVP_TYPE_BINARY;   }
00574         if(0 == safe_strcmp(QSF_TYPE_GLIST,   type_string)) { return KVP_TYPE_GLIST;    }
00575         if(0 == safe_strcmp(QSF_TYPE_FRAME,   type_string)) { return KVP_TYPE_FRAME;    }
00576         return 0;
00577 }
00578 
00579 static QofIdTypeConst
00580 kvp_value_to_qof_type_helper(KvpValueType n)
00581 {
00582         switch(n)
00583         {
00584                 case KVP_TYPE_GINT64   : { return QOF_TYPE_INT64;   break; }
00585                 case KVP_TYPE_DOUBLE   : { return QOF_TYPE_DOUBLE;  break; }
00586                 case KVP_TYPE_NUMERIC  : { return QOF_TYPE_NUMERIC; break; }
00587                 case KVP_TYPE_STRING   : { return QOF_TYPE_STRING;  break; }
00588                 case KVP_TYPE_GUID     : { return QOF_TYPE_GUID;    break; }
00589                 case KVP_TYPE_TIMESPEC : { return QOF_TYPE_DATE;    break; }
00590                 case KVP_TYPE_BINARY   : { return QSF_TYPE_BINARY;  break; }
00591                 case KVP_TYPE_GLIST    : { return QSF_TYPE_GLIST;   break; }
00592                 case KVP_TYPE_FRAME    : { return QSF_TYPE_FRAME;   break; }
00593                 default : { return NULL; }
00594         }
00595 }
00596 
00597 
00598 static void
00599 qsf_from_kvp_helper(const gchar *path, KvpValue *content, gpointer data)
00600 {
00601         qsf_param *params;
00602         QofParam *qof_param;
00603         xmlNodePtr node;
00604         KvpValueType n;
00605         gchar *full_path;
00606 
00607         params = (qsf_param*)data;
00608         qof_param = params->qof_param;
00609         full_path = NULL;
00610         g_return_if_fail(params && path && content);
00611         ENTER (" ");
00612         n = kvp_value_get_type(content);
00613         switch(n)
00614         {
00615                 case KVP_TYPE_GINT64   :
00616                 case KVP_TYPE_DOUBLE   :
00617                 case KVP_TYPE_NUMERIC  :
00618                 case KVP_TYPE_STRING   :
00619                 case KVP_TYPE_GUID     :
00620                 case KVP_TYPE_TIMESPEC :
00621                 case KVP_TYPE_BINARY   :
00622                 case KVP_TYPE_GLIST    :
00623                 {
00624                         node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
00625                                 BAD_CAST qof_param->param_type));
00626                         xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
00627                         xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 
00628                                 qof_param->param_name);
00629                         full_path = g_strconcat(params->full_kvp_path, "/", path, NULL);
00630                         xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST full_path);
00631                         xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, 
00632                                 BAD_CAST kvp_value_to_qof_type_helper(n));
00633                         PINFO (" set %s", kvp_value_to_qof_type_helper(n));
00634                         break;
00635                 }
00636                 case KVP_TYPE_FRAME:
00637                 {
00638                         if(!params->full_kvp_path) { params->full_kvp_path = g_strdup(path); }
00639                         else { 
00640                                 params->full_kvp_path = g_strconcat(params->full_kvp_path, 
00641                                         "/", path, NULL);
00642                         }
00643                         PINFO (" full=%s, path=%s ", params->full_kvp_path, path);
00644                         kvp_frame_for_each_slot(kvp_value_get_frame(content), 
00645                                 qsf_from_kvp_helper, params);
00646                         g_free(params->full_kvp_path);
00647                         params->full_kvp_path = NULL;
00648                         break;
00649                 }
00650                 default:
00651                 {
00652                         PERR (" unsupported value = %d", kvp_value_get_type(content));
00653                         break;
00654                 }
00655         }
00656         LEAVE (" ");
00657 }
00658 
00659 static void
00660 qsf_from_coll_cb (QofEntity *ent, gpointer user_data)
00661 {
00662         qsf_param *params;
00663         QofParam *qof_param;
00664         xmlNodePtr node;
00665         gchar qsf_guid[GUID_ENCODING_LENGTH + 1];
00666 
00667         params = (qsf_param*)user_data;
00668         if(!ent || !params) { return; }
00669         qof_param = params->qof_param;
00670         guid_to_string_buff(qof_entity_get_guid(ent), qsf_guid);
00671         node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
00672                 BAD_CAST qof_param->param_type));
00673         xmlNodeAddContent(node, BAD_CAST qsf_guid);
00674         xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
00675 }
00676 
00677 /******* reference handling ***********/
00678 
00679 static gint
00680 qof_reference_list_cb(gconstpointer a, gconstpointer b)
00681 {
00682         const QofEntityReference *aa;
00683         const QofEntityReference *bb;
00684 
00685         aa = (QofEntityReference*) a;
00686         bb = (QofEntityReference*) b;
00687         if(aa == NULL) { return 1; }
00688         g_return_val_if_fail((bb != NULL), 1);
00689         g_return_val_if_fail((aa->type != NULL), 1);
00690         if((0 == guid_compare(bb->ent_guid, aa->ent_guid))
00691                 &&(0 == safe_strcmp(bb->type, aa->type))
00692                 &&(0 == safe_strcmp(bb->param->param_name, aa->param->param_name)))
00693         {
00694                 return 0;
00695         }
00696         return 1;
00697 }
00698 
00699 static QofEntityReference*
00700 qof_reference_lookup(GList *referenceList, QofEntityReference *find)
00701 {
00702         GList *single_ref;
00703         QofEntityReference *ent_ref;
00704 
00705         if(referenceList == NULL) { return NULL; }
00706         g_return_val_if_fail(find != NULL, NULL);
00707         single_ref = NULL;
00708         ent_ref = NULL;
00709         single_ref = g_list_find_custom(referenceList, find, qof_reference_list_cb);
00710         if(single_ref == NULL) { return ent_ref; }
00711         ent_ref = (QofEntityReference*)single_ref->data;
00712         g_list_free(single_ref);
00713         return ent_ref;
00714 }
00715 
00716 static void
00717 reference_list_lookup(gpointer data, gpointer user_data)
00718 {
00719         QofEntity *ent;
00720         QofParam *ref_param;
00721         QofEntityReference *reference, *starter;
00722         qsf_param  *params;
00723         const GUID *guid;
00724         xmlNodePtr node, object_node;
00725         xmlNsPtr ns;
00726         GList *copy_list;
00727         gchar qsf_guid[GUID_ENCODING_LENGTH + 1], *ref_name;
00728 
00729         params = (qsf_param*)user_data;
00730         ref_param = (QofParam*)data;
00731         object_node = params->output_node;
00732         ent = params->qsf_ent;
00733         ns = params->qsf_ns;
00734         starter = g_new(QofEntityReference, 1);
00735         starter->ent_guid = qof_entity_get_guid(ent);
00736         starter->type = g_strdup(ent->e_type);
00737         starter->param = ref_param;
00738         starter->ref_guid = NULL;
00739         copy_list = g_list_copy(params->referenceList);
00740         reference = qof_reference_lookup(copy_list, starter);
00741         g_free(starter);
00742         if(reference != NULL) {
00743                 if((ref_param->param_getfcn == NULL)||(ref_param->param_setfcn == NULL))
00744                 {
00745                         return;
00746                 }
00747                 ref_name = g_strdup(reference->param->param_name);
00748                 node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST QOF_TYPE_GUID));
00749                 guid_to_string_buff(reference->ref_guid, qsf_guid);
00750                 xmlNodeAddContent(node, BAD_CAST qsf_guid);
00751                 xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ref_name);
00752                 g_free(ref_name);
00753         }
00754         else {
00755                 ent = (QofEntity*)ref_param->param_getfcn(ent, ref_param);
00756                 if(!ent) { return; }
00757                 if((0 == safe_strcmp(ref_param->param_type, QOF_TYPE_COLLECT)) ||
00758                         (0 == safe_strcmp(ref_param->param_type, QOF_TYPE_CHOICE)))
00759                 { return; }
00760                 node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST QOF_TYPE_GUID));
00761                 guid = qof_entity_get_guid(ent);
00762                 guid_to_string_buff(guid, qsf_guid);
00763                 xmlNodeAddContent(node, BAD_CAST qsf_guid);
00764                 xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ref_param->param_name);
00765         }
00766 }
00767 
00768 /*=====================================
00769         Convert QofEntity to QSF XML node
00770 qof_param holds the parameter sequence.
00771 =======================================*/
00772 static void
00773 qsf_entity_foreach(QofEntity *ent, gpointer data)
00774 {
00775         qsf_param  *params;
00776         GSList     *param_list, *supported;
00777         GList      *ref;
00778         xmlNodePtr node, object_node;
00779         xmlNsPtr   ns;
00780         gchar      *string_buffer;
00781         QofParam   *qof_param;
00782         QofEntity  *choice_ent;
00783         KvpFrame   *qsf_kvp;
00784         QofCollection *qsf_coll;
00785         gint        param_count;
00786         gboolean   own_guid;
00787         const GUID *cm_guid;
00788         gchar       cm_sa[GUID_ENCODING_LENGTH + 1];
00789 
00790         g_return_if_fail(data != NULL);
00791         params = (qsf_param*)data;
00792         param_count = ++params->count;
00793         ns = params->qsf_ns;
00794         qsf_kvp = kvp_frame_new();
00795         own_guid = FALSE;
00796         choice_ent = NULL;
00797         object_node = xmlNewChild(params->book_node, params->qsf_ns,
00798                 BAD_CAST QSF_OBJECT_TAG, NULL);
00799         xmlNewProp(object_node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ent->e_type);
00800         string_buffer = g_strdup_printf("%i", param_count);
00801         xmlNewProp(object_node, BAD_CAST QSF_OBJECT_COUNT, BAD_CAST string_buffer);
00802         g_free(string_buffer);
00803         param_list = g_slist_copy(params->qsf_sequence);
00804         while(param_list != NULL) {
00805                 qof_param = (QofParam*)param_list->data;
00806                 g_return_if_fail(qof_param != NULL);
00807                 if(0 == safe_strcmp(qof_param->param_type, QOF_TYPE_GUID))
00808                 {
00809                         if(!own_guid)
00810                         {
00811                                 cm_guid = qof_entity_get_guid(ent);
00812                                 node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST 
00813                                         QOF_TYPE_GUID));
00814                                 guid_to_string_buff(cm_guid, cm_sa);
00815                                 string_buffer = g_strdup(cm_sa);
00816                                 xmlNodeAddContent(node, BAD_CAST string_buffer);
00817                                 xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE , BAD_CAST 
00818                                         QOF_PARAM_GUID);
00819                                 g_free(string_buffer);
00820                                 own_guid = TRUE;
00821                         }
00822                         params->qsf_ent = ent;
00823                         params->output_node = object_node;
00824                         ref = qof_class_get_referenceList(ent->e_type);
00825                         if(ref != NULL) {
00826                                 g_list_foreach(ref, reference_list_lookup, params);
00827                         }
00828                 }
00829                 if(0 == safe_strcmp(qof_param->param_type, QOF_TYPE_COLLECT))
00830                 {
00831                         qsf_coll = qof_param->param_getfcn(ent, qof_param);
00832                         if(qsf_coll) {
00833                                 params->qof_param = qof_param;
00834                                 params->output_node = object_node;
00835                                 if(qof_collection_count(qsf_coll) > 0) {
00836                                         qof_collection_foreach(qsf_coll, qsf_from_coll_cb, params);
00837                                 }
00838                         }
00839                         param_list = g_slist_next(param_list);
00840                         continue;
00841                 }
00842                 if(0 == safe_strcmp(qof_param->param_type, QOF_TYPE_CHOICE))
00843                 {
00845                         choice_ent = (QofEntity*)qof_param->param_getfcn(ent, qof_param);
00846                         if(!choice_ent) {
00847                                 param_list = g_slist_next(param_list);
00848                                 continue;
00849                         }
00850                         node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST 
00851                                 qof_param->param_type));
00852                         cm_guid = qof_entity_get_guid(choice_ent);
00853                         guid_to_string_buff(cm_guid, cm_sa);
00854                         string_buffer = g_strdup(cm_sa);
00855                         xmlNodeAddContent(node, BAD_CAST string_buffer);
00856                         xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 
00857                                 qof_param->param_name);
00858                         xmlNewProp(node, BAD_CAST "name", BAD_CAST choice_ent->e_type);
00859                         g_free(string_buffer);
00860                         param_list = g_slist_next(param_list);
00861                         continue;
00862                 }
00863                 if(0 == safe_strcmp(qof_param->param_type, QOF_TYPE_KVP))
00864                 {
00865                         qsf_kvp = (KvpFrame*)qof_param->param_getfcn(ent,qof_param);
00866                         if(kvp_frame_is_empty(qsf_kvp)) { LEAVE(" "); return; }
00867                         params->qof_param = qof_param;
00868                         params->output_node = object_node;
00869                         kvp_frame_for_each_slot(qsf_kvp, qsf_from_kvp_helper, params);
00870                 }
00871                 if((qof_param->param_setfcn != NULL) && (qof_param->param_getfcn != NULL))
00872                 {
00873                         for( supported = g_slist_copy(params->supported_types);
00874                                 supported != NULL; supported = g_slist_next(supported))
00875                         {
00876                                 if(0 == safe_strcmp((const gchar*)supported->data, 
00877                                         (const gchar*)qof_param->param_type))
00878                                 {
00879                                         node = xmlAddChild(object_node, 
00880                                                 xmlNewNode(ns, BAD_CAST qof_param->param_type));
00881                                         string_buffer = g_strdup(qof_book_merge_param_as_string(qof_param, 
00882                                                 ent));
00883                                         xmlNodeAddContent(node, BAD_CAST string_buffer);
00884                                         xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST 
00885                                                 qof_param->param_name);
00886                                         g_free(string_buffer);
00887                                 }
00888                         }
00889                 }
00890                 param_list = g_slist_next(param_list);
00891         }
00892 }
00893 
00894 static void
00895 qsf_foreach_obj_type(QofObject *qsf_obj, gpointer data)
00896 {
00897         qsf_param *params;
00898         QofBook *book;
00899         GSList *support;
00900 
00901         g_return_if_fail(data != NULL);
00902         params = (qsf_param*) data;
00903         /* Skip unsupported objects */
00904         if((qsf_obj->create == NULL)||(qsf_obj->foreach == NULL)){
00905                 PINFO (" qsf_obj QOF support failed %s", qsf_obj->e_type);
00906                 return;
00907         }
00908         params->qof_obj_type = qsf_obj->e_type;
00909         params->qsf_sequence = NULL;
00910         book = params->book;
00911         support = g_slist_copy(params->supported_types);
00912         g_slist_foreach(support,qsf_supported_parameters, params);
00913         qof_object_foreach(qsf_obj->e_type, book, qsf_entity_foreach, params);
00914 }
00915 
00916 /*=====================================================
00917         Take a QofBook and prepare a QSF XML doc in memory
00918 =======================================================*/
00919 /*      QSF only uses one QofBook per file - count may be removed later. */
00920 static xmlDocPtr
00921 qofbook_to_qsf(QofBook *book, qsf_param *params)
00922 {
00923         xmlNodePtr top_node, node;
00924         xmlDocPtr doc;
00925         gchar buffer[GUID_ENCODING_LENGTH + 1];
00926         const GUID *book_guid;
00927 
00928         g_return_val_if_fail(book != NULL, NULL);
00929         params->book = book;
00930         params->referenceList = 
00931                 g_list_copy((GList*)qof_book_get_data(book, ENTITYREFERENCE));
00932         doc = xmlNewDoc(BAD_CAST QSF_XML_VERSION);
00933         top_node = xmlNewNode(NULL, BAD_CAST QSF_ROOT_TAG);
00934         xmlDocSetRootElement(doc, top_node);
00935         xmlSetNs(top_node, xmlNewNs(top_node, BAD_CAST QSF_DEFAULT_NS, NULL));
00936         params->qsf_ns = top_node->ns;
00937         node = xmlNewChild(top_node, params->qsf_ns, BAD_CAST QSF_BOOK_TAG, NULL);
00938         params->book_node = node;
00939         xmlNewProp(node, BAD_CAST QSF_BOOK_COUNT, BAD_CAST "1");
00940         book_guid = qof_book_get_guid(book);
00941         guid_to_string_buff(book_guid, buffer);
00942         xmlNewChild(params->book_node, params->qsf_ns, 
00943                 BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
00944         params->output_doc = doc;
00945         params->book_node = node;
00946         qof_object_foreach_type(qsf_foreach_obj_type, params);
00947         return params->output_doc;
00948 }
00949 
00950 static void
00951 write_qsf_from_book(const char *path, QofBook *book, qsf_param *params)
00952 {
00953         xmlDocPtr qsf_doc;
00954         gint write_result;
00955         QofBackend *be;
00956 
00957         be = qof_book_get_backend(book);
00958         qsf_doc = qofbook_to_qsf(book, params);
00959         write_result = 0;
00960         PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s",
00961                 params->use_gz_level, params->encoding);
00962         if((params->use_gz_level > 0) && (params->use_gz_level <= 9)) 
00963         {
00964                 xmlSetDocCompressMode(qsf_doc, params->use_gz_level); 
00965         }
00966         g_return_if_fail(
00967                 qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
00968         write_result = xmlSaveFormatFileEnc(path, qsf_doc, params->encoding, 1);
00969         if(write_result < 0) 
00970         {
00971                 qof_backend_set_error(be, ERR_FILEIO_WRITE_ERROR);
00972                 return;
00973         }
00974         xmlFreeDoc(qsf_doc);
00975 }
00976 
00977 static void
00978 write_qsf_to_stdout(QofBook *book, qsf_param *params)
00979 {
00980         xmlDocPtr qsf_doc;
00981 
00982         qsf_doc = qofbook_to_qsf(book, params);
00983         g_return_if_fail(
00984                 qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
00985         PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s", 
00986                 params->use_gz_level, params->encoding);
00987         xmlSaveFormatFileEnc("-", qsf_doc, params->encoding, 1);
00988         fprintf(stdout, "\n");
00989         xmlFreeDoc(qsf_doc);
00990 }
00991 
00992 static void
00993 qsf_write_file(QofBackend *be, QofBook *book)
00994 {
00995         QSFBackend *qsf_be;
00996         qsf_param *params;
00997         char *path;
00998 
00999         qsf_be = (QSFBackend*)be;
01000         params = qsf_be->params;
01001         /* if fullpath is blank, book_id was set to QOF_STDOUT */
01002         if (!qsf_be->fullpath || (*qsf_be->fullpath == '\0')) {
01003                 write_qsf_to_stdout(book, params);
01004                 return;
01005         }
01006         path = strdup(qsf_be->fullpath);
01007         write_qsf_from_book(path, book, params);
01008         g_free(path);
01009 }
01010 
01011 KvpValue*
01012 string_to_kvp_value(const gchar *content, KvpValueType type)
01013 {
01014         gchar        *tail;
01015         gint64      cm_i64;
01016         double      cm_double;
01017         gnc_numeric cm_numeric;
01018         GUID        *cm_guid;
01019         struct tm   kvp_time;
01020         time_t      kvp_time_t;
01021         Timespec    cm_date;
01022 
01023         switch(type)
01024         {
01025                 case KVP_TYPE_GINT64:
01026                 {
01027                         errno = 0;
01028                         cm_i64 = strtoll(content, &tail, 0);
01029                         if(errno == 0) {
01030                                 return kvp_value_new_gint64(cm_i64);
01031                         }
01032                         break;
01033                 }
01034                 case KVP_TYPE_DOUBLE:
01035                 {
01036                         errno = 0;
01037                         cm_double = strtod(content, &tail);
01038                         if(errno == 0) {
01039                                 return kvp_value_new_double(cm_double);
01040                         }
01041                         break;
01042                 }
01043                 case KVP_TYPE_NUMERIC:
01044                 {
01045                         string_to_gnc_numeric(content, &cm_numeric);
01046                         return kvp_value_new_gnc_numeric(cm_numeric);
01047                         break;
01048                 }
01049                 case KVP_TYPE_STRING:
01050                 {
01051                         return kvp_value_new_string(content);
01052                         break;
01053                 }
01054                 case KVP_TYPE_GUID:
01055                 {
01056                         cm_guid = g_new(GUID, 1);
01057                         if(TRUE == string_to_guid(content, cm_guid))
01058                         {
01059                                 return kvp_value_new_guid(cm_guid);
01060                         }
01061                         break;
01062                 }
01063                 case KVP_TYPE_TIMESPEC:
01064                 {
01065                         strptime(content, QSF_XSD_TIME, &kvp_time);
01066                         kvp_time_t = mktime(&kvp_time);
01067                         timespecFromTime_t(&cm_date, kvp_time_t);
01068                         return kvp_value_new_timespec(cm_date);
01069                         break;
01070                 }
01071                 case KVP_TYPE_BINARY:
01072 //              return kvp_value_new_binary(value->value.binary.data,
01073 //                                                                      value->value.binary.datasize);
01074                 break;
01075         case KVP_TYPE_GLIST:
01076 //              return kvp_value_new_glist(value->value.list);
01077                 break;
01078         case KVP_TYPE_FRAME:
01079 //              return kvp_value_new_frame(value->value.frame);
01080                 break;
01081         }
01082         return NULL;
01083 }
01084 
01085 /* ======================================================
01086         Commit XML data from file to QofEntity in a QofBook
01087 ========================================================= */
01088 void
01089 qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
01090 {
01091         qsf_param          *params;
01092         qsf_objects        *object_set;
01093         xmlNodePtr         node;
01094         QofEntityReference *reference;
01095         QofEntity          *qsf_ent;
01096         QofBook            *targetBook;
01097         const char         *qof_type, *parameter_name, *timechk;
01098         QofIdType          obj_type, reference_type;
01099         struct tm          qsf_time;
01100         time_t             qsf_time_t;
01101         gchar              *tail;
01102         /* cm_ prefix used for variables that hold the data to commit */
01103         gnc_numeric    cm_numeric;
01104         double         cm_double;
01105         gboolean       cm_boolean;
01106         gint32         cm_i32;
01107         gint64         cm_i64;
01108         Timespec       cm_date;
01109         gchar          cm_char,    (*char_getter)  (xmlNodePtr);
01110         GUID           *cm_guid;
01111         KvpFrame       *cm_kvp;
01112         KvpValue       *cm_value;
01113         KvpValueType   cm_type;
01114         QofSetterFunc  cm_setter;
01115         const QofParam *cm_param;
01116         void (*string_setter)    (QofEntity*, const gchar*);
01117         void (*date_setter)      (QofEntity*, Timespec);
01118         void (*numeric_setter)   (QofEntity*, gnc_numeric);
01119         void (*double_setter)    (QofEntity*, double);
01120         void (*boolean_setter)   (QofEntity*, gboolean);
01121         void (*i32_setter)       (QofEntity*, gint32);
01122         void (*i64_setter)       (QofEntity*, gint64);
01123         void (*char_setter)      (QofEntity*, gchar);
01124 
01125         g_return_if_fail(data && value && key);
01126         params = (qsf_param*)data;
01127         node = (xmlNodePtr)value;
01128         parameter_name = (const gchar*)key;
01129         qof_type = (gchar*)node->name;
01130         qsf_ent = params->qsf_ent;
01131         targetBook = params->book;
01132         memset (&qsf_time, '\0', sizeof(qsf_time));
01133         cm_date.tv_nsec = 0;
01134         cm_date.tv_sec = 0;
01135         obj_type = (gchar*)xmlGetProp(node->parent, BAD_CAST QSF_OBJECT_TYPE);
01136         if(0 == safe_strcasecmp(obj_type, parameter_name)) { return; }
01137         cm_setter = qof_class_get_parameter_setter(obj_type, parameter_name);
01138         cm_param = qof_class_get_parameter(obj_type, parameter_name);
01139         object_set = params->object_set;
01140         if(safe_strcmp(qof_type, QOF_TYPE_STRING) == 0)  {
01141                 string_setter = (void(*)(QofEntity*, const gchar*))cm_setter;
01142                 if(string_setter != NULL) { string_setter(qsf_ent, 
01143                         (gchar*)xmlNodeGetContent(node)); }
01144         }
01145         if(safe_strcmp(qof_type, QOF_TYPE_DATE) == 0) {
01146                 date_setter = (void(*)(QofEntity*, Timespec))cm_setter;
01147                 timechk = NULL;
01148                 timechk = strptime((char*)xmlNodeGetContent(node), QSF_XSD_TIME, 
01149                         &qsf_time);
01150                 g_return_if_fail(timechk != NULL);
01151                 qsf_time_t = mktime(&qsf_time);
01152                 if(qsf_time_t != -3600)
01153                 {
01154                         timespecFromTime_t(&cm_date, qsf_time_t);
01155                         if(date_setter != NULL) { date_setter(qsf_ent, cm_date); }
01156                 }
01157         }
01158         if((safe_strcmp(qof_type, QOF_TYPE_NUMERIC) == 0)  ||
01159         (safe_strcmp(qof_type, QOF_TYPE_DEBCRED) == 0)) {
01160                 numeric_setter = (void(*)(QofEntity*, gnc_numeric))cm_setter;
01161                 string_to_gnc_numeric((char*)xmlNodeGetContent(node), &cm_numeric);
01162                 if(numeric_setter != NULL) { numeric_setter(qsf_ent, cm_numeric); }
01163         }
01164         if(safe_strcmp(qof_type, QOF_TYPE_GUID) == 0) {
01165                 cm_guid = g_new(GUID, 1);
01166                 if(TRUE != string_to_guid((char*)xmlNodeGetContent(node), cm_guid))
01167                 {
01168                         qof_backend_set_error(params->be, ERR_QSF_BAD_OBJ_GUID);
01169                         PINFO (" string to guid conversion failed for %s:%s:%s",
01170                                 xmlNodeGetContent(node), obj_type, qof_type);
01171                         return;
01172                 }
01173                 reference_type = (char*)xmlGetProp(node, BAD_CAST QSF_OBJECT_TYPE);
01174                 if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type))
01175                 {
01176                         qof_entity_set_guid(qsf_ent, cm_guid);
01177                 }
01178                 else {
01179                         reference = qof_entity_get_reference_from(qsf_ent, cm_param);
01180                         if(reference) {
01181                                 params->referenceList = g_list_append(params->referenceList, 
01182                                         reference);
01183                         }
01184                 }
01185         }
01186         if(safe_strcmp(qof_type, QOF_TYPE_INT32) == 0) {
01187                 errno = 0;
01188                 cm_i32 = (gint32)strtol ((char*)xmlNodeGetContent(node), &tail, 0);
01189                 if(errno == 0) {
01190                         i32_setter = (void(*)(QofEntity*, gint32))cm_setter;
01191                         if(i32_setter != NULL) { i32_setter(qsf_ent, cm_i32); }
01192                 }
01193                 else { qof_backend_set_error(params->be, ERR_QSF_OVERFLOW); }
01194         }
01195         if(safe_strcmp(qof_type, QOF_TYPE_INT64) == 0) {
01196                 errno = 0;
01197                 cm_i64 = strtoll((gchar*)xmlNodeGetContent(node), &tail, 0);
01198                 if(errno == 0) {
01199                         i64_setter = (void(*)(QofEntity*, gint64))cm_setter;
01200                         if(i64_setter != NULL) { i64_setter(qsf_ent, cm_i64); }
01201                 }
01202                 else { qof_backend_set_error(params->be, ERR_QSF_OVERFLOW); }
01203         }
01204         if(safe_strcmp(qof_type, QOF_TYPE_DOUBLE) == 0) {
01205                 errno = 0;
01206                 cm_double = strtod((gchar*)xmlNodeGetContent(node), &tail);
01207                 if(errno == 0) {
01208                         double_setter = (void(*)(QofEntity*, double))cm_setter;
01209                         if(double_setter != NULL) { double_setter(qsf_ent, cm_double); }
01210                 }
01211         }
01212         if(safe_strcmp(qof_type, QOF_TYPE_BOOLEAN) == 0){
01213                 if(0 == safe_strcasecmp((gchar*)xmlNodeGetContent(node), 
01214                                 QSF_XML_BOOLEAN_TEST)) {
01215                         cm_boolean = TRUE;
01216                 }
01217                 else { cm_boolean = FALSE; }
01218                 boolean_setter = (void(*)(QofEntity*, gboolean))cm_setter;
01219                 if(boolean_setter != NULL) { boolean_setter(qsf_ent, cm_boolean); }
01220         }
01221         if(safe_strcmp(qof_type, QOF_TYPE_KVP) == 0) {
01222                 cm_type = qsf_to_kvp_helper((gchar*)xmlGetProp(node, BAD_CAST QSF_OBJECT_VALUE));
01223                 if(!cm_type) { return; }
01224                 cm_value = string_to_kvp_value((gchar*)xmlNodeGetContent(node), cm_type);
01225                 cm_kvp = (KvpFrame*)cm_param->param_getfcn(qsf_ent, cm_param);
01226                 cm_kvp = kvp_frame_set_value(cm_kvp, (gchar*)xmlGetProp(node, 
01227                         BAD_CAST QSF_OBJECT_KVP), cm_value);
01228         }
01229         if(safe_strcmp(qof_type, QOF_TYPE_COLLECT) == 0) {
01230                 QofCollection *qsf_coll;
01231                 QofIdType type;
01232                 QofEntityReference *reference;
01233                 QofParam *copy_param;
01234                 /* retrieve the *type* of the collection, ignore any contents. */
01235                 qsf_coll = cm_param->param_getfcn(qsf_ent, cm_param);
01236                 type = qof_collection_get_type(qsf_coll);
01237                 cm_guid = g_new(GUID, 1);
01238                 if(TRUE != string_to_guid((gchar*)xmlNodeGetContent(node), cm_guid))
01239                 {
01240                         qof_backend_set_error(params->be, ERR_QSF_BAD_OBJ_GUID);
01241                         PINFO (" string to guid collect failed for %s", xmlNodeGetContent(node));
01242                         return;
01243                 }
01244                 /* create a QofEntityReference with this type and GUID.
01245                  there is only one entity each time.
01246                  cm_guid contains the GUID of the reference.
01247                  type is the type of the reference. */
01248                 reference = g_new0(QofEntityReference, 1);
01249                 reference->type = g_strdup(qsf_ent->e_type);
01250                 reference->ref_guid = cm_guid;
01251                 reference->ent_guid = &qsf_ent->guid;
01252                 copy_param = g_new0(QofParam, 1);
01253                 copy_param->param_name = g_strdup(cm_param->param_name);
01254                 copy_param->param_type = g_strdup(cm_param->param_type);
01255                 reference->param = copy_param;
01256                 params->referenceList = g_list_append(params->referenceList, reference);
01257         }
01258         if(safe_strcmp(qof_type, QOF_TYPE_CHAR) == 0) {
01259                 char_getter = (gchar (*)(xmlNodePtr))xmlNodeGetContent;
01260                 cm_char = char_getter(node);
01261                 char_setter = (void(*)(QofEntity*, gchar))cm_setter;
01262                 if(char_setter != NULL) { char_setter(qsf_ent, cm_char); }
01263         }
01264 }
01265 
01266 static QofBackend*
01267 qsf_backend_new(void)
01268 {
01269         QSFBackend *qsf_be;
01270         QofBackend *be;
01271 
01272         qsf_be = g_new0(QSFBackend, 1);
01273         be = (QofBackend*) qsf_be;
01274         qof_backend_init(be);
01275         qsf_be->params = g_new(qsf_param, 1);
01276         qsf_be->params->be = be;
01277         qsf_param_init(qsf_be->params);
01278         qsf_be->be.session_begin = qsf_session_begin;
01279 
01280         be->session_end = qsf_session_end;
01281         be->destroy_backend = qsf_destroy_backend;
01282         be->load = qsf_file_type;
01283         be->save_may_clobber_data = NULL;
01284         /* The QSF backend will always load and save the entire QSF XML file. */
01285         be->begin = NULL;
01286         be->commit = NULL;
01287         be->rollback = NULL;
01288         /* QSF uses the built-in SQL, not a dedicated SQL server. */
01289         be->compile_query = NULL;
01290         be->free_query = NULL;
01291         be->run_query = NULL;
01292         be->counter = NULL;
01293         /* The QSF backend is not multi-user. */
01294         be->events_pending = NULL;
01295         be->process_events = NULL;
01296 
01297         be->sync = qsf_write_file;
01298         /* use for maps, later. */
01299         be->load_config = qsf_load_config;
01300         be->get_config = qsf_get_config;
01301 
01302         qsf_be->fullpath = NULL;
01303         return be;
01304 }
01305 
01306 /* The QOF method of loading each backend.
01307 QSF is loaded as a GModule using the QOF method - QofBackendProvider.
01308 */
01309 static void
01310 qsf_provider_free (QofBackendProvider *prov)
01311 {
01312         prov->provider_name = NULL;
01313         prov->access_method = NULL;
01314         g_free (prov);
01315 }
01316 
01317 void
01318 qsf_provider_init(void)
01319 {
01320         QofBackendProvider *prov;
01321 
01322         prov = g_new0 (QofBackendProvider, 1);
01323         prov->provider_name = "QSF Backend Version 0.2";
01324         prov->access_method = "file";
01325         prov->partial_book_supported = TRUE;
01326         prov->backend_new = qsf_backend_new;
01327         prov->check_data_type = qsf_determine_file_type;
01328         prov->provider_free = qsf_provider_free;
01329         qof_backend_register_provider (prov);
01330 }

Generated on Fri May 12 17:57:21 2006 for QOF by  doxygen 1.4.4