Subject: [RFC PATCH 09/18] midx: find details of nth object in midx

From: Derrick Stolee <[email-masked]>
Date: Sun, 7 Jan 2018 13:14:50 -0500

The MIDX file stores pack offset information for a list of objects. The
nth_midxed_object_* methods provide ways to extract this information.

Signed-off-by: Derrick Stolee <[email-masked]>
---
 midx.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 midx.h | 15 +++++++++++++++
 2 files changed, 70 insertions(+)

diff --git a/midx.c b/midx.c
index c631be451f..4e0df0285a 100644
--- a/midx.c
+++ b/midx.c
@@ -202,6 +202,61 @@ struct pack_midx_details_internal {
 	uint32_t internal_offset;
 };
 
+struct pack_midx_details *nth_midxed_object_details(struct midxed_git *m,
+						    uint32_t n,
+						    struct pack_midx_details *d)
+{
+	struct pack_midx_details_internal *d_internal;
+	const unsigned char *details = m->chunk_object_offsets;
+
+	if (n >= m->num_objects)
+		return NULL;
+
+	d_internal = (struct pack_midx_details_internal*)(details + 8 * n);
+	d->pack_int_id = ntohl(d_internal->pack_int_id);
+	d->offset = ntohl(d_internal->internal_offset);
+
+	if (m->chunk_large_offsets && d->offset & MIDX_LARGE_OFFSET_NEEDED) {
+		uint32_t large_offset = d->offset ^ MIDX_LARGE_OFFSET_NEEDED;
+		const unsigned char *large_offsets = m->chunk_large_offsets + 8 * large_offset;
+
+		d->offset =  (((uint64_t)ntohl(*((uint32_t *)(large_offsets + 0)))) << 32) |
+					 ntohl(*((uint32_t *)(large_offsets + 4)));
+	}
+
+	return d;
+}
+
+struct pack_midx_entry *nth_midxed_object_entry(struct midxed_git *m,
+						uint32_t n,
+						struct pack_midx_entry *e)
+{
+	struct pack_midx_details details;
+	const unsigned char *index = m->chunk_oid_lookup;
+
+	if (!nth_midxed_object_details(m, n, &details))
+		return NULL;
+
+	memcpy(e->oid.hash, index + m->hdr->hash_len * n, m->hdr->hash_len);
+	e->pack_int_id = details.pack_int_id;
+	e->offset = details.offset;
+
+	return e;
+}
+
+const struct object_id *nth_midxed_object_oid(struct object_id *oid,
+					      struct midxed_git *m,
+					      uint32_t n)
+{
+	struct pack_midx_entry e;
+
+	if (!nth_midxed_object_entry(m, n, &e))
+		return 0;
+
+	hashcpy(oid->hash, e.oid.hash);
+	return oid;
+}
+
 static int midx_sha1_compare(const void *_a, const void *_b)
 {
 	struct pack_midx_entry *a = *(struct pack_midx_entry **)_a;
diff --git a/midx.h b/midx.h
index 92b74e49db..9255909ae8 100644
--- a/midx.h
+++ b/midx.h
@@ -85,6 +85,21 @@ struct midxed_git {
 
 extern struct midxed_git *get_midxed_git(const char *pack_dir, struct object_id *oid);
 
+struct pack_midx_details {
+	uint32_t pack_int_id;
+	off_t offset;
+};
+
+extern struct pack_midx_details *nth_midxed_object_details(struct midxed_git *m,
+							   uint32_t n,
+							   struct pack_midx_details *d);
+extern struct pack_midx_entry *nth_midxed_object_entry(struct midxed_git *m,
+						       uint32_t n,
+						       struct pack_midx_entry *e);
+extern const struct object_id *nth_midxed_object_oid(struct object_id *oid,
+						     struct midxed_git *m,
+						     uint32_t n);
+
 /*
  * Write a single MIDX file storing the given entries for the
  * given list of packfiles. If midx_name is null, then a temp
-- 
2.15.0