sl@0
|
1 |
/* -*- mode: C; c-file-style: "gnu" -*- */
|
sl@0
|
2 |
/* dbus-gparser.c parse DBus description files
|
sl@0
|
3 |
*
|
sl@0
|
4 |
* Copyright (C) 2003, 2005 Red Hat, Inc.
|
sl@0
|
5 |
* Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
|
sl@0
|
6 |
* Licensed under the Academic Free License version 2.1
|
sl@0
|
7 |
*
|
sl@0
|
8 |
* This program is free software; you can redistribute it and/or modify
|
sl@0
|
9 |
* it under the terms of the GNU General Public License as published by
|
sl@0
|
10 |
* the Free Software Foundation; either version 2 of the License, or
|
sl@0
|
11 |
* (at your option) any later version.
|
sl@0
|
12 |
*
|
sl@0
|
13 |
* This program is distributed in the hope that it will be useful,
|
sl@0
|
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
sl@0
|
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
sl@0
|
16 |
* GNU General Public License for more details.
|
sl@0
|
17 |
*
|
sl@0
|
18 |
* You should have received a copy of the GNU General Public License
|
sl@0
|
19 |
* along with this program; if not, write to the Free Software
|
sl@0
|
20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
sl@0
|
21 |
*
|
sl@0
|
22 |
*/
|
sl@0
|
23 |
#include "dbus-gparser.h"
|
sl@0
|
24 |
#include "dbus/dbus-glib-lowlevel.h"
|
sl@0
|
25 |
#include "dbus-gidl.h"
|
sl@0
|
26 |
#include "dbus-gobject.h"
|
sl@0
|
27 |
#include "dbus/dbus-signature.h"
|
sl@0
|
28 |
#include <string.h>
|
sl@0
|
29 |
|
sl@0
|
30 |
|
sl@0
|
31 |
|
sl@0
|
32 |
#ifndef __SYMBIAN32__
|
sl@0
|
33 |
#include <libintl.h>
|
sl@0
|
34 |
#define _(x) gettext ((x))
|
sl@0
|
35 |
#define N_(x) x
|
sl@0
|
36 |
#else
|
sl@0
|
37 |
|
sl@0
|
38 |
#define _(x) x
|
sl@0
|
39 |
#define N_(x) x
|
sl@0
|
40 |
#endif
|
sl@0
|
41 |
|
sl@0
|
42 |
|
sl@0
|
43 |
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
sl@0
|
44 |
|
sl@0
|
45 |
#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
|
sl@0
|
46 |
|
sl@0
|
47 |
typedef struct
|
sl@0
|
48 |
{
|
sl@0
|
49 |
const char *name;
|
sl@0
|
50 |
const char **retloc;
|
sl@0
|
51 |
} LocateAttr;
|
sl@0
|
52 |
|
sl@0
|
53 |
static gboolean
|
sl@0
|
54 |
locate_attributes (const char *element_name,
|
sl@0
|
55 |
const char **attribute_names,
|
sl@0
|
56 |
const char **attribute_values,
|
sl@0
|
57 |
GError **error,
|
sl@0
|
58 |
const char *first_attribute_name,
|
sl@0
|
59 |
const char **first_attribute_retloc,
|
sl@0
|
60 |
...)
|
sl@0
|
61 |
{
|
sl@0
|
62 |
va_list args;
|
sl@0
|
63 |
const char *name;
|
sl@0
|
64 |
const char **retloc;
|
sl@0
|
65 |
int n_attrs;
|
sl@0
|
66 |
#define MAX_ATTRS 24
|
sl@0
|
67 |
LocateAttr attrs[MAX_ATTRS];
|
sl@0
|
68 |
gboolean retval;
|
sl@0
|
69 |
int i;
|
sl@0
|
70 |
|
sl@0
|
71 |
g_return_val_if_fail (first_attribute_name != NULL, FALSE);
|
sl@0
|
72 |
g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
|
sl@0
|
73 |
|
sl@0
|
74 |
retval = TRUE;
|
sl@0
|
75 |
|
sl@0
|
76 |
n_attrs = 1;
|
sl@0
|
77 |
attrs[0].name = first_attribute_name;
|
sl@0
|
78 |
attrs[0].retloc = first_attribute_retloc;
|
sl@0
|
79 |
*first_attribute_retloc = NULL;
|
sl@0
|
80 |
|
sl@0
|
81 |
va_start (args, first_attribute_retloc);
|
sl@0
|
82 |
|
sl@0
|
83 |
name = va_arg (args, const char*);
|
sl@0
|
84 |
retloc = va_arg (args, const char**);
|
sl@0
|
85 |
|
sl@0
|
86 |
while (name != NULL)
|
sl@0
|
87 |
{
|
sl@0
|
88 |
g_return_val_if_fail (retloc != NULL, FALSE);
|
sl@0
|
89 |
|
sl@0
|
90 |
g_assert (n_attrs < MAX_ATTRS);
|
sl@0
|
91 |
|
sl@0
|
92 |
attrs[n_attrs].name = name;
|
sl@0
|
93 |
attrs[n_attrs].retloc = retloc;
|
sl@0
|
94 |
n_attrs += 1;
|
sl@0
|
95 |
*retloc = NULL;
|
sl@0
|
96 |
|
sl@0
|
97 |
name = va_arg (args, const char*);
|
sl@0
|
98 |
retloc = va_arg (args, const char**);
|
sl@0
|
99 |
}
|
sl@0
|
100 |
|
sl@0
|
101 |
va_end (args);
|
sl@0
|
102 |
|
sl@0
|
103 |
if (!retval)
|
sl@0
|
104 |
return retval;
|
sl@0
|
105 |
|
sl@0
|
106 |
i = 0;
|
sl@0
|
107 |
while (attribute_names[i])
|
sl@0
|
108 |
{
|
sl@0
|
109 |
int j;
|
sl@0
|
110 |
gboolean found;
|
sl@0
|
111 |
|
sl@0
|
112 |
found = FALSE;
|
sl@0
|
113 |
j = 0;
|
sl@0
|
114 |
while (j < n_attrs)
|
sl@0
|
115 |
{
|
sl@0
|
116 |
if (strcmp (attrs[j].name, attribute_names[i]) == 0)
|
sl@0
|
117 |
{
|
sl@0
|
118 |
retloc = attrs[j].retloc;
|
sl@0
|
119 |
|
sl@0
|
120 |
if (*retloc != NULL)
|
sl@0
|
121 |
{
|
sl@0
|
122 |
g_set_error (error,
|
sl@0
|
123 |
G_MARKUP_ERROR,
|
sl@0
|
124 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
125 |
_("Attribute \"%s\" repeated twice on the same <%s> element"),
|
sl@0
|
126 |
attrs[j].name, element_name);
|
sl@0
|
127 |
retval = FALSE;
|
sl@0
|
128 |
goto out;
|
sl@0
|
129 |
}
|
sl@0
|
130 |
|
sl@0
|
131 |
*retloc = attribute_values[i];
|
sl@0
|
132 |
found = TRUE;
|
sl@0
|
133 |
}
|
sl@0
|
134 |
|
sl@0
|
135 |
++j;
|
sl@0
|
136 |
}
|
sl@0
|
137 |
|
sl@0
|
138 |
if (!found)
|
sl@0
|
139 |
{
|
sl@0
|
140 |
g_set_error (error,
|
sl@0
|
141 |
G_MARKUP_ERROR,
|
sl@0
|
142 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
143 |
_("Attribute \"%s\" is invalid on <%s> element in this context"),
|
sl@0
|
144 |
attribute_names[i], element_name);
|
sl@0
|
145 |
retval = FALSE;
|
sl@0
|
146 |
goto out;
|
sl@0
|
147 |
}
|
sl@0
|
148 |
|
sl@0
|
149 |
++i;
|
sl@0
|
150 |
}
|
sl@0
|
151 |
|
sl@0
|
152 |
out:
|
sl@0
|
153 |
return retval;
|
sl@0
|
154 |
}
|
sl@0
|
155 |
|
sl@0
|
156 |
#if 0
|
sl@0
|
157 |
static gboolean
|
sl@0
|
158 |
check_no_attributes (const char *element_name,
|
sl@0
|
159 |
const char **attribute_names,
|
sl@0
|
160 |
const char **attribute_values,
|
sl@0
|
161 |
GError **error)
|
sl@0
|
162 |
{
|
sl@0
|
163 |
if (attribute_names[0] != NULL)
|
sl@0
|
164 |
{
|
sl@0
|
165 |
g_set_error (error,
|
sl@0
|
166 |
G_MARKUP_ERROR,
|
sl@0
|
167 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
168 |
_("Attribute \"%s\" is invalid on <%s> element in this context"),
|
sl@0
|
169 |
attribute_names[0], element_name);
|
sl@0
|
170 |
return FALSE;
|
sl@0
|
171 |
}
|
sl@0
|
172 |
|
sl@0
|
173 |
return TRUE;
|
sl@0
|
174 |
}
|
sl@0
|
175 |
#endif
|
sl@0
|
176 |
|
sl@0
|
177 |
struct Parser
|
sl@0
|
178 |
{
|
sl@0
|
179 |
int refcount;
|
sl@0
|
180 |
|
sl@0
|
181 |
NodeInfo *result; /* Filled in when we pop the last node */
|
sl@0
|
182 |
GSList *node_stack;
|
sl@0
|
183 |
InterfaceInfo *interface;
|
sl@0
|
184 |
MethodInfo *method;
|
sl@0
|
185 |
SignalInfo *signal;
|
sl@0
|
186 |
PropertyInfo *property;
|
sl@0
|
187 |
ArgInfo *arg;
|
sl@0
|
188 |
gboolean in_annotation;
|
sl@0
|
189 |
};
|
sl@0
|
190 |
|
sl@0
|
191 |
Parser*
|
sl@0
|
192 |
parser_new (void)
|
sl@0
|
193 |
{
|
sl@0
|
194 |
Parser *parser;
|
sl@0
|
195 |
|
sl@0
|
196 |
parser = g_new0 (Parser, 1);
|
sl@0
|
197 |
|
sl@0
|
198 |
parser->refcount = 1;
|
sl@0
|
199 |
|
sl@0
|
200 |
return parser;
|
sl@0
|
201 |
}
|
sl@0
|
202 |
|
sl@0
|
203 |
Parser *
|
sl@0
|
204 |
parser_ref (Parser *parser)
|
sl@0
|
205 |
{
|
sl@0
|
206 |
parser->refcount += 1;
|
sl@0
|
207 |
|
sl@0
|
208 |
return parser;
|
sl@0
|
209 |
}
|
sl@0
|
210 |
|
sl@0
|
211 |
void
|
sl@0
|
212 |
parser_unref (Parser *parser)
|
sl@0
|
213 |
{
|
sl@0
|
214 |
parser->refcount -= 1;
|
sl@0
|
215 |
if (parser->refcount == 0)
|
sl@0
|
216 |
{
|
sl@0
|
217 |
if (parser->result)
|
sl@0
|
218 |
node_info_unref (parser->result);
|
sl@0
|
219 |
|
sl@0
|
220 |
g_free (parser);
|
sl@0
|
221 |
}
|
sl@0
|
222 |
}
|
sl@0
|
223 |
|
sl@0
|
224 |
gboolean
|
sl@0
|
225 |
parser_check_doctype (Parser *parser,
|
sl@0
|
226 |
const char *doctype,
|
sl@0
|
227 |
GError **error)
|
sl@0
|
228 |
{
|
sl@0
|
229 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
sl@0
|
230 |
|
sl@0
|
231 |
if (strcmp (doctype, "node") != 0)
|
sl@0
|
232 |
{
|
sl@0
|
233 |
g_set_error (error,
|
sl@0
|
234 |
G_MARKUP_ERROR,
|
sl@0
|
235 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
236 |
"D-BUS description file has the wrong document type %s, use node or interface",
|
sl@0
|
237 |
doctype);
|
sl@0
|
238 |
return FALSE;
|
sl@0
|
239 |
}
|
sl@0
|
240 |
else
|
sl@0
|
241 |
return TRUE;
|
sl@0
|
242 |
}
|
sl@0
|
243 |
|
sl@0
|
244 |
static gboolean
|
sl@0
|
245 |
parse_node (Parser *parser,
|
sl@0
|
246 |
const char *element_name,
|
sl@0
|
247 |
const char **attribute_names,
|
sl@0
|
248 |
const char **attribute_values,
|
sl@0
|
249 |
GError **error)
|
sl@0
|
250 |
{
|
sl@0
|
251 |
const char *name;
|
sl@0
|
252 |
NodeInfo *node;
|
sl@0
|
253 |
|
sl@0
|
254 |
if (parser->interface ||
|
sl@0
|
255 |
parser->method ||
|
sl@0
|
256 |
parser->signal ||
|
sl@0
|
257 |
parser->property ||
|
sl@0
|
258 |
parser->arg ||
|
sl@0
|
259 |
parser->in_annotation)
|
sl@0
|
260 |
{
|
sl@0
|
261 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
262 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
263 |
_("Can't put <%s> element here"),
|
sl@0
|
264 |
element_name);
|
sl@0
|
265 |
return FALSE;
|
sl@0
|
266 |
}
|
sl@0
|
267 |
|
sl@0
|
268 |
name = NULL;
|
sl@0
|
269 |
if (!locate_attributes (element_name, attribute_names,
|
sl@0
|
270 |
attribute_values, error,
|
sl@0
|
271 |
"name", &name,
|
sl@0
|
272 |
NULL))
|
sl@0
|
273 |
return FALSE;
|
sl@0
|
274 |
|
sl@0
|
275 |
/* Only the root node can have no name */
|
sl@0
|
276 |
if (parser->node_stack != NULL && name == NULL)
|
sl@0
|
277 |
{
|
sl@0
|
278 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
279 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
280 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
281 |
"name", element_name);
|
sl@0
|
282 |
return FALSE;
|
sl@0
|
283 |
}
|
sl@0
|
284 |
|
sl@0
|
285 |
/* Root element name must be absolute */
|
sl@0
|
286 |
if (parser->node_stack == NULL && name && *name != '/')
|
sl@0
|
287 |
{
|
sl@0
|
288 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
289 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
290 |
_("\"%s\" attribute on <%s> element must be an absolute object path, \"%s\" not OK"),
|
sl@0
|
291 |
"name", element_name, name);
|
sl@0
|
292 |
return FALSE;
|
sl@0
|
293 |
}
|
sl@0
|
294 |
|
sl@0
|
295 |
/* Other element names must not be absolute */
|
sl@0
|
296 |
if (parser->node_stack != NULL && name && *name == '/')
|
sl@0
|
297 |
{
|
sl@0
|
298 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
299 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
300 |
_("\"%s\" attribute on <%s> element must not be an absolute object path, \"%s\" starts with /"),
|
sl@0
|
301 |
"name", element_name, name);
|
sl@0
|
302 |
return FALSE;
|
sl@0
|
303 |
}
|
sl@0
|
304 |
|
sl@0
|
305 |
node = node_info_new (name);
|
sl@0
|
306 |
|
sl@0
|
307 |
if (parser->node_stack != NULL)
|
sl@0
|
308 |
{
|
sl@0
|
309 |
node_info_add_node (parser->node_stack->data,
|
sl@0
|
310 |
node);
|
sl@0
|
311 |
}
|
sl@0
|
312 |
|
sl@0
|
313 |
parser->node_stack = g_slist_prepend (parser->node_stack,
|
sl@0
|
314 |
node);
|
sl@0
|
315 |
|
sl@0
|
316 |
return TRUE;
|
sl@0
|
317 |
}
|
sl@0
|
318 |
|
sl@0
|
319 |
static gboolean
|
sl@0
|
320 |
parse_interface (Parser *parser,
|
sl@0
|
321 |
const char *element_name,
|
sl@0
|
322 |
const char **attribute_names,
|
sl@0
|
323 |
const char **attribute_values,
|
sl@0
|
324 |
GError **error)
|
sl@0
|
325 |
{
|
sl@0
|
326 |
const char *name;
|
sl@0
|
327 |
InterfaceInfo *iface;
|
sl@0
|
328 |
NodeInfo *top;
|
sl@0
|
329 |
|
sl@0
|
330 |
if (parser->interface ||
|
sl@0
|
331 |
parser->method ||
|
sl@0
|
332 |
parser->signal ||
|
sl@0
|
333 |
parser->property ||
|
sl@0
|
334 |
parser->arg ||
|
sl@0
|
335 |
parser->in_annotation ||
|
sl@0
|
336 |
(parser->node_stack == NULL))
|
sl@0
|
337 |
{
|
sl@0
|
338 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
339 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
340 |
_("Can't put <%s> element here"),
|
sl@0
|
341 |
element_name);
|
sl@0
|
342 |
return FALSE;
|
sl@0
|
343 |
}
|
sl@0
|
344 |
|
sl@0
|
345 |
name = NULL;
|
sl@0
|
346 |
if (!locate_attributes (element_name, attribute_names,
|
sl@0
|
347 |
attribute_values, error,
|
sl@0
|
348 |
"name", &name,
|
sl@0
|
349 |
NULL))
|
sl@0
|
350 |
return FALSE;
|
sl@0
|
351 |
|
sl@0
|
352 |
if (name == NULL)
|
sl@0
|
353 |
{
|
sl@0
|
354 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
355 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
356 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
357 |
"name", element_name);
|
sl@0
|
358 |
return FALSE;
|
sl@0
|
359 |
}
|
sl@0
|
360 |
|
sl@0
|
361 |
top = parser->node_stack->data;
|
sl@0
|
362 |
|
sl@0
|
363 |
iface = interface_info_new (name);
|
sl@0
|
364 |
node_info_add_interface (top, iface);
|
sl@0
|
365 |
interface_info_unref (iface);
|
sl@0
|
366 |
|
sl@0
|
367 |
parser->interface = iface;
|
sl@0
|
368 |
|
sl@0
|
369 |
return TRUE;
|
sl@0
|
370 |
}
|
sl@0
|
371 |
|
sl@0
|
372 |
static gboolean
|
sl@0
|
373 |
parse_method (Parser *parser,
|
sl@0
|
374 |
const char *element_name,
|
sl@0
|
375 |
const char **attribute_names,
|
sl@0
|
376 |
const char **attribute_values,
|
sl@0
|
377 |
GError **error)
|
sl@0
|
378 |
{
|
sl@0
|
379 |
const char *name;
|
sl@0
|
380 |
MethodInfo *method;
|
sl@0
|
381 |
|
sl@0
|
382 |
if (parser->interface == NULL ||
|
sl@0
|
383 |
parser->node_stack == NULL ||
|
sl@0
|
384 |
parser->method ||
|
sl@0
|
385 |
parser->signal ||
|
sl@0
|
386 |
parser->property ||
|
sl@0
|
387 |
parser->in_annotation ||
|
sl@0
|
388 |
parser->arg)
|
sl@0
|
389 |
{
|
sl@0
|
390 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
391 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
392 |
_("Can't put <%s> element here"),
|
sl@0
|
393 |
element_name);
|
sl@0
|
394 |
return FALSE;
|
sl@0
|
395 |
}
|
sl@0
|
396 |
|
sl@0
|
397 |
name = NULL;
|
sl@0
|
398 |
if (!locate_attributes (element_name, attribute_names,
|
sl@0
|
399 |
attribute_values, error,
|
sl@0
|
400 |
"name", &name,
|
sl@0
|
401 |
NULL))
|
sl@0
|
402 |
return FALSE;
|
sl@0
|
403 |
|
sl@0
|
404 |
if (name == NULL)
|
sl@0
|
405 |
{
|
sl@0
|
406 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
407 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
408 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
409 |
"name", element_name);
|
sl@0
|
410 |
return FALSE;
|
sl@0
|
411 |
}
|
sl@0
|
412 |
|
sl@0
|
413 |
method = method_info_new (name);
|
sl@0
|
414 |
interface_info_add_method (parser->interface, method);
|
sl@0
|
415 |
method_info_unref (method);
|
sl@0
|
416 |
|
sl@0
|
417 |
parser->method = method;
|
sl@0
|
418 |
|
sl@0
|
419 |
return TRUE;
|
sl@0
|
420 |
}
|
sl@0
|
421 |
|
sl@0
|
422 |
static gboolean
|
sl@0
|
423 |
parse_signal (Parser *parser,
|
sl@0
|
424 |
const char *element_name,
|
sl@0
|
425 |
const char **attribute_names,
|
sl@0
|
426 |
const char **attribute_values,
|
sl@0
|
427 |
GError **error)
|
sl@0
|
428 |
{
|
sl@0
|
429 |
const char *name;
|
sl@0
|
430 |
SignalInfo *signal;
|
sl@0
|
431 |
|
sl@0
|
432 |
if (parser->interface == NULL ||
|
sl@0
|
433 |
parser->node_stack == NULL ||
|
sl@0
|
434 |
parser->signal ||
|
sl@0
|
435 |
parser->method ||
|
sl@0
|
436 |
parser->property ||
|
sl@0
|
437 |
parser->in_annotation ||
|
sl@0
|
438 |
parser->arg)
|
sl@0
|
439 |
{
|
sl@0
|
440 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
441 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
442 |
_("Can't put <%s> element here"),
|
sl@0
|
443 |
element_name);
|
sl@0
|
444 |
return FALSE;
|
sl@0
|
445 |
}
|
sl@0
|
446 |
|
sl@0
|
447 |
name = NULL;
|
sl@0
|
448 |
if (!locate_attributes (element_name, attribute_names,
|
sl@0
|
449 |
attribute_values, error,
|
sl@0
|
450 |
"name", &name,
|
sl@0
|
451 |
NULL))
|
sl@0
|
452 |
return FALSE;
|
sl@0
|
453 |
|
sl@0
|
454 |
if (name == NULL)
|
sl@0
|
455 |
{
|
sl@0
|
456 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
457 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
458 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
459 |
"name", element_name);
|
sl@0
|
460 |
return FALSE;
|
sl@0
|
461 |
}
|
sl@0
|
462 |
|
sl@0
|
463 |
signal = signal_info_new (name);
|
sl@0
|
464 |
interface_info_add_signal (parser->interface, signal);
|
sl@0
|
465 |
signal_info_unref (signal);
|
sl@0
|
466 |
|
sl@0
|
467 |
parser->signal = signal;
|
sl@0
|
468 |
|
sl@0
|
469 |
return TRUE;
|
sl@0
|
470 |
}
|
sl@0
|
471 |
|
sl@0
|
472 |
static gboolean
|
sl@0
|
473 |
validate_signature (const char *str,
|
sl@0
|
474 |
const char *element_name,
|
sl@0
|
475 |
GError **error)
|
sl@0
|
476 |
{
|
sl@0
|
477 |
DBusError derror;
|
sl@0
|
478 |
|
sl@0
|
479 |
dbus_error_init (&derror);
|
sl@0
|
480 |
|
sl@0
|
481 |
if (!dbus_signature_validate (str, &derror))
|
sl@0
|
482 |
{
|
sl@0
|
483 |
dbus_set_g_error (error, &derror);
|
sl@0
|
484 |
return FALSE;
|
sl@0
|
485 |
}
|
sl@0
|
486 |
return TRUE;
|
sl@0
|
487 |
}
|
sl@0
|
488 |
|
sl@0
|
489 |
static gboolean
|
sl@0
|
490 |
parse_property (Parser *parser,
|
sl@0
|
491 |
const char *element_name,
|
sl@0
|
492 |
const char **attribute_names,
|
sl@0
|
493 |
const char **attribute_values,
|
sl@0
|
494 |
GError **error)
|
sl@0
|
495 |
{
|
sl@0
|
496 |
const char *name;
|
sl@0
|
497 |
const char *access;
|
sl@0
|
498 |
const char *type;
|
sl@0
|
499 |
PropertyInfo *property;
|
sl@0
|
500 |
PropertyAccessFlags access_flags;
|
sl@0
|
501 |
|
sl@0
|
502 |
if (parser->interface == NULL ||
|
sl@0
|
503 |
parser->node_stack == NULL ||
|
sl@0
|
504 |
parser->signal ||
|
sl@0
|
505 |
parser->method ||
|
sl@0
|
506 |
parser->property ||
|
sl@0
|
507 |
parser->in_annotation ||
|
sl@0
|
508 |
parser->arg)
|
sl@0
|
509 |
{
|
sl@0
|
510 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
511 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
512 |
_("Can't put <%s> element here"),
|
sl@0
|
513 |
element_name);
|
sl@0
|
514 |
return FALSE;
|
sl@0
|
515 |
}
|
sl@0
|
516 |
|
sl@0
|
517 |
name = NULL;
|
sl@0
|
518 |
if (!locate_attributes (element_name, attribute_names,
|
sl@0
|
519 |
attribute_values, error,
|
sl@0
|
520 |
"name", &name,
|
sl@0
|
521 |
"access", &access,
|
sl@0
|
522 |
"type", &type,
|
sl@0
|
523 |
NULL))
|
sl@0
|
524 |
return FALSE;
|
sl@0
|
525 |
|
sl@0
|
526 |
if (name == NULL)
|
sl@0
|
527 |
{
|
sl@0
|
528 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
529 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
530 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
531 |
"name", element_name);
|
sl@0
|
532 |
return FALSE;
|
sl@0
|
533 |
}
|
sl@0
|
534 |
|
sl@0
|
535 |
if (access == NULL)
|
sl@0
|
536 |
{
|
sl@0
|
537 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
538 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
539 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
540 |
"access", element_name);
|
sl@0
|
541 |
return FALSE;
|
sl@0
|
542 |
}
|
sl@0
|
543 |
|
sl@0
|
544 |
if (type == NULL)
|
sl@0
|
545 |
{
|
sl@0
|
546 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
547 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
548 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
549 |
"type", element_name);
|
sl@0
|
550 |
return FALSE;
|
sl@0
|
551 |
}
|
sl@0
|
552 |
|
sl@0
|
553 |
if (!validate_signature (type, element_name, error))
|
sl@0
|
554 |
return FALSE;
|
sl@0
|
555 |
|
sl@0
|
556 |
access_flags = 0;
|
sl@0
|
557 |
if (strcmp (access, "readwrite") == 0)
|
sl@0
|
558 |
access_flags = PROPERTY_READ | PROPERTY_WRITE;
|
sl@0
|
559 |
else if (strcmp (access, "read") == 0)
|
sl@0
|
560 |
access_flags = PROPERTY_READ;
|
sl@0
|
561 |
else if (strcmp (access, "write") == 0)
|
sl@0
|
562 |
access_flags = PROPERTY_WRITE;
|
sl@0
|
563 |
else
|
sl@0
|
564 |
{
|
sl@0
|
565 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
566 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
567 |
_("access=\"%s\" must have value readwrite, read, or write on %s\n"),
|
sl@0
|
568 |
access, element_name);
|
sl@0
|
569 |
return FALSE;
|
sl@0
|
570 |
}
|
sl@0
|
571 |
|
sl@0
|
572 |
property = property_info_new (name, type, access_flags);
|
sl@0
|
573 |
interface_info_add_property (parser->interface, property);
|
sl@0
|
574 |
property_info_unref (property);
|
sl@0
|
575 |
|
sl@0
|
576 |
parser->property = property;
|
sl@0
|
577 |
|
sl@0
|
578 |
return TRUE;
|
sl@0
|
579 |
}
|
sl@0
|
580 |
|
sl@0
|
581 |
static gboolean
|
sl@0
|
582 |
parse_arg (Parser *parser,
|
sl@0
|
583 |
const char *element_name,
|
sl@0
|
584 |
const char **attribute_names,
|
sl@0
|
585 |
const char **attribute_values,
|
sl@0
|
586 |
GError **error)
|
sl@0
|
587 |
{
|
sl@0
|
588 |
const char *name;
|
sl@0
|
589 |
const char *type;
|
sl@0
|
590 |
const char *direction;
|
sl@0
|
591 |
ArgDirection dir;
|
sl@0
|
592 |
ArgInfo *arg;
|
sl@0
|
593 |
char *generated_name;
|
sl@0
|
594 |
|
sl@0
|
595 |
if (!(parser->method || parser->signal) ||
|
sl@0
|
596 |
parser->node_stack == NULL ||
|
sl@0
|
597 |
parser->property ||
|
sl@0
|
598 |
parser->in_annotation ||
|
sl@0
|
599 |
parser->arg)
|
sl@0
|
600 |
{
|
sl@0
|
601 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
602 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
603 |
_("Can't put <%s> element here"),
|
sl@0
|
604 |
element_name);
|
sl@0
|
605 |
return FALSE;
|
sl@0
|
606 |
}
|
sl@0
|
607 |
|
sl@0
|
608 |
name = NULL;
|
sl@0
|
609 |
if (!locate_attributes (element_name, attribute_names,
|
sl@0
|
610 |
attribute_values, error,
|
sl@0
|
611 |
"name", &name,
|
sl@0
|
612 |
"type", &type,
|
sl@0
|
613 |
"direction", &direction,
|
sl@0
|
614 |
NULL))
|
sl@0
|
615 |
return FALSE;
|
sl@0
|
616 |
|
sl@0
|
617 |
/* name can be null for args */
|
sl@0
|
618 |
|
sl@0
|
619 |
if (type == NULL)
|
sl@0
|
620 |
{
|
sl@0
|
621 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
622 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
623 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
624 |
"type", element_name);
|
sl@0
|
625 |
return FALSE;
|
sl@0
|
626 |
}
|
sl@0
|
627 |
|
sl@0
|
628 |
if (direction == NULL)
|
sl@0
|
629 |
{
|
sl@0
|
630 |
/* methods default to in, signal to out */
|
sl@0
|
631 |
if (parser->method)
|
sl@0
|
632 |
direction = "in";
|
sl@0
|
633 |
else if (parser->signal)
|
sl@0
|
634 |
direction = "out";
|
sl@0
|
635 |
else
|
sl@0
|
636 |
g_assert_not_reached ();
|
sl@0
|
637 |
}
|
sl@0
|
638 |
|
sl@0
|
639 |
dir = ARG_INVALID;
|
sl@0
|
640 |
|
sl@0
|
641 |
if (strcmp (direction, "in") == 0)
|
sl@0
|
642 |
dir = ARG_IN;
|
sl@0
|
643 |
else if (strcmp (direction, "out") == 0)
|
sl@0
|
644 |
dir = ARG_OUT;
|
sl@0
|
645 |
|
sl@0
|
646 |
if (dir == ARG_INVALID ||
|
sl@0
|
647 |
(parser->signal && dir == ARG_IN))
|
sl@0
|
648 |
{
|
sl@0
|
649 |
if (parser->signal)
|
sl@0
|
650 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
651 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
652 |
_("Signals must have direction=\"out\" (just omit the direction attribute)"));
|
sl@0
|
653 |
else
|
sl@0
|
654 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
655 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
656 |
_("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
|
sl@0
|
657 |
"direction", element_name);
|
sl@0
|
658 |
return FALSE;
|
sl@0
|
659 |
}
|
sl@0
|
660 |
|
sl@0
|
661 |
if (!validate_signature (type, element_name, error))
|
sl@0
|
662 |
return FALSE;
|
sl@0
|
663 |
|
sl@0
|
664 |
generated_name = NULL;
|
sl@0
|
665 |
if (name == NULL)
|
sl@0
|
666 |
generated_name = g_strdup_printf ("arg%d",
|
sl@0
|
667 |
parser->method ?
|
sl@0
|
668 |
method_info_get_n_args (parser->method) :
|
sl@0
|
669 |
signal_info_get_n_args (parser->signal));
|
sl@0
|
670 |
|
sl@0
|
671 |
arg = arg_info_new (name ? name : generated_name, dir, type);
|
sl@0
|
672 |
if (parser->method)
|
sl@0
|
673 |
method_info_add_arg (parser->method, arg);
|
sl@0
|
674 |
else if (parser->signal)
|
sl@0
|
675 |
signal_info_add_arg (parser->signal, arg);
|
sl@0
|
676 |
else
|
sl@0
|
677 |
g_assert_not_reached ();
|
sl@0
|
678 |
|
sl@0
|
679 |
g_free (generated_name);
|
sl@0
|
680 |
|
sl@0
|
681 |
arg_info_unref (arg);
|
sl@0
|
682 |
|
sl@0
|
683 |
parser->arg = arg;
|
sl@0
|
684 |
|
sl@0
|
685 |
return TRUE;
|
sl@0
|
686 |
}
|
sl@0
|
687 |
|
sl@0
|
688 |
static gboolean
|
sl@0
|
689 |
parse_annotation (Parser *parser,
|
sl@0
|
690 |
const char *element_name,
|
sl@0
|
691 |
const char **attribute_names,
|
sl@0
|
692 |
const char **attribute_values,
|
sl@0
|
693 |
GError **error)
|
sl@0
|
694 |
{
|
sl@0
|
695 |
const char *name;
|
sl@0
|
696 |
const char *value;
|
sl@0
|
697 |
|
sl@0
|
698 |
if (!(parser->method || parser->interface || parser->arg) ||
|
sl@0
|
699 |
parser->node_stack == NULL ||
|
sl@0
|
700 |
parser->signal ||
|
sl@0
|
701 |
parser->property ||
|
sl@0
|
702 |
parser->in_annotation)
|
sl@0
|
703 |
{
|
sl@0
|
704 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
705 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
706 |
_("Can't put <%s> element here"),
|
sl@0
|
707 |
element_name);
|
sl@0
|
708 |
return FALSE;
|
sl@0
|
709 |
}
|
sl@0
|
710 |
|
sl@0
|
711 |
name = NULL;
|
sl@0
|
712 |
if (!locate_attributes (element_name, attribute_names,
|
sl@0
|
713 |
attribute_values, error,
|
sl@0
|
714 |
"name", &name,
|
sl@0
|
715 |
"value", &value,
|
sl@0
|
716 |
NULL))
|
sl@0
|
717 |
return FALSE;
|
sl@0
|
718 |
|
sl@0
|
719 |
if (name == NULL)
|
sl@0
|
720 |
{
|
sl@0
|
721 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
722 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
723 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
724 |
"name", element_name);
|
sl@0
|
725 |
return FALSE;
|
sl@0
|
726 |
}
|
sl@0
|
727 |
if (value == NULL)
|
sl@0
|
728 |
{
|
sl@0
|
729 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
730 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
731 |
_("\"%s\" attribute required on <%s> element "),
|
sl@0
|
732 |
"value", element_name);
|
sl@0
|
733 |
return FALSE;
|
sl@0
|
734 |
}
|
sl@0
|
735 |
|
sl@0
|
736 |
if (parser->arg)
|
sl@0
|
737 |
arg_info_add_annotation (parser->arg, name, value);
|
sl@0
|
738 |
else if (parser->method)
|
sl@0
|
739 |
method_info_add_annotation (parser->method, name, value);
|
sl@0
|
740 |
else if (parser->interface)
|
sl@0
|
741 |
interface_info_add_annotation (parser->interface, name, value);
|
sl@0
|
742 |
else
|
sl@0
|
743 |
g_assert_not_reached ();
|
sl@0
|
744 |
|
sl@0
|
745 |
parser->in_annotation = TRUE;
|
sl@0
|
746 |
|
sl@0
|
747 |
return TRUE;
|
sl@0
|
748 |
}
|
sl@0
|
749 |
|
sl@0
|
750 |
gboolean
|
sl@0
|
751 |
parser_start_element (Parser *parser,
|
sl@0
|
752 |
const char *element_name,
|
sl@0
|
753 |
const char **attribute_names,
|
sl@0
|
754 |
const char **attribute_values,
|
sl@0
|
755 |
GError **error)
|
sl@0
|
756 |
{
|
sl@0
|
757 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
sl@0
|
758 |
|
sl@0
|
759 |
if (ELEMENT_IS ("node"))
|
sl@0
|
760 |
{
|
sl@0
|
761 |
if (!parse_node (parser, element_name, attribute_names,
|
sl@0
|
762 |
attribute_values, error))
|
sl@0
|
763 |
return FALSE;
|
sl@0
|
764 |
}
|
sl@0
|
765 |
else if (ELEMENT_IS ("interface"))
|
sl@0
|
766 |
{
|
sl@0
|
767 |
if (!parse_interface (parser, element_name, attribute_names,
|
sl@0
|
768 |
attribute_values, error))
|
sl@0
|
769 |
return FALSE;
|
sl@0
|
770 |
}
|
sl@0
|
771 |
else if (ELEMENT_IS ("method"))
|
sl@0
|
772 |
{
|
sl@0
|
773 |
if (!parse_method (parser, element_name, attribute_names,
|
sl@0
|
774 |
attribute_values, error))
|
sl@0
|
775 |
return FALSE;
|
sl@0
|
776 |
}
|
sl@0
|
777 |
else if (ELEMENT_IS ("signal"))
|
sl@0
|
778 |
{
|
sl@0
|
779 |
if (!parse_signal (parser, element_name, attribute_names,
|
sl@0
|
780 |
attribute_values, error))
|
sl@0
|
781 |
return FALSE;
|
sl@0
|
782 |
}
|
sl@0
|
783 |
else if (ELEMENT_IS ("property"))
|
sl@0
|
784 |
{
|
sl@0
|
785 |
if (!parse_property (parser, element_name, attribute_names,
|
sl@0
|
786 |
attribute_values, error))
|
sl@0
|
787 |
return FALSE;
|
sl@0
|
788 |
}
|
sl@0
|
789 |
else if (ELEMENT_IS ("arg"))
|
sl@0
|
790 |
{
|
sl@0
|
791 |
if (!parse_arg (parser, element_name, attribute_names,
|
sl@0
|
792 |
attribute_values, error))
|
sl@0
|
793 |
return FALSE;
|
sl@0
|
794 |
}
|
sl@0
|
795 |
else if (ELEMENT_IS ("annotation"))
|
sl@0
|
796 |
{
|
sl@0
|
797 |
if (!parse_annotation (parser, element_name, attribute_names,
|
sl@0
|
798 |
attribute_values, error))
|
sl@0
|
799 |
return FALSE;
|
sl@0
|
800 |
}
|
sl@0
|
801 |
else
|
sl@0
|
802 |
{
|
sl@0
|
803 |
g_set_error (error, G_MARKUP_ERROR,
|
sl@0
|
804 |
G_MARKUP_ERROR_PARSE,
|
sl@0
|
805 |
_("Element <%s> not recognized"),
|
sl@0
|
806 |
element_name);
|
sl@0
|
807 |
}
|
sl@0
|
808 |
|
sl@0
|
809 |
return TRUE;
|
sl@0
|
810 |
}
|
sl@0
|
811 |
|
sl@0
|
812 |
gboolean
|
sl@0
|
813 |
parser_end_element (Parser *parser,
|
sl@0
|
814 |
const char *element_name,
|
sl@0
|
815 |
GError **error)
|
sl@0
|
816 |
{
|
sl@0
|
817 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
sl@0
|
818 |
|
sl@0
|
819 |
if (ELEMENT_IS ("interface"))
|
sl@0
|
820 |
{
|
sl@0
|
821 |
parser->interface = NULL;
|
sl@0
|
822 |
}
|
sl@0
|
823 |
else if (ELEMENT_IS ("method"))
|
sl@0
|
824 |
{
|
sl@0
|
825 |
parser->method = NULL;
|
sl@0
|
826 |
}
|
sl@0
|
827 |
else if (ELEMENT_IS ("signal"))
|
sl@0
|
828 |
{
|
sl@0
|
829 |
parser->signal = NULL;
|
sl@0
|
830 |
}
|
sl@0
|
831 |
else if (ELEMENT_IS ("property"))
|
sl@0
|
832 |
{
|
sl@0
|
833 |
parser->property = NULL;
|
sl@0
|
834 |
}
|
sl@0
|
835 |
else if (ELEMENT_IS ("arg"))
|
sl@0
|
836 |
{
|
sl@0
|
837 |
parser->arg = NULL;
|
sl@0
|
838 |
}
|
sl@0
|
839 |
else if (ELEMENT_IS ("annotation"))
|
sl@0
|
840 |
{
|
sl@0
|
841 |
parser->in_annotation = FALSE;
|
sl@0
|
842 |
}
|
sl@0
|
843 |
else if (ELEMENT_IS ("node"))
|
sl@0
|
844 |
{
|
sl@0
|
845 |
NodeInfo *top;
|
sl@0
|
846 |
|
sl@0
|
847 |
g_assert (parser->node_stack != NULL);
|
sl@0
|
848 |
top = parser->node_stack->data;
|
sl@0
|
849 |
|
sl@0
|
850 |
parser->node_stack = g_slist_remove (parser->node_stack,
|
sl@0
|
851 |
top);
|
sl@0
|
852 |
|
sl@0
|
853 |
if (parser->node_stack == NULL)
|
sl@0
|
854 |
parser->result = top; /* We are done, store the result */
|
sl@0
|
855 |
}
|
sl@0
|
856 |
else
|
sl@0
|
857 |
g_assert_not_reached (); /* should have had an error on start_element */
|
sl@0
|
858 |
|
sl@0
|
859 |
return TRUE;
|
sl@0
|
860 |
}
|
sl@0
|
861 |
|
sl@0
|
862 |
gboolean
|
sl@0
|
863 |
parser_content (Parser *parser,
|
sl@0
|
864 |
const char *content,
|
sl@0
|
865 |
int len,
|
sl@0
|
866 |
GError **error)
|
sl@0
|
867 |
{
|
sl@0
|
868 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
sl@0
|
869 |
|
sl@0
|
870 |
/* FIXME check that it's all whitespace */
|
sl@0
|
871 |
|
sl@0
|
872 |
return TRUE;
|
sl@0
|
873 |
}
|
sl@0
|
874 |
|
sl@0
|
875 |
gboolean
|
sl@0
|
876 |
parser_finished (Parser *parser,
|
sl@0
|
877 |
GError **error)
|
sl@0
|
878 |
{
|
sl@0
|
879 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
sl@0
|
880 |
|
sl@0
|
881 |
return TRUE;
|
sl@0
|
882 |
}
|
sl@0
|
883 |
|
sl@0
|
884 |
NodeInfo*
|
sl@0
|
885 |
parser_get_nodes (Parser *parser)
|
sl@0
|
886 |
{
|
sl@0
|
887 |
return parser->result;
|
sl@0
|
888 |
}
|
sl@0
|
889 |
|
sl@0
|
890 |
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
|