...

Source file src/github.com/mailru/easyjson/jwriter/writer.go

Documentation: github.com/mailru/easyjson/jwriter

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

View as plain text