diff options
Diffstat (limited to 'decode_scan.go')
-rw-r--r-- | decode_scan.go | 28 |
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), |