app/config/Makefile.am app/config/config-types.h new files that hold a

2003-09-15  Sven Neumann  <sven@gimp.org>

	* app/config/Makefile.am
	* app/config/config-types.h
	* app/config/gimpxmlparser.[ch]: new files that hold a simple XML
	parser based on GMarkupParser. It's not a full-featured XML parser;
	it only adds transparent handling of encodings to GMarkupParser
	and provides a convenient API to deal with files or IO channels.

	* app/vectors/gimpvectors-import.c: use the new GimpXmlParser.

	* app/vectors/gimpvectors-export.c: write encoding attribute.

	* app/tips-dialog.c
	* app/tips-parser.c: use the new GimpXmlParser.

	* app/vectors/Makefile.am: had to add one of those truly ugly
	hacks here in order to get the application linked.
This commit is contained in:
Sven Neumann
2003-09-15 15:24:52 +00:00
committed by Sven Neumann
parent b83e77dc48
commit 80bd6f1c2b
12 changed files with 423 additions and 154 deletions

View File

@ -1,3 +1,22 @@
2003-09-15 Sven Neumann <sven@gimp.org>
* app/config/Makefile.am
* app/config/config-types.h
* app/config/gimpxmlparser.[ch]: new files that hold a simple XML
parser based on GMarkupParser. It's not a full-featured XML parser;
it only adds transparent handling of encodings to GMarkupParser
and provides a convenient API to deal with files or IO channels.
* app/vectors/gimpvectors-import.c: use the new GimpXmlParser.
* app/vectors/gimpvectors-export.c: write encoding attribute.
* app/tips-dialog.c
* app/tips-parser.c: use the new GimpXmlParser.
* app/vectors/Makefile.am: had to add one of those truly ugly
hacks here in order to get the application linked.
2003-09-15 Michael Natterer <mitch@gimp.org>
* app/widgets/gimpitemtreeview.c (gimp_item_tree_view_constructor):

View File

@ -37,7 +37,9 @@ libappconfig_a_SOURCES = \
gimprc.h \
gimprc-blurbs.h \
gimpscanner.c \
gimpscanner.h
gimpscanner.h \
gimpxmlparser.c \
gimpxmlparser.h
AM_CPPFLAGS = \
-DG_LOG_DOMAIN=\"Gimp-Config\" \

View File

@ -31,6 +31,7 @@ typedef struct _GimpPluginConfig GimpPluginConfig;
typedef struct _GimpRc GimpRc;
typedef struct _GimpConfigWriter GimpConfigWriter;
typedef struct _GimpXmlParser GimpXmlParser;
#endif /* __CONFIG_TYPES_H__ */

248
app/config/gimpxmlparser.c Normal file
View File

@ -0,0 +1,248 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* GimpXmlParser
* Copyright (C) 2003 Sven Neumann <sven@gimp.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <glib-object.h>
#include "config-types.h"
#include "gimpxmlparser.h"
struct _GimpXmlParser
{
GMarkupParseContext *context;
};
static gchar * parse_encoding (const gchar *text,
gint text_len);
/**
* gimp_xml_parser_new:
* @parser: a #GMarkupParser
* @user_data: user data to pass to #GMarkupParser functions
*
* GimpXmlParser is a thin wrapper around GMarkupParser. This function
* creates one for you and sets up a GMarkupParseContext.
*
* Return value: a new #GimpXmlParser
**/
GimpXmlParser *
gimp_xml_parser_new (const GMarkupParser *markup_parser,
gpointer user_data)
{
GimpXmlParser *parser;
g_return_val_if_fail (markup_parser != NULL, NULL);
parser = g_new (GimpXmlParser, 1);
parser->context = g_markup_parse_context_new (markup_parser,
0, user_data, NULL);
return parser;
}
/**
* gimp_xml_parser_parse_file:
* @parser: a #GimpXmlParser
* @filename: name of a file to parse
* @error: return location for possible errors
*
* This function creates a GIOChannel for @filename and calls
* gimp_xml_parser_parse_io_channel() for you.
*
* Return value: %TRUE on success, %FALSE otherwise
**/
gboolean
gimp_xml_parser_parse_file (GimpXmlParser *parser,
const gchar *filename,
GError **error)
{
GIOChannel *io;
gboolean success;
g_return_val_if_fail (parser != NULL, FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
io = g_io_channel_new_file (filename, "r", error);
if (!io)
return FALSE;
success = gimp_xml_parser_parse_io_channel (parser, io, error);
g_io_channel_unref (io);
return success;
}
/**
* gimp_xml_parser_parse_io_channel:
* @parser: a #GimpXmlParser
* @io: a #GIOChannel
* @error: return location for possible errors
*
* Makes @parser read from the specified @io channel. This function
* returns when the GIOChannel becomes empty (end of file) or an
* error occurs, either reading from @io or parsing the read data.
*
* This function tries to determine the character encoding from the
* XML header and converts the content to UTF-8 for you.
*
* Return value: %TRUE on success, %FALSE otherwise
**/
gboolean
gimp_xml_parser_parse_io_channel (GimpXmlParser *parser,
GIOChannel *io,
GError **error)
{
GIOStatus status;
guchar buffer[8196];
gsize len = 0;
gsize bytes;
const gchar *io_encoding;
gchar *encoding = NULL;
g_return_val_if_fail (parser != NULL, FALSE);
g_return_val_if_fail (io != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
io_encoding = g_io_channel_get_encoding (io);
if (io_encoding && strcmp (io_encoding, "UTF-8"))
{
g_warning ("gimp_xml_parser_parse_io_channel():\n"
"The encoding has already been set on this GIOChannel!");
return FALSE;
}
/* try to determine the encoding */
while (len < sizeof (buffer) && !encoding)
{
status = g_io_channel_read_chars (io,
buffer + len, 1, &bytes, error);
len += bytes;
if (status == G_IO_STATUS_ERROR)
return FALSE;
if (status == G_IO_STATUS_EOF)
break;
encoding = parse_encoding (buffer, len);
}
if (encoding)
{
if (!g_io_channel_set_encoding (io, encoding, error))
return FALSE;
g_free (encoding);
}
while (TRUE)
{
if (!g_markup_parse_context_parse (parser->context, buffer, len, error))
return FALSE;
status = g_io_channel_read_chars (io,
buffer, sizeof (buffer), &len, error);
switch (status)
{
case G_IO_STATUS_ERROR:
return FALSE;
case G_IO_STATUS_EOF:
return g_markup_parse_context_end_parse (parser->context, error);
case G_IO_STATUS_NORMAL:
case G_IO_STATUS_AGAIN:
break;
}
}
}
/**
* gimp_xml_parser_free:
* @parser: a #GimpXmlParser
*
* Frees the resources allocated for @parser. You must not access
* @parser after calling this function.
**/
void
gimp_xml_parser_free (GimpXmlParser *parser)
{
g_return_if_fail (parser != NULL);
g_markup_parse_context_free (parser->context);
g_free (parser);
}
static gchar *
parse_encoding (const gchar *text,
gint text_len)
{
const gchar *start;
const gchar *end;
gint i;
g_return_val_if_fail (text, NULL);
if (text_len < 20)
return NULL;
start = g_strstr_len (text, text_len, "<?xml");
if (!start)
return NULL;
end = g_strstr_len (start, text_len - (start - text), "?>");
if (!end)
return NULL;
text_len = end - start;
if (text_len < 12)
return NULL;
start = g_strstr_len (start + 1, text_len - 1, "encoding=");
if (!start)
return NULL;
start += 9;
if (*start != '\"' && *start != '\'')
return NULL;
text_len = end - start;
if (text_len < 1)
return NULL;
for (i = 1; i < text_len; i++)
if (start[i] == start[0])
break;
if (i == text_len || i < 3)
return NULL;
return g_strndup (start + 1, i - 1);
}

View File

@ -0,0 +1,37 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* GimpXmlParser
* Copyright (C) 2003 Sven Neumann <sven@gimp.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GIMP_XML_PARSER_H__
#define __GIMP_XML_PARSER_H__
GimpXmlParser * gimp_xml_parser_new (const GMarkupParser *markup_parser,
gpointer user_data);
gboolean gimp_xml_parser_parse_file (GimpXmlParser *parser,
const gchar *filename,
GError **error);
gboolean gimp_xml_parser_parse_io_channel (GimpXmlParser *parser,
GIOChannel *io,
GError **error);
void gimp_xml_parser_free (GimpXmlParser *parser);
#endif /* __GIMP_XML_PARSER_H__ */

View File

@ -85,10 +85,31 @@ tips_dialog_create (Gimp *gimp)
tips = gimp_tips_from_file (filename, &error);
g_free (filename);
if (error)
if (!tips)
{
tips = g_list_prepend (tips,
gimp_tip_new (_("<b>The GIMP tips file could not be parsed correctly!</b>"), error->message));
GimpTip *tip;
if (error->code == G_FILE_ERROR_NOENT)
{
tip = gimp_tip_new (_("<b>Your GIMP tips file appears to be missing!</b>"),
NULL);
tip->thetip = g_strdup_printf (_("There should be a file called '%s'. "
"Please check your installation."),
filename);
}
else
{
tip = gimp_tip_new (_("<b>The GIMP tips file could not be parsed!</b>"),
error->message);
}
tips = g_list_prepend (tips, tip);
g_error_free (error);
}
else if (error)
{
g_printerr ("Error while parsing '%s': %s",
filename, error->message);
g_error_free (error);
}
}

View File

@ -21,11 +21,13 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "config/config-types.h"
#include "config/gimpxmlparser.h"
#include "tips-parser.h"
#include "gimp-intl.h"
@ -51,7 +53,6 @@ typedef enum
typedef struct _TipsParser TipsParser;
struct _TipsParser
{
const gchar *filename;
TipsParserState state;
TipsParserState last_known_state;
const gchar *locale;
@ -80,9 +81,6 @@ static void tips_parser_characters (GMarkupParseContext *context,
gsize text_len,
gpointer user_data,
GError **error);
static void tips_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data);
static void tips_parser_start_markup (TipsParser *parser,
const gchar *markup_name);
@ -103,7 +101,7 @@ static const GMarkupParser markup_parser =
tips_parser_end_element,
tips_parser_characters,
NULL, /* passthrough */
tips_parser_error
NULL /* error */
};
@ -148,29 +146,15 @@ GList *
gimp_tips_from_file (const gchar *filename,
GError **error)
{
GMarkupParseContext *context;
GimpXmlParser *xml_parser;
TipsParser *parser;
const gchar *tips_locale;
FILE *fp;
gsize bytes;
gchar buf[4096];
GList *tips = NULL;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
fp = fopen (filename, "r");
if (!fp)
{
g_set_error (error, 0, 0,
_("Your GIMP tips file appears to be missing! "
"There should be a file called '%s'. "
"Please check your installation."), filename);
return NULL;
}
parser = g_new0 (TipsParser, 1);
parser->filename = filename;
parser->value = g_string_new (NULL);
/* This is a special string to specify the language identifier to
@ -189,17 +173,11 @@ gimp_tips_from_file (const gchar *filename,
else
g_warning ("Wrong translation for 'tips-locale:', fix the translation!");
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
xml_parser = gimp_xml_parser_new (&markup_parser, parser);
while ((bytes = fread (buf, sizeof (gchar), sizeof (buf), fp)) > 0 &&
g_markup_parse_context_parse (context, buf, bytes, error))
;
gimp_xml_parser_parse_file (xml_parser, filename, error);
if (error == NULL || *error == NULL)
g_markup_parse_context_end_parse (context, error);
fclose (fp);
g_markup_parse_context_free (context);
gimp_xml_parser_free (xml_parser);
tips = g_list_reverse (parser->tips);
@ -367,16 +345,6 @@ tips_parser_characters (GMarkupParseContext *context,
}
}
static void
tips_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data)
{
TipsParser *parser = (TipsParser *) user_data;
g_warning ("%s: %s", parser->filename, error->message);
}
static void
tips_parser_start_markup (TipsParser *parser,
const gchar *markup_name)

View File

@ -85,10 +85,31 @@ tips_dialog_create (Gimp *gimp)
tips = gimp_tips_from_file (filename, &error);
g_free (filename);
if (error)
if (!tips)
{
tips = g_list_prepend (tips,
gimp_tip_new (_("<b>The GIMP tips file could not be parsed correctly!</b>"), error->message));
GimpTip *tip;
if (error->code == G_FILE_ERROR_NOENT)
{
tip = gimp_tip_new (_("<b>Your GIMP tips file appears to be missing!</b>"),
NULL);
tip->thetip = g_strdup_printf (_("There should be a file called '%s'. "
"Please check your installation."),
filename);
}
else
{
tip = gimp_tip_new (_("<b>The GIMP tips file could not be parsed!</b>"),
error->message);
}
tips = g_list_prepend (tips, tip);
g_error_free (error);
}
else if (error)
{
g_printerr ("Error while parsing '%s': %s",
filename, error->message);
g_error_free (error);
}
}

View File

@ -21,11 +21,13 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "config/config-types.h"
#include "config/gimpxmlparser.h"
#include "tips-parser.h"
#include "gimp-intl.h"
@ -51,7 +53,6 @@ typedef enum
typedef struct _TipsParser TipsParser;
struct _TipsParser
{
const gchar *filename;
TipsParserState state;
TipsParserState last_known_state;
const gchar *locale;
@ -80,9 +81,6 @@ static void tips_parser_characters (GMarkupParseContext *context,
gsize text_len,
gpointer user_data,
GError **error);
static void tips_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data);
static void tips_parser_start_markup (TipsParser *parser,
const gchar *markup_name);
@ -103,7 +101,7 @@ static const GMarkupParser markup_parser =
tips_parser_end_element,
tips_parser_characters,
NULL, /* passthrough */
tips_parser_error
NULL /* error */
};
@ -148,29 +146,15 @@ GList *
gimp_tips_from_file (const gchar *filename,
GError **error)
{
GMarkupParseContext *context;
GimpXmlParser *xml_parser;
TipsParser *parser;
const gchar *tips_locale;
FILE *fp;
gsize bytes;
gchar buf[4096];
GList *tips = NULL;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
fp = fopen (filename, "r");
if (!fp)
{
g_set_error (error, 0, 0,
_("Your GIMP tips file appears to be missing! "
"There should be a file called '%s'. "
"Please check your installation."), filename);
return NULL;
}
parser = g_new0 (TipsParser, 1);
parser->filename = filename;
parser->value = g_string_new (NULL);
/* This is a special string to specify the language identifier to
@ -189,17 +173,11 @@ gimp_tips_from_file (const gchar *filename,
else
g_warning ("Wrong translation for 'tips-locale:', fix the translation!");
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
xml_parser = gimp_xml_parser_new (&markup_parser, parser);
while ((bytes = fread (buf, sizeof (gchar), sizeof (buf), fp)) > 0 &&
g_markup_parse_context_parse (context, buf, bytes, error))
;
gimp_xml_parser_parse_file (xml_parser, filename, error);
if (error == NULL || *error == NULL)
g_markup_parse_context_end_parse (context, error);
fclose (fp);
g_markup_parse_context_free (context);
gimp_xml_parser_free (xml_parser);
tips = g_list_reverse (parser->tips);
@ -367,16 +345,6 @@ tips_parser_characters (GMarkupParseContext *context,
}
}
static void
tips_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data)
{
TipsParser *parser = (TipsParser *) user_data;
g_warning ("%s: %s", parser->filename, error->message);
}
static void
tips_parser_start_markup (TipsParser *parser,
const gchar *markup_name)

View File

@ -35,4 +35,6 @@ libappvectors_a_SOURCES = \
gimpvectors-preview.c \
gimpvectors-preview.h
## This is a truly ugly hack
libappvectors_a_LIBADD = ../config/gimpxmlparser.o

View File

@ -78,7 +78,7 @@ gimp_vectors_export (const GimpImage *image,
}
fprintf (file,
"<?xml version=\"1.0\" standalone=\"no\"?>\n"
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n"
" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
fprintf (file,

View File

@ -24,7 +24,6 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
@ -34,6 +33,8 @@
#include "vectors-types.h"
#include "config/gimpxmlparser.h"
#include "core/gimpimage.h"
#include "core/gimpimage-undo.h"
@ -134,32 +135,19 @@ gimp_vectors_import (GimpImage *image,
gboolean merge,
GError **error)
{
GMarkupParseContext *context;
FILE *file;
GimpXmlParser *parser;
GQueue *stack;
GList *paths;
SvgHandler *base;
gboolean success = TRUE;
gsize bytes;
gchar buf[4096];
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
file = fopen (filename, "r");
if (!file)
{
g_set_error (error, 0, 0,
_("Failed to open file: '%s': %s"),
filename, g_strerror (errno));
return FALSE;
}
stack = g_queue_new ();
/* the base of the stack, defines the size of the view-port */
base = g_new0 (SvgHandler, 1);
base->name = "image";
base->width = image->width;
@ -167,17 +155,11 @@ gimp_vectors_import (GimpImage *image,
g_queue_push_head (stack, base);
context = g_markup_parse_context_new (&markup_parser, 0, stack, NULL);
parser = gimp_xml_parser_new (&markup_parser, stack);
while (success &&
(bytes = fread (buf, sizeof (gchar), sizeof (buf), file)) > 0)
success = g_markup_parse_context_parse (context, buf, bytes, error);
success = gimp_xml_parser_parse_file (parser, filename, error);
if (success)
success = g_markup_parse_context_end_parse (context, error);
fclose (file);
g_markup_parse_context_free (context);
gimp_xml_parser_free (parser);
if (success)
{