|
1 /* -*- mode: C; c-file-style: "gnu" -*- */ |
|
2 /* desktop-file.c .desktop file parser |
|
3 * |
|
4 * Copyright (C) 2003 CodeFactory AB |
|
5 * Copyright (C) 2003 Red Hat Inc. |
|
6 * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
7 * Licensed under the Academic Free License version 2.1 |
|
8 * |
|
9 * This program is free software; you can redistribute it and/or modify |
|
10 * it under the terms of the GNU General Public License as published by |
|
11 * the Free Software Foundation; either version 2 of the License, or |
|
12 * (at your option) any later version. |
|
13 * |
|
14 * This program is distributed in the hope that it will be useful, |
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
17 * GNU General Public License for more details. |
|
18 * |
|
19 * You should have received a copy of the GNU General Public License |
|
20 * along with this program; if not, write to the Free Software |
|
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
22 * |
|
23 */ |
|
24 #ifndef __SYMBIAN32__ |
|
25 #include <dbus/dbus-sysdeps.h> |
|
26 #include <dbus/dbus-internals.h> |
|
27 #else |
|
28 #include "dbus-sysdeps.h" |
|
29 #include "dbus-internals.h" |
|
30 #endif //__SYMBIAN32__ |
|
31 #include "desktop-file.h" |
|
32 #include "utils.h" |
|
33 |
|
34 typedef struct |
|
35 { |
|
36 char *key; |
|
37 char *value; |
|
38 } BusDesktopFileLine; |
|
39 |
|
40 typedef struct |
|
41 { |
|
42 char *section_name; |
|
43 |
|
44 int n_lines; |
|
45 BusDesktopFileLine *lines; |
|
46 int n_allocated_lines; |
|
47 } BusDesktopFileSection; |
|
48 |
|
49 struct BusDesktopFile |
|
50 { |
|
51 int n_sections; |
|
52 BusDesktopFileSection *sections; |
|
53 int n_allocated_sections; |
|
54 }; |
|
55 |
|
56 /** |
|
57 * Parser for service files. |
|
58 */ |
|
59 typedef struct |
|
60 { |
|
61 DBusString data; /**< The data from the file */ |
|
62 |
|
63 BusDesktopFile *desktop_file; /**< The resulting object */ |
|
64 int current_section; /**< The current section being parsed */ |
|
65 |
|
66 int pos; /**< Current position */ |
|
67 int len; /**< Length */ |
|
68 int line_num; /**< Current line number */ |
|
69 |
|
70 } BusDesktopFileParser; |
|
71 |
|
72 #define VALID_KEY_CHAR 1 |
|
73 #define VALID_LOCALE_CHAR 2 |
|
74 unsigned char valid[256] = { |
|
75 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
76 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
77 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x3 , 0x2 , 0x0 , |
|
78 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
79 0x0 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , |
|
80 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , |
|
81 0x0 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , |
|
82 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
83 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
84 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
85 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
86 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
87 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
88 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
89 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
90 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , |
|
91 }; |
|
92 |
|
93 static void report_error (BusDesktopFileParser *parser, |
|
94 char *message, |
|
95 const char *error_name, |
|
96 DBusError *error); |
|
97 |
|
98 static void |
|
99 parser_free (BusDesktopFileParser *parser) |
|
100 { |
|
101 bus_desktop_file_free (parser->desktop_file); |
|
102 |
|
103 _dbus_string_free (&parser->data); |
|
104 } |
|
105 |
|
106 static void |
|
107 bus_desktop_file_line_free (BusDesktopFileLine *line) |
|
108 { |
|
109 dbus_free (line->key); |
|
110 dbus_free (line->value); |
|
111 } |
|
112 |
|
113 static void |
|
114 bus_desktop_file_section_free (BusDesktopFileSection *section) |
|
115 { |
|
116 int i; |
|
117 |
|
118 for (i = 0; i < section->n_lines; i++) |
|
119 bus_desktop_file_line_free (§ion->lines[i]); |
|
120 |
|
121 dbus_free (section->lines); |
|
122 dbus_free (section->section_name); |
|
123 } |
|
124 |
|
125 void |
|
126 bus_desktop_file_free (BusDesktopFile *desktop_file) |
|
127 { |
|
128 int i; |
|
129 |
|
130 for (i = 0; i < desktop_file->n_sections; i++) |
|
131 bus_desktop_file_section_free (&desktop_file->sections[i]); |
|
132 dbus_free (desktop_file->sections); |
|
133 |
|
134 dbus_free (desktop_file); |
|
135 } |
|
136 |
|
137 static dbus_bool_t |
|
138 grow_lines_in_section (BusDesktopFileSection *section) |
|
139 { |
|
140 BusDesktopFileLine *lines; |
|
141 |
|
142 int new_n_lines; |
|
143 |
|
144 if (section->n_allocated_lines == 0) |
|
145 new_n_lines = 1; |
|
146 else |
|
147 new_n_lines = section->n_allocated_lines*2; |
|
148 |
|
149 lines = dbus_realloc (section->lines, |
|
150 sizeof (BusDesktopFileLine) * new_n_lines); |
|
151 |
|
152 if (lines == NULL) |
|
153 return FALSE; |
|
154 |
|
155 section->lines = lines; |
|
156 section->n_allocated_lines = new_n_lines; |
|
157 |
|
158 return TRUE; |
|
159 } |
|
160 |
|
161 static dbus_bool_t |
|
162 grow_sections (BusDesktopFile *desktop_file) |
|
163 { |
|
164 int new_n_sections; |
|
165 BusDesktopFileSection *sections; |
|
166 |
|
167 if (desktop_file->n_allocated_sections == 0) |
|
168 new_n_sections = 1; |
|
169 else |
|
170 new_n_sections = desktop_file->n_allocated_sections*2; |
|
171 |
|
172 sections = dbus_realloc (desktop_file->sections, |
|
173 sizeof (BusDesktopFileSection) * new_n_sections); |
|
174 if (sections == NULL) |
|
175 return FALSE; |
|
176 |
|
177 desktop_file->sections = sections; |
|
178 |
|
179 desktop_file->n_allocated_sections = new_n_sections; |
|
180 |
|
181 return TRUE; |
|
182 } |
|
183 |
|
184 static char * |
|
185 unescape_string (BusDesktopFileParser *parser, |
|
186 const DBusString *str, |
|
187 int pos, |
|
188 int end_pos, |
|
189 DBusError *error) |
|
190 { |
|
191 char *retval, *q; |
|
192 |
|
193 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
194 |
|
195 /* len + 1 is enough, because unescaping never makes the |
|
196 * string longer |
|
197 */ |
|
198 retval = dbus_malloc (end_pos - pos + 1); |
|
199 if (retval == NULL) |
|
200 { |
|
201 BUS_SET_OOM (error); |
|
202 return NULL; |
|
203 } |
|
204 |
|
205 q = retval; |
|
206 |
|
207 while (pos < end_pos) |
|
208 { |
|
209 if (_dbus_string_get_byte (str, pos) == 0) |
|
210 { |
|
211 /* Found an embedded null */ |
|
212 dbus_free (retval); |
|
213 report_error (parser, "Text to be unescaped contains embedded nul", |
|
214 BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); |
|
215 return NULL; |
|
216 } |
|
217 |
|
218 if (_dbus_string_get_byte (str, pos) == '\\') |
|
219 { |
|
220 pos ++; |
|
221 |
|
222 if (pos >= end_pos) |
|
223 { |
|
224 /* Escape at end of string */ |
|
225 dbus_free (retval); |
|
226 report_error (parser, "Text to be unescaped ended in \\", |
|
227 BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); |
|
228 return NULL; |
|
229 } |
|
230 |
|
231 switch (_dbus_string_get_byte (str, pos)) |
|
232 { |
|
233 case 's': |
|
234 *q++ = ' '; |
|
235 break; |
|
236 case 't': |
|
237 *q++ = '\t'; |
|
238 break; |
|
239 case 'n': |
|
240 *q++ = '\n'; |
|
241 break; |
|
242 case 'r': |
|
243 *q++ = '\r'; |
|
244 break; |
|
245 case '\\': |
|
246 *q++ = '\\'; |
|
247 break; |
|
248 default: |
|
249 /* Invalid escape code */ |
|
250 dbus_free (retval); |
|
251 report_error (parser, "Text to be unescaped had invalid escape sequence", |
|
252 BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); |
|
253 return NULL; |
|
254 } |
|
255 pos++; |
|
256 } |
|
257 else |
|
258 { |
|
259 *q++ =_dbus_string_get_byte (str, pos); |
|
260 |
|
261 pos++; |
|
262 } |
|
263 } |
|
264 |
|
265 *q = 0; |
|
266 |
|
267 return retval; |
|
268 } |
|
269 |
|
270 static BusDesktopFileSection* |
|
271 new_section (BusDesktopFile *desktop_file, |
|
272 const char *name) |
|
273 { |
|
274 int n; |
|
275 char *name_copy; |
|
276 |
|
277 if (desktop_file->n_allocated_sections == desktop_file->n_sections) |
|
278 { |
|
279 if (!grow_sections (desktop_file)) |
|
280 return NULL; |
|
281 } |
|
282 |
|
283 name_copy = _dbus_strdup (name); |
|
284 if (name_copy == NULL) |
|
285 return NULL; |
|
286 |
|
287 n = desktop_file->n_sections; |
|
288 desktop_file->sections[n].section_name = name_copy; |
|
289 |
|
290 desktop_file->sections[n].n_lines = 0; |
|
291 desktop_file->sections[n].lines = NULL; |
|
292 desktop_file->sections[n].n_allocated_lines = 0; |
|
293 |
|
294 if (!grow_lines_in_section (&desktop_file->sections[n])) |
|
295 { |
|
296 dbus_free (desktop_file->sections[n].section_name); |
|
297 desktop_file->sections[n].section_name = NULL; |
|
298 return NULL; |
|
299 } |
|
300 |
|
301 desktop_file->n_sections += 1; |
|
302 |
|
303 return &desktop_file->sections[n]; |
|
304 } |
|
305 |
|
306 static BusDesktopFileSection* |
|
307 open_section (BusDesktopFileParser *parser, |
|
308 char *name) |
|
309 { |
|
310 BusDesktopFileSection *section; |
|
311 |
|
312 section = new_section (parser->desktop_file, name); |
|
313 if (section == NULL) |
|
314 return NULL; |
|
315 |
|
316 parser->current_section = parser->desktop_file->n_sections - 1; |
|
317 _dbus_assert (&parser->desktop_file->sections[parser->current_section] == section); |
|
318 |
|
319 return section; |
|
320 } |
|
321 |
|
322 static BusDesktopFileLine * |
|
323 new_line (BusDesktopFileParser *parser) |
|
324 { |
|
325 BusDesktopFileSection *section; |
|
326 BusDesktopFileLine *line; |
|
327 |
|
328 section = &parser->desktop_file->sections[parser->current_section]; |
|
329 |
|
330 if (section->n_allocated_lines == section->n_lines) |
|
331 { |
|
332 if (!grow_lines_in_section (section)) |
|
333 return NULL; |
|
334 } |
|
335 |
|
336 line = §ion->lines[section->n_lines++]; |
|
337 |
|
338 memset (line, 0, sizeof (BusDesktopFileLine)); |
|
339 |
|
340 return line; |
|
341 } |
|
342 |
|
343 static dbus_bool_t |
|
344 is_blank_line (BusDesktopFileParser *parser) |
|
345 { |
|
346 int p; |
|
347 char c; |
|
348 |
|
349 p = parser->pos; |
|
350 |
|
351 c = _dbus_string_get_byte (&parser->data, p); |
|
352 |
|
353 while (c && c != '\n') |
|
354 { |
|
355 if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f')) |
|
356 return FALSE; |
|
357 |
|
358 p++; |
|
359 c = _dbus_string_get_byte (&parser->data, p); |
|
360 } |
|
361 |
|
362 return TRUE; |
|
363 } |
|
364 |
|
365 static void |
|
366 parse_comment_or_blank (BusDesktopFileParser *parser) |
|
367 { |
|
368 int line_end; |
|
369 #ifdef __SYMBIAN32__ |
|
370 int eol_len; |
|
371 #endif |
|
372 |
|
373 #ifdef __SYMBIAN32__ |
|
374 if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len)) |
|
375 line_end = parser->len; |
|
376 #else |
|
377 if (!_dbus_string_find (&parser->data, parser->pos, "\n", &line_end)) |
|
378 line_end = parser->len; |
|
379 #endif |
|
380 |
|
381 if (line_end == parser->len) |
|
382 parser->pos = parser->len; |
|
383 else |
|
384 #ifdef __SYMBAN32__ |
|
385 parser->pos = line_end + eol_len; |
|
386 #else |
|
387 parser->pos = line_end + 1; |
|
388 #endif |
|
389 |
|
390 parser->line_num += 1; |
|
391 } |
|
392 |
|
393 static dbus_bool_t |
|
394 is_valid_section_name (const char *name) |
|
395 { |
|
396 /* 5. Group names may contain all ASCII characters except for control characters and '[' and ']'. */ |
|
397 |
|
398 while (*name) |
|
399 { |
|
400 if (!((*name >= 'A' && *name <= 'Z') || (*name >= 'a' || *name <= 'z') || |
|
401 *name == '\n' || *name == '\t')) |
|
402 return FALSE; |
|
403 |
|
404 name++; |
|
405 } |
|
406 |
|
407 return TRUE; |
|
408 } |
|
409 |
|
410 static dbus_bool_t |
|
411 parse_section_start (BusDesktopFileParser *parser, DBusError *error) |
|
412 { |
|
413 int line_end; |
|
414 #ifdef __SYMBIAN32__ |
|
415 int eol_len; |
|
416 #endif |
|
417 char *section_name; |
|
418 |
|
419 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
420 |
|
421 #ifdef __SYMBIAN32__ |
|
422 if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len)) |
|
423 line_end = parser->len; |
|
424 #else |
|
425 if (!_dbus_string_find (&parser->data, parser->pos, "\n", &line_end)) |
|
426 line_end = parser->len; |
|
427 #endif //__SYMBIAN32__ |
|
428 |
|
429 if (line_end - parser->pos <= 2 || |
|
430 _dbus_string_get_byte (&parser->data, line_end - 1) != ']') |
|
431 { |
|
432 report_error (parser, "Invalid syntax for section header", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); |
|
433 parser_free (parser); |
|
434 return FALSE; |
|
435 } |
|
436 |
|
437 section_name = unescape_string (parser, |
|
438 &parser->data, parser->pos + 1, line_end - 1, |
|
439 error); |
|
440 |
|
441 if (section_name == NULL) |
|
442 { |
|
443 parser_free (parser); |
|
444 return FALSE; |
|
445 } |
|
446 |
|
447 if (!is_valid_section_name (section_name)) |
|
448 { |
|
449 report_error (parser, "Invalid characters in section name", BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS, error); |
|
450 parser_free (parser); |
|
451 dbus_free (section_name); |
|
452 return FALSE; |
|
453 } |
|
454 |
|
455 if (open_section (parser, section_name) == NULL) |
|
456 { |
|
457 dbus_free (section_name); |
|
458 parser_free (parser); |
|
459 BUS_SET_OOM (error); |
|
460 return FALSE; |
|
461 } |
|
462 |
|
463 if (line_end == parser->len) |
|
464 parser->pos = parser->len; |
|
465 else |
|
466 #ifdef __SYMBIAN32__ |
|
467 parser->pos = line_end + eol_len; |
|
468 #else |
|
469 parser->pos = line_end + 1; |
|
470 #endif |
|
471 |
|
472 parser->line_num += 1; |
|
473 |
|
474 dbus_free (section_name); |
|
475 |
|
476 return TRUE; |
|
477 } |
|
478 |
|
479 static dbus_bool_t |
|
480 parse_key_value (BusDesktopFileParser *parser, DBusError *error) |
|
481 { |
|
482 int line_end; |
|
483 int key_start, key_end; |
|
484 int value_start; |
|
485 int p; |
|
486 char *value, *tmp; |
|
487 DBusString key; |
|
488 BusDesktopFileLine *line; |
|
489 #ifdef __SYMBIAN32__ |
|
490 int eol_len; |
|
491 #endif |
|
492 |
|
493 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
494 |
|
495 #ifdef __SYMBIAN32__ |
|
496 if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len)) |
|
497 line_end = parser->len; |
|
498 #else |
|
499 if (!_dbus_string_find (&parser->data, parser->pos, "\n", &line_end)) |
|
500 line_end = parser->len; |
|
501 #endif |
|
502 |
|
503 p = parser->pos; |
|
504 key_start = p; |
|
505 while (p < line_end && |
|
506 (valid[_dbus_string_get_byte (&parser->data, p)] & VALID_KEY_CHAR)) |
|
507 p++; |
|
508 key_end = p; |
|
509 |
|
510 if (key_start == key_end) |
|
511 { |
|
512 report_error (parser, "Empty key name", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); |
|
513 parser_free (parser); |
|
514 return FALSE; |
|
515 } |
|
516 |
|
517 /* We ignore locales for now */ |
|
518 if (p < line_end && _dbus_string_get_byte (&parser->data, p) == '[') |
|
519 { |
|
520 if (line_end == parser->len) |
|
521 parser->pos = parser->len; |
|
522 else |
|
523 #ifdef __SYMBIAN32__ |
|
524 parser->pos = line_end + eol_len; |
|
525 #else |
|
526 parser->pos = line_end + 1; |
|
527 #endif |
|
528 |
|
529 parser->line_num += 1; |
|
530 |
|
531 return TRUE; |
|
532 } |
|
533 |
|
534 /* Skip space before '=' */ |
|
535 while (p < line_end && _dbus_string_get_byte (&parser->data, p) == ' ') |
|
536 p++; |
|
537 |
|
538 if (p < line_end && _dbus_string_get_byte (&parser->data, p) != '=') |
|
539 { |
|
540 report_error (parser, "Invalid characters in key name", BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS, error); |
|
541 parser_free (parser); |
|
542 return FALSE; |
|
543 } |
|
544 |
|
545 if (p == line_end) |
|
546 { |
|
547 report_error (parser, "No '=' in key/value pair", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); |
|
548 parser_free (parser); |
|
549 return FALSE; |
|
550 } |
|
551 |
|
552 /* Skip the '=' */ |
|
553 p++; |
|
554 |
|
555 /* Skip space after '=' */ |
|
556 while (p < line_end && _dbus_string_get_byte (&parser->data, p) == ' ') |
|
557 p++; |
|
558 |
|
559 value_start = p; |
|
560 |
|
561 value = unescape_string (parser, &parser->data, value_start, line_end, error); |
|
562 if (value == NULL) |
|
563 { |
|
564 parser_free (parser); |
|
565 return FALSE; |
|
566 } |
|
567 |
|
568 line = new_line (parser); |
|
569 if (line == NULL) |
|
570 { |
|
571 dbus_free (value); |
|
572 parser_free (parser); |
|
573 BUS_SET_OOM (error); |
|
574 return FALSE; |
|
575 } |
|
576 |
|
577 if (!_dbus_string_init (&key)) |
|
578 { |
|
579 dbus_free (value); |
|
580 parser_free (parser); |
|
581 BUS_SET_OOM (error); |
|
582 return FALSE; |
|
583 } |
|
584 |
|
585 if (!_dbus_string_copy_len (&parser->data, key_start, key_end - key_start, |
|
586 &key, 0)) |
|
587 { |
|
588 _dbus_string_free (&key); |
|
589 dbus_free (value); |
|
590 parser_free (parser); |
|
591 BUS_SET_OOM (error); |
|
592 return FALSE; |
|
593 } |
|
594 |
|
595 if (!_dbus_string_steal_data (&key, &tmp)) |
|
596 { |
|
597 _dbus_string_free (&key); |
|
598 dbus_free (value); |
|
599 parser_free (parser); |
|
600 BUS_SET_OOM (error); |
|
601 return FALSE; |
|
602 } |
|
603 |
|
604 _dbus_string_free (&key); |
|
605 |
|
606 line->key = tmp; |
|
607 line->value = value; |
|
608 |
|
609 if (line_end == parser->len) |
|
610 parser->pos = parser->len; |
|
611 else |
|
612 parser->pos = line_end + 1; |
|
613 |
|
614 parser->line_num += 1; |
|
615 |
|
616 return TRUE; |
|
617 } |
|
618 |
|
619 static void |
|
620 report_error (BusDesktopFileParser *parser, |
|
621 char *message, |
|
622 const char *error_name, |
|
623 DBusError *error) |
|
624 { |
|
625 const char *section_name = NULL; |
|
626 |
|
627 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
628 |
|
629 if (parser->current_section != -1) |
|
630 section_name = parser->desktop_file->sections[parser->current_section].section_name; |
|
631 |
|
632 if (section_name) |
|
633 dbus_set_error (error, error_name, |
|
634 "Error in section %s at line %d: %s\n", section_name, parser->line_num, message); |
|
635 else |
|
636 dbus_set_error (error, error_name, |
|
637 "Error at line %d: %s\n", parser->line_num, message); |
|
638 } |
|
639 |
|
640 #if 0 |
|
641 static void |
|
642 dump_desktop_file (BusDesktopFile *file) |
|
643 { |
|
644 int i; |
|
645 |
|
646 for (i = 0; i < file->n_sections; i++) |
|
647 { |
|
648 int j; |
|
649 |
|
650 printf ("[%s]\n", file->sections[i].section_name); |
|
651 |
|
652 for (j = 0; j < file->sections[i].n_lines; j++) |
|
653 { |
|
654 printf ("%s=%s\n", file->sections[i].lines[j].key, |
|
655 file->sections[i].lines[j].value); |
|
656 } |
|
657 } |
|
658 } |
|
659 #endif |
|
660 |
|
661 BusDesktopFile* |
|
662 bus_desktop_file_load (DBusString *filename, |
|
663 DBusError *error) |
|
664 { |
|
665 DBusString str; |
|
666 BusDesktopFileParser parser; |
|
667 DBusStat sb; |
|
668 |
|
669 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
670 |
|
671 /* Clearly there's a race here, but it's just to make it unlikely |
|
672 * that we do something silly, we still handle doing it below. |
|
673 */ |
|
674 if (!_dbus_stat (filename, &sb, error)) |
|
675 return NULL; |
|
676 |
|
677 if (sb.size > _DBUS_ONE_KILOBYTE * 128) |
|
678 { |
|
679 dbus_set_error (error, DBUS_ERROR_FAILED, |
|
680 "Desktop file size (%ld bytes) is too large", (long) sb.size); |
|
681 return NULL; |
|
682 } |
|
683 |
|
684 if (!_dbus_string_init (&str)) |
|
685 { |
|
686 BUS_SET_OOM (error); |
|
687 return NULL; |
|
688 } |
|
689 |
|
690 if (!_dbus_file_get_contents (&str, filename, error)) |
|
691 { |
|
692 _dbus_string_free (&str); |
|
693 return NULL; |
|
694 } |
|
695 |
|
696 if (!_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str))) |
|
697 { |
|
698 _dbus_string_free (&str); |
|
699 dbus_set_error (error, DBUS_ERROR_FAILED, |
|
700 "invalid UTF-8"); |
|
701 return NULL; |
|
702 } |
|
703 |
|
704 parser.desktop_file = dbus_new0 (BusDesktopFile, 1); |
|
705 if (parser.desktop_file == NULL) |
|
706 { |
|
707 _dbus_string_free (&str); |
|
708 BUS_SET_OOM (error); |
|
709 return NULL; |
|
710 } |
|
711 |
|
712 parser.data = str; |
|
713 parser.line_num = 1; |
|
714 parser.pos = 0; |
|
715 parser.len = _dbus_string_get_length (&parser.data); |
|
716 parser.current_section = -1; |
|
717 |
|
718 while (parser.pos < parser.len) |
|
719 { |
|
720 if (_dbus_string_get_byte (&parser.data, parser.pos) == '[') |
|
721 { |
|
722 if (!parse_section_start (&parser, error)) |
|
723 { |
|
724 return NULL; |
|
725 } |
|
726 } |
|
727 else if (is_blank_line (&parser) || |
|
728 _dbus_string_get_byte (&parser.data, parser.pos) == '#') |
|
729 parse_comment_or_blank (&parser); |
|
730 else |
|
731 { |
|
732 if (!parse_key_value (&parser, error)) |
|
733 { |
|
734 return NULL; |
|
735 } |
|
736 } |
|
737 } |
|
738 |
|
739 _dbus_string_free (&parser.data); |
|
740 |
|
741 return parser.desktop_file; |
|
742 } |
|
743 |
|
744 static BusDesktopFileSection * |
|
745 lookup_section (BusDesktopFile *desktop_file, |
|
746 const char *section_name) |
|
747 { |
|
748 BusDesktopFileSection *section; |
|
749 int i; |
|
750 |
|
751 if (section_name == NULL) |
|
752 return NULL; |
|
753 |
|
754 for (i = 0; i < desktop_file->n_sections; i ++) |
|
755 { |
|
756 section = &desktop_file->sections[i]; |
|
757 |
|
758 if (strcmp (section->section_name, section_name) == 0) |
|
759 return section; |
|
760 } |
|
761 |
|
762 return NULL; |
|
763 } |
|
764 |
|
765 static BusDesktopFileLine * |
|
766 lookup_line (BusDesktopFile *desktop_file, |
|
767 BusDesktopFileSection *section, |
|
768 const char *keyname) |
|
769 { |
|
770 BusDesktopFileLine *line; |
|
771 int i; |
|
772 |
|
773 for (i = 0; i < section->n_lines; i++) |
|
774 { |
|
775 line = §ion->lines[i]; |
|
776 |
|
777 if (strcmp (line->key, keyname) == 0) |
|
778 return line; |
|
779 } |
|
780 |
|
781 return NULL; |
|
782 } |
|
783 |
|
784 dbus_bool_t |
|
785 bus_desktop_file_get_raw (BusDesktopFile *desktop_file, |
|
786 const char *section_name, |
|
787 const char *keyname, |
|
788 const char **val) |
|
789 { |
|
790 BusDesktopFileSection *section; |
|
791 BusDesktopFileLine *line; |
|
792 |
|
793 *val = NULL; |
|
794 |
|
795 section = lookup_section (desktop_file, section_name); |
|
796 |
|
797 if (!section) |
|
798 return FALSE; |
|
799 |
|
800 line = lookup_line (desktop_file, |
|
801 section, |
|
802 keyname); |
|
803 |
|
804 if (!line) |
|
805 return FALSE; |
|
806 |
|
807 *val = line->value; |
|
808 |
|
809 return TRUE; |
|
810 } |
|
811 |
|
812 dbus_bool_t |
|
813 bus_desktop_file_get_string (BusDesktopFile *desktop_file, |
|
814 const char *section, |
|
815 const char *keyname, |
|
816 char **val, |
|
817 DBusError *error) |
|
818 { |
|
819 const char *raw; |
|
820 |
|
821 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
822 |
|
823 *val = NULL; |
|
824 |
|
825 if (!bus_desktop_file_get_raw (desktop_file, section, keyname, &raw)) |
|
826 { |
|
827 dbus_set_error (error, DBUS_ERROR_FAILED, |
|
828 "No \"%s\" key in .service file\n", keyname); |
|
829 return FALSE; |
|
830 } |
|
831 |
|
832 *val = _dbus_strdup (raw); |
|
833 |
|
834 if (*val == NULL) |
|
835 { |
|
836 BUS_SET_OOM (error); |
|
837 return FALSE; |
|
838 } |
|
839 |
|
840 return TRUE; |
|
841 } |