~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to patch-delta.c

  • Committer: John Arbash Meinel
  • Author(s): Nicolas Pitre
  • Date: 2009-02-26 04:22:29 UTC
  • mto: (0.23.23 groupcompress_rabin)
  • mto: This revision was merged to the branch mainline in revision 4280.
  • Revision ID: john@arbash-meinel.com-20090226042229-qk6u230fwyxbmhd7
Add the diff-delta.c and patch-delta.c files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * patch-delta.c:
 
3
 * recreate a buffer from a source and the delta produced by diff-delta.c
 
4
 *
 
5
 * (C) 2005 Nicolas Pitre <nico@cam.org>
 
6
 *
 
7
 * This code is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License version 2 as
 
9
 * published by the Free Software Foundation.
 
10
 */
 
11
 
 
12
#include "git-compat-util.h"
 
13
#include "delta.h"
 
14
 
 
15
void *patch_delta(const void *src_buf, unsigned long src_size,
 
16
                  const void *delta_buf, unsigned long delta_size,
 
17
                  unsigned long *dst_size)
 
18
{
 
19
        const unsigned char *data, *top;
 
20
        unsigned char *dst_buf, *out, cmd;
 
21
        unsigned long size;
 
22
 
 
23
        if (delta_size < DELTA_SIZE_MIN)
 
24
                return NULL;
 
25
 
 
26
        data = delta_buf;
 
27
        top = (const unsigned char *) delta_buf + delta_size;
 
28
 
 
29
        /* make sure the orig file size matches what we expect */
 
30
        size = get_delta_hdr_size(&data, top);
 
31
        if (size != src_size)
 
32
                return NULL;
 
33
 
 
34
        /* now the result size */
 
35
        size = get_delta_hdr_size(&data, top);
 
36
        dst_buf = xmalloc(size + 1);
 
37
        dst_buf[size] = 0;
 
38
 
 
39
        out = dst_buf;
 
40
        while (data < top) {
 
41
                cmd = *data++;
 
42
                if (cmd & 0x80) {
 
43
                        unsigned long cp_off = 0, cp_size = 0;
 
44
                        if (cmd & 0x01) cp_off = *data++;
 
45
                        if (cmd & 0x02) cp_off |= (*data++ << 8);
 
46
                        if (cmd & 0x04) cp_off |= (*data++ << 16);
 
47
                        if (cmd & 0x08) cp_off |= (*data++ << 24);
 
48
                        if (cmd & 0x10) cp_size = *data++;
 
49
                        if (cmd & 0x20) cp_size |= (*data++ << 8);
 
50
                        if (cmd & 0x40) cp_size |= (*data++ << 16);
 
51
                        if (cp_size == 0) cp_size = 0x10000;
 
52
                        if (cp_off + cp_size < cp_size ||
 
53
                            cp_off + cp_size > src_size ||
 
54
                            cp_size > size)
 
55
                                break;
 
56
                        memcpy(out, (char *) src_buf + cp_off, cp_size);
 
57
                        out += cp_size;
 
58
                        size -= cp_size;
 
59
                } else if (cmd) {
 
60
                        if (cmd > size)
 
61
                                break;
 
62
                        memcpy(out, data, cmd);
 
63
                        out += cmd;
 
64
                        data += cmd;
 
65
                        size -= cmd;
 
66
                } else {
 
67
                        /*
 
68
                         * cmd == 0 is reserved for future encoding
 
69
                         * extensions. In the mean time we must fail when
 
70
                         * encountering them (might be data corruption).
 
71
                         */
 
72
                        error("unexpected delta opcode 0");
 
73
                        goto bad;
 
74
                }
 
75
        }
 
76
 
 
77
        /* sanity check */
 
78
        if (data != top || size != 0) {
 
79
                error("delta replay has gone wild");
 
80
                bad:
 
81
                free(dst_buf);
 
82
                return NULL;
 
83
        }
 
84
 
 
85
        *dst_size = out - dst_buf;
 
86
        return dst_buf;
 
87
}