[gcab] Implement listing files
- From: Marc-Andre Lureau <malureau src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcab] Implement listing files
- Date: Fri, 4 Jan 2013 22:58:05 +0000 (UTC)
commit a0f79f442229b6ca0413cb4eec45fce9f7b9143a
Author: Marc-Andrà Lureau <marcandre lureau gmail com>
Date: Sat Dec 22 03:34:22 2012 +0100
Implement listing files
gcab.c | 41 +++++++-
libgcab.syms | 1 +
libgcab/cabinet.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++
libgcab/cabinet.h | 39 +++++++-
libgcab/gcab-cabinet.c | 105 +++++++++++++++++++-
libgcab/gcab-cabinet.h | 16 +++-
libgcab/gcab-file.c | 16 +++
libgcab/gcab-folder.c | 73 ++++++++++++--
libgcab/gcab-folder.h | 1 +
libgcab/gcab-priv.h | 4 +
tests/testsuite.at | 6 +-
11 files changed, 547 insertions(+), 21 deletions(-)
---
diff --git a/gcab.c b/gcab.c
index cdc7dc8..930640d 100644
--- a/gcab.c
+++ b/gcab.c
@@ -69,8 +69,12 @@ main (int argc, char *argv[])
gchar **args = NULL;
int nopath = 0;
int compress = 0;
+ int list = 0;
+ int create = 0;
GOptionEntry entries[] = {
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, N_("Be verbose"), NULL },
+ { "list", 't', 0, G_OPTION_ARG_NONE, &list, N_("List content"), NULL },
+ { "create", 'c', 0, G_OPTION_ARG_NONE, &create, N_("Create archive"), NULL },
{ "zip", 'z', 0, G_OPTION_ARG_NONE, &compress, N_("Use zip compression"), NULL },
{ "nopath", 'n', 0, G_OPTION_ARG_NONE, &nopath, N_("Do not include path"), NULL },
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("FILE INPUT_FILES...") },
@@ -89,7 +93,8 @@ main (int argc, char *argv[])
g_option_context_set_description (context, s);
g_free(s);
g_option_context_set_summary (context, "\
-gcab saves many files together into a cabinet archive.\
+gcab saves many files together into a cabinet archive, and can restore\n\
+individual files from the archive.\
");
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
@@ -97,9 +102,35 @@ gcab saves many files together into a cabinet archive.\
gcab_error (_("option parsing failed: %s\n"), error->message);
g_option_context_free(context);
+ if ((list + create) != 1)
+ gcab_error (_("Please specify a single operation."));
if (!args || args[0] == NULL)
- gcab_error (_("output cabinet file must be specified."));
+ gcab_error (_("cabinet file must be specified."));
+
+ GCancellable *cancellable = g_cancellable_new ();
+ GCabCabinet *cabinet = gcab_cabinet_new ();
+
+ if (list) {
+ GFile *file = g_file_new_for_commandline_arg (args[0]);
+ GInputStream *in = G_INPUT_STREAM (g_file_read (file, cancellable, &error));
+
+ if (!in)
+ gcab_error (_("can't open %s for reading: %s\n"), args[0], error->message);
+ if (!gcab_cabinet_load (cabinet, in, cancellable, &error))
+ gcab_error (_("error reading %s: %s\n"), args[0], error->message);
+
+ GPtrArray *folders = gcab_cabinet_get_folders (cabinet);
+ for (i = 0; i < folders->len; i++) {
+ GList *l, *list = gcab_folder_get_files (g_ptr_array_index (folders, i));
+ for (l = list; l != NULL; l = l->next)
+ g_print ("%s\n", gcab_file_get_name (GCAB_FILE (l->data)));
+ g_list_free (list);
+ }
+ g_object_unref (in);
+ g_object_unref (file);
+ goto end;
+ }
if (args[1] == NULL)
gcab_error (_("please specify input files."));
@@ -132,7 +163,6 @@ gcab saves many files together into a cabinet archive.\
gcab_error (_("can't create cab file %s: %s"), args[0], error->message);
GFile *cwd = g_file_new_for_commandline_arg (".");
- GCabCabinet *cabinet = gcab_cabinet_new ();
if (!gcab_cabinet_add_folder (cabinet, folder, &error))
gcab_error (_("can't add folder to cabinet: %s"), args[0], error->message);
@@ -144,10 +174,13 @@ gcab saves many files together into a cabinet archive.\
&error))
gcab_error (_("can't write cab file %s: %s"), args[0], error->message);
- g_object_unref (cabinet);
g_object_unref (cwd);
g_object_unref (output);
g_object_unref (outputfile);
+end:
+ g_object_unref (cabinet);
+ g_object_unref (cancellable);
+
return 0;
}
diff --git a/libgcab.syms b/libgcab.syms
index 48f90e4..25e2317 100644
--- a/libgcab.syms
+++ b/libgcab.syms
@@ -6,6 +6,7 @@ LIBGCAB1_0.0 {
gcab_cabinet_new;
gcab_cabinet_write;
gcab_compression_get_type;
+ gcab_error_quark;
gcab_file_get_file;
gcab_file_get_name;
gcab_file_get_type;
diff --git a/libgcab/cabinet.c b/libgcab/cabinet.c
index a946968..fb0b370 100644
--- a/libgcab/cabinet.c
+++ b/libgcab/cabinet.c
@@ -43,6 +43,98 @@ cdata_set (cdata_t *cd, int type, guint8 *data, size_t size)
}
}
+static char *
+_data_input_stream_read_until (GDataInputStream *stream,
+ const gchar *stop_chars,
+ gsize stop_len,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GBufferedInputStream *bstream;
+ gchar *result;
+
+ bstream = G_BUFFERED_INPUT_STREAM (stream);
+
+ result = g_data_input_stream_read_upto (stream, stop_chars, stop_len,
+ NULL, cancellable, error);
+
+ /* If we're not at end of stream then we have a stop_char to consume. */
+ if (result != NULL && g_buffered_input_stream_get_available (bstream) > 0)
+ {
+ gsize res;
+ gchar b;
+
+ res = g_input_stream_read (G_INPUT_STREAM (stream), &b, 1, NULL, NULL);
+ g_assert (res == 1);
+ }
+
+ return result;
+}
+
+#define R1(val) G_STMT_START{ \
+ val = g_data_input_stream_read_byte (in, cancellable, error); \
+ if (*error) \
+ goto end; \
+}G_STMT_END
+#define R2(val) G_STMT_START{ \
+ val = g_data_input_stream_read_uint16 (in, cancellable, error); \
+ if (*error) \
+ goto end; \
+}G_STMT_END
+#define R4(val) G_STMT_START{ \
+ val = g_data_input_stream_read_uint32 (in, cancellable, error); \
+ if (*error) \
+ goto end; \
+}G_STMT_END
+#define RS(val) G_STMT_START{ \
+ val = _data_input_stream_read_until (in, "\0", 1, \
+ cancellable, error); \
+ if (*error) \
+ goto end; \
+}G_STMT_END
+#define RN(buff, size) G_STMT_START{ \
+ if (size) { \
+ g_input_stream_read (G_INPUT_STREAM (in), buff, size, cancellable, error); \
+ if (*error) \
+ goto end; \
+ } \
+}G_STMT_END
+
+static void
+hexdump (guchar *p, gsize s)
+{
+ gsize i;
+
+ for (i = 0; i < s; i++) {
+ if (i != 0) {
+ if (i % 16 == 0)
+ g_printerr ("\n");
+ else if (i % 8 == 0)
+ g_printerr (" ");
+ else
+ g_printerr (" ");
+ }
+
+ if (i % 16 == 0)
+ g_printerr ("%.8x ", i);
+
+ g_printerr ("%.2x", p[i]);
+ }
+
+ g_printerr ("\n");
+}
+
+#define P1(p, field) \
+ g_debug ("%15s: %.2x", #field, p->field)
+#define P2(p, field) \
+ g_debug ("%15s: %.4x", #field, p->field)
+#define P4(p, field) \
+ g_debug ("%15s: %.8x", #field, p->field)
+#define PS(p, field) \
+ g_debug ("%15s: %s", #field, p->field)
+#define PN(p, field, size) \
+ g_debug ("%15s:", #field), hexdump (p->field, size)
+
#define W1(val) \
g_data_output_stream_put_byte (out, val, cancellable, error)
#define W2(val) \
@@ -75,6 +167,92 @@ cheader_write (cheader_t *ch, GDataOutputStream *out,
}
G_GNUC_INTERNAL gboolean
+cheader_read (cheader_t *ch, GDataInputStream *in,
+ GCancellable *cancellable, GError **error)
+{
+ gboolean success = FALSE;
+ guint8 sig[4];
+
+ R1 (sig[0]);
+ R1 (sig[1]);
+ R1 (sig[2]);
+ R1 (sig[3]);
+ if (memcmp (sig, "MSCF", 4)) {
+ g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT,
+ "The input is not of cabinet format");
+ goto end;
+ }
+
+ R4 (ch->res1);
+ R4 (ch->size);
+ R4 (ch->res2);
+ R4 (ch->offsetfiles);
+ R4 (ch->res3);
+ R1 (ch->versionMIN);
+ R1 (ch->versionMAJ);
+ R2 (ch->nfolders);
+ R2 (ch->nfiles);
+ R2 (ch->flags);
+ R2 (ch->setID);
+ R2 (ch->cabID);
+
+ if (ch->flags & CABINET_HEADER_RESERVE) {
+ R2 (ch->res_header);
+ R1 (ch->res_folder);
+ R1 (ch->res_data);
+ ch->reserved = g_malloc (ch->res_header);
+ RN (ch->reserved, ch->res_header);
+ }
+
+ if (ch->flags & CABINET_HEADER_PREV) {
+ RS (ch->cab_prev);
+ RS (ch->disk_prev);
+ }
+
+ if (ch->flags & CABINET_HEADER_NEXT) {
+ RS (ch->cab_next);
+ RS (ch->disk_next);
+ }
+
+ if (g_getenv ("GCAB_DEBUG")) {
+ g_debug ("CFHEADER");
+ P4 (ch, res1);
+ P4 (ch, size);
+ P4 (ch, res2);
+ P4 (ch, offsetfiles);
+ P4 (ch, res3);
+ P1 (ch, versionMIN);
+ P1 (ch, versionMAJ);
+ P2 (ch, nfolders);
+ P2 (ch, nfiles);
+ P2 (ch, flags);
+ P2 (ch, setID);
+ P2 (ch, cabID);
+ if (ch->flags & CABINET_HEADER_RESERVE) {
+ P2 (ch, res_header);
+ P1 (ch, res_folder);
+ P1 (ch, res_data);
+ if (ch->res_header)
+ PN (ch, reserved, ch->res_header);
+ }
+ if (ch->flags & CABINET_HEADER_PREV) {
+ PS (ch, cab_prev);
+ PS (ch, disk_prev);
+ }
+ if (ch->flags & CABINET_HEADER_NEXT) {
+ PS (ch, cab_next);
+ PS (ch, disk_next);
+ }
+
+ }
+
+ success = TRUE;
+
+end:
+ return success;
+}
+
+G_GNUC_INTERNAL gboolean
cfolder_write (cfolder_t *cf, GDataOutputStream *out,
GCancellable *cancellable, GError **error)
{
@@ -86,6 +264,32 @@ cfolder_write (cfolder_t *cf, GDataOutputStream *out,
return TRUE;
}
+G_GNUC_INTERNAL gboolean
+cfolder_read (cfolder_t *cf, u1 res_size, GDataInputStream *in,
+ GCancellable *cancellable, GError **error)
+{
+ gboolean success = FALSE;
+
+ R4 (cf->offsetdata);
+ R2 (cf->ndatab);
+ R2 (cf->typecomp);
+ cf->reserved = g_malloc (res_size);
+ RN (cf->reserved, res_size);
+
+ if (g_getenv ("GCAB_DEBUG")) {
+ g_debug ("CFOLDER");
+ P4 (cf, offsetdata);
+ P2 (cf, ndatab);
+ P2 (cf, typecomp);
+ if (res_size)
+ PN (cf, reserved, res_size);
+ }
+
+ success = TRUE;
+
+end:
+ return success;
+}
G_GNUC_INTERNAL gboolean
cfile_write (cfile_t *cf, GDataOutputStream *out,
@@ -103,6 +307,38 @@ cfile_write (cfile_t *cf, GDataOutputStream *out,
return TRUE;
}
+
+G_GNUC_INTERNAL gboolean
+cfile_read (cfile_t *cf, GDataInputStream *in,
+ GCancellable *cancellable, GError **error)
+{
+ gboolean success = FALSE;
+
+ R4 (cf->usize);
+ R4 (cf->uoffset);
+ R2 (cf->index);
+ R2 (cf->date);
+ R2 (cf->time);
+ R2 (cf->fattr);
+ RS (cf->name);
+
+ if (g_getenv ("GCAB_DEBUG")) {
+ g_debug ("CFILE");
+ P4 (cf, usize);
+ P4 (cf, uoffset);
+ P2 (cf, index);
+ P2 (cf, date);
+ P2 (cf, time);
+ P2 (cf, fattr);
+ PS (cf, name);
+ }
+
+ success = TRUE;
+
+end:
+ return success;
+}
+
typedef unsigned long int CHECKSUM;
static CHECKSUM
@@ -159,3 +395,33 @@ cdata_write (cdata_t *cd, GDataOutputStream *out, int type,
return TRUE;
}
+
+G_GNUC_INTERNAL gboolean
+cdata_read (cdata_t *cd, u1 res_data, GDataInputStream *in,
+ GCancellable *cancellable, GError **error)
+
+{
+ gboolean success = FALSE;
+
+ R4 (cd->checksum);
+ R2 (cd->ncbytes);
+ R2 (cd->nubytes);
+ cd->reserved = g_malloc (res_data);
+ RN (cd->reserved, res_data);
+ RN (cd->data, cd->ncbytes);
+
+ if (g_getenv ("GCAB_DEBUG")) {
+ g_debug ("CDATA");
+ P4 (cd, checksum);
+ P2 (cd, ncbytes);
+ P2 (cd, nubytes);
+ if (res_data)
+ PN (cd, reserved, res_data);
+ PN (cd, data, 64);
+ }
+
+ success = TRUE;
+
+end:
+ return success;
+}
diff --git a/libgcab/cabinet.h b/libgcab/cabinet.h
index 3d575c9..264df46 100644
--- a/libgcab/cabinet.h
+++ b/libgcab/cabinet.h
@@ -37,7 +37,6 @@ typedef struct cdata cdata_t;
#define CFO_START 0x24 /* folder offset */
#define CFI_START 0x2C /* file offset */
-
struct cheader
{
u4 res1;
@@ -52,13 +51,28 @@ struct cheader
u2 flags;
u2 setID;
u2 cabID;
+ u2 res_header;
+ u1 res_folder;
+ u1 res_data;
+ guint8 *reserved;
+ gchar *cab_prev;
+ gchar *disk_prev;
+ gchar *cab_next;
+ gchar *disk_next;
};
+typedef enum {
+ CABINET_HEADER_PREV = 0x0001,
+ CABINET_HEADER_NEXT = 0x0002,
+ CABINET_HEADER_RESERVE = 0x0004,
+} CabinetHeaderFlags;
+
struct cfolder
{
u4 offsetdata;
u2 ndatab;
u2 typecomp;
+ guint8 *reserved;
};
struct cfile
@@ -77,6 +91,7 @@ struct cdata
u4 checksum;
u2 ncbytes;
u2 nubytes;
+ guint8 *reserved;
guint8 data[DATABLOCKSIZE*2];
};
@@ -84,10 +99,27 @@ gboolean cheader_write (cheader_t *ch,
GDataOutputStream *out,
GCancellable *cancellable,
GError **error);
+gboolean cheader_read (cheader_t *ch,
+ GDataInputStream *in,
+ GCancellable *cancellable,
+ GError **error);
gboolean cfolder_write (cfolder_t *cf,
GDataOutputStream *out,
GCancellable *cancellable,
GError **error);
+gboolean cfolder_read (cfolder_t *cf,
+ u1 res_folder,
+ GDataInputStream *in,
+ GCancellable *cancellable,
+ GError **error);
+gboolean cfile_write (cfile_t *cf,
+ GDataOutputStream *out,
+ GCancellable *cancellable,
+ GError **error);
+gboolean cfile_read (cfile_t *cf,
+ GDataInputStream *in,
+ GCancellable *cancellable,
+ GError **error);
gboolean cdata_write (cdata_t *cd,
GDataOutputStream *out,
int type,
@@ -96,8 +128,9 @@ gboolean cdata_write (cdata_t *cd,
gsize *bytes_written,
GCancellable *cancellable,
GError **error);
-gboolean cfile_write (cfile_t *cf,
- GDataOutputStream *out,
+gboolean cdata_read (cdata_t *cd,
+ u1 res_data,
+ GDataInputStream *in,
GCancellable *cancellable,
GError **error);
diff --git a/libgcab/gcab-cabinet.c b/libgcab/gcab-cabinet.c
index 3d1a0c7..20c638a 100644
--- a/libgcab/gcab-cabinet.c
+++ b/libgcab/gcab-cabinet.c
@@ -10,14 +10,23 @@ struct _GCabCabinet
GObject parent_instance;
GPtrArray *folders;
+ GByteArray *reserved;
};
enum {
PROP_0,
+
+ PROP_RESERVED
};
G_DEFINE_TYPE (GCabCabinet, gcab_cabinet, G_TYPE_OBJECT);
+GQuark
+gcab_error_quark (void)
+{
+ return g_quark_from_static_string ("gcab-error-quark");
+}
+
static void
gcab_cabinet_init (GCabCabinet *self)
{
@@ -30,6 +39,8 @@ gcab_cabinet_finalize (GObject *object)
GCabCabinet *self = GCAB_CABINET (object);
g_ptr_array_unref (self->folders);
+ if (self->reserved)
+ g_byte_array_unref (self->reserved);
G_OBJECT_CLASS (gcab_cabinet_parent_class)->finalize (object);
}
@@ -38,8 +49,14 @@ static void
gcab_cabinet_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
g_return_if_fail (GCAB_IS_CABINET (object));
+ GCabCabinet *self = GCAB_CABINET (object);
switch (prop_id) {
+ case PROP_RESERVED:
+ if (self->reserved)
+ g_byte_array_unref (self->reserved);
+ self->reserved = g_value_dup_boxed (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -50,8 +67,12 @@ static void
gcab_cabinet_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
g_return_if_fail (GCAB_IS_CABINET (object));
+ GCabCabinet *self = GCAB_CABINET (object);
switch (prop_id) {
+ case PROP_RESERVED:
+ g_value_set_boxed (value, self->reserved);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -66,6 +87,11 @@ gcab_cabinet_class_init (GCabCabinetClass *klass)
object_class->finalize = gcab_cabinet_finalize;
object_class->set_property = gcab_cabinet_set_property;
object_class->get_property = gcab_cabinet_get_property;
+
+ g_object_class_install_property (object_class, PROP_RESERVED,
+ g_param_spec_boxed ("reserved", "Reserved", "Reserved",
+ G_TYPE_BYTE_ARRAY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
/**
@@ -101,7 +127,7 @@ gcab_cabinet_add_folder (GCabCabinet *self,
GPtrArray *
gcab_cabinet_get_folders (GCabCabinet *self)
{
- g_return_val_if_fail (GCAB_IS_FOLDER (self), NULL);
+ g_return_val_if_fail (GCAB_IS_CABINET (self), NULL);
return self->folders;
}
@@ -139,6 +165,7 @@ gcab_cabinet_write (GCabCabinet *self,
g_return_val_if_fail (GCAB_IS_CABINET (self), FALSE);
g_return_val_if_fail (G_IS_OUTPUT_STREAM (out), FALSE);
g_return_val_if_fail (G_IS_SEEKABLE (out), FALSE);
+ g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (!error || *error == NULL, FALSE);
/* FIXME: current limitation of 1 folder */
g_return_val_if_fail (self->folders->len == 1, FALSE);
@@ -231,6 +258,8 @@ gcab_cabinet_write (GCabCabinet *self,
end:
g_clear_object (&dstream);
g_clear_object (&in);
+
+ return success;
}
/**
@@ -243,3 +272,77 @@ gcab_cabinet_new (void)
{
return g_object_new (GCAB_TYPE_CABINET, NULL);
}
+
+/**
+ * gcab_cabinet_load:
+ * @cabinet: a #GCabCabinet
+ * @stream: a #GInputStream
+ * @cancellable: (allow-none): optional #GCancellable object,
+ * %NULL to ignore
+ * @error: (allow-none): #GError to set on error, or %NULL
+ *
+ * Load a cabinet archive.
+ *
+ * Returns: %TRUE on success
+ **/
+gboolean
+gcab_cabinet_load (GCabCabinet *self,
+ GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (GCAB_IS_CABINET (self), FALSE);
+ g_return_val_if_fail (G_IS_INPUT_STREAM (stream), FALSE);
+ g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (!error || *error == NULL, FALSE);
+ g_return_val_if_fail (self->folders->len == 0, FALSE);
+
+ gboolean success = FALSE;
+ cheader_t cheader;
+ int i;
+ GDataInputStream *in = g_data_input_stream_new (stream);
+ g_data_input_stream_set_byte_order (in, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
+ GPtrArray *folders = self->folders;
+
+ if (!cheader_read (&cheader, in, cancellable, error))
+ goto end;
+
+ if (cheader.reserved)
+ g_object_set (self, "reserved",
+ g_byte_array_new_take (cheader.reserved, cheader.res_header),
+ NULL);
+
+ for (i = 0; i < cheader.nfolders; i++) {
+ cfolder_t cfolder = { 0, };
+ if (!cfolder_read (&cfolder, cheader.res_folder, in, cancellable, error))
+ goto end;
+
+ GCabFolder *folder = gcab_folder_new_with_cfolder (&cfolder);
+ if (cfolder.reserved)
+ g_object_set (folder, "reserved",
+ g_byte_array_new_take (cfolder.reserved, cheader.res_folder),
+ NULL);
+ g_ptr_array_add (folders, folder);
+ cfolder.reserved = NULL;
+ }
+
+ for (i = 0; i < cheader.nfiles; i++) {
+ cfile_t cfile = { 0, };
+ if (!cfile_read (&cfile, in, cancellable, error))
+ goto end;
+
+ GCabFile *file = gcab_file_new_with_cfile (&cfile);
+ GCabFolder *folder = g_ptr_array_index (folders, cfile.index);
+ if (!gcab_folder_add_file (folder, file, FALSE, cancellable, error)) {
+ g_object_unref (file);
+ goto end;
+ }
+ }
+
+ success = TRUE;
+
+end:
+ if (in)
+ g_object_unref (in);
+ return success;
+}
diff --git a/libgcab/gcab-cabinet.h b/libgcab/gcab-cabinet.h
index 7b2f48c..e32f347 100644
--- a/libgcab/gcab-cabinet.h
+++ b/libgcab/gcab-cabinet.h
@@ -35,16 +35,30 @@ G_BEGIN_DECLS
#define GCAB_IS_CABINET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCAB_TYPE_CABINET))
#define GCAB_CABINET_GET_CLASS(cabinet) (G_TYPE_INSTANCE_GET_CLASS ((cabinet), GCAB_TYPE_CABINET, GCabCabinetClass))
+#define GCAB_ERROR gcab_error_quark ()
+GQuark gcab_error_quark (void);
+
+typedef enum GCabError
+{
+ GCAB_ERROR_FORMAT
+} GCabError;
+
typedef struct _GCabCabinetClass GCabCabinetClass;
typedef struct _GCabCabinet GCabCabinet;
GType gcab_cabinet_get_type (void) G_GNUC_CONST;
GCabCabinet * gcab_cabinet_new (void);
+gboolean gcab_cabinet_load (GCabCabinet *cabinet,
+ GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+
+GPtrArray * gcab_cabinet_get_folders (GCabCabinet *cabinet);
+
gboolean gcab_cabinet_add_folder (GCabCabinet *cabinet,
GCabFolder *folder,
GError **error);
-GPtrArray * gcab_cabinet_get_folders (GCabCabinet *cabinet);
gboolean gcab_cabinet_write (GCabCabinet *cabinet,
GOutputStream *stream,
GCabFileCallback file_callback,
diff --git a/libgcab/gcab-file.c b/libgcab/gcab-file.c
index 93b28e8..8b652cc 100644
--- a/libgcab/gcab-file.c
+++ b/libgcab/gcab-file.c
@@ -180,8 +180,24 @@ gcab_file_get_file (GCabFile *self)
GCabFile *
gcab_file_new_with_file (const gchar *name, GFile *file)
{
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+
return g_object_new (GCAB_TYPE_FILE,
"name", name,
"file", file,
NULL);
}
+
+G_GNUC_INTERNAL GCabFile *
+gcab_file_new_with_cfile (const cfile_t *cfile)
+{
+ g_return_val_if_fail (cfile != NULL, NULL);
+
+ GCabFile *file = g_object_new (GCAB_TYPE_FILE,
+ "name", cfile->name,
+ NULL);
+ file->cfile = *cfile;
+
+ return file;
+}
diff --git a/libgcab/gcab-folder.c b/libgcab/gcab-folder.c
index 35c856d..ec3fe47 100644
--- a/libgcab/gcab-folder.c
+++ b/libgcab/gcab-folder.c
@@ -9,6 +9,7 @@ enum {
PROP_0,
PROP_COMPRESSION,
+ PROP_RESERVED
};
G_DEFINE_TYPE (GCabFolder, gcab_folder, G_TYPE_OBJECT);
@@ -25,6 +26,8 @@ gcab_folder_finalize (GObject *object)
GCabFolder *self = GCAB_FOLDER (object);
g_hash_table_unref (self->files);
+ if (self->reserved)
+ g_byte_array_unref (self->reserved);
G_OBJECT_CLASS (gcab_folder_parent_class)->finalize (object);
}
@@ -39,6 +42,11 @@ gcab_folder_set_property (GObject *object, guint prop_id, const GValue *value, G
case PROP_COMPRESSION:
self->compression = g_value_get_enum (value);
break;
+ case PROP_RESERVED:
+ if (self->reserved)
+ g_byte_array_unref (self->reserved);
+ self->reserved = g_value_dup_boxed (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -55,6 +63,9 @@ gcab_folder_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case PROP_COMPRESSION:
g_value_set_enum (value, self->compression);
break;
+ case PROP_RESERVED:
+ g_value_set_boxed (value, self->reserved);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -75,6 +86,12 @@ gcab_folder_class_init (GCabFolderClass *klass)
GCAB_TYPE_COMPRESSION, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_RESERVED,
+ g_param_spec_boxed ("reserved", "Reserved", "Reserved",
+ G_TYPE_BYTE_ARRAY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
}
/* calculate the number of datablocks we will need:
@@ -93,6 +110,18 @@ gcab_folder_get_ndatablocks (GCabFolder *self)
return total_size / DATABLOCKSIZE + 1 ;
}
+static gboolean
+add_file (GCabFolder *self, GCabFile *file)
+{
+ if (g_hash_table_lookup (self->files, (gpointer)gcab_file_get_name (file)))
+ return FALSE;
+
+ g_hash_table_insert (self->files,
+ (gpointer)gcab_file_get_name (file), g_object_ref (file));
+
+ return TRUE;
+}
+
#define FILE_ATTRS "standard::*,time::modified"
static gboolean
@@ -134,8 +163,8 @@ add_file_info (GCabFolder *self, GCabFile *file, GFileInfo *info,
} else if (file_type == G_FILE_TYPE_REGULAR) {
gcab_file_update_info (file, info);
- g_hash_table_insert (self->files,
- (gpointer)gcab_file_get_name (file), g_object_ref (file));
+ if (!add_file (self, file))
+ return FALSE;
} else {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
@@ -171,15 +200,19 @@ gcab_folder_add_file (GCabFolder *self, GCabFile *file,
g_return_val_if_fail (!error || *error == NULL, FALSE);
GFile *gfile = gcab_file_get_file (file);
- g_return_val_if_fail (G_IS_FILE (gfile), FALSE);
+ if (gfile) {
+ g_return_val_if_fail (G_IS_FILE (gfile), FALSE);
- GFileInfo *info = g_file_query_info (gfile, FILE_ATTRS, 0, NULL, error);
- if (*error)
- return FALSE;
+ GFileInfo *info = g_file_query_info (gfile, FILE_ATTRS, 0, NULL, error);
+ if (*error)
+ return FALSE;
- success = add_file_info (self, file, info,
- gcab_file_get_name (file), recurse, error);
- g_object_unref (info);
+ success = add_file_info (self, file, info,
+ gcab_file_get_name (file), recurse, error);
+ g_object_unref (info);
+ } else {
+ success = add_file (self, file);
+ }
return success;
}
@@ -211,3 +244,25 @@ gcab_folder_new (GCabCompression compression)
"compression", compression,
NULL);
}
+
+G_GNUC_INTERNAL GCabFolder *
+gcab_folder_new_with_cfolder (const cfolder_t *folder)
+{
+ return g_object_new (GCAB_TYPE_FOLDER,
+ "compression", folder->typecomp,
+ NULL);
+}
+
+/**
+ * gcab_folder_get_files:
+ * @cabfolder: a #GCabFolder
+ *
+ * Returns: (element-type GCabFile) (transfer full): list of files
+ **/
+GList *
+gcab_folder_get_files (GCabFolder *self)
+{
+ g_return_val_if_fail (GCAB_IS_FOLDER (self), 0);
+
+ return g_hash_table_get_values (self->files);
+}
diff --git a/libgcab/gcab-folder.h b/libgcab/gcab-folder.h
index fa75897..f8a7ac4 100644
--- a/libgcab/gcab-folder.h
+++ b/libgcab/gcab-folder.h
@@ -51,6 +51,7 @@ gboolean gcab_folder_add_file (GCabFolder *cabfolder,
GCancellable *cancellable,
GError **error);
guint gcab_folder_get_nfiles (GCabFolder *cabfolder);
+GList * gcab_folder_get_files (GCabFolder *cabfolder);
G_END_DECLS
diff --git a/libgcab/gcab-priv.h b/libgcab/gcab-priv.h
index 7c8a545..04f798f 100644
--- a/libgcab/gcab-priv.h
+++ b/libgcab/gcab-priv.h
@@ -24,8 +24,12 @@ struct _GCabFolder
GHashTable *files;
GCabCompression compression;
+ GByteArray *reserved;
};
+GCabFolder * gcab_folder_new_with_cfolder (const cfolder_t *folder);
+GCabFile * gcab_file_new_with_cfile (const cfile_t *file);
+
gboolean gcab_file_update_info (GCabFile *file, GFileInfo *info);
gboolean gcab_file_set_uoffset (GCabFile *file, u4 uoffset);
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 3496b55..d317101 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -30,14 +30,14 @@ AT_CHECK([_gcab ]$@)])
AT_SETUP([Invalid command line])
AT_CHECK_GCAB([], [1], [ignore], [ignore])
-AT_CHECK_GCAB([out.cab], [1], [ignore], [ignore])
+AT_CHECK_GCAB([-c out.cab], [1], [ignore], [ignore])
AT_CHECK([test -f out.cab], [1])
AT_CLEANUP
AT_SETUP([Add one file])
AT_DATA([test.txt], [This is test.txt
])
-AT_CHECK_GCAB([out.cab test.txt])
+AT_CHECK_GCAB([-c out.cab test.txt])
AT_CHECK([cabextract -ql out.cab | tail -n+3 | cut -d'|' -f3], [0],
[ test.txt
])
@@ -45,7 +45,7 @@ cp test.txt expout
AT_CHECK([cabextract -q out.cab], [0])
AT_CHECK([cat test.txt], [0], [expout])
#compressed
-AT_CHECK_GCAB([-z out.cab test.txt])
+AT_CHECK_GCAB([-cz out.cab test.txt])
AT_CHECK([cabextract -ql out.cab | tail -n+3 | cut -d'|' -f3], [0],
[ test.txt
])
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]