-
Notifications
You must be signed in to change notification settings - Fork 5
/
delta_apply.go
60 lines (56 loc) · 1.9 KB
/
delta_apply.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
// -----------------------------------------------------------------------------
// github.com/balacode/go-delta go-delta/[delta_apply.go]
// (c) balarabe@protonmail.com License: MIT
// -----------------------------------------------------------------------------
package delta
import (
"bytes"
"fmt"
)
// Apply uses the 'source' byte array, applies this
// Delta to it and returns the updated byte array.
// If this delta was not generated from source,
// returns an error.
func (ob *Delta) Apply(source []byte) ([]byte, error) {
if DebugTiming {
tmr.Start("Delta.Apply")
defer tmr.Stop("Delta.Apply")
}
if len(source) != ob.sourceSize {
return nil, mod.Error(fmt.Sprintf(
"Size of source [%d] does not match expected [%d]",
len(source), ob.sourceSize))
}
if !bytes.Equal(makeHash(source), ob.sourceHash) {
return nil, mod.Error("Delta does not belong to specified source")
}
buf := bytes.NewBuffer(make([]byte, 0, ob.targetSize))
for i, pt := range ob.parts {
var data []byte
switch {
case pt.sourceLoc == -1:
data = pt.data
case pt.sourceLoc < 0 || pt.sourceLoc >= ob.sourceSize:
return nil, mod.Error("part", i, "sourceLoc:", pt.sourceLoc,
"out of range 0 -", ob.sourceSize-1)
case pt.sourceLoc+pt.size > ob.sourceSize:
return nil, mod.Error("part", i, "sourceLoc:", pt.sourceLoc,
"+ size:", pt.size, "extends beyond", ob.sourceSize)
default:
data = source[pt.sourceLoc : pt.sourceLoc+pt.size]
}
n, err := buf.Write(data)
if err != nil {
return nil, mod.Error(err)
}
if n != pt.size {
return nil, mod.Error("Wrote", n, "bytes instead of", pt.size)
}
}
ret := buf.Bytes()
if !bytes.Equal(makeHash(ret), ob.targetHash) {
return nil, mod.Error("Result does not match target hash.")
}
return buf.Bytes(), nil
} // Apply
// end