-
Notifications
You must be signed in to change notification settings - Fork 7
/
Compressor.go
84 lines (68 loc) · 1.68 KB
/
Compressor.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
package compression
import (
"io"
"github.com/inkyblackness/hacked/ss1/serial"
)
type compressor struct {
coder serial.Coder
writer *WordWriter
dictBuffer dictEntryBuffer
overtime int
dictionary *dictEntry
dictionarySize int
curEntry *dictEntry
}
// NewCompressor creates a new compressor instance over a writer.
func NewCompressor(target io.Writer) io.WriteCloser {
coder := serial.NewEncoder(target)
obj := &compressor{
coder: coder,
writer: NewWordWriter(coder),
dictionary: rootDictEntry(),
dictionarySize: 0,
overtime: 0}
obj.resetDictionary()
return obj
}
func (obj *compressor) resetDictionary() {
obj.dictionarySize = 0
for i := 0; i < 0x100; i++ {
obj.dictionary.Add(byte(i), Word(i), obj.dictBuffer.entry(Word(i)))
}
obj.curEntry = obj.dictionary
}
func (obj *compressor) Close() error {
obj.writer.Write(obj.curEntry.key)
obj.writer.Close()
return obj.coder.FirstError()
}
func (obj *compressor) Write(p []byte) (n int, err error) {
for _, input := range p {
obj.addByte(input)
}
return len(p), obj.coder.FirstError()
}
func (obj *compressor) addByte(value byte) {
nextEntry := obj.curEntry.next[int(value)]
if nextEntry != nil {
obj.curEntry = nextEntry
} else {
obj.writer.Write(obj.curEntry.key)
key := Word(int(literalLimit) + obj.dictionarySize)
if key < Reset {
obj.curEntry.Add(value, key, obj.dictBuffer.entry(key))
obj.dictionarySize++
} else {
obj.onKeySaturation()
}
obj.curEntry = obj.dictionary.next[value]
}
}
func (obj *compressor) onKeySaturation() {
obj.overtime++
if obj.overtime > 1000 {
obj.writer.Write(Reset)
obj.resetDictionary()
obj.overtime = 0
}
}