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