github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/decoder/array.go (about)

     1  package decoder
     2  
     3  import (
     4  	"unsafe"
     5  
     6  	"github.com/trim21/go-phpserialize/internal/errors"
     7  	"github.com/trim21/go-phpserialize/internal/runtime"
     8  )
     9  
    10  type arrayDecoder struct {
    11  	elemType     *runtime.Type
    12  	size         uintptr
    13  	valueDecoder Decoder
    14  	alen         int
    15  	structName   string
    16  	fieldName    string
    17  	zeroValue    unsafe.Pointer
    18  }
    19  
    20  func newArrayDecoder(dec Decoder, elemType *runtime.Type, alen int, structName, fieldName string) *arrayDecoder {
    21  	zeroValue := *(*unsafe.Pointer)(unsafe_New(elemType))
    22  	return &arrayDecoder{
    23  		valueDecoder: dec,
    24  		elemType:     elemType,
    25  		size:         elemType.Size(),
    26  		alen:         alen,
    27  		structName:   structName,
    28  		fieldName:    fieldName,
    29  		zeroValue:    zeroValue,
    30  	}
    31  }
    32  
    33  func (d *arrayDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
    34  	buf := ctx.Buf
    35  	depth++
    36  	if depth > maxDecodeNestingDepth {
    37  		return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
    38  	}
    39  
    40  	switch buf[cursor] {
    41  	case 'N':
    42  		if err := validateNull(buf, cursor); err != nil {
    43  			return 0, err
    44  		}
    45  		cursor += 2
    46  		return cursor, nil
    47  	case 'a':
    48  		cursor++
    49  		if buf[cursor] != ':' {
    50  			return cursor, errors.ErrExpected("':' before array length", cursor)
    51  		}
    52  
    53  		// set zero value first, php array may skip some index
    54  		for i := 0; i < d.alen; i++ {
    55  			*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(i)*d.size)) = d.zeroValue
    56  		}
    57  
    58  		cursor++
    59  		if buf[cursor] == '0' {
    60  			err := validateEmptyArray(buf, cursor)
    61  			if err != nil {
    62  				return cursor, err
    63  			}
    64  			return cursor + 4, nil
    65  		}
    66  
    67  		_, end, err := readLengthInt(buf, cursor-1)
    68  		if err != nil {
    69  			return cursor, err
    70  		}
    71  		cursor = end + 1
    72  
    73  		idx := 0
    74  		for {
    75  			currentIndex, end, err := readInt(buf, cursor)
    76  			if err != nil {
    77  				return 0, err
    78  			}
    79  
    80  			idx = currentIndex
    81  			cursor = end
    82  
    83  			if idx < d.alen {
    84  				c, err := d.valueDecoder.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size))
    85  				if err != nil {
    86  					return 0, err
    87  				}
    88  				cursor = c
    89  			} else {
    90  				c, err := skipValue(buf, cursor, depth)
    91  				if err != nil {
    92  					return 0, err
    93  				}
    94  				cursor = c
    95  			}
    96  
    97  			if buf[cursor] == '}' {
    98  				cursor++
    99  				return cursor, nil
   100  			}
   101  		}
   102  	default:
   103  		return 0, errors.ErrUnexpectedEnd("array", cursor)
   104  	}
   105  }