-
Notifications
You must be signed in to change notification settings - Fork 1
/
rle.go
205 lines (165 loc) · 3.54 KB
/
rle.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package rle
import (
"bytes"
"errors"
"io"
)
// Reader is an io.Reader that decode RLE input from a wrapped reader
type Reader struct {
sym byte
run byte
r io.Reader
}
// NewReader creates a new Reader wrapping r
func NewReader(r io.Reader) *Reader {
return &Reader{r: r}
}
func (z *Reader) nextRun() (err error) {
var buf [1]byte
// read run length
n, err := z.r.Read(buf[:])
// error while reading
if n != 1 || err != nil {
return err
}
z.run = buf[0]
// read run symbol
n, err = z.r.Read(buf[:])
// unexpected EOF
if err == io.EOF {
return errors.New("invalid rle stream")
}
// error while reading
if n != 1 || err != nil {
return err
}
z.sym = buf[0]
return nil
}
// Read reads and decodes bytes from the wrapped stream, writing up to len(p) bytes into p
func (z *Reader) Read(p []byte) (n int, err error) {
for len(p) > 0 {
// read new data if needed
if z.run == 0 {
err = z.nextRun()
// error or EOF while reading
if err != nil {
return n, err
}
}
// write the symbol for z.run times
for len(p) > 0 && z.run > 0 {
p[0] = z.sym
p = p[1:]
n++
z.run--
}
}
return 0, nil
}
// WriteTo writes a decoded form of the wrapped input stream to w
func (z *Reader) WriteTo(w io.Writer) (n int64, err error) {
for {
// read next run (length and symbol)
err = z.nextRun()
// EOF
if err == io.EOF {
break
}
// error while reading
if err != nil {
return n, err
}
// repeat the symbol for run times
for i := 0; i < int(z.run); i++ {
buf := []byte{z.sym}
nwrite, err := w.Write(buf)
if nwrite != 1 || err != nil {
return n, err
}
n++
}
}
return n, nil
}
// Writer is an io.Writer that encode RLE input to a wrapped writer
type Writer struct {
sym byte
prev byte
run byte
w io.Writer
}
// NewWriter creates a new Writer wrapping w
func NewWriter(w io.Writer) *Writer {
return &Writer{w: w}
}
func (z *Writer) write(r io.Reader) (n int, err error) {
var buf [1]byte
// read the first byte from the stream
nRead, err := r.Read(buf[:])
// end of stream
if err == io.EOF {
return n, nil
}
// error while reading
if nRead != 1 || err != nil {
return n, err
}
z.sym = buf[0]
// error while reading
if err != nil {
return n, err
}
// update bytes read
n++
// init encoder status with the first byte
z.prev = z.sym
z.run = 1
// encode input stream until EOF or error
for {
// read next symbol
nRead, err := r.Read(buf[:])
// end of stream
if err == io.EOF {
break
}
// error while reading
if nRead != 1 || err != nil {
return n, err
}
z.sym = buf[0]
// update bytes read
n++
// read symbol is different or we reached the run size limit
if z.sym != z.prev || (z.run == 255 && z.sym == z.prev) {
wbuf := []byte{z.run, z.prev}
// flush run length and run symbol
nWrite, err := z.w.Write(wbuf)
if nWrite != 2 || err != nil {
return n, err
}
// reset encoder status
z.prev = z.sym
z.run = 1
} else {
// increment the run length
z.run++
}
}
// flush remaining data
wbuf := []byte{z.run, z.prev}
nWrite, err := z.w.Write(wbuf)
if nWrite != 2 || err != nil {
return n, err
}
return n, nil
}
// Write writes and encodes bytes to the wrapped stream, reading up to len(p) bytes from p
func (z *Writer) Write(p []byte) (n int, err error) {
return z.write(bytes.NewReader(p))
}
// ReadFrom reads input from r and writes a RLE encoded stream to the wrapped writer
func (z *Writer) ReadFrom(r io.Reader) (n int64, err error) {
written, err := z.write(r)
return int64(written), err
}