summaryrefslogtreecommitdiff
path: root/decode_scan.go
diff options
context:
space:
mode:
Diffstat (limited to 'decode_scan.go')
-rw-r--r--decode_scan.go28
1 files changed, 22 insertions, 6 deletions
diff --git a/decode_scan.go b/decode_scan.go
index 63694c4..7ef3e71 100644
--- a/decode_scan.go
+++ b/decode_scan.go
@@ -6,6 +6,7 @@ package lowmemjson
import (
"io"
+ "unicode/utf8"
"git.lukeshu.com/go/lowmemjson/internal/jsonparse"
)
@@ -22,10 +23,11 @@ type runeTypeScanner struct {
rTypeOK bool
repeat bool
- rRune rune
- rSize int
- rType jsonparse.RuneType
- rErr error
+ rRune rune
+ rSize int
+ rIsRune bool
+ rType jsonparse.RuneType
+ rErr error
}
// The returned error is a *ReadError, a *SyntaxError, or nil.
@@ -55,7 +57,18 @@ func (sc *runeTypeScanner) ReadRuneType() (rune, int, jsonparse.RuneType, error)
sc.offset += int64(sc.rSize)
switch err {
case nil:
- sc.rType, err = sc.parser.HandleRune(sc.rRune)
+ sc.rIsRune = true
+ if sc.rRune == utf8.RuneError && sc.rSize == 1 {
+ if bs, ok := sc.inner.(io.ByteScanner); ok {
+ _ = bs.UnreadByte() // UnreadRune doesn't back up the ReadByte-pos
+ b, _ := bs.ReadByte()
+ _ = bs.UnreadByte()
+ _, _, _ = sc.inner.ReadRune()
+ sc.rRune = rune(b)
+ sc.rIsRune = false
+ }
+ }
+ sc.rType, err = sc.parser.HandleRune(sc.rRune, sc.rIsRune)
if err != nil {
sc.rErr = &DecodeSyntaxError{
Offset: sc.offset - int64(sc.rSize),
@@ -92,6 +105,9 @@ func (sc *runeTypeScanner) ReadRuneType() (rune, int, jsonparse.RuneType, error)
}
}
sc.repeat = false
+ if sc.rSize > 0 && !sc.rIsRune {
+ return utf8.RuneError, sc.rSize, sc.rType, sc.rErr
+ }
return sc.rRune, sc.rSize, sc.rType, sc.rErr
}
@@ -124,7 +140,7 @@ func (sc *runeTypeScanner) PopReadBarrier() {
case sc.repeat:
// re-figure the rType and rErr
var err error
- sc.rType, err = sc.parser.HandleRune(sc.rRune)
+ sc.rType, err = sc.parser.HandleRune(sc.rRune, sc.rIsRune)
if err != nil {
sc.rErr = &DecodeSyntaxError{
Offset: sc.offset - int64(sc.rSize),