OSDN Git Service

Merge pull request #935 from Bytom/dev
[bytom/bytom.git] / common / bytes.go
1 // Copyright 2014 The go-ethereum Authors
2 // This file is part of the go-ethereum library.
3 //
4 // The go-ethereum library is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // The go-ethereum library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public License
15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16
17 // Package common contains various helper functions.
18 package common
19
20 import (
21         "bytes"
22         "encoding/binary"
23         "encoding/hex"
24         "math/big"
25         "strings"
26
27         log "github.com/sirupsen/logrus"
28 )
29
30 func ToHex(b []byte) string {
31         hex := Bytes2Hex(b)
32         // Prefer output of "0x0" instead of "0x"
33         if len(hex) == 0 {
34                 hex = "0"
35         }
36         return "0x" + hex
37 }
38
39 func FromHex(s string) []byte {
40         if len(s) > 1 {
41                 if s[0:2] == "0x" {
42                         s = s[2:]
43                 }
44                 if len(s)%2 == 1 {
45                         s = "0" + s
46                 }
47                 return Hex2Bytes(s)
48         }
49         return nil
50 }
51
52 // Number to bytes
53 //
54 // Returns the number in bytes with the specified base
55 func NumberToBytes(num interface{}, bits int) []byte {
56         buf := new(bytes.Buffer)
57         err := binary.Write(buf, binary.BigEndian, num)
58         if err != nil {
59                 log.WithField("err", err).Error("NumberToBytes failed")
60         }
61
62         return buf.Bytes()[buf.Len()-(bits/8):]
63 }
64
65 // Bytes to number
66 //
67 // Attempts to cast a byte slice to a unsigned integer
68 func BytesToNumber(b []byte) uint64 {
69         var number uint64
70
71         // Make sure the buffer is 64bits
72         data := make([]byte, 8)
73         data = append(data[:len(b)], b...)
74
75         buf := bytes.NewReader(data)
76         err := binary.Read(buf, binary.BigEndian, &number)
77         if err != nil {
78                 log.WithField("err", err).Error("BytesToNumber failed")
79         }
80
81         return number
82 }
83
84 // Read variable int
85 //
86 // Read a variable length number in big endian byte order
87 func ReadVarInt(buff []byte) (ret uint64) {
88         switch l := len(buff); {
89         case l > 4:
90                 d := LeftPadBytes(buff, 8)
91                 binary.Read(bytes.NewReader(d), binary.BigEndian, &ret)
92         case l > 2:
93                 var num uint32
94                 d := LeftPadBytes(buff, 4)
95                 binary.Read(bytes.NewReader(d), binary.BigEndian, &num)
96                 ret = uint64(num)
97         case l > 1:
98                 var num uint16
99                 d := LeftPadBytes(buff, 2)
100                 binary.Read(bytes.NewReader(d), binary.BigEndian, &num)
101                 ret = uint64(num)
102         default:
103                 var num uint8
104                 binary.Read(bytes.NewReader(buff), binary.BigEndian, &num)
105                 ret = uint64(num)
106         }
107
108         return
109 }
110
111 // Copy bytes
112 //
113 // Returns an exact copy of the provided bytes
114 func CopyBytes(b []byte) (copiedBytes []byte) {
115         copiedBytes = make([]byte, len(b))
116         copy(copiedBytes, b)
117
118         return
119 }
120
121 func HasHexPrefix(str string) bool {
122         l := len(str)
123         return l >= 2 && str[0:2] == "0x"
124 }
125
126 func IsHex(str string) bool {
127         l := len(str)
128         return l >= 4 && l%2 == 0 && str[0:2] == "0x"
129 }
130
131 func Bytes2Hex(d []byte) string {
132         return hex.EncodeToString(d)
133 }
134
135 func Hex2Bytes(str string) []byte {
136         h, _ := hex.DecodeString(str)
137
138         return h
139 }
140
141 func Hex2BytesFixed(str string, flen int) []byte {
142         h, _ := hex.DecodeString(str)
143         if len(h) == flen {
144                 return h
145         } else {
146                 if len(h) > flen {
147                         return h[len(h)-flen : len(h)]
148                 } else {
149                         hh := make([]byte, flen)
150                         copy(hh[flen-len(h):flen], h[:])
151                         return hh
152                 }
153         }
154 }
155
156 func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) {
157         if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") {
158                 ret = Hex2Bytes(str[2:])
159         } else {
160                 ret = cb(str)
161         }
162
163         return
164 }
165
166 func FormatData(data string) []byte {
167         if len(data) == 0 {
168                 return nil
169         }
170         // Simple stupid
171         d := new(big.Int)
172         if data[0:1] == "\"" && data[len(data)-1:] == "\"" {
173                 return RightPadBytes([]byte(data[1:len(data)-1]), 32)
174         } else if len(data) > 1 && data[:2] == "0x" {
175                 d.SetBytes(Hex2Bytes(data[2:]))
176         } else {
177                 d.SetString(data, 0)
178         }
179
180         return BigToBytes(d, 256)
181 }
182
183 func ParseData(data ...interface{}) (ret []byte) {
184         for _, item := range data {
185                 switch t := item.(type) {
186                 case string:
187                         var str []byte
188                         if IsHex(t) {
189                                 str = Hex2Bytes(t[2:])
190                         } else {
191                                 str = []byte(t)
192                         }
193
194                         ret = append(ret, RightPadBytes(str, 32)...)
195                 case []byte:
196                         ret = append(ret, LeftPadBytes(t, 32)...)
197                 }
198         }
199
200         return
201 }
202
203 func RightPadBytes(slice []byte, l int) []byte {
204         if l < len(slice) {
205                 return slice
206         }
207
208         padded := make([]byte, l)
209         copy(padded[0:len(slice)], slice)
210
211         return padded
212 }
213
214 func LeftPadBytes(slice []byte, l int) []byte {
215         if l < len(slice) {
216                 return slice
217         }
218
219         padded := make([]byte, l)
220         copy(padded[l-len(slice):], slice)
221
222         return padded
223 }
224
225 func LeftPadString(str string, l int) string {
226         if l < len(str) {
227                 return str
228         }
229
230         zeros := Bytes2Hex(make([]byte, (l-len(str))/2))
231
232         return zeros + str
233
234 }
235
236 func RightPadString(str string, l int) string {
237         if l < len(str) {
238                 return str
239         }
240
241         zeros := Bytes2Hex(make([]byte, (l-len(str))/2))
242
243         return str + zeros
244
245 }
246
247 func ToAddress(slice []byte) (addr []byte) {
248         if len(slice) < 20 {
249                 addr = LeftPadBytes(slice, 20)
250         } else if len(slice) > 20 {
251                 addr = slice[len(slice)-20:]
252         } else {
253                 addr = slice
254         }
255
256         addr = CopyBytes(addr)
257
258         return
259 }
260
261 func ByteSliceToInterface(slice [][]byte) (ret []interface{}) {
262         for _, i := range slice {
263                 ret = append(ret, i)
264         }
265
266         return
267 }
268
269 func Unit64ToBytes(n uint64) []byte {
270         buf := make([]byte, 8)
271         binary.LittleEndian.PutUint64(buf, n)
272         return buf
273 }
274
275 func BytesToUnit64(b []byte) uint64 {
276         return binary.LittleEndian.Uint64(b)
277 }