-
Notifications
You must be signed in to change notification settings - Fork 309
/
frameenc.go
118 lines (109 loc) · 3 KB
/
frameenc.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
// Copyright 2019+ Klaus Post. All rights reserved.
// License information can be found in the LICENSE file.
// Based on work by Yann Collet, released under BSD License.
package zstd
import (
"errors"
"fmt"
"io"
"math"
"math/bits"
)
type frameHeader struct {
ContentSize uint64
WindowSize uint32
SingleSegment bool
Checksum bool
DictID uint32 // Not stored.
}
const maxHeaderSize = 14
func (f frameHeader) appendTo(dst []byte) ([]byte, error) {
dst = append(dst, frameMagic...)
var fhd uint8
if f.Checksum {
fhd |= 1 << 2
}
if f.SingleSegment {
fhd |= 1 << 5
}
var fcs uint8
if f.ContentSize >= 256 {
fcs++
}
if f.ContentSize >= 65536+256 {
fcs++
}
if f.ContentSize >= 0xffffffff {
fcs++
}
fhd |= fcs << 6
dst = append(dst, fhd)
if !f.SingleSegment {
const winLogMin = 10
windowLog := (bits.Len32(f.WindowSize-1) - winLogMin) << 3
dst = append(dst, uint8(windowLog))
}
if f.SingleSegment && f.ContentSize == 0 {
return nil, errors.New("single segment, but no size set")
}
switch fcs {
case 0:
if f.SingleSegment {
dst = append(dst, uint8(f.ContentSize))
}
// Unless SingleSegment is set, framessizes < 256 are nto stored.
case 1:
f.ContentSize -= 256
dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8))
case 2:
dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24))
case 3:
dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24),
uint8(f.ContentSize>>32), uint8(f.ContentSize>>40), uint8(f.ContentSize>>48), uint8(f.ContentSize>>56))
default:
panic("invalid fcs")
}
return dst, nil
}
const skippableFrameHeader = 4 + 4
// calcSkippableFrame will return a total size to be added for written
// to be divisible by multiple.
// The value will always be > skippableFrameHeader.
// The function will panic if written < 0 or wantMultiple <= 0.
func calcSkippableFrame(written, wantMultiple int64) int {
if wantMultiple <= 0 {
panic("wantMultiple <= 0")
}
if written < 0 {
panic("written < 0")
}
leftOver := written % wantMultiple
if leftOver == 0 {
return 0
}
toAdd := wantMultiple - leftOver
for toAdd < skippableFrameHeader {
toAdd += wantMultiple
}
return int(toAdd)
}
// skippableFrame will add a skippable frame with a total size of bytes.
// total should be >= skippableFrameHeader and < math.MaxUint32.
func skippableFrame(dst []byte, total int, r io.Reader) ([]byte, error) {
if total == 0 {
return dst, nil
}
if total < skippableFrameHeader {
return dst, fmt.Errorf("requested skippable frame (%d) < 8", total)
}
if int64(total) > math.MaxUint32 {
return dst, fmt.Errorf("requested skippable frame (%d) > max uint32", total)
}
dst = append(dst, 0x50, 0x2a, 0x4d, 0x18)
f := uint32(total - skippableFrameHeader)
dst = append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24))
start := len(dst)
dst = append(dst, make([]byte, f)...)
_, err := io.ReadFull(r, dst[start:])
return dst, err
}