~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to diff-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
 * diff-delta.c: generate a delta between two buffers
 
3
 *
 
4
 * This code was greatly inspired by parts of LibXDiff from Davide Libenzi
 
5
 * http://www.xmailserver.org/xdiff-lib.html
 
6
 *
 
7
 * Rewritten for GIT by Nicolas Pitre <nico@cam.org>, (C) 2005-2007
 
8
 *
 
9
 * This code is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License version 2 as
 
11
 * published by the Free Software Foundation.
 
12
 */
 
13
 
 
14
#include "git-compat-util.h"
 
15
#include "delta.h"
 
16
 
 
17
/* maximum hash entry list for the same hash bucket */
 
18
#define HASH_LIMIT 64
 
19
 
 
20
#define RABIN_SHIFT 23
 
21
#define RABIN_WINDOW 16
 
22
 
 
23
static const unsigned int T[256] = {
 
24
        0x00000000, 0xab59b4d1, 0x56b369a2, 0xfdeadd73, 0x063f6795, 0xad66d344,
 
25
        0x508c0e37, 0xfbd5bae6, 0x0c7ecf2a, 0xa7277bfb, 0x5acda688, 0xf1941259,
 
26
        0x0a41a8bf, 0xa1181c6e, 0x5cf2c11d, 0xf7ab75cc, 0x18fd9e54, 0xb3a42a85,
 
27
        0x4e4ef7f6, 0xe5174327, 0x1ec2f9c1, 0xb59b4d10, 0x48719063, 0xe32824b2,
 
28
        0x1483517e, 0xbfdae5af, 0x423038dc, 0xe9698c0d, 0x12bc36eb, 0xb9e5823a,
 
29
        0x440f5f49, 0xef56eb98, 0x31fb3ca8, 0x9aa28879, 0x6748550a, 0xcc11e1db,
 
30
        0x37c45b3d, 0x9c9defec, 0x6177329f, 0xca2e864e, 0x3d85f382, 0x96dc4753,
 
31
        0x6b369a20, 0xc06f2ef1, 0x3bba9417, 0x90e320c6, 0x6d09fdb5, 0xc6504964,
 
32
        0x2906a2fc, 0x825f162d, 0x7fb5cb5e, 0xd4ec7f8f, 0x2f39c569, 0x846071b8,
 
33
        0x798aaccb, 0xd2d3181a, 0x25786dd6, 0x8e21d907, 0x73cb0474, 0xd892b0a5,
 
34
        0x23470a43, 0x881ebe92, 0x75f463e1, 0xdeadd730, 0x63f67950, 0xc8afcd81,
 
35
        0x354510f2, 0x9e1ca423, 0x65c91ec5, 0xce90aa14, 0x337a7767, 0x9823c3b6,
 
36
        0x6f88b67a, 0xc4d102ab, 0x393bdfd8, 0x92626b09, 0x69b7d1ef, 0xc2ee653e,
 
37
        0x3f04b84d, 0x945d0c9c, 0x7b0be704, 0xd05253d5, 0x2db88ea6, 0x86e13a77,
 
38
        0x7d348091, 0xd66d3440, 0x2b87e933, 0x80de5de2, 0x7775282e, 0xdc2c9cff,
 
39
        0x21c6418c, 0x8a9ff55d, 0x714a4fbb, 0xda13fb6a, 0x27f92619, 0x8ca092c8,
 
40
        0x520d45f8, 0xf954f129, 0x04be2c5a, 0xafe7988b, 0x5432226d, 0xff6b96bc,
 
41
        0x02814bcf, 0xa9d8ff1e, 0x5e738ad2, 0xf52a3e03, 0x08c0e370, 0xa39957a1,
 
42
        0x584ced47, 0xf3155996, 0x0eff84e5, 0xa5a63034, 0x4af0dbac, 0xe1a96f7d,
 
43
        0x1c43b20e, 0xb71a06df, 0x4ccfbc39, 0xe79608e8, 0x1a7cd59b, 0xb125614a,
 
44
        0x468e1486, 0xedd7a057, 0x103d7d24, 0xbb64c9f5, 0x40b17313, 0xebe8c7c2,
 
45
        0x16021ab1, 0xbd5bae60, 0x6cb54671, 0xc7ecf2a0, 0x3a062fd3, 0x915f9b02,
 
46
        0x6a8a21e4, 0xc1d39535, 0x3c394846, 0x9760fc97, 0x60cb895b, 0xcb923d8a,
 
47
        0x3678e0f9, 0x9d215428, 0x66f4eece, 0xcdad5a1f, 0x3047876c, 0x9b1e33bd,
 
48
        0x7448d825, 0xdf116cf4, 0x22fbb187, 0x89a20556, 0x7277bfb0, 0xd92e0b61,
 
49
        0x24c4d612, 0x8f9d62c3, 0x7836170f, 0xd36fa3de, 0x2e857ead, 0x85dcca7c,
 
50
        0x7e09709a, 0xd550c44b, 0x28ba1938, 0x83e3ade9, 0x5d4e7ad9, 0xf617ce08,
 
51
        0x0bfd137b, 0xa0a4a7aa, 0x5b711d4c, 0xf028a99d, 0x0dc274ee, 0xa69bc03f,
 
52
        0x5130b5f3, 0xfa690122, 0x0783dc51, 0xacda6880, 0x570fd266, 0xfc5666b7,
 
53
        0x01bcbbc4, 0xaae50f15, 0x45b3e48d, 0xeeea505c, 0x13008d2f, 0xb85939fe,
 
54
        0x438c8318, 0xe8d537c9, 0x153feaba, 0xbe665e6b, 0x49cd2ba7, 0xe2949f76,
 
55
        0x1f7e4205, 0xb427f6d4, 0x4ff24c32, 0xe4abf8e3, 0x19412590, 0xb2189141,
 
56
        0x0f433f21, 0xa41a8bf0, 0x59f05683, 0xf2a9e252, 0x097c58b4, 0xa225ec65,
 
57
        0x5fcf3116, 0xf49685c7, 0x033df00b, 0xa86444da, 0x558e99a9, 0xfed72d78,
 
58
        0x0502979e, 0xae5b234f, 0x53b1fe3c, 0xf8e84aed, 0x17bea175, 0xbce715a4,
 
59
        0x410dc8d7, 0xea547c06, 0x1181c6e0, 0xbad87231, 0x4732af42, 0xec6b1b93,
 
60
        0x1bc06e5f, 0xb099da8e, 0x4d7307fd, 0xe62ab32c, 0x1dff09ca, 0xb6a6bd1b,
 
61
        0x4b4c6068, 0xe015d4b9, 0x3eb80389, 0x95e1b758, 0x680b6a2b, 0xc352defa,
 
62
        0x3887641c, 0x93ded0cd, 0x6e340dbe, 0xc56db96f, 0x32c6cca3, 0x999f7872,
 
63
        0x6475a501, 0xcf2c11d0, 0x34f9ab36, 0x9fa01fe7, 0x624ac294, 0xc9137645,
 
64
        0x26459ddd, 0x8d1c290c, 0x70f6f47f, 0xdbaf40ae, 0x207afa48, 0x8b234e99,
 
65
        0x76c993ea, 0xdd90273b, 0x2a3b52f7, 0x8162e626, 0x7c883b55, 0xd7d18f84,
 
66
        0x2c043562, 0x875d81b3, 0x7ab75cc0, 0xd1eee811
 
67
};
 
68
 
 
69
static const unsigned int U[256] = {
 
70
        0x00000000, 0x7eb5200d, 0x5633f4cb, 0x2886d4c6, 0x073e5d47, 0x798b7d4a,
 
71
        0x510da98c, 0x2fb88981, 0x0e7cba8e, 0x70c99a83, 0x584f4e45, 0x26fa6e48,
 
72
        0x0942e7c9, 0x77f7c7c4, 0x5f711302, 0x21c4330f, 0x1cf9751c, 0x624c5511,
 
73
        0x4aca81d7, 0x347fa1da, 0x1bc7285b, 0x65720856, 0x4df4dc90, 0x3341fc9d,
 
74
        0x1285cf92, 0x6c30ef9f, 0x44b63b59, 0x3a031b54, 0x15bb92d5, 0x6b0eb2d8,
 
75
        0x4388661e, 0x3d3d4613, 0x39f2ea38, 0x4747ca35, 0x6fc11ef3, 0x11743efe,
 
76
        0x3eccb77f, 0x40799772, 0x68ff43b4, 0x164a63b9, 0x378e50b6, 0x493b70bb,
 
77
        0x61bda47d, 0x1f088470, 0x30b00df1, 0x4e052dfc, 0x6683f93a, 0x1836d937,
 
78
        0x250b9f24, 0x5bbebf29, 0x73386bef, 0x0d8d4be2, 0x2235c263, 0x5c80e26e,
 
79
        0x740636a8, 0x0ab316a5, 0x2b7725aa, 0x55c205a7, 0x7d44d161, 0x03f1f16c,
 
80
        0x2c4978ed, 0x52fc58e0, 0x7a7a8c26, 0x04cfac2b, 0x73e5d470, 0x0d50f47d,
 
81
        0x25d620bb, 0x5b6300b6, 0x74db8937, 0x0a6ea93a, 0x22e87dfc, 0x5c5d5df1,
 
82
        0x7d996efe, 0x032c4ef3, 0x2baa9a35, 0x551fba38, 0x7aa733b9, 0x041213b4,
 
83
        0x2c94c772, 0x5221e77f, 0x6f1ca16c, 0x11a98161, 0x392f55a7, 0x479a75aa,
 
84
        0x6822fc2b, 0x1697dc26, 0x3e1108e0, 0x40a428ed, 0x61601be2, 0x1fd53bef,
 
85
        0x3753ef29, 0x49e6cf24, 0x665e46a5, 0x18eb66a8, 0x306db26e, 0x4ed89263,
 
86
        0x4a173e48, 0x34a21e45, 0x1c24ca83, 0x6291ea8e, 0x4d29630f, 0x339c4302,
 
87
        0x1b1a97c4, 0x65afb7c9, 0x446b84c6, 0x3adea4cb, 0x1258700d, 0x6ced5000,
 
88
        0x4355d981, 0x3de0f98c, 0x15662d4a, 0x6bd30d47, 0x56ee4b54, 0x285b6b59,
 
89
        0x00ddbf9f, 0x7e689f92, 0x51d01613, 0x2f65361e, 0x07e3e2d8, 0x7956c2d5,
 
90
        0x5892f1da, 0x2627d1d7, 0x0ea10511, 0x7014251c, 0x5facac9d, 0x21198c90,
 
91
        0x099f5856, 0x772a785b, 0x4c921c31, 0x32273c3c, 0x1aa1e8fa, 0x6414c8f7,
 
92
        0x4bac4176, 0x3519617b, 0x1d9fb5bd, 0x632a95b0, 0x42eea6bf, 0x3c5b86b2,
 
93
        0x14dd5274, 0x6a687279, 0x45d0fbf8, 0x3b65dbf5, 0x13e30f33, 0x6d562f3e,
 
94
        0x506b692d, 0x2ede4920, 0x06589de6, 0x78edbdeb, 0x5755346a, 0x29e01467,
 
95
        0x0166c0a1, 0x7fd3e0ac, 0x5e17d3a3, 0x20a2f3ae, 0x08242768, 0x76910765,
 
96
        0x59298ee4, 0x279caee9, 0x0f1a7a2f, 0x71af5a22, 0x7560f609, 0x0bd5d604,
 
97
        0x235302c2, 0x5de622cf, 0x725eab4e, 0x0ceb8b43, 0x246d5f85, 0x5ad87f88,
 
98
        0x7b1c4c87, 0x05a96c8a, 0x2d2fb84c, 0x539a9841, 0x7c2211c0, 0x029731cd,
 
99
        0x2a11e50b, 0x54a4c506, 0x69998315, 0x172ca318, 0x3faa77de, 0x411f57d3,
 
100
        0x6ea7de52, 0x1012fe5f, 0x38942a99, 0x46210a94, 0x67e5399b, 0x19501996,
 
101
        0x31d6cd50, 0x4f63ed5d, 0x60db64dc, 0x1e6e44d1, 0x36e89017, 0x485db01a,
 
102
        0x3f77c841, 0x41c2e84c, 0x69443c8a, 0x17f11c87, 0x38499506, 0x46fcb50b,
 
103
        0x6e7a61cd, 0x10cf41c0, 0x310b72cf, 0x4fbe52c2, 0x67388604, 0x198da609,
 
104
        0x36352f88, 0x48800f85, 0x6006db43, 0x1eb3fb4e, 0x238ebd5d, 0x5d3b9d50,
 
105
        0x75bd4996, 0x0b08699b, 0x24b0e01a, 0x5a05c017, 0x728314d1, 0x0c3634dc,
 
106
        0x2df207d3, 0x534727de, 0x7bc1f318, 0x0574d315, 0x2acc5a94, 0x54797a99,
 
107
        0x7cffae5f, 0x024a8e52, 0x06852279, 0x78300274, 0x50b6d6b2, 0x2e03f6bf,
 
108
        0x01bb7f3e, 0x7f0e5f33, 0x57888bf5, 0x293dabf8, 0x08f998f7, 0x764cb8fa,
 
109
        0x5eca6c3c, 0x207f4c31, 0x0fc7c5b0, 0x7172e5bd, 0x59f4317b, 0x27411176,
 
110
        0x1a7c5765, 0x64c97768, 0x4c4fa3ae, 0x32fa83a3, 0x1d420a22, 0x63f72a2f,
 
111
        0x4b71fee9, 0x35c4dee4, 0x1400edeb, 0x6ab5cde6, 0x42331920, 0x3c86392d,
 
112
        0x133eb0ac, 0x6d8b90a1, 0x450d4467, 0x3bb8646a
 
113
};
 
114
 
 
115
struct index_entry {
 
116
        const unsigned char *ptr;
 
117
        unsigned int val;
 
118
};
 
119
 
 
120
struct unpacked_index_entry {
 
121
        struct index_entry entry;
 
122
        struct unpacked_index_entry *next;
 
123
};
 
124
 
 
125
struct delta_index {
 
126
        unsigned long memsize;
 
127
        const void *src_buf;
 
128
        unsigned long src_size;
 
129
        unsigned int hash_mask;
 
130
        struct index_entry *hash[FLEX_ARRAY];
 
131
};
 
132
 
 
133
struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
 
134
{
 
135
        unsigned int i, hsize, hmask, entries, prev_val, *hash_count;
 
136
        const unsigned char *data, *buffer = buf;
 
137
        struct delta_index *index;
 
138
        struct unpacked_index_entry *entry, **hash;
 
139
        struct index_entry *packed_entry, **packed_hash;
 
140
        void *mem;
 
141
        unsigned long memsize;
 
142
 
 
143
        if (!buf || !bufsize)
 
144
                return NULL;
 
145
 
 
146
        /* Determine index hash size.  Note that indexing skips the
 
147
           first byte to allow for optimizing the Rabin's polynomial
 
148
           initialization in create_delta(). */
 
149
        entries = (bufsize - 1)  / RABIN_WINDOW;
 
150
        hsize = entries / 4;
 
151
        for (i = 4; (1u << i) < hsize && i < 31; i++);
 
152
        hsize = 1 << i;
 
153
        hmask = hsize - 1;
 
154
 
 
155
        /* allocate lookup index */
 
156
        memsize = sizeof(*hash) * hsize +
 
157
                  sizeof(*entry) * entries;
 
158
        mem = malloc(memsize);
 
159
        if (!mem)
 
160
                return NULL;
 
161
        hash = mem;
 
162
        mem = hash + hsize;
 
163
        entry = mem;
 
164
 
 
165
        memset(hash, 0, hsize * sizeof(*hash));
 
166
 
 
167
        /* allocate an array to count hash entries */
 
168
        hash_count = calloc(hsize, sizeof(*hash_count));
 
169
        if (!hash_count) {
 
170
                free(hash);
 
171
                return NULL;
 
172
        }
 
173
 
 
174
        /* then populate the index */
 
175
        prev_val = ~0;
 
176
        for (data = buffer + entries * RABIN_WINDOW - RABIN_WINDOW;
 
177
             data >= buffer;
 
178
             data -= RABIN_WINDOW) {
 
179
                unsigned int val = 0;
 
180
                for (i = 1; i <= RABIN_WINDOW; i++)
 
181
                        val = ((val << 8) | data[i]) ^ T[val >> RABIN_SHIFT];
 
182
                if (val == prev_val) {
 
183
                        /* keep the lowest of consecutive identical blocks */
 
184
                        entry[-1].entry.ptr = data + RABIN_WINDOW;
 
185
                        --entries;
 
186
                } else {
 
187
                        prev_val = val;
 
188
                        i = val & hmask;
 
189
                        entry->entry.ptr = data + RABIN_WINDOW;
 
190
                        entry->entry.val = val;
 
191
                        entry->next = hash[i];
 
192
                        hash[i] = entry++;
 
193
                        hash_count[i]++;
 
194
                }
 
195
        }
 
196
 
 
197
        /*
 
198
         * Determine a limit on the number of entries in the same hash
 
199
         * bucket.  This guards us against pathological data sets causing
 
200
         * really bad hash distribution with most entries in the same hash
 
201
         * bucket that would bring us to O(m*n) computing costs (m and n
 
202
         * corresponding to reference and target buffer sizes).
 
203
         *
 
204
         * Make sure none of the hash buckets has more entries than
 
205
         * we're willing to test.  Otherwise we cull the entry list
 
206
         * uniformly to still preserve a good repartition across
 
207
         * the reference buffer.
 
208
         */
 
209
        for (i = 0; i < hsize; i++) {
 
210
                int acc;
 
211
 
 
212
                if (hash_count[i] <= HASH_LIMIT)
 
213
                        continue;
 
214
 
 
215
                /* We leave exactly HASH_LIMIT entries in the bucket */
 
216
                entries -= hash_count[i] - HASH_LIMIT;
 
217
 
 
218
                entry = hash[i];
 
219
                acc = 0;
 
220
 
 
221
                /*
 
222
                 * Assume that this loop is gone through exactly
 
223
                 * HASH_LIMIT times and is entered and left with
 
224
                 * acc==0.  So the first statement in the loop
 
225
                 * contributes (hash_count[i]-HASH_LIMIT)*HASH_LIMIT
 
226
                 * to the accumulator, and the inner loop consequently
 
227
                 * is run (hash_count[i]-HASH_LIMIT) times, removing
 
228
                 * one element from the list each time.  Since acc
 
229
                 * balances out to 0 at the final run, the inner loop
 
230
                 * body can't be left with entry==NULL.  So we indeed
 
231
                 * encounter entry==NULL in the outer loop only.
 
232
                 */
 
233
                do {
 
234
                        acc += hash_count[i] - HASH_LIMIT;
 
235
                        if (acc > 0) {
 
236
                                struct unpacked_index_entry *keep = entry;
 
237
                                do {
 
238
                                        entry = entry->next;
 
239
                                        acc -= HASH_LIMIT;
 
240
                                } while (acc > 0);
 
241
                                keep->next = entry->next;
 
242
                        }
 
243
                        entry = entry->next;
 
244
                } while (entry);
 
245
        }
 
246
        free(hash_count);
 
247
 
 
248
        /*
 
249
         * Now create the packed index in array form
 
250
         * rather than linked lists.
 
251
         */
 
252
        memsize = sizeof(*index)
 
253
                + sizeof(*packed_hash) * (hsize+1)
 
254
                + sizeof(*packed_entry) * entries;
 
255
        mem = malloc(memsize);
 
256
        if (!mem) {
 
257
                free(hash);
 
258
                return NULL;
 
259
        }
 
260
 
 
261
        index = mem;
 
262
        index->memsize = memsize;
 
263
        index->src_buf = buf;
 
264
        index->src_size = bufsize;
 
265
        index->hash_mask = hmask;
 
266
 
 
267
        mem = index->hash;
 
268
        packed_hash = mem;
 
269
        mem = packed_hash + (hsize+1);
 
270
        packed_entry = mem;
 
271
 
 
272
        for (i = 0; i < hsize; i++) {
 
273
                /*
 
274
                 * Coalesce all entries belonging to one linked list
 
275
                 * into consecutive array entries.
 
276
                 */
 
277
                packed_hash[i] = packed_entry;
 
278
                for (entry = hash[i]; entry; entry = entry->next)
 
279
                        *packed_entry++ = entry->entry;
 
280
        }
 
281
 
 
282
        /* Sentinel value to indicate the length of the last hash bucket */
 
283
        packed_hash[hsize] = packed_entry;
 
284
 
 
285
        assert(packed_entry - (struct index_entry *)mem == entries);
 
286
        free(hash);
 
287
 
 
288
        return index;
 
289
}
 
290
 
 
291
void free_delta_index(struct delta_index *index)
 
292
{
 
293
        free(index);
 
294
}
 
295
 
 
296
unsigned long sizeof_delta_index(struct delta_index *index)
 
297
{
 
298
        if (index)
 
299
                return index->memsize;
 
300
        else
 
301
                return 0;
 
302
}
 
303
 
 
304
/*
 
305
 * The maximum size for any opcode sequence, including the initial header
 
306
 * plus Rabin window plus biggest copy.
 
307
 */
 
308
#define MAX_OP_SIZE     (5 + 5 + 1 + RABIN_WINDOW + 7)
 
309
 
 
310
void *
 
311
create_delta(const struct delta_index *index,
 
312
             const void *trg_buf, unsigned long trg_size,
 
313
             unsigned long *delta_size, unsigned long max_size)
 
314
{
 
315
        unsigned int i, outpos, outsize, moff, msize, val;
 
316
        int inscnt;
 
317
        const unsigned char *ref_data, *ref_top, *data, *top;
 
318
        unsigned char *out;
 
319
 
 
320
        if (!trg_buf || !trg_size)
 
321
                return NULL;
 
322
 
 
323
        outpos = 0;
 
324
        outsize = 8192;
 
325
        if (max_size && outsize >= max_size)
 
326
                outsize = max_size + MAX_OP_SIZE + 1;
 
327
        out = malloc(outsize);
 
328
        if (!out)
 
329
                return NULL;
 
330
 
 
331
        /* store reference buffer size */
 
332
        i = index->src_size;
 
333
        while (i >= 0x80) {
 
334
                out[outpos++] = i | 0x80;
 
335
                i >>= 7;
 
336
        }
 
337
        out[outpos++] = i;
 
338
 
 
339
        /* store target buffer size */
 
340
        i = trg_size;
 
341
        while (i >= 0x80) {
 
342
                out[outpos++] = i | 0x80;
 
343
                i >>= 7;
 
344
        }
 
345
        out[outpos++] = i;
 
346
 
 
347
        ref_data = index->src_buf;
 
348
        ref_top = ref_data + index->src_size;
 
349
        data = trg_buf;
 
350
        top = (const unsigned char *) trg_buf + trg_size;
 
351
 
 
352
        outpos++;
 
353
        val = 0;
 
354
        for (i = 0; i < RABIN_WINDOW && data < top; i++, data++) {
 
355
                out[outpos++] = *data;
 
356
                val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT];
 
357
        }
 
358
        inscnt = i;
 
359
 
 
360
        moff = 0;
 
361
        msize = 0;
 
362
        while (data < top) {
 
363
                if (msize < 4096) {
 
364
                        struct index_entry *entry;
 
365
                        val ^= U[data[-RABIN_WINDOW]];
 
366
                        val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT];
 
367
                        i = val & index->hash_mask;
 
368
                        for (entry = index->hash[i]; entry < index->hash[i+1]; entry++) {
 
369
                                const unsigned char *ref = entry->ptr;
 
370
                                const unsigned char *src = data;
 
371
                                unsigned int ref_size = ref_top - ref;
 
372
                                if (entry->val != val)
 
373
                                        continue;
 
374
                                if (ref_size > top - src)
 
375
                                        ref_size = top - src;
 
376
                                if (ref_size <= msize)
 
377
                                        break;
 
378
                                while (ref_size-- && *src++ == *ref)
 
379
                                        ref++;
 
380
                                if (msize < ref - entry->ptr) {
 
381
                                        /* this is our best match so far */
 
382
                                        msize = ref - entry->ptr;
 
383
                                        moff = entry->ptr - ref_data;
 
384
                                        if (msize >= 4096) /* good enough */
 
385
                                                break;
 
386
                                }
 
387
                        }
 
388
                }
 
389
 
 
390
                if (msize < 4) {
 
391
                        if (!inscnt)
 
392
                                outpos++;
 
393
                        out[outpos++] = *data++;
 
394
                        inscnt++;
 
395
                        if (inscnt == 0x7f) {
 
396
                                out[outpos - inscnt - 1] = inscnt;
 
397
                                inscnt = 0;
 
398
                        }
 
399
                        msize = 0;
 
400
                } else {
 
401
                        unsigned int left;
 
402
                        unsigned char *op;
 
403
 
 
404
                        if (inscnt) {
 
405
                                while (moff && ref_data[moff-1] == data[-1]) {
 
406
                                        /* we can match one byte back */
 
407
                                        msize++;
 
408
                                        moff--;
 
409
                                        data--;
 
410
                                        outpos--;
 
411
                                        if (--inscnt)
 
412
                                                continue;
 
413
                                        outpos--;  /* remove count slot */
 
414
                                        inscnt--;  /* make it -1 */
 
415
                                        break;
 
416
                                }
 
417
                                out[outpos - inscnt - 1] = inscnt;
 
418
                                inscnt = 0;
 
419
                        }
 
420
 
 
421
                        /* A copy op is currently limited to 64KB (pack v2) */
 
422
                        left = (msize < 0x10000) ? 0 : (msize - 0x10000);
 
423
                        msize -= left;
 
424
 
 
425
                        op = out + outpos++;
 
426
                        i = 0x80;
 
427
 
 
428
                        if (moff & 0x000000ff)
 
429
                                out[outpos++] = moff >> 0,  i |= 0x01;
 
430
                        if (moff & 0x0000ff00)
 
431
                                out[outpos++] = moff >> 8,  i |= 0x02;
 
432
                        if (moff & 0x00ff0000)
 
433
                                out[outpos++] = moff >> 16, i |= 0x04;
 
434
                        if (moff & 0xff000000)
 
435
                                out[outpos++] = moff >> 24, i |= 0x08;
 
436
 
 
437
                        if (msize & 0x00ff)
 
438
                                out[outpos++] = msize >> 0, i |= 0x10;
 
439
                        if (msize & 0xff00)
 
440
                                out[outpos++] = msize >> 8, i |= 0x20;
 
441
 
 
442
                        *op = i;
 
443
 
 
444
                        data += msize;
 
445
                        moff += msize;
 
446
                        msize = left;
 
447
 
 
448
                        if (msize < 4096) {
 
449
                                int j;
 
450
                                val = 0;
 
451
                                for (j = -RABIN_WINDOW; j < 0; j++)
 
452
                                        val = ((val << 8) | data[j])
 
453
                                              ^ T[val >> RABIN_SHIFT];
 
454
                        }
 
455
                }
 
456
 
 
457
                if (outpos >= outsize - MAX_OP_SIZE) {
 
458
                        void *tmp = out;
 
459
                        outsize = outsize * 3 / 2;
 
460
                        if (max_size && outsize >= max_size)
 
461
                                outsize = max_size + MAX_OP_SIZE + 1;
 
462
                        if (max_size && outpos > max_size)
 
463
                                break;
 
464
                        out = realloc(out, outsize);
 
465
                        if (!out) {
 
466
                                free(tmp);
 
467
                                return NULL;
 
468
                        }
 
469
                }
 
470
        }
 
471
 
 
472
        if (inscnt)
 
473
                out[outpos - inscnt - 1] = inscnt;
 
474
 
 
475
        if (max_size && outpos > max_size) {
 
476
                free(out);
 
477
                return NULL;
 
478
        }
 
479
 
 
480
        *delta_size = outpos;
 
481
        return out;
 
482
}