github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/decoder/ptr.go (about) 1 package decoder 2 3 import ( 4 "reflect" 5 "unsafe" 6 7 "github.com/trim21/go-phpserialize/internal/errors" 8 "github.com/trim21/go-phpserialize/internal/runtime" 9 ) 10 11 type ptrDecoder struct { 12 dec Decoder 13 typ *runtime.Type 14 structName string 15 fieldName string 16 } 17 18 func newPtrDecoder(dec Decoder, typ *runtime.Type, structName, fieldName string) (Decoder, error) { 19 if typ.Kind() == reflect.Ptr { 20 return nil, &errors.UnsupportedTypeError{ 21 Type: runtime.RType2Type(runtime.PtrTo(typ)), 22 } 23 } 24 return &ptrDecoder{ 25 dec: dec, 26 typ: typ, 27 structName: structName, 28 fieldName: fieldName, 29 }, nil 30 } 31 32 func (d *ptrDecoder) contentDecoder() Decoder { 33 dec, ok := d.dec.(*ptrDecoder) 34 if !ok { 35 return d.dec 36 } 37 return dec.contentDecoder() 38 } 39 40 //nolint:golint 41 //go:linkname unsafe_New reflect.unsafe_New 42 func unsafe_New(*runtime.Type) unsafe.Pointer 43 44 func (d *ptrDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { 45 buf := ctx.Buf 46 if buf[cursor] == 'N' { 47 if err := validateNull(buf, cursor); err != nil { 48 return 0, err 49 } 50 if p != nil { 51 *(*unsafe.Pointer)(p) = nil 52 } 53 cursor += 2 54 return cursor, nil 55 } 56 57 var newptr unsafe.Pointer 58 59 if *(*unsafe.Pointer)(p) == nil { 60 newptr = unsafe_New(d.typ) 61 *(*unsafe.Pointer)(p) = newptr 62 } else { 63 newptr = *(*unsafe.Pointer)(p) 64 } 65 66 c, err := d.dec.Decode(ctx, cursor, depth, newptr) 67 if err != nil { 68 return 0, err 69 } 70 cursor = c 71 return cursor, nil 72 }