OSDN Git Service

new repo
[bytom/vapor.git] / common / bytes.go
1 // Package common contains various helper functions.
2 package common
3
4 import (
5         "bytes"
6         "encoding/binary"
7         "encoding/hex"
8         "math/big"
9         "strings"
10
11         log "github.com/sirupsen/logrus"
12 )
13
14 func ToHex(b []byte) string {
15         hex := Bytes2Hex(b)
16         // Prefer output of "0x0" instead of "0x"
17         if len(hex) == 0 {
18                 hex = "0"
19         }
20         return "0x" + hex
21 }
22
23 func FromHex(s string) []byte {
24         if len(s) > 1 {
25                 if s[0:2] == "0x" {
26                         s = s[2:]
27                 }
28                 if len(s)%2 == 1 {
29                         s = "0" + s
30                 }
31                 return Hex2Bytes(s)
32         }
33         return nil
34 }
35
36 // Number to bytes
37 //
38 // Returns the number in bytes with the specified base
39 func NumberToBytes(num interface{}, bits int) []byte {
40         buf := new(bytes.Buffer)
41         err := binary.Write(buf, binary.BigEndian, num)
42         if err != nil {
43                 log.WithField("err", err).Error("NumberToBytes failed")
44         }
45
46         return buf.Bytes()[buf.Len()-(bits/8):]
47 }
48
49 // Bytes to number
50 //
51 // Attempts to cast a byte slice to a unsigned integer
52 func BytesToNumber(b []byte) uint64 {
53         var number uint64
54
55         // Make sure the buffer is 64bits
56         data := make([]byte, 8)
57         data = append(data[:len(b)], b...)
58
59         buf := bytes.NewReader(data)
60         err := binary.Read(buf, binary.BigEndian, &number)
61         if err != nil {
62                 log.WithField("err", err).Error("BytesToNumber failed")
63         }
64
65         return number
66 }
67
68 // Read variable int
69 //
70 // Read a variable length number in big endian byte order
71 func ReadVarInt(buff []byte) (ret uint64) {
72         switch l := len(buff); {
73         case l > 4:
74                 d := LeftPadBytes(buff, 8)
75                 binary.Read(bytes.NewReader(d), binary.BigEndian, &ret)
76         case l > 2:
77                 var num uint32
78                 d := LeftPadBytes(buff, 4)
79                 binary.Read(bytes.NewReader(d), binary.BigEndian, &num)
80                 ret = uint64(num)
81         case l > 1:
82                 var num uint16
83                 d := LeftPadBytes(buff, 2)
84                 binary.Read(bytes.NewReader(d), binary.BigEndian, &num)
85                 ret = uint64(num)
86         default:
87                 var num uint8
88                 binary.Read(bytes.NewReader(buff), binary.BigEndian, &num)
89                 ret = uint64(num)
90         }
91
92         return
93 }
94
95 // Copy bytes
96 //
97 // Returns an exact copy of the provided bytes
98 func CopyBytes(b []byte) (copiedBytes []byte) {
99         copiedBytes = make([]byte, len(b))
100         copy(copiedBytes, b)
101
102         return
103 }
104
105 func HasHexPrefix(str string) bool {
106         l := len(str)
107         return l >= 2 && str[0:2] == "0x"
108 }
109
110 func IsHex(str string) bool {
111         l := len(str)
112         return l >= 4 && l%2 == 0 && str[0:2] == "0x"
113 }
114
115 func Bytes2Hex(d []byte) string {
116         return hex.EncodeToString(d)
117 }
118
119 func Hex2Bytes(str string) []byte {
120         h, _ := hex.DecodeString(str)
121         return h
122 }
123
124 func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) {
125         if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") {
126                 ret = Hex2Bytes(str[2:])
127         } else {
128                 ret = cb(str)
129         }
130
131         return
132 }
133
134 func FormatData(data string) []byte {
135         if len(data) == 0 {
136                 return nil
137         }
138         // Simple stupid
139         d := new(big.Int)
140         if data[0:1] == "\"" && data[len(data)-1:] == "\"" {
141                 return RightPadBytes([]byte(data[1:len(data)-1]), 32)
142         } else if len(data) > 1 && data[:2] == "0x" {
143                 d.SetBytes(Hex2Bytes(data[2:]))
144         } else {
145                 d.SetString(data, 0)
146         }
147
148         return BigToBytes(d, 256)
149 }
150
151 func ParseData(data ...interface{}) (ret []byte) {
152         for _, item := range data {
153                 switch t := item.(type) {
154                 case string:
155                         var str []byte
156                         if IsHex(t) {
157                                 str = Hex2Bytes(t[2:])
158                         } else {
159                                 str = []byte(t)
160                         }
161
162                         ret = append(ret, RightPadBytes(str, 32)...)
163                 case []byte:
164                         ret = append(ret, LeftPadBytes(t, 32)...)
165                 }
166         }
167
168         return
169 }
170
171 func RightPadBytes(slice []byte, l int) []byte {
172         if l < len(slice) {
173                 return slice
174         }
175
176         padded := make([]byte, l)
177         copy(padded[0:len(slice)], slice)
178
179         return padded
180 }
181
182 func LeftPadBytes(slice []byte, l int) []byte {
183         if l < len(slice) {
184                 return slice
185         }
186
187         padded := make([]byte, l)
188         copy(padded[l-len(slice):], slice)
189
190         return padded
191 }
192
193 func LeftPadString(str string, l int) string {
194         if l < len(str) {
195                 return str
196         }
197
198         zeros := Bytes2Hex(make([]byte, (l-len(str))/2))
199
200         return zeros + str
201
202 }
203
204 func RightPadString(str string, l int) string {
205         if l < len(str) {
206                 return str
207         }
208
209         zeros := Bytes2Hex(make([]byte, (l-len(str))/2))
210
211         return str + zeros
212 }
213
214 func ByteSliceToInterface(slice [][]byte) (ret []interface{}) {
215         for _, i := range slice {
216                 ret = append(ret, i)
217         }
218
219         return
220 }
221
222 func Unit64ToBytes(n uint64) []byte {
223         buf := make([]byte, 8)
224         binary.LittleEndian.PutUint64(buf, n)
225         return buf
226 }
227
228 func BytesToUnit64(b []byte) uint64 {
229         return binary.LittleEndian.Uint64(b)
230 }