summaryrefslogtreecommitdiff
path: root/decode_scan.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2022-08-16 22:40:19 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-17 00:12:35 -0600
commite57bee02e02b7e3697d6c3cb8b75923a92100427 (patch)
treef32610f2b73fbea1f2a94e108fabca18d31d5d27 /decode_scan.go
parent87b02577e50b76d373e3c6b921d776e39cb83346 (diff)
Add tests for decode reading too far
Diffstat (limited to 'decode_scan.go')
-rw-r--r--decode_scan.go62
1 files changed, 42 insertions, 20 deletions
diff --git a/decode_scan.go b/decode_scan.go
index fee9ec6..9fa6181 100644
--- a/decode_scan.go
+++ b/decode_scan.go
@@ -11,13 +11,11 @@ import (
type runeTypeScanner interface {
// The returned error is a *ReadError, a *SyntaxError, or nil.
- // An EOF condition is represented either as
+ // An EOF condition is represented as one of:
//
- // (char, size, RuneTypeEOF, nil)
- //
- // or
- //
- // (char, size, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.ErrUnexepctedEOF})
+ // end of value but not file: (_, >0, RuneTypeEOF, nil)
+ // end of both value and file: (_, 0, RuneTypeEOF, nil)
+ // end of file but not value: (_, 0, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.ErrUnexepctedEOF})
ReadRuneType() (rune, int, RuneType, error)
// The returned error is a *DecodeReadError, a *DecodeSyntaxError, io.EOF, or nil.
ReadRune() (rune, int, error)
@@ -31,6 +29,8 @@ type runeTypeScanner interface {
type runeTypeScannerImpl struct {
inner io.RuneReader
+ initialized bool
+
parser Parser
offset int64
@@ -109,6 +109,7 @@ func (sc *runeTypeScannerImpl) ReadRuneType() (rune, int, RuneType, error) {
}
}
}
+ sc.initialized = true
sc.repeat = false
sc.stuck = sc.rType == RuneTypeEOF || sc.rType == RuneTypeError
return sc.rRune, sc.rSize, sc.rType, sc.rErr
@@ -128,12 +129,13 @@ func (sc *runeTypeScannerImpl) ReadRune() (rune, int, error) {
var ErrInvalidUnreadRune = errors.New("lowmemjson: invalid use of UnreadRune")
-// UnreadRune undoes a call to .ReadRune() or .ReadRuneType(). If the
-// last call to .ReadRune() or .ReadRuneType() has already been
-// unread, or if that call returned an error or RuneTypeEOF, then
-// ErrInvalidRune is returned. Otherwise, nil is returned.
+// UnreadRune undoes a call to .ReadRune() or .ReadRuneType().
+//
+// If the last call to .ReadRune() or .ReadRuneType() has already been
+// unread, or if that call returned a rune with size 0, then
+// ErrInvalidUnreadRune is returned. Otherwise, nil is returned.
func (sc *runeTypeScannerImpl) UnreadRune() error {
- if sc.stuck || sc.repeat {
+ if !sc.initialized || sc.repeat || sc.rSize == 0 {
return ErrInvalidUnreadRune
}
sc.repeat = true
@@ -191,27 +193,46 @@ type elemRuneTypeScanner struct {
parser Parser
repeat bool
+ stuck bool
rType RuneType
+ rErr error
}
var _ runeTypeScanner = (*elemRuneTypeScanner)(nil)
func (sc *elemRuneTypeScanner) ReadRuneType() (rune, int, RuneType, error) {
+ // Read it, run it through the parent's parser.
r, s, t, e := sc.inner.ReadRuneType()
- // Check if we need to insert a premature EOF
- if t != RuneTypeError && t != RuneTypeEOF {
- if sc.repeat {
+ // Run it through our child parser.
+ if s > 0 || errors.Is(e, io.ErrUnexpectedEOF) {
+ if sc.repeat || sc.stuck {
sc.repeat = false
} else {
- sc.rType, _ = sc.parser.HandleRune(r)
- }
- if sc.rType == RuneTypeEOF {
- _ = sc.inner.UnreadRune()
+ var err error
+ if s > 0 {
+ sc.rType, err = sc.parser.HandleRune(r)
+ } else {
+ sc.rType, err = sc.parser.HandleEOF()
+ }
+ if err != nil {
+ sc.rErr = &DecodeSyntaxError{
+ Offset: sc.inner.InputOffset(),
+ Err: err,
+ }
+ } else {
+ sc.rErr = nil
+ }
}
- t = sc.rType
+ sc.stuck = sc.rType == RuneTypeEOF || sc.rType == RuneTypeError
+ t, e = sc.rType, sc.rErr
}
+
+ // Check if we need to truncate the result.
if t == RuneTypeEOF {
+ if s > 0 {
+ _ = sc.inner.UnreadRune()
+ }
return 0, 0, RuneTypeEOF, nil
}
@@ -231,8 +252,9 @@ func (sc *elemRuneTypeScanner) ReadRune() (rune, int, error) {
}
func (sc *elemRuneTypeScanner) UnreadRune() error {
+ ret := sc.inner.UnreadRune()
sc.repeat = true
- return sc.inner.UnreadRune()
+ return ret
}
func (sc *elemRuneTypeScanner) InputOffset() int64 { return sc.inner.InputOffset() }