/
util.go
333 lines (294 loc) · 7.33 KB
/
util.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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
package goutil
/*
#cgo CFLAGS: -Wno-deprecated -std=c99
#include <string.h>
typedef unsigned char * uint8ptr;
typedef short * int16ptr;
typedef short int16;
typedef unsigned short uint16;
static void goutil_convert_to_int16(uint8ptr src, size_t srcLen, int16ptr dst, size_t dstLen) {
if (srcLen <= (dstLen * 2)) {
uint8ptr tmp = (uint8ptr)dst;
memcpy(tmp, src, srcLen);
}
}
*/
import "C"
import (
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"os/exec"
"reflect"
"runtime"
"strconv"
"strings"
"unsafe"
)
// Atou16 convert a string to uint16
func Atou16(s string) uint16 {
return uint16(Atoi(s))
}
// Atou32 convert a string to uint32
func Atou32(s string) uint32 {
return uint32(Atoi(s))
}
// Atoi convert a string to int
func Atoi(s string) int {
// like strconv.ParseInt(s, 10, 0/32)
i, err := strconv.Atoi(s)
if err != nil {
buf := []byte(s)
for k := range buf {
if buf[k] < '0' || buf[k] > '9' {
i, _ = strconv.Atoi(string(buf[0:k]))
break
}
}
}
return i
}
func Atoi64(s string) int64 {
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
buf := []byte(s)
for k := range buf {
if buf[k] < '0' || buf[k] > '9' {
i, _ = strconv.ParseInt(string(buf[0:k]), 10, 64)
break
}
}
}
return i
}
// Itoa convert int to a string
func Itoa(i int) string {
return strconv.Itoa(i)
}
// This is a faster implentation of strconv.Itoa() without importing another library
// https://stackoverflow.com/a/39444005
func I32toa(n int32) string {
buf := [11]byte{}
pos := len(buf)
i := int64(n)
signed := i < 0
if signed {
i = -i
}
for {
pos--
buf[pos], i = '0'+byte(i%10), i/10
if i == 0 {
if signed {
pos--
buf[pos] = '-'
}
return string(buf[pos:])
}
}
}
// uint16base64 is a faster version of fmt.Sprintf("0x%04x", n)
//
// BenchmarkUint16Base16/fmt.Sprintf-8 10000000 154 ns/op 8 B/op 2 allocs/op
// BenchmarkUint16Base16/uint16base16-8 50000000 35.0 ns/op 8 B/op 1 allocs/op
func U16base16(n uint16) string {
var digit16 = []byte("0123456789abcdef")
b := []byte("0x0000")
b[5] = digit16[n&0x000f]
b[4] = digit16[n&0x00f0>>4]
b[3] = digit16[n&0x0f00>>8]
b[2] = digit16[n&0xf000>>12]
return string(b)
}
// ValueToBytes convert a uint16/uint32/uint64(Little-Endian) to []byte.
func ValueToBytes(T interface{}) []byte {
size := reflect.TypeOf(T).Size()
if size != 2 && size != 4 && size != 8 {
return nil
}
bytes := make([]byte, size)
if size == 2 {
binary.LittleEndian.PutUint16(bytes, T.(uint16))
} else if size == 4 {
binary.LittleEndian.PutUint32(bytes, T.(uint32))
} else if size == 8 {
binary.LittleEndian.PutUint64(bytes, T.(uint64))
} else {
return nil
}
return bytes
}
func Uint16ToBytes(val uint16) []byte {
return ValueToBytes(val)
}
func Uint32ToBytes(val uint32) []byte {
return ValueToBytes(val)
}
// BytesToValue convert []byte to a uint16/uint32/uint64(Little-Endian)
func BytesToValue(bytes []byte) interface{} {
size := len(bytes)
if size == 2 {
return binary.LittleEndian.Uint16(bytes)
} else if size == 4 {
return binary.LittleEndian.Uint32(bytes)
} else if size == 8 {
return binary.LittleEndian.Uint64(bytes)
} else {
return 0
}
}
func BytesToUint16(bytes []byte) uint16 {
return BytesToValue(bytes).(uint16)
}
func BytesToUint32(bytes []byte) uint32 {
return BytesToValue(bytes).(uint32)
}
// ValueOrderChange convert a uint16/uint32/uint64(LittleEndian/BigEndian) to
// another uint16/uint32/uint64(BigEndian/LittleEndian).
func ValueOrderChange(T interface{}, order binary.ByteOrder) interface{} {
bytes := ValueToBytes(T)
if bytes == nil {
fmt.Println("invalid bytes in ValueOrderChange")
return 0
}
if len(bytes) == 2 {
return order.Uint16(bytes[0:])
} else if len(bytes) == 4 {
return order.Uint32(bytes[0:])
} else if len(bytes) == 8 {
return order.Uint64(bytes[0:])
} else {
fmt.Println("invalid length in ValueOrderChange")
}
return 0
}
func HostToNet16(v uint16) uint16 {
return ValueOrderChange(v, binary.BigEndian).(uint16)
}
func HostToNet32(v uint32) uint32 {
return ValueOrderChange(v, binary.BigEndian).(uint32)
}
func NetToHost16(v uint16) uint16 {
return ValueOrderChange(v, binary.LittleEndian).(uint16)
}
func NetToHost32(v uint32) uint32 {
return ValueOrderChange(v, binary.LittleEndian).(uint32)
}
// ReadBig read a uint16/uint32/uint64(BigEndian) from io.Reader
func ReadBig(r io.Reader, data interface{}) error {
return binary.Read(r, binary.BigEndian, data)
}
// ReadLittle read a uint16/uint32/uint64(LittleEndian) from io.Reader
func ReadLittle(r io.Reader, data interface{}) error {
return binary.Read(r, binary.LittleEndian, data)
}
// WriteBig write a uint16/uint32/uint64(BigEndian) to io.Writer
func WriteBig(w io.Writer, data interface{}) error {
return binary.Write(w, binary.BigEndian, data)
}
// WriteLittle write a uint16/uint32/uint64(LittleEndian) to io.Writer
func WriteLittle(w io.Writer, data interface{}) error {
return binary.Write(w, binary.LittleEndian, data)
}
// ByteToInt16Slice converts []byte to []int16(LittleEndian).
func ByteToInt16Slice(buf []byte) ([]int16, error) {
if len(buf)%2 != 0 {
return nil, errors.New("trailing bytes")
}
vals := make([]int16, len(buf)/2)
for i := 0; i < len(vals); i++ {
val := binary.LittleEndian.Uint16(buf[i*2:])
vals[i] = int16(val)
}
return vals, nil
}
// Int16ToByteSlice converts []int16(LittleEndian) to []byte.
func Int16ToByteSlice(vals []int16) []byte {
buf := make([]byte, len(vals)*2)
for i, v := range vals {
binary.LittleEndian.PutUint16(buf[i*2:], uint16(v))
}
return buf
}
// StringPair like std::pair
type StringPair struct {
First string
Second string
}
func (s StringPair) ToString(sp string) string {
return s.First + sp + s.Second
}
type Uint32Slice []uint32
func (p Uint32Slice) Len() int {
return len(p)
}
func (p Uint32Slice) Less(i, j int) bool {
return p[i] <= p[j]
}
func (p Uint32Slice) Swap(i, j int) {
tmp := p[i]
p[i] = p[j]
p[j] = tmp
}
func (p Uint32Slice) Search(x uint32) int {
for idx, val := range p {
if val >= x {
return idx
}
}
return -1
}
// Auto Counter
type AutoCounter int
func (c *AutoCounter) Pre() int {
val := *c
*c += 1
return int(val)
}
func (c *AutoCounter) Post() int {
*c += 1
val := *c
return int(val)
}
// Return copy(capsize) of src and the size of data
func Clone2(src []byte, capsize int) ([]byte, int) {
dst := make([]byte, capsize)
size := Min(len(src), capsize)
copy(dst, src[:size])
return dst, size
}
// Return copy of src
func Clone(src []byte) []byte {
capsize := len(src)
dst, _ := Clone2(src, capsize)
return dst
}
// Convert []byte to int16[]
func Convert2Int16(src []byte) []int16 {
src_ptr := C.uint8ptr(unsafe.Pointer(&src[0]))
src_len := C.size_t(len(src))
dst := make([]int16, (len(src)+1)/2)
dst_ptr := C.int16ptr(unsafe.Pointer(&dst[0]))
dst_len := C.size_t(len(dst))
C.goutil_convert_to_int16(src_ptr, src_len, dst_ptr, dst_len)
return dst
}
// get caller's func name
func GoFuncName() string {
if counter, _, _, ok := runtime.Caller(1); !ok {
return "unknown_go_func"
} else {
fullname := runtime.FuncForPC(counter).Name()
parts := strings.Split(fullname, ".")
return parts[len(parts)-1]
}
}
// reset to normal when custom-tty exit
func HandleTTYOnExit() {
rawModeOff := exec.Command("/bin/stty", "-raw", "echo")
rawModeOff.Stdin = os.Stdin
_ = rawModeOff.Run()
rawModeOff.Wait()
}