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

Generated on Fri Sep 1 15:13:11 2006 for QOF by  doxygen 1.4.7