/src/tinysparql/src/libtinysparql/tracker-deserializer-xml.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2022, Red Hat Inc. |
3 | | * |
4 | | * This library is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Lesser General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2.1 of the License, or (at your option) any later version. |
8 | | * |
9 | | * This library is distributed in the hope that it will be useful, |
10 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | | * Lesser General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU Lesser General Public |
15 | | * License along with this library; if not, write to the |
16 | | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | | * Boston, MA 02110-1301, USA. |
18 | | * |
19 | | * Author: Carlos Garnacho <carlosg@gnome.org> |
20 | | */ |
21 | | |
22 | | /* Deserialization to cursors for the XML format defined at: |
23 | | * https://www.w3.org/TR/2013/REC-rdf-sparql-XMLres-20130321/ |
24 | | */ |
25 | | |
26 | | #include "config.h" |
27 | | |
28 | | #include "tracker-deserializer-xml.h" |
29 | | |
30 | | #include <libxml/xmlreader.h> |
31 | | |
32 | | typedef struct { |
33 | | TrackerSparqlValueType type; |
34 | | xmlChar *str; |
35 | | xmlChar *langtag; |
36 | | } ColumnData; |
37 | | |
38 | | struct _TrackerDeserializerXml { |
39 | | TrackerDeserializer parent_instance; |
40 | | xmlTextReaderPtr reader; |
41 | | GPtrArray *columns; |
42 | | GPtrArray *column_names; |
43 | | GError *error; |
44 | | gboolean started; |
45 | | }; |
46 | | |
47 | 0 | G_DEFINE_TYPE (TrackerDeserializerXml, |
48 | 0 | tracker_deserializer_xml, |
49 | 0 | TRACKER_TYPE_DESERIALIZER) |
50 | 0 |
|
51 | 0 | static ColumnData * |
52 | 0 | column_new (TrackerSparqlValueType type, |
53 | 0 | xmlChar *str, |
54 | 0 | xmlChar *langtag) |
55 | 0 | { |
56 | 0 | ColumnData *col; |
57 | |
|
58 | 0 | col = g_slice_new0 (ColumnData); |
59 | 0 | col->type = type; |
60 | 0 | col->str = str; |
61 | 0 | col->langtag = langtag; |
62 | |
|
63 | 0 | return col; |
64 | 0 | } |
65 | | |
66 | | static void |
67 | | column_free (gpointer data) |
68 | 0 | { |
69 | 0 | ColumnData *col = data; |
70 | |
|
71 | 0 | xmlFree (col->str); |
72 | 0 | xmlFree (col->langtag); |
73 | 0 | g_slice_free (ColumnData, col); |
74 | 0 | } |
75 | | |
76 | | static void |
77 | | tracker_deserializer_xml_finalize (GObject *object) |
78 | 0 | { |
79 | 0 | TrackerDeserializerXml *deserializer = |
80 | 0 | TRACKER_DESERIALIZER_XML (object); |
81 | |
|
82 | 0 | g_clear_pointer (&deserializer->reader, xmlFreeTextReader); |
83 | 0 | g_ptr_array_unref (deserializer->columns); |
84 | 0 | g_ptr_array_unref (deserializer->column_names); |
85 | |
|
86 | 0 | G_OBJECT_CLASS (tracker_deserializer_xml_parent_class)->finalize (object); |
87 | 0 | } |
88 | | |
89 | | static int |
90 | | stream_read (gpointer context, |
91 | | gchar *buf, |
92 | | int len) |
93 | 0 | { |
94 | 0 | GInputStream *stream = context; |
95 | |
|
96 | 0 | return g_input_stream_read (stream, buf, len, NULL, NULL); |
97 | 0 | } |
98 | | |
99 | | static int |
100 | | stream_close (gpointer context) |
101 | 0 | { |
102 | 0 | GInputStream *stream = context; |
103 | |
|
104 | 0 | return g_input_stream_close (stream, NULL, NULL) ? 0 : -1; |
105 | 0 | } |
106 | | |
107 | | static void |
108 | | error_handler (gpointer user_data, |
109 | | const gchar *msg, |
110 | | xmlParserSeverities severity, |
111 | | xmlTextReaderLocatorPtr locator) |
112 | 0 | { |
113 | 0 | TrackerDeserializerXml *deserializer = user_data; |
114 | |
|
115 | 0 | deserializer->error = g_error_new (TRACKER_SPARQL_ERROR, |
116 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
117 | 0 | "Could not parse XML response: %s", |
118 | 0 | msg); |
119 | 0 | } |
120 | | |
121 | | static gboolean |
122 | | reader_in_element (TrackerDeserializerXml *deserializer, |
123 | | const gchar *name, |
124 | | int depth) |
125 | 0 | { |
126 | 0 | return (xmlTextReaderNodeType (deserializer->reader) == XML_READER_TYPE_ELEMENT && |
127 | 0 | g_strcmp0 ((gchar *) xmlTextReaderConstName (deserializer->reader), name) == 0 && |
128 | 0 | xmlTextReaderDepth (deserializer->reader) == depth); |
129 | 0 | } |
130 | | |
131 | | static gboolean |
132 | | parse_head (TrackerDeserializerXml *deserializer, |
133 | | GError **error) |
134 | 0 | { |
135 | 0 | gboolean seen_link = FALSE; |
136 | |
|
137 | 0 | if (xmlTextReaderRead(deserializer->reader) <= 0 || |
138 | 0 | !reader_in_element (deserializer, "head", 1)) |
139 | 0 | goto error; |
140 | | |
141 | 0 | while (xmlTextReaderRead (deserializer->reader) > 0) { |
142 | 0 | if (xmlTextReaderNodeType (deserializer->reader) == XML_READER_TYPE_END_ELEMENT) |
143 | 0 | break; |
144 | | |
145 | 0 | if (reader_in_element (deserializer, "variable", 2)) { |
146 | 0 | xmlChar *name; |
147 | |
|
148 | 0 | if (seen_link) { |
149 | 0 | g_set_error (error, |
150 | 0 | TRACKER_SPARQL_ERROR, |
151 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
152 | 0 | "Wrong XML format, variable node found after link"); |
153 | 0 | break; |
154 | 0 | } |
155 | | |
156 | 0 | name = xmlTextReaderGetAttribute (deserializer->reader, |
157 | 0 | (xmlChar *) "name"); |
158 | 0 | g_ptr_array_add (deserializer->column_names, name); |
159 | 0 | } else if (reader_in_element (deserializer, "link", 2)) { |
160 | | /* We do nothing about extra links in headers, but still |
161 | | * mandate that these appear after all variable nodes |
162 | | * as per spec. |
163 | | */ |
164 | 0 | seen_link = TRUE; |
165 | 0 | } else { |
166 | 0 | goto error; |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | 0 | return TRUE; |
171 | | |
172 | 0 | error: |
173 | 0 | g_set_error (error, |
174 | 0 | TRACKER_SPARQL_ERROR, |
175 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
176 | 0 | "Wrong XML format, unexpected node '%s'", |
177 | 0 | xmlTextReaderConstName (deserializer->reader)); |
178 | |
|
179 | 0 | return FALSE; |
180 | 0 | } |
181 | | |
182 | | static void |
183 | | tracker_deserializer_xml_constructed (GObject *object) |
184 | 0 | { |
185 | 0 | TrackerDeserializerXml *deserializer = |
186 | 0 | TRACKER_DESERIALIZER_XML (object); |
187 | 0 | GInputStream *stream; |
188 | |
|
189 | 0 | G_OBJECT_CLASS (tracker_deserializer_xml_parent_class)->constructed (object); |
190 | |
|
191 | 0 | stream = tracker_deserializer_get_stream (TRACKER_DESERIALIZER (object)); |
192 | |
|
193 | 0 | deserializer->reader = xmlReaderForIO (stream_read, |
194 | 0 | stream_close, |
195 | 0 | stream, |
196 | 0 | NULL, NULL, 0); |
197 | 0 | if (deserializer->reader) { |
198 | 0 | xmlTextReaderSetErrorHandler (deserializer->reader, |
199 | 0 | error_handler, deserializer); |
200 | 0 | } |
201 | |
|
202 | 0 | if (deserializer->reader && |
203 | 0 | xmlTextReaderRead(deserializer->reader) > 0 && |
204 | 0 | reader_in_element (deserializer, "sparql", 0)) { |
205 | 0 | parse_head (deserializer, &deserializer->error); |
206 | 0 | } else { |
207 | 0 | g_set_error (&deserializer->error, |
208 | 0 | TRACKER_SPARQL_ERROR, |
209 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
210 | 0 | "Wrong XML format, variable node found after link"); |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | | static gint |
215 | | tracker_deserializer_xml_get_n_columns (TrackerSparqlCursor *cursor) |
216 | 0 | { |
217 | 0 | TrackerDeserializerXml *deserializer = |
218 | 0 | TRACKER_DESERIALIZER_XML (cursor); |
219 | |
|
220 | 0 | return deserializer->column_names->len; |
221 | 0 | } |
222 | | |
223 | | static TrackerSparqlValueType |
224 | | tracker_deserializer_xml_get_value_type (TrackerSparqlCursor *cursor, |
225 | | gint column) |
226 | 0 | { |
227 | 0 | TrackerDeserializerXml *deserializer = |
228 | 0 | TRACKER_DESERIALIZER_XML (cursor); |
229 | 0 | ColumnData *col; |
230 | |
|
231 | 0 | if (column < 0 || column >= (gint) deserializer->columns->len) |
232 | 0 | return TRACKER_SPARQL_VALUE_TYPE_UNBOUND; |
233 | | |
234 | 0 | col = g_ptr_array_index (deserializer->columns, column); |
235 | |
|
236 | 0 | return col->type; |
237 | 0 | } |
238 | | |
239 | | static const gchar * |
240 | | tracker_deserializer_xml_get_variable_name (TrackerSparqlCursor *cursor, |
241 | | gint column) |
242 | 0 | { |
243 | 0 | TrackerDeserializerXml *deserializer = |
244 | 0 | TRACKER_DESERIALIZER_XML (cursor); |
245 | |
|
246 | 0 | if (column < 0 || column >= (gint) deserializer->column_names->len) |
247 | 0 | return NULL; |
248 | | |
249 | 0 | return g_ptr_array_index (deserializer->column_names, column); |
250 | 0 | } |
251 | | |
252 | | static const gchar * |
253 | | tracker_deserializer_xml_get_string (TrackerSparqlCursor *cursor, |
254 | | gint column, |
255 | | const gchar **langtag, |
256 | | glong *length) |
257 | 0 | { |
258 | 0 | TrackerDeserializerXml *deserializer = |
259 | 0 | TRACKER_DESERIALIZER_XML (cursor); |
260 | 0 | ColumnData *col; |
261 | |
|
262 | 0 | if (length) |
263 | 0 | *length = 0; |
264 | 0 | if (langtag) |
265 | 0 | *langtag = NULL; |
266 | |
|
267 | 0 | if (column < 0 || column >= (gint) deserializer->columns->len) |
268 | 0 | return NULL; |
269 | | |
270 | 0 | col = g_ptr_array_index (deserializer->columns, column); |
271 | |
|
272 | 0 | if (length) |
273 | 0 | *length = strlen ((const gchar *) col->str); |
274 | 0 | if (langtag) |
275 | 0 | *langtag = (const gchar *) col->langtag; |
276 | |
|
277 | 0 | return (const gchar *) col->str; |
278 | 0 | } |
279 | | |
280 | | static gboolean |
281 | | maybe_propagate_error (TrackerDeserializerXml *deserializer, |
282 | | GError **error) |
283 | 0 | { |
284 | 0 | if (deserializer->error) { |
285 | 0 | g_propagate_error (error, deserializer->error); |
286 | 0 | deserializer->error = NULL; |
287 | 0 | return TRUE; |
288 | 0 | } |
289 | | |
290 | 0 | return FALSE; |
291 | 0 | } |
292 | | |
293 | | static gboolean |
294 | | parse_binding_type (TrackerDeserializerXml *deserializer, |
295 | | TrackerSparqlValueType *type, |
296 | | GError **error) |
297 | 0 | { |
298 | 0 | if (reader_in_element (deserializer, "uri", 4)) { |
299 | 0 | *type = TRACKER_SPARQL_VALUE_TYPE_URI; |
300 | 0 | } else if (reader_in_element (deserializer, "bnode", 4)) { |
301 | 0 | *type = TRACKER_SPARQL_VALUE_TYPE_BLANK_NODE; |
302 | 0 | } else if (reader_in_element (deserializer, "literal", 4)) { |
303 | 0 | xmlChar *datatype; |
304 | 0 | const gchar *suffix; |
305 | |
|
306 | 0 | datatype = xmlTextReaderGetAttribute (deserializer->reader, |
307 | 0 | (xmlChar *) "datatype"); |
308 | |
|
309 | 0 | if (!datatype || |
310 | 0 | !g_str_has_prefix ((const gchar *) datatype, TRACKER_PREFIX_XSD)) { |
311 | 0 | g_clear_pointer (&datatype, xmlFree); |
312 | 0 | *type = TRACKER_SPARQL_VALUE_TYPE_STRING; |
313 | 0 | return TRUE; |
314 | 0 | } |
315 | | |
316 | 0 | suffix = (const gchar *) &datatype[strlen (TRACKER_PREFIX_XSD)]; |
317 | |
|
318 | 0 | if (g_str_equal (suffix, "byte") || |
319 | 0 | g_str_equal (suffix, "int") || |
320 | 0 | g_str_equal (suffix, "integer") || |
321 | 0 | g_str_equal (suffix, "long")) |
322 | 0 | *type = TRACKER_SPARQL_VALUE_TYPE_INTEGER; |
323 | 0 | else if (g_str_equal (suffix, "decimal") || |
324 | 0 | g_str_equal (suffix, "double")) |
325 | 0 | *type = TRACKER_SPARQL_VALUE_TYPE_DOUBLE; |
326 | 0 | else if (g_str_equal (suffix, "date") || |
327 | 0 | g_str_equal (suffix, "dateTime")) |
328 | 0 | *type = TRACKER_SPARQL_VALUE_TYPE_DATETIME; |
329 | 0 | else if (g_str_equal (suffix, "boolean")) |
330 | 0 | *type = TRACKER_SPARQL_VALUE_TYPE_BOOLEAN; |
331 | 0 | else |
332 | 0 | *type = TRACKER_SPARQL_VALUE_TYPE_STRING; |
333 | |
|
334 | 0 | xmlFree (datatype); |
335 | 0 | } else { |
336 | 0 | g_set_error (error, |
337 | 0 | TRACKER_SPARQL_ERROR, |
338 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
339 | 0 | "Unknown binding type '%s'", |
340 | 0 | xmlTextReaderConstName (deserializer->reader)); |
341 | 0 | return FALSE; |
342 | 0 | } |
343 | | |
344 | 0 | return TRUE; |
345 | 0 | } |
346 | | |
347 | | static gboolean |
348 | | parse_binding (TrackerDeserializerXml *deserializer, |
349 | | TrackerSparqlValueType *type, |
350 | | xmlChar **name, |
351 | | xmlChar **value, |
352 | | xmlChar **langtag, |
353 | | GError **error) |
354 | 0 | { |
355 | 0 | xmlChar *binding_name = NULL, *binding_value = NULL, *binding_langtag = NULL; |
356 | |
|
357 | 0 | if (!reader_in_element (deserializer, "binding", 3)) |
358 | 0 | goto error; |
359 | | |
360 | 0 | binding_name = xmlTextReaderGetAttribute (deserializer->reader, |
361 | 0 | (xmlChar *) "name"); |
362 | |
|
363 | 0 | if (xmlTextReaderRead(deserializer->reader) <= 0) |
364 | 0 | goto error; |
365 | | |
366 | 0 | binding_langtag = xmlTextReaderGetAttribute (deserializer->reader, |
367 | 0 | (xmlChar *) "xml:lang"); |
368 | |
|
369 | 0 | if (!parse_binding_type (deserializer, type, error)) |
370 | 0 | goto error_already_set; |
371 | | |
372 | 0 | if (xmlTextReaderRead(deserializer->reader) <= 0) |
373 | 0 | goto error; |
374 | | |
375 | 0 | binding_value = xmlTextReaderValue (deserializer->reader); |
376 | | |
377 | | /* End of binding content */ |
378 | 0 | if (xmlTextReaderRead(deserializer->reader) <= 0 || |
379 | 0 | xmlTextReaderNodeType (deserializer->reader) != XML_READER_TYPE_END_ELEMENT) |
380 | 0 | goto error; |
381 | | |
382 | | /* End of binding */ |
383 | 0 | if (xmlTextReaderRead(deserializer->reader) <= 0 || |
384 | 0 | xmlTextReaderNodeType (deserializer->reader) != XML_READER_TYPE_END_ELEMENT) |
385 | 0 | goto error; |
386 | | |
387 | 0 | *name = binding_name; |
388 | 0 | *value = binding_value; |
389 | 0 | *langtag = binding_langtag; |
390 | |
|
391 | 0 | return TRUE; |
392 | 0 | error: |
393 | 0 | g_set_error (error, |
394 | 0 | TRACKER_SPARQL_ERROR, |
395 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
396 | 0 | "Wrong XML format, unexpected node '%s'", |
397 | 0 | xmlTextReaderConstName (deserializer->reader)); |
398 | 0 | error_already_set: |
399 | 0 | g_clear_pointer (&binding_name, xmlFree); |
400 | 0 | g_clear_pointer (&binding_value, xmlFree); |
401 | 0 | g_clear_pointer (&binding_langtag, xmlFree); |
402 | |
|
403 | 0 | return FALSE; |
404 | 0 | } |
405 | | |
406 | | static gboolean |
407 | | parse_result (TrackerDeserializerXml *deserializer, |
408 | | GError **error) |
409 | 0 | { |
410 | 0 | TrackerSparqlCursor *cursor = TRACKER_SPARQL_CURSOR (deserializer); |
411 | 0 | const gchar *var_name; |
412 | 0 | GHashTable *ht = NULL; |
413 | 0 | gint n_columns, i; |
414 | |
|
415 | 0 | if (!reader_in_element (deserializer, "result", 2)) |
416 | 0 | goto error; |
417 | | |
418 | 0 | g_ptr_array_set_size (deserializer->columns, 0); |
419 | 0 | ht = g_hash_table_new_full (g_str_hash, g_str_equal, xmlFree, column_free); |
420 | |
|
421 | 0 | while (xmlTextReaderRead (deserializer->reader) > 0) { |
422 | 0 | ColumnData *col; |
423 | 0 | xmlChar *name, *value, *langtag; |
424 | 0 | TrackerSparqlValueType type; |
425 | |
|
426 | 0 | if (xmlTextReaderNodeType (deserializer->reader) == XML_READER_TYPE_END_ELEMENT) |
427 | 0 | break; |
428 | | |
429 | 0 | if (!parse_binding (deserializer, &type, &name, &value, &langtag, error)) |
430 | 0 | goto error_already_set; |
431 | | |
432 | 0 | col = column_new (type, value, langtag); |
433 | 0 | g_hash_table_insert (ht, name, col); |
434 | 0 | } |
435 | | |
436 | 0 | if (maybe_propagate_error (deserializer, error)) |
437 | 0 | goto error_already_set; |
438 | | |
439 | 0 | n_columns = tracker_sparql_cursor_get_n_columns (cursor); |
440 | |
|
441 | 0 | for (i = 0; i < n_columns; i++) { |
442 | 0 | ColumnData *col; |
443 | 0 | gpointer key, value; |
444 | |
|
445 | 0 | var_name = tracker_sparql_cursor_get_variable_name (cursor, i); |
446 | |
|
447 | 0 | if (g_hash_table_lookup_extended (ht, var_name, &key, &value)) { |
448 | 0 | col = value; |
449 | 0 | g_hash_table_steal (ht, var_name); |
450 | 0 | xmlFree (key); |
451 | 0 | } else { |
452 | 0 | col = column_new (TRACKER_SPARQL_VALUE_TYPE_UNBOUND, NULL, NULL); |
453 | 0 | } |
454 | |
|
455 | 0 | g_ptr_array_add (deserializer->columns, col); |
456 | 0 | } |
457 | | |
458 | | /* There should be no bindings left */ |
459 | 0 | if (g_hash_table_size (ht) > 0) { |
460 | 0 | g_set_error (error, |
461 | 0 | TRACKER_SPARQL_ERROR, |
462 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
463 | 0 | "Wrong XML format, unexpected additional bindings"); |
464 | 0 | goto error_already_set; |
465 | 0 | } |
466 | | |
467 | 0 | g_clear_pointer (&ht, g_hash_table_unref); |
468 | |
|
469 | 0 | return TRUE; |
470 | | |
471 | 0 | error: |
472 | 0 | g_set_error (error, |
473 | 0 | TRACKER_SPARQL_ERROR, |
474 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
475 | 0 | "Wrong XML format, unexpected node '%s'", |
476 | 0 | xmlTextReaderConstName (deserializer->reader)); |
477 | 0 | error_already_set: |
478 | 0 | g_clear_pointer (&ht, g_hash_table_unref); |
479 | 0 | return FALSE; |
480 | 0 | } |
481 | | |
482 | | static gboolean |
483 | | tracker_deserializer_xml_next (TrackerSparqlCursor *cursor, |
484 | | GCancellable *cancellable, |
485 | | GError **error) |
486 | 0 | { |
487 | 0 | TrackerDeserializerXml *deserializer = |
488 | 0 | TRACKER_DESERIALIZER_XML (cursor); |
489 | |
|
490 | 0 | if (g_cancellable_set_error_if_cancelled (cancellable, error)) |
491 | 0 | return FALSE; |
492 | | |
493 | 0 | g_ptr_array_set_size (deserializer->columns, 0); |
494 | |
|
495 | 0 | again: |
496 | 0 | if (xmlTextReaderRead(deserializer->reader) <= 0) { |
497 | 0 | if (!maybe_propagate_error (deserializer, error)) { |
498 | 0 | g_set_error (error, |
499 | 0 | TRACKER_SPARQL_ERROR, |
500 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
501 | 0 | "Unexpected termination of XML document"); |
502 | 0 | } |
503 | 0 | return FALSE; |
504 | 0 | } |
505 | | |
506 | 0 | if (!deserializer->started) { |
507 | 0 | if (reader_in_element (deserializer, "results", 1)) { |
508 | 0 | deserializer->started = TRUE; |
509 | | /* We want to read the next element, the first <result> */ |
510 | 0 | goto again; |
511 | 0 | } else if (reader_in_element (deserializer, "boolean", 1)) { |
512 | 0 | ColumnData *col; |
513 | 0 | xmlChar *content; |
514 | |
|
515 | 0 | content = xmlTextReaderValue (deserializer->reader); |
516 | 0 | col = column_new (TRACKER_SPARQL_VALUE_TYPE_BOOLEAN, content, NULL); |
517 | 0 | g_ptr_array_add (deserializer->columns, col); |
518 | 0 | } else { |
519 | 0 | g_set_error (error, |
520 | 0 | TRACKER_SPARQL_ERROR, |
521 | 0 | TRACKER_SPARQL_ERROR_PARSE, |
522 | 0 | "Wrong XML format, unexpected node '%s'", |
523 | 0 | xmlTextReaderConstName (deserializer->reader)); |
524 | 0 | return FALSE; |
525 | 0 | } |
526 | 0 | } |
527 | | |
528 | | /* We've reached the end of results */ |
529 | 0 | if (xmlTextReaderNodeType (deserializer->reader) == XML_READER_TYPE_END_ELEMENT) |
530 | 0 | return FALSE; |
531 | | |
532 | 0 | return parse_result (deserializer, error); |
533 | 0 | } |
534 | | |
535 | | static void |
536 | | tracker_deserializer_xml_next_async (TrackerSparqlCursor *cursor, |
537 | | GCancellable *cancellable, |
538 | | GAsyncReadyCallback cb, |
539 | | gpointer user_data) |
540 | 0 | { |
541 | 0 | GError *error = NULL; |
542 | 0 | GTask *task; |
543 | |
|
544 | 0 | task = g_task_new (cursor, cancellable, cb, user_data); |
545 | |
|
546 | 0 | if (tracker_sparql_cursor_next (cursor, cancellable, &error)) |
547 | 0 | g_task_return_boolean (task, TRUE); |
548 | 0 | else if (!error) |
549 | 0 | g_task_return_boolean (task, FALSE); |
550 | 0 | else |
551 | 0 | g_task_return_error (task, error); |
552 | |
|
553 | 0 | g_object_unref (task); |
554 | 0 | } |
555 | | |
556 | | static gboolean |
557 | | tracker_deserializer_xml_next_finish (TrackerSparqlCursor *cursor, |
558 | | GAsyncResult *res, |
559 | | GError **error) |
560 | 0 | { |
561 | 0 | return g_task_propagate_boolean (G_TASK (res), error); |
562 | 0 | } |
563 | | |
564 | | static void |
565 | | tracker_deserializer_xml_close (TrackerSparqlCursor *cursor) |
566 | 0 | { |
567 | 0 | TrackerDeserializerXml *deserializer = |
568 | 0 | TRACKER_DESERIALIZER_XML (cursor); |
569 | |
|
570 | 0 | xmlTextReaderClose (deserializer->reader); |
571 | |
|
572 | 0 | TRACKER_SPARQL_CURSOR_CLASS (tracker_deserializer_xml_parent_class)->close (cursor); |
573 | 0 | } |
574 | | |
575 | | gboolean |
576 | | tracker_deserializer_xml_get_parser_location (TrackerDeserializer *deserializer, |
577 | | const char **name, |
578 | | goffset *line_no, |
579 | | goffset *column_no) |
580 | 0 | { |
581 | 0 | TrackerDeserializerXml *deserializer_xml = |
582 | 0 | TRACKER_DESERIALIZER_XML (deserializer); |
583 | |
|
584 | 0 | if (name) |
585 | 0 | *name = tracker_deserializer_get_name (deserializer); |
586 | |
|
587 | 0 | *line_no = xmlTextReaderGetParserLineNumber (deserializer_xml->reader); |
588 | 0 | *column_no = xmlTextReaderGetParserColumnNumber (deserializer_xml->reader); |
589 | |
|
590 | 0 | return TRUE; |
591 | 0 | } |
592 | | |
593 | | static void |
594 | | tracker_deserializer_xml_class_init (TrackerDeserializerXmlClass *klass) |
595 | 0 | { |
596 | 0 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
597 | 0 | TrackerSparqlCursorClass *cursor_class = |
598 | 0 | TRACKER_SPARQL_CURSOR_CLASS (klass); |
599 | 0 | TrackerDeserializerClass *deserializer_class = |
600 | 0 | TRACKER_DESERIALIZER_CLASS (klass); |
601 | |
|
602 | 0 | object_class->finalize = tracker_deserializer_xml_finalize; |
603 | 0 | object_class->constructed = tracker_deserializer_xml_constructed; |
604 | |
|
605 | 0 | cursor_class->get_n_columns = tracker_deserializer_xml_get_n_columns; |
606 | 0 | cursor_class->get_value_type = tracker_deserializer_xml_get_value_type; |
607 | 0 | cursor_class->get_variable_name = tracker_deserializer_xml_get_variable_name; |
608 | 0 | cursor_class->get_string = tracker_deserializer_xml_get_string; |
609 | 0 | cursor_class->next = tracker_deserializer_xml_next; |
610 | 0 | cursor_class->next_async = tracker_deserializer_xml_next_async; |
611 | 0 | cursor_class->next_finish = tracker_deserializer_xml_next_finish; |
612 | 0 | cursor_class->close = tracker_deserializer_xml_close; |
613 | |
|
614 | 0 | deserializer_class->get_parser_location = |
615 | 0 | tracker_deserializer_xml_get_parser_location; |
616 | 0 | } |
617 | | |
618 | | static void |
619 | | tracker_deserializer_xml_init (TrackerDeserializerXml *deserializer) |
620 | 0 | { |
621 | 0 | deserializer->columns = g_ptr_array_new_with_free_func (column_free); |
622 | 0 | deserializer->column_names = g_ptr_array_new_with_free_func (xmlFree); |
623 | 0 | } |
624 | | |
625 | | TrackerSparqlCursor * |
626 | | tracker_deserializer_xml_new (GInputStream *stream, |
627 | | TrackerNamespaceManager *namespaces) |
628 | 0 | { |
629 | 0 | return g_object_new (TRACKER_TYPE_DESERIALIZER_XML, |
630 | 0 | "stream", stream, |
631 | 0 | "namespace-manager", namespaces, |
632 | | NULL); |
633 | 0 | } |