1 /* MManager - a Desktop wide manager for multimedia applications.
3 * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
23 #include <libxml/tree.h>
24 #include <libxml/xmlwriter.h>
25 #include <libxml/xmlreader.h>
26 #include <libxml/xmlerror.h>
27 #include "mm-string-utils.h"
32 MMComparisionOperator op
;
37 xmlTextWriterPtr writer
;
41 static OperatorGrid operator_grid
[] =
43 { MM_COMP_EQUAL
, "EQ" },
44 { MM_COMP_GREATER
, "GR" },
45 { MM_COMP_GREATER_EQUAL
, "GRQ" },
46 { MM_COMP_LESS
, "LS" },
47 { MM_COMP_LESS_EQUAL
, "LSQ" },
52 set_error (int res
, GError
**error
, const char *obj_name
)
54 xmlErrorPtr xml_error
;
57 xml_error
= xmlGetLastError ();
58 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNSERIALIZE_FAILED
,
59 "Error while parsing the serialized xml %s: %s",
60 obj_name
, (xml_error
!= NULL
) ? (xml_error
->message
) : "");
61 } else if (res
== 0) {
62 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_EOF
,
63 "Error while parsing the serialized xml %s: unexpected "
64 "end of the xml buffer.", obj_name
);
69 set_hit_error (int res
, GError
**error
)
71 set_error (res
, error
, "Hit");
75 set_hit_collection_error (int res
, GError
**error
)
77 set_error (res
, error
, "HitCollection");
81 set_value_error (int res
, GError
**error
)
83 set_error (res
, error
, "Value");
87 set_filter_param_error (int res
, GError
**error
)
89 set_error (res
, error
, "FilterParam");
93 set_operator_error (int res
, GError
**error
)
95 set_error (res
, error
, "ComparisionOperator");
99 set_filter_error (int res
, GError
**error
)
101 set_error (res
, error
, "Filter");
105 set_pair_error (int res
, GError
**error
)
107 set_error (res
, error
, "Pair");
111 set_attribute_error (int res
, GError
**error
)
113 set_error (res
, error
, "Attribute");
117 serialize_value (xmlTextWriterPtr writer
, GValue
*v
, GError
**error
)
122 GType type
= G_VALUE_TYPE (v
);
124 /* guess the most used cases and handle those first */
125 if (type
== G_TYPE_STRING
) {
126 ret
= g_strdup (g_value_get_string (v
));
127 } else if (type
== G_TYPE_BOOLEAN
) {
128 ret
= g_strdup_printf ("%d", g_value_get_boolean (v
));
129 } else if (type
== G_TYPE_INT
) {
130 ret
= g_strdup_printf ("%d", g_value_get_int (v
));
131 } else if (type
== G_TYPE_FLOAT
) {
132 ret
= g_strdup_printf ("%f", g_value_get_float (v
));
133 } else if (type
== G_TYPE_DOUBLE
) {
134 char double_buff
[G_ASCII_DTOSTR_BUF_SIZE
];
135 ret
= g_ascii_dtostr (double_buff
, sizeof (double_buff
),
136 g_value_get_double (v
));
137 } else if (type
== G_TYPE_LONG
) {
138 ret
= g_strdup_printf ("%ld", g_value_get_long (v
));
139 } else if (type
== G_TYPE_INT64
) {
140 ret
= g_strdup_printf ("%lld", g_value_get_int64 (v
));
141 } else if (type
== G_TYPE_UINT
) {
142 ret
= g_strdup_printf ("%u", g_value_get_uint (v
));
143 } else if (type
== G_TYPE_ULONG
) {
144 ret
= g_strdup_printf ("%lu", g_value_get_ulong (v
));
145 } else if (type
== G_TYPE_UINT64
) {
146 ret
= g_strdup_printf ("%llu", g_value_get_uint64 (v
));
147 } else if (G_VALUE_HOLDS_CHAR (v
)) {
148 ret
= g_strdup_printf ("%c", g_value_get_char (v
));
149 } else if (G_VALUE_HOLDS_UCHAR (v
)) {
150 ret
= g_strdup_printf ("%c", g_value_get_uchar (v
));
152 g_warning ("Can't convert the value to string: unhandled type");
156 safe
= xmlCharStrdup (ret
);
159 res
= xmlTextWriterWriteElement (writer
, BAD_CAST ("value"), safe
);
162 set_value_error (res
, error
);
168 serialize_op (xmlTextWriterPtr writer
, MMComparisionOperator op
, GError
**error
)
173 for (idx
= 0; idx
< G_N_ELEMENTS (operator_grid
); idx
++) {
174 if (op
== operator_grid
[idx
].op
) {
175 str
= xmlCharStrdup (operator_grid
[idx
].string
);
180 res
= xmlTextWriterWriteElement (writer
, BAD_CAST ("op"), str
);
183 set_operator_error (res
, error
);
190 serialize_attribute (xmlTextWriterPtr writer
,
191 MMAttribute
*attribute
,
197 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("attribute"));
199 set_attribute_error (res
, error
);
203 safe_str
= xmlCharStrdup (mm_attribute_get_id (attribute
));
204 res
= xmlTextWriterWriteAttribute (writer
, BAD_CAST ("id"), safe_str
);
207 set_attribute_error (res
, error
);
211 safe_str
= xmlCharStrdup (mm_attribute_get_name (attribute
));
212 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("name"), safe_str
);
215 set_attribute_error (res
, error
);
219 safe_str
= xmlCharStrdup (mm_attribute_get_description (attribute
));
220 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("description"), safe_str
);
223 set_attribute_error (res
, error
);
227 res
= xmlTextWriterWriteAttribute (writer
, BAD_CAST ("type"),
228 BAD_CAST (g_type_name (mm_attribute_get_value_type (attribute
))));
230 set_attribute_error (res
, error
);
234 /* close "attribute" */
235 res
= xmlTextWriterEndElement (writer
);
237 set_attribute_error (res
, error
);
243 serialize_filter_param (MMFilterParam
*fp
,
246 MMAttribute
*attribute
;
248 MMComparisionOperator op
;
250 xmlTextWriterPtr writer
= data
->writer
;
251 GError
**error
= data
->error
;
253 attribute
= mm_filter_param_get_attribute (fp
);
254 val
= mm_filter_param_get_value (fp
);
255 op
= mm_filter_param_get_operator (fp
);
257 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("filter-param"));
259 set_filter_param_error (res
, error
);
263 serialize_attribute (writer
, attribute
, error
);
267 serialize_value (writer
, val
, error
);
271 serialize_op (writer
, op
, error
);
276 /* close "filter-param" */
277 res
= xmlTextWriterEndElement (writer
);
279 set_filter_param_error (res
, error
);
285 unserialize_operator (xmlTextReaderPtr reader
, MMComparisionOperator
*op
,
288 const xmlChar
* op_string
;
289 gboolean found
= FALSE
;
292 /* we should be on <op> */
293 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("op")) != 0) {
294 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
295 "Error while parsing the serialized xml opeator: the xml reader "
296 "does not point to a ComparisionOperator");
300 /* move on to the content */
301 res
= xmlTextReaderRead (reader
);
303 set_operator_error (res
, error
);
307 op_string
= xmlTextReaderConstValue (reader
);
308 for (idx
= 0; idx
< G_N_ELEMENTS (operator_grid
); idx
++) {
309 if (xmlStrcmp (op_string
, BAD_CAST (operator_grid
[idx
].string
)) == 0) {
316 res
= xmlTextReaderRead (reader
);
318 set_operator_error (res
, error
);
323 *op
= operator_grid
[idx
].op
;
328 unserialize_value (xmlTextReaderPtr reader
, GValue
*v
, GError
**error
)
332 const char *val_string
;
334 /* we should be on <value> */
335 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("value")) != 0) {
336 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
337 "Error while parsing the serialized xml value: the xml reader "
338 " does not point to a value");
342 /* move on to the content node */
343 res
= xmlTextReaderRead (reader
);
345 set_value_error (res
, error
);
349 type
= G_VALUE_TYPE (v
);
350 val_string
= (const char *) xmlTextReaderConstValue (reader
);
352 if (type
== G_TYPE_STRING
) {
353 g_value_set_string (v
, val_string
);
354 } else if (type
== G_TYPE_BOOLEAN
) {
356 sscanf (val_string
, "%d", &bval
);
357 g_value_set_boolean (v
, bval
);
358 } else if (type
== G_TYPE_INT
) {
360 sscanf (val_string
, "%d", &ival
);
361 g_value_set_int (v
, ival
);
362 } else if (type
== G_TYPE_FLOAT
) {
364 sscanf (val_string
, "%f", &fval
);
365 g_value_set_float (v
, fval
);
366 } else if (type
== G_TYPE_DOUBLE
) {
368 dval
= g_ascii_strtod (val_string
, NULL
);
369 g_value_set_double (v
, dval
);
370 } else if (type
== G_TYPE_LONG
) {
372 sscanf (val_string
, "%ld", &lval
);
373 g_value_set_long (v
, lval
);
374 } else if (type
== G_TYPE_INT64
) {
375 g_value_set_int64 (v
, g_ascii_strtoll (val_string
, NULL
, 0));
376 } else if (type
== G_TYPE_UINT
) {
378 sscanf (val_string
, "%u", &uval
);
379 g_value_set_uint (v
, uval
);
380 } else if (type
== G_TYPE_ULONG
) {
382 sscanf (val_string
, "%lu", &ulval
);
383 g_value_set_ulong (v
, ulval
);
384 } else if (type
== G_TYPE_UINT64
) {
385 g_value_set_uint64 (v
, g_ascii_strtoull (val_string
, NULL
, 0));
386 } else if (G_VALUE_HOLDS_CHAR (v
)) {
388 sscanf (val_string
, "%c", &cval
);
389 g_value_set_char (v
, cval
);
390 } else if (G_VALUE_HOLDS_UCHAR (v
)) {
392 sscanf (val_string
, "%c", &ucval
);
393 g_value_set_uchar (v
, ucval
);
395 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNKNOWN_GTYPE
,
396 "Can't convert the string to a value: unhandled type");
400 /* move over </value> */
401 res
= xmlTextReaderRead (reader
);
403 set_value_error (res
, error
);
411 unserialize_attribute (xmlTextReaderPtr reader
, MMAttribute
**attribute
, GError
**error
)
413 xmlChar
*id
, *name
, *desc
, *type_name
;
416 /* we should be on <attribute> */
417 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("attribute")) != 0) {
418 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
419 "Error while parsing the serialized xml attribute: the xml reader"
420 " does not point to an attribute.");
424 id
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("id"));
425 name
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("name"));
426 desc
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("desc"));
427 type_name
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("type"));
429 type
= g_type_from_name ((const char *) type_name
);
431 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNKNOWN_GTYPE
,
432 "Error while parsing the serialized xml attribute: cannot get a GType"
433 " for the name %s.", (const char *) type_name
);
437 *attribute
= mm_attribute_new (type
,
440 (const char *) desc
);
448 static MMFilterParam
*
449 unserialize_filter_param (xmlTextReaderPtr reader
, GError
**error
)
452 MMAttribute
*attribute
= NULL
;
453 MMComparisionOperator op
= MM_COMP_NONE
;
455 MMFilterParam
*fp
= NULL
;
457 res
= xmlTextReaderRead (reader
);
459 set_filter_param_error (res
, error
);
463 /* we're either on <attribute> or </filter-param> if the object is empty */
464 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
465 xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("filter-param")) == 0) && res
> 0) {
466 unserialize_attribute (reader
, &attribute
, error
);
471 res
= xmlTextReaderRead (reader
);
473 set_filter_param_error (res
, error
);
476 /* we're now on <value> */
477 val
= mm_create_gvalue_for_attribute (attribute
);
478 unserialize_value (reader
, val
, error
);
483 res
= xmlTextReaderRead (reader
);
485 set_filter_param_error (res
, error
);
488 /* we're now on <op> */
489 unserialize_operator (reader
, &op
, error
);
494 /* move after </op> */
495 res
= xmlTextReaderRead (reader
);
497 set_filter_param_error (res
, error
);
502 /* if we're here, everything in the unserialize sub-operations went well */
503 fp
= mm_filter_param_new (attribute
, val
, op
);
515 serialize_pair (MMAttribute
*attr
,
517 SerializeData
*pair_data
)
519 xmlTextWriterPtr writer
= pair_data
->writer
;
520 GError
**error
= pair_data
->error
;
524 /* an error occurred in a previous iteration of this function, don't do
530 xmlTextWriterStartElement (writer
, BAD_CAST ("pair"));
531 serialize_attribute (writer
, attr
, error
);
536 serialize_value (writer
, val
, error
);
542 res
= xmlTextWriterEndElement (writer
);
544 set_pair_error (res
, error
);
549 unserialize_hit (xmlTextReaderPtr reader
, GError
**error
)
552 MMAttribute
*attribute
= NULL
;
556 hit
= g_object_new (MM_TYPE_HIT
, NULL
);
560 res
= xmlTextReaderRead (reader
);
562 set_hit_error (res
, error
);
563 g_object_unref (hit
);
567 res
= xmlTextReaderRead (reader
);
568 /* now we should be on "attribute" */
570 set_hit_error (res
, error
);
571 g_object_unref (hit
);
575 unserialize_attribute (reader
, &attribute
, error
);
577 g_object_unref (hit
);
581 res
= xmlTextReaderRead (reader
);
582 /* we're now on "value" */
584 set_hit_error (res
, error
);
585 g_object_unref (hit
);
590 v
= mm_create_gvalue_for_attribute (attribute
);
591 unserialize_value (reader
, v
, error
);
593 g_object_unref (hit
);
598 mm_hit_set_value (hit
, attribute
, v
);
600 res
= xmlTextReaderRead (reader
);
601 /* now we're on </pair> */
603 set_hit_error (res
, error
);
604 g_object_unref (hit
);
609 res
= xmlTextReaderRead (reader
);
611 set_hit_error (res
, error
);
612 g_object_unref (hit
);
616 /* now we're either on <pair> again or </hit>. we must end they cycle
619 } while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
620 xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("hit"))));
625 /* public functions */
627 mm_filter_serialize (MMFilter
*filter
, GError
**error
)
629 char *serialized
= NULL
;
631 xmlTextWriterPtr writer
;
632 GList
*filter_params
;
633 SerializeData
*fp_data
;
636 buffer
= xmlBufferCreate ();
637 writer
= xmlNewTextWriterMemory (buffer
, 0);
639 res
= xmlTextWriterStartDocument (writer
, NULL
, NULL
, NULL
);
641 set_filter_error (res
, error
);
645 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("filter"));
647 set_filter_error (res
, error
);
651 filter_params
= mm_filter_get_filtering_params (filter
);
652 fp_data
= g_new0 (SerializeData
, 1);
653 fp_data
->writer
= writer
;
654 fp_data
->error
= error
;
655 g_list_foreach (filter_params
, (GFunc
) serialize_filter_param
, fp_data
);
662 res
= xmlTextWriterEndElement (writer
);
664 set_filter_error (res
, error
);
668 res
= xmlTextWriterEndDocument (writer
);
670 set_filter_error (res
, error
);
674 /* everything went well */
675 serialized
= g_strdup ((char *) xmlBufferContent (buffer
));
678 xmlFreeTextWriter (writer
);
679 xmlBufferFree (buffer
);
685 mm_hit_collection_serialize (MMHitCollection
*hc
, GError
**error
)
687 char *serialized
= NULL
;
690 xmlTextWriterPtr writer
;
692 GHashTable
*attrs_and_values
;
693 SerializeData
*pair_data
;
695 buffer
= xmlBufferCreate ();
696 writer
= xmlNewTextWriterMemory (buffer
, 0);
698 res
= xmlTextWriterStartDocument (writer
, NULL
, NULL
, NULL
);
700 set_hit_collection_error (res
, error
);
704 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("hit-collection"));
706 set_hit_collection_error (res
, error
);
710 while ((hit
= mm_hit_collection_get_next_hit (hc
)) != NULL
) {
711 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("hit"));
713 set_hit_collection_error (res
, error
);
717 attrs_and_values
= mm_hit_get_all_values (hit
);
719 pair_data
= g_slice_new0 (SerializeData
);
720 pair_data
->writer
= writer
;
721 pair_data
->error
= error
;
723 g_hash_table_foreach (attrs_and_values
,
724 (GHFunc
) serialize_pair
,
726 g_slice_free (SerializeData
, pair_data
);
728 /* an error occurred somewhere in one of the sub-functions */
733 res
= xmlTextWriterEndElement (writer
);
735 set_hit_collection_error (res
, error
);
740 /* close "hit-collection" */
741 res
= xmlTextWriterEndElement (writer
);
743 set_hit_collection_error (res
, error
);
746 res
= xmlTextWriterEndDocument (writer
);
748 set_hit_collection_error (res
, error
);
752 /* it seems everything has gone well */
753 serialized
= g_strdup ((char *) xmlBufferContent (buffer
));
756 xmlFreeTextWriter (writer
);
757 xmlBufferFree (buffer
);
763 mm_filter_unserialize (const char *s
, GError
**error
)
767 xmlTextReaderPtr reader
;
769 const xmlChar
*node_name
;
771 reader
= xmlReaderForMemory (s
, strlen (s
), NULL
, NULL
, 0);
773 /* cut all the elements before <filter> */
775 res
= xmlTextReaderRead (reader
);
776 node_name
= xmlTextReaderConstName (reader
);
777 } while (xmlStrcmp (node_name
, BAD_CAST ("filter")) != 0);
779 /* do the error checking here and not in each iteration of the cycle */
781 set_filter_error (res
, error
);
785 res
= xmlTextReaderRead (reader
);
786 node_name
= xmlTextReaderConstName (reader
);
787 f
= mm_filter_new ();
789 /* we're either on the first <filter-param> or on </filter> if the
790 * object is empty. cycle until we're on </filter>.
792 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
793 xmlStrcmp (node_name
, BAD_CAST ("filter")) == 0) && res
> 0) {
794 fp
= unserialize_filter_param (reader
, error
);
800 mm_filter_add_filtering_param (f
, fp
);
802 res
= xmlTextReaderRead (reader
);
803 node_name
= xmlTextReaderConstName (reader
);
807 /* do not return an incomplete filter */
808 set_filter_error (res
, error
);
814 xmlFreeTextReader (reader
);
820 mm_hit_collection_unserialize (const char *s
, GError
**error
)
822 MMHitCollection
*hc
= NULL
;
824 xmlTextReaderPtr reader
;
826 const xmlChar
*node_name
;
828 reader
= xmlReaderForMemory (s
, strlen (s
), NULL
, NULL
, 0);
830 /* cut all the elements before <hit-collection> */
832 res
= xmlTextReaderRead (reader
);
833 node_name
= xmlTextReaderConstName (reader
);
834 } while (xmlStrcmp (node_name
, BAD_CAST ("hit-collection")) != 0);
836 /* check for errors before <hit-collection> all at once, and not
837 * in every iteration of the cycle.
840 set_hit_collection_error (res
, error
);
844 hc
= mm_hit_collection_new ();
845 res
= xmlTextReaderRead (reader
);
846 node_name
= xmlTextReaderConstName (reader
);
848 /* we're either on the first <hit> or on </hit-collection> if the
849 * object is empty. cycle until we're at the end of file.
851 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
852 xmlStrcmp (node_name
, BAD_CAST ("hit-collection")) == 0) && res
> 0) {
853 hit
= unserialize_hit (reader
, error
);
855 /* do not return an incomplete HitCollection */
860 mm_hit_collection_add_hit (hc
, hit
);
861 g_object_unref (hit
);
862 res
= xmlTextReaderRead (reader
);
863 node_name
= xmlTextReaderConstName (reader
);
867 /* do not return an incomplete HitCollection */
868 set_hit_collection_error (res
, error
);
875 xmlFreeTextReader (reader
);