| | |
| | |
| | |
| |
|
| | |
| |
|
| | package json |
| |
|
| | import ( |
| | "bytes" |
| | "errors" |
| | "io" |
| | ) |
| |
|
| | |
| | type Decoder struct { |
| | r io.Reader |
| | buf []byte |
| | d decodeState |
| | scanp int |
| | scanned int64 |
| | scan scanner |
| | err error |
| |
|
| | tokenState int |
| | tokenStack []int |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func NewDecoder(r io.Reader) *Decoder { |
| | return &Decoder{r: r} |
| | } |
| |
|
| | |
| | |
| | func (dec *Decoder) UseNumber() { dec.d.useNumber = true } |
| |
|
| | |
| | |
| | |
| | func (dec *Decoder) DisallowUnknownFields() { dec.d.disallowUnknownFields = true } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (dec *Decoder) Decode(v any) error { |
| | if dec.err != nil { |
| | return dec.err |
| | } |
| |
|
| | if err := dec.tokenPrepareForDecode(); err != nil { |
| | return err |
| | } |
| |
|
| | if !dec.tokenValueAllowed() { |
| | return &SyntaxError{msg: "not at beginning of value", Offset: dec.InputOffset()} |
| | } |
| |
|
| | |
| | n, err := dec.readValue() |
| | if err != nil { |
| | return err |
| | } |
| | dec.d.init(dec.buf[dec.scanp : dec.scanp+n]) |
| | dec.scanp += n |
| |
|
| | |
| | |
| | |
| | err = dec.d.unmarshal(v) |
| |
|
| | |
| | dec.tokenValueEnd() |
| |
|
| | return err |
| | } |
| |
|
| | |
| | |
| | func (dec *Decoder) Buffered() io.Reader { |
| | return bytes.NewReader(dec.buf[dec.scanp:]) |
| | } |
| |
|
| | |
| | |
| | func (dec *Decoder) readValue() (int, error) { |
| | dec.scan.reset() |
| |
|
| | scanp := dec.scanp |
| | var err error |
| | Input: |
| | |
| | |
| | for scanp >= 0 { |
| |
|
| | |
| | for ; scanp < len(dec.buf); scanp++ { |
| | c := dec.buf[scanp] |
| | dec.scan.bytes++ |
| | switch dec.scan.step(&dec.scan, c) { |
| | case scanEnd: |
| | |
| | |
| | |
| | dec.scan.bytes-- |
| | break Input |
| | case scanEndObject, scanEndArray: |
| | |
| | |
| | |
| | if stateEndValue(&dec.scan, ' ') == scanEnd { |
| | scanp++ |
| | break Input |
| | } |
| | case scanError: |
| | dec.err = dec.scan.err |
| | return 0, dec.scan.err |
| | } |
| | } |
| |
|
| | |
| | |
| | if err != nil { |
| | if err == io.EOF { |
| | if dec.scan.step(&dec.scan, ' ') == scanEnd { |
| | break Input |
| | } |
| | if nonSpace(dec.buf) { |
| | err = io.ErrUnexpectedEOF |
| | } |
| | } |
| | dec.err = err |
| | return 0, err |
| | } |
| |
|
| | n := scanp - dec.scanp |
| | err = dec.refill() |
| | scanp = dec.scanp + n |
| | } |
| | return scanp - dec.scanp, nil |
| | } |
| |
|
| | func (dec *Decoder) refill() error { |
| | |
| | |
| | if dec.scanp > 0 { |
| | dec.scanned += int64(dec.scanp) |
| | n := copy(dec.buf, dec.buf[dec.scanp:]) |
| | dec.buf = dec.buf[:n] |
| | dec.scanp = 0 |
| | } |
| |
|
| | |
| | const minRead = 512 |
| | if cap(dec.buf)-len(dec.buf) < minRead { |
| | newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead) |
| | copy(newBuf, dec.buf) |
| | dec.buf = newBuf |
| | } |
| |
|
| | |
| | n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)]) |
| | dec.buf = dec.buf[0 : len(dec.buf)+n] |
| |
|
| | return err |
| | } |
| |
|
| | func nonSpace(b []byte) bool { |
| | for _, c := range b { |
| | if !isSpace(c) { |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| |
|
| | |
| | type Encoder struct { |
| | w io.Writer |
| | err error |
| | escapeHTML bool |
| |
|
| | indentBuf []byte |
| | indentPrefix string |
| | indentValue string |
| | } |
| |
|
| | |
| | func NewEncoder(w io.Writer) *Encoder { |
| | return &Encoder{w: w, escapeHTML: true} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func (enc *Encoder) Encode(v any) error { |
| | if enc.err != nil { |
| | return enc.err |
| | } |
| |
|
| | e := newEncodeState() |
| | defer encodeStatePool.Put(e) |
| |
|
| | err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML}) |
| | if err != nil { |
| | return err |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | e.WriteByte('\n') |
| |
|
| | b := e.Bytes() |
| | if enc.indentPrefix != "" || enc.indentValue != "" { |
| | enc.indentBuf, err = appendIndent(enc.indentBuf[:0], b, enc.indentPrefix, enc.indentValue) |
| | if err != nil { |
| | return err |
| | } |
| | b = enc.indentBuf |
| | } |
| | if _, err = enc.w.Write(b); err != nil { |
| | enc.err = err |
| | } |
| | return err |
| | } |
| |
|
| | |
| | |
| | |
| | func (enc *Encoder) SetIndent(prefix, indent string) { |
| | enc.indentPrefix = prefix |
| | enc.indentValue = indent |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (enc *Encoder) SetEscapeHTML(on bool) { |
| | enc.escapeHTML = on |
| | } |
| |
|
| | |
| | |
| | |
| | type RawMessage []byte |
| |
|
| | |
| | func (m RawMessage) MarshalJSON() ([]byte, error) { |
| | if m == nil { |
| | return []byte("null"), nil |
| | } |
| | return m, nil |
| | } |
| |
|
| | |
| | func (m *RawMessage) UnmarshalJSON(data []byte) error { |
| | if m == nil { |
| | return errors.New("json.RawMessage: UnmarshalJSON on nil pointer") |
| | } |
| | *m = append((*m)[0:0], data...) |
| | return nil |
| | } |
| |
|
| | var _ Marshaler = (*RawMessage)(nil) |
| | var _ Unmarshaler = (*RawMessage)(nil) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type Token any |
| |
|
| | const ( |
| | tokenTopValue = iota |
| | tokenArrayStart |
| | tokenArrayValue |
| | tokenArrayComma |
| | tokenObjectStart |
| | tokenObjectKey |
| | tokenObjectColon |
| | tokenObjectValue |
| | tokenObjectComma |
| | ) |
| |
|
| | |
| | func (dec *Decoder) tokenPrepareForDecode() error { |
| | |
| | |
| | |
| | switch dec.tokenState { |
| | case tokenArrayComma: |
| | c, err := dec.peek() |
| | if err != nil { |
| | return err |
| | } |
| | if c != ',' { |
| | return &SyntaxError{"expected comma after array element", dec.InputOffset()} |
| | } |
| | dec.scanp++ |
| | dec.tokenState = tokenArrayValue |
| | case tokenObjectColon: |
| | c, err := dec.peek() |
| | if err != nil { |
| | return err |
| | } |
| | if c != ':' { |
| | return &SyntaxError{"expected colon after object key", dec.InputOffset()} |
| | } |
| | dec.scanp++ |
| | dec.tokenState = tokenObjectValue |
| | } |
| | return nil |
| | } |
| |
|
| | func (dec *Decoder) tokenValueAllowed() bool { |
| | switch dec.tokenState { |
| | case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue: |
| | return true |
| | } |
| | return false |
| | } |
| |
|
| | func (dec *Decoder) tokenValueEnd() { |
| | switch dec.tokenState { |
| | case tokenArrayStart, tokenArrayValue: |
| | dec.tokenState = tokenArrayComma |
| | case tokenObjectValue: |
| | dec.tokenState = tokenObjectComma |
| | } |
| | } |
| |
|
| | |
| | type Delim rune |
| |
|
| | func (d Delim) String() string { |
| | return string(d) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (dec *Decoder) Token() (Token, error) { |
| | for { |
| | c, err := dec.peek() |
| | if err != nil { |
| | return nil, err |
| | } |
| | switch c { |
| | case '[': |
| | if !dec.tokenValueAllowed() { |
| | return dec.tokenError(c) |
| | } |
| | dec.scanp++ |
| | dec.tokenStack = append(dec.tokenStack, dec.tokenState) |
| | dec.tokenState = tokenArrayStart |
| | return Delim('['), nil |
| |
|
| | case ']': |
| | if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma { |
| | return dec.tokenError(c) |
| | } |
| | dec.scanp++ |
| | dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] |
| | dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] |
| | dec.tokenValueEnd() |
| | return Delim(']'), nil |
| |
|
| | case '{': |
| | if !dec.tokenValueAllowed() { |
| | return dec.tokenError(c) |
| | } |
| | dec.scanp++ |
| | dec.tokenStack = append(dec.tokenStack, dec.tokenState) |
| | dec.tokenState = tokenObjectStart |
| | return Delim('{'), nil |
| |
|
| | case '}': |
| | if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma { |
| | return dec.tokenError(c) |
| | } |
| | dec.scanp++ |
| | dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] |
| | dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] |
| | dec.tokenValueEnd() |
| | return Delim('}'), nil |
| |
|
| | case ':': |
| | if dec.tokenState != tokenObjectColon { |
| | return dec.tokenError(c) |
| | } |
| | dec.scanp++ |
| | dec.tokenState = tokenObjectValue |
| | continue |
| |
|
| | case ',': |
| | if dec.tokenState == tokenArrayComma { |
| | dec.scanp++ |
| | dec.tokenState = tokenArrayValue |
| | continue |
| | } |
| | if dec.tokenState == tokenObjectComma { |
| | dec.scanp++ |
| | dec.tokenState = tokenObjectKey |
| | continue |
| | } |
| | return dec.tokenError(c) |
| |
|
| | case '"': |
| | if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey { |
| | var x string |
| | old := dec.tokenState |
| | dec.tokenState = tokenTopValue |
| | err := dec.Decode(&x) |
| | dec.tokenState = old |
| | if err != nil { |
| | return nil, err |
| | } |
| | dec.tokenState = tokenObjectColon |
| | return x, nil |
| | } |
| | fallthrough |
| |
|
| | default: |
| | if !dec.tokenValueAllowed() { |
| | return dec.tokenError(c) |
| | } |
| | var x any |
| | if err := dec.Decode(&x); err != nil { |
| | return nil, err |
| | } |
| | return x, nil |
| | } |
| | } |
| | } |
| |
|
| | func (dec *Decoder) tokenError(c byte) (Token, error) { |
| | var context string |
| | switch dec.tokenState { |
| | case tokenTopValue: |
| | context = " looking for beginning of value" |
| | case tokenArrayStart, tokenArrayValue, tokenObjectValue: |
| | context = " looking for beginning of value" |
| | case tokenArrayComma: |
| | context = " after array element" |
| | case tokenObjectKey: |
| | context = " looking for beginning of object key string" |
| | case tokenObjectColon: |
| | context = " after object key" |
| | case tokenObjectComma: |
| | context = " after object key:value pair" |
| | } |
| | return nil, &SyntaxError{"invalid character " + quoteChar(c) + context, dec.InputOffset()} |
| | } |
| |
|
| | |
| | |
| | func (dec *Decoder) More() bool { |
| | c, err := dec.peek() |
| | return err == nil && c != ']' && c != '}' |
| | } |
| |
|
| | func (dec *Decoder) peek() (byte, error) { |
| | var err error |
| | for { |
| | for i := dec.scanp; i < len(dec.buf); i++ { |
| | c := dec.buf[i] |
| | if isSpace(c) { |
| | continue |
| | } |
| | dec.scanp = i |
| | return c, nil |
| | } |
| | |
| | if err != nil { |
| | return 0, err |
| | } |
| | err = dec.refill() |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func (dec *Decoder) InputOffset() int64 { |
| | return dec.scanned + int64(dec.scanp) |
| | } |
| |
|