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  }