go-json/decode_stream.go

201 lines
3.5 KiB
Go
Raw Normal View History

2020-05-24 15:31:10 +03:00
package json
import (
"bytes"
"io"
)
const (
2020-07-31 12:08:21 +03:00
readChunkSize = 512
2020-05-24 15:31:10 +03:00
)
type stream struct {
2020-08-14 11:59:49 +03:00
buf []byte
length int64
r io.Reader
offset int64
cursor int64
allRead bool
useNumber bool
disallowUnknownFields bool
2020-05-24 15:31:10 +03:00
}
func (s *stream) buffered() io.Reader {
return bytes.NewReader(s.buf[s.cursor:])
}
func (s *stream) totalOffset() int64 {
return s.offset + s.cursor
}
2020-07-30 16:41:53 +03:00
func (s *stream) prevChar() byte {
return s.buf[s.cursor-1]
}
2020-05-24 15:31:10 +03:00
func (s *stream) char() byte {
return s.buf[s.cursor]
}
2020-07-30 16:41:53 +03:00
func (s *stream) end() bool {
return s.allRead && s.length <= s.cursor
}
func (s *stream) progressN(n int64) bool {
if s.cursor+n < s.length-1 || s.read() {
s.cursor += n
return true
}
s.cursor = s.length
return false
}
func (s *stream) reset() {
s.buf = s.buf[s.cursor:]
s.length -= s.cursor
s.cursor = 0
}
2020-05-24 15:31:10 +03:00
func (s *stream) read() bool {
2020-07-31 06:22:00 +03:00
if s.allRead {
return false
}
2020-05-24 15:31:10 +03:00
buf := make([]byte, readChunkSize)
n, err := s.r.Read(buf)
2020-07-30 16:41:53 +03:00
if err != nil && err != io.EOF {
2020-05-24 15:31:10 +03:00
return false
}
2020-07-31 06:22:00 +03:00
if n < readChunkSize || err == io.EOF {
2020-07-30 16:41:53 +03:00
s.allRead = true
2020-07-31 06:22:00 +03:00
}
totalSize := s.length + int64(n) + 1
if totalSize > readChunkSize {
newBuf := make([]byte, totalSize)
copy(newBuf, s.buf)
copy(newBuf[s.length:], buf)
s.buf = newBuf
2020-07-31 14:24:39 +03:00
s.length = totalSize - 1
} else if s.length > 0 {
copy(buf[s.length:], buf)
copy(buf, s.buf[:s.length])
s.buf = buf
s.length = totalSize - 1
2020-07-31 06:22:00 +03:00
} else {
s.buf = buf
2020-07-31 14:24:39 +03:00
s.length = totalSize - 1
2020-07-31 06:22:00 +03:00
}
s.offset += s.cursor
if n == 0 {
2020-07-30 16:41:53 +03:00
return false
}
2020-05-24 15:31:10 +03:00
return true
}
2020-07-30 16:41:53 +03:00
func (s *stream) skipWhiteSpace() {
LOOP:
c := s.char()
if isWhiteSpace[c] {
2020-07-31 11:10:03 +03:00
s.cursor++
2020-07-30 16:41:53 +03:00
goto LOOP
} else if c == nul {
2020-07-31 11:10:03 +03:00
if s.read() {
goto LOOP
}
2020-07-30 16:41:53 +03:00
}
}
func (s *stream) skipValue() error {
s.skipWhiteSpace()
braceCount := 0
bracketCount := 0
for {
switch s.char() {
2020-07-31 11:10:03 +03:00
case nul:
if s.read() {
continue
}
return errUnexpectedEndOfJSON("value of object", s.totalOffset())
2020-07-30 16:41:53 +03:00
case '{':
braceCount++
case '[':
bracketCount++
case '}':
braceCount--
if braceCount == -1 && bracketCount == 0 {
return nil
}
case ']':
bracketCount--
case ',':
if bracketCount == 0 && braceCount == 0 {
return nil
}
case '"':
2020-07-31 11:10:03 +03:00
for {
s.cursor++
c := s.char()
if c == nul {
2020-07-31 11:10:03 +03:00
if !s.read() {
return errUnexpectedEndOfJSON("value of string", s.totalOffset())
}
c = s.char()
2020-07-31 11:10:03 +03:00
}
if c != '"' {
2020-07-30 16:41:53 +03:00
continue
}
if s.prevChar() == '\\' {
continue
}
if bracketCount == 0 && braceCount == 0 {
2020-07-31 11:10:03 +03:00
s.cursor++
2020-07-30 16:41:53 +03:00
return nil
}
break
}
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
2020-07-31 11:10:03 +03:00
for {
s.cursor++
c := s.char()
if floatTable[c] {
2020-07-30 16:41:53 +03:00
continue
} else if c == nul {
2020-07-31 11:10:03 +03:00
if s.read() {
s.cursor-- // for retry current character
2020-07-31 11:10:03 +03:00
continue
}
2020-07-30 16:41:53 +03:00
}
break
}
if bracketCount == 0 && braceCount == 0 {
return nil
}
continue
2020-07-31 14:24:39 +03:00
case 't':
if err := trueBytes(s); err != nil {
return err
}
if bracketCount == 0 && braceCount == 0 {
return nil
}
continue
case 'f':
if err := falseBytes(s); err != nil {
return err
}
if bracketCount == 0 && braceCount == 0 {
return nil
}
continue
case 'n':
if err := nullBytes(s); err != nil {
return err
}
if bracketCount == 0 && braceCount == 0 {
return nil
}
continue
2020-07-30 16:41:53 +03:00
}
2020-07-31 11:10:03 +03:00
s.cursor++
2020-07-30 16:41:53 +03:00
}
return errUnexpectedEndOfJSON("value of object", s.offset)
}