Fold branches/goffice-update/ back into trunk/.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@12096 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Joshua Sled
2005-12-04 21:27:17 +00:00
parent b73d9ce74a
commit 94e9fe5e6f
927 changed files with 420021 additions and 55983 deletions

View File

@@ -0,0 +1,134 @@
if OS_WIN32
install-libtool-import-lib:
$(INSTALL) .libs/libgsf-1.dll.a $(DESTDIR)$(libdir)
uninstall-libtool-import-lib:
-rm $(DESTDIR)$(libdir)/libgsf-1.dll.a
else
install-libtool-import-lib:
uninstall-libtool-import-lib:
endif
AM_CPPFLAGS = -I$(top_srcdir)/lib/libgsf-1.12.3 $(LIBGSF_CFLAGS) $(Z_CPPFLAGS) \
-DGNOMELOCALEDIR=\"$(datadir)/locale\"
lib_LTLIBRARIES = libgsf-1.la
libgsf_1_la_LIBADD = $(LIBGSF_LIBS) $(Z_LIBS) $(BZ2_LIBS)
libgsf_1_la_LDFLAGS = -version-info $(VERSION_INFO)
if PLATFORM_WIN32
libgsf_1_la_LDFLAGS += -no-undefined
endif
libgsf_1_la_SOURCES = \
gsf-utils.c \
gsf-libxml.c \
gsf-doc-meta-data.c \
gsf-docprop-vector.c \
gsf-msole-impl.h \
gsf-msole-utils.c \
gsf-timestamp.c \
gsf-zip-impl.h \
gsf-zip-utils.c \
\
gsf-input.c \
gsf-input-bzip.c \
gsf-input-gzip.c \
gsf-input-iochannel.c \
gsf-input-memory.c \
gsf-input-proxy.c \
gsf-input-stdio.c \
gsf-input-textline.c \
\
gsf-infile.c \
gsf-infile-msole.c \
gsf-infile-msvba.c \
gsf-infile-stdio.c \
gsf-infile-zip.c \
\
gsf-output.c \
gsf-output-bzip.c \
gsf-output-csv.c \
gsf-output-gzip.c \
gsf-output-iconv.c \
gsf-output-iochannel.c \
gsf-output-memory.c \
gsf-output-stdio.c \
\
gsf-outfile.c \
gsf-outfile-msole.c \
gsf-outfile-stdio.c \
gsf-outfile-zip.c \
\
gsf-shared-memory.c \
gsf-shared-memory.h \
gsf-structured-blob.c \
gsf-blob.c \
gsf-clip-data.c
# gsf-output-transaction.c \
# gsf-command-context.c \
# gsf-io-context.c
if !HAVE_GLIB26
libgsf_1_la_SOURCES += glib24_26-compat.c
endif
libgsf_1_includedir = $(includedir)/libgsf-1/gsf
libgsf_1_include_HEADERS = \
gsf.h \
gsf-utils.h \
gsf-libxml.h \
gsf-impl-utils.h \
gsf-doc-meta-data.h \
gsf-docprop-vector.h \
gsf-msole-utils.h \
gsf-timestamp.h \
\
gsf-input.h \
gsf-input-impl.h \
gsf-input-bzip.h \
gsf-input-gzip.h \
gsf-input-iochannel.h \
gsf-input-memory.h \
gsf-input-proxy.h \
gsf-input-stdio.h \
gsf-input-textline.h \
\
gsf-infile.h \
gsf-infile-impl.h \
gsf-infile-msole.h \
gsf-infile-msvba.h \
gsf-infile-stdio.h \
gsf-infile-zip.h \
\
gsf-output.h \
gsf-output-impl.h \
gsf-output-bzip.h \
gsf-output-csv.h \
gsf-output-gzip.h \
gsf-output-iconv.h \
gsf-output-iochannel.h \
gsf-output-memory.h \
gsf-output-stdio.h \
\
gsf-outfile.h \
gsf-outfile-impl.h \
gsf-outfile-msole.h \
gsf-outfile-stdio.h \
gsf-outfile-zip.h \
\
gsf-structured-blob.h \
gsf-meta-names.h \
gsf-blob.h \
gsf-clip-data.h
# gsf-command-context.h \
# gsf-io-context.h
if !HAVE_GLIB26
libgsf_1_include_HEADERS += glib24_26-compat.h
endif
install-data-local: install-libtool-import-lib
uninstall-local: uninstall-libtool-import-lib

View File

@@ -0,0 +1,204 @@
/** jsled, 2005-11-08: copied from glib-2.6.6 to support libgsf compilation
against glib-2.4.14. **/
#include <gsf/glib24_26-compat.h>
/* gstdio.c - wrappers for C library functions
*
* Copyright 2004 Tor Lillqvist
*
* GLib is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GLib 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GLib; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
//#include <stdio.h>
#include <string.h>
//#include <stdlib.h>
/** ------------------------------------------------------------ **/
/* START gconvert.c */
#include <glib/gunicode.h>
#include <glib/gconvert.h>
#include <glib/gthread.h>
typedef struct _GFilenameCharsetCache GFilenameCharsetCache;
struct _GFilenameCharsetCache {
gboolean is_utf8;
gchar *charset;
gchar **filename_charsets;
};
/**
* g_get_filename_charsets:
* @charsets: return location for the %NULL-terminated list of encoding names
*
* Determines the preferred character sets used for filenames.
* The first character set from the @charsets is the filename encoding, the
* subsequent character sets are used when trying to generate a displayable
* representation of a filename, see g_filename_display_name().
*
* On Unix, the character sets are determined by consulting the
* environment variables <envar>G_FILENAME_ENCODING</envar> and
* <envar>G_BROKEN_FILENAMES</envar>. On Windows, the character set
* used in the GLib API is always UTF-8 and said environment variables
* have no effect.
*
* <envar>G_FILENAME_ENCODING</envar> may be set to a comma-separated list
* of character set names. The special token "@locale" is taken to mean the
* character set for the current locale. If <envar>G_FILENAME_ENCODING</envar>
* is not set, but <envar>G_BROKEN_FILENAMES</envar> is, the character set of
* the current locale is taken as the filename encoding. If neither environment
* variable is set, UTF-8 is taken as the filename encoding, but the character
* set of the current locale is also put in the list of encodings.
*
* The returned @charsets belong to GLib and must not be freed.
*
* Note that on Unix, regardless of the locale character set or
* <envar>G_FILENAME_ENCODING</envar> value, the actual file names present on a
* system might be in any random encoding or just gibberish.
*
* Return value: %TRUE if the filename encoding is UTF-8.
*
* Since: 2.6
*/
gboolean
g_get_filename_charsets (G_CONST_RETURN gchar ***filename_charsets)
{
static const gchar *charsets[] = {
"UTF-8",
NULL
};
#ifdef G_OS_WIN32
/* On Windows GLib pretends that the filename charset is UTF-8 */
if (filename_charsets)
*filename_charsets = charsets;
return TRUE;
#else
gboolean result;
/* Cygwin works like before */
result = g_get_charset (&(charsets[0]));
if (filename_charsets)
*filename_charsets = charsets;
return result;
#endif
}
static gchar *
make_valid_utf8 (const gchar *name)
{
GString *string;
const gchar *remainder, *invalid;
gint remaining_bytes, valid_bytes;
string = NULL;
remainder = name;
remaining_bytes = strlen (name);
while (remaining_bytes != 0)
{
if (g_utf8_validate (remainder, remaining_bytes, &invalid))
break;
valid_bytes = invalid - remainder;
if (string == NULL)
string = g_string_sized_new (remaining_bytes);
g_string_append_len (string, remainder, valid_bytes);
g_string_append_c (string, '?');
remaining_bytes -= valid_bytes + 1;
remainder = invalid + 1;
}
if (string == NULL)
return g_strdup (name);
g_string_append (string, remainder);
g_string_append (string, " (invalid encoding)");
g_assert (g_utf8_validate (string->str, -1, NULL));
return g_string_free (string, FALSE);
}
/**
* g_filename_display_name:
* @filename: a pathname hopefully in the GLib file name encoding
*
* Converts a filename into a valid UTF-8 string. The
* conversion is not necessarily reversible, so you
* should keep the original around and use the return
* value of this function only for display purposes.
* Unlike g_filename_to_utf8(), the result is guaranteed
* to be non-NULL even if the filename actually isn't in the GLib
* file name encoding.
*
* If you know the whole pathname of the file you should use
* g_filename_display_basename(), since that allows location-based
* translation of filenames.
*
* Return value: a newly allocated string containing
* a rendition of the filename in valid UTF-8
*
* Since: 2.6
**/
gchar *
g_filename_display_name (const gchar *filename)
{
gint i;
const gchar **charsets;
gchar *display_name = NULL;
gboolean is_utf8;
is_utf8 = g_get_filename_charsets (&charsets);
if (is_utf8)
{
if (g_utf8_validate (filename, -1, NULL))
display_name = g_strdup (filename);
}
if (!display_name)
{
/* Try to convert from the filename charsets to UTF-8.
* Skip the first charset if it is UTF-8.
*/
for (i = is_utf8 ? 1 : 0; charsets[i]; i++)
{
display_name = g_convert (filename, -1, "UTF-8", charsets[i],
NULL, NULL, NULL);
if (display_name)
break;
}
}
/* if all conversions failed, we replace invalid UTF-8
* by a question mark
*/
if (!display_name)
display_name = make_valid_utf8 (filename);
return display_name;
}

View File

@@ -0,0 +1,79 @@
/* This file has been copied from glib-2.6.6 into libgsf-1.12.3 to support
* compilation against glib-2.4.14. -- jsled, 2005-11-08
*/
#ifndef __GLIB_24_26_COMPAT_H__
#define __GLIB_24_26_COMPAT_H__
#include <glib.h>
// START from gstdio.h
/* gstdio.h - GFilename wrappers for C library functions
*
* Copyright 2004 Tor Lillqvist
*
* GLib is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GLib 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GLib; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <sys/stat.h>
/* Just pass on to the system functions, so there's no potential for data
* format mismatches, especially with large file interfaces.
*/
#define g_open open
#define g_rename rename
#define g_mkdir mkdir
#define g_stat stat
#define g_lstat lstat
#define g_unlink unlink
#define g_remove remove
#define g_rmdir rmdir
#define g_fopen fopen
#define g_freopen freopen
// END from gstdio.h
// START from gconvert.h
gchar *g_filename_display_name (const gchar *filename); // G_GNUC_MALLOC;
// END from gconvert.h
/* from glib-2.6[.6] gutils.h */
#ifdef G_OS_WIN32
/* On Win32, the canonical directory separator is the backslash, and
* the search path separator is the semicolon. Note that also the
* (forward) slash works as directory separator.
*/
#define G_DIR_SEPARATOR '\\'
#define G_DIR_SEPARATOR_S "\\"
#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
#define G_SEARCHPATH_SEPARATOR ';'
#define G_SEARCHPATH_SEPARATOR_S ";"
#else /* !G_OS_WIN32 */
/* Unix */
#define G_DIR_SEPARATOR '/'
#define G_DIR_SEPARATOR_S "/"
#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR)
#define G_SEARCHPATH_SEPARATOR ':'
#define G_SEARCHPATH_SEPARATOR_S ":"
#endif /* !G_OS_WIN32 */
#endif /* __GLIB_24_26_COMPAT_H__ */

View File

@@ -0,0 +1,142 @@
#include "gsf-config.h"
#include <glib/gi18n-lib.h>
#include <string.h>
#include "gsf-utils.h"
#include "gsf-blob.h"
/* Private part of the GsfBlob structure */
struct _GsfBlobPrivate {
gsize size;
gpointer data;
};
G_DEFINE_TYPE (GsfBlob, gsf_blob, G_TYPE_OBJECT);
static void gsf_blob_finalize (GObject *object);
static void
gsf_blob_class_init (GsfBlobClass *class)
{
GObjectClass *object_class;
object_class = (GObjectClass *) class;
object_class->finalize = gsf_blob_finalize;
}
static void
gsf_blob_init (GsfBlob *blob)
{
GsfBlobPrivate *priv;
priv = g_new0 (GsfBlobPrivate, 1);
blob->priv = priv;
}
static void
gsf_blob_finalize (GObject *object)
{
GsfBlob *blob;
GsfBlobPrivate *priv;
blob = GSF_BLOB (object);
priv = blob->priv;
g_free (priv->data);
g_free (priv);
G_OBJECT_CLASS (gsf_blob_parent_class)->finalize (object);
}
/**
* gsf_blob_new:
* @size: Size of the data in bytes.
* @data_to_copy: Data which will be copied into the blob, or %NULL if @size is zero.
* @error: location to store error, or %NULL.
*
* Creates a new #GsfBlob object to hold the specified data. The blob can then
* be used as a facility for reference-counting for the data. The data is
* copied internally, so the blob does not hold references to external chunks
* of memory.
*
* Return value: A newly-created #GsfBlob, or %NULL if the data could not be copied.
*
* Error domain: #GSF_ERROR
*
* Possible errors: #GSF_ERROR_OUT_OF_MEMORY if the @data_to_copy could not be copied.
**/
GsfBlob *
gsf_blob_new (gsize size, gconstpointer data_to_copy, GError **error)
{
GsfBlob *blob;
GsfBlobPrivate *priv;
gpointer data;
g_return_val_if_fail ((size > 0 && data_to_copy != NULL) || (size == 0 && data_to_copy == NULL), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (data_to_copy) {
data = g_try_malloc (size);
if (!data) {
g_set_error (error,
GSF_ERROR,
GSF_ERROR_OUT_OF_MEMORY,
_("Not enough memory to copy %" G_GSIZE_FORMAT " bytes of data"),
size);
return NULL;
}
memcpy (data, data_to_copy, size);
} else
data = NULL;
blob = g_object_new (GSF_TYPE_BLOB,
NULL);
priv = blob->priv;
priv->size = size;
priv->data = data;
return blob;
}
/**
* gsf_blob_get_size:
* @blob: A #GsfBlob.
*
* Queries the size in bytes of the data stored in the blob.
*
* Return value: Size in bytes, or 0 if the data is %NULL.
**/
gsize
gsf_blob_get_size (GsfBlob *blob)
{
GsfBlobPrivate *priv;
g_return_val_if_fail (GSF_IS_BLOB (blob), 0);
priv = blob->priv;
return priv->size;
}
/**
* gsf_blob_peek_data:
* @blob: A #GsfBlob.
*
* Queries a pointer to the data stored in the blob. This does not copy the data
* for you; it returns a pointer to the actual buffer which the blob uses internally,
* so you should not free this buffer on your own.
*
* Return value: Pointer to the data stored in the blob, or %NULL if the size
* of the data is zero.
**/
gconstpointer
gsf_blob_peek_data (GsfBlob *blob)
{
GsfBlobPrivate *priv;
g_return_val_if_fail (GSF_IS_BLOB (blob), NULL);
priv = blob->priv;
return priv->data;
}

View File

@@ -0,0 +1,40 @@
#include <glib-object.h>
#ifndef GSF_BLOB_H
#define GSF_BLOB_H
G_BEGIN_DECLS
#define GSF_TYPE_BLOB (gsf_blob_get_type ())
#define GSF_BLOB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSF_TYPE_BLOB, GsfBlob))
#define GSF_BLOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSF_TYPE_BLOB, GsfBlobClass))
#define GSF_IS_BLOB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSF_TYPE_BLOB))
#define GSF_IS_BLOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSF_TYPE_BLOB))
#define GSF_BLOB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSF_TYPE_BLOB, GsfBlobClass))
typedef struct _GsfBlob GsfBlob;
typedef struct _GsfBlobClass GsfBlobClass;
typedef struct _GsfBlobPrivate GsfBlobPrivate;
struct _GsfBlob {
GObject object;
GsfBlobPrivate *priv;
};
struct _GsfBlobClass {
GObjectClass parent_class;
};
GType gsf_blob_get_type (void) G_GNUC_CONST;
GsfBlob *gsf_blob_new (gsize size,
gconstpointer data_to_copy,
GError **error);
gsize gsf_blob_get_size (GsfBlob *blob);
gconstpointer gsf_blob_peek_data (GsfBlob *blob);
G_END_DECLS
#endif

View File

@@ -0,0 +1,293 @@
#include "gsf-config.h"
#include <glib/gi18n-lib.h>
#include "gsf-clip-data.h"
#include "gsf-utils.h"
/* Private part of the GsfClipData structure */
struct _GsfClipDataPrivate {
GsfClipFormat format;
GsfBlob *data_blob;
};
G_DEFINE_TYPE (GsfClipData, gsf_clip_data, G_TYPE_OBJECT);
static void gsf_clip_data_finalize (GObject *object);
static void
gsf_clip_data_class_init (GsfClipDataClass *class)
{
GObjectClass *object_class;
object_class = (GObjectClass *) class;
object_class->finalize = gsf_clip_data_finalize;
}
static void
gsf_clip_data_init (GsfClipData *clip_data)
{
GsfClipDataPrivate *priv;
priv = g_new0 (GsfClipDataPrivate, 1);
clip_data->priv = priv;
}
static void
gsf_clip_data_finalize (GObject *object)
{
GsfClipData *clip_data;
GsfClipDataPrivate *priv;
clip_data = GSF_CLIP_DATA (object);
priv = clip_data->priv;
if (priv->data_blob)
g_object_unref (priv->data_blob);
G_OBJECT_CLASS (gsf_clip_data_parent_class)->finalize (object);
}
/**
* gsf_clip_data_new:
* @format: Format for the data inside the @data_blob
* @data_blob: Object which holds the binary contents for the #GsfClipData
*
* Creates a new #GsfClipData object. This function acquires a reference to the
* @data_blob, so you should unref the blob on your own if you no longer need it
* directly.
*
* Return value: A newly-created #GsfClipData.
**/
GsfClipData *
gsf_clip_data_new (GsfClipFormat format, GsfBlob *data_blob)
{
GsfClipData *clip_data;
GsfClipDataPrivate *priv;
g_return_val_if_fail (GSF_IS_BLOB (data_blob), NULL);
clip_data = g_object_new (GSF_TYPE_CLIP_DATA,
NULL);
priv = clip_data->priv;
priv->format = format;
priv->data_blob = g_object_ref (data_blob);
return clip_data;
}
/**
* gsf_clip_data_get_format:
* @clip_data: A #GsfClipData.
*
* Queries the clipboard data format of a #GsfClipData. The format refers to the data
* blob inside the @clip_data; use gsf_clip_data_get_data_blob() to get that data blob.
*
* Return value: The format in which the #GsfClipData's data blob is stored.
**/
GsfClipFormat
gsf_clip_data_get_format (GsfClipData *clip_data)
{
GsfClipDataPrivate *priv;
g_return_val_if_fail (GSF_IS_CLIP_DATA (clip_data), GSF_CLIP_FORMAT_UNKNOWN);
priv = clip_data->priv;
return priv->format;
}
/**
* gsf_clip_data_get_data_blob:
* @clip_data: A #GsfClipData.
*
* Queries the data blob that actually stores a #GsfClipData's binary data.
*
* Return value: A new reference to the #GsfBlob that stores this @clip_data's
* binary data. You must use g_object_unref() to dispose of that data blob when
* you are done with it.
**/
GsfBlob *
gsf_clip_data_get_data_blob (GsfClipData *clip_data)
{
GsfClipDataPrivate *priv;
g_return_val_if_fail (GSF_IS_CLIP_DATA (clip_data), NULL);
priv = clip_data->priv;
return g_object_ref (priv->data_blob);
}
static void
set_error_missing_clipboard_data (GError **error, const char *format_name, gsize at_least_size)
{
g_set_error (error,
GSF_ERROR,
GSF_ERROR_INVALID_DATA,
_("The clip_data is in %s, but it is smaller than "
"at least %" G_GSIZE_FORMAT " bytes"),
format_name,
at_least_size);
}
static gsize
get_windows_clipboard_data_offset (GsfClipFormatWindows format)
{
struct format_offset_pair {
GsfClipFormatWindows format;
gsize offset;
};
static const struct format_offset_pair pairs[] = {
{ GSF_CLIP_FORMAT_WINDOWS_UNKNOWN, 4 },
{ GSF_CLIP_FORMAT_WINDOWS_METAFILE, 12 },
{ GSF_CLIP_FORMAT_WINDOWS_DIB, 4 },
{ GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE, 4 } /* FIXME: does this have a PACKEDMETA in front
* as well, similar to GSF_CLIP_FORMAT_WINDOWS_METAFILE? */
};
static const int num_pairs = G_N_ELEMENTS (pairs);
int i;
for (i = 0; i < num_pairs; i++)
if (pairs[i].format == format)
return pairs[i].offset;
g_assert_not_reached ();
return 0;
}
/* Checks that the specified blob size matches the expected size for the format.
* Returns the same format if the size is correct, or
* GSF_CLIP_FORMAT_WINDOWS_ERROR if the size is too small.
*/
static GsfClipFormatWindows
check_format_windows (GsfClipFormatWindows format, const char *format_name, gsize blob_size, GError **error)
{
gsize offset;
offset = get_windows_clipboard_data_offset (format);
if (blob_size <= offset) {
set_error_missing_clipboard_data (error, format_name, offset + 1);
format = GSF_CLIP_FORMAT_WINDOWS_ERROR;
}
return format;
}
/**
* gsf_clip_data_get_windows_clipboard_format:
* @clip_data: A #GsfClipData.
* @error: Location to store error, or %NULL
*
* Queries the Windows clipboard data format for a #GsfClipData. The @clip_data must
* have been created with #GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD.
*
* Return value: A #GsfClipFormatWindows value.
*
* Possible errors: #GSF_ERROR_INVALID_DATA if the data blob in the @clip_data is
* smaller than it should be; in this case GSF_CLIP_FORMAT_WINDOWS_ERROR will be returned.
**/
GsfClipFormatWindows
gsf_clip_data_get_windows_clipboard_format (GsfClipData *clip_data, GError **error)
{
GsfClipDataPrivate *priv;
gsize size;
guint32 value;
gconstpointer data;
GsfClipFormatWindows format;
g_return_val_if_fail (GSF_IS_CLIP_DATA (clip_data), GSF_CLIP_FORMAT_WINDOWS_ERROR);
g_return_val_if_fail (error == NULL || *error == NULL, GSF_CLIP_FORMAT_WINDOWS_ERROR);
priv = clip_data->priv;
g_return_val_if_fail (priv->format == GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD, GSF_CLIP_FORMAT_WINDOWS_ERROR);
size = gsf_blob_get_size (priv->data_blob);
if (size < 4) {
g_set_error (error,
GSF_ERROR,
GSF_ERROR_INVALID_DATA,
_("The clip_data is in Windows clipboard format, but it is smaller than "
"the required 4 bytes."));
return GSF_CLIP_FORMAT_WINDOWS_ERROR;
}
data = gsf_blob_peek_data (priv->data_blob);
value = GSF_LE_GET_GUINT32 (data);
switch (value) {
case GSF_CLIP_FORMAT_WINDOWS_METAFILE:
format = check_format_windows (GSF_CLIP_FORMAT_WINDOWS_METAFILE, _("Windows Metafile format"),
size, error);
break;
case GSF_CLIP_FORMAT_WINDOWS_DIB:
case 2: /* CF_BITMAP */
format = check_format_windows (GSF_CLIP_FORMAT_WINDOWS_DIB, _("Windows DIB or BITMAP format"),
size, error);
break;
case GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE:
format = check_format_windows (GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE, _("Windows Enhanced Metafile format"),
size, error);
break;
default:
format = GSF_CLIP_FORMAT_WINDOWS_UNKNOWN;
break;
}
return format;
}
/**
* gsf_clip_data_peek_real_data:
* @clip_data: A #GsfClipData.
* @ret_size: Location to return the size of the returned data buffer.
* @error: Location to store error, or %NULL.
*
* Queries a pointer directly to the clipboard data of a #GsfClipData. The
* resulting pointer is not necessarily the same data pointer that was passed to
* gsf_blob_new() prior to creating the @clip_data. For example, if the data is
* in #GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD format, then it will have extra header
* bytes in front of the actual metafile data. This function will skip over
* those header bytes if necessary and return a pointer to the "real" data.
*
* Return value: Pointer to the real clipboard data. The size in bytes of this
* buffer is returned in the @ret_size argument.
**/
gconstpointer
gsf_clip_data_peek_real_data (GsfClipData *clip_data, gsize *ret_size, GError **error)
{
GsfClipDataPrivate *priv;
gconstpointer data;
gsize offset;
g_return_val_if_fail (GSF_IS_CLIP_DATA (clip_data), NULL);
g_return_val_if_fail (ret_size != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
priv = clip_data->priv;
data = gsf_blob_peek_data (priv->data_blob);
if (priv->format == GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD) {
GsfClipFormatWindows win_format;
win_format = gsf_clip_data_get_windows_clipboard_format (clip_data, error);
if (win_format == GSF_CLIP_FORMAT_WINDOWS_ERROR)
return NULL;
/* gsf_clip_data_get_windows_clipboard_format() already did the size checks for us,
* so we can jump to the offset right away without doing extra checks.
*/
offset = get_windows_clipboard_data_offset (win_format);
} else
offset = 0;
*ret_size = gsf_blob_get_size (priv->data_blob) - offset;
return (char *) data + offset; /* cast to avoid warning about void pointer arithmetic */
}

View File

@@ -0,0 +1,65 @@
#include <gsf/gsf-blob.h>
#ifndef GSF_CLIP_DATA_H
#define GSF_CLIP_DATA_H
G_BEGIN_DECLS
typedef enum {
GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD = -1,
GSF_CLIP_FORMAT_MACINTOSH_CLIPBOARD = -2,
GSF_CLIP_FORMAT_GUID = -3,
GSF_CLIP_FORMAT_NO_DATA = 0,
GSF_CLIP_FORMAT_CLIPBOARD_FORMAT_NAME = 1, /* in the file it's actually any positive integer */
GSF_CLIP_FORMAT_UNKNOWN /* this is our own value for unknown types or invalid data */
} GsfClipFormat;
typedef enum {
GSF_CLIP_FORMAT_WINDOWS_ERROR = -1, /* our own value */
GSF_CLIP_FORMAT_WINDOWS_UNKNOWN = -2, /* our own value */
GSF_CLIP_FORMAT_WINDOWS_METAFILE = 3, /* CF_METAFILEPICT */
GSF_CLIP_FORMAT_WINDOWS_DIB = 8, /* CF_DIB */
GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE = 14 /* CF_ENHMETAFILE */
} GsfClipFormatWindows;
#define GSF_TYPE_CLIP_DATA (gsf_clip_data_get_type ())
#define GSF_CLIP_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSF_TYPE_CLIP_DATA, GsfClipData))
#define GSF_CLIP_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSF_TYPE_CLIP_DATA, GsfClipDataClass))
#define GSF_IS_CLIP_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSF_TYPE_CLIP_DATA))
#define GSF_IS_CLIP_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSF_TYPE_CLIP_DATA))
#define GSF_CLIP_DATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSF_TYPE_CLIP_DATA, GsfClipDataClass))
typedef struct _GsfClipData GsfClipData;
typedef struct _GsfClipDataClass GsfClipDataClass;
typedef struct _GsfClipDataPrivate GsfClipDataPrivate;
struct _GsfClipData {
GObject object;
GsfClipDataPrivate *priv;
};
struct _GsfClipDataClass {
GObjectClass parent_class;
};
GType gsf_clip_data_get_type (void) G_GNUC_CONST;
GsfClipData *gsf_clip_data_new (GsfClipFormat format,
GsfBlob *data_blob);
GsfClipFormat gsf_clip_data_get_format (GsfClipData *clip_data);
GsfBlob *gsf_clip_data_get_data_blob (GsfClipData *clip_data);
GsfClipFormatWindows gsf_clip_data_get_windows_clipboard_format (GsfClipData *clip_data,
GError **error);
gconstpointer gsf_clip_data_peek_real_data (GsfClipData *clip_data,
gsize *ret_size,
GError **error);
G_END_DECLS
#endif

View File

@@ -0,0 +1,332 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-doc-meta-data.c:
*
* Copyright (C) 2002-2005 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-doc-meta-data.h>
#include <gsf/gsf-impl-utils.h>
struct _GsfDocMetaData {
GObject base;
GHashTable *table;
};
typedef GObjectClass GsfDocMetaDataClass;
struct _GsfDocProp {
char *name;
GValue *val;
char *linked_to; /* optionally NULL */
};
static GObjectClass *parent_class;
static void
gsf_doc_meta_data_finalize (GObject *obj)
{
g_hash_table_destroy (GSF_DOC_META_DATA (obj)->table);
parent_class->finalize (obj);
}
static void
gsf_doc_meta_data_init (GObject *obj)
{
GsfDocMetaData *meta = GSF_DOC_META_DATA (obj);
meta->table = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, (GDestroyNotify) gsf_doc_prop_free);
}
static void
gsf_doc_meta_data_class_init (GObjectClass *gobject_class)
{
gobject_class->finalize = gsf_doc_meta_data_finalize;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfDocMetaData, gsf_doc_meta_data,
gsf_doc_meta_data_class_init, gsf_doc_meta_data_init,
G_TYPE_OBJECT)
/**********************************************************************/
/**
* gsf_doc_meta_data_new :
*
* Returns a new metadata property collection
**/
GsfDocMetaData *
gsf_doc_meta_data_new (void)
{
return g_object_new (GSF_DOC_META_DATA_TYPE, NULL);
}
/**
* gsf_doc_meta_data_lookup :
* @meta : #GsfDocMetaData
* @name :
*
* Returns the property with name @id in @meta. The caller can modify the
* property value and link but not the name.
**/
GsfDocProp *
gsf_doc_meta_data_lookup (GsfDocMetaData const *meta, char const *name)
{
g_return_val_if_fail (IS_GSF_DOC_META_DATA (meta), NULL);
g_return_val_if_fail (name != NULL, NULL);
return g_hash_table_lookup (meta->table, name);
}
/**
* gsf_doc_meta_data_insert :
* @meta : #GsfDocMetaData
* @name :
* @value : #GValue
*
* Take ownership of @name and @value and insert a property into @meta.
* If a property exists with @name, it is replaced (The link is lost)
**/
void
gsf_doc_meta_data_insert (GsfDocMetaData *meta, char *name, GValue *value)
{
GsfDocProp *prop;
g_return_if_fail (IS_GSF_DOC_META_DATA (meta));
g_return_if_fail (name != NULL);
prop = g_new (GsfDocProp, 1);
prop->name = name;
prop->val = value;
prop->linked_to = NULL;
g_hash_table_replace (meta->table, prop->name, prop);
}
/**
* gsf_doc_meta_data_remove :
* @meta : the collection
* @name : the non-null string name of the property
*
* If @name does not exist in the collection, do nothing. If @name does exist,
* remove it and its value from the collection
**/
void
gsf_doc_meta_data_remove (GsfDocMetaData *meta, char const *name)
{
g_return_if_fail (IS_GSF_DOC_META_DATA (meta));
g_return_if_fail (name != NULL);
g_hash_table_remove (meta->table, name);
}
/**
* gsf_doc_meta_data_store :
* @meta : #GsfDocMetaData
* @name :
*
**/
GsfDocProp *
gsf_doc_meta_data_steal (GsfDocMetaData *meta, char const *name)
{
GsfDocProp *prop;
g_return_val_if_fail (IS_GSF_DOC_META_DATA (meta), NULL);
g_return_val_if_fail (name != NULL, NULL);
prop = g_hash_table_lookup (meta->table, name);
if (NULL != prop)
g_hash_table_steal (meta->table, name);
return prop;
}
/**
* gsf_doc_meta_data_store :
* @meta : #GsfDocMetaData
* @prop : #GsfDocProp
*
**/
void
gsf_doc_meta_data_store (GsfDocMetaData *meta, GsfDocProp *prop)
{
g_return_if_fail (IS_GSF_DOC_META_DATA (meta));
g_return_if_fail (prop != NULL);
g_return_if_fail (prop != g_hash_table_lookup (meta->table, prop->name));
g_hash_table_replace (meta->table, prop->name, prop);
}
/**
* gsf_doc_meta_data_foreach :
* @meta : the collection
* @func : the function called once for each element in the collection
* @user_data : any supplied user data or NULL
*
* Iterate through each (key, value) pair in this collection
**/
void
gsf_doc_meta_data_foreach (GsfDocMetaData const *meta, GHFunc func, gpointer user_data)
{
g_return_if_fail (IS_GSF_DOC_META_DATA (meta));
g_hash_table_foreach (meta->table, func, user_data);
}
/**
* gsf_doc_meta_data_size :
* @meta : the collection
*
* Returns the number of items in this collection
**/
gsize
gsf_doc_meta_data_size (GsfDocMetaData const *meta)
{
g_return_val_if_fail (meta != NULL, 0);
return (gsize) g_hash_table_size (meta->table);
}
/**********************************************************************/
/**
* gsf_doc_prop_new :
* @name :
*
* Returns a new #GsfDocProp which the caller is responsible for freeing.
* Takes ownership of @name.
**/
GsfDocProp *
gsf_doc_prop_new (char *name)
{
GsfDocProp *prop;
g_return_val_if_fail (name != NULL, NULL);
prop = g_new (GsfDocProp, 1);
prop->name = name;
prop->val = NULL;
prop->linked_to = NULL;
return prop;
}
/**
* gsf_doc_prop_free :
* @prop : #GsfDocProp
*
* If @prop is non NULL free the memory assosociated with it
**/
void
gsf_doc_prop_free (GsfDocProp *prop)
{
if (NULL != prop) {
g_free (prop->linked_to);
if (prop->val) {
g_value_unset (prop->val);
g_free (prop->val);
}
g_free (prop->name);
g_free (prop);
}
}
/**
* gsf_doc_prop_get_name :
* @prop : #GsfDocProp
*
* Returns the name of the property, the caller should not modify the result.
**/
char const *
gsf_doc_prop_get_name (GsfDocProp const *prop)
{
g_return_val_if_fail (prop != NULL, NULL);
return prop->name;
}
/**
* gsf_doc_prop_get_val :
* @prop : the property
*
* Returns the value of the property, the caller should not modify the result.
**/
GValue const *
gsf_doc_prop_get_val (GsfDocProp const *prop)
{
g_return_val_if_fail (prop != NULL, NULL);
return prop->val;
}
/**
* gsf_doc_prop_set_val :
* @prop : #GsfDocProp
* @val : #GValue
*
* Assigns @val to @prop, and unsets and frees the current value.
**/
void
gsf_doc_prop_set_val (GsfDocProp *prop, GValue *val)
{
g_return_if_fail (prop != NULL);
if (val != prop->val) {
g_value_unset (prop->val);
g_free (prop->val);
prop->val = val;
}
}
/**
* gsf_doc_prop_swap_val :
* @prop : #GsfDocProp
* @val : #GValue
*
* Returns the current value of @prop, and replaces it with @val
* Caller is responsible for unsetting and freeing the result.
**/
GValue *
gsf_doc_prop_swap_val (GsfDocProp *prop, GValue *val)
{
GValue *old_val;
g_return_val_if_fail (prop != NULL, NULL);
old_val = prop->val;
prop->val = val;
return old_val;
}
/**
* gsf_doc_prop_get_link :
* @prop : #GsfDocProp
*
* Returns the current link descriptor of @prop. The result should not be
* freed or modified.
**/
char const *
gsf_doc_prop_get_link (GsfDocProp const *prop)
{
g_return_val_if_fail (prop != NULL, NULL);
return prop->linked_to;
}
/**
* gsf_doc_prop_set_link :
* @prop : #GsfDocProp
* @link :
**/
void
gsf_doc_prop_set_link (GsfDocProp *prop, char *link)
{
g_return_if_fail (prop != NULL);
if (link != prop->linked_to) {
g_free (prop->linked_to);
prop->linked_to = link;
}
}

View File

@@ -0,0 +1,62 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-doc-meta-data.h: get, set, remove custom meta properties associated with documents
*
* Copyright (C) 2002-2005 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_DOC_META_DATA_H
#define GSF_DOC_META_DATA_H
#include <gsf/gsf.h>
#include <glib-object.h>
#include <sys/types.h>
G_BEGIN_DECLS
#define GSF_DOC_META_DATA_TYPE (gsf_doc_meta_data_get_type ())
#define GSF_DOC_META_DATA(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_DOC_META_DATA_TYPE, GsfDocMetaData))
#define IS_GSF_DOC_META_DATA(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_DOC_META_DATA_TYPE))
GType gsf_doc_meta_data_get_type (void);
GsfDocMetaData *gsf_doc_meta_data_new (void);
GsfDocProp *gsf_doc_meta_data_lookup (GsfDocMetaData const *meta,
char const *name);
void gsf_doc_meta_data_insert (GsfDocMetaData *meta,
char *name, GValue *value);
void gsf_doc_meta_data_remove (GsfDocMetaData *meta,
char const *name);
GsfDocProp *gsf_doc_meta_data_steal (GsfDocMetaData *meta,
char const *name);
void gsf_doc_meta_data_store (GsfDocMetaData *meta,
GsfDocProp *prop);
void gsf_doc_meta_data_foreach (GsfDocMetaData const *meta,
GHFunc func, gpointer user_data);
gsize gsf_doc_meta_data_size (GsfDocMetaData const *meta);
GsfDocProp *gsf_doc_prop_new (char *name);
void gsf_doc_prop_free (GsfDocProp *prop);
char const *gsf_doc_prop_get_name (GsfDocProp const *prop);
GValue const *gsf_doc_prop_get_val (GsfDocProp const *prop);
void gsf_doc_prop_set_val (GsfDocProp *prop, GValue *val);
GValue *gsf_doc_prop_swap_val (GsfDocProp *prop, GValue *val);
char const *gsf_doc_prop_get_link (GsfDocProp const *prop);
void gsf_doc_prop_set_link (GsfDocProp *prop, char *link);
G_END_DECLS
#endif /* GSF_DOC_META_DATA_H */

View File

@@ -0,0 +1,158 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-docprop-vector.c: A type implementing OLE Document Property vectors using a GValueArray
*
* Copyright (C) 2004-2005 Frank Chiulli (fc-linux@cox.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-docprop-vector.h>
#include <gsf/gsf-impl-utils.h>
#include <stdio.h>
struct _GsfDocPropVector {
GObject parent;
GValueArray *gva;
};
typedef GObjectClass GsfDocPropVectorClass;
#define GSF_DOCPROP_VECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GSF_DOCPROP_VECTOR_TYPE, GsfDocPropVectorClass))
#define GSF_DOCPROP_VECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GSF_DOCPROP_VECTOR_TYPE, GsfDocPropVectorClass))
#define IS_GSF_DOCPROP_VECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GSF_DOCPROP_VECTOR_TYPE))
static GObjectClass *parent_class;
GValueArray *
gsf_value_get_docprop_varray (GValue const *value)
{
GsfDocPropVector *v = gsf_value_get_docprop_vector (value);
return v ? v->gva : NULL;
}
/**
* gsf_docprop_value_get_vector
* @value: A GValue of type #GsfDocPropVector.
*
* This function returns a pointer to the GsfDocPropVector structure in @value.
* No additional references are created.
*
* Returns: A pointer to the #GsfDocPropVector structure in @value
**/
GsfDocPropVector *
gsf_value_get_docprop_vector (GValue const *value)
{
g_return_val_if_fail (VAL_IS_GSF_DOCPROP_VECTOR (value), NULL);
return (GsfDocPropVector *) g_value_get_object (value);
}
/**
* gsf_docprop_vector_append
* @vector: The vector to which the GValue will be added
* @value: The GValue to add to @vector
*
* Insert a copy of @value as the last element of @vector.
**/
void
gsf_docprop_vector_append (GsfDocPropVector *vector, GValue *value)
{
g_return_if_fail (vector != NULL);
g_return_if_fail (value != NULL);
if (G_IS_VALUE (value))
vector->gva = g_value_array_append (vector->gva, value);
}
/**
* gsf_docprop_vector_as_string
* @vector: The #GsfDocPropVector from which GValues will be extracted.
*
* This function returns a string which represents all the GValues in @vector.
* The caller is responsible for freeing the result.
*
* Returns: a string of comma-separated values
**/
gchar*
gsf_docprop_vector_as_string (GsfDocPropVector *vector)
{
gchar *rstring;
guint i;
guint num_values;
g_return_val_if_fail (vector != NULL, NULL);
g_return_val_if_fail (vector->gva != NULL, NULL);
rstring = g_new0 (gchar, 1);
num_values = vector->gva->n_values;
for (i = 0; i < num_values; i++) {
char *str;
GValue *v;
v = g_value_array_get_nth (vector->gva, i);
str = g_strdup_value_contents (v);
rstring = g_strconcat (rstring, str, ",", NULL);
g_free (str);
g_value_unset (v);
}
return rstring;
}
static void
gsf_docprop_vector_finalize (GObject *obj)
{
GsfDocPropVector *vector = (GsfDocPropVector *) obj;
if (vector->gva != NULL) {
g_value_array_free (vector->gva);
vector->gva = NULL;
}
parent_class->finalize (obj);
}
static void
gsf_docprop_vector_class_init (GObjectClass *gobject_class)
{
parent_class = g_type_class_peek (G_TYPE_OBJECT);
gobject_class->finalize = gsf_docprop_vector_finalize;
}
static void
gsf_docprop_vector_init (GsfDocPropVector *vector)
{
vector->gva = g_value_array_new (0);
}
GSF_CLASS (GsfDocPropVector, gsf_docprop_vector,
gsf_docprop_vector_class_init, gsf_docprop_vector_init,
G_TYPE_OBJECT)
/**
* gsf_docprop_vector_new
*
* This function creates a new gsf_docprop_vector object.
*
* Returns: GsfDocPropVector*
**/
GsfDocPropVector*
gsf_docprop_vector_new (void)
{
return g_object_new (GSF_DOCPROP_VECTOR_TYPE, NULL);
}

View File

@@ -0,0 +1,46 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-docprop-vectors.h: A type implementing OLE Document Property vectors
*
* Copyright (C) 2004-2005 Frank Chiulli (fc-linux@cox.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_DOCPROP_VECTOR_H
#define GSF_DOCPROP_VECTOR_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GSF_DOCPROP_VECTOR_TYPE (gsf_docprop_vector_get_type ())
#define GSF_DOCPROP_VECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GSF_DOCPROP_VECTOR, GsfDocPropVector))
#define IS_GSF_DOCPROP_VECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GSF_DOCPROP_VECTOR_TYPE))
typedef struct _GsfDocPropVector GsfDocPropVector;
GType gsf_docprop_vector_get_type (void);
GsfDocPropVector *gsf_docprop_vector_new (void);
void gsf_docprop_vector_append (GsfDocPropVector *vector, GValue *value);
gchar *gsf_docprop_vector_as_string (GsfDocPropVector *vector);
#define VAL_IS_GSF_DOCPROP_VECTOR(v) (G_TYPE_CHECK_VALUE_TYPE((v), GSF_DOCPROP_VECTOR_TYPE))
GsfDocPropVector *gsf_value_get_docprop_vector (GValue const *value);
GValueArray *gsf_value_get_docprop_varray (GValue const *value);
G_END_DECLS
#endif /* GSF_DOCPROP_VECTOR_H */

View File

@@ -0,0 +1,140 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-impl-utils.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_IMPL_UTILS_H
#define GSF_IMPL_UTILS_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
/* We need to do this with a version check as this header gets installed. */
#if GLIB_CHECK_VERSION(2,7,0)
#define GSF_PARAM_STATIC (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
#else
#define GSF_PARAM_STATIC 0
#endif
/*************************************************************************/
#define GSF_CLASS_FULL(name, prefix, base_init, base_finalize, \
class_init, class_finalize, instance_init, parent_type, \
abstract, interface_decl) \
GType \
prefix ## _get_type (void) \
{ \
static GType type = 0; \
if (type == 0) { \
static GTypeInfo const object_info = { \
sizeof (name ## Class), \
(GBaseInitFunc) base_init, \
(GBaseFinalizeFunc) base_finalize, \
(GClassInitFunc) class_init, \
(GClassFinalizeFunc) class_finalize, \
NULL, /* class_data */ \
sizeof (name), \
0, /* n_preallocs */ \
(GInstanceInitFunc) instance_init, \
NULL \
}; \
type = g_type_register_static (parent_type, #name, \
&object_info, (GTypeFlags) abstract); \
interface_decl \
} \
return type; \
}
#define GSF_CLASS(name, prefix, class_init, instance_init, parent) \
GSF_CLASS_FULL(name, prefix, NULL, NULL, class_init, NULL, \
instance_init, parent, 0, {})
#define GSF_CLASS_ABSTRACT(name, prefix, class_init, instance_init, parent) \
GSF_CLASS_FULL(name, prefix, NULL, NULL, class_init, NULL, \
instance_init, parent, G_TYPE_FLAG_ABSTRACT, {})
#define GSF_INTERFACE_FULL(type, init_func, iface_type) { \
static GInterfaceInfo const iface = { \
(GInterfaceInitFunc) init_func, NULL, NULL }; \
g_type_add_interface_static (type, iface_type, &iface); \
}
#define GSF_INTERFACE(init_func, iface_type) \
GSF_INTERFACE_FULL(type, init_func, iface_type)
/*************************************************************************/
#define GSF_DYNAMIC_CLASS_FULL(name, prefix, base_init, base_finalize, \
class_init, class_finalize, instance_init, parent_type, \
abstract, interface_decl) \
static GType prefix ## _type; \
\
GType prefix ## _get_type (void); \
void prefix ## _register_type (GTypeModule *module); \
\
GType \
prefix ## _get_type () \
{ \
g_return_val_if_fail (prefix ## _type != 0, 0); \
return prefix ## _type; \
} \
void \
prefix ## _register_type (GTypeModule *module) \
{ \
static GTypeInfo const type_info = { \
sizeof (name ## Class), \
(GBaseInitFunc) base_init, \
(GBaseFinalizeFunc) base_finalize, \
(GClassInitFunc) class_init, \
(GClassFinalizeFunc) class_finalize, \
NULL, /* class_data */ \
sizeof (name), \
0, /* n_preallocs */ \
(GInstanceInitFunc) instance_init, \
NULL \
}; \
GType type; \
\
g_return_if_fail (prefix ## _type == 0); \
\
type = prefix ## _type = g_type_module_register_type (module, \
parent_type, #name, &type_info, (GTypeFlags) abstract); \
interface_decl \
}
#define GSF_DYNAMIC_CLASS(name, prefix, class_init, instance_init, parent) \
GSF_DYNAMIC_CLASS_FULL(name, prefix, NULL, NULL, class_init, NULL, \
instance_init, parent, 0, {})
#define GSF_DYNAMIC_CLASS_ABSTRACT(name, prefix, class_init, instance_init, parent) \
GSF_DYNAMIC_CLASS_FULL(name, prefix, NULL, NULL, class_init, NULL, \
instance_init, parent, G_TYPE_FLAG_ABSTRACT, {})
#define GSF_DYNAMIC_INTERFACE_FULL(type, init_func, iface_type, module) { \
static GInterfaceInfo const iface = { \
(GInterfaceInitFunc) init_func, NULL, NULL }; \
g_type_module_add_interface (module, type, iface_type, &iface); \
}
#define GSF_DYNAMIC_INTERFACE(init_func, iface_type, module) \
GSF_DYNAMIC_INTERFACE_FULL(type, init_func, iface_type, module)
G_END_DECLS
#endif /* GSF_IMPL_UTILS_H */

View File

@@ -0,0 +1,50 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-impl.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INFILE_IMPL_H
#define GSF_INFILE_IMPL_H
#include <gsf/gsf.h>
#include <gsf/gsf-input-impl.h>
#include <gsf/gsf-infile.h>
G_BEGIN_DECLS
struct _GsfInfile {
GsfInput parent;
};
typedef struct {
GsfInputClass input_class;
int (*num_children) (GsfInfile *infile);
char const *(*name_by_index) (GsfInfile *infile, int i);
GsfInput *(*child_by_index) (GsfInfile *infile,
int i, GError **err);
GsfInput *(*child_by_name) (GsfInfile *infile,
char const *name, GError **err);
} GsfInfileClass;
#define GSF_INFILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSF_INFILE_TYPE, GsfInfileClass))
#define GSF_IS_INFILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSF_INFILE_TYPE))
G_END_DECLS
#endif /* GSF_INFILE_IMPL_H */

View File

@@ -0,0 +1,949 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-msole.c :
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
/* Lots of useful information in
* http://www.aafassociation.org/html/specs/aafcontainerspec-v1.0.1.pdf
*/
#include <gsf-config.h>
#include <gsf/gsf-infile-impl.h>
#include <gsf/gsf-infile-msole.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <gsf/gsf-msole-impl.h>
#include <gsf/gsf-input-proxy.h>
#include <string.h>
#include <stdio.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "libgsf:msole"
static GObjectClass *parent_class;
typedef struct {
guint32 *block;
guint32 num_blocks;
} MSOleBAT;
typedef struct {
char *name;
char *collation_name;
int index;
size_t size;
gboolean use_sb;
guint32 first_block;
gboolean is_directory;
GList *children;
unsigned char clsid[16]; /* 16 byte GUID used by some apps */
} MSOleDirent;
typedef struct {
struct {
MSOleBAT bat;
unsigned shift;
unsigned filter;
size_t size;
} bb, sb;
gsf_off_t max_block;
guint32 threshold; /* transition between small and big blocks */
guint32 sbat_start, num_sbat;
MSOleDirent *root_dir;
GsfInput *sb_file;
int ref_count;
} MSOleInfo;
struct _GsfInfileMSOle {
GsfInfile parent;
GsfInput *input;
MSOleInfo *info;
MSOleDirent *dirent;
MSOleBAT bat;
gsf_off_t cur_block;
struct {
guint8 *buf;
size_t buf_size;
} stream;
};
typedef struct {
GsfInfileClass parent_class;
} GsfInfileMSOleClass;
#define GSF_INFILE_MSOLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSF_INFILE_MSOLE_TYPE, GsfInfileMSOleClass))
#define GSF_IS_INFILE_MSOLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSF_INFILE_MSOLE_TYPE))
/* utility macros */
#define OLE_BIG_BLOCK(index, ole) ((index) >> ole->info->bb.shift)
static GsfInput *gsf_infile_msole_new_child (GsfInfileMSOle *parent,
MSOleDirent *dirent, GError **err);
static void ole_info_unref (MSOleInfo *info);
/**
* ole_get_block :
* @ole : the infile
* @block :
* @buffer : optionally NULL
*
* Read a block of data from the underlying input.
* Be really anal.
**/
static guint8 const *
ole_get_block (GsfInfileMSOle const *ole, guint32 block, guint8 *buffer)
{
g_return_val_if_fail (block < ole->info->max_block, NULL);
/* OLE_HEADER_SIZE is fixed at 512, but the sector containing the
* header is padded out to bb.size (sector size) when bb.size > 512. */
if (gsf_input_seek (ole->input,
(gsf_off_t)(MAX (OLE_HEADER_SIZE, ole->info->bb.size) + (block << ole->info->bb.shift)),
G_SEEK_SET) < 0)
return NULL;
return gsf_input_read (ole->input, ole->info->bb.size, buffer);
}
/**
* ole_make_bat :
* @metabat : a meta bat to connect to the raw blocks (small or large)
* @size_guess : An optional guess as to how many blocks are in the file
* @block : The first block in the list.
* @res : where to store the result.
*
* Walk the linked list of the supplied block allocation table and build up a
* table for the list starting in @block.
*
* Retrurns TRUE on error.
*/
static gboolean
ole_make_bat (MSOleBAT const *metabat, size_t size_guess, guint32 block,
MSOleBAT *res)
{
/* NOTE : Only use size as a suggestion, sometimes it is wrong */
GArray *bat = g_array_sized_new (FALSE, FALSE,
sizeof (guint32), size_guess);
guint8 *used = (guint8*)g_alloca (1 + metabat->num_blocks / 8);
memset (used, 0, 1 + metabat->num_blocks / 8);
if (block < metabat->num_blocks)
do {
/* Catch cycles in the bat list */
g_return_val_if_fail (0 == (used[block/8] & (1 << (block & 0x7))), TRUE);
used[block/8] |= 1 << (block & 0x7);
g_array_append_val (bat, block);
block = metabat->block [block];
} while (block < metabat->num_blocks);
res->block = NULL;
res->num_blocks = bat->len;
res->block = (guint32 *) (gpointer) g_array_free (bat, FALSE);
if (block != BAT_MAGIC_END_OF_CHAIN) {
g_warning ("This OLE2 file is invalid.\n"
"The Block Allocation Table for one of the streams had %x instead of a terminator (%x).\n"
"We might still be able to extract some data, but you'll want to check the file.",
block, BAT_MAGIC_END_OF_CHAIN);
}
return FALSE;
}
static void
ols_bat_release (MSOleBAT *bat)
{
if (bat->block != NULL) {
g_free (bat->block);
bat->block = NULL;
bat->num_blocks = 0;
}
}
/**
* ole_info_read_metabat :
* @ole :
* @bats :
*
* A small utility routine to read a set of references to bat blocks
* either from the OLE header, or a meta-bat block.
*
* Returns a pointer to the element after the last position filled.
**/
static guint32 *
ole_info_read_metabat (GsfInfileMSOle *ole, guint32 *bats, guint32 max,
guint32 const *metabat, guint32 const *metabat_end)
{
guint8 const *bat, *end;
for (; metabat < metabat_end; metabat++) {
bat = ole_get_block (ole, *metabat, NULL);
if (bat == NULL)
return NULL;
end = bat + ole->info->bb.size;
for ( ; bat < end ; bat += BAT_INDEX_SIZE, bats++) {
*bats = GSF_LE_GET_GUINT32 (bat);
g_return_val_if_fail (*bats < max ||
*bats >= BAT_MAGIC_METABAT, NULL);
}
}
return bats;
}
/**
* gsf_ole_get_guint32s :
* @dst :
* @src :
* @num_bytes :
*
* Copy some some raw data into an array of guint32.
**/
static void
gsf_ole_get_guint32s (guint32 *dst, guint8 const *src, int num_bytes)
{
for (; (num_bytes -= BAT_INDEX_SIZE) >= 0 ; src += BAT_INDEX_SIZE)
*dst++ = GSF_LE_GET_GUINT32 (src);
}
static GsfInput *
ole_info_get_sb_file (GsfInfileMSOle *parent)
{
MSOleBAT meta_sbat;
if (parent->info->sb_file != NULL)
return parent->info->sb_file;
parent->info->sb_file = gsf_infile_msole_new_child (parent,
parent->info->root_dir, NULL);
if (!parent->info->sb_file)
return NULL;
/* avoid creating a circular reference */
ole_info_unref (((GsfInfileMSOle *)parent->info->sb_file)->info);
g_return_val_if_fail (parent->info->sb.bat.block == NULL, NULL);
if (ole_make_bat (&parent->info->bb.bat,
parent->info->num_sbat, parent->info->sbat_start, &meta_sbat))
return NULL;
parent->info->sb.bat.num_blocks = meta_sbat.num_blocks * (parent->info->bb.size / BAT_INDEX_SIZE);
parent->info->sb.bat.block = g_new0 (guint32, parent->info->sb.bat.num_blocks);
ole_info_read_metabat (parent, parent->info->sb.bat.block,
parent->info->sb.bat.num_blocks,
meta_sbat.block, meta_sbat.block + meta_sbat.num_blocks);
ols_bat_release (&meta_sbat);
return parent->info->sb_file;
}
static gint
ole_dirent_cmp (MSOleDirent const *a, MSOleDirent const *b)
{
g_return_val_if_fail (a, 0);
g_return_val_if_fail (b, 0);
g_return_val_if_fail (a->collation_name, 0);
g_return_val_if_fail (b->collation_name, 0);
return strcmp (b->collation_name, a->collation_name);
}
/**
* ole_dirent_new :
* @ole :
* @entry :
* @parent : optional
*
* Parse dirent number @entry and recursively handle its siblings and children.
**/
static MSOleDirent *
ole_dirent_new (GsfInfileMSOle *ole, guint32 entry, MSOleDirent *parent)
{
MSOleDirent *dirent;
guint32 block, next, prev, child, size;
guint8 const *data;
guint8 type;
guint16 name_len;
if (entry >= DIRENT_MAGIC_END)
return NULL;
block = OLE_BIG_BLOCK (entry * DIRENT_SIZE, ole);
g_return_val_if_fail (block < ole->bat.num_blocks, NULL);
data = ole_get_block (ole, ole->bat.block [block], NULL);
if (data == NULL)
return NULL;
data += (DIRENT_SIZE * entry) % ole->info->bb.size;
type = GSF_LE_GET_GUINT8 (data + DIRENT_TYPE);
if (type != DIRENT_TYPE_DIR &&
type != DIRENT_TYPE_FILE &&
type != DIRENT_TYPE_ROOTDIR) {
g_warning ("Unknown stream type 0x%x", type);
return NULL;
}
/* It looks like directory (and root directory) sizes are sometimes bogus */
size = GSF_LE_GET_GUINT32 (data + DIRENT_FILE_SIZE);
g_return_val_if_fail (type == DIRENT_TYPE_DIR || type == DIRENT_TYPE_ROOTDIR ||
size <= (guint32)ole->input->size, NULL);
dirent = g_new0 (MSOleDirent, 1);
dirent->index = entry;
dirent->size = size;
/* Store the class id which is 16 byte identifier used by some apps */
memcpy(dirent->clsid, data + DIRENT_CLSID, sizeof(dirent->clsid));
/* root dir is always big block */
dirent->use_sb = parent && (size < ole->info->threshold);
dirent->first_block = (GSF_LE_GET_GUINT32 (data + DIRENT_FIRSTBLOCK));
dirent->is_directory = (type != DIRENT_TYPE_FILE);
dirent->children = NULL;
prev = GSF_LE_GET_GUINT32 (data + DIRENT_PREV);
next = GSF_LE_GET_GUINT32 (data + DIRENT_NEXT);
child = GSF_LE_GET_GUINT32 (data + DIRENT_CHILD);
name_len = GSF_LE_GET_GUINT16 (data + DIRENT_NAME_LEN);
dirent->name = NULL;
if (0 < name_len && name_len <= DIRENT_MAX_NAME_SIZE) {
gunichar2 uni_name [DIRENT_MAX_NAME_SIZE+1];
gchar const *end;
int i;
/* !#%!@$#^
* Sometimes, rarely, people store the stream name as ascii
* rather than utf16. Do a validation first just in case.
*/
if (!g_utf8_validate (data, -1, &end) ||
((guint8 const *)end - data + 1) != name_len) {
/* be wary about endianness */
for (i = 0 ; i < name_len ; i += 2)
uni_name [i/2] = GSF_LE_GET_GUINT16 (data + i);
uni_name [i/2] = 0;
dirent->name = g_utf16_to_utf8 (uni_name, -1, NULL, NULL, NULL);
} else
dirent->name = g_strndup ((gchar *)data, (gsize)((guint8 const *)end - data + 1));
}
/* be really anal in the face of screwups */
if (dirent->name == NULL)
dirent->name = g_strdup ("");
dirent->collation_name = g_utf8_collate_key (dirent->name, -1);
#if 0
printf ("%c '%s' :\tsize = %d\tfirst_block = 0x%x\n",
dirent->is_directory ? 'd' : ' ',
dirent->name, dirent->size, dirent->first_block);
#endif
if (parent != NULL)
parent->children = g_list_insert_sorted (parent->children,
dirent, (GCompareFunc)ole_dirent_cmp);
/* NOTE : These links are a tree, not a linked list */
if (prev == entry) {
g_warning ("Invalid OLE file with a cycle in its directory tree");
} else
ole_dirent_new (ole, prev, parent);
if (next == entry) {
g_warning ("Invalid OLE file with a cycle in its directory tree");
} else
ole_dirent_new (ole, next, parent);
if (dirent->is_directory)
ole_dirent_new (ole, child, dirent);
else if (child != DIRENT_MAGIC_END)
g_warning ("A non directory stream with children ?");
return dirent;
}
static void
ole_dirent_free (MSOleDirent *dirent)
{
GList *tmp;
g_return_if_fail (dirent != NULL);
g_free (dirent->name);
g_free (dirent->collation_name);
for (tmp = dirent->children; tmp; tmp = tmp->next)
ole_dirent_free ((MSOleDirent *)tmp->data);
g_list_free (dirent->children);
g_free (dirent);
}
/*****************************************************************************/
static void
ole_info_unref (MSOleInfo *info)
{
if (info->ref_count-- != 1)
return;
ols_bat_release (&info->bb.bat);
ols_bat_release (&info->sb.bat);
if (info->root_dir != NULL) {
ole_dirent_free (info->root_dir);
info->root_dir = NULL;
}
if (info->sb_file != NULL) {
g_object_unref (G_OBJECT (info->sb_file));
info->sb_file = NULL;
}
g_free (info);
}
static MSOleInfo *
ole_info_ref (MSOleInfo *info)
{
info->ref_count++;
return info;
}
/**
* ole_dup :
* @src :
*
* Utility routine to _partially_ replicate a file. It does NOT copy the bat
* blocks, or init the dirent.
*
* Return value: the partial duplicate.
**/
static GsfInfileMSOle *
ole_dup (GsfInfileMSOle const *src, GError **err)
{
GsfInfileMSOle *dst;
GsfInput *input;
g_return_val_if_fail (src != NULL, NULL);
input = gsf_input_dup (src->input, err);
if (input == NULL) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Failed to duplicate input stream");
return NULL;
}
dst = (GsfInfileMSOle *)g_object_new (GSF_INFILE_MSOLE_TYPE, NULL);
dst->input = input;
dst->info = ole_info_ref (src->info);
/* buf and buf_size are initialized to NULL */
return dst;
}
/**
* ole_init_info :
* @ole :
* @err : optionally NULL
*
* Read an OLE header and do some sanity checking
* along the way.
*
* Return value: TRUE on error setting @err if it is supplied.
**/
static gboolean
ole_init_info (GsfInfileMSOle *ole, GError **err)
{
static guint8 const signature[] =
{ 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
guint8 const *header, *tmp;
guint32 *metabat = NULL;
MSOleInfo *info;
guint32 bb_shift, sb_shift, num_bat, num_metabat, last, dirent_start;
guint32 metabat_block, *ptr;
/* check the header */
if (gsf_input_seek (ole->input, 0, G_SEEK_SET) ||
NULL == (header = gsf_input_read (ole->input, OLE_HEADER_SIZE, NULL)) ||
0 != memcmp (header, signature, sizeof (signature))) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"No OLE2 signature");
return TRUE;
}
bb_shift = GSF_LE_GET_GUINT16 (header + OLE_HEADER_BB_SHIFT);
sb_shift = GSF_LE_GET_GUINT16 (header + OLE_HEADER_SB_SHIFT);
num_bat = GSF_LE_GET_GUINT32 (header + OLE_HEADER_NUM_BAT);
dirent_start = GSF_LE_GET_GUINT32 (header + OLE_HEADER_DIRENT_START);
metabat_block = GSF_LE_GET_GUINT32 (header + OLE_HEADER_METABAT_BLOCK);
num_metabat = GSF_LE_GET_GUINT32 (header + OLE_HEADER_NUM_METABAT);
/* Some sanity checks
* 1) There should always be at least 1 BAT block
* 2) It makes no sense to have a block larger than 2^31 for now.
* Maybe relax this later, but not much.
*/
if (6 > bb_shift || bb_shift >= 31 || sb_shift > bb_shift) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Unreasonable block sizes");
return TRUE;
}
info = g_new0 (MSOleInfo, 1);
ole->info = info;
info->ref_count = 1;
info->bb.shift = bb_shift;
info->bb.size = 1 << info->bb.shift;
info->bb.filter = info->bb.size - 1;
info->sb.shift = sb_shift;
info->sb.size = 1 << info->sb.shift;
info->sb.filter = info->sb.size - 1;
info->threshold = GSF_LE_GET_GUINT32 (header + OLE_HEADER_THRESHOLD);
info->sbat_start = GSF_LE_GET_GUINT32 (header + OLE_HEADER_SBAT_START);
info->num_sbat = GSF_LE_GET_GUINT32 (header + OLE_HEADER_NUM_SBAT);
info->max_block = (gsf_input_size (ole->input) - OLE_HEADER_SIZE) / info->bb.size;
info->sb_file = NULL;
if (info->num_sbat == 0 && info->sbat_start != BAT_MAGIC_END_OF_CHAIN) {
g_warning ("There is are not supposed to be any blocks in the small block allocation table, yet there is a link to some. Ignoring it.");
}
/* very rough heuristic, just in case */
if (num_bat < info->max_block) {
info->bb.bat.num_blocks = num_bat * (info->bb.size / BAT_INDEX_SIZE);
info->bb.bat.block = g_new0 (guint32, info->bb.bat.num_blocks);
metabat = (guint32 *)g_alloca (MAX (info->bb.size, OLE_HEADER_SIZE));
/* Reading the elements invalidates this memory, make copy */
gsf_ole_get_guint32s (metabat, header + OLE_HEADER_START_BAT,
OLE_HEADER_SIZE - OLE_HEADER_START_BAT);
last = num_bat;
if (last > OLE_HEADER_METABAT_SIZE)
last = OLE_HEADER_METABAT_SIZE;
ptr = ole_info_read_metabat (ole, info->bb.bat.block,
info->bb.bat.num_blocks, metabat, metabat + last);
num_bat -= last;
} else
ptr = NULL;
last = (info->bb.size - BAT_INDEX_SIZE) / BAT_INDEX_SIZE;
while (ptr != NULL && num_metabat-- > 0) {
tmp = ole_get_block (ole, metabat_block, NULL);
if (tmp == NULL) {
ptr = NULL;
break;
}
/* Reading the elements invalidates this memory, make copy */
gsf_ole_get_guint32s (metabat, tmp, (int)info->bb.size);
if (num_metabat == 0) {
if (last < num_bat) {
/* there should be less that a full metabat block
* remaining */
ptr = NULL;
break;
}
last = num_bat;
} else if (num_metabat > 0) {
metabat_block = metabat[last];
num_bat -= last;
}
ptr = ole_info_read_metabat (ole, ptr,
info->bb.bat.num_blocks, metabat, metabat + last);
}
if (ptr == NULL) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Inconsistent block allocation table");
return TRUE;
}
/* Read the directory's bat, we do not know the size */
if (ole_make_bat (&info->bb.bat, 0, dirent_start, &ole->bat)) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Problems making block allocation table");
return TRUE;
}
/* Read the directory */
ole->dirent = info->root_dir = ole_dirent_new (ole, 0, NULL);
if (ole->dirent == NULL) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Problems reading directory");
return TRUE;
}
return FALSE;
}
static void
gsf_infile_msole_finalize (GObject *obj)
{
GsfInfileMSOle *ole = GSF_INFILE_MSOLE (obj);
if (ole->input != NULL) {
g_object_unref (G_OBJECT (ole->input));
ole->input = NULL;
}
if (ole->info != NULL &&
ole->info->sb_file != (GsfInput *)ole) {
ole_info_unref (ole->info);
ole->info = NULL;
}
ols_bat_release (&ole->bat);
g_free (ole->stream.buf);
parent_class->finalize (obj);
}
static GsfInput *
gsf_infile_msole_dup (GsfInput *src_input, GError **err)
{
GsfInfileMSOle const *src = GSF_INFILE_MSOLE (src_input);
GsfInfileMSOle *dst = ole_dup (src, err);
if (dst == NULL)
return NULL;
if (src->bat.block != NULL) {
dst->bat.block = g_new (guint32, src->bat.num_blocks),
memcpy (dst->bat.block, src->bat.block,
sizeof (guint32) * src->bat.num_blocks);
}
dst->bat.num_blocks = src->bat.num_blocks;
dst->dirent = src->dirent;
return GSF_INPUT (dst);
}
static guint8 const *
gsf_infile_msole_read (GsfInput *input, size_t num_bytes, guint8 *buffer)
{
GsfInfileMSOle *ole = GSF_INFILE_MSOLE (input);
gsf_off_t first_block, last_block, raw_block, offset, i;
guint8 const *data;
guint8 *ptr;
size_t count;
/* small block files are preload */
if (ole->dirent != NULL && ole->dirent->use_sb) {
if (buffer != NULL) {
memcpy (buffer, ole->stream.buf + input->cur_offset, num_bytes);
return buffer;
}
return ole->stream.buf + input->cur_offset;
}
/* GsfInput guarantees that num_bytes > 0 */
first_block = OLE_BIG_BLOCK (input->cur_offset, ole);
last_block = OLE_BIG_BLOCK (input->cur_offset + num_bytes - 1, ole);
offset = input->cur_offset & ole->info->bb.filter;
/* optimization : are all the raw blocks contiguous */
i = first_block;
raw_block = ole->bat.block [i];
while (++i <= last_block && ++raw_block == ole->bat.block [i])
;
if (i > last_block) {
/* optimization don't seek if we don't need to */
if (ole->cur_block != first_block) {
if (gsf_input_seek (ole->input,
(gsf_off_t)(MAX (OLE_HEADER_SIZE, ole->info->bb.size) + (ole->bat.block [first_block] << ole->info->bb.shift) + offset),
G_SEEK_SET) < 0)
return NULL;
}
ole->cur_block = last_block;
return gsf_input_read (ole->input, num_bytes, buffer);
}
/* damn, we need to copy it block by block */
if (buffer == NULL) {
if (ole->stream.buf_size < num_bytes) {
if (ole->stream.buf != NULL)
g_free (ole->stream.buf);
ole->stream.buf_size = num_bytes;
ole->stream.buf = g_new (guint8, num_bytes);
}
buffer = ole->stream.buf;
}
ptr = buffer;
for (i = first_block ; i <= last_block ; i++ , ptr += count, num_bytes -= count) {
count = ole->info->bb.size - offset;
if (count > num_bytes)
count = num_bytes;
data = ole_get_block (ole, ole->bat.block [i], NULL);
if (data == NULL)
return NULL;
/* TODO : this could be optimized to avoid the copy */
memcpy (ptr, data + offset, count);
offset = 0;
}
ole->cur_block = BAT_MAGIC_UNUSED;
return buffer;
}
static gboolean
gsf_infile_msole_seek (GsfInput *input, gsf_off_t offset, GSeekType whence)
{
GsfInfileMSOle *ole = GSF_INFILE_MSOLE (input);
(void) offset;
(void) whence;
ole->cur_block = BAT_MAGIC_UNUSED;
return FALSE;
}
static GsfInput *
gsf_infile_msole_new_child (GsfInfileMSOle *parent,
MSOleDirent *dirent, GError **err)
{
GsfInfileMSOle *child;
MSOleInfo *info;
MSOleBAT const *metabat;
GsfInput *sb_file = NULL;
size_t size_guess;
child = ole_dup (parent, err);
if (!child)
return NULL;
child->dirent = dirent;
gsf_input_set_size (GSF_INPUT (child), (gsf_off_t) dirent->size);
/* The root dirent defines the small block file */
if (dirent->index != 0) {
gsf_input_set_name (GSF_INPUT (child), dirent->name);
gsf_input_set_container (GSF_INPUT (child), GSF_INFILE (parent));
if (dirent->is_directory) {
/* be wary. It seems as if some implementations pretend that the
* directories contain data */
gsf_input_set_size (GSF_INPUT (child), 0);
return GSF_INPUT (child);
}
}
info = parent->info;
/* build the bat */
if (dirent->use_sb) {
metabat = &info->sb.bat;
size_guess = dirent->size >> info->sb.shift;
sb_file = ole_info_get_sb_file (parent);
if (!sb_file) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Failed to access child");
g_object_unref (G_OBJECT (child));
return NULL;
}
} else {
metabat = &info->bb.bat;
size_guess = dirent->size >> info->bb.shift;
}
if (ole_make_bat (metabat, size_guess + 1, dirent->first_block, &child->bat)) {
g_object_unref (G_OBJECT (child));
return NULL;
}
if (dirent->use_sb) {
unsigned i;
guint8 const *data;
g_return_val_if_fail (sb_file != NULL, NULL);
child->stream.buf_size = info->threshold;
child->stream.buf = g_new (guint8, info->threshold);
for (i = 0 ; i < child->bat.num_blocks; i++)
if (gsf_input_seek (GSF_INPUT (sb_file),
(gsf_off_t)(child->bat.block [i] << info->sb.shift), G_SEEK_SET) < 0 ||
(data = gsf_input_read (GSF_INPUT (sb_file),
info->sb.size,
child->stream.buf + (i << info->sb.shift))) == NULL) {
g_warning ("failure reading block %d", i);
g_object_unref (G_OBJECT (child));
return NULL;
}
}
return GSF_INPUT (child);
}
static GsfInput *
gsf_infile_msole_child_by_index (GsfInfile *infile, int target, GError **err)
{
GsfInfileMSOle *ole = GSF_INFILE_MSOLE (infile);
GList *p;
for (p = ole->dirent->children; p != NULL ; p = p->next)
if (target-- <= 0)
return gsf_infile_msole_new_child (ole,
(MSOleDirent *)p->data, err);
return NULL;
}
static char const *
gsf_infile_msole_name_by_index (GsfInfile *infile, int target)
{
GsfInfileMSOle *ole = GSF_INFILE_MSOLE (infile);
GList *p;
for (p = ole->dirent->children; p != NULL ; p = p->next)
if (target-- <= 0)
return ((MSOleDirent *)p->data)->name;
return NULL;
}
static GsfInput *
gsf_infile_msole_child_by_name (GsfInfile *infile, char const *name, GError **err)
{
GsfInfileMSOle *ole = GSF_INFILE_MSOLE (infile);
GList *p;
for (p = ole->dirent->children; p != NULL ; p = p->next) {
MSOleDirent *dirent = p->data;
if (dirent->name != NULL && !strcmp (name, dirent->name))
return gsf_infile_msole_new_child (ole, dirent, err);
}
return NULL;
}
static int
gsf_infile_msole_num_children (GsfInfile *infile)
{
GsfInfileMSOle *ole = GSF_INFILE_MSOLE (infile);
g_return_val_if_fail (ole->dirent != NULL, -1);
if (!ole->dirent->is_directory)
return -1;
return g_list_length (ole->dirent->children);
}
static void
gsf_infile_msole_init (GObject *obj)
{
GsfInfileMSOle *ole = GSF_INFILE_MSOLE (obj);
ole->input = NULL;
ole->info = NULL;
ole->bat.block = NULL;
ole->bat.num_blocks = 0;
ole->cur_block = BAT_MAGIC_UNUSED;
ole->stream.buf = NULL;
ole->stream.buf_size = 0;
}
static void
gsf_infile_msole_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
GsfInfileClass *infile_class = GSF_INFILE_CLASS (gobject_class);
gobject_class->finalize = gsf_infile_msole_finalize;
input_class->Dup = gsf_infile_msole_dup;
input_class->Read = gsf_infile_msole_read;
input_class->Seek = gsf_infile_msole_seek;
infile_class->num_children = gsf_infile_msole_num_children;
infile_class->name_by_index = gsf_infile_msole_name_by_index;
infile_class->child_by_index = gsf_infile_msole_child_by_index;
infile_class->child_by_name = gsf_infile_msole_child_by_name;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfInfileMSOle, gsf_infile_msole,
gsf_infile_msole_class_init, gsf_infile_msole_init,
GSF_INFILE_TYPE)
/**
* gsf_infile_msole_new :
* @source :
* @err :
*
* Opens the root directory of an MS OLE file.
* NOTE : adds a reference to @source
*
* Returns : the new ole file handler
**/
GsfInfile *
gsf_infile_msole_new (GsfInput *source, GError **err)
{
GsfInfileMSOle *ole;
gsf_off_t calling_pos;
g_return_val_if_fail (GSF_IS_INPUT (source), NULL);
ole = (GsfInfileMSOle *)g_object_new (GSF_INFILE_MSOLE_TYPE, NULL);
ole->input = gsf_input_proxy_new (source);
gsf_input_set_size (GSF_INPUT (ole), 0);
calling_pos = gsf_input_tell (source);
if (ole_init_info (ole, err)) {
/* It's not clear to me why we do this. And if this
fails, there's really nothing we can do. */
(void)gsf_input_seek (source, calling_pos, G_SEEK_SET);
g_object_unref (G_OBJECT (ole));
return NULL;
}
return GSF_INFILE (ole);
}
/**
* gsf_infile_msole_get_class_id :
* @ole: a #GsfInfileMSOle
* @res: 16 byte identifier (often a GUID in MS Windows apps)
*
* Retrieves the 16 byte indentifier (often a GUID in MS Windows apps)
* stored within the directory associated with @ole and stores it in @res.
*
* Returns TRUE on success
**/
gboolean
gsf_infile_msole_get_class_id (GsfInfileMSOle const *ole, guint8 *res)
{
g_return_val_if_fail (ole != NULL && ole->dirent != NULL, FALSE);
memcpy (res, ole->dirent->clsid,
sizeof(ole->dirent->clsid));
return TRUE;
}

View File

@@ -0,0 +1,42 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-msole.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INFILE_MSOLE_H
#define GSF_INFILE_MSOLE_H
#include <gsf/gsf.h>
G_BEGIN_DECLS
typedef struct _GsfInfileMSOle GsfInfileMSOle;
#define GSF_INFILE_MSOLE_TYPE (gsf_infile_msole_get_type ())
#define GSF_INFILE_MSOLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INFILE_MSOLE_TYPE, GsfInfileMSOle))
#define GSF_IS_INFILE_MSOLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INFILE_MSOLE_TYPE))
GType gsf_infile_msole_get_type (void);
GsfInfile *gsf_infile_msole_new (GsfInput *source, GError **err);
gboolean gsf_infile_msole_get_class_id (GsfInfileMSOle const *ole,
guint8 *res);
G_END_DECLS
#endif /* GSF_INFILE_MSOLE_H */

View File

@@ -0,0 +1,441 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-msvba.c :
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
/* Info extracted from
* svx/source/msfilter/msvbasic.cxx
* Costin Raiu, Kaspersky Labs, 'Apple of Discord'
* Virus bulletin's bontchev.pdf, svajcer.pdf
*
* and lots and lots of reading. There are lots of pieces missing still
* but the structure seems to hold together.
*/
#include <gsf-config.h>
#include <gsf/gsf-infile-msvba.h>
#include <gsf/gsf-infile.h>
#include <gsf/gsf-input-memory.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-msole-utils.h>
#include <gsf/gsf-utils.h>
#include <stdio.h>
#include <string.h>
static GObjectClass *parent_class;
struct _GsfInfileMSVBA {
GObject parent;
GsfInfile *source;
GList *children;
};
typedef GObjectClass GsfInfileMSVBAClass;
#define GSF_INFILE_MSVBA_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSF_INFILE_MSVBA_TYPE, GsfInfileMSVBAClass))
#define GSF_IS_INFILE_MSVBA_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSF_INFILE_MSVBA_TYPE))
static guint8 *
gsf_vba_inflate (GsfInput *input, gsf_off_t offset, int *size, gboolean add_null_terminator)
{
GByteArray *res = gsf_msole_inflate (input, offset + 3);
if (res == NULL)
return NULL;
*size = res->len;
if (add_null_terminator)
g_byte_array_append (res, "", 1);
return g_byte_array_free (res, FALSE);
}
static void
vba_extract_module_source (GsfInfileMSVBA *vba, char const *name, guint32 src_offset)
{
GsfInput *module;
guint8 *src_code;
int inflated_size;
g_return_if_fail (name != NULL);
module = gsf_infile_child_by_name (vba->source, name);
if (module == NULL)
return;
src_code = gsf_vba_inflate (module, (gsf_off_t) src_offset, &inflated_size, TRUE);
if (src_code != NULL) {
printf ("======================\n%s\n>>>>>>\n%s<<<<<<\n", name, src_code);
g_free (src_code);
} else
g_warning ("Problems extracting the source for %s @ %u", name, src_offset);
g_object_unref (module);
module = NULL;
}
/**
* vba_dir_read :
* @vba :
* @err : optionally NULL
*
* Read an VBA dirctory and its project file.
* along the way.
*
* Return value: FALSE on error setting @err if it is supplied.
**/
static gboolean
vba_dir_read (GsfInfileMSVBA *vba, GError **err)
{
int inflated_size, element_count = -1;
char const *msg = NULL;
char *name, *elem_stream = NULL;
guint32 len;
guint16 tag;
guint8 *inflated_data, *end, *ptr;
GsfInput *dir;
gboolean failed = TRUE;
/* 0. get the stream */
dir = gsf_infile_child_by_name (vba->source, "dir");
if (dir == NULL) {
msg = "Can't find the VBA directory stream.";
goto fail_stream;
}
/* 1. decompress it */
ptr = inflated_data = gsf_vba_inflate (dir, 0, &inflated_size, FALSE);
if (inflated_data == NULL)
goto fail_compression;
end = inflated_data + inflated_size;
/* 2. GUESS : based on several xls with macros and XL8GARY this looks like a
* series of sized records. Be _extra_ careful */
do {
/* I have seen
* type len data
* 1 4 1 0 0 0
* 2 4 9 4 0 0
* 3 2 4 e4
* 4 <var> project name
* 5 0
* 6 0
* 7 4
* 8 4
* 0x3d 0
* 0x40 0
* 0x14 4 9 4 0 0
*
* 0x0f == number of elements
* 0x1c == (Size 0)
* 0x1e == (Size 4)
* 0x48 == (Size 0)
* 0x31 == stream offset of the compressed source !
*
* 0x16 == an ascii dependency name
* 0x3e == a unicode dependency name
* 0x33 == a classid for a dependency with no trialing data
*
* 0x2f == a dummy classid
* 0x30 == a classid
* 0x0d == the classid
* 0x2f, and 0x0d appear contain
* uint32 classid_size;
* <classid>
* 00 00 00 00 00 00
* and sometimes some trailing junk
**/
if ((ptr + 6) > end) {
msg = "vba project header problem";
goto fail_content;
}
tag = GSF_LE_GET_GUINT16 (ptr);
len = GSF_LE_GET_GUINT32 (ptr + 2);
ptr += 6;
if ((ptr + len) > end) {
msg = "vba project header problem";
goto fail_content;
}
switch (tag) {
case 4:
name = g_strndup (ptr, len);
g_print ("Project Name : '%s'\n", name);
g_free (name);
break;
case 9:
g_print ("Quirk - duff tag length");
len += 2;
break;
case 0xf :
if (len != 2) {
g_warning ("element count is not what we expected");
break;
}
if (element_count >= 0) {
g_warning ("More than one element count ??");
break;
}
element_count = GSF_LE_GET_GUINT16 (ptr);
break;
/* dependencies */
case 0x0d : break;
case 0x2f : break;
case 0x30 : break;
case 0x33 : break;
case 0x3e : break;
case 0x16:
#if 0
name = g_strndup (ptr, len);
g_print ("Depend Name : '%s'\n", name);
g_free (name);
#endif
break;
/* elements */
case 0x47 : break;
case 0x32 : break;
case 0x1a:
#if 0
name = g_strndup (ptr, len);
g_print ("Element Name : '%s'\n", name);
g_free (name);
#endif
break;
case 0x19: elem_stream = g_strndup (ptr, len); break;
case 0x31:
if (len != 4) {
g_warning ("source offset property is not what we expected");
break;
}
vba_extract_module_source (vba, elem_stream,
GSF_LE_GET_GUINT32 (ptr));
g_free (elem_stream); elem_stream = NULL;
element_count--;
break;
default :
#if 0
g_print ("tag %hx : len %u\n", tag, len);
gsf_mem_dump (ptr, len);
#endif
break;
}
ptr += len;
} while (tag != 0x10);
g_free (elem_stream);
if (element_count != 0)
g_warning ("Number of elements differs from expectations");
failed = FALSE;
fail_content :
g_free (inflated_data);
fail_compression :
g_object_unref (G_OBJECT (dir));
fail_stream :
if (failed) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0, msg);
return FALSE;
}
return TRUE;
}
#define VBA56_DIRENT_RECORD_COUNT (2 + /* magic */ \
4 + /* version */ \
2 + /* 0x00 0xff */ \
22) /* unknown */
#define VBA56_DIRENT_HEADER_SIZE (VBA56_DIRENT_RECORD_COUNT + \
2 + /* type1 record count */ \
2) /* unknown */
#if 0
/**
* vba_project_read :
* @vba :
* @err : optionally NULL
*
* Read an VBA dirctory and its project file.
* along the way.
*
* Return value: FALSE on error setting @err if it is supplied.
**/
static gboolean
vba_project_read (GsfInfileMSVBA *vba, GError **err)
{
/* NOTE : This seems constant, find some confirmation */
static guint8 const signature[] = { 0xcc, 0x61 };
static struct {
guint8 const signature[4];
char const * const name;
int const vba_version;
gboolean const is_mac;
} const versions [] = {
{ { 0x5e, 0x00, 0x00, 0x01 }, "Office 97", 5, FALSE},
{ { 0x5f, 0x00, 0x00, 0x01 }, "Office 97 SR1", 5, FALSE },
{ { 0x65, 0x00, 0x00, 0x01 }, "Office 2000 alpha?", 6, FALSE },
{ { 0x6b, 0x00, 0x00, 0x01 }, "Office 2000 beta?", 6, FALSE },
{ { 0x6d, 0x00, 0x00, 0x01 }, "Office 2000", 6, FALSE },
{ { 0x6f, 0x00, 0x00, 0x01 }, "Office 2000", 6, FALSE },
{ { 0x70, 0x00, 0x00, 0x01 }, "Office XP beta 1/2", 6, FALSE },
{ { 0x73, 0x00, 0x00, 0x01 }, "Office XP", 6, FALSE },
{ { 0x76, 0x00, 0x00, 0x01 }, "Office 2003", 6, FALSE },
{ { 0x79, 0x00, 0x00, 0x01 }, "Office 2003", 6, FALSE },
{ { 0x60, 0x00, 0x00, 0x0e }, "MacOffice 98", 5, TRUE },
{ { 0x62, 0x00, 0x00, 0x0e }, "MacOffice 2001", 5, TRUE },
{ { 0x63, 0x00, 0x00, 0x0e }, "MacOffice X", 6, TRUE },
{ { 0x64, 0x00, 0x00, 0x0e }, "MacOffice 2004", 6, TRUE },
};
guint8 const *data;
unsigned i, count, len;
gunichar2 *uni_name;
char *name;
GsfInput *dir;
dir = gsf_infile_child_by_name (vba->source, "dir");
if (dir == NULL) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Can't find the VBA directory stream.");
return FALSE;
}
if (gsf_input_seek (dir, 0, G_SEEK_SET) ||
NULL == (data = gsf_input_read (dir, VBA56_DIRENT_HEADER_SIZE, NULL)) ||
0 != memcmp (data, signature, sizeof (signature))) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"No VBA signature");
return FALSE;
}
for (i = 0 ; i < G_N_ELEMENTS (versions); i++)
if (!memcmp (data+2, versions[i].signature, 4))
break;
if (i >= G_N_ELEMENTS (versions)) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Unknown VBA version signature 0x%x%x%x%x",
data[2], data[3], data[4], data[5]);
return FALSE;
}
puts (versions[i].name);
/* these depend strings seem to come in 2 blocks */
count = GSF_LE_GET_GUINT16 (data + VBA56_DIRENT_RECORD_COUNT);
for (; count > 0 ; count--) {
if (NULL == ((data = gsf_input_read (dir, 2, NULL))))
break;
len = GSF_LE_GET_GUINT16 (data);
if (NULL == ((data = gsf_input_read (dir, len, NULL)))) {
printf ("len == 0x%x ??\n", len);
break;
}
uni_name = g_new0 (gunichar2, len/2 + 1);
/* be wary about endianness */
for (i = 0 ; i < len ; i += 2)
uni_name [i/2] = GSF_LE_GET_GUINT16 (data + i);
name = g_utf16_to_utf8 (uni_name, -1, NULL, NULL, NULL);
g_free (uni_name);
printf ("%d %s\n", count, name);
/* ignore this blob ???? */
if (!strncmp ("*\\G", name, 3)) {
if (NULL == ((data = gsf_input_read (dir, 12, NULL)))) {
printf ("len == 0x%x ??\n", len);
break;
}
}
g_free (name);
}
g_return_val_if_fail (count == 0, FALSE);
return TRUE;
}
#endif
static void
gsf_infile_msvba_finalize (GObject *obj)
{
GsfInfileMSVBA *vba = GSF_INFILE_MSVBA (obj);
if (vba->source != NULL) {
g_object_unref (G_OBJECT (vba->source));
vba->source = NULL;
}
parent_class->finalize (obj);
}
static void
gsf_infile_msvba_init (GObject *obj)
{
GsfInfileMSVBA *vba = GSF_INFILE_MSVBA (obj);
vba->source = NULL;
vba->children = NULL;
}
static void
gsf_infile_msvba_class_init (GObjectClass *gobject_class)
{
gobject_class->finalize = gsf_infile_msvba_finalize;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfInfileMSVBA, gsf_infile_msvba,
gsf_infile_msvba_class_init, gsf_infile_msvba_init,
G_TYPE_OBJECT)
GsfInfile *
gsf_infile_msvba_new (GsfInfile *source, GError **err)
{
GsfInfileMSVBA *vba;
g_return_val_if_fail (GSF_IS_INFILE (source), NULL);
vba = g_object_new (GSF_INFILE_MSVBA_TYPE, NULL);
g_object_ref (G_OBJECT (source));
vba->source = source;
/* vba_project_read (vba, err); */
/* find the name offset pairs */
if (vba_dir_read (vba, err))
return GSF_INFILE (vba);
if (err != NULL && *err == NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Unable to parse VBA header");
g_object_unref (G_OBJECT (vba));
return NULL;
}

View File

@@ -0,0 +1,42 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-msvba.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INFILE_MSVBA_H
#define GSF_INFILE_MSVBA_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _GsfInfileMSVBA GsfInfileMSVBA;
#define GSF_INFILE_MSVBA_TYPE (gsf_infile_msvba_get_type ())
#define GSF_INFILE_MSVBA(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INFILE_MSVBA_TYPE, GsfInfileMSVBA))
#define GSF_IS_INFILE_MSVBA(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INFILE_MSVBA_TYPE))
GType gsf_infile_msvba_get_type (void);
GsfInfile *gsf_infile_msvba_new (GsfInfile *source, GError **err);
G_END_DECLS
#endif /* GSF_INFILE_MSVBA_H */

View File

@@ -0,0 +1,201 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-stdio.c: read a directory tree
*
* Copyright (C) 2004 Novell, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-infile.h>
#include <gsf/gsf-infile-impl.h>
#include <gsf/gsf-infile-stdio.h>
#include <gsf/gsf-input-impl.h>
#include <gsf/gsf-input-stdio.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <glib/gdir.h>
#include <string.h>
static GObjectClass *parent_class;
struct _GsfInfileStdio {
GsfInfile parent;
char *root;
GList *children;
};
typedef GsfInfileClass GsfInfileStdioClass;
static void
gsf_infile_stdio_finalize (GObject *obj)
{
GsfInfileStdio *ifs = GSF_INFILE_STDIO (obj);
g_free (ifs->root);
g_list_foreach (ifs->children, (GFunc) g_free, NULL);
g_list_free (ifs->children);
parent_class->finalize (obj);
}
static GsfInput *
gsf_infile_stdio_dup (GsfInput *src_input, G_GNUC_UNUSED GError **err)
{
GsfInfileStdio *src = GSF_INFILE_STDIO (src_input);
GsfInfileStdio *dst = g_object_new (gsf_infile_stdio_get_type(), NULL);
GList *ptr;
dst->root = g_strdup (src->root);
for (ptr = src->children; ptr != NULL ; ptr = ptr->next)
dst->children = g_list_prepend (dst->children,
g_strdup (ptr->data));
dst->children = g_list_reverse (dst->children);
return GSF_INPUT (dst);
}
static guint8 const *
gsf_infile_stdio_read (G_GNUC_UNUSED GsfInput *input, G_GNUC_UNUSED size_t num_bytes,
G_GNUC_UNUSED guint8 *buffer)
{
return NULL;
}
static GsfInput *
open_child (GsfInfileStdio *ifs, char const *name, GError **err)
{
GsfInput *child;
char *path = g_build_filename (ifs->root, name, NULL);
if (g_file_test (path, G_FILE_TEST_IS_DIR))
child = (GsfInput *) gsf_infile_stdio_new (path, err);
else
child = gsf_input_stdio_new (path, err);
g_free (path);
return child;
}
static GsfInput *
gsf_infile_stdio_child_by_index (GsfInfile *infile, int target, GError **err)
{
GsfInfileStdio *ifs = GSF_INFILE_STDIO (infile);
char const *name = g_list_nth_data (ifs->children, target);
if (!name)
return NULL;
return open_child (ifs, name, err);
}
static char const *
gsf_infile_stdio_name_by_index (GsfInfile *infile, int target)
{
GsfInfileStdio *ifs = GSF_INFILE_STDIO (infile);
return g_list_nth_data (ifs->children, target);
}
static GsfInput *
gsf_infile_stdio_child_by_name (GsfInfile *infile, char const *name, GError **err)
{
GsfInfileStdio *ifs = GSF_INFILE_STDIO (infile);
GList *ptr;
for (ptr = ifs->children; ptr != NULL; ptr = ptr->next)
if (!strcmp (ptr->data, name))
return open_child (ifs, name, err);
return NULL;
}
static int
gsf_infile_stdio_num_children (GsfInfile *infile)
{
GsfInfileStdio *ifs = GSF_INFILE_STDIO (infile);
return g_list_length (ifs->children);
}
static void
gsf_infile_stdio_init (GsfInfileStdio *ifs)
{
ifs->root = NULL;
ifs->children = NULL;
}
static void
gsf_infile_stdio_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
GsfInfileClass *infile_class = GSF_INFILE_CLASS (gobject_class);
parent_class = g_type_class_peek (GSF_INFILE_TYPE);
gobject_class->finalize = gsf_infile_stdio_finalize;
input_class->Dup = gsf_infile_stdio_dup;
input_class->Read = gsf_infile_stdio_read;
input_class->Seek = NULL;
infile_class->num_children = gsf_infile_stdio_num_children;
infile_class->name_by_index = gsf_infile_stdio_name_by_index;
infile_class->child_by_index = gsf_infile_stdio_child_by_index;
infile_class->child_by_name = gsf_infile_stdio_child_by_name;
}
GSF_CLASS (GsfInfileStdio, gsf_infile_stdio,
gsf_infile_stdio_class_init, gsf_infile_stdio_init,
GSF_INFILE_TYPE)
/**
* gsf_infile_stdio_new :
* @root : in locale dependent encoding
* @err : optionally NULL.
*
* Returns a new file or NULL.
**/
GsfInfile *
gsf_infile_stdio_new (char const *root, GError **err)
{
GsfInfileStdio *ifs;
GDir *dir;
char const *child;
dir = g_dir_open (root, 0, err);
if (dir == NULL)
return NULL;
ifs = g_object_new (gsf_infile_stdio_get_type(), NULL);
ifs->root = g_strdup (root);
while ((child = g_dir_read_name (dir)))
ifs->children = g_list_prepend (ifs->children,
g_strdup (child));
g_dir_close (dir);
gsf_input_set_name_from_filename (GSF_INPUT (ifs), root);
return GSF_INFILE (ifs);
}

View File

@@ -0,0 +1,40 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-stdio.h:
*
* Copyright (C) 2004 Novell, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INFILE_STDIO_H
#define GSF_INFILE_STDIO_H
#include <gsf/gsf.h>
G_BEGIN_DECLS
typedef struct _GsfInfileStdio GsfInfileStdio;
#define GSF_INFILE_STDIO_TYPE (gsf_infile_stdio_get_type ())
#define GSF_INFILE_STDIO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INFILE_STDIO_TYPE, GsfInfileStdio))
#define GSF_IS_INFILE_STDIO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INFILE_STDIO_TYPE))
GType gsf_infile_stdio_get_type (void);
GsfInfile *gsf_infile_stdio_new (char const *root, GError **err);
G_END_DECLS
#endif /* GSF_INFILE_STDIO_H */

View File

@@ -0,0 +1,866 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-zip.c :
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
* Tambet Ingo (tambet@ximian.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-infile-impl.h>
#include <gsf/gsf-infile-zip.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <gsf/gsf-zip-impl.h>
#include <gsf/gsf-input-proxy.h>
#include <string.h>
#include <zlib.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "libgsf:zip"
enum {
PROP_0,
PROP_SOURCE,
PROP_COMPRESSION_LEVEL,
PROP_INTERNAL_PARENT,
};
static GObjectClass *parent_class;
typedef struct {
guint16 entries;
guint32 dir_pos;
GList *dirent_list;
GsfZipVDir *vdir;
int ref_count;
} ZipInfo;
struct _GsfInfileZip {
GsfInfile parent;
GsfInput *source;
ZipInfo *info;
GsfZipVDir *vdir;
z_stream *stream;
guint32 restlen;
guint32 crestlen;
guint8 *buf;
size_t buf_size;
gsf_off_t seek_skipped;
GError *err;
GsfInfileZip *dup_parent;
};
typedef struct {
GsfInfileClass parent_class;
} GsfInfileZipClass;
#define GSF_INFILE_ZIP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSF_INFILE_ZIP_TYPE, GsfInfileZipClass))
#define GSF_IS_INFILE_ZIP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSF_INFILE_ZIP_TYPE))
static GsfZipVDir *
vdir_child_by_name (GsfZipVDir *vdir, char const *name)
{
GSList *l;
for (l = vdir->children; l; l = l->next) {
GsfZipVDir *child = (GsfZipVDir *) l->data;
if (strcmp (child->name, name) == 0)
return child;
}
return NULL;
}
static GsfZipVDir *
vdir_child_by_index (GsfZipVDir *vdir, int target)
{
return g_slist_nth_data (vdir->children, target);
}
static void
vdir_insert (GsfZipVDir *vdir, char const * name, GsfZipDirent *dirent)
{
char const *p;
char *dirname;
GsfZipVDir *child;
p = strchr (name, ZIP_NAME_SEPARATOR);
if (p) { /* A directory */
dirname = g_strndup (name, (gsize) (p - name));
child = vdir_child_by_name (vdir, dirname);
if (!child) {
child = gsf_vdir_new (dirname, TRUE, NULL);
gsf_vdir_add_child (vdir, child);
}
g_free (dirname);
if (*(p+1) != '\0') {
name = p+1;
vdir_insert (child, name, dirent);
}
} else { /* A simple file name */
child = gsf_vdir_new (name, FALSE, dirent);
gsf_vdir_add_child (vdir, child);
}
}
static gsf_off_t
zip_find_trailer (GsfInfileZip *zip)
{
static guint8 const trailer_signature[] =
{ 'P', 'K', 0x05, 0x06 };
gsf_off_t offset, trailer_offset, filesize;
gsf_off_t maplen;
guint8 const *data;
filesize = gsf_input_size (zip->source);
if (filesize < ZIP_TRAILER_SIZE)
return -1;
trailer_offset = filesize;
maplen = filesize & (ZIP_BUF_SIZE - 1);
if (maplen == 0)
maplen = ZIP_BUF_SIZE;
offset = filesize - maplen; /* offset is now BUFSIZ aligned */
while (TRUE) {
guchar *p, *s;
if (gsf_input_seek (zip->source, offset, G_SEEK_SET))
return -1;
if ((data = gsf_input_read (zip->source, maplen, NULL)) == NULL)
return -1;
p = (guchar *) data;
for (s = p + maplen - 1; (s >= p); s--, trailer_offset--) {
if ((*s == 'P') &&
(p + maplen - 1 - s > ZIP_TRAILER_SIZE - 2) &&
!memcmp (s, trailer_signature, sizeof (trailer_signature))) {
return --trailer_offset;
}
}
/* not found in currently mapped block, so update it if
* there is some room in before. The requirements are..
* (a) mappings should overlap so that trailer can cross BUFSIZ-boundary
* (b) trailer cannot be farther away than 64K from fileend
*/
/* outer loop cond */
if (offset <= 0)
return -1;
/* outer loop step */
offset -= ZIP_BUF_SIZE / 2;
maplen = MIN (filesize - offset, ZIP_BUF_SIZE);
trailer_offset = offset + maplen;
if (filesize - offset > 64 * 1024)
return -1;
} /*outer loop*/
return -1;
}
static GsfZipDirent *
zip_dirent_new_in (GsfInfileZip *zip, gsf_off_t *offset)
{
static guint8 const dirent_signature[] =
{ 'P', 'K', 0x01, 0x02 };
GsfZipDirent *dirent;
guint8 const *data;
guint16 name_len, extras_len, comment_len, compr_method;
guint32 crc32, csize, usize, off;
gchar *name;
/* Read data and check the header */
if (gsf_input_seek (zip->source, *offset, G_SEEK_SET) ||
NULL == (data = gsf_input_read (zip->source, ZIP_DIRENT_SIZE, NULL)) ||
0 != memcmp (data, dirent_signature, sizeof (dirent_signature))) {
return NULL;
}
name_len = GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_NAME_SIZE);
extras_len = GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_EXTRAS_SIZE);
comment_len = GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_COMMENT_SIZE);
compr_method = GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_COMPR_METHOD);
crc32 = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_CRC32);
csize = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_CSIZE);
usize = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_USIZE);
off = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_OFFSET);
if ((data = gsf_input_read (zip->source, name_len, NULL)) == NULL)
return NULL;
name = g_new (gchar, (gulong) (name_len + 1));
memcpy (name, data, name_len);
name[name_len] = '\0';
dirent = gsf_zip_dirent_new ();
dirent->name = name;
dirent->compr_method = compr_method;
dirent->crc32 = crc32;
dirent->csize = csize;
dirent->usize = usize;
dirent->offset = off;
*offset += ZIP_DIRENT_SIZE + name_len + extras_len + comment_len;
return dirent;
}
/*****************************************************************************/
static ZipInfo *
zip_info_ref (ZipInfo *info)
{
info->ref_count++;
return info;
}
static void
zip_info_unref (ZipInfo *info)
{
GList *p;
if (info->ref_count-- != 1)
return;
gsf_vdir_free (info->vdir, FALSE);
for (p = info->dirent_list; p != NULL; p = p->next)
gsf_zip_dirent_free ((GsfZipDirent *) p->data);
g_list_free (info->dirent_list);
g_free (info);
}
/**
* zip_dup :
* @src :
*
* Return value: the partial duplicate.
**/
static GsfInfileZip *
zip_dup (GsfInfileZip const *src, GError **err)
{
GsfInfileZip *dst;
g_return_val_if_fail (src != NULL, NULL);
dst = g_object_new (GSF_INFILE_ZIP_TYPE,
"internal-parent", src,
NULL);
if (dst->err) {
if (err)
*err = g_error_copy (dst->err);
g_object_unref (dst);
return NULL;
}
return dst;
}
/**
* zip_read_dirents:
* @zip :
*
* Read zip headers and do some sanity checking
* along the way.
*
* Return value: TRUE on error setting zip->err.
**/
static gboolean
zip_read_dirents (GsfInfileZip *zip)
{
guint8 const *trailer;
guint16 entries, i;
guint32 dir_pos;
ZipInfo *info;
gsf_off_t offset;
/* Find and check the trailing header */
offset = zip_find_trailer (zip);
if (offset < 0) {
zip->err = g_error_new (gsf_input_error_id (), 0,
"No Zip trailer");
return TRUE;
}
if (gsf_input_seek (zip->source, offset, G_SEEK_SET) ||
NULL == (trailer = gsf_input_read (zip->source, ZIP_TRAILER_SIZE, NULL))) {
zip->err = g_error_new (gsf_input_error_id (), 0,
"Error reading Zip signature");
return TRUE;
}
entries = GSF_LE_GET_GUINT32 (trailer + ZIP_TRAILER_ENTRIES);
dir_pos = GSF_LE_GET_GUINT32 (trailer + ZIP_TRAILER_DIR_POS);
info = g_new0 (ZipInfo, 1);
zip->info = info;
info->ref_count = 1;
info->entries = entries;
info->dir_pos = dir_pos;
/* Read the directory */
for (i = 0, offset = dir_pos; i < entries; i++) {
GsfZipDirent *d;
d = zip_dirent_new_in (zip, &offset);
if (d == NULL) {
zip->err = g_error_new (gsf_input_error_id (), 0,
"Error reading zip dirent");
return TRUE;
}
info->dirent_list = g_list_append (info->dirent_list, d);
}
return FALSE;
}
static void
zip_build_vdirs (GsfInfileZip *zip)
{
GList *l;
GsfZipDirent *dirent;
ZipInfo *info = zip->info;
info->vdir = gsf_vdir_new ("", TRUE, NULL);
for (l = info->dirent_list; l; l = l->next) {
dirent = (GsfZipDirent *) l->data;
vdir_insert (info->vdir, dirent->name, dirent);
}
}
/**
* zip_init_info :
* @zip :
*
* Read zip headers and do some sanity checking
* along the way.
*
* Return value: TRUE on error setting zip->err.
**/
static gboolean
zip_init_info (GsfInfileZip *zip)
{
gboolean ret;
ret = zip_read_dirents (zip);
if (ret != FALSE)
return ret;
zip_build_vdirs (zip);
return FALSE;
}
/* returns TRUE on error */
static gboolean
zip_child_init (GsfInfileZip *child, GError **errmsg)
{
static guint8 const header_signature[] =
{ 'P', 'K', 0x03, 0x04 };
guint8 const *data;
guint16 name_len, extras_len;
GsfZipDirent *dirent = child->vdir->dirent;
/* skip local header
* should test tons of other info, but trust that those are correct
**/
if (gsf_input_seek (child->source, (gsf_off_t) dirent->offset, G_SEEK_SET) ||
NULL == (data = gsf_input_read (child->source, ZIP_FILE_HEADER_SIZE, NULL)) ||
0 != memcmp (data, header_signature, sizeof (header_signature))) {
if (errmsg != NULL)
*errmsg = g_error_new (gsf_input_error_id (), 0,
"Unable to read zip header.");
return TRUE;
}
name_len = GSF_LE_GET_GUINT16 (data + ZIP_FILE_HEADER_NAME_SIZE);
extras_len = GSF_LE_GET_GUINT16 (data + ZIP_FILE_HEADER_EXTRAS_SIZE);
dirent->data_offset = dirent->offset + ZIP_FILE_HEADER_SIZE + name_len + extras_len;
child->restlen = dirent->usize;
child->crestlen = dirent->csize;
if (dirent->compr_method != GSF_ZIP_STORED) {
int err;
if (!child->stream)
child->stream = g_new0 (z_stream, 1);
err = inflateInit2 (child->stream, -MAX_WBITS);
if (err != Z_OK) {
if (errmsg != NULL)
*errmsg = g_error_new (gsf_input_error_id (), 0,
"problem uncompressing stream");
return TRUE;
}
}
return FALSE;
}
/* GsfInput class functions */
static GsfInput *
gsf_infile_zip_dup (GsfInput *src_input, GError **err)
{
GsfInfileZip const *src = GSF_INFILE_ZIP (src_input);
GsfInfileZip *dst = zip_dup (src, err);
if (dst == NULL)
return NULL;
dst->vdir = src->vdir;
if (dst->vdir->dirent && zip_child_init (dst, err)) {
g_object_unref (dst);
return NULL;
}
return GSF_INPUT (dst);
}
static gboolean
zip_update_stream_in (GsfInfileZip *zip)
{
guint32 read_now;
guint8 const *data;
gsf_off_t pos;
if (zip->crestlen == 0)
return FALSE;
read_now = MIN (zip->crestlen, ZIP_BLOCK_SIZE);
pos = zip->vdir->dirent->data_offset + zip->stream->total_in;
if (gsf_input_seek (zip->source, pos, G_SEEK_SET))
return FALSE;
if ((data = gsf_input_read (zip->source, read_now, NULL)) == NULL)
return FALSE;
zip->crestlen -= read_now;
zip->stream->next_in = (unsigned char *) data; /* next input byte */
zip->stream->avail_in = read_now; /* number of bytes available at next_in */
return TRUE;
}
static guint8 const *
gsf_infile_zip_read (GsfInput *input, size_t num_bytes, guint8 *buffer)
{
GsfInfileZip *zip = GSF_INFILE_ZIP (input);
GsfZipVDir *vdir = zip->vdir;
gsf_off_t pos;
if (zip->restlen < num_bytes)
return NULL;
switch (vdir->dirent->compr_method) {
case GSF_ZIP_STORED:
zip->restlen -= num_bytes;
pos = zip->vdir->dirent->data_offset + input->cur_offset;
if (gsf_input_seek (zip->source, pos, G_SEEK_SET))
return NULL;
return gsf_input_read (zip->source, num_bytes, buffer);
case GSF_ZIP_DEFLATED:
if (buffer == NULL) {
if (zip->buf_size < num_bytes) {
zip->buf_size = MAX (num_bytes, 256);
g_free (zip->buf);
zip->buf = g_new (guint8, zip->buf_size);
}
buffer = zip->buf;
}
zip->stream->avail_out = num_bytes;
zip->stream->next_out = (unsigned char *)buffer;
do {
int err;
int startlen;
if (zip->crestlen > 0 && zip->stream->avail_in == 0)
if (!zip_update_stream_in (zip))
break;
startlen = zip->stream->total_out;
err = inflate(zip->stream, Z_NO_FLUSH);
if (err == Z_STREAM_END)
zip->restlen = 0;
else if (err == Z_OK)
zip->restlen -= (zip->stream->total_out - startlen);
else
break;
} while (zip->restlen && zip->stream->avail_out);
return buffer;
default:
break;
}
return NULL;
}
static gboolean
gsf_infile_zip_seek (GsfInput *input, gsf_off_t offset, GSeekType whence)
{
GsfInfileZip *zip = GSF_INFILE_ZIP (input);
/* Global flag -- we don't want one per stream. */
static gboolean warned = FALSE;
gsf_off_t pos = offset;
/* Note, that pos has already been sanity checked. */
switch (whence) {
case G_SEEK_SET : break;
case G_SEEK_CUR : pos += input->cur_offset; break;
case G_SEEK_END : pos += input->size; break;
default : return TRUE;
}
if (zip->stream) {
zip->stream->next_in = NULL;
zip->stream->avail_in = 0;
zip->stream->total_in = 0;
}
if (zip_child_init (zip, NULL)) {
g_warning ("failure initializing zip child");
return TRUE;
}
input->cur_offset = 0;
if (gsf_input_seek_emulate (input, pos))
return TRUE;
zip->seek_skipped += pos;
if (!warned &&
zip->seek_skipped != pos && /* Don't warn for single seek. */
zip->seek_skipped >= 1000000) {
warned = TRUE;
g_warning ("Seeking in zip child streams is awfully slow.");
}
return FALSE;
}
/* GsfInfile class functions */
/*****************************************************************************/
static GsfInput *
gsf_infile_zip_new_child (GsfInfileZip *parent, GsfZipVDir *vdir, GError **err)
{
GsfInfileZip *child;
GsfZipDirent *dirent = vdir->dirent;
child = zip_dup (parent, err);
if (child == NULL)
return NULL;
gsf_input_set_name (GSF_INPUT (child), vdir->name);
gsf_input_set_container (GSF_INPUT (child), GSF_INFILE (parent));
child->vdir = vdir;
if (dirent) {
gsf_input_set_size (GSF_INPUT (child),
(gsf_off_t) dirent->usize);
if (zip_child_init (child, err) != FALSE) {
g_object_unref (child);
return NULL;
}
} else
gsf_input_set_size (GSF_INPUT (child), 0);
return GSF_INPUT (child);
}
static GsfInput *
gsf_infile_zip_child_by_index (GsfInfile *infile, int target, GError **err)
{
GsfInfileZip *zip = GSF_INFILE_ZIP (infile);
GsfZipVDir *child_vdir = vdir_child_by_index (zip->vdir, target);
if (child_vdir)
return gsf_infile_zip_new_child (zip, child_vdir, err);
return NULL;
}
static char const *
gsf_infile_zip_name_by_index (GsfInfile *infile, int target)
{
GsfInfileZip *zip = GSF_INFILE_ZIP (infile);
GsfZipVDir *child_vdir = vdir_child_by_index (zip->vdir, target);
if (child_vdir)
return child_vdir->name;
return NULL;
}
static GsfInput *
gsf_infile_zip_child_by_name (GsfInfile *infile, char const *name, GError **err)
{
GsfInfileZip *zip = GSF_INFILE_ZIP (infile);
GsfZipVDir *child_vdir = vdir_child_by_name (zip->vdir, name);
if (child_vdir)
return gsf_infile_zip_new_child (zip, child_vdir, err);
return NULL;
}
static int
gsf_infile_zip_num_children (GsfInfile *infile)
{
GsfInfileZip *zip = GSF_INFILE_ZIP (infile);
g_return_val_if_fail (zip->vdir != NULL, -1);
if (!zip->vdir->is_directory)
return -1;
return g_slist_length (zip->vdir->children);
}
static void
gsf_infile_zip_finalize (GObject *obj)
{
GsfInfileZip *zip = GSF_INFILE_ZIP (obj);
if (zip->source != NULL) {
g_object_unref (G_OBJECT (zip->source));
zip->source = NULL;
}
if (zip->info != NULL) {
zip_info_unref (zip->info);
zip->info = NULL;
}
if (zip->stream)
(void) inflateEnd (zip->stream);
g_free (zip->stream);
g_free (zip->buf);
g_clear_error (&zip->err);
parent_class->finalize (obj);
}
static GObject*
gsf_infile_zip_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
GsfInfileZip *zip;
zip = (GsfInfileZip *)(parent_class->constructor (type,
n_construct_properties,
construct_params));
if (zip->dup_parent) {
/* Special call from zip_dup. */
zip->source = gsf_input_dup (zip->dup_parent->source, &zip->err);
zip->info = zip_info_ref (zip->dup_parent->info);
zip->dup_parent = NULL;
} else {
if (!zip_init_info (zip))
zip->vdir = zip->info->vdir;
}
return (GObject *)zip;
}
static void
gsf_infile_zip_init (GObject *obj)
{
GsfInfileZip *zip = (GsfInfileZip *)obj;
zip->source = NULL;
zip->info = NULL;
zip->vdir = NULL;
zip->stream = NULL;
zip->restlen = 0;
zip->crestlen = 0;
zip->buf = NULL;
zip->buf_size = 0;
zip->seek_skipped = 0;
zip->err = NULL;
}
static void
gsf_infile_zip_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GsfInfileZip *zip = (GsfInfileZip *)object;
switch (property_id) {
case PROP_SOURCE:
g_value_set_object (value, zip->source);
break;
case PROP_COMPRESSION_LEVEL:
g_value_set_int (value,
zip->vdir->dirent
? zip->vdir->dirent->compr_method
: 0);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_infile_zip_set_source (GsfInfileZip *zip, GsfInput *src)
{
if (src)
src = gsf_input_proxy_new (src);
if (zip->source)
g_object_unref (zip->source);
zip->source = src;
}
static void
gsf_infile_zip_set_property (GObject *object,
guint property_id,
GValue const *value,
GParamSpec *pspec)
{
GsfInfileZip *zip = (GsfInfileZip *)object;
switch (property_id) {
case PROP_SOURCE:
gsf_infile_zip_set_source (zip, g_value_get_object (value));
break;
case PROP_INTERNAL_PARENT:
zip->dup_parent = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_infile_zip_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
GsfInfileClass *infile_class = GSF_INFILE_CLASS (gobject_class);
gobject_class->constructor = gsf_infile_zip_constructor;
gobject_class->finalize = gsf_infile_zip_finalize;
gobject_class->get_property = gsf_infile_zip_get_property;
gobject_class->set_property = gsf_infile_zip_set_property;
input_class->Dup = gsf_infile_zip_dup;
input_class->Read = gsf_infile_zip_read;
input_class->Seek = gsf_infile_zip_seek;
infile_class->num_children = gsf_infile_zip_num_children;
infile_class->name_by_index = gsf_infile_zip_name_by_index;
infile_class->child_by_index = gsf_infile_zip_child_by_index;
infile_class->child_by_name = gsf_infile_zip_child_by_name;
parent_class = g_type_class_peek_parent (gobject_class);
g_object_class_install_property
(gobject_class,
PROP_SOURCE,
g_param_spec_object ("source",
"Source",
"The archive being interpreted.",
GSF_INPUT_TYPE,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(gobject_class,
PROP_COMPRESSION_LEVEL,
g_param_spec_int ("compression-level",
"Compression Level",
"The level of compression used, zero meaning none.",
0, 10,
0,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
g_object_class_install_property
(gobject_class,
PROP_INTERNAL_PARENT,
g_param_spec_object ("internal-parent",
"",
"Internal use only",
GSF_INFILE_ZIP_TYPE,
GSF_PARAM_STATIC |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
}
GSF_CLASS (GsfInfileZip, gsf_infile_zip,
gsf_infile_zip_class_init, gsf_infile_zip_init,
GSF_INFILE_TYPE)
/**
* gsf_infile_zip_new :
* @source : A base #GsfInput
* @err : A #GError, optionally %null
*
* Opens the root directory of a Zip file.
* NOTE : adds a reference to @source
*
* Returns : the new zip file handler
**/
GsfInfile *
gsf_infile_zip_new (GsfInput *source, GError **err)
{
GsfInfileZip *zip;
g_return_val_if_fail (GSF_IS_INPUT (source), NULL);
zip = g_object_new (GSF_INFILE_ZIP_TYPE,
"source", source,
NULL);
if (zip->err) {
if (err)
*err = g_error_copy (zip->err);
g_object_unref (zip);
return NULL;
}
return GSF_INFILE (zip);
}

View File

@@ -0,0 +1,40 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile-zip.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INFILE_ZIP_H
#define GSF_INFILE_ZIP_H
#include <gsf/gsf.h>
G_BEGIN_DECLS
typedef struct _GsfInfileZip GsfInfileZip;
#define GSF_INFILE_ZIP_TYPE (gsf_infile_zip_get_type ())
#define GSF_INFILE_ZIP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INFILE_ZIP_TYPE, GsfInfileZip))
#define GSF_IS_INFILE_ZIP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INFILE_ZIP_TYPE))
GType gsf_infile_zip_get_type (void);
GsfInfile *gsf_infile_zip_new (GsfInput *source, GError **err);
G_END_DECLS
#endif /* GSF_INFILE_ZIP_H */

View File

@@ -0,0 +1,159 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile.c :
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-infile-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <stdarg.h>
#define GET_CLASS(instance) G_TYPE_INSTANCE_GET_CLASS (instance, GSF_INFILE_TYPE, GsfInfileClass)
/**
* gsf_infile_num_children :
* @infile : the structured storage
*
* Returns the number of children the storage has, or -1 if the storage can not
* have children.
**/
int
gsf_infile_num_children (GsfInfile *infile)
{
g_return_val_if_fail (infile != NULL, -1);
return GET_CLASS (infile)->num_children (infile);
}
/**
* gsf_infile_name_by_index :
* @infile :
* @i :
*
* Returns the utf8 encoded name of the @i-th child
* NOTE : DO NOT FREE THE STRING
**/
char const *
gsf_infile_name_by_index (GsfInfile *infile, int i)
{
g_return_val_if_fail (infile != NULL, NULL);
return GET_CLASS (infile)->name_by_index (infile, i);
}
/**
* gsf_infile_child_by_index :
* @infile :
* @i :
*
* TODO : For 2.0 api will change to include a GError.
* Returns a newly created child which must be unrefed.
**/
GsfInput *
gsf_infile_child_by_index (GsfInfile *infile, int i)
{
GError *err = NULL;
GsfInput *res;
g_return_val_if_fail (GSF_INFILE (infile) != NULL, NULL);
res = GET_CLASS (infile)->child_by_index (infile, i, &err);
if (err != NULL) {
char const *iname = gsf_input_name (GSF_INPUT (infile));
g_warning ("Unable to get child[%d] for infile '%s' because : %s",
i, iname ? iname : "?", err->message);
g_error_free (err);
g_return_val_if_fail (res == NULL, NULL); /* be anal */
}
return res;
}
/**
* gsf_infile_child_by_name :
* @infile :
* @name :
*
* TODO : For 2.0 api will change to include a GError.
* Returns a newly created child which must be unrefed.
**/
GsfInput *
gsf_infile_child_by_name (GsfInfile *infile, char const *name)
{
GError *err = NULL;
GsfInput *res;
g_return_val_if_fail (GSF_INFILE (infile) != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
res = GET_CLASS (infile)->child_by_name (infile, name, &err);
if (err != NULL) {
char const *iname = gsf_input_name (GSF_INPUT (infile));
g_warning ("Unable to get child['%s'] for infile '%s' because : %s",
name, iname ? iname : "?", err->message);
g_error_free (err);
g_return_val_if_fail (res == NULL, NULL); /* be anal */
}
return res;
}
/**
* gsf_infile_child_by_vname :
* @infile :
* @name : A %null terminated list of names
* @Varargs : the rest of the names
*
* Returns a newly created child which must be unrefed.
**/
GsfInput *
gsf_infile_child_by_vname (GsfInfile *infile, char const *name, ...)
{
va_list ap;
GsfInput *child = GSF_INPUT (infile);
GsfInfile *tmp = NULL;
g_return_val_if_fail (GSF_IS_INFILE (infile), NULL);
g_return_val_if_fail (name != NULL, NULL);
va_start (ap, name);
while (1) {
child = gsf_infile_child_by_name (infile, name);
name = va_arg (ap, char *);
if (tmp != NULL)
g_object_unref (G_OBJECT (tmp));
if (name == NULL)
break;
if (child == NULL)
break;
g_return_val_if_fail (GSF_IS_INFILE (child), NULL);
infile = tmp = GSF_INFILE (child);
}
va_end (ap);
return child;
}
GSF_CLASS_ABSTRACT (GsfInfile, gsf_infile, NULL, NULL, GSF_INPUT_TYPE)

View File

@@ -0,0 +1,44 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-infile.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INFILE_H
#define GSF_INFILE_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GSF_INFILE_TYPE (gsf_infile_get_type ())
#define GSF_INFILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INFILE_TYPE, GsfInfile))
#define GSF_IS_INFILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INFILE_TYPE))
GType gsf_infile_get_type (void);
int gsf_infile_num_children (GsfInfile *infile);
char const *gsf_infile_name_by_index (GsfInfile *infile, int i);
GsfInput *gsf_infile_child_by_index (GsfInfile *infile, int i);
GsfInput *gsf_infile_child_by_name (GsfInfile *infile, char const *name);
GsfInput *gsf_infile_child_by_vname (GsfInfile *infile, char const *name, ...);
G_END_DECLS
#endif /* GSF_INFILE_H */

View File

@@ -0,0 +1,109 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-iochannel.c: BZ2 based input
*
* Copyright (C) 2003-2004 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf-input-bzip.h>
#include <gsf-output-memory.h>
#include <string.h>
#ifdef HAVE_BZ2
/* For getting FILE. Don't ask. */
#include <stdio.h>
#include <bzlib.h>
#define BZ_BUFSIZ 1024
#endif
/**
* gsf_input_memory_new_from_bzip :
* @source : a #GsfInput
* @err : a #GError
*
* Returns a new #GsfInputMemory or NULL.
*/
GsfInput *
gsf_input_memory_new_from_bzip (GsfInput *source, GError **err)
{
#ifndef HAVE_BZ2
if (err)
*err = g_error_new (gsf_input_error_id (), 0,
"BZ2 support not enabled");
return NULL;
#else
bz_stream bzstm;
GsfInput *mem = NULL;
GsfOutput *sink = NULL;
guint8 out_buf [BZ_BUFSIZ];
int bzerr = BZ_OK;
g_return_val_if_fail (source != NULL, NULL);
memset (&bzstm, 0, sizeof (bzstm));
if (BZ_OK != BZ2_bzDecompressInit (&bzstm, 0, 0)) {
if (err)
*err = g_error_new (gsf_input_error_id (), 0,
"BZ2 decompress init failed");
return NULL;
}
sink = gsf_output_memory_new ();
for (;;) {
bzstm.next_out = (char *)out_buf;
bzstm.avail_out = (unsigned int)sizeof (out_buf);
if (bzstm.avail_in == 0) {
bzstm.avail_in = (unsigned int)MIN (gsf_input_remaining (source), BZ_BUFSIZ);
bzstm.next_in = (char *)gsf_input_read (source, bzstm.avail_in, NULL);
}
bzerr = BZ2_bzDecompress (&bzstm);
if (bzerr != BZ_OK && bzerr != BZ_STREAM_END) {
if (err)
*err = g_error_new (gsf_input_error_id (), 0,
"BZ2 decompress failed");
BZ2_bzDecompressEnd (&bzstm);
gsf_output_close (sink);
g_object_unref (G_OBJECT (sink));
return NULL;
}
gsf_output_write (sink, BZ_BUFSIZ - bzstm.avail_out, out_buf);
if (bzerr == BZ_STREAM_END)
break;
}
gsf_output_close (sink);
if (BZ_OK != BZ2_bzDecompressEnd (&bzstm)) {
if (err)
*err = g_error_new (gsf_input_error_id (), 0,
"BZ2 decompress end failed");
g_object_unref (G_OBJECT (sink));
return NULL;
}
mem = gsf_input_memory_new_clone (
gsf_output_memory_get_bytes (GSF_OUTPUT_MEMORY (sink)),
gsf_output_size (sink));
g_object_unref (G_OBJECT (sink));
return mem;
#endif
}

View File

@@ -0,0 +1,33 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-bzip.h: wrapper to compress to bzipped output
*
* Copyright (C) 2003-2004 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_BZIP_H
#define GSF_INPUT_BZIP_H
#include <gsf/gsf-input-memory.h>
G_BEGIN_DECLS
GsfInput *gsf_input_memory_new_from_bzip (GsfInput *source, GError **err);
G_END_DECLS
#endif /* GSF_INPUT_BZIP_H */

View File

@@ -0,0 +1,533 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-gzip.c: wrapper to uncompress gzipped input
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
* Copyright (C) 2005 Morten Welinder (terra@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-input-gzip.h>
#include <gsf/gsf-input-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <zlib.h>
#include <stdio.h>
#include <string.h>
#define Z_BUFSIZE 0x100
static GObjectClass *parent_class;
struct _GsfInputGZip {
GsfInput input;
GsfInput *source; /* compressed data */
gboolean raw; /* No header and no trailer. */
GError *err;
gsf_off_t uncompressed_size;
gboolean stop_byte_added;
z_stream stream;
guint8 const *gzipped_data;
uLong crc; /* crc32 of uncompressed data */
guint8 *buf;
size_t buf_size;
size_t header_size, trailer_size;
gsf_off_t seek_skipped;
};
typedef struct {
GsfInputClass input_class;
} GsfInputGZipClass;
enum {
PROP_0,
PROP_RAW,
PROP_SOURCE,
PROP_UNCOMPRESSED_SIZE
};
/* gzip flag byte */
#define GZIP_IS_ASCII 0x01 /* file contains text ? */
#define GZIP_HEADER_CRC 0x02 /* there is a CRC in the header */
#define GZIP_EXTRA_FIELD 0x04 /* there is an 'extra' field */
#define GZIP_ORIGINAL_NAME 0x08 /* the original is stored */
#define GZIP_HAS_COMMENT 0x10 /* There is a comment in the header */
#define GZIP_HEADER_FLAGS (unsigned)(GZIP_IS_ASCII |GZIP_HEADER_CRC |GZIP_EXTRA_FIELD |GZIP_ORIGINAL_NAME |GZIP_HAS_COMMENT)
static gboolean
check_header (GsfInputGZip *input)
{
if (input->raw) {
input->header_size = 0;
input->trailer_size = 0;
} else {
static guint8 const signature[2] = {0x1f, 0x8b};
guint8 const *data;
unsigned flags, len;
/* Check signature */
if (NULL == (data = gsf_input_read (input->source, 2 + 1 + 1 + 6, NULL)) ||
0 != memcmp (data, signature, sizeof (signature)))
return TRUE;
/* verify flags and compression type */
flags = data[3];
if (data[2] != Z_DEFLATED || (flags & ~GZIP_HEADER_FLAGS) != 0)
return TRUE;
/* If we have the size, don't bother seeking to the end. */
if (input->uncompressed_size < 0) {
/* Get the uncompressed size */
if (gsf_input_seek (input->source, (gsf_off_t) -4, G_SEEK_END) ||
NULL == (data = gsf_input_read (input->source, 4, NULL)))
return TRUE;
/* FIXME, but how? The size read here is modulo 2^32. */
input->uncompressed_size = GSF_LE_GET_GUINT32 (data);
if (input->uncompressed_size / 1000 > gsf_input_size (input->source)) {
g_warning ("Suspiciously well compressed file with better than 1000:1 ratio.\n"
"It is probably truncated or corrupt");
}
}
if (gsf_input_seek (input->source, 2 + 1 + 1 + 6, G_SEEK_SET))
return TRUE;
if (flags & GZIP_EXTRA_FIELD) {
if (NULL == (data = gsf_input_read (input->source, 2, NULL)))
return TRUE;
len = GSF_LE_GET_GUINT16 (data);
if (NULL == gsf_input_read (input->source, len, NULL))
return TRUE;
}
if (flags & GZIP_ORIGINAL_NAME) {
/* Skip over the filename (which is in ISO 8859-1 encoding). */
do {
if (NULL == (data = gsf_input_read (input->source, 1, NULL)))
return TRUE;
} while (*data != 0);
}
if (flags & GZIP_HAS_COMMENT) {
/* Skip over the comment (which is in ISO 8859-1 encoding). */
do {
if (NULL == (data = gsf_input_read (input->source, 1, NULL)))
return TRUE;
} while (*data != 0);
}
if (flags & GZIP_HEADER_CRC &&
NULL == (data = gsf_input_read (input->source, 2, NULL)))
return TRUE;
input->header_size = input->source->cur_offset;
/* the last 8 bytes are the crc and size. */
input->trailer_size = 8;
}
gsf_input_set_size (GSF_INPUT (input), input->uncompressed_size);
if (gsf_input_remaining (input->source) < input->trailer_size)
return TRUE; /* No room for payload */
return FALSE;
}
static gboolean
init_zip (GsfInputGZip *gzip, GError **err)
{
gsf_off_t cur_pos;
if (Z_OK != inflateInit2 (&(gzip->stream), -MAX_WBITS)) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Unable to initialize zlib");
return TRUE;
}
cur_pos = gsf_input_tell (gzip->source);
if (gsf_input_seek (gzip->source, 0, G_SEEK_SET)) {
if (err)
*err = g_error_new (gsf_input_error_id (), 0,
"Failed to rewind source");
return TRUE;
}
if (check_header (gzip) != FALSE) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Invalid gzip header");
if (gsf_input_seek (gzip->source, cur_pos, G_SEEK_SET)) {
g_warning ("attempt to restore position failed ??");
}
return TRUE;
}
return FALSE;
}
/**
* gsf_input_gzip_new :
* @source : The underlying data source.
* @err : optionally NULL.
*
* Adds a reference to @source.
*
* Returns a new file or NULL.
**/
GsfInput *
gsf_input_gzip_new (GsfInput *source, GError **err)
{
GsfInputGZip *gzip;
g_return_val_if_fail (GSF_IS_INPUT (source), NULL);
gzip = g_object_new (GSF_INPUT_GZIP_TYPE,
"source", source,
NULL);
if (gzip->err) {
if (err)
*err = g_error_copy (gzip->err);
g_object_unref (gzip);
return NULL;
}
return GSF_INPUT (gzip);
}
static void
gsf_input_gzip_finalize (GObject *obj)
{
GsfInputGZip *gzip = (GsfInputGZip *)obj;
if (gzip->source != NULL) {
g_object_unref (G_OBJECT (gzip->source));
gzip->source = NULL;
}
g_free (gzip->buf);
if (gzip->stream.state != NULL)
inflateEnd (&(gzip->stream));
g_clear_error (&gzip->err);
parent_class->finalize (obj);
}
static GsfInput *
gsf_input_gzip_dup (GsfInput *src_input, GError **err)
{
GsfInputGZip const *src = (GsfInputGZip *)src_input;
GsfInputGZip *dst;
GsfInput *src_source_copy;
if (src->source) {
src_source_copy = gsf_input_dup (src->source, err);
if (err)
return NULL;
} else
src_source_copy = NULL;
dst = g_object_new (GSF_INPUT_GZIP_TYPE,
"source", src_source_copy,
"raw", src->raw,
NULL);
if (src_source_copy)
g_object_unref (src_source_copy);
if (src->err) {
g_clear_error (&dst->err);
dst->err = g_error_copy (src->err);
} else if (dst->err) {
if (err)
*err = g_error_copy (dst->err);
g_object_unref (dst);
return NULL;
}
return GSF_INPUT (dst);
}
static guint8 const *
gsf_input_gzip_read (GsfInput *input, size_t num_bytes, guint8 *buffer)
{
GsfInputGZip *gzip = GSF_INPUT_GZIP (input);
if (buffer == NULL) {
if (gzip->buf_size < num_bytes) {
gzip->buf_size = MAX (num_bytes, 256);
g_free (gzip->buf);
gzip->buf = g_new (guint8, gzip->buf_size);
}
buffer = gzip->buf;
}
gzip->stream.next_out = buffer;
gzip->stream.avail_out = num_bytes;
while (gzip->stream.avail_out != 0) {
int zerr;
if (gzip->stream.avail_in == 0) {
gsf_off_t remain = gsf_input_remaining (gzip->source);
if (remain <= gzip->trailer_size) {
if (remain < gzip->trailer_size || gzip->stop_byte_added) {
g_clear_error (&gzip->err);
gzip->err = g_error_new
(gsf_input_error_id (), 0,
"truncated source");
return NULL;
}
/* zlib requires an extra byte. */
gzip->stream.avail_in = 1;
gzip->gzipped_data = "";
gzip->stop_byte_added = TRUE;
} else {
size_t n = MIN (remain - gzip->trailer_size,
Z_BUFSIZE);
gzip->gzipped_data =
gsf_input_read (gzip->source, n, NULL);
if (!gzip->gzipped_data) {
g_clear_error (&gzip->err);
gzip->err = g_error_new
(gsf_input_error_id (), 0,
"Failed to read from source");
return NULL;
}
gzip->stream.avail_in = n;
}
gzip->stream.next_in = (Byte *)gzip->gzipped_data;
}
zerr = inflate (&(gzip->stream), Z_NO_FLUSH);
if (zerr != Z_OK) {
if (zerr != Z_STREAM_END)
return NULL;
/* Premature end of stream. */
if (gzip->stream.avail_out != 0)
return NULL;
}
}
gzip->crc = crc32 (gzip->crc, buffer, (uInt)(gzip->stream.next_out - buffer));
return buffer;
}
static gboolean
gsf_input_gzip_seek (GsfInput *input, gsf_off_t offset, GSeekType whence)
{
GsfInputGZip *gzip = GSF_INPUT_GZIP (input);
/* Global flag -- we don't want one per stream. */
static gboolean warned = FALSE;
gsf_off_t pos = offset;
/* Note, that pos has already been sanity checked. */
switch (whence) {
case G_SEEK_SET : break;
case G_SEEK_CUR : pos += input->cur_offset; break;
case G_SEEK_END : pos += input->size; break;
default : return TRUE;
}
if (pos < input->cur_offset) {
if (gsf_input_seek (gzip->source,
(gsf_off_t)gzip->header_size,
G_SEEK_SET))
return TRUE;
gzip->crc = crc32 (0L, Z_NULL, 0);
gzip->stream.avail_in = 0;
if (inflateReset (&(gzip->stream)) != Z_OK)
return TRUE;
input->cur_offset = 0;
}
if (gsf_input_seek_emulate (input, pos))
return TRUE;
gzip->seek_skipped += pos;
if (!warned &&
gzip->seek_skipped != pos && /* Don't warn for single seek. */
gzip->seek_skipped >= 1000000) {
warned = TRUE;
g_warning ("Seeking in gzipped streams is awfully slow.");
}
return FALSE;
}
static void
gsf_input_gzip_init (GObject *obj)
{
GsfInputGZip *gzip = GSF_INPUT_GZIP (obj);
gzip->source = NULL;
gzip->raw = FALSE;
gzip->uncompressed_size = -1;
gzip->err = NULL;
gzip->stream.zalloc = (alloc_func)0;
gzip->stream.zfree = (free_func)0;
gzip->stream.opaque = (voidpf)0;
gzip->stream.next_in = Z_NULL;
gzip->stream.next_out = Z_NULL;
gzip->stream.avail_in = gzip->stream.avail_out = 0;
gzip->crc = crc32 (0L, Z_NULL, 0);
gzip->buf = NULL;
gzip->buf_size = 0;
gzip->seek_skipped = 0;
}
static void
gsf_input_gzip_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GsfInputGZip *gzip = (GsfInputGZip *)object;
switch (property_id) {
case PROP_RAW:
g_value_set_boolean (value, gzip->raw);
break;
case PROP_SOURCE:
g_value_set_object (value, gzip->source);
break;
case PROP_UNCOMPRESSED_SIZE:
g_value_set_int64 (value, gzip->uncompressed_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_input_gzip_set_source (GsfInputGZip *gzip, GsfInput *source)
{
if (source)
g_object_ref (GSF_INPUT (source));
if (gzip->source)
g_object_unref (gzip->source);
gzip->source = source;
}
static void
gsf_input_gzip_set_property (GObject *object,
guint property_id,
GValue const *value,
GParamSpec *pspec)
{
GsfInputGZip *gzip = (GsfInputGZip *)object;
switch (property_id) {
case PROP_RAW:
gzip->raw = g_value_get_boolean (value);
break;
case PROP_SOURCE:
gsf_input_gzip_set_source (gzip, g_value_get_object (value));
break;
case PROP_UNCOMPRESSED_SIZE:
gzip->uncompressed_size = g_value_get_int64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static GObject*
gsf_input_gzip_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
GsfInputGZip *gzip;
gzip = (GsfInputGZip *)(parent_class->constructor (type,
n_construct_properties,
construct_params));
if (!gzip->source) {
g_clear_error (&gzip->err);
gzip->err = g_error_new (gsf_input_error_id (), 0,
"NULL source");
} else if (gzip->raw && gzip->uncompressed_size < 0) {
g_clear_error (&gzip->err);
gzip->err = g_error_new (gsf_input_error_id (), 0,
"Uncompressed size not set");
} else if (init_zip (gzip, &gzip->err) != FALSE) {
/* Nothing more. */
}
return (GObject *)gzip;
}
static void
gsf_input_gzip_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
gobject_class->constructor = gsf_input_gzip_constructor;
gobject_class->finalize = gsf_input_gzip_finalize;
gobject_class->set_property = gsf_input_gzip_set_property;
gobject_class->get_property = gsf_input_gzip_get_property;
input_class->Dup = gsf_input_gzip_dup;
input_class->Read = gsf_input_gzip_read;
input_class->Seek = gsf_input_gzip_seek;
g_object_class_install_property
(gobject_class,
PROP_RAW,
g_param_spec_boolean ("raw", "Raw",
"Whether to read compressed data with no header and no trailer.",
FALSE,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(gobject_class,
PROP_SOURCE,
g_param_spec_object ("source", "Source",
"Where the compressed data comes from.",
GSF_INPUT_TYPE,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
/**
* GsfInputGzip:uncompressed_size:
*
* The size that the data will have after uncompression.
* The is mandatory for raw streams and if the uncompressed size is
* larger than 4GB.
*/
g_object_class_install_property
(gobject_class,
PROP_UNCOMPRESSED_SIZE,
g_param_spec_int64 ("uncompressed-size", "Size after decompression",
"The source's uncompressed size",
-1, G_MAXINT64, -1,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfInputGZip, gsf_input_gzip,
gsf_input_gzip_class_init, gsf_input_gzip_init, GSF_INPUT_TYPE)

View File

@@ -0,0 +1,40 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-gzip.h: wrapper to uncompress gzipped input
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_GZIP_H
#define GSF_INPUT_GZIP_H
#include "gsf-input.h"
G_BEGIN_DECLS
#define GSF_INPUT_GZIP_TYPE (gsf_input_gzip_get_type ())
#define GSF_INPUT_GZIP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INPUT_GZIP_TYPE, GsfInputGZip))
#define GSF_IS_INPUT_GZIP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INPUT_GZIP_TYPE))
typedef struct _GsfInputGZip GsfInputGZip;
GType gsf_input_gzip_get_type (void);
GsfInput *gsf_input_gzip_new (GsfInput *source, GError **err);
G_END_DECLS
#endif /* GSF_INPUT_GZIP_H */

View File

@@ -0,0 +1,69 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input.h-impl.h: interface for used by the ole layer to read raw data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_IMPL_H
#define GSF_INPUT_IMPL_H
#include <gsf/gsf.h>
#include <gsf/gsf-input.h>
#include <glib-object.h>
G_BEGIN_DECLS
struct _GsfInput {
GObject g_object;
gsf_off_t size, cur_offset;
char *name;
GsfInfile *container;
};
typedef struct {
GObjectClass g_object_class;
GsfInput *(*Dup) (GsfInput *input, GError **err);
const guint8 *(*Read) (GsfInput *input, size_t num_bytes,
guint8 *optional_buffer);
gboolean (*Seek) (GsfInput *input, gsf_off_t offset,
GSeekType whence);
GsfInput *(*OpenSibling) (GsfInput const *input,
char const *path, GError **err);
/* Padding for future expansion */
void (*_gsf_reserved0) (void);
void (*_gsf_reserved1) (void);
void (*_gsf_reserved2) (void);
void (*_gsf_reserved3) (void);
} GsfInputClass;
#define GSF_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSF_INPUT_TYPE, GsfInputClass))
#define GSF_IS_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSF_INPUT_TYPE))
/* protected */
gboolean gsf_input_set_name (GsfInput *input, char const *name);
gboolean gsf_input_set_name_from_filename (GsfInput *input, char const *filename);
gboolean gsf_input_set_container (GsfInput *input, GsfInfile *container);
gboolean gsf_input_set_size (GsfInput *input, gsf_off_t size);
gboolean gsf_input_seek_emulate (GsfInput *input, gsf_off_t pos);
G_END_DECLS
#endif /* GSF_INPUT_IMPL_H */

View File

@@ -0,0 +1,46 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-iochannel.c: GIOChannel based input
*
* Copyright (C) 2003-2004 Rodrigo Moya (rodrigo@gnome-db.org)
* Copyright (C) 2003-2004 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf-input-iochannel.h>
/**
* gsf_input_memory_new_from_iochannel :
* @channel : a #GIOChannel.
* @error : a #GError
*
* Returns a new #GsfInputMemory or NULL.
*/
GsfInput *
gsf_input_memory_new_from_iochannel (GIOChannel *channel,
GError **err)
{
gchar *buf;
gsize len;
g_return_val_if_fail (channel != NULL, NULL);
if (G_IO_STATUS_NORMAL != g_io_channel_read_to_end (channel, &buf, &len, err))
return NULL;
return gsf_input_memory_new (buf, len, TRUE);
}

View File

@@ -0,0 +1,34 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-iochannel.h: interface for use by the structured file layer to read data from IO channels
*
* Copyright (C) 2002-2004 Rodrigo Moya (rodrigo@gnome-db.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_IOCHANNEL_H
#define GSF_INPUT_IOCHANNEL_H
#include <gsf/gsf-input-memory.h>
G_BEGIN_DECLS
GsfInput *gsf_input_memory_new_from_iochannel (GIOChannel *channel,
GError **error);
G_END_DECLS
#endif /* GSF_INPUT_IOCHANNEL_H */

View File

@@ -0,0 +1,313 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-memory.c:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <string.h>
#include <gsf/gsf-input-memory.h>
#include <gsf/gsf-input-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <gsf/gsf-shared-memory.h>
#ifdef HAVE_GLIB26
#include <glib/gstdio.h>
#else
#include "glib24_26-compat.h"
#endif // HAVE_GLIB26
#ifdef HAVE_MMAP
#if defined(FREEBSD) || defined(__FreeBSD__)
/* We must keep the file open while pages are mapped. */
/* http://www.freebsd.org/cgi/query-pr.cgi?pr=48291 */
#define HAVE_BROKEN_MMAP
#endif /* defined(FREEBSD) || defined(__FreeBSD__) */
#elif defined(G_OS_WIN32)
#include <windows.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <io.h>
#include <fcntl.h>
#define MAP_FAILED NULL
#endif /* HAVE_MMAP */
#ifndef O_BINARY
#define O_BINARY 0
#endif
static GObjectClass *parent_class;
struct _GsfInputMemory {
GsfInput parent;
GsfSharedMemory *shared;
#ifdef HAVE_BROKEN_MMAP
int fd;
#endif
};
typedef GsfInputClass GsfInputMemoryClass;
/**
* gsf_input_memory_new:
* @buf: The input bytes
* @length: The length of @buf
* @needs_free: Whether you want this memory to be free'd at object destruction
*
* Returns: A new #GsfInputMemory
*/
GsfInput *
gsf_input_memory_new (guint8 const *buf, gsf_off_t length, gboolean needs_free)
{
GsfInputMemory *mem = g_object_new (GSF_INPUT_MEMORY_TYPE, NULL);
mem->shared = gsf_shared_memory_new ((void *)buf, length, needs_free);
gsf_input_set_size (GSF_INPUT (mem), length);
return GSF_INPUT (mem);
}
/**
* gsf_input_memory_new_clone:
* @buf: The input bytes
* @length: The length of @buf
*
* Returns: A new #GsfInputMemory
*/
GsfInput *
gsf_input_memory_new_clone (guint8 const *buf, gsf_off_t length)
{
GsfInputMemory *mem = NULL;
guint8 * cpy = g_try_malloc (length * sizeof (guint8));
if (cpy == NULL)
return NULL;
memcpy (cpy, buf, length);
mem = g_object_new (GSF_INPUT_MEMORY_TYPE, NULL);
mem->shared = gsf_shared_memory_new ((void *)cpy, length, TRUE);
gsf_input_set_size (GSF_INPUT (mem), length);
return GSF_INPUT (mem);
}
static void
gsf_input_memory_finalize (GObject *obj)
{
GsfInputMemory *mem = (GsfInputMemory *) (obj);
if (mem->shared)
g_object_unref (G_OBJECT (mem->shared));
#ifdef HAVE_BROKEN_MMAP
if (mem->fd != -1)
close (mem->fd);
#endif
parent_class->finalize (obj);
}
static GsfInput *
gsf_input_memory_dup (GsfInput *src_input, G_GNUC_UNUSED GError **err)
{
GsfInputMemory const *src = (GsfInputMemory *) (src_input);
GsfInputMemory *dst = g_object_new (GSF_INPUT_MEMORY_TYPE, NULL);
dst->shared = src->shared;
g_object_ref (G_OBJECT (dst->shared));
gsf_input_set_size (GSF_INPUT (dst), src->shared->size);
#ifdef HAVE_BROKEN_MMAP
if (src->fd != -1)
dst->fd = dup (src->fd);
#endif
return GSF_INPUT (dst);
}
static guint8 const *
gsf_input_memory_read (GsfInput *input, size_t num_bytes, guint8 *optional_buffer)
{
GsfInputMemory *mem = (GsfInputMemory *) (input);
guchar const *src = mem->shared->buf;
if (src == NULL)
return NULL;
if (optional_buffer) {
memcpy (optional_buffer, src + input->cur_offset, num_bytes);
return optional_buffer;
} else
return src + input->cur_offset;
}
static gboolean
gsf_input_memory_seek (G_GNUC_UNUSED GsfInput *input,
G_GNUC_UNUSED gsf_off_t offset,
G_GNUC_UNUSED GSeekType whence)
{
return FALSE;
}
static void
gsf_input_memory_init (GObject *obj)
{
GsfInputMemory *mem = (GsfInputMemory *) (obj);
mem->shared = NULL;
#ifdef HAVE_BROKEN_MMAP
mem->fd = -1;
#endif
}
static void
gsf_input_memory_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_input_memory_finalize;
input_class->Dup = gsf_input_memory_dup;
input_class->Read = gsf_input_memory_read;
input_class->Seek = gsf_input_memory_seek;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfInputMemory, gsf_input_memory,
gsf_input_memory_class_init, gsf_input_memory_init,
GSF_INPUT_TYPE)
/***************************************************************************/
#ifdef HAVE_MMAP
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#ifndef PROT_READ
#define PROT_READ 0x1
#endif /* PROT_READ */
#if !defined(MAP_FAILED) || defined(__osf__)
/* Someone needs their head examined - BSD ? */
# define MAP_FAILED ((void *)-1)
#endif /* !defined(MAP_FAILED) || defined(__osf__) */
#endif /* HAVE_MMAP */
/**
* gsf_input_mmap_new:
* @filename: The file on disk that you want to mmap
* @err: A #GError, or optionally %null
*
* Returns: A new #GsfInputMemory
*/
GsfInput *
gsf_input_mmap_new (char const *filename, GError **err)
{
#if defined(HAVE_MMAP) || defined(G_OS_WIN32)
GsfInputMemory *mem;
guint8 *buf = NULL;
struct stat st;
int fd;
size_t size;
fd = g_open (filename, O_RDONLY | O_BINARY, 0);
if (fd < 0 || fstat (fd, &st) < 0) {
if (err != NULL) {
int save_errno = errno;
char *utf8name = g_filename_display_name (filename);
*err = g_error_new (gsf_input_error_id (), 0,
"%s: %s",
utf8name, g_strerror (save_errno));
g_free (utf8name);
}
if (fd >= 0) close (fd);
return NULL;
}
if (!S_ISREG (st.st_mode)) {
if (err != NULL) {
char *utf8name = g_filename_display_name (filename);
*err = g_error_new (gsf_input_error_id (), 0,
"%s: Is not a regular file",
utf8name);
g_free (utf8name);
}
close (fd);
return NULL;
}
size = (size_t) st.st_size;
if ((off_t) size != st.st_size) { /* Check for overflow */
if (err != NULL) {
char *utf8name = g_filename_display_name (filename);
*err = g_error_new (gsf_input_error_id (), 0,
"%s: File too large to be memory mapped",
utf8name);
g_free (utf8name);
}
close (fd);
return NULL;
}
#ifdef G_OS_WIN32
{
HANDLE handle = CreateFileMapping ((HANDLE)_get_osfhandle (fd), NULL, PAGE_READONLY, 0, 0, NULL);
buf = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, 0);
CloseHandle (handle);
}
#else
buf = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, (off_t) 0);
#endif
if (buf == MAP_FAILED) {
if (err != NULL) {
int save_errno = errno;
char *utf8name = g_filename_display_name (filename);
*err = g_error_new (gsf_input_error_id (), 0,
"%s: %s",
utf8name, g_strerror (save_errno));
g_free (utf8name);
}
close (fd);
return NULL;
}
mem = g_object_new (GSF_INPUT_MEMORY_TYPE, NULL);
mem->shared = gsf_shared_memory_mmapped_new (buf, (gsf_off_t) size);
gsf_input_set_size (GSF_INPUT (mem), (gsf_off_t) size);
gsf_input_set_name (GSF_INPUT (mem), filename);
#ifdef HAVE_BROKEN_MMAP
mem->fd = fd;
#else
close (fd);
#endif
return GSF_INPUT (mem);
#else
(void)filename;
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"mmap not supported");
return NULL;
#endif
}

View File

@@ -0,0 +1,43 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-memory.h: interface for used by the ole layer to read raw data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_MEMORY_H
#define GSF_INPUT_MEMORY_H
#include "gsf-input.h"
G_BEGIN_DECLS
#define GSF_INPUT_MEMORY_TYPE (gsf_input_memory_get_type ())
#define GSF_INPUT_MEMORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INPUT_MEMORY_TYPE, GsfInputMemory))
#define GSF_IS_INPUT_MEMORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INPUT_MEMORY_TYPE))
typedef struct _GsfInputMemory GsfInputMemory;
GType gsf_input_memory_get_type (void);
GsfInput *gsf_input_memory_new (guint8 const *buf, gsf_off_t length,
gboolean needs_free);
GsfInput *gsf_input_memory_new_clone (guint8 const *buf, gsf_off_t length);
GsfInput *gsf_input_mmap_new (char const *filename, GError **err);
G_END_DECLS
#endif /* GSF_INPUT_MEMORY_H */

View File

@@ -0,0 +1,169 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-proxy.c: proxy object (with its own current position)
*
* Copyright (C) 2004 Morten Welinder (terra@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-input-proxy.h>
#include <gsf/gsf-input-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
static GObjectClass *parent_class;
struct _GsfInputProxy {
GsfInput input;
GsfInput *source;
gsf_off_t offset;
};
typedef struct {
GsfInputClass input_class;
} GsfInputProxyClass;
/**
* gsf_input_proxy_new_section :
* @source : The underlying data source.
* @offset : Offset into source for start of section.
* @size : Length of section.
*
* This creates a new proxy to a section of the given source. The new
* object will have its own current position, but any operation on it
* can change the source's position.
*
* If a proxy to a proxy is created, the intermediate proxy is short-
* circuited.
*
* This function will ref the source.
*
* Returns a new input object.
**/
GsfInput *
gsf_input_proxy_new_section (GsfInput *source,
gsf_off_t offset,
gsf_off_t size)
{
GsfInputProxy *proxy;
gsf_off_t source_size;
g_return_val_if_fail (GSF_IS_INPUT (source), NULL);
g_return_val_if_fail (offset >= 0, NULL);
source_size = gsf_input_size (source);
g_return_val_if_fail (offset <= source_size, NULL);
g_return_val_if_fail (size <= source_size - offset, NULL);
proxy = g_object_new (GSF_INPUT_PROXY_TYPE, NULL);
proxy->offset = offset;
gsf_input_set_size (GSF_INPUT (proxy), size);
/* Short-circuit multiple proxies. */
if (GSF_IS_INPUT_PROXY (source)) {
GsfInputProxy *proxy_source = GSF_INPUT_PROXY (source);
proxy->offset += proxy_source->offset;
source = proxy_source->source;
}
proxy->source = g_object_ref (source);
return GSF_INPUT (proxy);
}
/**
* gsf_input_proxy_new :
* @source : The underlying data source.
*
* This creates a new proxy to the entire, given input source. See
* gsf_input_proxy_new_section for details.
*
* Returns a new input object.
**/
GsfInput *
gsf_input_proxy_new (GsfInput *source)
{
return gsf_input_proxy_new_section (source, 0, gsf_input_size (source));
}
static void
gsf_input_proxy_finalize (GObject *obj)
{
GsfInputProxy *proxy = (GsfInputProxy *)obj;
if (proxy->source != NULL) {
g_object_unref (G_OBJECT (proxy->source));
proxy->source = NULL;
}
parent_class->finalize (obj);
}
static GsfInput *
gsf_input_proxy_dup (GsfInput *src_input, G_GNUC_UNUSED GError **err)
{
return gsf_input_proxy_new (src_input);
}
static guint8 const *
gsf_input_proxy_read (GsfInput *input, size_t num_bytes, guint8 *buffer)
{
GsfInputProxy *proxy = GSF_INPUT_PROXY (input);
/* Seek to our position in the source. */
if (gsf_input_seek (proxy->source,
proxy->offset + gsf_input_tell (input),
G_SEEK_SET))
return NULL;
/* Read the data. */
return gsf_input_read (proxy->source, num_bytes, buffer);
}
static gboolean
gsf_input_proxy_seek (G_GNUC_UNUSED GsfInput *input,
G_GNUC_UNUSED gsf_off_t offset,
G_GNUC_UNUSED GSeekType whence)
{
return FALSE;
}
static void
gsf_input_proxy_init (GObject *obj)
{
GsfInputProxy *proxy = GSF_INPUT_PROXY (obj);
proxy->source = NULL;
proxy->offset = 0;
}
static void
gsf_input_proxy_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_input_proxy_finalize;
input_class->Dup = gsf_input_proxy_dup;
input_class->Read = gsf_input_proxy_read;
input_class->Seek = gsf_input_proxy_seek;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfInputProxy, gsf_input_proxy,
gsf_input_proxy_class_init, gsf_input_proxy_init, GSF_INPUT_TYPE)

View File

@@ -0,0 +1,43 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-proxy.h: proxy object (with its own current position)
*
* Copyright (C) 2004 Morten Welinder (terra@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_PROXY_H
#define GSF_INPUT_PROXY_H
#include "gsf-input.h"
G_BEGIN_DECLS
#define GSF_INPUT_PROXY_TYPE (gsf_input_proxy_get_type ())
#define GSF_INPUT_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INPUT_PROXY_TYPE, GsfInputProxy))
#define GSF_IS_INPUT_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INPUT_PROXY_TYPE))
typedef struct _GsfInputProxy GsfInputProxy;
GType gsf_input_proxy_get_type (void);
GsfInput *gsf_input_proxy_new (GsfInput *source);
GsfInput *gsf_input_proxy_new_section (GsfInput *source,
gsf_off_t offset,
gsf_off_t size);
G_END_DECLS
#endif /* GSF_INPUT_PROXY_H */

View File

@@ -0,0 +1,281 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-stdio.c: stdio based input
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-input-stdio.h>
#include <gsf/gsf-input-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#ifdef HAVE_GLIB26
#include <glib/gstdio.h>
#else
#include "glib24_26-compat.h"
#endif // HAVE_GLIB26
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
static GObjectClass *parent_class;
struct _GsfInputStdio {
GsfInput input;
FILE *file;
char *filename;
guint8 *buf;
size_t buf_size;
gboolean keep_open;
};
typedef struct {
GsfInputClass input_class;
} GsfInputStdioClass;
/**
* gsf_input_stdio_new :
* @filename : in utf8.
* @err : optionally NULL.
*
* Returns a new file or NULL.
**/
GsfInput *
gsf_input_stdio_new (char const *filename, GError **err)
{
GsfInputStdio *input;
struct stat st;
FILE *file;
gsf_off_t size;
g_return_val_if_fail (filename != NULL, NULL);
file = g_fopen (filename, "rb");
if (file == NULL || fstat (fileno (file), &st) < 0) {
if (err) {
int save_errno = errno;
char *utf8name = g_filename_display_name (filename);
g_set_error (err,
G_FILE_ERROR,
g_file_error_from_errno (save_errno),
"%s: %s",
utf8name, g_strerror (save_errno));
g_free (utf8name);
}
if (file) fclose (file); /* Just in case. */
return NULL;
}
if (!S_ISREG (st.st_mode)) {
if (err) {
char *utf8name = g_filename_display_name (filename);
g_set_error (err, gsf_input_error_id (), 0,
"%s: not a regular file",
utf8name);
g_free (utf8name);
}
fclose (file);
return NULL;
}
size = st.st_size;
input = (GsfInputStdio *)g_object_new (GSF_INPUT_STDIO_TYPE, NULL);
input->file = file;
input->filename = g_strdup (filename);
input->buf = NULL;
input->buf_size = 0;
input->keep_open = FALSE;
gsf_input_set_size (GSF_INPUT (input), size);
gsf_input_set_name_from_filename (GSF_INPUT (input), filename);
return GSF_INPUT (input);
}
/**
* gsf_input_stdio_new_FILE :
* @filename : The filename corresponding to @file.
* @file : an existing stdio FILE *
* @keep_open : Should @file be closed when the wrapper is closed
*
* Assumes ownership of @file. If @keep_open is true, ownership reverts
* to caller when the GsfObject is closed.
*
* Returns a new GsfInput wrapper for @file. Note: the file must be
* seekable, so this will not work for stdin when that is a tty or pipe.
**/
GsfInput *
gsf_input_stdio_new_FILE (char const *filename, FILE *file, gboolean keep_open)
{
GsfInputStdio *stdio;
struct stat st;
gsf_off_t size;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (file != NULL, NULL);
if (fstat (fileno (file), &st) < 0)
return NULL;
if (!S_ISREG (st.st_mode))
/* It's not that we really care, but we need st.st_size to be sane. */
return NULL;
size = st.st_size;
stdio = g_object_new (GSF_INPUT_STDIO_TYPE, NULL);
stdio->file = file;
stdio->keep_open = keep_open;
stdio->filename = g_strdup (filename);
gsf_input_set_size (GSF_INPUT (stdio), size);
gsf_input_set_name_from_filename (GSF_INPUT (stdio), filename);
return GSF_INPUT (stdio);
}
static void
gsf_input_stdio_finalize (GObject *obj)
{
GsfInputStdio *input = (GsfInputStdio *)obj;
if (input->file != NULL) {
if (!input->keep_open)
fclose (input->file);
input->file = NULL;
}
g_free (input->buf);
input->buf = NULL;
input->buf_size = 0;
g_free (input->filename);
parent_class->finalize (obj);
}
static GsfInput *
gsf_input_stdio_dup (GsfInput *src_input, GError **err)
{
GsfInputStdio const *src = (GsfInputStdio *)src_input;
return gsf_input_stdio_new (src->filename, err);
}
static guint8 const *
gsf_input_stdio_read (GsfInput *input, size_t num_bytes,
guint8 *buffer)
{
GsfInputStdio *stdio = GSF_INPUT_STDIO (input);
size_t nread = 0, total_read = 0;
g_return_val_if_fail (stdio != NULL, NULL);
g_return_val_if_fail (stdio->file != NULL, NULL);
if (buffer == NULL) {
if (stdio->buf_size < num_bytes) {
stdio->buf_size = num_bytes;
g_free (stdio->buf);
stdio->buf = g_new (guint8, stdio->buf_size);
}
buffer = stdio->buf;
}
while (total_read < num_bytes) {
nread = fread (buffer + total_read, 1,
num_bytes - total_read, stdio->file);
total_read += nread;
if (total_read < num_bytes &&
(ferror (stdio->file) || feof (stdio->file)))
return NULL;
}
return buffer;
}
static gboolean
gsf_input_stdio_seek (GsfInput *input, gsf_off_t offset, GSeekType whence)
{
GsfInputStdio const *stdio = GSF_INPUT_STDIO (input);
int stdio_whence = SEEK_SET;
#ifndef HAVE_FSEEKO
long loffset;
#else
off_t loffset;
#endif
if (stdio->file == NULL)
return TRUE;
loffset = offset;
if ((gsf_off_t) loffset != offset) { /* Check for overflow */
#ifdef HAVE_FSEEKO
g_warning ("offset too large for fseeko");
#else
g_warning ("offset too large for fseek");
#endif
return TRUE;
}
switch (whence) {
case G_SEEK_CUR : stdio_whence = SEEK_CUR; break;
case G_SEEK_END : stdio_whence = SEEK_END; break;
case G_SEEK_SET:
default:
break;
}
errno = 0;
#ifdef HAVE_FSEEKO
if (0 == fseeko (stdio->file, loffset, stdio_whence))
return FALSE;
#else
if (0 == fseek (stdio->file, loffset, stdio_whence))
return FALSE;
#endif
return TRUE;
}
static void
gsf_input_stdio_init (GObject *obj)
{
GsfInputStdio *stdio = GSF_INPUT_STDIO (obj);
stdio->file = NULL;
stdio->filename = NULL;
stdio->buf = NULL;
stdio->buf_size = 0;
stdio->keep_open = FALSE;
}
static void
gsf_input_stdio_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_input_stdio_finalize;
input_class->Dup = gsf_input_stdio_dup;
input_class->Read = gsf_input_stdio_read;
input_class->Seek = gsf_input_stdio_seek;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfInputStdio, gsf_input_stdio,
gsf_input_stdio_class_init, gsf_input_stdio_init, GSF_INPUT_TYPE)

View File

@@ -0,0 +1,44 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-stdio.h: interface for use by the structured file layer to read raw data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_STDIO_H
#define GSF_INPUT_STDIO_H
#include "gsf-input.h"
#include <stdio.h>
G_BEGIN_DECLS
#define GSF_INPUT_STDIO_TYPE (gsf_input_stdio_get_type ())
#define GSF_INPUT_STDIO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INPUT_STDIO_TYPE, GsfInputStdio))
#define GSF_IS_INPUT_STDIO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INPUT_STDIO_TYPE))
typedef struct _GsfInputStdio GsfInputStdio;
GType gsf_input_stdio_get_type (void);
GsfInput *gsf_input_stdio_new (char const *filename, GError **err);
GsfInput *gsf_input_stdio_new_FILE (char const *filename, FILE *file,
gboolean keep_open);
G_END_DECLS
#endif /* GSF_INPUT_STDIO_H */

View File

@@ -0,0 +1,322 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-textline.c: textline based input
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-input-textline.h>
#include <gsf/gsf-input-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <string.h>
static GObjectClass *parent_class;
struct _GsfInputTextline {
GsfInput input;
GsfInput *source;
guint8 const *remainder;
unsigned remainder_size;
unsigned max_line_size;
unsigned char *buf;
unsigned buf_size;
/* int current_line; */
};
typedef struct {
GsfInputClass input_class;
} GsfInputTextlineClass;
/**
* gsf_input_textline_new :
* @source : in some combination of ascii and utf8
*
* NOTE : adds a reference to @source
*
* Returns a new file or NULL.
**/
GsfInput *
gsf_input_textline_new (GsfInput *source)
{
GsfInputTextline *input;
g_return_val_if_fail (source != NULL, NULL);
input = g_object_new (GSF_INPUT_TEXTLINE_TYPE, NULL);
g_object_ref (G_OBJECT (source));
input->source = source;
input->buf = NULL;
input->buf_size = 0;
gsf_input_set_size (GSF_INPUT (source), gsf_input_size (source));
return GSF_INPUT (input);
}
static void
gsf_input_textline_finalize (GObject *obj)
{
GsfInputTextline *input = (GsfInputTextline *)obj;
if (input->source != NULL) {
g_object_unref (G_OBJECT (input->source));
input->source = NULL;
}
if (input->buf != NULL) {
g_free (input->buf);
input->buf = NULL;
}
input->buf_size = 0;
parent_class->finalize (obj);
}
static GsfInput *
gsf_input_textline_dup (GsfInput *src_input, G_GNUC_UNUSED GError **err)
{
GsfInputTextline const *src = (GsfInputTextline *)src_input;
GsfInputTextline *dst = g_object_new (GSF_INPUT_TEXTLINE_TYPE, NULL);
dst->source = src->source;
g_object_ref (G_OBJECT (dst->source));
gsf_input_set_size (GSF_INPUT (dst), gsf_input_size (src_input));
return GSF_INPUT (dst);
}
static guint8 const *
gsf_input_textline_read (GsfInput *input, size_t num_bytes, guint8 *buffer)
{
GsfInputTextline *textline = GSF_INPUT_TEXTLINE (input);
textline->remainder = NULL;
return gsf_input_read (textline->source, num_bytes, buffer);
}
static gboolean
gsf_input_textline_seek (GsfInput *input, gsf_off_t offset, GSeekType whence)
{
GsfInputTextline *textline = GSF_INPUT_TEXTLINE (input);
textline->remainder = NULL;
return gsf_input_seek (textline->source, offset, whence);
}
static void
gsf_input_textline_init (GObject *obj)
{
GsfInputTextline *textline = GSF_INPUT_TEXTLINE (obj);
textline->source = NULL;
textline->remainder = NULL;
textline->remainder_size = 0;
textline->max_line_size = 512; /* an initial guess */
textline->buf = NULL;
textline->buf_size = 0;
}
static void
gsf_input_textline_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_input_textline_finalize;
input_class->Dup = gsf_input_textline_dup;
input_class->Read = gsf_input_textline_read;
input_class->Seek = gsf_input_textline_seek;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfInputTextline, gsf_input_textline,
gsf_input_textline_class_init, gsf_input_textline_init, GSF_INPUT_TYPE)
/**
* gsf_input_textline_ascii_gets :
* @input :
*
* A utility routine to read things line by line from the underlying source.
* Trailing newlines and carriage returns are stripped, and the resultant buffer
* can be edited.
*
* returns the string read, or NULL on eof.
**/
unsigned char *
gsf_input_textline_ascii_gets (GsfInputTextline *textline)
{
guint8 const *ptr ,*end;
gsf_off_t remain;
unsigned len, count = 0;
g_return_val_if_fail (textline != NULL, NULL);
while (1) {
if (textline->remainder == NULL ||
textline->remainder_size == 0) {
remain = gsf_input_remaining (textline->source);
len = MIN (remain, textline->max_line_size);
textline->remainder = gsf_input_read (textline->source, len, NULL);
if (textline->remainder == NULL)
return NULL;
textline->remainder_size = len;
}
ptr = textline->remainder;
end = ptr + textline->remainder_size;
for (; ptr < end ; ptr++)
if (*ptr == '\n' || *ptr == '\r')
break;
/* copy the remains into the buffer, grow it if necessary */
len = ptr - textline->remainder;
if (count + len >= textline->buf_size) {
textline->buf_size += len;
textline->buf = g_renew (guint8, textline->buf,
textline->buf_size + 1);
}
g_return_val_if_fail (textline->buf != NULL, NULL);
memcpy (textline->buf + count, textline->remainder, len);
count += len;
if (ptr < end) {
unsigned char last = ptr [0];
/* eat the trailing new line */
ptr++;
if (ptr >= end) {
/* be extra careful, the newline is at the bound */
if (gsf_input_remaining (textline->source) > 0) {
ptr = gsf_input_read (textline->source, 1, NULL);
if (ptr == NULL)
return NULL;
textline->remainder = ptr;
textline->remainder_size = 1;
end = ptr + 1;
} else
ptr = end = NULL;
}
if (ptr != NULL &&
((last == '\n' && *ptr == '\r') ||
(last == '\r' && *ptr == '\n')))
ptr++;
break;
} else if (gsf_input_remaining (textline->source) <= 0) {
ptr = end = NULL;
break;
} else
textline->remainder = NULL;
}
textline->remainder = ptr;
textline->remainder_size = end - ptr;
textline->buf [count] = '\0';
return textline->buf;
}
/**
* gsf_input_textline_utf8_gets :
* @input :
*
* A utility routine to read things line by line from the underlying source.
* Trailing newlines and carriage returns are stripped, and the resultant buffer
* can be edited.
*
* returns the string read, or NULL on eof.
**/
guint8 *
gsf_input_textline_utf8_gets (GsfInputTextline *textline)
{
guint8 const *ptr ,*end;
gsf_off_t remain;
unsigned len, count = 0;
g_return_val_if_fail (textline != NULL, NULL);
while (1) {
if (textline->remainder == NULL ||
textline->remainder_size == 0) {
remain = gsf_input_remaining (textline->source);
len = MIN (remain, textline->max_line_size);
textline->remainder = gsf_input_read (textline->source, len, NULL);
if (textline->remainder == NULL)
return NULL;
textline->remainder_size = len;
}
ptr = textline->remainder;
end = ptr + textline->remainder_size;
for (; ptr < end ; ptr = (guint8 *) g_utf8_next_char (ptr))
if (*ptr == '\n' || *ptr == '\r')
break;
/* copy the remains into the buffer, grow it if necessary */
len = ptr - textline->remainder;
if (count + len >= textline->buf_size) {
textline->buf_size += len;
textline->buf = g_renew (guint8, textline->buf,
textline->buf_size + 1);
}
g_return_val_if_fail (textline->buf != NULL, NULL);
memcpy (textline->buf + count, textline->remainder, len);
count += len;
if (ptr < end) {
unsigned char last = ptr [0];
/* eat the trailing new line */
ptr++;
if (ptr >= end) {
/* be extra careful, the newline is at the bound */
if (gsf_input_remaining (textline->source) > 0) {
ptr = gsf_input_read (textline->source, 1, NULL);
if (ptr == NULL)
return NULL;
textline->remainder = ptr;
textline->remainder_size = 1;
end = ptr + 1;
} else
ptr = end = NULL;
}
if (ptr != NULL &&
((last == '\n' && *ptr == '\r') ||
(last == '\r' && *ptr == '\n')))
ptr++;
break;
} else if (gsf_input_remaining (textline->source) <= 0) {
ptr = end = NULL;
break;
} else
textline->remainder = NULL;
}
textline->remainder = ptr;
textline->remainder_size = end - ptr;
textline->buf [count] = '\0';
return textline->buf;
}

View File

@@ -0,0 +1,43 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input-textline.h: a utility wrapper to pull in text, line by line.
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_TEXTLINE_H
#define GSF_INPUT_TEXTLINE_H
#include "gsf-input.h"
G_BEGIN_DECLS
#define GSF_INPUT_TEXTLINE_TYPE (gsf_input_textline_get_type ())
#define GSF_INPUT_TEXTLINE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INPUT_TEXTLINE_TYPE, GsfInputTextline))
#define GSF_IS_INPUT_TEXTLINE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INPUT_TEXTLINE_TYPE))
typedef struct _GsfInputTextline GsfInputTextline;
GType gsf_input_textline_get_type (void);
GsfInput *gsf_input_textline_new (GsfInput *source);
unsigned char *gsf_input_textline_ascii_gets (GsfInputTextline *input);
guint8 *gsf_input_textline_utf8_gets (GsfInputTextline *input);
G_END_DECLS
#endif /* GSF_INPUT_TEXTLINE_H */

View File

@@ -0,0 +1,651 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input.c: interface for used by the ole layer to read raw data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-input-impl.h>
#include <gsf/gsf-input-gzip.h>
#include <gsf/gsf-impl-utils.h>
#include <string.h>
#ifdef HAVE_BZIP
#include <gsf/gsf-input-bzip.h>
#endif
#define GET_CLASS(instance) G_TYPE_INSTANCE_GET_CLASS (instance, GSF_INPUT_TYPE, GsfInputClass)
static GObjectClass *parent_class;
enum {
PROP_0,
PROP_NAME,
PROP_SIZE,
PROP_EOF,
PROP_REMAINING,
PROP_POS
};
#if 0
static void
gsf_input_set_property (GObject *object,
guint property_id,
GValue const *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
#endif
static void
gsf_input_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
/* gsf_off_t is typedef'd to gint64 */
switch (property_id) {
case PROP_NAME:
g_value_set_string (value, gsf_input_name (GSF_INPUT (object)));
break;
case PROP_SIZE:
g_value_set_int64 (value, gsf_input_size (GSF_INPUT (object)));
break;
case PROP_EOF:
g_value_set_boolean (value, gsf_input_eof (GSF_INPUT (object)));
break;
case PROP_REMAINING:
g_value_set_int64 (value, gsf_input_remaining (GSF_INPUT (object)));
break;
case PROP_POS:
g_value_set_int64 (value, gsf_input_tell (GSF_INPUT (object)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_input_finalize (GObject *obj)
{
GsfInput *input = GSF_INPUT (obj);
if (input->name != NULL) {
g_free (input->name);
input->name = NULL;
}
if (input->container != NULL) {
g_object_unref (G_OBJECT (input->container));
input->container = NULL;
}
parent_class->finalize (obj);
}
static void
gsf_input_init (GObject *obj)
{
GsfInput *input = GSF_INPUT (obj);
input->size = 0;
input->cur_offset = 0;
input->name = NULL;
input->container = NULL;
}
static void
gsf_input_class_init (GObjectClass *gobject_class)
{
parent_class = g_type_class_peek_parent (gobject_class);
gobject_class->finalize = gsf_input_finalize;
/* gobject_class->set_property = gsf_input_set_property; */
gobject_class->get_property = gsf_input_get_property;
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string ("name", "Name",
"The Input's Name",
NULL,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_SIZE,
g_param_spec_int64 ("size", "Size",
"The Input's Size",
0, G_MAXINT64, 0,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_EOF,
g_param_spec_boolean ("eof", "OEF",
"End Of File",
FALSE,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_REMAINING,
g_param_spec_int64 ("remaining", "Remaining",
"Amount of Data Remaining",
0, G_MAXINT64, 0,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_POS,
g_param_spec_int64 ("position", "Position",
"The Output's Current Position",
0, G_MAXINT64, 0,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
}
GSF_CLASS_ABSTRACT (GsfInput, gsf_input,
gsf_input_class_init, gsf_input_init,
G_TYPE_OBJECT)
/**
* gsf_input_name :
* @input : the input stream
*
* Returns @input's name in utf8 form, or NULL if it has no name.
**/
char const *
gsf_input_name (GsfInput *input)
{
g_return_val_if_fail (GSF_IS_INPUT (input), NULL);
return input->name;
}
/**
* gsf_input_container :
* @input : the input stream
*
* Returns, but does not add a reference to @input's container.
* Potentially NULL
**/
GsfInfile *
gsf_input_container (GsfInput *input)
{
g_return_val_if_fail (GSF_IS_INPUT (input), NULL);
return input->container;
}
/**
* gsf_input_dup :
* @input : The input to duplicate
* @err : optionally NULL
*
* Duplicates input @src leaving the new one at the same offset.
*
* Returns : the duplicate, or NULL on error
**/
GsfInput *
gsf_input_dup (GsfInput *input, GError **err)
{
GsfInput *dst;
g_return_val_if_fail (input != NULL, NULL);
dst = GET_CLASS (input)->Dup (input, err);
if (dst != NULL) {
if (dst->size != input->size) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Duplicate size mismatch");
g_object_unref (dst);
return NULL;
}
if (gsf_input_seek (dst, input->cur_offset, G_SEEK_SET)) {
if (err != NULL)
*err = g_error_new (gsf_input_error_id (), 0,
"Seek failed");
g_object_unref (dst);
return NULL;
}
if (input->name != NULL)
gsf_input_set_name (dst, input->name);
dst->container = input->container;
if (dst->container != NULL)
g_object_ref (G_OBJECT (dst->container));
}
return dst;
}
/**
* gsf_input_open_sibling :
* @input : The input
*
* NOT CURRENTLY IMPLEMENTED
*
* Attempts to open a 'sibling' of @input. The caller is responsible for
* managing the resulting object.
*
* NOT CURRENTLY IMPLEMENTED
*
* Returns : the size or -1 on error
**/
GsfInput *
gsf_input_sibling (GsfInput const *input, char const *name, GError **err)
{
g_return_val_if_fail (GET_CLASS (input)->OpenSibling, NULL);
return GET_CLASS (input)->OpenSibling (input, name, err);
}
/**
* gsf_input_size :
* @input : The input
*
* Looks up and caches the number of bytes in the input
*
* Returns : the size or -1 on error
**/
gsf_off_t
gsf_input_size (GsfInput *input)
{
g_return_val_if_fail (input != NULL, -1);
return input->size;
}
/**
* gsf_input_eof :
* @input : the input
*
* Are we at the end of the file ?
*
* Returns : TRUE if the input is at the eof.
**/
gboolean
gsf_input_eof (GsfInput *input)
{
g_return_val_if_fail (input != NULL, FALSE);
return input->cur_offset >= input->size;
}
/**
* gsf_input_read :
* @input : the input stream
* @num_bytes : number of bytes to read
* @optional_buffer : NULL, or pointer to destination memory area
*
* Read at least @num_bytes. Does not change the current position if there
* is an error. Will only read if the entire amount can be read. Invalidates
* the buffer associated with previous calls to gsf_input_read.
*
* Returns : pointer to the buffer or NULL if there is an error or 0 bytes are
* requested.
**/
guint8 const *
gsf_input_read (GsfInput *input, size_t num_bytes, guint8 *optional_buffer)
{
guint8 const *res;
g_return_val_if_fail (input != NULL, NULL);
if (num_bytes == 0 || (input->cur_offset + num_bytes) > input->size)
return NULL;
res = GET_CLASS (input)->Read (input, num_bytes, optional_buffer);
if (res == NULL)
return NULL;
input->cur_offset += num_bytes;
return res;
}
/**
* gsf_input_remaining :
* @input : the input stream
*
* Returns the number of bytes left in the file.
**/
gsf_off_t
gsf_input_remaining (GsfInput *input)
{
g_return_val_if_fail (input != NULL, 0);
return input->size - input->cur_offset;
}
/**
* gsf_input_tell :
* @input : the input stream
*
* Returns the current offset in the file.
**/
gsf_off_t
gsf_input_tell (GsfInput *input)
{
g_return_val_if_fail (input != NULL, 0);
return input->cur_offset;
}
/**
* gsf_input_seek :
* @input : the input stream
* @offset : target offset
* @whence : determines whether the offset is relative to the beginning or
* the end of the stream, or to the current location.
*
* Returns TRUE on error.
**/
gboolean
gsf_input_seek (GsfInput *input, gsf_off_t offset, GSeekType whence)
{
gsf_off_t pos = offset;
g_return_val_if_fail (input != NULL, TRUE);
switch (whence) {
case G_SEEK_SET : break;
case G_SEEK_CUR : pos += input->cur_offset; break;
case G_SEEK_END : pos += input->size; break;
default : return TRUE;
}
if (pos < 0 || pos > input->size)
return TRUE;
/*
* If we go nowhere, just return. This in particular handles null
* seeks for streams with no seek method.
*/
if (pos == input->cur_offset)
return FALSE;
if (GET_CLASS (input)->Seek (input, offset, whence))
return TRUE;
input->cur_offset = pos;
return FALSE;
}
/**
* gsf_input_set_name :
* @input : the input stream
* @name : the new name of the stream, or NULL.
*
* protected.
*
* Returns : TRUE if the assignment was ok.
**/
gboolean
gsf_input_set_name (GsfInput *input, char const *name)
{
char *buf;
g_return_val_if_fail (input != NULL, FALSE);
buf = g_strdup (name);
g_free (input->name);
input->name = buf;
return TRUE;
}
/**
* gsf_input_set_name_from_filename :
* @input : the input stream
* @filename : the (fs-sys encoded) filename
*
* protected.
*
* Returns : TRUE if the assignment was ok.
**/
gboolean
gsf_input_set_name_from_filename (GsfInput *input, char const *filename)
{
g_return_val_if_fail (input != NULL, FALSE);
g_free (input->name);
input->name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
return TRUE;
}
/**
* gsf_input_set_container :
* @input : the input stream
* @container :
*
* Returns : TRUE if the assignment was ok.
*/
gboolean
gsf_input_set_container (GsfInput *input, GsfInfile *container)
{
g_return_val_if_fail (input != NULL, FALSE);
if (container != NULL)
g_object_ref (G_OBJECT (container));
if (input->container != NULL)
g_object_unref (G_OBJECT (input->container));
input->container = container;
return TRUE;
}
/**
* gsf_input_set_size :
* @input : the input stream
* @size : the size of the stream
*
* Returns : TRUE if the assignment was ok.
*/
gboolean
gsf_input_set_size (GsfInput *input, gsf_off_t size)
{
g_return_val_if_fail (input != NULL, FALSE);
g_return_val_if_fail (size >= 0, FALSE);
input->size = size;
return TRUE;
}
/**
* gsf_input_seek_emulate: Emulate forward seeks by reading.
* @input : stream to emulate seek for
* @pos : absolute position to seek to
*
* Returns : TRUE if the emulation failed.
*/
gboolean
gsf_input_seek_emulate (GsfInput *input, gsf_off_t pos)
{
if (pos < input->cur_offset)
return TRUE;
while (pos > input->cur_offset) {
gsf_off_t readcount = MIN (pos - input->cur_offset, 8192);
if (!gsf_input_read (input, readcount, NULL))
return TRUE;
}
return FALSE;
}
/****************************************************************************/
/**
* gsf_input_error_id :
*
* Returns : A utility quark to flag a GError as being an input problem.
*/
GQuark
gsf_input_error_id (void)
{
static GQuark quark;
if (!quark)
quark = g_quark_from_static_string ("gsf_input_error_id");
return quark;
}
/**
* gsf_input_error :
*
* Deprecated in 1.12.0
* Returns : A utility quark to flag a GError as being an input problem.
*/
GQuark
gsf_input_error (void)
{
return gsf_input_error_id ();
}
/****************************************************************************/
#define GSF_READ_BUFSIZE (1024 * 4)
/**
* gsf_input_copy :
* @input : a non-null #GsfInput
* @output : a non-null #GsfOutput
*
* Copy the contents from @input to @output from their respective
* current positions. So if you want to be sure to copy *everything*,
* make sure to call gsf_input_seek (input, 0, G_SEEK_SET) and
* gsf_output_seek (output, 0, G_SEEK_SET) first, if applicable.
*
* Returns : TRUE on Success
**/
gboolean
gsf_input_copy (GsfInput *input, GsfOutput *output)
{
gsf_off_t remaining = 0;
gsf_off_t toread = 0;
const guint8 * buffer = NULL;
gboolean success = TRUE;
g_return_val_if_fail (input != NULL, FALSE);
g_return_val_if_fail (output != NULL, FALSE);
while ((remaining = gsf_input_remaining (input)) > 0 && (success)) {
toread = MIN (remaining, GSF_READ_BUFSIZE);
if (NULL == (buffer = gsf_input_read (input, toread, NULL)))
success = FALSE;
else
success = gsf_output_write (output, toread, buffer);
}
return success;
}
/****************************************************************************/
/**
* gsf_input_uncompress: maybe uncompress stream.
* @src: stream to be uncompressed.
*
* Returns: A stream equivalent to the source stream, but uncompressed if
* the source was compressed.
*
* This functions takes ownership of the incoming reference and yields a
* new one as its output.
*/
GsfInput *
gsf_input_uncompress (GsfInput *src)
{
gsf_off_t cur_offset = src->cur_offset;
const guint8 *data;
if (gsf_input_seek (src, 0, G_SEEK_SET))
goto error;
/* Read header up front, so we avoid extra seeks in tests. */
data = gsf_input_read (src, 4, NULL);
if (!data)
goto error;
/* Let's try gzip. */
{
const unsigned char gzip_sig[2] = { 0x1f, 0x8b };
if (memcmp (gzip_sig, data, sizeof (gzip_sig)) == 0) {
GsfInput *res = gsf_input_gzip_new (src, NULL);
if (res) {
g_object_unref (G_OBJECT (src));
return gsf_input_uncompress (res);
}
}
}
#ifdef HAVE_BZIP
/* Let's try bzip. */
{
guint8 const *bzip_sig = "BZh";
if (memcmp (gzip_sig, data, strlen (bzip_sig)) == 0) {
GsfInput *res = gsf_input_memory_new_from_bzip (src, NULL);
if (res) {
g_object_unref (G_OBJECT (src));
return gsf_input_uncompress (res);
}
}
}
#endif
/* Other methods go here. */
error:
(void)gsf_input_seek (src, cur_offset, G_SEEK_SET);
return src;
}
#if 0
#include <gsf/gsf-input-stdio.h>
#ifdef HAVE_GNOME
#include <gsf-gnome/gsf-input-gnomevfs.h>
#endif
GsfInput *
gsf_input_new_for_uri (char const * uri, GError ** err)
{
GsfInput * input = NULL;
size_t len;
g_return_val_if_fail (uri, NULL);
len = strlen (uri);
g_return_val_if_fail (len, NULL);
if (len > 3 && !strstr (uri, ":/")) {
/* assume plain file */
input = gsf_input_stdio_new (uri, err);
} else {
#if HAVE_GNOME
/* have gnome, let GnomeVFS deal with this */
input = gsf_input_gnomevfs_new (uri, err);
#else
if (len > 7 && !strncmp (uri, "file:/", 6)) {
/* dumb attempt to translate this into a local path */
input = gsf_input_stdio_new (uri+7, err);
}
/* else: unknown or unhandled protocol - bail */
#endif
}
return input;
}
#endif

View File

@@ -0,0 +1,64 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-input.h: interface for used by the ole layer to read raw data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_INPUT_H
#define GSF_INPUT_H
#include <gsf/gsf.h>
#include <glib-object.h>
#include <sys/types.h>
#include <gsf/gsf-output.h>
G_BEGIN_DECLS
#define GSF_INPUT_TYPE (gsf_input_get_type ())
#define GSF_INPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_INPUT_TYPE, GsfInput))
#define GSF_IS_INPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_INPUT_TYPE))
GType gsf_input_get_type (void);
char const *gsf_input_name (GsfInput *input);
GsfInfile *gsf_input_container (GsfInput *input);
GsfInput *gsf_input_dup (GsfInput *input, GError **err);
GsfInput *gsf_input_sibling (GsfInput const *input, char const *name, GError **err);
gsf_off_t gsf_input_size (GsfInput *input);
gboolean gsf_input_eof (GsfInput *input);
guint8 const *gsf_input_read (GsfInput *input, size_t num_bytes,
guint8 *optional_buffer);
gsf_off_t gsf_input_remaining (GsfInput *input);
gsf_off_t gsf_input_tell (GsfInput *input);
gboolean gsf_input_seek (GsfInput *input,
gsf_off_t offset, GSeekType whence);
/* Utilities */
gboolean gsf_input_copy (GsfInput *input, GsfOutput *output);
GsfInput *gsf_input_uncompress (GsfInput *src);
GQuark gsf_input_error_id (void);
#ifndef GSF_DISABLE_DEPRECATED
/* deprecated in 1.12.0, use gsf_input_error_id */
GQuark gsf_input_error (void);
#endif /* GSF_DISABLE_DEPRECATED */
G_END_DECLS
#endif /* GSF_INPUT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-libxml.h: Utility wrappers for using gsf with libxml
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_LIBXML_H
#define GSF_LIBXML_H
#include <gsf/gsf.h>
#include <glib-object.h>
#include <libxml/tree.h>
G_BEGIN_DECLS
/****************************************************************************/
/* GSF wrappers for libxml2 */
xmlParserCtxt *gsf_xml_parser_context (GsfInput *input);
#if 0
/* this is cleaner, tack it on for 2.0 */
xmlSAXHandlerPtr sax, gpointer user);
#endif
int gsf_xmlDocFormatDump (GsfOutput *output,
xmlDoc *cur,
char const *encoding,
gboolean format);
/****************************************************************************/
/* Simplified GSF based xml import (based on libxml2 SAX) */
typedef struct _GsfXMLBlob GsfXMLBlob;
typedef struct _GsfXMLIn GsfXMLIn;
typedef struct _GsfXMLInDoc GsfXMLInDoc;
typedef struct _GsfXMLInNode GsfXMLInNode;
typedef struct _GsfXMLInNS GsfXMLInNS;
typedef enum {
GSF_XML_NO_CONTENT,
GSF_XML_CONTENT,
GSF_XML_SHARED_CONTENT
} GsfXMLContent;
typedef gboolean (*GsfXMLInUnknownFunc) (GsfXMLIn *state, xmlChar const *elem, xmlChar const **attrs);
struct _GsfXMLIn {
GsfXMLInDoc const *doc; /* init before parsing */
/* look but do not change */
GsfXMLInNode const *node; /* current node */
GSList *state_stack;
GsfXMLInNS const *default_ns; /* optionally NULL */
GSList *ns_stack;
GString *content;
gint unknown_depth; /* handle recursive unknown tags */
GHashTable *ns_prefixes; /* current ns prefixes */
GPtrArray *ns_by_id; /* indexed by id */
};
struct _GsfXMLInNode {
char const *id;
int ns_id;
char const *name;
char const *parent_id;
gboolean parent_initialized;
GSList *groups;
unsigned has_content;
gboolean deprecated_unused_allow_unknown; /* remains here for binary compat */
gboolean check_children_for_ns;
void (*start) (GsfXMLIn *state, xmlChar const **attrs);
void (*end) (GsfXMLIn *state, GsfXMLBlob *unknown);
union {
int v_int;
gboolean v_bool;
gpointer v_blob;
char const *v_str;
} user_data;
};
struct _GsfXMLInNS {
char const *uri;
unsigned ns_id;
};
#define GSF_XML_IN_NS(id, uri) \
{ uri, id}
#define GSF_XML_IN_NODE_FULL(parent_id, id, ns, name, has_content, \
deprecated_unused_allow_unknown, check_ns, start, end, user) \
{ \
#id, ns, name, #parent_id, FALSE, NULL, \
has_content, deprecated_unused_allow_unknown, check_ns, start, end, { user } \
}
#define GSF_XML_IN_NODE(parent_id, id, ns, name, has_content, start, end) \
GSF_XML_IN_NODE_FULL(parent_id, id, ns, name, has_content, \
FALSE, FALSE, start, end, 0)
GsfXMLInDoc *gsf_xml_in_doc_new (GsfXMLInNode *root, GsfXMLInNS *ns);
void gsf_xml_in_doc_free (GsfXMLInDoc *doc);
void gsf_xml_in_doc_extend (GsfXMLInDoc *doc,
GsfXMLInNode *nodes);
void gsf_xml_in_doc_set_unknown_handler (GsfXMLInDoc *doc,
GsfXMLInUnknownFunc handler);
gboolean gsf_xml_in_parse (GsfXMLIn *state, GsfInput *input);
char const *gsf_xml_in_check_ns (GsfXMLIn const *state, char const *str,
unsigned int ns_id);
gboolean gsf_xml_in_namecmp (GsfXMLIn const *state, char const *str,
unsigned int ns_id, char const *name);
/****************************************************************************/
/* Simplified GSF based xml export (does not use libxml) */
typedef struct _GsfXMLOut GsfXMLOut;
#define GSF_XML_OUT_TYPE (gsf_xml_out_get_type ())
#define GSF_XML_OUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_XML_OUT_TYPE, GsfXMLOut))
#define GSF_IS_XML_OUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_XML_OUT_TYPE))
GType gsf_xml_out_get_type (void);
GsfXMLOut *gsf_xml_out_new (GsfOutput *output);
void gsf_xml_out_set_doc_type (GsfXMLOut *xml, char const *type);
void gsf_xml_out_start_element (GsfXMLOut *xml, char const *id);
char const *gsf_xml_out_end_element (GsfXMLOut *xml);
void gsf_xml_out_simple_element (GsfXMLOut *xml, char const *id,
char const *content);
void gsf_xml_out_simple_int_element (GsfXMLOut *xml, char const *id,
int val);
void gsf_xml_out_simple_float_element (GsfXMLOut *xml, char const *id,
double val, int precision);
void gsf_xml_out_add_cstr_unchecked (GsfXMLOut *xml, char const *id,
char const *val_utf8);
void gsf_xml_out_add_cstr (GsfXMLOut *xml, char const *id,
char const *val_utf8);
void gsf_xml_out_add_bool (GsfXMLOut *xml, char const *id,
gboolean val);
void gsf_xml_out_add_int (GsfXMLOut *xml, char const *id,
int val);
void gsf_xml_out_add_uint (GsfXMLOut *xml, char const *id,
unsigned int val);
void gsf_xml_out_add_float (GsfXMLOut *xml, char const *id,
double val, int precision);
void gsf_xml_out_add_color (GsfXMLOut *xml, char const *id,
unsigned int r, unsigned int g, unsigned int b);
void gsf_xml_out_add_base64 (GsfXMLOut *xml, char const *id,
guint8 const *data, unsigned int len);
void gsf_xml_out_add_enum (GsfXMLOut *xml, char const *id,
GType etype, gint val);
G_END_DECLS
#endif /* GSF_LIBXML_H */

View File

@@ -0,0 +1,182 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-meta-names.h: a list of gsf-meta-names to "generically" represent
* all diviserly available implementation-specific
* meta-names.
*
* Author: Veerapuram Varadhan (vvaradhan@novell.com)
*
* Copyright (C) 2004 Novell, Inc
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_META_NAMES_H
#define GSF_META_NAMES_H
/* (String) A formal name given to the resource */
#define GSF_META_NAME_TITLE "dc:title"
/* (String) An account of the content of the resource */
#define GSF_META_NAME_DESCRIPTION "dc:description"
/* (String) The topic of the content of the resource, *typically* including keywords */
#define GSF_META_NAME_SUBJECT "dc:subject"
/* (Date as ISO String) The last time this document was saved */
#define GSF_META_NAME_DATE_MODIFIED "dc:date-modified"
/* (Date as ISO String) A date associated with an event in the life cycle of the resource (creation/publication date) */
#define GSF_META_NAME_DATE_CREATED "gsf:date-created"
/* (String) Searchable, indexable keywords. Similar to PDF keywords or HTML's meta block */
#define GSF_META_NAME_KEYWORDS "dc:keywords"
/* (String) A language of the intellectual content of the resource (basically xx_YY form for us) */
#define GSF_META_NAME_LANGUAGE "dc:language"
/* (Integer) Count of revision on the document, if appropriate */
#define GSF_META_NAME_REVISION_COUNT "gsf:revision-count"
/* (Date as ISO String) The total-time taken till last-modified */
#define GSF_META_NAME_EDITING_DURATION "gsf:editing-duration"
/* (Integer) Count of tables in the document, if appropriate */
#define GSF_META_NAME_TABLE_COUNT "gsf:table-count"
/* (Integer) Count of images in the document, if appropriate */
#define GSF_META_NAME_IMAGE_COUNT "gsf:image-count"
/* (Integer) Count of objects (OLE and other graphics) in the document, if appropriate */
#define GSF_META_NAME_OBJECT_COUNT "gsf:object-count"
/* (Integer) Count of pages in the document, if appropriate */
#define GSF_META_NAME_PAGE_COUNT "gsf:page-count"
/* (Integer) Count of paragraphs in the document, if appropriate */
#define GSF_META_NAME_PARAGRAPH_COUNT "gsf:paragraph-count"
/* (Integer) Count of words in the document */
#define GSF_META_NAME_WORD_COUNT "gsf:word-count"
/* (Integer) Count of characters in the document */
#define GSF_META_NAME_CHARACTER_COUNT "gsf:character-count"
/* (Integer) Count of cells in the spread-sheet document, if appropriate */
#define GSF_META_NAME_CELL_COUNT "gsf:cell-count"
/* (Integer) Count of pages in the document, if appropriate */
#define GSF_META_NAME_SPREADSHEET_COUNT "gsf:spreadsheet-count"
/* (String) An entity primarily responsible for making the content of the resource
* typically a person, organization, or service
*/
#define GSF_META_NAME_CREATOR "gsf:creator"
/* (String) The template file that is been used to generate this document */
#define GSF_META_NAME_TEMPLATE "gsf:template"
/* (String) The entity that made the last change to the document,
* typically a person, organization, or service
*/
#define GSF_META_NAME_LAST_SAVED_BY "gsf:last-saved-by"
/* (Date as ISO String) The last time this document was printed */
#define GSF_META_NAME_LAST_PRINTED "gsf:last-printed"
/* (Integer) Level of security.
* Level Value
* ----- -----
* None 0
* Password protected 1
* Read-only recommended 2
* Read-only enforced 3
* Locked for annotations 4
*
*/
#define GSF_META_NAME_SECURITY "gsf:security"
/* (String) Category of the document (example???) */
#define GSF_META_NAME_CATEGORY "gsf:category"
/* (String) Type of presentation, like "On-screen Show", "SlideView" etc */
#define GSF_META_NAME_PRESENTATION_FORMAT "gsf:presentation-format"
/* (Clipboard Format (VT_CF)) Thumbnail data of the document, typically
* a preview image of the document
*/
#define GSF_META_NAME_THUMBNAIL "gsf:thumbnail"
/* (String) The creator (product) of this document. AbiWord, Gnumeric, etc... */
#define GSF_META_NAME_GENERATOR "gsf:generator"
/* (Integer) Count of liness in the document */
#define GSF_META_NAME_LINE_COUNT "gsf:line-count"
/* (Integer) Count of slides in the presentation document */
#define GSF_META_NAME_SLIDE_COUNT "gsf:slide-count"
/* (Integer) Count of "notes" in the document */
#define GSF_META_NAME_NOTE_COUNT "gsf:note-count"
/* (Integer) Count of hidden-slides in the presentation document */
#define GSF_META_NAME_HIDDEN_SLIDE_COUNT "gsf:hidden-slide-count"
/* (Integer) Count of "multi-media" clips in the document */
#define GSF_META_NAME_MM_CLIP_COUNT "gsf:MM-clip-count"
/* (Integer) Count of bytes in the document */
#define GSF_META_NAME_BYTE_COUNT "gsf:byte-count"
/* (Boolean) ????? */
#define GSF_META_NAME_SCALE "gsf:scale"
/* (VT_VECTOR|VT_VARIANT) ??????? */
#define GSF_META_NAME_HEADING_PAIRS "gsf:heading-pairs"
/* (VT_VECTOR|VT_LPSTR) ??????? */
#define GSF_META_NAME_DOCUMENT_PARTS "gsf:document-parts"
/* (String) Name of the manager of "CREATOR" entity */
#define GSF_META_NAME_MANAGER "gsf:manager"
/* (String) Name of the company/organization that
* the "CREATOR" entity is associated with.
*/
#define GSF_META_NAME_COMPANY "gsf:company"
/* (Boolean) ??????? */
#define GSF_META_NAME_LINKS_DIRTY "gsf:links-dirty"
/* (Unknown) User-defined names */
#define GSF_META_NAME_MSOLE_UNKNOWN_17 "msole:unknown-doc-17"
#define GSF_META_NAME_MSOLE_UNKNOWN_18 "msole:unknown-doc-18"
#define GSF_META_NAME_MSOLE_UNKNOWN_19 "msole:unknown-doc-19" /* bool */
#define GSF_META_NAME_MSOLE_UNKNOWN_20 "msole:unknown-doc-20"
#define GSF_META_NAME_MSOLE_UNKNOWN_21 "msole:unknown-doc-21"
#define GSF_META_NAME_MSOLE_UNKNOWN_22 "msole:unknown-doc-22" /* bool */
#define GSF_META_NAME_MSOLE_UNKNOWN_23 "msole:unknown-doc-23" /* i4 */
/* (None) Reserved name (PID) for Dictionary */
#define GSF_META_NAME_DICTIONARY "gsf:dictionary"
/* (Unsigned Integer) Identifier representing the default
* system locale.
*/
#define GSF_META_NAME_LOCALE_SYSTEM_DEFAULT "gsf:default-locale"
/* (Unsigned Integer) Identifier representing the case-sensitiveness */
#define GSF_META_NAME_CASE_SENSITIVE "gsf:case-sensitivity"
#endif /* GSF_META_NAMES_H */

View File

@@ -0,0 +1,84 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-msole-impl.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_MSOLE_IMPL_H
#define GSF_MSOLE_IMPL_H
#include <gsf/gsf.h>
G_BEGIN_DECLS
#define OLE_HEADER_SIZE 0x200 /* independent of big block size size */
#define OLE_HEADER_SIGNATURE 0x00
#define OLE_HEADER_CLSID 0x08 /* See ReadClassStg */
#define OLE_HEADER_MINOR_VER 0x18 /* 0x33 and 0x3e have been seen */
#define OLE_HEADER_MAJOR_VER 0x1a /* 0x3 been seen in wild */
#define OLE_HEADER_BYTE_ORDER 0x1c /* 0xfe 0xff == Intel Little Endian */
#define OLE_HEADER_BB_SHIFT 0x1e
#define OLE_HEADER_SB_SHIFT 0x20
/* 0x22..0x27 reserved == 0 */
#define OLE_HEADER_CSECTDIR 0x28
#define OLE_HEADER_NUM_BAT 0x2c
#define OLE_HEADER_DIRENT_START 0x30
/* 0x34..0x37 transacting signature must be 0 */
#define OLE_HEADER_THRESHOLD 0x38
#define OLE_HEADER_SBAT_START 0x3c
#define OLE_HEADER_NUM_SBAT 0x40
#define OLE_HEADER_METABAT_BLOCK 0x44
#define OLE_HEADER_NUM_METABAT 0x48
#define OLE_HEADER_START_BAT 0x4c
#define BAT_INDEX_SIZE 4
#define OLE_HEADER_METABAT_SIZE ((OLE_HEADER_SIZE - OLE_HEADER_START_BAT) / BAT_INDEX_SIZE)
#define DIRENT_MAX_NAME_SIZE 0x40
#define DIRENT_DETAILS_SIZE 0x40
#define DIRENT_SIZE (DIRENT_MAX_NAME_SIZE + DIRENT_DETAILS_SIZE)
#define DIRENT_NAME_LEN 0x40 /* length in bytes incl 0 terminator */
#define DIRENT_TYPE 0x42
#define DIRENT_COLOUR 0x43
#define DIRENT_PREV 0x44
#define DIRENT_NEXT 0x48
#define DIRENT_CHILD 0x4c
#define DIRENT_CLSID 0x50 /* only for dirs */
#define DIRENT_USERFLAGS 0x60 /* only for dirs */
#define DIRENT_CREATE_TIME 0x64 /* for files */
#define DIRENT_MODIFY_TIME 0x6c /* for files */
#define DIRENT_FIRSTBLOCK 0x74
#define DIRENT_FILE_SIZE 0x78
/* 0x7c..0x7f reserved == 0 */
#define DIRENT_TYPE_INVALID 0
#define DIRENT_TYPE_DIR 1
#define DIRENT_TYPE_FILE 2
#define DIRENT_TYPE_LOCKBYTES 3 /* ? */
#define DIRENT_TYPE_PROPERTY 4 /* ? */
#define DIRENT_TYPE_ROOTDIR 5
#define DIRENT_MAGIC_END 0xffffffff
/* flags in the block allocation list to denote special blocks */
#define BAT_MAGIC_UNUSED 0xffffffff /* -1 */
#define BAT_MAGIC_END_OF_CHAIN 0xfffffffe /* -2 */
#define BAT_MAGIC_BAT 0xfffffffd /* a bat block, -3 */
#define BAT_MAGIC_METABAT 0xfffffffc /* a metabat block -4 */
G_END_DECLS
#endif /* GSF_MSOLE_IMPL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-msole-utils.h: various tools for handling MS OLE files
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_MSOLE_UTILS_H
#define GSF_MSOLE_UTILS_H
#include <gsf/gsf.h>
#include <gsf/gsf-doc-meta-data.h>
G_BEGIN_DECLS
GError *gsf_msole_metadata_read (GsfInput *in,
GsfDocMetaData *accum);
gboolean gsf_msole_metadata_write (GsfOutput *out,
GsfDocMetaData const *meta_data,
gboolean doc_not_component);
guint gsf_msole_lid_for_language (char const *lang);
guint gsf_msole_codepage_to_lid (int codepage);
int gsf_msole_lid_to_codepage (guint lid);
gchar *gsf_msole_lid_to_codepage_str (guint lid);
char const *gsf_msole_language_for_lid (guint lid);
int gsf_msole_iconv_win_codepage (void) ;
GIConv gsf_msole_iconv_open_for_import (int codepage) ;
GIConv gsf_msole_iconv_open_for_export (void) ;
GIConv gsf_msole_iconv_open_codepage_for_import (char const *to, int codepage);
GIConv gsf_msole_iconv_open_codepages_for_export (int codepage_to, char const *from);
GIConv gsf_msole_iconv_open_codepage_for_export (int codepage_to);
GByteArray *gsf_msole_inflate (GsfInput *input, gsf_off_t offset);
G_END_DECLS
#endif /* GSF_MSOLE_UTILS_H */

View File

@@ -0,0 +1,48 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile-impl.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTFILE_IMPL_H
#define GSF_OUTFILE_IMPL_H
#include <gsf/gsf.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-outfile.h>
G_BEGIN_DECLS
struct _GsfOutfile {
GsfOutput parent;
};
typedef struct {
GsfOutputClass output_class;
GsfOutput *(*new_child) (GsfOutfile *outfile,
char const *name, gboolean is_dir,
char const *first_property_name,
va_list args);
} GsfOutfileClass;
#define GSF_OUTFILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSF_OUTFILE_TYPE, GsfOutfileClass))
#define GSF_IS_OUTFILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSF_OUTFILE_TYPE))
G_END_DECLS
#endif /* GSF_OUTFILE_IMPL_H */

View File

@@ -0,0 +1,795 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile-msole.c:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Outc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-outfile-impl.h>
#include <gsf/gsf-outfile-msole.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-msole-impl.h>
#include <gsf/gsf-utils.h>
#include <string.h>
#include <stdio.h>
static GObjectClass *parent_class;
static GsfOutputClass *gsf_output_class;
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "libgsf:msole"
typedef enum { MSOLE_DIR, MSOLE_SMALL_BLOCK, MSOLE_BIG_BLOCK } MSOleOutfileType;
/* The most common values */
#define OLE_DEFAULT_THRESHOLD 0x1000
#define OLE_DEFAULT_BB_SIZE (1 << OLE_DEFAULT_BB_SHIFT)
#define OLE_DEFAULT_SB_SIZE (1 << OLE_DEFAULT_SB_SHIFT)
struct _GsfOutfileMSOle {
GsfOutfile parent;
GsfOutput *sink;
GsfOutfileMSOle *root;
MSOleOutfileType type;
unsigned first_block;
unsigned blocks;
unsigned child_index;
struct {
unsigned shift;
unsigned size;
} bb, sb;
union {
struct {
GSList *children;
GPtrArray *root_order; /* only valid for the root */
} dir;
struct {
guint8 *buf;
} small_block;
struct {
size_t start_offset; /* in bytes */
} big_block;
} content;
unsigned char clsid[16]; /* 16 byte GUID used by some apps */
};
typedef GsfOutfileClass GsfOutfileMSOleClass;
static void
gsf_outfile_msole_finalize (GObject *obj)
{
GsfOutfileMSOle *ole = GSF_OUTFILE_MSOLE (obj);
GsfOutput *output = GSF_OUTPUT (obj);
if (!gsf_output_is_closed (output))
gsf_output_close (output);
if (ole->sink != NULL) {
g_object_unref (G_OBJECT (ole->sink));
ole->sink = NULL;
}
switch (ole->type) {
case MSOLE_DIR:
if (ole->content.dir.children != NULL) {
g_slist_free (ole->content.dir.children);
ole->content.dir.children = NULL;
}
if (ole->content.dir.root_order != NULL)
g_warning ("Finalizing a MSOle Outfile without closing it.");
break;
case MSOLE_SMALL_BLOCK:
if (ole->content.small_block.buf != NULL) {
g_free (ole->content.small_block.buf);
ole->content.small_block.buf = NULL;
}
break;
case MSOLE_BIG_BLOCK:
break;
default :
g_warning ("Unknown file type");
}
parent_class->finalize (obj);
}
static gboolean
gsf_outfile_msole_seek (GsfOutput *output, gsf_off_t offset,
GSeekType whence)
{
GsfOutfileMSOle *ole = (GsfOutfileMSOle *)output;
switch (whence) {
case G_SEEK_SET : break;
case G_SEEK_CUR : offset += output->cur_offset; break;
case G_SEEK_END : offset += output->cur_size; break;
default :
break; /*checked in GsfOutput wrapper */
}
switch (ole->type) {
case MSOLE_DIR:
if (offset != 0) {
g_warning ("Attempt to seek a directory");
return FALSE;
}
return TRUE;
case MSOLE_SMALL_BLOCK:
/* it is ok to seek past the big block threshold
* we don't convert until they _write_ something
*/
return TRUE;
case MSOLE_BIG_BLOCK:
return gsf_output_seek (ole->sink,
(gsf_off_t)(ole->content.big_block.start_offset + offset),
G_SEEK_SET);
default :
return FALSE;
}
return FALSE;
}
/* Globals to support variable OLE sector size. */
/* 512 and 4096 bytes are the only known values for sector size on */
/* Win2k/XP platforms. Attempts to create OLE files on Win2k/XP with */
/* other values using StgCreateStorageEx() fail with invalid parameter. */
/* This code has been tested with 128,256,512,4096,8192 sizes for */
/* libgsf read/write. Interoperability with MS OLE32.DLL has been */
/* tested with 512 and 4096 block size for filesizes up to 2GB. */
#define ZERO_PAD_BUF_SIZE 4096
/* static objects are zero-initialized as per C/C++ standards */
static guint8 const zero_buf [ZERO_PAD_BUF_SIZE];
/* Calculate the block of the current offset in the file. A useful idiom is to
* pad_zero to move to the start of the next block, then get the block number.
* This avoids fence post type problems with partial blocks. */
static inline guint32
ole_cur_block (GsfOutfileMSOle const *ole)
{
return (gsf_output_tell (ole->sink) - OLE_HEADER_SIZE) >> ole->bb.shift;
}
static inline unsigned
ole_bytes_left_in_block (GsfOutfileMSOle *ole)
{
/* blocks are multiples of bb.size (the header is padded out to bb.size) */
unsigned r = gsf_output_tell (ole->sink) % ole->bb.size;
return (r != 0) ? (ole->bb.size - r) : 0;
}
static void
ole_pad_zero (GsfOutfileMSOle *ole)
{
/* no need to bounds check. len will always be less than bb.size, and
* we already check that zero_buf is big enough at creation */
unsigned len = ole_bytes_left_in_block (ole);
if (len > 0)
gsf_output_write (ole->sink, len, zero_buf);
}
/* Utility routine to generate a BAT for a file known to be sequential and
* continuous. */
static void
ole_write_bat (GsfOutput *sink, guint32 block, unsigned blocks)
{
guint8 buf [BAT_INDEX_SIZE];
/* FIXME FIXME FIXME optimize this to dump a buffer in 1 step */
while (blocks-- > 1) {
block++;
GSF_LE_SET_GUINT32 (buf, block);
gsf_output_write (sink, BAT_INDEX_SIZE, buf);
}
GSF_LE_SET_GUINT32 (buf, BAT_MAGIC_END_OF_CHAIN);
gsf_output_write (sink, BAT_INDEX_SIZE, buf);
}
static void
ole_write_const (GsfOutput *sink, guint32 value, unsigned n)
{
guint8 buf [BAT_INDEX_SIZE];
GSF_LE_SET_GUINT32 (buf, value);
while (n-- > 0)
gsf_output_write (sink, BAT_INDEX_SIZE, buf);
}
static void
ole_pad_bat_unused (GsfOutfileMSOle *ole, unsigned residual)
{
ole_write_const (ole->sink, BAT_MAGIC_UNUSED,
(ole_bytes_left_in_block (ole) / BAT_INDEX_SIZE) - residual);
}
/* write the metadata (dirents, small block, xbats) and close the sink */
static gboolean
gsf_outfile_msole_close_root (GsfOutfileMSOle *ole)
{
GsfOutfile *tmp;
guint8 buf [OLE_HEADER_SIZE];
guint32 sbat_start, num_sbat, sb_data_start, sb_data_size, sb_data_blocks;
guint32 bat_start, num_bat, dirent_start, num_dirent_blocks, next, child_index;
unsigned i, j, blocks, num_xbat, xbat_pos;
gsf_off_t data_size;
unsigned metabat_size = ole->bb.size / BAT_INDEX_SIZE - 1;
GPtrArray *elem = ole->root->content.dir.root_order;
/* write small block data */
blocks = 0;
sb_data_start = ole_cur_block (ole);
data_size = gsf_output_tell (ole->sink);
for (i = 0 ; i < elem->len ; i++) {
GsfOutfileMSOle *child = g_ptr_array_index (elem, i);
if (child->type == MSOLE_SMALL_BLOCK) {
gsf_off_t size = gsf_output_size (GSF_OUTPUT (child));
if (size > 0) {
child->blocks = ((size - 1) >> ole->sb.shift) + 1;
gsf_output_write (ole->sink,
child->blocks << ole->sb.shift,
child->content.small_block.buf);
child->first_block = blocks;
blocks += child->blocks;
} else {
child->blocks = 0;
child->first_block = BAT_MAGIC_END_OF_CHAIN;
}
}
}
data_size = gsf_output_tell (ole->sink) - data_size;
sb_data_size = data_size;
if ((gsf_off_t) sb_data_size != data_size) {
/* Check for overflow */
g_warning ("File too big");
return FALSE;
}
ole_pad_zero (ole);
sb_data_blocks = ole_cur_block (ole) - sb_data_start;
/* write small block BAT (the meta bat is in a file) */
sbat_start = ole_cur_block (ole);
for (i = 0 ; i < elem->len ; i++) {
GsfOutfileMSOle *child = g_ptr_array_index (elem, i);
if (child->type == MSOLE_SMALL_BLOCK && child->blocks > 0)
ole_write_bat (ole->sink, child->first_block, child->blocks);
}
ole_pad_bat_unused (ole, 0);
num_sbat = ole_cur_block (ole) - sbat_start;
/* write dirents */
dirent_start = ole_cur_block (ole);
for (i = 0 ; i < elem->len ; i++) {
GsfOutfileMSOle *child = g_ptr_array_index (elem, i);
glong j, name_len = 0;
memset (buf, 0, DIRENT_SIZE);
/* Hard code 'Root Entry' for the root */
if (i == 0 || gsf_output_name (GSF_OUTPUT (child)) != NULL) {
char const *name = (i == 0)
? "Root Entry" : gsf_output_name (GSF_OUTPUT (child));
gunichar2 *name_utf16 = g_utf8_to_utf16 (name,
-1, NULL, &name_len, NULL);
if (name_len >= DIRENT_MAX_NAME_SIZE)
name_len = DIRENT_MAX_NAME_SIZE-1;
/* be wary about endianness */
for (j = 0 ; j < name_len ; j++)
GSF_LE_SET_GUINT16 (buf + j*2, name_utf16 [j]);
g_free (name_utf16);
name_len++;
}
GSF_LE_SET_GUINT16 (buf + DIRENT_NAME_LEN, name_len*2);
if (child->root == child) {
GSF_LE_SET_GUINT8 (buf + DIRENT_TYPE, DIRENT_TYPE_ROOTDIR);
GSF_LE_SET_GUINT32 (buf + DIRENT_FIRSTBLOCK,
(sb_data_size > 0) ? sb_data_start : BAT_MAGIC_END_OF_CHAIN);
GSF_LE_SET_GUINT32 (buf + DIRENT_FILE_SIZE, sb_data_size);
memcpy (buf + DIRENT_CLSID, child->clsid, sizeof (child->clsid));
} else if (child->type == MSOLE_DIR) {
GSF_LE_SET_GUINT8 (buf + DIRENT_TYPE, DIRENT_TYPE_DIR);
GSF_LE_SET_GUINT32 (buf + DIRENT_FIRSTBLOCK, BAT_MAGIC_END_OF_CHAIN);
GSF_LE_SET_GUINT32 (buf + DIRENT_FILE_SIZE, 0);
/* write the class id */
memcpy (buf + DIRENT_CLSID, child->clsid, sizeof (child->clsid));
} else {
guint32 size = child->parent.parent.cur_size;
if ((gsf_off_t) size != child->parent.parent.cur_size)
g_warning ("File too big");
GSF_LE_SET_GUINT8 (buf + DIRENT_TYPE, DIRENT_TYPE_FILE);
GSF_LE_SET_GUINT32 (buf + DIRENT_FIRSTBLOCK, child->first_block);
GSF_LE_SET_GUINT32 (buf + DIRENT_FILE_SIZE, size);
}
/* make everything black (red == 0) */
GSF_LE_SET_GUINT8 (buf + DIRENT_COLOUR, 1);
tmp = gsf_output_container (GSF_OUTPUT (child));
next = DIRENT_MAGIC_END;
if (child->root != child && tmp != NULL) {
GSList *ptr = GSF_OUTFILE_MSOLE (tmp)->content.dir.children;
for (; ptr != NULL ; ptr = ptr->next)
if (ptr->data == child) {
if (ptr->next != NULL) {
GsfOutfileMSOle *sibling = ptr->next->data;
next = sibling->child_index;
}
break;
}
}
/* make linked list rather than tree, only use next */
GSF_LE_SET_GUINT32 (buf + DIRENT_PREV, DIRENT_MAGIC_END);
GSF_LE_SET_GUINT32 (buf + DIRENT_NEXT, next);
child_index = DIRENT_MAGIC_END;
if (child->type == MSOLE_DIR && child->content.dir.children != NULL) {
GsfOutfileMSOle *first = child->content.dir.children->data;
child_index = first->child_index;
}
GSF_LE_SET_GUINT32 (buf + DIRENT_CHILD, child_index);
gsf_output_write (ole->sink, DIRENT_SIZE, buf);
}
ole_pad_zero (ole);
num_dirent_blocks = ole_cur_block (ole) - dirent_start;
/* write BAT */
bat_start = ole_cur_block (ole);
for (i = 0 ; i < elem->len ; i++) {
GsfOutfileMSOle *child = g_ptr_array_index (elem, i);
if (child->type == MSOLE_BIG_BLOCK)
ole_write_bat (ole->sink, child->first_block, child->blocks);
}
if (sb_data_blocks > 0)
ole_write_bat (ole->sink, sb_data_start, sb_data_blocks);
if (num_sbat > 0)
ole_write_bat (ole->sink, sbat_start, num_sbat);
ole_write_bat (ole->sink, dirent_start, num_dirent_blocks);
/* List the BAT and meta-BAT blocks in the BAT. Doing this may
* increase the size of the bat and hence the metabat, so be
* prepared to iterate.
*/
num_bat = 0;
num_xbat = 0;
recalc_bat_bat :
i = ((ole->sink->cur_size
+ BAT_INDEX_SIZE * (num_bat + num_xbat)
- OLE_HEADER_SIZE - 1) >> ole->bb.shift) + 1;
i -= bat_start;
if (num_bat != i) {
num_bat = i;
goto recalc_bat_bat;
}
i = 0;
if (num_bat > OLE_HEADER_METABAT_SIZE)
i = 1 + ((num_bat - OLE_HEADER_METABAT_SIZE - 1)
/ metabat_size);
if (num_xbat != i) {
num_xbat = i;
goto recalc_bat_bat;
}
ole_write_const (ole->sink, BAT_MAGIC_BAT, num_bat);
ole_write_const (ole->sink, BAT_MAGIC_METABAT, num_xbat);
ole_pad_bat_unused (ole, 0);
if (num_xbat > 0) {
xbat_pos = ole_cur_block (ole);
blocks = OLE_HEADER_METABAT_SIZE;
} else {
xbat_pos = BAT_MAGIC_END_OF_CHAIN;
blocks = num_bat;
}
/* fix up the header */
if (ole->bb.size == 4096) {
/* set _cSectDir for 4k sector files */
GSF_LE_SET_GUINT32 (buf, num_dirent_blocks);
gsf_output_seek (ole->sink,
(gsf_off_t) OLE_HEADER_CSECTDIR, G_SEEK_SET);
gsf_output_write (ole->sink, 4, buf);
}
GSF_LE_SET_GUINT32 (buf, num_bat);
GSF_LE_SET_GUINT32 (buf+4, dirent_start);
gsf_output_seek (ole->sink,
(gsf_off_t) OLE_HEADER_NUM_BAT, G_SEEK_SET);
gsf_output_write (ole->sink, 8, buf);
GSF_LE_SET_GUINT32 (buf+0x0,
(num_sbat > 0) ? sbat_start : BAT_MAGIC_END_OF_CHAIN);
GSF_LE_SET_GUINT32 (buf+0x4, num_sbat);
GSF_LE_SET_GUINT32 (buf+0x8, xbat_pos);
GSF_LE_SET_GUINT32 (buf+0xc, num_xbat);
gsf_output_seek (ole->sink, (gsf_off_t) OLE_HEADER_SBAT_START,
G_SEEK_SET);
gsf_output_write (ole->sink, 0x10, buf);
/* write initial Meta-BAT */
for (i = 0 ; i < blocks ; i++) {
GSF_LE_SET_GUINT32 (buf, bat_start + i);
gsf_output_write (ole->sink, BAT_INDEX_SIZE, buf);
}
/* write extended Meta-BAT */
if (num_xbat > 0) {
gsf_output_seek (ole->sink, 0, G_SEEK_END);
for (i = 0 ; i++ < num_xbat ; ) {
bat_start += blocks;
num_bat -= blocks;
blocks = (num_bat > metabat_size) ? metabat_size : num_bat;
for (j = 0 ; j < blocks ; j++) {
GSF_LE_SET_GUINT32 (buf, bat_start + j);
gsf_output_write (ole->sink, BAT_INDEX_SIZE, buf);
}
if (i == num_xbat) {
ole_pad_bat_unused (ole, 1);
xbat_pos = BAT_MAGIC_END_OF_CHAIN;
} else
xbat_pos++;
GSF_LE_SET_GUINT32 (buf, xbat_pos);
gsf_output_write (ole->sink, BAT_INDEX_SIZE, buf);
}
}
/* free the children */
for (i = 0 ; i < elem->len ; i++)
g_object_unref (G_OBJECT (g_ptr_array_index (elem, i)));
g_ptr_array_free (elem, TRUE);
ole->content.dir.root_order = NULL;
return gsf_output_close (ole->sink);
}
static gboolean
gsf_outfile_msole_close (GsfOutput *output)
{
GsfOutfileMSOle *ole = (GsfOutfileMSOle *)output;
if (gsf_output_container (output) == NULL) /* The root dir */
return gsf_outfile_msole_close_root (ole);
if (ole->type == MSOLE_BIG_BLOCK) {
gsf_outfile_msole_seek (output, 0, G_SEEK_END);
ole_pad_zero (ole);
ole->blocks = ole_cur_block (ole) - ole->first_block;
return gsf_output_unwrap (G_OBJECT (output), ole->sink);
}
return TRUE;
}
static gboolean
gsf_outfile_msole_write (GsfOutput *output,
size_t num_bytes, guint8 const *data)
{
GsfOutfileMSOle *ole = (GsfOutfileMSOle *)output;
size_t wsize;
g_return_val_if_fail (ole->type != MSOLE_DIR, FALSE);
if (ole->type == MSOLE_SMALL_BLOCK) {
gboolean ok;
guint8 *buf;
gsf_off_t start_offset;
if ((output->cur_offset + num_bytes) < OLE_DEFAULT_THRESHOLD) {
memcpy (ole->content.small_block.buf + output->cur_offset,
data, num_bytes);
return TRUE;
}
ok = gsf_output_wrap (G_OBJECT (output), ole->sink);
if (!ok)
return FALSE;
buf = ole->content.small_block.buf;
ole->content.small_block.buf = NULL;
start_offset = gsf_output_tell (ole->sink);
ole->content.big_block.start_offset = start_offset;
if ((gsf_off_t) ole->content.big_block.start_offset
!= start_offset) {
/* Check for overflow */
g_warning ("File too big");
return FALSE;
}
ole->first_block = ole_cur_block (ole);
ole->type = MSOLE_BIG_BLOCK;
wsize = output->cur_size;
if ((gsf_off_t) wsize != output->cur_size) {
/* Check for overflow */
g_warning ("File too big");
return FALSE;
}
gsf_output_write (ole->sink, wsize, buf);
g_free (buf);
}
g_return_val_if_fail (ole->type == MSOLE_BIG_BLOCK, FALSE);
gsf_output_write (ole->sink, num_bytes, data);
return TRUE;
}
static gsf_off_t gsf_outfile_msole_vprintf (GsfOutput *output,
char const *format, va_list args) G_GNUC_PRINTF (2, 0);
static gsf_off_t
gsf_outfile_msole_vprintf (GsfOutput *output, char const *format, va_list args)
{
GsfOutfileMSOle *ole = (GsfOutfileMSOle *)output;
/* An optimization. */
if (ole->type == MSOLE_BIG_BLOCK)
return gsf_output_vprintf (ole->sink, format, args);
/* In other cases, use the gsf_output_real_vprintf fallback method.
* (This eventually calls gsf_outfile_msole_write, which will also
* check that ole->type != MSOLE_DIR.)
*/
return gsf_output_class->Vprintf (output, format, args);
}
static void
ole_register_child (GsfOutfileMSOle *root, GsfOutfileMSOle *child)
{
child->root = root;
g_object_ref (G_OBJECT (child));
child->child_index = root->content.dir.root_order->len;
g_ptr_array_add (root->content.dir.root_order, child);
}
static gint
ole_name_cmp (GsfOutfileMSOle const *a, GsfOutfileMSOle const *b)
{
/* According to the docs length is more important than lexical order */
char const *a_name = gsf_output_name ((GsfOutput const *)a);
char const *b_name = gsf_output_name ((GsfOutput const *)b);
/* be anal */
if (a_name == NULL)
return (b_name == NULL) ? 0 : -1;
else if (b_name == NULL)
return 1;
else {
unsigned a_len = g_utf8_strlen (a_name, -1);
unsigned b_len = g_utf8_strlen (b_name, -1);
if (a_len != b_len)
return a_len - b_len;
return g_utf8_collate (a_name, b_name);
}
}
static void
gsf_outfile_msole_set_block_shift (GsfOutfileMSOle *ole,
unsigned bb_shift, unsigned sb_shift)
{
ole->bb.shift = bb_shift;
ole->bb.size = (1 << ole->bb.shift);
ole->sb.shift = sb_shift;
ole->sb.size = (1 << ole->sb.shift);
}
static GsfOutput *
gsf_outfile_msole_new_child (GsfOutfile *parent,
char const *name, gboolean is_dir,
char const *first_property_name, va_list args)
{
GsfOutfileMSOle *ole_parent = (GsfOutfileMSOle *)parent;
GsfOutfileMSOle *child;
g_return_val_if_fail (ole_parent != NULL, NULL);
g_return_val_if_fail (ole_parent->type == MSOLE_DIR, NULL);
child = (GsfOutfileMSOle *)g_object_new_valist (
GSF_OUTFILE_MSOLE_TYPE, first_property_name, args);
if (is_dir) {
child->type = MSOLE_DIR;
child->content.dir.children = NULL;
} else {
/* start as small block */
child->type = MSOLE_SMALL_BLOCK;
child->content.small_block.buf = g_new0 (guint8, OLE_DEFAULT_THRESHOLD);
}
g_object_ref (G_OBJECT (ole_parent->sink));
child->sink = ole_parent->sink;
child->root = ole_parent->root;
gsf_outfile_msole_set_block_shift (child,
ole_parent->bb.shift, ole_parent->sb.shift);
gsf_output_set_name (GSF_OUTPUT (child), name);
gsf_output_set_container (GSF_OUTPUT (child), parent);
ole_parent->content.dir.children = g_slist_insert_sorted (
ole_parent->content.dir.children, child,
(GCompareFunc)ole_name_cmp);
ole_register_child (ole_parent->root, child);
return GSF_OUTPUT (child);
}
static void
gsf_outfile_msole_init (GObject *obj)
{
GsfOutfileMSOle *ole = GSF_OUTFILE_MSOLE (obj);
ole->sink = NULL;
ole->root = NULL;
ole->type = MSOLE_DIR;
gsf_outfile_msole_set_block_shift (ole,
OLE_DEFAULT_BB_SHIFT, OLE_DEFAULT_SB_SHIFT);
ole->content.dir.children = NULL;
ole->content.dir.root_order = NULL;
memset (ole->clsid, 0, sizeof (ole->clsid));
}
static void
gsf_outfile_msole_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
GsfOutfileClass *outfile_class = GSF_OUTFILE_CLASS (gobject_class);
gobject_class->finalize = gsf_outfile_msole_finalize;
output_class->Close = gsf_outfile_msole_close;
output_class->Seek = gsf_outfile_msole_seek;
output_class->Write = gsf_outfile_msole_write;
output_class->Vprintf = gsf_outfile_msole_vprintf;
outfile_class->new_child = gsf_outfile_msole_new_child;
parent_class = g_type_class_peek_parent (gobject_class);
gsf_output_class = g_type_class_peek (GSF_OUTPUT_TYPE);
}
GSF_CLASS (GsfOutfileMSOle, gsf_outfile_msole,
gsf_outfile_msole_class_init, gsf_outfile_msole_init,
GSF_OUTFILE_TYPE)
/* returns the number of times 1 must be shifted left to reach value */
static unsigned
compute_shift (unsigned value)
{
unsigned i = 0;
while ((value >> i) > 1)
i++;
return i;
}
/**
* gsf_outfile_msole_new_full :
* @sink : a #GsfOutput to hold the OLE2 file.
* @bb_size : size of large blocks.
* @sb_size : size of small blocks.
*
* Creates the root directory of an MS OLE file and manages the addition of
* children.
*
* NOTE : adds a reference to @sink
*
* Returns the new ole file handler
**/
GsfOutfile *
gsf_outfile_msole_new_full (GsfOutput *sink, guint bb_size, guint sb_size)
{
static guint8 const default_header [] = {
/* 0x00 */ 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1,
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x18 */ 0x3e, 0x00, 0x03, 0x00, 0xfe, 0xff, 0x09, 0x00,
/* 0x20 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x30 */ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
/* 0x38 */ 0x00, 0x10, 0x00, 0x00 /* 0x3c-0x4b: filled on close */
};
guint8 *buf;
GsfOutfileMSOle *ole;
g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
ole = g_object_new (GSF_OUTFILE_MSOLE_TYPE, NULL);
g_object_ref (G_OBJECT (sink));
ole->sink = sink;
ole->type = MSOLE_DIR;
ole->content.dir.root_order = g_ptr_array_new ();
ole_register_child (ole, ole);
gsf_outfile_msole_set_block_shift (ole,
compute_shift (bb_size), compute_shift (sb_size));
if (ole->bb.size != bb_size ||
ole->sb.size != sb_size ||
bb_size <= sb_size ||
bb_size < DIRENT_SIZE ||
sb_size < 8 ||
ZERO_PAD_BUF_SIZE < ole->bb.size) {
if (ZERO_PAD_BUF_SIZE < ole->bb.size)
g_warning ("Block size is too big, failing back to defaults.");
else
g_warning ("Incorrect block sizes, failing back to defaults.");
gsf_outfile_msole_set_block_shift (ole,
OLE_DEFAULT_BB_SHIFT, OLE_DEFAULT_SB_SHIFT);
}
/* The names are the same */
gsf_output_set_name (GSF_OUTPUT (ole), gsf_output_name (sink));
gsf_output_set_container (GSF_OUTPUT (ole), NULL);
/* build the header */
buf = g_new (guint8, OLE_HEADER_SIZE);
memcpy (buf, default_header, sizeof (default_header));
memset (buf + sizeof (default_header), 0xff,
OLE_HEADER_SIZE - sizeof (default_header));
GSF_LE_SET_GUINT16 (buf + OLE_HEADER_BB_SHIFT, ole->bb.shift);
GSF_LE_SET_GUINT16 (buf + OLE_HEADER_SB_SHIFT, ole->sb.shift);
/* 4k sector OLE files seen in the wild have version 4 */
if (ole->bb.size == 4096)
GSF_LE_SET_GUINT16 (buf + OLE_HEADER_MAJOR_VER, 4);
gsf_output_write (sink, OLE_HEADER_SIZE, buf);
g_free (buf);
/* header must be padded out to bb.size with zeros */
ole_pad_zero(ole);
return GSF_OUTFILE (ole);
}
/**
* gsf_outfile_msole_new :
* @sink : a #GsfOutput to hold the OLE2 file
*
* Creates the root directory of an MS OLE file and manages the addition of
* children.
*
* NOTE : adds a reference to @sink
*
* Returns the new ole file handler
**/
GsfOutfile *
gsf_outfile_msole_new (GsfOutput *sink)
{
return gsf_outfile_msole_new_full (sink,
OLE_DEFAULT_BB_SIZE, OLE_DEFAULT_SB_SIZE);
}
/**
* gsf_outfile_msole_set_class_id :
* @ole: a #GsfOutfileMSOle
* @clsid: 16 byte identifier (often a GUID in MS Windows apps)
*
* Write @clsid to the directory associated with @ole.
*
* Returns TRUE on success.
**/
gboolean
gsf_outfile_msole_set_class_id (GsfOutfileMSOle *ole, guint8 const *clsid)
{
g_return_val_if_fail (ole != NULL && ole->type == MSOLE_DIR, FALSE);
memcpy (ole->clsid, clsid, sizeof (ole->clsid));
return TRUE;
}

View File

@@ -0,0 +1,48 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile-msole.h: interface for creating OLE files
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTFILE_MSOLE_H
#define GSF_OUTFILE_MSOLE_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _GsfOutfileMSOle GsfOutfileMSOle;
#define GSF_OUTFILE_MSOLE_TYPE (gsf_outfile_msole_get_type ())
#define GSF_OUTFILE_MSOLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTFILE_MSOLE_TYPE, GsfOutfileMSOle))
#define GSF_IS_OUTFILE_MSOLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTFILE_MSOLE_TYPE))
#define OLE_DEFAULT_SB_SHIFT 6
#define OLE_DEFAULT_BB_SHIFT 9
GType gsf_outfile_msole_get_type (void);
GsfOutfile *gsf_outfile_msole_new (GsfOutput *sink);
GsfOutfile *gsf_outfile_msole_new_full (GsfOutput *sink,
guint bb_size, guint sb_size);
gboolean gsf_outfile_msole_set_class_id (GsfOutfileMSOle *ole,
guint8 const *clsid);
G_END_DECLS
#endif /* GSF_OUTFILE_H */

View File

@@ -0,0 +1,170 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile-stdio.c: A directory tree wrapper for Outfile
*
* Copyright (C) 2004 Novell, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-outfile-impl.h>
#include <gsf/gsf-outfile-stdio.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-output-stdio.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#ifdef HAVE_GLIB26
#include <glib/gstdio.h>
#else
#include "glib24_26-compat.h"
#endif // HAVE_GLIB26
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
static GObjectClass *parent_class;
struct _GsfOutfileStdio {
GsfOutfile parent;
char *root;
};
typedef GsfOutfileClass GsfOutfileStdioClass;
static void
gsf_outfile_stdio_finalize (GObject *obj)
{
GsfOutfileStdio *ofs = GSF_OUTFILE_STDIO (obj);
g_free (ofs->root);
parent_class->finalize (obj);
}
static GsfOutput *
gsf_outfile_stdio_new_child (GsfOutfile *parent,
char const *name, gboolean is_dir,
G_GNUC_UNUSED char const *first_property_name,
G_GNUC_UNUSED va_list args)
{
GsfOutfileStdio *ofs = GSF_OUTFILE_STDIO (parent);
GsfOutput *child;
char *path = g_build_filename (ofs->root, name, NULL);
/* FIXME FIXME FIXME FIX : allow args */
if (is_dir)
child = (GsfOutput *)gsf_outfile_stdio_new (path, NULL);
else
child = gsf_output_stdio_new (path, NULL);
g_free (path);
return child;
}
static gboolean
gsf_outfile_stdio_close (G_GNUC_UNUSED GsfOutput *output)
{
return TRUE;
}
static void
gsf_outfile_stdio_init (GsfOutfileStdio *ofs)
{
ofs->root = NULL;
}
static void
gsf_outfile_stdio_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
GsfOutfileClass *outfile_class = GSF_OUTFILE_CLASS (gobject_class);
parent_class = g_type_class_peek (GSF_OUTFILE_TYPE);
gobject_class->finalize = gsf_outfile_stdio_finalize;
output_class->Close = gsf_outfile_stdio_close;
output_class->Seek = NULL;
output_class->Write = NULL;
output_class->Vprintf = NULL;
outfile_class->new_child = gsf_outfile_stdio_new_child;
}
GSF_CLASS (GsfOutfileStdio, gsf_outfile_stdio,
gsf_outfile_stdio_class_init, gsf_outfile_stdio_init,
GSF_OUTFILE_TYPE)
/**
* gsf_outfile_stdio_new :
* @root : root directory in utf8.
* @err : optionally NULL.
*
* Returns a new outfile or NULL.
**/
GsfOutfile *
gsf_outfile_stdio_new_valist (char const *root, GError **err,
char const *first_property_name,
va_list var_args)
{
GsfOutfileStdio *ofs;
if (0 != g_mkdir (root, 0777)) {
if (err != NULL) {
int save_errno = errno;
char *utf8name = g_filename_display_name (root);
*err = g_error_new (gsf_output_error_id (), 0,
"%s: %s",
utf8name, g_strerror (save_errno));
g_free (utf8name);
}
return NULL;
}
ofs = (GsfOutfileStdio *) g_object_new_valist (GSF_OUTFILE_STDIO_TYPE,
first_property_name, var_args);
ofs->root = g_strdup (root);
gsf_output_set_name_from_filename (GSF_OUTPUT (ofs), root);
return GSF_OUTFILE (ofs);
}
GsfOutfile *
gsf_outfile_stdio_new_full (char const *root, GError **err,
const gchar *first_property_name,
...)
{
GsfOutfile *res;
va_list var_args;
va_start (var_args, first_property_name);
res = gsf_outfile_stdio_new_valist (root, err, first_property_name, var_args);
va_end (var_args);
return res;
}
/**
* gsf_outfile_stdio_new :
* @root : root directory in utf8.
* @err : optionally NULL.
*
* Returns a new outfile or NULL.
**/
GsfOutfile *
gsf_outfile_stdio_new (char const *root, GError **err)
{
return gsf_outfile_stdio_new_full (root, err, NULL);
}

View File

@@ -0,0 +1,46 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile-stdio.h: write a directory tree
*
* Copyright (C) 2004 Novell, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTFILE_STDIO_H
#define GSF_OUTFILE_STDIO_H
#include <gsf/gsf.h>
G_BEGIN_DECLS
typedef struct _GsfOutfileStdio GsfOutfileStdio;
#define GSF_OUTFILE_STDIO_TYPE (gsf_outfile_stdio_get_type ())
#define GSF_OUTFILE_STDIO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTFILE_STDIO_TYPE, GsfOutfileStdio))
#define GSF_IS_OUTFILE_STDIO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTFILE_STDIO_TYPE))
GType gsf_outfile_stdio_get_type (void);
GsfOutfile *gsf_outfile_stdio_new (char const *root, GError **err);
GsfOutfile *gsf_outfile_stdio_new_full (char const *root, GError **err,
char const *first_property_name,
...); /* G_GNUC_NULL_TERMINATED */
GsfOutfile *gsf_outfile_stdio_new_valist (char const *root, GError **err,
char const *first_property_name,
va_list var_args);
G_END_DECLS
#endif /* GSF_OUTFILE_H */

View File

@@ -0,0 +1,764 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile-zip.c: zip archive output.
*
* Copyright (C) 2002-2004 Jon K Hellan (hellan@acm.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Outc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-outfile-impl.h>
#include <gsf/gsf-outfile-zip.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <gsf/gsf-zip-impl.h>
#include <string.h>
#include <time.h>
#include <zlib.h>
#ifndef HAVE_GLIB26
#include <gsf/glib24_26-compat.h>
#endif
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "libgsf:zip"
enum {
PROP_0,
PROP_SINK,
PROP_ENTRY_NAME,
PROP_COMPRESSION_LEVEL
};
static GObjectClass *parent_class;
struct _GsfOutfileZip {
GsfOutfile parent;
GsfOutput *sink;
GsfOutfileZip *root;
char *entry_name;
GsfZipVDir *vdir;
GPtrArray *root_order; /* only valid for the root */
z_stream *stream;
GsfZipCompressionMethod compression_method;
gboolean writing;
guint8 *buf;
size_t buf_size;
};
typedef struct {
GsfOutfileClass parent_class;
} GsfOutfileZipClass;
#define GSF_OUTFILE_ZIP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSF_OUTFILE_ZIP_TYPE, GsfOutfileZipClass))
#define GSF_IS_OUTFILE_ZIP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSF_OUTFILE_ZIP_TYPE))
static void
disconnect_children (GsfOutfileZip *zip)
{
unsigned i;
if (!zip->root_order)
return;
for (i = 0 ; i < zip->root_order->len ; i++) {
GsfOutfileZip *child =
g_ptr_array_index (zip->root_order, i);
if (child)
g_object_unref (child);
}
g_ptr_array_free (zip->root_order, TRUE);
zip->root_order = NULL;
}
static void
gsf_outfile_zip_finalize (GObject *obj)
{
GsfOutfileZip *zip = GSF_OUTFILE_ZIP (obj);
/* If the closing failed, we might have stuff here. */
disconnect_children (zip);
if (zip->sink != NULL) {
g_object_unref (zip->sink);
zip->sink = NULL;
}
g_free (zip->entry_name);
if (zip->stream)
(void) deflateEnd (zip->stream);
g_free (zip->stream);
g_free (zip->buf);
if (zip == zip->root)
gsf_vdir_free (zip->vdir, TRUE); /* Frees vdirs recursively */
parent_class->finalize (obj);
}
static GObject *
gsf_outfile_zip_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
GsfOutfileZip *zip =(GsfOutfileZip *)
(parent_class->constructor (type,
n_construct_properties,
construct_params));
if (!zip->entry_name) {
zip->vdir = gsf_vdir_new ("", TRUE, NULL);
zip->root_order = g_ptr_array_new ();
zip->root = zip;
/* The names are the same */
gsf_output_set_name (GSF_OUTPUT (zip), gsf_output_name (zip->sink));
gsf_output_set_container (GSF_OUTPUT (zip), NULL);
}
return (GObject *)zip;
}
static gboolean
gsf_outfile_zip_seek (G_GNUC_UNUSED GsfOutput *output,
G_GNUC_UNUSED gsf_off_t offset,
G_GNUC_UNUSED GSeekType whence)
{
return FALSE;
}
static gboolean
zip_dirent_write (GsfOutput *sink, GsfZipDirent *dirent)
{
static guint8 const dirent_signature[] =
{ 'P', 'K', 0x01, 0x02 };
guint8 buf[ZIP_DIRENT_SIZE];
int nlen = strlen (dirent->name);
gboolean ret;
memset (buf, 0, sizeof buf);
memcpy (buf, dirent_signature, sizeof dirent_signature);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_ENCODER, 0x317); /* Unix */
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_EXTRACT, 0x14);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_FLAGS, 0x08);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_COMPR_METHOD,
dirent->compr_method);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_DOSTIME, dirent->dostime);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_CRC32, dirent->crc32);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_CSIZE, dirent->csize);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_USIZE, dirent->usize);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_NAME_SIZE, nlen);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_EXTRAS_SIZE, 0);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_COMMENT_SIZE, 0);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_DISKSTART, 0);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_FILE_TYPE, 0);
/* Hardcode file mode 644 */
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_FILE_MODE, 0644 << 16);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_OFFSET, dirent->offset);
ret = gsf_output_write (sink, sizeof buf, buf);
if (ret)
ret = gsf_output_write (sink, nlen, dirent->name);
return ret;
}
static gboolean
zip_trailer_write (GsfOutfileZip *zip, unsigned entries, gsf_off_t dirpos)
{
static guint8 const trailer_signature[] =
{ 'P', 'K', 0x05, 0x06 };
guint8 buf[ZIP_TRAILER_SIZE];
gsf_off_t pos = gsf_output_tell (zip->sink);
memset (buf, 0, sizeof buf);
memcpy (buf, trailer_signature, sizeof trailer_signature);
GSF_LE_SET_GUINT16 (buf + ZIP_TRAILER_ENTRIES, entries);
GSF_LE_SET_GUINT16 (buf + ZIP_TRAILER_TOTAL_ENTRIES, entries);
GSF_LE_SET_GUINT32 (buf + ZIP_TRAILER_DIR_SIZE, pos - dirpos);
GSF_LE_SET_GUINT32 (buf + ZIP_TRAILER_DIR_POS, dirpos);
return gsf_output_write (zip->sink, sizeof buf, buf);
}
static gboolean
zip_close_root (GsfOutput *output)
{
GsfOutfileZip *zip = GSF_OUTFILE_ZIP (output);
GsfOutfileZip *child;
gsf_off_t dirpos = gsf_output_tell (zip->sink);
GPtrArray *elem = zip->root_order;
unsigned entries = elem->len;
unsigned i;
/* Check that children are closed */
for (i = 0 ; i < elem->len ; i++) {
child = g_ptr_array_index (elem, i);
if (!gsf_output_is_closed (GSF_OUTPUT (child))) {
g_warning ("Child still open");
return FALSE;
}
}
/* Write directory */
for (i = 0 ; i < entries ; i++) {
child = g_ptr_array_index (elem, i);
if (!zip_dirent_write (zip->sink, child->vdir->dirent))
return FALSE;
}
disconnect_children (zip);
return zip_trailer_write (zip, entries, dirpos);
}
static void
stream_name_write_to_buf (GsfOutfileZip *zip, GString *res)
{
GsfOutput *output = GSF_OUTPUT (zip);
GsfOutfile *container;
if (zip == zip->root)
return;
container = gsf_output_container (output);
if (container) {
stream_name_write_to_buf (GSF_OUTFILE_ZIP (container), res);
if (res->len) {
/* Forward slash is specified by the format. */
g_string_append_c (res, '/');
}
}
if (zip->entry_name)
g_string_append (res, zip->entry_name);
}
static char *
stream_name_build (GsfOutfileZip *zip)
{
GString *str = g_string_sized_new (80);
stream_name_write_to_buf (zip, str);
return g_string_free (str, FALSE);
}
static guint32
zip_time_make (time_t t)
{
struct tm *localnow = localtime (&t);
guint32 ztime;
ztime = (localnow->tm_year - 80) & 0x7f;
ztime = (ztime << 4) | ((localnow->tm_mon + 1) & 0x0f);
ztime = (ztime << 5) | (localnow->tm_mday & 0x1f);
ztime = (ztime << 5) | (localnow->tm_hour & 0x1f);
ztime = (ztime << 6) | (localnow->tm_min & 0x3f);
ztime = (ztime << 5) | ((localnow->tm_sec / 2) & 0x1f);
return ztime;
}
static GsfZipDirent*
zip_dirent_new_out (GsfOutfileZip *zip)
{
GsfZipDirent *dirent = gsf_zip_dirent_new ();
dirent->name = stream_name_build (zip);
dirent->compr_method = zip->compression_method;
dirent->dostime = zip_time_make (time (NULL));
return dirent;
}
static gboolean
zip_header_write (GsfOutfileZip *zip)
{
static guint8 const header_signature[] =
{ 'P', 'K', 0x03, 0x04 };
guint8 hbuf[ZIP_HEADER_SIZE];
GsfZipDirent *dirent = zip->vdir->dirent;
guint16 flags = 0;
char *name = dirent->name;
int nlen = strlen (name);
gboolean ret;
memset (hbuf, 0, sizeof hbuf);
memcpy (hbuf, header_signature, sizeof header_signature);
GSF_LE_SET_GUINT16 (hbuf + ZIP_HEADER_VERSION, 0x14);
if (dirent->compr_method == GSF_ZIP_DEFLATED)
flags = 0x08;
GSF_LE_SET_GUINT16 (hbuf + ZIP_HEADER_FLAGS, flags);
GSF_LE_SET_GUINT16 (hbuf + ZIP_HEADER_COMP_METHOD,
dirent->compr_method);
GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_TIME, dirent->dostime);
GSF_LE_SET_GUINT16 (hbuf + ZIP_HEADER_NAME_LEN, nlen);
ret = gsf_output_write (zip->sink, sizeof hbuf, hbuf);
if (ret)
ret = gsf_output_write (zip->sink, nlen, name);
return ret;
}
static gboolean
zip_init_write (GsfOutput *output)
{
GsfOutfileZip *zip = GSF_OUTFILE_ZIP (output);
GsfZipDirent *dirent;
int ret;
if (zip->root->writing) {
g_warning ("Already writing to another stream in archive");
return FALSE;
}
if (!gsf_output_wrap (G_OBJECT (output), zip->sink))
return FALSE;
dirent = zip_dirent_new_out (zip);
dirent->offset = gsf_output_tell (zip->sink);
if (zip->vdir->dirent)
g_warning ("Leak.");
zip->vdir->dirent = dirent;
zip_header_write (zip);
zip->writing = TRUE;
zip->root->writing = TRUE;
dirent->crc32 = crc32 (0L, Z_NULL, 0);
if (zip->compression_method == GSF_ZIP_DEFLATED) {
if (!zip->stream) {
zip->stream = g_new0 (z_stream, 1);
}
ret = deflateInit2 (zip->stream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL,
Z_DEFAULT_STRATEGY);
if (ret != Z_OK)
return FALSE;
if (!zip->buf) {
zip->buf_size = ZIP_BUF_SIZE;
zip->buf = g_new (guint8, zip->buf_size);
}
zip->stream->next_out = zip->buf;
zip->stream->avail_out = zip->buf_size;
}
return TRUE;
}
static gboolean
zip_output_block (GsfOutfileZip *zip)
{
size_t num_bytes = zip->buf_size - zip->stream->avail_out;
GsfZipDirent *dirent = zip->vdir->dirent;
if (!gsf_output_write (zip->sink, num_bytes, zip->buf)) {
return FALSE;
}
dirent->csize += num_bytes;
zip->stream->next_out = zip->buf;
zip->stream->avail_out = zip->buf_size;
return TRUE;
}
static gboolean
zip_flush (GsfOutfileZip *zip)
{
int zret;
do {
zret = deflate (zip->stream, Z_FINISH);
if (zret == Z_OK || (zret == Z_BUF_ERROR && zip->stream->avail_out == 0)) {
/* In this case Z_OK or Z_BUF_ERROR means more buffer
space is needed */
if (!zip_output_block (zip))
return FALSE;
}
} while (zret == Z_OK || zret == Z_BUF_ERROR);
if (zret != Z_STREAM_END)
return FALSE;
if (!zip_output_block (zip))
return FALSE;
return TRUE;
}
/* Write the per stream data descriptor */
static gboolean
zip_ddesc_write (GsfOutfileZip *zip)
{
static guint8 const ddesc_signature[] =
{ 'P', 'K', 0x07, 0x08 };
guint8 buf[16];
GsfZipDirent *dirent = zip->vdir->dirent;
memcpy (buf, ddesc_signature, sizeof ddesc_signature);
GSF_LE_SET_GUINT32 (buf + 4, dirent->crc32);
GSF_LE_SET_GUINT32 (buf + 8, dirent->csize);
GSF_LE_SET_GUINT32 (buf + 12, dirent->usize);
if (!gsf_output_write (zip->sink, sizeof buf, buf)) {
return FALSE;
}
return TRUE;
}
static gboolean
zip_header_write_sizes (GsfOutfileZip *zip)
{
guint8 hbuf[ZIP_HEADER_SIZE];
GsfZipDirent *dirent = zip->vdir->dirent;
gsf_off_t pos = gsf_output_tell (zip->sink);
if (!gsf_output_seek (zip->sink, dirent->offset + ZIP_HEADER_CRC,
G_SEEK_SET))
return FALSE;
GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_CRC, dirent->crc32);
GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_COMP_SIZE, dirent->csize);
GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_UNCOMP_SIZE, dirent->usize);
if (!gsf_output_write (zip->sink, 12, hbuf + ZIP_HEADER_CRC))
return FALSE;
if (!gsf_output_seek (zip->sink, pos, G_SEEK_SET))
return FALSE;
return TRUE;
}
static gboolean
zip_close_stream (GsfOutput *output)
{
GsfOutfileZip *zip = GSF_OUTFILE_ZIP (output);
gboolean result;
if (!zip->writing)
if (!zip_init_write (output))
return FALSE;
if (zip->compression_method == GSF_ZIP_DEFLATED) {
if (!zip_flush (zip))
return FALSE;
if (!zip_ddesc_write (zip)) /* Write data descriptor */
return FALSE;
} else {
if (!zip_header_write_sizes (zip)) /* Write crc, sizes */
return FALSE;
}
zip->root->writing = FALSE;
result = gsf_output_unwrap (G_OBJECT (output), zip->sink);
/* Free unneeded memory */
if (zip->stream) {
(void) deflateEnd (zip->stream);
g_free (zip->stream);
zip->stream = NULL;
g_free (zip->buf);
zip->buf = NULL;
}
return result;
}
static gboolean
gsf_outfile_zip_close (GsfOutput *output)
{
GsfOutfileZip *zip = GSF_OUTFILE_ZIP (output);
gboolean ret;
/* The root dir */
if (zip == zip->root)
ret = zip_close_root (output);
else if (zip->vdir->is_directory)
/* Directories: Do nothing. Should change this to actually
* write dirs which don't have children. */
ret = TRUE;
else
ret = zip_close_stream (output);
return ret;
}
static gboolean
gsf_outfile_zip_write (GsfOutput *output,
size_t num_bytes, guint8 const *data)
{
GsfOutfileZip *zip = GSF_OUTFILE_ZIP (output);
GsfZipDirent *dirent;
int ret;
g_return_val_if_fail (zip && zip->vdir, FALSE);
g_return_val_if_fail (!zip->vdir->is_directory, FALSE);
g_return_val_if_fail (data, FALSE);
if (!zip->writing)
if (!zip_init_write (output))
return FALSE;
dirent = zip->vdir->dirent;
if (zip->compression_method == GSF_ZIP_DEFLATED) {
zip->stream->next_in = (unsigned char *) data;
zip->stream->avail_in = num_bytes;
while (zip->stream->avail_in > 0) {
if (zip->stream->avail_out == 0) {
if (!zip_output_block (zip))
return FALSE;
}
ret = deflate (zip->stream, Z_NO_FLUSH);
if (ret != Z_OK)
return FALSE;
}
} else {
if (!gsf_output_write (zip->sink, num_bytes, data))
return FALSE;
dirent->csize += num_bytes;
}
dirent->crc32 = crc32 (dirent->crc32, data, num_bytes);
dirent->usize += num_bytes;
return TRUE;
}
static void
root_register_child (GsfOutfileZip *root, GsfOutfileZip *child)
{
child->root = root;
if (!child->vdir->is_directory) {
g_object_ref (child);
g_ptr_array_add (root->root_order, child);
}
}
static void
gsf_outfile_zip_set_sink (GsfOutfileZip *zip, GsfOutput *sink)
{
if (sink)
g_object_ref (sink);
if (zip->sink)
g_object_unref (zip->sink);
zip->sink = sink;
}
static GsfOutput *
gsf_outfile_zip_new_child (GsfOutfile *parent,
char const *name, gboolean is_dir,
char const *first_property_name, va_list args)
{
GsfOutfileZip *zip_parent = (GsfOutfileZip *)parent;
GsfOutfileZip *child;
size_t n_params = 0;
GParameter *params = NULL;
char *display_name;
g_return_val_if_fail (zip_parent != NULL, NULL);
g_return_val_if_fail (zip_parent->vdir, NULL);
g_return_val_if_fail (zip_parent->vdir->is_directory, NULL);
g_return_val_if_fail (name && *name, NULL);
gsf_property_settings_collect (GSF_OUTFILE_ZIP_TYPE,
&params, &n_params,
"sink", zip_parent->sink,
"entry-name", name,
NULL);
gsf_property_settings_collect_valist (GSF_OUTFILE_ZIP_TYPE,
&params, &n_params,
first_property_name,
args);
child = (GsfOutfileZip *)g_object_newv (GSF_OUTFILE_ZIP_TYPE,
n_params,
params);
gsf_property_settings_free (params, n_params);
child->vdir = gsf_vdir_new (name, is_dir, NULL);
/* FIXME: It isn't clear what encoding name is in. */
display_name = g_filename_display_name (name);
gsf_output_set_name (GSF_OUTPUT (child), display_name);
g_free (display_name);
gsf_output_set_container (GSF_OUTPUT (child), parent);
gsf_vdir_add_child (zip_parent->vdir, child->vdir);
root_register_child (zip_parent->root, child);
return GSF_OUTPUT (child);
}
static void
gsf_outfile_zip_init (GObject *obj)
{
GsfOutfileZip *zip = GSF_OUTFILE_ZIP (obj);
zip->sink = NULL;
zip->root = NULL;
zip->entry_name = NULL;
zip->vdir = NULL;
zip->root_order = NULL;
zip->stream = NULL;
zip->compression_method = GSF_ZIP_DEFLATED;
zip->writing = FALSE;
zip->buf = NULL;
zip->buf_size = 0;
}
static void
gsf_outfile_zip_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GsfOutfileZip *zip = (GsfOutfileZip *)object;
switch (property_id) {
case PROP_SINK:
g_value_set_object (value, zip->sink);
break;
case PROP_ENTRY_NAME:
g_value_set_string (value, zip->entry_name);
break;
case PROP_COMPRESSION_LEVEL:
g_value_set_int (value,
zip->vdir->dirent
? zip->vdir->dirent->compr_method
: 0);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_outfile_zip_set_property (GObject *object,
guint property_id,
GValue const *value,
GParamSpec *pspec)
{
GsfOutfileZip *zip = (GsfOutfileZip *)object;
switch (property_id) {
case PROP_SINK:
gsf_outfile_zip_set_sink (zip, g_value_get_object (value));
break;
case PROP_ENTRY_NAME:
zip->entry_name = g_strdup (g_value_get_string (value));
break;
case PROP_COMPRESSION_LEVEL: {
int level = g_value_get_int (value);
switch (level) {
case GSF_ZIP_STORED:
case GSF_ZIP_DEFLATED:
zip->compression_method = level;
break;
default:
g_warning ("Unsupported compression level %d", level);
}
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_outfile_zip_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *input_class = GSF_OUTPUT_CLASS (gobject_class);
GsfOutfileClass *outfile_class = GSF_OUTFILE_CLASS (gobject_class);
gobject_class->constructor = gsf_outfile_zip_constructor;
gobject_class->finalize = gsf_outfile_zip_finalize;
gobject_class->get_property = gsf_outfile_zip_get_property;
gobject_class->set_property = gsf_outfile_zip_set_property;
input_class->Write = gsf_outfile_zip_write;
input_class->Seek = gsf_outfile_zip_seek;
input_class->Close = gsf_outfile_zip_close;
outfile_class->new_child = gsf_outfile_zip_new_child;
parent_class = g_type_class_peek_parent (gobject_class);
g_object_class_install_property
(gobject_class,
PROP_SINK,
g_param_spec_object ("sink", "Sink",
"Where the archive is written.",
GSF_OUTPUT_TYPE,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(gobject_class,
PROP_ENTRY_NAME,
g_param_spec_string ("entry-name", "Entry Name",
"The filename of this member in the archive without path.",
NULL,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(gobject_class,
PROP_COMPRESSION_LEVEL,
g_param_spec_int ("compression-level",
"Compression Level",
"The level of compression used, zero meaning none.",
0, 10,
GSF_ZIP_DEFLATED,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
GSF_CLASS (GsfOutfileZip, gsf_outfile_zip,
gsf_outfile_zip_class_init, gsf_outfile_zip_init,
GSF_OUTFILE_TYPE)
/**
* gsf_outfile_zip_new :
* @sink :
* @err :
*
* Creates the root directory of a Zip file and manages the addition of
* children.
*
* NOTE : adds a reference to @sink
*
* Returns : the new zip file handler
**/
GsfOutfile *
gsf_outfile_zip_new (GsfOutput *sink, G_GNUC_UNUSED GError **err)
{
g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
return (GsfOutfile *)g_object_new (GSF_OUTFILE_ZIP_TYPE,
"sink", sink,
NULL);
}
/* deprecated has no effect */
gboolean
gsf_outfile_zip_set_compression_method (G_GNUC_UNUSED GsfOutfileZip *zip,
G_GNUC_UNUSED GsfZipCompressionMethod method)
{
return TRUE;
}

View File

@@ -0,0 +1,59 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile-zip.h: interface for zip archive output.
*
* Copyright (C) 2002-2004 Jon K Hellan (hellan@acm.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTFILE_ZIP_H
#define GSF_OUTFILE_ZIP_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
typedef enum {
GSF_ZIP_STORED = 0, /* supported for export */
GSF_ZIP_SHRUNK = 1,
GSF_ZIP_REDUCEDx1 = 2,
GSF_ZIP_REDUCEDx2 = 3,
GSF_ZIP_REDUCEDx3 = 4,
GSF_ZIP_REDUCEDx4 = 5,
GSF_ZIP_IMPLODED = 6,
GSF_ZIP_TOKENIZED = 7,
GSF_ZIP_DEFLATED = 8, /* supported for export */
GSF_ZIP_DEFLATED_BETTER = 9,
GSF_ZIP_IMPLODED_BETTER = 10
} GsfZipCompressionMethod;
typedef struct _GsfOutfileZip GsfOutfileZip;
#define GSF_OUTFILE_ZIP_TYPE (gsf_outfile_zip_get_type ())
#define GSF_OUTFILE_ZIP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTFILE_ZIP_TYPE, GsfOutfileZip))
#define GSF_IS_OUTFILE_ZIP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTFILE_ZIP_TYPE))
GType gsf_outfile_zip_get_type (void);
GsfOutfile *gsf_outfile_zip_new (GsfOutput *sink, GError **err);
/* Deprecated. Has no effect. */
gboolean gsf_outfile_zip_set_compression_method (GsfOutfileZip *zip,
GsfZipCompressionMethod method);
G_END_DECLS
#endif /* GSF_OUTFILE_H */

View File

@@ -0,0 +1,83 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile.c :
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-outfile-impl.h>
#include <gsf/gsf-impl-utils.h>
#define GET_CLASS(instance) G_TYPE_INSTANCE_GET_CLASS (instance, GSF_OUTFILE_TYPE, GsfOutfileClass)
/**
* gsf_outfile_new_child :
* @outfile : A #GsfOutfile
* @name : The name of the new child to create
* @is_dir : TRUE to create a directory, FALSE to create a plain file
*
* Returns a newly created child
**/
GsfOutput *
gsf_outfile_new_child (GsfOutfile *outfile,
char const *name, gboolean is_dir)
{
return gsf_outfile_new_child_full (outfile, name, is_dir, NULL);
}
/**
* gsf_outfile_new_child_full :
* @outfile : A #GsfOutfile
* @name : The name of the new child to create
* @is_dir : TRUE to create a directory, FALSE to create a plain file
* @first_property_name :
* @Varargs :
*
* Returns a newly created child
**/
GsfOutput *
gsf_outfile_new_child_full (GsfOutfile *outfile,
char const *name, gboolean is_dir,
char const *first_property_name,
...)
{
GsfOutput *res;
va_list args;
g_return_val_if_fail (outfile != NULL, NULL);
va_start (args, first_property_name);
res = gsf_outfile_new_child_varg (outfile, name, is_dir,
first_property_name, args);
va_end (args);
return res;
}
GsfOutput *
gsf_outfile_new_child_varg (GsfOutfile *outfile,
char const *name, gboolean is_dir,
char const *first_property_name,
va_list args)
{
g_return_val_if_fail (outfile != NULL, NULL);
return GET_CLASS (outfile)->new_child (outfile, name, is_dir,
first_property_name, args);
}
GSF_CLASS_ABSTRACT (GsfOutfile, gsf_outfile, NULL, NULL, GSF_OUTPUT_TYPE)

View File

@@ -0,0 +1,48 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-outfile.h: interface for creating structured files
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTFILE_H
#define GSF_OUTFILE_H
#include <gsf/gsf.h>
G_BEGIN_DECLS
#define GSF_OUTFILE_TYPE (gsf_outfile_get_type ())
#define GSF_OUTFILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTFILE_TYPE, GsfOutfile))
#define GSF_IS_OUTFILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTFILE_TYPE))
GType gsf_outfile_get_type (void);
GsfOutput *gsf_outfile_new_child (GsfOutfile *outfile,
char const *name, gboolean is_dir);
GsfOutput *gsf_outfile_new_child_full (GsfOutfile *outfile,
char const *name, gboolean is_dir,
char const *first_property_name,
...);
GsfOutput *gsf_outfile_new_child_varg (GsfOutfile *outfile,
char const *name, gboolean is_dir,
char const *first_property_name,
va_list args);
G_END_DECLS
#endif /* GSF_OUTFILE_H */

View File

@@ -0,0 +1,264 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-bzip.c: wrapper to compress to bzipped output
*
* Copyright (C) 2003-2004 Dom Lachowicz (cinamod@hotmail.com)
* 2002-2004 Jon K Hellan (hellan@acm.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-output-bzip.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#ifdef HAVE_BZ2
/* For getting FILE. Don't ask. */
#include <stdio.h>
#include <bzlib.h>
#define BZ_BUFSIZE 1024
#endif
static GObjectClass *parent_class;
struct _GsfOutputBzip {
GsfOutput output;
#ifdef HAVE_BZ2
GsfOutput *sink; /* compressed data */
bz_stream stream;
guint8 *buf;
size_t buf_size;
#endif
};
typedef struct {
GsfOutputClass output_class;
} GsfOutputBzipClass;
static void
gsf_output_bzip_finalize (GObject *obj)
{
#ifdef HAVE_BZ2
GsfOutputBzip *bzip = (GsfOutputBzip *)obj;
if (bzip->sink != NULL) {
g_object_unref (G_OBJECT (bzip->sink));
bzip->sink = NULL;
}
g_free (bzip->buf);
#endif
parent_class->finalize (obj);
}
#ifdef HAVE_BZ2
static gboolean
init_bzip (GsfOutputBzip *bzip, GError **err)
{
int ret;
ret = BZ2_bzCompressInit (&bzip->stream, 6, 0, 0);
if (ret != BZ_OK) {
if (err != NULL)
*err = g_error_new (gsf_output_error_id (), 0,
"Unable to initialize BZ2 library");
return FALSE;
}
if (!bzip->buf) {
bzip->buf_size = BZ_BUFSIZE;
bzip->buf = g_new (guint8, bzip->buf_size);
}
bzip->stream.next_out = bzip->buf;
bzip->stream.avail_out = bzip->buf_size;
return TRUE;
}
static gboolean
bzip_output_block (GsfOutputBzip *bzip)
{
size_t num_bytes = bzip->buf_size - bzip->stream.avail_out;
if (!gsf_output_write (bzip->sink, num_bytes, bzip->buf))
return FALSE;
bzip->stream.next_out = bzip->buf;
bzip->stream.avail_out = bzip->buf_size;
return TRUE;
}
static gboolean
bzip_flush (GsfOutputBzip *bzip)
{
int zret;
do {
zret = BZ2_bzCompress (&bzip->stream, BZ_FINISH);
if (zret == BZ_FINISH_OK) {
/* In this case BZ_FINISH_OK means more buffer space
needed */
if (!bzip_output_block (bzip))
return FALSE;
}
} while (zret == BZ_FINISH_OK);
if (zret != BZ_STREAM_END) {
g_warning ("Unexpected error code %d from bzlib during compression.",
zret);
return FALSE;
}
if (!bzip_output_block (bzip))
return FALSE;
return TRUE;
}
#endif
static gboolean
gsf_output_bzip_write (GsfOutput *output,
size_t num_bytes, guint8 const *data)
{
#ifdef HAVE_BZ2
GsfOutputBzip *bzip = GSF_OUTPUT_BZIP (output);
g_return_val_if_fail (data, FALSE);
bzip->stream.next_in = (unsigned char *) data;
bzip->stream.avail_in = num_bytes;
while (bzip->stream.avail_in > 0) {
int zret;
if (bzip->stream.avail_out == 0) {
if (!bzip_output_block (bzip))
return FALSE;
}
zret = BZ2_bzCompress (&bzip->stream, BZ_RUN);
if (zret != BZ_RUN_OK) {
g_warning ("Unexpected error code %d from bzlib during compression.",
zret);
return FALSE;
}
}
if (bzip->stream.avail_out == 0) {
if (!bzip_output_block (bzip))
return FALSE;
}
return TRUE;
#else
return FALSE;
#endif
}
static gboolean
gsf_output_bzip_seek (G_GNUC_UNUSED GsfOutput *output,
G_GNUC_UNUSED gsf_off_t offset,
G_GNUC_UNUSED GSeekType whence)
{
return FALSE;
}
static gboolean
gsf_output_bzip_close (GsfOutput *output)
{
#ifdef HAVE_BZ2
GsfOutputBzip *bzip = GSF_OUTPUT_BZIP (output);
gboolean rt;
rt = bzip_flush (bzip);
BZ2_bzCompressEnd (&bzip->stream);
return rt;
#else
return FALSE;
#endif
}
static void
gsf_output_bzip_init (GObject *obj)
{
#ifdef HAVE_BZ2
GsfOutputBzip *bzip = GSF_OUTPUT_BZIP (obj);
bzip->sink = NULL;
bzip->stream.bzalloc = NULL;
bzip->stream.bzfree = NULL;
bzip->stream.opaque = NULL;
bzip->stream.next_in = NULL;
bzip->stream.next_out = NULL;
bzip->stream.avail_in = bzip->stream.avail_out = 0;
bzip->buf = NULL;
bzip->buf_size = 0;
#endif
}
static void
gsf_output_bzip_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_output_bzip_finalize;
output_class->Write = gsf_output_bzip_write;
output_class->Seek = gsf_output_bzip_seek;
output_class->Close = gsf_output_bzip_close;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfOutputBzip, gsf_output_bzip,
gsf_output_bzip_class_init, gsf_output_bzip_init,
GSF_OUTPUT_TYPE)
/**
* gsf_output_bzip_new :
* @sink : The underlying data source.
* @err : optionally NULL.
*
* Adds a reference to @sink.
*
* Returns a new file or NULL.
**/
GsfOutput *
gsf_output_bzip_new (GsfOutput *sink, GError **err)
{
#ifdef HAVE_BZ2
GsfOutputBzip *bzip;
g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
bzip = g_object_new (GSF_OUTPUT_BZIP_TYPE, NULL);
g_object_ref (G_OBJECT (sink));
bzip->sink = sink;
if (!init_bzip (bzip, err)) {
g_object_unref (G_OBJECT (bzip));
return NULL;
}
return GSF_OUTPUT (bzip);
#else
if (err)
*err = g_error_new (gsf_output_error_id (), 0,
"BZ2 support not enabled");
return NULL;
#endif
}

View File

@@ -0,0 +1,40 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-bzip.h: wrapper to compress to bzipped output
*
* Copyright (C) 2003-2004 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_BZIP_H
#define GSF_OUTPUT_BZIP_H
#include "gsf-output.h"
G_BEGIN_DECLS
#define GSF_OUTPUT_BZIP_TYPE (gsf_output_bzip_get_type ())
#define GSF_OUTPUT_BZIP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_BZIP_TYPE, GsfOutputBzip))
#define GSF_IS_OUTPUT_BZIP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_BZIP_TYPE))
typedef struct _GsfOutputBzip GsfOutputBzip;
GType gsf_output_bzip_get_type (void);
GsfOutput *gsf_output_bzip_new (GsfOutput *sink, GError **err);
G_END_DECLS
#endif /* GSF_OUTPUT_BZIP_H */

View File

@@ -0,0 +1,352 @@
/*
* gsf-output-csv.c: a GsfOutput to write .csv style files.
*
* Copyright (C) 2005 Morten Welinder (terra@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-output-csv.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <glib/gconvert.h>
#include <string.h>
static GObjectClass *parent_class;
enum {
PROP_0,
PROP_SINK,
PROP_QUOTE,
PROP_QUOTING_MODE,
PROP_QUOTING_TRIGGERS,
PROP_EOL,
PROP_SEPARATOR
};
static void
gsf_output_csv_finalize (GObject *obj)
{
GsfOutputCsv *csv = (GsfOutputCsv *)obj;
if (csv->sink != NULL)
g_object_unref (G_OBJECT (csv->sink));
g_free (csv->quote);
g_free (csv->quoting_triggers);
g_free (csv->eol);
g_free (csv->separator);
g_string_free (csv->buf, TRUE);
parent_class->finalize (obj);
}
static gboolean
gsf_output_csv_write (GsfOutput *output,
size_t num_bytes, guint8 const *data)
{
GsfOutputCsv *csv = GSF_OUTPUT_CSV (output);
return gsf_output_write (csv->sink, num_bytes, data);
}
static gboolean
gsf_output_csv_seek (GsfOutput *output,
gsf_off_t offset,
GSeekType whence)
{
GsfOutputCsv *csv = GSF_OUTPUT_CSV (output);
return gsf_output_seek (csv->sink, offset, whence);
}
static gboolean
gsf_output_csv_close (G_GNUC_UNUSED GsfOutput *output)
{
return TRUE;
}
gboolean
gsf_output_csv_write_field (GsfOutputCsv *csv, char const *field, size_t len)
{
gboolean quote;
gboolean ok;
char const *end;
g_return_val_if_fail (GSF_IS_OUTPUT_CSV (csv), FALSE);
g_return_val_if_fail (field != NULL, FALSE);
if (len == (size_t)-1)
len = strlen (field);
end = field + len;
if (csv->fields_on_line && csv->separator_len)
g_string_append_len (csv->buf,
csv->separator,
csv->separator_len);
csv->fields_on_line = TRUE;
switch (csv->quoting_mode) {
default:
case GSF_OUTPUT_CSV_QUOTING_MODE_NEVER:
quote = FALSE;
break;
case GSF_OUTPUT_CSV_QUOTING_MODE_ALWAYS:
quote = TRUE;
break;
case GSF_OUTPUT_CSV_QUOTING_MODE_AUTO: {
char const *p = field;
quote = FALSE;
while (p < end) {
gunichar c = g_utf8_get_char (p);
if (g_utf8_strchr (csv->quoting_triggers, -1, c)) {
quote = TRUE;
break;
}
p = g_utf8_next_char (p);
}
break;
}
}
if (quote && csv->quote_len > 0) {
g_string_append_len (csv->buf,
csv->quote,
csv->quote_len);
while (field < end) {
gunichar c = g_utf8_get_char (field);
if (g_utf8_strchr (csv->quote, -1, c))
g_string_append_len (csv->buf,
csv->quote,
csv->quote_len);
g_string_append_unichar (csv->buf, c);
field = g_utf8_next_char (field);
}
g_string_append_len (csv->buf,
csv->quote,
csv->quote_len);
} else
g_string_append_len (csv->buf, field, len);
ok = gsf_output_write (csv->sink, csv->buf->len, csv->buf->str);
g_string_truncate (csv->buf, 0);
return ok;
}
/* ------------------------------------------------------------------------- */
gboolean
gsf_output_csv_write_eol (GsfOutputCsv *csv)
{
g_return_val_if_fail (GSF_IS_OUTPUT_CSV (csv), FALSE);
csv->fields_on_line = FALSE;
return gsf_output_write (csv->sink, csv->eol_len, csv->eol);
}
/* ------------------------------------------------------------------------- */
GType
gsf_output_csv_quoting_mode_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GEnumValue values[] = {
{ GSF_OUTPUT_CSV_QUOTING_MODE_NEVER, (char *)"GSF_OUTPUT_CSV_QUOTING_MODE_NEVER", (char *)"never" },
{ GSF_OUTPUT_CSV_QUOTING_MODE_AUTO, (char *)"GSF_OUTPUT_CSV_QUOTING_MODE_AUTO", (char *)"auto" },
{ GSF_OUTPUT_CSV_QUOTING_MODE_ALWAYS, (char *)"GSF_OUTPUT_CSV_QUOTING_MODE_ALWAYS", (char *)"always" },
{ 0, NULL, NULL }
};
etype = g_enum_register_static ("GsfOutputCsvQuotingMode", values);
}
return etype;
}
/* ------------------------------------------------------------------------- */
static void
gsf_output_csv_init (GObject *obj)
{
GsfOutputCsv *csv = (GsfOutputCsv *)obj;
csv->quoting_triggers = g_strdup ("");
csv->eol = g_strdup ("\n");
csv->buf = g_string_new (NULL);
}
static void
gsf_output_csv_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GsfOutputCsv *csv = (GsfOutputCsv *)object;
switch (property_id) {
case PROP_SINK:
g_value_set_object (value, csv->sink);
break;
case PROP_QUOTE:
g_value_set_string (value, csv->quote);
break;
case PROP_QUOTING_MODE:
g_value_set_enum (value, csv->quoting_mode);
break;
case PROP_QUOTING_TRIGGERS:
g_value_set_string (value, csv->quoting_triggers);
break;
case PROP_EOL:
g_value_set_string (value, csv->eol);
break;
case PROP_SEPARATOR:
g_value_set_string (value, csv->separator);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_output_csv_set_sink (GsfOutputCsv *csv, GsfOutput *sink)
{
g_return_if_fail (GSF_IS_OUTPUT (sink));
g_object_ref (sink);
if (csv->sink)
g_object_unref (csv->sink);
csv->sink = sink;
}
static void
gsf_output_csv_set_property (GObject *object,
guint property_id,
GValue const *value,
GParamSpec *pspec)
{
GsfOutputCsv *csv = (GsfOutputCsv *)object;
char *scopy;
switch (property_id) {
case PROP_SINK:
gsf_output_csv_set_sink (csv, g_value_get_object (value));
break;
case PROP_QUOTE:
scopy = g_strdup (g_value_get_string (value));
g_free (csv->quote);
csv->quote = scopy;
csv->quote_len = scopy ? strlen (scopy) : 0;
break;
case PROP_QUOTING_MODE:
csv->quoting_mode = g_value_get_enum (value);
break;
case PROP_QUOTING_TRIGGERS:
scopy = g_strdup (g_value_get_string (value));
g_free (csv->quoting_triggers);
csv->quoting_triggers = scopy ? scopy : g_strdup ("");
if (*csv->quoting_triggers)
csv->quoting_mode = GSF_OUTPUT_CSV_QUOTING_MODE_AUTO;
break;
case PROP_EOL:
scopy = g_strdup (g_value_get_string (value));
g_free (csv->eol);
csv->eol = scopy ? scopy : g_strdup ("");
csv->eol_len = strlen (csv->eol);
break;
case PROP_SEPARATOR:
scopy = g_strdup (g_value_get_string (value));
g_free (csv->separator);
csv->separator = scopy;
csv->separator_len = scopy ? strlen (scopy) : 0;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_output_csv_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_output_csv_finalize;
gobject_class->set_property = gsf_output_csv_set_property;
gobject_class->get_property = gsf_output_csv_get_property;
output_class->Write = gsf_output_csv_write;
output_class->Seek = gsf_output_csv_seek;
output_class->Close = gsf_output_csv_close;
g_object_class_install_property
(gobject_class,
PROP_SINK,
g_param_spec_object ("sink", "Sink",
"Where the compressed data is written.",
GSF_OUTPUT_TYPE,
GSF_PARAM_STATIC |
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_QUOTE,
g_param_spec_string ("quote", "Quote",
"The string used for quoting fields.",
"\"",
GSF_PARAM_STATIC |
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_QUOTING_MODE,
g_param_spec_enum ("quoting-mode",
"Quoting Mode",
"When to quote fields.",
GSF_OUTPUT_CSV_QUOTING_MODE_TYPE,
GSF_OUTPUT_CSV_QUOTING_MODE_NEVER,
GSF_PARAM_STATIC |
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_QUOTING_TRIGGERS,
g_param_spec_string ("quoting-triggers", "Quoting Triggers",
"Characters that cause field quoting.",
NULL,
GSF_PARAM_STATIC |
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_SEPARATOR,
g_param_spec_string ("separator", "Separator",
"The field separator.",
",",
GSF_PARAM_STATIC |
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_EOL,
g_param_spec_string ("eol", "eol",
"The end-of-line marker.",
"\n",
GSF_PARAM_STATIC |
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE));
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfOutputCsv, gsf_output_csv,
gsf_output_csv_class_init, gsf_output_csv_init, GSF_OUTPUT_TYPE)

View File

@@ -0,0 +1,70 @@
/*
* gsf-output-csv.h: a GsfOutput to write .csv style files.
*
* Copyright (C) 2005 Morten Welinder (terra@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_CSV_H
#define GSF_OUTPUT_CSV_H
#include "gsf-output.h"
G_BEGIN_DECLS
typedef enum {
GSF_OUTPUT_CSV_QUOTING_MODE_NEVER,
GSF_OUTPUT_CSV_QUOTING_MODE_AUTO,
GSF_OUTPUT_CSV_QUOTING_MODE_ALWAYS
} GsfOutputCsvQuotingMode;
GType gsf_output_csv_quoting_mode_get_type (void);
#define GSF_OUTPUT_CSV_QUOTING_MODE_TYPE (gsf_output_csv_quoting_mode_get_type ())
typedef struct {
GsfOutput output;
GsfOutput *sink;
char *quote;
size_t quote_len;
GsfOutputCsvQuotingMode quoting_mode;
char *quoting_triggers;
char *eol;
size_t eol_len;
char *separator;
size_t separator_len;
gboolean fields_on_line;
GString *buf;
} GsfOutputCsv;
#define GSF_OUTPUT_CSV_TYPE (gsf_output_csv_get_type ())
#define GSF_OUTPUT_CSV(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_CSV_TYPE, GsfOutputCsv))
#define GSF_IS_OUTPUT_CSV(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_CSV_TYPE))
GType gsf_output_csv_get_type (void);
gboolean gsf_output_csv_write_field (GsfOutputCsv *csv,
char const *field,
size_t len);
gboolean gsf_output_csv_write_eol (GsfOutputCsv *csv);
typedef struct {
GsfOutputClass output_class;
} GsfOutputCsvClass;
G_END_DECLS
#endif /* GSF_OUTPUT_CSV_H */

View File

@@ -0,0 +1,401 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-gzip.c: wrapper to compress to gzipped output. See rfc1952.
*
* Copyright (C) 2002-2004 Jon K Hellan (hellan@acm.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-output-gzip.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <zlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
static GObjectClass *parent_class;
struct _GsfOutputGZip {
GsfOutput output;
GsfOutput *sink; /* compressed data */
gboolean raw; /* No header and no trailer. */
z_stream stream;
uLong crc; /* crc32 of uncompressed data */
size_t isize;
guint8 *buf;
size_t buf_size;
};
typedef struct {
GsfOutputClass output_class;
} GsfOutputGZipClass;
enum {
PROP_0,
PROP_RAW,
PROP_SINK
};
/* gzip flag byte */
#define GZIP_ORIGINAL_NAME 0x08 /* the original is stored */
static gboolean
init_gzip (GsfOutputGZip *gzip)
{
int ret;
ret = deflateInit2 (&gzip->stream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL,
Z_DEFAULT_STRATEGY);
if (ret != Z_OK)
return FALSE;
if (!gzip->buf) {
gzip->buf_size = 0x100;
gzip->buf = g_new (guint8, gzip->buf_size);
}
gzip->stream.next_out = gzip->buf;
gzip->stream.avail_out = gzip->buf_size;
return TRUE;
}
static gboolean
gzip_output_header (GsfOutputGZip *gzip)
{
guint8 buf[3 + 1 + 4 + 2];
static guint8 const gzip_signature[] = { 0x1f, 0x8b, 0x08 } ;
time_t mtime = time (NULL);
char const *name = gsf_output_name (gzip->sink);
/* FIXME: What to do about gz extension ... ? */
int nlen = 0; /* name ? strlen (name) : 0; */
gboolean ret;
memset (buf, 0, sizeof buf);
memcpy (buf, gzip_signature, 3);
if (nlen > 0)
buf[3] = GZIP_ORIGINAL_NAME;
GSF_LE_SET_GUINT32 (buf + 4, (guint32) mtime);
buf[9] = 3; /* UNIX */
ret = gsf_output_write (gzip->sink, sizeof buf, buf);
if (ret && name && nlen > 0)
ret = gsf_output_write (gzip->sink, nlen, name);
return ret;
}
/**
* gsf_output_gzip_new :
* @sink : The underlying data source.
* @err : optionally NULL.
*
* Adds a reference to @sink.
*
* Returns a new file or NULL.
**/
GsfOutput *
gsf_output_gzip_new (GsfOutput *sink, GError **err)
{
GsfOutput *output;
const GError *con_err;
g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
output = g_object_new (GSF_OUTPUT_GZIP_TYPE, "sink", sink, NULL);
con_err = gsf_output_error (output);
if (con_err) {
if (err)
*err = g_error_copy (con_err);
g_object_unref (output);
return NULL;
}
return output;
}
static void
gsf_output_gzip_finalize (GObject *obj)
{
GsfOutputGZip *gzip = (GsfOutputGZip *)obj;
if (gzip->sink != NULL) {
g_object_unref (G_OBJECT (gzip->sink));
gzip->sink = NULL;
}
g_free (gzip->buf);
/* FIXME: check for error? */
deflateEnd (&gzip->stream);
parent_class->finalize (obj);
}
static gboolean
gzip_output_block (GsfOutputGZip *gzip)
{
size_t num_bytes = gzip->buf_size - gzip->stream.avail_out;
if (!gsf_output_write (gzip->sink, num_bytes, gzip->buf)) {
gsf_output_set_error (GSF_OUTPUT (gzip), 0,
"Failed to write");
return FALSE;
}
gzip->stream.next_out = gzip->buf;
gzip->stream.avail_out = gzip->buf_size;
return TRUE;
}
static gboolean
gzip_flush (GsfOutputGZip *gzip)
{
int zret;
do {
zret = deflate (&gzip->stream, Z_FINISH);
if (zret == Z_OK) {
/* In this case Z_OK means more buffer space
needed */
if (!gzip_output_block (gzip))
return FALSE;
}
} while (zret == Z_OK);
if (zret != Z_STREAM_END) {
gsf_output_set_error (GSF_OUTPUT (gzip), 0,
"Unexpected compression failure");
g_warning ("Unexpected error code %d from zlib during compression.",
zret);
return FALSE;
}
if (!gzip_output_block (gzip))
return FALSE;
return TRUE;
}
static gboolean
gsf_output_gzip_write (GsfOutput *output,
size_t num_bytes, guint8 const *data)
{
GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (output);
g_return_val_if_fail (data, FALSE);
gzip->stream.next_in = (unsigned char *) data;
gzip->stream.avail_in = num_bytes;
while (gzip->stream.avail_in > 0) {
int zret;
if (gzip->stream.avail_out == 0) {
if (!gzip_output_block (gzip))
return FALSE;
}
zret = deflate (&gzip->stream, Z_NO_FLUSH);
if (zret != Z_OK) {
gsf_output_set_error (output, 0,
"Unexpected compression failure");
g_warning ("Unexpected error code %d from zlib during compression.",
zret);
return FALSE;
}
}
gzip->crc = crc32 (gzip->crc, data, num_bytes);
gzip->isize += num_bytes;
if (gzip->stream.avail_out == 0) {
if (!gzip_output_block (gzip))
return FALSE;
}
return TRUE;
}
static gboolean
gsf_output_gzip_seek (G_GNUC_UNUSED GsfOutput *output,
G_GNUC_UNUSED gsf_off_t offset,
G_GNUC_UNUSED GSeekType whence)
{
return FALSE;
}
static gboolean
gsf_output_gzip_close (GsfOutput *output)
{
if (!gsf_output_error (output)) {
GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (output);
if (!gzip_flush (gzip))
return FALSE;
if (!gzip->raw) {
guint8 buf[8];
GSF_LE_SET_GUINT32 (buf, gzip->crc);
GSF_LE_SET_GUINT32 (buf + 4, gzip->isize);
if (!gsf_output_write (gzip->sink, 8, buf))
return FALSE;
}
}
return TRUE;
}
static void
gsf_output_gzip_init (GObject *obj)
{
GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (obj);
gzip->sink = NULL;
gzip->stream.zalloc = (alloc_func)0;
gzip->stream.zfree = (free_func)0;
gzip->stream.opaque = (voidpf)0;
gzip->stream.next_in = Z_NULL;
gzip->stream.next_out = Z_NULL;
gzip->stream.avail_in = gzip->stream.avail_out = 0;
gzip->crc = crc32 (0L, Z_NULL, 0);
gzip->isize = 0;
gzip->buf = NULL;
gzip->buf_size = 0;
}
static void
gsf_output_gzip_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GsfOutputGZip *gzip = (GsfOutputGZip *)object;
switch (property_id) {
case PROP_RAW:
g_value_set_boolean (value, gzip->raw);
break;
case PROP_SINK:
g_value_set_object (value, gzip->sink);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_output_gzip_set_sink (GsfOutputGZip *gzip, GsfOutput *sink)
{
if (sink)
g_object_ref (GSF_OUTPUT (sink));
if (gzip->sink)
g_object_unref (gzip->sink);
gzip->sink = sink;
}
static void
gsf_output_gzip_set_property (GObject *object,
guint property_id,
GValue const *value,
GParamSpec *pspec)
{
GsfOutputGZip *gzip = (GsfOutputGZip *)object;
switch (property_id) {
case PROP_RAW:
gzip->raw = g_value_get_boolean (value);
break;
case PROP_SINK:
gsf_output_gzip_set_sink (gzip, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static GObject*
gsf_output_gzip_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
GsfOutputGZip *gzip;
gzip = (GsfOutputGZip *)(parent_class->constructor (type,
n_construct_properties,
construct_params));
if (!gzip->sink)
gsf_output_set_error (GSF_OUTPUT (gzip),
0,
"NULL sink");
else if (!init_gzip (gzip))
gsf_output_set_error (GSF_OUTPUT (gzip),
0,
"Failed to initialize zlib structure");
else if (!gzip->raw && !gzip_output_header (gzip))
gsf_output_set_error (GSF_OUTPUT (gzip),
0,
"Failed to write gzip header");
return (GObject *)gzip;
}
static void
gsf_output_gzip_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
gobject_class->constructor = gsf_output_gzip_constructor;
gobject_class->finalize = gsf_output_gzip_finalize;
gobject_class->set_property = gsf_output_gzip_set_property;
gobject_class->get_property = gsf_output_gzip_get_property;
output_class->Write = gsf_output_gzip_write;
output_class->Seek = gsf_output_gzip_seek;
output_class->Close = gsf_output_gzip_close;
g_object_class_install_property
(gobject_class,
PROP_RAW,
g_param_spec_boolean ("raw", "Raw",
"Whether to write compressed data with no header/tailer.",
FALSE,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(gobject_class,
PROP_SINK,
g_param_spec_object ("sink", "Sink",
"Where the compressed data is written.",
GSF_OUTPUT_TYPE,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfOutputGZip, gsf_output_gzip,
gsf_output_gzip_class_init, gsf_output_gzip_init, GSF_OUTPUT_TYPE)

View File

@@ -0,0 +1,40 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-gzip.h: wrapper to compress to gzipped output
*
* Copyright (C) 2002-2004 Jon K Hellan (hellan@acm.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_GZIP_H
#define GSF_OUTPUT_GZIP_H
#include "gsf-output.h"
G_BEGIN_DECLS
#define GSF_OUTPUT_GZIP_TYPE (gsf_output_gzip_get_type ())
#define GSF_OUTPUT_GZIP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_GZIP_TYPE, GsfOutputGZip))
#define GSF_IS_OUTPUT_GZIP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_GZIP_TYPE))
typedef struct _GsfOutputGZip GsfOutputGZip;
GType gsf_output_gzip_get_type (void);
GsfOutput *gsf_output_gzip_new (GsfOutput *sink, GError **err);
G_END_DECLS
#endif /* GSF_OUTPUT_GZIP_H */

View File

@@ -0,0 +1,320 @@
/*
* gsf-output-iconv.c: wrapper to convert character sets.
*
* Copyright (C) 2005 Morten Welinder (terra@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-output-iconv.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#include <glib/gconvert.h>
#include <string.h>
#define BUF_SIZE 0x400
static GObjectClass *parent_class;
struct _GsfOutputIconv {
GsfOutput output;
GsfOutput *sink;
char *input_charset;
char *output_charset;
char *fallback;
guint8 *buf;
size_t buf_len;
};
enum {
PROP_0,
PROP_SINK,
PROP_INPUT_CHARSET,
PROP_OUTPUT_CHARSET,
PROP_FALLBACK
};
/**
* gsf_output_iconv_new :
* @sink : The underlying data source.
* @dst : The target character set.
* @src : The source character set.
*
* Adds a reference to @sink.
*
* Returns a new GsfOutput object or NULL.
**/
GsfOutput *
gsf_output_iconv_new (GsfOutput *sink, char const *dst, char const *src)
{
GError *error = NULL;
g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
if (!dst) dst = "UTF-8";
if (!src) src = "UTF-8";
g_free (g_convert ("", 0, dst, src, NULL, NULL, &error));
if (error) {
g_error_free (error);
return NULL;
}
return g_object_new (GSF_OUTPUT_ICONV_TYPE,
"sink", sink,
"input-charset", src,
"output-charset", dst,
NULL);
}
static void
gsf_output_iconv_finalize (GObject *obj)
{
GsfOutputIconv *ic = (GsfOutputIconv *)obj;
if (ic->sink != NULL)
g_object_unref (G_OBJECT (ic->sink));
g_free (ic->input_charset);
g_free (ic->output_charset);
g_free (ic->buf);
parent_class->finalize (obj);
}
static gboolean
iconv_flush (GsfOutputIconv *ic, gboolean must_empty)
{
if (gsf_output_error (GSF_OUTPUT (ic)))
return FALSE;
if (ic->buf_len > 0) {
gsize bytes_read, bytes_written;
gboolean ok;
char *data = g_convert_with_fallback (ic->buf, ic->buf_len,
ic->output_charset,
ic->input_charset,
ic->fallback,
&bytes_read,
&bytes_written,
NULL);
if (data == NULL || bytes_read <= 0) {
gsf_output_set_error (GSF_OUTPUT (ic),
0,
"Failed to convert string");
ok = FALSE;
} else {
ic->buf_len -= bytes_read;
if (ic->buf_len)
g_memmove (ic->buf, ic->buf + ic->buf_len, ic->buf_len);
ok = gsf_output_write (ic->sink, bytes_written, data);
if (!ok) {
gsf_output_set_error (GSF_OUTPUT (ic),
0,
"Failed to write");
}
}
g_free (data);
return ok && (!must_empty || ic->buf_len == 0);
} else
return TRUE;
}
static gboolean
gsf_output_iconv_write (GsfOutput *output,
size_t num_bytes, guint8 const *data)
{
GsfOutputIconv *ic = GSF_OUTPUT_ICONV (output);
g_return_val_if_fail (data, FALSE);
while (num_bytes > 0) {
if (gsf_output_error (output))
return FALSE;
if (ic->buf_len == BUF_SIZE)
iconv_flush (ic, FALSE);
else {
size_t count = MIN (BUF_SIZE - ic->buf_len, num_bytes);
memcpy (ic->buf + ic->buf_len, data, count);
ic->buf_len += count;
num_bytes -= count;
data += count;
}
}
return TRUE;
}
static gboolean
gsf_output_iconv_seek (G_GNUC_UNUSED GsfOutput *output,
G_GNUC_UNUSED gsf_off_t offset,
G_GNUC_UNUSED GSeekType whence)
{
return FALSE;
}
static gboolean
gsf_output_iconv_close (GsfOutput *output)
{
if (!gsf_output_error (output)) {
GsfOutputIconv *ic = GSF_OUTPUT_ICONV (output);
if (!iconv_flush (ic, TRUE))
return FALSE;
}
return TRUE;
}
static void
gsf_output_iconv_init (GObject *obj)
{
GsfOutputIconv *ic = GSF_OUTPUT_ICONV (obj);
ic->buf = g_malloc (BUF_SIZE);
ic->buf_len = 0;
}
static void
gsf_output_iconv_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GsfOutputIconv *ic = (GsfOutputIconv *)object;
switch (property_id) {
case PROP_SINK:
g_value_set_object (value, ic->sink);
break;
case PROP_INPUT_CHARSET:
g_value_set_string (value, ic->input_charset);
break;
case PROP_OUTPUT_CHARSET:
g_value_set_string (value, ic->output_charset);
break;
case PROP_FALLBACK:
g_value_set_string (value, ic->fallback);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_output_iconv_set_sink (GsfOutputIconv *ic, GsfOutput *sink)
{
g_return_if_fail (GSF_IS_OUTPUT (sink));
g_object_ref (sink);
if (ic->sink)
g_object_unref (ic->sink);
ic->sink = sink;
}
static void
gsf_output_iconv_set_property (GObject *object,
guint property_id,
GValue const *value,
GParamSpec *pspec)
{
GsfOutputIconv *ic = (GsfOutputIconv *)object;
char *scopy;
switch (property_id) {
case PROP_SINK:
gsf_output_iconv_set_sink (ic, g_value_get_object (value));
break;
case PROP_INPUT_CHARSET:
ic->input_charset = g_strdup (g_value_get_string (value));
break;
case PROP_OUTPUT_CHARSET:
ic->output_charset = g_strdup (g_value_get_string (value));
break;
case PROP_FALLBACK:
scopy = g_strdup (g_value_get_string (value));
g_free (ic->fallback);
ic->fallback = scopy;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_output_iconv_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_output_iconv_finalize;
gobject_class->set_property = gsf_output_iconv_set_property;
gobject_class->get_property = gsf_output_iconv_get_property;
output_class->Write = gsf_output_iconv_write;
output_class->Seek = gsf_output_iconv_seek;
output_class->Close = gsf_output_iconv_close;
g_object_class_install_property
(gobject_class,
PROP_SINK,
g_param_spec_object ("sink", "Sink",
"Where the converted data is written.",
GSF_OUTPUT_TYPE,
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(gobject_class,
PROP_INPUT_CHARSET,
g_param_spec_string ("input-charset", "Input Charset",
"The character set to convert from.",
"UTF-8",
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(gobject_class,
PROP_OUTPUT_CHARSET,
g_param_spec_string ("output-charset", "Output Charset",
"The character set to convert to.",
"UTF-8",
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
/**
* GsfOutputIconv:fallback:
*
* Either NULL or a UTF-8 string (representable in the target encoding)
* to convert and output in place of characters that cannot be represented
* in the target encoding. NULL means use \u1234 or \U12345678 format.
*/
g_object_class_install_property
(gobject_class,
PROP_FALLBACK,
g_param_spec_string ("fallback", "Fallback",
"The string to use for invalid characters.",
NULL,
GSF_PARAM_STATIC |
G_PARAM_READWRITE));
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfOutputIconv, gsf_output_iconv,
gsf_output_iconv_class_init, gsf_output_iconv_init, GSF_OUTPUT_TYPE)

View File

@@ -0,0 +1,43 @@
/*
* gsf-output-iconv.h: wrapper to convert character sets.
*
* Copyright (C) 2005 Morten Welinder (terra@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_ICONV_H
#define GSF_OUTPUT_ICONV_H
#include "gsf-output.h"
G_BEGIN_DECLS
typedef struct {
GsfOutputClass output_class;
} GsfOutputIconvClass;
#define GSF_OUTPUT_ICONV_TYPE (gsf_output_iconv_get_type ())
#define GSF_OUTPUT_ICONV(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_ICONV_TYPE, GsfOutputIconv))
#define GSF_IS_OUTPUT_ICONV(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_ICONV_TYPE))
typedef struct _GsfOutputIconv GsfOutputIconv;
GType gsf_output_iconv_get_type (void);
GsfOutput *gsf_output_iconv_new (GsfOutput *sink, char const *dst, char const *src);
G_END_DECLS
#endif /* GSF_OUTPUT_ICONV_H */

View File

@@ -0,0 +1,38 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-impl.h: interface for storing data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_IMPL_H
#define GSF_OUTPUT_IMPL_H
#include <gsf/gsf.h>
#include <gsf/gsf-output.h>
#include <glib-object.h>
G_BEGIN_DECLS
/* protected */
gboolean gsf_output_set_name (GsfOutput *output, char const *name);
gboolean gsf_output_set_name_from_filename (GsfOutput *output, char const *filename);
gboolean gsf_output_set_container (GsfOutput *output, GsfOutfile *container);
G_END_DECLS
#endif /* GSF_OUTPUT_IMPL_H */

View File

@@ -0,0 +1,130 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-iochannel.c
*
* Copyright (C) 2002-2004 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-output-iochannel.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-impl-utils.h>
static GsfOutputClass *parent_class;
struct _GsfOutputIOChannel {
GsfOutput output;
GIOChannel * channel;
};
typedef struct {
GsfOutputClass output_class;
} GsfOutputIOChannelClass;
/**
* gsf_output_iochannel_new :
* @channel: A #GIOChannel
*
* Returns a new file or NULL.
**/
GsfOutput *
gsf_output_iochannel_new (GIOChannel *channel)
{
GsfOutputIOChannel *output = NULL;
g_return_val_if_fail (channel != NULL, NULL);
output = g_object_new (GSF_OUTPUT_IOCHANNEL_TYPE, NULL);
output->channel = channel;
return GSF_OUTPUT (output);
}
static gboolean
gsf_output_iochannel_close (GsfOutput *output)
{
g_io_channel_shutdown (GSF_OUTPUT_IOCHANNEL (output)->channel, TRUE, NULL);
if (parent_class->Close)
parent_class->Close (output);
return TRUE;
}
static void
gsf_output_iochannel_finalize (GObject *obj)
{
g_io_channel_unref (GSF_OUTPUT_IOCHANNEL (obj)->channel);
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static gboolean
gsf_output_iochannel_seek (GsfOutput *output, gsf_off_t offset,
GSeekType whence)
{
GsfOutputIOChannel *io = GSF_OUTPUT_IOCHANNEL (output);
GIOStatus status = G_IO_STATUS_NORMAL;
status = g_io_channel_seek_position (io->channel, offset, whence, NULL);
if (status == G_IO_STATUS_NORMAL)
return TRUE;
gsf_output_set_error (output, status, " ");
return FALSE;
}
static gboolean
gsf_output_iochannel_write (GsfOutput *output,
size_t num_bytes,
guint8 const *buffer)
{
GsfOutputIOChannel *io = GSF_OUTPUT_IOCHANNEL (output);
GIOStatus status = G_IO_STATUS_NORMAL;
size_t bytes_written = 0, total_written = 0;
g_return_val_if_fail (io != NULL, FALSE);
while ((status == G_IO_STATUS_NORMAL) && (total_written < num_bytes)) {
status = g_io_channel_write_chars (io->channel, (const gchar *)(buffer + total_written),
num_bytes - total_written, &bytes_written, NULL);
total_written += bytes_written;
}
return (status == G_IO_STATUS_NORMAL && total_written == num_bytes);
}
static void
gsf_output_iochannel_init (GObject *obj)
{
GsfOutputIOChannel *io = GSF_OUTPUT_IOCHANNEL (obj);
io->channel = NULL;
}
static void
gsf_output_iochannel_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_output_iochannel_finalize;
output_class->Close = gsf_output_iochannel_close;
output_class->Seek = gsf_output_iochannel_seek;
output_class->Write = gsf_output_iochannel_write;
parent_class = GSF_OUTPUT_CLASS (g_type_class_peek_parent (gobject_class));
}
GSF_CLASS (GsfOutputIOChannel, gsf_output_iochannel,
gsf_output_iochannel_class_init, gsf_output_iochannel_init, GSF_OUTPUT_TYPE)

View File

@@ -0,0 +1,40 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-iochannel.h
*
* Copyright (C) 2002-2004 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_IOCHANNEL_H
#define GSF_OUTPUT_IOCHANNEL_H
#include "gsf-output.h"
G_BEGIN_DECLS
#define GSF_OUTPUT_IOCHANNEL_TYPE (gsf_output_iochannel_get_type ())
#define GSF_OUTPUT_IOCHANNEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_IOCHANNEL_TYPE, GsfOutputIOChannel))
#define GSF_IS_OUTPUT_IOCHANNEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_IOCHANNEL_TYPE))
typedef struct _GsfOutputIOChannel GsfOutputIOChannel;
GType gsf_output_iochannel_get_type (void);
GsfOutput *gsf_output_iochannel_new (GIOChannel * channel);
G_END_DECLS
#endif /* GSF_OUTPUT_IOCHANNEL_H */

View File

@@ -0,0 +1,200 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-memory.c:
*
* Copyright (C) 2002-2004 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-output-memory.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <string.h>
#define MIN_BLOCK 512
#define MAX_STEP (MIN_BLOCK * 128)
static GsfOutputClass *parent_class;
struct _GsfOutputMemory {
GsfOutput output;
guint8 *buffer;
size_t capacity;
};
typedef struct {
GsfOutputClass output_class;
} GsfOutputMemoryClass;
/**
* gsf_output_memory_new :
*
* Returns a new file or NULL.
**/
GsfOutput *
gsf_output_memory_new (void)
{
return g_object_new (GSF_OUTPUT_MEMORY_TYPE, NULL);
}
static gboolean
gsf_output_memory_close (GsfOutput *output)
{
return (parent_class->Close == NULL) ||
parent_class->Close (output);
}
static void
gsf_output_memory_finalize (GObject *obj)
{
GsfOutputMemory *mem = GSF_OUTPUT_MEMORY (obj);
g_free (mem->buffer);
mem->buffer = NULL;
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static gboolean
gsf_output_memory_seek (G_GNUC_UNUSED GsfOutput *output,
G_GNUC_UNUSED gsf_off_t offset,
G_GNUC_UNUSED GSeekType whence)
{
/* let parent implementation handle maneuvering cur_offset */
return TRUE;
}
static gboolean
gsf_output_memory_expand (GsfOutputMemory *mem, gsf_off_t needed)
{
gsf_off_t capacity = MAX (mem->capacity, MIN_BLOCK);
gsize lcapacity;
/* If we need >= MAX_STEP, align to a next multiple of MAX_STEP.
* Since MAX_STEP is probably a power of two, this computation
* should reduce to "dec, shr, inc, shl", which is probably
* quicker then branching.
*/
if (needed < MAX_STEP)
while (capacity < needed)
capacity *= 2;
else
capacity = ((needed - 1) / MAX_STEP + 1) * MAX_STEP;
/* Check for overflow: g_renew() casts its parameters to gsize. */
lcapacity = capacity;
if ((gsf_off_t) lcapacity != capacity || capacity < 0) {
g_warning ("overflow in gsf_output_memory_expand");
return FALSE;
}
mem->buffer = g_renew (guint8, mem->buffer, lcapacity);
mem->capacity = capacity;
return TRUE;
}
static gboolean
gsf_output_memory_write (GsfOutput *output,
size_t num_bytes,
guint8 const *buffer)
{
GsfOutputMemory *mem = GSF_OUTPUT_MEMORY (output);
g_return_val_if_fail (mem != NULL, FALSE);
if (!mem->buffer) {
mem->buffer = g_new (guint8, MIN_BLOCK);
mem->capacity = MIN_BLOCK;
}
if (num_bytes + output->cur_offset > mem->capacity) {
if (!gsf_output_memory_expand (mem, output->cur_offset + num_bytes))
return FALSE;
}
memcpy (mem->buffer + output->cur_offset, buffer, num_bytes);
return TRUE;
}
static gsf_off_t gsf_output_memory_vprintf (GsfOutput *output,
char const *format, va_list args) G_GNUC_PRINTF (2, 0);
static gsf_off_t
gsf_output_memory_vprintf (GsfOutput *output, char const *format, va_list args)
{
GsfOutputMemory *mem = (GsfOutputMemory *)output;
if (mem->buffer) {
va_list args2;
gsf_off_t len;
/*
* We need to make a copy as args will become unusable after
* the g_vsnprintf call.
*/
G_VA_COPY (args2, args);
len =
g_vsnprintf (mem->buffer + output->cur_offset,
mem->capacity - output->cur_offset,
format, args);
if (len < mem->capacity - output->cur_offset)
return len; /* There was sufficient space */
return parent_class->Vprintf (output, format, args2);
}
return parent_class->Vprintf (output, format, args);
}
static void
gsf_output_memory_init (GObject *obj)
{
GsfOutputMemory *mem = GSF_OUTPUT_MEMORY (obj);
mem->buffer = NULL;
mem->capacity = 0;
}
static void
gsf_output_memory_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_output_memory_finalize;
output_class->Close = gsf_output_memory_close;
output_class->Seek = gsf_output_memory_seek;
output_class->Write = gsf_output_memory_write;
output_class->Vprintf = gsf_output_memory_vprintf;
parent_class = GSF_OUTPUT_CLASS (g_type_class_peek_parent (gobject_class));
}
/**
* gsf_output_memory_get_bytes :
* @mem : the output device.
*
* Returns: The data that has been written to @mem, or %null
**/
const guint8 *
gsf_output_memory_get_bytes (GsfOutputMemory * mem)
{
g_return_val_if_fail (mem != NULL, NULL);
return mem->buffer;
}
GSF_CLASS (GsfOutputMemory, gsf_output_memory,
gsf_output_memory_class_init, gsf_output_memory_init, GSF_OUTPUT_TYPE)

View File

@@ -0,0 +1,41 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-memory.h
*
* Copyright (C) 2002-2004 Dom Lachowicz (cinamod@hotmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_MEMORY_H
#define GSF_OUTPUT_MEMORY_H
#include "gsf-output.h"
G_BEGIN_DECLS
#define GSF_OUTPUT_MEMORY_TYPE (gsf_output_memory_get_type ())
#define GSF_OUTPUT_MEMORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_MEMORY_TYPE, GsfOutputMemory))
#define GSF_IS_OUTPUT_MEMORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_MEMORY_TYPE))
typedef struct _GsfOutputMemory GsfOutputMemory;
GType gsf_output_memory_get_type (void);
GsfOutput *gsf_output_memory_new (void);
const guint8* gsf_output_memory_get_bytes (GsfOutputMemory * mem);
G_END_DECLS
#endif /* GSF_OUTPUT_MEMORY_H */

View File

@@ -0,0 +1,574 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-stdio.c: stdio based output
*
* Copyright (C) 2002-2005 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-output-stdio.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-utils.h>
#ifdef HAVE_GLIB26
#include <glib/gstdio.h>
#else
#include "glib24_26-compat.h"
#endif // HAVE_GLIB26
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef G_OS_WIN32
#include <wchar.h>
#include <direct.h>
#include <glib/gwin32.h>
#ifdef HAVE_IO_H
#include <io.h>
#endif
#endif /* G_OS_WIN32 */
#ifndef W_OK
#define W_OK 2
#endif
static GObjectClass *parent_class;
struct _GsfOutputStdio {
GsfOutput output;
FILE *file;
char *real_filename, *temp_filename;
gboolean create_backup_copy, keep_open;
struct stat st;
};
typedef struct {
GsfOutputClass output_class;
} GsfOutputStdioClass;
static int
rename_wrapper (char const *oldfilename, char const *newfilename)
{
int result = g_rename (oldfilename, newfilename);
#ifdef G_OS_WIN32
if (result) {
/* Win32's rename does not unlink the target. */
(void)g_unlink (newfilename);
result = g_rename (oldfilename, newfilename);
}
#endif
return result;
}
static int
chmod_wrapper (const char *filename, mode_t mode)
{
#ifdef HAVE_G_CHMOD
return g_chmod (filename, mode);
#else
return chmod (filename, mode);
#endif
}
static int
access_wrapper (char const *filename, int what)
{
#ifdef HAVE_G_ACCESS
return g_access (filename, what);
#else
return access (filename, what);
#endif
}
#define GSF_MAX_LINK_LEVEL 256
/* Calls g_file_read_link() until we find a real filename. */
static char *
follow_symlinks (char const *filename, GError **error)
{
gchar *followed_filename, *link;
gint link_count = 0;
g_return_val_if_fail (filename != NULL, NULL);
followed_filename = g_strdup (filename);
while ((link = g_file_read_link (followed_filename, NULL)) != NULL &&
++link_count <= GSF_MAX_LINK_LEVEL) {
if (g_path_is_absolute (link)) {
g_free (followed_filename);
followed_filename = link;
} else {
/* If the linkname is not an absolute path name, append
* it to the directory name of the followed filename. E.g.
* we may have /foo/bar/baz.lnk -> eek.txt, which really
* is /foo/bar/eek.txt. */
gchar *dir = g_path_get_dirname (followed_filename);
g_free (followed_filename);
followed_filename = g_build_filename (dir, link, NULL);
g_free (dir);
g_free (link);
}
}
if (link == NULL)
return followed_filename;
/* Too many symlinks */
if (error != NULL) {
#ifdef ELOOP
int err = ELOOP;
#else
/* We have links, but not ELOOP. Very strange. */
int err = EINVAL;
#endif
*error = g_error_new_literal (gsf_output_error_id (), err,
g_strerror (err));
}
g_free (followed_filename);
return NULL;
}
static gboolean
close_file_helper (GsfOutputStdio *stdio, gboolean seterr)
{
gboolean res = (0 == fclose (stdio->file));
stdio->file = NULL;
if (!res && seterr)
gsf_output_set_error (GSF_OUTPUT (stdio), errno,
"Failed to close file: %s",
g_strerror (errno));
return res;
}
static gboolean
unlink_file_helper (GsfOutputStdio *stdio)
{
if (!stdio->temp_filename)
return TRUE;
if (g_unlink (stdio->temp_filename) == 0) {
g_free (stdio->temp_filename);
stdio->temp_filename = NULL;
return TRUE;
}
return FALSE;
}
static gboolean
gsf_output_stdio_close (GsfOutput *output)
{
GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (output);
gboolean res;
char *backup_filename = NULL;
if (stdio->file == NULL)
return FALSE;
if (gsf_output_error (output)) {
res = TRUE;
if (!stdio->keep_open && !close_file_helper (stdio, FALSE))
res = FALSE;
if (!unlink_file_helper (stdio))
res = FALSE;
return res;
}
if (stdio->keep_open) {
gboolean res = (0 == fflush (stdio->file));
if (!res)
gsf_output_set_error (output, errno,
"Failed to flush.");
stdio->file = NULL;
return res;
}
res = close_file_helper (stdio, TRUE);
/* short circuit our when dealing with raw FILE */
if (!stdio->real_filename)
return res;
if (!res) {
unlink_file_helper (stdio);
return FALSE;
}
/* Move the original file to a backup */
if (stdio->create_backup_copy) {
gint result;
backup_filename = g_strconcat (stdio->real_filename, ".bak", NULL);
result = rename_wrapper (stdio->real_filename, backup_filename);
if (result != 0) {
char *utf8name = g_filename_display_name (backup_filename);
gsf_output_set_error (output, errno,
"Could not backup the original as %s.",
utf8name);
g_free (utf8name);
g_free (backup_filename);
g_unlink (stdio->temp_filename);
return FALSE;
}
}
/* Move the temp file to the original file */
if (rename_wrapper (stdio->temp_filename, stdio->real_filename) != 0) {
gint saved_errno = errno;
if (backup_filename != NULL &&
rename_wrapper (backup_filename, stdio->real_filename) != 0)
saved_errno = errno;
res = gsf_output_set_error (output,
saved_errno,
g_strerror (saved_errno));
} else {
/* Restore permissions. There is not much error checking we
* can do here, I'm afraid. The final data is saved anyways.
* Note the order: mode, uid+gid, gid, uid, mode.
*/
chmod_wrapper (stdio->real_filename, stdio->st.st_mode);
#ifdef HAVE_CHOWN
if (chown (stdio->real_filename,
stdio->st.st_uid,
stdio->st.st_gid)) {
/* We cannot set both. Maybe we can set one. */
chown (stdio->real_filename, -1, stdio->st.st_gid);
chown (stdio->real_filename, stdio->st.st_uid, -1);
}
chmod_wrapper (stdio->real_filename, stdio->st.st_mode);
#endif
}
g_free (backup_filename);
return res;
}
static void
gsf_output_stdio_finalize (GObject *obj)
{
GsfOutput *output = (GsfOutput *)obj;
GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (output);
if (!gsf_output_is_closed (output))
gsf_output_close (output);
g_free (stdio->real_filename);
stdio->real_filename = NULL;
g_free (stdio->temp_filename);
stdio->temp_filename = NULL;
parent_class->finalize (obj);
}
static gboolean
gsf_output_stdio_seek (GsfOutput *output, gsf_off_t offset, GSeekType whence)
{
GsfOutputStdio const *stdio = GSF_OUTPUT_STDIO (output);
int stdio_whence = 0; /* make compiler shut up */
#ifndef HAVE_FSEEKO
long loffset;
#else
off_t loffset;
#endif
g_return_val_if_fail (stdio->file != NULL,
gsf_output_set_error (output, 0, "missing file"));
loffset = offset;
if ((gsf_off_t) loffset != offset) { /* Check for overflow */
#ifdef HAVE_FSEEKO
g_warning ("offset too large for fseeko");
return gsf_output_set_error (output, 0, "offset too large for fseeko");
#else
g_warning ("offset too large for fseek");
return gsf_output_set_error (output, 0, "offset too large for fseek");
#endif
}
switch (whence) {
default : ; /*checked in GsfOutput wrapper */
case G_SEEK_SET : stdio_whence = SEEK_SET; break;
case G_SEEK_CUR : stdio_whence = SEEK_CUR; break;
case G_SEEK_END : stdio_whence = SEEK_END; break;
}
errno = 0;
#ifdef HAVE_FSEEKO
if (0 == fseeko (stdio->file, loffset, stdio_whence))
return TRUE;
#else
if (0 == fseek (stdio->file, loffset, stdio_whence))
return TRUE;
#endif
return gsf_output_set_error (output, errno, g_strerror (errno));
}
static gboolean
gsf_output_stdio_write (GsfOutput *output,
size_t num_bytes,
guint8 const *buffer)
{
GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (output);
size_t written, remaining;
g_return_val_if_fail (stdio != NULL, FALSE);
g_return_val_if_fail (stdio->file != NULL, FALSE);
remaining = num_bytes;
while (remaining > 0) {
written = fwrite (buffer + (num_bytes - remaining), 1,
remaining, stdio->file);
if ((written < remaining) && ferror (stdio->file) != 0)
return gsf_output_set_error (output, errno, g_strerror (errno));
remaining -= written;
}
return TRUE;
}
static gsf_off_t gsf_output_stdio_vprintf (GsfOutput *output,
char const *fmt, va_list args) G_GNUC_PRINTF (2, 0);
static gsf_off_t
gsf_output_stdio_vprintf (GsfOutput *output, char const *fmt, va_list args)
{
return vfprintf (((GsfOutputStdio *)output)->file, fmt, args);
}
static void
gsf_output_stdio_init (GObject *obj)
{
GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (obj);
stdio->file = NULL;
stdio->create_backup_copy = FALSE;
stdio->keep_open = FALSE;
}
static void
gsf_output_stdio_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
gobject_class->finalize = gsf_output_stdio_finalize;
output_class->Close = gsf_output_stdio_close;
output_class->Seek = gsf_output_stdio_seek;
output_class->Write = gsf_output_stdio_write;
output_class->Vprintf = gsf_output_stdio_vprintf;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfOutputStdio, gsf_output_stdio,
gsf_output_stdio_class_init, gsf_output_stdio_init, GSF_OUTPUT_TYPE)
GsfOutput *
gsf_output_stdio_new_valist (char const *filename, GError **err,
char const *first_property_name,
va_list var_args)
{
GsfOutputStdio *stdio;
FILE *file = NULL;
char *dirname = NULL;
char *temp_filename = NULL;
char *real_filename = follow_symlinks (filename, err);
int fd;
mode_t saved_umask;
struct stat st;
gboolean fixup_mode = FALSE;
if (real_filename == NULL)
goto failure;
/* Get the directory in which the real filename lives */
dirname = g_path_get_dirname (real_filename);
if (g_stat (real_filename, &st) == 0) {
if (!S_ISREG (st.st_mode)) {
if (err != NULL) {
char *dname = g_filename_display_name
(real_filename);
*err = g_error_new (gsf_output_error_id (), 0,
"%s: Is not a regular file",
dname);
g_free (dname);
}
goto failure;
}
/* FIXME? Race conditions en masse. */
if (access_wrapper (real_filename, W_OK) == -1) {
if (err != NULL) {
int save_errno = errno;
char *dname = g_filename_display_name
(real_filename);
*err = g_error_new
(gsf_output_error_id (), errno,
"%s: %s",
dname, g_strerror (save_errno));
g_free (dname);
}
goto failure;
}
} else {
/*
* File does not exist. Compute the permissions and uid/gid
* that we will use for the newly-created file.
*/
memset (&st, 0, sizeof (st));
/* Use default permissions */
st.st_mode = 0666; fixup_mode = TRUE;
#ifdef HAVE_CHOWN
{
struct stat dir_st;
st.st_uid = getuid ();
if (g_stat (dirname, &dir_st) == 0 &&
S_ISDIR (dir_st.st_mode) &&
(dir_st.st_mode & S_ISGID))
st.st_gid = dir_st.st_gid;
else
st.st_gid = getgid ();
}
#endif
}
/* Save to a temporary file. We set the umask because some (buggy)
* implementations of mkstemp() use permissions 0666 and we want 0600.
*/
temp_filename = g_build_filename (dirname, ".gsf-save-XXXXXX", NULL);
/* Oh, joy. What about threads? --MW */
saved_umask = umask (0077);
fd = g_mkstemp (temp_filename); /* this modifies temp_filename to the used name */
umask (saved_umask);
if (fixup_mode)
st.st_mode &= ~saved_umask;
if (fd < 0 || NULL == (file = fdopen (fd, "wb"))) {
if (err != NULL) {
int save_errno = errno;
char *dname = g_filename_display_name
(temp_filename);
*err = g_error_new
(gsf_output_error_id (), errno,
"%s: %s",
dname, g_strerror (save_errno));
g_free (dname);
}
goto failure;
}
stdio = (GsfOutputStdio *)g_object_new_valist (GSF_OUTPUT_STDIO_TYPE,
first_property_name, var_args);
stdio->file = file;
stdio->st = st;
stdio->create_backup_copy = FALSE;
stdio->real_filename = real_filename;
stdio->temp_filename = temp_filename;
gsf_output_set_name_from_filename (GSF_OUTPUT (stdio), filename);
g_free (dirname);
return GSF_OUTPUT (stdio);
failure:
g_free (temp_filename);
g_free (real_filename);
g_free (dirname);
return NULL;
}
/**
* gsf_output_stdio_new_full :
* @filename : name of file to create or replace.
* @err : optionally NULL.
* @first_property_name : NULL terminated list of properties
* @Varargs :
*
* Returns a new file or NULL.
**/
GsfOutput *
gsf_output_stdio_new_full (char const *filename, GError **err,
char const *first_property_name, ...)
{
GsfOutput *res;
va_list var_args;
va_start (var_args, first_property_name);
res = gsf_output_stdio_new_valist (filename, err, first_property_name, var_args);
va_end (var_args);
return res;
}
/**
* gsf_output_stdio_new :
* @filename : name of file to create or replace.
* @err : optionally NULL.
*
* Returns a new file or NULL.
**/
GsfOutput *
gsf_output_stdio_new (char const *filename, GError **err)
{
return gsf_output_stdio_new_full (filename, err, NULL);
}
/**
* gsf_output_stdio_new_FILE :
* @filename : The filename corresponding to @file.
* @file : an existing stdio FILE *
* @keep_open : Should @file be closed when the wrapper is closed
*
* Assumes ownership of @file. If @keep_open is true, ownership reverts
* to caller when the GsfObject is closed.
*
* Returns a new GsfOutput wrapper for @file. Warning: the result will be
* seekable only if @file is seekable. If it is seekable, the resulting
* GsfOutput object will seek relative to @file's beginning, not its
* current location at the time the GsfOutput object is created.
**/
GsfOutput *
gsf_output_stdio_new_FILE (char const *filename, FILE *file, gboolean keep_open)
{
GsfOutputStdio *stdio;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (file != NULL, NULL);
stdio = g_object_new (GSF_OUTPUT_STDIO_TYPE, NULL);
stdio->file = file;
stdio->keep_open = keep_open;
stdio->real_filename = stdio->temp_filename = NULL;
gsf_output_set_name_from_filename (GSF_OUTPUT (stdio), filename);
return GSF_OUTPUT (stdio);
}

View File

@@ -0,0 +1,49 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output-stdio.h: stdio based output
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_STDIO_H
#define GSF_OUTPUT_STDIO_H
#include "gsf-output.h"
#include <stdio.h>
G_BEGIN_DECLS
#define GSF_OUTPUT_STDIO_TYPE (gsf_output_stdio_get_type ())
#define GSF_OUTPUT_STDIO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_STDIO_TYPE, GsfOutputStdio))
#define GSF_IS_OUTPUT_STDIO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_STDIO_TYPE))
typedef struct _GsfOutputStdio GsfOutputStdio;
GType gsf_output_stdio_get_type (void);
GsfOutput *gsf_output_stdio_new (char const *filename, GError **err);
GsfOutput *gsf_output_stdio_new_full (char const *filename, GError **err,
char const *first_property_name,
...); /* G_GNUC_NULL_TERMINATED */
GsfOutput *gsf_output_stdio_new_valist (char const *filename, GError **err,
char const *first_property_name,
va_list var_args);
GsfOutput *gsf_output_stdio_new_FILE (char const *filename, FILE *file,
gboolean keep_open);
G_END_DECLS
#endif /* GSF_OUTPUT_STDIO_H */

View File

@@ -0,0 +1,605 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output.c: interface for storing data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-output-impl.h>
#include <gsf/gsf-impl-utils.h>
#include <string.h>
static gsf_off_t gsf_output_real_vprintf (GsfOutput *output,
char const* format, va_list args) G_GNUC_PRINTF (2, 0);
#define GET_CLASS(instance) G_TYPE_INSTANCE_GET_CLASS (instance, GSF_OUTPUT_TYPE, GsfOutputClass)
static GObjectClass *parent_class;
enum {
PROP_0,
PROP_NAME,
PROP_SIZE,
PROP_CLOSED,
PROP_POS
};
static void
gsf_output_set_property (GObject *object,
guint property_id,
G_GNUC_UNUSED GValue const *value,
GParamSpec *pspec)
{
switch (property_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_output_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
/* gsf_off_t is typedef'd to gint64 */
switch (property_id) {
case PROP_NAME:
g_value_set_string (value, gsf_output_name (GSF_OUTPUT (object)));
break;
case PROP_SIZE:
g_value_set_int64 (value, gsf_output_size (GSF_OUTPUT (object)));
break;
case PROP_POS:
g_value_set_int64 (value, gsf_output_tell (GSF_OUTPUT (object)));
break;
case PROP_CLOSED:
g_value_set_boolean (value, gsf_output_is_closed (GSF_OUTPUT (object)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gsf_output_dispose (GObject *obj)
{
GsfOutput *output = GSF_OUTPUT (obj);
if (!output->is_closed) {
/* g_warning ("Disposing of an unclosed stream"); */
gsf_output_close (output);
}
g_free (output->name);
output->name = NULL;
g_free (output->printf_buf);
output->printf_buf = NULL;
g_clear_error (&output->err);
if (output->container != NULL) {
g_object_unref (G_OBJECT (output->container));
output->container = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (obj);
}
static void
gsf_output_init (GObject *obj)
{
GsfOutput *output = GSF_OUTPUT (obj);
output->cur_offset = 0;
output->cur_size = 0;
output->name = NULL;
output->wrapped_by = NULL;
output->container = NULL;
output->err = NULL;
output->is_closed = FALSE;
output->printf_buf = NULL;
output->printf_buf_size = 0;
}
static void
gsf_output_class_init (GObjectClass *gobject_class)
{
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
gobject_class->dispose = gsf_output_dispose;
gobject_class->set_property = gsf_output_set_property;
gobject_class->get_property = gsf_output_get_property;
output_class->Vprintf = gsf_output_real_vprintf;
parent_class = g_type_class_peek_parent (gobject_class);
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string ("name", "Name",
"The Output's Name",
NULL,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_SIZE,
g_param_spec_int64 ("size", "Size",
"The Output's Size",
0, G_MAXINT64, 0,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_POS,
g_param_spec_int64 ("position", "Position",
"The Output's Current Position",
0, G_MAXINT64, 0,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_CLOSED,
g_param_spec_boolean ("is-closed", "Is Closed",
"Whether the Output is Closed",
FALSE,
GSF_PARAM_STATIC |
G_PARAM_READABLE));
}
GSF_CLASS_ABSTRACT (GsfOutput, gsf_output,
gsf_output_class_init, gsf_output_init,
G_TYPE_OBJECT)
/**
* gsf_output_name :
* @output :
*
* Returns @output's name in utf8 form, DO NOT FREE THIS STRING
**/
char const *
gsf_output_name (GsfOutput const *output)
{
g_return_val_if_fail (GSF_IS_OUTPUT (output), NULL);
return output->name;
}
/**
* gsf_output_container :
* @output :
*
* Returns, but does not add a reference to @output's container.
* Potentially NULL
**/
GsfOutfile *
gsf_output_container (GsfOutput const *output)
{
g_return_val_if_fail (GSF_IS_OUTPUT (output), NULL);
return output->container;
}
/**
* gsf_output_size :
* @output :
*
* Returns the size of the output, or -1 if it does not have a size.
**/
gsf_off_t
gsf_output_size (GsfOutput *output)
{
g_return_val_if_fail (GSF_IS_OUTPUT (output), -1);
return output->cur_size;
}
/**
* gsf_output_close :
* @output :
*
* Close a stream.
* Returns FALSE on error
**/
gboolean
gsf_output_close (GsfOutput *output)
{
gboolean res;
g_return_val_if_fail (GSF_IS_OUTPUT (output),
gsf_output_set_error (output, 0, "<internal>"));
g_return_val_if_fail (!output->is_closed,
gsf_output_set_error (output, 0, "<internal>"));
/* The implementation will log any errors, but we can never try to
* close multiple times even on failure.
*/
res = GET_CLASS (output)->Close (output);
output->is_closed = TRUE;
return res;
}
/**
* gsf_output_is_closed :
* @output :
*
* Returns TRUE if @output has already been closed.
**/
gboolean
gsf_output_is_closed (GsfOutput const *output)
{
g_return_val_if_fail (GSF_IS_OUTPUT (output), TRUE);
return output->is_closed;
}
/**
* gsf_output_tell :
* @output :
*
* Returns the current position in the file
**/
gsf_off_t
gsf_output_tell (GsfOutput *output)
{
g_return_val_if_fail (output != NULL, 0);
return output->cur_offset;
}
/**
* gsf_output_seek :
* @output :
* @offset :
* @whence :
*
* Returns FALSE on error.
**/
gboolean
gsf_output_seek (GsfOutput *output, gsf_off_t offset, GSeekType whence)
{
gsf_off_t pos = offset;
g_return_val_if_fail (output != NULL, FALSE);
switch (whence) {
case G_SEEK_SET: break;
case G_SEEK_CUR: pos += output->cur_offset; break;
case G_SEEK_END: pos += output->cur_size; break;
default :
g_warning ("Invalid seek type %d", (int)whence);
return FALSE;
}
if (pos < 0) {
g_warning ("Invalid seek position %" GSF_OFF_T_FORMAT
", which is before the start of the file", pos);
return FALSE;
}
/* If we go nowhere, just return. This in particular handles null
* seeks for streams with no seek method.
*/
if (pos == output->cur_offset)
return TRUE;
if (GET_CLASS (output)->Seek (output, offset, whence)) {
/* NOTE : it is possible for the current pos to be beyond the
* end of the file. The intervening space is not filled with 0
* until something is written.
*/
output->cur_offset = pos;
return TRUE;
}
/* the implementation should have assigned whatever errors are necessary */
return FALSE;
}
static inline gboolean
gsf_output_inc_cur_offset (GsfOutput *output, gsf_off_t num_bytes)
{
output->cur_offset += num_bytes;
if (output->cur_offset < num_bytes)
return gsf_output_set_error (output, 0, "Output size overflow.");
if (output->cur_size < output->cur_offset)
output->cur_size = output->cur_offset;
return TRUE;
}
/**
* gsf_output_write :
* @output :
* @num_bytes :
* @data :
*
* Returns FALSE on error.
**/
gboolean
gsf_output_write (GsfOutput *output,
size_t num_bytes, guint8 const *data)
{
g_return_val_if_fail (output != NULL, FALSE);
if (num_bytes == 0)
return TRUE;
if (GET_CLASS (output)->Write (output, num_bytes, data))
return gsf_output_inc_cur_offset (output, num_bytes);
/* the implementation should have assigned whatever errors are necessary */
return FALSE;
}
/**
* gsf_output_error :
* @output :
*
* Returns the last error logged on the output, or NULL.
**/
GError const *
gsf_output_error (GsfOutput const *output)
{
g_return_val_if_fail (GSF_IS_OUTPUT (output), NULL);
return output->err;
}
/**
* gsf_output_set_name :
* @output :
* @name :
*
* <note>This is a utility routine that should only be used by derived
* outputs.</note>
*
* Returns : TRUE if the assignment was ok.
**/
gboolean
gsf_output_set_name (GsfOutput *output, char const *name)
{
char *buf;
g_return_val_if_fail (GSF_IS_OUTPUT (output), FALSE);
buf = g_strdup (name);
g_free (output->name);
output->name = buf;
return TRUE;
}
/**
* gsf_output_set_name_from_filename :
* @output : the output stream
* @filename : the (fs-sys encoded) filename
*
* <note>This is a utility routine that should only be used by derived
* outputs.</note>
*
* Returns : TRUE if the assignment was ok.
**/
gboolean
gsf_output_set_name_from_filename (GsfOutput *output, char const *filename)
{
g_return_val_if_fail (GSF_IS_OUTPUT (output), FALSE);
g_free (output->name);
output->name = filename
? g_filename_to_utf8 (filename, -1, NULL, NULL, NULL)
: NULL;
return TRUE;
}
/**
* gsf_output_set_container :
* @output :
* @container :
*
* <note>This is a utility routine that should only be used by derived
* outputs.</note>
*
* Returns : TRUE if the assignment was ok.
**/
gboolean
gsf_output_set_container (GsfOutput *output, GsfOutfile *container)
{
g_return_val_if_fail (GSF_IS_OUTPUT (output), FALSE);
if (container != NULL)
g_object_ref (G_OBJECT (container));
if (output->container != NULL)
g_object_unref (G_OBJECT (output->container));
output->container = container;
return TRUE;
}
/**
* gsf_output_set_error :
* @output :
* @code :
* @format :
* @Varargs :
*
* <note>This is a utility routine that should only be used by derived
* outputs.</note>
*
* Returns Always returns FALSE to facilitate its use.
**/
gboolean
gsf_output_set_error (GsfOutput *output,
gint code,
char const *format,
...)
{
g_return_val_if_fail (GSF_IS_OUTPUT (output), FALSE);
g_clear_error (&output->err);
if (format != NULL) {
va_list args;
va_start (args, format);
output->err = g_new (GError, 1);
output->err->domain = gsf_output_error_id ();
output->err->code = code;
output->err->message = g_strdup_vprintf (format, args);
va_end (args);
}
return FALSE;
}
static void
cb_output_unwrap (GsfOutput *wrapee, G_GNUC_UNUSED GObject *wrapper)
{
wrapee->wrapped_by = NULL;
}
/**
* gsf_output_wrap :
* @wrapper :
* @wrapee :
*
* Returns TRUE if the wrapping succeeded.
**/
gboolean
gsf_output_wrap (GObject *wrapper, GsfOutput *wrapee)
{
g_return_val_if_fail (wrapper != NULL, FALSE);
g_return_val_if_fail (wrapee != NULL, FALSE);
if (wrapee->wrapped_by != NULL) {
g_warning ("Attempt to wrap an output that is already wrapped.");
return FALSE;
}
g_object_weak_ref (G_OBJECT (wrapper),
(GWeakNotify) cb_output_unwrap, wrapee);
wrapee->wrapped_by = wrapper;
return TRUE;
}
/**
* gsf_output_unwrap :
* @wrapper :
* @wrapee :
*
* Returns TRUE if the unwrapping succeeded.
**/
gboolean
gsf_output_unwrap (GObject *wrapper, GsfOutput *wrapee)
{
g_return_val_if_fail (wrapee != NULL, FALSE);
g_return_val_if_fail (wrapee->wrapped_by == wrapper, FALSE);
wrapee->wrapped_by = NULL;
g_object_weak_unref (G_OBJECT (wrapper),
(GWeakNotify) cb_output_unwrap, wrapee);
return TRUE;
}
GQuark
gsf_output_error_id (void)
{
static GQuark quark;
if (!quark)
quark = g_quark_from_static_string ("gsf_output_error");
return quark;
}
/**
* gsf_output_printf:
* @output: A #GsfOutput
* @format: The printf-style format string
* @Varargs: the arguments for @format
*
* Returns: TRUE if successful, FALSE if not
**/
gboolean
gsf_output_printf (GsfOutput *output, char const *format, ...)
{
va_list args;
gboolean res;
va_start (args, format);
res = (gsf_output_vprintf (output, format, args) >= 0);
va_end (args);
return res;
}
/**
* gsf_output_vprintf:
* @output: A #GsfOutput
* @format: The printf-style format string
* @args: the arguments for @format
*
* Returns: number of bytes printed, a negative value if not successful
**/
gsf_off_t
gsf_output_vprintf (GsfOutput *output, char const *format, va_list args)
{
gsf_off_t num_bytes;
g_return_val_if_fail (output != NULL, -1);
g_return_val_if_fail (format != NULL, -1);
/* g_return_val_if_fail (strlen (format) > 0, -1); -- Why? */
num_bytes = GET_CLASS (output)->Vprintf (output, format, args);
if (num_bytes >= 0)
if (!gsf_output_inc_cur_offset (output, num_bytes))
return -1;
return num_bytes;
}
static gsf_off_t
gsf_output_real_vprintf (GsfOutput *output, char const *fmt, va_list args)
{
gsf_off_t reslen;
if (NULL == output->printf_buf) {
output->printf_buf_size = 128;
output->printf_buf = g_new (char, output->printf_buf_size);
}
reslen = g_vsnprintf (output->printf_buf, output->printf_buf_size, fmt, args);
/* handle C99 or older -1 case of vsnprintf */
if (reslen < 0 || reslen >= output->printf_buf_size) {
g_free (output->printf_buf);
output->printf_buf = g_strdup_vprintf (fmt, args);
reslen = output->printf_buf_size = strlen (output->printf_buf);
}
if (reslen == 0 ||
GET_CLASS (output)->Write (output, reslen, output->printf_buf))
return reslen;
return -1;
}
/**
* gsf_output_puts:
* @output: A #GsfOutput
* @line: %null terminated string to write
*
* Like fputs, this assumes that the line already ends with a newline
*
* Returns: TRUE if successful, FALSE if not
**/
gboolean
gsf_output_puts (GsfOutput *output, char const *line)
{
size_t nbytes = 0;
g_return_val_if_fail (line != NULL, FALSE);
nbytes = strlen (line);
return gsf_output_write (output, nbytes, line);
}

View File

@@ -0,0 +1,96 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-output.h: interface for storing data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_OUTPUT_H
#define GSF_OUTPUT_H
#include <gsf/gsf.h>
#include <sys/types.h>
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct {
GObjectClass g_object_class;
gboolean (*Close) (GsfOutput *output);
gboolean (*Seek) (GsfOutput *output,
gsf_off_t offset, GSeekType whence);
gboolean (*Write) (GsfOutput *output,
size_t num_bytes, guint8 const *data);
gsf_off_t (*Vprintf) (GsfOutput *output,
char const *format, va_list args);
} GsfOutputClass;
#define GSF_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSF_OUTPUT_TYPE, GsfOutputClass))
#define GSF_IS_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSF_OUTPUT_TYPE))
struct _GsfOutput {
GObject g_object;
/*< protected >*/
gsf_off_t cur_size, cur_offset;
char *name;
GObject *wrapped_by;
GsfOutfile *container;
GError *err;
gboolean is_closed;
char *printf_buf;
int printf_buf_size;
};
#define GSF_OUTPUT_TYPE (gsf_output_get_type ())
#define GSF_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_TYPE, GsfOutput))
#define GSF_IS_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_TYPE))
GType gsf_output_get_type (void);
char const *gsf_output_name (GsfOutput const *output);
GsfOutfile *gsf_output_container (GsfOutput const *output);
GError const *gsf_output_error (GsfOutput const *output);
gboolean gsf_output_set_error (GsfOutput *output,
gint code,
char const *format,
...) G_GNUC_PRINTF (3, 4);
gsf_off_t gsf_output_size (GsfOutput *output);
gboolean gsf_output_close (GsfOutput *output);
gboolean gsf_output_is_closed (GsfOutput const *output);
gsf_off_t gsf_output_tell (GsfOutput *output);
gboolean gsf_output_seek (GsfOutput *output,
gsf_off_t offset, GSeekType whence);
gboolean gsf_output_write (GsfOutput *output,
size_t num_bytes, guint8 const *data);
gboolean gsf_output_wrap (GObject *wrapper, GsfOutput *wrapee);
gboolean gsf_output_unwrap (GObject *wrapper, GsfOutput *wrapee);
GQuark gsf_output_error_id (void);
gboolean gsf_output_printf (GsfOutput *output, char const *format,
...) G_GNUC_PRINTF (2, 3);
gsf_off_t gsf_output_vprintf (GsfOutput *output, char const *format,
va_list args) G_GNUC_PRINTF (2, 0);
gboolean gsf_output_puts (GsfOutput *output, char const *line);
G_END_DECLS
#endif /* GSF_OUTPUT_H */

View File

@@ -0,0 +1,107 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-shared-memory.c:
*
* Copyright (C) 2002-2004 Morten Welinder (terra@diku.dk)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-shared-memory.h>
#include <gsf/gsf-impl-utils.h>
#ifdef HAVE_MMAP
#include <sys/types.h>
#include <sys/mman.h>
#elif defined(G_OS_WIN32)
#include <windows.h>
#endif
typedef struct {
GObjectClass g_object_class;
} GsfSharedMemoryClass;
static GObjectClass *parent_class;
GsfSharedMemory *
gsf_shared_memory_new (void *buf, gsf_off_t size, gboolean needs_free)
{
GsfSharedMemory *mem = g_object_new (GSF_SHARED_MEMORY_TYPE, NULL);
mem->buf = buf;
mem->size = size;
mem->needs_free = needs_free;
mem->needs_unmap = FALSE;
return mem;
}
GsfSharedMemory *
gsf_shared_memory_mmapped_new (void *buf, gsf_off_t size)
{
#if defined(HAVE_MMAP) || defined(G_OS_WIN32)
size_t msize = size;
if ((gsf_off_t)msize != size) {
g_warning ("memory buffer size too large");
return NULL;
} else {
GsfSharedMemory *mem = gsf_shared_memory_new (buf, size, FALSE);
mem->needs_unmap = TRUE;
return mem;
}
#else
return NULL;
#endif
}
static void
gsf_shared_memory_finalize (GObject *obj)
{
GsfSharedMemory *mem = (GsfSharedMemory *) (obj);
if (mem->buf != NULL) {
if (mem->needs_free)
g_free (mem->buf);
else if (mem->needs_unmap) {
#ifdef HAVE_MMAP
munmap (mem->buf, mem->size);
#elif defined(G_OS_WIN32)
UnmapViewOfFile (mem->buf);
#else
g_assert_not_reached ();
#endif
}
}
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static void
gsf_shared_memory_init (GObject *obj)
{
GsfSharedMemory *mem = (GsfSharedMemory *) (obj);
mem->buf = NULL;
}
static void
gsf_shared_memory_class_init (GObjectClass *gobject_class)
{
parent_class = g_type_class_peek_parent (gobject_class);
gobject_class->finalize = gsf_shared_memory_finalize;
}
GSF_CLASS (GsfSharedMemory, gsf_shared_memory,
gsf_shared_memory_class_init, gsf_shared_memory_init,
G_TYPE_OBJECT)

View File

@@ -0,0 +1,50 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-shared-memory.h
*
* Copyright (C) 2002-2004 Morten Welinder (terra@diku.dk)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_SHARED_MEMORY_H
#define GSF_SHARED_MEMORY_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GSF_SHARED_MEMORY_TYPE (gsf_shared_memory_get_type ())
#define GSF_SHARED_MEMORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_SHARED_MEMORY_TYPE, GsfSharedMemory))
#define GSF_IS_SHARED_MEMORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_SHARED_MEMORY_TYPE))
typedef struct _GsfSharedMemory GsfSharedMemory;
struct _GsfSharedMemory {
GObject g_object;
void *buf;
gsf_off_t size;
gboolean needs_free;
gboolean needs_unmap;
};
GType gsf_shared_memory_get_type (void);
GsfSharedMemory *gsf_shared_memory_new (void *buf, gsf_off_t size, gboolean needs_free);
GsfSharedMemory *gsf_shared_memory_mmapped_new (void *buf, gsf_off_t size);
G_END_DECLS
#endif /* GSF_SHARED_MEMORY_H */

View File

@@ -0,0 +1,298 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-structured_blob.c : Utility storage to blob in/out a tree of data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-structured-blob.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-infile-impl.h>
#include <gsf/gsf-input.h>
#include <gsf/gsf-outfile.h>
#include <gsf/gsf-output.h>
#include <gsf/gsf-shared-memory.h>
#include <string.h>
static GObjectClass *parent_class;
struct _GsfStructuredBlob {
GsfInfile base;
GsfSharedMemory *data;
GPtrArray *children;
};
typedef struct {
GsfInfileClass base;
} GsfStructuredBlobClass;
static void
blob_finalize (GObject *obj)
{
unsigned i;
GsfStructuredBlob *blob = GSF_STRUCTURED_BLOB (obj);
if (blob->data != NULL) {
g_object_unref (G_OBJECT (blob->data));
blob->data = NULL;
}
if (blob->children != NULL) {
for (i = 0; i < blob->children->len ; i++)
g_object_unref (g_ptr_array_index (blob->children, i));
g_ptr_array_free (blob->children, TRUE);
blob->children = NULL;
}
parent_class->finalize (obj);
}
static GsfInput *
blob_dup (GsfInput *input, G_GNUC_UNUSED GError **err)
{
GsfStructuredBlob const *src = (GsfStructuredBlob *) input;
GsfStructuredBlob *dst = g_object_new (GSF_STRUCTURED_BLOB_TYPE, NULL);
if (src->data != NULL) {
dst->data = src->data;
g_object_ref (G_OBJECT (dst->data));
}
if (src->children != NULL) {
unsigned i;
gpointer child;
dst->children = g_ptr_array_sized_new (src->children->len);
g_ptr_array_set_size (dst->children, src->children->len);
for (i = 0; i < src->children->len ; i++) {
child = g_ptr_array_index (src->children, i);
g_ptr_array_index (dst->children, i) = child;
g_object_ref (child);
}
}
return GSF_INPUT (dst);
}
static guint8 const *
blob_read (GsfInput *input, size_t num_bytes, guint8 *optional_buffer)
{
GsfStructuredBlob *blob = (GsfStructuredBlob *) input;
guchar const *src = blob->data->buf;
if (src == NULL)
return NULL;
if (optional_buffer) {
memcpy (optional_buffer, src + input->cur_offset, num_bytes);
return optional_buffer;
} else
return src + input->cur_offset;
}
static gboolean
blob_seek (G_GNUC_UNUSED GsfInput *input,
G_GNUC_UNUSED gsf_off_t offset,
G_GNUC_UNUSED GSeekType whence)
{
return FALSE;
}
static int
blob_num_children (GsfInfile *infile)
{
GsfStructuredBlob const *blob = (GsfStructuredBlob *) infile;
if (blob->children != NULL)
return blob->children->len;
return -1;
}
static char const *
blob_name_by_index (GsfInfile *infile, int i)
{
GsfStructuredBlob const *blob = (GsfStructuredBlob *) infile;
if (blob->children != NULL) {
g_return_val_if_fail (i < 0 || (unsigned)i >= blob->children->len, NULL);
return gsf_input_name (g_ptr_array_index (blob->children, i));
}
return NULL;
}
static GsfInput *
blob_child_by_index (GsfInfile *infile, int i, GError **err)
{
GsfStructuredBlob const *blob = (GsfStructuredBlob *) infile;
if (blob->children != NULL) {
g_return_val_if_fail (i < 0 || (unsigned)i >= blob->children->len, NULL);
return gsf_input_dup (g_ptr_array_index (blob->children, i), err);
}
return NULL;
}
static GsfInput *
blob_child_by_name (GsfInfile *infile, char const *name, GError **err)
{
GsfStructuredBlob const *blob = (GsfStructuredBlob *) infile;
if (blob->children != NULL) {
unsigned i;
GsfInput *child;
for (i = 0 ; i < blob->children->len ;) {
child = g_ptr_array_index (blob->children, i);
if (!strcmp (gsf_input_name (child), name))
return gsf_input_dup (child, err);
}
}
return NULL;
}
static void
gsf_structured_blob_init (GObject *obj)
{
GsfStructuredBlob *blob = GSF_STRUCTURED_BLOB (obj);
blob->data = NULL;
blob->children = NULL;
}
static void
gsf_structured_blob_class_init (GObjectClass *gobject_class)
{
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
GsfInfileClass *infile_class = GSF_INFILE_CLASS (gobject_class);
gobject_class->finalize = blob_finalize;
input_class->Dup = blob_dup;
input_class->Read = blob_read;
input_class->Seek = blob_seek;
infile_class->num_children = blob_num_children;
infile_class->name_by_index = blob_name_by_index;
infile_class->child_by_index = blob_child_by_index;
infile_class->child_by_name = blob_child_by_name;
parent_class = g_type_class_peek_parent (gobject_class);
}
GSF_CLASS (GsfStructuredBlob, gsf_structured_blob,
gsf_structured_blob_class_init, gsf_structured_blob_init,
GSF_INFILE_TYPE)
/**
* gsf_structured_blob_read :
* @input : An input (potentially a GsfInfile) holding the blob
*
* Returns a freshly created tree of blobs
**/
GsfStructuredBlob *
gsf_structured_blob_read (GsfInput *input)
{
GsfStructuredBlob *blob;
gsf_off_t content_size;
int i = 0;
g_return_val_if_fail (GSF_IS_INPUT (input), NULL);
blob = g_object_new (GSF_STRUCTURED_BLOB_TYPE, NULL);
content_size = gsf_input_remaining (input);
if (content_size > 0) {
guint8 *buf = (guint8*)g_try_malloc (content_size);
if (buf == NULL) {
g_warning ("Failed attempting to allocate %" GSF_OFF_T_FORMAT " bytes",
content_size);
g_object_unref (G_OBJECT (blob));
return NULL;
}
gsf_input_read (input, content_size, buf);
blob->data = gsf_shared_memory_new (buf, content_size, TRUE);
}
gsf_input_set_name (GSF_INPUT (blob), gsf_input_name (input));
if (GSF_IS_INFILE (input))
i = gsf_infile_num_children (GSF_INFILE (input));
if (i > 0) {
GsfInput *child;
GsfStructuredBlob *child_blob;
blob->children = g_ptr_array_sized_new (i);
g_ptr_array_set_size (blob->children, i);
while (i-- > 0) {
child = gsf_infile_child_by_index (GSF_INFILE (input), i);
child_blob = gsf_structured_blob_read (child);
g_object_unref (G_OBJECT (child));
g_ptr_array_index (blob->children, i) = child_blob;
#if 0
/*
* We don't need this, and setting it causes circular
* links.
*/
gsf_input_set_container (GSF_INPUT (child_blob),
GSF_INFILE (blob));
#endif
}
}
return blob;
}
/**
* gsf_structured_blob_write :
* @blob :
* @container :
*
* Dumps structured blob @blob onto the @container. Will fail if the output is
* not an Outfile and blob has multiple streams.
*
* Returns : TRUE on success.
**/
gboolean
gsf_structured_blob_write (GsfStructuredBlob *blob, GsfOutfile *container)
{
GsfOutput *output;
gboolean has_kids;
g_return_val_if_fail (GSF_IS_STRUCTURED_BLOB (blob), FALSE);
g_return_val_if_fail (GSF_IS_OUTFILE (container), FALSE);
has_kids = (blob->children != NULL && blob->children->len > 0);
output = gsf_outfile_new_child (GSF_OUTFILE (container),
gsf_input_name (GSF_INPUT (blob)),
has_kids);
if (has_kids) {
GsfStructuredBlob *child_blob;
unsigned i;
for (i = 0 ; i < blob->children->len ; i++) {
child_blob = g_ptr_array_index (blob->children, i);
if (!gsf_structured_blob_write (child_blob, GSF_OUTFILE (output)))
return FALSE;
}
}
if (blob->data != NULL)
gsf_output_write (output, blob->data->size, blob->data->buf);
gsf_output_close (output);
g_object_unref (G_OBJECT (output));
return TRUE;
}

View File

@@ -0,0 +1,45 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-structured-blob.h: Utility storage to blob in/out a tree of data
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_STRUCTURED_BLOB_H
#define GSF_STRUCTURED_BLOB_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GSF_STRUCTURED_BLOB_TYPE (gsf_structured_blob_get_type ())
#define GSF_STRUCTURED_BLOB(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_STRUCTURED_BLOB_TYPE, GsfStructuredBlob))
#define GSF_IS_STRUCTURED_BLOB(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_STRUCTURED_BLOB_TYPE))
typedef struct _GsfStructuredBlob GsfStructuredBlob;
/* inherits from GsfInfile */
GType gsf_structured_blob_get_type (void);
GsfStructuredBlob *gsf_structured_blob_read (GsfInput *input);
gboolean gsf_structured_blob_write (GsfStructuredBlob *blob,
GsfOutfile *container);
G_END_DECLS
#endif /* GSF_STRUCTURED_BLOB_H */

View File

@@ -0,0 +1,99 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-timestamp.c:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-timestamp.h>
#include <string.h>
#include <time.h>
static void
timestamp_to_string (GValue const *src_value, GValue *dest_value)
{
char *str = gsf_timestamp_as_string (g_value_get_boxed (src_value));
g_value_set_string (dest_value, str);
g_free (str);
}
GType
gsf_timestamp_get_type (void)
{
static GType our_type = 0;
if (our_type == 0) {
our_type = g_boxed_type_register_static ("GsfTimestamp",
(GBoxedCopyFunc)gsf_timestamp_copy,
(GBoxedFreeFunc)gsf_timestamp_free);
g_value_register_transform_func (our_type, G_TYPE_STRING,
&timestamp_to_string);
}
return our_type;
}
GsfTimestamp *
gsf_timestamp_copy (GsfTimestamp const *stamp)
{
GsfTimestamp *res = g_new0 (GsfTimestamp, 1);
res->timet = stamp->timet;
return res;
}
void
gsf_timestamp_free (GsfTimestamp *stamp)
{
g_free (stamp);
}
int
gsf_timestamp_parse (G_GNUC_UNUSED char const *spec,
G_GNUC_UNUSED GsfTimestamp *stamp)
{
return 0;
}
char *
gsf_timestamp_as_string (GsfTimestamp const *stamp)
{
time_t t;
g_return_val_if_fail (stamp != NULL, g_strdup ("<invalid>"));
/* Use an honest time_t for ctime. */
t = stamp->timet;
/* FIXME FIXME FIXME ctime is not thread safe, use ctime_r if available */
return g_strdup (ctime (&t));
}
guint
gsf_timestamp_hash (GsfTimestamp const *stamp)
{
return stamp->timet;
}
gboolean
gsf_timestamp_equal (GsfTimestamp const *a, GsfTimestamp const *b)
{
return a->timet == b->timet;
}
void
gsf_value_set_timestamp (GValue *value, GsfTimestamp const *stamp)
{
g_value_set_boxed (value, stamp);
}

View File

@@ -0,0 +1,60 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-timestamp.h: A useful little type for metadata, contains a superset of
* all the features it would be nice to have.
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_TIMESTAMP_H
#define GSF_TIMESTAMP_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GSF_TIMESTAMP_TYPE (gsf_timestamp_get_type ())
#define VAL_IS_GSF_TIMESTAMP(v) (G_TYPE_CHECK_VALUE_TYPE((v), GSF_TIMESTAMP_TYPE))
struct _GsfTimestamp {
GDate date; /* In local timezone */
glong seconds; /* time of day */
GString time_zone; /* possibly blank */
guint32 timet;
};
GType gsf_timestamp_get_type (void);
GsfTimestamp *gsf_timestamp_new_now (void);
GsfTimestamp *gsf_timestamp_new (GDate const *date, glong seconds,
char const *tz);
GsfTimestamp *gsf_timestamp_copy (GsfTimestamp const *stamp);
void gsf_timestamp_free (GsfTimestamp *stamp);
int gsf_timestamp_parse (char const *spec, GsfTimestamp *stamp);
char *gsf_timestamp_as_string (GsfTimestamp const *stamp);
guint gsf_timestamp_hash (GsfTimestamp const *stamp);
gboolean gsf_timestamp_equal (GsfTimestamp const *a,
GsfTimestamp const *b);
void gsf_value_set_timestamp (GValue *value, GsfTimestamp const *stamp);
G_END_DECLS
#endif /* GSF_TIMESTAMP_H */

View File

@@ -0,0 +1,773 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-utils.c:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf-utils.h>
#include <gsf/gsf-input.h>
#include <gobject/gvaluecollector.h>
#include <glib/gi18n-lib.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#ifndef HAVE_GLIB26
#include <gsf/glib24_26-compat.h>
#endif
/*
* Glib gets this wrong, really. ARM's floating point format is a weird
* mixture.
*/
#define G_ARMFLOAT_ENDIAN 56781234
#if defined(__arm__) && !defined(__vfp__) && (G_BYTE_ORDER == G_LITTLE_ENDIAN)
#define G_FLOAT_BYTE_ORDER G_ARMFLOAT_ENDIAN
#else
#define G_FLOAT_BYTE_ORDER G_BYTE_ORDER
#endif
static void base64_init (void);
/**
* gsf_init :
*
* Initializes the GSF library
*/
void
gsf_init (void)
{
#ifdef ENABLE_NLS
bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
#endif
g_type_init ();
base64_init ();
}
/**
* gsf_shutdown:
*
* De-intializes the GSF library
*/
void
gsf_shutdown (void)
{
}
void
gsf_init_dynamic (GTypeModule *module)
{
(void)module;
}
void
gsf_shutdown_dynamic (GTypeModule *module)
{
(void)module;
}
static void
gsf_mem_dump_full (guint8 const *ptr, size_t len, gsf_off_t offset)
{
gsf_off_t i, j, off;
for (i = 0 ; i < (len+15)/16 ; i++) {
g_print ("%8lx | ", (long)(i*16 + offset));
for (j = 0;j < 16; j++) {
off = j + (i << 4);
off<len ? g_print("%2x ", ptr[off]) : g_print("XX ");
}
g_print ("| ");
for (j = 0 ; j < 16 ; j++) {
off = j + (i<<4);
g_print ("%c", off < len ? (ptr[off] >= '!' && ptr[off] < 127 ? ptr[off] : '.') : '*');
}
g_print ("\n");
}
}
/**
* gsf_mem_dump :
* @ptr: memory area to be dumped.
* @len: how many bytes will be dumped.
*
* Dump @len bytes from the memory location given by @ptr.
**/
void
gsf_mem_dump (guint8 const *ptr, size_t len)
{
gsf_mem_dump_full (ptr, len, 0);
}
/**
* gsf_input_dump :
* @input: a #GsfInput
* @dump_as_hex: If TRUE, dump in hexidecmal format
*
* Dumps @input's contents to STDOUT, optionally in hex format.
*/
void
gsf_input_dump (GsfInput *input, gboolean dump_as_hex)
{
gsf_off_t offset = 0;
size_t size, count;
guint8 const *data;
/* read in small blocks to excercise things */
size = gsf_input_size (GSF_INPUT (input));
while (size > 0) {
count = size;
if (count > 0x100)
count = 0x100;
data = gsf_input_read (GSF_INPUT (input), count, NULL);
g_return_if_fail (data != NULL);
if (dump_as_hex)
gsf_mem_dump_full (data, count, offset);
else
fwrite (data, 1, count, stdout);
size -= count;
offset += count;
}
if (!dump_as_hex)
fflush (stdout);
}
guint64
gsf_le_get_guint64 (void const *p)
{
#if G_BYTE_ORDER == G_BIG_ENDIAN
if (sizeof (guint64) == 8) {
guint64 li;
int i;
guint8 *t = (guint8 *)&li;
guint8 *p2 = (guint8 *)p;
int sd = sizeof (li);
for (i = 0; i < sd; i++)
t[i] = p2[sd - 1 - i];
return li;
} else {
g_error ("Big endian machine, but weird size of guint64");
}
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
if (sizeof (guint64) == 8) {
/*
* On i86, we could access directly, but Alphas require
* aligned access.
*/
guint64 data;
memcpy (&data, p, sizeof (data));
return data;
} else {
g_error ("Little endian machine, but weird size of guint64");
}
#else
#error "Byte order not recognised -- out of luck"
#endif
}
float
gsf_le_get_float (void const *p)
{
#if G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
if (sizeof (float) == 4) {
float f;
int i;
guint8 *t = (guint8 *)&f;
guint8 *p2 = (guint8 *)p;
int sd = sizeof (f);
for (i = 0; i < sd; i++)
t[i] = p2[sd - 1 - i];
return f;
} else {
g_error ("Big endian machine, but weird size of floats");
}
#elif (G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN) || (G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN)
if (sizeof (float) == 4) {
/*
* On i86, we could access directly, but Alphas require
* aligned access.
*/
float data;
memcpy (&data, p, sizeof (data));
return data;
} else {
g_error ("Little endian machine, but weird size of floats");
}
#else
#error "Floating-point byte order not recognised -- out of luck"
#endif
}
void
gsf_le_set_float (void *p, float d)
{
#if G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
if (sizeof (float) == 4) {
int i;
guint8 *t = (guint8 *)&d;
guint8 *p2 = (guint8 *)p;
int sd = sizeof (d);
for (i = 0; i < sd; i++)
p2[sd - 1 - i] = t[i];
} else {
g_error ("Big endian machine, but weird size of floats");
}
#elif (G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN) || (G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN)
if (sizeof (float) == 4) {
/*
* On i86, we could access directly, but Alphas require
* aligned access.
*/
memcpy (p, &d, sizeof (d));
} else {
g_error ("Little endian machine, but weird size of floats");
}
#else
#error "Floating-point byte order not recognised -- out of luck"
#endif
}
double
gsf_le_get_double (void const *p)
{
#if G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN
double data;
memcpy ((char *)&data + 4, p, 4);
memcpy ((char *)&data, (char const *)p + 4, 4);
return data;
#elif G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
if (sizeof (double) == 8) {
double d;
int i;
guint8 *t = (guint8 *)&d;
guint8 *p2 = (guint8 *)p;
int sd = sizeof (d);
for (i = 0; i < sd; i++)
t[i] = p2[sd - 1 - i];
return d;
} else {
g_error ("Big endian machine, but weird size of doubles");
}
#elif G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN
if (sizeof (double) == 8) {
/*
* On i86, we could access directly, but Alphas require
* aligned access.
*/
double data;
memcpy (&data, p, sizeof (data));
return data;
} else {
g_error ("Little endian machine, but weird size of doubles");
}
#else
#error "Floating-point byte order not recognised -- out of luck"
#endif
}
void
gsf_le_set_double (void *p, double d)
{
#if G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN
memcpy (p, (char const *)&d + 4, 4);
memcpy ((char *)p + 4, &d, 4);
#elif G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
if (sizeof (double) == 8) {
int i;
guint8 *t = (guint8 *)&d;
guint8 *p2 = (guint8 *)p;
int sd = sizeof (d);
for (i = 0; i < sd; i++)
p2[sd - 1 - i] = t[i];
} else {
g_error ("Big endian machine, but weird size of doubles");
}
#elif G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN
if (sizeof (double) == 8) {
/*
* On i86, we could access directly, but Alphas require
* aligned access.
*/
memcpy (p, &d, sizeof (d));
} else {
g_error ("Little endian machine, but weird size of doubles");
}
#else
#error "Floating-point byte order not recognised -- out of luck"
#endif
}
/**
* gsf_extension_pointer:
* @path: A filename or file path.
*
* Extracts the extension from the end of a filename (the part after the final
* '.' in the filename).
*
* Returns: A pointer to the extension part of the filename, or a
* pointer to the end of the string if the filename does not
* have an extension.
*/
char const *
gsf_extension_pointer (char const *path)
{
char const *s, *end;
g_return_val_if_fail (path != NULL, NULL);
end = path + strlen (path);
for (s = end; s > path; ) {
s--;
if (G_IS_DIR_SEPARATOR (*s))
break;
if (*s == '.')
return s + 1;
}
return end;
}
/**
* gsf_iconv_close : A utility wrapper to safely close an iconv handle
* @handle :
**/
void
gsf_iconv_close (GIConv handle)
{
if (handle != NULL && handle != ((GIConv)-1))
g_iconv_close (handle);
}
/**
* gsf_filename_to_utf8:
* @filename: file name suitable for open(2).
* @quoted: if TRUE, the resulting utf8 file name will be quoted
* (unless it is invalid).
*
* A utility wrapper to make sure filenames are valid utf8.
* Caller must g_free the result.
*
* Returns @filename using utf-8 encoding for display
**/
char *
gsf_filename_to_utf8 (char const *filename, gboolean quoted)
{
char *dname = g_filename_display_name (filename);
char *result;
if (quoted) {
result = g_strconcat ("\"", dname, "\"", NULL);
g_free (dname);
} else
result = dname;
return result;
}
/***************************************************************************/
/* some code taken from evolution/camel/camel-mime-utils.c */
/*
* Copyright (C) 2000 Ximian Inc.
*
* Authors: Michael Zucchi <notzed@ximian.com>
* Jeffrey Stedfast <fejj@ximian.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* 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., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* dont touch this file without my permission - Michael */
static guint8 camel_mime_base64_rank[256];
static char const *base64_alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#define d(x)
/* Line length for base64 encoding. Must be a multiple of 4. */
enum { BASE64_LINE_LEN = 76 };
static void
base64_init(void)
{
int i;
memset(camel_mime_base64_rank, 0xff, sizeof(camel_mime_base64_rank));
for (i=0;i<64;i++) {
camel_mime_base64_rank[(unsigned int)base64_alphabet[i]] = i;
}
camel_mime_base64_rank['='] = 0;
}
/* call this when finished encoding everything, to
flush off the last little bit */
size_t
gsf_base64_encode_close (guint8 const *in, size_t inlen,
gboolean break_lines, guint8 *out, int *state, unsigned int *save)
{
int c1, c2;
guint8 *outptr = out;
if (inlen>0)
outptr += gsf_base64_encode_step(in, inlen, break_lines, outptr, state, save);
c1 = ((guint8 *)save)[1];
c2 = ((guint8 *)save)[2];
d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
(int)((char *)save)[0],
(int)((char *)save)[1],
(int)((char *)save)[2]));
switch (((char *)save)[0]) {
case 2:
outptr[2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
g_assert(outptr[2] != 0);
goto skip;
case 1:
outptr[2] = '=';
skip:
outptr[0] = base64_alphabet[ c1 >> 2 ];
outptr[1] = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )];
outptr[3] = '=';
outptr += 4;
++*state;
break;
}
if (break_lines && *state > 0)
*outptr++ = '\n';
*save = 0;
*state = 0;
return outptr-out;
}
/*
performs an 'encode step', only encodes blocks of 3 characters to the
output at a time, saves left-over state in state and save (initialise to
0 on first invocation).
*/
size_t
gsf_base64_encode_step (guint8 const *in, size_t len,
gboolean break_lines, guint8 *out, int *state, unsigned int *save)
{
register guint8 const *inptr;
register guint8 *outptr;
if (len<=0)
return 0;
inptr = in;
outptr = out;
d(printf("we have %d chars, and %d saved chars\n", len, ((char *)save)[0]));
if (len + ((char *)save)[0] > 2) {
guint8 const *inend = in+len-2;
register int c1, c2, c3;
register int already;
already = *state;
switch (((char *)save)[0]) {
case 1: c1 = ((guint8 *)save)[1]; goto skip1;
case 2: c1 = ((guint8 *)save)[1];
c2 = ((guint8 *)save)[2]; goto skip2;
}
/* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */
while (inptr < inend) {
c1 = *inptr++;
skip1:
c2 = *inptr++;
skip2:
c3 = *inptr++;
*outptr++ = base64_alphabet[ c1 >> 2 ];
*outptr++ = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ];
*outptr++ = base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ];
*outptr++ = base64_alphabet[ c3 & 0x3f ];
/* this is a bit ugly ... */
if (break_lines && (++already) * 4 >= BASE64_LINE_LEN) {
*outptr++='\n';
already = 0;
}
}
((char *)save)[0] = 0;
len = 2-(inptr-inend);
*state = already;
}
d(printf("state = %d, len = %d\n",
(int)((char *)save)[0],
len));
if (len>0) {
register char *saveout;
/* points to the slot for the next char to save */
saveout = & (((char *)save)[1]) + ((char *)save)[0];
/* len can only be 0 1 or 2 */
switch(len) {
case 2: *saveout++ = *inptr++;
case 1: *saveout++ = *inptr++;
}
((char *)save)[0]+=len;
}
d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
(int)((char *)save)[0],
(int)((char *)save)[1],
(int)((char *)save)[2]));
return outptr-out;
}
/**
* gsf_base64_decode_step: decode a chunk of base64 encoded data
* @in: input stream
* @len: max length of data to decode
* @out: output stream
* @state: holds the number of bits that are stored in @save
* @save: leftover bits that have not yet been decoded
*
* Decodes a chunk of base64 encoded data
*
* Returns the number of bytes converted
**/
size_t
gsf_base64_decode_step (guint8 const *in, size_t len, guint8 *out,
int *state, guint *save)
{
register guint8 const *inptr;
register guint8 *outptr, c;
register unsigned int v;
guint8 const *inend;
int i;
inend = in+len;
outptr = out;
/* convert 4 base64 bytes to 3 normal bytes */
v=*save;
i=*state;
inptr = in;
while (inptr<inend) {
c = camel_mime_base64_rank[*inptr++];
if (c != 0xff) {
v = (v<<6) | c;
i++;
if (i==4) {
*outptr++ = v>>16;
*outptr++ = v>>8;
*outptr++ = v;
i=0;
}
}
}
*save = v;
*state = i;
/* quick scan back for '=' on the end somewhere */
/* fortunately we can drop 1 output char for each trailing = (upto 2) */
i=2;
while (inptr>in && i) {
inptr--;
if (camel_mime_base64_rank[*inptr] != 0xff) {
if (*inptr == '=' && outptr>out)
outptr--;
i--;
}
}
/* if i!= 0 then there is a truncation error! */
return outptr-out;
}
guint8 *
gsf_base64_encode_simple (guint8 const *data, size_t len)
{
guint8 *out;
int state = 0, outlen;
unsigned int save = 0;
gboolean break_lines = TRUE;
outlen = len * 4 / 3 + 5;
if (break_lines)
outlen += outlen / BASE64_LINE_LEN + 1;
out = g_new (guint8, outlen);
outlen = gsf_base64_encode_close (data, len, break_lines,
out, &state, &save);
out [outlen] = '\0';
return out;
}
size_t
gsf_base64_decode_simple (guint8 *data, size_t len)
{
int state = 0;
unsigned int save = 0;
return gsf_base64_decode_step (data, len, data, &state, &save);
}
/* Largely a copy of g_object_new_valist. */
/**
* gsf_property_settings_collect_valist: collect property setting from a va_list.
* @object_type: the GType for which the properties are being set.
* @p_n_params: a pointer to the number of properties collected. (Used for
* both input and output.)
* @p_params: a pointer to the GParameter array that holds the properties.
* (Used for both input and output. This may point to a NULL pointer if
* there are no properties collected yet.)
* @first_property_name: the name of the first property being set, or NULL.
* @var_args: a va_list holding the remainder of the property names and
* values, terminated by a NULL.
*
* This function builds a GParameter array suitable for g_object_newv.
**/
void
gsf_property_settings_collect_valist (GType object_type,
GParameter **p_params,
size_t *p_n_params,
const gchar *first_property_name,
va_list var_args)
{
GObjectClass *class;
GParameter *params = *p_params;
const gchar *name;
size_t n_params = *p_n_params;
size_t n_alloced_params = n_params; /* We might have more. */
g_return_if_fail (G_TYPE_IS_OBJECT (object_type));
class = g_type_class_ref (object_type);
name = first_property_name;
while (name)
{
gchar *error = NULL;
GParamSpec *pspec = g_object_class_find_property (class, name);
if (!pspec)
{
g_warning ("%s: object class `%s' has no property named `%s'",
G_STRFUNC,
g_type_name (object_type),
name);
break;
}
if (n_params >= n_alloced_params)
{
n_alloced_params += 16;
params = g_renew (GParameter, params, n_alloced_params);
}
params[n_params].name = name;
params[n_params].value.g_type = 0;
g_value_init (&params[n_params].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
G_VALUE_COLLECT (&params[n_params].value, var_args, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRFUNC, error);
g_free (error);
g_value_unset (&params[n_params].value);
break;
}
n_params++;
name = va_arg (var_args, gchar*);
}
g_type_class_unref (class);
*p_params = params;
*p_n_params = n_params;
}
/* This is a vararg version of gsf_property_settings_collect_valist. */
void
gsf_property_settings_collect (GType object_type,
GParameter **p_params,
size_t *p_n_params,
const gchar *first_property_name,
...)
{
va_list var_args;
va_start (var_args, first_property_name);
gsf_property_settings_collect_valist (object_type, p_params, p_n_params, first_property_name, var_args);
va_end (var_args);
}
void
gsf_property_settings_free (GParameter *params,
size_t n_params)
{
while (n_params--)
g_value_unset (&params[n_params].value);
g_free (params);
}
/* Errors */
/**
* gsf_error_quark:
*
* Returns the #GQuark used to identify libgsf errors in #GError structures.
* Specific error codes come from the #GsfError enumeration.
*
* Return value: A #GQuark.
**/
GQuark
gsf_error_quark (void)
{
static GQuark quark;
if (quark == 0)
quark = g_quark_from_static_string ("gsf-error-quark");
return quark;
}

View File

@@ -0,0 +1,142 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-utils.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_UTILS_H
#define GSF_UTILS_H
#include <gsf/gsf.h>
#include <glib-object.h>
G_BEGIN_DECLS
/* Do this the ugly way so that we don't have to worry about alignment */
#define GSF_LE_GET_GUINT8(p) (*(guint8 const *)(p))
#define GSF_LE_GET_GUINT16(p) \
(guint16)((((guint8 const *)(p))[0] << 0) | \
(((guint8 const *)(p))[1] << 8))
#define GSF_LE_GET_GUINT32(p) \
(guint32)((((guint8 const *)(p))[0] << 0) | \
(((guint8 const *)(p))[1] << 8) | \
(((guint8 const *)(p))[2] << 16) | \
(((guint8 const *)(p))[3] << 24))
#define GSF_LE_GET_GUINT64(p) (gsf_le_get_guint64 (p))
#define GSF_LE_GET_GINT8(p) ((gint8)GSF_LE_GET_GUINT8(p))
#define GSF_LE_GET_GINT16(p) ((gint16)GSF_LE_GET_GUINT16(p))
#define GSF_LE_GET_GINT32(p) ((gint32)GSF_LE_GET_GUINT32(p))
#define GSF_LE_GET_GINT64(p) ((gint64)GSF_LE_GET_GUINT64(p))
#define GSF_LE_GET_FLOAT(p) (gsf_le_get_float (p))
#define GSF_LE_GET_DOUBLE(p) (gsf_le_get_double (p))
guint64 gsf_le_get_guint64 (void const *p);
float gsf_le_get_float (void const *p);
double gsf_le_get_double (void const *p);
#define GSF_LE_SET_GUINT8(p, dat) \
(*((guint8 *)(p)) = ((dat) & 0xff))
#define GSF_LE_SET_GUINT16(p, dat) \
((*((guint8 *)(p) + 0) = ((dat) & 0xff)),\
(*((guint8 *)(p) + 1) = ((dat) >> 8) & 0xff))
#define GSF_LE_SET_GUINT32(p, dat) \
((*((guint8 *)(p) + 0) = (guchar) ((dat)) & 0xff), \
(*((guint8 *)(p) + 1) = (guchar) ((dat) >> 8) & 0xff), \
(*((guint8 *)(p) + 2) = (guchar) ((dat) >> 16) & 0xff), \
(*((guint8 *)(p) + 3) = (guchar) ((dat) >> 24) & 0xff))
#define GSF_LE_SET_GUINT64(p, dat) \
((*((guint8 *)(p) + 0) = (guchar) ((dat)) & 0xff), \
(*((guint8 *)(p) + 1) = (guchar) ((dat) >> 8) & 0xff), \
(*((guint8 *)(p) + 2) = (guchar) ((dat) >> 16) & 0xff), \
(*((guint8 *)(p) + 3) = (guchar) ((dat) >> 24) & 0xff), \
(*((guint8 *)(p) + 4) = (guchar) ((dat) >> 32) & 0xff), \
(*((guint8 *)(p) + 5) = (guchar) ((dat) >> 40) & 0xff), \
(*((guint8 *)(p) + 6) = (guchar) ((dat) >> 48) & 0xff), \
(*((guint8 *)(p) + 7) = (guchar) ((dat) >> 56) & 0xff))
#define GSF_LE_SET_GINT8(p,dat) GSF_LE_SET_GUINT8((p),(dat))
#define GSF_LE_SET_GINT16(p,dat) GSF_LE_SET_GUINT16((p),(dat))
#define GSF_LE_SET_GINT32(p,dat) GSF_LE_SET_GUINT32((p),(dat))
#define GSF_LE_SET_GINT64(p,dat) GSF_LE_SET_GUINT64((p),(dat))
#define GSF_LE_SET_FLOAT(p,dat) gsf_le_set_float((p),(dat))
#define GSF_LE_SET_DOUBLE(p,dat) gsf_le_set_double((p),(dat))
void gsf_le_set_float (void *p, float f);
void gsf_le_set_double (void *p, double d);
void gsf_init (void);
void gsf_shutdown (void);
void gsf_init_dynamic (GTypeModule *module);
void gsf_shutdown_dynamic (GTypeModule *module);
/* Debugging utilities */
void gsf_mem_dump (guint8 const *ptr, size_t len);
void gsf_input_dump (GsfInput *input, gboolean dump_as_hex);
/* base64 encoding utilities */
guint8 *gsf_base64_encode_simple (guint8 const *data, size_t len);
size_t gsf_base64_encode_close (guint8 const *in, size_t inlen,
gboolean break_lines, guint8 *out,
int *state, guint *save);
size_t gsf_base64_encode_step (guint8 const *in, size_t len,
gboolean break_lines, guint8 *out,
int *state, guint *save);
size_t gsf_base64_decode_simple (guint8 *data, size_t len);
size_t gsf_base64_decode_step (guint8 const *in, size_t len,
guint8 *out, int *state, guint *save);
/* For putting filenames into error messages. */
char *gsf_filename_to_utf8 (char const *filename, gboolean quoted);
/* Some version checking */
extern int libgsf_major_version;
extern int libgsf_minor_version;
extern int libgsf_micro_version;
char const *gsf_extension_pointer (char const * path);
void gsf_iconv_close (GIConv handle);
void gsf_property_settings_collect_valist (GType object_type,
GParameter **p_params,
size_t *p_n_params,
const gchar *first_property_name,
va_list var_args);
void gsf_property_settings_collect (GType object_type,
GParameter **p_params,
size_t *p_n_params,
const gchar *first_property_name,
...);
void gsf_property_settings_free (GParameter *params,
size_t n_params);
/* Errors */
#define GSF_ERROR (gsf_error_quark ())
typedef enum {
GSF_ERROR_OUT_OF_MEMORY,
GSF_ERROR_INVALID_DATA
} GsfError;
GQuark gsf_error_quark (void);
G_END_DECLS
#endif /* GSF_UTILS_H */

View File

@@ -0,0 +1,117 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-zip-impl.h:
*
* Copyright (C) 2002-2004 Tambet Ingo (tambet@ximian.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_ZIP_IMPL_H
#define GSF_ZIP_IMPL_H
#include <gsf/gsf-outfile-zip.h> /* for GsfZipCompressionMethod */
G_BEGIN_DECLS
#define ZIP_HEADER_SIZE 30
#define ZIP_HEADER_VERSION 4
#define ZIP_HEADER_OS 5
#define ZIP_HEADER_FLAGS 6
#define ZIP_HEADER_COMP_METHOD 8
#define ZIP_HEADER_TIME 10
#define ZIP_HEADER_CRC 14
#define ZIP_HEADER_COMP_SIZE 18
#define ZIP_HEADER_UNCOMP_SIZE 22
#define ZIP_HEADER_NAME_LEN 26
#define ZIP_HEADER_EXTRA_LEN 28
#define ZIP_TRAILER_SIZE 22
#define ZIP_TRAILER_DISK 4
#define ZIP_TRAILER_DIR_DISK 6
#define ZIP_TRAILER_ENTRIES 8
#define ZIP_TRAILER_TOTAL_ENTRIES 10
#define ZIP_TRAILER_DIR_SIZE 12
#define ZIP_TRAILER_DIR_POS 16
#define ZIP_TRAILER_COMMENT_SIZE 20
#define ZIP_DIRENT_SIZE 46
#define ZIP_DIRENT_ENCODER 4
#define ZIP_DIRENT_EXTRACT 6
#define ZIP_DIRENT_FLAGS 8
#define ZIP_DIRENT_COMPR_METHOD 10
#define ZIP_DIRENT_DOSTIME 12
#define ZIP_DIRENT_CRC32 16
#define ZIP_DIRENT_CSIZE 20
#define ZIP_DIRENT_USIZE 24
#define ZIP_DIRENT_NAME_SIZE 28
#define ZIP_DIRENT_EXTRAS_SIZE 30
#define ZIP_DIRENT_COMMENT_SIZE 32
#define ZIP_DIRENT_DISKSTART 34
#define ZIP_DIRENT_FILE_TYPE 36
#define ZIP_DIRENT_FILE_MODE 38
#define ZIP_DIRENT_OFFSET 42
#define ZIP_FILE_HEADER_SIZE 30
#define ZIP_FILE_HEADER_EXTRACT 4
#define ZIP_FILE_HEADER_FLAGS 6
#define ZIP_FILE_HEADER_COMPR_METHOD 8
#define ZIP_FILE_HEADER_DOSTIME 10
#define ZIP_FILE_HEADER_CRC32 14
#define ZIP_FILE_HEADER_CSIZE 18
#define ZIP_FILE_HEADER_USIZE 22
#define ZIP_FILE_HEADER_NAME_SIZE 26
#define ZIP_FILE_HEADER_EXTRAS_SIZE 28
#define ZIP_NAME_SEPARATOR '/'
#define ZIP_BLOCK_SIZE 32768
#define ZIP_BUF_SIZE 512
/* z_flags */
#define ZZIP_IS_ENCRYPTED(p) ((*(unsigned char*)p)&1)
#define ZZIP_IS_COMPRLEVEL(p) (((*(unsigned char*)p)>>1)&3)
#define ZZIP_IS_STREAMED(p) (((*(unsigned char*)p)>>3)&1)
typedef struct {
char *name;
GsfZipCompressionMethod compr_method;
guint32 crc32;
size_t csize;
size_t usize;
gsf_off_t offset;
gsf_off_t data_offset;
guint32 dostime;
} GsfZipDirent;
typedef struct {
char *name;
gboolean is_directory;
GsfZipDirent *dirent;
GSList *children, *last_child;
} GsfZipVDir;
GsfZipDirent *gsf_zip_dirent_new (void);
void gsf_zip_dirent_free (GsfZipDirent *dirent);
GsfZipVDir *gsf_vdir_new (char const *name, gboolean is_directory,
GsfZipDirent *dirent);
void gsf_vdir_free (GsfZipVDir *vdir, gboolean free_dirent);
void gsf_vdir_add_child (GsfZipVDir *vdir, GsfZipVDir *child);
G_END_DECLS
#endif /* GSF_ZIP_IMPL_H */

View File

@@ -0,0 +1,85 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-zip-utils.c: tools for zip archive output.
*
* Copyright (C) 2002-2004 Jon K Hellan (hellan@acm.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Outc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <gsf-config.h>
#include <gsf/gsf.h>
#include <sys/types.h>
#include <string.h>
#include "gsf-zip-impl.h"
/* Doesn't do much, but include for symmetry */
GsfZipDirent*
gsf_zip_dirent_new (void)
{
return g_new0 (GsfZipDirent, 1);
}
void
gsf_zip_dirent_free (GsfZipDirent *dirent)
{
g_return_if_fail (dirent != NULL);
g_free (dirent->name);
dirent->name = NULL;
g_free (dirent);
}
GsfZipVDir *
gsf_vdir_new (char const *name, gboolean is_directory, GsfZipDirent *dirent)
{
GsfZipVDir *vdir = g_new (GsfZipVDir, 1);
vdir->name = g_strdup (name);
vdir->is_directory = is_directory;
vdir->dirent = dirent;
vdir->children = NULL;
return vdir;
}
void
gsf_vdir_free (GsfZipVDir *vdir, gboolean free_dirent)
{
GSList *l;
if (!vdir)
return;
for (l = vdir->children; l; l = l->next)
gsf_vdir_free ((GsfZipVDir *)l->data, free_dirent);
g_slist_free (vdir->children);
g_free (vdir->name);
if (free_dirent && vdir->dirent)
gsf_zip_dirent_free (vdir->dirent);
g_free (vdir);
}
void
gsf_vdir_add_child (GsfZipVDir *vdir, GsfZipVDir *child)
{
GSList *tail = g_slist_append (NULL, child);
if (vdir->children)
vdir->last_child->next = tail;
else
vdir->children = tail;
vdir->last_child = tail;
}

View File

@@ -0,0 +1,48 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf.h:
*
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef GSF_H
#define GSF_H
#include <glib.h>
G_BEGIN_DECLS
typedef struct _GsfInput GsfInput;
typedef struct _GsfInfile GsfInfile;
typedef struct _GsfOutput GsfOutput;
typedef struct _GsfOutfile GsfOutfile;
typedef struct _GsfDocProp GsfDocProp;
typedef struct _GsfDocMetaData GsfDocMetaData;
typedef struct _GsfTimestamp GsfTimestamp;
/* FIXME:
* gsf_off_t is really supposed to be the widest type off_t can be configured
* to on the platform
*/
typedef gint64 gsf_off_t;
#define GSF_OFF_T_FORMAT G_GINT64_FORMAT
G_END_DECLS
#endif /* GSF_H */

View File

@@ -0,0 +1,3 @@
int libgsf_major_version = @LIBGSF_MAJOR_VERSION@; /* The ABI version */
int libgsf_minor_version = @LIBGSF_MINOR_VERSION@; /* The API version */
int libgsf_micro_version = @LIBGSF_MICRO_VERSION@; /* bug fixes */