diff options
Diffstat (limited to 'vendor/github.com/go-logfmt')
-rw-r--r-- | vendor/github.com/go-logfmt/logfmt/LICENSE | 22 | ||||
-rw-r--r-- | vendor/github.com/go-logfmt/logfmt/decode.go | 237 | ||||
-rw-r--r-- | vendor/github.com/go-logfmt/logfmt/doc.go | 6 | ||||
-rw-r--r-- | vendor/github.com/go-logfmt/logfmt/encode.go | 321 | ||||
-rw-r--r-- | vendor/github.com/go-logfmt/logfmt/fuzz.go | 126 | ||||
-rw-r--r-- | vendor/github.com/go-logfmt/logfmt/jsonstring.go | 277 |
6 files changed, 0 insertions, 989 deletions
diff --git a/vendor/github.com/go-logfmt/logfmt/LICENSE b/vendor/github.com/go-logfmt/logfmt/LICENSE deleted file mode 100644 index c02650896..000000000 --- a/vendor/github.com/go-logfmt/logfmt/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 go-logfmt - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/vendor/github.com/go-logfmt/logfmt/decode.go b/vendor/github.com/go-logfmt/logfmt/decode.go deleted file mode 100644 index 04e0efff5..000000000 --- a/vendor/github.com/go-logfmt/logfmt/decode.go +++ /dev/null @@ -1,237 +0,0 @@ -package logfmt - -import ( - "bufio" - "bytes" - "fmt" - "io" - "unicode/utf8" -) - -// A Decoder reads and decodes logfmt records from an input stream. -type Decoder struct { - pos int - key []byte - value []byte - lineNum int - s *bufio.Scanner - err error -} - -// NewDecoder returns a new decoder that reads from r. -// -// The decoder introduces its own buffering and may read data from r beyond -// the logfmt records requested. -func NewDecoder(r io.Reader) *Decoder { - dec := &Decoder{ - s: bufio.NewScanner(r), - } - return dec -} - -// ScanRecord advances the Decoder to the next record, which can then be -// parsed with the ScanKeyval method. It returns false when decoding stops, -// either by reaching the end of the input or an error. After ScanRecord -// returns false, the Err method will return any error that occurred during -// decoding, except that if it was io.EOF, Err will return nil. -func (dec *Decoder) ScanRecord() bool { - if dec.err != nil { - return false - } - if !dec.s.Scan() { - dec.err = dec.s.Err() - return false - } - dec.lineNum++ - dec.pos = 0 - return true -} - -// ScanKeyval advances the Decoder to the next key/value pair of the current -// record, which can then be retrieved with the Key and Value methods. It -// returns false when decoding stops, either by reaching the end of the -// current record or an error. -func (dec *Decoder) ScanKeyval() bool { - dec.key, dec.value = nil, nil - if dec.err != nil { - return false - } - - line := dec.s.Bytes() - - // garbage - for p, c := range line[dec.pos:] { - if c > ' ' { - dec.pos += p - goto key - } - } - dec.pos = len(line) - return false - -key: - const invalidKeyError = "invalid key" - - start, multibyte := dec.pos, false - for p, c := range line[dec.pos:] { - switch { - case c == '=': - dec.pos += p - if dec.pos > start { - dec.key = line[start:dec.pos] - if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 { - dec.syntaxError(invalidKeyError) - return false - } - } - if dec.key == nil { - dec.unexpectedByte(c) - return false - } - goto equal - case c == '"': - dec.pos += p - dec.unexpectedByte(c) - return false - case c <= ' ': - dec.pos += p - if dec.pos > start { - dec.key = line[start:dec.pos] - if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 { - dec.syntaxError(invalidKeyError) - return false - } - } - return true - case c >= utf8.RuneSelf: - multibyte = true - } - } - dec.pos = len(line) - if dec.pos > start { - dec.key = line[start:dec.pos] - if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 { - dec.syntaxError(invalidKeyError) - return false - } - } - return true - -equal: - dec.pos++ - if dec.pos >= len(line) { - return true - } - switch c := line[dec.pos]; { - case c <= ' ': - return true - case c == '"': - goto qvalue - } - - // value - start = dec.pos - for p, c := range line[dec.pos:] { - switch { - case c == '=' || c == '"': - dec.pos += p - dec.unexpectedByte(c) - return false - case c <= ' ': - dec.pos += p - if dec.pos > start { - dec.value = line[start:dec.pos] - } - return true - } - } - dec.pos = len(line) - if dec.pos > start { - dec.value = line[start:dec.pos] - } - return true - -qvalue: - const ( - untermQuote = "unterminated quoted value" - invalidQuote = "invalid quoted value" - ) - - hasEsc, esc := false, false - start = dec.pos - for p, c := range line[dec.pos+1:] { - switch { - case esc: - esc = false - case c == '\\': - hasEsc, esc = true, true - case c == '"': - dec.pos += p + 2 - if hasEsc { - v, ok := unquoteBytes(line[start:dec.pos]) - if !ok { - dec.syntaxError(invalidQuote) - return false - } - dec.value = v - } else { - start++ - end := dec.pos - 1 - if end > start { - dec.value = line[start:end] - } - } - return true - } - } - dec.pos = len(line) - dec.syntaxError(untermQuote) - return false -} - -// Key returns the most recent key found by a call to ScanKeyval. The returned -// slice may point to internal buffers and is only valid until the next call -// to ScanRecord. It does no allocation. -func (dec *Decoder) Key() []byte { - return dec.key -} - -// Value returns the most recent value found by a call to ScanKeyval. The -// returned slice may point to internal buffers and is only valid until the -// next call to ScanRecord. It does no allocation when the value has no -// escape sequences. -func (dec *Decoder) Value() []byte { - return dec.value -} - -// Err returns the first non-EOF error that was encountered by the Scanner. -func (dec *Decoder) Err() error { - return dec.err -} - -func (dec *Decoder) syntaxError(msg string) { - dec.err = &SyntaxError{ - Msg: msg, - Line: dec.lineNum, - Pos: dec.pos + 1, - } -} - -func (dec *Decoder) unexpectedByte(c byte) { - dec.err = &SyntaxError{ - Msg: fmt.Sprintf("unexpected %q", c), - Line: dec.lineNum, - Pos: dec.pos + 1, - } -} - -// A SyntaxError represents a syntax error in the logfmt input stream. -type SyntaxError struct { - Msg string - Line int - Pos int -} - -func (e *SyntaxError) Error() string { - return fmt.Sprintf("logfmt syntax error at pos %d on line %d: %s", e.Pos, e.Line, e.Msg) -} diff --git a/vendor/github.com/go-logfmt/logfmt/doc.go b/vendor/github.com/go-logfmt/logfmt/doc.go deleted file mode 100644 index 378e9ad12..000000000 --- a/vendor/github.com/go-logfmt/logfmt/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Package logfmt implements utilities to marshal and unmarshal data in the -// logfmt format. The logfmt format records key/value pairs in a way that -// balances readability for humans and simplicity of computer parsing. It is -// most commonly used as a more human friendly alternative to JSON for -// structured logging. -package logfmt diff --git a/vendor/github.com/go-logfmt/logfmt/encode.go b/vendor/github.com/go-logfmt/logfmt/encode.go deleted file mode 100644 index 55f1603ca..000000000 --- a/vendor/github.com/go-logfmt/logfmt/encode.go +++ /dev/null @@ -1,321 +0,0 @@ -package logfmt - -import ( - "bytes" - "encoding" - "errors" - "fmt" - "io" - "reflect" - "strings" - "unicode/utf8" -) - -// MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence -// of alternating keys and values. -func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) { - buf := &bytes.Buffer{} - if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// An Encoder writes logfmt data to an output stream. -type Encoder struct { - w io.Writer - scratch bytes.Buffer - needSep bool -} - -// NewEncoder returns a new encoder that writes to w. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - w: w, - } -} - -var ( - space = []byte(" ") - equals = []byte("=") - newline = []byte("\n") - null = []byte("null") -) - -// EncodeKeyval writes the logfmt encoding of key and value to the stream. A -// single space is written before the second and subsequent keys in a record. -// Nothing is written if a non-nil error is returned. -func (enc *Encoder) EncodeKeyval(key, value interface{}) error { - enc.scratch.Reset() - if enc.needSep { - if _, err := enc.scratch.Write(space); err != nil { - return err - } - } - if err := writeKey(&enc.scratch, key); err != nil { - return err - } - if _, err := enc.scratch.Write(equals); err != nil { - return err - } - if err := writeValue(&enc.scratch, value); err != nil { - return err - } - _, err := enc.w.Write(enc.scratch.Bytes()) - enc.needSep = true - return err -} - -// EncodeKeyvals writes the logfmt encoding of keyvals to the stream. Keyvals -// is a variadic sequence of alternating keys and values. Keys of unsupported -// type are skipped along with their corresponding value. Values of -// unsupported type or that cause a MarshalerError are replaced by their error -// but do not cause EncodeKeyvals to return an error. If a non-nil error is -// returned some key/value pairs may not have be written. -func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error { - if len(keyvals) == 0 { - return nil - } - if len(keyvals)%2 == 1 { - keyvals = append(keyvals, nil) - } - for i := 0; i < len(keyvals); i += 2 { - k, v := keyvals[i], keyvals[i+1] - err := enc.EncodeKeyval(k, v) - if err == ErrUnsupportedKeyType { - continue - } - if _, ok := err.(*MarshalerError); ok || err == ErrUnsupportedValueType { - v = err - err = enc.EncodeKeyval(k, v) - } - if err != nil { - return err - } - } - return nil -} - -// MarshalerError represents an error encountered while marshaling a value. -type MarshalerError struct { - Type reflect.Type - Err error -} - -func (e *MarshalerError) Error() string { - return "error marshaling value of type " + e.Type.String() + ": " + e.Err.Error() -} - -// ErrNilKey is returned by Marshal functions and Encoder methods if a key is -// a nil interface or pointer value. -var ErrNilKey = errors.New("nil key") - -// ErrInvalidKey is returned by Marshal functions and Encoder methods if a key -// contains an invalid character. -var ErrInvalidKey = errors.New("invalid key") - -// ErrUnsupportedKeyType is returned by Encoder methods if a key has an -// unsupported type. -var ErrUnsupportedKeyType = errors.New("unsupported key type") - -// ErrUnsupportedValueType is returned by Encoder methods if a value has an -// unsupported type. -var ErrUnsupportedValueType = errors.New("unsupported value type") - -func writeKey(w io.Writer, key interface{}) error { - if key == nil { - return ErrNilKey - } - - switch k := key.(type) { - case string: - return writeStringKey(w, k) - case []byte: - if k == nil { - return ErrNilKey - } - return writeBytesKey(w, k) - case encoding.TextMarshaler: - kb, err := safeMarshal(k) - if err != nil { - return err - } - if kb == nil { - return ErrNilKey - } - return writeBytesKey(w, kb) - case fmt.Stringer: - ks, ok := safeString(k) - if !ok { - return ErrNilKey - } - return writeStringKey(w, ks) - default: - rkey := reflect.ValueOf(key) - switch rkey.Kind() { - case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct: - return ErrUnsupportedKeyType - case reflect.Ptr: - if rkey.IsNil() { - return ErrNilKey - } - return writeKey(w, rkey.Elem().Interface()) - } - return writeStringKey(w, fmt.Sprint(k)) - } -} - -func invalidKeyRune(r rune) bool { - return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError -} - -func invalidKeyString(key string) bool { - return len(key) == 0 || strings.IndexFunc(key, invalidKeyRune) != -1 -} - -func invalidKey(key []byte) bool { - return len(key) == 0 || bytes.IndexFunc(key, invalidKeyRune) != -1 -} - -func writeStringKey(w io.Writer, key string) error { - if invalidKeyString(key) { - return ErrInvalidKey - } - _, err := io.WriteString(w, key) - return err -} - -func writeBytesKey(w io.Writer, key []byte) error { - if invalidKey(key) { - return ErrInvalidKey - } - _, err := w.Write(key) - return err -} - -func writeValue(w io.Writer, value interface{}) error { - switch v := value.(type) { - case nil: - return writeBytesValue(w, null) - case string: - return writeStringValue(w, v, true) - case []byte: - return writeBytesValue(w, v) - case encoding.TextMarshaler: - vb, err := safeMarshal(v) - if err != nil { - return err - } - if vb == nil { - vb = null - } - return writeBytesValue(w, vb) - case error: - se, ok := safeError(v) - return writeStringValue(w, se, ok) - case fmt.Stringer: - ss, ok := safeString(v) - return writeStringValue(w, ss, ok) - default: - rvalue := reflect.ValueOf(value) - switch rvalue.Kind() { - case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct: - return ErrUnsupportedValueType - case reflect.Ptr: - if rvalue.IsNil() { - return writeBytesValue(w, null) - } - return writeValue(w, rvalue.Elem().Interface()) - } - return writeStringValue(w, fmt.Sprint(v), true) - } -} - -func needsQuotedValueRune(r rune) bool { - return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError -} - -func writeStringValue(w io.Writer, value string, ok bool) error { - var err error - if ok && value == "null" { - _, err = io.WriteString(w, `"null"`) - } else if strings.IndexFunc(value, needsQuotedValueRune) != -1 { - _, err = writeQuotedString(w, value) - } else { - _, err = io.WriteString(w, value) - } - return err -} - -func writeBytesValue(w io.Writer, value []byte) error { - var err error - if bytes.IndexFunc(value, needsQuotedValueRune) != -1 { - _, err = writeQuotedBytes(w, value) - } else { - _, err = w.Write(value) - } - return err -} - -// EndRecord writes a newline character to the stream and resets the encoder -// to the beginning of a new record. -func (enc *Encoder) EndRecord() error { - _, err := enc.w.Write(newline) - if err == nil { - enc.needSep = false - } - return err -} - -// Reset resets the encoder to the beginning of a new record. -func (enc *Encoder) Reset() { - enc.needSep = false -} - -func safeError(err error) (s string, ok bool) { - defer func() { - if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() { - s, ok = "null", false - } else { - panic(panicVal) - } - } - }() - s, ok = err.Error(), true - return -} - -func safeString(str fmt.Stringer) (s string, ok bool) { - defer func() { - if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() { - s, ok = "null", false - } else { - panic(panicVal) - } - } - }() - s, ok = str.String(), true - return -} - -func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) { - defer func() { - if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() { - b, err = nil, nil - } else { - panic(panicVal) - } - } - }() - b, err = tm.MarshalText() - if err != nil { - return nil, &MarshalerError{ - Type: reflect.TypeOf(tm), - Err: err, - } - } - return -} diff --git a/vendor/github.com/go-logfmt/logfmt/fuzz.go b/vendor/github.com/go-logfmt/logfmt/fuzz.go deleted file mode 100644 index 6553b35e8..000000000 --- a/vendor/github.com/go-logfmt/logfmt/fuzz.go +++ /dev/null @@ -1,126 +0,0 @@ -// +build gofuzz - -package logfmt - -import ( - "bufio" - "bytes" - "fmt" - "io" - "reflect" - - kr "github.com/kr/logfmt" -) - -// Fuzz checks reserialized data matches -func Fuzz(data []byte) int { - parsed, err := parse(data) - if err != nil { - return 0 - } - var w1 bytes.Buffer - if err = write(parsed, &w1); err != nil { - panic(err) - } - parsed, err = parse(w1.Bytes()) - if err != nil { - panic(err) - } - var w2 bytes.Buffer - if err = write(parsed, &w2); err != nil { - panic(err) - } - if !bytes.Equal(w1.Bytes(), w2.Bytes()) { - panic(fmt.Sprintf("reserialized data does not match:\n%q\n%q\n", w1.Bytes(), w2.Bytes())) - } - return 1 -} - -// FuzzVsKR checks go-logfmt/logfmt against kr/logfmt -func FuzzVsKR(data []byte) int { - parsed, err := parse(data) - parsedKR, errKR := parseKR(data) - - // github.com/go-logfmt/logfmt is a stricter parser. It returns errors for - // more inputs than github.com/kr/logfmt. Ignore any inputs that have a - // stict error. - if err != nil { - return 0 - } - - // Fail if the more forgiving parser finds an error not found by the - // stricter parser. - if errKR != nil { - panic(fmt.Sprintf("unmatched error: %v", errKR)) - } - - if !reflect.DeepEqual(parsed, parsedKR) { - panic(fmt.Sprintf("parsers disagree:\n%+v\n%+v\n", parsed, parsedKR)) - } - return 1 -} - -type kv struct { - k, v []byte -} - -func parse(data []byte) ([][]kv, error) { - var got [][]kv - dec := NewDecoder(bytes.NewReader(data)) - for dec.ScanRecord() { - var kvs []kv - for dec.ScanKeyval() { - kvs = append(kvs, kv{dec.Key(), dec.Value()}) - } - got = append(got, kvs) - } - return got, dec.Err() -} - -func parseKR(data []byte) ([][]kv, error) { - var ( - s = bufio.NewScanner(bytes.NewReader(data)) - err error - h saveHandler - got [][]kv - ) - for err == nil && s.Scan() { - h.kvs = nil - err = kr.Unmarshal(s.Bytes(), &h) - got = append(got, h.kvs) - } - if err == nil { - err = s.Err() - } - return got, err -} - -type saveHandler struct { - kvs []kv -} - -func (h *saveHandler) HandleLogfmt(key, val []byte) error { - if len(key) == 0 { - key = nil - } - if len(val) == 0 { - val = nil - } - h.kvs = append(h.kvs, kv{key, val}) - return nil -} - -func write(recs [][]kv, w io.Writer) error { - enc := NewEncoder(w) - for _, rec := range recs { - for _, f := range rec { - if err := enc.EncodeKeyval(f.k, f.v); err != nil { - return err - } - } - if err := enc.EndRecord(); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/go-logfmt/logfmt/jsonstring.go b/vendor/github.com/go-logfmt/logfmt/jsonstring.go deleted file mode 100644 index 030ac85fc..000000000 --- a/vendor/github.com/go-logfmt/logfmt/jsonstring.go +++ /dev/null @@ -1,277 +0,0 @@ -package logfmt - -import ( - "bytes" - "io" - "strconv" - "sync" - "unicode" - "unicode/utf16" - "unicode/utf8" -) - -// Taken from Go's encoding/json and modified for use here. - -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -var hex = "0123456789abcdef" - -var bufferPool = sync.Pool{ - New: func() interface{} { - return &bytes.Buffer{} - }, -} - -func getBuffer() *bytes.Buffer { - return bufferPool.Get().(*bytes.Buffer) -} - -func poolBuffer(buf *bytes.Buffer) { - buf.Reset() - bufferPool.Put(buf) -} - -// NOTE: keep in sync with writeQuotedBytes below. -func writeQuotedString(w io.Writer, s string) (int, error) { - buf := getBuffer() - buf.WriteByte('"') - start := 0 - for i := 0; i < len(s); { - if b := s[i]; b < utf8.RuneSelf { - if 0x20 <= b && b != '\\' && b != '"' { - i++ - continue - } - if start < i { - buf.WriteString(s[start:i]) - } - switch b { - case '\\', '"': - buf.WriteByte('\\') - buf.WriteByte(b) - case '\n': - buf.WriteByte('\\') - buf.WriteByte('n') - case '\r': - buf.WriteByte('\\') - buf.WriteByte('r') - case '\t': - buf.WriteByte('\\') - buf.WriteByte('t') - default: - // This encodes bytes < 0x20 except for \n, \r, and \t. - buf.WriteString(`\u00`) - buf.WriteByte(hex[b>>4]) - buf.WriteByte(hex[b&0xF]) - } - i++ - start = i - continue - } - c, size := utf8.DecodeRuneInString(s[i:]) - if c == utf8.RuneError { - if start < i { - buf.WriteString(s[start:i]) - } - buf.WriteString(`\ufffd`) - i += size - start = i - continue - } - i += size - } - if start < len(s) { - buf.WriteString(s[start:]) - } - buf.WriteByte('"') - n, err := w.Write(buf.Bytes()) - poolBuffer(buf) - return n, err -} - -// NOTE: keep in sync with writeQuoteString above. -func writeQuotedBytes(w io.Writer, s []byte) (int, error) { - buf := getBuffer() - buf.WriteByte('"') - start := 0 - for i := 0; i < len(s); { - if b := s[i]; b < utf8.RuneSelf { - if 0x20 <= b && b != '\\' && b != '"' { - i++ - continue - } - if start < i { - buf.Write(s[start:i]) - } - switch b { - case '\\', '"': - buf.WriteByte('\\') - buf.WriteByte(b) - case '\n': - buf.WriteByte('\\') - buf.WriteByte('n') - case '\r': - buf.WriteByte('\\') - buf.WriteByte('r') - case '\t': - buf.WriteByte('\\') - buf.WriteByte('t') - default: - // This encodes bytes < 0x20 except for \n, \r, and \t. - buf.WriteString(`\u00`) - buf.WriteByte(hex[b>>4]) - buf.WriteByte(hex[b&0xF]) - } - i++ - start = i - continue - } - c, size := utf8.DecodeRune(s[i:]) - if c == utf8.RuneError { - if start < i { - buf.Write(s[start:i]) - } - buf.WriteString(`\ufffd`) - i += size - start = i - continue - } - i += size - } - if start < len(s) { - buf.Write(s[start:]) - } - buf.WriteByte('"') - n, err := w.Write(buf.Bytes()) - poolBuffer(buf) - return n, err -} - -// getu4 decodes \uXXXX from the beginning of s, returning the hex value, -// or it returns -1. -func getu4(s []byte) rune { - if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { - return -1 - } - r, err := strconv.ParseUint(string(s[2:6]), 16, 64) - if err != nil { - return -1 - } - return rune(r) -} - -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] - - // Check for unusual characters. If there are none, - // then no unquoting is needed, so return a slice of the - // original bytes. - 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 { - 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) { - // Out of room? Can only happen if s is full of - // malformed UTF-8 and we're replacing each - // byte with RuneError. - 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 { - // A valid pair; consume. - r += 6 - w += utf8.EncodeRune(b[w:], dec) - break - } - // Invalid surrogate; fall back to replacement rune. - rr = unicode.ReplacementChar - } - w += utf8.EncodeRune(b[w:], rr) - } - - // Quote, control characters are invalid. - case c == '"', c < ' ': - return - - // ASCII - case c < utf8.RuneSelf: - b[w] = c - r++ - w++ - - // Coerce to well-formed UTF-8. - default: - rr, size := utf8.DecodeRune(s[r:]) - r += size - w += utf8.EncodeRune(b[w:], rr) - } - } - return b[0:w], true -} |