mirror of
				https://github.com/40t/go-sniffer.git
				synced 2025-10-25 10:29:18 +08:00 
			
		
		
		
	Merge branch 'develop'
This commit is contained in:
		
							
								
								
									
										25
									
								
								plugSrc/mongodb/build/bson/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								plugSrc/mongodb/build/bson/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | BSON library for Go | ||||||
|  |  | ||||||
|  | Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> | ||||||
|  |  | ||||||
|  | All rights reserved. | ||||||
|  |  | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are met:  | ||||||
|  |  | ||||||
|  | 1. Redistributions of source code must retain the above copyright notice, this | ||||||
|  |    list of conditions and the following disclaimer.  | ||||||
|  | 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |    this list of conditions and the following disclaimer in the documentation | ||||||
|  |    and/or other materials provided with the distribution.  | ||||||
|  |  | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||||
|  | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||||||
|  | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||||
|  | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										738
									
								
								plugSrc/mongodb/build/bson/bson.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										738
									
								
								plugSrc/mongodb/build/bson/bson.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,738 @@ | |||||||
|  | // BSON library for Go | ||||||
|  | // | ||||||
|  | // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> | ||||||
|  | // | ||||||
|  | // All rights reserved. | ||||||
|  | // | ||||||
|  | // Redistribution and use in source and binary forms, with or without | ||||||
|  | // modification, are permitted provided that the following conditions are met: | ||||||
|  | // | ||||||
|  | // 1. Redistributions of source code must retain the above copyright notice, this | ||||||
|  | //    list of conditions and the following disclaimer. | ||||||
|  | // 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  | //    this list of conditions and the following disclaimer in the documentation | ||||||
|  | //    and/or other materials provided with the distribution. | ||||||
|  | // | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||||
|  | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||||||
|  | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||||
|  | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  | ||||||
|  | // Package bson is an implementation of the BSON specification for Go: | ||||||
|  | // | ||||||
|  | //     http://bsonspec.org | ||||||
|  | // | ||||||
|  | // It was created as part of the mgo MongoDB driver for Go, but is standalone | ||||||
|  | // and may be used on its own without the driver. | ||||||
|  | package bson | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"crypto/md5" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"encoding/hex" | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | 	"reflect" | ||||||
|  | 	"runtime" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  | 	"sync/atomic" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // The public API. | ||||||
|  |  | ||||||
|  | // A value implementing the bson.Getter interface will have its GetBSON | ||||||
|  | // method called when the given value has to be marshalled, and the result | ||||||
|  | // of this method will be marshaled in place of the actual object. | ||||||
|  | // | ||||||
|  | // If GetBSON returns return a non-nil error, the marshalling procedure | ||||||
|  | // will stop and error out with the provided value. | ||||||
|  | type Getter interface { | ||||||
|  | 	GetBSON() (interface{}, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A value implementing the bson.Setter interface will receive the BSON | ||||||
|  | // value via the SetBSON method during unmarshaling, and the object | ||||||
|  | // itself will not be changed as usual. | ||||||
|  | // | ||||||
|  | // If setting the value works, the method should return nil or alternatively | ||||||
|  | // bson.SetZero to set the respective field to its zero value (nil for | ||||||
|  | // pointer types). If SetBSON returns a value of type bson.TypeError, the | ||||||
|  | // BSON value will be omitted from a map or slice being decoded and the | ||||||
|  | // unmarshalling will continue. If it returns any other non-nil error, the | ||||||
|  | // unmarshalling procedure will stop and error out with the provided value. | ||||||
|  | // | ||||||
|  | // This interface is generally useful in pointer receivers, since the method | ||||||
|  | // will want to change the receiver. A type field that implements the Setter | ||||||
|  | // interface doesn't have to be a pointer, though. | ||||||
|  | // | ||||||
|  | // Unlike the usual behavior, unmarshalling onto a value that implements a | ||||||
|  | // Setter interface will NOT reset the value to its zero state. This allows | ||||||
|  | // the value to decide by itself how to be unmarshalled. | ||||||
|  | // | ||||||
|  | // For example: | ||||||
|  | // | ||||||
|  | //     type MyString string | ||||||
|  | // | ||||||
|  | //     func (s *MyString) SetBSON(raw bson.Raw) error { | ||||||
|  | //         return raw.Unmarshal(s) | ||||||
|  | //     } | ||||||
|  | // | ||||||
|  | type Setter interface { | ||||||
|  | 	SetBSON(raw Raw) error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetZero may be returned from a SetBSON method to have the value set to | ||||||
|  | // its respective zero value. When used in pointer values, this will set the | ||||||
|  | // field to nil rather than to the pre-allocated value. | ||||||
|  | var SetZero = errors.New("set to zero") | ||||||
|  |  | ||||||
|  | // M is a convenient alias for a map[string]interface{} map, useful for | ||||||
|  | // dealing with BSON in a native way.  For instance: | ||||||
|  | // | ||||||
|  | //     bson.M{"a": 1, "b": true} | ||||||
|  | // | ||||||
|  | // There's no special handling for this type in addition to what's done anyway | ||||||
|  | // for an equivalent map type.  Elements in the map will be dumped in an | ||||||
|  | // undefined ordered. See also the bson.D type for an ordered alternative. | ||||||
|  | type M map[string]interface{} | ||||||
|  |  | ||||||
|  | // D represents a BSON document containing ordered elements. For example: | ||||||
|  | // | ||||||
|  | //     bson.D{{"a", 1}, {"b", true}} | ||||||
|  | // | ||||||
|  | // In some situations, such as when creating indexes for MongoDB, the order in | ||||||
|  | // which the elements are defined is important.  If the order is not important, | ||||||
|  | // using a map is generally more comfortable. See bson.M and bson.RawD. | ||||||
|  | type D []DocElem | ||||||
|  |  | ||||||
|  | // DocElem is an element of the bson.D document representation. | ||||||
|  | type DocElem struct { | ||||||
|  | 	Name  string | ||||||
|  | 	Value interface{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Map returns a map out of the ordered element name/value pairs in d. | ||||||
|  | func (d D) Map() (m M) { | ||||||
|  | 	m = make(M, len(d)) | ||||||
|  | 	for _, item := range d { | ||||||
|  | 		m[item.Name] = item.Value | ||||||
|  | 	} | ||||||
|  | 	return m | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // The Raw type represents raw unprocessed BSON documents and elements. | ||||||
|  | // Kind is the kind of element as defined per the BSON specification, and | ||||||
|  | // Data is the raw unprocessed data for the respective element. | ||||||
|  | // Using this type it is possible to unmarshal or marshal values partially. | ||||||
|  | // | ||||||
|  | // Relevant documentation: | ||||||
|  | // | ||||||
|  | //     http://bsonspec.org/#/specification | ||||||
|  | // | ||||||
|  | type Raw struct { | ||||||
|  | 	Kind byte | ||||||
|  | 	Data []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RawD represents a BSON document containing raw unprocessed elements. | ||||||
|  | // This low-level representation may be useful when lazily processing | ||||||
|  | // documents of uncertain content, or when manipulating the raw content | ||||||
|  | // documents in general. | ||||||
|  | type RawD []RawDocElem | ||||||
|  |  | ||||||
|  | // See the RawD type. | ||||||
|  | type RawDocElem struct { | ||||||
|  | 	Name  string | ||||||
|  | 	Value Raw | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes | ||||||
|  | // long. MongoDB objects by default have such a property set in their "_id" | ||||||
|  | // property. | ||||||
|  | // | ||||||
|  | // http://www.mongodb.org/display/DOCS/Object+IDs | ||||||
|  | type ObjectId string | ||||||
|  |  | ||||||
|  | // ObjectIdHex returns an ObjectId from the provided hex representation. | ||||||
|  | // Calling this function with an invalid hex representation will | ||||||
|  | // cause a runtime panic. See the IsObjectIdHex function. | ||||||
|  | func ObjectIdHex(s string) ObjectId { | ||||||
|  | 	d, err := hex.DecodeString(s) | ||||||
|  | 	if err != nil || len(d) != 12 { | ||||||
|  | 		panic(fmt.Sprintf("invalid input to ObjectIdHex: %q", s)) | ||||||
|  | 	} | ||||||
|  | 	return ObjectId(d) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsObjectIdHex returns whether s is a valid hex representation of | ||||||
|  | // an ObjectId. See the ObjectIdHex function. | ||||||
|  | func IsObjectIdHex(s string) bool { | ||||||
|  | 	if len(s) != 24 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	_, err := hex.DecodeString(s) | ||||||
|  | 	return err == nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // objectIdCounter is atomically incremented when generating a new ObjectId | ||||||
|  | // using NewObjectId() function. It's used as a counter part of an id. | ||||||
|  | var objectIdCounter uint32 = readRandomUint32() | ||||||
|  |  | ||||||
|  | // readRandomUint32 returns a random objectIdCounter. | ||||||
|  | func readRandomUint32() uint32 { | ||||||
|  | 	var b [4]byte | ||||||
|  | 	_, err := io.ReadFull(rand.Reader, b[:]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(fmt.Errorf("cannot read random object id: %v", err)) | ||||||
|  | 	} | ||||||
|  | 	return uint32((uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // machineId stores machine id generated once and used in subsequent calls | ||||||
|  | // to NewObjectId function. | ||||||
|  | var machineId = readMachineId() | ||||||
|  | var processId = os.Getpid() | ||||||
|  |  | ||||||
|  | // readMachineId generates and returns a machine id. | ||||||
|  | // If this function fails to get the hostname it will cause a runtime error. | ||||||
|  | func readMachineId() []byte { | ||||||
|  | 	var sum [3]byte | ||||||
|  | 	id := sum[:] | ||||||
|  | 	hostname, err1 := os.Hostname() | ||||||
|  | 	if err1 != nil { | ||||||
|  | 		_, err2 := io.ReadFull(rand.Reader, id) | ||||||
|  | 		if err2 != nil { | ||||||
|  | 			panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2)) | ||||||
|  | 		} | ||||||
|  | 		return id | ||||||
|  | 	} | ||||||
|  | 	hw := md5.New() | ||||||
|  | 	hw.Write([]byte(hostname)) | ||||||
|  | 	copy(id, hw.Sum(nil)) | ||||||
|  | 	return id | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewObjectId returns a new unique ObjectId. | ||||||
|  | func NewObjectId() ObjectId { | ||||||
|  | 	var b [12]byte | ||||||
|  | 	// Timestamp, 4 bytes, big endian | ||||||
|  | 	binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix())) | ||||||
|  | 	// Machine, first 3 bytes of md5(hostname) | ||||||
|  | 	b[4] = machineId[0] | ||||||
|  | 	b[5] = machineId[1] | ||||||
|  | 	b[6] = machineId[2] | ||||||
|  | 	// Pid, 2 bytes, specs don't specify endianness, but we use big endian. | ||||||
|  | 	b[7] = byte(processId >> 8) | ||||||
|  | 	b[8] = byte(processId) | ||||||
|  | 	// Increment, 3 bytes, big endian | ||||||
|  | 	i := atomic.AddUint32(&objectIdCounter, 1) | ||||||
|  | 	b[9] = byte(i >> 16) | ||||||
|  | 	b[10] = byte(i >> 8) | ||||||
|  | 	b[11] = byte(i) | ||||||
|  | 	return ObjectId(b[:]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled | ||||||
|  | // with the provided number of seconds from epoch UTC, and all other parts | ||||||
|  | // filled with zeroes. It's not safe to insert a document with an id generated | ||||||
|  | // by this method, it is useful only for queries to find documents with ids | ||||||
|  | // generated before or after the specified timestamp. | ||||||
|  | func NewObjectIdWithTime(t time.Time) ObjectId { | ||||||
|  | 	var b [12]byte | ||||||
|  | 	binary.BigEndian.PutUint32(b[:4], uint32(t.Unix())) | ||||||
|  | 	return ObjectId(string(b[:])) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // String returns a hex string representation of the id. | ||||||
|  | // Example: ObjectIdHex("4d88e15b60f486e428412dc9"). | ||||||
|  | func (id ObjectId) String() string { | ||||||
|  | 	return fmt.Sprintf(`ObjectIdHex("%x")`, string(id)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Hex returns a hex representation of the ObjectId. | ||||||
|  | func (id ObjectId) Hex() string { | ||||||
|  | 	return hex.EncodeToString([]byte(id)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MarshalJSON turns a bson.ObjectId into a json.Marshaller. | ||||||
|  | func (id ObjectId) MarshalJSON() ([]byte, error) { | ||||||
|  | 	return []byte(fmt.Sprintf(`"%x"`, string(id))), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var nullBytes = []byte("null") | ||||||
|  |  | ||||||
|  | // UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller. | ||||||
|  | func (id *ObjectId) UnmarshalJSON(data []byte) error { | ||||||
|  | 	if len(data) > 0 && (data[0] == '{' || data[0] == 'O') { | ||||||
|  | 		var v struct { | ||||||
|  | 			Id json.RawMessage `json:"$oid"` | ||||||
|  | 			Func struct { | ||||||
|  | 				Id json.RawMessage | ||||||
|  | 			} `json:"$oidFunc"` | ||||||
|  | 		} | ||||||
|  | 		err := jdec(data, &v) | ||||||
|  | 		if err == nil { | ||||||
|  | 			if len(v.Id) > 0 { | ||||||
|  | 				data = []byte(v.Id) | ||||||
|  | 			} else { | ||||||
|  | 				data = []byte(v.Func.Id) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) { | ||||||
|  | 		*id = "" | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if len(data) != 26 || data[0] != '"' || data[25] != '"' { | ||||||
|  | 		return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s", string(data))) | ||||||
|  | 	} | ||||||
|  | 	var buf [12]byte | ||||||
|  | 	_, err := hex.Decode(buf[:], data[1:25]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s (%s)", string(data), err)) | ||||||
|  | 	} | ||||||
|  | 	*id = ObjectId(string(buf[:])) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MarshalText turns bson.ObjectId into an encoding.TextMarshaler. | ||||||
|  | func (id ObjectId) MarshalText() ([]byte, error) { | ||||||
|  | 	return []byte(fmt.Sprintf("%x", string(id))), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler. | ||||||
|  | func (id *ObjectId) UnmarshalText(data []byte) error { | ||||||
|  | 	if len(data) == 1 && data[0] == ' ' || len(data) == 0 { | ||||||
|  | 		*id = "" | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if len(data) != 24 { | ||||||
|  | 		return fmt.Errorf("invalid ObjectId: %s", data) | ||||||
|  | 	} | ||||||
|  | 	var buf [12]byte | ||||||
|  | 	_, err := hex.Decode(buf[:], data[:]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("invalid ObjectId: %s (%s)", data, err) | ||||||
|  | 	} | ||||||
|  | 	*id = ObjectId(string(buf[:])) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Valid returns true if id is valid. A valid id must contain exactly 12 bytes. | ||||||
|  | func (id ObjectId) Valid() bool { | ||||||
|  | 	return len(id) == 12 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // byteSlice returns byte slice of id from start to end. | ||||||
|  | // Calling this function with an invalid id will cause a runtime panic. | ||||||
|  | func (id ObjectId) byteSlice(start, end int) []byte { | ||||||
|  | 	if len(id) != 12 { | ||||||
|  | 		panic(fmt.Sprintf("invalid ObjectId: %q", string(id))) | ||||||
|  | 	} | ||||||
|  | 	return []byte(string(id)[start:end]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Time returns the timestamp part of the id. | ||||||
|  | // It's a runtime error to call this method with an invalid id. | ||||||
|  | func (id ObjectId) Time() time.Time { | ||||||
|  | 	// First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch. | ||||||
|  | 	secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4))) | ||||||
|  | 	return time.Unix(secs, 0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Machine returns the 3-byte machine id part of the id. | ||||||
|  | // It's a runtime error to call this method with an invalid id. | ||||||
|  | func (id ObjectId) Machine() []byte { | ||||||
|  | 	return id.byteSlice(4, 7) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Pid returns the process id part of the id. | ||||||
|  | // It's a runtime error to call this method with an invalid id. | ||||||
|  | func (id ObjectId) Pid() uint16 { | ||||||
|  | 	return binary.BigEndian.Uint16(id.byteSlice(7, 9)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Counter returns the incrementing value part of the id. | ||||||
|  | // It's a runtime error to call this method with an invalid id. | ||||||
|  | func (id ObjectId) Counter() int32 { | ||||||
|  | 	b := id.byteSlice(9, 12) | ||||||
|  | 	// Counter is stored as big-endian 3-byte value | ||||||
|  | 	return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // The Symbol type is similar to a string and is used in languages with a | ||||||
|  | // distinct symbol type. | ||||||
|  | type Symbol string | ||||||
|  |  | ||||||
|  | // Now returns the current time with millisecond precision. MongoDB stores | ||||||
|  | // timestamps with the same precision, so a Time returned from this method | ||||||
|  | // will not change after a roundtrip to the database. That's the only reason | ||||||
|  | // why this function exists. Using the time.Now function also works fine | ||||||
|  | // otherwise. | ||||||
|  | func Now() time.Time { | ||||||
|  | 	return time.Unix(0, time.Now().UnixNano()/1e6*1e6) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MongoTimestamp is a special internal type used by MongoDB that for some | ||||||
|  | // strange reason has its own datatype defined in BSON. | ||||||
|  | type MongoTimestamp int64 | ||||||
|  |  | ||||||
|  | type orderKey int64 | ||||||
|  |  | ||||||
|  | // MaxKey is a special value that compares higher than all other possible BSON | ||||||
|  | // values in a MongoDB database. | ||||||
|  | var MaxKey = orderKey(1<<63 - 1) | ||||||
|  |  | ||||||
|  | // MinKey is a special value that compares lower than all other possible BSON | ||||||
|  | // values in a MongoDB database. | ||||||
|  | var MinKey = orderKey(-1 << 63) | ||||||
|  |  | ||||||
|  | type undefined struct{} | ||||||
|  |  | ||||||
|  | // Undefined represents the undefined BSON value. | ||||||
|  | var Undefined undefined | ||||||
|  |  | ||||||
|  | // Binary is a representation for non-standard binary values.  Any kind should | ||||||
|  | // work, but the following are known as of this writing: | ||||||
|  | // | ||||||
|  | //   0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}. | ||||||
|  | //   0x01 - Function (!?) | ||||||
|  | //   0x02 - Obsolete generic. | ||||||
|  | //   0x03 - UUID | ||||||
|  | //   0x05 - MD5 | ||||||
|  | //   0x80 - User defined. | ||||||
|  | // | ||||||
|  | type Binary struct { | ||||||
|  | 	Kind byte | ||||||
|  | 	Data []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RegEx represents a regular expression.  The Options field may contain | ||||||
|  | // individual characters defining the way in which the pattern should be | ||||||
|  | // applied, and must be sorted. Valid options as of this writing are 'i' for | ||||||
|  | // case insensitive matching, 'm' for multi-line matching, 'x' for verbose | ||||||
|  | // mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all | ||||||
|  | // mode (a '.' matches everything), and 'u' to make \w, \W, and similar match | ||||||
|  | // unicode. The value of the Options parameter is not verified before being | ||||||
|  | // marshaled into the BSON format. | ||||||
|  | type RegEx struct { | ||||||
|  | 	Pattern string | ||||||
|  | 	Options string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // JavaScript is a type that holds JavaScript code. If Scope is non-nil, it | ||||||
|  | // will be marshaled as a mapping from identifiers to values that may be | ||||||
|  | // used when evaluating the provided Code. | ||||||
|  | type JavaScript struct { | ||||||
|  | 	Code  string | ||||||
|  | 	Scope interface{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DBPointer refers to a document id in a namespace. | ||||||
|  | // | ||||||
|  | // This type is deprecated in the BSON specification and should not be used | ||||||
|  | // except for backwards compatibility with ancient applications. | ||||||
|  | type DBPointer struct { | ||||||
|  | 	Namespace string | ||||||
|  | 	Id        ObjectId | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const initialBufferSize = 64 | ||||||
|  |  | ||||||
|  | func handleErr(err *error) { | ||||||
|  | 	if r := recover(); r != nil { | ||||||
|  | 		if _, ok := r.(runtime.Error); ok { | ||||||
|  | 			panic(r) | ||||||
|  | 		} else if _, ok := r.(externalPanic); ok { | ||||||
|  | 			panic(r) | ||||||
|  | 		} else if s, ok := r.(string); ok { | ||||||
|  | 			*err = errors.New(s) | ||||||
|  | 		} else if e, ok := r.(error); ok { | ||||||
|  | 			*err = e | ||||||
|  | 		} else { | ||||||
|  | 			panic(r) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Marshal serializes the in value, which may be a map or a struct value. | ||||||
|  | // In the case of struct values, only exported fields will be serialized, | ||||||
|  | // and the order of serialized fields will match that of the struct itself. | ||||||
|  | // The lowercased field name is used as the key for each exported field, | ||||||
|  | // but this behavior may be changed using the respective field tag. | ||||||
|  | // The tag may also contain flags to tweak the marshalling behavior for | ||||||
|  | // the field. The tag formats accepted are: | ||||||
|  | // | ||||||
|  | //     "[<key>][,<flag1>[,<flag2>]]" | ||||||
|  | // | ||||||
|  | //     `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)` | ||||||
|  | // | ||||||
|  | // The following flags are currently supported: | ||||||
|  | // | ||||||
|  | //     omitempty  Only include the field if it's not set to the zero | ||||||
|  | //                value for the type or to empty slices or maps. | ||||||
|  | // | ||||||
|  | //     minsize    Marshal an int64 value as an int32, if that's feasible | ||||||
|  | //                while preserving the numeric value. | ||||||
|  | // | ||||||
|  | //     inline     Inline the field, which must be a struct or a map, | ||||||
|  | //                causing all of its fields or keys to be processed as if | ||||||
|  | //                they were part of the outer struct. For maps, keys must | ||||||
|  | //                not conflict with the bson keys of other struct fields. | ||||||
|  | // | ||||||
|  | // Some examples: | ||||||
|  | // | ||||||
|  | //     type T struct { | ||||||
|  | //         A bool | ||||||
|  | //         B int    "myb" | ||||||
|  | //         C string "myc,omitempty" | ||||||
|  | //         D string `bson:",omitempty" json:"jsonkey"` | ||||||
|  | //         E int64  ",minsize" | ||||||
|  | //         F int64  "myf,omitempty,minsize" | ||||||
|  | //     } | ||||||
|  | // | ||||||
|  | func Marshal(in interface{}) (out []byte, err error) { | ||||||
|  | 	defer handleErr(&err) | ||||||
|  | 	e := &encoder{make([]byte, 0, initialBufferSize)} | ||||||
|  | 	e.addDoc(reflect.ValueOf(in)) | ||||||
|  | 	return e.out, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Unmarshal deserializes data from in into the out value.  The out value | ||||||
|  | // must be a map, a pointer to a struct, or a pointer to a bson.D value. | ||||||
|  | // In the case of struct values, only exported fields will be deserialized. | ||||||
|  | // The lowercased field name is used as the key for each exported field, | ||||||
|  | // but this behavior may be changed using the respective field tag. | ||||||
|  | // The tag may also contain flags to tweak the marshalling behavior for | ||||||
|  | // the field. The tag formats accepted are: | ||||||
|  | // | ||||||
|  | //     "[<key>][,<flag1>[,<flag2>]]" | ||||||
|  | // | ||||||
|  | //     `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)` | ||||||
|  | // | ||||||
|  | // The following flags are currently supported during unmarshal (see the | ||||||
|  | // Marshal method for other flags): | ||||||
|  | // | ||||||
|  | //     inline     Inline the field, which must be a struct or a map. | ||||||
|  | //                Inlined structs are handled as if its fields were part | ||||||
|  | //                of the outer struct. An inlined map causes keys that do | ||||||
|  | //                not match any other struct field to be inserted in the | ||||||
|  | //                map rather than being discarded as usual. | ||||||
|  | // | ||||||
|  | // The target field or element types of out may not necessarily match | ||||||
|  | // the BSON values of the provided data.  The following conversions are | ||||||
|  | // made automatically: | ||||||
|  | // | ||||||
|  | // - Numeric types are converted if at least the integer part of the | ||||||
|  | //   value would be preserved correctly | ||||||
|  | // - Bools are converted to numeric types as 1 or 0 | ||||||
|  | // - Numeric types are converted to bools as true if not 0 or false otherwise | ||||||
|  | // - Binary and string BSON data is converted to a string, array or byte slice | ||||||
|  | // | ||||||
|  | // If the value would not fit the type and cannot be converted, it's | ||||||
|  | // silently skipped. | ||||||
|  | // | ||||||
|  | // Pointer values are initialized when necessary. | ||||||
|  | func Unmarshal(in []byte, out interface{}) (err error) { | ||||||
|  | 	if raw, ok := out.(*Raw); ok { | ||||||
|  | 		raw.Kind = 3 | ||||||
|  | 		raw.Data = in | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	defer handleErr(&err) | ||||||
|  | 	v := reflect.ValueOf(out) | ||||||
|  | 	switch v.Kind() { | ||||||
|  | 	case reflect.Ptr: | ||||||
|  | 		fallthrough | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		d := newDecoder(in) | ||||||
|  | 		d.readDocTo(v) | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		return errors.New("Unmarshal can't deal with struct values. Use a pointer.") | ||||||
|  | 	default: | ||||||
|  | 		return errors.New("Unmarshal needs a map or a pointer to a struct.") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Unmarshal deserializes raw into the out value.  If the out value type | ||||||
|  | // is not compatible with raw, a *bson.TypeError is returned. | ||||||
|  | // | ||||||
|  | // See the Unmarshal function documentation for more details on the | ||||||
|  | // unmarshalling process. | ||||||
|  | func (raw Raw) Unmarshal(out interface{}) (err error) { | ||||||
|  | 	defer handleErr(&err) | ||||||
|  | 	v := reflect.ValueOf(out) | ||||||
|  | 	switch v.Kind() { | ||||||
|  | 	case reflect.Ptr: | ||||||
|  | 		v = v.Elem() | ||||||
|  | 		fallthrough | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		d := newDecoder(raw.Data) | ||||||
|  | 		good := d.readElemTo(v, raw.Kind) | ||||||
|  | 		if !good { | ||||||
|  | 			return &TypeError{v.Type(), raw.Kind} | ||||||
|  | 		} | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		return errors.New("Raw Unmarshal can't deal with struct values. Use a pointer.") | ||||||
|  | 	default: | ||||||
|  | 		return errors.New("Raw Unmarshal needs a map or a valid pointer.") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type TypeError struct { | ||||||
|  | 	Type reflect.Type | ||||||
|  | 	Kind byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *TypeError) Error() string { | ||||||
|  | 	return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Maintain a mapping of keys to structure field indexes | ||||||
|  |  | ||||||
|  | type structInfo struct { | ||||||
|  | 	FieldsMap  map[string]fieldInfo | ||||||
|  | 	FieldsList []fieldInfo | ||||||
|  | 	InlineMap  int | ||||||
|  | 	Zero       reflect.Value | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type fieldInfo struct { | ||||||
|  | 	Key       string | ||||||
|  | 	Num       int | ||||||
|  | 	OmitEmpty bool | ||||||
|  | 	MinSize   bool | ||||||
|  | 	Inline    []int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var structMap = make(map[reflect.Type]*structInfo) | ||||||
|  | var structMapMutex sync.RWMutex | ||||||
|  |  | ||||||
|  | type externalPanic string | ||||||
|  |  | ||||||
|  | func (e externalPanic) String() string { | ||||||
|  | 	return string(e) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getStructInfo(st reflect.Type) (*structInfo, error) { | ||||||
|  | 	structMapMutex.RLock() | ||||||
|  | 	sinfo, found := structMap[st] | ||||||
|  | 	structMapMutex.RUnlock() | ||||||
|  | 	if found { | ||||||
|  | 		return sinfo, nil | ||||||
|  | 	} | ||||||
|  | 	n := st.NumField() | ||||||
|  | 	fieldsMap := make(map[string]fieldInfo) | ||||||
|  | 	fieldsList := make([]fieldInfo, 0, n) | ||||||
|  | 	inlineMap := -1 | ||||||
|  | 	for i := 0; i != n; i++ { | ||||||
|  | 		field := st.Field(i) | ||||||
|  | 		if field.PkgPath != "" && !field.Anonymous { | ||||||
|  | 			continue // Private field | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		info := fieldInfo{Num: i} | ||||||
|  |  | ||||||
|  | 		tag := field.Tag.Get("bson") | ||||||
|  | 		if tag == "" && strings.Index(string(field.Tag), ":") < 0 { | ||||||
|  | 			tag = string(field.Tag) | ||||||
|  | 		} | ||||||
|  | 		if tag == "-" { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		inline := false | ||||||
|  | 		fields := strings.Split(tag, ",") | ||||||
|  | 		if len(fields) > 1 { | ||||||
|  | 			for _, flag := range fields[1:] { | ||||||
|  | 				switch flag { | ||||||
|  | 				case "omitempty": | ||||||
|  | 					info.OmitEmpty = true | ||||||
|  | 				case "minsize": | ||||||
|  | 					info.MinSize = true | ||||||
|  | 				case "inline": | ||||||
|  | 					inline = true | ||||||
|  | 				default: | ||||||
|  | 					msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st) | ||||||
|  | 					panic(externalPanic(msg)) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			tag = fields[0] | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if inline { | ||||||
|  | 			switch field.Type.Kind() { | ||||||
|  | 			case reflect.Map: | ||||||
|  | 				if inlineMap >= 0 { | ||||||
|  | 					return nil, errors.New("Multiple ,inline maps in struct " + st.String()) | ||||||
|  | 				} | ||||||
|  | 				if field.Type.Key() != reflect.TypeOf("") { | ||||||
|  | 					return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) | ||||||
|  | 				} | ||||||
|  | 				inlineMap = info.Num | ||||||
|  | 			case reflect.Struct: | ||||||
|  | 				sinfo, err := getStructInfo(field.Type) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return nil, err | ||||||
|  | 				} | ||||||
|  | 				for _, finfo := range sinfo.FieldsList { | ||||||
|  | 					if _, found := fieldsMap[finfo.Key]; found { | ||||||
|  | 						msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() | ||||||
|  | 						return nil, errors.New(msg) | ||||||
|  | 					} | ||||||
|  | 					if finfo.Inline == nil { | ||||||
|  | 						finfo.Inline = []int{i, finfo.Num} | ||||||
|  | 					} else { | ||||||
|  | 						finfo.Inline = append([]int{i}, finfo.Inline...) | ||||||
|  | 					} | ||||||
|  | 					fieldsMap[finfo.Key] = finfo | ||||||
|  | 					fieldsList = append(fieldsList, finfo) | ||||||
|  | 				} | ||||||
|  | 			default: | ||||||
|  | 				panic("Option ,inline needs a struct value or map field") | ||||||
|  | 			} | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if tag != "" { | ||||||
|  | 			info.Key = tag | ||||||
|  | 		} else { | ||||||
|  | 			info.Key = strings.ToLower(field.Name) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if _, found = fieldsMap[info.Key]; found { | ||||||
|  | 			msg := "Duplicated key '" + info.Key + "' in struct " + st.String() | ||||||
|  | 			return nil, errors.New(msg) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		fieldsList = append(fieldsList, info) | ||||||
|  | 		fieldsMap[info.Key] = info | ||||||
|  | 	} | ||||||
|  | 	sinfo = &structInfo{ | ||||||
|  | 		fieldsMap, | ||||||
|  | 		fieldsList, | ||||||
|  | 		inlineMap, | ||||||
|  | 		reflect.New(st).Elem(), | ||||||
|  | 	} | ||||||
|  | 	structMapMutex.Lock() | ||||||
|  | 	structMap[st] = sinfo | ||||||
|  | 	structMapMutex.Unlock() | ||||||
|  | 	return sinfo, nil | ||||||
|  | } | ||||||
							
								
								
									
										310
									
								
								plugSrc/mongodb/build/bson/decimal.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								plugSrc/mongodb/build/bson/decimal.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,310 @@ | |||||||
|  | // BSON library for Go | ||||||
|  | // | ||||||
|  | // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> | ||||||
|  | // | ||||||
|  | // All rights reserved. | ||||||
|  | // | ||||||
|  | // Redistribution and use in source and binary forms, with or without | ||||||
|  | // modification, are permitted provided that the following conditions are met: | ||||||
|  | // | ||||||
|  | // 1. Redistributions of source code must retain the above copyright notice, this | ||||||
|  | //    list of conditions and the following disclaimer. | ||||||
|  | // 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  | //    this list of conditions and the following disclaimer in the documentation | ||||||
|  | //    and/or other materials provided with the distribution. | ||||||
|  | // | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||||
|  | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||||||
|  | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||||
|  | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  | ||||||
|  | package bson | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Decimal128 holds decimal128 BSON values. | ||||||
|  | type Decimal128 struct { | ||||||
|  | 	h, l uint64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d Decimal128) String() string { | ||||||
|  | 	var pos int     // positive sign | ||||||
|  | 	var e int       // exponent | ||||||
|  | 	var h, l uint64 // significand high/low | ||||||
|  |  | ||||||
|  | 	if d.h>>63&1 == 0 { | ||||||
|  | 		pos = 1 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch d.h >> 58 & (1<<5 - 1) { | ||||||
|  | 	case 0x1F: | ||||||
|  | 		return "NaN" | ||||||
|  | 	case 0x1E: | ||||||
|  | 		return "-Inf"[pos:] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	l = d.l | ||||||
|  | 	if d.h>>61&3 == 3 { | ||||||
|  | 		// Bits: 1*sign 2*ignored 14*exponent 111*significand. | ||||||
|  | 		// Implicit 0b100 prefix in significand. | ||||||
|  | 		e = int(d.h>>47&(1<<14-1)) - 6176 | ||||||
|  | 		//h = 4<<47 | d.h&(1<<47-1) | ||||||
|  | 		// Spec says all of these values are out of range. | ||||||
|  | 		h, l = 0, 0 | ||||||
|  | 	} else { | ||||||
|  | 		// Bits: 1*sign 14*exponent 113*significand | ||||||
|  | 		e = int(d.h>>49&(1<<14-1)) - 6176 | ||||||
|  | 		h = d.h & (1<<49 - 1) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Would be handled by the logic below, but that's trivial and common. | ||||||
|  | 	if h == 0 && l == 0 && e == 0 { | ||||||
|  | 		return "-0"[pos:] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero. | ||||||
|  | 	var last = len(repr) | ||||||
|  | 	var i = len(repr) | ||||||
|  | 	var dot = len(repr) + e | ||||||
|  | 	var rem uint32 | ||||||
|  | Loop: | ||||||
|  | 	for d9 := 0; d9 < 5; d9++ { | ||||||
|  | 		h, l, rem = divmod(h, l, 1e9) | ||||||
|  | 		for d1 := 0; d1 < 9; d1++ { | ||||||
|  | 			// Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc. | ||||||
|  | 			if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) { | ||||||
|  | 				e += len(repr) - i | ||||||
|  | 				i-- | ||||||
|  | 				repr[i] = '.' | ||||||
|  | 				last = i - 1 | ||||||
|  | 				dot = len(repr) // Unmark. | ||||||
|  | 			} | ||||||
|  | 			c := '0' + byte(rem%10) | ||||||
|  | 			rem /= 10 | ||||||
|  | 			i-- | ||||||
|  | 			repr[i] = c | ||||||
|  | 			// Handle "0E+3", "1E+3", etc. | ||||||
|  | 			if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) { | ||||||
|  | 				last = i | ||||||
|  | 				break Loop | ||||||
|  | 			} | ||||||
|  | 			if c != '0' { | ||||||
|  | 				last = i | ||||||
|  | 			} | ||||||
|  | 			// Break early. Works without it, but why. | ||||||
|  | 			if dot > i && l == 0 && h == 0 && rem == 0 { | ||||||
|  | 				break Loop | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	repr[last-1] = '-' | ||||||
|  | 	last-- | ||||||
|  |  | ||||||
|  | 	if e > 0 { | ||||||
|  | 		return string(repr[last+pos:]) + "E+" + strconv.Itoa(e) | ||||||
|  | 	} | ||||||
|  | 	if e < 0 { | ||||||
|  | 		return string(repr[last+pos:]) + "E" + strconv.Itoa(e) | ||||||
|  | 	} | ||||||
|  | 	return string(repr[last+pos:]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) { | ||||||
|  | 	div64 := uint64(div) | ||||||
|  | 	a := h >> 32 | ||||||
|  | 	aq := a / div64 | ||||||
|  | 	ar := a % div64 | ||||||
|  | 	b := ar<<32 + h&(1<<32-1) | ||||||
|  | 	bq := b / div64 | ||||||
|  | 	br := b % div64 | ||||||
|  | 	c := br<<32 + l>>32 | ||||||
|  | 	cq := c / div64 | ||||||
|  | 	cr := c % div64 | ||||||
|  | 	d := cr<<32 + l&(1<<32-1) | ||||||
|  | 	dq := d / div64 | ||||||
|  | 	dr := d % div64 | ||||||
|  | 	return (aq<<32 | bq), (cq<<32 | dq), uint32(dr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var dNaN = Decimal128{0x1F << 58, 0} | ||||||
|  | var dPosInf = Decimal128{0x1E << 58, 0} | ||||||
|  | var dNegInf = Decimal128{0x3E << 58, 0} | ||||||
|  |  | ||||||
|  | func dErr(s string) (Decimal128, error) { | ||||||
|  | 	return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ParseDecimal128(s string) (Decimal128, error) { | ||||||
|  | 	orig := s | ||||||
|  | 	if s == "" { | ||||||
|  | 		return dErr(orig) | ||||||
|  | 	} | ||||||
|  | 	neg := s[0] == '-' | ||||||
|  | 	if neg || s[0] == '+' { | ||||||
|  | 		s = s[1:] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') { | ||||||
|  | 		if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") { | ||||||
|  | 			return dNaN, nil | ||||||
|  | 		} | ||||||
|  | 		if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") { | ||||||
|  | 			if neg { | ||||||
|  | 				return dNegInf, nil | ||||||
|  | 			} | ||||||
|  | 			return dPosInf, nil | ||||||
|  | 		} | ||||||
|  | 		return dErr(orig) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var h, l uint64 | ||||||
|  | 	var e int | ||||||
|  |  | ||||||
|  | 	var add, ovr uint32 | ||||||
|  | 	var mul uint32 = 1 | ||||||
|  | 	var dot = -1 | ||||||
|  | 	var digits = 0 | ||||||
|  | 	var i = 0 | ||||||
|  | 	for i < len(s) { | ||||||
|  | 		c := s[i] | ||||||
|  | 		if mul == 1e9 { | ||||||
|  | 			h, l, ovr = muladd(h, l, mul, add) | ||||||
|  | 			mul, add = 1, 0 | ||||||
|  | 			if ovr > 0 || h&((1<<15-1)<<49) > 0 { | ||||||
|  | 				return dErr(orig) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if c >= '0' && c <= '9' { | ||||||
|  | 			i++ | ||||||
|  | 			if c > '0' || digits > 0 { | ||||||
|  | 				digits++ | ||||||
|  | 			} | ||||||
|  | 			if digits > 34 { | ||||||
|  | 				if c == '0' { | ||||||
|  | 					// Exact rounding. | ||||||
|  | 					e++ | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 				return dErr(orig) | ||||||
|  | 			} | ||||||
|  | 			mul *= 10 | ||||||
|  | 			add *= 10 | ||||||
|  | 			add += uint32(c - '0') | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if c == '.' { | ||||||
|  | 			i++ | ||||||
|  | 			if dot >= 0 || i == 1 && len(s) == 1 { | ||||||
|  | 				return dErr(orig) | ||||||
|  | 			} | ||||||
|  | 			if i == len(s) { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			if s[i] < '0' || s[i] > '9' || e > 0 { | ||||||
|  | 				return dErr(orig) | ||||||
|  | 			} | ||||||
|  | 			dot = i | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		break | ||||||
|  | 	} | ||||||
|  | 	if i == 0 { | ||||||
|  | 		return dErr(orig) | ||||||
|  | 	} | ||||||
|  | 	if mul > 1 { | ||||||
|  | 		h, l, ovr = muladd(h, l, mul, add) | ||||||
|  | 		if ovr > 0 || h&((1<<15-1)<<49) > 0 { | ||||||
|  | 			return dErr(orig) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if dot >= 0 { | ||||||
|  | 		e += dot - i | ||||||
|  | 	} | ||||||
|  | 	if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') { | ||||||
|  | 		i++ | ||||||
|  | 		eneg := s[i] == '-' | ||||||
|  | 		if eneg || s[i] == '+' { | ||||||
|  | 			i++ | ||||||
|  | 			if i == len(s) { | ||||||
|  | 				return dErr(orig) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		n := 0 | ||||||
|  | 		for i < len(s) && n < 1e4 { | ||||||
|  | 			c := s[i] | ||||||
|  | 			i++ | ||||||
|  | 			if c < '0' || c > '9' { | ||||||
|  | 				return dErr(orig) | ||||||
|  | 			} | ||||||
|  | 			n *= 10 | ||||||
|  | 			n += int(c - '0') | ||||||
|  | 		} | ||||||
|  | 		if eneg { | ||||||
|  | 			n = -n | ||||||
|  | 		} | ||||||
|  | 		e += n | ||||||
|  | 		for e < -6176 { | ||||||
|  | 			// Subnormal. | ||||||
|  | 			var div uint32 = 1 | ||||||
|  | 			for div < 1e9 && e < -6176 { | ||||||
|  | 				div *= 10 | ||||||
|  | 				e++ | ||||||
|  | 			} | ||||||
|  | 			var rem uint32 | ||||||
|  | 			h, l, rem = divmod(h, l, div) | ||||||
|  | 			if rem > 0 { | ||||||
|  | 				return dErr(orig) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		for e > 6111 { | ||||||
|  | 			// Clamped. | ||||||
|  | 			var mul uint32 = 1 | ||||||
|  | 			for mul < 1e9 && e > 6111 { | ||||||
|  | 				mul *= 10 | ||||||
|  | 				e-- | ||||||
|  | 			} | ||||||
|  | 			h, l, ovr = muladd(h, l, mul, 0) | ||||||
|  | 			if ovr > 0 || h&((1<<15-1)<<49) > 0 { | ||||||
|  | 				return dErr(orig) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if e < -6176 || e > 6111 { | ||||||
|  | 			return dErr(orig) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if i < len(s) { | ||||||
|  | 		return dErr(orig) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	h |= uint64(e+6176) & uint64(1<<14-1) << 49 | ||||||
|  | 	if neg { | ||||||
|  | 		h |= 1 << 63 | ||||||
|  | 	} | ||||||
|  | 	return Decimal128{h, l}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) { | ||||||
|  | 	mul64 := uint64(mul) | ||||||
|  | 	a := mul64 * (l & (1<<32 - 1)) | ||||||
|  | 	b := a>>32 + mul64*(l>>32) | ||||||
|  | 	c := b>>32 + mul64*(h&(1<<32-1)) | ||||||
|  | 	d := c>>32 + mul64*(h>>32) | ||||||
|  |  | ||||||
|  | 	a = a&(1<<32-1) + uint64(add) | ||||||
|  | 	b = b&(1<<32-1) + a>>32 | ||||||
|  | 	c = c&(1<<32-1) + b>>32 | ||||||
|  | 	d = d&(1<<32-1) + c>>32 | ||||||
|  |  | ||||||
|  | 	return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32) | ||||||
|  | } | ||||||
							
								
								
									
										849
									
								
								plugSrc/mongodb/build/bson/decode.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										849
									
								
								plugSrc/mongodb/build/bson/decode.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,849 @@ | |||||||
|  | // BSON library for Go | ||||||
|  | // | ||||||
|  | // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> | ||||||
|  | // | ||||||
|  | // All rights reserved. | ||||||
|  | // | ||||||
|  | // Redistribution and use in source and binary forms, with or without | ||||||
|  | // modification, are permitted provided that the following conditions are met: | ||||||
|  | // | ||||||
|  | // 1. Redistributions of source code must retain the above copyright notice, this | ||||||
|  | //    list of conditions and the following disclaimer. | ||||||
|  | // 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  | //    this list of conditions and the following disclaimer in the documentation | ||||||
|  | //    and/or other materials provided with the distribution. | ||||||
|  | // | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||||
|  | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||||||
|  | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||||
|  | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | // gobson - BSON library for Go. | ||||||
|  |  | ||||||
|  | package bson | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"math" | ||||||
|  | 	"net/url" | ||||||
|  | 	"reflect" | ||||||
|  | 	"strconv" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type decoder struct { | ||||||
|  | 	in      []byte | ||||||
|  | 	i       int | ||||||
|  | 	docType reflect.Type | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var typeM = reflect.TypeOf(M{}) | ||||||
|  |  | ||||||
|  | func newDecoder(in []byte) *decoder { | ||||||
|  | 	return &decoder{in, 0, typeM} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Some helper functions. | ||||||
|  |  | ||||||
|  | func corrupted() { | ||||||
|  | 	panic("Document is corrupted") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func settableValueOf(i interface{}) reflect.Value { | ||||||
|  | 	v := reflect.ValueOf(i) | ||||||
|  | 	sv := reflect.New(v.Type()).Elem() | ||||||
|  | 	sv.Set(v) | ||||||
|  | 	return sv | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Unmarshaling of documents. | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	setterUnknown = iota | ||||||
|  | 	setterNone | ||||||
|  | 	setterType | ||||||
|  | 	setterAddr | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var setterStyles map[reflect.Type]int | ||||||
|  | var setterIface reflect.Type | ||||||
|  | var setterMutex sync.RWMutex | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	var iface Setter | ||||||
|  | 	setterIface = reflect.TypeOf(&iface).Elem() | ||||||
|  | 	setterStyles = make(map[reflect.Type]int) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func setterStyle(outt reflect.Type) int { | ||||||
|  | 	setterMutex.RLock() | ||||||
|  | 	style := setterStyles[outt] | ||||||
|  | 	setterMutex.RUnlock() | ||||||
|  | 	if style == setterUnknown { | ||||||
|  | 		setterMutex.Lock() | ||||||
|  | 		defer setterMutex.Unlock() | ||||||
|  | 		if outt.Implements(setterIface) { | ||||||
|  | 			setterStyles[outt] = setterType | ||||||
|  | 		} else if reflect.PtrTo(outt).Implements(setterIface) { | ||||||
|  | 			setterStyles[outt] = setterAddr | ||||||
|  | 		} else { | ||||||
|  | 			setterStyles[outt] = setterNone | ||||||
|  | 		} | ||||||
|  | 		style = setterStyles[outt] | ||||||
|  | 	} | ||||||
|  | 	return style | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getSetter(outt reflect.Type, out reflect.Value) Setter { | ||||||
|  | 	style := setterStyle(outt) | ||||||
|  | 	if style == setterNone { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if style == setterAddr { | ||||||
|  | 		if !out.CanAddr() { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		out = out.Addr() | ||||||
|  | 	} else if outt.Kind() == reflect.Ptr && out.IsNil() { | ||||||
|  | 		out.Set(reflect.New(outt.Elem())) | ||||||
|  | 	} | ||||||
|  | 	return out.Interface().(Setter) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func clearMap(m reflect.Value) { | ||||||
|  | 	var none reflect.Value | ||||||
|  | 	for _, k := range m.MapKeys() { | ||||||
|  | 		m.SetMapIndex(k, none) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readDocTo(out reflect.Value) { | ||||||
|  | 	var elemType reflect.Type | ||||||
|  | 	outt := out.Type() | ||||||
|  | 	outk := outt.Kind() | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		if outk == reflect.Ptr && out.IsNil() { | ||||||
|  | 			out.Set(reflect.New(outt.Elem())) | ||||||
|  | 		} | ||||||
|  | 		if setter := getSetter(outt, out); setter != nil { | ||||||
|  | 			var raw Raw | ||||||
|  | 			d.readDocTo(reflect.ValueOf(&raw)) | ||||||
|  | 			err := setter.SetBSON(raw) | ||||||
|  | 			if _, ok := err.(*TypeError); err != nil && !ok { | ||||||
|  | 				panic(err) | ||||||
|  | 			} | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if outk == reflect.Ptr { | ||||||
|  | 			out = out.Elem() | ||||||
|  | 			outt = out.Type() | ||||||
|  | 			outk = out.Kind() | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		break | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var fieldsMap map[string]fieldInfo | ||||||
|  | 	var inlineMap reflect.Value | ||||||
|  | 	start := d.i | ||||||
|  |  | ||||||
|  | 	origout := out | ||||||
|  | 	if outk == reflect.Interface { | ||||||
|  | 		if d.docType.Kind() == reflect.Map { | ||||||
|  | 			mv := reflect.MakeMap(d.docType) | ||||||
|  | 			out.Set(mv) | ||||||
|  | 			out = mv | ||||||
|  | 		} else { | ||||||
|  | 			dv := reflect.New(d.docType).Elem() | ||||||
|  | 			out.Set(dv) | ||||||
|  | 			out = dv | ||||||
|  | 		} | ||||||
|  | 		outt = out.Type() | ||||||
|  | 		outk = outt.Kind() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	docType := d.docType | ||||||
|  | 	keyType := typeString | ||||||
|  | 	convertKey := false | ||||||
|  | 	switch outk { | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		keyType = outt.Key() | ||||||
|  | 		if keyType.Kind() != reflect.String { | ||||||
|  | 			panic("BSON map must have string keys. Got: " + outt.String()) | ||||||
|  | 		} | ||||||
|  | 		if keyType != typeString { | ||||||
|  | 			convertKey = true | ||||||
|  | 		} | ||||||
|  | 		elemType = outt.Elem() | ||||||
|  | 		if elemType == typeIface { | ||||||
|  | 			d.docType = outt | ||||||
|  | 		} | ||||||
|  | 		if out.IsNil() { | ||||||
|  | 			out.Set(reflect.MakeMap(out.Type())) | ||||||
|  | 		} else if out.Len() > 0 { | ||||||
|  | 			clearMap(out) | ||||||
|  | 		} | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		if outt != typeRaw { | ||||||
|  | 			sinfo, err := getStructInfo(out.Type()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				panic(err) | ||||||
|  | 			} | ||||||
|  | 			fieldsMap = sinfo.FieldsMap | ||||||
|  | 			out.Set(sinfo.Zero) | ||||||
|  | 			if sinfo.InlineMap != -1 { | ||||||
|  | 				inlineMap = out.Field(sinfo.InlineMap) | ||||||
|  | 				if !inlineMap.IsNil() && inlineMap.Len() > 0 { | ||||||
|  | 					clearMap(inlineMap) | ||||||
|  | 				} | ||||||
|  | 				elemType = inlineMap.Type().Elem() | ||||||
|  | 				if elemType == typeIface { | ||||||
|  | 					d.docType = inlineMap.Type() | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	case reflect.Slice: | ||||||
|  | 		switch outt.Elem() { | ||||||
|  | 		case typeDocElem: | ||||||
|  | 			origout.Set(d.readDocElems(outt)) | ||||||
|  | 			return | ||||||
|  | 		case typeRawDocElem: | ||||||
|  | 			origout.Set(d.readRawDocElems(outt)) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		fallthrough | ||||||
|  | 	default: | ||||||
|  | 		panic("Unsupported document type for unmarshalling: " + out.Type().String()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	end := int(d.readInt32()) | ||||||
|  | 	end += d.i - 4 | ||||||
|  | 	if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	for d.in[d.i] != '\x00' { | ||||||
|  | 		kind := d.readByte() | ||||||
|  | 		name := d.readCStr() | ||||||
|  | 		if d.i >= end { | ||||||
|  | 			corrupted() | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		switch outk { | ||||||
|  | 		case reflect.Map: | ||||||
|  | 			e := reflect.New(elemType).Elem() | ||||||
|  | 			if d.readElemTo(e, kind) { | ||||||
|  | 				k := reflect.ValueOf(name) | ||||||
|  | 				if convertKey { | ||||||
|  | 					k = k.Convert(keyType) | ||||||
|  | 				} | ||||||
|  | 				out.SetMapIndex(k, e) | ||||||
|  | 			} | ||||||
|  | 		case reflect.Struct: | ||||||
|  | 			if outt == typeRaw { | ||||||
|  | 				d.dropElem(kind) | ||||||
|  | 			} else { | ||||||
|  | 				if info, ok := fieldsMap[name]; ok { | ||||||
|  | 					if info.Inline == nil { | ||||||
|  | 						d.readElemTo(out.Field(info.Num), kind) | ||||||
|  | 					} else { | ||||||
|  | 						d.readElemTo(out.FieldByIndex(info.Inline), kind) | ||||||
|  | 					} | ||||||
|  | 				} else if inlineMap.IsValid() { | ||||||
|  | 					if inlineMap.IsNil() { | ||||||
|  | 						inlineMap.Set(reflect.MakeMap(inlineMap.Type())) | ||||||
|  | 					} | ||||||
|  | 					e := reflect.New(elemType).Elem() | ||||||
|  | 					if d.readElemTo(e, kind) { | ||||||
|  | 						inlineMap.SetMapIndex(reflect.ValueOf(name), e) | ||||||
|  | 					} | ||||||
|  | 				} else { | ||||||
|  | 					d.dropElem(kind) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		case reflect.Slice: | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if d.i >= end { | ||||||
|  | 			corrupted() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	d.i++ // '\x00' | ||||||
|  | 	if d.i != end { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	d.docType = docType | ||||||
|  |  | ||||||
|  | 	if outt == typeRaw { | ||||||
|  | 		out.Set(reflect.ValueOf(Raw{0x03, d.in[start:d.i]})) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readArrayDocTo(out reflect.Value) { | ||||||
|  | 	end := int(d.readInt32()) | ||||||
|  | 	end += d.i - 4 | ||||||
|  | 	if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	i := 0 | ||||||
|  | 	l := out.Len() | ||||||
|  | 	for d.in[d.i] != '\x00' { | ||||||
|  | 		if i >= l { | ||||||
|  | 			panic("Length mismatch on array field") | ||||||
|  | 		} | ||||||
|  | 		kind := d.readByte() | ||||||
|  | 		for d.i < end && d.in[d.i] != '\x00' { | ||||||
|  | 			d.i++ | ||||||
|  | 		} | ||||||
|  | 		if d.i >= end { | ||||||
|  | 			corrupted() | ||||||
|  | 		} | ||||||
|  | 		d.i++ | ||||||
|  | 		d.readElemTo(out.Index(i), kind) | ||||||
|  | 		if d.i >= end { | ||||||
|  | 			corrupted() | ||||||
|  | 		} | ||||||
|  | 		i++ | ||||||
|  | 	} | ||||||
|  | 	if i != l { | ||||||
|  | 		panic("Length mismatch on array field") | ||||||
|  | 	} | ||||||
|  | 	d.i++ // '\x00' | ||||||
|  | 	if d.i != end { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readSliceDoc(t reflect.Type) interface{} { | ||||||
|  | 	tmp := make([]reflect.Value, 0, 8) | ||||||
|  | 	elemType := t.Elem() | ||||||
|  | 	if elemType == typeRawDocElem { | ||||||
|  | 		d.dropElem(0x04) | ||||||
|  | 		return reflect.Zero(t).Interface() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	end := int(d.readInt32()) | ||||||
|  | 	end += d.i - 4 | ||||||
|  | 	if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	for d.in[d.i] != '\x00' { | ||||||
|  | 		kind := d.readByte() | ||||||
|  | 		for d.i < end && d.in[d.i] != '\x00' { | ||||||
|  | 			d.i++ | ||||||
|  | 		} | ||||||
|  | 		if d.i >= end { | ||||||
|  | 			corrupted() | ||||||
|  | 		} | ||||||
|  | 		d.i++ | ||||||
|  | 		e := reflect.New(elemType).Elem() | ||||||
|  | 		if d.readElemTo(e, kind) { | ||||||
|  | 			tmp = append(tmp, e) | ||||||
|  | 		} | ||||||
|  | 		if d.i >= end { | ||||||
|  | 			corrupted() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	d.i++ // '\x00' | ||||||
|  | 	if d.i != end { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	n := len(tmp) | ||||||
|  | 	slice := reflect.MakeSlice(t, n, n) | ||||||
|  | 	for i := 0; i != n; i++ { | ||||||
|  | 		slice.Index(i).Set(tmp[i]) | ||||||
|  | 	} | ||||||
|  | 	return slice.Interface() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var typeSlice = reflect.TypeOf([]interface{}{}) | ||||||
|  | var typeIface = typeSlice.Elem() | ||||||
|  |  | ||||||
|  | func (d *decoder) readDocElems(typ reflect.Type) reflect.Value { | ||||||
|  | 	docType := d.docType | ||||||
|  | 	d.docType = typ | ||||||
|  | 	slice := make([]DocElem, 0, 8) | ||||||
|  | 	d.readDocWith(func(kind byte, name string) { | ||||||
|  | 		e := DocElem{Name: name} | ||||||
|  | 		v := reflect.ValueOf(&e.Value) | ||||||
|  | 		if d.readElemTo(v.Elem(), kind) { | ||||||
|  | 			slice = append(slice, e) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	slicev := reflect.New(typ).Elem() | ||||||
|  | 	slicev.Set(reflect.ValueOf(slice)) | ||||||
|  | 	d.docType = docType | ||||||
|  | 	return slicev | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readRawDocElems(typ reflect.Type) reflect.Value { | ||||||
|  | 	docType := d.docType | ||||||
|  | 	d.docType = typ | ||||||
|  | 	slice := make([]RawDocElem, 0, 8) | ||||||
|  | 	d.readDocWith(func(kind byte, name string) { | ||||||
|  | 		e := RawDocElem{Name: name} | ||||||
|  | 		v := reflect.ValueOf(&e.Value) | ||||||
|  | 		if d.readElemTo(v.Elem(), kind) { | ||||||
|  | 			slice = append(slice, e) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	slicev := reflect.New(typ).Elem() | ||||||
|  | 	slicev.Set(reflect.ValueOf(slice)) | ||||||
|  | 	d.docType = docType | ||||||
|  | 	return slicev | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readDocWith(f func(kind byte, name string)) { | ||||||
|  | 	end := int(d.readInt32()) | ||||||
|  | 	end += d.i - 4 | ||||||
|  | 	if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	for d.in[d.i] != '\x00' { | ||||||
|  | 		kind := d.readByte() | ||||||
|  | 		name := d.readCStr() | ||||||
|  | 		if d.i >= end { | ||||||
|  | 			corrupted() | ||||||
|  | 		} | ||||||
|  | 		f(kind, name) | ||||||
|  | 		if d.i >= end { | ||||||
|  | 			corrupted() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	d.i++ // '\x00' | ||||||
|  | 	if d.i != end { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Unmarshaling of individual elements within a document. | ||||||
|  |  | ||||||
|  | var blackHole = settableValueOf(struct{}{}) | ||||||
|  |  | ||||||
|  | func (d *decoder) dropElem(kind byte) { | ||||||
|  | 	d.readElemTo(blackHole, kind) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Attempt to decode an element from the document and put it into out. | ||||||
|  | // If the types are not compatible, the returned ok value will be | ||||||
|  | // false and out will be unchanged. | ||||||
|  | func (d *decoder) readElemTo(out reflect.Value, kind byte) (good bool) { | ||||||
|  |  | ||||||
|  | 	start := d.i | ||||||
|  |  | ||||||
|  | 	if kind == 0x03 { | ||||||
|  | 		// Delegate unmarshaling of documents. | ||||||
|  | 		outt := out.Type() | ||||||
|  | 		outk := out.Kind() | ||||||
|  | 		switch outk { | ||||||
|  | 		case reflect.Interface, reflect.Ptr, reflect.Struct, reflect.Map: | ||||||
|  | 			d.readDocTo(out) | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 		if setterStyle(outt) != setterNone { | ||||||
|  | 			d.readDocTo(out) | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 		if outk == reflect.Slice { | ||||||
|  | 			switch outt.Elem() { | ||||||
|  | 			case typeDocElem: | ||||||
|  | 				out.Set(d.readDocElems(outt)) | ||||||
|  | 			case typeRawDocElem: | ||||||
|  | 				out.Set(d.readRawDocElems(outt)) | ||||||
|  | 			default: | ||||||
|  | 				d.readDocTo(blackHole) | ||||||
|  | 			} | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 		d.readDocTo(blackHole) | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var in interface{} | ||||||
|  |  | ||||||
|  | 	switch kind { | ||||||
|  | 	case 0x01: // Float64 | ||||||
|  | 		in = d.readFloat64() | ||||||
|  | 	case 0x02: // UTF-8 string | ||||||
|  | 		in = d.readStr() | ||||||
|  | 	case 0x03: // Document | ||||||
|  | 		panic("Can't happen. Handled above.") | ||||||
|  | 	case 0x04: // Array | ||||||
|  | 		outt := out.Type() | ||||||
|  | 		if setterStyle(outt) != setterNone { | ||||||
|  | 			// Skip the value so its data is handed to the setter below. | ||||||
|  | 			d.dropElem(kind) | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		for outt.Kind() == reflect.Ptr { | ||||||
|  | 			outt = outt.Elem() | ||||||
|  | 		} | ||||||
|  | 		switch outt.Kind() { | ||||||
|  | 		case reflect.Array: | ||||||
|  | 			d.readArrayDocTo(out) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Slice: | ||||||
|  | 			in = d.readSliceDoc(outt) | ||||||
|  | 		default: | ||||||
|  | 			in = d.readSliceDoc(typeSlice) | ||||||
|  | 		} | ||||||
|  | 	case 0x05: // Binary | ||||||
|  | 		b := d.readBinary() | ||||||
|  | 		if b.Kind == 0x00 || b.Kind == 0x02 { | ||||||
|  | 			in = b.Data | ||||||
|  | 		} else { | ||||||
|  | 			in = b | ||||||
|  | 		} | ||||||
|  | 	case 0x06: // Undefined (obsolete, but still seen in the wild) | ||||||
|  | 		in = Undefined | ||||||
|  | 	case 0x07: // ObjectId | ||||||
|  | 		in = ObjectId(d.readBytes(12)) | ||||||
|  | 	case 0x08: // Bool | ||||||
|  | 		in = d.readBool() | ||||||
|  | 	case 0x09: // Timestamp | ||||||
|  | 		// MongoDB handles timestamps as milliseconds. | ||||||
|  | 		i := d.readInt64() | ||||||
|  | 		if i == -62135596800000 { | ||||||
|  | 			in = time.Time{} // In UTC for convenience. | ||||||
|  | 		} else { | ||||||
|  | 			in = time.Unix(i/1e3, i%1e3*1e6) | ||||||
|  | 		} | ||||||
|  | 	case 0x0A: // Nil | ||||||
|  | 		in = nil | ||||||
|  | 	case 0x0B: // RegEx | ||||||
|  | 		in = d.readRegEx() | ||||||
|  | 	case 0x0C: | ||||||
|  | 		in = DBPointer{Namespace: d.readStr(), Id: ObjectId(d.readBytes(12))} | ||||||
|  | 	case 0x0D: // JavaScript without scope | ||||||
|  | 		in = JavaScript{Code: d.readStr()} | ||||||
|  | 	case 0x0E: // Symbol | ||||||
|  | 		in = Symbol(d.readStr()) | ||||||
|  | 	case 0x0F: // JavaScript with scope | ||||||
|  | 		d.i += 4 // Skip length | ||||||
|  | 		js := JavaScript{d.readStr(), make(M)} | ||||||
|  | 		d.readDocTo(reflect.ValueOf(js.Scope)) | ||||||
|  | 		in = js | ||||||
|  | 	case 0x10: // Int32 | ||||||
|  | 		in = int(d.readInt32()) | ||||||
|  | 	case 0x11: // Mongo-specific timestamp | ||||||
|  | 		in = MongoTimestamp(d.readInt64()) | ||||||
|  | 	case 0x12: // Int64 | ||||||
|  | 		in = d.readInt64() | ||||||
|  | 	case 0x13: // Decimal128 | ||||||
|  | 		in = Decimal128{ | ||||||
|  | 			l: uint64(d.readInt64()), | ||||||
|  | 			h: uint64(d.readInt64()), | ||||||
|  | 		} | ||||||
|  | 	case 0x7F: // Max key | ||||||
|  | 		in = MaxKey | ||||||
|  | 	case 0xFF: // Min key | ||||||
|  | 		in = MinKey | ||||||
|  | 	default: | ||||||
|  | 		panic(fmt.Sprintf("Unknown element kind (0x%02X)", kind)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	outt := out.Type() | ||||||
|  |  | ||||||
|  | 	if outt == typeRaw { | ||||||
|  | 		out.Set(reflect.ValueOf(Raw{kind, d.in[start:d.i]})) | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if setter := getSetter(outt, out); setter != nil { | ||||||
|  | 		err := setter.SetBSON(Raw{kind, d.in[start:d.i]}) | ||||||
|  | 		if err == SetZero { | ||||||
|  | 			out.Set(reflect.Zero(outt)) | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 		if err == nil { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 		if _, ok := err.(*TypeError); !ok { | ||||||
|  | 			panic(err) | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if in == nil { | ||||||
|  | 		out.Set(reflect.Zero(outt)) | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	outk := outt.Kind() | ||||||
|  |  | ||||||
|  | 	// Dereference and initialize pointer if necessary. | ||||||
|  | 	first := true | ||||||
|  | 	for outk == reflect.Ptr { | ||||||
|  | 		if !out.IsNil() { | ||||||
|  | 			out = out.Elem() | ||||||
|  | 		} else { | ||||||
|  | 			elem := reflect.New(outt.Elem()) | ||||||
|  | 			if first { | ||||||
|  | 				// Only set if value is compatible. | ||||||
|  | 				first = false | ||||||
|  | 				defer func(out, elem reflect.Value) { | ||||||
|  | 					if good { | ||||||
|  | 						out.Set(elem) | ||||||
|  | 					} | ||||||
|  | 				}(out, elem) | ||||||
|  | 			} else { | ||||||
|  | 				out.Set(elem) | ||||||
|  | 			} | ||||||
|  | 			out = elem | ||||||
|  | 		} | ||||||
|  | 		outt = out.Type() | ||||||
|  | 		outk = outt.Kind() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	inv := reflect.ValueOf(in) | ||||||
|  | 	if outt == inv.Type() { | ||||||
|  | 		out.Set(inv) | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch outk { | ||||||
|  | 	case reflect.Interface: | ||||||
|  | 		out.Set(inv) | ||||||
|  | 		return true | ||||||
|  | 	case reflect.String: | ||||||
|  | 		switch inv.Kind() { | ||||||
|  | 		case reflect.String: | ||||||
|  | 			out.SetString(inv.String()) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Slice: | ||||||
|  | 			if b, ok := in.([]byte); ok { | ||||||
|  | 				out.SetString(string(b)) | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		case reflect.Int, reflect.Int64: | ||||||
|  | 			if outt == typeJSONNumber { | ||||||
|  | 				out.SetString(strconv.FormatInt(inv.Int(), 10)) | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		case reflect.Float64: | ||||||
|  | 			if outt == typeJSONNumber { | ||||||
|  | 				out.SetString(strconv.FormatFloat(inv.Float(), 'f', -1, 64)) | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		// Remember, array (0x04) slices are built with the correct | ||||||
|  | 		// element type.  If we are here, must be a cross BSON kind | ||||||
|  | 		// conversion (e.g. 0x05 unmarshalling on string). | ||||||
|  | 		if outt.Elem().Kind() != reflect.Uint8 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		switch inv.Kind() { | ||||||
|  | 		case reflect.String: | ||||||
|  | 			slice := []byte(inv.String()) | ||||||
|  | 			out.Set(reflect.ValueOf(slice)) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Slice: | ||||||
|  | 			switch outt.Kind() { | ||||||
|  | 			case reflect.Array: | ||||||
|  | 				reflect.Copy(out, inv) | ||||||
|  | 			case reflect.Slice: | ||||||
|  | 				out.SetBytes(inv.Bytes()) | ||||||
|  | 			} | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 		switch inv.Kind() { | ||||||
|  | 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 			out.SetInt(inv.Int()) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Float32, reflect.Float64: | ||||||
|  | 			out.SetInt(int64(inv.Float())) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Bool: | ||||||
|  | 			if inv.Bool() { | ||||||
|  | 				out.SetInt(1) | ||||||
|  | 			} else { | ||||||
|  | 				out.SetInt(0) | ||||||
|  | 			} | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 			panic("can't happen: no uint types in BSON (!?)") | ||||||
|  | 		} | ||||||
|  | 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 		switch inv.Kind() { | ||||||
|  | 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 			out.SetUint(uint64(inv.Int())) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Float32, reflect.Float64: | ||||||
|  | 			out.SetUint(uint64(inv.Float())) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Bool: | ||||||
|  | 			if inv.Bool() { | ||||||
|  | 				out.SetUint(1) | ||||||
|  | 			} else { | ||||||
|  | 				out.SetUint(0) | ||||||
|  | 			} | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 			panic("Can't happen. No uint types in BSON.") | ||||||
|  | 		} | ||||||
|  | 	case reflect.Float32, reflect.Float64: | ||||||
|  | 		switch inv.Kind() { | ||||||
|  | 		case reflect.Float32, reflect.Float64: | ||||||
|  | 			out.SetFloat(inv.Float()) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 			out.SetFloat(float64(inv.Int())) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Bool: | ||||||
|  | 			if inv.Bool() { | ||||||
|  | 				out.SetFloat(1) | ||||||
|  | 			} else { | ||||||
|  | 				out.SetFloat(0) | ||||||
|  | 			} | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 			panic("Can't happen. No uint types in BSON?") | ||||||
|  | 		} | ||||||
|  | 	case reflect.Bool: | ||||||
|  | 		switch inv.Kind() { | ||||||
|  | 		case reflect.Bool: | ||||||
|  | 			out.SetBool(inv.Bool()) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 			out.SetBool(inv.Int() != 0) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Float32, reflect.Float64: | ||||||
|  | 			out.SetBool(inv.Float() != 0) | ||||||
|  | 			return true | ||||||
|  | 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 			panic("Can't happen. No uint types in BSON?") | ||||||
|  | 		} | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		if outt == typeURL && inv.Kind() == reflect.String { | ||||||
|  | 			u, err := url.Parse(inv.String()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				panic(err) | ||||||
|  | 			} | ||||||
|  | 			out.Set(reflect.ValueOf(u).Elem()) | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 		if outt == typeBinary { | ||||||
|  | 			if b, ok := in.([]byte); ok { | ||||||
|  | 				out.Set(reflect.ValueOf(Binary{Data: b})) | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Parsers of basic types. | ||||||
|  |  | ||||||
|  | func (d *decoder) readRegEx() RegEx { | ||||||
|  | 	re := RegEx{} | ||||||
|  | 	re.Pattern = d.readCStr() | ||||||
|  | 	re.Options = d.readCStr() | ||||||
|  | 	return re | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readBinary() Binary { | ||||||
|  | 	l := d.readInt32() | ||||||
|  | 	b := Binary{} | ||||||
|  | 	b.Kind = d.readByte() | ||||||
|  | 	b.Data = d.readBytes(l) | ||||||
|  | 	if b.Kind == 0x02 && len(b.Data) >= 4 { | ||||||
|  | 		// Weird obsolete format with redundant length. | ||||||
|  | 		b.Data = b.Data[4:] | ||||||
|  | 	} | ||||||
|  | 	return b | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readStr() string { | ||||||
|  | 	l := d.readInt32() | ||||||
|  | 	b := d.readBytes(l - 1) | ||||||
|  | 	if d.readByte() != '\x00' { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	return string(b) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readCStr() string { | ||||||
|  | 	start := d.i | ||||||
|  | 	end := start | ||||||
|  | 	l := len(d.in) | ||||||
|  | 	for ; end != l; end++ { | ||||||
|  | 		if d.in[end] == '\x00' { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	d.i = end + 1 | ||||||
|  | 	if d.i > l { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	return string(d.in[start:end]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readBool() bool { | ||||||
|  | 	b := d.readByte() | ||||||
|  | 	if b == 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if b == 1 { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	panic(fmt.Sprintf("encoded boolean must be 1 or 0, found %d", b)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readFloat64() float64 { | ||||||
|  | 	return math.Float64frombits(uint64(d.readInt64())) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readInt32() int32 { | ||||||
|  | 	b := d.readBytes(4) | ||||||
|  | 	return int32((uint32(b[0]) << 0) | | ||||||
|  | 		(uint32(b[1]) << 8) | | ||||||
|  | 		(uint32(b[2]) << 16) | | ||||||
|  | 		(uint32(b[3]) << 24)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readInt64() int64 { | ||||||
|  | 	b := d.readBytes(8) | ||||||
|  | 	return int64((uint64(b[0]) << 0) | | ||||||
|  | 		(uint64(b[1]) << 8) | | ||||||
|  | 		(uint64(b[2]) << 16) | | ||||||
|  | 		(uint64(b[3]) << 24) | | ||||||
|  | 		(uint64(b[4]) << 32) | | ||||||
|  | 		(uint64(b[5]) << 40) | | ||||||
|  | 		(uint64(b[6]) << 48) | | ||||||
|  | 		(uint64(b[7]) << 56)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readByte() byte { | ||||||
|  | 	i := d.i | ||||||
|  | 	d.i++ | ||||||
|  | 	if d.i > len(d.in) { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	return d.in[i] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *decoder) readBytes(length int32) []byte { | ||||||
|  | 	if length < 0 { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	start := d.i | ||||||
|  | 	d.i += int(length) | ||||||
|  | 	if d.i < start || d.i > len(d.in) { | ||||||
|  | 		corrupted() | ||||||
|  | 	} | ||||||
|  | 	return d.in[start : start+int(length)] | ||||||
|  | } | ||||||
							
								
								
									
										514
									
								
								plugSrc/mongodb/build/bson/encode.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										514
									
								
								plugSrc/mongodb/build/bson/encode.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,514 @@ | |||||||
|  | // BSON library for Go | ||||||
|  | // | ||||||
|  | // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> | ||||||
|  | // | ||||||
|  | // All rights reserved. | ||||||
|  | // | ||||||
|  | // Redistribution and use in source and binary forms, with or without | ||||||
|  | // modification, are permitted provided that the following conditions are met: | ||||||
|  | // | ||||||
|  | // 1. Redistributions of source code must retain the above copyright notice, this | ||||||
|  | //    list of conditions and the following disclaimer. | ||||||
|  | // 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  | //    this list of conditions and the following disclaimer in the documentation | ||||||
|  | //    and/or other materials provided with the distribution. | ||||||
|  | // | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||||
|  | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||||||
|  | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||||
|  | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | // gobson - BSON library for Go. | ||||||
|  |  | ||||||
|  | package bson | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  | 	"math" | ||||||
|  | 	"net/url" | ||||||
|  | 	"reflect" | ||||||
|  | 	"strconv" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Some internal infrastructure. | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	typeBinary         = reflect.TypeOf(Binary{}) | ||||||
|  | 	typeObjectId       = reflect.TypeOf(ObjectId("")) | ||||||
|  | 	typeDBPointer      = reflect.TypeOf(DBPointer{"", ObjectId("")}) | ||||||
|  | 	typeSymbol         = reflect.TypeOf(Symbol("")) | ||||||
|  | 	typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0)) | ||||||
|  | 	typeOrderKey       = reflect.TypeOf(MinKey) | ||||||
|  | 	typeDocElem        = reflect.TypeOf(DocElem{}) | ||||||
|  | 	typeRawDocElem     = reflect.TypeOf(RawDocElem{}) | ||||||
|  | 	typeRaw            = reflect.TypeOf(Raw{}) | ||||||
|  | 	typeURL            = reflect.TypeOf(url.URL{}) | ||||||
|  | 	typeTime           = reflect.TypeOf(time.Time{}) | ||||||
|  | 	typeString         = reflect.TypeOf("") | ||||||
|  | 	typeJSONNumber     = reflect.TypeOf(json.Number("")) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const itoaCacheSize = 32 | ||||||
|  |  | ||||||
|  | var itoaCache []string | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	itoaCache = make([]string, itoaCacheSize) | ||||||
|  | 	for i := 0; i != itoaCacheSize; i++ { | ||||||
|  | 		itoaCache[i] = strconv.Itoa(i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func itoa(i int) string { | ||||||
|  | 	if i < itoaCacheSize { | ||||||
|  | 		return itoaCache[i] | ||||||
|  | 	} | ||||||
|  | 	return strconv.Itoa(i) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Marshaling of the document value itself. | ||||||
|  |  | ||||||
|  | type encoder struct { | ||||||
|  | 	out []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addDoc(v reflect.Value) { | ||||||
|  | 	for { | ||||||
|  | 		if vi, ok := v.Interface().(Getter); ok { | ||||||
|  | 			getv, err := vi.GetBSON() | ||||||
|  | 			if err != nil { | ||||||
|  | 				panic(err) | ||||||
|  | 			} | ||||||
|  | 			v = reflect.ValueOf(getv) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if v.Kind() == reflect.Ptr { | ||||||
|  | 			v = v.Elem() | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		break | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if v.Type() == typeRaw { | ||||||
|  | 		raw := v.Interface().(Raw) | ||||||
|  | 		if raw.Kind != 0x03 && raw.Kind != 0x00 { | ||||||
|  | 			panic("Attempted to marshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document") | ||||||
|  | 		} | ||||||
|  | 		if len(raw.Data) == 0 { | ||||||
|  | 			panic("Attempted to marshal empty Raw document") | ||||||
|  | 		} | ||||||
|  | 		e.addBytes(raw.Data...) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	start := e.reserveInt32() | ||||||
|  |  | ||||||
|  | 	switch v.Kind() { | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		e.addMap(v) | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		e.addStruct(v) | ||||||
|  | 	case reflect.Array, reflect.Slice: | ||||||
|  | 		e.addSlice(v) | ||||||
|  | 	default: | ||||||
|  | 		panic("Can't marshal " + v.Type().String() + " as a BSON document") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	e.addBytes(0) | ||||||
|  | 	e.setInt32(start, int32(len(e.out)-start)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addMap(v reflect.Value) { | ||||||
|  | 	for _, k := range v.MapKeys() { | ||||||
|  | 		e.addElem(k.String(), v.MapIndex(k), false) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addStruct(v reflect.Value) { | ||||||
|  | 	sinfo, err := getStructInfo(v.Type()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	var value reflect.Value | ||||||
|  | 	if sinfo.InlineMap >= 0 { | ||||||
|  | 		m := v.Field(sinfo.InlineMap) | ||||||
|  | 		if m.Len() > 0 { | ||||||
|  | 			for _, k := range m.MapKeys() { | ||||||
|  | 				ks := k.String() | ||||||
|  | 				if _, found := sinfo.FieldsMap[ks]; found { | ||||||
|  | 					panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks)) | ||||||
|  | 				} | ||||||
|  | 				e.addElem(ks, m.MapIndex(k), false) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, info := range sinfo.FieldsList { | ||||||
|  | 		if info.Inline == nil { | ||||||
|  | 			value = v.Field(info.Num) | ||||||
|  | 		} else { | ||||||
|  | 			value = v.FieldByIndex(info.Inline) | ||||||
|  | 		} | ||||||
|  | 		if info.OmitEmpty && isZero(value) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		e.addElem(info.Key, value, info.MinSize) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isZero(v reflect.Value) bool { | ||||||
|  | 	switch v.Kind() { | ||||||
|  | 	case reflect.String: | ||||||
|  | 		return len(v.String()) == 0 | ||||||
|  | 	case reflect.Ptr, reflect.Interface: | ||||||
|  | 		return v.IsNil() | ||||||
|  | 	case reflect.Slice: | ||||||
|  | 		return v.Len() == 0 | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		return v.Len() == 0 | ||||||
|  | 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 		return v.Int() == 0 | ||||||
|  | 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 		return v.Uint() == 0 | ||||||
|  | 	case reflect.Float32, reflect.Float64: | ||||||
|  | 		return v.Float() == 0 | ||||||
|  | 	case reflect.Bool: | ||||||
|  | 		return !v.Bool() | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		vt := v.Type() | ||||||
|  | 		if vt == typeTime { | ||||||
|  | 			return v.Interface().(time.Time).IsZero() | ||||||
|  | 		} | ||||||
|  | 		for i := 0; i < v.NumField(); i++ { | ||||||
|  | 			if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous { | ||||||
|  | 				continue // Private field | ||||||
|  | 			} | ||||||
|  | 			if !isZero(v.Field(i)) { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addSlice(v reflect.Value) { | ||||||
|  | 	vi := v.Interface() | ||||||
|  | 	if d, ok := vi.(D); ok { | ||||||
|  | 		for _, elem := range d { | ||||||
|  | 			e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if d, ok := vi.(RawD); ok { | ||||||
|  | 		for _, elem := range d { | ||||||
|  | 			e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	l := v.Len() | ||||||
|  | 	et := v.Type().Elem() | ||||||
|  | 	if et == typeDocElem { | ||||||
|  | 		for i := 0; i < l; i++ { | ||||||
|  | 			elem := v.Index(i).Interface().(DocElem) | ||||||
|  | 			e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if et == typeRawDocElem { | ||||||
|  | 		for i := 0; i < l; i++ { | ||||||
|  | 			elem := v.Index(i).Interface().(RawDocElem) | ||||||
|  | 			e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	for i := 0; i < l; i++ { | ||||||
|  | 		e.addElem(itoa(i), v.Index(i), false) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Marshaling of elements in a document. | ||||||
|  |  | ||||||
|  | func (e *encoder) addElemName(kind byte, name string) { | ||||||
|  | 	e.addBytes(kind) | ||||||
|  | 	e.addBytes([]byte(name)...) | ||||||
|  | 	e.addBytes(0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { | ||||||
|  |  | ||||||
|  | 	if !v.IsValid() { | ||||||
|  | 		e.addElemName(0x0A, name) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if getter, ok := v.Interface().(Getter); ok { | ||||||
|  | 		getv, err := getter.GetBSON() | ||||||
|  | 		if err != nil { | ||||||
|  | 			panic(err) | ||||||
|  | 		} | ||||||
|  | 		e.addElem(name, reflect.ValueOf(getv), minSize) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v.Kind() { | ||||||
|  |  | ||||||
|  | 	case reflect.Interface: | ||||||
|  | 		e.addElem(name, v.Elem(), minSize) | ||||||
|  |  | ||||||
|  | 	case reflect.Ptr: | ||||||
|  | 		e.addElem(name, v.Elem(), minSize) | ||||||
|  |  | ||||||
|  | 	case reflect.String: | ||||||
|  | 		s := v.String() | ||||||
|  | 		switch v.Type() { | ||||||
|  | 		case typeObjectId: | ||||||
|  | 			if len(s) != 12 { | ||||||
|  | 				panic("ObjectIDs must be exactly 12 bytes long (got " + | ||||||
|  | 					strconv.Itoa(len(s)) + ")") | ||||||
|  | 			} | ||||||
|  | 			e.addElemName(0x07, name) | ||||||
|  | 			e.addBytes([]byte(s)...) | ||||||
|  | 		case typeSymbol: | ||||||
|  | 			e.addElemName(0x0E, name) | ||||||
|  | 			e.addStr(s) | ||||||
|  | 		case typeJSONNumber: | ||||||
|  | 			n := v.Interface().(json.Number) | ||||||
|  | 			if i, err := n.Int64(); err == nil { | ||||||
|  | 				e.addElemName(0x12, name) | ||||||
|  | 				e.addInt64(i) | ||||||
|  | 			} else if f, err := n.Float64(); err == nil { | ||||||
|  | 				e.addElemName(0x01, name) | ||||||
|  | 				e.addFloat64(f) | ||||||
|  | 			} else { | ||||||
|  | 				panic("failed to convert json.Number to a number: " + s) | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			e.addElemName(0x02, name) | ||||||
|  | 			e.addStr(s) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	case reflect.Float32, reflect.Float64: | ||||||
|  | 		e.addElemName(0x01, name) | ||||||
|  | 		e.addFloat64(v.Float()) | ||||||
|  |  | ||||||
|  | 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 		u := v.Uint() | ||||||
|  | 		if int64(u) < 0 { | ||||||
|  | 			panic("BSON has no uint64 type, and value is too large to fit correctly in an int64") | ||||||
|  | 		} else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) { | ||||||
|  | 			e.addElemName(0x10, name) | ||||||
|  | 			e.addInt32(int32(u)) | ||||||
|  | 		} else { | ||||||
|  | 			e.addElemName(0x12, name) | ||||||
|  | 			e.addInt64(int64(u)) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 		switch v.Type() { | ||||||
|  | 		case typeMongoTimestamp: | ||||||
|  | 			e.addElemName(0x11, name) | ||||||
|  | 			e.addInt64(v.Int()) | ||||||
|  |  | ||||||
|  | 		case typeOrderKey: | ||||||
|  | 			if v.Int() == int64(MaxKey) { | ||||||
|  | 				e.addElemName(0x7F, name) | ||||||
|  | 			} else { | ||||||
|  | 				e.addElemName(0xFF, name) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		default: | ||||||
|  | 			i := v.Int() | ||||||
|  | 			if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 { | ||||||
|  | 				// It fits into an int32, encode as such. | ||||||
|  | 				e.addElemName(0x10, name) | ||||||
|  | 				e.addInt32(int32(i)) | ||||||
|  | 			} else { | ||||||
|  | 				e.addElemName(0x12, name) | ||||||
|  | 				e.addInt64(i) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	case reflect.Bool: | ||||||
|  | 		e.addElemName(0x08, name) | ||||||
|  | 		if v.Bool() { | ||||||
|  | 			e.addBytes(1) | ||||||
|  | 		} else { | ||||||
|  | 			e.addBytes(0) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		e.addElemName(0x03, name) | ||||||
|  | 		e.addDoc(v) | ||||||
|  |  | ||||||
|  | 	case reflect.Slice: | ||||||
|  | 		vt := v.Type() | ||||||
|  | 		et := vt.Elem() | ||||||
|  | 		if et.Kind() == reflect.Uint8 { | ||||||
|  | 			e.addElemName(0x05, name) | ||||||
|  | 			e.addBinary(0x00, v.Bytes()) | ||||||
|  | 		} else if et == typeDocElem || et == typeRawDocElem { | ||||||
|  | 			e.addElemName(0x03, name) | ||||||
|  | 			e.addDoc(v) | ||||||
|  | 		} else { | ||||||
|  | 			e.addElemName(0x04, name) | ||||||
|  | 			e.addDoc(v) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	case reflect.Array: | ||||||
|  | 		et := v.Type().Elem() | ||||||
|  | 		if et.Kind() == reflect.Uint8 { | ||||||
|  | 			e.addElemName(0x05, name) | ||||||
|  | 			if v.CanAddr() { | ||||||
|  | 				e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte)) | ||||||
|  | 			} else { | ||||||
|  | 				n := v.Len() | ||||||
|  | 				e.addInt32(int32(n)) | ||||||
|  | 				e.addBytes(0x00) | ||||||
|  | 				for i := 0; i < n; i++ { | ||||||
|  | 					el := v.Index(i) | ||||||
|  | 					e.addBytes(byte(el.Uint())) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			e.addElemName(0x04, name) | ||||||
|  | 			e.addDoc(v) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		switch s := v.Interface().(type) { | ||||||
|  |  | ||||||
|  | 		case Raw: | ||||||
|  | 			kind := s.Kind | ||||||
|  | 			if kind == 0x00 { | ||||||
|  | 				kind = 0x03 | ||||||
|  | 			} | ||||||
|  | 			if len(s.Data) == 0 && kind != 0x06 && kind != 0x0A && kind != 0xFF && kind != 0x7F { | ||||||
|  | 				panic("Attempted to marshal empty Raw document") | ||||||
|  | 			} | ||||||
|  | 			e.addElemName(kind, name) | ||||||
|  | 			e.addBytes(s.Data...) | ||||||
|  |  | ||||||
|  | 		case Binary: | ||||||
|  | 			e.addElemName(0x05, name) | ||||||
|  | 			e.addBinary(s.Kind, s.Data) | ||||||
|  |  | ||||||
|  | 		case Decimal128: | ||||||
|  | 			e.addElemName(0x13, name) | ||||||
|  | 			e.addInt64(int64(s.l)) | ||||||
|  | 			e.addInt64(int64(s.h)) | ||||||
|  |  | ||||||
|  | 		case DBPointer: | ||||||
|  | 			e.addElemName(0x0C, name) | ||||||
|  | 			e.addStr(s.Namespace) | ||||||
|  | 			if len(s.Id) != 12 { | ||||||
|  | 				panic("ObjectIDs must be exactly 12 bytes long (got " + | ||||||
|  | 					strconv.Itoa(len(s.Id)) + ")") | ||||||
|  | 			} | ||||||
|  | 			e.addBytes([]byte(s.Id)...) | ||||||
|  |  | ||||||
|  | 		case RegEx: | ||||||
|  | 			e.addElemName(0x0B, name) | ||||||
|  | 			e.addCStr(s.Pattern) | ||||||
|  | 			e.addCStr(s.Options) | ||||||
|  |  | ||||||
|  | 		case JavaScript: | ||||||
|  | 			if s.Scope == nil { | ||||||
|  | 				e.addElemName(0x0D, name) | ||||||
|  | 				e.addStr(s.Code) | ||||||
|  | 			} else { | ||||||
|  | 				e.addElemName(0x0F, name) | ||||||
|  | 				start := e.reserveInt32() | ||||||
|  | 				e.addStr(s.Code) | ||||||
|  | 				e.addDoc(reflect.ValueOf(s.Scope)) | ||||||
|  | 				e.setInt32(start, int32(len(e.out)-start)) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		case time.Time: | ||||||
|  | 			// MongoDB handles timestamps as milliseconds. | ||||||
|  | 			e.addElemName(0x09, name) | ||||||
|  | 			e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6)) | ||||||
|  |  | ||||||
|  | 		case url.URL: | ||||||
|  | 			e.addElemName(0x02, name) | ||||||
|  | 			e.addStr(s.String()) | ||||||
|  |  | ||||||
|  | 		case undefined: | ||||||
|  | 			e.addElemName(0x06, name) | ||||||
|  |  | ||||||
|  | 		default: | ||||||
|  | 			e.addElemName(0x03, name) | ||||||
|  | 			e.addDoc(v) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	default: | ||||||
|  | 		panic("Can't marshal " + v.Type().String() + " in a BSON document") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // -------------------------------------------------------------------------- | ||||||
|  | // Marshaling of base types. | ||||||
|  |  | ||||||
|  | func (e *encoder) addBinary(subtype byte, v []byte) { | ||||||
|  | 	if subtype == 0x02 { | ||||||
|  | 		// Wonder how that brilliant idea came to life. Obsolete, luckily. | ||||||
|  | 		e.addInt32(int32(len(v) + 4)) | ||||||
|  | 		e.addBytes(subtype) | ||||||
|  | 		e.addInt32(int32(len(v))) | ||||||
|  | 	} else { | ||||||
|  | 		e.addInt32(int32(len(v))) | ||||||
|  | 		e.addBytes(subtype) | ||||||
|  | 	} | ||||||
|  | 	e.addBytes(v...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addStr(v string) { | ||||||
|  | 	e.addInt32(int32(len(v) + 1)) | ||||||
|  | 	e.addCStr(v) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addCStr(v string) { | ||||||
|  | 	e.addBytes([]byte(v)...) | ||||||
|  | 	e.addBytes(0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) reserveInt32() (pos int) { | ||||||
|  | 	pos = len(e.out) | ||||||
|  | 	e.addBytes(0, 0, 0, 0) | ||||||
|  | 	return pos | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) setInt32(pos int, v int32) { | ||||||
|  | 	e.out[pos+0] = byte(v) | ||||||
|  | 	e.out[pos+1] = byte(v >> 8) | ||||||
|  | 	e.out[pos+2] = byte(v >> 16) | ||||||
|  | 	e.out[pos+3] = byte(v >> 24) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addInt32(v int32) { | ||||||
|  | 	u := uint32(v) | ||||||
|  | 	e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addInt64(v int64) { | ||||||
|  | 	u := uint64(v) | ||||||
|  | 	e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24), | ||||||
|  | 		byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addFloat64(v float64) { | ||||||
|  | 	e.addInt64(int64(math.Float64bits(v))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *encoder) addBytes(v ...byte) { | ||||||
|  | 	e.out = append(e.out, v...) | ||||||
|  | } | ||||||
							
								
								
									
										380
									
								
								plugSrc/mongodb/build/bson/json.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								plugSrc/mongodb/build/bson/json.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | |||||||
|  | package bson | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"fmt" | ||||||
|  | 	"github.com/40t/go-sniffer/plugSrc/mongodb/build/internal/json" | ||||||
|  | 	"strconv" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // UnmarshalJSON unmarshals a JSON value that may hold non-standard | ||||||
|  | // syntax as defined in BSON's extended JSON specification. | ||||||
|  | func UnmarshalJSON(data []byte, value interface{}) error { | ||||||
|  | 	d := json.NewDecoder(bytes.NewBuffer(data)) | ||||||
|  | 	d.Extend(&jsonExt) | ||||||
|  | 	return d.Decode(value) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MarshalJSON marshals a JSON value that may hold non-standard | ||||||
|  | // syntax as defined in BSON's extended JSON specification. | ||||||
|  | func MarshalJSON(value interface{}) ([]byte, error) { | ||||||
|  | 	var buf bytes.Buffer | ||||||
|  | 	e := json.NewEncoder(&buf) | ||||||
|  | 	e.Extend(&jsonExt) | ||||||
|  | 	err := e.Encode(value) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return buf.Bytes(), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // jdec is used internally by the JSON decoding functions | ||||||
|  | // so they may unmarshal functions without getting into endless | ||||||
|  | // recursion due to keyed objects. | ||||||
|  | func jdec(data []byte, value interface{}) error { | ||||||
|  | 	d := json.NewDecoder(bytes.NewBuffer(data)) | ||||||
|  | 	d.Extend(&funcExt) | ||||||
|  | 	return d.Decode(value) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var jsonExt json.Extension | ||||||
|  | var funcExt json.Extension | ||||||
|  |  | ||||||
|  | // TODO | ||||||
|  | // - Shell regular expressions ("/regexp/opts") | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	jsonExt.DecodeUnquotedKeys(true) | ||||||
|  | 	jsonExt.DecodeTrailingCommas(true) | ||||||
|  |  | ||||||
|  | 	funcExt.DecodeFunc("BinData", "$binaryFunc", "$type", "$binary") | ||||||
|  | 	jsonExt.DecodeKeyed("$binary", jdecBinary) | ||||||
|  | 	jsonExt.DecodeKeyed("$binaryFunc", jdecBinary) | ||||||
|  | 	jsonExt.EncodeType([]byte(nil), jencBinarySlice) | ||||||
|  | 	jsonExt.EncodeType(Binary{}, jencBinaryType) | ||||||
|  |  | ||||||
|  | 	funcExt.DecodeFunc("ISODate", "$dateFunc", "S") | ||||||
|  | 	funcExt.DecodeFunc("new Date", "$dateFunc", "S") | ||||||
|  | 	jsonExt.DecodeKeyed("$date", jdecDate) | ||||||
|  | 	jsonExt.DecodeKeyed("$dateFunc", jdecDate) | ||||||
|  | 	jsonExt.EncodeType(time.Time{}, jencDate) | ||||||
|  |  | ||||||
|  | 	funcExt.DecodeFunc("Timestamp", "$timestamp", "t", "i") | ||||||
|  | 	jsonExt.DecodeKeyed("$timestamp", jdecTimestamp) | ||||||
|  | 	jsonExt.EncodeType(MongoTimestamp(0), jencTimestamp) | ||||||
|  |  | ||||||
|  | 	funcExt.DecodeConst("undefined", Undefined) | ||||||
|  |  | ||||||
|  | 	jsonExt.DecodeKeyed("$regex", jdecRegEx) | ||||||
|  | 	jsonExt.EncodeType(RegEx{}, jencRegEx) | ||||||
|  |  | ||||||
|  | 	funcExt.DecodeFunc("ObjectId", "$oidFunc", "Id") | ||||||
|  | 	jsonExt.DecodeKeyed("$oid", jdecObjectId) | ||||||
|  | 	jsonExt.DecodeKeyed("$oidFunc", jdecObjectId) | ||||||
|  | 	jsonExt.EncodeType(ObjectId(""), jencObjectId) | ||||||
|  |  | ||||||
|  | 	funcExt.DecodeFunc("DBRef", "$dbrefFunc", "$ref", "$id") | ||||||
|  | 	jsonExt.DecodeKeyed("$dbrefFunc", jdecDBRef) | ||||||
|  |  | ||||||
|  | 	funcExt.DecodeFunc("NumberLong", "$numberLongFunc", "N") | ||||||
|  | 	jsonExt.DecodeKeyed("$numberLong", jdecNumberLong) | ||||||
|  | 	jsonExt.DecodeKeyed("$numberLongFunc", jdecNumberLong) | ||||||
|  | 	jsonExt.EncodeType(int64(0), jencNumberLong) | ||||||
|  | 	jsonExt.EncodeType(int(0), jencInt) | ||||||
|  |  | ||||||
|  | 	funcExt.DecodeConst("MinKey", MinKey) | ||||||
|  | 	funcExt.DecodeConst("MaxKey", MaxKey) | ||||||
|  | 	jsonExt.DecodeKeyed("$minKey", jdecMinKey) | ||||||
|  | 	jsonExt.DecodeKeyed("$maxKey", jdecMaxKey) | ||||||
|  | 	jsonExt.EncodeType(orderKey(0), jencMinMaxKey) | ||||||
|  |  | ||||||
|  | 	jsonExt.DecodeKeyed("$undefined", jdecUndefined) | ||||||
|  | 	jsonExt.EncodeType(Undefined, jencUndefined) | ||||||
|  |  | ||||||
|  | 	jsonExt.Extend(&funcExt) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func fbytes(format string, args ...interface{}) []byte { | ||||||
|  | 	var buf bytes.Buffer | ||||||
|  | 	fmt.Fprintf(&buf, format, args...) | ||||||
|  | 	return buf.Bytes() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecBinary(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		Binary []byte `json:"$binary"` | ||||||
|  | 		Type   string `json:"$type"` | ||||||
|  | 		Func   struct { | ||||||
|  | 			Binary []byte `json:"$binary"` | ||||||
|  | 			Type   int64  `json:"$type"` | ||||||
|  | 		} `json:"$binaryFunc"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var binData []byte | ||||||
|  | 	var binKind int64 | ||||||
|  | 	if v.Type == "" && v.Binary == nil { | ||||||
|  | 		binData = v.Func.Binary | ||||||
|  | 		binKind = v.Func.Type | ||||||
|  | 	} else if v.Type == "" { | ||||||
|  | 		return v.Binary, nil | ||||||
|  | 	} else { | ||||||
|  | 		binData = v.Binary | ||||||
|  | 		binKind, err = strconv.ParseInt(v.Type, 0, 64) | ||||||
|  | 		if err != nil { | ||||||
|  | 			binKind = -1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if binKind == 0 { | ||||||
|  | 		return binData, nil | ||||||
|  | 	} | ||||||
|  | 	if binKind < 0 || binKind > 255 { | ||||||
|  | 		return nil, fmt.Errorf("invalid type in binary object: %s", data) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return Binary{Kind: byte(binKind), Data: binData}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencBinarySlice(v interface{}) ([]byte, error) { | ||||||
|  | 	in := v.([]byte) | ||||||
|  | 	out := make([]byte, base64.StdEncoding.EncodedLen(len(in))) | ||||||
|  | 	base64.StdEncoding.Encode(out, in) | ||||||
|  | 	return fbytes(`{"$binary":"%s","$type":"0x0"}`, out), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencBinaryType(v interface{}) ([]byte, error) { | ||||||
|  | 	in := v.(Binary) | ||||||
|  | 	out := make([]byte, base64.StdEncoding.EncodedLen(len(in.Data))) | ||||||
|  | 	base64.StdEncoding.Encode(out, in.Data) | ||||||
|  | 	return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const jdateFormat = "2006-01-02T15:04:05.999Z" | ||||||
|  |  | ||||||
|  | func jdecDate(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		S    string `json:"$date"` | ||||||
|  | 		Func struct { | ||||||
|  | 			S string | ||||||
|  | 		} `json:"$dateFunc"` | ||||||
|  | 	} | ||||||
|  | 	_ = jdec(data, &v) | ||||||
|  | 	if v.S == "" { | ||||||
|  | 		v.S = v.Func.S | ||||||
|  | 	} | ||||||
|  | 	if v.S != "" { | ||||||
|  | 		for _, format := range []string{jdateFormat, "2006-01-02"} { | ||||||
|  | 			t, err := time.Parse(format, v.S) | ||||||
|  | 			if err == nil { | ||||||
|  | 				return t, nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return nil, fmt.Errorf("cannot parse date: %q", v.S) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var vn struct { | ||||||
|  | 		Date struct { | ||||||
|  | 			N int64 `json:"$numberLong,string"` | ||||||
|  | 		} `json:"$date"` | ||||||
|  | 		Func struct { | ||||||
|  | 			S int64 | ||||||
|  | 		} `json:"$dateFunc"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &vn) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("cannot parse date: %q", data) | ||||||
|  | 	} | ||||||
|  | 	n := vn.Date.N | ||||||
|  | 	if n == 0 { | ||||||
|  | 		n = vn.Func.S | ||||||
|  | 	} | ||||||
|  | 	return time.Unix(n/1000, n%1000*1e6).UTC(), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencDate(v interface{}) ([]byte, error) { | ||||||
|  | 	t := v.(time.Time) | ||||||
|  | 	return fbytes(`{"$date":%q}`, t.Format(jdateFormat)), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecTimestamp(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		Func struct { | ||||||
|  | 			T int32 `json:"t"` | ||||||
|  | 			I int32 `json:"i"` | ||||||
|  | 		} `json:"$timestamp"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return MongoTimestamp(uint64(v.Func.T)<<32 | uint64(uint32(v.Func.I))), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencTimestamp(v interface{}) ([]byte, error) { | ||||||
|  | 	ts := uint64(v.(MongoTimestamp)) | ||||||
|  | 	return fbytes(`{"$timestamp":{"t":%d,"i":%d}}`, ts>>32, uint32(ts)), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecRegEx(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		Regex   string `json:"$regex"` | ||||||
|  | 		Options string `json:"$options"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return RegEx{v.Regex, v.Options}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencRegEx(v interface{}) ([]byte, error) { | ||||||
|  | 	re := v.(RegEx) | ||||||
|  | 	type regex struct { | ||||||
|  | 		Regex   string `json:"$regex"` | ||||||
|  | 		Options string `json:"$options"` | ||||||
|  | 	} | ||||||
|  | 	return json.Marshal(regex{re.Pattern, re.Options}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecObjectId(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		Id   string `json:"$oid"` | ||||||
|  | 		Func struct { | ||||||
|  | 			Id string | ||||||
|  | 		} `json:"$oidFunc"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if v.Id == "" { | ||||||
|  | 		v.Id = v.Func.Id | ||||||
|  | 	} | ||||||
|  | 	return ObjectIdHex(v.Id), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencObjectId(v interface{}) ([]byte, error) { | ||||||
|  | 	return fbytes(`{"$oid":"%s"}`, v.(ObjectId).Hex()), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecDBRef(data []byte) (interface{}, error) { | ||||||
|  | 	// TODO Support unmarshaling $ref and $id into the input value. | ||||||
|  | 	var v struct { | ||||||
|  | 		Obj map[string]interface{} `json:"$dbrefFunc"` | ||||||
|  | 	} | ||||||
|  | 	// TODO Fix this. Must not be required. | ||||||
|  | 	v.Obj = make(map[string]interface{}) | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return v.Obj, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecNumberLong(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		N    int64 `json:"$numberLong,string"` | ||||||
|  | 		Func struct { | ||||||
|  | 			N int64 `json:",string"` | ||||||
|  | 		} `json:"$numberLongFunc"` | ||||||
|  | 	} | ||||||
|  | 	var vn struct { | ||||||
|  | 		N    int64 `json:"$numberLong"` | ||||||
|  | 		Func struct { | ||||||
|  | 			N int64 | ||||||
|  | 		} `json:"$numberLongFunc"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		err = jdec(data, &vn) | ||||||
|  | 		v.N = vn.N | ||||||
|  | 		v.Func.N = vn.Func.N | ||||||
|  | 	} | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if v.N != 0 { | ||||||
|  | 		return v.N, nil | ||||||
|  | 	} | ||||||
|  | 	return v.Func.N, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencNumberLong(v interface{}) ([]byte, error) { | ||||||
|  | 	n := v.(int64) | ||||||
|  | 	f := `{"$numberLong":"%d"}` | ||||||
|  | 	if n <= 1<<53 { | ||||||
|  | 		f = `{"$numberLong":%d}` | ||||||
|  | 	} | ||||||
|  | 	return fbytes(f, n), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencInt(v interface{}) ([]byte, error) { | ||||||
|  | 	n := v.(int) | ||||||
|  | 	f := `{"$numberLong":"%d"}` | ||||||
|  | 	if int64(n) <= 1<<53 { | ||||||
|  | 		f = `%d` | ||||||
|  | 	} | ||||||
|  | 	return fbytes(f, n), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecMinKey(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		N int64 `json:"$minKey"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if v.N != 1 { | ||||||
|  | 		return nil, fmt.Errorf("invalid $minKey object: %s", data) | ||||||
|  | 	} | ||||||
|  | 	return MinKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecMaxKey(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		N int64 `json:"$maxKey"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if v.N != 1 { | ||||||
|  | 		return nil, fmt.Errorf("invalid $maxKey object: %s", data) | ||||||
|  | 	} | ||||||
|  | 	return MaxKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencMinMaxKey(v interface{}) ([]byte, error) { | ||||||
|  | 	switch v.(orderKey) { | ||||||
|  | 	case MinKey: | ||||||
|  | 		return []byte(`{"$minKey":1}`), nil | ||||||
|  | 	case MaxKey: | ||||||
|  | 		return []byte(`{"$maxKey":1}`), nil | ||||||
|  | 	} | ||||||
|  | 	panic(fmt.Sprintf("invalid $minKey/$maxKey value: %d", v)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jdecUndefined(data []byte) (interface{}, error) { | ||||||
|  | 	var v struct { | ||||||
|  | 		B bool `json:"$undefined"` | ||||||
|  | 	} | ||||||
|  | 	err := jdec(data, &v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if !v.B { | ||||||
|  | 		return nil, fmt.Errorf("invalid $undefined object: %s", data) | ||||||
|  | 	} | ||||||
|  | 	return Undefined, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jencUndefined(v interface{}) ([]byte, error) { | ||||||
|  | 	return []byte(`{"$undefined":true}`), nil | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								plugSrc/mongodb/build/internal/json/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								plugSrc/mongodb/build/internal/json/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | Copyright (c) 2012 The Go Authors. All rights reserved. | ||||||
|  |  | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are | ||||||
|  | met: | ||||||
|  |  | ||||||
|  |    * Redistributions of source code must retain the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer. | ||||||
|  |    * Redistributions in binary form must reproduce the above | ||||||
|  | copyright notice, this list of conditions and the following disclaimer | ||||||
|  | in the documentation and/or other materials provided with the | ||||||
|  | distribution. | ||||||
|  |    * Neither the name of Google Inc. nor the names of its | ||||||
|  | contributors may be used to endorse or promote products derived from | ||||||
|  | this software without specific prior written permission. | ||||||
|  |  | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										1685
									
								
								plugSrc/mongodb/build/internal/json/decode.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1685
									
								
								plugSrc/mongodb/build/internal/json/decode.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1256
									
								
								plugSrc/mongodb/build/internal/json/encode.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1256
									
								
								plugSrc/mongodb/build/internal/json/encode.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										95
									
								
								plugSrc/mongodb/build/internal/json/extension.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								plugSrc/mongodb/build/internal/json/extension.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | |||||||
|  | package json | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Extension holds a set of additional rules to be used when unmarshaling | ||||||
|  | // strict JSON or JSON-like content. | ||||||
|  | type Extension struct { | ||||||
|  | 	funcs  map[string]funcExt | ||||||
|  | 	consts map[string]interface{} | ||||||
|  | 	keyed  map[string]func([]byte) (interface{}, error) | ||||||
|  | 	encode map[reflect.Type]func(v interface{}) ([]byte, error) | ||||||
|  |  | ||||||
|  | 	unquotedKeys   bool | ||||||
|  | 	trailingCommas bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type funcExt struct { | ||||||
|  | 	key  string | ||||||
|  | 	args []string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Extend changes the decoder behavior to consider the provided extension. | ||||||
|  | func (dec *Decoder) Extend(ext *Extension) { dec.d.ext = *ext } | ||||||
|  |  | ||||||
|  | // Extend changes the encoder behavior to consider the provided extension. | ||||||
|  | func (enc *Encoder) Extend(ext *Extension) { enc.ext = *ext } | ||||||
|  |  | ||||||
|  | // Extend includes in e the extensions defined in ext. | ||||||
|  | func (e *Extension) Extend(ext *Extension) { | ||||||
|  | 	for name, fext := range ext.funcs { | ||||||
|  | 		e.DecodeFunc(name, fext.key, fext.args...) | ||||||
|  | 	} | ||||||
|  | 	for name, value := range ext.consts { | ||||||
|  | 		e.DecodeConst(name, value) | ||||||
|  | 	} | ||||||
|  | 	for key, decode := range ext.keyed { | ||||||
|  | 		e.DecodeKeyed(key, decode) | ||||||
|  | 	} | ||||||
|  | 	for typ, encode := range ext.encode { | ||||||
|  | 		if e.encode == nil { | ||||||
|  | 			e.encode = make(map[reflect.Type]func(v interface{}) ([]byte, error)) | ||||||
|  | 		} | ||||||
|  | 		e.encode[typ] = encode | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DecodeFunc defines a function call that may be observed inside JSON content. | ||||||
|  | // A function with the provided name will be unmarshaled as the document | ||||||
|  | // {key: {args[0]: ..., args[N]: ...}}. | ||||||
|  | func (e *Extension) DecodeFunc(name string, key string, args ...string) { | ||||||
|  | 	if e.funcs == nil { | ||||||
|  | 		e.funcs = make(map[string]funcExt) | ||||||
|  | 	} | ||||||
|  | 	e.funcs[name] = funcExt{key, args} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DecodeConst defines a constant name that may be observed inside JSON content | ||||||
|  | // and will be decoded with the provided value. | ||||||
|  | func (e *Extension) DecodeConst(name string, value interface{}) { | ||||||
|  | 	if e.consts == nil { | ||||||
|  | 		e.consts = make(map[string]interface{}) | ||||||
|  | 	} | ||||||
|  | 	e.consts[name] = value | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DecodeKeyed defines a key that when observed as the first element inside a | ||||||
|  | // JSON document triggers the decoding of that document via the provided | ||||||
|  | // decode function. | ||||||
|  | func (e *Extension) DecodeKeyed(key string, decode func(data []byte) (interface{}, error)) { | ||||||
|  | 	if e.keyed == nil { | ||||||
|  | 		e.keyed = make(map[string]func([]byte) (interface{}, error)) | ||||||
|  | 	} | ||||||
|  | 	e.keyed[key] = decode | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DecodeUnquotedKeys defines whether to accept map keys that are unquoted strings. | ||||||
|  | func (e *Extension) DecodeUnquotedKeys(accept bool) { | ||||||
|  | 	e.unquotedKeys = accept | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DecodeTrailingCommas defines whether to accept trailing commas in maps and arrays. | ||||||
|  | func (e *Extension) DecodeTrailingCommas(accept bool) { | ||||||
|  | 	e.trailingCommas = accept | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // EncodeType registers a function to encode values with the same type of the | ||||||
|  | // provided sample. | ||||||
|  | func (e *Extension) EncodeType(sample interface{}, encode func(v interface{}) ([]byte, error)) { | ||||||
|  | 	if e.encode == nil { | ||||||
|  | 		e.encode = make(map[reflect.Type]func(v interface{}) ([]byte, error)) | ||||||
|  | 	} | ||||||
|  | 	e.encode[reflect.TypeOf(sample)] = encode | ||||||
|  | } | ||||||
							
								
								
									
										143
									
								
								plugSrc/mongodb/build/internal/json/fold.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								plugSrc/mongodb/build/internal/json/fold.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | // Copyright 2013 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package json | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"unicode/utf8" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	caseMask     = ^byte(0x20) // Mask to ignore case in ASCII. | ||||||
|  | 	kelvin       = '\u212a' | ||||||
|  | 	smallLongEss = '\u017f' | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // foldFunc returns one of four different case folding equivalence | ||||||
|  | // functions, from most general (and slow) to fastest: | ||||||
|  | // | ||||||
|  | // 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 | ||||||
|  | // 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') | ||||||
|  | // 3) asciiEqualFold, no special, but includes non-letters (including _) | ||||||
|  | // 4) simpleLetterEqualFold, no specials, no non-letters. | ||||||
|  | // | ||||||
|  | // The letters S and K are special because they map to 3 runes, not just 2: | ||||||
|  | //  * S maps to s and to U+017F 'ſ' Latin small letter long s | ||||||
|  | //  * k maps to K and to U+212A 'K' Kelvin sign | ||||||
|  | // See https://play.golang.org/p/tTxjOc0OGo | ||||||
|  | // | ||||||
|  | // The returned function is specialized for matching against s and | ||||||
|  | // should only be given s. It's not curried for performance reasons. | ||||||
|  | func foldFunc(s []byte) func(s, t []byte) bool { | ||||||
|  | 	nonLetter := false | ||||||
|  | 	special := false // special letter | ||||||
|  | 	for _, b := range s { | ||||||
|  | 		if b >= utf8.RuneSelf { | ||||||
|  | 			return bytes.EqualFold | ||||||
|  | 		} | ||||||
|  | 		upper := b & caseMask | ||||||
|  | 		if upper < 'A' || upper > 'Z' { | ||||||
|  | 			nonLetter = true | ||||||
|  | 		} else if upper == 'K' || upper == 'S' { | ||||||
|  | 			// See above for why these letters are special. | ||||||
|  | 			special = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if special { | ||||||
|  | 		return equalFoldRight | ||||||
|  | 	} | ||||||
|  | 	if nonLetter { | ||||||
|  | 		return asciiEqualFold | ||||||
|  | 	} | ||||||
|  | 	return simpleLetterEqualFold | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // equalFoldRight is a specialization of bytes.EqualFold when s is | ||||||
|  | // known to be all ASCII (including punctuation), but contains an 's', | ||||||
|  | // 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. | ||||||
|  | // See comments on foldFunc. | ||||||
|  | func equalFoldRight(s, t []byte) bool { | ||||||
|  | 	for _, sb := range s { | ||||||
|  | 		if len(t) == 0 { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		tb := t[0] | ||||||
|  | 		if tb < utf8.RuneSelf { | ||||||
|  | 			if sb != tb { | ||||||
|  | 				sbUpper := sb & caseMask | ||||||
|  | 				if 'A' <= sbUpper && sbUpper <= 'Z' { | ||||||
|  | 					if sbUpper != tb&caseMask { | ||||||
|  | 						return false | ||||||
|  | 					} | ||||||
|  | 				} else { | ||||||
|  | 					return false | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			t = t[1:] | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		// sb is ASCII and t is not. t must be either kelvin | ||||||
|  | 		// sign or long s; sb must be s, S, k, or K. | ||||||
|  | 		tr, size := utf8.DecodeRune(t) | ||||||
|  | 		switch sb { | ||||||
|  | 		case 's', 'S': | ||||||
|  | 			if tr != smallLongEss { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		case 'k', 'K': | ||||||
|  | 			if tr != kelvin { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		t = t[size:] | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  | 	if len(t) > 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // asciiEqualFold is a specialization of bytes.EqualFold for use when | ||||||
|  | // s is all ASCII (but may contain non-letters) and contains no | ||||||
|  | // special-folding letters. | ||||||
|  | // See comments on foldFunc. | ||||||
|  | func asciiEqualFold(s, t []byte) bool { | ||||||
|  | 	if len(s) != len(t) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	for i, sb := range s { | ||||||
|  | 		tb := t[i] | ||||||
|  | 		if sb == tb { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { | ||||||
|  | 			if sb&caseMask != tb&caseMask { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // simpleLetterEqualFold is a specialization of bytes.EqualFold for | ||||||
|  | // use when s is all ASCII letters (no underscores, etc) and also | ||||||
|  | // doesn't contain 'k', 'K', 's', or 'S'. | ||||||
|  | // See comments on foldFunc. | ||||||
|  | func simpleLetterEqualFold(s, t []byte) bool { | ||||||
|  | 	if len(s) != len(t) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	for i, b := range s { | ||||||
|  | 		if b&caseMask != t[i]&caseMask { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
							
								
								
									
										141
									
								
								plugSrc/mongodb/build/internal/json/indent.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								plugSrc/mongodb/build/internal/json/indent.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | // Copyright 2010 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package json | ||||||
|  |  | ||||||
|  | import "bytes" | ||||||
|  |  | ||||||
|  | // Compact appends to dst the JSON-encoded src with | ||||||
|  | // insignificant space characters elided. | ||||||
|  | func Compact(dst *bytes.Buffer, src []byte) error { | ||||||
|  | 	return compact(dst, src, false) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func compact(dst *bytes.Buffer, src []byte, escape bool) error { | ||||||
|  | 	origLen := dst.Len() | ||||||
|  | 	var scan scanner | ||||||
|  | 	scan.reset() | ||||||
|  | 	start := 0 | ||||||
|  | 	for i, c := range src { | ||||||
|  | 		if escape && (c == '<' || c == '>' || c == '&') { | ||||||
|  | 			if start < i { | ||||||
|  | 				dst.Write(src[start:i]) | ||||||
|  | 			} | ||||||
|  | 			dst.WriteString(`\u00`) | ||||||
|  | 			dst.WriteByte(hex[c>>4]) | ||||||
|  | 			dst.WriteByte(hex[c&0xF]) | ||||||
|  | 			start = i + 1 | ||||||
|  | 		} | ||||||
|  | 		// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). | ||||||
|  | 		if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { | ||||||
|  | 			if start < i { | ||||||
|  | 				dst.Write(src[start:i]) | ||||||
|  | 			} | ||||||
|  | 			dst.WriteString(`\u202`) | ||||||
|  | 			dst.WriteByte(hex[src[i+2]&0xF]) | ||||||
|  | 			start = i + 3 | ||||||
|  | 		} | ||||||
|  | 		v := scan.step(&scan, c) | ||||||
|  | 		if v >= scanSkipSpace { | ||||||
|  | 			if v == scanError { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			if start < i { | ||||||
|  | 				dst.Write(src[start:i]) | ||||||
|  | 			} | ||||||
|  | 			start = i + 1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if scan.eof() == scanError { | ||||||
|  | 		dst.Truncate(origLen) | ||||||
|  | 		return scan.err | ||||||
|  | 	} | ||||||
|  | 	if start < len(src) { | ||||||
|  | 		dst.Write(src[start:]) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newline(dst *bytes.Buffer, prefix, indent string, depth int) { | ||||||
|  | 	dst.WriteByte('\n') | ||||||
|  | 	dst.WriteString(prefix) | ||||||
|  | 	for i := 0; i < depth; i++ { | ||||||
|  | 		dst.WriteString(indent) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Indent appends to dst an indented form of the JSON-encoded src. | ||||||
|  | // Each element in a JSON object or array begins on a new, | ||||||
|  | // indented line beginning with prefix followed by one or more | ||||||
|  | // copies of indent according to the indentation nesting. | ||||||
|  | // The data appended to dst does not begin with the prefix nor | ||||||
|  | // any indentation, to make it easier to embed inside other formatted JSON data. | ||||||
|  | // Although leading space characters (space, tab, carriage return, newline) | ||||||
|  | // at the beginning of src are dropped, trailing space characters | ||||||
|  | // at the end of src are preserved and copied to dst. | ||||||
|  | // For example, if src has no trailing spaces, neither will dst; | ||||||
|  | // if src ends in a trailing newline, so will dst. | ||||||
|  | func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { | ||||||
|  | 	origLen := dst.Len() | ||||||
|  | 	var scan scanner | ||||||
|  | 	scan.reset() | ||||||
|  | 	needIndent := false | ||||||
|  | 	depth := 0 | ||||||
|  | 	for _, c := range src { | ||||||
|  | 		scan.bytes++ | ||||||
|  | 		v := scan.step(&scan, c) | ||||||
|  | 		if v == scanSkipSpace { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if v == scanError { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if needIndent && v != scanEndObject && v != scanEndArray { | ||||||
|  | 			needIndent = false | ||||||
|  | 			depth++ | ||||||
|  | 			newline(dst, prefix, indent, depth) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Emit semantically uninteresting bytes | ||||||
|  | 		// (in particular, punctuation in strings) unmodified. | ||||||
|  | 		if v == scanContinue { | ||||||
|  | 			dst.WriteByte(c) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Add spacing around real punctuation. | ||||||
|  | 		switch c { | ||||||
|  | 		case '{', '[': | ||||||
|  | 			// delay indent so that empty object and array are formatted as {} and []. | ||||||
|  | 			needIndent = true | ||||||
|  | 			dst.WriteByte(c) | ||||||
|  |  | ||||||
|  | 		case ',': | ||||||
|  | 			dst.WriteByte(c) | ||||||
|  | 			newline(dst, prefix, indent, depth) | ||||||
|  |  | ||||||
|  | 		case ':': | ||||||
|  | 			dst.WriteByte(c) | ||||||
|  | 			dst.WriteByte(' ') | ||||||
|  |  | ||||||
|  | 		case '}', ']': | ||||||
|  | 			if needIndent { | ||||||
|  | 				// suppress indent in empty object/array | ||||||
|  | 				needIndent = false | ||||||
|  | 			} else { | ||||||
|  | 				depth-- | ||||||
|  | 				newline(dst, prefix, indent, depth) | ||||||
|  | 			} | ||||||
|  | 			dst.WriteByte(c) | ||||||
|  |  | ||||||
|  | 		default: | ||||||
|  | 			dst.WriteByte(c) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if scan.eof() == scanError { | ||||||
|  | 		dst.Truncate(origLen) | ||||||
|  | 		return scan.err | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										697
									
								
								plugSrc/mongodb/build/internal/json/scanner.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										697
									
								
								plugSrc/mongodb/build/internal/json/scanner.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,697 @@ | |||||||
|  | // Copyright 2010 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package json | ||||||
|  |  | ||||||
|  | // JSON value parser state machine. | ||||||
|  | // Just about at the limit of what is reasonable to write by hand. | ||||||
|  | // Some parts are a bit tedious, but overall it nicely factors out the | ||||||
|  | // otherwise common code from the multiple scanning functions | ||||||
|  | // in this package (Compact, Indent, checkValid, nextValue, etc). | ||||||
|  | // | ||||||
|  | // This file starts with two simple examples using the scanner | ||||||
|  | // before diving into the scanner itself. | ||||||
|  |  | ||||||
|  | import "strconv" | ||||||
|  |  | ||||||
|  | // checkValid verifies that data is valid JSON-encoded data. | ||||||
|  | // scan is passed in for use by checkValid to avoid an allocation. | ||||||
|  | func checkValid(data []byte, scan *scanner) error { | ||||||
|  | 	scan.reset() | ||||||
|  | 	for _, c := range data { | ||||||
|  | 		scan.bytes++ | ||||||
|  | 		if scan.step(scan, c) == scanError { | ||||||
|  | 			return scan.err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if scan.eof() == scanError { | ||||||
|  | 		return scan.err | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // nextValue splits data after the next whole JSON value, | ||||||
|  | // returning that value and the bytes that follow it as separate slices. | ||||||
|  | // scan is passed in for use by nextValue to avoid an allocation. | ||||||
|  | func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) { | ||||||
|  | 	scan.reset() | ||||||
|  | 	for i, c := range data { | ||||||
|  | 		v := scan.step(scan, c) | ||||||
|  | 		if v >= scanEndObject { | ||||||
|  | 			switch v { | ||||||
|  | 			// probe the scanner with a space to determine whether we will | ||||||
|  | 			// get scanEnd on the next character. Otherwise, if the next character | ||||||
|  | 			// is not a space, scanEndTop allocates a needless error. | ||||||
|  | 			case scanEndObject, scanEndArray, scanEndParams: | ||||||
|  | 				if scan.step(scan, ' ') == scanEnd { | ||||||
|  | 					return data[:i+1], data[i+1:], nil | ||||||
|  | 				} | ||||||
|  | 			case scanError: | ||||||
|  | 				return nil, nil, scan.err | ||||||
|  | 			case scanEnd: | ||||||
|  | 				return data[:i], data[i:], nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if scan.eof() == scanError { | ||||||
|  | 		return nil, nil, scan.err | ||||||
|  | 	} | ||||||
|  | 	return data, nil, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A SyntaxError is a description of a JSON syntax error. | ||||||
|  | type SyntaxError struct { | ||||||
|  | 	msg    string // description of error | ||||||
|  | 	Offset int64  // error occurred after reading Offset bytes | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *SyntaxError) Error() string { return e.msg } | ||||||
|  |  | ||||||
|  | // A scanner is a JSON scanning state machine. | ||||||
|  | // Callers call scan.reset() and then pass bytes in one at a time | ||||||
|  | // by calling scan.step(&scan, c) for each byte. | ||||||
|  | // The return value, referred to as an opcode, tells the | ||||||
|  | // caller about significant parsing events like beginning | ||||||
|  | // and ending literals, objects, and arrays, so that the | ||||||
|  | // caller can follow along if it wishes. | ||||||
|  | // The return value scanEnd indicates that a single top-level | ||||||
|  | // JSON value has been completed, *before* the byte that | ||||||
|  | // just got passed in.  (The indication must be delayed in order | ||||||
|  | // to recognize the end of numbers: is 123 a whole value or | ||||||
|  | // the beginning of 12345e+6?). | ||||||
|  | type scanner struct { | ||||||
|  | 	// The step is a func to be called to execute the next transition. | ||||||
|  | 	// Also tried using an integer constant and a single func | ||||||
|  | 	// with a switch, but using the func directly was 10% faster | ||||||
|  | 	// on a 64-bit Mac Mini, and it's nicer to read. | ||||||
|  | 	step func(*scanner, byte) int | ||||||
|  |  | ||||||
|  | 	// Reached end of top-level value. | ||||||
|  | 	endTop bool | ||||||
|  |  | ||||||
|  | 	// Stack of what we're in the middle of - array values, object keys, object values. | ||||||
|  | 	parseState []int | ||||||
|  |  | ||||||
|  | 	// Error that happened, if any. | ||||||
|  | 	err error | ||||||
|  |  | ||||||
|  | 	// 1-byte redo (see undo method) | ||||||
|  | 	redo      bool | ||||||
|  | 	redoCode  int | ||||||
|  | 	redoState func(*scanner, byte) int | ||||||
|  |  | ||||||
|  | 	// total bytes consumed, updated by decoder.Decode | ||||||
|  | 	bytes int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // These values are returned by the state transition functions | ||||||
|  | // assigned to scanner.state and the method scanner.eof. | ||||||
|  | // They give details about the current state of the scan that | ||||||
|  | // callers might be interested to know about. | ||||||
|  | // It is okay to ignore the return value of any particular | ||||||
|  | // call to scanner.state: if one call returns scanError, | ||||||
|  | // every subsequent call will return scanError too. | ||||||
|  | const ( | ||||||
|  | 	// Continue. | ||||||
|  | 	scanContinue     = iota // uninteresting byte | ||||||
|  | 	scanBeginLiteral        // end implied by next result != scanContinue | ||||||
|  | 	scanBeginObject         // begin object | ||||||
|  | 	scanObjectKey           // just finished object key (string) | ||||||
|  | 	scanObjectValue         // just finished non-last object value | ||||||
|  | 	scanEndObject           // end object (implies scanObjectValue if possible) | ||||||
|  | 	scanBeginArray          // begin array | ||||||
|  | 	scanArrayValue          // just finished array value | ||||||
|  | 	scanEndArray            // end array (implies scanArrayValue if possible) | ||||||
|  | 	scanBeginName           // begin function call | ||||||
|  | 	scanParam               // begin function argument | ||||||
|  | 	scanEndParams           // end function call | ||||||
|  | 	scanSkipSpace           // space byte; can skip; known to be last "continue" result | ||||||
|  |  | ||||||
|  | 	// Stop. | ||||||
|  | 	scanEnd   // top-level value ended *before* this byte; known to be first "stop" result | ||||||
|  | 	scanError // hit an error, scanner.err. | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // These values are stored in the parseState stack. | ||||||
|  | // They give the current state of a composite value | ||||||
|  | // being scanned. If the parser is inside a nested value | ||||||
|  | // the parseState describes the nested state, outermost at entry 0. | ||||||
|  | const ( | ||||||
|  | 	parseObjectKey   = iota // parsing object key (before colon) | ||||||
|  | 	parseObjectValue        // parsing object value (after colon) | ||||||
|  | 	parseArrayValue         // parsing array value | ||||||
|  | 	parseName               // parsing unquoted name | ||||||
|  | 	parseParam              // parsing function argument value | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // reset prepares the scanner for use. | ||||||
|  | // It must be called before calling s.step. | ||||||
|  | func (s *scanner) reset() { | ||||||
|  | 	s.step = stateBeginValue | ||||||
|  | 	s.parseState = s.parseState[0:0] | ||||||
|  | 	s.err = nil | ||||||
|  | 	s.redo = false | ||||||
|  | 	s.endTop = false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // eof tells the scanner that the end of input has been reached. | ||||||
|  | // It returns a scan status just as s.step does. | ||||||
|  | func (s *scanner) eof() int { | ||||||
|  | 	if s.err != nil { | ||||||
|  | 		return scanError | ||||||
|  | 	} | ||||||
|  | 	if s.endTop { | ||||||
|  | 		return scanEnd | ||||||
|  | 	} | ||||||
|  | 	s.step(s, ' ') | ||||||
|  | 	if s.endTop { | ||||||
|  | 		return scanEnd | ||||||
|  | 	} | ||||||
|  | 	if s.err == nil { | ||||||
|  | 		s.err = &SyntaxError{"unexpected end of JSON input", s.bytes} | ||||||
|  | 	} | ||||||
|  | 	return scanError | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // pushParseState pushes a new parse state p onto the parse stack. | ||||||
|  | func (s *scanner) pushParseState(p int) { | ||||||
|  | 	s.parseState = append(s.parseState, p) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // popParseState pops a parse state (already obtained) off the stack | ||||||
|  | // and updates s.step accordingly. | ||||||
|  | func (s *scanner) popParseState() { | ||||||
|  | 	n := len(s.parseState) - 1 | ||||||
|  | 	s.parseState = s.parseState[0:n] | ||||||
|  | 	s.redo = false | ||||||
|  | 	if n == 0 { | ||||||
|  | 		s.step = stateEndTop | ||||||
|  | 		s.endTop = true | ||||||
|  | 	} else { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isSpace(c byte) bool { | ||||||
|  | 	return c == ' ' || c == '\t' || c == '\r' || c == '\n' | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateBeginValueOrEmpty is the state after reading `[`. | ||||||
|  | func stateBeginValueOrEmpty(s *scanner, c byte) int { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	if c == ']' { | ||||||
|  | 		return stateEndValue(s, c) | ||||||
|  | 	} | ||||||
|  | 	return stateBeginValue(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateBeginValue is the state at the beginning of the input. | ||||||
|  | func stateBeginValue(s *scanner, c byte) int { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	switch c { | ||||||
|  | 	case '{': | ||||||
|  | 		s.step = stateBeginStringOrEmpty | ||||||
|  | 		s.pushParseState(parseObjectKey) | ||||||
|  | 		return scanBeginObject | ||||||
|  | 	case '[': | ||||||
|  | 		s.step = stateBeginValueOrEmpty | ||||||
|  | 		s.pushParseState(parseArrayValue) | ||||||
|  | 		return scanBeginArray | ||||||
|  | 	case '"': | ||||||
|  | 		s.step = stateInString | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	case '-': | ||||||
|  | 		s.step = stateNeg | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	case '0': // beginning of 0.123 | ||||||
|  | 		s.step = state0 | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	case 'n': | ||||||
|  | 		s.step = stateNew0 | ||||||
|  | 		return scanBeginName | ||||||
|  | 	} | ||||||
|  | 	if '1' <= c && c <= '9' { // beginning of 1234.5 | ||||||
|  | 		s.step = state1 | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	} | ||||||
|  | 	if isName(c) { | ||||||
|  | 		s.step = stateName | ||||||
|  | 		return scanBeginName | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "looking for beginning of value") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isName(c byte) bool { | ||||||
|  | 	return c == '$' || c == '_' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateBeginStringOrEmpty is the state after reading `{`. | ||||||
|  | func stateBeginStringOrEmpty(s *scanner, c byte) int { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	if c == '}' { | ||||||
|  | 		n := len(s.parseState) | ||||||
|  | 		s.parseState[n-1] = parseObjectValue | ||||||
|  | 		return stateEndValue(s, c) | ||||||
|  | 	} | ||||||
|  | 	return stateBeginString(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateBeginString is the state after reading `{"key": value,`. | ||||||
|  | func stateBeginString(s *scanner, c byte) int { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	if c == '"' { | ||||||
|  | 		s.step = stateInString | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	} | ||||||
|  | 	if isName(c) { | ||||||
|  | 		s.step = stateName | ||||||
|  | 		return scanBeginName | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "looking for beginning of object key string") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateEndValue is the state after completing a value, | ||||||
|  | // such as after reading `{}` or `true` or `["x"`. | ||||||
|  | func stateEndValue(s *scanner, c byte) int { | ||||||
|  | 	n := len(s.parseState) | ||||||
|  | 	if n == 0 { | ||||||
|  | 		// Completed top-level before the current byte. | ||||||
|  | 		s.step = stateEndTop | ||||||
|  | 		s.endTop = true | ||||||
|  | 		return stateEndTop(s, c) | ||||||
|  | 	} | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	ps := s.parseState[n-1] | ||||||
|  | 	switch ps { | ||||||
|  | 	case parseObjectKey: | ||||||
|  | 		if c == ':' { | ||||||
|  | 			s.parseState[n-1] = parseObjectValue | ||||||
|  | 			s.step = stateBeginValue | ||||||
|  | 			return scanObjectKey | ||||||
|  | 		} | ||||||
|  | 		return s.error(c, "after object key") | ||||||
|  | 	case parseObjectValue: | ||||||
|  | 		if c == ',' { | ||||||
|  | 			s.parseState[n-1] = parseObjectKey | ||||||
|  | 			s.step = stateBeginStringOrEmpty | ||||||
|  | 			return scanObjectValue | ||||||
|  | 		} | ||||||
|  | 		if c == '}' { | ||||||
|  | 			s.popParseState() | ||||||
|  | 			return scanEndObject | ||||||
|  | 		} | ||||||
|  | 		return s.error(c, "after object key:value pair") | ||||||
|  | 	case parseArrayValue: | ||||||
|  | 		if c == ',' { | ||||||
|  | 			s.step = stateBeginValueOrEmpty | ||||||
|  | 			return scanArrayValue | ||||||
|  | 		} | ||||||
|  | 		if c == ']' { | ||||||
|  | 			s.popParseState() | ||||||
|  | 			return scanEndArray | ||||||
|  | 		} | ||||||
|  | 		return s.error(c, "after array element") | ||||||
|  | 	case parseParam: | ||||||
|  | 		if c == ',' { | ||||||
|  | 			s.step = stateBeginValue | ||||||
|  | 			return scanParam | ||||||
|  | 		} | ||||||
|  | 		if c == ')' { | ||||||
|  | 			s.popParseState() | ||||||
|  | 			return scanEndParams | ||||||
|  | 		} | ||||||
|  | 		return s.error(c, "after array element") | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateEndTop is the state after finishing the top-level value, | ||||||
|  | // such as after reading `{}` or `[1,2,3]`. | ||||||
|  | // Only space characters should be seen now. | ||||||
|  | func stateEndTop(s *scanner, c byte) int { | ||||||
|  | 	if c != ' ' && c != '\t' && c != '\r' && c != '\n' { | ||||||
|  | 		// Complain about non-space byte on next call. | ||||||
|  | 		s.error(c, "after top-level value") | ||||||
|  | 	} | ||||||
|  | 	return scanEnd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateInString is the state after reading `"`. | ||||||
|  | func stateInString(s *scanner, c byte) int { | ||||||
|  | 	if c == '"' { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c == '\\' { | ||||||
|  | 		s.step = stateInStringEsc | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c < 0x20 { | ||||||
|  | 		return s.error(c, "in string literal") | ||||||
|  | 	} | ||||||
|  | 	return scanContinue | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateInStringEsc is the state after reading `"\` during a quoted string. | ||||||
|  | func stateInStringEsc(s *scanner, c byte) int { | ||||||
|  | 	switch c { | ||||||
|  | 	case 'b', 'f', 'n', 'r', 't', '\\', '/', '"': | ||||||
|  | 		s.step = stateInString | ||||||
|  | 		return scanContinue | ||||||
|  | 	case 'u': | ||||||
|  | 		s.step = stateInStringEscU | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in string escape code") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateInStringEscU is the state after reading `"\u` during a quoted string. | ||||||
|  | func stateInStringEscU(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | ||||||
|  | 		s.step = stateInStringEscU1 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	// numbers | ||||||
|  | 	return s.error(c, "in \\u hexadecimal character escape") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateInStringEscU1 is the state after reading `"\u1` during a quoted string. | ||||||
|  | func stateInStringEscU1(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | ||||||
|  | 		s.step = stateInStringEscU12 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	// numbers | ||||||
|  | 	return s.error(c, "in \\u hexadecimal character escape") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateInStringEscU12 is the state after reading `"\u12` during a quoted string. | ||||||
|  | func stateInStringEscU12(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | ||||||
|  | 		s.step = stateInStringEscU123 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	// numbers | ||||||
|  | 	return s.error(c, "in \\u hexadecimal character escape") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateInStringEscU123 is the state after reading `"\u123` during a quoted string. | ||||||
|  | func stateInStringEscU123(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | ||||||
|  | 		s.step = stateInString | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	// numbers | ||||||
|  | 	return s.error(c, "in \\u hexadecimal character escape") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateNeg is the state after reading `-` during a number. | ||||||
|  | func stateNeg(s *scanner, c byte) int { | ||||||
|  | 	if c == '0' { | ||||||
|  | 		s.step = state0 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if '1' <= c && c <= '9' { | ||||||
|  | 		s.step = state1 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in numeric literal") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // state1 is the state after reading a non-zero integer during a number, | ||||||
|  | // such as after reading `1` or `100` but not `0`. | ||||||
|  | func state1(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		s.step = state1 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return state0(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // state0 is the state after reading `0` during a number. | ||||||
|  | func state0(s *scanner, c byte) int { | ||||||
|  | 	if c == '.' { | ||||||
|  | 		s.step = stateDot | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c == 'e' || c == 'E' { | ||||||
|  | 		s.step = stateE | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateEndValue(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateDot is the state after reading the integer and decimal point in a number, | ||||||
|  | // such as after reading `1.`. | ||||||
|  | func stateDot(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		s.step = stateDot0 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "after decimal point in numeric literal") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateDot0 is the state after reading the integer, decimal point, and subsequent | ||||||
|  | // digits of a number, such as after reading `3.14`. | ||||||
|  | func stateDot0(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c == 'e' || c == 'E' { | ||||||
|  | 		s.step = stateE | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateEndValue(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateE is the state after reading the mantissa and e in a number, | ||||||
|  | // such as after reading `314e` or `0.314e`. | ||||||
|  | func stateE(s *scanner, c byte) int { | ||||||
|  | 	if c == '+' || c == '-' { | ||||||
|  | 		s.step = stateESign | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateESign(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateESign is the state after reading the mantissa, e, and sign in a number, | ||||||
|  | // such as after reading `314e-` or `0.314e+`. | ||||||
|  | func stateESign(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		s.step = stateE0 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in exponent of numeric literal") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateE0 is the state after reading the mantissa, e, optional sign, | ||||||
|  | // and at least one digit of the exponent in a number, | ||||||
|  | // such as after reading `314e-2` or `0.314e+1` or `3.14e0`. | ||||||
|  | func stateE0(s *scanner, c byte) int { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateEndValue(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateNew0 is the state after reading `n`. | ||||||
|  | func stateNew0(s *scanner, c byte) int { | ||||||
|  | 	if c == 'e' { | ||||||
|  | 		s.step = stateNew1 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	s.step = stateName | ||||||
|  | 	return stateName(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateNew1 is the state after reading `ne`. | ||||||
|  | func stateNew1(s *scanner, c byte) int { | ||||||
|  | 	if c == 'w' { | ||||||
|  | 		s.step = stateNew2 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	s.step = stateName | ||||||
|  | 	return stateName(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateNew2 is the state after reading `new`. | ||||||
|  | func stateNew2(s *scanner, c byte) int { | ||||||
|  | 	s.step = stateName | ||||||
|  | 	if c == ' ' { | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateName(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateName is the state while reading an unquoted function name. | ||||||
|  | func stateName(s *scanner, c byte) int { | ||||||
|  | 	if isName(c) { | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c == '(' { | ||||||
|  | 		s.step = stateParamOrEmpty | ||||||
|  | 		s.pushParseState(parseParam) | ||||||
|  | 		return scanParam | ||||||
|  | 	} | ||||||
|  | 	return stateEndValue(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateParamOrEmpty is the state after reading `(`. | ||||||
|  | func stateParamOrEmpty(s *scanner, c byte) int { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	if c == ')' { | ||||||
|  | 		return stateEndValue(s, c) | ||||||
|  | 	} | ||||||
|  | 	return stateBeginValue(s, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateT is the state after reading `t`. | ||||||
|  | func stateT(s *scanner, c byte) int { | ||||||
|  | 	if c == 'r' { | ||||||
|  | 		s.step = stateTr | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal true (expecting 'r')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateTr is the state after reading `tr`. | ||||||
|  | func stateTr(s *scanner, c byte) int { | ||||||
|  | 	if c == 'u' { | ||||||
|  | 		s.step = stateTru | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal true (expecting 'u')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateTru is the state after reading `tru`. | ||||||
|  | func stateTru(s *scanner, c byte) int { | ||||||
|  | 	if c == 'e' { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal true (expecting 'e')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateF is the state after reading `f`. | ||||||
|  | func stateF(s *scanner, c byte) int { | ||||||
|  | 	if c == 'a' { | ||||||
|  | 		s.step = stateFa | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal false (expecting 'a')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateFa is the state after reading `fa`. | ||||||
|  | func stateFa(s *scanner, c byte) int { | ||||||
|  | 	if c == 'l' { | ||||||
|  | 		s.step = stateFal | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal false (expecting 'l')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateFal is the state after reading `fal`. | ||||||
|  | func stateFal(s *scanner, c byte) int { | ||||||
|  | 	if c == 's' { | ||||||
|  | 		s.step = stateFals | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal false (expecting 's')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateFals is the state after reading `fals`. | ||||||
|  | func stateFals(s *scanner, c byte) int { | ||||||
|  | 	if c == 'e' { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal false (expecting 'e')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateN is the state after reading `n`. | ||||||
|  | func stateN(s *scanner, c byte) int { | ||||||
|  | 	if c == 'u' { | ||||||
|  | 		s.step = stateNu | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal null (expecting 'u')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateNu is the state after reading `nu`. | ||||||
|  | func stateNu(s *scanner, c byte) int { | ||||||
|  | 	if c == 'l' { | ||||||
|  | 		s.step = stateNul | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal null (expecting 'l')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateNul is the state after reading `nul`. | ||||||
|  | func stateNul(s *scanner, c byte) int { | ||||||
|  | 	if c == 'l' { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal null (expecting 'l')") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateError is the state after reaching a syntax error, | ||||||
|  | // such as after reading `[1}` or `5.1.2`. | ||||||
|  | func stateError(s *scanner, c byte) int { | ||||||
|  | 	return scanError | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // error records an error and switches to the error state. | ||||||
|  | func (s *scanner) error(c byte, context string) int { | ||||||
|  | 	s.step = stateError | ||||||
|  | 	s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes} | ||||||
|  | 	return scanError | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // quoteChar formats c as a quoted character literal | ||||||
|  | func quoteChar(c byte) string { | ||||||
|  | 	// special cases - different from quoted strings | ||||||
|  | 	if c == '\'' { | ||||||
|  | 		return `'\''` | ||||||
|  | 	} | ||||||
|  | 	if c == '"' { | ||||||
|  | 		return `'"'` | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// use quoted string with different quotation marks | ||||||
|  | 	s := strconv.Quote(string(c)) | ||||||
|  | 	return "'" + s[1:len(s)-1] + "'" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // undo causes the scanner to return scanCode from the next state transition. | ||||||
|  | // This gives callers a simple 1-byte undo mechanism. | ||||||
|  | func (s *scanner) undo(scanCode int) { | ||||||
|  | 	if s.redo { | ||||||
|  | 		panic("json: invalid use of scanner") | ||||||
|  | 	} | ||||||
|  | 	s.redoCode = scanCode | ||||||
|  | 	s.redoState = s.step | ||||||
|  | 	s.step = stateRedo | ||||||
|  | 	s.redo = true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stateRedo helps implement the scanner's 1-byte undo. | ||||||
|  | func stateRedo(s *scanner, c byte) int { | ||||||
|  | 	s.redo = false | ||||||
|  | 	s.step = s.redoState | ||||||
|  | 	return s.redoCode | ||||||
|  | } | ||||||
							
								
								
									
										510
									
								
								plugSrc/mongodb/build/internal/json/stream.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								plugSrc/mongodb/build/internal/json/stream.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,510 @@ | |||||||
|  | // Copyright 2010 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package json | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // A Decoder reads and decodes JSON values from an input stream. | ||||||
|  | type Decoder struct { | ||||||
|  | 	r     io.Reader | ||||||
|  | 	buf   []byte | ||||||
|  | 	d     decodeState | ||||||
|  | 	scanp int // start of unread data in buf | ||||||
|  | 	scan  scanner | ||||||
|  | 	err   error | ||||||
|  |  | ||||||
|  | 	tokenState int | ||||||
|  | 	tokenStack []int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewDecoder returns a new decoder that reads from r. | ||||||
|  | // | ||||||
|  | // The decoder introduces its own buffering and may | ||||||
|  | // read data from r beyond the JSON values requested. | ||||||
|  | func NewDecoder(r io.Reader) *Decoder { | ||||||
|  | 	return &Decoder{r: r} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UseNumber causes the Decoder to unmarshal a number into an interface{} as a | ||||||
|  | // Number instead of as a float64. | ||||||
|  | func (dec *Decoder) UseNumber() { dec.d.useNumber = true } | ||||||
|  |  | ||||||
|  | // Decode reads the next JSON-encoded value from its | ||||||
|  | // input and stores it in the value pointed to by v. | ||||||
|  | // | ||||||
|  | // See the documentation for Unmarshal for details about | ||||||
|  | // the conversion of JSON into a Go value. | ||||||
|  | func (dec *Decoder) Decode(v interface{}) error { | ||||||
|  | 	if dec.err != nil { | ||||||
|  | 		return dec.err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := dec.tokenPrepareForDecode(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !dec.tokenValueAllowed() { | ||||||
|  | 		return &SyntaxError{msg: "not at beginning of value"} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Read whole value into buffer. | ||||||
|  | 	n, err := dec.readValue() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	dec.d.init(dec.buf[dec.scanp : dec.scanp+n]) | ||||||
|  | 	dec.scanp += n | ||||||
|  |  | ||||||
|  | 	// Don't save err from unmarshal into dec.err: | ||||||
|  | 	// the connection is still usable since we read a complete JSON | ||||||
|  | 	// object from it before the error happened. | ||||||
|  | 	err = dec.d.unmarshal(v) | ||||||
|  |  | ||||||
|  | 	// fixup token streaming state | ||||||
|  | 	dec.tokenValueEnd() | ||||||
|  |  | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Buffered returns a reader of the data remaining in the Decoder's | ||||||
|  | // buffer. The reader is valid until the next call to Decode. | ||||||
|  | func (dec *Decoder) Buffered() io.Reader { | ||||||
|  | 	return bytes.NewReader(dec.buf[dec.scanp:]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // readValue reads a JSON value into dec.buf. | ||||||
|  | // It returns the length of the encoding. | ||||||
|  | func (dec *Decoder) readValue() (int, error) { | ||||||
|  | 	dec.scan.reset() | ||||||
|  |  | ||||||
|  | 	scanp := dec.scanp | ||||||
|  | 	var err error | ||||||
|  | Input: | ||||||
|  | 	for { | ||||||
|  | 		// Look in the buffer for a new value. | ||||||
|  | 		for i, c := range dec.buf[scanp:] { | ||||||
|  | 			dec.scan.bytes++ | ||||||
|  | 			v := dec.scan.step(&dec.scan, c) | ||||||
|  | 			if v == scanEnd { | ||||||
|  | 				scanp += i | ||||||
|  | 				break Input | ||||||
|  | 			} | ||||||
|  | 			// scanEnd is delayed one byte. | ||||||
|  | 			// We might block trying to get that byte from src, | ||||||
|  | 			// so instead invent a space byte. | ||||||
|  | 			if (v == scanEndObject || v == scanEndArray) && dec.scan.step(&dec.scan, ' ') == scanEnd { | ||||||
|  | 				scanp += i + 1 | ||||||
|  | 				break Input | ||||||
|  | 			} | ||||||
|  | 			if v == scanError { | ||||||
|  | 				dec.err = dec.scan.err | ||||||
|  | 				return 0, dec.scan.err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		scanp = len(dec.buf) | ||||||
|  |  | ||||||
|  | 		// Did the last read have an error? | ||||||
|  | 		// Delayed until now to allow buffer scan. | ||||||
|  | 		if err != nil { | ||||||
|  | 			if err == io.EOF { | ||||||
|  | 				if dec.scan.step(&dec.scan, ' ') == scanEnd { | ||||||
|  | 					break Input | ||||||
|  | 				} | ||||||
|  | 				if nonSpace(dec.buf) { | ||||||
|  | 					err = io.ErrUnexpectedEOF | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			dec.err = err | ||||||
|  | 			return 0, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		n := scanp - dec.scanp | ||||||
|  | 		err = dec.refill() | ||||||
|  | 		scanp = dec.scanp + n | ||||||
|  | 	} | ||||||
|  | 	return scanp - dec.scanp, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (dec *Decoder) refill() error { | ||||||
|  | 	// Make room to read more into the buffer. | ||||||
|  | 	// First slide down data already consumed. | ||||||
|  | 	if dec.scanp > 0 { | ||||||
|  | 		n := copy(dec.buf, dec.buf[dec.scanp:]) | ||||||
|  | 		dec.buf = dec.buf[:n] | ||||||
|  | 		dec.scanp = 0 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Grow buffer if not large enough. | ||||||
|  | 	const minRead = 512 | ||||||
|  | 	if cap(dec.buf)-len(dec.buf) < minRead { | ||||||
|  | 		newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead) | ||||||
|  | 		copy(newBuf, dec.buf) | ||||||
|  | 		dec.buf = newBuf | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Read. Delay error for next iteration (after scan). | ||||||
|  | 	n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)]) | ||||||
|  | 	dec.buf = dec.buf[0 : len(dec.buf)+n] | ||||||
|  |  | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func nonSpace(b []byte) bool { | ||||||
|  | 	for _, c := range b { | ||||||
|  | 		if !isSpace(c) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // An Encoder writes JSON values to an output stream. | ||||||
|  | type Encoder struct { | ||||||
|  | 	w          io.Writer | ||||||
|  | 	err        error | ||||||
|  | 	escapeHTML bool | ||||||
|  |  | ||||||
|  | 	indentBuf    *bytes.Buffer | ||||||
|  | 	indentPrefix string | ||||||
|  | 	indentValue  string | ||||||
|  |  | ||||||
|  | 	ext Extension | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewEncoder returns a new encoder that writes to w. | ||||||
|  | func NewEncoder(w io.Writer) *Encoder { | ||||||
|  | 	return &Encoder{w: w, escapeHTML: true} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Encode writes the JSON encoding of v to the stream, | ||||||
|  | // followed by a newline character. | ||||||
|  | // | ||||||
|  | // See the documentation for Marshal for details about the | ||||||
|  | // conversion of Go values to JSON. | ||||||
|  | func (enc *Encoder) Encode(v interface{}) error { | ||||||
|  | 	if enc.err != nil { | ||||||
|  | 		return enc.err | ||||||
|  | 	} | ||||||
|  | 	e := newEncodeState() | ||||||
|  | 	e.ext = enc.ext | ||||||
|  | 	err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Terminate each value with a newline. | ||||||
|  | 	// This makes the output look a little nicer | ||||||
|  | 	// when debugging, and some kind of space | ||||||
|  | 	// is required if the encoded value was a number, | ||||||
|  | 	// so that the reader knows there aren't more | ||||||
|  | 	// digits coming. | ||||||
|  | 	e.WriteByte('\n') | ||||||
|  |  | ||||||
|  | 	b := e.Bytes() | ||||||
|  | 	if enc.indentBuf != nil { | ||||||
|  | 		enc.indentBuf.Reset() | ||||||
|  | 		err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		b = enc.indentBuf.Bytes() | ||||||
|  | 	} | ||||||
|  | 	if _, err = enc.w.Write(b); err != nil { | ||||||
|  | 		enc.err = err | ||||||
|  | 	} | ||||||
|  | 	encodeStatePool.Put(e) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Indent sets the encoder to format each encoded value with Indent. | ||||||
|  | func (enc *Encoder) Indent(prefix, indent string) { | ||||||
|  | 	enc.indentBuf = new(bytes.Buffer) | ||||||
|  | 	enc.indentPrefix = prefix | ||||||
|  | 	enc.indentValue = indent | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DisableHTMLEscaping causes the encoder not to escape angle brackets | ||||||
|  | // ("<" and ">") or ampersands ("&") in JSON strings. | ||||||
|  | func (enc *Encoder) DisableHTMLEscaping() { | ||||||
|  | 	enc.escapeHTML = false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RawMessage is a raw encoded JSON value. | ||||||
|  | // It implements Marshaler and Unmarshaler and can | ||||||
|  | // be used to delay JSON decoding or precompute a JSON encoding. | ||||||
|  | type RawMessage []byte | ||||||
|  |  | ||||||
|  | // MarshalJSON returns *m as the JSON encoding of m. | ||||||
|  | func (m *RawMessage) MarshalJSON() ([]byte, error) { | ||||||
|  | 	return *m, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UnmarshalJSON sets *m to a copy of data. | ||||||
|  | func (m *RawMessage) UnmarshalJSON(data []byte) error { | ||||||
|  | 	if m == nil { | ||||||
|  | 		return errors.New("json.RawMessage: UnmarshalJSON on nil pointer") | ||||||
|  | 	} | ||||||
|  | 	*m = append((*m)[0:0], data...) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var _ Marshaler = (*RawMessage)(nil) | ||||||
|  | var _ Unmarshaler = (*RawMessage)(nil) | ||||||
|  |  | ||||||
|  | // A Token holds a value of one of these types: | ||||||
|  | // | ||||||
|  | //	Delim, for the four JSON delimiters [ ] { } | ||||||
|  | //	bool, for JSON booleans | ||||||
|  | //	float64, for JSON numbers | ||||||
|  | //	Number, for JSON numbers | ||||||
|  | //	string, for JSON string literals | ||||||
|  | //	nil, for JSON null | ||||||
|  | // | ||||||
|  | type Token interface{} | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	tokenTopValue = iota | ||||||
|  | 	tokenArrayStart | ||||||
|  | 	tokenArrayValue | ||||||
|  | 	tokenArrayComma | ||||||
|  | 	tokenObjectStart | ||||||
|  | 	tokenObjectKey | ||||||
|  | 	tokenObjectColon | ||||||
|  | 	tokenObjectValue | ||||||
|  | 	tokenObjectComma | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // advance tokenstate from a separator state to a value state | ||||||
|  | func (dec *Decoder) tokenPrepareForDecode() error { | ||||||
|  | 	// Note: Not calling peek before switch, to avoid | ||||||
|  | 	// putting peek into the standard Decode path. | ||||||
|  | 	// peek is only called when using the Token API. | ||||||
|  | 	switch dec.tokenState { | ||||||
|  | 	case tokenArrayComma: | ||||||
|  | 		c, err := dec.peek() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if c != ',' { | ||||||
|  | 			return &SyntaxError{"expected comma after array element", 0} | ||||||
|  | 		} | ||||||
|  | 		dec.scanp++ | ||||||
|  | 		dec.tokenState = tokenArrayValue | ||||||
|  | 	case tokenObjectColon: | ||||||
|  | 		c, err := dec.peek() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if c != ':' { | ||||||
|  | 			return &SyntaxError{"expected colon after object key", 0} | ||||||
|  | 		} | ||||||
|  | 		dec.scanp++ | ||||||
|  | 		dec.tokenState = tokenObjectValue | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (dec *Decoder) tokenValueAllowed() bool { | ||||||
|  | 	switch dec.tokenState { | ||||||
|  | 	case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue: | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (dec *Decoder) tokenValueEnd() { | ||||||
|  | 	switch dec.tokenState { | ||||||
|  | 	case tokenArrayStart, tokenArrayValue: | ||||||
|  | 		dec.tokenState = tokenArrayComma | ||||||
|  | 	case tokenObjectValue: | ||||||
|  | 		dec.tokenState = tokenObjectComma | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A Delim is a JSON array or object delimiter, one of [ ] { or }. | ||||||
|  | type Delim rune | ||||||
|  |  | ||||||
|  | func (d Delim) String() string { | ||||||
|  | 	return string(d) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Token returns the next JSON token in the input stream. | ||||||
|  | // At the end of the input stream, Token returns nil, io.EOF. | ||||||
|  | // | ||||||
|  | // Token guarantees that the delimiters [ ] { } it returns are | ||||||
|  | // properly nested and matched: if Token encounters an unexpected | ||||||
|  | // delimiter in the input, it will return an error. | ||||||
|  | // | ||||||
|  | // The input stream consists of basic JSON values—bool, string, | ||||||
|  | // number, and null—along with delimiters [ ] { } of type Delim | ||||||
|  | // to mark the start and end of arrays and objects. | ||||||
|  | // Commas and colons are elided. | ||||||
|  | func (dec *Decoder) Token() (Token, error) { | ||||||
|  | 	for { | ||||||
|  | 		c, err := dec.peek() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		switch c { | ||||||
|  | 		case '[': | ||||||
|  | 			if !dec.tokenValueAllowed() { | ||||||
|  | 				return dec.tokenError(c) | ||||||
|  | 			} | ||||||
|  | 			dec.scanp++ | ||||||
|  | 			dec.tokenStack = append(dec.tokenStack, dec.tokenState) | ||||||
|  | 			dec.tokenState = tokenArrayStart | ||||||
|  | 			return Delim('['), nil | ||||||
|  |  | ||||||
|  | 		case ']': | ||||||
|  | 			if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma { | ||||||
|  | 				return dec.tokenError(c) | ||||||
|  | 			} | ||||||
|  | 			dec.scanp++ | ||||||
|  | 			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] | ||||||
|  | 			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] | ||||||
|  | 			dec.tokenValueEnd() | ||||||
|  | 			return Delim(']'), nil | ||||||
|  |  | ||||||
|  | 		case '{': | ||||||
|  | 			if !dec.tokenValueAllowed() { | ||||||
|  | 				return dec.tokenError(c) | ||||||
|  | 			} | ||||||
|  | 			dec.scanp++ | ||||||
|  | 			dec.tokenStack = append(dec.tokenStack, dec.tokenState) | ||||||
|  | 			dec.tokenState = tokenObjectStart | ||||||
|  | 			return Delim('{'), nil | ||||||
|  |  | ||||||
|  | 		case '}': | ||||||
|  | 			if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma { | ||||||
|  | 				return dec.tokenError(c) | ||||||
|  | 			} | ||||||
|  | 			dec.scanp++ | ||||||
|  | 			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] | ||||||
|  | 			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] | ||||||
|  | 			dec.tokenValueEnd() | ||||||
|  | 			return Delim('}'), nil | ||||||
|  |  | ||||||
|  | 		case ':': | ||||||
|  | 			if dec.tokenState != tokenObjectColon { | ||||||
|  | 				return dec.tokenError(c) | ||||||
|  | 			} | ||||||
|  | 			dec.scanp++ | ||||||
|  | 			dec.tokenState = tokenObjectValue | ||||||
|  | 			continue | ||||||
|  |  | ||||||
|  | 		case ',': | ||||||
|  | 			if dec.tokenState == tokenArrayComma { | ||||||
|  | 				dec.scanp++ | ||||||
|  | 				dec.tokenState = tokenArrayValue | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			if dec.tokenState == tokenObjectComma { | ||||||
|  | 				dec.scanp++ | ||||||
|  | 				dec.tokenState = tokenObjectKey | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			return dec.tokenError(c) | ||||||
|  |  | ||||||
|  | 		case '"': | ||||||
|  | 			if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey { | ||||||
|  | 				var x string | ||||||
|  | 				old := dec.tokenState | ||||||
|  | 				dec.tokenState = tokenTopValue | ||||||
|  | 				err := dec.Decode(&x) | ||||||
|  | 				dec.tokenState = old | ||||||
|  | 				if err != nil { | ||||||
|  | 					clearOffset(err) | ||||||
|  | 					return nil, err | ||||||
|  | 				} | ||||||
|  | 				dec.tokenState = tokenObjectColon | ||||||
|  | 				return x, nil | ||||||
|  | 			} | ||||||
|  | 			fallthrough | ||||||
|  |  | ||||||
|  | 		default: | ||||||
|  | 			if !dec.tokenValueAllowed() { | ||||||
|  | 				return dec.tokenError(c) | ||||||
|  | 			} | ||||||
|  | 			var x interface{} | ||||||
|  | 			if err := dec.Decode(&x); err != nil { | ||||||
|  | 				clearOffset(err) | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			return x, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func clearOffset(err error) { | ||||||
|  | 	if s, ok := err.(*SyntaxError); ok { | ||||||
|  | 		s.Offset = 0 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (dec *Decoder) tokenError(c byte) (Token, error) { | ||||||
|  | 	var context string | ||||||
|  | 	switch dec.tokenState { | ||||||
|  | 	case tokenTopValue: | ||||||
|  | 		context = " looking for beginning of value" | ||||||
|  | 	case tokenArrayStart, tokenArrayValue, tokenObjectValue: | ||||||
|  | 		context = " looking for beginning of value" | ||||||
|  | 	case tokenArrayComma: | ||||||
|  | 		context = " after array element" | ||||||
|  | 	case tokenObjectKey: | ||||||
|  | 		context = " looking for beginning of object key string" | ||||||
|  | 	case tokenObjectColon: | ||||||
|  | 		context = " after object key" | ||||||
|  | 	case tokenObjectComma: | ||||||
|  | 		context = " after object key:value pair" | ||||||
|  | 	} | ||||||
|  | 	return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, 0} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // More reports whether there is another element in the | ||||||
|  | // current array or object being parsed. | ||||||
|  | func (dec *Decoder) More() bool { | ||||||
|  | 	c, err := dec.peek() | ||||||
|  | 	return err == nil && c != ']' && c != '}' | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (dec *Decoder) peek() (byte, error) { | ||||||
|  | 	var err error | ||||||
|  | 	for { | ||||||
|  | 		for i := dec.scanp; i < len(dec.buf); i++ { | ||||||
|  | 			c := dec.buf[i] | ||||||
|  | 			if isSpace(c) { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			dec.scanp = i | ||||||
|  | 			return c, nil | ||||||
|  | 		} | ||||||
|  | 		// buffer has been scanned, now report any error | ||||||
|  | 		if err != nil { | ||||||
|  | 			return 0, err | ||||||
|  | 		} | ||||||
|  | 		err = dec.refill() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | TODO | ||||||
|  |  | ||||||
|  | // EncodeToken writes the given JSON token to the stream. | ||||||
|  | // It returns an error if the delimiters [ ] { } are not properly used. | ||||||
|  | // | ||||||
|  | // EncodeToken does not call Flush, because usually it is part of | ||||||
|  | // a larger operation such as Encode, and those will call Flush when finished. | ||||||
|  | // Callers that create an Encoder and then invoke EncodeToken directly, | ||||||
|  | // without using Encode, need to call Flush when finished to ensure that | ||||||
|  | // the JSON is written to the underlying writer. | ||||||
|  | func (e *Encoder) EncodeToken(t Token) error  { | ||||||
|  | 	... | ||||||
|  | } | ||||||
|  |  | ||||||
|  | */ | ||||||
							
								
								
									
										44
									
								
								plugSrc/mongodb/build/internal/json/tags.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								plugSrc/mongodb/build/internal/json/tags.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | // Copyright 2011 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package json | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // tagOptions is the string following a comma in a struct field's "json" | ||||||
|  | // tag, or the empty string. It does not include the leading comma. | ||||||
|  | type tagOptions string | ||||||
|  |  | ||||||
|  | // parseTag splits a struct field's json tag into its name and | ||||||
|  | // comma-separated options. | ||||||
|  | func parseTag(tag string) (string, tagOptions) { | ||||||
|  | 	if idx := strings.Index(tag, ","); idx != -1 { | ||||||
|  | 		return tag[:idx], tagOptions(tag[idx+1:]) | ||||||
|  | 	} | ||||||
|  | 	return tag, tagOptions("") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Contains reports whether a comma-separated list of options | ||||||
|  | // contains a particular substr flag. substr must be surrounded by a | ||||||
|  | // string boundary or commas. | ||||||
|  | func (o tagOptions) Contains(optionName string) bool { | ||||||
|  | 	if len(o) == 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	s := string(o) | ||||||
|  | 	for s != "" { | ||||||
|  | 		var next string | ||||||
|  | 		i := strings.Index(s, ",") | ||||||
|  | 		if i >= 0 { | ||||||
|  | 			s, next = s[:i], s[i+1:] | ||||||
|  | 		} | ||||||
|  | 		if s == optionName { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 		s = next | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
| @@ -4,9 +4,9 @@ import ( | |||||||
| 	"encoding/binary" | 	"encoding/binary" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"gopkg.in/mgo.v2/bson" |  | ||||||
| 	"io" |  | ||||||
| 	"time" | 	"time" | ||||||
|  | 	"io" | ||||||
|  | 	"github.com/40t/go-sniffer/plugSrc/mongodb/build/bson" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func GetNowStr(isClient bool) string { | func GetNowStr(isClient bool) string { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user