package logfmt

import (
	
	
	
	
	
	
	
)

// 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( *bytes.Buffer) {
	.Reset()
	bufferPool.Put()
}

// NOTE: keep in sync with writeQuotedBytes below.
func writeQuotedString( io.Writer,  string) (int, error) {
	 := getBuffer()
	.WriteByte('"')
	 := 0
	for  := 0;  < len(); {
		if  := [];  < utf8.RuneSelf {
			if 0x20 <=  &&  != '\\' &&  != '"' {
				++
				continue
			}
			if  <  {
				.WriteString([:])
			}
			switch  {
			case '\\', '"':
				.WriteByte('\\')
				.WriteByte()
			case '\n':
				.WriteByte('\\')
				.WriteByte('n')
			case '\r':
				.WriteByte('\\')
				.WriteByte('r')
			case '\t':
				.WriteByte('\\')
				.WriteByte('t')
			default:
				// This encodes bytes < 0x20 except for \n, \r, and \t.
				.WriteString(`\u00`)
				.WriteByte(hex[>>4])
				.WriteByte(hex[&0xF])
			}
			++
			 = 
			continue
		}
		,  := utf8.DecodeRuneInString([:])
		if  == utf8.RuneError {
			if  <  {
				.WriteString([:])
			}
			.WriteString(`\ufffd`)
			 += 
			 = 
			continue
		}
		 += 
	}
	if  < len() {
		.WriteString([:])
	}
	.WriteByte('"')
	,  := .Write(.Bytes())
	poolBuffer()
	return , 
}

// NOTE: keep in sync with writeQuoteString above.
func writeQuotedBytes( io.Writer,  []byte) (int, error) {
	 := getBuffer()
	.WriteByte('"')
	 := 0
	for  := 0;  < len(); {
		if  := [];  < utf8.RuneSelf {
			if 0x20 <=  &&  != '\\' &&  != '"' {
				++
				continue
			}
			if  <  {
				.Write([:])
			}
			switch  {
			case '\\', '"':
				.WriteByte('\\')
				.WriteByte()
			case '\n':
				.WriteByte('\\')
				.WriteByte('n')
			case '\r':
				.WriteByte('\\')
				.WriteByte('r')
			case '\t':
				.WriteByte('\\')
				.WriteByte('t')
			default:
				// This encodes bytes < 0x20 except for \n, \r, and \t.
				.WriteString(`\u00`)
				.WriteByte(hex[>>4])
				.WriteByte(hex[&0xF])
			}
			++
			 = 
			continue
		}
		,  := utf8.DecodeRune([:])
		if  == utf8.RuneError {
			if  <  {
				.Write([:])
			}
			.WriteString(`\ufffd`)
			 += 
			 = 
			continue
		}
		 += 
	}
	if  < len() {
		.Write([:])
	}
	.WriteByte('"')
	,  := .Write(.Bytes())
	poolBuffer()
	return , 
}

// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
// or it returns -1.
func getu4( []byte) rune {
	if len() < 6 || [0] != '\\' || [1] != 'u' {
		return -1
	}
	,  := strconv.ParseUint(string([2:6]), 16, 64)
	if  != nil {
		return -1
	}
	return rune()
}

func unquoteBytes( []byte) ( []byte,  bool) {
	if len() < 2 || [0] != '"' || [len()-1] != '"' {
		return
	}
	 = [1 : len()-1]

	// Check for unusual characters. If there are none,
	// then no unquoting is needed, so return a slice of the
	// original bytes.
	 := 0
	for  < len() {
		 := []
		if  == '\\' ||  == '"' ||  < ' ' {
			break
		}
		if  < utf8.RuneSelf {
			++
			continue
		}
		,  := utf8.DecodeRune([:])
		if  == utf8.RuneError {
			break
		}
		 += 
	}
	if  == len() {
		return , true
	}

	 := make([]byte, len()+2*utf8.UTFMax)
	 := copy(, [0:])
	for  < len() {
		// Out of room?  Can only happen if s is full of
		// malformed UTF-8 and we're replacing each
		// byte with RuneError.
		if  >= len()-2*utf8.UTFMax {
			 := make([]byte, (len()+utf8.UTFMax)*2)
			copy(, [0:])
			 = 
		}
		switch  := []; {
		case  == '\\':
			++
			if  >= len() {
				return
			}
			switch [] {
			default:
				return
			case '"', '\\', '/', '\'':
				[] = []
				++
				++
			case 'b':
				[] = '\b'
				++
				++
			case 'f':
				[] = '\f'
				++
				++
			case 'n':
				[] = '\n'
				++
				++
			case 'r':
				[] = '\r'
				++
				++
			case 't':
				[] = '\t'
				++
				++
			case 'u':
				--
				 := getu4([:])
				if  < 0 {
					return
				}
				 += 6
				if utf16.IsSurrogate() {
					 := getu4([:])
					if  := utf16.DecodeRune(, );  != unicode.ReplacementChar {
						// A valid pair; consume.
						 += 6
						 += utf8.EncodeRune([:], )
						break
					}
					// Invalid surrogate; fall back to replacement rune.
					 = unicode.ReplacementChar
				}
				 += utf8.EncodeRune([:], )
			}

		// Quote, control characters are invalid.
		case  == '"',  < ' ':
			return

		// ASCII
		case  < utf8.RuneSelf:
			[] = 
			++
			++

		// Coerce to well-formed UTF-8.
		default:
			,  := utf8.DecodeRune([:])
			 += 
			 += utf8.EncodeRune([:], )
		}
	}
	return [0:], true
}