| #include "object.h" | 
 | #include "blob.h" | 
 | #include "tree.h" | 
 | #include "commit.h" | 
 | #include "tag.h" | 
 | #include "delta.h" | 
 | #include "cache.h" | 
 |  | 
 | /* the delta object definition (it can alias any other object) */ | 
 | struct delta { | 
 | 	union { | 
 | 		struct object object; | 
 | 		struct blob blob; | 
 | 		struct tree tree; | 
 | 		struct commit commit; | 
 | 		struct tag tag; | 
 | 	} u; | 
 | }; | 
 |  | 
 | struct delta *lookup_delta(unsigned char *sha1) | 
 | { | 
 | 	struct object *obj = lookup_object(sha1); | 
 | 	if (!obj) { | 
 | 		struct delta *ret = xmalloc(sizeof(struct delta)); | 
 | 		memset(ret, 0, sizeof(struct delta)); | 
 | 		created_object(sha1, &ret->u.object); | 
 | 		return ret; | 
 | 	} | 
 | 	return (struct delta *) obj; | 
 | } | 
 |  | 
 | int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size) | 
 | { | 
 | 	struct object *reference; | 
 | 	struct object_list *p; | 
 |  | 
 | 	if (item->u.object.delta) | 
 | 		return 0; | 
 | 	item->u.object.delta = 1; | 
 | 	if (size <= 20) | 
 | 		return -1; | 
 | 	reference = lookup_object(buffer); | 
 | 	if (!reference) { | 
 | 		struct delta *ref = xmalloc(sizeof(struct delta)); | 
 | 		memset(ref, 0, sizeof(struct delta)); | 
 | 		created_object(buffer, &ref->u.object); | 
 | 		reference = &ref->u.object; | 
 | 	} | 
 |  | 
 | 	p = xmalloc(sizeof(*p)); | 
 | 	p->item = &item->u.object; | 
 | 	p->next = reference->attached_deltas; | 
 | 	reference->attached_deltas = p; | 
 | 	return 0; | 
 | } | 
 |  | 
 | int process_deltas(void *src, unsigned long src_size, const char *src_type, | 
 | 		   struct object_list *delta_list) | 
 | { | 
 | 	int deepest = 0; | 
 | 	do { | 
 | 		struct object *obj = delta_list->item; | 
 | 		static char type[10]; | 
 | 		void *map, *delta, *buf; | 
 | 		unsigned long map_size, delta_size, buf_size; | 
 | 		map = map_sha1_file(obj->sha1, &map_size); | 
 | 		if (!map) | 
 | 			continue; | 
 | 		delta = unpack_sha1_file(map, map_size, type, &delta_size); | 
 | 		munmap(map, map_size); | 
 | 		if (!delta) | 
 | 			continue; | 
 | 		if (strcmp(type, "delta") || delta_size <= 20) { | 
 | 			free(delta); | 
 | 			continue; | 
 | 		} | 
 | 		buf = patch_delta(src, src_size, | 
 | 				  delta+20, delta_size-20, | 
 | 				  &buf_size); | 
 | 		free(delta); | 
 | 		if (!buf) | 
 | 			continue; | 
 | 		if (check_sha1_signature(obj->sha1, buf, buf_size, src_type) < 0) | 
 | 			printf("sha1 mismatch for delta %s\n", sha1_to_hex(obj->sha1)); | 
 | 		if (obj->type && obj->type != src_type) { | 
 | 			error("got %s when expecting %s for delta %s", | 
 | 			      src_type, obj->type, sha1_to_hex(obj->sha1)); | 
 | 			free(buf); | 
 | 			continue; | 
 | 		} | 
 | 		obj->type = src_type; | 
 | 		if (src_type == blob_type) { | 
 | 			parse_blob_buffer((struct blob *)obj, buf, buf_size); | 
 | 		} else if (src_type == tree_type) { | 
 | 			parse_tree_buffer((struct tree *)obj, buf, buf_size); | 
 | 		} else if (src_type == commit_type) { | 
 | 			parse_commit_buffer((struct commit *)obj, buf, buf_size); | 
 | 		} else if (src_type == tag_type) { | 
 | 			parse_tag_buffer((struct tag *)obj, buf, buf_size); | 
 | 		} else { | 
 | 			error("unknown object type %s", src_type); | 
 | 			free(buf); | 
 | 			continue; | 
 | 		} | 
 | 		if (obj->attached_deltas) { | 
 | 			int depth = process_deltas(buf, buf_size, src_type, | 
 | 						   obj->attached_deltas); | 
 | 			if (deepest < depth) | 
 | 				deepest = depth; | 
 | 		} | 
 | 		free(buf); | 
 | 	} while ((delta_list = delta_list->next)); | 
 | 	return deepest + 1; | 
 | } |