diff options
Diffstat (limited to 'cmd/explain-pack/delta.go')
| -rw-r--r-- | cmd/explain-pack/delta.go | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/cmd/explain-pack/delta.go b/cmd/explain-pack/delta.go new file mode 100644 index 00000000..22e32195 --- /dev/null +++ b/cmd/explain-pack/delta.go @@ -0,0 +1,120 @@ +package main + +import ( + "fmt" +) + +func (explainer *explainer) walkDelta(base, payload []byte, pos int) ([]byte, bool, error) { + explainer.printf("\tdelta\n") + + building := base != nil + + var result []byte + + insn := 0 + + for pos < len(payload) { + op := payload[pos] + pos++ + insn++ + + switch { + case op&0x80 != 0: + next, seg, err := explainer.decodeCopy(base, payload, pos, op) + if err != nil { + return nil, false, err + } + + pos = next + + if building { + result = append(result, seg...) + } + case op != 0: + next, lit, err := explainer.decodeInsert(payload, pos, int(op)) + if err != nil { + return nil, false, err + } + + pos = next + + if building { + result = append(result, lit...) + } + default: + explainer.printf("\t\tinvalid opcode 0x00; stopping delta decode\n") + + return nil, false, nil + } + } + + if !building { + return nil, false, nil + } + + return result, true, nil +} + +func (explainer *explainer) decodeCopy(base, payload []byte, pos int, op byte) (int, []byte, error) { + offset := 0 + + for i := range 4 { + if op&(1<<uint(i)) == 0 { + continue + } + + if pos >= len(payload) { + return 0, nil, fmt.Errorf("truncated copy offset") + } + + offset |= int(payload[pos]) << (8 * uint(i)) + pos++ + } + + size := 0 + + for i := range 3 { + if op&(1<<uint(4+i)) == 0 { + continue + } + + if pos >= len(payload) { + return 0, nil, fmt.Errorf("truncated copy size") + } + + size |= int(payload[pos]) << (8 * uint(i)) + pos++ + } + + if size == 0 { + size = 0x10000 + } + + explainer.printf("\t\tcpy %d from %d\n", size, offset) + + if base == nil { + return pos, nil, nil + } + + if offset < 0 || offset+size > len(base) { + return 0, nil, fmt.Errorf("copy of %d byte(s) from base offset %d exceeds base length %d", size, offset, len(base)) + } + + seg := base[offset : offset+size] + hexBlock(explainer.out, "\t\t\t", seg) + + return pos, seg, nil +} + +func (explainer *explainer) decodeInsert(payload []byte, pos, n int) (int, []byte, error) { + if pos+n > len(payload) { + return 0, nil, fmt.Errorf("truncated insert payload") + } + + lit := payload[pos : pos+n] + + explainer.printf("\t\tins %d\n", n) + hexBlock(explainer.out, "\t\t\t", lit) + + return pos + n, lit, nil +} |
