[evolution-ews] First implementation of incremental patches
- From: David Woodhouse <dwmw2 src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews] First implementation of incremental patches
- Date: Fri, 3 May 2013 22:57:47 +0000 (UTC)
commit 3227110b008fe4895dcd13169b79e47ece8fbefb
Author: David Woodhouse <David Woodhouse intel com>
Date: Fri May 3 23:55:32 2013 +0100
First implementation of incremental patches
Also fix extra_length handling — actually apply it, and also do sanity
checks on the length after handling it not before.
src/addressbook/lzx/ews-oal-decompress.c | 214 ++++++++++++++++++++++++-
src/addressbook/lzx/ews-oal-decompress.h | 4 +
src/addressbook/lzx/gal-lzx-decompress-test.c | 12 ++-
src/addressbook/lzx/lzx.h | 1 +
src/addressbook/lzx/lzxd.c | 31 +++--
5 files changed, 249 insertions(+), 13 deletions(-)
---
diff --git a/src/addressbook/lzx/ews-oal-decompress.c b/src/addressbook/lzx/ews-oal-decompress.c
index a97f347..1d902a6 100644
--- a/src/addressbook/lzx/ews-oal-decompress.c
+++ b/src/addressbook/lzx/ews-oal-decompress.c
@@ -48,13 +48,17 @@ typedef struct {
guint32 h_version;
guint32 l_version;
guint32 max_block_size;
+ guint32 source_size;
guint32 target_size;
+ guint32 source_crc;
+ guint32 target_crc;
} LzxHeader;
typedef struct {
guint32 flags;
guint32 comp_size;
guint32 ucomp_size;
+ guint32 source_size;
guint32 crc;
} LzxBlockHeader;
@@ -220,7 +224,8 @@ oal_decompress_v4_full_detail_file (const gchar *filename,
else if (window_bits > 25)
window_bits = 25;
- lzs = lzxd_init (input, output, window_bits, 0, 16, lzx_b->ucomp_size);
+ lzs = lzxd_init (input, output, NULL, 0, window_bits,
+ 0, 16, lzx_b->ucomp_size);
if (lzxd_decompress (lzs, lzs->length) != LZX_ERR_OK) {
g_set_error_literal (&err, g_quark_from_string ("lzx"), 1, "decompression
failed");
@@ -255,3 +260,210 @@ exit:
return ret;
}
+static LzxHeader *
+read_patch_headers (FILE *input,
+ GError **error)
+{
+ LzxHeader *lzx_h;
+ gboolean success;
+
+ lzx_h = g_new0 (LzxHeader, 1);
+
+ success = read_uint32 (input, &lzx_h->h_version);
+ if (!success)
+ goto exit;
+ success = read_uint32 (input, &lzx_h->l_version);
+ if (!success)
+ goto exit;
+
+ if (lzx_h->h_version != 0x00000003 || lzx_h->l_version != 0x00000002) {
+ g_free (lzx_h);
+ /* set the right domain later */
+ g_set_error_literal (error, g_quark_from_string ("lzx"), 1, "wrong version header");
+ return NULL;
+ }
+
+ success = read_uint32 (input, &lzx_h->max_block_size);
+ if (!success)
+ goto exit;
+ success = read_uint32 (input, &lzx_h->source_size);
+ if (!success)
+ goto exit;
+ success = read_uint32 (input, &lzx_h->target_size);
+ if (!success)
+ goto exit;
+ success = read_uint32 (input, &lzx_h->source_crc);
+ if (!success)
+ goto exit;
+ success = read_uint32 (input, &lzx_h->target_crc);
+ if (!success)
+ goto exit;
+
+exit:
+ if (!success) {
+ /* set the right domain later */
+ g_set_error_literal (error, g_quark_from_string ("lzx"), 1, "Unable to read lzx main header");
+
+ g_free (lzx_h);
+ lzx_h = NULL;
+ }
+
+ return lzx_h;
+}
+static LzxBlockHeader *
+read_patch_block_header (FILE *input,
+ GError **error)
+{
+ LzxBlockHeader *lzx_b;
+ gboolean success;
+
+ lzx_b = g_new0 (LzxBlockHeader, 1);
+
+ success = read_uint32 (input, &lzx_b->comp_size);
+ if (!success)
+ goto exit;
+
+ success = read_uint32 (input, &lzx_b->ucomp_size);
+ if (!success)
+ goto exit;
+
+ success = read_uint32 (input, &lzx_b->source_size);
+ if (!success)
+ goto exit;
+
+ success = read_uint32 (input, &lzx_b->crc);
+
+exit:
+ if (!success) {
+ /* set the right domain later */
+ g_set_error_literal (error, g_quark_from_string ("lzx"), 1, "Unable to read lzx block
header");
+
+ g_free (lzx_b);
+ lzx_b = NULL;
+ }
+
+ return lzx_b;
+}
+
+gboolean
+oal_apply_binpatch (const gchar *filename, const gchar *orig_filename,
+ const gchar *output_filename,
+ GError **error)
+{
+ LzxHeader *lzx_h = NULL;
+ guint total_decomp_size = 0;
+ FILE *input = NULL, *output = NULL, *orig_input = NULL;
+ gboolean ret = TRUE;
+ GError *err = NULL;
+ unsigned char *ref_data = NULL;
+ int ref_data_len = 0;
+
+ input = fopen (filename, "rb");
+ if (!input) {
+ g_set_error_literal (&err, g_quark_from_string ("lzx"), 1, "unable to open the input file");
+ ret = FALSE;
+ goto exit;
+ }
+
+ orig_input = fopen (orig_filename, "rb");
+ if (!orig_input) {
+ g_set_error_literal (&err, g_quark_from_string ("lzx"), 1, "unable to open the input file");
+ ret = FALSE;
+ goto exit;
+ }
+
+ output = fopen (output_filename, "wb");
+ if (!output) {
+ g_set_error_literal (&err, g_quark_from_string ("lzx"), 1, "unable to open the output file");
+ ret = FALSE;
+ goto exit;
+ }
+
+ lzx_h = read_patch_headers (input, &err);
+ if (!lzx_h) {
+ ret = FALSE;
+ goto exit;
+ }
+
+ printf("patch header: %x %x\n", lzx_h->source_size, lzx_h->target_size);
+ /* TODO decompressing multiple lzx_blocks has not been tested yet. Will need to get a setup and test
it. */
+ do {
+ LzxBlockHeader *lzx_b;
+ struct lzxd_stream *lzs;
+ goffset offset;
+ guint ref_size, window_bits;
+
+ lzx_b = read_patch_block_header (input, &err);
+ if (err) {
+ printf("err block header\n");
+ ret = FALSE;
+ goto exit;
+ }
+
+ /* note the file offset */
+ offset = ftell (input);
+
+ if (lzx_b->source_size > ref_data_len) {
+ free(ref_data);
+ ref_data_len = lzx_b->source_size;
+ ref_data = malloc(ref_data_len);
+ }
+
+ printf("read %x\n", lzx_b->source_size);
+ if (fread(ref_data, 1, lzx_b->source_size, orig_input) != lzx_b->source_size) {
+ perror("Failed to read original source data\n");
+ ret = FALSE;
+ goto exit;
+ }
+
+ /* The window size should be the smallest power of two between 2^17 and 2^25 that is
+ greater than or equal to the sum of the size of the reference data rounded up to
+ a multiple of 32768 and the size of the subject data. Since we have no reference
+ data, forget that and the rounding. Just the smallest power of two which is large
+ enough to cover the subject data (lzx_b->ucomp_size). */
+ ref_size = (lzx_b->source_size + 32767) & ~32767;
+ window_bits = g_bit_nth_msf(ref_size + lzx_b->ucomp_size - 1, -1) + 1;
+
+ if (window_bits < 17)
+ window_bits = 17;
+ else if (window_bits > 25)
+ window_bits = 25;
+
+ lzs = lzxd_init (input, output, ref_data, lzx_b->source_size,
+ window_bits, 0, 16, lzx_b->ucomp_size);
+
+ if (lzxd_decompress (lzs, lzs->length) != LZX_ERR_OK) {
+ g_set_error_literal (&err, g_quark_from_string ("lzx"), 1, "decompression failed");
+ ret = FALSE;
+ goto exit;
+ }
+
+ /* Set the fp to beggining of next block. This is a HACK, looks like decompress reads beyond
the block.
+ * Since we can identify the next block start from block header, we just reset the offset */
+ offset += lzx_b->comp_size;
+ fseek (input, offset, SEEK_SET);
+
+ total_decomp_size += lzx_b->ucomp_size;
+ g_free (lzx_b);
+ } while (total_decomp_size < lzx_h->target_size);
+
+exit:
+ if (input)
+ fclose (input);
+
+ if (orig_input)
+ fclose (orig_input);
+
+ if (output)
+ fclose (output);
+
+ if (err) {
+ ret = FALSE;
+ g_propagate_error (error, err);
+ g_unlink (output_filename);
+ }
+
+ g_free (lzx_h);
+
+ return ret;
+}
diff --git a/src/addressbook/lzx/ews-oal-decompress.h b/src/addressbook/lzx/ews-oal-decompress.h
index cf07b58..dfac44b 100644
--- a/src/addressbook/lzx/ews-oal-decompress.h
+++ b/src/addressbook/lzx/ews-oal-decompress.h
@@ -27,5 +27,9 @@
gboolean
oal_decompress_v4_full_detail_file (const gchar *filename, const gchar *output_filename, GError **error);
+gboolean
+oal_apply_binpatch (const gchar *filename, const gchar *orig_filename,
+ const gchar *output_filename,
+ GError **error);
#endif
diff --git a/src/addressbook/lzx/gal-lzx-decompress-test.c b/src/addressbook/lzx/gal-lzx-decompress-test.c
index 213aad3..a14f25e 100644
--- a/src/addressbook/lzx/gal-lzx-decompress-test.c
+++ b/src/addressbook/lzx/gal-lzx-decompress-test.c
@@ -5,11 +5,21 @@ gint
main (gint argc,
gchar *argv[])
{
- if (argc != 3) {
+ if (argc != 3 && argc != 4) {
g_print ("Pass an lzx file and an output filename as argument \n");
return -1;
}
+ if (argc == 4) {
+ g_print("Applying binary patch %s to %s to create %s\n",
+ argv[1], argv[2], argv[3]);
+ if (oal_apply_binpatch(argv[1], argv[2], argv[3], NULL))
+ g_print("Successfully applied\n");
+ else
+ g_print("apply failed\n");
+ } else
+
+
if (oal_decompress_v4_full_detail_file (argv[1], argv[2], NULL))
g_print ("Successfully decompressed \n");
else
diff --git a/src/addressbook/lzx/lzx.h b/src/addressbook/lzx/lzx.h
index ac96f5d..e489f25 100644
--- a/src/addressbook/lzx/lzx.h
+++ b/src/addressbook/lzx/lzx.h
@@ -166,6 +166,7 @@ struct lzxd_stream {
*/
extern struct lzxd_stream *lzxd_init(FILE *input,
FILE *output,
+ unsigned char *ref_data, int ref_data_len,
int window_bits,
int reset_interval,
int input_buffer_size,
diff --git a/src/addressbook/lzx/lzxd.c b/src/addressbook/lzx/lzxd.c
index 0312ba1..63f109e 100644
--- a/src/addressbook/lzx/lzxd.c
+++ b/src/addressbook/lzx/lzxd.c
@@ -215,6 +215,7 @@ static int pos_slots[9] = {34, 36, 38, 42, 50, 66, 98, 162, 290};
struct lzxd_stream *lzxd_init(FILE *input,
FILE *output,
+ unsigned char *ref_data, int ref_data_len,
int window_bits,
int reset_interval,
int input_buffer_size,
@@ -226,6 +227,8 @@ struct lzxd_stream *lzxd_init(FILE *input,
/* LZX supports window sizes of 2^17 (128Kb) through 2^25 (32Mb) */
if (window_bits < 17 || window_bits > 26) return NULL;
+ if (ref_data_len > window_size) return NULL;
+
input_buffer_size = (input_buffer_size + 1) & -2;
if (!input_buffer_size) return NULL;
@@ -236,6 +239,10 @@ struct lzxd_stream *lzxd_init(FILE *input,
/* allocate decompression window and input buffer */
lzx->window = malloc((size_t) window_size);
+
+ if (ref_data_len)
+ memcpy(lzx->window + window_size - ref_data_len, ref_data, ref_data_len);
+
lzx->inbuf = malloc((size_t) input_buffer_size);
if (!lzx->window || !lzx->inbuf) {
free(lzx->window);
@@ -461,12 +468,6 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
R2 = R1; R1 = R0; R0 = match_offset;
}
- if ((window_posn + match_length) > lzx->window_size) {
- D(("match ran over window wrap %lu %d ", ftell (lzx->input), match_length))
- lzx->o_ptr = &lzx->window[lzx->frame_posn];
- return lzx->error = LZX_ERR_DECRUNCH;
- }
-
/* check for extra len */
if (match_length == 257) {
READ_BITS (bit, 1);
@@ -497,6 +498,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
match_length += extra_len;
+ if ((window_posn + match_length) > lzx->window_size) {
+ D(("match ran over window wrap %lu %d ", ftell (lzx->input), match_length))
+ lzx->o_ptr = &lzx->window[lzx->frame_posn];
+ return lzx->error = LZX_ERR_DECRUNCH;
+ }
+
/* copy match */
rundest = &window[window_posn];
i = match_length;
@@ -583,11 +590,6 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
R2 = R1; R1 = R0; R0 = match_offset;
}
- if ((window_posn + match_length) > lzx->window_size) {
- D(("match ran over window wrap"))
- return lzx->error = LZX_ERR_DECRUNCH;
- }
-
/* check for extra len */
if (match_length == 257) {
READ_BITS (bit, 1);
@@ -614,8 +616,15 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* 0 */
READ_BITS (extra_len, 8);
}
+ match_length += extra_len;
}
+ if ((window_posn + match_length) > lzx->window_size) {
+ D(("match ran over window wrap"))
+ return lzx->error = LZX_ERR_DECRUNCH;
+ }
+
+
/* copy match */
rundest = &window[window_posn];
i = match_length;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]