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
)
123 GType type
= G_VALUE_TYPE (v
);
125 /* guess the most used cases and handle those first */
126 if (type
== G_TYPE_STRING
) {
127 ret
= g_strdup (g_value_get_string (v
));
128 } else if (type
== G_TYPE_BOOLEAN
) {
129 ret
= g_strdup_printf ("%d", g_value_get_boolean (v
));
130 } else if (type
== G_TYPE_INT
) {
131 ret
= g_strdup_printf ("%d", g_value_get_int (v
));
132 } else if (type
== G_TYPE_FLOAT
) {
133 ret
= g_strdup_printf ("%f", g_value_get_float (v
));
134 } else if (type
== G_TYPE_DOUBLE
) {
135 char double_buff
[G_ASCII_DTOSTR_BUF_SIZE
];
136 ret
= g_ascii_dtostr (double_buff
, sizeof (double_buff
),
137 g_value_get_double (v
));
138 } else if (type
== G_TYPE_LONG
) {
139 ret
= g_strdup_printf ("%ld", g_value_get_long (v
));
140 } else if (type
== G_TYPE_INT64
) {
141 ret
= g_strdup_printf ("%lld", g_value_get_int64 (v
));
142 } else if (type
== G_TYPE_UINT
) {
143 ret
= g_strdup_printf ("%u", g_value_get_uint (v
));
144 } else if (type
== G_TYPE_ULONG
) {
145 ret
= g_strdup_printf ("%lu", g_value_get_ulong (v
));
146 } else if (type
== G_TYPE_UINT64
) {
147 ret
= g_strdup_printf ("%llu", g_value_get_uint64 (v
));
148 } else if (G_VALUE_HOLDS_CHAR (v
)) {
149 ret
= g_strdup_printf ("%c", g_value_get_char (v
));
150 } else if (G_VALUE_HOLDS_UCHAR (v
)) {
151 ret
= g_strdup_printf ("%c", g_value_get_uchar (v
));
153 g_warning ("Can't convert the value to string: unhandled type");
157 safe
= xmlCharStrdup (ret
);
160 res
= xmlTextWriterWriteElement (writer
, BAD_CAST ("value"), safe
);
163 set_value_error (res
, error
);
169 serialize_op (xmlTextWriterPtr writer
, MMComparisionOperator op
, GError
**error
)
174 for (idx
= 0; idx
< G_N_ELEMENTS (operator_grid
); idx
++) {
175 if (op
== operator_grid
[idx
].op
) {
176 str
= xmlCharStrdup (operator_grid
[idx
].string
);
181 res
= xmlTextWriterWriteElement (writer
, BAD_CAST ("op"), str
);
184 set_operator_error (res
, error
);
191 serialize_attribute (xmlTextWriterPtr writer
,
192 MMAttribute
*attribute
,
198 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("attribute"));
200 set_attribute_error (res
, error
);
204 safe_str
= xmlCharStrdup (mm_attribute_get_id (attribute
));
205 res
= xmlTextWriterWriteAttribute (writer
, BAD_CAST ("id"), safe_str
);
208 set_attribute_error (res
, error
);
212 safe_str
= xmlCharStrdup (mm_attribute_get_name (attribute
));
213 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("name"), safe_str
);
216 set_attribute_error (res
, error
);
220 safe_str
= xmlCharStrdup (mm_attribute_get_description (attribute
));
221 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("description"), safe_str
);
224 set_attribute_error (res
, error
);
228 res
= xmlTextWriterWriteAttribute (writer
, BAD_CAST ("type"),
229 BAD_CAST (g_type_name (mm_attribute_get_value_type (attribute
))));
231 set_attribute_error (res
, error
);
235 /* close "attribute" */
236 res
= xmlTextWriterEndElement (writer
);
238 set_attribute_error (res
, error
);
244 serialize_filter_param (MMFilterParam
*fp
,
247 MMAttribute
*attribute
;
249 MMComparisionOperator op
;
251 xmlTextWriterPtr writer
= data
->writer
;
252 GError
**error
= data
->error
;
254 attribute
= mm_filter_param_get_attribute (fp
);
255 val
= mm_filter_param_get_value (fp
);
256 op
= mm_filter_param_get_operator (fp
);
258 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("filter-param"));
260 set_filter_param_error (res
, error
);
264 serialize_attribute (writer
, attribute
, error
);
268 serialize_value (writer
, val
, error
);
272 serialize_op (writer
, op
, error
);
277 /* close "filter-param" */
278 res
= xmlTextWriterEndElement (writer
);
280 set_filter_param_error (res
, error
);
286 unserialize_operator (xmlTextReaderPtr reader
, MMComparisionOperator
*op
,
289 const xmlChar
* op_string
;
290 gboolean found
= FALSE
;
293 /* we should be on <op> */
294 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("op")) != 0) {
295 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
296 "Error while parsing the serialized xml opeator: the xml reader "
297 "does not point to a ComparisionOperator");
301 /* move on to the content */
302 res
= xmlTextReaderRead (reader
);
304 set_operator_error (res
, error
);
308 op_string
= xmlTextReaderConstValue (reader
);
309 for (idx
= 0; idx
< G_N_ELEMENTS (operator_grid
); idx
++) {
310 if (xmlStrcmp (op_string
, BAD_CAST (operator_grid
[idx
].string
)) == 0) {
317 res
= xmlTextReaderRead (reader
);
319 set_operator_error (res
, error
);
324 *op
= operator_grid
[idx
].op
;
329 unserialize_value (xmlTextReaderPtr reader
, GValue
*v
, GError
**error
)
333 const char *val_string
;
335 /* we should be on <value> */
336 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("value")) != 0) {
337 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
338 "Error while parsing the serialized xml value: the xml reader "
339 " does not point to a value");
343 /* move on to the content node */
344 res
= xmlTextReaderRead (reader
);
346 set_value_error (res
, error
);
350 type
= G_VALUE_TYPE (v
);
351 val_string
= (const char *) xmlTextReaderConstValue (reader
);
353 if (type
== G_TYPE_STRING
) {
354 g_value_set_string (v
, val_string
);
355 } else if (type
== G_TYPE_BOOLEAN
) {
357 sscanf (val_string
, "%d", &bval
);
358 g_value_set_boolean (v
, bval
);
359 } else if (type
== G_TYPE_INT
) {
361 sscanf (val_string
, "%d", &ival
);
362 g_value_set_int (v
, ival
);
363 } else if (type
== G_TYPE_FLOAT
) {
365 sscanf (val_string
, "%f", &fval
);
366 g_value_set_float (v
, fval
);
367 } else if (type
== G_TYPE_DOUBLE
) {
369 dval
= g_ascii_strtod (val_string
, NULL
);
370 g_value_set_double (v
, dval
);
371 } else if (type
== G_TYPE_LONG
) {
373 sscanf (val_string
, "%ld", &lval
);
374 g_value_set_long (v
, lval
);
375 } else if (type
== G_TYPE_INT64
) {
376 g_value_set_int64 (v
, g_ascii_strtoll (val_string
, NULL
, 0));
377 } else if (type
== G_TYPE_UINT
) {
379 sscanf (val_string
, "%u", &uval
);
380 g_value_set_uint (v
, uval
);
381 } else if (type
== G_TYPE_ULONG
) {
383 sscanf (val_string
, "%lu", &ulval
);
384 g_value_set_ulong (v
, ulval
);
385 } else if (type
== G_TYPE_UINT64
) {
386 g_value_set_uint64 (v
, g_ascii_strtoull (val_string
, NULL
, 0));
387 } else if (G_VALUE_HOLDS_CHAR (v
)) {
389 sscanf (val_string
, "%c", &cval
);
390 g_value_set_char (v
, cval
);
391 } else if (G_VALUE_HOLDS_UCHAR (v
)) {
393 sscanf (val_string
, "%c", &ucval
);
394 g_value_set_uchar (v
, ucval
);
396 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNKNOWN_GTYPE
,
397 "Can't convert the string to a value: unhandled type");
401 /* move over </value> */
402 res
= xmlTextReaderRead (reader
);
404 set_value_error (res
, error
);
412 unserialize_attribute (xmlTextReaderPtr reader
, MMAttribute
**attribute
, GError
**error
)
414 xmlChar
*id
, *name
, *desc
, *type_name
;
417 /* we should be on <attribute> */
418 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("attribute")) != 0) {
419 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
420 "Error while parsing the serialized xml attribute: the xml reader"
421 " does not point to an attribute.");
425 id
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("id"));
426 name
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("name"));
427 desc
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("desc"));
428 type_name
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("type"));
430 type
= g_type_from_name ((const char *) type_name
);
432 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNKNOWN_GTYPE
,
433 "Error while parsing the serialized xml attribute: cannot get a GType"
434 " for the name %s.", (const char *) type_name
);
438 *attribute
= mm_attribute_new (type
,
441 (const char *) desc
);
449 static MMFilterParam
*
450 unserialize_filter_param (xmlTextReaderPtr reader
, GError
**error
)
453 MMAttribute
*attribute
= NULL
;
454 MMComparisionOperator op
= MM_COMP_NONE
;
456 MMFilterParam
*fp
= NULL
;
458 res
= xmlTextReaderRead (reader
);
460 set_filter_param_error (res
, error
);
464 /* we're either on <attribute> or </filter-param> if the object is empty */
465 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
466 xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("filter-param")) == 0) && res
> 0) {
467 unserialize_attribute (reader
, &attribute
, error
);
472 res
= xmlTextReaderRead (reader
);
474 set_filter_param_error (res
, error
);
477 /* we're now on <value> */
478 val
= mm_create_gvalue_for_attribute (attribute
);
479 unserialize_value (reader
, val
, error
);
484 res
= xmlTextReaderRead (reader
);
486 set_filter_param_error (res
, error
);
489 /* we're now on <op> */
490 unserialize_operator (reader
, &op
, error
);
495 /* move after </op> */
496 res
= xmlTextReaderRead (reader
);
498 set_filter_param_error (res
, error
);
503 /* if we're here, everything in the unserialize sub-operations went well */
504 fp
= mm_filter_param_new (attribute
, val
, op
);
516 serialize_pair (MMAttribute
*attr
,
518 SerializeData
*pair_data
)
520 xmlTextWriterPtr writer
= pair_data
->writer
;
521 GError
**error
= pair_data
->error
;
525 /* an error occurred in a previous iteration of this function, don't do
531 xmlTextWriterStartElement (writer
, BAD_CAST ("pair"));
532 serialize_attribute (writer
, attr
, error
);
537 serialize_value (writer
, val
, error
);
543 res
= xmlTextWriterEndElement (writer
);
545 set_pair_error (res
, error
);
550 unserialize_hit (xmlTextReaderPtr reader
, GError
**error
)
553 MMAttribute
*attribute
= NULL
;
557 hit
= g_object_new (MM_TYPE_HIT
, NULL
);
561 res
= xmlTextReaderRead (reader
);
563 set_hit_error (res
, error
);
564 g_object_unref (hit
);
568 res
= xmlTextReaderRead (reader
);
569 /* now we should be on "attribute" */
571 set_hit_error (res
, error
);
572 g_object_unref (hit
);
576 unserialize_attribute (reader
, &attribute
, error
);
578 g_object_unref (hit
);
582 res
= xmlTextReaderRead (reader
);
583 /* we're now on "value" */
585 set_hit_error (res
, error
);
586 g_object_unref (hit
);
591 v
= mm_create_gvalue_for_attribute (attribute
);
592 unserialize_value (reader
, v
, error
);
594 g_object_unref (hit
);
599 mm_hit_set_value (hit
, attribute
, v
);
601 res
= xmlTextReaderRead (reader
);
602 /* now we're on </pair> */
604 set_hit_error (res
, error
);
605 g_object_unref (hit
);
610 res
= xmlTextReaderRead (reader
);
612 set_hit_error (res
, error
);
613 g_object_unref (hit
);
617 /* now we're either on <pair> again or </hit>. we must end they cycle
620 } while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
621 xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("hit"))));
626 /* public functions */
628 mm_filter_serialize (MMFilter
*filter
, GError
**error
)
630 char *serialized
= NULL
;
632 xmlTextWriterPtr writer
;
633 GList
*filter_params
;
634 SerializeData
*fp_data
;
637 buffer
= xmlBufferCreate ();
638 writer
= xmlNewTextWriterMemory (buffer
, 0);
640 res
= xmlTextWriterStartDocument (writer
, NULL
, NULL
, NULL
);
642 set_filter_error (res
, error
);
646 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("filter"));
648 set_filter_error (res
, error
);
652 filter_params
= mm_filter_get_filtering_params (filter
);
653 fp_data
= g_new0 (SerializeData
, 1);
654 fp_data
->writer
= writer
;
655 fp_data
->error
= error
;
656 g_list_foreach (filter_params
, (GFunc
) serialize_filter_param
, fp_data
);
663 res
= xmlTextWriterEndElement (writer
);
665 set_filter_error (res
, error
);
669 res
= xmlTextWriterEndDocument (writer
);
671 set_filter_error (res
, error
);
675 /* everything went well */
676 serialized
= g_strdup ((char *) xmlBufferContent (buffer
));
679 xmlFreeTextWriter (writer
);
680 xmlBufferFree (buffer
);
686 mm_hit_collection_serialize (MMHitCollection
*hc
, GError
**error
)
688 char *serialized
= NULL
;
691 xmlTextWriterPtr writer
;
693 GHashTable
*attrs_and_values
;
694 SerializeData
*pair_data
;
696 buffer
= xmlBufferCreate ();
697 writer
= xmlNewTextWriterMemory (buffer
, 0);
699 res
= xmlTextWriterStartDocument (writer
, NULL
, NULL
, NULL
);
701 set_hit_collection_error (res
, error
);
705 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("hit-collection"));
707 set_hit_collection_error (res
, error
);
711 while ((hit
= mm_hit_collection_get_next_hit (hc
)) != NULL
) {
712 res
= xmlTextWriterStartElement (writer
, BAD_CAST ("hit"));
714 set_hit_collection_error (res
, error
);
718 attrs_and_values
= mm_hit_get_all_values (hit
);
720 pair_data
= g_slice_new0 (SerializeData
);
721 pair_data
->writer
= writer
;
722 pair_data
->error
= error
;
724 g_hash_table_foreach (attrs_and_values
,
725 (GHFunc
) serialize_pair
,
727 g_slice_free (SerializeData
, pair_data
);
729 /* an error occurred somewhere in one of the sub-functions */
734 res
= xmlTextWriterEndElement (writer
);
736 set_hit_collection_error (res
, error
);
741 /* close "hit-collection" */
742 res
= xmlTextWriterEndElement (writer
);
744 set_hit_collection_error (res
, error
);
747 res
= xmlTextWriterEndDocument (writer
);
749 set_hit_collection_error (res
, error
);
753 /* it seems everything has gone well */
754 serialized
= g_strdup ((char *) xmlBufferContent (buffer
));
757 xmlFreeTextWriter (writer
);
758 xmlBufferFree (buffer
);
764 mm_filter_unserialize (const char *s
, GError
**error
)
768 xmlTextReaderPtr reader
;
770 const xmlChar
*node_name
;
772 reader
= xmlReaderForMemory (s
, strlen (s
), NULL
, NULL
, 0);
774 /* cut all the elements before <filter> */
776 res
= xmlTextReaderRead (reader
);
777 node_name
= xmlTextReaderConstName (reader
);
778 } while (xmlStrcmp (node_name
, BAD_CAST ("filter")) != 0);
780 /* do the error checking here and not in each iteration of the cycle */
782 set_filter_error (res
, error
);
786 res
= xmlTextReaderRead (reader
);
787 node_name
= xmlTextReaderConstName (reader
);
788 f
= mm_filter_new ();
790 /* we're either on the first <filter-param> or on </filter> if the
791 * object is empty. cycle until we're on </filter>.
793 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
794 xmlStrcmp (node_name
, BAD_CAST ("filter")) == 0) && res
> 0) {
795 fp
= unserialize_filter_param (reader
, error
);
801 mm_filter_add_filtering_param (f
, fp
);
803 res
= xmlTextReaderRead (reader
);
804 node_name
= xmlTextReaderConstName (reader
);
808 /* do not return an incomplete filter */
809 set_filter_error (res
, error
);
815 xmlFreeTextReader (reader
);
821 mm_hit_collection_unserialize (const char *s
, GError
**error
)
823 MMHitCollection
*hc
= NULL
;
825 xmlTextReaderPtr reader
;
827 const xmlChar
*node_name
;
829 reader
= xmlReaderForMemory (s
, strlen (s
), NULL
, NULL
, 0);
831 /* cut all the elements before <hit-collection> */
833 res
= xmlTextReaderRead (reader
);
834 node_name
= xmlTextReaderConstName (reader
);
835 } while (xmlStrcmp (node_name
, BAD_CAST ("hit-collection")) != 0);
837 /* check for errors before <hit-collection> all at once, and not
838 * in every iteration of the cycle.
841 set_hit_collection_error (res
, error
);
845 hc
= mm_hit_collection_new ();
846 res
= xmlTextReaderRead (reader
);
847 node_name
= xmlTextReaderConstName (reader
);
849 /* we're either on the first <hit> or on </hit-collection> if the
850 * object is empty. cycle until we're at the end of file.
852 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
853 xmlStrcmp (node_name
, BAD_CAST ("hit-collection")) == 0) && res
> 0) {
854 hit
= unserialize_hit (reader
, error
);
856 /* do not return an incomplete HitCollection */
861 mm_hit_collection_add_hit (hc
, hit
);
862 g_object_unref (hit
);
863 res
= xmlTextReaderRead (reader
);
864 node_name
= xmlTextReaderConstName (reader
);
868 /* do not return an incomplete HitCollection */
869 set_hit_collection_error (res
, error
);
876 xmlFreeTextReader (reader
);