os/ossrv/ofdbus/dbus-glib/dbus/dbus-gloader-expat.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* -*- mode: C; c-file-style: "gnu" -*- */
sl@0
     2
/* dbus-gloader-expat.c  expat XML loader
sl@0
     3
 *
sl@0
     4
 * Copyright (C) 2003 Red Hat, Inc.
sl@0
     5
 *
sl@0
     6
 * Licensed under the Academic Free License version 2.1
sl@0
     7
 *
sl@0
     8
 * This program is free software; you can redistribute it and/or modify
sl@0
     9
 * it under the terms of the GNU General Public License as published by
sl@0
    10
 * the Free Software Foundation; either version 2 of the License, or
sl@0
    11
 * (at your option) any later version.
sl@0
    12
 *
sl@0
    13
 * This program is distributed in the hope that it will be useful,
sl@0
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
sl@0
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
sl@0
    16
 * GNU General Public License for more details.
sl@0
    17
 *
sl@0
    18
 * You should have received a copy of the GNU General Public License
sl@0
    19
 * along with this program; if not, write to the Free Software
sl@0
    20
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
sl@0
    21
 *
sl@0
    22
 */
sl@0
    23
sl@0
    24
#include "dbus-gparser.h"
sl@0
    25
#include <expat.h>
sl@0
    26
#include <string.h>
sl@0
    27
sl@0
    28
static void*
sl@0
    29
expat_g_malloc (size_t sz)
sl@0
    30
{
sl@0
    31
  return g_malloc (sz);
sl@0
    32
}
sl@0
    33
sl@0
    34
static void*
sl@0
    35
expat_g_realloc (void *mem, size_t sz)
sl@0
    36
{
sl@0
    37
  return g_realloc (mem, sz);
sl@0
    38
}
sl@0
    39
sl@0
    40
static XML_Memory_Handling_Suite memsuite =
sl@0
    41
{
sl@0
    42
  expat_g_malloc,
sl@0
    43
  expat_g_realloc,
sl@0
    44
  g_free
sl@0
    45
};
sl@0
    46
sl@0
    47
/**
sl@0
    48
 * Context for Expat parser for introspection data.
sl@0
    49
 */
sl@0
    50
typedef struct
sl@0
    51
{
sl@0
    52
  Parser *parser;       /**< The parser for the introspection data */
sl@0
    53
  const char *filename; /**< The filename being loaded */
sl@0
    54
  GString *content;     /**< The content of the current element */
sl@0
    55
  GError **error;       /**< Error return location */
sl@0
    56
  gboolean failed;      /**< True if parse has failed */
sl@0
    57
} ExpatParseContext;
sl@0
    58
sl@0
    59
static dbus_bool_t
sl@0
    60
process_content (ExpatParseContext *context)
sl@0
    61
{
sl@0
    62
  if (context->failed)
sl@0
    63
    return FALSE;
sl@0
    64
sl@0
    65
  if (context->content->len > 0)
sl@0
    66
    {
sl@0
    67
      if (!parser_content (context->parser,
sl@0
    68
                           context->content->str,
sl@0
    69
                           context->content->len,
sl@0
    70
                           context->error))
sl@0
    71
        {
sl@0
    72
          context->failed = TRUE;
sl@0
    73
          return FALSE;
sl@0
    74
        }
sl@0
    75
      g_string_set_size (context->content, 0);
sl@0
    76
    }
sl@0
    77
sl@0
    78
  return TRUE;
sl@0
    79
}
sl@0
    80
sl@0
    81
static void
sl@0
    82
expat_StartElementHandler (void            *userData,
sl@0
    83
                           const XML_Char  *name,
sl@0
    84
                           const XML_Char **atts)
sl@0
    85
{
sl@0
    86
  ExpatParseContext *context = userData;
sl@0
    87
  int i;
sl@0
    88
  char **names;
sl@0
    89
  char **values;
sl@0
    90
sl@0
    91
  /* Expat seems to suck and can't abort the parse if we
sl@0
    92
   * throw an error. Expat 2.0 is supposed to fix this.
sl@0
    93
   */
sl@0
    94
  if (context->failed)
sl@0
    95
    return;
sl@0
    96
sl@0
    97
  if (!process_content (context))
sl@0
    98
    return;
sl@0
    99
sl@0
   100
  /* "atts" is key, value, key, value, NULL */
sl@0
   101
  for (i = 0; atts[i] != NULL; ++i)
sl@0
   102
    ; /* nothing */
sl@0
   103
sl@0
   104
  g_assert (i % 2 == 0);
sl@0
   105
  names = g_new0 (char *, i / 2 + 1);
sl@0
   106
  values = g_new0 (char *, i / 2 + 1);
sl@0
   107
sl@0
   108
  i = 0;
sl@0
   109
  while (atts[i] != NULL)
sl@0
   110
    {
sl@0
   111
      g_assert (i % 2 == 0);
sl@0
   112
      names [i / 2] = (char*) atts[i];
sl@0
   113
      values[i / 2] = (char*) atts[i+1];
sl@0
   114
sl@0
   115
      i += 2;
sl@0
   116
    }
sl@0
   117
sl@0
   118
  if (!parser_start_element (context->parser,
sl@0
   119
                             name,
sl@0
   120
                             (const char **) names,
sl@0
   121
                             (const char **) values,
sl@0
   122
                             context->error))
sl@0
   123
    {
sl@0
   124
      g_free (names);
sl@0
   125
      g_free (values);
sl@0
   126
      context->failed = TRUE;
sl@0
   127
      return;
sl@0
   128
    }
sl@0
   129
sl@0
   130
  g_free (names);
sl@0
   131
  g_free (values);
sl@0
   132
}
sl@0
   133
sl@0
   134
static void
sl@0
   135
expat_EndElementHandler (void           *userData,
sl@0
   136
                         const XML_Char *name)
sl@0
   137
{
sl@0
   138
  ExpatParseContext *context = userData;
sl@0
   139
sl@0
   140
  if (!process_content (context))
sl@0
   141
    return;
sl@0
   142
sl@0
   143
  if (!parser_end_element (context->parser,
sl@0
   144
                           name,
sl@0
   145
                           context->error))
sl@0
   146
    {
sl@0
   147
      context->failed = TRUE;
sl@0
   148
      return;
sl@0
   149
    }
sl@0
   150
}
sl@0
   151
sl@0
   152
/* s is not 0 terminated. */
sl@0
   153
static void
sl@0
   154
expat_CharacterDataHandler (void           *userData,
sl@0
   155
                            const XML_Char *s,
sl@0
   156
                            int             len)
sl@0
   157
{
sl@0
   158
  ExpatParseContext *context = userData;
sl@0
   159
sl@0
   160
  if (context->failed)
sl@0
   161
    return;
sl@0
   162
sl@0
   163
  g_string_append_len (context->content,
sl@0
   164
                       s, len);
sl@0
   165
}
sl@0
   166
sl@0
   167
NodeInfo*
sl@0
   168
description_load_from_file (const char       *filename,
sl@0
   169
                            GError          **error)
sl@0
   170
{
sl@0
   171
  char *contents;
sl@0
   172
  gsize len;
sl@0
   173
  NodeInfo *nodes;
sl@0
   174
  
sl@0
   175
  contents = NULL;
sl@0
   176
  if (!g_file_get_contents (filename, &contents, &len, error))
sl@0
   177
    return NULL;
sl@0
   178
sl@0
   179
  nodes = description_load_from_string (contents, len, error);
sl@0
   180
  g_free (contents);
sl@0
   181
sl@0
   182
  return nodes;
sl@0
   183
}
sl@0
   184
sl@0
   185
NodeInfo*
sl@0
   186
description_load_from_string (const char  *str,
sl@0
   187
                              int          len,
sl@0
   188
                              GError     **error)
sl@0
   189
{
sl@0
   190
  XML_Parser expat;
sl@0
   191
  ExpatParseContext context;
sl@0
   192
  NodeInfo *nodes;
sl@0
   193
  
sl@0
   194
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
sl@0
   195
sl@0
   196
  if (len < 0)
sl@0
   197
    len = strlen (str);
sl@0
   198
  
sl@0
   199
  expat = NULL;
sl@0
   200
  context.parser = NULL;
sl@0
   201
  context.error = error;
sl@0
   202
  context.failed = FALSE;
sl@0
   203
  
sl@0
   204
  expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
sl@0
   205
  if (expat == NULL)
sl@0
   206
    g_error ("No memory to create XML parser\n");
sl@0
   207
sl@0
   208
  context.parser = parser_new ();
sl@0
   209
  context.content = g_string_new (NULL);
sl@0
   210
  
sl@0
   211
  XML_SetUserData (expat, &context);
sl@0
   212
  XML_SetElementHandler (expat,
sl@0
   213
                         expat_StartElementHandler,
sl@0
   214
                         expat_EndElementHandler);
sl@0
   215
  XML_SetCharacterDataHandler (expat,
sl@0
   216
                               expat_CharacterDataHandler);
sl@0
   217
  
sl@0
   218
  if (!XML_Parse (expat, str, len, TRUE))
sl@0
   219
    {
sl@0
   220
      if (context.error != NULL &&
sl@0
   221
          *context.error == NULL)
sl@0
   222
        {
sl@0
   223
            enum XML_Error e;
sl@0
   224
sl@0
   225
            e = XML_GetErrorCode (expat);
sl@0
   226
            if (e == XML_ERROR_NO_MEMORY)
sl@0
   227
              g_error ("Not enough memory to parse XML document");
sl@0
   228
            else
sl@0
   229
              g_set_error (error,
sl@0
   230
                           G_MARKUP_ERROR,
sl@0
   231
                           G_MARKUP_ERROR_PARSE,
sl@0
   232
                           "Error in D-BUS description XML, line %d, column %d: %s\n",
sl@0
   233
                           XML_GetCurrentLineNumber (expat),
sl@0
   234
                           XML_GetCurrentColumnNumber (expat),
sl@0
   235
                           XML_ErrorString (e));
sl@0
   236
        }
sl@0
   237
      
sl@0
   238
        goto failed;
sl@0
   239
    }
sl@0
   240
  
sl@0
   241
  if (context.failed)
sl@0
   242
    goto failed;
sl@0
   243
sl@0
   244
  if (!parser_finished (context.parser, error))
sl@0
   245
    goto failed;
sl@0
   246
sl@0
   247
  XML_ParserFree (expat);
sl@0
   248
  g_string_free (context.content, TRUE);
sl@0
   249
sl@0
   250
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
sl@0
   251
  nodes = parser_get_nodes (context.parser);
sl@0
   252
  node_info_ref (nodes);
sl@0
   253
  parser_unref (context.parser);
sl@0
   254
  return nodes;
sl@0
   255
sl@0
   256
 failed:
sl@0
   257
  g_return_val_if_fail (error == NULL || *error != NULL, NULL);
sl@0
   258
sl@0
   259
  g_string_free (context.content, TRUE);
sl@0
   260
  if (expat)
sl@0
   261
    XML_ParserFree (expat);
sl@0
   262
  if (context.parser)
sl@0
   263
    parser_unref (context.parser);
sl@0
   264
  return NULL;
sl@0
   265
}
sl@0
   266