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
|