Exemple #1
0
static GvdbItem *
get_parent (GHashTable *table,
	    gchar      *key,
	    gint        length)
{
  GvdbItem *grandparent, *parent;

  if (length == 1)
    return NULL;

  while (key[--length - 1] != '/');
  key[length] = '\0';

  parent = g_hash_table_lookup (table, key);

  if (parent == NULL)
    {
      parent = gvdb_hash_table_insert (table, key);

      grandparent = get_parent (table, key, length);

      if (grandparent != NULL)
	gvdb_item_set_parent (parent, grandparent);
    }

  return parent;
}
Exemple #2
0
void
gvdb_hash_table_insert_string (GHashTable  *table,
                               const gchar *key,
                               const gchar *value)
{
  GvdbItem *item;

  item = gvdb_hash_table_insert (table, key);
  gvdb_item_set_value (item, g_variant_new_string (value));
}
Exemple #3
0
GHashTable *
gvdb_hash_table_new (GHashTable  *parent,
                     const gchar *name_in_parent)
{
  GHashTable *table;

  table = g_hash_table_new_full (g_str_hash, g_str_equal,
                                 g_free, gvdb_item_free);

  if (parent)
    {
      GvdbItem *item;

      item = gvdb_hash_table_insert (parent, name_in_parent);
      gvdb_item_set_hash_table (item, table);
    }

  return table;
}
static void
start_element (GMarkupParseContext  *context,
               const gchar          *element_name,
               const gchar         **attribute_names,
               const gchar         **attribute_values,
               gpointer              user_data,
               GError              **error)
{
  ParseState *state = user_data;
  const GSList *element_stack;
  const gchar *container;

  element_stack = g_markup_parse_context_get_element_stack (context);
  container = element_stack->next ? element_stack->next->data : NULL;

#define COLLECT(first, ...) \
  g_markup_collect_attributes (element_name,                                 \
                               attribute_names, attribute_values, error,     \
                               first, __VA_ARGS__, G_MARKUP_COLLECT_INVALID)
#define OPTIONAL   G_MARKUP_COLLECT_OPTIONAL
#define STRDUP     G_MARKUP_COLLECT_STRDUP
#define STRING     G_MARKUP_COLLECT_STRING
#define NO_ATTRS()  COLLECT (G_MARKUP_COLLECT_INVALID, NULL)

  if (container == NULL)
    {
      if (strcmp (element_name, "schemalist") == 0)
        {
          COLLECT (OPTIONAL | STRDUP,
                   "gettext-domain",
                   &state->schemalist_domain);
          return;
        }
    }
  else if (strcmp (container, "schemalist") == 0)
    {
      if (strcmp (element_name, "schema") == 0)
        {
          const gchar *id, *path;

          if (COLLECT (STRING, "id", &id,
                       OPTIONAL | STRING, "path", &path,
                       OPTIONAL | STRDUP, "gettext-domain",
                                          &state->schema_domain))
            {
              if (!g_hash_table_lookup (state->schemas, id))
                {
                  state->schema = gvdb_hash_table_new (state->schemas, id);
                  state->schema_root = gvdb_hash_table_insert (state->schema, "");

                  if (path != NULL)
                    gvdb_hash_table_insert_string (state->schema,
                                                   ".path", path);
                }
              else
                g_set_error (error, G_MARKUP_ERROR,
                             G_MARKUP_ERROR_INVALID_CONTENT,
                             "<schema id='%s'> already specified", id);
            }
          return;
        }
    }
  else if (strcmp (container, "schema") == 0)
    {
      if (strcmp (element_name, "key") == 0)
        {
          const gchar *name, *type;

          if (COLLECT (STRING, "name", &name, STRING, "type", &type))
            {
              if (!is_valid_keyname (name, error))
                return;

              if (!g_hash_table_lookup (state->schema, name))
                {
                  state->key = gvdb_hash_table_insert (state->schema, name);
                  gvdb_item_set_parent (state->key, state->schema_root);
                }
              else
                {
                  g_set_error (error, G_MARKUP_ERROR,
                               G_MARKUP_ERROR_INVALID_CONTENT,
                               "<key name='%s'> already specified", name);
                  return;
                }

              if (g_variant_type_string_is_valid (type))
                state->type = g_variant_type_new (type);
              else
                {
                  g_set_error (error, G_MARKUP_ERROR,
                               G_MARKUP_ERROR_INVALID_CONTENT,
                               "invalid GVariant type string '%s'", type);
                  return;
                }

              g_variant_builder_init (&state->key_options,
                                      G_VARIANT_TYPE ("a{sv}"));
            }

          return;
        }
      else if (strcmp (element_name, "child") == 0)
        {
          const gchar *name, *schema;

          if (COLLECT (STRING, "name", &name, STRING, "schema", &schema))
            {
              gchar *childname;

              if (!is_valid_keyname (name, error))
                return;

              childname = g_strconcat (name, "/", NULL);

              if (!g_hash_table_lookup (state->schema, childname))
                gvdb_hash_table_insert_string (state->schema, childname, schema);
              else
                g_set_error (error, G_MARKUP_ERROR,
                             G_MARKUP_ERROR_INVALID_CONTENT,
                             "<child name='%s'> already specified", name);

              g_free (childname);
              return;
            }
        }
    }
  else if (strcmp (container, "key") == 0)
    {
      if (strcmp (element_name, "default") == 0)
        {
          const gchar *l10n;

          if (COLLECT (STRING | OPTIONAL, "l10n", &l10n,
                       STRDUP | OPTIONAL, "context", &state->context))
            {
              if (l10n != NULL)
                {
                  if (!g_hash_table_lookup (state->schema, ".gettext-domain"))
                    {
                      const gchar *domain = state->schema_domain ?
                                            state->schema_domain :
                                            state->schemalist_domain;

                      if (domain == NULL)
                        {
                          g_set_error_literal (error, G_MARKUP_ERROR,
                                               G_MARKUP_ERROR_INVALID_CONTENT,
                                               "l10n requested, but no "
                                               "gettext domain given");
                          return;
                        }

                      gvdb_hash_table_insert_string (state->schema,
                                                     ".gettext-domain",
                                                     domain);

                      if (strcmp (l10n, "messages") == 0)
                        state->l10n = 'm';
                      else if (strcmp (l10n, "time") == 0)
                        state->l10n = 't';
                      else
                        {
                          g_set_error (error, G_MARKUP_ERROR,
                                       G_MARKUP_ERROR_INVALID_CONTENT,
                                       "unsupported l10n category: %s", l10n);
                          return;
                        }
                    }
                }
              else
                {
                  state->l10n = '\0';

                  if (state->context != NULL)
                    {
                      g_set_error_literal (error, G_MARKUP_ERROR,
                                           G_MARKUP_ERROR_INVALID_CONTENT,
                                           "translation context given for "
                                           " value without l10n enabled");
                      return;
                    }
                }

              state->string = g_string_new (NULL);
            }

          return;
        }
      else if (strcmp (element_name, "summary") == 0 ||
               strcmp (element_name, "description") == 0)
        {
          state->string = g_string_new (NULL);
          NO_ATTRS ();
          return;
        }
      else if (strcmp (element_name, "range") == 0)
        {
          const gchar *min_str, *max_str;

          if (!type_allows_range (state->type))
            {
              gchar *type = g_variant_type_dup_string (state->type);
              g_set_error (error, G_MARKUP_ERROR,
                          G_MARKUP_ERROR_INVALID_CONTENT,
                          "Element <%s> not allowed for keys of type \"%s\"\n",
                          element_name, type);
              g_free (type);
              return;
            }

          if (!COLLECT (STRING, "min", &min_str,
                        STRING, "max", &max_str))
            return;

          state->min = g_variant_parse (state->type, min_str, NULL, NULL, error);
          if (state->min == NULL)
            return;

          state->max = g_variant_parse (state->type, max_str, NULL, NULL, error);
          if (state->max == NULL)
            return;

          if (g_variant_compare (state->min, state->max) > 0)
            {
              g_set_error (error, G_MARKUP_ERROR,
                           G_MARKUP_ERROR_INVALID_CONTENT,
                           "Element <%s> specified minimum is greater than maxmimum",
                           element_name);
              return;
            }

          g_variant_builder_add (&state->key_options, "{sv}", "range",
                                 g_variant_new ("(@?@?)", state->min, state->max));
          return;
        }
      else if (strcmp (element_name, "choices") == 0)
        {
          if (!type_allows_choices (state->type))
            {
              gchar *type = g_variant_type_dup_string (state->type);
              g_set_error (error, G_MARKUP_ERROR,
                           G_MARKUP_ERROR_INVALID_CONTENT,
                           "Element <%s> not allowed for keys of type \"%s\"\n",
                           element_name, type);
              g_free (type);
              return;
            }

          state->choices = g_string_new ("\xff");

          NO_ATTRS ();
          return;
        }
    }
  else if (strcmp (container, "choices") == 0)
    {
      if (strcmp (element_name, "choice") == 0)
        {
          const gchar *value;

          if (COLLECT (STRING, "value", &value))
            g_string_append_printf (state->choices, "%s\xff", value);

          return;
        }
    }

  if (container)
    g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
                 "Element <%s> not allowed inside <%s>\n",
                 element_name, container);
  else
    g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
                 "Element <%s> not allowed at toplevel\n", element_name);
}
Exemple #5
0
static GHashTable *
parse_resource_file (const gchar *filename,
                     gboolean     collect_data,
                     GHashTable  *files)
{
  GMarkupParser parser = { start_element, end_element, text };
  ParseState state = { 0, };
  GMarkupParseContext *context;
  GError *error = NULL;
  gchar *contents;
  GHashTable *table = NULL;
  gsize size;

  if (!g_file_get_contents (filename, &contents, &size, &error))
    {
      g_printerr ("%s\n", error->message);
      g_clear_error (&error);
      return NULL;
    }

  state.collect_data = collect_data;
  state.table = g_hash_table_ref (files);

  context = g_markup_parse_context_new (&parser,
					G_MARKUP_TREAT_CDATA_AS_TEXT |
					G_MARKUP_PREFIX_ERROR_POSITION,
					&state, NULL);

  if (!g_markup_parse_context_parse (context, contents, size, &error) ||
      !g_markup_parse_context_end_parse (context, &error))
    {
      g_printerr ("%s: %s.\n", filename, error->message);
      g_clear_error (&error);
    }
  else
    {
      GHashTableIter iter;
      const char *key;
      char *mykey;
      gsize key_len;
      FileData *data;
      GVariant *v_data;
      GVariantBuilder builder;
      GvdbItem *item;

      table = gvdb_hash_table_new (NULL, NULL);

      g_hash_table_iter_init (&iter, state.table);
      while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&data))
	{
	  key_len = strlen (key);
	  mykey = g_strdup (key);

	  item = gvdb_hash_table_insert (table, key);
	  gvdb_item_set_parent (item,
				get_parent (table, mykey, key_len));

	  g_free (mykey);

	  g_variant_builder_init (&builder, G_VARIANT_TYPE ("(uuay)"));

	  g_variant_builder_add (&builder, "u", data->size); /* Size */
	  g_variant_builder_add (&builder, "u", data->flags); /* Flags */

	  v_data = g_variant_new_from_data (G_VARIANT_TYPE("ay"),
					    data->content, data->content_size, TRUE,
					    g_free, data->content);
	  g_variant_builder_add_value (&builder, v_data);
	  data->content = NULL; /* Take ownership */

	  gvdb_item_set_value (item,
			       g_variant_builder_end (&builder));
	}
    }

  g_hash_table_unref (state.table);
  g_markup_parse_context_free (context);
  g_free (contents);

  return table;
}