summary refs log tree commit diff
path: root/LibGit/TreeObject.cs
diff options
context:
space:
mode:
Diffstat (limited to 'LibGit/TreeObject.cs')
-rw-r--r--LibGit/TreeObject.cs101
1 files changed, 101 insertions, 0 deletions
diff --git a/LibGit/TreeObject.cs b/LibGit/TreeObject.cs
new file mode 100644
index 0000000..7d5eb36
--- /dev/null
+++ b/LibGit/TreeObject.cs
@@ -0,0 +1,101 @@
+using System.IO.Compression;
+using System.Text.Json.Serialization;
+using LibGit.Extensions;
+using LibGit.Interfaces;
+
+namespace LibGit;
+
+public class TreeObject
+{
+    [JsonIgnore] public IRepoSource RepoSource { get; }
+    public string ObjectId { get; }
+
+    public TreeObject(IRepoSource repoSource, string objectId)
+    {
+        RepoSource = repoSource;
+        ObjectId = objectId;
+    }
+
+    private const bool _debug = false;
+
+    public string Length { get; set; }
+    public Dictionary<string, TreeObjectEntry> Entries { get; set; } = new();
+
+    public TreeObject ReadFromZlibCompressedObjFile(Stream bytes)
+    {
+        if (_debug) Console.WriteLine($"Decompressing {GetType().Name}");
+        using ZLibStream stream = new ZLibStream(bytes, CompressionMode.Decompress);
+        using var result = new MemoryStream();
+        stream.CopyTo(result);
+        stream.Flush();
+        stream.Close();
+        return ReadFromDecompressedObjFile(result);
+    }
+
+    public TreeObject ReadFromDecompressedObjFile(Stream data)
+    {
+        if (_debug) Console.WriteLine("Parsing tree object");
+        // var data = new Queue<byte>(bytes.ToArray());
+        int iters = 0;
+        data.Seek(0, SeekOrigin.Begin);
+        if (_debug) Console.WriteLine($"Iteration {iters}: starting pos: {data.Position}/+{data.Remaining()}/{data.Length}");
+        Length = data.ReadNullTerminatedField(asciiPrefix: "tree ").AsString();
+        while (data.Remaining() > 20)
+        {
+            if (_debug) Console.WriteLine($"readTree.Iteration {iters} ({data.Position}/+{data.Remaining()}/{data.Length})");
+
+            var entry = ReadFileEntry(data);
+            Entries.Add(entry.Key, entry.Value);
+        }
+
+        if (data.Remaining() > 0)
+        {
+            Console.WriteLine($"--parseTree: Unparsed data after {iters} iteration(s) of parsing TreeObject--");
+            Console.WriteLine(this.ToJson());
+            Console.WriteLine("--HexDump of remaining data--");
+            data.Peek(data.Remaining()).HexDump();
+            //Console.WriteLine($"Unparsed data: {Encoding.UTF8.GetString(data.ToArray())}");
+        }
+
+        data.Close();
+
+        if (_debug)
+        {
+            Console.WriteLine($"-- Read tree object of size {Length} --");
+            foreach (var x in Entries.ToList())
+            {
+                Console.WriteLine($"{x.Value.Mode} {x.Value.Hash} {x.Key}");
+            }
+
+            foreach (var x in Entries.ToList())
+            {
+                Console.WriteLine($"Path: {x.Key}");
+                Console.WriteLine($"Mode: {x.Value.Mode}");
+                Console.WriteLine($"Hash: {x.Value.Hash}");
+            }
+        }
+
+        return this;
+    }
+
+    //parsing
+
+    private static KeyValuePair<string, TreeObjectEntry> ReadFileEntry(Stream data)
+    {
+        if (_debug) Console.WriteLine($"--tree.ReadFileEntry--");
+        var path = "";
+        TreeObjectEntry entry = new();
+        //entry format: <mode> <path>\0<hash>
+        entry.Mode = data.ReadSpaceTerminatedField().AsString();
+        path = data.ReadNullTerminatedField().AsString();
+        entry.Hash = string.Join("", data.ReadBytes(20).Select(x => $"{x:x2}"));
+
+        return new KeyValuePair<string, TreeObjectEntry>(path, entry);
+    }
+
+    public class TreeObjectEntry
+    {
+        public string Mode { get; set; }
+        public string Hash { get; set; }
+    }
+}
\ No newline at end of file