package json
import (
"encoding"
"encoding/base64"
"fmt"
"reflect"
"strconv"
"strings"
"unicode"
"unicode/utf16"
"unicode/utf8"
_ "unsafe"
)
func Unmarshal (data []byte , v any ) error {
var d decodeState
err := checkValid (data , &d .scan )
if err != nil {
return err
}
d .init (data )
return d .unmarshal (v )
}
type Unmarshaler interface {
UnmarshalJSON ([]byte ) error
}
type UnmarshalTypeError struct {
Value string
Type reflect .Type
Offset int64
Struct string
Field string
}
func (e *UnmarshalTypeError ) Error () string {
if e .Struct != "" || e .Field != "" {
return "json: cannot unmarshal " + e .Value + " into Go struct field " + e .Struct + "." + e .Field + " of type " + e .Type .String ()
}
return "json: cannot unmarshal " + e .Value + " into Go value of type " + e .Type .String ()
}
type UnmarshalFieldError struct {
Key string
Type reflect .Type
Field reflect .StructField
}
func (e *UnmarshalFieldError ) Error () string {
return "json: cannot unmarshal object key " + strconv .Quote (e .Key ) + " into unexported field " + e .Field .Name + " of type " + e .Type .String ()
}
type InvalidUnmarshalError struct {
Type reflect .Type
}
func (e *InvalidUnmarshalError ) Error () string {
if e .Type == nil {
return "json: Unmarshal(nil)"
}
if e .Type .Kind () != reflect .Pointer {
return "json: Unmarshal(non-pointer " + e .Type .String () + ")"
}
return "json: Unmarshal(nil " + e .Type .String () + ")"
}
func (d *decodeState ) unmarshal (v any ) error {
rv := reflect .ValueOf (v )
if rv .Kind () != reflect .Pointer || rv .IsNil () {
return &InvalidUnmarshalError {reflect .TypeOf (v )}
}
d .scan .reset ()
d .scanWhile (scanSkipSpace )
err := d .value (rv )
if err != nil {
return d .addErrorContext (err )
}
return d .savedError
}
type Number string
func (n Number ) String () string { return string (n ) }
func (n Number ) Float64 () (float64 , error ) {
return strconv .ParseFloat (string (n ), 64 )
}
func (n Number ) Int64 () (int64 , error ) {
return strconv .ParseInt (string (n ), 10 , 64 )
}
type errorContext struct {
Struct reflect .Type
FieldStack []string
}
type decodeState struct {
data []byte
off int
opcode int
scan scanner
errorContext *errorContext
savedError error
useNumber bool
disallowUnknownFields bool
}
func (d *decodeState ) readIndex () int {
return d .off - 1
}
const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?"
func (d *decodeState ) init (data []byte ) *decodeState {
d .data = data
d .off = 0
d .savedError = nil
if d .errorContext != nil {
d .errorContext .Struct = nil
d .errorContext .FieldStack = d .errorContext .FieldStack [:0 ]
}
return d
}
func (d *decodeState ) saveError (err error ) {
if d .savedError == nil {
d .savedError = d .addErrorContext (err )
}
}
func (d *decodeState ) addErrorContext (err error ) error {
if d .errorContext != nil && (d .errorContext .Struct != nil || len (d .errorContext .FieldStack ) > 0 ) {
switch err := err .(type ) {
case *UnmarshalTypeError :
err .Struct = d .errorContext .Struct .Name ()
err .Field = strings .Join (d .errorContext .FieldStack , "." )
}
}
return err
}
func (d *decodeState ) skip () {
s , data , i := &d .scan , d .data , d .off
depth := len (s .parseState )
for {
op := s .step (s , data [i ])
i ++
if len (s .parseState ) < depth {
d .off = i
d .opcode = op
return
}
}
}
func (d *decodeState ) scanNext () {
if d .off < len (d .data ) {
d .opcode = d .scan .step (&d .scan , d .data [d .off ])
d .off ++
} else {
d .opcode = d .scan .eof ()
d .off = len (d .data ) + 1
}
}
func (d *decodeState ) scanWhile (op int ) {
s , data , i := &d .scan , d .data , d .off
for i < len (data ) {
newOp := s .step (s , data [i ])
i ++
if newOp != op {
d .opcode = newOp
d .off = i
return
}
}
d .off = len (data ) + 1
d .opcode = d .scan .eof ()
}
func (d *decodeState ) rescanLiteral () {
data , i := d .data , d .off
Switch :
switch data [i -1 ] {
case '"' :
for ; i < len (data ); i ++ {
switch data [i ] {
case '\\' :
i ++
case '"' :
i ++
break Switch
}
}
case '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '-' :
for ; i < len (data ); i ++ {
switch data [i ] {
case '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ,
'.' , 'e' , 'E' , '+' , '-' :
default :
break Switch
}
}
case 't' :
i += len ("rue" )
case 'f' :
i += len ("alse" )
case 'n' :
i += len ("ull" )
}
if i < len (data ) {
d .opcode = stateEndValue (&d .scan , data [i ])
} else {
d .opcode = scanEnd
}
d .off = i + 1
}
func (d *decodeState ) value (v reflect .Value ) error {
switch d .opcode {
default :
panic (phasePanicMsg )
case scanBeginArray :
if v .IsValid () {
if err := d .array (v ); err != nil {
return err
}
} else {
d .skip ()
}
d .scanNext ()
case scanBeginObject :
if v .IsValid () {
if err := d .object (v ); err != nil {
return err
}
} else {
d .skip ()
}
d .scanNext ()
case scanBeginLiteral :
start := d .readIndex ()
d .rescanLiteral ()
if v .IsValid () {
if err := d .literalStore (d .data [start :d .readIndex ()], v , false ); err != nil {
return err
}
}
}
return nil
}
type unquotedValue struct {}
func (d *decodeState ) valueQuoted () any {
switch d .opcode {
default :
panic (phasePanicMsg )
case scanBeginArray , scanBeginObject :
d .skip ()
d .scanNext ()
case scanBeginLiteral :
v := d .literalInterface ()
switch v .(type ) {
case nil , string :
return v
}
}
return unquotedValue {}
}
func indirect(v reflect .Value , decodingNull bool ) (Unmarshaler , encoding .TextUnmarshaler , reflect .Value ) {
v0 := v
haveAddr := false
if v .Kind () != reflect .Pointer && v .Type ().Name () != "" && v .CanAddr () {
haveAddr = true
v = v .Addr ()
}
for {
if v .Kind () == reflect .Interface && !v .IsNil () {
e := v .Elem ()
if e .Kind () == reflect .Pointer && !e .IsNil () && (!decodingNull || e .Elem ().Kind () == reflect .Pointer ) {
haveAddr = false
v = e
continue
}
}
if v .Kind () != reflect .Pointer {
break
}
if decodingNull && v .CanSet () {
break
}
if v .Elem ().Kind () == reflect .Interface && v .Elem ().Elem () == v {
v = v .Elem ()
break
}
if v .IsNil () {
v .Set (reflect .New (v .Type ().Elem ()))
}
if v .Type ().NumMethod () > 0 && v .CanInterface () {
if u , ok := v .Interface ().(Unmarshaler ); ok {
return u , nil , reflect .Value {}
}
if !decodingNull {
if u , ok := v .Interface ().(encoding .TextUnmarshaler ); ok {
return nil , u , reflect .Value {}
}
}
}
if haveAddr {
v = v0
haveAddr = false
} else {
v = v .Elem ()
}
}
return nil , nil , v
}
func (d *decodeState ) array (v reflect .Value ) error {
u , ut , pv := indirect (v , false )
if u != nil {
start := d .readIndex ()
d .skip ()
return u .UnmarshalJSON (d .data [start :d .off ])
}
if ut != nil {
d .saveError (&UnmarshalTypeError {Value : "array" , Type : v .Type (), Offset : int64 (d .off )})
d .skip ()
return nil
}
v = pv
switch v .Kind () {
case reflect .Interface :
if v .NumMethod () == 0 {
ai := d .arrayInterface ()
v .Set (reflect .ValueOf (ai ))
return nil
}
fallthrough
default :
d .saveError (&UnmarshalTypeError {Value : "array" , Type : v .Type (), Offset : int64 (d .off )})
d .skip ()
return nil
case reflect .Array , reflect .Slice :
break
}
i := 0
for {
d .scanWhile (scanSkipSpace )
if d .opcode == scanEndArray {
break
}
if v .Kind () == reflect .Slice {
if i >= v .Cap () {
v .Grow (1 )
}
if i >= v .Len () {
v .SetLen (i + 1 )
}
}
if i < v .Len () {
if err := d .value (v .Index (i )); err != nil {
return err
}
} else {
if err := d .value (reflect .Value {}); err != nil {
return err
}
}
i ++
if d .opcode == scanSkipSpace {
d .scanWhile (scanSkipSpace )
}
if d .opcode == scanEndArray {
break
}
if d .opcode != scanArrayValue {
panic (phasePanicMsg )
}
}
if i < v .Len () {
if v .Kind () == reflect .Array {
for ; i < v .Len (); i ++ {
v .Index (i ).SetZero ()
}
} else {
v .SetLen (i )
}
}
if i == 0 && v .Kind () == reflect .Slice {
v .Set (reflect .MakeSlice (v .Type (), 0 , 0 ))
}
return nil
}
var nullLiteral = []byte ("null" )
var textUnmarshalerType = reflect .TypeFor [encoding .TextUnmarshaler ]()
func (d *decodeState ) object (v reflect .Value ) error {
u , ut , pv := indirect (v , false )
if u != nil {
start := d .readIndex ()
d .skip ()
return u .UnmarshalJSON (d .data [start :d .off ])
}
if ut != nil {
d .saveError (&UnmarshalTypeError {Value : "object" , Type : v .Type (), Offset : int64 (d .off )})
d .skip ()
return nil
}
v = pv
t := v .Type ()
if v .Kind () == reflect .Interface && v .NumMethod () == 0 {
oi := d .objectInterface ()
v .Set (reflect .ValueOf (oi ))
return nil
}
var fields structFields
switch v .Kind () {
case reflect .Map :
switch t .Key ().Kind () {
case reflect .String ,
reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 ,
reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
default :
if !reflect .PointerTo (t .Key ()).Implements (textUnmarshalerType ) {
d .saveError (&UnmarshalTypeError {Value : "object" , Type : t , Offset : int64 (d .off )})
d .skip ()
return nil
}
}
if v .IsNil () {
v .Set (reflect .MakeMap (t ))
}
case reflect .Struct :
fields = cachedTypeFields (t )
default :
d .saveError (&UnmarshalTypeError {Value : "object" , Type : t , Offset : int64 (d .off )})
d .skip ()
return nil
}
var mapElem reflect .Value
var origErrorContext errorContext
if d .errorContext != nil {
origErrorContext = *d .errorContext
}
for {
d .scanWhile (scanSkipSpace )
if d .opcode == scanEndObject {
break
}
if d .opcode != scanBeginLiteral {
panic (phasePanicMsg )
}
start := d .readIndex ()
d .rescanLiteral ()
item := d .data [start :d .readIndex ()]
key , ok := unquoteBytes (item )
if !ok {
panic (phasePanicMsg )
}
var subv reflect .Value
destring := false
if v .Kind () == reflect .Map {
elemType := t .Elem ()
if !mapElem .IsValid () {
mapElem = reflect .New (elemType ).Elem ()
} else {
mapElem .SetZero ()
}
subv = mapElem
} else {
f := fields .byExactName [string (key )]
if f == nil {
f = fields .byFoldedName [string (foldName (key ))]
}
if f != nil {
subv = v
destring = f .quoted
for _ , i := range f .index {
if subv .Kind () == reflect .Pointer {
if subv .IsNil () {
if !subv .CanSet () {
d .saveError (fmt .Errorf ("json: cannot set embedded pointer to unexported struct: %v" , subv .Type ().Elem ()))
subv = reflect .Value {}
destring = false
break
}
subv .Set (reflect .New (subv .Type ().Elem ()))
}
subv = subv .Elem ()
}
subv = subv .Field (i )
}
if d .errorContext == nil {
d .errorContext = new (errorContext )
}
d .errorContext .FieldStack = append (d .errorContext .FieldStack , f .name )
d .errorContext .Struct = t
} else if d .disallowUnknownFields {
d .saveError (fmt .Errorf ("json: unknown field %q" , key ))
}
}
if d .opcode == scanSkipSpace {
d .scanWhile (scanSkipSpace )
}
if d .opcode != scanObjectKey {
panic (phasePanicMsg )
}
d .scanWhile (scanSkipSpace )
if destring {
switch qv := d .valueQuoted ().(type ) {
case nil :
if err := d .literalStore (nullLiteral , subv , false ); err != nil {
return err
}
case string :
if err := d .literalStore ([]byte (qv ), subv , true ); err != nil {
return err
}
default :
d .saveError (fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v" , subv .Type ()))
}
} else {
if err := d .value (subv ); err != nil {
return err
}
}
if v .Kind () == reflect .Map {
kt := t .Key ()
var kv reflect .Value
if reflect .PointerTo (kt ).Implements (textUnmarshalerType ) {
kv = reflect .New (kt )
if err := d .literalStore (item , kv , true ); err != nil {
return err
}
kv = kv .Elem ()
} else {
switch kt .Kind () {
case reflect .String :
kv = reflect .New (kt ).Elem ()
kv .SetString (string (key ))
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
s := string (key )
n , err := strconv .ParseInt (s , 10 , 64 )
if err != nil || kt .OverflowInt (n ) {
d .saveError (&UnmarshalTypeError {Value : "number " + s , Type : kt , Offset : int64 (start + 1 )})
break
}
kv = reflect .New (kt ).Elem ()
kv .SetInt (n )
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
s := string (key )
n , err := strconv .ParseUint (s , 10 , 64 )
if err != nil || kt .OverflowUint (n ) {
d .saveError (&UnmarshalTypeError {Value : "number " + s , Type : kt , Offset : int64 (start + 1 )})
break
}
kv = reflect .New (kt ).Elem ()
kv .SetUint (n )
default :
panic ("json: Unexpected key type" )
}
}
if kv .IsValid () {
v .SetMapIndex (kv , subv )
}
}
if d .opcode == scanSkipSpace {
d .scanWhile (scanSkipSpace )
}
if d .errorContext != nil {
d .errorContext .FieldStack = d .errorContext .FieldStack [:len (origErrorContext .FieldStack )]
d .errorContext .Struct = origErrorContext .Struct
}
if d .opcode == scanEndObject {
break
}
if d .opcode != scanObjectValue {
panic (phasePanicMsg )
}
}
return nil
}
func (d *decodeState ) convertNumber (s string ) (any , error ) {
if d .useNumber {
return Number (s ), nil
}
f , err := strconv .ParseFloat (s , 64 )
if err != nil {
return nil , &UnmarshalTypeError {Value : "number " + s , Type : reflect .TypeFor [float64 ](), Offset : int64 (d .off )}
}
return f , nil
}
var numberType = reflect .TypeFor [Number ]()
func (d *decodeState ) literalStore (item []byte , v reflect .Value , fromQuoted bool ) error {
if len (item ) == 0 {
d .saveError (fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ()))
return nil
}
isNull := item [0 ] == 'n'
u , ut , pv := indirect (v , isNull )
if u != nil {
return u .UnmarshalJSON (item )
}
if ut != nil {
if item [0 ] != '"' {
if fromQuoted {
d .saveError (fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ()))
return nil
}
val := "number"
switch item [0 ] {
case 'n' :
val = "null"
case 't' , 'f' :
val = "bool"
}
d .saveError (&UnmarshalTypeError {Value : val , Type : v .Type (), Offset : int64 (d .readIndex ())})
return nil
}
s , ok := unquoteBytes (item )
if !ok {
if fromQuoted {
return fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ())
}
panic (phasePanicMsg )
}
return ut .UnmarshalText (s )
}
v = pv
switch c := item [0 ]; c {
case 'n' :
if fromQuoted && string (item ) != "null" {
d .saveError (fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ()))
break
}
switch v .Kind () {
case reflect .Interface , reflect .Pointer , reflect .Map , reflect .Slice :
v .SetZero ()
}
case 't' , 'f' :
value := item [0 ] == 't'
if fromQuoted && string (item ) != "true" && string (item ) != "false" {
d .saveError (fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ()))
break
}
switch v .Kind () {
default :
if fromQuoted {
d .saveError (fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ()))
} else {
d .saveError (&UnmarshalTypeError {Value : "bool" , Type : v .Type (), Offset : int64 (d .readIndex ())})
}
case reflect .Bool :
v .SetBool (value )
case reflect .Interface :
if v .NumMethod () == 0 {
v .Set (reflect .ValueOf (value ))
} else {
d .saveError (&UnmarshalTypeError {Value : "bool" , Type : v .Type (), Offset : int64 (d .readIndex ())})
}
}
case '"' :
s , ok := unquoteBytes (item )
if !ok {
if fromQuoted {
return fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ())
}
panic (phasePanicMsg )
}
switch v .Kind () {
default :
d .saveError (&UnmarshalTypeError {Value : "string" , Type : v .Type (), Offset : int64 (d .readIndex ())})
case reflect .Slice :
if v .Type ().Elem ().Kind () != reflect .Uint8 {
d .saveError (&UnmarshalTypeError {Value : "string" , Type : v .Type (), Offset : int64 (d .readIndex ())})
break
}
b := make ([]byte , base64 .StdEncoding .DecodedLen (len (s )))
n , err := base64 .StdEncoding .Decode (b , s )
if err != nil {
d .saveError (err )
break
}
v .SetBytes (b [:n ])
case reflect .String :
t := string (s )
if v .Type () == numberType && !isValidNumber (t ) {
return fmt .Errorf ("json: invalid number literal, trying to unmarshal %q into Number" , item )
}
v .SetString (t )
case reflect .Interface :
if v .NumMethod () == 0 {
v .Set (reflect .ValueOf (string (s )))
} else {
d .saveError (&UnmarshalTypeError {Value : "string" , Type : v .Type (), Offset : int64 (d .readIndex ())})
}
}
default :
if c != '-' && (c < '0' || c > '9' ) {
if fromQuoted {
return fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ())
}
panic (phasePanicMsg )
}
switch v .Kind () {
default :
if v .Kind () == reflect .String && v .Type () == numberType {
v .SetString (string (item ))
break
}
if fromQuoted {
return fmt .Errorf ("json: invalid use of ,string struct tag, trying to unmarshal %q into %v" , item , v .Type ())
}
d .saveError (&UnmarshalTypeError {Value : "number" , Type : v .Type (), Offset : int64 (d .readIndex ())})
case reflect .Interface :
n , err := d .convertNumber (string (item ))
if err != nil {
d .saveError (err )
break
}
if v .NumMethod () != 0 {
d .saveError (&UnmarshalTypeError {Value : "number" , Type : v .Type (), Offset : int64 (d .readIndex ())})
break
}
v .Set (reflect .ValueOf (n ))
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
n , err := strconv .ParseInt (string (item ), 10 , 64 )
if err != nil || v .OverflowInt (n ) {
d .saveError (&UnmarshalTypeError {Value : "number " + string (item ), Type : v .Type (), Offset : int64 (d .readIndex ())})
break
}
v .SetInt (n )
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
n , err := strconv .ParseUint (string (item ), 10 , 64 )
if err != nil || v .OverflowUint (n ) {
d .saveError (&UnmarshalTypeError {Value : "number " + string (item ), Type : v .Type (), Offset : int64 (d .readIndex ())})
break
}
v .SetUint (n )
case reflect .Float32 , reflect .Float64 :
n , err := strconv .ParseFloat (string (item ), v .Type ().Bits ())
if err != nil || v .OverflowFloat (n ) {
d .saveError (&UnmarshalTypeError {Value : "number " + string (item ), Type : v .Type (), Offset : int64 (d .readIndex ())})
break
}
v .SetFloat (n )
}
}
return nil
}
func (d *decodeState ) valueInterface () (val any ) {
switch d .opcode {
default :
panic (phasePanicMsg )
case scanBeginArray :
val = d .arrayInterface ()
d .scanNext ()
case scanBeginObject :
val = d .objectInterface ()
d .scanNext ()
case scanBeginLiteral :
val = d .literalInterface ()
}
return
}
func (d *decodeState ) arrayInterface () []any {
var v = make ([]any , 0 )
for {
d .scanWhile (scanSkipSpace )
if d .opcode == scanEndArray {
break
}
v = append (v , d .valueInterface ())
if d .opcode == scanSkipSpace {
d .scanWhile (scanSkipSpace )
}
if d .opcode == scanEndArray {
break
}
if d .opcode != scanArrayValue {
panic (phasePanicMsg )
}
}
return v
}
func (d *decodeState ) objectInterface () map [string ]any {
m := make (map [string ]any )
for {
d .scanWhile (scanSkipSpace )
if d .opcode == scanEndObject {
break
}
if d .opcode != scanBeginLiteral {
panic (phasePanicMsg )
}
start := d .readIndex ()
d .rescanLiteral ()
item := d .data [start :d .readIndex ()]
key , ok := unquote (item )
if !ok {
panic (phasePanicMsg )
}
if d .opcode == scanSkipSpace {
d .scanWhile (scanSkipSpace )
}
if d .opcode != scanObjectKey {
panic (phasePanicMsg )
}
d .scanWhile (scanSkipSpace )
m [key ] = d .valueInterface ()
if d .opcode == scanSkipSpace {
d .scanWhile (scanSkipSpace )
}
if d .opcode == scanEndObject {
break
}
if d .opcode != scanObjectValue {
panic (phasePanicMsg )
}
}
return m
}
func (d *decodeState ) literalInterface () any {
start := d .readIndex ()
d .rescanLiteral ()
item := d .data [start :d .readIndex ()]
switch c := item [0 ]; c {
case 'n' :
return nil
case 't' , 'f' :
return c == 't'
case '"' :
s , ok := unquote (item )
if !ok {
panic (phasePanicMsg )
}
return s
default :
if c != '-' && (c < '0' || c > '9' ) {
panic (phasePanicMsg )
}
n , err := d .convertNumber (string (item ))
if err != nil {
d .saveError (err )
}
return n
}
}
func getu4(s []byte ) rune {
if len (s ) < 6 || s [0 ] != '\\' || s [1 ] != 'u' {
return -1
}
var r rune
for _ , c := range s [2 :6 ] {
switch {
case '0' <= c && c <= '9' :
c = c - '0'
case 'a' <= c && c <= 'f' :
c = c - 'a' + 10
case 'A' <= c && c <= 'F' :
c = c - 'A' + 10
default :
return -1
}
r = r *16 + rune (c )
}
return r
}
func unquote(s []byte ) (t string , ok bool ) {
s , ok = unquoteBytes (s )
t = string (s )
return
}
func unquoteBytes(s []byte ) (t []byte , ok bool ) {
if len (s ) < 2 || s [0 ] != '"' || s [len (s )-1 ] != '"' {
return
}
s = s [1 : len (s )-1 ]
r := 0
for r < len (s ) {
c := s [r ]
if c == '\\' || c == '"' || c < ' ' {
break
}
if c < utf8 .RuneSelf {
r ++
continue
}
rr , size := utf8 .DecodeRune (s [r :])
if rr == utf8 .RuneError && size == 1 {
break
}
r += size
}
if r == len (s ) {
return s , true
}
b := make ([]byte , len (s )+2 *utf8 .UTFMax )
w := copy (b , s [0 :r ])
for r < len (s ) {
if w >= len (b )-2 *utf8 .UTFMax {
nb := make ([]byte , (len (b )+utf8 .UTFMax )*2 )
copy (nb , b [0 :w ])
b = nb
}
switch c := s [r ]; {
case c == '\\' :
r ++
if r >= len (s ) {
return
}
switch s [r ] {
default :
return
case '"' , '\\' , '/' , '\'' :
b [w ] = s [r ]
r ++
w ++
case 'b' :
b [w ] = '\b'
r ++
w ++
case 'f' :
b [w ] = '\f'
r ++
w ++
case 'n' :
b [w ] = '\n'
r ++
w ++
case 'r' :
b [w ] = '\r'
r ++
w ++
case 't' :
b [w ] = '\t'
r ++
w ++
case 'u' :
r --
rr := getu4 (s [r :])
if rr < 0 {
return
}
r += 6
if utf16 .IsSurrogate (rr ) {
rr1 := getu4 (s [r :])
if dec := utf16 .DecodeRune (rr , rr1 ); dec != unicode .ReplacementChar {
r += 6
w += utf8 .EncodeRune (b [w :], dec )
break
}
rr = unicode .ReplacementChar
}
w += utf8 .EncodeRune (b [w :], rr )
}
case c == '"' , c < ' ' :
return
case c < utf8 .RuneSelf :
b [w ] = c
r ++
w ++
default :
rr , size := utf8 .DecodeRune (s [r :])
r += size
w += utf8 .EncodeRune (b [w :], rr )
}
}
return b [0 :w ], true
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .