"Initial commit to Gerrit"
[profile/ivi/libgsf.git] / gsf / gsf-doc-meta-data.c
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * gsf-doc-meta-data.c:
4  *
5  * Copyright (C) 2002-2006 Dom Lachowicz (cinamod@hotmail.com)
6  *                         Jody Goldberg (jody@gnome.org)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2.1 of the GNU Lesser General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
20  * USA
21  */
22
23 #include <gsf-config.h>
24 #include <gsf/gsf-doc-meta-data.h>
25 #include <gsf/gsf-docprop-vector.h>
26 #include <gsf/gsf-impl-utils.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 struct _GsfDocMetaData {
31         GObject base;
32
33         GHashTable *table;
34 };
35 typedef GObjectClass GsfDocMetaDataClass;
36
37 struct _GsfDocProp {
38         char   *name;
39         GValue *val;
40         char   *linked_to; /* optionally NULL */
41 };
42
43 static GObjectClass *parent_class;
44
45 static void
46 gsf_doc_meta_data_finalize (GObject *obj)
47 {
48         g_hash_table_destroy (GSF_DOC_META_DATA (obj)->table);
49         parent_class->finalize (obj);
50 }
51
52 static void
53 gsf_doc_meta_data_init (GObject *obj)
54 {
55         GsfDocMetaData *meta = GSF_DOC_META_DATA (obj);
56         meta->table = g_hash_table_new_full (g_str_hash, g_str_equal,
57                 NULL, (GDestroyNotify) gsf_doc_prop_free);
58 }
59
60 static void
61 gsf_doc_meta_data_class_init (GObjectClass *gobject_class)
62 {
63         gobject_class->finalize = gsf_doc_meta_data_finalize;
64         parent_class = g_type_class_peek_parent (gobject_class);
65 }
66
67 GSF_CLASS(GsfDocMetaData, gsf_doc_meta_data,
68           gsf_doc_meta_data_class_init, gsf_doc_meta_data_init,
69           G_TYPE_OBJECT)
70
71 /**********************************************************************/
72
73 /**
74  * gsf_doc_meta_data_new :
75  *
76  * Returns: a new metadata property collection
77  **/
78 GsfDocMetaData *
79 gsf_doc_meta_data_new (void)
80 {
81         return g_object_new (GSF_DOC_META_DATA_TYPE, NULL);
82 }
83
84 /**
85  * gsf_doc_meta_data_lookup :
86  * @meta : #GsfDocMetaData
87  * @name :
88  *
89  * Returns: the property with name @id in @meta.  The caller can modify the
90  * property value and link but not the name.
91  **/
92 GsfDocProp *
93 gsf_doc_meta_data_lookup (GsfDocMetaData const *meta, char const *name)
94 {
95         g_return_val_if_fail (IS_GSF_DOC_META_DATA (meta), NULL);
96         g_return_val_if_fail (name != NULL, NULL);
97         return g_hash_table_lookup (meta->table, name);
98 }
99
100 /**
101  * gsf_doc_meta_data_insert :
102  * @meta : #GsfDocMetaData
103  * @name : the id.
104  * @value : #GValue
105  *
106  * Take ownership of @name and @value and insert a property into @meta.
107  * If a property exists with @name, it is replaced (The link is lost)
108  **/
109 void
110 gsf_doc_meta_data_insert (GsfDocMetaData *meta, char *name, GValue *value)
111 {
112         GsfDocProp *prop;
113         
114         g_return_if_fail (IS_GSF_DOC_META_DATA (meta));
115         g_return_if_fail (name != NULL);
116         prop = g_new (GsfDocProp, 1);
117         prop->name = name;
118         prop->val  = value;
119         prop->linked_to = NULL;
120         g_hash_table_replace (meta->table, prop->name, prop);
121 }
122
123 /**
124  * gsf_doc_meta_data_remove :
125  * @meta : the collection
126  * @name : the non-null string name of the property
127  *
128  * If @name does not exist in the collection, do nothing. If @name does exist,
129  * remove it and its value from the collection
130  **/
131 void
132 gsf_doc_meta_data_remove (GsfDocMetaData *meta, char const *name)
133 {
134         g_return_if_fail (IS_GSF_DOC_META_DATA (meta));
135         g_return_if_fail (name != NULL);
136         g_hash_table_remove (meta->table, name);
137 }
138
139 /**
140  * gsf_doc_meta_data_store :
141  * @meta : #GsfDocMetaData
142  * @name : 
143  *
144  **/
145 GsfDocProp *
146 gsf_doc_meta_data_steal (GsfDocMetaData *meta, char const *name)
147 {
148         GsfDocProp *prop;
149         g_return_val_if_fail (IS_GSF_DOC_META_DATA (meta), NULL);
150         g_return_val_if_fail (name != NULL, NULL);
151         prop = g_hash_table_lookup (meta->table, name);
152         if (NULL != prop)
153                 g_hash_table_steal (meta->table, name);
154         return prop;
155 }
156
157 /**
158  * gsf_doc_meta_data_store :
159  * @meta : #GsfDocMetaData
160  * @prop : #GsfDocProp
161  *
162  **/
163 void
164 gsf_doc_meta_data_store (GsfDocMetaData *meta, GsfDocProp *prop)
165 {
166         g_return_if_fail (IS_GSF_DOC_META_DATA (meta));
167         g_return_if_fail (prop != NULL);
168         g_return_if_fail (prop != g_hash_table_lookup (meta->table, prop->name));
169         g_hash_table_replace (meta->table, prop->name, prop);
170 }
171
172 static void
173 cb_collect_pairs (char *prop_name, GsfDocProp *prop, GPtrArray *pairs)
174 {
175         g_ptr_array_add (pairs, prop_name);
176         g_ptr_array_add (pairs, prop);
177 }
178
179 static int
180 deref_strcmp (const char **a, const char **b)
181 {
182         return strcmp (*a, *b);
183 }
184
185 /**
186  * gsf_doc_meta_data_foreach :
187  * @meta : the collection
188  * @func : the function called once for each element in the collection
189  * @user_data : any supplied user data or %NULL
190  *
191  * Iterate through each (key, value) pair in this collection
192  **/
193 void
194 gsf_doc_meta_data_foreach (GsfDocMetaData const *meta, GHFunc func, gpointer user_data)
195 {
196         GPtrArray *pairs;
197         unsigned ui;
198
199         g_return_if_fail (IS_GSF_DOC_META_DATA (meta));
200
201         if (g_hash_table_size (meta->table) == 0)
202                 return;
203
204         /* Sort the pairs by property name in order to generate consistent
205            files. */
206         pairs = g_ptr_array_new ();
207         g_hash_table_foreach (meta->table, (GHFunc)cb_collect_pairs, pairs);
208
209         qsort (&g_ptr_array_index (pairs, 0),
210                pairs->len / 2,
211                2 * sizeof (gpointer),
212                (GCompareFunc)deref_strcmp);
213
214         for (ui = 0; ui < pairs->len; ui += 2)
215                 func (g_ptr_array_index (pairs, ui),
216                       g_ptr_array_index (pairs, ui + 1),
217                       user_data);
218
219         g_ptr_array_free (pairs, TRUE);
220 }
221
222 /**
223  * gsf_doc_meta_data_size :
224  * @meta : the collection
225  *
226  * Returns: the number of items in this collection
227  **/
228 gsize
229 gsf_doc_meta_data_size (GsfDocMetaData const *meta)
230 {
231         g_return_val_if_fail (meta != NULL, 0);
232         return (gsize) g_hash_table_size (meta->table);
233 }
234
235 static void
236 cb_print_property (G_GNUC_UNUSED char const *name,
237                    GsfDocProp const *prop)
238 {
239         if (gsf_doc_prop_get_link (prop) != NULL)
240                 g_print ("prop '%s' LINKED TO  -> '%s'\n",
241                          name, gsf_doc_prop_get_link (prop));
242         else
243                 g_print ("prop '%s'\n", name);
244
245         gsf_doc_prop_dump (prop);
246 }
247
248 /**
249  * gsf_doc_meta_dump :
250  * @meta : #GsfDocMetaData
251  *
252  * A debugging utility to dump the content of @meta via g_print
253  **/
254 void
255 gsf_doc_meta_dump (GsfDocMetaData const *meta)
256 {
257         gsf_doc_meta_data_foreach (meta,
258                 (GHFunc) cb_print_property, NULL);
259 }
260
261 /**********************************************************************/
262
263 /**
264  * gsf_doc_prop_new :
265  * @name :
266  *
267  * Returns: a new #GsfDocProp which the caller is responsible for freeing.
268  * Takes ownership of @name.
269  **/
270 GsfDocProp *
271 gsf_doc_prop_new  (char *name)
272 {
273         GsfDocProp *prop;
274
275         g_return_val_if_fail (name != NULL, NULL);
276
277         prop = g_new (GsfDocProp, 1);
278         prop->name = name;
279         prop->val  = NULL;
280         prop->linked_to = NULL;
281
282         return prop;
283 }
284
285 /**
286  * gsf_doc_prop_free :
287  * @prop : #GsfDocProp
288  *
289  * If @prop is non %NULL free the memory associated with it
290  **/
291 void
292 gsf_doc_prop_free (GsfDocProp *prop)
293 {
294         if (NULL != prop) {
295                 g_free (prop->linked_to);
296
297                 if (prop->val) {
298                         g_value_unset (prop->val);
299                         g_free (prop->val);
300                 }
301                 g_free (prop->name);
302                 g_free (prop);
303         }
304 }
305
306 /**
307  * gsf_doc_prop_get_name :
308  * @prop : #GsfDocProp
309  *
310  * Returns: the name of the property, the caller should not modify the result.
311  **/
312 char const *
313 gsf_doc_prop_get_name (GsfDocProp const *prop)
314 {
315         g_return_val_if_fail (prop != NULL, NULL);
316         return prop->name;
317 }
318
319 /**
320  * gsf_doc_prop_get_val :
321  * @prop : the property
322  *
323  * Returns: the value of the property, the caller should not modify the result.
324  **/
325 GValue const *
326 gsf_doc_prop_get_val (GsfDocProp const *prop)
327 {
328         g_return_val_if_fail (prop != NULL, NULL);
329         return prop->val;
330 }
331
332 /**
333  * gsf_doc_prop_set_val :
334  * @prop : #GsfDocProp
335  * @val  : #GValue
336  *
337  * Assigns @val to @prop, and unsets and frees the current value.
338  **/
339 void
340 gsf_doc_prop_set_val (GsfDocProp *prop, GValue *val)
341 {
342         g_return_if_fail (prop != NULL);
343
344         if (val != prop->val) {
345                 if (prop->val != NULL) {
346                         g_value_unset (prop->val);
347                         g_free (prop->val);
348                 }
349                 prop->val = val;
350         }
351 }
352
353 /**
354  * gsf_doc_prop_swap_val :
355  * @prop : #GsfDocProp
356  * @val  : #GValue
357  *
358  * Returns: the current value of @prop, and replaces it with @val
359  *      Caller is responsible for unsetting and freeing the result.
360  **/
361 GValue *
362 gsf_doc_prop_swap_val (GsfDocProp *prop, GValue *val)
363 {
364         GValue *old_val;
365         g_return_val_if_fail (prop != NULL, NULL);
366
367         old_val = prop->val;
368         prop->val = val;
369         return old_val;
370 }
371
372 /**
373  * gsf_doc_prop_get_link :
374  * @prop : #GsfDocProp
375  *
376  * Returns: the current link descriptor of @prop.  The result should not be
377  *      freed or modified.
378  **/
379 char const *
380 gsf_doc_prop_get_link (GsfDocProp const *prop)
381 {
382         g_return_val_if_fail (prop != NULL, NULL);
383         return prop->linked_to;
384 }
385
386 /**
387  * gsf_doc_prop_set_link :
388  * @prop : #GsfDocProp
389  * @link : optionally %NULL
390  *
391  * Sets @prop's link to @link
392  **/
393 void
394 gsf_doc_prop_set_link (GsfDocProp *prop, char *link)
395 {
396         g_return_if_fail (prop != NULL);
397
398         if (link != prop->linked_to) {
399                 g_free (prop->linked_to);
400                 prop->linked_to = link;
401         }
402 }
403
404 /**
405  * gsf_doc_prop_dump :
406  * @prop : #GsfDocProp
407  *
408  * A debugging utility to dump @prop as text via g_print
409  * New in 1.14.2
410  **/
411 void
412 gsf_doc_prop_dump (GsfDocProp const *prop)
413 {
414         GValue const *val = gsf_doc_prop_get_val  (prop);
415         char *tmp;
416         if (VAL_IS_GSF_DOCPROP_VECTOR ((GValue *)val)) {
417                 GValueArray *va = gsf_value_get_docprop_varray (val);
418                 unsigned i;
419
420                 for (i = 0 ; i < va->n_values; i++) {
421                         tmp = g_strdup_value_contents (
422                                 g_value_array_get_nth (va, i));
423                         g_print ("\t[%u] = %s\n", i, tmp);
424                         g_free (tmp);
425                 }
426         } else {
427                 tmp = g_strdup_value_contents (val);
428                 g_print ("\t= %s\n", tmp);
429                 g_free (tmp);
430         }
431 }