git.gammaspectra.live/P2Pool/consensus/v3@v3.8.0/monero/client/levin/portable_storage.go (about) 1 package levin 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 ) 7 8 const ( 9 PortableStorageSignatureA uint32 = 0x01011101 10 PortableStorageSignatureB uint32 = 0x01020101 11 PortableStorageFormatVersion byte = 0x01 12 13 PortableRawSizeMarkMask byte = 0x03 14 PortableRawSizeMarkByte byte = 0x00 15 PortableRawSizeMarkWord uint16 = 0x01 16 PortableRawSizeMarkDword uint32 = 0x02 17 PortableRawSizeMarkInt64 uint64 = 0x03 18 ) 19 20 type Entry struct { 21 Name string 22 Serializable Serializable `json:"-,omitempty"` 23 Value interface{} 24 } 25 26 func (e Entry) String() string { 27 v, ok := e.Value.(string) 28 if !ok { 29 panic(fmt.Errorf("interface couldnt be casted to string")) 30 } 31 32 return v 33 } 34 35 func (e Entry) Uint8() uint8 { 36 v, ok := e.Value.(uint8) 37 if !ok { 38 panic(fmt.Errorf("interface couldnt be casted to uint8")) 39 } 40 41 return v 42 } 43 44 func (e Entry) Uint16() uint16 { 45 v, ok := e.Value.(uint16) 46 if !ok { 47 panic(fmt.Errorf("interface couldnt be casted to uint16")) 48 } 49 50 return v 51 } 52 53 func (e Entry) Uint32() uint32 { 54 v, ok := e.Value.(uint32) 55 if !ok { 56 panic(fmt.Errorf("interface couldnt be casted to uint32")) 57 } 58 59 return v 60 } 61 62 func (e Entry) Uint64() uint64 { 63 v, ok := e.Value.(uint64) 64 if !ok { 65 panic(fmt.Errorf("interface couldnt be casted to uint64")) 66 } 67 68 return v 69 } 70 71 func (e Entry) Entries() Entries { 72 v, ok := e.Value.(Entries) 73 if !ok { 74 panic(fmt.Errorf("interface couldnt be casted to levin.Entries")) 75 } 76 77 return v 78 } 79 80 func (e Entry) Bytes() []byte { 81 return nil 82 } 83 84 type Entries []Entry 85 86 func (e Entries) Bytes() []byte { 87 return nil 88 } 89 90 type PortableStorage struct { 91 Entries Entries 92 } 93 94 func NewPortableStorageFromBytes(bytes []byte) (*PortableStorage, error) { 95 var ( 96 size = 0 97 idx = 0 98 ) 99 100 { // sig-a 101 size = 4 102 103 if len(bytes[idx:]) < size { 104 return nil, fmt.Errorf("sig-a out of bounds") 105 } 106 107 sig := binary.LittleEndian.Uint32(bytes[idx : idx+size]) 108 idx += size 109 110 if sig != uint32(PortableStorageSignatureA) { 111 return nil, fmt.Errorf("sig-a doesn't match") 112 } 113 } 114 115 { // sig-b 116 size = 4 117 sig := binary.LittleEndian.Uint32(bytes[idx : idx+size]) 118 idx += size 119 120 if sig != uint32(PortableStorageSignatureB) { 121 return nil, fmt.Errorf("sig-b doesn't match") 122 } 123 } 124 125 { // format ver 126 size = 1 127 version := bytes[idx] 128 idx += size 129 130 if version != PortableStorageFormatVersion { 131 return nil, fmt.Errorf("version doesn't match") 132 } 133 } 134 135 ps := &PortableStorage{} 136 137 _, ps.Entries = ReadObject(bytes[idx:]) 138 139 return ps, nil 140 } 141 142 func ReadString(bytes []byte) (int, string) { 143 idx := 0 144 145 n, strLen := ReadVarInt(bytes) 146 idx += n 147 148 return idx + strLen, string(bytes[idx : idx+strLen]) 149 } 150 151 func ReadObject(bytes []byte) (int, Entries) { 152 idx := 0 153 154 n, i := ReadVarInt(bytes[idx:]) 155 idx += n 156 157 entries := make(Entries, i) 158 159 for iter := 0; iter < i; iter++ { 160 entries[iter] = Entry{} 161 entry := &entries[iter] 162 163 lenName := int(bytes[idx]) 164 idx += 1 165 166 entry.Name = string(bytes[idx : idx+lenName]) 167 idx += lenName 168 169 ttype := bytes[idx] 170 idx += 1 171 172 n, obj := ReadAny(bytes[idx:], ttype) 173 idx += n 174 175 entry.Value = obj 176 } 177 178 return idx, entries 179 } 180 181 func ReadArray(ttype byte, bytes []byte) (int, Entries) { 182 var ( 183 idx = 0 184 n = 0 185 ) 186 187 n, i := ReadVarInt(bytes[idx:]) 188 idx += n 189 190 entries := make(Entries, i) 191 192 for iter := 0; iter < i; iter++ { 193 n, obj := ReadAny(bytes[idx:], ttype) 194 idx += n 195 196 entries[iter] = Entry{ 197 Value: obj, 198 } 199 } 200 201 return idx, entries 202 } 203 204 func ReadAny(bytes []byte, ttype byte) (int, interface{}) { 205 var ( 206 idx = 0 207 n = 0 208 ) 209 210 if ttype&BoostSerializeFlagArray != 0 { 211 internalType := ttype &^ BoostSerializeFlagArray 212 n, obj := ReadArray(internalType, bytes[idx:]) 213 idx += n 214 215 return idx, obj 216 } 217 218 if ttype == BoostSerializeTypeObject { 219 n, obj := ReadObject(bytes[idx:]) 220 idx += n 221 222 return idx, obj 223 } 224 225 if ttype == BoostSerializeTypeUint8 { 226 obj := uint8(bytes[idx]) 227 n += 1 228 idx += n 229 230 return idx, obj 231 } 232 233 if ttype == BoostSerializeTypeUint16 { 234 obj := binary.LittleEndian.Uint16(bytes[idx:]) 235 n += 2 236 idx += n 237 238 return idx, obj 239 } 240 241 if ttype == BoostSerializeTypeUint32 { 242 obj := binary.LittleEndian.Uint32(bytes[idx:]) 243 n += 4 244 idx += n 245 246 return idx, obj 247 } 248 249 if ttype == BoostSerializeTypeUint64 { 250 obj := binary.LittleEndian.Uint64(bytes[idx:]) 251 n += 8 252 idx += n 253 254 return idx, obj 255 } 256 257 if ttype == BoostSerializeTypeInt64 { 258 obj := binary.LittleEndian.Uint64(bytes[idx:]) 259 n += 8 260 idx += n 261 262 return idx, int64(obj) 263 } 264 265 if ttype == BoostSerializeTypeString { 266 n, obj := ReadString(bytes[idx:]) 267 idx += n 268 269 return idx, obj 270 } 271 272 if ttype == BoostSerializeTypeBool { 273 obj := bytes[idx] > 0 274 n += 1 275 idx += n 276 277 return idx, obj 278 } 279 280 panic(fmt.Errorf("unknown ttype %x", ttype)) 281 return -1, nil 282 } 283 284 // reads var int, returning number of bytes read and the integer in that byte 285 // sequence. 286 func ReadVarInt(b []byte) (int, int) { 287 sizeMask := b[0] & PortableRawSizeMarkMask 288 289 switch uint32(sizeMask) { 290 case uint32(PortableRawSizeMarkByte): 291 return 1, int(b[0] >> 2) 292 case uint32(PortableRawSizeMarkWord): 293 return 2, int((binary.LittleEndian.Uint16(b[0:2])) >> 2) 294 case PortableRawSizeMarkDword: 295 return 4, int((binary.LittleEndian.Uint32(b[0:4])) >> 2) 296 case uint32(PortableRawSizeMarkInt64): 297 panic("int64 not supported") // TODO 298 // return int((binary.LittleEndian.Uint64(b[0:8])) >> 2) 299 // '-> bad 300 default: 301 panic(fmt.Errorf("malformed sizemask: %+v", sizeMask)) 302 } 303 304 return -1, -1 305 } 306 307 func (s *PortableStorage) Bytes() []byte { 308 var ( 309 body = make([]byte, 9) // fit _at least_ signatures + format ver 310 b = make([]byte, 8) // biggest type 311 312 idx = 0 313 size = 0 314 ) 315 316 { // signature a 317 size = 4 318 319 binary.LittleEndian.PutUint32(b, PortableStorageSignatureA) 320 copy(body[idx:], b[:size]) 321 idx += size 322 } 323 324 { // signature b 325 size = 4 326 327 binary.LittleEndian.PutUint32(b, PortableStorageSignatureB) 328 copy(body[idx:], b[:size]) 329 idx += size 330 } 331 332 { // format ver 333 size = 1 334 335 b[0] = PortableStorageFormatVersion 336 copy(body[idx:], b[:size]) 337 idx += size 338 } 339 340 // // write_var_in 341 varInB, err := VarIn(len(s.Entries)) 342 if err != nil { 343 panic(fmt.Errorf("varin '%d': %w", len(s.Entries), err)) 344 } 345 346 body = append(body, varInB...) 347 for _, entry := range s.Entries { 348 body = append(body, byte(len(entry.Name))) // section name length 349 body = append(body, []byte(entry.Name)...) // section name 350 body = append(body, entry.Serializable.Bytes()...) 351 } 352 353 return body 354 } 355 356 type Serializable interface { 357 Bytes() []byte 358 } 359 360 type Section struct { 361 Entries []Entry 362 } 363 364 func (s Section) Bytes() []byte { 365 body := []byte{ 366 BoostSerializeTypeObject, 367 } 368 369 varInB, err := VarIn(len(s.Entries)) 370 if err != nil { 371 panic(fmt.Errorf("varin '%d': %w", len(s.Entries), err)) 372 } 373 374 body = append(body, varInB...) 375 for _, entry := range s.Entries { 376 body = append(body, byte(len(entry.Name))) // section name length 377 body = append(body, []byte(entry.Name)...) // section name 378 body = append(body, entry.Serializable.Bytes()...) 379 } 380 381 return body 382 } 383 384 func VarIn(i int) ([]byte, error) { 385 if i <= 63 { 386 return []byte{ 387 (byte(i) << 2) | PortableRawSizeMarkByte, 388 }, nil 389 } 390 391 if i <= 16383 { 392 b := []byte{0x00, 0x00} 393 binary.LittleEndian.PutUint16(b, 394 (uint16(i)<<2)|PortableRawSizeMarkWord, 395 ) 396 397 return b, nil 398 } 399 400 if i <= 1073741823 { 401 b := []byte{0x00, 0x00, 0x00, 0x00} 402 binary.LittleEndian.PutUint32(b, 403 (uint32(i)<<2)|PortableRawSizeMarkDword, 404 ) 405 406 return b, nil 407 } 408 409 return nil, fmt.Errorf("int %d too big", i) 410 }