4 * Copyright (C) 2005 Novell, Inc.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
28 #include <libxml/parser.h>
32 #include "beagle-private.h"
33 #include "beagle-parser.h"
34 #include "beagle-request.h"
35 #include "beagle-response.h"
39 /* I would kill a man for some reflection */
42 /* Always present layers */
43 BEAGLE_PARSER_STATE_TOPLEVEL
,
44 BEAGLE_PARSER_STATE_RESPONSE_WRAPPER
,
45 BEAGLE_PARSER_STATE_MESSAGE
,
46 BEAGLE_PARSER_LAST_STATE
= BEAGLE_PARSER_STATE_MESSAGE
49 int _beagle_parser_state_index
= BEAGLE_PARSER_LAST_STATE
;
53 /* Specific message types */
55 PARSER_STATE_ERROR_MESSAGE
,
57 /* HitsAddedResponse */
58 PARSER_STATE_HITS_ADDED_HITS
,
59 PARSER_STATE_HITS_ADDED_HIT
,
60 PARSER_STATE_HITS_ADDED_PROPERTIES
,
61 PARSER_STATE_HITS_ADDED_PROPERTY
,
63 /* HitsSubtractedResponse */
64 PARSER_STATE_HITS_SUBTRACTED_URIS
,
65 PARSER_STATE_HITS_SUBTRACTED_URI
,
67 /* DaemonInformationResponse */
70 struct _BeagleParserContext
{
71 xmlParserCtxt
*xml_context
;
79 BeagleResponse
*response
;
82 /* Used for debugging */
88 start_message (BeagleParserContext
*ctx
, const char **attrs
)
93 GType gtype_to_match
= 0;
95 for (i
= 0; attrs
[i
] != NULL
; i
+= 2) {
96 if (strcmp (attrs
[i
], "xsi:type") == 0)
97 ctx
->message_type
= g_strdup (attrs
[i
+ 1]);
100 gtypes
= g_type_children (BEAGLE_TYPE_REQUEST
, &num_gtypes
);
102 for (i
= 0; i
< num_gtypes
; i
++) {
103 BeagleRequestClass
*klass
= g_type_class_peek (gtypes
[i
]);
106 * This can validly return NULL if we're trying to peek at a
107 * class which has never been referenced. It'll never happen
108 * for the class we're looking for, however, because it must
109 * have been referenced to be instantiated in the first place.
114 gtype_to_match
= (GType
) g_hash_table_lookup (klass
->response_types
,
117 if (gtype_to_match
!= 0)
122 g_assert (gtype_to_match
!= 0);
124 ctx
->response
= g_object_new (gtype_to_match
, 0);
128 static BeagleParserHandler parser_handlers
[] = {
129 /* Always present layers */
131 BEAGLE_PARSER_STATE_TOPLEVEL
,
132 BEAGLE_PARSER_STATE_RESPONSE_WRAPPER
,
137 BEAGLE_PARSER_STATE_RESPONSE_WRAPPER
,
138 BEAGLE_PARSER_STATE_MESSAGE
,
146 sax_start_document (void *data
)
148 BeagleParserContext
*ctx
= (BeagleParserContext
*) data
;
150 ctx
->state
= BEAGLE_PARSER_STATE_TOPLEVEL
;
154 sax_end_document (void *data
)
156 BeagleParserContext
*ctx
= (BeagleParserContext
*) data
;
158 if (ctx
->state
!= BEAGLE_PARSER_STATE_TOPLEVEL
)
159 printf ("Invalid document!\n");
162 static BeagleParserHandler
*
163 find_handler (BeagleParserContext
*ctx
, BeagleParserHandler
*handlers
, const xmlChar
*name
, gboolean src
)
167 for (i
= 0; handlers
[i
].name
!= NULL
; i
++) {
168 BeagleParserHandler handler
= handlers
[i
];
172 state
= handler
.src_state
;
174 state
= handler
.dest_state
;
176 /* -1 here is last state before we get to the per
179 state
= BEAGLE_PARSER_LAST_STATE
;
181 if (state
== ctx
->state
&&
182 strcmp (handler
.name
, name
) == 0) {
184 return &handlers
[i
];
191 static BeagleParserHandler
*
192 get_handler (BeagleParserContext
*ctx
, const xmlChar
*name
, gboolean src
)
194 BeagleResponseClass
*response_class
;
195 BeagleParserHandler
*handler
;
197 handler
= find_handler (ctx
, parser_handlers
, name
, src
);
202 /* Now try the per-object handlers */
204 response_class
= BEAGLE_RESPONSE_GET_CLASS (ctx
->response
);
206 if (response_class
->parser_handlers
) {
207 handler
= find_handler (ctx
, response_class
->parser_handlers
, name
, src
);
218 sax_start_element (void *data
, const xmlChar
*name
, const xmlChar
**attrs
)
220 BeagleParserContext
*ctx
= (BeagleParserContext
*) data
;
221 BeagleParserHandler
*handler
;
224 handler
= get_handler (ctx
, name
, TRUE
);
226 if (handler
!= NULL
) {
227 ctx
->state
= handler
->dest_state
;
229 if (handler
->start_element_func
!= NULL
)
230 handler
->start_element_func (ctx
, (const char **)attrs
);
232 g_warning ("Unhandled element: %s!\n", name
);
235 g_free (ctx
->text_buffer
);
236 ctx
->text_buffer
= NULL
;
240 sax_end_element (void *data
, const xmlChar
*name
)
242 BeagleParserContext
*ctx
= (BeagleParserContext
*) data
;
243 BeagleParserHandler
*handler
;
245 handler
= get_handler (ctx
, name
, FALSE
);
246 if (handler
!= NULL
) {
247 if (handler
->end_element_func
!= NULL
)
248 handler
->end_element_func (ctx
);
250 if (handler
->src_state
== -1)
251 ctx
->state
= BEAGLE_PARSER_LAST_STATE
;
253 ctx
->state
= handler
->src_state
;
256 g_free (ctx
->text_buffer
);
257 ctx
->text_buffer
= NULL
;
261 sax_characters (void *data
, const xmlChar
*ch
, int len
)
263 BeagleParserContext
*ctx
= (BeagleParserContext
*) data
;
265 if (ctx
->text_buffer
!= NULL
) {
266 char *buf
= g_malloc0 (ctx
->buffer_len
+ len
+ 1);
267 strcpy (buf
, ctx
->text_buffer
);
268 strncpy (buf
+ ctx
->buffer_len
, ch
, len
);
269 g_free (ctx
->text_buffer
);
270 ctx
->text_buffer
= buf
;
271 ctx
->buffer_len
+= len
;
273 ctx
->text_buffer
= g_strndup (ch
, len
);
274 ctx
->buffer_len
= len
;
279 sax_warning (void *data
, const char *msg
, ...)
283 va_start (args
, msg
);
285 printf ("warning: ");
292 sax_error (void *data
, const char *msg
, ...)
296 BeagleParserContext
*ctx
= (BeagleParserContext
*)data
;
298 g_print ("String is: %s\n", ctx
->debug_str
->str
);
300 va_start (args
, msg
);
307 g_warning ("got parser error");
310 static xmlSAXHandler sax_handler
= {
311 NULL
, /* internalSubset */
312 NULL
, /* isStandalone */
313 NULL
, /* hasInternalSubset */
314 NULL
, /* hasExternalSubset */
315 NULL
, /* resolveEntity */
316 NULL
, /* getEntity */
317 NULL
, /* entityDecl */
318 NULL
, /* notationDecl */
319 NULL
, /* attributeDecl */
320 NULL
, /* elementDecl */
321 NULL
, /* unparsedEntityDecl */
322 NULL
, /* setDocumentLocator */
323 sax_start_document
, /* startDocument */
324 sax_end_document
, /* endDocument */
325 sax_start_element
, /* startElement */
326 sax_end_element
, /* endElement */
327 NULL
, /* reference */
328 sax_characters
, /* characters */
329 NULL
, /* ignorableWhitespace */
330 NULL
, /* processingInstruction */
332 sax_warning
, /* warning */
333 sax_error
, /* error */
334 sax_error
, /* fatalError */
337 BeagleParserContext
*
338 _beagle_parser_context_new (void)
340 BeagleParserContext
*ctx
= g_new0 (BeagleParserContext
, 1);
341 ctx
->message_type
= NULL
;
342 ctx
->text_buffer
= NULL
;
343 ctx
->xml_context
= NULL
;
345 xmlSubstituteEntitiesDefault (1);
351 _beagle_parser_context_get_response (BeagleParserContext
*ctx
)
353 return ctx
->response
;
357 _beagle_parser_context_get_text_buffer (BeagleParserContext
*ctx
)
359 return g_strndup (ctx
->text_buffer
, ctx
->buffer_len
);
364 _beagle_parser_context_parse_chunk (BeagleParserContext
*ctx
, const char *buf
, gsize bytes
)
366 if (ctx
->xml_context
== NULL
) {
367 ctx
->xml_context
= xmlCreatePushParserCtxt (&sax_handler
, ctx
,
370 ctx
->debug_str
= g_string_new (NULL
);
375 g_string_append_len (ctx
->debug_str
, buf
, bytes
);
377 xmlParseChunk (ctx
->xml_context
, buf
, bytes
, 0);
381 _beagle_parser_context_finished (BeagleParserContext
*ctx
)
383 BeagleResponse
*resp
;
385 if (ctx
->xml_context
!= NULL
) {
386 xmlParseChunk (ctx
->xml_context
, NULL
, 0, 1);
387 xmlFreeParserCtxt (ctx
->xml_context
);
388 ctx
->xml_context
= NULL
;
391 g_print ("Message: %s\n", ctx
->debug_str
->str
);
392 g_string_free (ctx
->debug_str
, TRUE
);
396 resp
= ctx
->response
;
398 g_free (ctx
->message_type
);
399 g_free (ctx
->text_buffer
);