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
;
36 static OperatorGrid operator_grid
[] =
38 { MM_COMP_EQUAL
, "EQ" },
39 { MM_COMP_GREATER
, "GR" },
40 { MM_COMP_GREATER_EQUAL
, "GRQ" },
41 { MM_COMP_LESS
, "LS" },
42 { MM_COMP_LESS_EQUAL
, "LSQ" },
47 set_error (int res
, GError
**error
, const char *obj_name
)
49 xmlErrorPtr xml_error
;
52 xml_error
= xmlGetLastError ();
53 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNSERIALIZE_FAILED
,
54 "Error while parsing the serialized xml %s: %s",
55 obj_name
, (xml_error
!= NULL
) ? (xml_error
->message
) : "");
56 } else if (res
== 0) {
57 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_EOF
,
58 "Error while parsing the serialized xml %s: unexpected "
59 "end of the xml buffer.", obj_name
);
64 set_hit_error (int res
, GError
**error
)
66 set_error (res
, error
, "Hit");
70 set_hit_collection_error (int res
, GError
**error
)
72 set_error (res
, error
, "HitCollection");
76 set_value_error (int res
, GError
**error
)
78 set_error (res
, error
, "Value");
82 set_filter_param_error (int res
, GError
**error
)
84 set_error (res
, error
, "FilterParam");
88 set_operator_error (int res
, GError
**error
)
90 set_error (res
, error
, "ComparisionOperator");
94 set_filter_error (int res
, GError
**error
)
96 set_error (res
, error
, "Filter");
100 serialize_value (xmlTextWriterPtr writer
, GValue
*v
)
104 GType type
= G_VALUE_TYPE (v
);
106 /* guess the most used cases and handle those first */
107 if (type
== G_TYPE_STRING
) {
108 ret
= g_strdup (g_value_get_string (v
));
109 } else if (type
== G_TYPE_BOOLEAN
) {
110 ret
= g_strdup_printf ("%d", g_value_get_boolean (v
));
111 } else if (type
== G_TYPE_INT
) {
112 ret
= g_strdup_printf ("%d", g_value_get_int (v
));
113 } else if (type
== G_TYPE_FLOAT
) {
114 ret
= g_strdup_printf ("%f", g_value_get_float (v
));
115 } else if (type
== G_TYPE_DOUBLE
) {
116 char double_buff
[G_ASCII_DTOSTR_BUF_SIZE
];
117 ret
= g_ascii_dtostr (double_buff
, sizeof (double_buff
),
118 g_value_get_double (v
));
119 } else if (type
== G_TYPE_LONG
) {
120 ret
= g_strdup_printf ("%ld", g_value_get_long (v
));
121 } else if (type
== G_TYPE_INT64
) {
122 ret
= g_strdup_printf ("%lld", g_value_get_int64 (v
));
123 } else if (type
== G_TYPE_UINT
) {
124 ret
= g_strdup_printf ("%u", g_value_get_uint (v
));
125 } else if (type
== G_TYPE_ULONG
) {
126 ret
= g_strdup_printf ("%lu", g_value_get_ulong (v
));
127 } else if (type
== G_TYPE_UINT64
) {
128 ret
= g_strdup_printf ("%llu", g_value_get_uint64 (v
));
129 } else if (G_VALUE_HOLDS_CHAR (v
)) {
130 ret
= g_strdup_printf ("%c", g_value_get_char (v
));
131 } else if (G_VALUE_HOLDS_UCHAR (v
)) {
132 ret
= g_strdup_printf ("%c", g_value_get_uchar (v
));
134 g_warning ("Can't convert the value to string: unhandled type");
138 safe
= xmlCharStrdup (ret
);
141 xmlTextWriterWriteElement (writer
, BAD_CAST ("value"), safe
);
146 serialize_op (xmlTextWriterPtr writer
, MMComparisionOperator op
)
151 for (idx
= 0; idx
< G_N_ELEMENTS (operator_grid
); idx
++) {
152 if (op
== operator_grid
[idx
].op
) {
153 str
= xmlCharStrdup (operator_grid
[idx
].string
);
158 xmlTextWriterWriteElement (writer
, BAD_CAST ("op"), str
);
164 serialize_attribute (xmlTextWriterPtr writer
,
165 MMAttribute
*attribute
)
169 xmlTextWriterStartElement (writer
, BAD_CAST ("attribute"));
170 safe_str
= xmlCharStrdup (mm_attribute_get_id (attribute
));
171 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("id"), safe_str
);
173 safe_str
= xmlCharStrdup (mm_attribute_get_name (attribute
));
174 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("name"), safe_str
);
176 safe_str
= xmlCharStrdup (mm_attribute_get_description (attribute
));
177 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("description"), safe_str
);
179 xmlTextWriterWriteAttribute (writer
, BAD_CAST ("type"), BAD_CAST (g_type_name (mm_attribute_get_value_type (attribute
))));
180 /* close "attribute" */
181 xmlTextWriterEndElement (writer
);
185 add_filter_param_to_xml (MMFilterParam
*fp
,
186 xmlTextWriterPtr writer
)
188 MMAttribute
*attribute
;
190 MMComparisionOperator op
;
192 attribute
= mm_filter_param_get_attribute (fp
);
193 val
= mm_filter_param_get_value (fp
);
194 op
= mm_filter_param_get_operator (fp
);
196 xmlTextWriterStartElement (writer
, BAD_CAST ("filter-param"));
198 serialize_attribute (writer
, attribute
);
199 serialize_value (writer
, val
);
200 serialize_op (writer
, op
);
202 /* close "filter-param" */
203 xmlTextWriterEndElement (writer
);
207 unserialize_operator (xmlTextReaderPtr reader
, MMComparisionOperator
*op
,
210 const xmlChar
* op_string
;
211 gboolean found
= FALSE
;
214 /* we should be on <op> */
215 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("op")) != 0) {
216 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
217 "Error while parsing the serialized xml opeator: the xml reader "
218 "does not point to a ComparisionOperator");
222 /* move on to the content */
223 res
= xmlTextReaderRead (reader
);
225 set_operator_error (res
, error
);
229 op_string
= xmlTextReaderConstValue (reader
);
230 for (idx
= 0; idx
< G_N_ELEMENTS (operator_grid
); idx
++) {
231 if (xmlStrcmp (op_string
, BAD_CAST (operator_grid
[idx
].string
)) == 0) {
238 res
= xmlTextReaderRead (reader
);
240 set_operator_error (res
, error
);
245 *op
= operator_grid
[idx
].op
;
250 unserialize_value (xmlTextReaderPtr reader
, GValue
*v
, GError
**error
)
254 const char *val_string
;
256 /* we should be on <value> */
257 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("value")) != 0) {
258 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
259 "Error while parsing the serialized xml value: the xml reader "
260 " does not point to a value");
264 /* move on to the content node */
265 res
= xmlTextReaderRead (reader
);
267 set_value_error (res
, error
);
271 type
= G_VALUE_TYPE (v
);
272 val_string
= (const char *) xmlTextReaderConstValue (reader
);
274 if (type
== G_TYPE_STRING
) {
275 g_value_set_string (v
, val_string
);
276 } else if (type
== G_TYPE_BOOLEAN
) {
278 sscanf (val_string
, "%d", &bval
);
279 g_value_set_boolean (v
, bval
);
280 } else if (type
== G_TYPE_INT
) {
282 sscanf (val_string
, "%d", &ival
);
283 g_value_set_int (v
, ival
);
284 } else if (type
== G_TYPE_FLOAT
) {
286 sscanf (val_string
, "%f", &fval
);
287 g_value_set_float (v
, fval
);
288 } else if (type
== G_TYPE_DOUBLE
) {
290 dval
= g_ascii_strtod (val_string
, NULL
);
291 g_value_set_double (v
, dval
);
292 } else if (type
== G_TYPE_LONG
) {
294 sscanf (val_string
, "%ld", &lval
);
295 g_value_set_long (v
, lval
);
296 } else if (type
== G_TYPE_INT64
) {
297 g_value_set_int64 (v
, g_ascii_strtoll (val_string
, NULL
, 0));
298 } else if (type
== G_TYPE_UINT
) {
300 sscanf (val_string
, "%u", &uval
);
301 g_value_set_uint (v
, uval
);
302 } else if (type
== G_TYPE_ULONG
) {
304 sscanf (val_string
, "%lu", &ulval
);
305 g_value_set_ulong (v
, ulval
);
306 } else if (type
== G_TYPE_UINT64
) {
307 g_value_set_uint64 (v
, g_ascii_strtoull (val_string
, NULL
, 0));
308 } else if (G_VALUE_HOLDS_CHAR (v
)) {
310 sscanf (val_string
, "%c", &cval
);
311 g_value_set_char (v
, cval
);
312 } else if (G_VALUE_HOLDS_UCHAR (v
)) {
314 sscanf (val_string
, "%c", &ucval
);
315 g_value_set_uchar (v
, ucval
);
317 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNKNOWN_GTYPE
,
318 "Can't convert the string to a value: unhandled type");
322 /* move over </value> */
323 res
= xmlTextReaderRead (reader
);
325 set_value_error (res
, error
);
333 unserialize_attribute (xmlTextReaderPtr reader
, MMAttribute
**attribute
, GError
**error
)
335 xmlChar
*id
, *name
, *desc
, *type_name
;
338 /* we should be on <attribute> */
339 if (xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("attribute")) != 0) {
340 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNEXPECTED_NODE
,
341 "Error while parsing the serialized xml attribute: the xml reader"
342 " does not point to an attribute.");
346 id
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("id"));
347 name
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("name"));
348 desc
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("desc"));
349 type_name
= xmlTextReaderGetAttribute (reader
, BAD_CAST ("type"));
351 type
= g_type_from_name ((const char *) type_name
);
353 g_set_error (error
, MM_XML_ERROR_QUARK
, MM_XML_ERROR_UNKNOWN_GTYPE
,
354 "Error while parsing the serialized xml attribute: cannot get a GType"
355 " for the name %s.", (const char *) type_name
);
359 *attribute
= mm_attribute_new (type
,
362 (const char *) desc
);
370 static MMFilterParam
*
371 unserialize_filter_param (xmlTextReaderPtr reader
, GError
**error
)
374 MMAttribute
*attribute
= NULL
;
375 MMComparisionOperator op
= MM_COMP_NONE
;
377 MMFilterParam
*fp
= NULL
;
379 res
= xmlTextReaderRead (reader
);
381 set_filter_param_error (res
, error
);
385 /* we're either on <attribute> or </filter-param> if the object is empty */
386 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
387 xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("filter-param")) == 0) && res
> 0) {
388 unserialize_attribute (reader
, &attribute
, error
);
393 res
= xmlTextReaderRead (reader
);
395 set_filter_param_error (res
, error
);
398 /* we're now on <value> */
399 val
= mm_create_gvalue_for_attribute (attribute
);
400 unserialize_value (reader
, val
, error
);
405 res
= xmlTextReaderRead (reader
);
407 set_filter_param_error (res
, error
);
410 /* we're now on <op> */
411 unserialize_operator (reader
, &op
, error
);
416 /* move after </op> */
417 res
= xmlTextReaderRead (reader
);
419 set_filter_param_error (res
, error
);
424 /* if we're here, everything in the unserialize sub-operations went well */
425 fp
= mm_filter_param_new (attribute
, val
, op
);
437 serialize_pair (gpointer _attr
,
441 MMAttribute
*attr
= _attr
;
443 xmlTextWriterPtr writer
= _writer
;
445 xmlTextWriterStartElement (writer
, BAD_CAST ("pair"));
446 serialize_attribute (writer
, attr
);
447 serialize_value (writer
, val
);
450 xmlTextWriterEndElement (writer
);
454 unserialize_hit (xmlTextReaderPtr reader
, GError
**error
)
457 MMAttribute
*attribute
= NULL
;
461 hit
= g_object_new (MM_TYPE_HIT
, NULL
);
465 res
= xmlTextReaderRead (reader
);
467 set_hit_error (res
, error
);
468 g_object_unref (hit
);
472 res
= xmlTextReaderRead (reader
);
473 /* now we should be on "attribute" */
475 set_hit_error (res
, error
);
476 g_object_unref (hit
);
480 unserialize_attribute (reader
, &attribute
, error
);
482 g_object_unref (hit
);
486 res
= xmlTextReaderRead (reader
);
487 /* we're now on "value" */
489 set_hit_error (res
, error
);
490 g_object_unref (hit
);
495 v
= mm_create_gvalue_for_attribute (attribute
);
496 unserialize_value (reader
, v
, error
);
498 g_object_unref (hit
);
503 mm_hit_set_value (hit
, attribute
, v
);
505 res
= xmlTextReaderRead (reader
);
506 /* now we're on </pair> */
508 set_hit_error (res
, error
);
509 g_object_unref (hit
);
514 res
= xmlTextReaderRead (reader
);
516 set_hit_error (res
, error
);
517 g_object_unref (hit
);
521 /* now we're either on <pair> again or </hit>. we must end they cycle
524 } while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
525 xmlStrcmp (xmlTextReaderConstName (reader
), BAD_CAST ("hit"))));
530 /* public functions */
532 mm_filter_serialize (MMFilter
*filter
)
536 xmlTextWriterPtr writer
;
537 GList
*filter_params
;
539 buffer
= xmlBufferCreate ();
540 writer
= xmlNewTextWriterMemory (buffer
, 0);
542 xmlTextWriterStartDocument (writer
, NULL
, NULL
, NULL
);
544 xmlTextWriterStartElement (writer
, BAD_CAST ("filter"));
545 filter_params
= mm_filter_get_filtering_params (filter
);
546 g_list_foreach (filter_params
, (GFunc
) add_filter_param_to_xml
, writer
);
548 xmlTextWriterEndElement (writer
);
550 xmlTextWriterEndDocument (writer
);
552 xmlFreeTextWriter (writer
);
553 serialized
= g_strdup ((char *) xmlBufferContent (buffer
));
554 xmlBufferFree (buffer
);
560 mm_hit_collection_serialize (MMHitCollection
*hc
)
564 xmlTextWriterPtr writer
;
566 GHashTable
*attrs_and_values
;
568 buffer
= xmlBufferCreate ();
569 writer
= xmlNewTextWriterMemory (buffer
, 0);
571 xmlTextWriterStartDocument (writer
, NULL
, NULL
, NULL
);
573 xmlTextWriterStartElement (writer
, BAD_CAST ("hit-collection"));
574 while ((hit
= mm_hit_collection_get_next_hit (hc
)) != NULL
) {
575 xmlTextWriterStartElement (writer
, BAD_CAST ("hit"));
576 attrs_and_values
= mm_hit_get_all_values (hit
);
577 g_hash_table_foreach (attrs_and_values
,
578 (GHFunc
) serialize_pair
,
581 xmlTextWriterEndElement (writer
);
584 /* close "hit-collection" */
585 xmlTextWriterEndElement (writer
);
586 xmlTextWriterEndDocument (writer
);
588 xmlFreeTextWriter (writer
);
589 serialized
= g_strdup ((char *) xmlBufferContent (buffer
));
590 xmlBufferFree (buffer
);
596 mm_filter_unserialize (const char *s
, GError
**error
)
600 xmlTextReaderPtr reader
;
602 const xmlChar
*node_name
;
604 reader
= xmlReaderForMemory (s
, strlen (s
), NULL
, NULL
, 0);
606 /* cut all the elements before <filter> */
608 res
= xmlTextReaderRead (reader
);
609 node_name
= xmlTextReaderConstName (reader
);
610 } while (xmlStrcmp (node_name
, BAD_CAST ("filter")) != 0);
612 /* do the error checking here and not in each iteration of the cycle */
614 set_filter_error (res
, error
);
618 res
= xmlTextReaderRead (reader
);
619 node_name
= xmlTextReaderConstName (reader
);
620 f
= mm_filter_new ();
622 /* we're either on the first <filter-param> or on </filter> if the
623 * object is empty. cycle until we're on </filter>.
625 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
626 xmlStrcmp (node_name
, BAD_CAST ("filter")) == 0) && res
> 0) {
627 fp
= unserialize_filter_param (reader
, error
);
633 mm_filter_add_filtering_param (f
, fp
);
635 res
= xmlTextReaderRead (reader
);
636 node_name
= xmlTextReaderConstName (reader
);
640 /* do not return an incomplete filter */
641 set_filter_error (res
, error
);
647 xmlFreeTextReader (reader
);
653 mm_hit_collection_unserialize (const char *s
, GError
**error
)
655 MMHitCollection
*hc
= NULL
;
657 xmlTextReaderPtr reader
;
659 const xmlChar
*node_name
;
661 reader
= xmlReaderForMemory (s
, strlen (s
), NULL
, NULL
, 0);
663 /* cut all the elements before <hit-collection> */
665 res
= xmlTextReaderRead (reader
);
666 node_name
= xmlTextReaderConstName (reader
);
667 } while (xmlStrcmp (node_name
, BAD_CAST ("hit-collection")) != 0);
669 /* check for errors before <hit-collection> all at once, and not
670 * in every iteration of the cycle.
673 set_hit_collection_error (res
, error
);
677 hc
= mm_hit_collection_new ();
678 res
= xmlTextReaderRead (reader
);
679 node_name
= xmlTextReaderConstName (reader
);
681 /* we're either on the first <hit> or on </hit-collection> if the
682 * object is empty. cycle until we're at the end of file.
684 while (!((xmlTextReaderNodeType (reader
) == XML_READER_TYPE_END_ELEMENT
) &&
685 xmlStrcmp (node_name
, BAD_CAST ("hit-collection")) == 0) && res
> 0) {
686 hit
= unserialize_hit (reader
, error
);
688 /* do not return an incomplete HitCollection */
693 mm_hit_collection_add_hit (hc
, hit
);
694 g_object_unref (hit
);
695 res
= xmlTextReaderRead (reader
);
696 node_name
= xmlTextReaderConstName (reader
);
700 /* do not return an incomplete HitCollection */
701 set_hit_collection_error (res
, error
);
708 xmlFreeTextReader (reader
);