github.com/racerxdl/gonx@v0.0.0-20210103083128-c5afc43bcbd2/services/vi/parcel.go (about)

     1  package vi
     2  
     3  import (
     4  	"encoding/binary"
     5  	"github.com/racerxdl/gonx/internal"
     6  	"github.com/racerxdl/gonx/nx/nxerrors"
     7  	"unsafe"
     8  )
     9  
    10  // Parcel Represents a parcel
    11  // 	Bounds checking is the caller's responsibility.
    12  // 	Objects aren't currently supported very well.
    13  type Parcel struct {
    14  	Contents struct {
    15  		DataSize      uint32
    16  		DataOffset    uint32
    17  		ObjectsSize   uint32
    18  		ObjectsOffset uint32
    19  		Payload       [0x200]byte
    20  	}
    21  	ReadHead         int
    22  	WriteHead        int
    23  	WritingFinalized bool
    24  }
    25  
    26  func (p *Parcel) ReadString() string {
    27  	length := p.ReadU32()
    28  	if length == 0xFFFFFFFF {
    29  		return ""
    30  	}
    31  
    32  	size := 2 * (length + 1)
    33  
    34  	u16 := p.ReadInPlace(int(size))
    35  	u8 := make([]byte, len(u16)/2)
    36  	for i := range u8 {
    37  		u8[i] = uint8(binary.LittleEndian.Uint16(u16[i*2 : i*2+1]))
    38  	}
    39  
    40  	return string(u8)
    41  }
    42  
    43  func (p *Parcel) ReadU32() uint32 {
    44  	d := p.ReadInPlace(4)
    45  	return binary.LittleEndian.Uint32(d)
    46  }
    47  
    48  func (p *Parcel) ReadBinder() (*Binder, error) {
    49  	fbo := FlatBinderObject{}
    50  	d := p.ReadInPlace(int(unsafe.Sizeof(fbo)))
    51  	internal.Memcpy(unsafe.Pointer(&fbo), unsafe.Pointer(&d[0]), uintptr(len(d)))
    52  
    53  	binder := &Binder{}
    54  	binder.Handle = fbo.GetHandle()
    55  
    56  	err := binder.AdjustRefCount(1, 0)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	err = binder.AdjustRefCount(1, 1)
    61  
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	return binder, nil
    67  }
    68  
    69  func (p *Parcel) ReadInPlace(length int) []byte {
    70  	d := p.Contents.Payload[p.ReadHead : p.ReadHead+length]
    71  	p.ReadHead += length
    72  	return d
    73  }
    74  
    75  func (p *Parcel) Remaining() int {
    76  	return p.WriteHead - p.ReadHead
    77  }
    78  
    79  func (p *Parcel) WriteRemaining() int {
    80  	return len(p.Contents.Payload) - p.WriteHead
    81  }
    82  
    83  func (p *Parcel) FinalizeWriting() ([]byte, int) {
    84  	p.WritingFinalized = true
    85  	p.Contents.DataSize = uint32(p.WriteHead)
    86  	p.Contents.DataOffset = 0x10
    87  	p.Contents.ObjectsSize = 0
    88  	p.Contents.ObjectsOffset = uint32(0x10 + p.WriteHead)
    89  
    90  	buff := make([]byte, unsafe.Sizeof(p.Contents))
    91  	internal.Memcpy(unsafe.Pointer(&buff[0]), unsafe.Pointer(&p.Contents), uintptr(len(buff)))
    92  
    93  	return buff, int(0x10 + p.WriteHead)
    94  }
    95  
    96  func (p *Parcel) WriteInPlace(data []byte) {
    97  	copy(p.Contents.Payload[p.WriteHead:], data)
    98  	p.WriteHead += (len(data) + 3) & int(^3) // Alignment
    99  }
   100  
   101  func (p *Parcel) WriteInPlaceU16(data []uint16) {
   102  	internal.Memcpy(unsafe.Pointer(&p.Contents.Payload[p.WriteHead]), unsafe.Pointer(&data[0]), uintptr(len(data)*2))
   103  	dLen := len(data) * 2
   104  	p.WriteHead += (dLen + 3) & int(^3) // Alignment
   105  }
   106  
   107  func (p *Parcel) WriteInPlaceU32(data []uint32) {
   108  	internal.Memcpy(unsafe.Pointer(&p.Contents.Payload[p.WriteHead]), unsafe.Pointer(&data[0]), uintptr(len(data)*4))
   109  	dLen := len(data) * 4
   110  	p.WriteHead += (dLen + 3) & int(^3) // Alignment
   111  }
   112  
   113  func (p *Parcel) WriteU32(v uint32) {
   114  	p.Contents.Payload[p.WriteHead] = byte(v)
   115  	p.Contents.Payload[p.WriteHead+1] = byte(v >> 8)
   116  	p.Contents.Payload[p.WriteHead+2] = byte(v >> 16)
   117  	p.Contents.Payload[p.WriteHead+3] = byte(v >> 24)
   118  	p.WriteHead += 4
   119  }
   120  
   121  func (p *Parcel) WriteString16(data string) {
   122  	strlen := len(data)
   123  	p.WriteU32(uint32(strlen))
   124  	b := make([]uint16, strlen+1)
   125  	for i, v := range data {
   126  		b[i] = uint16(v)
   127  	}
   128  	p.WriteInPlaceU16(b)
   129  }
   130  
   131  func (p *Parcel) WriteInterfaceToken(token string) {
   132  	p.WriteU32(0x100)
   133  	p.WriteString16(token)
   134  }
   135  
   136  func ParcelLoad(flattened []byte) (*Parcel, error) {
   137  	p := &Parcel{}
   138  	p.Contents.DataSize = binary.LittleEndian.Uint32(flattened[0:4])
   139  	p.Contents.DataOffset = binary.LittleEndian.Uint32(flattened[4:8])
   140  	p.Contents.ObjectsSize = binary.LittleEndian.Uint32(flattened[8:12])
   141  	p.Contents.ObjectsOffset = binary.LittleEndian.Uint32(flattened[12:16])
   142  
   143  	if p.Contents.DataSize > 0x200 { // bigger than payload
   144  		return nil, nxerrors.ParcelDataTooBig
   145  	}
   146  
   147  	copy(p.Contents.Payload[:], flattened[p.Contents.DataOffset:])
   148  
   149  	p.WriteHead = int(p.Contents.DataSize)
   150  	p.ReadHead = 0
   151  	p.WritingFinalized = true
   152  
   153  	return p, nil
   154  }