aboutsummaryrefslogtreecommitdiff
path: root/packed_read_pack.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-02-20 12:51:16 +0800
committerGravatar Runxi Yu2026-02-20 12:57:31 +0800
commit9730560a82426408243cb15349f6955a4ba34f60 (patch)
tree00cfcfc75db7b1de795b822f70246abd40199b86 /packed_read_pack.go
parentRevert "packed: Use random delta seed" (diff)
signatureNo signature
Revert "packed: Write packs with deltas"
This reverts commit 17c9aee0e781026353ead4ac749a3ae89c83d007.
Diffstat (limited to 'packed_read_pack.go')
-rw-r--r--packed_read_pack.go150
1 files changed, 150 insertions, 0 deletions
diff --git a/packed_read_pack.go b/packed_read_pack.go
index 31279c8f..56098ee5 100644
--- a/packed_read_pack.go
+++ b/packed_read_pack.go
@@ -108,6 +108,24 @@ func packSectionInflate(pf *packFile, start uint64, sizeHint int) (bufpool.Buffe
return body, nil
}
+func packDeltaReadOfsDistance(data []byte) (uint64, int, error) {
+ if len(data) == 0 {
+ return 0, 0, io.ErrUnexpectedEOF
+ }
+ b := data[0]
+ dist := uint64(b & 0x7f)
+ consumed := 1
+ for (b & 0x80) != 0 {
+ if consumed >= len(data) {
+ return 0, 0, io.ErrUnexpectedEOF
+ }
+ b = data[consumed]
+ consumed++
+ dist = ((dist + 1) << 7) + uint64(b&0x7f)
+ }
+ return dist, consumed, nil
+}
+
type packKey struct {
path string
ofs uint64
@@ -326,6 +344,138 @@ func (repo *Repository) packBodyResolveWithin(pf *packFile, ofs uint64) (ObjectT
return resultTy, body, nil
}
+func packDeltaApply(base, delta bufpool.Buffer) (bufpool.Buffer, error) {
+ pos := 0
+ baseBytes := base.Bytes()
+ deltaBytes := delta.Bytes()
+ srcSize, err := packVarintRead(deltaBytes, &pos)
+ if err != nil {
+ return bufpool.Buffer{}, err
+ }
+ dstSize, err := packVarintRead(deltaBytes, &pos)
+ if err != nil {
+ return bufpool.Buffer{}, err
+ }
+ if srcSize != len(baseBytes) {
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ out := bufpool.Borrow(dstSize)
+ out.Resize(dstSize)
+ outBytes := out.Bytes()
+ outPos := 0
+
+ for pos < len(deltaBytes) {
+ op := deltaBytes[pos]
+ pos++
+ switch {
+ case op&0x80 != 0:
+ off := 0
+ n := 0
+ if op&0x01 != 0 {
+ if pos >= len(deltaBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ off |= int(deltaBytes[pos])
+ pos++
+ }
+ if op&0x02 != 0 {
+ if pos >= len(deltaBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ off |= int(deltaBytes[pos]) << 8
+ pos++
+ }
+ if op&0x04 != 0 {
+ if pos >= len(deltaBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ off |= int(deltaBytes[pos]) << 16
+ pos++
+ }
+ if op&0x08 != 0 {
+ if pos >= len(deltaBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ off |= int(deltaBytes[pos]) << 24
+ pos++
+ }
+ if op&0x10 != 0 {
+ if pos >= len(deltaBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ n |= int(deltaBytes[pos])
+ pos++
+ }
+ if op&0x20 != 0 {
+ if pos >= len(deltaBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ n |= int(deltaBytes[pos]) << 8
+ pos++
+ }
+ if op&0x40 != 0 {
+ if pos >= len(deltaBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ n |= int(deltaBytes[pos]) << 16
+ pos++
+ }
+ if n == 0 {
+ n = 0x10000
+ }
+ if off+n > len(baseBytes) || outPos+n > len(outBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ copy(outBytes[outPos:], baseBytes[off:off+n])
+ outPos += n
+ case op != 0:
+ n := int(op)
+ if pos+n > len(deltaBytes) || outPos+n > len(outBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ copy(outBytes[outPos:], deltaBytes[pos:pos+n])
+ pos += n
+ outPos += n
+ default:
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ }
+
+ if outPos != len(outBytes) {
+ out.Release()
+ return bufpool.Buffer{}, ErrInvalidObject
+ }
+ return out, nil
+}
+
+func packVarintRead(buf []byte, pos *int) (int, error) {
+ res := 0
+ shift := 0
+ for {
+ if *pos >= len(buf) {
+ return 0, ErrInvalidObject
+ }
+ b := buf[*pos]
+ *pos++
+ res |= int(b&0x7f) << shift
+ if (b & 0x80) == 0 {
+ break
+ }
+ shift += 7
+ }
+ return res, nil
+}
+
type packFile struct {
relPath string
size int64