ofdbus/dbus/bus/desktop-file.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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 (&section->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 = &section->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 = &section->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 }