github.com/3JoB/go-json@v0.10.4/internal/decoder/stream.go (about)

     1  package decoder
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io"
     7  	"strconv"
     8  	"unsafe"
     9  
    10  	"github.com/3JoB/go-json/internal/errors"
    11  	"github.com/3JoB/unsafeConvert"
    12  )
    13  
    14  const (
    15  	initBufSize = 512
    16  )
    17  
    18  type Stream struct {
    19  	r                     io.Reader
    20  	buf                   []byte
    21  	bufSize               int64
    22  	length                int64
    23  	offset                int64
    24  	cursor                int64
    25  	filledBuffer          bool
    26  	allRead               bool
    27  	UseNumber             bool
    28  	DisallowUnknownFields bool
    29  	Option                *Option
    30  }
    31  
    32  func NewStream(r io.Reader) *Stream {
    33  	return &Stream{
    34  		r:       r,
    35  		bufSize: initBufSize,
    36  		buf:     make([]byte, initBufSize),
    37  		Option:  &Option{},
    38  	}
    39  }
    40  
    41  func (s *Stream) TotalOffset() int64 {
    42  	return s.totalOffset()
    43  }
    44  
    45  func (s *Stream) Buffered() io.Reader {
    46  	buflen := int64(len(s.buf))
    47  	for i := s.cursor; i < buflen; i++ {
    48  		if s.buf[i] == nul {
    49  			return bytes.NewReader(s.buf[s.cursor:i])
    50  		}
    51  	}
    52  	return bytes.NewReader(s.buf[s.cursor:])
    53  }
    54  
    55  func (s *Stream) PrepareForDecode() error {
    56  	for {
    57  		switch s.char() {
    58  		case ' ', '\t', '\r', '\n':
    59  			s.cursor++
    60  			continue
    61  		case ',', ':':
    62  			s.cursor++
    63  			return nil
    64  		case nul:
    65  			if s.read() {
    66  				continue
    67  			}
    68  			return io.EOF
    69  		}
    70  		break
    71  	}
    72  	return nil
    73  }
    74  
    75  func (s *Stream) totalOffset() int64 {
    76  	return s.offset + s.cursor
    77  }
    78  
    79  func (s *Stream) char() byte {
    80  	return s.buf[s.cursor]
    81  }
    82  
    83  func (s *Stream) equalChar(c byte) bool {
    84  	cur := s.buf[s.cursor]
    85  	if cur == nul {
    86  		s.read()
    87  		cur = s.buf[s.cursor]
    88  	}
    89  	return cur == c
    90  }
    91  
    92  func (s *Stream) stat() ([]byte, int64, unsafe.Pointer) {
    93  	return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data
    94  }
    95  
    96  func (s *Stream) bufptr() unsafe.Pointer {
    97  	return (*sliceHeader)(unsafe.Pointer(&s.buf)).data
    98  }
    99  
   100  func (s *Stream) statForRetry() ([]byte, int64, unsafe.Pointer) {
   101  	s.cursor-- // for retry ( because caller progress cursor position in each loop )
   102  	return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data
   103  }
   104  
   105  func (s *Stream) Reset() {
   106  	s.reset()
   107  }
   108  
   109  func (s *Stream) More() bool {
   110  	for {
   111  		switch s.char() {
   112  		case ' ', '\n', '\r', '\t':
   113  			s.cursor++
   114  			continue
   115  		case '}', ']':
   116  			return false
   117  		case nul:
   118  			if s.read() {
   119  				continue
   120  			}
   121  			return false
   122  		}
   123  		break
   124  	}
   125  	return true
   126  }
   127  
   128  func (s *Stream) Token() (any, error) {
   129  	for {
   130  		c := s.char()
   131  		switch c {
   132  		case ' ', '\n', '\r', '\t':
   133  			s.cursor++
   134  		case '{', '[', ']', '}':
   135  			s.cursor++
   136  			return json.Delim(c), nil
   137  		case ',', ':':
   138  			s.cursor++
   139  		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
   140  			bytes := floatBytes(s)
   141  			str := *(*string)(unsafe.Pointer(&bytes))
   142  			if s.UseNumber {
   143  				return json.Number(str), nil
   144  			}
   145  			f64, err := strconv.ParseFloat(str, 64)
   146  			if err != nil {
   147  				return nil, err
   148  			}
   149  			return f64, nil
   150  		case '"':
   151  			bytes, cursor, err := stringBytes(s)
   152  			s.cursor = cursor
   153  			if err != nil {
   154  				return nil, err
   155  			}
   156  			return unsafeConvert.StringReflect(bytes), nil
   157  		case 't':
   158  			if err := trueBytes(s); err != nil {
   159  				return nil, err
   160  			}
   161  			return true, nil
   162  		case 'f':
   163  			if err := falseBytes(s); err != nil {
   164  				return nil, err
   165  			}
   166  			return false, nil
   167  		case 'n':
   168  			if err := nullBytes(s); err != nil {
   169  				return nil, err
   170  			}
   171  			return nil, nil
   172  		case nul:
   173  			if s.read() {
   174  				continue
   175  			}
   176  			goto END
   177  		default:
   178  			return nil, errors.ErrInvalidCharacter(s.char(), "token", s.totalOffset())
   179  		}
   180  	}
   181  END:
   182  	return nil, io.EOF
   183  }
   184  
   185  func (s *Stream) reset() {
   186  	s.offset += s.cursor
   187  	s.buf = s.buf[s.cursor:]
   188  	s.length -= s.cursor
   189  	s.cursor = 0
   190  }
   191  
   192  func (s *Stream) readBuf() []byte {
   193  	if s.filledBuffer {
   194  		s.bufSize *= 2
   195  		remainBuf := s.buf
   196  		s.buf = make([]byte, s.bufSize)
   197  		copy(s.buf, remainBuf)
   198  	}
   199  	return s.buf[s.length:]
   200  }
   201  
   202  func (s *Stream) read() bool {
   203  	if s.allRead {
   204  		return false
   205  	}
   206  	buf := s.readBuf()
   207  	last := len(buf) - 1
   208  	n, err := s.r.Read(buf[:last])
   209  	buf[n] = nul
   210  	s.length += int64(n)
   211  	if n == last {
   212  		s.filledBuffer = true
   213  	} else {
   214  		s.filledBuffer = false
   215  	}
   216  	if err == io.EOF {
   217  		s.allRead = true
   218  	} else if err != nil {
   219  		return false
   220  	}
   221  	return true
   222  }
   223  
   224  // form: https://github.com/goccy/go-json/pull/446
   225  func (s *Stream) requires(cursor, n int64) (read int) {
   226  RETRY:
   227  	if s.length-cursor < n {
   228  		if !s.read() {
   229  			return -1
   230  		}
   231  		read++
   232  		goto RETRY
   233  	}
   234  	return
   235  }
   236  
   237  // form: https://github.com/goccy/go-json/pull/446
   238  func (s *Stream) syncBufptr(r int, p *unsafe.Pointer) int {
   239  	if r > 0 {
   240  		*p = s.bufptr()
   241  	}
   242  	return r
   243  }
   244  
   245  func (s *Stream) skipWhiteSpace() byte {
   246  	p := s.bufptr()
   247  LOOP:
   248  	c := char(p, s.cursor)
   249  	switch c {
   250  	case ' ', '\n', '\t', '\r':
   251  		s.cursor++
   252  		goto LOOP
   253  	case nul:
   254  		if s.read() {
   255  			p = s.bufptr()
   256  			goto LOOP
   257  		}
   258  	}
   259  	return c
   260  }
   261  
   262  func (s *Stream) skipObject(depth int64) error {
   263  	braceCount := 1
   264  	_, cursor, p := s.stat()
   265  	for {
   266  		switch char(p, cursor) {
   267  		case '{':
   268  			braceCount++
   269  			depth++
   270  			if depth > maxDecodeNestingDepth {
   271  				return errors.ErrExceededMaxDepth(s.char(), s.cursor)
   272  			}
   273  		case '}':
   274  			braceCount--
   275  			depth--
   276  			if braceCount == 0 {
   277  				s.cursor = cursor + 1
   278  				return nil
   279  			}
   280  		case '[':
   281  			depth++
   282  			if depth > maxDecodeNestingDepth {
   283  				return errors.ErrExceededMaxDepth(s.char(), s.cursor)
   284  			}
   285  		case ']':
   286  			depth--
   287  		case '"':
   288  			for {
   289  				cursor++
   290  				switch char(p, cursor) {
   291  				case '\\':
   292  					cursor++
   293  					if char(p, cursor) == nul {
   294  						s.cursor = cursor
   295  						if s.read() {
   296  							_, cursor, p = s.stat()
   297  							continue
   298  						}
   299  						return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
   300  					}
   301  				case '"':
   302  					goto SWITCH_OUT
   303  				case nul:
   304  					s.cursor = cursor
   305  					if s.read() {
   306  						_, cursor, p = s.statForRetry()
   307  						continue
   308  					}
   309  					return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
   310  				}
   311  			}
   312  		case nul:
   313  			s.cursor = cursor
   314  			if s.read() {
   315  				_, cursor, p = s.stat()
   316  				continue
   317  			}
   318  			return errors.ErrUnexpectedEndOfJSON("object of object", cursor)
   319  		}
   320  	SWITCH_OUT:
   321  		cursor++
   322  	}
   323  }
   324  
   325  func (s *Stream) skipArray(depth int64) error {
   326  	bracketCount := 1
   327  	_, cursor, p := s.stat()
   328  	for {
   329  		switch char(p, cursor) {
   330  		case '[':
   331  			bracketCount++
   332  			depth++
   333  			if depth > maxDecodeNestingDepth {
   334  				return errors.ErrExceededMaxDepth(s.char(), s.cursor)
   335  			}
   336  		case ']':
   337  			bracketCount--
   338  			depth--
   339  			if bracketCount == 0 {
   340  				s.cursor = cursor + 1
   341  				return nil
   342  			}
   343  		case '{':
   344  			depth++
   345  			if depth > maxDecodeNestingDepth {
   346  				return errors.ErrExceededMaxDepth(s.char(), s.cursor)
   347  			}
   348  		case '}':
   349  			depth--
   350  		case '"':
   351  			for {
   352  				cursor++
   353  				switch char(p, cursor) {
   354  				case '\\':
   355  					cursor++
   356  					if char(p, cursor) == nul {
   357  						s.cursor = cursor
   358  						if s.read() {
   359  							_, cursor, p = s.stat()
   360  							continue
   361  						}
   362  						return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
   363  					}
   364  				case '"':
   365  					goto SWITCH_OUT
   366  				case nul:
   367  					s.cursor = cursor
   368  					if s.read() {
   369  						_, cursor, p = s.statForRetry()
   370  						continue
   371  					}
   372  					return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
   373  				}
   374  			}
   375  		case nul:
   376  			s.cursor = cursor
   377  			if s.read() {
   378  				_, cursor, p = s.stat()
   379  				continue
   380  			}
   381  			return errors.ErrUnexpectedEndOfJSON("array of object", cursor)
   382  		}
   383  	SWITCH_OUT:
   384  		cursor++
   385  	}
   386  }
   387  
   388  func (s *Stream) SkipErrorValue() {
   389  	_ = s.skipValue(0)
   390  }
   391  
   392  func (s *Stream) skipValue(depth int64) error {
   393  	_, cursor, p := s.stat()
   394  	for {
   395  		switch char(p, cursor) {
   396  		case ' ', '\n', '\t', '\r':
   397  			cursor++
   398  			continue
   399  		case nul:
   400  			s.cursor = cursor
   401  			if s.read() {
   402  				_, cursor, p = s.stat()
   403  				continue
   404  			}
   405  			return errors.ErrUnexpectedEndOfJSON("value of object", s.totalOffset())
   406  		case '{':
   407  			s.cursor = cursor + 1
   408  			return s.skipObject(depth + 1)
   409  		case '[':
   410  			s.cursor = cursor + 1
   411  			return s.skipArray(depth + 1)
   412  		case '"':
   413  			for {
   414  				cursor++
   415  				switch char(p, cursor) {
   416  				case '\\':
   417  					cursor++
   418  					if char(p, cursor) == nul {
   419  						s.cursor = cursor
   420  						if s.read() {
   421  							_, cursor, p = s.stat()
   422  							continue
   423  						}
   424  						return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
   425  					}
   426  				case '"':
   427  					s.cursor = cursor + 1
   428  					return nil
   429  				case nul:
   430  					s.cursor = cursor
   431  					if s.read() {
   432  						_, cursor, p = s.statForRetry()
   433  						continue
   434  					}
   435  					return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
   436  				}
   437  			}
   438  		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
   439  			for {
   440  				cursor++
   441  				c := char(p, cursor)
   442  				if floatTable[c] {
   443  					continue
   444  				} else if c == nul {
   445  					if s.read() {
   446  						_, cursor, p = s.stat()
   447  						continue
   448  					}
   449  				}
   450  				s.cursor = cursor
   451  				return nil
   452  			}
   453  		case 't':
   454  			s.cursor = cursor
   455  			if err := trueBytes(s); err != nil {
   456  				return err
   457  			}
   458  			return nil
   459  		case 'f':
   460  			s.cursor = cursor
   461  			if err := falseBytes(s); err != nil {
   462  				return err
   463  			}
   464  			return nil
   465  		case 'n':
   466  			s.cursor = cursor
   467  			if err := nullBytes(s); err != nil {
   468  				return err
   469  			}
   470  			return nil
   471  		}
   472  		cursor++
   473  	}
   474  }
   475  
   476  func nullBytes(s *Stream) error {
   477  	if s.requires(s.cursor, 4) < 0 {
   478  		s.cursor = s.length
   479  		return errors.ErrUnexpectedEndOfJSON("null", s.cursor)
   480  	}
   481  	// current cursor's character is 'n'
   482  	s.cursor++
   483  	if s.char() != 'u' {
   484  		return errors.ErrInvalidCharacter(s.char(), "null", s.totalOffset())
   485  	}
   486  	s.cursor++
   487  	if s.char() != 'l' {
   488  		return errors.ErrInvalidCharacter(s.char(), "null", s.totalOffset())
   489  	}
   490  	s.cursor++
   491  	if s.char() != 'l' {
   492  		return errors.ErrInvalidCharacter(s.char(), "null", s.totalOffset())
   493  	}
   494  	s.cursor++
   495  	return nil
   496  }
   497  
   498  func trueBytes(s *Stream) error {
   499  	if s.requires(s.cursor, 4) < 0 {
   500  		s.cursor = s.length
   501  		return errors.ErrUnexpectedEndOfJSON("bool(true)", s.cursor)
   502  	}
   503  	// current cursor's character is 't'
   504  	s.cursor++
   505  	if s.char() != 'r' {
   506  		return errors.ErrInvalidCharacter(s.char(), "bool(true)", s.totalOffset())
   507  	}
   508  	s.cursor++
   509  	if s.char() != 'u' {
   510  		return errors.ErrInvalidCharacter(s.char(), "bool(true)", s.totalOffset())
   511  	}
   512  	s.cursor++
   513  	if s.char() != 'e' {
   514  		return errors.ErrInvalidCharacter(s.char(), "bool(true)", s.totalOffset())
   515  	}
   516  	s.cursor++
   517  	return nil
   518  }
   519  
   520  func falseBytes(s *Stream) error {
   521  	if s.requires(s.cursor, 5) < 0 {
   522  		s.cursor = s.length
   523  		return errors.ErrUnexpectedEndOfJSON("bool(false)", s.cursor)
   524  	}
   525  	// current cursor's character is 'f'
   526  	s.cursor++
   527  	if s.char() != 'a' {
   528  		return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset())
   529  	}
   530  	s.cursor++
   531  	if s.char() != 'l' {
   532  		return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset())
   533  	}
   534  	s.cursor++
   535  	if s.char() != 's' {
   536  		return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset())
   537  	}
   538  	s.cursor++
   539  	if s.char() != 'e' {
   540  		return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset())
   541  	}
   542  	s.cursor++
   543  	return nil
   544  }