-
Notifications
You must be signed in to change notification settings - Fork 4
/
zascii.go
197 lines (179 loc) · 4.82 KB
/
zascii.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
// Copyright 2014 The zephyr-go authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package zephyr
import (
"encoding/binary"
"errors"
)
// The zephyrascii implementation is going to intentionally be
// stricter than libzephyr's for now. Byte sequences MUST be bracketed
// at every word and MUST be uppercase.
const upperHexTable = "0123456789ABCDEF"
// The encoded length of a zephyrascii word.
const zephyrasciiWordLength = 2 + 2*4
// DecodedZAsciiLength returns the decoded length of a zephyrascii
// input of length n.
func DecodedZAsciiLength(n int) int {
if n == 0 {
return 0
}
result := 4 * (n / (zephyrasciiWordLength + 1))
result += ((n % (zephyrasciiWordLength + 1)) - 2) / 2
return result
}
func decodeUpperHexChar(c byte) (byte, error) {
if '0' <= c && c <= '9' {
return c - '0', nil
} else if 'A' <= c && c <= 'F' {
return c - 'A' + 10, nil
} else {
return 0, errors.New("bad hex character")
}
}
func decodeUpperHex(dst, src []byte) (int, error) {
if len(src)%2 != 0 {
return 0, errors.New("bad hex length")
}
for i := 0; i < len(src)/2; i++ {
hi, err := decodeUpperHexChar(src[2*i])
if err != nil {
return 0, err
}
lo, err := decodeUpperHexChar(src[2*i+1])
if err != nil {
return 0, err
}
dst[i] = (hi<<4 | lo)
}
return len(src) / 2, nil
}
// DecodeZAsciiInto decodes zephyrascii from src and writes the output
// into dst. It returns the number of bytes written.
func DecodeZAsciiInto(dst, src []byte) (int, error) {
if len(src) == 0 {
return 0, nil
}
// Check the lengths ahead of time.
lastLen := len(src) % (zephyrasciiWordLength + 1)
if lastLen < 2+2 || lastLen%2 != 0 {
return 0, errors.New("bad zephyrascii field length")
}
j := 0
for i := 0; i < len(src); i += zephyrasciiWordLength + 1 {
if i > 0 && src[i-1] != ' ' {
return 0, errors.New("expected ' '")
}
if src[i] != '0' || src[i+1] != 'x' {
return 0, errors.New("expected '0x'")
}
limit := i + zephyrasciiWordLength
if limit > len(src) {
limit = len(src)
}
decoded, err := decodeUpperHex(dst[j:], src[i+2:limit])
if err != nil {
return 0, err
}
j += decoded
}
return j, nil
}
// DecodeZAscii decodes zephyrascii and returns the decoded result as
// a byte slice.
func DecodeZAscii(src []byte) ([]byte, error) {
dst := make([]byte, DecodedZAsciiLength(len(src)))
if l, err := DecodeZAsciiInto(dst, src); err != nil {
return nil, err
} else if l != len(dst) {
panic(l)
}
return dst, nil
}
// DecodeZAscii16 decodes the zephyrascii encoding of a 16-bit integer
// and returns the result as a uint16.
func DecodeZAscii16(src []byte) (uint16, error) {
if len(src) != 2+2*2 {
return 0, errors.New("bad length for uint16 zephyrascii")
}
dst, err := DecodeZAscii(src)
if err != nil {
return 0, err
}
if len(dst) != 2 {
panic(dst)
}
return binary.BigEndian.Uint16(dst), nil
}
// DecodeZAscii32 decodes the zephyrascii encoding of a 32-bit integer
// and returns the result as a uint32.
func DecodeZAscii32(src []byte) (uint32, error) {
if len(src) != 2+2*4 {
return 0, errors.New("bad length for uint32 zephyrascii")
}
dst, err := DecodeZAscii(src)
if err != nil {
return 0, err
}
if len(dst) != 4 {
panic(dst)
}
return binary.BigEndian.Uint32(dst), nil
}
// EncodedZAsciiLength returns the length of the zephyrascii encoding
// of a byte slice of length n.
func EncodedZAsciiLength(n int) int {
if n == 0 {
return 0
}
fullWords := (n / 4) * (zephyrasciiWordLength + 1)
rest := n % 4
if rest == 0 {
// Remove trailing space.
return fullWords - 1
}
// Account for 0x and remainder.
return fullWords + 2 + rest*2
}
// EncodeZAscii encodes a byte slice as zephyrascii.
func EncodeZAscii(src []byte) []byte {
dst := make([]byte, EncodedZAsciiLength(len(src)))
j := 0
for i, v := range src {
if i%4 == 0 {
if i > 0 {
dst[j] = ' '
j++
}
dst[j] = '0'
dst[j+1] = 'x'
j += 2
}
dst[j] = upperHexTable[v>>4]
dst[j+1] = upperHexTable[v&0xf]
j += 2
}
return dst
}
// EncodeZAscii16 encodes a 16-bit integer as zephyrascii.
func EncodeZAscii16(val uint16) []byte {
src := make([]byte, 2)
binary.BigEndian.PutUint16(src, val)
return EncodeZAscii(src)
}
// EncodeZAscii32 encodes a 32-bit integer as zephyrascii.
func EncodeZAscii32(val uint32) []byte {
src := make([]byte, 4)
binary.BigEndian.PutUint32(src, val)
return EncodeZAscii(src)
}