blob: f0593d2bcd593f1d5c0a5fb659549d994e1fc1e3 [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// Copyright (C) MongoDB, Inc. 2017-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7package bsoncore
8
9import (
10 "bytes"
11 "encoding/base64"
12 "fmt"
13 "math"
14 "sort"
15 "strconv"
16 "strings"
17 "time"
18 "unicode/utf8"
19
20 "github.com/mongodb/mongo-go-driver/bson/bsontype"
21 "github.com/mongodb/mongo-go-driver/bson/primitive"
22)
23
24// ElementTypeError specifies that a method to obtain a BSON value an incorrect type was called on a bson.Value.
25type ElementTypeError struct {
26 Method string
27 Type bsontype.Type
28}
29
30// Error implements the error interface.
31func (ete ElementTypeError) Error() string {
32 return "Call of " + ete.Method + " on " + ete.Type.String() + " type"
33}
34
35// Value represents a BSON value with a type and raw bytes.
36type Value struct {
37 Type bsontype.Type
38 Data []byte
39}
40
41// Validate ensures the value is a valid BSON value.
42func (v Value) Validate() error {
43 _, _, valid := readValue(v.Data, v.Type)
44 if !valid {
45 return NewInsufficientBytesError(v.Data, v.Data)
46 }
47 return nil
48}
49
50// IsNumber returns true if the type of v is a numeric BSON type.
51func (v Value) IsNumber() bool {
52 switch v.Type {
53 case bsontype.Double, bsontype.Int32, bsontype.Int64, bsontype.Decimal128:
54 return true
55 default:
56 return false
57 }
58}
59
60// AsInt32 returns a BSON number as an int32. If the BSON type is not a numeric one, this method
61// will panic.
62//
63// TODO(skriptble): Add support for Decimal128.
64func (v Value) AsInt32() int32 { return 0 }
65
66// AsInt32OK functions the same as AsInt32 but returns a boolean instead of panicking. False
67// indicates an error.
68//
69// TODO(skriptble): Add support for Decimal128.
70func (v Value) AsInt32OK() (int32, bool) { return 0, false }
71
72// AsInt64 returns a BSON number as an int64. If the BSON type is not a numeric one, this method
73// will panic.
74//
75// TODO(skriptble): Add support for Decimal128.
76func (v Value) AsInt64() int64 { return 0 }
77
78// AsInt64OK functions the same as AsInt64 but returns a boolean instead of panicking. False
79// indicates an error.
80//
81// TODO(skriptble): Add support for Decimal128.
82func (v Value) AsInt64OK() (int64, bool) { return 0, false }
83
84// AsFloat64 returns a BSON number as an float64. If the BSON type is not a numeric one, this method
85// will panic.
86//
87// TODO(skriptble): Add support for Decimal128.
88func (v Value) AsFloat64() float64 { return 0 }
89
90// AsFloat64OK functions the same as AsFloat64 but returns a boolean instead of panicking. False
91// indicates an error.
92//
93// TODO(skriptble): Add support for Decimal128.
94func (v Value) AsFloat64OK() (float64, bool) { return 0, false }
95
96// Add will add this value to another. This is currently only implemented for strings and numbers.
97// If either value is a string, the other type is coerced into a string and added to the other.
98//
99// This method will alter v and will attempt to reuse the []byte of v. If the []byte is too small,
100// it will be expanded.
101func (v *Value) Add(v2 Value) error { return nil }
102
103// Equal compaes v to v2 and returns true if they are equal.
104func (v Value) Equal(v2 Value) bool {
105 if v.Type != v2.Type {
106 return false
107 }
108
109 return bytes.Equal(v.Data, v2.Data)
110}
111
112// String implements the fmt.String interface. This method will return values in extended JSON
113// format. If the value is not valid, this returns an empty string
114func (v Value) String() string {
115 switch v.Type {
116 case bsontype.Double:
117 f64, ok := v.DoubleOK()
118 if !ok {
119 return ""
120 }
121 return fmt.Sprintf(`{"$numberDouble":"%s"}`, formatDouble(f64))
122 case bsontype.String:
123 str, ok := v.StringValueOK()
124 if !ok {
125 return ""
126 }
127 return escapeString(str)
128 case bsontype.EmbeddedDocument:
129 doc, ok := v.DocumentOK()
130 if !ok {
131 return ""
132 }
133 return doc.String()
134 case bsontype.Array:
135 arr, ok := v.ArrayOK()
136 if !ok {
137 return ""
138 }
139 return docAsArray(arr, false)
140 case bsontype.Binary:
141 subtype, data, ok := v.BinaryOK()
142 if !ok {
143 return ""
144 }
145 return fmt.Sprintf(`{"$binary":{"base64":"%s","subType":"%02x"}}`, base64.StdEncoding.EncodeToString(data), subtype)
146 case bsontype.Undefined:
147 return `{"$undefined":true}`
148 case bsontype.ObjectID:
149 oid, ok := v.ObjectIDOK()
150 if !ok {
151 return ""
152 }
153 return fmt.Sprintf(`{"$oid":%s}`, oid.Hex())
154 case bsontype.Boolean:
155 b, ok := v.BooleanOK()
156 if !ok {
157 return ""
158 }
159 return strconv.FormatBool(b)
160 case bsontype.DateTime:
161 dt, ok := v.DateTimeOK()
162 if !ok {
163 return ""
164 }
165 return fmt.Sprintf(`{"$date":{"$numberLong":"%d"}}`, dt)
166 case bsontype.Null:
167 return "null"
168 case bsontype.Regex:
169 pattern, options, ok := v.RegexOK()
170 if !ok {
171 return ""
172 }
173 return fmt.Sprintf(
174 `{"$regularExpression":{"pattern":%s,"options":"%s"}}`,
175 escapeString(pattern), sortStringAlphebeticAscending(options),
176 )
177 case bsontype.DBPointer:
178 ns, pointer, ok := v.DBPointerOK()
179 if !ok {
180 return ""
181 }
182 return fmt.Sprintf(`{"$dbPointer":{"$ref":%s,"$id":{"$oid":"%s"}}}`, escapeString(ns), pointer.Hex())
183 case bsontype.JavaScript:
184 js, ok := v.JavaScriptOK()
185 if !ok {
186 return ""
187 }
188 return fmt.Sprintf(`{"$code":%s}`, escapeString(js))
189 case bsontype.Symbol:
190 symbol, ok := v.SymbolOK()
191 if !ok {
192 return ""
193 }
194 return fmt.Sprintf(`{"$symbol":%s}`, escapeString(symbol))
195 case bsontype.CodeWithScope:
196 code, scope, ok := v.CodeWithScopeOK()
197 if !ok {
198 return ""
199 }
200 return fmt.Sprintf(`{"$code":%s,"$scope":%s}`, code, scope)
201 case bsontype.Int32:
202 i32, ok := v.Int32OK()
203 if !ok {
204 return ""
205 }
206 return fmt.Sprintf(`{"$numberInt":"%d"}`, i32)
207 case bsontype.Timestamp:
208 t, i, ok := v.TimestampOK()
209 if !ok {
210 return ""
211 }
212 return fmt.Sprintf(`{"$timestamp":{"t":"%s","i":"%s"}}`, strconv.FormatUint(uint64(t), 10), strconv.FormatUint(uint64(i), 10))
213 case bsontype.Int64:
214 i64, ok := v.Int64OK()
215 if !ok {
216 return ""
217 }
218 return fmt.Sprintf(`{"$numberLong":"%d"}`, i64)
219 case bsontype.Decimal128:
220 d128, ok := v.Decimal128OK()
221 if !ok {
222 return ""
223 }
224 return fmt.Sprintf(`{"$numberDecimal":"%s"}`, d128.String())
225 case bsontype.MinKey:
226 return `{"$minKey":1}`
227 case bsontype.MaxKey:
228 return `{"$maxKey":1}`
229 default:
230 return ""
231 }
232}
233
234// DebugString outputs a human readable version of Document. It will attempt to stringify the
235// valid components of the document even if the entire document is not valid.
236func (v Value) DebugString() string {
237 switch v.Type {
238 case bsontype.String:
239 str, ok := v.StringValueOK()
240 if !ok {
241 return "<malformed>"
242 }
243 return escapeString(str)
244 case bsontype.EmbeddedDocument:
245 doc, ok := v.DocumentOK()
246 if !ok {
247 return "<malformed>"
248 }
249 return doc.DebugString()
250 case bsontype.Array:
251 arr, ok := v.ArrayOK()
252 if !ok {
253 return "<malformed>"
254 }
255 return docAsArray(arr, true)
256 case bsontype.CodeWithScope:
257 code, scope, ok := v.CodeWithScopeOK()
258 if !ok {
259 return ""
260 }
261 return fmt.Sprintf(`{"$code":%s,"$scope":%s}`, code, scope.DebugString())
262 default:
263 str := v.String()
264 if str == "" {
265 return "<malformed>"
266 }
267 return str
268 }
269}
270
271// Double returns the float64 value for this element.
272// It panics if e's BSON type is not bsontype.Double.
273func (v Value) Double() float64 {
274 if v.Type != bsontype.Double {
275 panic(ElementTypeError{"bsoncore.Value.Double", v.Type})
276 }
277 f64, _, ok := ReadDouble(v.Data)
278 if !ok {
279 panic(NewInsufficientBytesError(v.Data, v.Data))
280 }
281 return f64
282}
283
284// DoubleOK is the same as Double, but returns a boolean instead of panicking.
285func (v Value) DoubleOK() (float64, bool) {
286 if v.Type != bsontype.Double {
287 return 0, false
288 }
289 f64, _, ok := ReadDouble(v.Data)
290 if !ok {
291 return 0, false
292 }
293 return f64, true
294}
295
296// StringValue returns the string balue for this element.
297// It panics if e's BSON type is not bsontype.String.
298//
299// NOTE: This method is called StringValue to avoid a collision with the String method which
300// implements the fmt.Stringer interface.
301func (v Value) StringValue() string {
302 if v.Type != bsontype.String {
303 panic(ElementTypeError{"bsoncore.Value.StringValue", v.Type})
304 }
305 str, _, ok := ReadString(v.Data)
306 if !ok {
307 panic(NewInsufficientBytesError(v.Data, v.Data))
308 }
309 return str
310}
311
312// StringValueOK is the same as StringValue, but returns a boolean instead of
313// panicking.
314func (v Value) StringValueOK() (string, bool) {
315 if v.Type != bsontype.String {
316 return "", false
317 }
318 str, _, ok := ReadString(v.Data)
319 if !ok {
320 return "", false
321 }
322 return str, true
323}
324
325// Document returns the BSON document the Value represents as a Document. It panics if the
326// value is a BSON type other than document.
327func (v Value) Document() Document {
328 if v.Type != bsontype.EmbeddedDocument {
329 panic(ElementTypeError{"bsoncore.Value.Document", v.Type})
330 }
331 doc, _, ok := ReadDocument(v.Data)
332 if !ok {
333 panic(NewInsufficientBytesError(v.Data, v.Data))
334 }
335 return doc
336}
337
338// DocumentOK is the same as Document, except it returns a boolean
339// instead of panicking.
340func (v Value) DocumentOK() (Document, bool) {
341 if v.Type != bsontype.EmbeddedDocument {
342 return nil, false
343 }
344 doc, _, ok := ReadDocument(v.Data)
345 if !ok {
346 return nil, false
347 }
348 return doc, true
349}
350
351// Array returns the BSON array the Value represents as an Array. It panics if the
352// value is a BSON type other than array.
353func (v Value) Array() Document {
354 if v.Type != bsontype.Array {
355 panic(ElementTypeError{"bsoncore.Value.Array", v.Type})
356 }
357 arr, _, ok := ReadArray(v.Data)
358 if !ok {
359 panic(NewInsufficientBytesError(v.Data, v.Data))
360 }
361 return arr
362}
363
364// ArrayOK is the same as Array, except it returns a boolean instead
365// of panicking.
366func (v Value) ArrayOK() (Document, bool) {
367 if v.Type != bsontype.Array {
368 return nil, false
369 }
370 arr, _, ok := ReadArray(v.Data)
371 if !ok {
372 return nil, false
373 }
374 return arr, true
375}
376
377// Binary returns the BSON binary value the Value represents. It panics if the value is a BSON type
378// other than binary.
379func (v Value) Binary() (subtype byte, data []byte) {
380 if v.Type != bsontype.Binary {
381 panic(ElementTypeError{"bsoncore.Value.Binary", v.Type})
382 }
383 subtype, data, _, ok := ReadBinary(v.Data)
384 if !ok {
385 panic(NewInsufficientBytesError(v.Data, v.Data))
386 }
387 return subtype, data
388}
389
390// BinaryOK is the same as Binary, except it returns a boolean instead of
391// panicking.
392func (v Value) BinaryOK() (subtype byte, data []byte, ok bool) {
393 if v.Type != bsontype.Binary {
394 return 0x00, nil, false
395 }
396 subtype, data, _, ok = ReadBinary(v.Data)
397 if !ok {
398 return 0x00, nil, false
399 }
400 return subtype, data, true
401}
402
403// ObjectID returns the BSON objectid value the Value represents. It panics if the value is a BSON
404// type other than objectid.
405func (v Value) ObjectID() primitive.ObjectID {
406 if v.Type != bsontype.ObjectID {
407 panic(ElementTypeError{"bsoncore.Value.ObjectID", v.Type})
408 }
409 oid, _, ok := ReadObjectID(v.Data)
410 if !ok {
411 panic(NewInsufficientBytesError(v.Data, v.Data))
412 }
413 return oid
414}
415
416// ObjectIDOK is the same as ObjectID, except it returns a boolean instead of
417// panicking.
418func (v Value) ObjectIDOK() (primitive.ObjectID, bool) {
419 if v.Type != bsontype.ObjectID {
420 return primitive.ObjectID{}, false
421 }
422 oid, _, ok := ReadObjectID(v.Data)
423 if !ok {
424 return primitive.ObjectID{}, false
425 }
426 return oid, true
427}
428
429// Boolean returns the boolean value the Value represents. It panics if the
430// value is a BSON type other than boolean.
431func (v Value) Boolean() bool {
432 if v.Type != bsontype.Boolean {
433 panic(ElementTypeError{"bsoncore.Value.Boolean", v.Type})
434 }
435 b, _, ok := ReadBoolean(v.Data)
436 if !ok {
437 panic(NewInsufficientBytesError(v.Data, v.Data))
438 }
439 return b
440}
441
442// BooleanOK is the same as Boolean, except it returns a boolean instead of
443// panicking.
444func (v Value) BooleanOK() (bool, bool) {
445 if v.Type != bsontype.Boolean {
446 return false, false
447 }
448 b, _, ok := ReadBoolean(v.Data)
449 if !ok {
450 return false, false
451 }
452 return b, true
453}
454
455// DateTime returns the BSON datetime value the Value represents as a
456// unix timestamp. It panics if the value is a BSON type other than datetime.
457func (v Value) DateTime() int64 {
458 if v.Type != bsontype.DateTime {
459 panic(ElementTypeError{"bsoncore.Value.DateTime", v.Type})
460 }
461 dt, _, ok := ReadDateTime(v.Data)
462 if !ok {
463 panic(NewInsufficientBytesError(v.Data, v.Data))
464 }
465 return dt
466}
467
468// DateTimeOK is the same as DateTime, except it returns a boolean instead of
469// panicking.
470func (v Value) DateTimeOK() (int64, bool) {
471 if v.Type != bsontype.DateTime {
472 return 0, false
473 }
474 dt, _, ok := ReadDateTime(v.Data)
475 if !ok {
476 return 0, false
477 }
478 return dt, true
479}
480
481// Time returns the BSON datetime value the Value represents. It panics if the value is a BSON
482// type other than datetime.
483func (v Value) Time() time.Time {
484 if v.Type != bsontype.DateTime {
485 panic(ElementTypeError{"bsoncore.Value.Time", v.Type})
486 }
487 dt, _, ok := ReadDateTime(v.Data)
488 if !ok {
489 panic(NewInsufficientBytesError(v.Data, v.Data))
490 }
491 return time.Unix(int64(dt)/1000, int64(dt)%1000*1000000)
492}
493
494// TimeOK is the same as Time, except it returns a boolean instead of
495// panicking.
496func (v Value) TimeOK() (time.Time, bool) {
497 if v.Type != bsontype.DateTime {
498 return time.Time{}, false
499 }
500 dt, _, ok := ReadDateTime(v.Data)
501 if !ok {
502 return time.Time{}, false
503 }
504 return time.Unix(int64(dt)/1000, int64(dt)%1000*1000000), true
505}
506
507// Regex returns the BSON regex value the Value represents. It panics if the value is a BSON
508// type other than regex.
509func (v Value) Regex() (pattern, options string) {
510 if v.Type != bsontype.Regex {
511 panic(ElementTypeError{"bsoncore.Value.Regex", v.Type})
512 }
513 pattern, options, _, ok := ReadRegex(v.Data)
514 if !ok {
515 panic(NewInsufficientBytesError(v.Data, v.Data))
516 }
517 return pattern, options
518}
519
520// RegexOK is the same as Regex, except it returns a boolean instead of
521// panicking.
522func (v Value) RegexOK() (pattern, options string, ok bool) {
523 if v.Type != bsontype.Regex {
524 return "", "", false
525 }
526 pattern, options, _, ok = ReadRegex(v.Data)
527 if !ok {
528 return "", "", false
529 }
530 return pattern, options, true
531}
532
533// DBPointer returns the BSON dbpointer value the Value represents. It panics if the value is a BSON
534// type other than DBPointer.
535func (v Value) DBPointer() (string, primitive.ObjectID) {
536 if v.Type != bsontype.DBPointer {
537 panic(ElementTypeError{"bsoncore.Value.DBPointer", v.Type})
538 }
539 ns, pointer, _, ok := ReadDBPointer(v.Data)
540 if !ok {
541 panic(NewInsufficientBytesError(v.Data, v.Data))
542 }
543 return ns, pointer
544}
545
546// DBPointerOK is the same as DBPoitner, except that it returns a boolean
547// instead of panicking.
548func (v Value) DBPointerOK() (string, primitive.ObjectID, bool) {
549 if v.Type != bsontype.DBPointer {
550 return "", primitive.ObjectID{}, false
551 }
552 ns, pointer, _, ok := ReadDBPointer(v.Data)
553 if !ok {
554 return "", primitive.ObjectID{}, false
555 }
556 return ns, pointer, true
557}
558
559// JavaScript returns the BSON JavaScript code value the Value represents. It panics if the value is
560// a BSON type other than JavaScript code.
561func (v Value) JavaScript() string {
562 if v.Type != bsontype.JavaScript {
563 panic(ElementTypeError{"bsoncore.Value.JavaScript", v.Type})
564 }
565 js, _, ok := ReadJavaScript(v.Data)
566 if !ok {
567 panic(NewInsufficientBytesError(v.Data, v.Data))
568 }
569 return js
570}
571
572// JavaScriptOK is the same as Javascript, excepti that it returns a boolean
573// instead of panicking.
574func (v Value) JavaScriptOK() (string, bool) {
575 if v.Type != bsontype.JavaScript {
576 return "", false
577 }
578 js, _, ok := ReadJavaScript(v.Data)
579 if !ok {
580 return "", false
581 }
582 return js, true
583}
584
585// Symbol returns the BSON symbol value the Value represents. It panics if the value is a BSON
586// type other than symbol.
587func (v Value) Symbol() string {
588 if v.Type != bsontype.Symbol {
589 panic(ElementTypeError{"bsoncore.Value.Symbol", v.Type})
590 }
591 symbol, _, ok := ReadSymbol(v.Data)
592 if !ok {
593 panic(NewInsufficientBytesError(v.Data, v.Data))
594 }
595 return symbol
596}
597
598// SymbolOK is the same as Symbol, excepti that it returns a boolean
599// instead of panicking.
600func (v Value) SymbolOK() (string, bool) {
601 if v.Type != bsontype.Symbol {
602 return "", false
603 }
604 symbol, _, ok := ReadSymbol(v.Data)
605 if !ok {
606 return "", false
607 }
608 return symbol, true
609}
610
611// CodeWithScope returns the BSON JavaScript code with scope the Value represents.
612// It panics if the value is a BSON type other than JavaScript code with scope.
613func (v Value) CodeWithScope() (string, Document) {
614 if v.Type != bsontype.CodeWithScope {
615 panic(ElementTypeError{"bsoncore.Value.CodeWithScope", v.Type})
616 }
617 code, scope, _, ok := ReadCodeWithScope(v.Data)
618 if !ok {
619 panic(NewInsufficientBytesError(v.Data, v.Data))
620 }
621 return code, scope
622}
623
624// CodeWithScopeOK is the same as CodeWithScope, except that it returns a boolean instead of
625// panicking.
626func (v Value) CodeWithScopeOK() (string, Document, bool) {
627 if v.Type != bsontype.CodeWithScope {
628 return "", nil, false
629 }
630 code, scope, _, ok := ReadCodeWithScope(v.Data)
631 if !ok {
632 return "", nil, false
633 }
634 return code, scope, true
635}
636
637// Int32 returns the int32 the Value represents. It panics if the value is a BSON type other than
638// int32.
639func (v Value) Int32() int32 {
640 if v.Type != bsontype.Int32 {
641 panic(ElementTypeError{"bsoncore.Value.Int32", v.Type})
642 }
643 i32, _, ok := ReadInt32(v.Data)
644 if !ok {
645 panic(NewInsufficientBytesError(v.Data, v.Data))
646 }
647 return i32
648}
649
650// Int32OK is the same as Int32, except that it returns a boolean instead of
651// panicking.
652func (v Value) Int32OK() (int32, bool) {
653 if v.Type != bsontype.Int32 {
654 return 0, false
655 }
656 i32, _, ok := ReadInt32(v.Data)
657 if !ok {
658 return 0, false
659 }
660 return i32, true
661}
662
663// Timestamp returns the BSON timestamp value the Value represents. It panics if the value is a
664// BSON type other than timestamp.
665func (v Value) Timestamp() (t, i uint32) {
666 if v.Type != bsontype.Timestamp {
667 panic(ElementTypeError{"bsoncore.Value.Timestamp", v.Type})
668 }
669 t, i, _, ok := ReadTimestamp(v.Data)
670 if !ok {
671 panic(NewInsufficientBytesError(v.Data, v.Data))
672 }
673 return t, i
674}
675
676// TimestampOK is the same as Timestamp, except that it returns a boolean
677// instead of panicking.
678func (v Value) TimestampOK() (t, i uint32, ok bool) {
679 if v.Type != bsontype.Timestamp {
680 return 0, 0, false
681 }
682 t, i, _, ok = ReadTimestamp(v.Data)
683 if !ok {
684 return 0, 0, false
685 }
686 return t, i, true
687}
688
689// Int64 returns the int64 the Value represents. It panics if the value is a BSON type other than
690// int64.
691func (v Value) Int64() int64 {
692 if v.Type != bsontype.Int64 {
693 panic(ElementTypeError{"bsoncore.Value.Int64", v.Type})
694 }
695 i64, _, ok := ReadInt64(v.Data)
696 if !ok {
697 panic(NewInsufficientBytesError(v.Data, v.Data))
698 }
699 return i64
700}
701
702// Int64OK is the same as Int64, except that it returns a boolean instead of
703// panicking.
704func (v Value) Int64OK() (int64, bool) {
705 if v.Type != bsontype.Int64 {
706 return 0, false
707 }
708 i64, _, ok := ReadInt64(v.Data)
709 if !ok {
710 return 0, false
711 }
712 return i64, true
713}
714
715// Decimal128 returns the decimal the Value represents. It panics if the value is a BSON type other than
716// decimal.
717func (v Value) Decimal128() primitive.Decimal128 {
718 if v.Type != bsontype.Decimal128 {
719 panic(ElementTypeError{"bsoncore.Value.Decimal128", v.Type})
720 }
721 d128, _, ok := ReadDecimal128(v.Data)
722 if !ok {
723 panic(NewInsufficientBytesError(v.Data, v.Data))
724 }
725 return d128
726}
727
728// Decimal128OK is the same as Decimal128, except that it returns a boolean
729// instead of panicking.
730func (v Value) Decimal128OK() (primitive.Decimal128, bool) {
731 if v.Type != bsontype.Decimal128 {
732 return primitive.Decimal128{}, false
733 }
734 d128, _, ok := ReadDecimal128(v.Data)
735 if !ok {
736 return primitive.Decimal128{}, false
737 }
738 return d128, true
739}
740
741var hexChars = "0123456789abcdef"
742
743func escapeString(s string) string {
744 escapeHTML := true
745 var buf bytes.Buffer
746 buf.WriteByte('"')
747 start := 0
748 for i := 0; i < len(s); {
749 if b := s[i]; b < utf8.RuneSelf {
750 if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
751 i++
752 continue
753 }
754 if start < i {
755 buf.WriteString(s[start:i])
756 }
757 switch b {
758 case '\\', '"':
759 buf.WriteByte('\\')
760 buf.WriteByte(b)
761 case '\n':
762 buf.WriteByte('\\')
763 buf.WriteByte('n')
764 case '\r':
765 buf.WriteByte('\\')
766 buf.WriteByte('r')
767 case '\t':
768 buf.WriteByte('\\')
769 buf.WriteByte('t')
770 case '\b':
771 buf.WriteByte('\\')
772 buf.WriteByte('b')
773 case '\f':
774 buf.WriteByte('\\')
775 buf.WriteByte('f')
776 default:
777 // This encodes bytes < 0x20 except for \t, \n and \r.
778 // If escapeHTML is set, it also escapes <, >, and &
779 // because they can lead to security holes when
780 // user-controlled strings are rendered into JSON
781 // and served to some browsers.
782 buf.WriteString(`\u00`)
783 buf.WriteByte(hexChars[b>>4])
784 buf.WriteByte(hexChars[b&0xF])
785 }
786 i++
787 start = i
788 continue
789 }
790 c, size := utf8.DecodeRuneInString(s[i:])
791 if c == utf8.RuneError && size == 1 {
792 if start < i {
793 buf.WriteString(s[start:i])
794 }
795 buf.WriteString(`\ufffd`)
796 i += size
797 start = i
798 continue
799 }
800 // U+2028 is LINE SEPARATOR.
801 // U+2029 is PARAGRAPH SEPARATOR.
802 // They are both technically valid characters in JSON strings,
803 // but don't work in JSONP, which has to be evaluated as JavaScript,
804 // and can lead to security holes there. It is valid JSON to
805 // escape them, so we do so unconditionally.
806 // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
807 if c == '\u2028' || c == '\u2029' {
808 if start < i {
809 buf.WriteString(s[start:i])
810 }
811 buf.WriteString(`\u202`)
812 buf.WriteByte(hexChars[c&0xF])
813 i += size
814 start = i
815 continue
816 }
817 i += size
818 }
819 if start < len(s) {
820 buf.WriteString(s[start:])
821 }
822 buf.WriteByte('"')
823 return buf.String()
824}
825
826func formatDouble(f float64) string {
827 var s string
828 if math.IsInf(f, 1) {
829 s = "Infinity"
830 } else if math.IsInf(f, -1) {
831 s = "-Infinity"
832 } else if math.IsNaN(f) {
833 s = "NaN"
834 } else {
835 // Print exactly one decimalType place for integers; otherwise, print as many are necessary to
836 // perfectly represent it.
837 s = strconv.FormatFloat(f, 'G', -1, 64)
838 if !strings.ContainsRune(s, '.') {
839 s += ".0"
840 }
841 }
842
843 return s
844}
845
846type sortableString []rune
847
848func (ss sortableString) Len() int {
849 return len(ss)
850}
851
852func (ss sortableString) Less(i, j int) bool {
853 return ss[i] < ss[j]
854}
855
856func (ss sortableString) Swap(i, j int) {
857 oldI := ss[i]
858 ss[i] = ss[j]
859 ss[j] = oldI
860}
861
862func sortStringAlphebeticAscending(s string) string {
863 ss := sortableString([]rune(s))
864 sort.Sort(ss)
865 return string([]rune(ss))
866}
867
868func docAsArray(d Document, debug bool) string {
869 if len(d) < 5 {
870 return ""
871 }
872 var buf bytes.Buffer
873 buf.WriteByte('[')
874
875 length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length
876
877 length -= 4
878
879 var elem Element
880 var ok bool
881 first := true
882 for length > 1 {
883 if !first {
884 buf.WriteByte(',')
885 }
886 elem, rem, ok = ReadElement(rem)
887 length -= int32(len(elem))
888 if !ok {
889 return ""
890 }
891 if debug {
892 fmt.Fprintf(&buf, "%s ", elem.Value().DebugString())
893 } else {
894 fmt.Fprintf(&buf, "%s", elem.Value())
895 }
896 first = false
897 }
898 buf.WriteByte(']')
899
900 return buf.String()
901}