summary refs log tree commit diff
path: root/LibGit/GitPack.cs
diff options
context:
space:
mode:
Diffstat (limited to 'LibGit/GitPack.cs')
-rw-r--r--LibGit/GitPack.cs135
1 files changed, 135 insertions, 0 deletions
diff --git a/LibGit/GitPack.cs b/LibGit/GitPack.cs
new file mode 100644
index 0000000..58c6edc
--- /dev/null
+++ b/LibGit/GitPack.cs
@@ -0,0 +1,135 @@
+using LibGit.Extensions;
+
+namespace LibGit;
+
+public class GitPack
+{
+    public string PackId { get; set; }
+    public GitRepo Repo { get; set; }
+    
+    public int Version { get; set; }
+    public int ObjectCount { get; set; }
+    public List<GitPackObject> Objects { get; set; } = new List<GitPackObject>();
+    
+    public GitPack Read(Stream stream)
+    {
+        stream.Peek(12).HexDump(16);
+        
+        Console.Write(" Header: "); stream.Peek(04).ToArray()[0..].HexDump(4);
+        Console.Write("Version: "); stream.Peek(08).ToArray()[4..].HexDump(4);
+        Console.Write(" ObjCnt: "); stream.Peek(12).ToArray()[8..].HexDump(4);
+        
+        if(!stream.StartsWith("PACK"))
+            throw new Exception("Invalid pack file header");
+
+        stream.Skip(4);
+        
+        Version = stream.ReadInt32BE();
+        ObjectCount = stream.ReadInt32BE();
+        Console.WriteLine($"Got git v{Version} pack with {ObjectCount} objects");
+        for (int i = 0; i < ObjectCount; i++)
+        {
+            Objects.Add(new GitPackObject().Read(stream));
+        }
+
+        return this;
+    }
+    
+    public GitPack(string packId, GitRepo repo)
+    {
+        PackId = packId;
+        Repo = repo;
+    }
+}
+
+public class GitPackIndex
+{
+    public int Version { get; set; }
+    public int[] fanOutTable = new int[256];
+    public GitPackIndex Read(Stream stream)
+    {
+        if(!stream.StartsWith(new byte[]{0xff,0x74,0x4f,0x63}))
+            throw new Exception("Invalid pack index file header or pack is v1");
+
+        stream.Skip(4);
+        Version = stream.ReadInt32BE();
+        Console.WriteLine($"Got git v{Version} pack index");
+        
+        //fan-out table
+        for (int i = 0; i < 256; i++)
+        {
+            fanOutTable[i] = stream.ReadInt32BE();
+        }
+        
+
+        
+        
+        return this;
+    }
+}
+
+
+public class GitPackObject
+{
+    private const bool _debug = true; 
+    public GitPackObject Read(Stream stream)
+    {
+        stream.Peek(64).HexDump(32);
+        var header = stream.ReadBytes(4).ToArray();
+        ObjType = (GitObjectType)((header[0] & 0b0111_0000) >> 4);
+        if(ObjType == 0 || (int)ObjType == 5 || (int)ObjType > 7)
+            throw new Exception($"Invalid object type: {(int)ObjType}");
+        Size = header[0] & 0b0000_1111;
+        
+        Offset = 0;
+        for (int i = 1; i < 4; i++)
+        {
+            Offset <<= 8;
+            Offset |= header[i];
+        }
+        
+        if ((Size & 0b0000_1000) != 0)
+        {
+            Size <<= 4;
+            Size |= stream.ReadVLQ();
+        }
+
+        // ObjType = Type switch
+        // {
+        //     1 => GitObjectType.Commit,
+        //     2 => GitObjectType.Tree,
+        //     3 => GitObjectType.Blob,
+        //     4 => GitObjectType.Tag,
+        //     5 => GitObjectType.Invalid, 
+        //     6 => GitObjectType.OffsDelta,
+        //     7 => GitObjectType.RefDelta,
+        //     _ => throw new Exception($"Invalid object type {Type}")
+        // };
+
+        if(_debug) Console.WriteLine($"pack obj type: {ObjType} ({(int)ObjType}), size: {Size}, offset: {Offset}, sizeBytes: {SizeBytes}");
+        Console.WriteLine("Data: ");
+        stream.Peek(Size).Take(16).ToArray().HexDump(16);
+        stream.ReadBytes(Size).ZlibDecompress().Take(16).HexDump(16);
+        
+        return this;
+    }
+
+    public GitObjectType ObjType { get; set; }
+
+    public int SizeBytes { get; set; }
+
+    public int Size { get; set; }
+
+    public int Offset { get; set; }
+}
+
+public enum GitObjectType
+{
+    Commit = 1,
+    Tree,
+    Blob,
+    Tag,
+    Invalid, // Reserved for future expansion, see https://git-scm.com/docs/pack-format#_object_types
+    OffsDelta,
+    RefDelta
+}
\ No newline at end of file