summaryrefslogtreecommitdiff
path: root/vendor/github.com/goccy/go-json/internal/decoder/stream.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/goccy/go-json/internal/decoder/stream.go')
-rw-r--r--vendor/github.com/goccy/go-json/internal/decoder/stream.go556
1 files changed, 556 insertions, 0 deletions
diff --git a/vendor/github.com/goccy/go-json/internal/decoder/stream.go b/vendor/github.com/goccy/go-json/internal/decoder/stream.go
new file mode 100644
index 000000000..a383f7259
--- /dev/null
+++ b/vendor/github.com/goccy/go-json/internal/decoder/stream.go
@@ -0,0 +1,556 @@
+package decoder
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "strconv"
+ "unsafe"
+
+ "github.com/goccy/go-json/internal/errors"
+)
+
+const (
+ initBufSize = 512
+)
+
+type Stream struct {
+ buf []byte
+ bufSize int64
+ length int64
+ r io.Reader
+ offset int64
+ cursor int64
+ filledBuffer bool
+ allRead bool
+ UseNumber bool
+ DisallowUnknownFields bool
+ Option *Option
+}
+
+func NewStream(r io.Reader) *Stream {
+ return &Stream{
+ r: r,
+ bufSize: initBufSize,
+ buf: make([]byte, initBufSize),
+ Option: &Option{},
+ }
+}
+
+func (s *Stream) TotalOffset() int64 {
+ return s.totalOffset()
+}
+
+func (s *Stream) Buffered() io.Reader {
+ buflen := int64(len(s.buf))
+ for i := s.cursor; i < buflen; i++ {
+ if s.buf[i] == nul {
+ return bytes.NewReader(s.buf[s.cursor:i])
+ }
+ }
+ return bytes.NewReader(s.buf[s.cursor:])
+}
+
+func (s *Stream) PrepareForDecode() error {
+ for {
+ switch s.char() {
+ case ' ', '\t', '\r', '\n':
+ s.cursor++
+ continue
+ case ',', ':':
+ s.cursor++
+ return nil
+ case nul:
+ if s.read() {
+ continue
+ }
+ return io.EOF
+ }
+ break
+ }
+ return nil
+}
+
+func (s *Stream) totalOffset() int64 {
+ return s.offset + s.cursor
+}
+
+func (s *Stream) char() byte {
+ return s.buf[s.cursor]
+}
+
+func (s *Stream) equalChar(c byte) bool {
+ cur := s.buf[s.cursor]
+ if cur == nul {
+ s.read()
+ cur = s.buf[s.cursor]
+ }
+ return cur == c
+}
+
+func (s *Stream) stat() ([]byte, int64, unsafe.Pointer) {
+ return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data
+}
+
+func (s *Stream) bufptr() unsafe.Pointer {
+ return (*sliceHeader)(unsafe.Pointer(&s.buf)).data
+}
+
+func (s *Stream) statForRetry() ([]byte, int64, unsafe.Pointer) {
+ s.cursor-- // for retry ( because caller progress cursor position in each loop )
+ return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data
+}
+
+func (s *Stream) Reset() {
+ s.reset()
+ s.bufSize = int64(len(s.buf))
+}
+
+func (s *Stream) More() bool {
+ for {
+ switch s.char() {
+ case ' ', '\n', '\r', '\t':
+ s.cursor++
+ continue
+ case '}', ']':
+ return false
+ case nul:
+ if s.read() {
+ continue
+ }
+ return false
+ }
+ break
+ }
+ return true
+}
+
+func (s *Stream) Token() (interface{}, error) {
+ for {
+ c := s.char()
+ switch c {
+ case ' ', '\n', '\r', '\t':
+ s.cursor++
+ case '{', '[', ']', '}':
+ s.cursor++
+ return json.Delim(c), nil
+ case ',', ':':
+ s.cursor++
+ case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ bytes := floatBytes(s)
+ str := *(*string)(unsafe.Pointer(&bytes))
+ if s.UseNumber {
+ return json.Number(str), nil
+ }
+ f64, err := strconv.ParseFloat(str, 64)
+ if err != nil {
+ return nil, err
+ }
+ return f64, nil
+ case '"':
+ bytes, err := stringBytes(s)
+ if err != nil {
+ return nil, err
+ }
+ return string(bytes), nil
+ case 't':
+ if err := trueBytes(s); err != nil {
+ return nil, err
+ }
+ return true, nil
+ case 'f':
+ if err := falseBytes(s); err != nil {
+ return nil, err
+ }
+ return false, nil
+ case 'n':
+ if err := nullBytes(s); err != nil {
+ return nil, err
+ }
+ return nil, nil
+ case nul:
+ if s.read() {
+ continue
+ }
+ goto END
+ default:
+ return nil, errors.ErrInvalidCharacter(s.char(), "token", s.totalOffset())
+ }
+ }
+END:
+ return nil, io.EOF
+}
+
+func (s *Stream) reset() {
+ s.offset += s.cursor
+ s.buf = s.buf[s.cursor:]
+ s.length -= s.cursor
+ s.cursor = 0
+}
+
+func (s *Stream) readBuf() []byte {
+ if s.filledBuffer {
+ s.bufSize *= 2
+ remainBuf := s.buf
+ s.buf = make([]byte, s.bufSize)
+ copy(s.buf, remainBuf)
+ }
+ remainLen := s.length - s.cursor
+ remainNotNulCharNum := int64(0)
+ for i := int64(0); i < remainLen; i++ {
+ if s.buf[s.cursor+i] == nul {
+ break
+ }
+ remainNotNulCharNum++
+ }
+ s.length = s.cursor + remainNotNulCharNum
+ return s.buf[s.cursor+remainNotNulCharNum:]
+}
+
+func (s *Stream) read() bool {
+ if s.allRead {
+ return false
+ }
+ buf := s.readBuf()
+ last := len(buf) - 1
+ buf[last] = nul
+ n, err := s.r.Read(buf[:last])
+ s.length += int64(n)
+ if n == last {
+ s.filledBuffer = true
+ } else {
+ s.filledBuffer = false
+ }
+ if err == io.EOF {
+ s.allRead = true
+ } else if err != nil {
+ return false
+ }
+ return true
+}
+
+func (s *Stream) skipWhiteSpace() byte {
+ p := s.bufptr()
+LOOP:
+ c := char(p, s.cursor)
+ switch c {
+ case ' ', '\n', '\t', '\r':
+ s.cursor++
+ goto LOOP
+ case nul:
+ if s.read() {
+ p = s.bufptr()
+ goto LOOP
+ }
+ }
+ return c
+}
+
+func (s *Stream) skipObject(depth int64) error {
+ braceCount := 1
+ _, cursor, p := s.stat()
+ for {
+ switch char(p, cursor) {
+ case '{':
+ braceCount++
+ depth++
+ if depth > maxDecodeNestingDepth {
+ return errors.ErrExceededMaxDepth(s.char(), s.cursor)
+ }
+ case '}':
+ braceCount--
+ depth--
+ if braceCount == 0 {
+ s.cursor = cursor + 1
+ return nil
+ }
+ case '[':
+ depth++
+ if depth > maxDecodeNestingDepth {
+ return errors.ErrExceededMaxDepth(s.char(), s.cursor)
+ }
+ case ']':
+ depth--
+ case '"':
+ for {
+ cursor++
+ switch char(p, cursor) {
+ case '\\':
+ cursor++
+ if char(p, cursor) == nul {
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.stat()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
+ }
+ case '"':
+ goto SWITCH_OUT
+ case nul:
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.statForRetry()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
+ }
+ }
+ case nul:
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.stat()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("object of object", cursor)
+ }
+ SWITCH_OUT:
+ cursor++
+ }
+}
+
+func (s *Stream) skipArray(depth int64) error {
+ bracketCount := 1
+ _, cursor, p := s.stat()
+ for {
+ switch char(p, cursor) {
+ case '[':
+ bracketCount++
+ depth++
+ if depth > maxDecodeNestingDepth {
+ return errors.ErrExceededMaxDepth(s.char(), s.cursor)
+ }
+ case ']':
+ bracketCount--
+ depth--
+ if bracketCount == 0 {
+ s.cursor = cursor + 1
+ return nil
+ }
+ case '{':
+ depth++
+ if depth > maxDecodeNestingDepth {
+ return errors.ErrExceededMaxDepth(s.char(), s.cursor)
+ }
+ case '}':
+ depth--
+ case '"':
+ for {
+ cursor++
+ switch char(p, cursor) {
+ case '\\':
+ cursor++
+ if char(p, cursor) == nul {
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.stat()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
+ }
+ case '"':
+ goto SWITCH_OUT
+ case nul:
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.statForRetry()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
+ }
+ }
+ case nul:
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.stat()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("array of object", cursor)
+ }
+ SWITCH_OUT:
+ cursor++
+ }
+}
+
+func (s *Stream) skipValue(depth int64) error {
+ _, cursor, p := s.stat()
+ for {
+ switch char(p, cursor) {
+ case ' ', '\n', '\t', '\r':
+ cursor++
+ continue
+ case nul:
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.stat()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("value of object", s.totalOffset())
+ case '{':
+ s.cursor = cursor + 1
+ return s.skipObject(depth + 1)
+ case '[':
+ s.cursor = cursor + 1
+ return s.skipArray(depth + 1)
+ case '"':
+ for {
+ cursor++
+ switch char(p, cursor) {
+ case '\\':
+ cursor++
+ if char(p, cursor) == nul {
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.stat()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
+ }
+ case '"':
+ s.cursor = cursor + 1
+ return nil
+ case nul:
+ s.cursor = cursor
+ if s.read() {
+ _, cursor, p = s.statForRetry()
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
+ }
+ }
+ case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ for {
+ cursor++
+ c := char(p, cursor)
+ if floatTable[c] {
+ continue
+ } else if c == nul {
+ if s.read() {
+ _, cursor, p = s.stat()
+ continue
+ }
+ }
+ s.cursor = cursor
+ return nil
+ }
+ case 't':
+ s.cursor = cursor
+ if err := trueBytes(s); err != nil {
+ return err
+ }
+ return nil
+ case 'f':
+ s.cursor = cursor
+ if err := falseBytes(s); err != nil {
+ return err
+ }
+ return nil
+ case 'n':
+ s.cursor = cursor
+ if err := nullBytes(s); err != nil {
+ return err
+ }
+ return nil
+ }
+ cursor++
+ }
+}
+
+func nullBytes(s *Stream) error {
+ // current cursor's character is 'n'
+ s.cursor++
+ if s.char() != 'u' {
+ if err := retryReadNull(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ if s.char() != 'l' {
+ if err := retryReadNull(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ if s.char() != 'l' {
+ if err := retryReadNull(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ return nil
+}
+
+func retryReadNull(s *Stream) error {
+ if s.char() == nul && s.read() {
+ return nil
+ }
+ return errors.ErrInvalidCharacter(s.char(), "null", s.totalOffset())
+}
+
+func trueBytes(s *Stream) error {
+ // current cursor's character is 't'
+ s.cursor++
+ if s.char() != 'r' {
+ if err := retryReadTrue(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ if s.char() != 'u' {
+ if err := retryReadTrue(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ if s.char() != 'e' {
+ if err := retryReadTrue(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ return nil
+}
+
+func retryReadTrue(s *Stream) error {
+ if s.char() == nul && s.read() {
+ return nil
+ }
+ return errors.ErrInvalidCharacter(s.char(), "bool(true)", s.totalOffset())
+}
+
+func falseBytes(s *Stream) error {
+ // current cursor's character is 'f'
+ s.cursor++
+ if s.char() != 'a' {
+ if err := retryReadFalse(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ if s.char() != 'l' {
+ if err := retryReadFalse(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ if s.char() != 's' {
+ if err := retryReadFalse(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ if s.char() != 'e' {
+ if err := retryReadFalse(s); err != nil {
+ return err
+ }
+ }
+ s.cursor++
+ return nil
+}
+
+func retryReadFalse(s *Stream) error {
+ if s.char() == nul && s.read() {
+ return nil
+ }
+ return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset())
+}