-
Notifications
You must be signed in to change notification settings - Fork 0
/
signature.go
122 lines (98 loc) · 2.65 KB
/
signature.go
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package rdiff
import (
"encoding/binary"
"errors"
"fmt"
"io"
)
type Signature struct {
blockSize uint32
checksumType ChecksumType
strongChecksumSize uint32
weakChecksums map[uint32]int
strongChecksums [][]byte
}
func WriteSignature(in io.Reader, out io.Writer, checksumType ChecksumType, blockSize uint32, strongChecksumSize uint32) error {
checksum, err := NewChecksum(checksumType)
if err != nil {
return err
}
maxStrongChecksumSize := checksum.MaxStrongChecksumSize()
if strongChecksumSize > maxStrongChecksumSize {
return fmt.Errorf("strong checksum size %d exceeds max allowed value %d for checksum type %#x", strongChecksumSize, maxStrongChecksumSize, checksumType)
}
if err := binary.Write(out, binary.BigEndian, checksumType); err != nil {
return err
}
if err := binary.Write(out, binary.BigEndian, blockSize); err != nil {
return err
}
if err := binary.Write(out, binary.BigEndian, strongChecksumSize); err != nil {
return err
}
blockIndex := 0
for {
block := make([]byte, blockSize)
byteCount, err := io.ReadFull(in, block)
if err != nil && !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrUnexpectedEOF) {
return err
}
if byteCount == 0 {
break
}
block = block[:byteCount]
weakChecksum := checksum.CalculateWeakChecksum(block)
if err = binary.Write(out, binary.BigEndian, weakChecksum); err != nil {
return err
}
strongChecksum, err := checksum.CalculateStrongChecksum(block, strongChecksumSize)
if err != nil {
return err
}
if _, err = out.Write(strongChecksum); err != nil {
return err
}
blockIndex++
}
return nil
}
func ReadSignature(input io.Reader) (*Signature, error) {
var checksumType ChecksumType
if err := binary.Read(input, binary.BigEndian, &checksumType); err != nil {
return nil, err
}
var blockSize uint32
if err := binary.Read(input, binary.BigEndian, &blockSize); err != nil {
return nil, err
}
var strongChecksumSize uint32
if err := binary.Read(input, binary.BigEndian, &strongChecksumSize); err != nil {
return nil, err
}
weakChecksums := make(map[uint32]int)
var strongChecksums [][]byte
blockIndex := 0
for {
var weakChecksum uint32
err := binary.Read(input, binary.BigEndian, &weakChecksum)
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
weakChecksums[weakChecksum] = blockIndex
blockIndex++
strongChecksum := make([]byte, strongChecksumSize)
if _, err = io.ReadFull(input, strongChecksum); err != nil {
return nil, err
}
strongChecksums = append(strongChecksums, strongChecksum)
}
return &Signature{
blockSize,
checksumType,
strongChecksumSize,
weakChecksums,
strongChecksums,
}, nil
}