1
2
3
4
5
6
7 package json
8
9 import (
10 "errors"
11 "io"
12 "strings"
13
14 "encoding/json/internal"
15 "encoding/json/internal/jsonflags"
16 "encoding/json/jsontext"
17 )
18
19
20 var export = jsontext.Internal.Export(&internal.AllowInternalUse)
21
22
23 func Valid(data []byte) bool {
24 return checkValid(data) == nil
25 }
26
27 func checkValid(data []byte) error {
28 d := export.GetBufferedDecoder(data)
29 defer export.PutBufferedDecoder(d)
30 xd := export.Decoder(d)
31 xd.Struct.Flags.Set(jsonflags.AllowDuplicateNames | jsonflags.AllowInvalidUTF8 | 1)
32 if _, err := d.ReadValue(); err != nil {
33 return transformSyntacticError(err)
34 }
35 if err := xd.CheckEOF(); err != nil {
36 return transformSyntacticError(err)
37 }
38 return nil
39 }
40
41
42
43 type SyntaxError struct {
44 msg string
45 Offset int64
46 }
47
48 func (e *SyntaxError) Error() string { return e.msg }
49
50 var errUnexpectedEnd = errors.New("unexpected end of JSON input")
51
52 func transformSyntacticError(err error) error {
53 switch serr, ok := err.(*jsontext.SyntacticError); {
54 case serr != nil:
55 if serr.Err == io.ErrUnexpectedEOF {
56 serr.Err = errUnexpectedEnd
57 }
58 msg := serr.Err.Error()
59 if i := strings.Index(msg, " (expecting"); i >= 0 && !strings.Contains(msg, " in literal") {
60 msg = msg[:i]
61 }
62 return &SyntaxError{Offset: serr.ByteOffset, msg: syntaxErrorReplacer.Replace(msg)}
63 case ok:
64 return (*SyntaxError)(nil)
65 case export.IsIOError(err):
66 return errors.Unwrap(err)
67 default:
68 return err
69 }
70 }
71
72
73
74
75
76 var syntaxErrorReplacer = strings.NewReplacer(
77 "object name", "object key",
78 "at start of value", "looking for beginning of value",
79 "at start of string", "looking for beginning of object key string",
80 "after object value", "after object key:value pair",
81 "in number", "in numeric literal",
82 )
83
View as plain text