| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 | // Package jwriter contains a JSON writer.package jwriterimport (	"io"	"strconv"	"unicode/utf8"	"github.com/mailru/easyjson/buffer")// Flags describe various encoding options. The behavior may be actually implemented in the encoder, but// Flags field in Writer is used to set and pass them around.type Flags intconst (	NilMapAsEmpty   Flags = 1 << iota // Encode nil map as '{}' rather than 'null'.	NilSliceAsEmpty                   // Encode nil slice as '[]' rather than 'null'.)// Writer is a JSON writer.type Writer struct {	Flags Flags	Error        error	Buffer       buffer.Buffer	NoEscapeHTML bool}// Size returns the size of the data that was written out.func (w *Writer) Size() int {	return w.Buffer.Size()}// DumpTo outputs the data to given io.Writer, resetting the buffer.func (w *Writer) DumpTo(out io.Writer) (written int, err error) {	return w.Buffer.DumpTo(out)}// BuildBytes returns writer data as a single byte slice. You can optionally provide one byte slice// as argument that it will try to reuse.func (w *Writer) BuildBytes(reuse ...[]byte) ([]byte, error) {	if w.Error != nil {		return nil, w.Error	}	return w.Buffer.BuildBytes(reuse...), nil}// ReadCloser returns an io.ReadCloser that can be used to read the data.// ReadCloser also resets the buffer.func (w *Writer) ReadCloser() (io.ReadCloser, error) {	if w.Error != nil {		return nil, w.Error	}	return w.Buffer.ReadCloser(), nil}// RawByte appends raw binary data to the buffer.func (w *Writer) RawByte(c byte) {	w.Buffer.AppendByte(c)}// RawByte appends raw binary data to the buffer.func (w *Writer) RawString(s string) {	w.Buffer.AppendString(s)}// Raw appends raw binary data to the buffer or sets the error if it is given. Useful for// calling with results of MarshalJSON-like functions.func (w *Writer) Raw(data []byte, err error) {	switch {	case w.Error != nil:		return	case err != nil:		w.Error = err	case len(data) > 0:		w.Buffer.AppendBytes(data)	default:		w.RawString("null")	}}// RawText encloses raw binary data in quotes and appends in to the buffer.// Useful for calling with results of MarshalText-like functions.func (w *Writer) RawText(data []byte, err error) {	switch {	case w.Error != nil:		return	case err != nil:		w.Error = err	case len(data) > 0:		w.String(string(data))	default:		w.RawString("null")	}}// Base64Bytes appends data to the buffer after base64 encoding itfunc (w *Writer) Base64Bytes(data []byte) {	if data == nil {		w.Buffer.AppendString("null")		return	}	w.Buffer.AppendByte('"')	w.base64(data)	w.Buffer.AppendByte('"')}func (w *Writer) Uint8(n uint8) {	w.Buffer.EnsureSpace(3)	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)}func (w *Writer) Uint16(n uint16) {	w.Buffer.EnsureSpace(5)	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)}func (w *Writer) Uint32(n uint32) {	w.Buffer.EnsureSpace(10)	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)}func (w *Writer) Uint(n uint) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)}func (w *Writer) Uint64(n uint64) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)}func (w *Writer) Int8(n int8) {	w.Buffer.EnsureSpace(4)	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)}func (w *Writer) Int16(n int16) {	w.Buffer.EnsureSpace(6)	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)}func (w *Writer) Int32(n int32) {	w.Buffer.EnsureSpace(11)	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)}func (w *Writer) Int(n int) {	w.Buffer.EnsureSpace(21)	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)}func (w *Writer) Int64(n int64) {	w.Buffer.EnsureSpace(21)	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)}func (w *Writer) Uint8Str(n uint8) {	w.Buffer.EnsureSpace(3)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Uint16Str(n uint16) {	w.Buffer.EnsureSpace(5)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Uint32Str(n uint32) {	w.Buffer.EnsureSpace(10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) UintStr(n uint) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Uint64Str(n uint64) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) UintptrStr(n uintptr) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Int8Str(n int8) {	w.Buffer.EnsureSpace(4)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Int16Str(n int16) {	w.Buffer.EnsureSpace(6)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Int32Str(n int32) {	w.Buffer.EnsureSpace(11)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) IntStr(n int) {	w.Buffer.EnsureSpace(21)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Int64Str(n int64) {	w.Buffer.EnsureSpace(21)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Float32(n float32) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)}func (w *Writer) Float32Str(n float32) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Float64(n float64) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, 'g', -1, 64)}func (w *Writer) Float64Str(n float64) {	w.Buffer.EnsureSpace(20)	w.Buffer.Buf = append(w.Buffer.Buf, '"')	w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 64)	w.Buffer.Buf = append(w.Buffer.Buf, '"')}func (w *Writer) Bool(v bool) {	w.Buffer.EnsureSpace(5)	if v {		w.Buffer.Buf = append(w.Buffer.Buf, "true"...)	} else {		w.Buffer.Buf = append(w.Buffer.Buf, "false"...)	}}const chars = "0123456789abcdef"func getTable(falseValues ...int) [128]bool {	table := [128]bool{}	for i := 0; i < 128; i++ {		table[i] = true	}	for _, v := range falseValues {		table[v] = false	}	return table}var (	htmlEscapeTable   = getTable(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, '"', '&', '<', '>', '\\')	htmlNoEscapeTable = getTable(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, '"', '\\'))func (w *Writer) String(s string) {	w.Buffer.AppendByte('"')	// Portions of the string that contain no escapes are appended as	// byte slices.	p := 0 // last non-escape symbol	escapeTable := &htmlEscapeTable	if w.NoEscapeHTML {		escapeTable = &htmlNoEscapeTable	}	for i := 0; i < len(s); {		c := s[i]		if c < utf8.RuneSelf {			if escapeTable[c] {				// single-width character, no escaping is required				i++				continue			}			w.Buffer.AppendString(s[p:i])			switch c {			case '\t':				w.Buffer.AppendString(`\t`)			case '\r':				w.Buffer.AppendString(`\r`)			case '\n':				w.Buffer.AppendString(`\n`)			case '\\':				w.Buffer.AppendString(`\\`)			case '"':				w.Buffer.AppendString(`\"`)			default:				w.Buffer.AppendString(`\u00`)				w.Buffer.AppendByte(chars[c>>4])				w.Buffer.AppendByte(chars[c&0xf])			}			i++			p = i			continue		}		// broken utf		runeValue, runeWidth := utf8.DecodeRuneInString(s[i:])		if runeValue == utf8.RuneError && runeWidth == 1 {			w.Buffer.AppendString(s[p:i])			w.Buffer.AppendString(`\ufffd`)			i++			p = i			continue		}		// jsonp stuff - tab separator and line separator		if runeValue == '\u2028' || runeValue == '\u2029' {			w.Buffer.AppendString(s[p:i])			w.Buffer.AppendString(`\u202`)			w.Buffer.AppendByte(chars[runeValue&0xf])			i += runeWidth			p = i			continue		}		i += runeWidth	}	w.Buffer.AppendString(s[p:])	w.Buffer.AppendByte('"')}const encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"const padChar = '='func (w *Writer) base64(in []byte) {	if len(in) == 0 {		return	}	w.Buffer.EnsureSpace(((len(in)-1)/3 + 1) * 4)	si := 0	n := (len(in) / 3) * 3	for si < n {		// Convert 3x 8bit source bytes into 4 bytes		val := uint(in[si+0])<<16 | uint(in[si+1])<<8 | uint(in[si+2])		w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F], encode[val>>6&0x3F], encode[val&0x3F])		si += 3	}	remain := len(in) - si	if remain == 0 {		return	}	// Add the remaining small block	val := uint(in[si+0]) << 16	if remain == 2 {		val |= uint(in[si+1]) << 8	}	w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F])	switch remain {	case 2:		w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>6&0x3F], byte(padChar))	case 1:		w.Buffer.Buf = append(w.Buffer.Buf, byte(padChar), byte(padChar))	}}
 |