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 }