Fix a bug in filter_serialize () and update tests.
[mmediamanager.git] / src / mm-string-utils.c
blob296df71dbb31b19b3199c666514ea771f0ef4a29
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"
31 typedef struct {
32 MMComparisionOperator op;
33 const char *string;
34 } OperatorGrid;
36 typedef struct {
37 xmlTextWriterPtr writer;
38 GError **error;
39 } SerializeData;
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" },
48 { MM_COMP_NONE, "" }
51 static void
52 set_error (int res, GError **error, const char *obj_name)
54 xmlErrorPtr xml_error;
56 if (res == -1) {
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);
68 static void
69 set_hit_error (int res, GError **error)
71 set_error (res, error, "Hit");
74 static void
75 set_hit_collection_error (int res, GError **error)
77 set_error (res, error, "HitCollection");
80 static void
81 set_value_error (int res, GError **error)
83 set_error (res, error, "Value");
86 static void
87 set_filter_param_error (int res, GError **error)
89 set_error (res, error, "FilterParam");
92 static void
93 set_operator_error (int res, GError **error)
95 set_error (res, error, "ComparisionOperator");
98 static void
99 set_filter_error (int res, GError **error)
101 set_error (res, error, "Filter");
104 static void
105 set_pair_error (int res, GError **error)
107 set_error (res, error, "Pair");
110 static void
111 set_attribute_error (int res, GError **error)
113 set_error (res, error, "Attribute");
116 static void
117 serialize_value (xmlTextWriterPtr writer, GValue *v, GError **error)
119 xmlChar *safe;
120 int res;
121 char *ret = NULL;
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));
151 } else {
152 g_warning ("Can't convert the value to string: unhandled type");
153 return;
156 safe = xmlCharStrdup (ret);
157 g_free (ret);
159 res = xmlTextWriterWriteElement (writer, BAD_CAST ("value"), safe);
160 g_free (safe);
161 if (res == -1) {
162 set_value_error (res, error);
163 return;
167 static void
168 serialize_op (xmlTextWriterPtr writer, MMComparisionOperator op, GError **error)
170 int idx, res;
171 xmlChar *str = NULL;
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);
179 if (str) {
180 res = xmlTextWriterWriteElement (writer, BAD_CAST ("op"), str);
181 g_free (str);
182 if (res == -1) {
183 set_operator_error (res, error);
184 return;
189 static void
190 serialize_attribute (xmlTextWriterPtr writer,
191 MMAttribute *attribute,
192 GError **error)
194 xmlChar *safe_str;
195 int res;
197 res = xmlTextWriterStartElement (writer, BAD_CAST ("attribute"));
198 if (res == -1) {
199 set_attribute_error (res, error);
200 return;
203 safe_str = xmlCharStrdup (mm_attribute_get_id (attribute));
204 res = xmlTextWriterWriteAttribute (writer, BAD_CAST ("id"), safe_str);
205 g_free (safe_str);
206 if (res == -1) {
207 set_attribute_error (res, error);
208 return;
211 safe_str = xmlCharStrdup (mm_attribute_get_name (attribute));
212 xmlTextWriterWriteAttribute (writer, BAD_CAST ("name"), safe_str);
213 g_free (safe_str);
214 if (res == -1) {
215 set_attribute_error (res, error);
216 return;
219 safe_str = xmlCharStrdup (mm_attribute_get_description (attribute));
220 xmlTextWriterWriteAttribute (writer, BAD_CAST ("description"), safe_str);
221 g_free (safe_str);
222 if (res == -1) {
223 set_attribute_error (res, error);
224 return;
227 res = xmlTextWriterWriteAttribute (writer, BAD_CAST ("type"),
228 BAD_CAST (g_type_name (mm_attribute_get_value_type (attribute))));
229 if (res == -1) {
230 set_attribute_error (res, error);
231 return;
234 /* close "attribute" */
235 res = xmlTextWriterEndElement (writer);
236 if (res == -1) {
237 set_attribute_error (res, error);
238 return;
242 static void
243 serialize_filter_param (MMFilterParam *fp,
244 SerializeData *data)
246 MMAttribute *attribute;
247 GValue *val;
248 MMComparisionOperator op;
249 int res;
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"));
258 if (res == -1) {
259 set_filter_param_error (res, error);
260 return;
263 serialize_attribute (writer, attribute, error);
264 if (*error) {
265 return;
267 serialize_value (writer, val, error);
268 if (*error) {
269 return;
271 serialize_op (writer, op, error);
272 if (*error) {
273 return;
276 /* close "filter-param" */
277 res = xmlTextWriterEndElement (writer);
278 if (res == -1) {
279 set_filter_param_error (res, error);
280 return;
284 static void
285 unserialize_operator (xmlTextReaderPtr reader, MMComparisionOperator *op,
286 GError **error)
288 const xmlChar * op_string;
289 gboolean found = FALSE;
290 int idx, res;
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");
297 return;
300 /* move on to the content */
301 res = xmlTextReaderRead (reader);
302 if (res <= 0) {
303 set_operator_error (res, error);
304 return;
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) {
310 found = TRUE;
311 break;
315 /* move to </op> */
316 res = xmlTextReaderRead (reader);
317 if (res <= 0) {
318 set_operator_error (res, error);
319 return;
322 if (found) {
323 *op = operator_grid[idx].op;
327 static void
328 unserialize_value (xmlTextReaderPtr reader, GValue *v, GError **error)
330 int res;
331 GType type;
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");
339 return;
342 /* move on to the content node */
343 res = xmlTextReaderRead (reader);
344 if (res <= 0) {
345 set_value_error (res, error);
346 return;
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) {
355 gboolean bval;
356 sscanf (val_string, "%d", &bval);
357 g_value_set_boolean (v, bval);
358 } else if (type == G_TYPE_INT) {
359 gint ival;
360 sscanf (val_string, "%d", &ival);
361 g_value_set_int (v, ival);
362 } else if (type == G_TYPE_FLOAT) {
363 gfloat fval;
364 sscanf (val_string, "%f", &fval);
365 g_value_set_float (v, fval);
366 } else if (type == G_TYPE_DOUBLE) {
367 gdouble dval;
368 dval = g_ascii_strtod (val_string, NULL);
369 g_value_set_double (v, dval);
370 } else if (type == G_TYPE_LONG) {
371 glong lval;
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) {
377 guint uval;
378 sscanf (val_string, "%u", &uval);
379 g_value_set_uint (v, uval);
380 } else if (type == G_TYPE_ULONG) {
381 gulong ulval;
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)) {
387 gchar cval;
388 sscanf (val_string, "%c", &cval);
389 g_value_set_char (v, cval);
390 } else if (G_VALUE_HOLDS_UCHAR (v)) {
391 guchar ucval;
392 sscanf (val_string, "%c", &ucval);
393 g_value_set_uchar (v, ucval);
394 } else {
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");
397 return;
400 /* move over </value> */
401 res = xmlTextReaderRead (reader);
402 if (res <= 0) {
403 set_value_error (res, error);
404 g_value_unset (v);
405 g_free (v);
406 v = NULL;
410 static void
411 unserialize_attribute (xmlTextReaderPtr reader, MMAttribute **attribute, GError **error)
413 xmlChar *id, *name, *desc, *type_name;
414 GType type;
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.");
421 return;
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);
430 if (type == 0) {
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);
434 goto out;
437 *attribute = mm_attribute_new (type,
438 (const char *) id,
439 (const char *) name,
440 (const char *) desc);
441 out:
442 g_free (id);
443 g_free (name);
444 g_free (desc);
445 g_free (type_name);
448 static MMFilterParam *
449 unserialize_filter_param (xmlTextReaderPtr reader, GError **error)
451 int res;
452 MMAttribute *attribute = NULL;
453 MMComparisionOperator op = MM_COMP_NONE;
454 GValue *val = NULL;
455 MMFilterParam *fp = NULL;
457 res = xmlTextReaderRead (reader);
458 if (res <= 0) {
459 set_filter_param_error (res, error);
460 goto out;
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);
467 if (*error) {
468 goto out;
471 res = xmlTextReaderRead (reader);
472 if (res <= 0) {
473 set_filter_param_error (res, error);
474 goto out;
476 /* we're now on <value> */
477 val = mm_create_gvalue_for_attribute (attribute);
478 unserialize_value (reader, val, error);
479 if (*error) {
480 goto out;
483 res = xmlTextReaderRead (reader);
484 if (res <= 0) {
485 set_filter_param_error (res, error);
486 goto out;
488 /* we're now on <op> */
489 unserialize_operator (reader, &op, error);
490 if (*error) {
491 goto out;
494 /* move after </op> */
495 res = xmlTextReaderRead (reader);
496 if (res <= 0) {
497 set_filter_param_error (res, error);
498 goto out;
502 /* if we're here, everything in the unserialize sub-operations went well */
503 fp = mm_filter_param_new (attribute, val, op);
505 out:
506 if (val) {
507 g_value_unset (val);
508 g_free (val);
511 return fp;
514 static void
515 serialize_pair (MMAttribute *attr,
516 GValue *val,
517 SerializeData *pair_data)
519 xmlTextWriterPtr writer = pair_data->writer;
520 GError **error = pair_data->error;
521 int res;
523 if (*error) {
524 /* an error occurred in a previous iteration of this function, don't do
525 * anything.
527 return;
530 xmlTextWriterStartElement (writer, BAD_CAST ("pair"));
531 serialize_attribute (writer, attr, error);
532 if (*error) {
533 return;
536 serialize_value (writer, val, error);
537 if (*error) {
538 return;
541 /* end "pair" */
542 res = xmlTextWriterEndElement (writer);
543 if (res == -1) {
544 set_pair_error (res, error);
548 static MMHit *
549 unserialize_hit (xmlTextReaderPtr reader, GError **error)
551 int res;
552 MMAttribute *attribute = NULL;
553 GValue *v;
554 MMHit *hit = NULL;
556 hit = g_object_new (MM_TYPE_HIT, NULL);
558 do {
559 /* skip <pair> */
560 res = xmlTextReaderRead (reader);
561 if (res <= 0) {
562 set_hit_error (res, error);
563 g_object_unref (hit);
564 hit = NULL;
565 break;
567 res = xmlTextReaderRead (reader);
568 /* now we should be on "attribute" */
569 if (res <= 0) {
570 set_hit_error (res, error);
571 g_object_unref (hit);
572 hit = NULL;
573 break;
575 unserialize_attribute (reader, &attribute, error);
576 if (*error) {
577 g_object_unref (hit);
578 hit = NULL;
579 break;
581 res = xmlTextReaderRead (reader);
582 /* we're now on "value" */
583 if (res <= 0) {
584 set_hit_error (res, error);
585 g_object_unref (hit);
586 hit = NULL;
587 break;
590 v = mm_create_gvalue_for_attribute (attribute);
591 unserialize_value (reader, v, error);
592 if (*error) {
593 g_object_unref (hit);
594 hit = NULL;
595 break;
598 mm_hit_set_value (hit, attribute, v);
600 res = xmlTextReaderRead (reader);
601 /* now we're on </pair> */
602 if (res <= 0) {
603 set_hit_error (res, error);
604 g_object_unref (hit);
605 hit = NULL;
606 break;
609 res = xmlTextReaderRead (reader);
610 if (res <= 0) {
611 set_hit_error (res, error);
612 g_object_unref (hit);
613 hit = NULL;
614 break;
616 /* now we're either on <pair> again or </hit>. we must end they cycle
617 * on </hit>.
619 } while (!((xmlTextReaderNodeType (reader) == XML_READER_TYPE_END_ELEMENT) &&
620 xmlStrcmp (xmlTextReaderConstName (reader), BAD_CAST ("hit"))));
622 return hit;
625 /* public functions */
626 char *
627 mm_filter_serialize (MMFilter *filter, GError **error)
629 char *serialized = NULL;
630 xmlBufferPtr buffer;
631 xmlTextWriterPtr writer;
632 GList *filter_params;
633 SerializeData *fp_data;
634 int res;
636 buffer = xmlBufferCreate ();
637 writer = xmlNewTextWriterMemory (buffer, 0);
639 res = xmlTextWriterStartDocument (writer, NULL, NULL, NULL);
640 if (res == -1) {
641 set_filter_error (res, error);
642 goto out;
645 res = xmlTextWriterStartElement (writer, BAD_CAST ("filter"));
646 if (res == -1) {
647 set_filter_error (res, error);
648 goto out;
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);
656 g_free (fp_data);
657 if (*error) {
658 goto out;
661 /* close "filter" */
662 res = xmlTextWriterEndElement (writer);
663 if (res == -1) {
664 set_filter_error (res, error);
665 goto out;
668 res = xmlTextWriterEndDocument (writer);
669 if (res == -1) {
670 set_filter_error (res, error);
671 goto out;
674 /* everything went well */
675 serialized = g_strdup ((char *) xmlBufferContent (buffer));
677 out:
678 xmlFreeTextWriter (writer);
679 xmlBufferFree (buffer);
681 return serialized;
684 char *
685 mm_hit_collection_serialize (MMHitCollection *hc, GError **error)
687 char *serialized = NULL;
688 int res;
689 xmlBufferPtr buffer;
690 xmlTextWriterPtr writer;
691 MMHit *hit;
692 GHashTable *attrs_and_values;
693 SerializeData *pair_data;
695 buffer = xmlBufferCreate ();
696 writer = xmlNewTextWriterMemory (buffer, 0);
698 res = xmlTextWriterStartDocument (writer, NULL, NULL, NULL);
699 if (res == -1) {
700 set_hit_collection_error (res, error);
701 goto out;
704 res = xmlTextWriterStartElement (writer, BAD_CAST ("hit-collection"));
705 if (res == -1) {
706 set_hit_collection_error (res, error);
707 goto out;
710 while ((hit = mm_hit_collection_get_next_hit (hc)) != NULL) {
711 res = xmlTextWriterStartElement (writer, BAD_CAST ("hit"));
712 if (res == -1) {
713 set_hit_collection_error (res, error);
714 goto out;
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,
725 pair_data);
726 g_slice_free (SerializeData, pair_data);
727 if (*error) {
728 /* an error occurred somewhere in one of the sub-functions */
729 goto out;
732 /* close "hit" */
733 res = xmlTextWriterEndElement (writer);
734 if (res == -1) {
735 set_hit_collection_error (res, error);
736 goto out;
740 /* close "hit-collection" */
741 res = xmlTextWriterEndElement (writer);
742 if (res == -1) {
743 set_hit_collection_error (res, error);
744 goto out;
746 res = xmlTextWriterEndDocument (writer);
747 if (res == -1) {
748 set_hit_collection_error (res, error);
749 goto out;
752 /* it seems everything has gone well */
753 serialized = g_strdup ((char *) xmlBufferContent (buffer));
755 out:
756 xmlFreeTextWriter (writer);
757 xmlBufferFree (buffer);
759 return serialized;
762 MMFilter *
763 mm_filter_unserialize (const char *s, GError **error)
765 MMFilter *f = NULL;
766 MMFilterParam *fp;
767 xmlTextReaderPtr reader;
768 int res;
769 const xmlChar *node_name;
771 reader = xmlReaderForMemory (s, strlen (s), NULL, NULL, 0);
773 /* cut all the elements before <filter> */
774 do {
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 */
780 if (res <= 0) {
781 set_filter_error (res, error);
782 goto out;
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);
795 if (*error) {
796 g_object_unref (f);
797 f = NULL;
798 goto out;
800 mm_filter_add_filtering_param (f, fp);
801 g_object_unref (fp);
802 res = xmlTextReaderRead (reader);
803 node_name = xmlTextReaderConstName (reader);
806 if (res <= 0) {
807 /* do not return an incomplete filter */
808 set_filter_error (res, error);
809 g_object_unref (f);
810 f = NULL;
813 out:
814 xmlFreeTextReader (reader);
816 return f;
819 MMHitCollection *
820 mm_hit_collection_unserialize (const char *s, GError **error)
822 MMHitCollection *hc = NULL;
823 MMHit *hit;
824 xmlTextReaderPtr reader;
825 int res;
826 const xmlChar *node_name;
828 reader = xmlReaderForMemory (s, strlen (s), NULL, NULL, 0);
830 /* cut all the elements before <hit-collection> */
831 do {
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.
839 if (res <= 0) {
840 set_hit_collection_error (res, error);
841 goto out;
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);
854 if (*error) {
855 /* do not return an incomplete HitCollection */
856 g_object_unref (hc);
857 hc = NULL;
858 goto out;
860 mm_hit_collection_add_hit (hc, hit);
861 g_object_unref (hit);
862 res = xmlTextReaderRead (reader);
863 node_name = xmlTextReaderConstName (reader);
866 if (res <= 0) {
867 /* do not return an incomplete HitCollection */
868 set_hit_collection_error (res, error);
869 g_object_unref (hc);
870 hc = NULL;
871 goto out;
874 out:
875 xmlFreeTextReader (reader);
877 return hc;