Blame src/delta.c

Packit Service 20376f
/*
Packit Service 20376f
 * Copyright (C) the libgit2 contributors. All rights reserved.
Packit Service 20376f
 *
Packit Service 20376f
 * This file is part of libgit2, distributed under the GNU GPL v2 with
Packit Service 20376f
 * a Linking Exception. For full terms see the included COPYING file.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
#include "delta.h"
Packit Service 20376f
Packit Service 20376f
/* maximum hash entry list for the same hash bucket */
Packit Service 20376f
#define HASH_LIMIT 64
Packit Service 20376f
Packit Service 20376f
#define RABIN_SHIFT 23
Packit Service 20376f
#define RABIN_WINDOW 16
Packit Service 20376f
Packit Service 20376f
static const unsigned int T[256] = {
Packit Service 20376f
	0x00000000, 0xab59b4d1, 0x56b369a2, 0xfdeadd73, 0x063f6795, 0xad66d344,
Packit Service 20376f
	0x508c0e37, 0xfbd5bae6, 0x0c7ecf2a, 0xa7277bfb, 0x5acda688, 0xf1941259,
Packit Service 20376f
	0x0a41a8bf, 0xa1181c6e, 0x5cf2c11d, 0xf7ab75cc, 0x18fd9e54, 0xb3a42a85,
Packit Service 20376f
	0x4e4ef7f6, 0xe5174327, 0x1ec2f9c1, 0xb59b4d10, 0x48719063, 0xe32824b2,
Packit Service 20376f
	0x1483517e, 0xbfdae5af, 0x423038dc, 0xe9698c0d, 0x12bc36eb, 0xb9e5823a,
Packit Service 20376f
	0x440f5f49, 0xef56eb98, 0x31fb3ca8, 0x9aa28879, 0x6748550a, 0xcc11e1db,
Packit Service 20376f
	0x37c45b3d, 0x9c9defec, 0x6177329f, 0xca2e864e, 0x3d85f382, 0x96dc4753,
Packit Service 20376f
	0x6b369a20, 0xc06f2ef1, 0x3bba9417, 0x90e320c6, 0x6d09fdb5, 0xc6504964,
Packit Service 20376f
	0x2906a2fc, 0x825f162d, 0x7fb5cb5e, 0xd4ec7f8f, 0x2f39c569, 0x846071b8,
Packit Service 20376f
	0x798aaccb, 0xd2d3181a, 0x25786dd6, 0x8e21d907, 0x73cb0474, 0xd892b0a5,
Packit Service 20376f
	0x23470a43, 0x881ebe92, 0x75f463e1, 0xdeadd730, 0x63f67950, 0xc8afcd81,
Packit Service 20376f
	0x354510f2, 0x9e1ca423, 0x65c91ec5, 0xce90aa14, 0x337a7767, 0x9823c3b6,
Packit Service 20376f
	0x6f88b67a, 0xc4d102ab, 0x393bdfd8, 0x92626b09, 0x69b7d1ef, 0xc2ee653e,
Packit Service 20376f
	0x3f04b84d, 0x945d0c9c, 0x7b0be704, 0xd05253d5, 0x2db88ea6, 0x86e13a77,
Packit Service 20376f
	0x7d348091, 0xd66d3440, 0x2b87e933, 0x80de5de2, 0x7775282e, 0xdc2c9cff,
Packit Service 20376f
	0x21c6418c, 0x8a9ff55d, 0x714a4fbb, 0xda13fb6a, 0x27f92619, 0x8ca092c8,
Packit Service 20376f
	0x520d45f8, 0xf954f129, 0x04be2c5a, 0xafe7988b, 0x5432226d, 0xff6b96bc,
Packit Service 20376f
	0x02814bcf, 0xa9d8ff1e, 0x5e738ad2, 0xf52a3e03, 0x08c0e370, 0xa39957a1,
Packit Service 20376f
	0x584ced47, 0xf3155996, 0x0eff84e5, 0xa5a63034, 0x4af0dbac, 0xe1a96f7d,
Packit Service 20376f
	0x1c43b20e, 0xb71a06df, 0x4ccfbc39, 0xe79608e8, 0x1a7cd59b, 0xb125614a,
Packit Service 20376f
	0x468e1486, 0xedd7a057, 0x103d7d24, 0xbb64c9f5, 0x40b17313, 0xebe8c7c2,
Packit Service 20376f
	0x16021ab1, 0xbd5bae60, 0x6cb54671, 0xc7ecf2a0, 0x3a062fd3, 0x915f9b02,
Packit Service 20376f
	0x6a8a21e4, 0xc1d39535, 0x3c394846, 0x9760fc97, 0x60cb895b, 0xcb923d8a,
Packit Service 20376f
	0x3678e0f9, 0x9d215428, 0x66f4eece, 0xcdad5a1f, 0x3047876c, 0x9b1e33bd,
Packit Service 20376f
	0x7448d825, 0xdf116cf4, 0x22fbb187, 0x89a20556, 0x7277bfb0, 0xd92e0b61,
Packit Service 20376f
	0x24c4d612, 0x8f9d62c3, 0x7836170f, 0xd36fa3de, 0x2e857ead, 0x85dcca7c,
Packit Service 20376f
	0x7e09709a, 0xd550c44b, 0x28ba1938, 0x83e3ade9, 0x5d4e7ad9, 0xf617ce08,
Packit Service 20376f
	0x0bfd137b, 0xa0a4a7aa, 0x5b711d4c, 0xf028a99d, 0x0dc274ee, 0xa69bc03f,
Packit Service 20376f
	0x5130b5f3, 0xfa690122, 0x0783dc51, 0xacda6880, 0x570fd266, 0xfc5666b7,
Packit Service 20376f
	0x01bcbbc4, 0xaae50f15, 0x45b3e48d, 0xeeea505c, 0x13008d2f, 0xb85939fe,
Packit Service 20376f
	0x438c8318, 0xe8d537c9, 0x153feaba, 0xbe665e6b, 0x49cd2ba7, 0xe2949f76,
Packit Service 20376f
	0x1f7e4205, 0xb427f6d4, 0x4ff24c32, 0xe4abf8e3, 0x19412590, 0xb2189141,
Packit Service 20376f
	0x0f433f21, 0xa41a8bf0, 0x59f05683, 0xf2a9e252, 0x097c58b4, 0xa225ec65,
Packit Service 20376f
	0x5fcf3116, 0xf49685c7, 0x033df00b, 0xa86444da, 0x558e99a9, 0xfed72d78,
Packit Service 20376f
	0x0502979e, 0xae5b234f, 0x53b1fe3c, 0xf8e84aed, 0x17bea175, 0xbce715a4,
Packit Service 20376f
	0x410dc8d7, 0xea547c06, 0x1181c6e0, 0xbad87231, 0x4732af42, 0xec6b1b93,
Packit Service 20376f
	0x1bc06e5f, 0xb099da8e, 0x4d7307fd, 0xe62ab32c, 0x1dff09ca, 0xb6a6bd1b,
Packit Service 20376f
	0x4b4c6068, 0xe015d4b9, 0x3eb80389, 0x95e1b758, 0x680b6a2b, 0xc352defa,
Packit Service 20376f
	0x3887641c, 0x93ded0cd, 0x6e340dbe, 0xc56db96f, 0x32c6cca3, 0x999f7872,
Packit Service 20376f
	0x6475a501, 0xcf2c11d0, 0x34f9ab36, 0x9fa01fe7, 0x624ac294, 0xc9137645,
Packit Service 20376f
	0x26459ddd, 0x8d1c290c, 0x70f6f47f, 0xdbaf40ae, 0x207afa48, 0x8b234e99,
Packit Service 20376f
	0x76c993ea, 0xdd90273b, 0x2a3b52f7, 0x8162e626, 0x7c883b55, 0xd7d18f84,
Packit Service 20376f
	0x2c043562, 0x875d81b3, 0x7ab75cc0, 0xd1eee811
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
static const unsigned int U[256] = {
Packit Service 20376f
	0x00000000, 0x7eb5200d, 0x5633f4cb, 0x2886d4c6, 0x073e5d47, 0x798b7d4a,
Packit Service 20376f
	0x510da98c, 0x2fb88981, 0x0e7cba8e, 0x70c99a83, 0x584f4e45, 0x26fa6e48,
Packit Service 20376f
	0x0942e7c9, 0x77f7c7c4, 0x5f711302, 0x21c4330f, 0x1cf9751c, 0x624c5511,
Packit Service 20376f
	0x4aca81d7, 0x347fa1da, 0x1bc7285b, 0x65720856, 0x4df4dc90, 0x3341fc9d,
Packit Service 20376f
	0x1285cf92, 0x6c30ef9f, 0x44b63b59, 0x3a031b54, 0x15bb92d5, 0x6b0eb2d8,
Packit Service 20376f
	0x4388661e, 0x3d3d4613, 0x39f2ea38, 0x4747ca35, 0x6fc11ef3, 0x11743efe,
Packit Service 20376f
	0x3eccb77f, 0x40799772, 0x68ff43b4, 0x164a63b9, 0x378e50b6, 0x493b70bb,
Packit Service 20376f
	0x61bda47d, 0x1f088470, 0x30b00df1, 0x4e052dfc, 0x6683f93a, 0x1836d937,
Packit Service 20376f
	0x250b9f24, 0x5bbebf29, 0x73386bef, 0x0d8d4be2, 0x2235c263, 0x5c80e26e,
Packit Service 20376f
	0x740636a8, 0x0ab316a5, 0x2b7725aa, 0x55c205a7, 0x7d44d161, 0x03f1f16c,
Packit Service 20376f
	0x2c4978ed, 0x52fc58e0, 0x7a7a8c26, 0x04cfac2b, 0x73e5d470, 0x0d50f47d,
Packit Service 20376f
	0x25d620bb, 0x5b6300b6, 0x74db8937, 0x0a6ea93a, 0x22e87dfc, 0x5c5d5df1,
Packit Service 20376f
	0x7d996efe, 0x032c4ef3, 0x2baa9a35, 0x551fba38, 0x7aa733b9, 0x041213b4,
Packit Service 20376f
	0x2c94c772, 0x5221e77f, 0x6f1ca16c, 0x11a98161, 0x392f55a7, 0x479a75aa,
Packit Service 20376f
	0x6822fc2b, 0x1697dc26, 0x3e1108e0, 0x40a428ed, 0x61601be2, 0x1fd53bef,
Packit Service 20376f
	0x3753ef29, 0x49e6cf24, 0x665e46a5, 0x18eb66a8, 0x306db26e, 0x4ed89263,
Packit Service 20376f
	0x4a173e48, 0x34a21e45, 0x1c24ca83, 0x6291ea8e, 0x4d29630f, 0x339c4302,
Packit Service 20376f
	0x1b1a97c4, 0x65afb7c9, 0x446b84c6, 0x3adea4cb, 0x1258700d, 0x6ced5000,
Packit Service 20376f
	0x4355d981, 0x3de0f98c, 0x15662d4a, 0x6bd30d47, 0x56ee4b54, 0x285b6b59,
Packit Service 20376f
	0x00ddbf9f, 0x7e689f92, 0x51d01613, 0x2f65361e, 0x07e3e2d8, 0x7956c2d5,
Packit Service 20376f
	0x5892f1da, 0x2627d1d7, 0x0ea10511, 0x7014251c, 0x5facac9d, 0x21198c90,
Packit Service 20376f
	0x099f5856, 0x772a785b, 0x4c921c31, 0x32273c3c, 0x1aa1e8fa, 0x6414c8f7,
Packit Service 20376f
	0x4bac4176, 0x3519617b, 0x1d9fb5bd, 0x632a95b0, 0x42eea6bf, 0x3c5b86b2,
Packit Service 20376f
	0x14dd5274, 0x6a687279, 0x45d0fbf8, 0x3b65dbf5, 0x13e30f33, 0x6d562f3e,
Packit Service 20376f
	0x506b692d, 0x2ede4920, 0x06589de6, 0x78edbdeb, 0x5755346a, 0x29e01467,
Packit Service 20376f
	0x0166c0a1, 0x7fd3e0ac, 0x5e17d3a3, 0x20a2f3ae, 0x08242768, 0x76910765,
Packit Service 20376f
	0x59298ee4, 0x279caee9, 0x0f1a7a2f, 0x71af5a22, 0x7560f609, 0x0bd5d604,
Packit Service 20376f
	0x235302c2, 0x5de622cf, 0x725eab4e, 0x0ceb8b43, 0x246d5f85, 0x5ad87f88,
Packit Service 20376f
	0x7b1c4c87, 0x05a96c8a, 0x2d2fb84c, 0x539a9841, 0x7c2211c0, 0x029731cd,
Packit Service 20376f
	0x2a11e50b, 0x54a4c506, 0x69998315, 0x172ca318, 0x3faa77de, 0x411f57d3,
Packit Service 20376f
	0x6ea7de52, 0x1012fe5f, 0x38942a99, 0x46210a94, 0x67e5399b, 0x19501996,
Packit Service 20376f
	0x31d6cd50, 0x4f63ed5d, 0x60db64dc, 0x1e6e44d1, 0x36e89017, 0x485db01a,
Packit Service 20376f
	0x3f77c841, 0x41c2e84c, 0x69443c8a, 0x17f11c87, 0x38499506, 0x46fcb50b,
Packit Service 20376f
	0x6e7a61cd, 0x10cf41c0, 0x310b72cf, 0x4fbe52c2, 0x67388604, 0x198da609,
Packit Service 20376f
	0x36352f88, 0x48800f85, 0x6006db43, 0x1eb3fb4e, 0x238ebd5d, 0x5d3b9d50,
Packit Service 20376f
	0x75bd4996, 0x0b08699b, 0x24b0e01a, 0x5a05c017, 0x728314d1, 0x0c3634dc,
Packit Service 20376f
	0x2df207d3, 0x534727de, 0x7bc1f318, 0x0574d315, 0x2acc5a94, 0x54797a99,
Packit Service 20376f
	0x7cffae5f, 0x024a8e52, 0x06852279, 0x78300274, 0x50b6d6b2, 0x2e03f6bf,
Packit Service 20376f
	0x01bb7f3e, 0x7f0e5f33, 0x57888bf5, 0x293dabf8, 0x08f998f7, 0x764cb8fa,
Packit Service 20376f
	0x5eca6c3c, 0x207f4c31, 0x0fc7c5b0, 0x7172e5bd, 0x59f4317b, 0x27411176,
Packit Service 20376f
	0x1a7c5765, 0x64c97768, 0x4c4fa3ae, 0x32fa83a3, 0x1d420a22, 0x63f72a2f,
Packit Service 20376f
	0x4b71fee9, 0x35c4dee4, 0x1400edeb, 0x6ab5cde6, 0x42331920, 0x3c86392d,
Packit Service 20376f
	0x133eb0ac, 0x6d8b90a1, 0x450d4467, 0x3bb8646a
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
struct index_entry {
Packit Service 20376f
	const unsigned char *ptr;
Packit Service 20376f
	unsigned int val;
Packit Service 20376f
	struct index_entry *next;
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
struct git_delta_index {
Packit Service 20376f
	unsigned long memsize;
Packit Service 20376f
	const void *src_buf;
Packit Service 20376f
	size_t src_size;
Packit Service 20376f
	unsigned int hash_mask;
Packit Service 20376f
	struct index_entry *hash[GIT_FLEX_ARRAY];
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
static int lookup_index_alloc(
Packit Service 20376f
	void **out, unsigned long *out_len, size_t entries, size_t hash_count)
Packit Service 20376f
{
Packit Service 20376f
	size_t entries_len, hash_len, index_len;
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_MULTIPLY(&entries_len, entries, sizeof(struct index_entry));
Packit Service 20376f
	GITERR_CHECK_ALLOC_MULTIPLY(&hash_len, hash_count, sizeof(struct index_entry *));
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&index_len, sizeof(struct git_delta_index), entries_len);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&index_len, index_len, hash_len);
Packit Service 20376f
Packit Service 20376f
	if (!git__is_ulong(index_len)) {
Packit Service 20376f
		giterr_set(GITERR_NOMEMORY, "overly large delta");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	*out = git__malloc(index_len);
Packit Service 20376f
	GITERR_CHECK_ALLOC(*out);
Packit Service 20376f
Packit Service 20376f
	*out_len = index_len;
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_delta_index_init(
Packit Service 20376f
	git_delta_index **out, const void *buf, size_t bufsize)
Packit Service 20376f
{
Packit Service 20376f
	unsigned int i, hsize, hmask, entries, prev_val, *hash_count;
Packit Service 20376f
	const unsigned char *data, *buffer = buf;
Packit Service 20376f
	struct git_delta_index *index;
Packit Service 20376f
	struct index_entry *entry, **hash;
Packit Service 20376f
	void *mem;
Packit Service 20376f
	unsigned long memsize;
Packit Service 20376f
Packit Service 20376f
	*out = NULL;
Packit Service 20376f
Packit Service 20376f
	if (!buf || !bufsize)
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	/* Determine index hash size.  Note that indexing skips the
Packit Service 20376f
	   first byte to allow for optimizing the rabin polynomial
Packit Service 20376f
	   initialization in create_delta(). */
Packit Service 20376f
	entries = (unsigned int)(bufsize - 1) / RABIN_WINDOW;
Packit Service 20376f
	if (bufsize >= 0xffffffffUL) {
Packit Service 20376f
		/*
Packit Service 20376f
		 * Current delta format can't encode offsets into
Packit Service 20376f
		 * reference buffer with more than 32 bits.
Packit Service 20376f
		 */
Packit Service 20376f
		entries = 0xfffffffeU / RABIN_WINDOW;
Packit Service 20376f
	}
Packit Service 20376f
	hsize = entries / 4;
Packit Service 20376f
	for (i = 4; i < 31 && (1u << i) < hsize; i++);
Packit Service 20376f
	hsize = 1 << i;
Packit Service 20376f
	hmask = hsize - 1;
Packit Service 20376f
Packit Service 20376f
	if (lookup_index_alloc(&mem, &memsize, entries, hsize) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	index = mem;
Packit Service 20376f
	mem = index->hash;
Packit Service 20376f
	hash = mem;
Packit Service 20376f
	mem = hash + hsize;
Packit Service 20376f
	entry = mem;
Packit Service 20376f
Packit Service 20376f
	index->memsize = memsize;
Packit Service 20376f
	index->src_buf = buf;
Packit Service 20376f
	index->src_size = bufsize;
Packit Service 20376f
	index->hash_mask = hmask;
Packit Service 20376f
	memset(hash, 0, hsize * sizeof(*hash));
Packit Service 20376f
Packit Service 20376f
	/* allocate an array to count hash entries */
Packit Service 20376f
	hash_count = git__calloc(hsize, sizeof(*hash_count));
Packit Service 20376f
	if (!hash_count) {
Packit Service 20376f
		git__free(index);
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/* then populate the index */
Packit Service 20376f
	prev_val = ~0;
Packit Service 20376f
	for (data = buffer + entries * RABIN_WINDOW - RABIN_WINDOW;
Packit Service 20376f
	     data >= buffer;
Packit Service 20376f
	     data -= RABIN_WINDOW) {
Packit Service 20376f
		unsigned int val = 0;
Packit Service 20376f
		for (i = 1; i <= RABIN_WINDOW; i++)
Packit Service 20376f
			val = ((val << 8) | data[i]) ^ T[val >> RABIN_SHIFT];
Packit Service 20376f
		if (val == prev_val) {
Packit Service 20376f
			/* keep the lowest of consecutive identical blocks */
Packit Service 20376f
			entry[-1].ptr = data + RABIN_WINDOW;
Packit Service 20376f
		} else {
Packit Service 20376f
			prev_val = val;
Packit Service 20376f
			i = val & hmask;
Packit Service 20376f
			entry->ptr = data + RABIN_WINDOW;
Packit Service 20376f
			entry->val = val;
Packit Service 20376f
			entry->next = hash[i];
Packit Service 20376f
			hash[i] = entry++;
Packit Service 20376f
			hash_count[i]++;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * Determine a limit on the number of entries in the same hash
Packit Service 20376f
	 * bucket.  This guard us against patological data sets causing
Packit Service 20376f
	 * really bad hash distribution with most entries in the same hash
Packit Service 20376f
	 * bucket that would bring us to O(m*n) computing costs (m and n
Packit Service 20376f
	 * corresponding to reference and target buffer sizes).
Packit Service 20376f
	 *
Packit Service 20376f
	 * Make sure none of the hash buckets has more entries than
Packit Service 20376f
	 * we're willing to test.  Otherwise we cull the entry list
Packit Service 20376f
	 * uniformly to still preserve a good repartition across
Packit Service 20376f
	 * the reference buffer.
Packit Service 20376f
	 */
Packit Service 20376f
	for (i = 0; i < hsize; i++) {
Packit Service 20376f
		if (hash_count[i] < HASH_LIMIT)
Packit Service 20376f
			continue;
Packit Service 20376f
Packit Service 20376f
		entry = hash[i];
Packit Service 20376f
		do {
Packit Service 20376f
			struct index_entry *keep = entry;
Packit Service 20376f
			int skip = hash_count[i] / HASH_LIMIT / 2;
Packit Service 20376f
			do {
Packit Service 20376f
				entry = entry->next;
Packit Service 20376f
			} while(--skip && entry);
Packit Service 20376f
			keep->next = entry;
Packit Service 20376f
		} while (entry);
Packit Service 20376f
	}
Packit Service 20376f
	git__free(hash_count);
Packit Service 20376f
Packit Service 20376f
	*out = index;
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_delta_index_free(git_delta_index *index)
Packit Service 20376f
{
Packit Service 20376f
	git__free(index);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
size_t git_delta_index_size(git_delta_index *index)
Packit Service 20376f
{
Packit Service 20376f
	assert(index);
Packit Service 20376f
Packit Service 20376f
	return index->memsize;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/*
Packit Service 20376f
 * The maximum size for any opcode sequence, including the initial header
Packit Service 20376f
 * plus rabin window plus biggest copy.
Packit Service 20376f
 */
Packit Service 20376f
#define MAX_OP_SIZE	(5 + 5 + 1 + RABIN_WINDOW + 7)
Packit Service 20376f
Packit Service 20376f
int git_delta_create_from_index(
Packit Service 20376f
	void **out,
Packit Service 20376f
	size_t *out_len,
Packit Service 20376f
	const struct git_delta_index *index,
Packit Service 20376f
	const void *trg_buf,
Packit Service 20376f
	size_t trg_size,
Packit Service 20376f
	size_t max_size)
Packit Service 20376f
{
Packit Service 20376f
	unsigned int i, bufpos, bufsize, moff, msize, val;
Packit Service 20376f
	int inscnt;
Packit Service 20376f
	const unsigned char *ref_data, *ref_top, *data, *top;
Packit Service 20376f
	unsigned char *buf;
Packit Service 20376f
Packit Service 20376f
	*out = NULL;
Packit Service 20376f
	*out_len = 0;
Packit Service 20376f
Packit Service 20376f
	if (!trg_buf || !trg_size)
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	bufpos = 0;
Packit Service 20376f
	bufsize = 8192;
Packit Service 20376f
	if (max_size && bufsize >= max_size)
Packit Service 20376f
		bufsize = (unsigned int)(max_size + MAX_OP_SIZE + 1);
Packit Service 20376f
	buf = git__malloc(bufsize);
Packit Service 20376f
	GITERR_CHECK_ALLOC(buf);
Packit Service 20376f
Packit Service 20376f
	/* store reference buffer size */
Packit Service 20376f
	i = index->src_size;
Packit Service 20376f
	while (i >= 0x80) {
Packit Service 20376f
		buf[bufpos++] = i | 0x80;
Packit Service 20376f
		i >>= 7;
Packit Service 20376f
	}
Packit Service 20376f
	buf[bufpos++] = i;
Packit Service 20376f
Packit Service 20376f
	/* store target buffer size */
Packit Service 20376f
	i = trg_size;
Packit Service 20376f
	while (i >= 0x80) {
Packit Service 20376f
		buf[bufpos++] = i | 0x80;
Packit Service 20376f
		i >>= 7;
Packit Service 20376f
	}
Packit Service 20376f
	buf[bufpos++] = i;
Packit Service 20376f
Packit Service 20376f
	ref_data = index->src_buf;
Packit Service 20376f
	ref_top = ref_data + index->src_size;
Packit Service 20376f
	data = trg_buf;
Packit Service 20376f
	top = (const unsigned char *) trg_buf + trg_size;
Packit Service 20376f
Packit Service 20376f
	bufpos++;
Packit Service 20376f
	val = 0;
Packit Service 20376f
	for (i = 0; i < RABIN_WINDOW && data < top; i++, data++) {
Packit Service 20376f
		buf[bufpos++] = *data;
Packit Service 20376f
		val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT];
Packit Service 20376f
	}
Packit Service 20376f
	inscnt = i;
Packit Service 20376f
Packit Service 20376f
	moff = 0;
Packit Service 20376f
	msize = 0;
Packit Service 20376f
	while (data < top) {
Packit Service 20376f
		if (msize < 4096) {
Packit Service 20376f
			struct index_entry *entry;
Packit Service 20376f
			val ^= U[data[-RABIN_WINDOW]];
Packit Service 20376f
			val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT];
Packit Service 20376f
			i = val & index->hash_mask;
Packit Service 20376f
			for (entry = index->hash[i]; entry; entry = entry->next) {
Packit Service 20376f
				const unsigned char *ref = entry->ptr;
Packit Service 20376f
				const unsigned char *src = data;
Packit Service 20376f
				unsigned int ref_size = (unsigned int)(ref_top - ref);
Packit Service 20376f
				if (entry->val != val)
Packit Service 20376f
					continue;
Packit Service 20376f
				if (ref_size > (unsigned int)(top - src))
Packit Service 20376f
					ref_size = (unsigned int)(top - src);
Packit Service 20376f
				if (ref_size <= msize)
Packit Service 20376f
					break;
Packit Service 20376f
				while (ref_size-- && *src++ == *ref)
Packit Service 20376f
					ref++;
Packit Service 20376f
				if (msize < (unsigned int)(ref - entry->ptr)) {
Packit Service 20376f
					/* this is our best match so far */
Packit Service 20376f
					msize = (unsigned int)(ref - entry->ptr);
Packit Service 20376f
					moff = (unsigned int)(entry->ptr - ref_data);
Packit Service 20376f
					if (msize >= 4096) /* good enough */
Packit Service 20376f
						break;
Packit Service 20376f
				}
Packit Service 20376f
			}
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		if (msize < 4) {
Packit Service 20376f
			if (!inscnt)
Packit Service 20376f
				bufpos++;
Packit Service 20376f
			buf[bufpos++] = *data++;
Packit Service 20376f
			inscnt++;
Packit Service 20376f
			if (inscnt == 0x7f) {
Packit Service 20376f
				buf[bufpos - inscnt - 1] = inscnt;
Packit Service 20376f
				inscnt = 0;
Packit Service 20376f
			}
Packit Service 20376f
			msize = 0;
Packit Service 20376f
		} else {
Packit Service 20376f
			unsigned int left;
Packit Service 20376f
			unsigned char *op;
Packit Service 20376f
Packit Service 20376f
			if (inscnt) {
Packit Service 20376f
				while (moff && ref_data[moff-1] == data[-1]) {
Packit Service 20376f
					/* we can match one byte back */
Packit Service 20376f
					msize++;
Packit Service 20376f
					moff--;
Packit Service 20376f
					data--;
Packit Service 20376f
					bufpos--;
Packit Service 20376f
					if (--inscnt)
Packit Service 20376f
						continue;
Packit Service 20376f
					bufpos--;  /* remove count slot */
Packit Service 20376f
					inscnt--;  /* make it -1 */
Packit Service 20376f
					break;
Packit Service 20376f
				}
Packit Service 20376f
				buf[bufpos - inscnt - 1] = inscnt;
Packit Service 20376f
				inscnt = 0;
Packit Service 20376f
			}
Packit Service 20376f
Packit Service 20376f
			/* A copy op is currently limited to 64KB (pack v2) */
Packit Service 20376f
			left = (msize < 0x10000) ? 0 : (msize - 0x10000);
Packit Service 20376f
			msize -= left;
Packit Service 20376f
Packit Service 20376f
			op = buf + bufpos++;
Packit Service 20376f
			i = 0x80;
Packit Service 20376f
Packit Service 20376f
			if (moff & 0x000000ff)
Packit Service 20376f
				buf[bufpos++] = moff >> 0,  i |= 0x01;
Packit Service 20376f
			if (moff & 0x0000ff00)
Packit Service 20376f
				buf[bufpos++] = moff >> 8,  i |= 0x02;
Packit Service 20376f
			if (moff & 0x00ff0000)
Packit Service 20376f
				buf[bufpos++] = moff >> 16, i |= 0x04;
Packit Service 20376f
			if (moff & 0xff000000)
Packit Service 20376f
				buf[bufpos++] = moff >> 24, i |= 0x08;
Packit Service 20376f
Packit Service 20376f
			if (msize & 0x00ff)
Packit Service 20376f
				buf[bufpos++] = msize >> 0, i |= 0x10;
Packit Service 20376f
			if (msize & 0xff00)
Packit Service 20376f
				buf[bufpos++] = msize >> 8, i |= 0x20;
Packit Service 20376f
Packit Service 20376f
			*op = i;
Packit Service 20376f
Packit Service 20376f
			data += msize;
Packit Service 20376f
			moff += msize;
Packit Service 20376f
			msize = left;
Packit Service 20376f
Packit Service 20376f
			if (msize < 4096) {
Packit Service 20376f
				int j;
Packit Service 20376f
				val = 0;
Packit Service 20376f
				for (j = -RABIN_WINDOW; j < 0; j++)
Packit Service 20376f
					val = ((val << 8) | data[j])
Packit Service 20376f
					      ^ T[val >> RABIN_SHIFT];
Packit Service 20376f
			}
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		if (bufpos >= bufsize - MAX_OP_SIZE) {
Packit Service 20376f
			void *tmp = buf;
Packit Service 20376f
			bufsize = bufsize * 3 / 2;
Packit Service 20376f
			if (max_size && bufsize >= max_size)
Packit Service 20376f
				bufsize = max_size + MAX_OP_SIZE + 1;
Packit Service 20376f
			if (max_size && bufpos > max_size)
Packit Service 20376f
				break;
Packit Service 20376f
			buf = git__realloc(buf, bufsize);
Packit Service 20376f
			if (!buf) {
Packit Service 20376f
				git__free(tmp);
Packit Service 20376f
				return -1;
Packit Service 20376f
			}
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (inscnt)
Packit Service 20376f
		buf[bufpos - inscnt - 1] = inscnt;
Packit Service 20376f
Packit Service 20376f
	if (max_size && bufpos > max_size) {
Packit Service 20376f
		giterr_set(GITERR_NOMEMORY, "delta would be larger than maximum size");
Packit Service 20376f
		git__free(buf);
Packit Service 20376f
		return GIT_EBUFS;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	*out_len = bufpos;
Packit Service 20376f
	*out = buf;
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/*
Packit Service 20376f
* Delta application was heavily cribbed from BinaryDelta.java in JGit, which
Packit Service 20376f
* itself was heavily cribbed from patch-delta.c in the
Packit Service 20376f
* GIT project.	The original delta patching code was written by
Packit Service 20376f
* Nicolas Pitre <nico@cam.org>.
Packit Service 20376f
*/
Packit Service 20376f
Packit Service 20376f
static int hdr_sz(
Packit Service 20376f
	size_t *size,
Packit Service 20376f
	const unsigned char **delta,
Packit Service 20376f
	const unsigned char *end)
Packit Service 20376f
{
Packit Service 20376f
	const unsigned char *d = *delta;
Packit Service 20376f
	size_t r = 0;
Packit Service 20376f
	unsigned int c, shift = 0;
Packit Service 20376f
Packit Service 20376f
	do {
Packit Service 20376f
		if (d == end) {
Packit Service 20376f
			giterr_set(GITERR_INVALID, "truncated delta");
Packit Service 20376f
			return -1;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		c = *d++;
Packit Service 20376f
		r |= (c & 0x7f) << shift;
Packit Service 20376f
		shift += 7;
Packit Service 20376f
	} while (c & 0x80);
Packit Service 20376f
	*delta = d;
Packit Service 20376f
	*size = r;
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_delta_read_header(
Packit Service 20376f
	size_t *base_out,
Packit Service 20376f
	size_t *result_out,
Packit Service 20376f
	const unsigned char *delta,
Packit Service 20376f
	size_t delta_len)
Packit Service 20376f
{
Packit Service 20376f
	const unsigned char *delta_end = delta + delta_len;
Packit Service 20376f
	if ((hdr_sz(base_out, &delta, delta_end) < 0) ||
Packit Service 20376f
		(hdr_sz(result_out, &delta, delta_end) < 0))
Packit Service 20376f
		return -1;
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
#define DELTA_HEADER_BUFFER_LEN 16
Packit Service 20376f
int git_delta_read_header_fromstream(
Packit Service 20376f
	size_t *base_sz, size_t *res_sz, git_packfile_stream *stream)
Packit Service 20376f
{
Packit Service 20376f
	static const size_t buffer_len = DELTA_HEADER_BUFFER_LEN;
Packit Service 20376f
	unsigned char buffer[DELTA_HEADER_BUFFER_LEN];
Packit Service 20376f
	const unsigned char *delta, *delta_end;
Packit Service 20376f
	size_t len;
Packit Service 20376f
	ssize_t read;
Packit Service 20376f
Packit Service 20376f
	len = read = 0;
Packit Service 20376f
	while (len < buffer_len) {
Packit Service 20376f
		read = git_packfile_stream_read(stream, &buffer[len], buffer_len - len);
Packit Service 20376f
Packit Service 20376f
		if (read == 0)
Packit Service 20376f
			break;
Packit Service 20376f
Packit Service 20376f
		if (read == GIT_EBUFS)
Packit Service 20376f
			continue;
Packit Service 20376f
Packit Service 20376f
		len += read;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	delta = buffer;
Packit Service 20376f
	delta_end = delta + len;
Packit Service 20376f
	if ((hdr_sz(base_sz, &delta, delta_end) < 0) ||
Packit Service 20376f
		(hdr_sz(res_sz, &delta, delta_end) < 0))
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_delta_apply(
Packit Service 20376f
	void **out,
Packit Service 20376f
	size_t *out_len,
Packit Service 20376f
	const unsigned char *base,
Packit Service 20376f
	size_t base_len,
Packit Service 20376f
	const unsigned char *delta,
Packit Service 20376f
	size_t delta_len)
Packit Service 20376f
{
Packit Service 20376f
	const unsigned char *delta_end = delta + delta_len;
Packit Service 20376f
	size_t base_sz, res_sz, alloc_sz;
Packit Service 20376f
	unsigned char *res_dp;
Packit Service 20376f
Packit Service 20376f
	*out = NULL;
Packit Service 20376f
	*out_len = 0;
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * Check that the base size matches the data we were given;
Packit Service 20376f
	 * if not we would underflow while accessing data from the
Packit Service 20376f
	 * base object, resulting in data corruption or segfault.
Packit Service 20376f
	 */
Packit Service 20376f
	if ((hdr_sz(&base_sz, &delta, delta_end) < 0) || (base_sz != base_len)) {
Packit Service 20376f
		giterr_set(GITERR_INVALID, "failed to apply delta: base size does not match given data");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (hdr_sz(&res_sz, &delta, delta_end) < 0) {
Packit Service 20376f
		giterr_set(GITERR_INVALID, "failed to apply delta: base size does not match given data");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_sz, res_sz, 1);
Packit Service 20376f
	res_dp = git__malloc(alloc_sz);
Packit Service 20376f
	GITERR_CHECK_ALLOC(res_dp);
Packit Service 20376f
Packit Service 20376f
	res_dp[res_sz] = '\0';
Packit Service 20376f
	*out = res_dp;
Packit Service 20376f
	*out_len = res_sz;
Packit Service 20376f
Packit Service 20376f
	while (delta < delta_end) {
Packit Service 20376f
		unsigned char cmd = *delta++;
Packit Service 20376f
		if (cmd & 0x80) {
Packit Service 20376f
			/* cmd is a copy instruction; copy from the base. */
Packit Service 20376f
			size_t off = 0, len = 0, end;
Packit Service 20376f
Packit Service 20376f
#define ADD_DELTA(o, shift) { if (delta < delta_end) (o) |= ((unsigned) *delta++ << shift); else goto fail; }
Packit Service 20376f
			if (cmd & 0x01) ADD_DELTA(off, 0UL);
Packit Service 20376f
			if (cmd & 0x02) ADD_DELTA(off, 8UL);
Packit Service 20376f
			if (cmd & 0x04) ADD_DELTA(off, 16UL);
Packit Service 20376f
			if (cmd & 0x08) ADD_DELTA(off, 24UL);
Packit Service 20376f
Packit Service 20376f
			if (cmd & 0x10) ADD_DELTA(len, 0UL);
Packit Service 20376f
			if (cmd & 0x20) ADD_DELTA(len, 8UL);
Packit Service 20376f
			if (cmd & 0x40) ADD_DELTA(len, 16UL);
Packit Service 20376f
			if (!len)       len = 0x10000;
Packit Service 20376f
#undef ADD_DELTA
Packit Service 20376f
Packit Service 20376f
			if (GIT_ADD_SIZET_OVERFLOW(&end, off, len) ||
Packit Service 20376f
			    base_len < end || res_sz < len)
Packit Service 20376f
				goto fail;
Packit Service 20376f
Packit Service 20376f
			memcpy(res_dp, base + off, len);
Packit Service 20376f
			res_dp += len;
Packit Service 20376f
			res_sz -= len;
Packit Service 20376f
Packit Service 20376f
		} else if (cmd) {
Packit Service 20376f
			/*
Packit Service 20376f
			 * cmd is a literal insert instruction; copy from
Packit Service 20376f
			 * the delta stream itself.
Packit Service 20376f
			 */
Packit Service 20376f
			if (delta_end - delta < cmd || res_sz < cmd)
Packit Service 20376f
				goto fail;
Packit Service 20376f
			memcpy(res_dp, delta, cmd);
Packit Service 20376f
			delta += cmd;
Packit Service 20376f
			res_dp += cmd;
Packit Service 20376f
			res_sz -= cmd;
Packit Service 20376f
Packit Service 20376f
		} else {
Packit Service 20376f
			/* cmd == 0 is reserved for future encodings. */
Packit Service 20376f
			goto fail;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (delta != delta_end || res_sz)
Packit Service 20376f
		goto fail;
Packit Service 20376f
	return 0;
Packit Service 20376f
Packit Service 20376f
fail:
Packit Service 20376f
	git__free(*out);
Packit Service 20376f
Packit Service 20376f
	*out = NULL;
Packit Service 20376f
	*out_len = 0;
Packit Service 20376f
Packit Service 20376f
	giterr_set(GITERR_INVALID, "failed to apply delta");
Packit Service 20376f
	return -1;
Packit Service 20376f
}