mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 08:42:27 -05:00 
			
		
		
		
	- github.com/KimMachineGun/automemlimit v0.7.2 => v0.7.3
- github.com/gin-contrib/cors v1.7.5 => v1.7.6
- github.com/minio/minio-go/v7 v7.0.92 => v7.0.94
- github.com/spf13/cast v1.8.0 => v1.9.2
- github.com/uptrace/bun{,/*} v1.2.11 => v1.2.14
- golang.org/x/image v0.27.0 => v0.28.0
- golang.org/x/net v0.40.0 => v0.41.0
- code.superseriousbusiness.org/go-swagger v0.31.0-gts-go1.23-fix => v0.32.3-gts-go1.23-fix
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4304
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
		
	
			
		
			
				
	
	
		
			830 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			830 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
 | |
| // Use of this source code is governed by a MIT license found in the LICENSE file.
 | |
| 
 | |
| package codec
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"io"
 | |
| 	"os"
 | |
| )
 | |
| 
 | |
| // decReader abstracts the reading source, allowing implementations that can
 | |
| // read from an io.Reader or directly off a byte slice with zero-copying.
 | |
| type decReaderI interface {
 | |
| 	// readx will return a view of the []byte in one of 2 ways:
 | |
| 	//   - direct view into []byte which decoding is happening from (if bytes)
 | |
| 	//   - view into a mutable []byte which the ioReader is using (if IO)
 | |
| 	//
 | |
| 	// Users should directly consume the contents read, and not store for future use.
 | |
| 	readx(n uint) []byte
 | |
| 
 | |
| 	// skip n bytes
 | |
| 	skip(n uint)
 | |
| 
 | |
| 	readb([]byte)
 | |
| 
 | |
| 	// readxb will read n bytes, returning as out, and a flag stating whether
 | |
| 	// an internal buffer (not the view) was used.
 | |
| 	readxb(n uint) (out []byte, usingBuf bool)
 | |
| 
 | |
| 	readn1() byte
 | |
| 	readn2() [2]byte
 | |
| 	readn3() [3]byte
 | |
| 	readn4() [4]byte
 | |
| 	readn8() [8]byte
 | |
| 	// readn1eof() (v uint8, eof bool)
 | |
| 
 | |
| 	// // read up to 8 bytes at a time
 | |
| 	// readn(num uint8) (v [8]byte)
 | |
| 
 | |
| 	numread() uint // number of bytes read
 | |
| 
 | |
| 	// skip any whitespace characters, and return the first non-matching byte
 | |
| 	skipWhitespace() (token byte)
 | |
| 
 | |
| 	// jsonReadNum will read a sequence of numeric characters, checking from the last
 | |
| 	// read byte. It will return a sequence of numeric characters (v),
 | |
| 	// and the next token character (tok - returned separately),
 | |
| 	//
 | |
| 	// if an EOF is found before the next token is seen, it returns a token value of 0.
 | |
| 	jsonReadNum() (v []byte, token byte)
 | |
| 
 | |
| 	// jsonReadAsisChars recognizes 2 terminal characters (" or \).
 | |
| 	// jsonReadAsisChars will read json plain characters until it reaches a terminal char,
 | |
| 	// and returns a slice up to the terminal char (excluded),
 | |
| 	// and also returns the terminal char separately (" or \).
 | |
| 	jsonReadAsisChars() (v []byte, terminal byte)
 | |
| 
 | |
| 	// readUntil will read characters until it reaches a ",
 | |
| 	// return a slice up to " (excluded)
 | |
| 	jsonReadUntilDblQuote() (v []byte)
 | |
| 
 | |
| 	// skip will skip any byte that matches, and return the first non-matching byte
 | |
| 	// skip(accept *bitset256) (token byte)
 | |
| 
 | |
| 	// readTo will read any byte that matches, stopping once no-longer matching.
 | |
| 	// readTo(accept *bitset256) (out []byte)
 | |
| 
 | |
| 	// // readUntil will read characters until it reaches a stop char,
 | |
| 	// // return a slice up to the terminal byte (excluded)
 | |
| 	// readUntil(stop byte) (out []byte)
 | |
| 
 | |
| 	// only supported when reading from bytes
 | |
| 	// bytesReadFrom(startpos uint) []byte
 | |
| 
 | |
| 	// isBytes() bool
 | |
| 	resetIO(r io.Reader, bufsize int, maxInitLen int, blist *bytesFreeList)
 | |
| 
 | |
| 	resetBytes(in []byte)
 | |
| 
 | |
| 	// nextValueBytes() captures bytes read between a call to startRecording and stopRecording.
 | |
| 	// startRecording will always includes the last byte read.
 | |
| 	startRecording()
 | |
| 	// stopRecording will include all bytes read between the point of startRecording and now.
 | |
| 	stopRecording() []byte
 | |
| }
 | |
| 
 | |
| // // ------------------------------------------------
 | |
| 
 | |
| const maxConsecutiveEmptyReads = 16 // 2 is sufficient, 16 is enough, 64 is optimal
 | |
| 
 | |
| // const defBufReaderSize = 4096
 | |
| 
 | |
| // --------------------
 | |
| 
 | |
| // ioReaderByteScanner contains the io.Reader and io.ByteScanner interfaces
 | |
| type ioReaderByteScanner interface {
 | |
| 	io.Reader
 | |
| 	io.ByteScanner
 | |
| }
 | |
| 
 | |
| // MARKER: why not separate bufioDecReader from ioDecReader?
 | |
| //
 | |
| // We tried, but only readn1 of bufioDecReader came close to being
 | |
| // inlined (at inline cost 82). All other methods were at inline cost >= 90.
 | |
| //
 | |
| // Consequently, there's no performance impact from having both together
 | |
| // (except a single if z.bufio branch, which is likely well predicted and happens
 | |
| // only once per call (right at the top).
 | |
| 
 | |
| // ioDecReader is a decReader that reads off an io.Reader.
 | |
| type ioDecReader struct {
 | |
| 	r io.Reader
 | |
| 
 | |
| 	blist *bytesFreeList
 | |
| 
 | |
| 	maxInitLen uint
 | |
| 
 | |
| 	n uint // num read
 | |
| 
 | |
| 	bufsize uint
 | |
| 
 | |
| 	bufio     bool // are we buffering (rc and wc are valid)
 | |
| 	rbr       bool // r is a byte reader
 | |
| 	recording bool // are we recording (src and erc are valid)
 | |
| 	done      bool // did we reach EOF and are we done?
 | |
| 
 | |
| 	// valid when: bufio=false
 | |
| 	b  [1]byte       // tiny buffer for reading single byte (if z.br == nil)
 | |
| 	l  byte          // last byte read
 | |
| 	br io.ByteReader // main reader used for ReadByte
 | |
| 
 | |
| 	// valid when: bufio=true
 | |
| 	wc  uint // read cursor
 | |
| 	rc  uint // write cursor
 | |
| 	err error
 | |
| 
 | |
| 	// valid when: recording=true
 | |
| 	recc uint // start-recording cursor (valid: recording=true)
 | |
| 
 | |
| 	buf []byte // buffer for bufio OR recording (if !bufio)
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) resetBytes(in []byte) {
 | |
| 	halt.errorStr("resetBytes unsupported by ioDecReader")
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) resetIO(r io.Reader, bufsize int, maxInitLen int, blist *bytesFreeList) {
 | |
| 	buf := z.buf
 | |
| 	*z = ioDecReader{}
 | |
| 	z.maxInitLen = max(1024, uint(maxInitLen))
 | |
| 	z.blist = blist
 | |
| 	z.buf = blist.check(buf, max(256, bufsize))
 | |
| 	z.bufsize = uint(max(0, bufsize))
 | |
| 	z.bufio = z.bufsize > 0
 | |
| 	if z.bufio {
 | |
| 		z.buf = z.buf[:cap(z.buf)]
 | |
| 	} else {
 | |
| 		z.buf = z.buf[:0]
 | |
| 	}
 | |
| 	if r == nil {
 | |
| 		z.r = &eofReader
 | |
| 	} else {
 | |
| 		z.r = r
 | |
| 	}
 | |
| 	z.br, z.rbr = z.r.(io.ByteReader)
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) numread() uint {
 | |
| 	return z.n
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readn2() [2]byte {
 | |
| 	return ([2]byte)(z.readx(2))
 | |
| 	// using readb forced return bs onto heap, unnecessarily
 | |
| 	// z.readb(bs[:])
 | |
| 	// return
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readn3() [3]byte {
 | |
| 	return ([3]byte)(z.readx(3))
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readn4() [4]byte {
 | |
| 	return ([4]byte)(z.readx(4))
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readn8() [8]byte {
 | |
| 	return ([8]byte)(z.readx(8))
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readx(n uint) (bs []byte) {
 | |
| 	return bytesOK(z.readxb(n))
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readErr() (err error) {
 | |
| 	err, z.err = z.err, nil
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) checkErr() {
 | |
| 	halt.onerror(z.readErr())
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readOne() (b byte, err error) {
 | |
| 	n, err := z.r.Read(z.b[:])
 | |
| 	if n == 1 {
 | |
| 		err = nil
 | |
| 		b = z.b[0]
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // fillbuf reads a new chunk into the buffer.
 | |
| func (z *ioDecReader) fillbuf(bufsize uint) (numShift, numRead uint) {
 | |
| 	z.checkErr()
 | |
| 	bufsize = max(bufsize, z.bufsize)
 | |
| 
 | |
| 	// Slide existing data to beginning.
 | |
| 	if z.recording {
 | |
| 		numShift = z.recc // recc is always <= rc
 | |
| 	} else {
 | |
| 		numShift = z.rc
 | |
| 	}
 | |
| 	if numShift > 0 {
 | |
| 		numShift-- // never shift last byte read out
 | |
| 	}
 | |
| 	copy(z.buf, z.buf[numShift:z.wc])
 | |
| 	z.wc -= numShift
 | |
| 	z.rc -= numShift
 | |
| 	if z.recording {
 | |
| 		z.recc -= numShift
 | |
| 	}
 | |
| 	// add enough to allow u to read up to bufsize again iff
 | |
| 	// - buf is fully written
 | |
| 	// - NOTE: don't pre-allocate more until needed
 | |
| 	if uint(len(z.buf)) == z.wc {
 | |
| 		if bufsize+z.wc < uint(cap(z.buf)) {
 | |
| 			z.buf = z.buf[:uint(cap(z.buf))]
 | |
| 		} else {
 | |
| 			bufsize = max(uint(cap(z.buf)*3/2), bufsize+z.wc)
 | |
| 			buf := z.blist.get(int(bufsize))
 | |
| 			buf = buf[:cap(buf)]
 | |
| 			copy(buf, z.buf[:z.wc])
 | |
| 			z.blist.put(z.buf)
 | |
| 			z.buf = buf
 | |
| 		}
 | |
| 	}
 | |
| 	// Read new data: try a limited number of times.
 | |
| 	// if n == 0: try up to maxConsecutiveEmptyReads
 | |
| 	// if n > 0 and err == nil: try one more time (to see if we get n == 0 and EOF)
 | |
| 	for i := maxConsecutiveEmptyReads; i > 0; i-- {
 | |
| 		n, err := z.r.Read(z.buf[z.wc:])
 | |
| 		numRead += uint(n)
 | |
| 		z.wc += uint(n)
 | |
| 		if err != nil {
 | |
| 			// if os read dealine, and we have read something, return
 | |
| 			z.err = err
 | |
| 			if err == io.EOF {
 | |
| 				z.done = true
 | |
| 			} else if errors.Is(err, os.ErrDeadlineExceeded) {
 | |
| 				// os read deadline, but some bytes read: return (don't store err)
 | |
| 				z.err = nil
 | |
| 			}
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// if z.wc == uint(len(z.buf)) {
 | |
| 		// 	return
 | |
| 		// }
 | |
| 		// only read one time if results returned
 | |
| 		// if n > 0 && i > 2 {
 | |
| 		// 	i = 2 // try max one more time (to see about getting EOF)
 | |
| 		// }
 | |
| 
 | |
| 		// Once you have some data from this read call, move on.
 | |
| 		// Consequently, a blocked Read has less chance of happening.
 | |
| 		if n > 0 {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	z.err = io.ErrNoProgress // either no data read OR not enough data read, without an EOF
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readb(bs []byte) {
 | |
| 	if len(bs) == 0 {
 | |
| 		return
 | |
| 	}
 | |
| 	var err error
 | |
| 	var n int
 | |
| 	if z.bufio {
 | |
| 	BUFIO:
 | |
| 		for z.rc == z.wc {
 | |
| 			z.fillbuf(0)
 | |
| 		}
 | |
| 		n = copy(bs, z.buf[z.rc:z.wc])
 | |
| 		z.rc += uint(n)
 | |
| 		z.n += uint(n)
 | |
| 		if n == len(bs) {
 | |
| 			return
 | |
| 		}
 | |
| 		bs = bs[n:]
 | |
| 		goto BUFIO
 | |
| 	}
 | |
| 
 | |
| 	// -------- NOT BUFIO ------
 | |
| 
 | |
| 	var nn uint
 | |
| 	bs0 := bs
 | |
| READER:
 | |
| 	n, err = z.r.Read(bs)
 | |
| 	if n > 0 {
 | |
| 		z.l = bs[n-1]
 | |
| 		nn += uint(n)
 | |
| 		bs = bs[n:]
 | |
| 	}
 | |
| 	if len(bs) != 0 && err == nil {
 | |
| 		goto READER
 | |
| 	}
 | |
| 	if z.recording {
 | |
| 		z.buf = append(z.buf, bs0[:nn]...)
 | |
| 	}
 | |
| 	z.n += nn
 | |
| 	if len(bs) != 0 {
 | |
| 		halt.onerror(err)
 | |
| 		halt.errorf("ioDecReader.readb read %d out of %d bytes requested", nn, len(bs0))
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readn1() (b uint8) {
 | |
| 	if z.bufio {
 | |
| 		for z.rc == z.wc {
 | |
| 			z.fillbuf(0)
 | |
| 		}
 | |
| 		b = z.buf[z.rc]
 | |
| 		z.rc++
 | |
| 		z.n++
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// -------- NOT BUFIO ------
 | |
| 
 | |
| 	var err error
 | |
| 	if z.rbr {
 | |
| 		b, err = z.br.ReadByte()
 | |
| 	} else {
 | |
| 		b, err = z.readOne()
 | |
| 	}
 | |
| 	halt.onerror(err)
 | |
| 	z.l = b
 | |
| 	z.n++
 | |
| 	if z.recording {
 | |
| 		z.buf = append(z.buf, b)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readxb(n uint) (out []byte, useBuf bool) {
 | |
| 	if n == 0 {
 | |
| 		return zeroByteSlice, false
 | |
| 	}
 | |
| 
 | |
| 	if z.bufio {
 | |
| 	BUFIO:
 | |
| 		nn := int(n+z.rc) - int(z.wc)
 | |
| 		if nn > 0 {
 | |
| 			z.fillbuf(decInferLen(nn, z.maxInitLen, 1))
 | |
| 			goto BUFIO
 | |
| 		}
 | |
| 		pos := z.rc
 | |
| 		z.rc += uint(n)
 | |
| 		z.n += uint(n)
 | |
| 		out = z.buf[pos:z.rc]
 | |
| 		useBuf = true
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// -------- NOT BUFIO ------
 | |
| 
 | |
| 	useBuf = true
 | |
| 	out = z.buf
 | |
| 	r0 := uint(len(out))
 | |
| 	r := r0
 | |
| 	nn := int(n)
 | |
| 	var n2 uint
 | |
| 	for nn > 0 {
 | |
| 		n2 = r + decInferLen(int(nn), z.maxInitLen, 1)
 | |
| 		if cap(out) < int(n2) {
 | |
| 			out2 := z.blist.putGet(out, int(n2))[:n2] // make([]byte, len2+len3)
 | |
| 			copy(out2, out)
 | |
| 			out = out2
 | |
| 		} else {
 | |
| 			out = out[:n2]
 | |
| 		}
 | |
| 		n3, err := z.r.Read(out[r:n2])
 | |
| 		if n3 > 0 {
 | |
| 			z.l = out[r+uint(n3)-1]
 | |
| 			nn -= n3
 | |
| 			r += uint(n3)
 | |
| 		}
 | |
| 		halt.onerror(err)
 | |
| 	}
 | |
| 	z.buf = out[:r0+n]
 | |
| 	out = out[r0 : r0+n]
 | |
| 	z.n += n
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) skip(n uint) {
 | |
| 	if n == 0 {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if z.bufio {
 | |
| 	BUFIO:
 | |
| 		n2 := min(n, z.wc-z.rc)
 | |
| 		// handle in-line, so z.buf doesn't grow much (since we're skipping)
 | |
| 		// ie by setting z.rc, fillbuf should keep shifting left (unless recording)
 | |
| 		z.rc += n2
 | |
| 		z.n += n2
 | |
| 		n -= n2
 | |
| 		if n > 0 {
 | |
| 			z.fillbuf(decInferLen(int(n+z.rc)-int(z.wc), z.maxInitLen, 1))
 | |
| 			goto BUFIO
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// -------- NOT BUFIO ------
 | |
| 
 | |
| 	var out []byte
 | |
| 	var fromBlist bool
 | |
| 	if z.recording {
 | |
| 		out = z.buf
 | |
| 	} else {
 | |
| 		nn := int(decInferLen(int(n), z.maxInitLen, 1))
 | |
| 		if cap(z.buf) >= nn/2 {
 | |
| 			out = z.buf[:cap(z.buf)]
 | |
| 		} else {
 | |
| 			fromBlist = true
 | |
| 			out = z.blist.get(nn)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	var r, n2 uint
 | |
| 	nn := int(n)
 | |
| 	for nn > 0 {
 | |
| 		n2 = uint(nn)
 | |
| 		if z.recording {
 | |
| 			r = uint(len(out))
 | |
| 			n2 = r + decInferLen(int(nn), z.maxInitLen, 1)
 | |
| 			if cap(out) < int(n2) {
 | |
| 				out2 := z.blist.putGet(out, int(n2))[:n2] // make([]byte, len2+len3)
 | |
| 				copy(out2, out)
 | |
| 				out = out2
 | |
| 			} else {
 | |
| 				out = out[:n2]
 | |
| 			}
 | |
| 		}
 | |
| 		n3, err := z.r.Read(out[r:n2])
 | |
| 		if n3 > 0 {
 | |
| 			z.l = out[r+uint(n3)-1]
 | |
| 			z.n += uint(n3)
 | |
| 			nn -= n3
 | |
| 		}
 | |
| 		halt.onerror(err)
 | |
| 	}
 | |
| 	if z.recording {
 | |
| 		z.buf = out
 | |
| 	} else if fromBlist {
 | |
| 		z.blist.put(out)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // ---- JSON SPECIFIC HELPERS HERE ----
 | |
| 
 | |
| func (z *ioDecReader) jsonReadNum() (bs []byte, token byte) {
 | |
| 	var start, pos, end uint
 | |
| 	if z.bufio {
 | |
| 		// read and fill into buf, then take substring
 | |
| 		start = z.rc - 1 // include last byte read
 | |
| 		pos = start
 | |
| 	BUFIO:
 | |
| 		if pos == z.wc {
 | |
| 			if z.done {
 | |
| 				end = pos
 | |
| 				goto END
 | |
| 			}
 | |
| 			numshift, numread := z.fillbuf(0)
 | |
| 			start -= numshift
 | |
| 			pos -= numshift
 | |
| 			if numread == 0 {
 | |
| 				end = pos
 | |
| 				goto END
 | |
| 			}
 | |
| 		}
 | |
| 		token = z.buf[pos]
 | |
| 		pos++
 | |
| 		if isNumberChar(token) {
 | |
| 			goto BUFIO
 | |
| 		}
 | |
| 		end = pos - 1
 | |
| 	END:
 | |
| 		z.n += (pos - z.rc)
 | |
| 		z.rc = pos
 | |
| 		return z.buf[start:end], token
 | |
| 	}
 | |
| 
 | |
| 	// if not recording, add the last read byte into buf
 | |
| 	if !z.recording {
 | |
| 		z.buf = append(z.buf[:0], z.l)
 | |
| 	}
 | |
| 	start = uint(len(z.buf) - 1) // incl last byte in z.buf
 | |
| 	var b byte
 | |
| 	var err error
 | |
| 
 | |
| READER:
 | |
| 	if z.rbr {
 | |
| 		b, err = z.br.ReadByte()
 | |
| 	} else {
 | |
| 		b, err = z.readOne()
 | |
| 	}
 | |
| 	if err == io.EOF {
 | |
| 		return z.buf[start:], 0
 | |
| 	}
 | |
| 	halt.onerror(err)
 | |
| 	z.l = b
 | |
| 	z.n++
 | |
| 	z.buf = append(z.buf, b)
 | |
| 	if isNumberChar(b) {
 | |
| 		goto READER
 | |
| 	}
 | |
| 	return z.buf[start : len(z.buf)-1], b
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) skipWhitespace() (tok byte) {
 | |
| 	var pos uint
 | |
| 	if z.bufio {
 | |
| 		pos = z.rc
 | |
| 	BUFIO:
 | |
| 		if pos == z.wc {
 | |
| 			if z.done {
 | |
| 				halt.onerror(io.ErrUnexpectedEOF)
 | |
| 			}
 | |
| 			numshift, numread := z.fillbuf(0)
 | |
| 			pos -= numshift
 | |
| 			if numread == 0 {
 | |
| 				halt.onerror(io.ErrUnexpectedEOF)
 | |
| 			}
 | |
| 		}
 | |
| 		tok = z.buf[pos]
 | |
| 		pos++
 | |
| 		if isWhitespaceChar(tok) {
 | |
| 			goto BUFIO
 | |
| 		}
 | |
| 		z.n += (pos - z.rc)
 | |
| 		z.rc = pos
 | |
| 		return tok
 | |
| 	}
 | |
| 
 | |
| 	var err error
 | |
| READER:
 | |
| 	if z.rbr {
 | |
| 		tok, err = z.br.ReadByte()
 | |
| 	} else {
 | |
| 		tok, err = z.readOne()
 | |
| 	}
 | |
| 	halt.onerror(err)
 | |
| 	z.n++
 | |
| 	z.l = tok
 | |
| 	if z.recording {
 | |
| 		z.buf = append(z.buf, tok)
 | |
| 	}
 | |
| 	if isWhitespaceChar(tok) {
 | |
| 		goto READER
 | |
| 	}
 | |
| 	return tok
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) readUntil(stop1, stop2 byte) (bs []byte, tok byte) {
 | |
| 	var start, pos uint
 | |
| 	if z.bufio {
 | |
| 		start = z.rc
 | |
| 		pos = start
 | |
| 	BUFIO:
 | |
| 		if pos == z.wc {
 | |
| 			if z.done {
 | |
| 				halt.onerror(io.ErrUnexpectedEOF)
 | |
| 			}
 | |
| 			numshift, numread := z.fillbuf(0)
 | |
| 			start -= numshift
 | |
| 			pos -= numshift
 | |
| 			if numread == 0 {
 | |
| 				halt.onerror(io.ErrUnexpectedEOF)
 | |
| 			}
 | |
| 		}
 | |
| 		tok = z.buf[pos]
 | |
| 		pos++
 | |
| 		if tok == stop1 || tok == stop2 {
 | |
| 			z.n += (pos - z.rc)
 | |
| 			z.rc = pos
 | |
| 			return z.buf[start : pos-1], tok
 | |
| 		}
 | |
| 		goto BUFIO
 | |
| 	}
 | |
| 
 | |
| 	var err error
 | |
| 	if !z.recording {
 | |
| 		z.buf = z.buf[:0]
 | |
| 	}
 | |
| 	start = uint(len(z.buf))
 | |
| READER:
 | |
| 	if z.rbr {
 | |
| 		tok, err = z.br.ReadByte()
 | |
| 	} else {
 | |
| 		tok, err = z.readOne()
 | |
| 	}
 | |
| 	halt.onerror(err)
 | |
| 	z.n++
 | |
| 	z.l = tok
 | |
| 	z.buf = append(z.buf, tok)
 | |
| 	if tok == stop1 || tok == stop2 {
 | |
| 		return z.buf[start : len(z.buf)-1], tok
 | |
| 	}
 | |
| 	goto READER
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) jsonReadAsisChars() (bs []byte, tok byte) {
 | |
| 	return z.readUntil('"', '\\')
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) jsonReadUntilDblQuote() (bs []byte) {
 | |
| 	bs, _ = z.readUntil('"', 0)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // ---- start/stop recording ----
 | |
| 
 | |
| func (z *ioDecReader) startRecording() {
 | |
| 	z.recording = true
 | |
| 	// always include last byte read
 | |
| 	if z.bufio {
 | |
| 		z.recc = z.rc - 1
 | |
| 	} else {
 | |
| 		z.buf = append(z.buf[:0], z.l)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (z *ioDecReader) stopRecording() (v []byte) {
 | |
| 	z.recording = false
 | |
| 	if z.bufio {
 | |
| 		v = z.buf[z.recc:z.rc]
 | |
| 		z.recc = 0
 | |
| 	} else {
 | |
| 		v = z.buf
 | |
| 		z.buf = z.buf[:0]
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // ------------------------------------
 | |
| 
 | |
| // bytesDecReader is a decReader that reads off a byte slice with zero copying
 | |
| //
 | |
| // Note: we do not try to convert index'ing out of bounds to an io error.
 | |
| // instead, we let it bubble up to the exported Encode/Decode method
 | |
| // and recover it as an io error.
 | |
| //
 | |
| // Every function here MUST defensively check bounds either explicitly
 | |
| // or via a bounds check.
 | |
| //
 | |
| // see panicValToErr(...) function in helper.go.
 | |
| type bytesDecReader struct {
 | |
| 	b  []byte // data
 | |
| 	c  uint   // cursor
 | |
| 	r  uint   // recording cursor
 | |
| 	xb []byte // buffer for readxb
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) resetIO(r io.Reader, bufsize int, maxInitLen int, blist *bytesFreeList) {
 | |
| 	halt.errorStr("resetIO unsupported by bytesDecReader")
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) resetBytes(in []byte) {
 | |
| 	// it's ok to resize a nil slice, so long as it's not past 0
 | |
| 	z.b = in[:len(in):len(in)] // reslicing must not go past capacity
 | |
| 	z.c = 0
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) numread() uint {
 | |
| 	return z.c
 | |
| }
 | |
| 
 | |
| // Note: slicing from a non-constant start position is more expensive,
 | |
| // as more computation is required to decipher the pointer start position.
 | |
| // However, we do it only once, and it's better than reslicing both z.b and return value.
 | |
| 
 | |
| func (z *bytesDecReader) readx(n uint) (bs []byte) {
 | |
| 	bs = z.b[z.c : z.c+n]
 | |
| 	z.c += n
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) skip(n uint) {
 | |
| 	if z.c+n > uint(cap(z.b)) {
 | |
| 		halt.error(&outOfBoundsError{uint(cap(z.b)), z.c + n})
 | |
| 	}
 | |
| 	z.c += n
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) readxb(n uint) (out []byte, usingBuf bool) {
 | |
| 	return z.readx(n), false
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) readb(bs []byte) {
 | |
| 	copy(bs, z.readx(uint(len(bs))))
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) readn1() (v uint8) {
 | |
| 	v = z.b[z.c]
 | |
| 	z.c++
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) readn2() (bs [2]byte) {
 | |
| 	bs = [2]byte(z.b[z.c:])
 | |
| 	z.c += 2
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) readn3() (bs [3]byte) {
 | |
| 	bs = [3]byte(z.b[z.c:])
 | |
| 	z.c += 3
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) readn4() (bs [4]byte) {
 | |
| 	bs = [4]byte(z.b[z.c:])
 | |
| 	z.c += 4
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) readn8() (bs [8]byte) {
 | |
| 	bs = [8]byte(z.b[z.c:])
 | |
| 	z.c += 8
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) jsonReadNum() (bs []byte, token byte) {
 | |
| 	start := z.c - 1 // include last byte
 | |
| 	i := start
 | |
| LOOP:
 | |
| 	// gracefully handle end of slice (~= EOF)
 | |
| 	if i < uint(len(z.b)) {
 | |
| 		if isNumberChar(z.b[i]) {
 | |
| 			i++
 | |
| 			goto LOOP
 | |
| 		}
 | |
| 		token = z.b[i]
 | |
| 	}
 | |
| 	z.c = i + 1
 | |
| 	bs = z.b[start:i] // byteSliceOf(z.b, start, i)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) jsonReadAsisChars() (bs []byte, token byte) {
 | |
| 	i := z.c
 | |
| LOOP:
 | |
| 	token = z.b[i]
 | |
| 	i++
 | |
| 	if token == '"' || token == '\\' {
 | |
| 		// z.c, i = i, z.c
 | |
| 		// return byteSliceOf(z.b, i, z.c-1), token
 | |
| 		bs = z.b[z.c : i-1]
 | |
| 		z.c = i
 | |
| 		return
 | |
| 		// return z.b[i : z.c-1], token
 | |
| 	}
 | |
| 	goto LOOP
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) skipWhitespace() (token byte) {
 | |
| 	i := z.c
 | |
| LOOP:
 | |
| 	// setting token before check reduces inlining cost,
 | |
| 	// making containerNext inlineable
 | |
| 	token = z.b[i]
 | |
| 	if !isWhitespaceChar(token) {
 | |
| 		z.c = i + 1
 | |
| 		return
 | |
| 	}
 | |
| 	i++
 | |
| 	goto LOOP
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) jsonReadUntilDblQuote() (out []byte) {
 | |
| 	i := z.c
 | |
| LOOP:
 | |
| 	if z.b[i] == '"' {
 | |
| 		out = z.b[z.c:i] // byteSliceOf(z.b, z.c, i)
 | |
| 		z.c = i + 1
 | |
| 		return
 | |
| 	}
 | |
| 	i++
 | |
| 	goto LOOP
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) startRecording() {
 | |
| 	z.r = z.c - 1
 | |
| }
 | |
| 
 | |
| func (z *bytesDecReader) stopRecording() (v []byte) {
 | |
| 	v = z.b[z.r:z.c]
 | |
| 	z.r = 0
 | |
| 	return
 | |
| }
 | |
| 
 | |
| type devNullReader struct{}
 | |
| 
 | |
| func (devNullReader) Read(p []byte) (int, error) { return 0, io.EOF }
 | |
| func (devNullReader) Close() error               { return nil }
 | |
| func (devNullReader) ReadByte() (byte, error)    { return 0, io.EOF }
 | |
| func (devNullReader) UnreadByte() error          { return io.EOF }
 | |
| 
 | |
| // MARKER: readn{1,2,3,4,8} should throw an out of bounds error if past length.
 | |
| // MARKER: readn1: explicitly ensure bounds check is done
 | |
| // MARKER: readn{2,3,4,8}: ensure you slice z.b completely so we get bounds error if past end.
 |