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  }