-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathencode.go
115 lines (100 loc) · 3.05 KB
/
encode.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
package bsony
import (
"bytes"
"encoding/binary"
"errors"
"math"
)
func hasEnoughBytes(b []byte, offset int, n int) error {
if len(b)-offset < n {
return errShortDoc
}
return nil
}
func writeTypeAndKey(dst []byte, offset int, t Type, key string) int {
dst[offset] = byte(t)
nullByteOffset := offset + 1 + len(key)
copy(dst[offset+1:nullByteOffset], []byte(key))
dst[nullByteOffset] = 0
// return offset for next thing to write
return nullByteOffset + 1
}
func readTypeAndKey(src []byte, offset int) (Type, string, error) {
if err := hasEnoughBytes(src, offset, 2); err != nil {
return 0, "", err
}
t := src[offset]
nullByteOffset := bytes.IndexByte(src[offset+1:], 0)
if nullByteOffset == -1 {
return 0, "", errors.New("key not found")
}
key := string(src[offset+1 : offset+1+nullByteOffset])
return Type(t), key, nil
}
func writeFloat64(dst []byte, offset int, value float64) int {
bits := math.Float64bits(value)
binary.LittleEndian.PutUint64(dst[offset:offset+8], bits)
// return offset for next thing to write
return offset + 8
}
func readFloat64(src []byte, offset int) (float64, error) {
if err := hasEnoughBytes(src, offset, 8); err != nil {
return 0, err
}
bits := binary.LittleEndian.Uint64(src[offset : offset+8])
return math.Float64frombits(bits), nil
}
func writeInt32(dst []byte, offset int, value int32) int {
binary.LittleEndian.PutUint32(dst[offset:offset+4], uint32(value))
return offset + 4
}
func writeUint32(dst []byte, offset int, value uint32) int {
binary.LittleEndian.PutUint32(dst[offset:offset+4], value)
return offset + 4
}
func readInt32(src []byte, offset int) (int32, error) {
if err := hasEnoughBytes(src, offset, 4); err != nil {
return 0, err
}
bits := binary.LittleEndian.Uint32(src[offset : offset+4])
return int32(bits), nil
}
func writeInt64(dst []byte, offset int, value int64) int {
binary.LittleEndian.PutUint64(dst[offset:offset+8], uint64(value))
return offset + 8
}
func writeUint64(dst []byte, offset int, value uint64) int {
binary.LittleEndian.PutUint64(dst[offset:offset+8], value)
return offset + 8
}
func readInt64(src []byte, offset int) (int64, error) {
if err := hasEnoughBytes(src, offset, 8); err != nil {
return 0, err
}
bits := binary.LittleEndian.Uint64(src[offset : offset+8])
return int64(bits), nil
}
func writeString(dst []byte, offset int, value string) int {
strlen := len(value)
// Length is string length plus 1 for null byte
offset = writeInt32(dst, offset, int32(strlen)+1)
copy(dst[offset:offset+strlen], []byte(value))
dst[offset+strlen] = 0
return offset + strlen + 1
}
func writeCString(dst []byte, offset int, value string) int {
strlen := len(value)
copy(dst[offset:offset+strlen], []byte(value))
dst[offset+strlen] = 0
return offset + strlen + 1
}
func readCString(src []byte, offset int) (string, error) {
if err := hasEnoughBytes(src, offset, 1); err != nil {
return "", err
}
nullPos := bytes.IndexByte(src[offset:], 0)
if nullPos == -1 {
return "", errors.New("cstring null terminator not found")
}
return string(src[offset : offset+nullPos]), nil
}