1
2
3
4
5
6
7 package bsonrw
8
9 import (
10 "bytes"
11 "encoding/base64"
12 "fmt"
13 "io"
14 "math"
15 "sort"
16 "strconv"
17 "strings"
18 "sync"
19 "time"
20 "unicode/utf8"
21
22 "go.mongodb.org/mongo-driver/bson/primitive"
23 )
24
25
26
27
28 type ExtJSONValueWriterPool struct {
29 pool sync.Pool
30 }
31
32
33
34
35 func NewExtJSONValueWriterPool() *ExtJSONValueWriterPool {
36 return &ExtJSONValueWriterPool{
37 pool: sync.Pool{
38 New: func() interface{} {
39 return new(extJSONValueWriter)
40 },
41 },
42 }
43 }
44
45
46
47
48 func (bvwp *ExtJSONValueWriterPool) Get(w io.Writer, canonical, escapeHTML bool) ValueWriter {
49 vw := bvwp.pool.Get().(*extJSONValueWriter)
50 if writer, ok := w.(*SliceWriter); ok {
51 vw.reset(*writer, canonical, escapeHTML)
52 vw.w = writer
53 return vw
54 }
55 vw.buf = vw.buf[:0]
56 vw.w = w
57 return vw
58 }
59
60
61
62
63
64 func (bvwp *ExtJSONValueWriterPool) Put(vw ValueWriter) (ok bool) {
65 bvw, ok := vw.(*extJSONValueWriter)
66 if !ok {
67 return false
68 }
69
70 if _, ok := bvw.w.(*SliceWriter); ok {
71 bvw.buf = nil
72 }
73 bvw.w = nil
74
75 bvwp.pool.Put(bvw)
76 return true
77 }
78
79 type ejvwState struct {
80 mode mode
81 }
82
83 type extJSONValueWriter struct {
84 w io.Writer
85 buf []byte
86
87 stack []ejvwState
88 frame int64
89 canonical bool
90 escapeHTML bool
91 newlines bool
92 }
93
94
95 func NewExtJSONValueWriter(w io.Writer, canonical, escapeHTML bool) (ValueWriter, error) {
96 if w == nil {
97 return nil, errNilWriter
98 }
99
100
101
102
103 return newExtJSONWriter(w, canonical, escapeHTML, true), nil
104 }
105
106 func newExtJSONWriter(w io.Writer, canonical, escapeHTML, newlines bool) *extJSONValueWriter {
107 stack := make([]ejvwState, 1, 5)
108 stack[0] = ejvwState{mode: mTopLevel}
109
110 return &extJSONValueWriter{
111 w: w,
112 buf: []byte{},
113 stack: stack,
114 canonical: canonical,
115 escapeHTML: escapeHTML,
116 newlines: newlines,
117 }
118 }
119
120 func newExtJSONWriterFromSlice(buf []byte, canonical, escapeHTML bool) *extJSONValueWriter {
121 stack := make([]ejvwState, 1, 5)
122 stack[0] = ejvwState{mode: mTopLevel}
123
124 return &extJSONValueWriter{
125 buf: buf,
126 stack: stack,
127 canonical: canonical,
128 escapeHTML: escapeHTML,
129 }
130 }
131
132 func (ejvw *extJSONValueWriter) reset(buf []byte, canonical, escapeHTML bool) {
133 if ejvw.stack == nil {
134 ejvw.stack = make([]ejvwState, 1, 5)
135 }
136
137 ejvw.stack = ejvw.stack[:1]
138 ejvw.stack[0] = ejvwState{mode: mTopLevel}
139 ejvw.canonical = canonical
140 ejvw.escapeHTML = escapeHTML
141 ejvw.frame = 0
142 ejvw.buf = buf
143 ejvw.w = nil
144 }
145
146 func (ejvw *extJSONValueWriter) advanceFrame() {
147 if ejvw.frame+1 >= int64(len(ejvw.stack)) {
148 length := len(ejvw.stack)
149 if length+1 >= cap(ejvw.stack) {
150
151 buf := make([]ejvwState, 2*cap(ejvw.stack)+1)
152 copy(buf, ejvw.stack)
153 ejvw.stack = buf
154 }
155 ejvw.stack = ejvw.stack[:length+1]
156 }
157 ejvw.frame++
158 }
159
160 func (ejvw *extJSONValueWriter) push(m mode) {
161 ejvw.advanceFrame()
162
163 ejvw.stack[ejvw.frame].mode = m
164 }
165
166 func (ejvw *extJSONValueWriter) pop() {
167 switch ejvw.stack[ejvw.frame].mode {
168 case mElement, mValue:
169 ejvw.frame--
170 case mDocument, mArray, mCodeWithScope:
171 ejvw.frame -= 2
172 }
173 }
174
175 func (ejvw *extJSONValueWriter) invalidTransitionErr(destination mode, name string, modes []mode) error {
176 te := TransitionError{
177 name: name,
178 current: ejvw.stack[ejvw.frame].mode,
179 destination: destination,
180 modes: modes,
181 action: "write",
182 }
183 if ejvw.frame != 0 {
184 te.parent = ejvw.stack[ejvw.frame-1].mode
185 }
186 return te
187 }
188
189 func (ejvw *extJSONValueWriter) ensureElementValue(destination mode, callerName string, addmodes ...mode) error {
190 switch ejvw.stack[ejvw.frame].mode {
191 case mElement, mValue:
192 default:
193 modes := []mode{mElement, mValue}
194 if addmodes != nil {
195 modes = append(modes, addmodes...)
196 }
197 return ejvw.invalidTransitionErr(destination, callerName, modes)
198 }
199
200 return nil
201 }
202
203 func (ejvw *extJSONValueWriter) writeExtendedSingleValue(key string, value string, quotes bool) {
204 var s string
205 if quotes {
206 s = fmt.Sprintf(`{"$%s":"%s"}`, key, value)
207 } else {
208 s = fmt.Sprintf(`{"$%s":%s}`, key, value)
209 }
210
211 ejvw.buf = append(ejvw.buf, []byte(s)...)
212 }
213
214 func (ejvw *extJSONValueWriter) WriteArray() (ArrayWriter, error) {
215 if err := ejvw.ensureElementValue(mArray, "WriteArray"); err != nil {
216 return nil, err
217 }
218
219 ejvw.buf = append(ejvw.buf, '[')
220
221 ejvw.push(mArray)
222 return ejvw, nil
223 }
224
225 func (ejvw *extJSONValueWriter) WriteBinary(b []byte) error {
226 return ejvw.WriteBinaryWithSubtype(b, 0x00)
227 }
228
229 func (ejvw *extJSONValueWriter) WriteBinaryWithSubtype(b []byte, btype byte) error {
230 if err := ejvw.ensureElementValue(mode(0), "WriteBinaryWithSubtype"); err != nil {
231 return err
232 }
233
234 var buf bytes.Buffer
235 buf.WriteString(`{"$binary":{"base64":"`)
236 buf.WriteString(base64.StdEncoding.EncodeToString(b))
237 buf.WriteString(fmt.Sprintf(`","subType":"%02x"}},`, btype))
238
239 ejvw.buf = append(ejvw.buf, buf.Bytes()...)
240
241 ejvw.pop()
242 return nil
243 }
244
245 func (ejvw *extJSONValueWriter) WriteBoolean(b bool) error {
246 if err := ejvw.ensureElementValue(mode(0), "WriteBoolean"); err != nil {
247 return err
248 }
249
250 ejvw.buf = append(ejvw.buf, []byte(strconv.FormatBool(b))...)
251 ejvw.buf = append(ejvw.buf, ',')
252
253 ejvw.pop()
254 return nil
255 }
256
257 func (ejvw *extJSONValueWriter) WriteCodeWithScope(code string) (DocumentWriter, error) {
258 if err := ejvw.ensureElementValue(mCodeWithScope, "WriteCodeWithScope"); err != nil {
259 return nil, err
260 }
261
262 var buf bytes.Buffer
263 buf.WriteString(`{"$code":`)
264 writeStringWithEscapes(code, &buf, ejvw.escapeHTML)
265 buf.WriteString(`,"$scope":{`)
266
267 ejvw.buf = append(ejvw.buf, buf.Bytes()...)
268
269 ejvw.push(mCodeWithScope)
270 return ejvw, nil
271 }
272
273 func (ejvw *extJSONValueWriter) WriteDBPointer(ns string, oid primitive.ObjectID) error {
274 if err := ejvw.ensureElementValue(mode(0), "WriteDBPointer"); err != nil {
275 return err
276 }
277
278 var buf bytes.Buffer
279 buf.WriteString(`{"$dbPointer":{"$ref":"`)
280 buf.WriteString(ns)
281 buf.WriteString(`","$id":{"$oid":"`)
282 buf.WriteString(oid.Hex())
283 buf.WriteString(`"}}},`)
284
285 ejvw.buf = append(ejvw.buf, buf.Bytes()...)
286
287 ejvw.pop()
288 return nil
289 }
290
291 func (ejvw *extJSONValueWriter) WriteDateTime(dt int64) error {
292 if err := ejvw.ensureElementValue(mode(0), "WriteDateTime"); err != nil {
293 return err
294 }
295
296 t := time.Unix(dt/1e3, dt%1e3*1e6).UTC()
297
298 if ejvw.canonical || t.Year() < 1970 || t.Year() > 9999 {
299 s := fmt.Sprintf(`{"$numberLong":"%d"}`, dt)
300 ejvw.writeExtendedSingleValue("date", s, false)
301 } else {
302 ejvw.writeExtendedSingleValue("date", t.Format(rfc3339Milli), true)
303 }
304
305 ejvw.buf = append(ejvw.buf, ',')
306
307 ejvw.pop()
308 return nil
309 }
310
311 func (ejvw *extJSONValueWriter) WriteDecimal128(d primitive.Decimal128) error {
312 if err := ejvw.ensureElementValue(mode(0), "WriteDecimal128"); err != nil {
313 return err
314 }
315
316 ejvw.writeExtendedSingleValue("numberDecimal", d.String(), true)
317 ejvw.buf = append(ejvw.buf, ',')
318
319 ejvw.pop()
320 return nil
321 }
322
323 func (ejvw *extJSONValueWriter) WriteDocument() (DocumentWriter, error) {
324 if ejvw.stack[ejvw.frame].mode == mTopLevel {
325 ejvw.buf = append(ejvw.buf, '{')
326 return ejvw, nil
327 }
328
329 if err := ejvw.ensureElementValue(mDocument, "WriteDocument", mTopLevel); err != nil {
330 return nil, err
331 }
332
333 ejvw.buf = append(ejvw.buf, '{')
334 ejvw.push(mDocument)
335 return ejvw, nil
336 }
337
338 func (ejvw *extJSONValueWriter) WriteDouble(f float64) error {
339 if err := ejvw.ensureElementValue(mode(0), "WriteDouble"); err != nil {
340 return err
341 }
342
343 s := formatDouble(f)
344
345 if ejvw.canonical {
346 ejvw.writeExtendedSingleValue("numberDouble", s, true)
347 } else {
348 switch s {
349 case "Infinity":
350 fallthrough
351 case "-Infinity":
352 fallthrough
353 case "NaN":
354 s = fmt.Sprintf(`{"$numberDouble":"%s"}`, s)
355 }
356 ejvw.buf = append(ejvw.buf, []byte(s)...)
357 }
358
359 ejvw.buf = append(ejvw.buf, ',')
360
361 ejvw.pop()
362 return nil
363 }
364
365 func (ejvw *extJSONValueWriter) WriteInt32(i int32) error {
366 if err := ejvw.ensureElementValue(mode(0), "WriteInt32"); err != nil {
367 return err
368 }
369
370 s := strconv.FormatInt(int64(i), 10)
371
372 if ejvw.canonical {
373 ejvw.writeExtendedSingleValue("numberInt", s, true)
374 } else {
375 ejvw.buf = append(ejvw.buf, []byte(s)...)
376 }
377
378 ejvw.buf = append(ejvw.buf, ',')
379
380 ejvw.pop()
381 return nil
382 }
383
384 func (ejvw *extJSONValueWriter) WriteInt64(i int64) error {
385 if err := ejvw.ensureElementValue(mode(0), "WriteInt64"); err != nil {
386 return err
387 }
388
389 s := strconv.FormatInt(i, 10)
390
391 if ejvw.canonical {
392 ejvw.writeExtendedSingleValue("numberLong", s, true)
393 } else {
394 ejvw.buf = append(ejvw.buf, []byte(s)...)
395 }
396
397 ejvw.buf = append(ejvw.buf, ',')
398
399 ejvw.pop()
400 return nil
401 }
402
403 func (ejvw *extJSONValueWriter) WriteJavascript(code string) error {
404 if err := ejvw.ensureElementValue(mode(0), "WriteJavascript"); err != nil {
405 return err
406 }
407
408 var buf bytes.Buffer
409 writeStringWithEscapes(code, &buf, ejvw.escapeHTML)
410
411 ejvw.writeExtendedSingleValue("code", buf.String(), false)
412 ejvw.buf = append(ejvw.buf, ',')
413
414 ejvw.pop()
415 return nil
416 }
417
418 func (ejvw *extJSONValueWriter) WriteMaxKey() error {
419 if err := ejvw.ensureElementValue(mode(0), "WriteMaxKey"); err != nil {
420 return err
421 }
422
423 ejvw.writeExtendedSingleValue("maxKey", "1", false)
424 ejvw.buf = append(ejvw.buf, ',')
425
426 ejvw.pop()
427 return nil
428 }
429
430 func (ejvw *extJSONValueWriter) WriteMinKey() error {
431 if err := ejvw.ensureElementValue(mode(0), "WriteMinKey"); err != nil {
432 return err
433 }
434
435 ejvw.writeExtendedSingleValue("minKey", "1", false)
436 ejvw.buf = append(ejvw.buf, ',')
437
438 ejvw.pop()
439 return nil
440 }
441
442 func (ejvw *extJSONValueWriter) WriteNull() error {
443 if err := ejvw.ensureElementValue(mode(0), "WriteNull"); err != nil {
444 return err
445 }
446
447 ejvw.buf = append(ejvw.buf, []byte("null")...)
448 ejvw.buf = append(ejvw.buf, ',')
449
450 ejvw.pop()
451 return nil
452 }
453
454 func (ejvw *extJSONValueWriter) WriteObjectID(oid primitive.ObjectID) error {
455 if err := ejvw.ensureElementValue(mode(0), "WriteObjectID"); err != nil {
456 return err
457 }
458
459 ejvw.writeExtendedSingleValue("oid", oid.Hex(), true)
460 ejvw.buf = append(ejvw.buf, ',')
461
462 ejvw.pop()
463 return nil
464 }
465
466 func (ejvw *extJSONValueWriter) WriteRegex(pattern string, options string) error {
467 if err := ejvw.ensureElementValue(mode(0), "WriteRegex"); err != nil {
468 return err
469 }
470
471 var buf bytes.Buffer
472 buf.WriteString(`{"$regularExpression":{"pattern":`)
473 writeStringWithEscapes(pattern, &buf, ejvw.escapeHTML)
474 buf.WriteString(`,"options":"`)
475 buf.WriteString(sortStringAlphebeticAscending(options))
476 buf.WriteString(`"}},`)
477
478 ejvw.buf = append(ejvw.buf, buf.Bytes()...)
479
480 ejvw.pop()
481 return nil
482 }
483
484 func (ejvw *extJSONValueWriter) WriteString(s string) error {
485 if err := ejvw.ensureElementValue(mode(0), "WriteString"); err != nil {
486 return err
487 }
488
489 var buf bytes.Buffer
490 writeStringWithEscapes(s, &buf, ejvw.escapeHTML)
491
492 ejvw.buf = append(ejvw.buf, buf.Bytes()...)
493 ejvw.buf = append(ejvw.buf, ',')
494
495 ejvw.pop()
496 return nil
497 }
498
499 func (ejvw *extJSONValueWriter) WriteSymbol(symbol string) error {
500 if err := ejvw.ensureElementValue(mode(0), "WriteSymbol"); err != nil {
501 return err
502 }
503
504 var buf bytes.Buffer
505 writeStringWithEscapes(symbol, &buf, ejvw.escapeHTML)
506
507 ejvw.writeExtendedSingleValue("symbol", buf.String(), false)
508 ejvw.buf = append(ejvw.buf, ',')
509
510 ejvw.pop()
511 return nil
512 }
513
514 func (ejvw *extJSONValueWriter) WriteTimestamp(t uint32, i uint32) error {
515 if err := ejvw.ensureElementValue(mode(0), "WriteTimestamp"); err != nil {
516 return err
517 }
518
519 var buf bytes.Buffer
520 buf.WriteString(`{"$timestamp":{"t":`)
521 buf.WriteString(strconv.FormatUint(uint64(t), 10))
522 buf.WriteString(`,"i":`)
523 buf.WriteString(strconv.FormatUint(uint64(i), 10))
524 buf.WriteString(`}},`)
525
526 ejvw.buf = append(ejvw.buf, buf.Bytes()...)
527
528 ejvw.pop()
529 return nil
530 }
531
532 func (ejvw *extJSONValueWriter) WriteUndefined() error {
533 if err := ejvw.ensureElementValue(mode(0), "WriteUndefined"); err != nil {
534 return err
535 }
536
537 ejvw.writeExtendedSingleValue("undefined", "true", false)
538 ejvw.buf = append(ejvw.buf, ',')
539
540 ejvw.pop()
541 return nil
542 }
543
544 func (ejvw *extJSONValueWriter) WriteDocumentElement(key string) (ValueWriter, error) {
545 switch ejvw.stack[ejvw.frame].mode {
546 case mDocument, mTopLevel, mCodeWithScope:
547 var buf bytes.Buffer
548 writeStringWithEscapes(key, &buf, ejvw.escapeHTML)
549
550 ejvw.buf = append(ejvw.buf, []byte(fmt.Sprintf(`%s:`, buf.String()))...)
551 ejvw.push(mElement)
552 default:
553 return nil, ejvw.invalidTransitionErr(mElement, "WriteDocumentElement", []mode{mDocument, mTopLevel, mCodeWithScope})
554 }
555
556 return ejvw, nil
557 }
558
559 func (ejvw *extJSONValueWriter) WriteDocumentEnd() error {
560 switch ejvw.stack[ejvw.frame].mode {
561 case mDocument, mTopLevel, mCodeWithScope:
562 default:
563 return fmt.Errorf("incorrect mode to end document: %s", ejvw.stack[ejvw.frame].mode)
564 }
565
566
567 if ejvw.buf[len(ejvw.buf)-1] == ',' {
568 ejvw.buf[len(ejvw.buf)-1] = '}'
569 } else {
570 ejvw.buf = append(ejvw.buf, '}')
571 }
572
573 switch ejvw.stack[ejvw.frame].mode {
574 case mCodeWithScope:
575 ejvw.buf = append(ejvw.buf, '}')
576 fallthrough
577 case mDocument:
578 ejvw.buf = append(ejvw.buf, ',')
579 case mTopLevel:
580
581
582
583 if ejvw.newlines {
584 ejvw.buf = append(ejvw.buf, '\n')
585 }
586 if ejvw.w != nil {
587 if _, err := ejvw.w.Write(ejvw.buf); err != nil {
588 return err
589 }
590 ejvw.buf = ejvw.buf[:0]
591 }
592 }
593
594 ejvw.pop()
595 return nil
596 }
597
598 func (ejvw *extJSONValueWriter) WriteArrayElement() (ValueWriter, error) {
599 switch ejvw.stack[ejvw.frame].mode {
600 case mArray:
601 ejvw.push(mValue)
602 default:
603 return nil, ejvw.invalidTransitionErr(mValue, "WriteArrayElement", []mode{mArray})
604 }
605
606 return ejvw, nil
607 }
608
609 func (ejvw *extJSONValueWriter) WriteArrayEnd() error {
610 switch ejvw.stack[ejvw.frame].mode {
611 case mArray:
612
613 if ejvw.buf[len(ejvw.buf)-1] == ',' {
614 ejvw.buf[len(ejvw.buf)-1] = ']'
615 } else {
616 ejvw.buf = append(ejvw.buf, ']')
617 }
618
619 ejvw.buf = append(ejvw.buf, ',')
620
621 ejvw.pop()
622 default:
623 return fmt.Errorf("incorrect mode to end array: %s", ejvw.stack[ejvw.frame].mode)
624 }
625
626 return nil
627 }
628
629 func formatDouble(f float64) string {
630 var s string
631 if math.IsInf(f, 1) {
632 s = "Infinity"
633 } else if math.IsInf(f, -1) {
634 s = "-Infinity"
635 } else if math.IsNaN(f) {
636 s = "NaN"
637 } else {
638
639
640 s = strconv.FormatFloat(f, 'G', -1, 64)
641 if !strings.ContainsRune(s, 'E') && !strings.ContainsRune(s, '.') {
642 s += ".0"
643 }
644 }
645
646 return s
647 }
648
649 var hexChars = "0123456789abcdef"
650
651 func writeStringWithEscapes(s string, buf *bytes.Buffer, escapeHTML bool) {
652 buf.WriteByte('"')
653 start := 0
654 for i := 0; i < len(s); {
655 if b := s[i]; b < utf8.RuneSelf {
656 if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
657 i++
658 continue
659 }
660 if start < i {
661 buf.WriteString(s[start:i])
662 }
663 switch b {
664 case '\\', '"':
665 buf.WriteByte('\\')
666 buf.WriteByte(b)
667 case '\n':
668 buf.WriteByte('\\')
669 buf.WriteByte('n')
670 case '\r':
671 buf.WriteByte('\\')
672 buf.WriteByte('r')
673 case '\t':
674 buf.WriteByte('\\')
675 buf.WriteByte('t')
676 case '\b':
677 buf.WriteByte('\\')
678 buf.WriteByte('b')
679 case '\f':
680 buf.WriteByte('\\')
681 buf.WriteByte('f')
682 default:
683
684
685
686
687
688 buf.WriteString(`\u00`)
689 buf.WriteByte(hexChars[b>>4])
690 buf.WriteByte(hexChars[b&0xF])
691 }
692 i++
693 start = i
694 continue
695 }
696 c, size := utf8.DecodeRuneInString(s[i:])
697 if c == utf8.RuneError && size == 1 {
698 if start < i {
699 buf.WriteString(s[start:i])
700 }
701 buf.WriteString(`\ufffd`)
702 i += size
703 start = i
704 continue
705 }
706
707
708
709
710
711
712
713 if c == '\u2028' || c == '\u2029' {
714 if start < i {
715 buf.WriteString(s[start:i])
716 }
717 buf.WriteString(`\u202`)
718 buf.WriteByte(hexChars[c&0xF])
719 i += size
720 start = i
721 continue
722 }
723 i += size
724 }
725 if start < len(s) {
726 buf.WriteString(s[start:])
727 }
728 buf.WriteByte('"')
729 }
730
731 type sortableString []rune
732
733 func (ss sortableString) Len() int {
734 return len(ss)
735 }
736
737 func (ss sortableString) Less(i, j int) bool {
738 return ss[i] < ss[j]
739 }
740
741 func (ss sortableString) Swap(i, j int) {
742 oldI := ss[i]
743 ss[i] = ss[j]
744 ss[j] = oldI
745 }
746
747 func sortStringAlphebeticAscending(s string) string {
748 ss := sortableString([]rune(s))
749 sort.Sort(ss)
750 return string([]rune(ss))
751 }
752
View as plain text