Subject: [PATCH 6/9] pv4_tree_desc: complete interface

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Wed, 9 Oct 2013 21:46:13 +0700

Best "explained" with an example

  void walk(const unsigned char *sha1)
  {
    struct pv4_tree_desc desc;
    /*
     * Start pv4_tree_desc from an SHA-1. If it's a v4 tree, v4 walker
     * will be used. Otherwise v2 is walked.
     */
    pv4_tree_desc_from_sha1(&desc, sha1, 0);
    recurse(&desc);
    pv4_release_tree_desc(&desc);
  }

  void recurse(struct pv4_tree_desc *desc)
  {
    /*
     * Then you can go over entries, one by one, similar to the
     * current tree walker. Current entry is in desc->v2.entry.
     * Pathlen in desc->pathlen. Do not use tree_entry_len() because
     * that one is only correct for v2 entries
     */
    while (pv4_get_entry(desc)) {
      printf("%s %s\n", sha1_to_hex(desc->v2.entry.sha1),
             desc->v2.entry.path);

      /*
       * Once you have an initialized pv4_tree_desc you may skip the
       * SHA-1 lookup step if the next tree is in the same pack.
       */
      if (S_ISDIR(desc->v2.entry.mode)) {
        struct pv4_tree_desc new_desc;
        pv4_tree_desc_from_entry(&new_desc, desc);
        recurse(&new_desc);

        /* Finally release everything */
        pv4_release_tree_desc(&new_desc);
      }
    }
  }

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 packv4-parse.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 packv4-parse.h | 12 +++++++++
 2 files changed, 92 insertions(+)

diff --git a/packv4-parse.c b/packv4-parse.c
index f222456..7d257af 100644
--- a/packv4-parse.c
+++ b/packv4-parse.c
@@ -732,3 +732,83 @@ unsigned long pv4_unpack_object_header_buffer(const unsigned char *base,
 	*sizep = val >> 4;
 	return cp - base;
 }
+
+int pv4_tree_desc_from_sha1(struct pv4_tree_desc *desc,
+			    const unsigned char *sha1,
+			    unsigned flags)
+{
+	unsigned long size;
+	enum object_type type;
+	void *data;
+	struct object_info oi;
+
+	assert(!(flags & ~0xff) &&
+	       "you are not supposed to set these from outside!");
+
+	memset(desc, 0, sizeof(*desc));
+	strbuf_init(&desc->buf, 0);
+
+	memset(&oi, 0, sizeof(oi));
+	if (!sha1_object_info_extended(sha1, &oi) &&
+	    oi.whence == OI_PACKED &&
+	    oi.u.packed.real_type == OBJ_PV4_TREE &&
+	    oi.u.packed.pack->version >= 4) {
+		desc->p = oi.u.packed.pack;
+		desc->obj_offset = oi.u.packed.offset;
+		desc->flags = flags;
+		return 0;
+	}
+
+	data = read_sha1_file(sha1, &type, &size);
+	if (!data || type != OBJ_TREE) {
+		free(data);
+		return -1;
+	}
+	desc->flags = flags;
+	desc->flags |= PV4_TREE_CANONICAL;
+	init_tree_desc(&desc->v2, data, size);
+	/*
+	 * we can attach to strbuf because read_sha1_file always
+	 * appends NUL at the end
+	 */
+	strbuf_attach(&desc->buf, data, size, size + 1);
+	return 0;
+}
+
+int pv4_tree_desc_from_entry(struct pv4_tree_desc *desc,
+			     const struct pv4_tree_desc *src,
+			     unsigned flags)
+{
+	if (!src->sha1_index)
+		return pv4_tree_desc_from_sha1(desc,
+					       src->v2.entry.sha1,
+					       flags);
+	assert(!(flags & ~0xff) &&
+	       "you are not supposed to set these from outside!");
+	memset(desc, 0, sizeof(*desc));
+	strbuf_init(&desc->buf, 0);
+	desc->p = src->p;
+	desc->obj_offset =
+		nth_packed_object_offset(desc->p, src->sha1_index - 1);
+	desc->flags = flags;
+	return 0;
+}
+
+void pv4_release_tree_desc(struct pv4_tree_desc *desc)
+{
+	strbuf_release(&desc->buf);
+	unuse_pack(&desc->w_curs);
+}
+
+int pv4_tree_entry(struct pv4_tree_desc *desc)
+{
+	if (desc->flags & PV4_TREE_CANONICAL) {
+		if (!desc->v2.size)
+			return 0;
+		if (desc->start)
+			update_tree_entry(&desc->v2);
+		desc->start++;
+		return 1;
+	}
+	return !decode_entries(desc, desc->obj_offset, desc->start++, 1);
+}
diff --git a/packv4-parse.h b/packv4-parse.h
index fe0ea38..874f57c 100644
--- a/packv4-parse.h
+++ b/packv4-parse.h
@@ -36,6 +36,8 @@ struct pv4_tree_desc {
 	/* v4 entry */
 	struct packed_git *p;
 	struct pack_window *w_curs;
+	off_t obj_offset;
+	unsigned start;
 	unsigned int sha1_index;
 	int pathlen;
 
@@ -46,4 +48,14 @@ struct pv4_tree_desc {
 	struct strbuf buf;
 };
 
+int pv4_tree_desc_from_sha1(struct pv4_tree_desc *desc,
+			    const unsigned char *sha1,
+			    unsigned flags);
+int pv4_tree_desc_from_entry(struct pv4_tree_desc *desc,
+			     const struct pv4_tree_desc *src,
+			     unsigned flags);
+void pv4_release_tree_desc(struct pv4_tree_desc *desc);
+
+int pv4_tree_entry(struct pv4_tree_desc *desc);
+
 #endif
-- 
1.8.2.83.gc99314b