-
Notifications
You must be signed in to change notification settings - Fork 1
/
writer.go
110 lines (87 loc) · 1.69 KB
/
writer.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
package yenc
import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"hash"
"hash/crc32"
"io"
"strconv"
)
const (
null byte = 0x00
cr byte = 0x0a
lf byte = 0x0d
escape byte = 0x3d
tab byte = 0x09
space byte = 0x20
)
type Writer struct {
CRC hash.Hash32
Length, Line int
Name string
Header, Footer *Header
curLineLen int
w io.Writer
cls bool
body, out *bytes.Buffer
}
func NewWriter(w io.Writer) *Writer {
b := &bytes.Buffer{}
return &Writer{
body: b,
out: &bytes.Buffer{},
w: w,
CRC: crc32.New(crc32.IEEETable),
Line: 128,
Header: &Header{},
Footer: &Header{},
}
}
func (w *Writer) Write(p []byte) (written int, err error) {
if w.cls {
return 0, io.ErrClosedPipe
}
//Add original to CRC
w.CRC.Write(p)
w.Length += len(p)
for i := range p {
b := p[i]
b += byteOffset
switch b {
case null, cr, lf, tab, escape, 0x2e:
w.body.WriteByte(escape)
b += specialOffset
w.curLineLen++
}
written++
w.body.WriteByte(b)
w.curLineLen++
if w.curLineLen >= w.Line {
w.body.Write([]byte("\r\n"))
w.curLineLen = 0
}
}
return
}
func (w *Writer) Close() error {
w.cls = true
w.Header.Put("size", strconv.Itoa(w.Length))
w.Header.Put("name", w.Name)
w.Header.Put("line", strconv.Itoa(w.Line))
fmt.Fprintf(w.w, "=ybegin %s \r\n", w.Header)
_, err := io.Copy(w.w, w.body)
if err != nil {
return err
}
if w.curLineLen > 0 {
fmt.Fprint(w.w, "\r\n")
}
p := make([]byte, 4)
binary.BigEndian.PutUint32(p, w.CRC.Sum32())
w.Footer.Put("pcrc32", hex.EncodeToString(p))
w.Footer.Put("size", strconv.Itoa(w.Length))
fmt.Fprintf(w.w, "=yend %s\r\n", w.Footer)
return nil
}