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