Source file src/encoding/json/v2_scanner.go

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build goexperiment.jsonv2
     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  // export exposes internal functionality of the "jsontext" package.
    20  var export = jsontext.Internal.Export(&internal.AllowInternalUse)
    21  
    22  // Valid reports whether data is a valid JSON encoding.
    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  // A SyntaxError is a description of a JSON syntax error.
    42  // [Unmarshal] will return a SyntaxError if the JSON can't be parsed.
    43  type SyntaxError struct {
    44  	msg    string // description of error
    45  	Offset int64  // error occurred after reading Offset bytes
    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) // v1 historically did not wrap IO errors
    67  	default:
    68  		return err
    69  	}
    70  }
    71  
    72  // syntaxErrorReplacer replaces certain string literals in the v2 error
    73  // to better match the historical string rendering of syntax errors.
    74  // In particular, v2 uses the terminology "object name" to match RFC 8259,
    75  // while v1 uses "object key", which is not a term found in JSON literature.
    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