writer.go raw

   1  // Package jwriter contains a JSON writer.
   2  package jwriter
   3  
   4  import (
   5  	"io"
   6  	"strconv"
   7  	"unicode/utf8"
   8  
   9  	"github.com/mailru/easyjson/buffer"
  10  )
  11  
  12  // Flags describe various encoding options. The behavior may be actually implemented in the encoder, but
  13  // Flags field in Writer is used to set and pass them around.
  14  type Flags int
  15  
  16  const (
  17  	NilMapAsEmpty   Flags = 1 << iota // Encode nil map as '{}' rather than 'null'.
  18  	NilSliceAsEmpty                   // Encode nil slice as '[]' rather than 'null'.
  19  )
  20  
  21  // Writer is a JSON writer.
  22  type Writer struct {
  23  	Flags Flags
  24  
  25  	Error        error
  26  	Buffer       buffer.Buffer
  27  	NoEscapeHTML bool
  28  }
  29  
  30  // Size returns the size of the data that was written out.
  31  func (w *Writer) Size() int {
  32  	return w.Buffer.Size()
  33  }
  34  
  35  // DumpTo outputs the data to given io.Writer, resetting the buffer.
  36  func (w *Writer) DumpTo(out io.Writer) (written int, err error) {
  37  	return w.Buffer.DumpTo(out)
  38  }
  39  
  40  // BuildBytes returns writer data as a single byte slice. You can optionally provide one byte slice
  41  // as argument that it will try to reuse.
  42  func (w *Writer) BuildBytes(reuse ...[]byte) ([]byte, error) {
  43  	if w.Error != nil {
  44  		return nil, w.Error
  45  	}
  46  
  47  	return w.Buffer.BuildBytes(reuse...), nil
  48  }
  49  
  50  // ReadCloser returns an io.ReadCloser that can be used to read the data.
  51  // ReadCloser also resets the buffer.
  52  func (w *Writer) ReadCloser() (io.ReadCloser, error) {
  53  	if w.Error != nil {
  54  		return nil, w.Error
  55  	}
  56  
  57  	return w.Buffer.ReadCloser(), nil
  58  }
  59  
  60  // RawByte appends raw binary data to the buffer.
  61  func (w *Writer) RawByte(c byte) {
  62  	w.Buffer.AppendByte(c)
  63  }
  64  
  65  // RawByte appends raw binary data to the buffer.
  66  func (w *Writer) RawString(s string) {
  67  	w.Buffer.AppendString(s)
  68  }
  69  
  70  // RawBytesString appends string from bytes to the buffer.
  71  func (w *Writer) RawBytesString(data []byte, err error) {
  72  	switch {
  73  	case w.Error != nil:
  74  		return
  75  	case err != nil:
  76  		w.Error = err
  77  	default:
  78  		w.String(string(data))
  79  	}
  80  }
  81  
  82  // Raw appends raw binary data to the buffer or sets the error if it is given. Useful for
  83  // calling with results of MarshalJSON-like functions.
  84  func (w *Writer) Raw(data []byte, err error) {
  85  	switch {
  86  	case w.Error != nil:
  87  		return
  88  	case err != nil:
  89  		w.Error = err
  90  	case len(data) > 0:
  91  		w.Buffer.AppendBytes(data)
  92  	default:
  93  		w.RawString("null")
  94  	}
  95  }
  96  
  97  // RawText encloses raw binary data in quotes and appends in to the buffer.
  98  // Useful for calling with results of MarshalText-like functions.
  99  func (w *Writer) RawText(data []byte, err error) {
 100  	switch {
 101  	case w.Error != nil:
 102  		return
 103  	case err != nil:
 104  		w.Error = err
 105  	case len(data) > 0:
 106  		w.String(string(data))
 107  	default:
 108  		w.RawString("null")
 109  	}
 110  }
 111  
 112  // Base64Bytes appends data to the buffer after base64 encoding it
 113  func (w *Writer) Base64Bytes(data []byte) {
 114  	if data == nil {
 115  		w.Buffer.AppendString("null")
 116  		return
 117  	}
 118  	w.Buffer.AppendByte('"')
 119  	w.base64(data)
 120  	w.Buffer.AppendByte('"')
 121  }
 122  
 123  func (w *Writer) Uint8(n uint8) {
 124  	w.Buffer.EnsureSpace(3)
 125  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 126  }
 127  
 128  func (w *Writer) Uint16(n uint16) {
 129  	w.Buffer.EnsureSpace(5)
 130  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 131  }
 132  
 133  func (w *Writer) Uint32(n uint32) {
 134  	w.Buffer.EnsureSpace(10)
 135  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 136  }
 137  
 138  func (w *Writer) Uint(n uint) {
 139  	w.Buffer.EnsureSpace(20)
 140  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 141  }
 142  
 143  func (w *Writer) Uint64(n uint64) {
 144  	w.Buffer.EnsureSpace(20)
 145  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
 146  }
 147  
 148  func (w *Writer) Int8(n int8) {
 149  	w.Buffer.EnsureSpace(4)
 150  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
 151  }
 152  
 153  func (w *Writer) Int16(n int16) {
 154  	w.Buffer.EnsureSpace(6)
 155  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
 156  }
 157  
 158  func (w *Writer) Int32(n int32) {
 159  	w.Buffer.EnsureSpace(11)
 160  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
 161  }
 162  
 163  func (w *Writer) Int(n int) {
 164  	w.Buffer.EnsureSpace(21)
 165  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
 166  }
 167  
 168  func (w *Writer) Int64(n int64) {
 169  	w.Buffer.EnsureSpace(21)
 170  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
 171  }
 172  
 173  func (w *Writer) Uint8Str(n uint8) {
 174  	w.Buffer.EnsureSpace(3)
 175  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 176  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 177  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 178  }
 179  
 180  func (w *Writer) Uint16Str(n uint16) {
 181  	w.Buffer.EnsureSpace(5)
 182  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 183  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 184  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 185  }
 186  
 187  func (w *Writer) Uint32Str(n uint32) {
 188  	w.Buffer.EnsureSpace(10)
 189  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 190  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 191  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 192  }
 193  
 194  func (w *Writer) UintStr(n uint) {
 195  	w.Buffer.EnsureSpace(20)
 196  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 197  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 198  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 199  }
 200  
 201  func (w *Writer) Uint64Str(n uint64) {
 202  	w.Buffer.EnsureSpace(20)
 203  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 204  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
 205  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 206  }
 207  
 208  func (w *Writer) UintptrStr(n uintptr) {
 209  	w.Buffer.EnsureSpace(20)
 210  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 211  	w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
 212  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 213  }
 214  
 215  func (w *Writer) Int8Str(n int8) {
 216  	w.Buffer.EnsureSpace(4)
 217  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 218  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
 219  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 220  }
 221  
 222  func (w *Writer) Int16Str(n int16) {
 223  	w.Buffer.EnsureSpace(6)
 224  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 225  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
 226  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 227  }
 228  
 229  func (w *Writer) Int32Str(n int32) {
 230  	w.Buffer.EnsureSpace(11)
 231  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 232  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
 233  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 234  }
 235  
 236  func (w *Writer) IntStr(n int) {
 237  	w.Buffer.EnsureSpace(21)
 238  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 239  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
 240  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 241  }
 242  
 243  func (w *Writer) Int64Str(n int64) {
 244  	w.Buffer.EnsureSpace(21)
 245  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 246  	w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
 247  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 248  }
 249  
 250  func (w *Writer) Float32(n float32) {
 251  	w.Buffer.EnsureSpace(20)
 252  	w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
 253  }
 254  
 255  func (w *Writer) Float32Str(n float32) {
 256  	w.Buffer.EnsureSpace(20)
 257  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 258  	w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
 259  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 260  }
 261  
 262  func (w *Writer) Float64(n float64) {
 263  	w.Buffer.EnsureSpace(20)
 264  	w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, 'g', -1, 64)
 265  }
 266  
 267  func (w *Writer) Float64Str(n float64) {
 268  	w.Buffer.EnsureSpace(20)
 269  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 270  	w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 64)
 271  	w.Buffer.Buf = append(w.Buffer.Buf, '"')
 272  }
 273  
 274  func (w *Writer) Bool(v bool) {
 275  	w.Buffer.EnsureSpace(5)
 276  	if v {
 277  		w.Buffer.Buf = append(w.Buffer.Buf, "true"...)
 278  	} else {
 279  		w.Buffer.Buf = append(w.Buffer.Buf, "false"...)
 280  	}
 281  }
 282  
 283  const chars = "0123456789abcdef"
 284  
 285  func getTable(falseValues ...int) [128]bool {
 286  	table := [128]bool{}
 287  
 288  	for i := 0; i < 128; i++ {
 289  		table[i] = true
 290  	}
 291  
 292  	for _, v := range falseValues {
 293  		table[v] = false
 294  	}
 295  
 296  	return table
 297  }
 298  
 299  var (
 300  	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, '"', '&', '<', '>', '\\')
 301  	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, '"', '\\')
 302  )
 303  
 304  func (w *Writer) String(s string) {
 305  	w.Buffer.AppendByte('"')
 306  
 307  	// Portions of the string that contain no escapes are appended as
 308  	// byte slices.
 309  
 310  	p := 0 // last non-escape symbol
 311  
 312  	escapeTable := &htmlEscapeTable
 313  	if w.NoEscapeHTML {
 314  		escapeTable = &htmlNoEscapeTable
 315  	}
 316  
 317  	for i := 0; i < len(s); {
 318  		c := s[i]
 319  
 320  		if c < utf8.RuneSelf {
 321  			if escapeTable[c] {
 322  				// single-width character, no escaping is required
 323  				i++
 324  				continue
 325  			}
 326  
 327  			w.Buffer.AppendString(s[p:i])
 328  			switch c {
 329  			case '\t':
 330  				w.Buffer.AppendString(`\t`)
 331  			case '\r':
 332  				w.Buffer.AppendString(`\r`)
 333  			case '\n':
 334  				w.Buffer.AppendString(`\n`)
 335  			case '\\':
 336  				w.Buffer.AppendString(`\\`)
 337  			case '"':
 338  				w.Buffer.AppendString(`\"`)
 339  			default:
 340  				w.Buffer.AppendString(`\u00`)
 341  				w.Buffer.AppendByte(chars[c>>4])
 342  				w.Buffer.AppendByte(chars[c&0xf])
 343  			}
 344  
 345  			i++
 346  			p = i
 347  			continue
 348  		}
 349  
 350  		// broken utf
 351  		runeValue, runeWidth := utf8.DecodeRuneInString(s[i:])
 352  		if runeValue == utf8.RuneError && runeWidth == 1 {
 353  			w.Buffer.AppendString(s[p:i])
 354  			w.Buffer.AppendString(`\ufffd`)
 355  			i++
 356  			p = i
 357  			continue
 358  		}
 359  
 360  		// jsonp stuff - tab separator and line separator
 361  		if runeValue == '\u2028' || runeValue == '\u2029' {
 362  			w.Buffer.AppendString(s[p:i])
 363  			w.Buffer.AppendString(`\u202`)
 364  			w.Buffer.AppendByte(chars[runeValue&0xf])
 365  			i += runeWidth
 366  			p = i
 367  			continue
 368  		}
 369  		i += runeWidth
 370  	}
 371  	w.Buffer.AppendString(s[p:])
 372  	w.Buffer.AppendByte('"')
 373  }
 374  
 375  const encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 376  const padChar = '='
 377  
 378  func (w *Writer) base64(in []byte) {
 379  
 380  	if len(in) == 0 {
 381  		return
 382  	}
 383  
 384  	w.Buffer.EnsureSpace(((len(in)-1)/3 + 1) * 4)
 385  
 386  	si := 0
 387  	n := (len(in) / 3) * 3
 388  
 389  	for si < n {
 390  		// Convert 3x 8bit source bytes into 4 bytes
 391  		val := uint(in[si+0])<<16 | uint(in[si+1])<<8 | uint(in[si+2])
 392  
 393  		w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F], encode[val>>6&0x3F], encode[val&0x3F])
 394  
 395  		si += 3
 396  	}
 397  
 398  	remain := len(in) - si
 399  	if remain == 0 {
 400  		return
 401  	}
 402  
 403  	// Add the remaining small block
 404  	val := uint(in[si+0]) << 16
 405  	if remain == 2 {
 406  		val |= uint(in[si+1]) << 8
 407  	}
 408  
 409  	w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F])
 410  
 411  	switch remain {
 412  	case 2:
 413  		w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>6&0x3F], byte(padChar))
 414  	case 1:
 415  		w.Buffer.Buf = append(w.Buffer.Buf, byte(padChar), byte(padChar))
 416  	}
 417  }
 418