Commit d8603ed901d4af4d0d2b493d1164c74eae34f147

Vicent Marti 2010-07-10T16:51:15

Add parsing of tree file contents. The basic information (pointed trees and blobs) of each tree object in a revision pool can now be parsed and queried. Signed-off-by: Vicent Marti <tanoku@gmail.com>

diff --git a/src/commit.c b/src/commit.c
index 6b0b661..e4e5611 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -83,6 +83,7 @@ git_commit *git_commit_parse(git_revpool *pool, const git_oid *id)
 	return commit;
 
 error_cleanup:
+	/* FIXME: do not free; the commit is owned by the revpool */
 	free(commit);
 	return NULL;
 }
diff --git a/src/git/tree.h b/src/git/tree.h
index d5f668c..9a4973b 100644
--- a/src/git/tree.h
+++ b/src/git/tree.h
@@ -28,6 +28,18 @@ typedef struct git_tree git_tree;
 GIT_EXTERN(git_tree *) git_tree_lookup(git_revpool *pool, const git_oid *id);
 
 /**
+ * Locate a reference to a tree object and parse its
+ * contents.
+ * The generated tree object is owned by the revision
+ * pool and shall not be freed by the user.
+ *
+ * @param pool the pool to use when locating the tree.
+ * @param id identity of the tree to locate.
+ * @return the tree; NULL if the tree could not be created
+ */
+GIT_EXTERN(git_tree *) git_tree_parse(git_revpool *pool, const git_oid *id);
+
+/**
  * Get the id of a tree.
  * @param tree a previously loaded tree.
  * @return object identity for the tree.
diff --git a/src/tree.c b/src/tree.c
index 2ba363e..47b0273 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -65,3 +65,77 @@ git_tree *git_tree_lookup(git_revpool *pool, const git_oid *id)
 
 	return tree;
 }
+
+
+git_tree *git_tree_parse(git_revpool *pool, const git_oid *id)
+{
+	git_tree *tree = NULL;
+
+	if ((tree = git_tree_lookup(pool, id)) == NULL)
+		return NULL;
+
+	if (git_tree__parse(tree) < 0)
+		goto error_cleanup;
+
+	return tree;
+
+error_cleanup:
+	/* FIXME: do not free; the tree is owned by the revpool */
+	free(tree);
+	return NULL;
+}
+
+int git_tree__parse(git_tree *tree)
+{
+	static const char tree_header[] = {'t', 'r', 'e', 'e', ' '};
+
+	int error = 0;
+	git_obj odb_object;
+	char *buffer, *buffer_end;
+
+	error = git_odb_read(&odb_object, tree->object.pool->db, &tree->object.id);
+	if (error < 0)
+		return error;
+
+	buffer = odb_object.data;
+	buffer_end = odb_object.data + odb_object.len;
+
+	if (memcmp(buffer, tree_header, 5) != 0)
+		return GIT_EOBJCORRUPTED;
+
+	buffer += 5;
+
+	tree->byte_size = strtol(buffer, &buffer, 10);
+
+	if (*buffer++ != 0)
+		return GIT_EOBJCORRUPTED;
+
+	while (buffer < buffer_end) {
+		git_tree_entry *entry;
+
+		entry = git__malloc(sizeof(git_tree_entry));
+		entry->next = tree->entries;
+
+		entry->attr = strtol(buffer, &buffer, 10);
+
+		if (*buffer++ != ' ') {
+			error = GIT_EOBJCORRUPTED;
+			break;
+		}
+
+		entry->filename = git__strdup(buffer);
+
+		if (entry->filename == NULL) {
+			error = GIT_EOBJCORRUPTED;
+			break;
+		}
+		buffer += strlen(entry->filename);
+
+		git_oid_mkraw(&entry->oid, (const unsigned char *)buffer);
+		buffer += GIT_OID_RAWSZ;
+
+		tree->entries = entry;
+	}
+
+	return error;
+}
diff --git a/src/tree.h b/src/tree.h
index 532a2f4..3733456 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -4,10 +4,26 @@
 #include <git/tree.h>
 #include "revobject.h"
 
+struct git_tree_entry {
+
+	unsigned int attr;
+	char *filename;
+	git_oid oid;
+
+	struct git_tree_entry *next;
+};
+
+typedef struct git_tree_entry git_tree_entry;
+
 struct git_tree {
 	git_revpool_object object;
+
+	size_t byte_size;
+	git_tree_entry *entries;
+	unsigned int entry_count;
 };
 
 void git_tree__free(git_tree *tree);
+int git_tree__parse(git_tree *tree);
 
 #endif