diff --git a/feature_adapter.go b/feature_adapter.go index edb477c4..40a701ab 100644 --- a/feature_adapter.go +++ b/feature_adapter.go @@ -125,3 +125,8 @@ func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) { config.EscapeHTML = escapeHTML adapter.stream.cfg = config.Froze().(*frozenConfig) } + +// Valid reports whether data is a valid JSON encoding. +func Valid(data []byte) bool { + return ConfigDefault.Valid(data) +} diff --git a/feature_config.go b/feature_config.go index 3201bcdc..68721082 100644 --- a/feature_config.go +++ b/feature_config.go @@ -45,6 +45,7 @@ type API interface { Get(data []byte, path ...interface{}) Any NewEncoder(writer io.Writer) *Encoder NewDecoder(reader io.Reader) *Decoder + Valid(data []byte) bool } // ConfigDefault the default API @@ -333,3 +334,10 @@ func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder { iter := Parse(cfg, reader, 512) return &Decoder{iter} } + +func (cfg *frozenConfig) Valid(data []byte) bool { + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + iter.Skip() + return iter.Error == nil +} diff --git a/feature_iter.go b/feature_iter.go index dc7026c5..54a3a0fd 100644 --- a/feature_iter.go +++ b/feature_iter.go @@ -215,7 +215,7 @@ func (iter *Iterator) ReportError(operation string, msg string) { } context := string(iter.buf[contextStart:contextEnd]) iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...", - operation, msg, iter.head - peekStart, parsing, context) + operation, msg, iter.head-peekStart, parsing, context) } // CurrentBuffer gets current buffer as string for debugging purpose diff --git a/feature_iter_array.go b/feature_iter_array.go index 73360944..6188cb45 100644 --- a/feature_iter_array.go +++ b/feature_iter_array.go @@ -42,7 +42,7 @@ func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { c = iter.nextToken() } if c != ']' { - iter.ReportError("ReadArrayCB", "expect ] in the end, but found " + string([]byte{c})) + iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c})) return false } return true diff --git a/feature_iter_object.go b/feature_iter_object.go index 0b2205b8..6ec8fb7f 100644 --- a/feature_iter_object.go +++ b/feature_iter_object.go @@ -24,7 +24,7 @@ func (iter *Iterator) ReadObject() (ret string) { if c == '}' { return "" // end of object } - iter.ReportError("ReadObject", `expect " after {, but found ` + string([]byte{c})) + iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c})) return case ',': return string(iter.readObjectFieldAsBytes()) @@ -105,14 +105,14 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { if c == '}' { return true } - iter.ReportError("ReadObjectCB", `expect " after }, but found ` + string([]byte{c})) + iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c})) return false } if c == 'n' { iter.skipThreeBytes('u', 'l', 'l') return true // null } - iter.ReportError("ReadObjectCB", `expect { or n, but found ` + string([]byte{c})) + iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c})) return false } @@ -125,7 +125,7 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { iter.unreadByte() field := iter.ReadString() if iter.nextToken() != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found " + string([]byte{c})) + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) return false } if !callback(iter, field) { @@ -135,7 +135,7 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { for c == ',' { field = iter.ReadString() if iter.nextToken() != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found " + string([]byte{c})) + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) return false } if !callback(iter, field) { @@ -152,14 +152,14 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { if c == '}' { return true } - iter.ReportError("ReadMapCB", `expect " after }, but found ` + string([]byte{c})) + iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c})) return false } if c == 'n' { iter.skipThreeBytes('u', 'l', 'l') return true // null } - iter.ReportError("ReadMapCB", `expect { or n, but found ` + string([]byte{c})) + iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) return false } @@ -176,7 +176,7 @@ func (iter *Iterator) readObjectStart() bool { iter.skipThreeBytes('u', 'l', 'l') return false } - iter.ReportError("readObjectStart", "expect { or n, but found " + string([]byte{c})) + iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c})) return false } @@ -192,7 +192,7 @@ func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) { } } if iter.buf[iter.head] != ':' { - iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found " + string([]byte{iter.buf[iter.head]})) + iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]})) return } iter.head++ diff --git a/feature_iter_skip.go b/feature_iter_skip.go index e6c81fb1..f58beb91 100644 --- a/feature_iter_skip.go +++ b/feature_iter_skip.go @@ -25,7 +25,7 @@ func (iter *Iterator) ReadBool() (ret bool) { iter.skipFourBytes('a', 'l', 's', 'e') return false } - iter.ReportError("ReadBool", "expect t or f, but found " + string([]byte{c})) + iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c})) return } diff --git a/feature_iter_string.go b/feature_iter_string.go index a2a57274..adc487ea 100644 --- a/feature_iter_string.go +++ b/feature_iter_string.go @@ -28,7 +28,7 @@ func (iter *Iterator) ReadString() (ret string) { iter.skipThreeBytes('u', 'l', 'l') return "" } - iter.ReportError("ReadString", `expects " or n, but found ` + string([]byte{c})) + iter.ReportError("ReadString", `expects " or n, but found `+string([]byte{c})) return } @@ -139,7 +139,7 @@ func (iter *Iterator) ReadStringAsSlice() (ret []byte) { } return copied } - iter.ReportError("ReadStringAsSlice", `expects " or n, but found ` + string([]byte{c})) + iter.ReportError("ReadStringAsSlice", `expects " or n, but found `+string([]byte{c})) return } @@ -156,7 +156,7 @@ func (iter *Iterator) readU4() (ret rune) { } else if c >= 'A' && c <= 'F' { ret = ret*16 + rune(c-'A'+10) } else { - iter.ReportError("readU4", "expects 0~9 or a~f, but found " + string([]byte{c})) + iter.ReportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c})) return } } diff --git a/feature_reflect_native.go b/feature_reflect_native.go index 50c5c457..95bd1e87 100644 --- a/feature_reflect_native.go +++ b/feature_reflect_native.go @@ -608,7 +608,7 @@ type stringModeNumberDecoder struct { func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { c := iter.nextToken() if c != '"' { - iter.ReportError("stringModeNumberDecoder", `expect ", but found ` + string([]byte{c})) + iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) return } decoder.elemDecoder.Decode(ptr, iter) @@ -617,7 +617,7 @@ func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterato } c = iter.readByte() if c != '"' { - iter.ReportError("stringModeNumberDecoder", `expect ", but found ` + string([]byte{c})) + iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) return } } diff --git a/jsoniter_invalid_test.go b/jsoniter_invalid_test.go index 9f30bf5d..69be4dc5 100644 --- a/jsoniter_invalid_test.go +++ b/jsoniter_invalid_test.go @@ -130,3 +130,9 @@ func Test_invalid_number(t *testing.T) { should.Nil(err) should.Equal(string(result2), string(result)) } + +func Test_valid(t *testing.T) { + should := require.New(t) + should.True(Valid([]byte(`{}`))) + should.False(Valid([]byte(`{`))) +}