qsf-backend.c

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

Generated on Fri Oct 21 15:49:56 2005 for QOF by  doxygen 1.4.5