00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #include <glib.h>
00026 #include <libxml/xmlversion.h>
00027 #include <libxml/xmlmemory.h>
00028 #include <libxml/tree.h>
00029 #include <libxml/parser.h>
00030 #include <libxml/xmlschemas.h>
00031 #include "qof.h"
00032 #include "qof-backend-qsf.h"
00033 #include "qsf-dir.h"
00034 #include "qsf-xml.h"
00035
00036 static QofLogModule log_module = QOF_MOD_QSF;
00037
00038 gint
00039 qsf_compare_tag_strings (const xmlChar * node_name, gchar * tag_name)
00040 {
00041 return xmlStrcmp (node_name, (const xmlChar *) tag_name);
00042 }
00043
00044 gint
00045 qsf_strings_equal (const xmlChar * node_name, gchar * tag_name)
00046 {
00047 if (0 == qsf_compare_tag_strings (node_name, tag_name))
00048 {
00049 return 1;
00050 }
00051 return 0;
00052 }
00053
00054 gint
00055 qsf_is_element (xmlNodePtr a, xmlNsPtr ns, gchar * c)
00056 {
00057 g_return_val_if_fail (a != NULL, 0);
00058 g_return_val_if_fail (ns != NULL, 0);
00059 g_return_val_if_fail (c != NULL, 0);
00060 if ((a->ns == ns) && (a->type == XML_ELEMENT_NODE) &&
00061 qsf_strings_equal (a->name, c))
00062 {
00063 return 1;
00064 }
00065 return 0;
00066 }
00067
00068 gint
00069 qsf_check_tag (QsfParam * params, gchar * qof_type)
00070 {
00071 return qsf_is_element (params->child_node, params->qsf_ns, qof_type);
00072 }
00073
00074 gboolean
00075 qsf_is_valid (const gchar * schema_dir, const gchar * schema_filename,
00076 xmlDocPtr doc)
00077 {
00078 xmlSchemaParserCtxtPtr qsf_schema_file;
00079 xmlSchemaPtr qsf_schema;
00080 xmlSchemaValidCtxtPtr qsf_context;
00081 gchar *schema_path;
00082 gint result;
00083
00084 g_return_val_if_fail (doc || schema_filename, FALSE);
00085 schema_path = g_strdup_printf ("%s/%s", schema_dir, schema_filename);
00086 qsf_schema_file = xmlSchemaNewParserCtxt (schema_path);
00087 qsf_schema = xmlSchemaParse (qsf_schema_file);
00088 qsf_context = xmlSchemaNewValidCtxt (qsf_schema);
00089 result = xmlSchemaValidateDoc (qsf_context, doc);
00090 xmlSchemaFreeParserCtxt (qsf_schema_file);
00091 xmlSchemaFreeValidCtxt (qsf_context);
00092 xmlSchemaFree (qsf_schema);
00093 g_free (schema_path);
00094 if (result == 0)
00095 {
00096 return TRUE;
00097 }
00098 return FALSE;
00099 }
00100
00101 void
00102 qsf_valid_foreach (xmlNodePtr parent, QsfValidCB cb,
00103 struct QsfNodeIterate *qsfiter, QsfValidator * valid)
00104 {
00105 xmlNodePtr cur_node;
00106
00107 qsfiter->v_fcn = &cb;
00108 for (cur_node = parent->children; cur_node != NULL;
00109 cur_node = cur_node->next)
00110 {
00111 cb (cur_node, qsfiter->ns, valid);
00112 }
00113 }
00114
00115 void
00116 qsf_node_foreach (xmlNodePtr parent, QsfNodeCB cb,
00117 struct QsfNodeIterate *qsfiter, QsfParam * params)
00118 {
00119 xmlNodePtr cur_node;
00120
00121 if (!parent)
00122 return;
00123 g_return_if_fail (params);
00124 g_return_if_fail (qsfiter->ns);
00125 qsfiter->fcn = &cb;
00126 for (cur_node = parent->children; cur_node != NULL;
00127 cur_node = cur_node->next)
00128 {
00129 cb (cur_node, qsfiter->ns, params);
00130 }
00131 }
00132
00133 void
00134 qsf_object_validation_handler (xmlNodePtr child, xmlNsPtr ns,
00135 QsfValidator * valid)
00136 {
00137 xmlNodePtr cur_node;
00138 xmlChar *object_declaration;
00139 guint count;
00140 QsfStatus type;
00141 gboolean is_registered;
00142
00143 count = 0;
00144 type = QSF_NO_OBJECT;
00145 is_registered = FALSE;
00146 for (cur_node = child->children; cur_node != NULL;
00147 cur_node = cur_node->next)
00148 {
00149 if (qsf_is_element (cur_node, ns, QSF_OBJECT_TAG))
00150 {
00151 object_declaration =
00152 xmlGetProp (cur_node, BAD_CAST QSF_OBJECT_TYPE);
00153 is_registered = qof_class_is_registered (object_declaration);
00154 if (is_registered)
00155 {
00156 type = QSF_REGISTERED_OBJECT;
00157 }
00158 else
00159 {
00160 type = QSF_DEFINED_OBJECT;
00161 }
00162 xmlFree (object_declaration);
00163 count = g_hash_table_size (valid->object_table);
00164 g_hash_table_insert (valid->object_table, object_declaration,
00165 GINT_TO_POINTER (type));
00166
00167 if (g_hash_table_size (valid->object_table) > count)
00168 {
00169 valid->valid_object_count++;
00170 if (is_registered)
00171 {
00172 valid->qof_registered_count++;
00173 }
00174 }
00175 }
00176 }
00177 }
00178
00179 gboolean
00180 is_our_qsf_object (const gchar * path)
00181 {
00182 xmlDocPtr doc;
00183 struct QsfNodeIterate qsfiter;
00184 xmlNodePtr object_root;
00185 QsfValidator valid;
00186 gint table_count;
00187
00188 g_return_val_if_fail ((path != NULL), FALSE);
00189 doc = xmlParseFile (path);
00190 if (doc == NULL)
00191 {
00192 return FALSE;
00193 }
00194 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00195 {
00196 PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR,
00197 QSF_OBJECT_SCHEMA, path);
00198 return FALSE;
00199 }
00200 object_root = xmlDocGetRootElement (doc);
00201
00202 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
00203 valid.qof_registered_count = 0;
00204 valid.valid_object_count = 0;
00205 qsfiter.ns = object_root->ns;
00206 qsf_valid_foreach (object_root, qsf_object_validation_handler,
00207 &qsfiter, &valid);
00208 table_count = g_hash_table_size (valid.object_table);
00209 g_hash_table_destroy (valid.object_table);
00210 xmlFreeDoc (doc);
00211 if (table_count == valid.qof_registered_count)
00212 {
00213 return TRUE;
00214 }
00215 return FALSE;
00216 }
00217
00218 gboolean
00219 is_qsf_object (const gchar * path)
00220 {
00221 xmlDocPtr doc;
00222
00223 g_return_val_if_fail ((path != NULL), FALSE);
00224 if (path == NULL)
00225 {
00226 return FALSE;
00227 }
00228 doc = xmlParseFile (path);
00229 if (doc == NULL)
00230 {
00231 return FALSE;
00232 }
00233 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00234 {
00235 return FALSE;
00236 }
00237
00238
00239 return TRUE;
00240 }
00241
00242 gboolean
00243 is_our_qsf_object_be (QsfParam * params)
00244 {
00245 xmlDocPtr doc;
00246 struct QsfNodeIterate qsfiter;
00247 xmlNodePtr object_root;
00248 QsfValidator valid;
00249 gint table_count;
00250
00251 g_return_val_if_fail ((params != NULL), FALSE);
00252 if (params->filepath == NULL)
00253 {
00254 qof_error_set_be (params->be, qof_error_register
00255 (_("The QSF XML file '%s' could not be found."), TRUE));
00256 return FALSE;
00257 }
00258 if (params->file_type != QSF_UNDEF)
00259 {
00260 return FALSE;
00261 }
00262 doc = xmlParseFile (params->filepath);
00263 if (doc == NULL)
00264 {
00265 qof_error_set_be (params->be, qof_error_register
00266 (_("There was an error parsing the file '%s'."), TRUE));
00267 return FALSE;
00268 }
00269 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00270 {
00271 qof_error_set_be (params->be, qof_error_register
00272 (_("Invalid QSF Object file! The QSF object file '%s' "
00273 " failed to validate against the QSF object schema. "
00274 "The XML structure of the file is either not well-formed "
00275 "or the file contains illegal data."), TRUE));
00276 xmlFreeDoc (doc);
00277 return FALSE;
00278 }
00279 params->file_type = IS_QSF_OBJ;
00280 object_root = xmlDocGetRootElement (doc);
00281 xmlFreeDoc (doc);
00282 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
00283 valid.qof_registered_count = 0;
00284 qsfiter.ns = object_root->ns;
00285 qsf_valid_foreach (object_root, qsf_object_validation_handler,
00286 &qsfiter, &valid);
00287 table_count = g_hash_table_size (valid.object_table);
00288 if (table_count == valid.qof_registered_count)
00289 {
00290 g_hash_table_destroy (valid.object_table);
00291 return TRUE;
00292 }
00293 g_hash_table_destroy (valid.object_table);
00294 qof_error_set_be (params->be, params->err_nomap);
00295 return FALSE;
00296 }
00297
00298 gboolean
00299 is_qsf_object_be (QsfParam * params)
00300 {
00301 gboolean result;
00302 xmlDocPtr doc;
00303 GList *maps;
00304 gchar *path;
00305
00306 g_return_val_if_fail ((params != NULL), FALSE);
00307 path = g_strdup (params->filepath);
00308 if (path == NULL)
00309 {
00310 qof_error_set_be (params->be, qof_error_register
00311 (_("The QSF XML file '%s' could not be found."), TRUE));
00312 return FALSE;
00313 }
00314
00315
00316
00317
00318
00319 if (params->file_type == QSF_UNDEF)
00320 {
00321 doc = xmlParseFile (path);
00322 if (doc == NULL)
00323 {
00324 qof_error_set_be (params->be, qof_error_register
00325 (_("There was an error parsing the file '%s'."), TRUE));
00326 return FALSE;
00327 }
00328 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00329 {
00330 qof_error_set_be (params->be, qof_error_register
00331 (_("Invalid QSF Object file! The QSF object file '%s' "
00332 " failed to validate against the QSF object schema. "
00333 "The XML structure of the file is either not well-formed "
00334 "or the file contains illegal data."), TRUE));
00335 return FALSE;
00336 }
00337 }
00338 result = FALSE;
00339
00340 for (maps = params->map_files; maps; maps = maps->next)
00341 {
00342 QofErrorId err;
00343 result = is_qsf_object_with_map_be (maps->data, params);
00344 err = qof_error_check_be (params->be);
00345 if ((err == QOF_SUCCESS) && result)
00346 {
00347 params->map_path = maps->data;
00348 PINFO ("map chosen = %s", params->map_path);
00349 break;
00350 }
00351 }
00352 return result;
00353 }
00354
00355 static void
00356 qsf_supported_data_types (gpointer type, gpointer user_data)
00357 {
00358 QsfParam *params;
00359
00360 g_return_if_fail (user_data != NULL);
00361 g_return_if_fail (type != NULL);
00362 params = (QsfParam *) user_data;
00363 if (qsf_is_element (params->param_node, params->qsf_ns,
00364 (gchar *) type))
00365 {
00366 g_hash_table_insert (params->qsf_parameter_hash,
00367 xmlGetProp (params->param_node,
00368 BAD_CAST QSF_OBJECT_TYPE), params->param_node);
00369 }
00370 }
00371
00372 static void
00373 qsf_parameter_handler (xmlNodePtr child, xmlNsPtr qsf_ns,
00374 QsfParam * params)
00375 {
00376
00377 if (!qsf_ns)
00378 return;
00379 params->param_node = child;
00380 g_slist_foreach (params->supported_types, qsf_supported_data_types,
00381 params);
00382 }
00383
00384 void
00385 qsf_object_node_handler (xmlNodePtr child, xmlNsPtr qsf_ns,
00386 QsfParam * params)
00387 {
00388 struct QsfNodeIterate qsfiter;
00389 QsfObject *object_set;
00390 gchar *tail, *object_count_s;
00391 gint64 c;
00392
00393 g_return_if_fail (child != NULL);
00394 g_return_if_fail (qsf_ns != NULL);
00395 params->qsf_ns = qsf_ns;
00396 if (qsf_is_element (child, qsf_ns, QSF_OBJECT_TAG))
00397 {
00398 params->qsf_parameter_hash = NULL;
00399 c = 0;
00400 object_set = g_new (QsfObject, 1);
00401 params->object_set = object_set;
00402 object_set->object_count = 0;
00403 object_set->parameters =
00404 g_hash_table_new (g_str_hash, g_str_equal);
00405 object_set->object_type = ((gchar *) xmlGetProp (child,
00406 BAD_CAST QSF_OBJECT_TYPE));
00407 object_count_s = ((gchar *) xmlGetProp (child,
00408 BAD_CAST QSF_OBJECT_COUNT));
00409 if (object_count_s)
00410 {
00411 c = (gint64) strtol (object_count_s, &tail, 0);
00412 object_set->object_count = (gint) c;
00413 g_free (object_count_s);
00414 }
00415 params->qsf_object_list =
00416 g_list_prepend (params->qsf_object_list, object_set);
00417 qsfiter.ns = qsf_ns;
00418 params->qsf_parameter_hash = object_set->parameters;
00419 qsf_node_foreach (child, qsf_parameter_handler, &qsfiter, params);
00420 }
00421 }
00422
00423 void
00424 qsf_book_node_handler (xmlNodePtr child, xmlNsPtr ns, QsfParam * params)
00425 {
00426 gchar *book_count_s, *tail;
00427 gint book_count;
00428 xmlNodePtr child_node;
00429 struct QsfNodeIterate qsfiter;
00430 gchar *buffer;
00431 GUID book_guid;
00432
00433 g_return_if_fail (child);
00434 g_return_if_fail (params);
00435 ENTER (" child=%s", child->name);
00436 if (qsf_is_element (child, ns, QSF_BOOK_TAG))
00437 {
00438 book_count_s =
00439 (gchar *) xmlGetProp (child, BAD_CAST QSF_BOOK_COUNT);
00440 if (book_count_s)
00441 {
00442 book_count = (gint) strtol (book_count_s, &tail, 0);
00443
00444 g_free (book_count_s);
00445 g_return_if_fail (book_count == 1);
00446 }
00447 qsfiter.ns = ns;
00448 child_node = child->children->next;
00449 if (qsf_is_element (child_node, ns, QSF_BOOK_GUID))
00450 {
00451 DEBUG (" trying to set book GUID");
00452 buffer = BAD_CAST xmlNodeGetContent (child_node);
00453 g_return_if_fail (TRUE == string_to_guid (buffer, &book_guid));
00454 qof_entity_set_guid ((QofEntity *) params->book, &book_guid);
00455 xmlNewChild (params->output_node, params->qsf_ns,
00456 BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
00457 xmlFree (buffer);
00458 }
00459 qsf_node_foreach (child, qsf_object_node_handler, &qsfiter, params);
00460 }
00461 LEAVE (" ");
00462 }