Attempts to determine the final object ID of the given deltified object. May return null if this is not yet possible (if the delta is a ref-based delta and we do not yet know the offset of the base object).
fn indexPackHashDelta(
allocator: Allocator,
format: Oid.Format,
pack: *Io.File.Reader,
delta: IndexEntry,
index_entries: std.AutoHashMapUnmanaged(Oid, IndexEntry),
cache: *ObjectCache,
) !?Oid
fn indexPackHashDelta(
allocator: Allocator,
format: Oid.Format,
pack: *Io.File.Reader,
delta: IndexEntry,
index_entries: std.AutoHashMapUnmanaged(Oid, IndexEntry),
cache: *ObjectCache,
) !?Oid {
// Figure out the chain of deltas to resolve
var base_offset = delta.offset;
var base_header: EntryHeader = undefined;
var delta_offsets: std.ArrayList(u64) = .empty;
defer delta_offsets.deinit(allocator);
const base_object = while (true) {
if (cache.get(base_offset)) |base_object| break base_object;
try pack.seekTo(base_offset);
base_header = try EntryHeader.read(format, &pack.interface);
switch (base_header) {
.ofs_delta => |ofs_delta| {
try delta_offsets.append(allocator, base_offset);
base_offset = std.math.sub(u64, base_offset, ofs_delta.offset) catch return error.InvalidObject;
},
.ref_delta => |ref_delta| {
try delta_offsets.append(allocator, base_offset);
base_offset = (index_entries.get(ref_delta.base_object) orelse return null).offset;
},
else => {
const base_data = try readObjectRaw(allocator, &pack.interface, base_header.uncompressedLength());
errdefer allocator.free(base_data);
const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };
try cache.put(allocator, base_offset, base_object);
break base_object;
},
}
};
const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);
var entry_hasher_buffer: [64]u8 = undefined;
var entry_hasher: Oid.Hashing = .init(format, &entry_hasher_buffer);
const entry_hasher_w = entry_hasher.writer();
// Writes to hashers cannot fail.
entry_hasher_w.print("{t} {d}\x00", .{ base_object.type, base_data.len }) catch unreachable;
entry_hasher_w.writeAll(base_data) catch unreachable;
return entry_hasher.final();
}