github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/common/sink/serialize.go (about) 1 package sink 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "io" 8 "math" 9 ) 10 11 var ErrRange = errors.New("value out of range") 12 var ErrEof = errors.New("got EOF, can not get the next byte") 13 14 // SerializableData describe the data need be serialized. 15 type SerializableData interface { 16 // Write data to writer 17 Serialize(w io.Writer) error 18 19 // read data to reader 20 Deserialize(r io.Reader) error 21 } 22 23 /* 24 ****************************************************************************** 25 * public func for outside calling 26 ****************************************************************************** 27 * 1. WriteVarUint func, depend on the inpute number's Actual number size, 28 * serialize to bytes. 29 * uint8 => (LittleEndian)num in 1 byte = 1bytes 30 * uint16 => 0xfd(1 byte) + (LittleEndian)num in 2 bytes = 3bytes 31 * uint32 => 0xfe(1 byte) + (LittleEndian)num in 4 bytes = 5bytes 32 * uint64 => 0xff(1 byte) + (LittleEndian)num in 8 bytes = 9bytes 33 * 2. ReadVarUint func, this func will read the first byte to determined 34 * the num length to read.and retrun the uint64 35 * first byte = 0xfd, read the next 2 bytes as uint16 36 * first byte = 0xfe, read the next 4 bytes as uint32 37 * first byte = 0xff, read the next 8 bytes as uint64 38 * other else, read this byte as uint8 39 * 3. WriteVarBytes func, this func will output two item as serialization. 40 * length of bytes (uint8/uint16/uint32/uint64) + bytes 41 * 4. WriteString func, this func will output two item as serialization. 42 * length of string(uint8/uint16/uint32/uint64) + bytes(string) 43 * 5. ReadVarBytes func, this func will first read a uint to identify the 44 * length of bytes, and use it to get the next length's bytes to return. 45 * 6. ReadString func, this func will first read a uint to identify the 46 * length of string, and use it to get the next bytes as a string. 47 * 7. GetVarUintSize func, this func will return the length of a uint when it 48 * serialized by the WriteVarUint func. 49 * 8. ReadBytes func, this func will read the specify lenth's bytes and retun. 50 * 9. ReadUint8,16,32,64 read uint with fixed length 51 * 10.WriteUint8,16,32,64 Write uint with fixed length 52 * 11.ToArray SerializableData to ToArray() func. 53 ****************************************************************************** 54 */ 55 56 func WriteVarUint(writer io.Writer, value uint64) error { 57 var buf [9]byte 58 var len = 0 59 if value < 0xFD { 60 buf[0] = uint8(value) 61 len = 1 62 } else if value <= 0xFFFF { 63 buf[0] = 0xFD 64 binary.LittleEndian.PutUint16(buf[1:], uint16(value)) 65 len = 3 66 } else if value <= 0xFFFFFFFF { 67 buf[0] = 0xFE 68 binary.LittleEndian.PutUint32(buf[1:], uint32(value)) 69 len = 5 70 } else { 71 buf[0] = 0xFF 72 binary.LittleEndian.PutUint64(buf[1:], uint64(value)) 73 len = 9 74 } 75 _, err := writer.Write(buf[:len]) 76 return err 77 } 78 79 func ReadVarUint(reader io.Reader, maxint uint64) (uint64, error) { 80 var res uint64 81 if maxint == 0x00 { 82 maxint = math.MaxUint64 83 } 84 var fb [9]byte 85 _, err := io.ReadFull(reader, fb[:1]) 86 if err != nil { 87 return 0, err 88 } 89 90 if fb[0] == byte(0xfd) { 91 _, err := io.ReadFull(reader, fb[1:3]) 92 if err != nil { 93 return 0, err 94 } 95 res = uint64(binary.LittleEndian.Uint16(fb[1:3])) 96 } else if fb[0] == byte(0xfe) { 97 _, err := io.ReadFull(reader, fb[1:5]) 98 if err != nil { 99 return 0, err 100 } 101 res = uint64(binary.LittleEndian.Uint32(fb[1:5])) 102 } else if fb[0] == byte(0xff) { 103 _, err := io.ReadFull(reader, fb[1:9]) 104 if err != nil { 105 return 0, err 106 } 107 res = uint64(binary.LittleEndian.Uint64(fb[1:9])) 108 } else { 109 res = uint64(fb[0]) 110 } 111 if res > maxint { 112 return 0, ErrRange 113 } 114 return res, nil 115 } 116 117 func WriteVarBytes(writer io.Writer, value []byte) error { 118 err := WriteVarUint(writer, uint64(len(value))) 119 if err != nil { 120 return err 121 } 122 _, err = writer.Write(value) 123 return err 124 } 125 126 func WriteString(writer io.Writer, value string) error { 127 return WriteVarBytes(writer, []byte(value)) 128 } 129 130 func ReadVarBytes(reader io.Reader) ([]byte, error) { 131 val, err := ReadVarUint(reader, 0) 132 if err != nil { 133 return nil, err 134 } 135 str, err := byteXReader(reader, val) 136 if err != nil { 137 return nil, err 138 } 139 return str, nil 140 } 141 142 func ReadString(reader io.Reader) (string, error) { 143 val, err := ReadVarBytes(reader) 144 if err != nil { 145 return "", err 146 } 147 return string(val), nil 148 } 149 150 func GetVarUintSize(value uint64) int { 151 if value < 0xfd { 152 return 1 153 } else if value <= 0xffff { 154 return 3 155 } else if value <= 0xFFFFFFFF { 156 return 5 157 } else { 158 return 9 159 } 160 } 161 162 func ReadBytes(reader io.Reader, length uint64) ([]byte, error) { 163 str, err := byteXReader(reader, length) 164 if err != nil { 165 return nil, err 166 } 167 return str, nil 168 } 169 170 func ReadUint8(reader io.Reader) (uint8, error) { 171 var p [1]byte 172 _, err := io.ReadFull(reader, p[:]) 173 if err != nil { 174 return 0, ErrEof 175 } 176 return uint8(p[0]), nil 177 } 178 179 func ReadUint16(reader io.Reader) (uint16, error) { 180 var p [2]byte 181 _, err := io.ReadFull(reader, p[:]) 182 if err != nil { 183 return 0, ErrEof 184 } 185 return binary.LittleEndian.Uint16(p[:]), nil 186 } 187 188 func ReadUint32(reader io.Reader) (uint32, error) { 189 var p [4]byte 190 _, err := io.ReadFull(reader, p[:]) 191 if err != nil { 192 return 0, ErrEof 193 } 194 return binary.LittleEndian.Uint32(p[:]), nil 195 } 196 197 func ReadUint64(reader io.Reader) (uint64, error) { 198 var p [8]byte 199 _, err := io.ReadFull(reader, p[:]) 200 if err != nil { 201 return 0, ErrEof 202 } 203 return binary.LittleEndian.Uint64(p[:]), nil 204 } 205 206 func WriteUint8(writer io.Writer, val uint8) error { 207 var p [1]byte 208 p[0] = byte(val) 209 _, err := writer.Write(p[:]) 210 return err 211 } 212 213 func WriteUint16(writer io.Writer, val uint16) error { 214 var p [2]byte 215 binary.LittleEndian.PutUint16(p[:], val) 216 _, err := writer.Write(p[:]) 217 return err 218 } 219 220 func WriteUint32(writer io.Writer, val uint32) error { 221 var p [4]byte 222 binary.LittleEndian.PutUint32(p[:], val) 223 _, err := writer.Write(p[:]) 224 return err 225 } 226 227 func WriteUint64(writer io.Writer, val uint64) error { 228 var p [8]byte 229 binary.LittleEndian.PutUint64(p[:], val) 230 _, err := writer.Write(p[:]) 231 return err 232 } 233 234 func ToArray(data SerializableData) []byte { 235 buf := new(bytes.Buffer) 236 data.Serialize(buf) 237 return buf.Bytes() 238 } 239 240 //************************************************************************** 241 //** internal func *** 242 //************************************************************************** 243 //** 2.byteXReader: read x byte and return []byte. 244 //** 3.byteToUint8: change byte -> uint8 and return. 245 //************************************************************************** 246 247 func byteXReader(reader io.Reader, x uint64) ([]byte, error) { 248 if x == 0 { 249 return nil, nil 250 } 251 //fast path to avoid buffer reallocation 252 if x < 2*1024*1024 { 253 p := make([]byte, x) 254 _, err := io.ReadFull(reader, p) 255 if err != nil { 256 return nil, err 257 } 258 return p, nil 259 } 260 261 // normal path to avoid attack 262 limited := io.LimitReader(reader, int64(x)) 263 buf := &bytes.Buffer{} 264 n, _ := buf.ReadFrom(limited) 265 if n == int64(x) { 266 return buf.Bytes(), nil 267 } 268 return nil, ErrEof 269 } 270 271 func WriteBool(writer io.Writer, val bool) error { 272 err := binary.Write(writer, binary.LittleEndian, val) 273 return err 274 } 275 276 func ReadBool(reader io.Reader) (bool, error) { 277 var x bool 278 err := binary.Read(reader, binary.LittleEndian, &x) 279 return x, err 280 } 281 282 func WriteByte(writer io.Writer, val byte) error { 283 _, err := writer.Write([]byte{val}) 284 if err != nil { 285 return err 286 } 287 return nil 288 } 289 290 func ReadByte(reader io.Reader) (byte, error) { 291 b, err := byteXReader(reader, 1) 292 if err != nil { 293 return 0, err 294 } 295 return b[0], nil 296 }