[evolution-ews] First implementation of incremental patches



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]