diff options
author | Marc-André Lureau <marcandre.lureau@gmail.com> | 2012-12-18 14:35:14 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2013-01-09 13:56:07 +0100 |
commit | 0a97c9f43718d34aacc834c60f3ced60e9ce956f (patch) | |
tree | 7a5b5975cd92862283df669f9af62005fe63baa9 /libmsi | |
parent | 880b9016b1d751d480a282b9a8556c54701a86f4 (diff) | |
download | msitools-0a97c9f43718d34aacc834c60f3ced60e9ce956f.tar.gz msitools-0a97c9f43718d34aacc834c60f3ced60e9ce956f.tar.xz msitools-0a97c9f43718d34aacc834c60f3ced60e9ce956f.zip |
record: add set_stream() and get_stream() using GIO
Use GInputStream for record stream manipulation
Diffstat (limited to 'libmsi')
-rw-r--r-- | libmsi/Makefile.am | 1 | ||||
-rw-r--r-- | libmsi/libmsi-istream.c | 155 | ||||
-rw-r--r-- | libmsi/libmsi-istream.h | 47 | ||||
-rw-r--r-- | libmsi/libmsi-record.c | 123 | ||||
-rw-r--r-- | libmsi/msipriv.h | 5 |
5 files changed, 280 insertions, 51 deletions
diff --git a/libmsi/Makefile.am b/libmsi/Makefile.am index c03e7ab..38dbe2e 100644 --- a/libmsi/Makefile.am +++ b/libmsi/Makefile.am @@ -17,6 +17,7 @@ libmsi_la_SOURCES = \ drop.c \ insert.c \ libmsi-database.c \ + libmsi-istream.c \ libmsi-query.c \ libmsi-record.c \ libmsi-summary-info.c \ diff --git a/libmsi/libmsi-istream.c b/libmsi/libmsi-istream.c new file mode 100644 index 0000000..85653e5 --- /dev/null +++ b/libmsi/libmsi-istream.c @@ -0,0 +1,155 @@ +/* + * This library 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.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "msipriv.h" +#include "libmsi-istream.h" + +struct _LibmsiIStream +{ + GInputStream parent; + + GsfInput *input; +}; + +static void libmsi_seekable_iface_init (GSeekableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (LibmsiIStream, libmsi_istream, G_TYPE_INPUT_STREAM, + G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE, + libmsi_seekable_iface_init); + ) + +static goffset +libmsi_tell (GSeekable *seekable) +{ + g_return_val_if_fail (LIBMSI_IS_ISTREAM(seekable), FALSE); + + return gsf_input_tell (LIBMSI_ISTREAM(seekable)->input); +} + +static gboolean +libmsi_can_seek (GSeekable *seekable) +{ + return TRUE; +} + +static gboolean +libmsi_seek (GSeekable *seekable, goffset offset, + GSeekType type, GCancellable *cancellable) +{ + g_return_val_if_fail (LIBMSI_IS_ISTREAM(seekable), FALSE); + + return !gsf_input_seek (LIBMSI_ISTREAM(seekable)->input, offset, type); +} + +static gboolean +libmsi_can_truncate (GSeekable *seekable) +{ + return FALSE; +} + +static void +libmsi_seekable_iface_init (GSeekableIface *iface) +{ + iface->tell = libmsi_tell; + iface->can_seek = libmsi_can_seek; + iface->seek = libmsi_seek; + iface->can_truncate = libmsi_can_truncate; +} + +static void +libmsi_istream_init (LibmsiIStream *self) +{ +} + +static void +libmsi_istream_finalize (GObject *object) +{ + LibmsiIStream *self = LIBMSI_ISTREAM (object); + + if (self->input) + g_object_unref (self->input); + + G_OBJECT_CLASS (libmsi_istream_parent_class)->finalize (object); +} + +static gssize +input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + LibmsiIStream *self = LIBMSI_ISTREAM (stream); + gssize remaining = gsf_input_remaining (self->input); + + if (remaining == 0) + return 0; + + count = MIN(count, remaining); + if (!gsf_input_read (self->input, count, buffer)) + return -1; + + return count; +} + +static gssize +input_stream_skip (GInputStream *stream, + gsize count, + GCancellable *cancellable, + GError **error) +{ + LibmsiIStream *self = LIBMSI_ISTREAM (stream); + + count = MIN (count, gsf_input_remaining (self->input)); + if (!gsf_input_seek (self->input, count, G_SEEK_CUR)) + return -1; + + return count; +} + +static gboolean +input_stream_close (GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + return TRUE; +} + +static void +libmsi_istream_class_init (LibmsiIStreamClass *klass) +{ + GObjectClass* object_class = G_OBJECT_CLASS (klass); + GInputStreamClass *istream_class; + + object_class->finalize = libmsi_istream_finalize; + + istream_class = G_INPUT_STREAM_CLASS (klass); + istream_class->read_fn = input_stream_read; + istream_class->skip = input_stream_skip; + istream_class->close_fn = input_stream_close; +} + +G_GNUC_INTERNAL LibmsiIStream * +libmsi_istream_new (GsfInput *input) +{ + GsfInput *dup = gsf_input_dup (input, NULL); + g_return_val_if_fail (dup, NULL); + + LibmsiIStream *self = g_object_new (LIBMSI_TYPE_ISTREAM, NULL); + self->input = dup; + + return self; +} diff --git a/libmsi/libmsi-istream.h b/libmsi/libmsi-istream.h new file mode 100644 index 0000000..c835bd9 --- /dev/null +++ b/libmsi/libmsi-istream.h @@ -0,0 +1,47 @@ +/* + * This library 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.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _LIBMSI_ISTREAM_H +#define _LIBMSI_ISTREAM_H + +#include <glib-object.h> +#include <gio/gio.h> + +#include "libmsi-types.h" + +G_BEGIN_DECLS + +#define LIBMSI_TYPE_ISTREAM (libmsi_istream_get_type ()) +#define LIBMSI_ISTREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LIBMSI_TYPE_ISTREAM, LibmsiIStream)) +#define LIBMSI_ISTREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LIBMSI_TYPE_ISTREAM, LibmsiIStreamClass)) +#define LIBMSI_IS_ISTREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LIBMSI_TYPE_ISTREAM)) +#define LIBMSI_IS_ISTREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LIBMSI_TYPE_ISTREAM)) +#define LIBMSI_ISTREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LIBMSI_TYPE_ISTREAM, LibmsiIStreamClass)) + +typedef struct _LibmsiIStreamClass LibmsiIStreamClass; + +struct _LibmsiIStreamClass +{ + GOutputStreamClass parent_class; +}; + +GType libmsi_istream_get_type (void) G_GNUC_CONST; + +gssize libmsi_istream_get_size (LibmsiIStream *ostream); + +G_END_DECLS + +#endif /* _LIBMSI_ISTREAM_H */ diff --git a/libmsi/libmsi-record.c b/libmsi/libmsi-record.c index aa77ad6..da5d8bf 100644 --- a/libmsi/libmsi-record.c +++ b/libmsi/libmsi-record.c @@ -577,80 +577,101 @@ libmsi_record_load_stream(LibmsiRecord *rec, unsigned field, const char *szFilen return ret == LIBMSI_RESULT_SUCCESS; } -unsigned _libmsi_record_save_stream(const LibmsiRecord *rec, unsigned field, char *buf, unsigned *sz) +/** + * libmsi_record_set_stream: + * @record: a #LibmsiRecord + * @field: a field identifier + * @input: a #GInputStream + * @count: the number of bytes to read from @input + * @cancellable: (allow-none): optional GCancellable object, %NULL to ignore + * @error: (allow-none): #GError to set on error, or %NULL + * + * Set the stream content from @input stream. + * + * Returns: %TRUE on success + **/ +gboolean +libmsi_record_set_stream (LibmsiRecord *rec, guint field, + GInputStream *input, gsize count, + GCancellable *cancellable, GError **error) { - uint64_t left; - GsfInput *stm; - - TRACE("%p %d %p %p\n", rec, field, buf, sz); - - if( !sz ) - return LIBMSI_RESULT_INVALID_PARAMETER; - - if( field > rec->count) - return LIBMSI_RESULT_INVALID_PARAMETER; - - if ( rec->fields[field].type == LIBMSI_FIELD_TYPE_NULL ) - { - *sz = 0; - return LIBMSI_RESULT_INVALID_DATA; + g_return_val_if_fail (LIBMSI_IS_RECORD (rec), FALSE); + g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE); + g_return_val_if_fail (field > 0 && field <= rec->count, FALSE); + g_return_val_if_fail (count > 0, FALSE); + g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (!error || *error == NULL, FALSE); + + gsize bytes_read = 0; + GsfInput *stm = NULL; + guint8 *data = g_malloc (count); + + if (!g_input_stream_read_all (input, data, count, &bytes_read, + cancellable, error) || + bytes_read != count) { + g_free (data); + return FALSE; } - if( rec->fields[field].type != LIBMSI_FIELD_TYPE_STREAM ) - return LIBMSI_RESULT_INVALID_DATATYPE; + stm = gsf_input_memory_new (data, count, TRUE); + if (_libmsi_record_load_stream (rec, field, stm) != LIBMSI_RESULT_SUCCESS) { + g_object_unref (stm); + return FALSE; + } - stm = rec->fields[field].u.stream; - if( !stm ) - return LIBMSI_RESULT_INVALID_PARAMETER; + return TRUE; +} - left = gsf_input_size(stm) - gsf_input_tell(stm); +static GsfInput * +_libmsi_record_get_stream (LibmsiRecord *rec, unsigned field, GError **error) +{ + GsfInput *stm; - /* if there's no buffer pointer, calculate the length to the end */ - if( !buf ) - { - *sz = left; + if (field > rec->count) { + g_set_error (error, LIBMSI_RESULT_ERROR, LIBMSI_RESULT_INVALID_PARAMETER, G_STRFUNC); + return NULL; + } - return LIBMSI_RESULT_SUCCESS; + if (rec->fields[field].type == LIBMSI_FIELD_TYPE_NULL) { + g_set_error (error, LIBMSI_RESULT_ERROR, LIBMSI_RESULT_INVALID_DATA, G_STRFUNC); + return NULL; } - /* read the data */ - if (*sz > left) - *sz = left; + if (rec->fields[field].type != LIBMSI_FIELD_TYPE_STREAM) { + g_set_error (error, LIBMSI_RESULT_ERROR, LIBMSI_RESULT_INVALID_DATATYPE, G_STRFUNC); + return NULL; + } - if (*sz > 0 && !gsf_input_read( stm, *sz, buf )) - { - *sz = 0; - return LIBMSI_RESULT_FUNCTION_FAILED; + stm = rec->fields[field].u.stream; + if (!stm) { + g_set_error (error, LIBMSI_RESULT_ERROR, LIBMSI_RESULT_INVALID_PARAMETER, G_STRFUNC); + return NULL; } - return LIBMSI_RESULT_SUCCESS; + return stm; } /** - * libmsi_record_save_stream: - * @rec: a %LibmsiRecord + * libmsi_record_get_stream: + * @record: a #LibmsiRecord * @field: a field identifier - * @buf: a buffer of size specified by %sz, or %NULL to return size - * @sz: a pointer to %buf size * - * Read the stream data into %buf from record %field. + * Get the stream associated with the given record @field. * - * Returns: %TRUE on success. + * Returns: (transfer full): a new #GInputStream **/ -gboolean -libmsi_record_save_stream(LibmsiRecord *rec, unsigned field, char *buf, unsigned *sz) +GInputStream * +libmsi_record_get_stream (LibmsiRecord *rec, guint field) { - unsigned ret; - - TRACE("%d %d %p %p\n", rec, field, buf, sz); + GsfInput *stm; - g_return_val_if_fail (LIBMSI_IS_RECORD (rec), FALSE); + g_return_val_if_fail (LIBMSI_IS_RECORD (rec), NULL); - g_object_ref(rec); - ret = _libmsi_record_save_stream( rec, field, buf, sz ); - g_object_unref(rec); + stm = _libmsi_record_get_stream (rec, field, NULL); + if (!stm) + return NULL; - return ret == LIBMSI_RESULT_SUCCESS; + return G_INPUT_STREAM (libmsi_istream_new (stm)); } unsigned _libmsi_record_set_gsf_input( LibmsiRecord *rec, unsigned field, GsfInput *stm ) diff --git a/libmsi/msipriv.h b/libmsi/msipriv.h index a74f9a5..4c52718 100644 --- a/libmsi/msipriv.h +++ b/libmsi/msipriv.h @@ -304,6 +304,8 @@ struct _LibmsiSummaryInfo LibmsiOLEVariant property[MSI_MAX_PROPS]; }; +typedef struct _LibmsiIStream LibmsiIStream; + extern const char clsid_msi_transform[16]; extern const char clsid_msi_database[16]; extern const char clsid_msi_patch[16]; @@ -415,6 +417,9 @@ extern unsigned msi_view_get_row(LibmsiDatabase *, LibmsiView *, unsigned, Libms /* summary information */ extern unsigned msi_add_suminfo( LibmsiDatabase *db, char ***records, int num_records, int num_columns ); +/* IStream internals */ +LibmsiIStream * libmsi_istream_new (GsfInput *input); + /* Helpers */ extern char *msi_dup_record_field(LibmsiRecord *row, int index); extern char *msi_dup_property( LibmsiDatabase *db, const char *prop ); |