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 }