From 20347573683aca32e401ce2b099c907a3e955462 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Sun, 2 May 2021 17:01:56 +0900 Subject: [PATCH] Fix stream decoding for null/true/false value --- decode_bool.go | 48 ----------------------- decode_stream.go | 99 ++++++++++++++++++++++++++++++++++++++++++++++++ decode_string.go | 22 ----------- json_test.go | 9 +++++ 4 files changed, 108 insertions(+), 70 deletions(-) diff --git a/decode_bool.go b/decode_bool.go index 84a4a3d..d818896 100644 --- a/decode_bool.go +++ b/decode_bool.go @@ -13,54 +13,6 @@ func newBoolDecoder(structName, fieldName string) *boolDecoder { return &boolDecoder{structName: structName, fieldName: fieldName} } -func trueBytes(s *stream) error { - if s.cursor+3 >= s.length { - if !s.read() { - return errInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) - } - } - s.cursor++ - if s.char() != 'r' { - return errInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) - } - s.cursor++ - if s.char() != 'u' { - return errInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) - } - s.cursor++ - if s.char() != 'e' { - return errInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) - } - s.cursor++ - return nil -} - -func falseBytes(s *stream) error { - if s.cursor+4 >= s.length { - if !s.read() { - return errInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) - } - } - s.cursor++ - if s.char() != 'a' { - return errInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) - } - s.cursor++ - if s.char() != 'l' { - return errInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) - } - s.cursor++ - if s.char() != 's' { - return errInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) - } - s.cursor++ - if s.char() != 'e' { - return errInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) - } - s.cursor++ - return nil -} - func (d *boolDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { s.skipWhiteSpace() for { diff --git a/decode_stream.go b/decode_stream.go index 257b8fc..b1c99f9 100644 --- a/decode_stream.go +++ b/decode_stream.go @@ -313,3 +313,102 @@ func (s *stream) skipValue(depth int64) error { cursor++ } } + +func nullBytes(s *stream) error { + // current cursor's character is 'n' + s.cursor++ + if s.char() != 'u' { + if err := retryReadNull(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'l' { + if err := retryReadNull(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'l' { + if err := retryReadNull(s); err != nil { + return err + } + } + s.cursor++ + return nil +} + +func retryReadNull(s *stream) error { + if s.char() == nul && s.read() { + return nil + } + return errInvalidCharacter(s.char(), "null", s.totalOffset()) +} + +func trueBytes(s *stream) error { + // current cursor's character is 't' + s.cursor++ + if s.char() != 'r' { + if err := retryReadTrue(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'u' { + if err := retryReadTrue(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'e' { + if err := retryReadTrue(s); err != nil { + return err + } + } + s.cursor++ + return nil +} + +func retryReadTrue(s *stream) error { + if s.char() == nul && s.read() { + return nil + } + return errInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) +} + +func falseBytes(s *stream) error { + // current cursor's character is 'f' + s.cursor++ + if s.char() != 'a' { + if err := retryReadFalse(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'l' { + if err := retryReadFalse(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 's' { + if err := retryReadFalse(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'e' { + if err := retryReadFalse(s); err != nil { + return err + } + } + s.cursor++ + return nil +} + +func retryReadFalse(s *stream) error { + if s.char() == nul && s.read() { + return nil + } + return errInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) +} diff --git a/decode_string.go b/decode_string.go index e87222e..c258257 100644 --- a/decode_string.go +++ b/decode_string.go @@ -233,28 +233,6 @@ ERROR: return nil, errUnexpectedEndOfJSON("string", s.totalOffset()) } -func nullBytes(s *stream) error { - if s.cursor+3 >= s.length { - if !s.read() { - return errInvalidCharacter(s.char(), "null", s.totalOffset()) - } - } - s.cursor++ - if s.char() != 'u' { - return errInvalidCharacter(s.char(), "null", s.totalOffset()) - } - s.cursor++ - if s.char() != 'l' { - return errInvalidCharacter(s.char(), "null", s.totalOffset()) - } - s.cursor++ - if s.char() != 'l' { - return errInvalidCharacter(s.char(), "null", s.totalOffset()) - } - s.cursor++ - return nil -} - func (d *stringDecoder) decodeStreamByte(s *stream) ([]byte, error) { for { switch s.char() { diff --git a/json_test.go b/json_test.go index 47a6c38..869b783 100644 --- a/json_test.go +++ b/json_test.go @@ -32,6 +32,15 @@ func TestValid(t *testing.T) { } } +func TestValidWithComplexData(t *testing.T) { + data := []byte(`{"ABCDEFGHIJKL":[{"MNOPQRSTUVWX":[{"YABC":{"DEFG":[{"HIJKLMNO":{"PQRS":"TUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDE","FGHIJKLM":"NOPQRSTUVW"},"XYABCDEFGH":[{"IJKLMNOP":"!=","Q":{"RSTU":"V","WXYABCDE":"FGHIJKLMNO"},"P":{"QRSTUVWX":"YAB"},"CDEFGHIJ":"KLMNOP","QRSTUVWX":"YABCDEFGHI"}],"JKLMNOPQRSTUVW":null,"XYABCDEF":"GHIJ"},{"KLMNOPQR":{"STUVWXY":{"ABCDEFGH":"IJKLMN_OPQ_RST","U":{"VWXY":"A","BCDEFGHI":"JKLMNOPQRS"},"TUVWXYAB":"CDEFG","HIJKLMNO":"PQRSTUVWXY"},"ABCDEFGH":"IJKLMNOP!Q41R8ST98U00V204W9800998XYA8427B","CDEFGHIJ":"KLMNOP","QRSTUVWX":"YABCDEFGHI"},"JKLMNOPQRS":null,"TUVWXYABCDEFGH":null,"IJKLMNOP":"QRST"}],"UVWXYABC":"DEFGH","IJKLMNOP":"QRSTUVWXY"},"ABCDEFGH":9,"IJKL":"MNOPQRST/UVWXYABCDE//FGHIJKLMNOPQRST!4UV2WXYABC7826D7659EF223GH40I91J","KLMNOPQRST":[{"UVWXYABCDEFG":null,"HIJKLMNO":0,"PQRS":"T","UVWX":{"YABC":{"DEFG":"HIJK/LMNO/PQRSTU","VWXYABCD":"EFGHIJKLM","NOPQRSTU":"VWXY"},"ABCDEFGH":"IJKLMNO","PQRSTUVW":"XYAB"},"CDEFGHIJ":"KLMNOPQR"}],"STUVWXYA":null,"BCDEFGH":null,"IJKLMN":null,"OPQRSTUVWXYABC":null,"DEFGHIJK":"LMNOPQRS"},{"TUVW":{"XYAB":[{"CDEFGHIJ":{"KLMN":"OPQRSTUV/WXYABCDEFG//HIJKLMNOPQRSTUV!4WX2YABCDE7826F7659GH223IJ40K91L","MNOPQRST":"UVWXYABCDE"},"FGHIJKLMNO":[{"PQRS":"T","UVWXYABC":"DEFGHIJKLM"}],"NOPQRSTUVWXYAB":null,"CDEFGHIJ":"KLMN"}],"OPQRSTUV":"WXYAB","CDEFGHIJ":"KLMNOPQRS"},"TUVWXYAB":9,"CDEF":"GHIJKLMN/OPQRSTUVWX//YABCDEFGHIJKLM!4NO2PQRSTU7826V7659WX223YA40B91C","DEFGHIJKLM":[{"NOPQRSTUVWXY":null,"ABCDEFGH":0,"IJKL":"M","NOPQ":{"RSTU":{"VWXY":"ABCD/EFGH/IJKLMN","OPQRSTUV":"WXYABCDEF","GHIJKLMN":"OPQR"},"STUVWXYA":"BCDEFGH","IJKLMNOP":"QRST"},"UVWXYABC":"DEFGHIJK"}],"LMNOPQRS":null,"TUVWXYA":null,"BCDEFG":null,"HIJKLMNOPQRSTU":null,"VWXYABCD":"EFGHIJKL"},{"MNOP":{"QRST":[{"UVWXYABC":0,"DEFG":["HIJK"],"LMNO":[{"PQRS":{"TUVW":"XYABCDEF/GHIJKLMNOP","QRSTUVWX":"YABCDEFGH","IJKLMNOP":"QRST"},"UVWXYABC":"DEFGHIJ","KLMNOPQR":"STUV"}],"WXYAB":[{"CDEF":{"GHIJ":{"KLMN":"OPQRSTUV/WXYABCDEFG","HIJKLMNO":"PQRSTUVWX","YABCDEFG":"HIJK"},"LMNOPQRS":"TUVWXYA","BCDEFGHI":"JKLM"},"NOPQRSTU":"VWX"}],"YABCDEFG":"HIJKLMNOPQR","STUVWXYA":"BCDEFGHIJ"},{"KLMNOPQR":"=","S":{"TUVWXYA":{"BCDE":"FGHI","JKLMNOPQ":"RSTUVWXYAB"},"CDEFGHIJ":"@KLMN/OPQR/STUVWX","YABCDEFG":"HIJKLM","NOPQRSTU":"VWXYABCDEF"},"G":{"HIJKLMNO":{"PQRS":"TUVW/XYAB/CDEFGH//IJKLMN!O41P8QR98S00T204U9800998VWX8427Y","ABCDEFGH":"IJKLMNOPQR"},"STUVWXYABC":null,"DEFGHIJKLMNOPQ":null,"RSTUVWXY":"ABCD"},"EFGHIJKL":"MNOPQR","STUVWXYA":"BCDEFGHIJK"},{"LMNOPQR":[{"STUV":"WXYA","BCDEFGHI":"JKLMNOPQRS"}],"TUVWXYAB":"CDEFGH","IJKLMNOP":"QRSTUVWXY"}],"ABCDEFGH":"IJKLM","NOPQRSTU":"VWXYABCDE"},"FGHIJKLM":37,"NOPQ":"RSTUVWXY/ABCDEFGHIJ//KLMNOPQRST!U41V8WX98Y00A204B9800998CDE8427F","GHIJKLMNOP":null,"QRSTUVWX":null,"YABCDEF":[{"GHIJKLMNOPQR":null,"STUVWXYA":0,"BCDE":"","FGHI":{"JKLM":{"NOPQ":"RSTUVWXY/ABCDEFGHIJ","KLMNOPQR":"STUVWXYAB","CDEFGHIJ":"KLMN"},"OPQRSTUV":"WXYABCD","EFGHIJKL":"MNOP"},"QRSTUVWX":"YABCDEFG"}],"HIJKLM":null,"NOPQRSTUVWXYAB":null,"CDEFGHIJ":"KLMNOPQR"}],"STUVWXYABC":null,"DEFGHIJK":[{"LMNO":{"PQRS":"TUVW/XYAB/CDEFGH","IJKLMNOP":"QRSTUVWXY","ABCDEFGH":"IJKL"},"MNOPQRST":"UVWXYAB","CDEFGHIJ":"KLMN"}],"OPQRSTUV":1,"WXYA":"BCDEFGHI/JKLMNOPQRS","TUVWXYAB":null,"CDEFGHIJKLMNOP":null,"QRSTUVWX":"YABCDE","FGHIJKLM":"NOPQ"}]}`) + expected := stdjson.Valid(data) + actual := json.Valid(data) + if expected != actual { + t.Fatalf("failed to valid: expected %v but got %v", expected, actual) + } +} + type example struct { compact string indent string