Add interface for the DBus module.
[mmediamanager.git] / src / mm-string-utils.c
blob4b2c5514d98ca99e1d38391a33a304e4b7cc1f35
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.
21 #include <glib.h>
22 #include <string.h>
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"
28 #include "mm-utils.h"
29 #include "mm-hit.h"
30 #include "mm-error.h"
32 typedef struct {
33 MMComparisionOperator op;
34 const char *string;
35 } OperatorGrid;
37 typedef struct {
38 xmlTextWriterPtr writer;
39 GError **error;
40 } SerializeData;
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" },
49 { MM_COMP_NONE, "" }
52 static void
53 set_error (int res, GError **error, const char *obj_name)
55 xmlErrorPtr xml_error;
57 if (res == -1) {
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);
69 static void
70 set_hit_error (int res, GError **error)
72 set_error (res, error, "Hit");
75 static void
76 set_hit_collection_error (int res, GError **error)
78 set_error (res, error, "HitCollection");
81 static void
82 set_value_error (int res, GError **error)
84 set_error (res, error, "Value");
87 static void
88 set_filter_param_error (int res, GError **error)
90 set_error (res, error, "FilterParam");
93 static void
94 set_operator_error (int res, GError **error)
96 set_error (res, error, "ComparisionOperator");
99 static void
100 set_filter_error (int res, GError **error)
102 set_error (res, error, "Filter");
105 static void
106 set_pair_error (int res, GError **error)
108 set_error (res, error, "Pair");
111 static void
112 set_attribute_error (int res, GError **error)
114 set_error (res, error, "Attribute");
117 static void
118 serialize_value (xmlTextWriterPtr writer, GValue *v, GError **error)
120 xmlChar *safe;
121 int res;
122 char *ret = NULL;
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));
152 } else {
153 g_warning ("Can't convert the value to string: unhandled type");
154 return;
157 safe = xmlCharStrdup (ret);
158 g_free (ret);
160 res = xmlTextWriterWriteElement (writer, BAD_CAST ("value"), safe);
161 g_free (safe);
162 if (res == -1) {
163 set_value_error (res, error);
164 return;
168 static void
169 serialize_op (xmlTextWriterPtr writer, MMComparisionOperator op, GError **error)
171 int idx, res;
172 xmlChar *str = NULL;
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);
180 if (str) {
181 res = xmlTextWriterWriteElement (writer, BAD_CAST ("op"), str);
182 g_free (str);
183 if (res == -1) {
184 set_operator_error (res, error);
185 return;
190 static void
191 serialize_attribute (xmlTextWriterPtr writer,
192 MMAttribute *attribute,
193 GError **error)
195 xmlChar *safe_str;
196 int res;
198 res = xmlTextWriterStartElement (writer, BAD_CAST ("attribute"));
199 if (res == -1) {
200 set_attribute_error (res, error);
201 return;
204 safe_str = xmlCharStrdup (mm_attribute_get_id (attribute));
205 res = xmlTextWriterWriteAttribute (writer, BAD_CAST ("id"), safe_str);
206 g_free (safe_str);
207 if (res == -1) {
208 set_attribute_error (res, error);
209 return;
212 safe_str = xmlCharStrdup (mm_attribute_get_name (attribute));
213 xmlTextWriterWriteAttribute (writer, BAD_CAST ("name"), safe_str);
214 g_free (safe_str);
215 if (res == -1) {
216 set_attribute_error (res, error);
217 return;
220 safe_str = xmlCharStrdup (mm_attribute_get_description (attribute));
221 xmlTextWriterWriteAttribute (writer, BAD_CAST ("description"), safe_str);
222 g_free (safe_str);
223 if (res == -1) {
224 set_attribute_error (res, error);
225 return;
228 res = xmlTextWriterWriteAttribute (writer, BAD_CAST ("type"),
229 BAD_CAST (g_type_name (mm_attribute_get_value_type (attribute))));
230 if (res == -1) {
231 set_attribute_error (res, error);
232 return;
235 /* close "attribute" */
236 res = xmlTextWriterEndElement (writer);
237 if (res == -1) {
238 set_attribute_error (res, error);
239 return;
243 static void
244 serialize_filter_param (MMFilterParam *fp,
245 SerializeData *data)
247 MMAttribute *attribute;
248 GValue *val;
249 MMComparisionOperator op;
250 int res;
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"));
259 if (res == -1) {
260 set_filter_param_error (res, error);
261 return;
264 serialize_attribute (writer, attribute, error);
265 if (*error) {
266 return;
268 serialize_value (writer, val, error);
269 if (*error) {
270 return;
272 serialize_op (writer, op, error);
273 if (*error) {
274 return;
277 /* close "filter-param" */
278 res = xmlTextWriterEndElement (writer);
279 if (res == -1) {
280 set_filter_param_error (res, error);
281 return;
285 static void
286 unserialize_operator (xmlTextReaderPtr reader, MMComparisionOperator *op,
287 GError **error)
289 const xmlChar * op_string;
290 gboolean found = FALSE;
291 int idx, res;
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");
298 return;
301 /* move on to the content */
302 res = xmlTextReaderRead (reader);
303 if (res <= 0) {
304 set_operator_error (res, error);
305 return;
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) {
311 found = TRUE;
312 break;
316 /* move to </op> */
317 res = xmlTextReaderRead (reader);
318 if (res <= 0) {
319 set_operator_error (res, error);
320 return;
323 if (found) {
324 *op = operator_grid[idx].op;
328 static void
329 unserialize_value (xmlTextReaderPtr reader, GValue *v, GError **error)
331 int res;
332 GType type;
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");
340 return;
343 /* move on to the content node */
344 res = xmlTextReaderRead (reader);
345 if (res <= 0) {
346 set_value_error (res, error);
347 return;
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) {
356 gboolean bval;
357 sscanf (val_string, "%d", &bval);
358 g_value_set_boolean (v, bval);
359 } else if (type == G_TYPE_INT) {
360 gint ival;
361 sscanf (val_string, "%d", &ival);
362 g_value_set_int (v, ival);
363 } else if (type == G_TYPE_FLOAT) {
364 gfloat fval;
365 sscanf (val_string, "%f", &fval);
366 g_value_set_float (v, fval);
367 } else if (type == G_TYPE_DOUBLE) {
368 gdouble dval;
369 dval = g_ascii_strtod (val_string, NULL);
370 g_value_set_double (v, dval);
371 } else if (type == G_TYPE_LONG) {
372 glong lval;
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) {
378 guint uval;
379 sscanf (val_string, "%u", &uval);
380 g_value_set_uint (v, uval);
381 } else if (type == G_TYPE_ULONG) {
382 gulong ulval;
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)) {
388 gchar cval;
389 sscanf (val_string, "%c", &cval);
390 g_value_set_char (v, cval);
391 } else if (G_VALUE_HOLDS_UCHAR (v)) {
392 guchar ucval;
393 sscanf (val_string, "%c", &ucval);
394 g_value_set_uchar (v, ucval);
395 } else {
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");
398 return;
401 /* move over </value> */
402 res = xmlTextReaderRead (reader);
403 if (res <= 0) {
404 set_value_error (res, error);
405 g_value_unset (v);
406 g_free (v);
407 v = NULL;
411 static void
412 unserialize_attribute (xmlTextReaderPtr reader, MMAttribute **attribute, GError **error)
414 xmlChar *id, *name, *desc, *type_name;
415 GType type;
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.");
422 return;
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);
431 if (type == 0) {
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);
435 goto out;
438 *attribute = mm_attribute_new (type,
439 (const char *) id,
440 (const char *) name,
441 (const char *) desc);
442 out:
443 g_free (id);
444 g_free (name);
445 g_free (desc);
446 g_free (type_name);
449 static MMFilterParam *
450 unserialize_filter_param (xmlTextReaderPtr reader, GError **error)
452 int res;
453 MMAttribute *attribute = NULL;
454 MMComparisionOperator op = MM_COMP_NONE;
455 GValue *val = NULL;
456 MMFilterParam *fp = NULL;
458 res = xmlTextReaderRead (reader);
459 if (res <= 0) {
460 set_filter_param_error (res, error);
461 goto out;
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);
468 if (*error) {
469 goto out;
472 res = xmlTextReaderRead (reader);
473 if (res <= 0) {
474 set_filter_param_error (res, error);
475 goto out;
477 /* we're now on <value> */
478 val = mm_create_gvalue_for_attribute (attribute);
479 unserialize_value (reader, val, error);
480 if (*error) {
481 goto out;
484 res = xmlTextReaderRead (reader);
485 if (res <= 0) {
486 set_filter_param_error (res, error);
487 goto out;
489 /* we're now on <op> */
490 unserialize_operator (reader, &op, error);
491 if (*error) {
492 goto out;
495 /* move after </op> */
496 res = xmlTextReaderRead (reader);
497 if (res <= 0) {
498 set_filter_param_error (res, error);
499 goto out;
503 /* if we're here, everything in the unserialize sub-operations went well */
504 fp = mm_filter_param_new (attribute, val, op);
506 out:
507 if (val) {
508 g_value_unset (val);
509 g_free (val);
512 return fp;
515 static void
516 serialize_pair (MMAttribute *attr,
517 GValue *val,
518 SerializeData *pair_data)
520 xmlTextWriterPtr writer = pair_data->writer;
521 GError **error = pair_data->error;
522 int res;
524 if (*error) {
525 /* an error occurred in a previous iteration of this function, don't do
526 * anything.
528 return;
531 xmlTextWriterStartElement (writer, BAD_CAST ("pair"));
532 serialize_attribute (writer, attr, error);
533 if (*error) {
534 return;
537 serialize_value (writer, val, error);
538 if (*error) {
539 return;
542 /* end "pair" */
543 res = xmlTextWriterEndElement (writer);
544 if (res == -1) {
545 set_pair_error (res, error);
549 static MMHit *
550 unserialize_hit (xmlTextReaderPtr reader, GError **error)
552 int res;
553 MMAttribute *attribute = NULL;
554 GValue *v;
555 MMHit *hit = NULL;
557 hit = g_object_new (MM_TYPE_HIT, NULL);
559 do {
560 /* skip <pair> */
561 res = xmlTextReaderRead (reader);
562 if (res <= 0) {
563 set_hit_error (res, error);
564 g_object_unref (hit);
565 hit = NULL;
566 break;
568 res = xmlTextReaderRead (reader);
569 /* now we should be on "attribute" */
570 if (res <= 0) {
571 set_hit_error (res, error);
572 g_object_unref (hit);
573 hit = NULL;
574 break;
576 unserialize_attribute (reader, &attribute, error);
577 if (*error) {
578 g_object_unref (hit);
579 hit = NULL;
580 break;
582 res = xmlTextReaderRead (reader);
583 /* we're now on "value" */
584 if (res <= 0) {
585 set_hit_error (res, error);
586 g_object_unref (hit);
587 hit = NULL;
588 break;
591 v = mm_create_gvalue_for_attribute (attribute);
592 unserialize_value (reader, v, error);
593 if (*error) {
594 g_object_unref (hit);
595 hit = NULL;
596 break;
599 mm_hit_set_value (hit, attribute, v);
601 res = xmlTextReaderRead (reader);
602 /* now we're on </pair> */
603 if (res <= 0) {
604 set_hit_error (res, error);
605 g_object_unref (hit);
606 hit = NULL;
607 break;
610 res = xmlTextReaderRead (reader);
611 if (res <= 0) {
612 set_hit_error (res, error);
613 g_object_unref (hit);
614 hit = NULL;
615 break;
617 /* now we're either on <pair> again or </hit>. we must end they cycle
618 * on </hit>.
620 } while (!((xmlTextReaderNodeType (reader) == XML_READER_TYPE_END_ELEMENT) &&
621 xmlStrcmp (xmlTextReaderConstName (reader), BAD_CAST ("hit"))));
623 return hit;
626 /* public functions */
627 char *
628 mm_filter_serialize (MMFilter *filter, GError **error)
630 char *serialized = NULL;
631 xmlBufferPtr buffer;
632 xmlTextWriterPtr writer;
633 GList *filter_params;
634 SerializeData *fp_data;
635 int res;
637 buffer = xmlBufferCreate ();
638 writer = xmlNewTextWriterMemory (buffer, 0);
640 res = xmlTextWriterStartDocument (writer, NULL, NULL, NULL);
641 if (res == -1) {
642 set_filter_error (res, error);
643 goto out;
646 res = xmlTextWriterStartElement (writer, BAD_CAST ("filter"));
647 if (res == -1) {
648 set_filter_error (res, error);
649 goto out;
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);
657 g_free (fp_data);
658 if (*error) {
659 goto out;
662 /* close "filter" */
663 res = xmlTextWriterEndElement (writer);
664 if (res == -1) {
665 set_filter_error (res, error);
666 goto out;
669 res = xmlTextWriterEndDocument (writer);
670 if (res == -1) {
671 set_filter_error (res, error);
672 goto out;
675 /* everything went well */
676 serialized = g_strdup ((char *) xmlBufferContent (buffer));
678 out:
679 xmlFreeTextWriter (writer);
680 xmlBufferFree (buffer);
682 return serialized;
685 char *
686 mm_hit_collection_serialize (MMHitCollection *hc, GError **error)
688 char *serialized = NULL;
689 int res;
690 xmlBufferPtr buffer;
691 xmlTextWriterPtr writer;
692 MMHit *hit;
693 GHashTable *attrs_and_values;
694 SerializeData *pair_data;
696 buffer = xmlBufferCreate ();
697 writer = xmlNewTextWriterMemory (buffer, 0);
699 res = xmlTextWriterStartDocument (writer, NULL, NULL, NULL);
700 if (res == -1) {
701 set_hit_collection_error (res, error);
702 goto out;
705 res = xmlTextWriterStartElement (writer, BAD_CAST ("hit-collection"));
706 if (res == -1) {
707 set_hit_collection_error (res, error);
708 goto out;
711 while ((hit = mm_hit_collection_get_next_hit (hc)) != NULL) {
712 res = xmlTextWriterStartElement (writer, BAD_CAST ("hit"));
713 if (res == -1) {
714 set_hit_collection_error (res, error);
715 goto out;
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,
726 pair_data);
727 g_slice_free (SerializeData, pair_data);
728 if (*error) {
729 /* an error occurred somewhere in one of the sub-functions */
730 goto out;
733 /* close "hit" */
734 res = xmlTextWriterEndElement (writer);
735 if (res == -1) {
736 set_hit_collection_error (res, error);
737 goto out;
741 /* close "hit-collection" */
742 res = xmlTextWriterEndElement (writer);
743 if (res == -1) {
744 set_hit_collection_error (res, error);
745 goto out;
747 res = xmlTextWriterEndDocument (writer);
748 if (res == -1) {
749 set_hit_collection_error (res, error);
750 goto out;
753 /* it seems everything has gone well */
754 serialized = g_strdup ((char *) xmlBufferContent (buffer));
756 out:
757 xmlFreeTextWriter (writer);
758 xmlBufferFree (buffer);
760 return serialized;
763 MMFilter *
764 mm_filter_unserialize (const char *s, GError **error)
766 MMFilter *f = NULL;
767 MMFilterParam *fp;
768 xmlTextReaderPtr reader;
769 int res;
770 const xmlChar *node_name;
772 reader = xmlReaderForMemory (s, strlen (s), NULL, NULL, 0);
774 /* cut all the elements before <filter> */
775 do {
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 */
781 if (res <= 0) {
782 set_filter_error (res, error);
783 goto out;
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);
796 if (*error) {
797 g_object_unref (f);
798 f = NULL;
799 goto out;
801 mm_filter_add_filtering_param (f, fp);
802 g_object_unref (fp);
803 res = xmlTextReaderRead (reader);
804 node_name = xmlTextReaderConstName (reader);
807 if (res <= 0) {
808 /* do not return an incomplete filter */
809 set_filter_error (res, error);
810 g_object_unref (f);
811 f = NULL;
814 out:
815 xmlFreeTextReader (reader);
817 return f;
820 MMHitCollection *
821 mm_hit_collection_unserialize (const char *s, GError **error)
823 MMHitCollection *hc = NULL;
824 MMHit *hit;
825 xmlTextReaderPtr reader;
826 int res;
827 const xmlChar *node_name;
829 reader = xmlReaderForMemory (s, strlen (s), NULL, NULL, 0);
831 /* cut all the elements before <hit-collection> */
832 do {
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.
840 if (res <= 0) {
841 set_hit_collection_error (res, error);
842 goto out;
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);
855 if (*error) {
856 /* do not return an incomplete HitCollection */
857 g_object_unref (hc);
858 hc = NULL;
859 goto out;
861 mm_hit_collection_add_hit (hc, hit);
862 g_object_unref (hit);
863 res = xmlTextReaderRead (reader);
864 node_name = xmlTextReaderConstName (reader);
867 if (res <= 0) {
868 /* do not return an incomplete HitCollection */
869 set_hit_collection_error (res, error);
870 g_object_unref (hc);
871 hc = NULL;
872 goto out;
875 out:
876 xmlFreeTextReader (reader);
878 return hc;