github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/decoder/string.go (about) 1 package decoder 2 3 import ( 4 "reflect" 5 "unsafe" 6 7 "github.com/trim21/go-phpserialize/internal/errors" 8 ) 9 10 type stringDecoder struct { 11 structName string 12 fieldName string 13 } 14 15 func newStringDecoder(structName, fieldName string) *stringDecoder { 16 return &stringDecoder{ 17 structName: structName, 18 fieldName: fieldName, 19 } 20 } 21 22 func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *errors.UnmarshalTypeError { 23 return &errors.UnmarshalTypeError{ 24 Value: typeName, 25 Type: reflect.TypeOf(""), 26 Offset: offset, 27 Struct: d.structName, 28 Field: d.fieldName, 29 } 30 } 31 32 func (d *stringDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { 33 bytes, c, err := d.decodeByte(ctx.Buf, cursor) 34 if err != nil { 35 return 0, err 36 } 37 if bytes == nil { 38 return c, nil 39 } 40 cursor = c 41 **(**string)(unsafe.Pointer(&p)) = *(*string)(unsafe.Pointer(&bytes)) 42 return cursor, nil 43 } 44 45 var ( 46 hexToInt = [256]int{ 47 '0': 0, 48 '1': 1, 49 '2': 2, 50 '3': 3, 51 '4': 4, 52 '5': 5, 53 '6': 6, 54 '7': 7, 55 '8': 8, 56 '9': 9, 57 'A': 10, 58 'B': 11, 59 'C': 12, 60 'D': 13, 61 'E': 14, 62 'F': 15, 63 'a': 10, 64 'b': 11, 65 'c': 12, 66 'd': 13, 67 'e': 14, 68 'f': 15, 69 } 70 ) 71 72 func unicodeToRune(code []byte) rune { 73 var r rune 74 for i := 0; i < len(code); i++ { 75 r = r*16 + rune(hexToInt[code[i]]) 76 } 77 return r 78 } 79 80 func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { 81 switch buf[cursor] { 82 case 'n': 83 if err := validateNull(buf, cursor); err != nil { 84 return nil, 0, err 85 } 86 cursor += 2 87 return nil, cursor, nil 88 case 'b': 89 return nil, 0, d.errUnmarshalType("bool", cursor) 90 case 'd': 91 return nil, 0, d.errUnmarshalType("float", cursor) 92 case 's': 93 cursor++ 94 break 95 case 'i': 96 return nil, 0, d.errUnmarshalType("number", cursor) 97 // read int as string 98 default: 99 return nil, 0, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) 100 } 101 102 s, end, err := readString(buf, cursor) 103 if err != nil { 104 return nil, 0, err 105 } 106 107 return s, end, nil 108 }