-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathencoder.go
More file actions
140 lines (117 loc) · 3.23 KB
/
encoder.go
File metadata and controls
140 lines (117 loc) · 3.23 KB
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
package govtk
import (
"bytes"
"encoding/base64"
"encoding/binary"
"fmt"
"io"
"log"
)
// The encoder interface provides functionality to convert int or float data
// towards a payload. Additionally, the encoder encodes the payload's data.
type encoder interface {
binarise(data interface{}) *payload
encode(*payload) ([]byte, error)
//decode([]byte) *Payload // todo
format() string
}
// asciier encodes the payload using the ascii format.
type asciier struct{}
// Binarise creates a payload where the body is filled with the bytes of the
// string representation of the provided data. A space (" ") is inserted
// after each element of the data, except after the last.
func (a asciier) binarise(data interface{}) *payload {
p := newPayload()
// temp func to write []byte to buffer
writeVal := func(buf io.Writer, data []byte) {
err := binary.Write(buf, binary.LittleEndian, data)
if err != nil {
log.Fatal(err)
}
}
// temp func to write a separator (" ") to buffer
writeSep := func(buf io.Writer) {
err := binary.Write(buf, binary.LittleEndian, []byte(" "))
if err != nil {
log.Fatal(err)
}
}
// each type needs a string conversion before writing to buffer
switch v := data.(type) {
case []int:
for i, x := range v {
writeVal(p.body, []byte(fmt.Sprintf("%d", x)))
if i < len(v)-1 {
writeSep(p.body)
}
}
case []float64:
for i, x := range v {
writeVal(p.body, []byte(fmt.Sprintf("%f", x)))
if i < len(v)-1 {
writeSep(p.body)
}
}
default:
log.Fatalf("No binarise case for %T in asciier", v)
}
// set header
if err := p.setHeader(); err != nil {
log.Fatalf("could not set header %v", err)
}
return p
}
// Encode encodes the payload to []byte.
// For ascii format only the body of the payload is required.
func (a asciier) encode(p *payload) ([]byte, error) {
return p.body.Bytes(), nil
}
func (a asciier) format() string { return formatAscii }
// base64er encodes the payload using standard base64 encoding.
type base64er struct{}
func (b base64er) binarise(data interface{}) *payload {
p, err := newPayloadFromData(data)
if err != nil {
log.Fatalf("Cannot convert data to payload: %v", err)
}
return p
}
func (b base64er) encode(p *payload) ([]byte, error) {
enc := base64.StdEncoding
data := new(bytes.Buffer)
encoder := base64.NewEncoder(enc, data)
// write header
if _, err := encoder.Write(p.head.Bytes()); err != nil {
return nil, err
}
// compress header and body separately
if p.isCompressed() {
if err := encoder.Close(); err != nil {
return nil, err
}
encoder = base64.NewEncoder(enc, data)
}
// write body
if _, err := encoder.Write(p.body.Bytes()); err != nil {
return nil, err
}
// close body
if err := encoder.Close(); err != nil {
return nil, err
}
return data.Bytes(), nil
}
func (b base64er) format() string { return formatBinary }
// binaryer encodes the payload as raw binary data.
type binaryer struct{}
func (b binaryer) binarise(data interface{}) *payload {
p, err := newPayloadFromData(data)
if err != nil {
log.Fatalf("Cannot convert data to payload: %v", err)
}
return p
}
func (b binaryer) encode(p *payload) ([]byte, error) {
return append(p.head.Bytes(), p.body.Bytes()...), nil
}
func (b binaryer) format() string { return formatRaw }