bson 0.20

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bson might be problematic. Click here for more details.

@@ -0,0 +1,224 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ # A byte buffer.
18
+ module BSON
19
+ class ByteBuffer
20
+
21
+ # Commonly-used integers.
22
+ INT_LOOKUP = {
23
+ 0 => [0, 0, 0, 0],
24
+ 1 => [1, 0, 0, 0],
25
+ 2 => [2, 0, 0, 0],
26
+ 3 => [3, 0, 0, 0],
27
+ 4 => [4, 0, 0, 0],
28
+ 2001 => [209, 7, 0, 0],
29
+ 2002 => [210, 7, 0, 0],
30
+ 2004 => [212, 7, 0, 0],
31
+ 2005 => [213, 7, 0, 0],
32
+ 2006 => [214, 7, 0, 0]
33
+ }
34
+
35
+ attr_reader :order
36
+
37
+ def initialize(initial_data=[])
38
+ @buf = initial_data
39
+ @cursor = @buf.length
40
+ @order = :little_endian
41
+ @int_pack_order = 'V'
42
+ @double_pack_order = 'E'
43
+ end
44
+
45
+ if RUBY_VERSION >= '1.9'
46
+ def self.to_utf8(str)
47
+ str.encode("utf-8")
48
+ end
49
+ else
50
+ def self.to_utf8(str)
51
+ begin
52
+ str.unpack("U*")
53
+ rescue => ex
54
+ raise InvalidStringEncoding, "String not valid utf-8: #{str}"
55
+ end
56
+ str
57
+ end
58
+ end
59
+
60
+ def self.serialize_cstr(buf, val)
61
+ buf.put_array(to_utf8(val.to_s).unpack("C*") + [0])
62
+ end
63
+
64
+ # +endianness+ should be :little_endian or :big_endian. Default is :little_endian
65
+ def order=(endianness)
66
+ @order = endianness
67
+ @int_pack_order = endianness == :little_endian ? 'V' : 'N'
68
+ @double_pack_order = endianness == :little_endian ? 'E' : 'G'
69
+ end
70
+
71
+ def rewind
72
+ @cursor = 0
73
+ end
74
+
75
+ def position
76
+ @cursor
77
+ end
78
+
79
+ def position=(val)
80
+ @cursor = val
81
+ end
82
+
83
+ def clear
84
+ @buf = []
85
+ rewind
86
+ end
87
+
88
+ def size
89
+ @buf.size
90
+ end
91
+ alias_method :length, :size
92
+
93
+ # Appends a second ByteBuffer object, +buffer+, to the current buffer.
94
+ def append!(buffer)
95
+ @buf = @buf + buffer.to_a
96
+ self
97
+ end
98
+
99
+ # Prepends a second ByteBuffer object, +buffer+, to the current buffer.
100
+ def prepend!(buffer)
101
+ @buf = buffer.to_a + @buf
102
+ self
103
+ end
104
+
105
+ def put(byte, offset=nil)
106
+ @cursor = offset if offset
107
+ @buf[@cursor] = byte
108
+ @cursor += 1
109
+ end
110
+
111
+ def put_array(array, offset=nil)
112
+ @cursor = offset if offset
113
+ @buf[@cursor, array.length] = array
114
+ @cursor += array.length
115
+ end
116
+
117
+ def put_int(i, offset=nil)
118
+ unless a = INT_LOOKUP[i]
119
+ a = []
120
+ [i].pack(@int_pack_order).each_byte { |b| a << b }
121
+ end
122
+ put_array(a, offset)
123
+ end
124
+
125
+ def put_long(i, offset=nil)
126
+ offset = @cursor unless offset
127
+ if @int_pack_order == 'N'
128
+ put_int(i >> 32, offset)
129
+ put_int(i & 0xffffffff, offset + 4)
130
+ else
131
+ put_int(i & 0xffffffff, offset)
132
+ put_int(i >> 32, offset + 4)
133
+ end
134
+ end
135
+
136
+ def put_double(d, offset=nil)
137
+ a = []
138
+ [d].pack(@double_pack_order).each_byte { |b| a << b }
139
+ put_array(a, offset)
140
+ end
141
+
142
+ # If +size+ == nil, returns one byte. Else returns array of bytes of length
143
+ # # +size+.
144
+ def get(len=nil)
145
+ one_byte = len.nil?
146
+ len ||= 1
147
+ check_read_length(len)
148
+ start = @cursor
149
+ @cursor += len
150
+ if one_byte
151
+ @buf[start]
152
+ else
153
+ if @buf.respond_to? "unpack"
154
+ @buf[start, len].unpack("C*")
155
+ else
156
+ @buf[start, len]
157
+ end
158
+ end
159
+ end
160
+
161
+ def get_int
162
+ check_read_length(4)
163
+ vals = ""
164
+ (@cursor..@cursor+3).each { |i| vals << @buf[i].chr }
165
+ @cursor += 4
166
+ vals.unpack(@int_pack_order)[0]
167
+ end
168
+
169
+ def get_long
170
+ i1 = get_int
171
+ i2 = get_int
172
+ if @int_pack_order == 'N'
173
+ (i1 << 32) + i2
174
+ else
175
+ (i2 << 32) + i1
176
+ end
177
+ end
178
+
179
+ def get_double
180
+ check_read_length(8)
181
+ vals = ""
182
+ (@cursor..@cursor+7).each { |i| vals << @buf[i].chr }
183
+ @cursor += 8
184
+ vals.unpack(@double_pack_order)[0]
185
+ end
186
+
187
+ def more?
188
+ @cursor < @buf.size
189
+ end
190
+
191
+ def to_a
192
+ if @buf.respond_to? "unpack"
193
+ @buf.unpack("C*")
194
+ else
195
+ @buf
196
+ end
197
+ end
198
+
199
+ def unpack(args)
200
+ to_a
201
+ end
202
+
203
+ def to_s
204
+ if @buf.respond_to? :fast_pack
205
+ @buf.fast_pack
206
+ elsif @buf.respond_to? "pack"
207
+ @buf.pack("C*")
208
+ else
209
+ @buf
210
+ end
211
+ end
212
+
213
+ def dump
214
+ @buf.each_with_index { |c, i| $stderr.puts "#{'%04d' % i}: #{'%02x' % c} #{'%03o' % c} #{'%s' % c.chr} #{'%3d' % c}" }
215
+ end
216
+
217
+ private
218
+
219
+ def check_read_length(len)
220
+ raise "attempt to read past end of buffer" if @cursor + len > @buf.length
221
+ end
222
+
223
+ end
224
+ end
@@ -0,0 +1,39 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ module BSON
18
+ # Generic Mongo Ruby Driver exception class.
19
+ class MongoRubyError < StandardError; end
20
+
21
+ # Raised when MongoDB itself has returned an error.
22
+ class MongoDBError < RuntimeError; end
23
+
24
+ # This will replace MongoDBError.
25
+ class BSONError < MongoDBError; end
26
+
27
+ # Raised when given a string is not valid utf-8 (Ruby 1.8 only).
28
+ class InvalidStringEncoding < BSONError; end
29
+
30
+ # Raised when attempting to initialize an invalid ObjectID.
31
+ class InvalidObjectID < BSONError; end
32
+
33
+ # Raised when trying to insert a document that exceeds the 4MB limit or
34
+ # when the document contains objects that can't be serialized as BSON.
35
+ class InvalidDocument < BSONError; end
36
+
37
+ # Raised when an invalid name is used.
38
+ class InvalidKeyName < BSONError; end
39
+ end
@@ -0,0 +1,140 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ # A hash in which the order of keys are preserved.
18
+ #
19
+ # Under Ruby 1.9 and greater, this class has no added methods because Ruby's
20
+ # Hash already keeps its keys ordered by order of insertion.
21
+ class OrderedHash < Hash
22
+
23
+ def ==(other)
24
+ begin
25
+ !other.nil? &&
26
+ keys == other.keys &&
27
+ values == other.values
28
+ rescue
29
+ false
30
+ end
31
+ end
32
+
33
+ # We only need the body of this class if the RUBY_VERSION is before 1.9
34
+ if RUBY_VERSION < '1.9'
35
+ attr_accessor :ordered_keys
36
+
37
+ def self.[] *args
38
+ oh = OrderedHash.new
39
+ if Hash === args[0]
40
+ oh.merge! args[0]
41
+ elsif (args.size % 2) != 0
42
+ raise ArgumentError, "odd number of elements for Hash"
43
+ else
44
+ 0.step(args.size - 1, 2) do |key|
45
+ value = key + 1
46
+ oh[args[key]] = args[value]
47
+ end
48
+ end
49
+ oh
50
+ end
51
+
52
+ def initialize(*a, &b)
53
+ super
54
+ @ordered_keys = []
55
+ end
56
+
57
+ def keys
58
+ @ordered_keys || []
59
+ end
60
+
61
+ def []=(key, value)
62
+ @ordered_keys ||= []
63
+ @ordered_keys << key unless @ordered_keys.include?(key)
64
+ super(key, value)
65
+ end
66
+
67
+ def each
68
+ @ordered_keys ||= []
69
+ @ordered_keys.each { |k| yield k, self[k] }
70
+ self
71
+ end
72
+ alias :each_pair :each
73
+
74
+ def to_a
75
+ @ordered_keys ||= []
76
+ @ordered_keys.map { |k| [k, self[k]] }
77
+ end
78
+
79
+ def values
80
+ collect { |k, v| v }
81
+ end
82
+
83
+ def merge(other)
84
+ oh = self.dup
85
+ oh.merge!(other)
86
+ oh
87
+ end
88
+
89
+ def merge!(other)
90
+ @ordered_keys ||= []
91
+ @ordered_keys += other.keys # unordered if not an OrderedHash
92
+ @ordered_keys.uniq!
93
+ super(other)
94
+ end
95
+
96
+ alias :update :merge!
97
+
98
+ def inspect
99
+ str = '{'
100
+ str << (@ordered_keys || []).collect { |k| "\"#{k}\"=>#{self.[](k).inspect}" }.join(", ")
101
+ str << '}'
102
+ end
103
+
104
+ def delete(key, &block)
105
+ @ordered_keys.delete(key) if @ordered_keys
106
+ super
107
+ end
108
+
109
+ def delete_if(&block)
110
+ self.each { |k,v|
111
+ if yield k, v
112
+ delete(k)
113
+ end
114
+ }
115
+ end
116
+
117
+ def clear
118
+ super
119
+ @ordered_keys = []
120
+ end
121
+
122
+ def hash
123
+ code = 17
124
+ each_pair do |key, value|
125
+ code = 37 * code + key.hash
126
+ code = 37 * code + value.hash
127
+ end
128
+ code & 0x7fffffff
129
+ end
130
+
131
+ def eql?(o)
132
+ if o.instance_of? OrderedHash
133
+ self.hash == o.hash
134
+ else
135
+ false
136
+ end
137
+ end
138
+
139
+ end
140
+ end
@@ -0,0 +1,54 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'bson/byte_buffer'
18
+
19
+ module BSON
20
+
21
+ # An array of binary bytes with a MongoDB subtype. See the subtype
22
+ # constants for reference.
23
+ #
24
+ # Use this class when storing binary data in documents.
25
+ class Binary < ByteBuffer
26
+
27
+ SUBTYPE_BYTES = 0x02
28
+ SUBTYPE_UUID = 0x03
29
+ SUBTYPE_MD5 = 0x05
30
+ SUBTYPE_USER_DEFINED = 0x80
31
+
32
+ # One of the SUBTYPE_* constants. Default is SUBTYPE_BYTES.
33
+ attr_accessor :subtype
34
+
35
+ # Create a buffer for storing binary data in MongoDB.
36
+ #
37
+ # @param [Array, String] data to story as BSON binary. If a string is given, the value will be
38
+ # concerted to an array of bytes using String#unpack("c*").
39
+ # @param [Fixnum] one of four values specifying a BSON binary subtype. Possible values are
40
+ # SUBTYPE_BYTES, SUBTYPE_UUID, SUBTYPE_MD5, and SUBTYPE_USER_DEFINED.
41
+ #
42
+ # @see http://www.mongodb.org/display/DOCS/BSON#BSON-noteondatabinary BSON binary subtypes.
43
+ def initialize(data=[], subtype=SUBTYPE_BYTES)
44
+ data = data.unpack("c*") if data.is_a?(String)
45
+ super(data)
46
+ @subtype = subtype
47
+ end
48
+
49
+ def inspect
50
+ "<BSON::Binary:#{object_id}>"
51
+ end
52
+
53
+ end
54
+ end