authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-04-12 13:35:24 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-04-12 13:35:24 -07:00
logd4eda1fd309d4efb29b98559c0f6aa4716b4121b
tree93ff2e60df6f4a906d65e634c68a0e7eaa3ecf04
parent273ab35efde5b9ba792f6a32e17efaa23cca5b74
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

implement ofs_delta packed object type


1 files changed, 79 insertions(+), 8 deletions(-)

git.zig+79-8
...@@ -1014,7 +1014,7 @@ pub const Repository = struct {...@@ -1014,7 +1014,7 @@ pub const Repository = struct {
1014 const object_id = &extras.to_hex(name_bytes[i * 20 ..][0..20].*);1014 const object_id = &extras.to_hex(name_bytes[i * 20 ..][0..20].*);
1015 const pack_offset = std.mem.readInt(u32, offset_bytes[i * 4 ..][0..4], .big);1015 const pack_offset = std.mem.readInt(u32, offset_bytes[i * 4 ..][0..4], .big);
1016 if (std.mem.eql(u8, object_id, oid)) {1016 if (std.mem.eql(u8, object_id, oid)) {
1017 std.log.debug("found {s} in {s} at offset {d}", .{ obj, idx_path, pack_offset });1017 std.log.debug("found {s} in {s} at offset {d}", .{ oid, idx_path, pack_offset });
1018 const pack_index = r.pack_content.getIndex(idx_path) orelse clk: {1018 const pack_index = r.pack_content.getIndex(idx_path) orelse clk: {
1019 var pack_path: [128]u8 = @splat(0);1019 var pack_path: [128]u8 = @splat(0);
1020 @memcpy(pack_path[0..13], "objects/pack/");1020 @memcpy(pack_path[0..13], "objects/pack/");
...@@ -1037,7 +1037,7 @@ pub const Repository = struct {...@@ -1037,7 +1037,7 @@ pub const Repository = struct {
1037 } else return null;1037 } else return null;
10381038
1039 // parse .pack1039 // parse .pack
1040 std.log.warn("pack_index={d} pack_offset={d}", .{ pack_index, pack_offset });1040 std.log.debug("pack_index={d} pack_offset={d}", .{ pack_index, pack_offset });
10411041
1042 return try r.getPackedObject(oid, pack_index, pack_offset);1042 return try r.getPackedObject(oid, pack_index, pack_offset);
1043 }1043 }
...@@ -1049,11 +1049,8 @@ pub const Repository = struct {...@@ -1049,11 +1049,8 @@ pub const Repository = struct {
1049 switch (pack_version) {1049 switch (pack_version) {
1050 2 => {1050 2 => {
1051 const packedobj_content = pack_content[pack_offset..];1051 const packedobj_content = pack_content[pack_offset..];
1052 // var packedobj_fbs = std.ArrayListUnmanaged(u8).initBuffer(packedobj_content);
1053 var packedobj_fbs = nio.FixedBufferStream([]const u8).init(packedobj_content);1052 var packedobj_fbs = nio.FixedBufferStream([]const u8).init(packedobj_content);
1054
1055 const PackedObjType = enum(u3) { none, commit, tree, blob, tag, reserved, ofs_delta, ref_delta };1053 const PackedObjType = enum(u3) { none, commit, tree, blob, tag, reserved, ofs_delta, ref_delta };
1056
1057 var c: usize = packedobj_fbs.takeByte();1054 var c: usize = packedobj_fbs.takeByte();
1058 const ty: PackedObjType = @enumFromInt((c >> 4) & 7);1055 const ty: PackedObjType = @enumFromInt((c >> 4) & 7);
1059 var size: usize = c & 15;1056 var size: usize = c & 15;
...@@ -1063,8 +1060,6 @@ pub const Repository = struct {...@@ -1063,8 +1060,6 @@ pub const Repository = struct {
1063 size += (c & 0x7f) << shift;1060 size += (c & 0x7f) << shift;
1064 shift += 7;1061 shift += 7;
1065 }1062 }
1066 std.log.warn("type={s} size={d}", .{ @tagName(ty), size });
1067
1068 switch (ty) {1063 switch (ty) {
1069 .none => {1064 .none => {
1070 unreachable;1065 unreachable;
...@@ -1087,7 +1082,83 @@ pub const Repository = struct {...@@ -1087,7 +1082,83 @@ pub const Repository = struct {
1087 },1082 },
1088 .ofs_delta => {1083 .ofs_delta => {
1089 std.log.debug("type={s} size={d}", .{ @tagName(ty), size });1084 std.log.debug("type={s} size={d}", .{ @tagName(ty), size });
1090 unreachable;1085 var offset: usize = 0;
1086 while (true) {
1087 const c2: usize = packedobj_fbs.takeByte();
1088 offset = (offset << 7) | (c2 & 0x7f);
1089 if (c2 & 0x80 == 0) break;
1090 offset += 1;
1091 }
1092 const base_pack_offset = pack_offset - offset;
1093 const base_obj = try r.getPackedObject(null, pack_index, base_pack_offset);
1094 std.log.debug("base: type={s} content=[{d}]", .{ @tagName(base_obj.type), base_obj.content.len });
1095
1096 const compressed_content = packedobj_fbs.rest()[0..size];
1097 var bufr = nio.FixedBufferStream([]const u8).init(compressed_content);
1098
1099 var list: std.ArrayListUnmanaged(u8) = .empty;
1100 defer list.deinit(r.gpa);
1101 try list.ensureUnusedCapacity(r.gpa, size);
1102 try std.compress.flate.inflate.decompress(.zlib, bufr.anyReadable(), list.writer(r.gpa));
1103
1104 std.log.debug("transformation data={d}", .{list.items});
1105
1106 var unpackedobj_fbs = nio.FixedBufferStream([]const u8).init(list.items);
1107
1108 var list2: std.ArrayListUnmanaged(u8) = .empty;
1109 errdefer list2.deinit(r.gpa);
1110
1111 var base_size: usize = 0;
1112 while (true) {
1113 const c2: usize = unpackedobj_fbs.takeByte();
1114 base_size = (base_size << 7) | (c2 & 0x7f);
1115 if (c2 & 0x80 == 0) break;
1116 base_size += 1;
1117 }
1118 std.log.debug("base_size={d}", .{base_size});
1119
1120 var obj_size: usize = 0;
1121 while (true) {
1122 const c2: usize = unpackedobj_fbs.takeByte();
1123 obj_size = (obj_size << 7) | (c2 & 0x7f);
1124 if (c2 & 0x80 == 0) break;
1125 obj_size += 1;
1126 }
1127 std.log.debug("obj_size={d}", .{obj_size});
1128
1129 while (unpackedobj_fbs.pos < unpackedobj_fbs.buffer.len) {
1130 const c2 = unpackedobj_fbs.takeByte();
1131 if (c2 & 0x80 > 0) {
1132 // copy range from base
1133 var b: extras.RingBuffer(u8, 7) = .{};
1134 for (0..7) |i| {
1135 const mask = @as(u8, 1) << @intCast(i);
1136 b.append(if (c2 & mask > 0) unpackedobj_fbs.takeByte() else 0);
1137 }
1138 const start: u32 = @bitCast(b.items[0..4].*);
1139 const nbytes: u24 = @bitCast(b.items[4..7].*);
1140 std.log.debug("- copy from base: start={d} nbytes={d}", .{ start, nbytes });
1141 const bytes = base_obj.content[start..][0..nbytes];
1142 // std.log.debug("{s}\n", .{bytes});
1143 try list2.appendSlice(r.gpa, bytes);
1144 } else {
1145 // append new data
1146 const nbytes = c2 & 0x7f;
1147 std.log.debug("- append new bytes={d}", .{nbytes});
1148 if (nbytes == 0) continue;
1149 const bytes = unpackedobj_fbs.takeSlice(nbytes);
1150 // std.log.debug("{s}\n", .{bytes});
1151 try list2.appendSlice(r.gpa, bytes);
1152 }
1153 }
1154
1155 std.log.debug("- done", .{});
1156 // std.log.debug("{s}\n", .{list2.items});
1157 const _type = base_obj.type;
1158 const content = try list2.toOwnedSlice(r.gpa);
1159 const obj: GitObject = .{ .type = _type, .content = content };
1160 if (maybe_oid) |oid| try r.unpacked_objects.put(r.gpa, oid, obj);
1161 return obj;
1091 },1162 },
1092 .ref_delta => {1163 .ref_delta => {
1093 std.log.debug("type={s} size={d}", .{ @tagName(ty), size });1164 std.log.debug("type={s} size={d}", .{ @tagName(ty), size });