gojay

high performance JSON encoder/decoder with stream API for Golang
git clone git://git.lair.cx/gojay
Log | Files | Refs | README | LICENSE

commit 5d576d6e2e8d5991f65837611dbdd54a942e79f6
parent cc21d73a8fa3d9e51582b80b8bddfc472c864df2
Author: francois.parquet <francois.parquet@lalamove.com>
Date:   Wed,  8 Aug 2018 14:33:14 +0800

fix bug on escape sequence when skiping object or array

Diffstat:
Mdecode_array.go | 16++++++++++++----
Mdecode_array_test.go | 12+++++++++---
Mdecode_object.go | 14+++++++++++---
Mdecode_object_test.go | 2+-
4 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/decode_array.go b/decode_array.go @@ -79,26 +79,34 @@ func (dec *Decoder) skipArray() (int, error) { arraysOpen++ case '"': j++ + var isInEscapeSeq bool + var isFirstQuote = true for ; j < dec.length || dec.read(); j++ { if dec.data[j] != '"' { continue } - if dec.data[j-1] != '\\' { + if dec.data[j-1] != '\\' || (!isInEscapeSeq && !isFirstQuote) { break + } else { + isInEscapeSeq = false + } + if isFirstQuote { + isFirstQuote = false } // loop backward and count how many anti slash found // to see if string is effectively escaped - ct := 1 - for i := j - 2; i > 0; i-- { + ct := 0 + for i := j - 1; i > 0; i-- { if dec.data[i] != '\\' { break } ct++ } - // is even number of slashes, quote is not escaped + // is pair number of slashes, quote is not escaped if ct&1 == 0 { break } + isInEscapeSeq = true } default: continue diff --git a/decode_array_test.go b/decode_array_test.go @@ -510,10 +510,12 @@ func TestUnmarshalJSONArrays(t *testing.T) { func TestSkipArray(t *testing.T) { testCases := []struct { + name string json string expectations func(*testing.T, int, error) }{ { + name: "basic", json: `"testbasic"]`, expectations: func(t *testing.T, i int, err error) { assert.Equal(t, len(`"testbasic"]`), i) @@ -521,6 +523,7 @@ func TestSkipArray(t *testing.T) { }, }, { + name: "complex escape string", json: `"test \\\\\" escape"]`, expectations: func(t *testing.T, i int, err error) { assert.Equal(t, len(`"test \\\\\" escape"]`), i) @@ -528,6 +531,7 @@ func TestSkipArray(t *testing.T) { }, }, { + name: "complex escape slash", json: `"test \\\\\\"]`, expectations: func(t *testing.T, i int, err error) { assert.Equal(t, len(`"test \\\\\\"]`), i) @@ -544,9 +548,11 @@ func TestSkipArray(t *testing.T) { } for _, test := range testCases { - dec := NewDecoder(strings.NewReader(test.json)) - i, err := dec.skipArray() - test.expectations(t, i, err) + t.Run(test.name, func(t *testing.T) { + dec := NewDecoder(strings.NewReader(test.json)) + i, err := dec.skipArray() + test.expectations(t, i, err) + }) } } diff --git a/decode_object.go b/decode_object.go @@ -116,16 +116,23 @@ func (dec *Decoder) skipObject() (int, error) { objectsOpen++ case '"': j++ + var isInEscapeSeq bool + var isFirstQuote = true for ; j < dec.length || dec.read(); j++ { if dec.data[j] != '"' { continue } - if dec.data[j-1] != '\\' { + if dec.data[j-1] != '\\' || (!isInEscapeSeq && !isFirstQuote) { break + } else { + isInEscapeSeq = false + } + if isFirstQuote { + isFirstQuote = false } // loop backward and count how many anti slash found // to see if string is effectively escaped - ct := 1 + ct := 0 for i := j - 1; i > 0; i-- { if dec.data[i] != '\\' { break @@ -134,8 +141,9 @@ func (dec *Decoder) skipObject() (int, error) { } // is pair number of slashes, quote is not escaped if ct&1 == 0 { - continue + break } + isInEscapeSeq = true } default: continue diff --git a/decode_object_test.go b/decode_object_test.go @@ -1370,7 +1370,7 @@ func TestSkipObject(t *testing.T) { }, { name: "basic-escaped", - json: `"key":"value\\\\\\" hello"}`, + json: `"key":"value\\\\\\\" hello"}`, }, { name: "basic-err",