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"
33 MMComparisionOperator op
;
38 xmlTextWriterPtr writer
;
42 static OperatorGrid operator_grid
[] =
44 { MM_COMP_EQUAL
, "EQ" },
45 { MM_COMP_GREATER
, "GR" },
46 { MM_COMP_GREATER_EQUAL
, "GRQ" },
47 { MM_COMP_LESS
, "LS" },
48 { MM_COMP_LESS_EQUAL
, "LSQ" },
53 set_error (int res
, GError
**error
, const char *obj_name
)
55 xmlErrorPtr xml_error
;
58 xml_error
= xmlGetLastError ();
59 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNSERIALIZE_FAILED
,
60 "Error while parsing the serialized xml %s: %s",
61 obj_name
, (xml_error
!= NULL
) ? (xml_error
->message
) : "");
62 } else if (res
== 0) {
63 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_EOF
,
64 "Error while parsing the serialized xml %s: unexpected "
65 "end of the xml buffer.", obj_name
);
70 set_hit_error (int res
, GError
**error
)
72 set_error (res
, error
, "Hit");
76 set_hit_collection_error (int res
, GError
**error
)
78 set_error (res
, error
, "HitCollection");
82 set_value_error (int res
, GError
**error
)
84 set_error (res
, error
, "Value");
88 set_filter_param_error (int res
, GError
**error
)
90 set_error (res
, error
, "FilterParam");
94 set_operator_error (int res
, GError
**error
)
96 set_error (res
, error
, "ComparisionOperator");
100 set_filter_error (int res
, GError
**error
)
102 set_error (res
, error
, "Filter");
106 set_pair_error (int res
, GError
**error
)
108 set_error (res
, error
, "Pair");
112 set_attribute_error (int res
, GError
**error
)
114 set_error (res
, error
, "Attribute");
118 serialize_value (xmlTextWriterPtr writer
, GValue
*v
, GError
**error
)
124 ret
= mm_gvalue_to_string (v
);
129 safe
= xmlCharStrdup (ret
);
132 res
= xmlTextWriterWriteElement (writer
, BAD_CAST ("value"), safe
);
135 set_value_error (res
, error
);
141 serialize_op (xmlTextWriterPtr writer
, MMComparisionOperator op
, GError
**error
)
146 for (idx
= 0; idx
< G_N_ELEMENTS (operator_grid
); idx
++) {
147 if (op
== operator_grid
[idx
].op
) {
148 str
= xmlCharStrdup (operator_grid
[idx
].string
);
153 res
= xmlTextWriterWriteElement (writer
, BAD_CAST ("op"), str
);
156 set_operator_error (res
, error
);
163 serialize_attribute (xmlTextWriterPtr writer
,
164 MMAttribute
*attribute
,
170 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("attribute"));
172 set_attribute_error (res
, error
);
176 safe_str
= xmlCharStrdup (mm_attribute_get_id (attribute
));
177 res
= xmlTextWriterWriteAttribute (writer
, BAD_CAST ("id"), safe_str
);
180 set_attribute_error (res
, error
);
184 safe_str
= xmlCharStrdup (mm_attribute_get_name (attribute
));
185 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("name"), safe_str
);
188 set_attribute_error (res
, error
);
192 safe_str
= xmlCharStrdup (mm_attribute_get_description (attribute
));
193 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("description"), safe_str
);
196 set_attribute_error (res
, error
);
200 res
= xmlTextWriterWriteAttribute (writer
, BAD_CAST ("type"),
201 BAD_CAST (g_type_name (mm_attribute_get_value_type (attribute
))));
203 set_attribute_error (res
, error
);
207 /* close "attribute" */
208 res
= xmlTextWriterEndElement (writer
);
210 set_attribute_error (res
, error
);
216 serialize_filter_param (MMFilterParam
*fp
,
219 MMAttribute
*attribute
;
221 MMComparisionOperator op
;
223 xmlTextWriterPtr writer
= data
->writer
;
224 GError
**error
= data
->error
;
226 attribute
= mm_filter_param_get_attribute (fp
);
227 val
= mm_filter_param_get_value (fp
);
228 op
= mm_filter_param_get_operator (fp
);
230 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("filter-param"));
232 set_filter_param_error (res
, error
);
236 serialize_attribute (writer
, attribute
, error
);
240 serialize_value (writer
, val
, error
);
244 serialize_op (writer
, op
, error
);
249 /* close "filter-param" */
250 res
= xmlTextWriterEndElement (writer
);
252 set_filter_param_error (res
, error
);
258 unserialize_operator (xmlTextReaderPtr reader
, MMComparisionOperator
*op
,
261 const xmlChar
* op_string
;
262 gboolean found
= FALSE
;
265 /* we should be on <op> */
266 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("op")) != 0) {
267 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
268 "Error while parsing the serialized xml opeator: the xml reader "
269 "does not point to a ComparisionOperator");
273 /* move on to the content */
274 res
= xmlTextReaderRead (reader
);
276 set_operator_error (res
, error
);
280 op_string
= xmlTextReaderConstValue (reader
);
281 for (idx
= 0; idx
< G_N_ELEMENTS (operator_grid
); idx
++) {
282 if (xmlStrcmp (op_string
, BAD_CAST (operator_grid
[idx
].string
)) == 0) {
289 res
= xmlTextReaderRead (reader
);
291 set_operator_error (res
, error
);
296 *op
= operator_grid
[idx
].op
;
301 unserialize_value (xmlTextReaderPtr reader
, GValue
*v
, GError
**error
)
305 const char *val_string
;
308 /* we should be on <value> */
309 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("value")) != 0) {
310 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
311 "Error while parsing the serialized xml value: the xml reader "
312 " does not point to a value");
316 /* move on to the content node */
317 res
= xmlTextReaderRead (reader
);
319 set_value_error (res
, error
);
323 type
= G_VALUE_TYPE (v
);
324 val_string
= (const char *) xmlTextReaderConstValue (reader
);
326 result
= mm_gvalue_from_string (val_string
, type
, v
);
328 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNKNOWN_GTYPE
,
329 "Can't convert the string to a value: unhandled type");
333 /* move over </value> */
334 res
= xmlTextReaderRead (reader
);
336 set_value_error (res
, error
);
344 unserialize_attribute (xmlTextReaderPtr reader
, MMAttribute
**attribute
, GError
**error
)
346 xmlChar
*id
, *name
, *desc
, *type_name
;
349 /* we should be on <attribute> */
350 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("attribute")) != 0) {
351 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
352 "Error while parsing the serialized xml attribute: the xml reader"
353 " does not point to an attribute.");
357 id
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("id"));
358 name
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("name"));
359 desc
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("desc"));
360 type_name
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("type"));
362 type
= g_type_from_name ((const char *) type_name
);
364 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNKNOWN_GTYPE
,
365 "Error while parsing the serialized xml attribute: cannot get a GType"
366 " for the name %s.", (const char *) type_name
);
370 *attribute
= mm_attribute_new (type
,
373 (const char *) desc
);
381 static MMFilterParam
*
382 unserialize_filter_param (xmlTextReaderPtr reader
, GError
**error
)
385 MMAttribute
*attribute
= NULL
;
386 MMComparisionOperator op
= MM_COMP_NONE
;
388 MMFilterParam
*fp
= NULL
;
390 res
= xmlTextReaderRead (reader
);
392 set_filter_param_error (res
, error
);
396 /* we're either on <attribute> or </filter-param> if the object is empty */
397 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
398 xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("filter-param")) == 0) && res
> 0) {
399 unserialize_attribute (reader
, &attribute
, error
);
404 res
= xmlTextReaderRead (reader
);
406 set_filter_param_error (res
, error
);
409 /* we're now on <value> */
410 val
= mm_create_gvalue_for_attribute (attribute
);
411 unserialize_value (reader
, val
, error
);
416 res
= xmlTextReaderRead (reader
);
418 set_filter_param_error (res
, error
);
421 /* we're now on <op> */
422 unserialize_operator (reader
, &op
, error
);
427 /* move after </op> */
428 res
= xmlTextReaderRead (reader
);
430 set_filter_param_error (res
, error
);
435 /* if we're here, everything in the unserialize sub-operations went well */
436 fp
= mm_filter_param_new (attribute
, val
, op
);
448 serialize_pair (MMAttribute
*attr
,
450 SerializeData
*pair_data
)
452 xmlTextWriterPtr writer
= pair_data
->writer
;
453 GError
**error
= pair_data
->error
;
457 /* an error occurred in a previous iteration of this function, don't do
463 xmlTextWriterStartElement (writer
, BAD_CAST ("pair"));
464 serialize_attribute (writer
, attr
, error
);
469 serialize_value (writer
, val
, error
);
475 res
= xmlTextWriterEndElement (writer
);
477 set_pair_error (res
, error
);
482 unserialize_hit (xmlTextReaderPtr reader
, GError
**error
)
485 MMAttribute
*attribute
= NULL
;
489 hit
= g_object_new (MM_TYPE_HIT
, NULL
);
493 res
= xmlTextReaderRead (reader
);
495 set_hit_error (res
, error
);
496 g_object_unref (hit
);
500 res
= xmlTextReaderRead (reader
);
501 /* now we should be on "attribute" */
503 set_hit_error (res
, error
);
504 g_object_unref (hit
);
508 unserialize_attribute (reader
, &attribute
, error
);
510 g_object_unref (hit
);
514 res
= xmlTextReaderRead (reader
);
515 /* we're now on "value" */
517 set_hit_error (res
, error
);
518 g_object_unref (hit
);
523 v
= mm_create_gvalue_for_attribute (attribute
);
524 unserialize_value (reader
, v
, error
);
526 g_object_unref (hit
);
531 mm_hit_set_value (hit
, attribute
, v
);
533 res
= xmlTextReaderRead (reader
);
534 /* now we're on </pair> */
536 set_hit_error (res
, error
);
537 g_object_unref (hit
);
542 res
= xmlTextReaderRead (reader
);
544 set_hit_error (res
, error
);
545 g_object_unref (hit
);
549 /* now we're either on <pair> again or </hit>. we must end they cycle
552 } while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
553 xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("hit"))));
558 /* public functions */
561 * mm_filter_serialize:
562 * @filter: a #MMFilter object.
565 * Builds a serialized XML version of @filter.
567 * Return value: a newly allocated string buffer containing the serialized
572 mm_filter_serialize (MMFilter
*filter
, GError
**error
)
574 char *serialized
= NULL
;
576 xmlTextWriterPtr writer
;
577 GList
*filter_params
;
578 SerializeData
*fp_data
;
581 buffer
= xmlBufferCreate ();
582 writer
= xmlNewTextWriterMemory (buffer
, 0);
584 res
= xmlTextWriterStartDocument (writer
, NULL
, NULL
, NULL
);
586 set_filter_error (res
, error
);
590 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("filter"));
592 set_filter_error (res
, error
);
596 filter_params
= mm_filter_get_filtering_params (filter
);
597 fp_data
= g_new0 (SerializeData
, 1);
598 fp_data
->writer
= writer
;
599 fp_data
->error
= error
;
600 g_list_foreach (filter_params
, (GFunc
) serialize_filter_param
, fp_data
);
607 res
= xmlTextWriterEndElement (writer
);
609 set_filter_error (res
, error
);
613 res
= xmlTextWriterEndDocument (writer
);
615 set_filter_error (res
, error
);
619 /* everything went well */
620 serialized
= g_strdup ((char *) xmlBufferContent (buffer
));
623 xmlFreeTextWriter (writer
);
624 xmlBufferFree (buffer
);
630 * mm_hit_collection_serialize:
631 * @hc: a #MMHitCollection object.
634 * Builds a serialized XML version of the #MMHitCollection.
636 * Return value: a newly allocated string buffer containing the serialized
641 mm_hit_collection_serialize (MMHitCollection
*hc
, GError
**error
)
643 char *serialized
= NULL
;
646 xmlTextWriterPtr writer
;
648 GHashTable
*attrs_and_values
;
649 SerializeData
*pair_data
;
651 buffer
= xmlBufferCreate ();
652 writer
= xmlNewTextWriterMemory (buffer
, 0);
654 res
= xmlTextWriterStartDocument (writer
, NULL
, NULL
, NULL
);
656 set_hit_collection_error (res
, error
);
660 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("hit-collection"));
662 set_hit_collection_error (res
, error
);
666 while ((hit
= mm_hit_collection_get_next_hit (hc
)) != NULL
) {
667 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("hit"));
669 g_object_unref (hit
);
670 set_hit_collection_error (res
, error
);
674 attrs_and_values
= mm_hit_get_all_values (hit
);
675 g_object_unref (hit
);
677 pair_data
= g_slice_new0 (SerializeData
);
678 pair_data
->writer
= writer
;
679 pair_data
->error
= error
;
681 g_hash_table_foreach (attrs_and_values
,
682 (GHFunc
) serialize_pair
,
684 g_slice_free (SerializeData
, pair_data
);
685 g_hash_table_destroy (attrs_and_values
);
688 /* an error occurred somewhere in one of the sub-functions */
693 res
= xmlTextWriterEndElement (writer
);
695 set_hit_collection_error (res
, error
);
700 /* close "hit-collection" */
701 res
= xmlTextWriterEndElement (writer
);
703 set_hit_collection_error (res
, error
);
706 res
= xmlTextWriterEndDocument (writer
);
708 set_hit_collection_error (res
, error
);
712 /* it seems everything has gone well */
713 serialized
= g_strdup ((char *) xmlBufferContent (buffer
));
716 xmlFreeTextWriter (writer
);
717 xmlBufferFree (buffer
);
723 * mm_filter_unserialize:
724 * @s: a serialized #MMFilter, obtained with
725 * #mm_filter_serialize.
728 * Builds a #MMFilter object from a serialized XML string.
730 * Return value: a #MMFilter object. Unref it when done.
734 mm_filter_unserialize (const char *s
, GError
**error
)
738 xmlTextReaderPtr reader
;
740 const xmlChar
*node_name
;
742 reader
= xmlReaderForMemory (s
, strlen (s
), NULL
, NULL
, 0);
744 /* cut all the elements before <filter> */
746 res
= xmlTextReaderRead (reader
);
747 node_name
= xmlTextReaderConstName (reader
);
748 } while (xmlStrcmp (node_name
, BAD_CAST ("filter")) != 0);
750 /* do the error checking here and not in each iteration of the cycle */
752 set_filter_error (res
, error
);
756 res
= xmlTextReaderRead (reader
);
757 node_name
= xmlTextReaderConstName (reader
);
758 f
= mm_filter_new ();
760 /* we're either on the first <filter-param> or on </filter> if the
761 * object is empty. cycle until we're on </filter>.
763 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
764 xmlStrcmp (node_name
, BAD_CAST ("filter")) == 0) && res
> 0) {
765 fp
= unserialize_filter_param (reader
, error
);
771 mm_filter_add_filtering_param (f
, fp
);
773 res
= xmlTextReaderRead (reader
);
774 node_name
= xmlTextReaderConstName (reader
);
778 /* do not return an incomplete filter */
779 set_filter_error (res
, error
);
785 xmlFreeTextReader (reader
);
791 * mm_hit_collection_unserialize:
792 * @s: a serialized #MMHitCollection, obtained with
793 * #mm_hit_collection_serialize.
796 * Builds a #MMHitCollection object from a serialized XML string.
798 * Return value: a #MMHitCollection object. Unref it when done.
802 mm_hit_collection_unserialize (const char *s
, GError
**error
)
804 MMHitCollection
*hc
= NULL
;
806 xmlTextReaderPtr reader
;
808 const xmlChar
*node_name
;
810 reader
= xmlReaderForMemory (s
, strlen (s
), NULL
, NULL
, 0);
812 /* cut all the elements before <hit-collection> */
814 res
= xmlTextReaderRead (reader
);
815 node_name
= xmlTextReaderConstName (reader
);
816 } while (xmlStrcmp (node_name
, BAD_CAST ("hit-collection")) != 0);
818 /* check for errors before <hit-collection> all at once, and not
819 * in every iteration of the cycle.
822 set_hit_collection_error (res
, error
);
826 hc
= mm_hit_collection_new ();
827 res
= xmlTextReaderRead (reader
);
828 node_name
= xmlTextReaderConstName (reader
);
830 /* we're either on the first <hit> or on </hit-collection> if the
831 * object is empty. cycle until we're at the end of file.
833 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
834 xmlStrcmp (node_name
, BAD_CAST ("hit-collection")) == 0) && res
> 0) {
835 hit
= unserialize_hit (reader
, error
);
837 /* do not return an incomplete HitCollection */
842 mm_hit_collection_add_hit (hc
, hit
);
843 g_object_unref (hit
);
844 res
= xmlTextReaderRead (reader
);
845 node_name
= xmlTextReaderConstName (reader
);
849 /* do not return an incomplete HitCollection */
850 set_hit_collection_error (res
, error
);
857 xmlFreeTextReader (reader
);
863 * mm_gvalue_to_string:
866 * Builds a serialized XML version of a #GValue.
868 * Return value: a newly allocated string buffer containing the serialized
873 mm_gvalue_to_string (GValue
*v
)
876 GType type
= G_VALUE_TYPE (v
);
878 /* guess the most used cases and handle those first */
879 if (type
== G_TYPE_STRING
) {
880 ret
= g_strdup (g_value_get_string (v
));
881 } else if (type
== G_TYPE_BOOLEAN
) {
882 ret
= g_strdup_printf ("%d", g_value_get_boolean (v
));
883 } else if (type
== G_TYPE_INT
) {
884 ret
= g_strdup_printf ("%d", g_value_get_int (v
));
885 } else if (type
== G_TYPE_FLOAT
) {
886 ret
= g_strdup_printf ("%f", g_value_get_float (v
));
887 } else if (type
== G_TYPE_DOUBLE
) {
888 char double_buff
[G_ASCII_DTOSTR_BUF_SIZE
];
889 ret
= g_ascii_dtostr (double_buff
, sizeof (double_buff
),
890 g_value_get_double (v
));
891 } else if (type
== G_TYPE_LONG
) {
892 ret
= g_strdup_printf ("%ld", g_value_get_long (v
));
893 } else if (type
== G_TYPE_INT64
) {
894 ret
= g_strdup_printf ("%lld", g_value_get_int64 (v
));
895 } else if (type
== G_TYPE_UINT
) {
896 ret
= g_strdup_printf ("%u", g_value_get_uint (v
));
897 } else if (type
== G_TYPE_ULONG
) {
898 ret
= g_strdup_printf ("%lu", g_value_get_ulong (v
));
899 } else if (type
== G_TYPE_UINT64
) {
900 ret
= g_strdup_printf ("%llu", g_value_get_uint64 (v
));
901 } else if (G_VALUE_HOLDS_CHAR (v
)) {
902 ret
= g_strdup_printf ("%c", g_value_get_char (v
));
903 } else if (G_VALUE_HOLDS_UCHAR (v
)) {
904 ret
= g_strdup_printf ("%c", g_value_get_uchar (v
));
906 g_warning ("Can't convert the value to string: unhandled type");
913 * mm_gvalue_from_string:
914 * @val_string: a string description of a #GValue. You can use
915 * #mm_gvalue_to_string to have one.
916 * @type: the type of the #GValue.
917 * @v: a zero-filled uninitialized #GValue.
919 * Fills @v with the #GValue contained in the XML description @val_string.
921 * Return value: %TRUE in case of success, %FALSE in case of failure.
925 mm_gvalue_from_string (const char *val_string
, GType type
, GValue
*v
)
927 gboolean retval
= TRUE
;
929 g_value_init (v
, type
);
931 if (type
== G_TYPE_STRING
) {
932 g_value_set_string (v
, val_string
);
933 } else if (type
== G_TYPE_BOOLEAN
) {
935 sscanf (val_string
, "%d", &bval
);
936 g_value_set_boolean (v
, bval
);
937 } else if (type
== G_TYPE_INT
) {
939 sscanf (val_string
, "%d", &ival
);
940 g_value_set_int (v
, ival
);
941 } else if (type
== G_TYPE_FLOAT
) {
943 sscanf (val_string
, "%f", &fval
);
944 g_value_set_float (v
, fval
);
945 } else if (type
== G_TYPE_DOUBLE
) {
947 dval
= g_ascii_strtod (val_string
, NULL
);
948 g_value_set_double (v
, dval
);
949 } else if (type
== G_TYPE_LONG
) {
951 sscanf (val_string
, "%ld", &lval
);
952 g_value_set_long (v
, lval
);
953 } else if (type
== G_TYPE_INT64
) {
954 g_value_set_int64 (v
, g_ascii_strtoll (val_string
, NULL
, 0));
955 } else if (type
== G_TYPE_UINT
) {
957 sscanf (val_string
, "%u", &uval
);
958 g_value_set_uint (v
, uval
);
959 } else if (type
== G_TYPE_ULONG
) {
961 sscanf (val_string
, "%lu", &ulval
);
962 g_value_set_ulong (v
, ulval
);
963 } else if (type
== G_TYPE_UINT64
) {
964 g_value_set_uint64 (v
, g_ascii_strtoull (val_string
, NULL
, 0));
965 } else if (G_VALUE_HOLDS_CHAR (v
)) {
967 sscanf (val_string
, "%c", &cval
);
968 g_value_set_char (v
, cval
);
969 } else if (G_VALUE_HOLDS_UCHAR (v
)) {
971 sscanf (val_string
, "%c", &ucval
);
972 g_value_set_uchar (v
, ucval
);