1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
26 #include <libxml/entities.h>
27 #include <libxml/tree.h>
28 #include <libxml/xmlmemory.h>
30 #include <glib/gstdio.h>
32 #include "e-xml-hash-utils.h"
33 #include "e-xml-utils.h"
37 * @doc: The #xmlDoc to store in a hash table.
38 * @type: The value type to use as a key in the hash table.
40 * Creates a #GHashTable representation of the #xmlDoc @doc.
41 * If @type is * @E_XML_HASH_TYPE_PROPERTY, all XML nodes will be
42 * indexed in the #GHashTable by name. If @type is
43 * %E_XML_HASH_TYPE_OBJECT_UID, then XML objects will be indexed in
44 * the hash by their UID (other nodes will still be indexed by name).
46 * Returns: (transfer full): The newly-created #GHashTable representation
50 e_xml_to_hash (xmlDoc *doc,
57 hash = g_hash_table_new (g_str_hash, g_str_equal);
59 root = xmlDocGetRootElement (doc);
60 for (node = root->xmlChildrenNode; node; node = node->next) {
61 if (node->name == NULL || node->type != XML_ELEMENT_NODE)
64 if (type == E_XML_HASH_TYPE_OBJECT_UID &&
65 !strcmp ((gchar *) node->name, "object"))
66 key = xmlGetProp (node, (xmlChar *)"uid");
68 key = xmlStrdup (node->name);
71 g_warning ("Key not found!!");
75 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
78 g_warning ("Found a key with no value!!");
83 hash, g_strdup ((gchar *) key),
84 g_strdup ((gchar *) value));
100 foreach_save_func (gpointer key,
104 struct save_data *sd = user_data;
108 if (sd->type == E_XML_HASH_TYPE_OBJECT_UID) {
109 new_node = xmlNewNode (NULL, (xmlChar *)"object");
110 xmlNewProp (new_node, (xmlChar *)"uid", (const xmlChar *) key);
112 new_node = xmlNewNode (NULL, (const xmlChar *) key);
114 enc = xmlEncodeEntitiesReentrant (sd->doc, value);
115 xmlNodeSetContent (new_node, enc);
118 xmlAddChild (sd->root, new_node);
123 * @hash: The #GHashTable to extract the XML from
124 * @type: The #EXmlHashType used to store the XML
125 * @root_name: The name to call the new #xmlDoc
127 * Uses the key/value pair representation of an XML structure in @hash
128 * to build an equivalent #xmlDoc. This is the reverse of e_xml_to_hash().
130 * Returns: the #xmlDoc created from the data in @hash
133 e_xml_from_hash (GHashTable *hash,
135 const gchar *root_name)
140 doc = xmlNewDoc ((xmlChar *)"1.0");
141 doc->encoding = xmlStrdup ((xmlChar *)"UTF-8");
144 sd.root = xmlNewDocNode (doc, NULL, (xmlChar *) root_name, NULL);
145 xmlDocSetRootElement (doc, sd.root);
147 g_hash_table_foreach (hash, foreach_save_func, &sd);
152 free_values (gpointer key,
161 * e_xml_destroy_hash:
162 * @hash: the #GHashTable to destroy
164 * Frees the memory used by @hash and its contents.
167 e_xml_destroy_hash (GHashTable *hash)
169 g_hash_table_foreach (hash, free_values, NULL);
170 g_hash_table_destroy (hash);
176 * A hash table representation of an XML file.
185 * @filename: the name of an XML file
187 * Creates a new #EXmlHash from the file @filename. If @filename does
188 * not already exist, an empty #EXmlHash will be created.
190 * Returns: The new #EXmlHash structure, or %NULL if unable to parse
194 e_xmlhash_new (const gchar *filename)
199 g_return_val_if_fail (filename != NULL, NULL);
201 hash = g_new0 (EXmlHash, 1);
202 hash->filename = g_strdup (filename);
204 if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
205 doc = e_xml_parse_file (filename);
207 e_xmlhash_destroy (hash);
211 hash->objects = e_xml_to_hash (doc, E_XML_HASH_TYPE_OBJECT_UID);
214 hash->objects = g_hash_table_new (g_str_hash, g_str_equal);
222 * @hash: the #EXmlHash to add an entry to
223 * @key: the key to use for the entry
224 * @data: the value of the new entry
226 * Adds a new key/value pair to the #EXmlHash @hash.
229 e_xmlhash_add (EXmlHash *hash,
233 g_return_if_fail (hash != NULL);
234 g_return_if_fail (key != NULL);
235 g_return_if_fail (data != NULL);
237 e_xmlhash_remove (hash, key);
238 g_hash_table_insert (hash->objects, g_strdup (key), g_strdup (data));
243 * @hash: the #EXmlHash to remove an entry from
244 * @key: the key of the entry to remove
246 * Remove the entry in @hash with key equal to @key, if it exists.
249 e_xmlhash_remove (EXmlHash *hash,
256 g_return_if_fail (hash != NULL);
257 g_return_if_fail (key != NULL);
259 found = g_hash_table_lookup_extended (
260 hash->objects, key, &orig_key, &orig_value);
262 g_hash_table_remove (hash->objects, key);
270 * @hash: the #EXmlHash to compare against
271 * @key: the key of the hash entry to compare with
272 * @compare_data: the data to compare against the hash entry
274 * Compares the value with key equal to @key in @hash against
277 * Returns: E_XMLHASH_STATUS_SAME if the value and @compare_data are
278 * equal,E_XMLHASH_STATUS_DIFFERENT if they are different, or
279 * E_XMLHASH_STATUS_NOT_FOUND if there is no entry in @hash with
280 * its key equal to @key.
283 e_xmlhash_compare (EXmlHash *hash,
285 const gchar *compare_data)
290 g_return_val_if_fail (hash != NULL, E_XMLHASH_STATUS_NOT_FOUND);
291 g_return_val_if_fail (key != NULL, E_XMLHASH_STATUS_NOT_FOUND);
292 g_return_val_if_fail (compare_data != NULL, E_XMLHASH_STATUS_NOT_FOUND);
294 data = g_hash_table_lookup (hash->objects, key);
296 return E_XMLHASH_STATUS_NOT_FOUND;
298 rc = strcmp (data, compare_data);
300 return E_XMLHASH_STATUS_SAME;
302 return E_XMLHASH_STATUS_DIFFERENT;
311 foreach_hash_func (gpointer key,
315 foreach_data_t *data = (foreach_data_t *) user_data;
317 data->func ((const gchar *) key, (const gchar *) value, data->user_data);
321 * e_xmlhash_foreach_key:
322 * @hash: an #EXmlHash
323 * @func: (scope async): the #EXmlHashFunc to execute on the data in @hash
324 * @user_data: the data to pass to @func
326 * Executes @func against each key/value pair in @hash.
329 e_xmlhash_foreach_key (EXmlHash *hash,
335 g_return_if_fail (hash != NULL);
336 g_return_if_fail (func != NULL);
339 data.user_data = user_data;
340 g_hash_table_foreach (hash->objects, foreach_hash_func, &data);
344 * e_xmlhash_foreach_key_remove:
345 * @hash: an #EXmlHash
346 * @func: (scope async): the #EXmlHashFunc to execute on the data in @hash
347 * @user_data: the data to pass to @func
349 * Calls g_hash_table_foreach_remove() on @hash<!-- -->'s internal hash
350 * table. See g_hash_table_foreach_remove() for details.
353 e_xmlhash_foreach_key_remove (EXmlHash *hash,
354 EXmlHashRemoveFunc func,
357 g_return_if_fail (hash != NULL);
358 g_return_if_fail (func != NULL);
360 g_hash_table_foreach_remove (hash->objects, (GHRFunc) func, user_data);
365 * @hash: The #EXmlHash to write.
367 * Writes the XML represented by @hash to the file originally passed
368 * to e_xmlhash_new().
371 e_xmlhash_write (EXmlHash *hash)
375 g_return_if_fail (hash != NULL);
377 doc = e_xml_from_hash (
378 hash->objects, E_XML_HASH_TYPE_OBJECT_UID, "xmlhash");
380 e_xml_save_file (hash->filename, doc);
387 * @hash: The #EXmlHash to destroy.
389 * Frees the memory associated with @hash.
392 e_xmlhash_destroy (EXmlHash *hash)
394 g_return_if_fail (hash != NULL);
396 g_free (hash->filename);
398 e_xml_destroy_hash (hash->objects);