diff options
| author | 2025-05-22 16:27:55 +0200 | |
|---|---|---|
| committer | 2025-05-22 16:27:55 +0200 | |
| commit | b6ff55662e0281c0d6e111f9307625ef695df2fa (patch) | |
| tree | 5f7761efa0b51a7a7d56f96fce3681c8e9b66fe9 /vendor/github.com/tinylib/msgp/msgp/read_bytes.go | |
| parent | [chore/woodpecker] don't make `test` depend on `lint` (#4189) (diff) | |
| download | gotosocial-b6ff55662e0281c0d6e111f9307625ef695df2fa.tar.xz | |
[chore] update dependencies (#4188)
Update dependencies:
- github.com/gin-gonic/gin v1.10.0 -> v1.10.1
- github.com/gin-contrib/sessions v1.10.3 -> v1.10.4
- github.com/jackc/pgx/v5 v5.7.4 -> v5.7.5
- github.com/minio/minio-go/v7 v7.0.91 -> v7.0.92
- github.com/pquerna/otp v1.4.0 -> v1.5.0
- github.com/tdewolff/minify/v2 v2.23.5 -> v2.23.8
- github.com/yuin/goldmark v1.7.11 -> v1.7.12
- go.opentelemetry.io/otel{,/*} v1.35.0 -> v1.36.0
- modernc.org/sqlite v1.37.0 -> v1.37.1
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4188
Reviewed-by: Daenney <daenney@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
Diffstat (limited to 'vendor/github.com/tinylib/msgp/msgp/read_bytes.go')
| -rw-r--r-- | vendor/github.com/tinylib/msgp/msgp/read_bytes.go | 1393 |
1 files changed, 1393 insertions, 0 deletions
diff --git a/vendor/github.com/tinylib/msgp/msgp/read_bytes.go b/vendor/github.com/tinylib/msgp/msgp/read_bytes.go new file mode 100644 index 000000000..8ed15a968 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/msgp/read_bytes.go @@ -0,0 +1,1393 @@ +package msgp + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "math" + "strconv" + "time" +) + +var big = binary.BigEndian + +// NextType returns the type of the next +// object in the slice. If the length +// of the input is zero, it returns +// [InvalidType]. +func NextType(b []byte) Type { + if len(b) == 0 { + return InvalidType + } + spec := getBytespec(b[0]) + t := spec.typ + if t == ExtensionType && len(b) > int(spec.size) { + var tp int8 + if spec.extra == constsize { + tp = int8(b[1]) + } else { + tp = int8(b[spec.size-1]) + } + switch tp { + case TimeExtension, MsgTimeExtension: + return TimeType + case Complex128Extension: + return Complex128Type + case Complex64Extension: + return Complex64Type + default: + return ExtensionType + } + } + return t +} + +// IsNil returns true if len(b)>0 and +// the leading byte is a 'nil' MessagePack +// byte; false otherwise +func IsNil(b []byte) bool { + if len(b) != 0 && b[0] == mnil { + return true + } + return false +} + +// Raw is raw MessagePack. +// Raw allows you to read and write +// data without interpreting its contents. +type Raw []byte + +// MarshalMsg implements [Marshaler]. +// It appends the raw contents of 'raw' +// to the provided byte slice. If 'raw' +// is 0 bytes, 'nil' will be appended instead. +func (r Raw) MarshalMsg(b []byte) ([]byte, error) { + i := len(r) + if i == 0 { + return AppendNil(b), nil + } + o, l := ensure(b, i) + copy(o[l:], []byte(r)) + return o, nil +} + +// UnmarshalMsg implements [Unmarshaler]. +// It sets the contents of *Raw to be the next +// object in the provided byte slice. +func (r *Raw) UnmarshalMsg(b []byte) ([]byte, error) { + l := len(b) + out, err := Skip(b) + if err != nil { + return b, err + } + rlen := l - len(out) + if IsNil(b[:rlen]) { + rlen = 0 + } + if cap(*r) < rlen { + *r = make(Raw, rlen) + } else { + *r = (*r)[0:rlen] + } + copy(*r, b[:rlen]) + return out, nil +} + +// EncodeMsg implements [Encodable]. +// It writes the raw bytes to the writer. +// If r is empty, it writes 'nil' instead. +func (r Raw) EncodeMsg(w *Writer) error { + if len(r) == 0 { + return w.WriteNil() + } + _, err := w.Write([]byte(r)) + return err +} + +// DecodeMsg implements [Decodable]. +// It sets the value of *Raw to be the +// next object on the wire. +func (r *Raw) DecodeMsg(f *Reader) error { + *r = (*r)[:0] + err := appendNext(f, (*[]byte)(r)) + if IsNil(*r) { + *r = (*r)[:0] + } + return err +} + +// Msgsize implements [Sizer]. +func (r Raw) Msgsize() int { + l := len(r) + if l == 0 { + return 1 // for 'nil' + } + return l +} + +func appendNext(f *Reader, d *[]byte) error { + amt, o, err := getNextSize(f.R) + if err != nil { + return err + } + var i int + *d, i = ensure(*d, int(amt)) + _, err = f.R.ReadFull((*d)[i:]) + if err != nil { + return err + } + for o > 0 { + err = appendNext(f, d) + if err != nil { + return err + } + o-- + } + return nil +} + +// MarshalJSON implements [json.Marshaler]. +func (r *Raw) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + _, err := UnmarshalAsJSON(&buf, []byte(*r)) + return buf.Bytes(), err +} + +// ReadMapHeaderBytes reads a map header size +// from 'b' and returns the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a map) +func ReadMapHeaderBytes(b []byte) (sz uint32, o []byte, err error) { + l := len(b) + if l < 1 { + err = ErrShortBytes + return + } + + lead := b[0] + b = b[1:] + if isfixmap(lead) { + sz = uint32(rfixmap(lead)) + o = b + return + } + + switch lead { + case mmap16: + if len(b) < 2 { + err = ErrShortBytes + return + } + sz = uint32(big.Uint16(b)) + o = b[2:] + return + + case mmap32: + if len(b) < 4 { + err = ErrShortBytes + return + } + sz = big.Uint32(b) + o = b[4:] + return + + default: + err = badPrefix(MapType, lead) + return + } +} + +// ReadMapKeyZC attempts to read a map key +// from 'b' and returns the key bytes and the remaining bytes +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a str or bin) +func ReadMapKeyZC(b []byte) ([]byte, []byte, error) { + o, x, err := ReadStringZC(b) + if err != nil { + if tperr, ok := err.(TypeError); ok && tperr.Encoded == BinType { + return ReadBytesZC(b) + } + return nil, b, err + } + return o, x, nil +} + +// ReadArrayHeaderBytes attempts to read +// the array header size off of 'b' and return +// the size and remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not an array) +func ReadArrayHeaderBytes(b []byte) (sz uint32, o []byte, err error) { + if len(b) < 1 { + return 0, nil, ErrShortBytes + } + lead := b[0] + b = b[1:] + if isfixarray(lead) { + sz = uint32(rfixarray(lead)) + o = b + return + } + + switch lead { + case marray16: + if len(b) < 2 { + err = ErrShortBytes + return + } + sz = uint32(big.Uint16(b)) + o = b[2:] + return + + case marray32: + if len(b) < 4 { + err = ErrShortBytes + return + } + sz = big.Uint32(b) + o = b[4:] + return + + default: + err = badPrefix(ArrayType, lead) + return + } +} + +// ReadBytesHeader reads the 'bin' header size +// off of 'b' and returns the size and remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a bin object) +func ReadBytesHeader(b []byte) (sz uint32, o []byte, err error) { + if len(b) < 1 { + return 0, nil, ErrShortBytes + } + switch b[0] { + case mbin8: + if len(b) < 2 { + err = ErrShortBytes + return + } + sz = uint32(b[1]) + o = b[2:] + return + case mbin16: + if len(b) < 3 { + err = ErrShortBytes + return + } + sz = uint32(big.Uint16(b[1:])) + o = b[3:] + return + case mbin32: + if len(b) < 5 { + err = ErrShortBytes + return + } + sz = big.Uint32(b[1:]) + o = b[5:] + return + default: + err = badPrefix(BinType, b[0]) + return + } +} + +// ReadNilBytes tries to read a "nil" byte +// off of 'b' and return the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a 'nil') +// - [InvalidPrefixError] +func ReadNilBytes(b []byte) ([]byte, error) { + if len(b) < 1 { + return nil, ErrShortBytes + } + if b[0] != mnil { + return b, badPrefix(NilType, b[0]) + } + return b[1:], nil +} + +// ReadFloat64Bytes tries to read a float64 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a float64) +func ReadFloat64Bytes(b []byte) (f float64, o []byte, err error) { + if len(b) < 9 { + if len(b) >= 5 && b[0] == mfloat32 { + var tf float32 + tf, o, err = ReadFloat32Bytes(b) + f = float64(tf) + return + } + err = ErrShortBytes + return + } + + if b[0] != mfloat64 { + if b[0] == mfloat32 { + var tf float32 + tf, o, err = ReadFloat32Bytes(b) + f = float64(tf) + return + } + err = badPrefix(Float64Type, b[0]) + return + } + + f = math.Float64frombits(getMuint64(b)) + o = b[9:] + return +} + +// ReadFloat32Bytes tries to read a float32 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a float32) +func ReadFloat32Bytes(b []byte) (f float32, o []byte, err error) { + if len(b) < 5 { + err = ErrShortBytes + return + } + + if b[0] != mfloat32 { + err = TypeError{Method: Float32Type, Encoded: getType(b[0])} + return + } + + f = math.Float32frombits(getMuint32(b)) + o = b[5:] + return +} + +// ReadBoolBytes tries to read a bool +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a bool) +func ReadBoolBytes(b []byte) (bool, []byte, error) { + if len(b) < 1 { + return false, b, ErrShortBytes + } + switch b[0] { + case mtrue: + return true, b[1:], nil + case mfalse: + return false, b[1:], nil + default: + return false, b, badPrefix(BoolType, b[0]) + } +} + +// ReadDurationBytes tries to read a time.Duration +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - TypeError (not a int) +func ReadDurationBytes(b []byte) (d time.Duration, o []byte, err error) { + i, o, err := ReadInt64Bytes(b) + return time.Duration(i), o, err +} + +// ReadInt64Bytes tries to read an int64 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a int) +func ReadInt64Bytes(b []byte) (i int64, o []byte, err error) { + if len(b) < 1 { + return 0, nil, ErrShortBytes + } + + lead := b[0] + b = b[1:] + if isfixint(lead) { + i = int64(rfixint(lead)) + o = b + return + } + if isnfixint(lead) { + i = int64(rnfixint(lead)) + o = b + return + } + + switch lead { + case mint8: + if len(b) < 1 { + err = ErrShortBytes + return + } + i = int64(int8(b[0])) + o = b[1:] + return + + case muint8: + if len(b) < 1 { + err = ErrShortBytes + return + } + i = int64(b[0]) + o = b[1:] + return + + case mint16: + if len(b) < 2 { + err = ErrShortBytes + return + } + i = int64(int16(big.Uint16(b))) + o = b[2:] + return + + case muint16: + if len(b) < 2 { + err = ErrShortBytes + return + } + i = int64(big.Uint16(b)) + o = b[2:] + return + + case mint32: + if len(b) < 4 { + err = ErrShortBytes + return + } + i = int64(int32(big.Uint32(b))) + o = b[4:] + return + + case muint32: + if len(b) < 4 { + err = ErrShortBytes + return + } + i = int64(big.Uint32(b)) + o = b[4:] + return + + case mint64: + if len(b) < 8 { + err = ErrShortBytes + return + } + i = int64(big.Uint64(b)) + o = b[8:] + return + + case muint64: + if len(b) < 8 { + err = ErrShortBytes + return + } + u := big.Uint64(b) + if u > math.MaxInt64 { + err = UintOverflow{Value: u, FailedBitsize: 64} + return + } + i = int64(u) + o = b[8:] + return + + default: + err = badPrefix(IntType, lead) + return + } +} + +// ReadInt32Bytes tries to read an int32 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a int) +// - [IntOverflow] (value doesn't fit in int32) +func ReadInt32Bytes(b []byte) (int32, []byte, error) { + i, o, err := ReadInt64Bytes(b) + if i > math.MaxInt32 || i < math.MinInt32 { + return 0, o, IntOverflow{Value: i, FailedBitsize: 32} + } + return int32(i), o, err +} + +// ReadInt16Bytes tries to read an int16 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a int) +// - [IntOverflow] (value doesn't fit in int16) +func ReadInt16Bytes(b []byte) (int16, []byte, error) { + i, o, err := ReadInt64Bytes(b) + if i > math.MaxInt16 || i < math.MinInt16 { + return 0, o, IntOverflow{Value: i, FailedBitsize: 16} + } + return int16(i), o, err +} + +// ReadInt8Bytes tries to read an int16 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a int) +// - [IntOverflow] (value doesn't fit in int8) +func ReadInt8Bytes(b []byte) (int8, []byte, error) { + i, o, err := ReadInt64Bytes(b) + if i > math.MaxInt8 || i < math.MinInt8 { + return 0, o, IntOverflow{Value: i, FailedBitsize: 8} + } + return int8(i), o, err +} + +// ReadIntBytes tries to read an int +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a int) +// - [IntOverflow] (value doesn't fit in int; 32-bit platforms only) +func ReadIntBytes(b []byte) (int, []byte, error) { + if smallint { + i, b, err := ReadInt32Bytes(b) + return int(i), b, err + } + i, b, err := ReadInt64Bytes(b) + return int(i), b, err +} + +// ReadUint64Bytes tries to read a uint64 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a uint) +func ReadUint64Bytes(b []byte) (u uint64, o []byte, err error) { + if len(b) < 1 { + return 0, nil, ErrShortBytes + } + + lead := b[0] + b = b[1:] + if isfixint(lead) { + u = uint64(rfixint(lead)) + o = b + return + } + + switch lead { + case mint8: + if len(b) < 1 { + err = ErrShortBytes + return + } + v := int64(int8(b[0])) + if v < 0 { + err = UintBelowZero{Value: v} + return + } + u = uint64(v) + o = b[1:] + return + + case muint8: + if len(b) < 1 { + err = ErrShortBytes + return + } + u = uint64(b[0]) + o = b[1:] + return + + case mint16: + if len(b) < 2 { + err = ErrShortBytes + return + } + v := int64((int16(b[0]) << 8) | int16(b[1])) + if v < 0 { + err = UintBelowZero{Value: v} + return + } + u = uint64(v) + o = b[2:] + return + + case muint16: + if len(b) < 2 { + err = ErrShortBytes + return + } + u = uint64(big.Uint16(b)) + o = b[2:] + return + + case mint32: + if len(b) < 4 { + err = ErrShortBytes + return + } + v := int64(int32(big.Uint32(b))) + if v < 0 { + err = UintBelowZero{Value: v} + return + } + u = uint64(v) + o = b[4:] + return + + case muint32: + if len(b) < 4 { + err = ErrShortBytes + return + } + u = uint64(big.Uint32(b)) + o = b[4:] + return + + case mint64: + if len(b) < 8 { + err = ErrShortBytes + return + } + v := int64(big.Uint64(b)) + if v < 0 { + err = UintBelowZero{Value: v} + return + } + u = uint64(v) + o = b[8:] + return + + case muint64: + if len(b) < 8 { + err = ErrShortBytes + return + } + u = big.Uint64(b) + o = b[8:] + return + + default: + if isnfixint(lead) { + err = UintBelowZero{Value: int64(rnfixint(lead))} + } else { + err = badPrefix(UintType, lead) + } + return + } +} + +// ReadUint32Bytes tries to read a uint32 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a uint) +// - [UintOverflow] (value too large for uint32) +func ReadUint32Bytes(b []byte) (uint32, []byte, error) { + v, o, err := ReadUint64Bytes(b) + if v > math.MaxUint32 { + return 0, nil, UintOverflow{Value: v, FailedBitsize: 32} + } + return uint32(v), o, err +} + +// ReadUint16Bytes tries to read a uint16 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a uint) +// - [UintOverflow] (value too large for uint16) +func ReadUint16Bytes(b []byte) (uint16, []byte, error) { + v, o, err := ReadUint64Bytes(b) + if v > math.MaxUint16 { + return 0, nil, UintOverflow{Value: v, FailedBitsize: 16} + } + return uint16(v), o, err +} + +// ReadUint8Bytes tries to read a uint8 +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a uint) +// - [UintOverflow] (value too large for uint8) +func ReadUint8Bytes(b []byte) (uint8, []byte, error) { + v, o, err := ReadUint64Bytes(b) + if v > math.MaxUint8 { + return 0, nil, UintOverflow{Value: v, FailedBitsize: 8} + } + return uint8(v), o, err +} + +// ReadUintBytes tries to read a uint +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a uint) +// - [UintOverflow] (value too large for uint; 32-bit platforms only) +func ReadUintBytes(b []byte) (uint, []byte, error) { + if smallint { + u, b, err := ReadUint32Bytes(b) + return uint(u), b, err + } + u, b, err := ReadUint64Bytes(b) + return uint(u), b, err +} + +// ReadByteBytes is analogous to ReadUint8Bytes +func ReadByteBytes(b []byte) (byte, []byte, error) { + return ReadUint8Bytes(b) +} + +// ReadBytesBytes reads a 'bin' object +// from 'b' and returns its vaue and +// the remaining bytes in 'b'. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - [TypeError] (not a 'bin' object) +func ReadBytesBytes(b []byte, scratch []byte) (v []byte, o []byte, err error) { + return readBytesBytes(b, scratch, false) +} + +func readBytesBytes(b []byte, scratch []byte, zc bool) (v []byte, o []byte, err error) { + l := len(b) + if l < 1 { + return nil, nil, ErrShortBytes + } + + lead := b[0] + b = b[1:] + var read int + switch lead { + case mbin8: + if len(b) < 1 { + err = ErrShortBytes + return + } + + read = int(b[0]) + b = b[1:] + + case mbin16: + if len(b) < 2 { + err = ErrShortBytes + return + } + read = int(big.Uint16(b)) + b = b[2:] + + case mbin32: + if len(b) < 4 { + err = ErrShortBytes + return + } + read = int(big.Uint32(b)) + b = b[4:] + + default: + err = badPrefix(BinType, lead) + return + } + + if len(b) < read { + err = ErrShortBytes + return + } + + // zero-copy + if zc { + v = b[0:read] + o = b[read:] + return + } + + if cap(scratch) >= read { + v = scratch[0:read] + } else { + v = make([]byte, read) + } + + o = b[copy(v, b):] + return +} + +// ReadBytesZC extracts the messagepack-encoded +// binary field without copying. The returned []byte +// points to the same memory as the input slice. +// +// Possible errors: +// +// - [ErrShortBytes] (b not long enough) +// - [TypeError] (object not 'bin') +func ReadBytesZC(b []byte) (v []byte, o []byte, err error) { + return readBytesBytes(b, nil, true) +} + +func ReadExactBytes(b []byte, into []byte) (o []byte, err error) { + if len(b) < 1 { + err = ErrShortBytes + return + } + + lead := b[0] + var read uint32 + b = b[1:] + switch lead { + case mbin8: + if len(b) < 1 { + err = ErrShortBytes + return + } + + read = uint32(b[0]) + b = b[1:] + + case mbin16: + if len(b) < 2 { + err = ErrShortBytes + return + } + read = uint32(big.Uint16(b)) + b = b[2:] + + case mbin32: + if len(b) < 4 { + err = ErrShortBytes + return + } + read = big.Uint32(b) + b = b[4:] + + default: + err = badPrefix(BinType, lead) + return + } + + if read != uint32(len(into)) { + err = ArrayError{Wanted: uint32(len(into)), Got: read} + return + } + + o = b[copy(into, b):] + return +} + +// ReadStringZC reads a messagepack string field +// without copying. The returned []byte points +// to the same memory as the input slice. +// +// Possible errors: +// +// - [ErrShortBytes] (b not long enough) +// - [TypeError] (object not 'str') +func ReadStringZC(b []byte) (v []byte, o []byte, err error) { + if len(b) < 1 { + return nil, nil, ErrShortBytes + } + + lead := b[0] + var read int + + b = b[1:] + if isfixstr(lead) { + read = int(rfixstr(lead)) + } else { + switch lead { + case mstr8: + if len(b) < 1 { + err = ErrShortBytes + return + } + read = int(b[0]) + b = b[1:] + + case mstr16: + if len(b) < 2 { + err = ErrShortBytes + return + } + read = int(big.Uint16(b)) + b = b[2:] + + case mstr32: + if len(b) < 4 { + err = ErrShortBytes + return + } + read = int(big.Uint32(b)) + b = b[4:] + + default: + err = TypeError{Method: StrType, Encoded: getType(lead)} + return + } + } + + if len(b) < read { + err = ErrShortBytes + return + } + + v = b[0:read] + o = b[read:] + return +} + +// ReadStringBytes reads a 'str' object +// from 'b' and returns its value and the +// remaining bytes in 'b'. +// +// Possible errors: +// +// - [ErrShortBytes] (b not long enough) +// - [TypeError] (not 'str' type) +// - [InvalidPrefixError] +func ReadStringBytes(b []byte) (string, []byte, error) { + v, o, err := ReadStringZC(b) + return string(v), o, err +} + +// ReadStringAsBytes reads a 'str' object +// into a slice of bytes. 'v' is the value of +// the 'str' object, which may reside in memory +// pointed to by 'scratch.' 'o' is the remaining bytes +// in 'b'. +// +// Possible errors: +// +// - [ErrShortBytes] (b not long enough) +// - [TypeError] (not 'str' type) +// - [InvalidPrefixError] (unknown type marker) +func ReadStringAsBytes(b []byte, scratch []byte) (v []byte, o []byte, err error) { + var tmp []byte + tmp, o, err = ReadStringZC(b) + v = append(scratch[:0], tmp...) + return +} + +// ReadComplex128Bytes reads a complex128 +// extension object from 'b' and returns the +// remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (not enough bytes in 'b') +// - [TypeError] (object not a complex128) +// - [InvalidPrefixError] +// - [ExtensionTypeError] (object an extension of the correct size, but not a complex128) +func ReadComplex128Bytes(b []byte) (c complex128, o []byte, err error) { + if len(b) < 18 { + err = ErrShortBytes + return + } + if b[0] != mfixext16 { + err = badPrefix(Complex128Type, b[0]) + return + } + if int8(b[1]) != Complex128Extension { + err = errExt(int8(b[1]), Complex128Extension) + return + } + c = complex(math.Float64frombits(big.Uint64(b[2:])), + math.Float64frombits(big.Uint64(b[10:]))) + o = b[18:] + return +} + +// ReadComplex64Bytes reads a complex64 +// extension object from 'b' and returns the +// remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (not enough bytes in 'b') +// - [TypeError] (object not a complex64) +// - [ExtensionTypeError] (object an extension of the correct size, but not a complex64) +func ReadComplex64Bytes(b []byte) (c complex64, o []byte, err error) { + if len(b) < 10 { + err = ErrShortBytes + return + } + if b[0] != mfixext8 { + err = badPrefix(Complex64Type, b[0]) + return + } + if b[1] != Complex64Extension { + err = errExt(int8(b[1]), Complex64Extension) + return + } + c = complex(math.Float32frombits(big.Uint32(b[2:])), + math.Float32frombits(big.Uint32(b[6:]))) + o = b[10:] + return +} + +// ReadTimeUTCBytes does the same as ReadTimeBytes, but returns the value as UTC. +func ReadTimeUTCBytes(b []byte) (t time.Time, o []byte, err error) { + t, o, err = ReadTimeBytes(b) + return t.UTC(), o, err +} + +// ReadTimeBytes reads a time.Time +// extension object from 'b' and returns the +// remaining bytes. +// Both the official and the format in this package will be read. +// +// Possible errors: +// +// - [ErrShortBytes] (not enough bytes in 'b') +// - [TypeError] (object not a time extension 5 or -1) +// - [ExtensionTypeError] (object an extension of the correct size, but not a time.Time) +func ReadTimeBytes(b []byte) (t time.Time, o []byte, err error) { + if len(b) < 6 { + err = ErrShortBytes + return + } + typ, o, b, err := readExt(b) + if err != nil { + return + } + switch typ { + case TimeExtension: + if len(b) != 12 { + err = ErrShortBytes + return + } + sec, nsec := getUnix(b) + t = time.Unix(sec, int64(nsec)).Local() + return + case MsgTimeExtension: + switch len(b) { + case 4: + t = time.Unix(int64(binary.BigEndian.Uint32(b)), 0).Local() + return + case 8: + v := binary.BigEndian.Uint64(b) + nanos := int64(v >> 34) + if nanos > 999999999 { + // In timestamp 64 and timestamp 96 formats, nanoseconds must not be larger than 999999999. + err = InvalidTimestamp{Nanos: nanos} + return + } + t = time.Unix(int64(v&(1<<34-1)), nanos).Local() + return + case 12: + nanos := int64(binary.BigEndian.Uint32(b)) + if nanos > 999999999 { + // In timestamp 64 and timestamp 96 formats, nanoseconds must not be larger than 999999999. + err = InvalidTimestamp{Nanos: nanos} + return + } + ux := int64(binary.BigEndian.Uint64(b[4:])) + t = time.Unix(ux, nanos).Local() + return + default: + err = InvalidTimestamp{FieldLength: len(b)} + return + } + default: + err = errExt(int8(b[2]), TimeExtension) + return + } +} + +// ReadMapStrIntfBytes reads a map[string]interface{} +// out of 'b' and returns the map and remaining bytes. +// If 'old' is non-nil, the values will be read into that map. +func ReadMapStrIntfBytes(b []byte, old map[string]interface{}) (v map[string]interface{}, o []byte, err error) { + return readMapStrIntfBytesDepth(b, old, 0) +} + +func readMapStrIntfBytesDepth(b []byte, old map[string]interface{}, depth int) (v map[string]interface{}, o []byte, err error) { + if depth >= recursionLimit { + err = ErrRecursion + return + } + + var sz uint32 + o = b + sz, o, err = ReadMapHeaderBytes(o) + + if err != nil { + return + } + + if old != nil { + for key := range old { + delete(old, key) + } + v = old + } else { + v = make(map[string]interface{}, int(sz)) + } + + for z := uint32(0); z < sz; z++ { + if len(o) < 1 { + err = ErrShortBytes + return + } + var key []byte + key, o, err = ReadMapKeyZC(o) + if err != nil { + return + } + var val interface{} + val, o, err = readIntfBytesDepth(o, depth) + if err != nil { + return + } + v[string(key)] = val + } + return +} + +// ReadIntfBytes attempts to read +// the next object out of 'b' as a raw interface{} and +// return the remaining bytes. +func ReadIntfBytes(b []byte) (i interface{}, o []byte, err error) { + return readIntfBytesDepth(b, 0) +} + +func readIntfBytesDepth(b []byte, depth int) (i interface{}, o []byte, err error) { + if depth >= recursionLimit { + err = ErrRecursion + return + } + if len(b) < 1 { + err = ErrShortBytes + return + } + + k := NextType(b) + + switch k { + case MapType: + i, o, err = readMapStrIntfBytesDepth(b, nil, depth+1) + return + + case ArrayType: + var sz uint32 + sz, o, err = ReadArrayHeaderBytes(b) + if err != nil { + return + } + j := make([]interface{}, int(sz)) + i = j + for d := range j { + j[d], o, err = readIntfBytesDepth(o, depth+1) + if err != nil { + return + } + } + return + + case Float32Type: + i, o, err = ReadFloat32Bytes(b) + return + + case Float64Type: + i, o, err = ReadFloat64Bytes(b) + return + + case IntType: + i, o, err = ReadInt64Bytes(b) + return + + case UintType: + i, o, err = ReadUint64Bytes(b) + return + + case BoolType: + i, o, err = ReadBoolBytes(b) + return + + case TimeType: + i, o, err = ReadTimeBytes(b) + return + + case Complex64Type: + i, o, err = ReadComplex64Bytes(b) + return + + case Complex128Type: + i, o, err = ReadComplex128Bytes(b) + return + + case ExtensionType: + var t int8 + t, err = peekExtension(b) + if err != nil { + return + } + // use a user-defined extension, + // if it's been registered + f, ok := extensionReg[t] + if ok { + e := f() + o, err = ReadExtensionBytes(b, e) + i = e + return + } + // last resort is a raw extension + e := RawExtension{} + e.Type = int8(t) + o, err = ReadExtensionBytes(b, &e) + i = &e + return + + case NilType: + o, err = ReadNilBytes(b) + return + + case BinType: + i, o, err = ReadBytesBytes(b, nil) + return + + case StrType: + i, o, err = ReadStringBytes(b) + return + + default: + err = InvalidPrefixError(b[0]) + return + } +} + +// Skip skips the next object in 'b' and +// returns the remaining bytes. If the object +// is a map or array, all of its elements +// will be skipped. +// +// Possible errors: +// +// - [ErrShortBytes] (not enough bytes in b) +// - [InvalidPrefixError] (bad encoding) +// - [ErrRecursion] (too deeply nested data) +func Skip(b []byte) ([]byte, error) { + return skipDepth(b, 0) +} + +func skipDepth(b []byte, depth int) ([]byte, error) { + if depth >= recursionLimit { + return b, ErrRecursion + } + sz, asz, err := getSize(b) + if err != nil { + return b, err + } + if uintptr(len(b)) < sz { + return b, ErrShortBytes + } + b = b[sz:] + for asz > 0 { + b, err = skipDepth(b, depth+1) + if err != nil { + return b, err + } + asz-- + } + return b, nil +} + +// returns (skip N bytes, skip M objects, error) +func getSize(b []byte) (uintptr, uintptr, error) { + l := len(b) + if l == 0 { + return 0, 0, ErrShortBytes + } + lead := b[0] + spec := getBytespec(lead) // get type information + size, mode := spec.size, spec.extra + if size == 0 { + return 0, 0, InvalidPrefixError(lead) + } + if mode >= 0 { // fixed composites + return uintptr(size), uintptr(mode), nil + } + if l < int(size) { + return 0, 0, ErrShortBytes + } + switch mode { + case extra8: + return uintptr(size) + uintptr(b[1]), 0, nil + case extra16: + return uintptr(size) + uintptr(big.Uint16(b[1:])), 0, nil + case extra32: + return uintptr(size) + uintptr(big.Uint32(b[1:])), 0, nil + case map16v: + return uintptr(size), 2 * uintptr(big.Uint16(b[1:])), nil + case map32v: + return uintptr(size), 2 * uintptr(big.Uint32(b[1:])), nil + case array16v: + return uintptr(size), uintptr(big.Uint16(b[1:])), nil + case array32v: + return uintptr(size), uintptr(big.Uint32(b[1:])), nil + default: + return 0, 0, fatal + } +} + +// ReadJSONNumberBytes tries to read a number +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - TypeError (not a number (int/float)) +func ReadJSONNumberBytes(b []byte) (number json.Number, o []byte, err error) { + if len(b) < 1 { + return "", nil, ErrShortBytes + } + if i, o, err := ReadInt64Bytes(b); err == nil { + return json.Number(strconv.FormatInt(i, 10)), o, nil + } + f, o, err := ReadFloat64Bytes(b) + if err == nil { + return json.Number(strconv.FormatFloat(f, 'f', -1, 64)), o, nil + } + return "", nil, TypeError{Method: NumberType, Encoded: getType(b[0])} +} |
