QOF
0.7.5
|
00001 /*************************************************************************** 00002 * qsf-xml.c 00003 * 00004 * Fri Nov 26 19:29:47 2004 00005 * Copyright 2004,2005,2006 Neil Williams <linux@codehelp.co.uk> 00006 * 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 <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 /* if insert was successful - i.e. object is unique so far */ 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 /* check that all objects in the file are already registered in QOF */ 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 /* Note cannot test against a map here, so if the file is valid QSF, 00238 accept it and work out the details later. */ 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 /* skip validation if is_our_qsf_object has already been called. */ 00315 /* if (ERR_QSF_INVALID_OBJ == qof_backend_get_error (params->be)) 00316 { 00317 return FALSE; 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 /* retrieve list of maps from config frame. */ 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 /* spurious */ 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 /* More than one book not currently supported. */ 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 }