diff options
Diffstat (limited to 'LibGit/GitPack.cs')
-rw-r--r-- | LibGit/GitPack.cs | 135 |
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 |