aboutsummaryrefslogtreecommitdiff
path: root/internal/format/packfile/delta/header.go
blob: d5dd93fb332361d41da40a8b376749c5b2be3806 (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package delta

import (
	"errors"
	"fmt"
)

// ErrMalformedDelta reports that
// a delta payload is truncated, overlong,
// declares sizes that overflow uint64,
// contains invalid instructions,
// or does not match the supplied base or declared sizes.
var ErrMalformedDelta = errors.New("internal/format/packfile/delta: malformed delta")

// MaxSizeVarintLen is the maximum encoded length
// of one delta header size varint.
// Every uint64 size is encodable within this bound,
// and parsing rejects longer encodings.
const MaxSizeVarintLen = 10

// MaxHeaderSizesLen is the maximum encoded length
// of the base/result size header of a delta payload.
//
// Callers reading a delta from a stream may inflate
// MaxHeaderSizesLen bytes
// (or fewer if the payload ends sooner)
// and parse with [ParseHeaderSizes];
// no valid header is longer.
const MaxHeaderSizesLen = 2 * MaxSizeVarintLen

// ParseHeaderSizes parses the base size and result size varints
// at the beginning of one inflated delta payload.
func ParseHeaderSizes(data []byte) (baseSize, resultSize uint64, consumed int, err error) {
	baseSize, consumed, err = parseSizeVarint(data, 0)
	if err != nil {
		return 0, 0, 0, err
	}

	resultSize, consumed, err = parseSizeVarint(data, consumed)
	if err != nil {
		return 0, 0, 0, err
	}

	return baseSize, resultSize, consumed, nil
}

// AppendHeaderSizes appends the base/result size header encoding
// of one delta payload to dst.
func AppendHeaderSizes(dst []byte, baseSize, resultSize uint64) []byte {
	dst = appendSizeVarint(dst, baseSize)

	return appendSizeVarint(dst, resultSize)
}

// appendSizeVarint appends the encoding of one delta header size varint to dst.
func appendSizeVarint(dst []byte, value uint64) []byte {
	for value >= 0x80 {
		dst = append(dst, byte(value)|0x80)
		value >>= 7
	}

	return append(dst, byte(value))
}

// parseSizeVarint parses one delta header size varint
// beginning at pos,
// and returns the position past it.
func parseSizeVarint(data []byte, pos int) (value uint64, consumed int, err error) {
	start := pos

	shift := uint(0)

	for {
		if pos-start >= MaxSizeVarintLen {
			return 0, 0, fmt.Errorf("%w: overlong size varint", ErrMalformedDelta)
		}

		if pos >= len(data) {
			return 0, 0, fmt.Errorf("%w: truncated size varint", ErrMalformedDelta)
		}

		b := data[pos]
		pos++

		group := uint64(b & 0x7f)
		if group<<shift>>shift != group {
			return 0, 0, fmt.Errorf("%w: size overflows uint64", ErrMalformedDelta)
		}

		value |= group << shift

		if b&0x80 == 0 {
			return value, pos, nil
		}

		shift += 7
	}
}