+ fn applyDelta(alloc: Alloc, baseData: []const u8, deltData: []const u8) ![]u8 {
+ var fbs = std.io.fixedBufferStream(deltData);
+ const deltDataReader = fbs.reader().any();
+ const baseObjectSize = try getSize(deltDataReader, false);
+ const resultObjectSize = try getSize(deltDataReader, false);
+ const deltaDataOffset = baseObjectSize.bytelen + resultObjectSize.bytelen;
+
+ const result = try alloc.alloc(u8, resultObjectSize.size);
+ var resultCounter: u64 = 0;
+
+ var counter: u64 = 0;
+ while (true) {
+ const b = deltData[deltaDataOffset + counter];
+
+ if (b & 0b10000000 != 0) {
+ var dataOffset: u64 = 0;
+ var dataSize: u64 = 0;
+ var bitsSet: u8 = 0;
+ for (0..4) |i| { // offset bits
+ if (b & (@as(u64, 1) << @min(3, i)) != 0) {
+ dataOffset += @as(u64, deltData[deltaDataOffset + counter + 1 + bitsSet]) << @min(3 * 8, i * 8);
+ bitsSet += 1;
+ }
+ }
+ for (4..7) |i| { // size bits
+ if (b & (@as(u64, 1) << @min(6, i)) != 0) {
+ dataSize += @as(u64, deltData[deltaDataOffset + counter + 1 + bitsSet]) << @min(6 * 8, (i - 4) * 8);
+ bitsSet += 1;
+ }
+ }
+ counter += bitsSet;
+
+ std.mem.copyForwards(
+ u8,
+ result[resultCounter..result.len],
+ baseData[dataOffset .. dataOffset + dataSize],
+ );
+
+ resultCounter += dataSize;
+ } else {
+ const dataSize: u7 = @truncate(b);
+
+ std.mem.copyForwards(
+ u8,
+ result[resultCounter..result.len],
+ deltData[deltaDataOffset + counter + 1 .. deltaDataOffset + counter + 1 + dataSize],
+ );
+ resultCounter += dataSize;
+ counter += dataSize;
+ }
+
+ counter += 1;
+ if (deltaDataOffset + counter >= deltData.len)
+ break;
+ }
+
+ return result;
+ }
+
+ fn ofsDelta(self: *PackFile, offset: i64) anyerror!Object {
+ const pckReader = self.pckFile.reader().any();
+
+ const pos = try self.pckFile.getPos();
+
+ try self.pckFile.seekBy(-offset);
+ const baseObject = try self.readObject(pckReader);
+ defer self.alloc.free(baseObject.data);
+
+ try self.pckFile.seekTo(pos);
+ const deltaData = try decompress(self.alloc, pckReader);
+ defer self.alloc.free(deltaData);
+
+ const objectData = try applyDelta(self.alloc, baseObject.data, deltaData);
+ return Object.init(baseObject.kind, objectData);
+ }
+
+ fn readObject(self: *PackFile, reader: Reader) anyerror!Object {
+ const firstByte = try reader.readByte();
+ const objectKind: u3 = @truncate(firstByte >> 4);
+ try self.pckFile.seekBy(-1);
+ const objectSize = try getSize(reader, true);
+
+ if (objectKind == 6) {
+ const offset = try getOffset(reader);
+ return try self.ofsDelta(
+ @intCast(offset.offset + objectSize.bytelen + offset.bytelen),
+ );
+ } else {
+ const objectData = try decompress(self.alloc, reader);
+ return Object.init(objectKind, objectData);
+ }
+ }
+
+ pub fn getObject(self: *PackFile, id: Id) !?Object {
+ if (self.objectOffsets.get(id)) |offset| {
+ const pckReader = self.pckFile.reader().any();
+ try self.pckFile.seekTo(offset);
+
+ return try self.readObject(pckReader);
+ }
+ return null;
+ }