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