├── License.txt
├── README.md
├── bson
├── binary.js
├── binary_parser.js
├── binary_parser_old.js
├── binary_utils.js
├── bson.js
├── collections.js
├── float_parser.js
├── objectid.js
└── timestamp.js
├── cmds.js
├── commands.js
├── crypto
└── md5.js
├── examples
├── dbjoin.js
├── dbtestjoin.js
└── tonsdbjoins.js
├── goog
└── math
│ ├── integer.js
│ └── long.js
├── gridfs
├── chunk.js
└── gridstore.js
├── mongous.js
├── package.json
├── reply.js
└── responses
├── mongo_reply.js
├── mongo_reply_old.js
└── mr.js
/License.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright 2014 Mark Nadal and other contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Mongous
2 | ==========
3 | Mongous, for hu*mongous*, is a simple and blazing fast MongoDB driver that uses a jQuery like syntax.
4 |
5 | ### How it works
6 |
7 | var $ = require("mongous").Mongous;
8 |
9 | $("database.collection").save({my:"value"});
10 |
11 | $("database.collection").find({},function(r){
12 | console.log(r);
13 | });
14 |
15 | Done. App development has never felt as close to the shell as this! Making it a breeze to grab'n'store anything anywhere in your code without the nasty hassle of connections, collections, and cascading callbacks.
16 |
17 | ### Database & Collections
18 |
19 | - db('Database.Collection')
20 | - Database is the name of your database
21 | - Collection is the name of your collection
22 | - Examples
23 | - db('blog.post')
24 | - db('blog.post.body')
25 |
26 | ### Commands
27 |
28 | - **Update** db('blog.post').update(find, update, ...)
29 | - find
30 | is the object you want to find.
31 | - update
32 | is what you want to update find with.
33 | - ...
34 | - { upsert: true, multi: false }
35 | - true, true
36 | - **Save** db('blog.post').save(what)
37 | - what
38 | is the object to be updated or created.
39 | - **Insert** db('blog.post').insert(what...)
40 | - what
41 | is an object to be created.
42 | is an array of objects to be created.
43 | - Examples
44 | - db('blog.post').save({hello: 'world'})
45 | - db('blog.post').save([{hello: 'world'}, {foo: 'bar'}])
46 | - db('blog.post').save({hello: 'world'}, {foo: 'bar'})
47 | - **Remove** db('blog.post').remove(what, ...)
48 | - what is the object to be removed.
49 | - ...
50 | true for atomic.
51 | - **Find** db('blog.users').find(..., function(reply){ })
52 | - reply
53 | is the reply from MongoDB.
54 | - reply.documents
55 | are the documents that you found from MongoDB.
56 | - ...
57 | params are filtered by type
58 | - Objects
59 | - first object
60 | is what you want to find.
61 | - second object
62 | are fields you want
63 |
Ex: { name: 1, age: 1 }
64 | - third object
65 | is any of the following options:
66 |
{ lim: x, skip: y, sort:{age: 1} }
67 | - Numbers
68 | - first number
69 | is the limit (return all if not specified)
70 | - second number
71 | is the skip
72 | - Examples
73 | - db('blog.users').find(5, function(reply){ })
74 | reply.documents is the first 5 documents,
75 | - db('blog.users').find(5, {age: 23}, function(reply){ })
76 | with age of 23,
77 | - db('blog.users').find({age: 27}, 5, {name: 1}, function(reply){ })
78 | and a name.
79 | - db('blog.users').find(5, {age: 27}, {name: 1}, {lim: 10}, function(reply){ })
80 | is the same as the previous example, except the limit is 10 instead of 5.
81 | - db('blog.users').find(5, function(reply){ }, 2)
82 | reply.documents skips the first 2 documents and is the next 3 documents.
83 | - db('blog.users').find(function(reply){ }, {age: 25}, {}, {limit: 5, skip: 2})
84 | is the same as the previous example except only of doucments with the age of 25.
85 | - db('blog.users').find({}, {}, {sort: {age: -1}}, function(reply){ })
86 | reply.documents is sorted by age in a decsending (acsending while it is {age:1} ) order.
87 | - **Operations** db('blog.$cmd').find(command,1)
88 | - command
89 | is the database operation command you want to perform.
90 | - Example
91 | db('blog.$cmd').find({drop:"users"},1)
92 | drops the users collection, deleting it.
93 | - **Authentication** db('blog.$cmd').auth(username,password,callback)
94 | - username, password
95 | username and password of the 'blog' database
96 | - callback
97 | the callback function when authentication is finished.
98 | - Example
99 | - db('blog.$cmd').auth('user','pass',function(reply){})
100 | - **Open** db().open(host,port)
101 | - Only necessary to call if you explicitly want a different host and port, elsewise it lazy opens.
102 |
103 | Mongous is a reduction ('less is more') of node-mongodb-driver by Christian Kvalheim.
--------------------------------------------------------------------------------
/bson/binary.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Module dependencies.
4 | */
5 |
6 | var Buffer = require('buffer').Buffer; // TODO just use global Buffer
7 | var bson = require('./bson');
8 | // debug = require('util').debug,
9 | //inspect = require('util').inspect;
10 |
11 | /**
12 | * Binary constructor.
13 | *
14 | * @param {Buffer} buffer (optional)
15 | */
16 |
17 | function Binary(buffer, subType) {
18 | if(buffer instanceof Number) {
19 | this.sub_type = buffer;
20 | } else {
21 | this.sub_type = subType == null ? bson.BSON.BSON_BINARY_SUBTYPE_DEFAULT : subType;
22 | }
23 |
24 | if(buffer != null && !(buffer instanceof Number)) {
25 | this.buffer = typeof buffer == 'string' ? new Buffer(buffer) : buffer;
26 | this.position = buffer.length;
27 | } else {
28 | this.buffer = new Buffer(Binary.BUFFER_SIZE);
29 | this.position = 0;
30 | }
31 | };
32 |
33 | /**
34 | * Updates this binary with `byte_value`.
35 | *
36 | * @param {TODO} byte_value
37 | */
38 |
39 | Binary.prototype.put = function put (byte_value) {
40 | if (this.buffer.length > this.position) {
41 | this.buffer[this.position++] = byte_value.charCodeAt(0);
42 | } else {
43 | // Create additional overflow buffer
44 | var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length);
45 | // Combine the two buffers together
46 | this.buffer.copy(buffer, 0, 0, this.buffer.length);
47 | this.buffer = buffer;
48 | this.buffer[this.position++] = byte_value.charCodeAt(0);
49 | }
50 | };
51 |
52 | /**
53 | * Writes.
54 | *
55 | * @param {String} string
56 | * @param {Number} offset
57 | */
58 |
59 | Binary.prototype.write = function write (string, offset) {
60 | offset = offset ? offset : this.position;
61 |
62 | // If the buffer is to small let's extend the buffer
63 | if (this.buffer.length < offset + string.length) {
64 | var buffer = new Buffer(this.buffer.length + string.length);
65 | this.buffer.copy(buffer, 0, 0, this.buffer.length);
66 | // Assign the new buffer
67 | this.buffer = buffer;
68 | }
69 |
70 | if (string instanceof Buffer) {
71 | string.copy(this.buffer, offset, 0, string.length);
72 | } else {
73 | this.buffer.write(string, 'binary', offset);
74 | }
75 |
76 | this.position = offset + string.length;
77 | };
78 |
79 | /**
80 | * Reads `length` bytes starting at `position`.
81 | *
82 | * @param {Number} position
83 | * @param {Number} length
84 | * @return {String}
85 | */
86 |
87 | Binary.prototype.read = function read (position, length) {
88 | length = length && length > 0
89 | ? length
90 | : this.position;
91 |
92 | return this.buffer.toString('binary', position, position + length);
93 | };
94 |
95 | /**
96 | * Returns the value of this binary as a string.
97 | *
98 | * @return {String}
99 | */
100 |
101 | Binary.prototype.value = function value(asRaw) {
102 | asRaw = asRaw == null ? false : asRaw;
103 | return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position);
104 | };
105 |
106 | /**
107 | * Length.
108 | *
109 | * @return {Number}
110 | */
111 |
112 | Binary.prototype.length = function length () {
113 | return this.position;
114 | };
115 |
116 | Binary.BUFFER_SIZE = 256;
117 |
118 | /**
119 | * Expose.
120 | */
121 |
122 | exports.Binary = Binary;
123 |
124 |
--------------------------------------------------------------------------------
/bson/binary_parser.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Module dependencies.
4 | */
5 |
6 | //var sys = require('util');
7 |
8 | /**
9 | * Binary Parser.
10 | * Jonas Raoni Soares Silva
11 | * http://jsfromhell.com/classes/binary-parser [v1.0]
12 | */
13 |
14 | var chr = String.fromCharCode;
15 |
16 | var maxBits = [];
17 | for (var i = 0; i < 64; i++) {
18 | maxBits[i] = Math.pow(2, i);
19 | }
20 |
21 | function BinaryParser (bigEndian, allowExceptions) {
22 | this.bigEndian = bigEndian;
23 | this.allowExceptions = allowExceptions;
24 | };
25 |
26 | BinaryParser.warn = function warn (msg) {
27 | if (this.allowExceptions) {
28 | throw new Error(msg);
29 | }
30 |
31 | return 1;
32 | };
33 |
34 | BinaryParser.decodeFloat = function decodeFloat (data, precisionBits, exponentBits) {
35 | var b = new this.Buffer(this.bigEndian, data);
36 |
37 | b.checkBuffer(precisionBits + exponentBits + 1);
38 |
39 | var bias = maxBits[exponentBits - 1] - 1
40 | , signal = b.readBits(precisionBits + exponentBits, 1)
41 | , exponent = b.readBits(precisionBits, exponentBits)
42 | , significand = 0
43 | , divisor = 2
44 | , curByte = b.buffer.length + (-precisionBits >> 3) - 1;
45 |
46 | do {
47 | for (var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 );
48 | } while (precisionBits -= startBit);
49 |
50 | return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 );
51 | };
52 |
53 | BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian) {
54 | var b = new this.Buffer(this.bigEndian || forceBigEndian, data)
55 | , x = b.readBits(0, bits)
56 | , max = maxBits[bits]; //max = Math.pow( 2, bits );
57 |
58 | return signed && x >= max / 2
59 | ? x - max
60 | : x;
61 | };
62 |
63 | BinaryParser.encodeFloat = function encodeFloat (data, precisionBits, exponentBits) {
64 | var bias = maxBits[exponentBits - 1] - 1
65 | , minExp = -bias + 1
66 | , maxExp = bias
67 | , minUnnormExp = minExp - precisionBits
68 | , n = parseFloat(data)
69 | , status = isNaN(n) || n == -Infinity || n == +Infinity ? n : 0
70 | , exp = 0
71 | , len = 2 * bias + 1 + precisionBits + 3
72 | , bin = new Array(len)
73 | , signal = (n = status !== 0 ? 0 : n) < 0
74 | , intPart = Math.floor(n = Math.abs(n))
75 | , floatPart = n - intPart
76 | , lastBit
77 | , rounded
78 | , result
79 | , i
80 | , j;
81 |
82 | for (i = len; i; bin[--i] = 0);
83 |
84 | for (i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2));
85 |
86 | for (i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0 ) && --floatPart);
87 |
88 | for (i = -1; ++i < len && !bin[i];);
89 |
90 | if (bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]) {
91 | if (!(rounded = bin[lastBit])) {
92 | for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]);
93 | }
94 |
95 | for (j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0));
96 | }
97 |
98 | for (i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];);
99 |
100 | if ((exp = bias + 1 - i) >= minExp && exp <= maxExp) {
101 | ++i;
102 | } else if (exp < minExp) {
103 | exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow");
104 | i = bias + 1 - (exp = minExp - 1);
105 | }
106 |
107 | if (intPart || status !== 0) {
108 | this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status);
109 | exp = maxExp + 1;
110 | i = bias + 2;
111 |
112 | if (status == -Infinity) {
113 | signal = 1;
114 | } else if (isNaN(status)) {
115 | bin[i] = 1;
116 | }
117 | }
118 |
119 | for (n = Math.abs(exp + bias), j = exponentBits + 1, result = ""; --j; result = (n % 2) + result, n = n >>= 1);
120 |
121 | for (n = 0, j = 0, i = (result = (signal ? "1" : "0") + result + bin.slice(i, i + precisionBits).join("")).length, r = []; i; j = (j + 1) % 8) {
122 | n += (1 << j) * result.charAt(--i);
123 | if (j == 7) {
124 | r[r.length] = String.fromCharCode(n);
125 | n = 0;
126 | }
127 | }
128 |
129 | r[r.length] = n
130 | ? String.fromCharCode(n)
131 | : "";
132 |
133 | return (this.bigEndian ? r.reverse() : r).join("");
134 | };
135 |
136 | BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) {
137 | var max = maxBits[bits];
138 |
139 | if (data >= max || data < -(max / 2)) {
140 | this.warn("encodeInt::overflow");
141 | data = 0;
142 | }
143 |
144 | if (data < 0) {
145 | data += max;
146 | }
147 |
148 | for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256));
149 |
150 | for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0");
151 |
152 | return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join("");
153 | };
154 |
155 | BinaryParser.toSmall = function( data ){ return this.decodeInt( data, 8, true ); };
156 | BinaryParser.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); };
157 | BinaryParser.toByte = function( data ){ return this.decodeInt( data, 8, false ); };
158 | BinaryParser.fromByte = function( data ){ return this.encodeInt( data, 8, false ); };
159 | BinaryParser.toShort = function( data ){ return this.decodeInt( data, 16, true ); };
160 | BinaryParser.fromShort = function( data ){ return this.encodeInt( data, 16, true ); };
161 | BinaryParser.toWord = function( data ){ return this.decodeInt( data, 16, false ); };
162 | BinaryParser.fromWord = function( data ){ return this.encodeInt( data, 16, false ); };
163 | BinaryParser.toInt = function( data ){ return this.decodeInt( data, 32, true ); };
164 | BinaryParser.fromInt = function( data ){ return this.encodeInt( data, 32, true ); };
165 | BinaryParser.toLong = function( data ){ return this.decodeInt( data, 64, true ); };
166 | BinaryParser.fromLong = function( data ){ return this.encodeInt( data, 64, true ); };
167 | BinaryParser.toDWord = function( data ){ return this.decodeInt( data, 32, false ); };
168 | BinaryParser.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); };
169 | BinaryParser.toQWord = function( data ){ return this.decodeInt( data, 64, true ); };
170 | BinaryParser.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); };
171 | BinaryParser.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); };
172 | BinaryParser.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); };
173 | BinaryParser.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); };
174 | BinaryParser.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); };
175 |
176 | // Factor out the encode so it can be shared by add_header and push_int32
177 | BinaryParser.encode_int32 = function encode_int32 (number) {
178 | var a, b, c, d, unsigned;
179 | unsigned = (number < 0) ? (number + 0x100000000) : number;
180 | a = Math.floor(unsigned / 0xffffff);
181 | unsigned &= 0xffffff;
182 | b = Math.floor(unsigned / 0xffff);
183 | unsigned &= 0xffff;
184 | c = Math.floor(unsigned / 0xff);
185 | unsigned &= 0xff;
186 | d = Math.floor(unsigned);
187 | return chr(a) + chr(b) + chr(c) + chr(d);
188 | };
189 |
190 | BinaryParser.encode_int64 = function encode_int64 (number) {
191 | var a, b, c, d, e, f, g, h, unsigned;
192 | unsigned = (number < 0) ? (number + 0x10000000000000000) : number;
193 | a = Math.floor(unsigned / 0xffffffffffffff);
194 | unsigned &= 0xffffffffffffff;
195 | b = Math.floor(unsigned / 0xffffffffffff);
196 | unsigned &= 0xffffffffffff;
197 | c = Math.floor(unsigned / 0xffffffffff);
198 | unsigned &= 0xffffffffff;
199 | d = Math.floor(unsigned / 0xffffffff);
200 | unsigned &= 0xffffffff;
201 | e = Math.floor(unsigned / 0xffffff);
202 | unsigned &= 0xffffff;
203 | f = Math.floor(unsigned / 0xffff);
204 | unsigned &= 0xffff;
205 | g = Math.floor(unsigned / 0xff);
206 | unsigned &= 0xff;
207 | h = Math.floor(unsigned);
208 | return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h);
209 | };
210 |
211 | /**
212 | * UTF8 methods
213 | */
214 |
215 | // Take a raw binary string and return a utf8 string
216 | BinaryParser.decode_utf8 = function decode_utf8 (binaryStr) {
217 | var len = binaryStr.length
218 | , decoded = ''
219 | , i = 0
220 | , c = 0
221 | , c1 = 0
222 | , c2 = 0
223 | , c3;
224 |
225 | while (i < len) {
226 | c = binaryStr.charCodeAt(i);
227 | if (c < 128) {
228 | decoded += String.fromCharCode(c);
229 | i++;
230 | } else if ((c > 191) && (c < 224)) {
231 | c2 = binaryStr.charCodeAt(i+1);
232 | decoded += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
233 | i += 2;
234 | } else {
235 | c2 = binaryStr.charCodeAt(i+1);
236 | c3 = binaryStr.charCodeAt(i+2);
237 | decoded += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
238 | i += 3;
239 | }
240 | }
241 |
242 | return decoded;
243 | };
244 |
245 | // Encode a cstring
246 | BinaryParser.encode_cstring = function encode_cstring (s) {
247 | return unescape(encodeURIComponent(s)) + BinaryParser.fromByte(0);
248 | };
249 |
250 | // Take a utf8 string and return a binary string
251 | BinaryParser.encode_utf8 = function encode_utf8 (s) {
252 | var a = ""
253 | , c;
254 |
255 | for (var n = 0, len = s.length; n < len; n++) {
256 | c = s.charCodeAt(n);
257 |
258 | if (c < 128) {
259 | a += String.fromCharCode(c);
260 | } else if ((c > 127) && (c < 2048)) {
261 | a += String.fromCharCode((c>>6) | 192) ;
262 | a += String.fromCharCode((c&63) | 128);
263 | } else {
264 | a += String.fromCharCode((c>>12) | 224);
265 | a += String.fromCharCode(((c>>6) & 63) | 128);
266 | a += String.fromCharCode((c&63) | 128);
267 | }
268 | }
269 |
270 | return a;
271 | };
272 |
273 | BinaryParser.hprint = function hprint (s) {
274 | var number;
275 |
276 | for (var i = 0, len = s.length; i < len; i++) {
277 | if (s.charCodeAt(i) < 32) {
278 | number = s.charCodeAt(i) <= 15
279 | ? "0" + s.charCodeAt(i).toString(16)
280 | : s.charCodeAt(i).toString(16);
281 | process.stdout.write(number + " ")
282 | } else {
283 | number = s.charCodeAt(i) <= 15
284 | ? "0" + s.charCodeAt(i).toString(16)
285 | : s.charCodeAt(i).toString(16);
286 | process.stdout.write(number + " ")
287 | }
288 | }
289 |
290 | process.stdout.write("\n\n");
291 | };
292 |
293 | BinaryParser.ilprint = function hprint (s) {
294 | var number;
295 |
296 | for (var i = 0, len = s.length; i < len; i++) {
297 | if (s.charCodeAt(i) < 32) {
298 | number = s.charCodeAt(i) <= 15
299 | ? "0" + s.charCodeAt(i).toString(10)
300 | : s.charCodeAt(i).toString(10);
301 |
302 | //sys.debug(number+' : ');
303 | } else {
304 | number = s.charCodeAt(i) <= 15
305 | ? "0" + s.charCodeAt(i).toString(10)
306 | : s.charCodeAt(i).toString(10);
307 | //sys.debug(number+' : '+ s.charAt(i));
308 | }
309 | }
310 | };
311 |
312 | BinaryParser.hlprint = function hprint (s) {
313 | var number;
314 |
315 | for (var i = 0, len = s.length; i < len; i++) {
316 | if (s.charCodeAt(i) < 32) {
317 | number = s.charCodeAt(i) <= 15
318 | ? "0" + s.charCodeAt(i).toString(16)
319 | : s.charCodeAt(i).toString(16);
320 | //sys.debug(number+' : ');
321 | } else {
322 | number = s.charCodeAt(i) <= 15
323 | ? "0" + s.charCodeAt(i).toString(16)
324 | : s.charCodeAt(i).toString(16);
325 | //sys.debug(number+' : '+ s.charAt(i));
326 | }
327 | }
328 | };
329 |
330 | /**
331 | * BinaryParser buffer constructor.
332 | */
333 |
334 | function BinaryParserBuffer (bigEndian, buffer) {
335 | this.bigEndian = bigEndian || 0;
336 | this.buffer = [];
337 | this.setBuffer(buffer);
338 | };
339 |
340 | BinaryParserBuffer.prototype.setBuffer = function setBuffer (data) {
341 | var l, i, b;
342 |
343 | if (data) {
344 | i = l = data.length;
345 | b = this.buffer = new Array(l);
346 | for (; i; b[l - i] = data.charCodeAt(--i));
347 | this.bigEndian && b.reverse();
348 | }
349 | };
350 |
351 | BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits (neededBits) {
352 | return this.buffer.length >= -(-neededBits >> 3);
353 | };
354 |
355 | BinaryParserBuffer.prototype.checkBuffer = function checkBuffer (neededBits) {
356 | if (!this.hasNeededBits(neededBits)) {
357 | throw new Error("checkBuffer::missing bytes");
358 | }
359 | };
360 |
361 | BinaryParserBuffer.prototype.readBits = function readBits (start, length) {
362 | //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
363 |
364 | function shl (a, b) {
365 | for (; b--; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1);
366 | return a;
367 | }
368 |
369 | if (start < 0 || length <= 0) {
370 | return 0;
371 | }
372 |
373 | this.checkBuffer(start + length);
374 |
375 | var offsetLeft
376 | , offsetRight = start % 8
377 | , curByte = this.buffer.length - ( start >> 3 ) - 1
378 | , lastByte = this.buffer.length + ( -( start + length ) >> 3 )
379 | , diff = curByte - lastByte
380 | , sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[lastByte++] & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight : 0);
381 |
382 | for(; diff; sum += shl(this.buffer[lastByte++], (diff-- << 3) - offsetRight));
383 |
384 | return sum;
385 | };
386 |
387 | /**
388 | * Expose.
389 | */
390 |
391 | exports.BinaryParser = BinaryParser;
392 | BinaryParser.Buffer = BinaryParserBuffer;
393 |
--------------------------------------------------------------------------------
/bson/binary_parser_old.js:
--------------------------------------------------------------------------------
1 | //+ Jonas Raoni Soares Silva
2 | //@ http://jsfromhell.com/classes/binary-parser [v1.0]
3 | var chr = String.fromCharCode;
4 |
5 | var p = exports.BinaryParser = function( bigEndian, allowExceptions ){
6 | this.bigEndian = bigEndian;
7 | this.allowExceptions = allowExceptions;
8 | };
9 |
10 | var Buffer = exports.BinaryParser.Buffer = function( bigEndian, buffer ){
11 | this.bigEndian = bigEndian || 0;
12 | this.buffer = [];
13 | this.setBuffer( buffer );
14 | };
15 |
16 | Buffer.prototype.setBuffer = function( data ){
17 | if( data ){
18 | for( var l, i = l = data.length, b = this.buffer = new Array( l ); i; b[l - i] = data.charCodeAt( --i ) );
19 | this.bigEndian && b.reverse();
20 | }
21 | };
22 |
23 | Buffer.prototype.hasNeededBits = function( neededBits ){
24 | return this.buffer.length >= -( -neededBits >> 3 );
25 | };
26 |
27 | Buffer.prototype.checkBuffer = function( neededBits ){
28 | if( !this.hasNeededBits( neededBits ) )
29 | throw new Error( "checkBuffer::missing bytes" );
30 | };
31 |
32 | Buffer.prototype.readBits = function( start, length ){
33 | //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
34 | function shl( a, b ){
35 | for( ; b--; a = ( ( a %= 0x7fffffff + 1 ) & 0x40000000 ) == 0x40000000 ? a * 2 : ( a - 0x40000000 ) * 2 + 0x7fffffff + 1 );
36 | return a;
37 | }
38 | if( start < 0 || length <= 0 )
39 | return 0;
40 | this.checkBuffer( start + length );
41 | for( var offsetLeft, offsetRight = start % 8, curByte = this.buffer.length - ( start >> 3 ) - 1, lastByte = this.buffer.length + ( -( start + length ) >> 3 ), diff = curByte - lastByte, sum = ( ( this.buffer[ curByte ] >> offsetRight ) & ( ( 1 << ( diff ? 8 - offsetRight : length ) ) - 1 ) ) + ( diff && ( offsetLeft = ( start + length ) % 8 ) ? ( this.buffer[ lastByte++ ] & ( ( 1 << offsetLeft ) - 1 ) ) << ( diff-- << 3 ) - offsetRight : 0 ); diff; sum += shl( this.buffer[ lastByte++ ], ( diff-- << 3 ) - offsetRight ) );
42 | return sum;
43 | };
44 |
45 | p.warn = function( msg ){
46 | if( this.allowExceptions )
47 | throw new Error( msg );
48 | return 1;
49 | };
50 | p.decodeFloat = function( data, precisionBits, exponentBits ){
51 | var b = new this.Buffer( this.bigEndian, data );
52 | b.checkBuffer( precisionBits + exponentBits + 1 );
53 | var bias = Math.pow( 2, exponentBits - 1 ) - 1, signal = b.readBits( precisionBits + exponentBits, 1 ), exponent = b.readBits( precisionBits, exponentBits ), significand = 0,
54 | divisor = 2, curByte = b.buffer.length + ( -precisionBits >> 3 ) - 1;
55 | do{
56 | for( var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 );
57 | }while( precisionBits -= startBit );
58 | return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 );
59 | };
60 | p.decodeInt = function( data, bits, signed, forceBigEndian ){
61 | var b = new this.Buffer( this.bigEndian||forceBigEndian, data ), x = b.readBits( 0, bits ), max = Math.pow( 2, bits );
62 | return signed && x >= max / 2 ? x - max : x;
63 | };
64 | p.encodeFloat = function( data, precisionBits, exponentBits ){
65 | var bias = Math.pow( 2, exponentBits - 1 ) - 1, minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits,
66 | status = isNaN( n = parseFloat( data ) ) || n == -Infinity || n == +Infinity ? n : 0,
67 | exp = 0, len = 2 * bias + 1 + precisionBits + 3, bin = new Array( len ),
68 | signal = ( n = status !== 0 ? 0 : n ) < 0, n = Math.abs( n ), intPart = Math.floor( n ), floatPart = n - intPart,
69 | i, lastBit, rounded, j, result;
70 | for( i = len; i; bin[--i] = 0 );
71 | for( i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor( intPart / 2 ) );
72 | for( i = bias + 1; floatPart > 0 && i; ( bin[++i] = ( ( floatPart *= 2 ) >= 1 ) - 0 ) && --floatPart );
73 | for( i = -1; ++i < len && !bin[i]; );
74 | if( bin[( lastBit = precisionBits - 1 + ( i = ( exp = bias + 1 - i ) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - ( exp = minExp - 1 ) ) ) + 1] ){
75 | if( !( rounded = bin[lastBit] ) ){
76 | for( j = lastBit + 2; !rounded && j < len; rounded = bin[j++] );
77 | }
78 | for( j = lastBit + 1; rounded && --j >= 0; ( bin[j] = !bin[j] - 0 ) && ( rounded = 0 ) );
79 | }
80 | for( i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i]; );
81 | if( ( exp = bias + 1 - i ) >= minExp && exp <= maxExp )
82 | ++i;
83 | else if( exp < minExp ){
84 | exp != bias + 1 - len && exp < minUnnormExp && this.warn( "encodeFloat::float underflow" );
85 | i = bias + 1 - ( exp = minExp - 1 );
86 | }
87 | if( intPart || status !== 0 ){
88 | this.warn( intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status );
89 | exp = maxExp + 1;
90 | i = bias + 2;
91 | if( status == -Infinity )
92 | signal = 1;
93 | else if( isNaN( status ) )
94 | bin[i] = 1;
95 | }
96 | for( n = Math.abs( exp + bias ), j = exponentBits + 1, result = ""; --j; result = ( n % 2 ) + result, n = n >>= 1 );
97 | for( n = 0, j = 0, i = ( result = ( signal ? "1" : "0" ) + result + bin.slice( i, i + precisionBits ).join( "" ) ).length, r = []; i; j = ( j + 1 ) % 8 ){
98 | n += ( 1 << j ) * result.charAt( --i );
99 | if( j == 7 ){
100 | r[r.length] = String.fromCharCode( n );
101 | n = 0;
102 | }
103 | }
104 | r[r.length] = n ? String.fromCharCode( n ) : "";
105 | return ( this.bigEndian ? r.reverse() : r ).join( "" );
106 | };
107 | p.encodeInt = function( data, bits, signed, forceBigEndian ){
108 | var max = Math.pow( 2, bits );
109 | ( data >= max || data < -( max / 2 ) ) && this.warn( "encodeInt::overflow" ) && ( data = 0 );
110 | data < 0 && ( data += max );
111 | for( var r = []; data; r[r.length] = String.fromCharCode( data % 256 ), data = Math.floor( data / 256 ) );
112 | for( bits = -( -bits >> 3 ) - r.length; bits--; r[r.length] = "\0" );
113 | return ( (this.bigEndian||forceBigEndian) ? r.reverse() : r ).join( "" );
114 | };
115 | p.toSmall = function( data ){ return this.decodeInt( data, 8, true ); };
116 | p.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); };
117 | p.toByte = function( data ){ return this.decodeInt( data, 8, false ); };
118 | p.fromByte = function( data ){ return this.encodeInt( data, 8, false ); };
119 | p.toShort = function( data ){ return this.decodeInt( data, 16, true ); };
120 | p.fromShort = function( data ){ return this.encodeInt( data, 16, true ); };
121 | p.toWord = function( data ){ return this.decodeInt( data, 16, false ); };
122 | p.fromWord = function( data ){ return this.encodeInt( data, 16, false ); };
123 | p.toInt = function( data ){ return this.decodeInt( data, 32, true ); };
124 | p.fromInt = function( data ){ return this.encodeInt( data, 32, true ); };
125 | p.toLong = function( data ){ return this.decodeInt( data, 64, true ); };
126 | p.fromLong = function( data ){ return this.encodeInt( data, 64, true ); };
127 | p.toDWord = function( data ){ return this.decodeInt( data, 32, false ); };
128 | p.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); };
129 | p.toQWord = function( data ){ return this.decodeInt( data, 64, true ); };
130 | p.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); };
131 | p.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); };
132 | p.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); };
133 | p.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); };
134 | p.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); };
135 |
136 | // Factor out the encode so it can be shared by add_header and push_int32
137 | p.encode_int32 = function(number) {
138 | var a, b, c, d, unsigned;
139 | unsigned = (number < 0) ? (number + 0x100000000) : number;
140 | a = Math.floor(unsigned / 0xffffff);
141 | unsigned &= 0xffffff;
142 | b = Math.floor(unsigned / 0xffff);
143 | unsigned &= 0xffff;
144 | c = Math.floor(unsigned / 0xff);
145 | unsigned &= 0xff;
146 | d = Math.floor(unsigned);
147 | return chr(a) + chr(b) + chr(c) + chr(d);
148 | };
149 |
150 | p.encode_int64 = function(number) {
151 | var a, b, c, d, e, f, g, h, unsigned;
152 | unsigned = (number < 0) ? (number + 0x10000000000000000) : number;
153 | a = Math.floor(unsigned / 0xffffffffffffff);
154 | unsigned &= 0xffffffffffffff;
155 | b = Math.floor(unsigned / 0xffffffffffff);
156 | unsigned &= 0xffffffffffff;
157 | c = Math.floor(unsigned / 0xffffffffff);
158 | unsigned &= 0xffffffffff;
159 | d = Math.floor(unsigned / 0xffffffff);
160 | unsigned &= 0xffffffff;
161 | e = Math.floor(unsigned / 0xffffff);
162 | unsigned &= 0xffffff;
163 | f = Math.floor(unsigned / 0xffff);
164 | unsigned &= 0xffff;
165 | g = Math.floor(unsigned / 0xff);
166 | unsigned &= 0xff;
167 | h = Math.floor(unsigned);
168 | return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h);
169 | };
170 |
171 | /**
172 | UTF8 methods
173 | **/
174 |
175 | // Take a raw binary string and return a utf8 string
176 | p.decode_utf8 = function(a) {
177 | var string = "";
178 | var i = 0;
179 | var c = c1 = c2 = 0;
180 |
181 | while ( i < a.length ) {
182 | c = a.charCodeAt(i);
183 | if (c < 128) {
184 | string += String.fromCharCode(c);
185 | i++;
186 | } else if((c > 191) && (c < 224)) {
187 | c2 = a.charCodeAt(i+1);
188 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
189 | i += 2;
190 | } else {
191 | c2 = a.charCodeAt(i+1);
192 | c3 = a.charCodeAt(i+2);
193 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
194 | i += 3;
195 | }
196 | }
197 | return string;
198 | };
199 |
200 | // Encode a cstring correctly
201 | p.encode_cstring = function(s) {
202 | return unescape(encodeURIComponent(s)) + p.fromByte(0);
203 | };
204 |
205 | // Take a utf8 string and return a binary string
206 | p.encode_utf8 = function(s) {
207 | var a="";
208 | for (var n=0; n< s.length; n++) {
209 | var c=s.charCodeAt(n);
210 | if (c<128) {
211 | a += String.fromCharCode(c);
212 | } else if ((c>127)&&(c<2048)) {
213 | a += String.fromCharCode( (c>>6) | 192) ;
214 | a += String.fromCharCode( (c&63) | 128);
215 | } else {
216 | a += String.fromCharCode( (c>>12) | 224);
217 | a += String.fromCharCode( ((c>>6) & 63) | 128);
218 | a += String.fromCharCode( (c&63) | 128);
219 | }
220 | }
221 | return a;
222 | };
223 |
224 | p.pprint = function(s) {
225 | for (var i=0; i> 24) & 0xff;
4 | buffer[2] = (value >> 16) & 0xff;
5 | buffer[1] = (value >> 8) & 0xff;
6 | buffer[0] = value & 0xff;
7 | return buffer;
8 | }
9 |
10 | exports.encodeIntInPlace = function(value, buffer, index) {
11 | buffer[index + 3] = (value >> 24) & 0xff;
12 | buffer[index + 2] = (value >> 16) & 0xff;
13 | buffer[index + 1] = (value >> 8) & 0xff;
14 | buffer[index] = value & 0xff;
15 | }
16 |
17 | exports.encodeCString = function(string) {
18 | var buf = new Buffer(string, 'utf8');
19 | return [buf, new Buffer([0])];
20 | }
21 |
22 | exports.decodeUInt32 = function(array, index) {
23 | return array[index] | array[index + 1] << 8 | array[index + 2] << 16 | array[index + 3] << 24;
24 | }
25 |
26 | // Decode the int
27 | exports.decodeUInt8 = function(array, index) {
28 | return array[index];
29 | }
30 |
--------------------------------------------------------------------------------
/bson/collections.js:
--------------------------------------------------------------------------------
1 | /*
2 | Ordered Hash Definition
3 | */
4 | var OrderedHash = exports.OrderedHash = function(arguments) {
5 | this.ordered_keys = [];
6 | this.values = {};
7 | var index = 0;
8 |
9 | for(var argument in arguments) {
10 | var value = arguments[argument];
11 | this.values[argument] = value;
12 | this.ordered_keys[index++] = argument;
13 | }
14 | };
15 |
16 | // Functions to add values
17 | OrderedHash.prototype.add = function(key, value) {
18 | if(this.values[key] == null) {
19 | this.ordered_keys[this.ordered_keys.length] = key;
20 | }
21 |
22 | this.values[key] = value;
23 | return this;
24 | };
25 |
26 | OrderedHash.prototype.remove = function(key) {
27 | var new_ordered_keys = [];
28 | // Remove all non_needed keys
29 | for(var i = 0; i < this.ordered_keys.length; i++) {
30 | if(!(this.ordered_keys[i] == key)) {
31 | new_ordered_keys[new_ordered_keys.length] = this.ordered_keys[i];
32 | }
33 | }
34 | // Assign the new arrays
35 | this.ordered_keys = new_ordered_keys;
36 | // Remove this reference to this
37 | delete this.values[key];
38 | return this;
39 | };
40 |
41 | OrderedHash.prototype.unorderedHash = function() {
42 | var hash = {};
43 | for(var i = 0; i < this.ordered_keys.length; i++) {
44 | hash[this.ordered_keys[i]] = this.values[this.ordered_keys[i]];
45 | }
46 | return hash;
47 | };
48 |
49 | // Fetch the keys for the hash
50 | OrderedHash.prototype.keys = function() {
51 | return this.ordered_keys;
52 | };
53 |
54 | OrderedHash.prototype.get = function(key) {
55 | return this.values[key];
56 | };
57 |
58 | OrderedHash.prototype.length = function(){
59 | return this.keys().length;
60 | };
61 |
62 | OrderedHash.prototype.toArray = function() {
63 | var result = {},
64 | keys = this.keys();
65 |
66 | for (var key in keys)
67 | result[key] = this.values[key];
68 |
69 | return result;
70 | };
--------------------------------------------------------------------------------
/bson/float_parser.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2008, Fair Oaks Labs, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | //
10 | // * Redistributions in binary form must reproduce the above copyright notice,
11 | // this list of conditions and the following disclaimer in the documentation
12 | // and/or other materials provided with the distribution.
13 | //
14 | // * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors
15 | // may be used to endorse or promote products derived from this software
16 | // without specific prior written permission.
17 | //
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | // POSSIBILITY OF SUCH DAMAGE.
29 | //
30 | //
31 | // Modifications to writeIEEE754 to support negative zeroes made by Brian White
32 |
33 | exports.readIEEE754 = function(buffer, offset, endian, mLen, nBytes) {
34 | var e, m,
35 | bBE = (endian === 'big'),
36 | eLen = nBytes * 8 - mLen - 1,
37 | eMax = (1 << eLen) - 1,
38 | eBias = eMax >> 1,
39 | nBits = -7,
40 | i = bBE ? 0 : (nBytes - 1),
41 | d = bBE ? 1 : -1,
42 | s = buffer[offset + i];
43 |
44 | i += d;
45 |
46 | e = s & ((1 << (-nBits)) - 1);
47 | s >>= (-nBits);
48 | nBits += eLen;
49 | for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
50 |
51 | m = e & ((1 << (-nBits)) - 1);
52 | e >>= (-nBits);
53 | nBits += mLen;
54 | for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
55 |
56 | if (e === 0) {
57 | e = 1 - eBias;
58 | } else if (e === eMax) {
59 | return m ? NaN : ((s ? -1 : 1) * Infinity);
60 | } else {
61 | m = m + Math.pow(2, mLen);
62 | e = e - eBias;
63 | }
64 | return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
65 | };
66 |
67 | exports.writeIEEE754 = function(buffer, value, offset, endian, mLen, nBytes) {
68 | var e, m, c,
69 | bBE = (endian === 'big'),
70 | eLen = nBytes * 8 - mLen - 1,
71 | eMax = (1 << eLen) - 1,
72 | eBias = eMax >> 1,
73 | rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
74 | i = bBE ? (nBytes-1) : 0,
75 | d = bBE ? -1 : 1,
76 | s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
77 |
78 | value = Math.abs(value);
79 |
80 | if (isNaN(value) || value === Infinity) {
81 | m = isNaN(value) ? 1 : 0;
82 | e = eMax;
83 | } else {
84 | e = Math.floor(Math.log(value) / Math.LN2);
85 | if (value * (c = Math.pow(2, -e)) < 1) {
86 | e--;
87 | c *= 2;
88 | }
89 | if (e+eBias >= 1) {
90 | value += rt / c;
91 | } else {
92 | value += rt * Math.pow(2, 1 - eBias);
93 | }
94 | if (value * c >= 2) {
95 | e++;
96 | c /= 2;
97 | }
98 |
99 | if (e + eBias >= eMax) {
100 | m = 0;
101 | e = eMax;
102 | } else if (e + eBias >= 1) {
103 | m = (value * c - 1) * Math.pow(2, mLen);
104 | e = e + eBias;
105 | } else {
106 | m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
107 | e = 0;
108 | }
109 | }
110 |
111 | for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
112 |
113 | e = (e << mLen) | m;
114 | eLen += mLen;
115 | for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
116 |
117 | buffer[offset + i - d] |= s * 128;
118 | };
119 |
--------------------------------------------------------------------------------
/bson/objectid.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Module dependencies.
3 | */
4 |
5 | var BinaryParser = require('./binary_parser').BinaryParser;
6 | //inspect = require('util').inspect,
7 | //debug = require('util').debug;
8 |
9 | /**
10 | * Machine id.
11 | *
12 | * Create a random 3-byte value (i.e. unique for this
13 | * process). Other drivers use a md5 of the machine id here, but
14 | * that would mean an asyc call to gethostname, so we don't bother.
15 | */
16 |
17 | var MACHINE_ID = parseInt(Math.random() * 0xFFFFFF, 10);
18 |
19 | /**
20 | * Constructor.
21 | *
22 | * @param {String} id (optional)
23 | */
24 |
25 | function ObjectID (id) {
26 | // Throw an error if it's not a valid setup
27 | if(id != null && (id.length != 12 && id.length != 24)) throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters in hex format");
28 | // Generate id based on the input
29 | if (null == id) {
30 | this.id = this.generate();
31 | } else if (/^[0-9a-fA-F]{24}$/.test(id)) {
32 | return ObjectID.createFromHexString(id);
33 | } else {
34 | this.id = id;
35 | }
36 | };
37 |
38 | /**
39 | * Updates the ObjectID index.
40 | *
41 | * @return {Number}
42 | */
43 |
44 | ObjectID.prototype.get_inc = function() {
45 | return ObjectID.index = (ObjectID.index + 1) % 0xFFFFFF;
46 | };
47 |
48 | /**
49 | * Generates an ObjectId.
50 | *
51 | * @return {String}
52 | */
53 |
54 | ObjectID.prototype.generate = function() {
55 | var unixTime = parseInt(Date.now()/1000, 10);
56 | var time4Bytes = BinaryParser.encodeInt(unixTime, 32, true, true);
57 | var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false);
58 | var pid2Bytes = BinaryParser.fromShort(process.pid);
59 | var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true);
60 | return time4Bytes + machine3Bytes + pid2Bytes + index3Bytes;
61 | };
62 |
63 | /**
64 | * Converts this ObjectId to a hex string.
65 | *
66 | * @return {String}
67 | */
68 |
69 | ObjectID.prototype.toHexString = function() {
70 | var hexString = ''
71 | , number
72 | , value;
73 |
74 | for (var index = 0, len = this.id.length; index < len; index++) {
75 | value = BinaryParser.toByte(this.id.substr(index, 1));
76 | number = value <= 15
77 | ? '0' + value.toString(16)
78 | : value.toString(16);
79 | hexString = hexString + number;
80 | }
81 |
82 | return hexString;
83 | };
84 |
85 | /**
86 | * Converts this id to a string.
87 | *
88 | * @return {String}
89 | */
90 |
91 | ObjectID.prototype.toString = function() {
92 | return this.toHexString();
93 | };
94 |
95 | /**
96 | * Converts to a string representation of this Id.
97 | */
98 |
99 | ObjectID.prototype.inspect = ObjectID.prototype.toString;
100 |
101 | /**
102 | * Converts to its JSON representation.
103 | */
104 |
105 | ObjectID.prototype.toJSON = ObjectID.prototype.toString;
106 |
107 | /**
108 | * Compares the equality of this ObjectID with `otherID`.
109 | *
110 | * @return {Bool}
111 | */
112 |
113 | ObjectID.prototype.equals = function equals (otherID) {
114 | var id = (otherID instanceof ObjectID || otherID.toHexString)
115 | ? otherID.id
116 | : ObjectID.createFromHexString(otherID).id;
117 |
118 | return this.id === id;
119 | }
120 |
121 | /**
122 | * Returns the generation time in seconds that this
123 | * ID was generated.
124 | *
125 | * @return {Number}
126 | */
127 |
128 | ObjectID.prototype.__defineGetter__("generationTime", function() {
129 | return BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true) * 1000;
130 | });
131 |
132 | /**
133 | * Statics.
134 | */
135 |
136 | ObjectID.index = 0;
137 |
138 | ObjectID.createPk = function createPk () {
139 | return new ObjectID();
140 | };
141 |
142 | /**
143 | * Creates an ObjectID from a hex string representation
144 | * of an ObjectID.
145 | *
146 | * @param {String} hexString
147 | * @return {ObjectID}
148 | */
149 |
150 | ObjectID.createFromHexString = function createFromHexString (hexString) {
151 | var len = hexString.length;
152 |
153 | if (len > 12*2) {
154 | throw new Error('Id cannot be longer than 12 bytes');
155 | }
156 |
157 | var result = ''
158 | , string
159 | , number;
160 |
161 | for (var index = 0; index < len; index += 2) {
162 | string = hexString.substr(index, 2);
163 | number = parseInt(string, 16);
164 | result += BinaryParser.fromByte(number);
165 | }
166 |
167 | return new ObjectID(result);
168 | };
169 |
170 | /**
171 | * Expose.
172 | */
173 |
174 | exports.ObjectID = ObjectID;
175 |
176 |
--------------------------------------------------------------------------------
/bson/timestamp.js:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License, Version 2.0 (the "License");
2 | // you may not use this file except in compliance with the License.
3 | // You may obtain a copy of the License at
4 | //
5 | // http://www.apache.org/licenses/LICENSE-2.0
6 | //
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 |
13 | // Copyright 2009 Google Inc. All Rights Reserved
14 |
15 | /**
16 | * @fileoverview Defines a exports.Timestamp class for representing a 64-bit two's-complement
17 | * integer value, which faithfully simulates the behavior of a Java "Timestamp". This
18 | * implementation is derived from exports.TimestampLib in GWT.
19 | *
20 | */
21 |
22 | /**
23 | * Constructs a 64-bit two's-complement integer, given its low and high 32-bit
24 | * values as *signed* integers. See the from* functions below for more
25 | * convenient ways of constructing exports.Timestamps.
26 | *
27 | * The internal representation of a Timestamp is the two given signed, 32-bit values.
28 | * We use 32-bit pieces because these are the size of integers on which
29 | * Javascript performs bit-operations. For operations like addition and
30 | * multiplication, we split each number into 16-bit pieces, which can easily be
31 | * multiplied within Javascript's floating-point representation without overflow
32 | * or change in sign.
33 | *
34 | * In the algorithms below, we frequently reduce the negative case to the
35 | * positive case by negating the input(s) and then post-processing the result.
36 | * Note that we must ALWAYS check specially whether those values are MIN_VALUE
37 | * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
38 | * a positive number, it overflows back into a negative). Not handling this
39 | * case would often result in infinite recursion.
40 | *
41 | * @param {number} low The low (signed) 32 bits of the Timestamp.
42 | * @param {number} high The high (signed) 32 bits of the Timestamp.
43 | * @constructor
44 | */
45 | exports.Timestamp = function(low, high) {
46 | /**
47 | * @type {number}
48 | * @private
49 | */
50 | this.low_ = low | 0; // force into 32 signed bits.
51 |
52 | /**
53 | * @type {number}
54 | * @private
55 | */
56 | this.high_ = high | 0; // force into 32 signed bits.
57 | };
58 |
59 |
60 | // NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
61 | // from* methods on which they depend.
62 |
63 |
64 | /**
65 | * A cache of the exports.Timestamp representations of small integer values.
66 | * @type {Object}
67 | * @private
68 | */
69 | exports.Timestamp.INT_CACHE_ = {};
70 |
71 |
72 | /**
73 | * Returns a exports.Timestamp representing the given (32-bit) integer value.
74 | * @param {number} value The 32-bit integer in question.
75 | * @return {exports.Timestamp} The corresponding exports.Timestamp value.
76 | */
77 | exports.Timestamp.fromInt = function(value) {
78 | if (-128 <= value && value < 128) {
79 | var cachedObj = exports.Timestamp.INT_CACHE_[value];
80 | if (cachedObj) {
81 | return cachedObj;
82 | }
83 | }
84 |
85 | var obj = new exports.Timestamp(value | 0, value < 0 ? -1 : 0);
86 | if (-128 <= value && value < 128) {
87 | exports.Timestamp.INT_CACHE_[value] = obj;
88 | }
89 | return obj;
90 | };
91 |
92 |
93 | /**
94 | * Returns a exports.Timestamp representing the given value, provided that it is a finite
95 | * number. Otherwise, zero is returned.
96 | * @param {number} value The number in question.
97 | * @return {exports.Timestamp} The corresponding exports.Timestamp value.
98 | */
99 | exports.Timestamp.fromNumber = function(value) {
100 | if (isNaN(value) || !isFinite(value)) {
101 | return exports.Timestamp.ZERO;
102 | } else if (value <= -exports.Timestamp.TWO_PWR_63_DBL_) {
103 | return exports.Timestamp.MIN_VALUE;
104 | } else if (value + 1 >= exports.Timestamp.TWO_PWR_63_DBL_) {
105 | return exports.Timestamp.MAX_VALUE;
106 | } else if (value < 0) {
107 | return exports.Timestamp.fromNumber(-value).negate();
108 | } else {
109 | return new exports.Timestamp(
110 | (value % exports.Timestamp.TWO_PWR_32_DBL_) | 0,
111 | (value / exports.Timestamp.TWO_PWR_32_DBL_) | 0);
112 | }
113 | };
114 |
115 |
116 | /**
117 | * Returns a exports.Timestamp representing the 64-bit integer that comes by concatenating
118 | * the given high and low bits. Each is assumed to use 32 bits.
119 | * @param {number} lowBits The low 32-bits.
120 | * @param {number} highBits The high 32-bits.
121 | * @return {exports.Timestamp} The corresponding exports.Timestamp value.
122 | */
123 | exports.Timestamp.fromBits = function(lowBits, highBits) {
124 | return new exports.Timestamp(lowBits, highBits);
125 | };
126 |
127 |
128 | /**
129 | * Returns a exports.Timestamp representation of the given string, written using the given
130 | * radix.
131 | * @param {string} str The textual representation of the exports.Timestamp.
132 | * @param {number} opt_radix The radix in which the text is written.
133 | * @return {exports.Timestamp} The corresponding exports.Timestamp value.
134 | */
135 | exports.Timestamp.fromString = function(str, opt_radix) {
136 | if (str.length == 0) {
137 | throw Error('number format error: empty string');
138 | }
139 |
140 | var radix = opt_radix || 10;
141 | if (radix < 2 || 36 < radix) {
142 | throw Error('radix out of range: ' + radix);
143 | }
144 |
145 | if (str.charAt(0) == '-') {
146 | return exports.Timestamp.fromString(str.substring(1), radix).negate();
147 | } else if (str.indexOf('-') >= 0) {
148 | throw Error('number format error: interior "-" character: ' + str);
149 | }
150 |
151 | // Do several (8) digits each time through the loop, so as to
152 | // minimize the calls to the very expensive emulated div.
153 | var radixToPower = exports.Timestamp.fromNumber(Math.pow(radix, 8));
154 |
155 | var result = exports.Timestamp.ZERO;
156 | for (var i = 0; i < str.length; i += 8) {
157 | var size = Math.min(8, str.length - i);
158 | var value = parseInt(str.substring(i, i + size), radix);
159 | if (size < 8) {
160 | var power = exports.Timestamp.fromNumber(Math.pow(radix, size));
161 | result = result.multiply(power).add(exports.Timestamp.fromNumber(value));
162 | } else {
163 | result = result.multiply(radixToPower);
164 | result = result.add(exports.Timestamp.fromNumber(value));
165 | }
166 | }
167 | return result;
168 | };
169 |
170 |
171 | // NOTE: the compiler should inline these constant values below and then remove
172 | // these variables, so there should be no runtime penalty for these.
173 |
174 |
175 | /**
176 | * Number used repeated below in calculations. This must appear before the
177 | * first call to any from* function below.
178 | * @type {number}
179 | * @private
180 | */
181 | exports.Timestamp.TWO_PWR_16_DBL_ = 1 << 16;
182 |
183 | /**
184 | * @type {number}
185 | * @private
186 | */
187 | exports.Timestamp.TWO_PWR_24_DBL_ = 1 << 24;
188 |
189 | /**
190 | * @type {number}
191 | * @private
192 | */
193 | exports.Timestamp.TWO_PWR_32_DBL_ =
194 | exports.Timestamp.TWO_PWR_16_DBL_ * exports.Timestamp.TWO_PWR_16_DBL_;
195 |
196 | /**
197 | * @type {number}
198 | * @private
199 | */
200 | exports.Timestamp.TWO_PWR_31_DBL_ =
201 | exports.Timestamp.TWO_PWR_32_DBL_ / 2;
202 |
203 | /**
204 | * @type {number}
205 | * @private
206 | */
207 | exports.Timestamp.TWO_PWR_48_DBL_ =
208 | exports.Timestamp.TWO_PWR_32_DBL_ * exports.Timestamp.TWO_PWR_16_DBL_;
209 |
210 | /**
211 | * @type {number}
212 | * @private
213 | */
214 | exports.Timestamp.TWO_PWR_64_DBL_ =
215 | exports.Timestamp.TWO_PWR_32_DBL_ * exports.Timestamp.TWO_PWR_32_DBL_;
216 |
217 | /**
218 | * @type {number}
219 | * @private
220 | */
221 | exports.Timestamp.TWO_PWR_63_DBL_ =
222 | exports.Timestamp.TWO_PWR_64_DBL_ / 2;
223 |
224 |
225 | /** @type {exports.Timestamp} */
226 | exports.Timestamp.ZERO = exports.Timestamp.fromInt(0);
227 |
228 | /** @type {exports.Timestamp} */
229 | exports.Timestamp.ONE = exports.Timestamp.fromInt(1);
230 |
231 | /** @type {exports.Timestamp} */
232 | exports.Timestamp.NEG_ONE = exports.Timestamp.fromInt(-1);
233 |
234 | /** @type {exports.Timestamp} */
235 | exports.Timestamp.MAX_VALUE =
236 | exports.Timestamp.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
237 |
238 | /** @type {exports.Timestamp} */
239 | exports.Timestamp.MIN_VALUE = exports.Timestamp.fromBits(0, 0x80000000 | 0);
240 |
241 |
242 | /**
243 | * @type {exports.Timestamp}
244 | * @private
245 | */
246 | exports.Timestamp.TWO_PWR_24_ = exports.Timestamp.fromInt(1 << 24);
247 |
248 |
249 | /** @return {number} The value, assuming it is a 32-bit integer. */
250 | exports.Timestamp.prototype.toInt = function() {
251 | return this.low_;
252 | };
253 |
254 |
255 | /** @return {number} The closest floating-point representation to this value. */
256 | exports.Timestamp.prototype.toNumber = function() {
257 | return this.high_ * exports.Timestamp.TWO_PWR_32_DBL_ +
258 | this.getLowBitsUnsigned();
259 | };
260 |
261 | /** convert code to JSON **/
262 | exports.Timestamp.prototype.toJSON = function() {
263 | return this.toString();
264 | }
265 |
266 | /**
267 | * @param {number} opt_radix The radix in which the text should be written.
268 | * @return {string} The textual representation of this value.
269 | */
270 | exports.Timestamp.prototype.toString = function(opt_radix) {
271 | var radix = opt_radix || 10;
272 | if (radix < 2 || 36 < radix) {
273 | throw Error('radix out of range: ' + radix);
274 | }
275 |
276 | if (this.isZero()) {
277 | return '0';
278 | }
279 |
280 | if (this.isNegative()) {
281 | if (this.equals(exports.Timestamp.MIN_VALUE)) {
282 | // We need to change the exports.Timestamp value before it can be negated, so we remove
283 | // the bottom-most digit in this base and then recurse to do the rest.
284 | var radixTimestamp = exports.Timestamp.fromNumber(radix);
285 | var div = this.div(radixTimestamp);
286 | var rem = div.multiply(radixTimestamp).subtract(this);
287 | return div.toString(radix) + rem.toInt().toString(radix);
288 | } else {
289 | return '-' + this.negate().toString(radix);
290 | }
291 | }
292 |
293 | // Do several (6) digits each time through the loop, so as to
294 | // minimize the calls to the very expensive emulated div.
295 | var radixToPower = exports.Timestamp.fromNumber(Math.pow(radix, 6));
296 |
297 | var rem = this;
298 | var result = '';
299 | while (true) {
300 | var remDiv = rem.div(radixToPower);
301 | var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt();
302 | var digits = intval.toString(radix);
303 |
304 | rem = remDiv;
305 | if (rem.isZero()) {
306 | return digits + result;
307 | } else {
308 | while (digits.length < 6) {
309 | digits = '0' + digits;
310 | }
311 | result = '' + digits + result;
312 | }
313 | }
314 | };
315 |
316 |
317 | /** @return {number} The high 32-bits as a signed value. */
318 | exports.Timestamp.prototype.getHighBits = function() {
319 | return this.high_;
320 | };
321 |
322 |
323 | /** @return {number} The low 32-bits as a signed value. */
324 | exports.Timestamp.prototype.getLowBits = function() {
325 | return this.low_;
326 | };
327 |
328 |
329 | /** @return {number} The low 32-bits as an unsigned value. */
330 | exports.Timestamp.prototype.getLowBitsUnsigned = function() {
331 | return (this.low_ >= 0) ?
332 | this.low_ : exports.Timestamp.TWO_PWR_32_DBL_ + this.low_;
333 | };
334 |
335 |
336 | /**
337 | * @return {number} Returns the number of bits needed to represent the absolute
338 | * value of this exports.Timestamp.
339 | */
340 | exports.Timestamp.prototype.getNumBitsAbs = function() {
341 | if (this.isNegative()) {
342 | if (this.equals(exports.Timestamp.MIN_VALUE)) {
343 | return 64;
344 | } else {
345 | return this.negate().getNumBitsAbs();
346 | }
347 | } else {
348 | var val = this.high_ != 0 ? this.high_ : this.low_;
349 | for (var bit = 31; bit > 0; bit--) {
350 | if ((val & (1 << bit)) != 0) {
351 | break;
352 | }
353 | }
354 | return this.high_ != 0 ? bit + 33 : bit + 1;
355 | }
356 | };
357 |
358 |
359 | /** @return {boolean} Whether this value is zero. */
360 | exports.Timestamp.prototype.isZero = function() {
361 | return this.high_ == 0 && this.low_ == 0;
362 | };
363 |
364 |
365 | /** @return {boolean} Whether this value is negative. */
366 | exports.Timestamp.prototype.isNegative = function() {
367 | return this.high_ < 0;
368 | };
369 |
370 |
371 | /** @return {boolean} Whether this value is odd. */
372 | exports.Timestamp.prototype.isOdd = function() {
373 | return (this.low_ & 1) == 1;
374 | };
375 |
376 |
377 | /**
378 | * @param {exports.Timestamp} other exports.Timestamp to compare against.
379 | * @return {boolean} Whether this exports.Timestamp equals the other.
380 | */
381 | exports.Timestamp.prototype.equals = function(other) {
382 | return (this.high_ == other.high_) && (this.low_ == other.low_);
383 | };
384 |
385 |
386 | /**
387 | * @param {exports.Timestamp} other exports.Timestamp to compare against.
388 | * @return {boolean} Whether this exports.Timestamp does not equal the other.
389 | */
390 | exports.Timestamp.prototype.notEquals = function(other) {
391 | return (this.high_ != other.high_) || (this.low_ != other.low_);
392 | };
393 |
394 |
395 | /**
396 | * @param {exports.Timestamp} other exports.Timestamp to compare against.
397 | * @return {boolean} Whether this exports.Timestamp is less than the other.
398 | */
399 | exports.Timestamp.prototype.lessThan = function(other) {
400 | return this.compare(other) < 0;
401 | };
402 |
403 |
404 | /**
405 | * @param {exports.Timestamp} other exports.Timestamp to compare against.
406 | * @return {boolean} Whether this exports.Timestamp is less than or equal to the other.
407 | */
408 | exports.Timestamp.prototype.lessThanOrEqual = function(other) {
409 | return this.compare(other) <= 0;
410 | };
411 |
412 |
413 | /**
414 | * @param {exports.Timestamp} other exports.Timestamp to compare against.
415 | * @return {boolean} Whether this exports.Timestamp is greater than the other.
416 | */
417 | exports.Timestamp.prototype.greaterThan = function(other) {
418 | return this.compare(other) > 0;
419 | };
420 |
421 |
422 | /**
423 | * @param {exports.Timestamp} other exports.Timestamp to compare against.
424 | * @return {boolean} Whether this exports.Timestamp is greater than or equal to the other.
425 | */
426 | exports.Timestamp.prototype.greaterThanOrEqual = function(other) {
427 | return this.compare(other) >= 0;
428 | };
429 |
430 |
431 | /**
432 | * Compares this exports.Timestamp with the given one.
433 | * @param {exports.Timestamp} other exports.Timestamp to compare against.
434 | * @return {number} 0 if they are the same, 1 if the this is greater, and -1
435 | * if the given one is greater.
436 | */
437 | exports.Timestamp.prototype.compare = function(other) {
438 | if (this.equals(other)) {
439 | return 0;
440 | }
441 |
442 | var thisNeg = this.isNegative();
443 | var otherNeg = other.isNegative();
444 | if (thisNeg && !otherNeg) {
445 | return -1;
446 | }
447 | if (!thisNeg && otherNeg) {
448 | return 1;
449 | }
450 |
451 | // at this point, the signs are the same, so subtraction will not overflow
452 | if (this.subtract(other).isNegative()) {
453 | return -1;
454 | } else {
455 | return 1;
456 | }
457 | };
458 |
459 |
460 | /** @return {exports.Timestamp} The negation of this value. */
461 | exports.Timestamp.prototype.negate = function() {
462 | if (this.equals(exports.Timestamp.MIN_VALUE)) {
463 | return exports.Timestamp.MIN_VALUE;
464 | } else {
465 | return this.not().add(exports.Timestamp.ONE);
466 | }
467 | };
468 |
469 |
470 | /**
471 | * Returns the sum of this and the given exports.Timestamp.
472 | * @param {exports.Timestamp} other exports.Timestamp to add to this one.
473 | * @return {exports.Timestamp} The sum of this and the given exports.Timestamp.
474 | */
475 | exports.Timestamp.prototype.add = function(other) {
476 | // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
477 |
478 | var a48 = this.high_ >>> 16;
479 | var a32 = this.high_ & 0xFFFF;
480 | var a16 = this.low_ >>> 16;
481 | var a00 = this.low_ & 0xFFFF;
482 |
483 | var b48 = other.high_ >>> 16;
484 | var b32 = other.high_ & 0xFFFF;
485 | var b16 = other.low_ >>> 16;
486 | var b00 = other.low_ & 0xFFFF;
487 |
488 | var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
489 | c00 += a00 + b00;
490 | c16 += c00 >>> 16;
491 | c00 &= 0xFFFF;
492 | c16 += a16 + b16;
493 | c32 += c16 >>> 16;
494 | c16 &= 0xFFFF;
495 | c32 += a32 + b32;
496 | c48 += c32 >>> 16;
497 | c32 &= 0xFFFF;
498 | c48 += a48 + b48;
499 | c48 &= 0xFFFF;
500 | return exports.Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
501 | };
502 |
503 |
504 | /**
505 | * Returns the difference of this and the given exports.Timestamp.
506 | * @param {exports.Timestamp} other exports.Timestamp to subtract from this.
507 | * @return {exports.Timestamp} The difference of this and the given exports.Timestamp.
508 | */
509 | exports.Timestamp.prototype.subtract = function(other) {
510 | return this.add(other.negate());
511 | };
512 |
513 |
514 | /**
515 | * Returns the product of this and the given Timestamp.
516 | * @param {exports.Timestamp} other exports.Timestamp to multiply with this.
517 | * @return {exports.Timestamp} The product of this and the other.
518 | */
519 | exports.Timestamp.prototype.multiply = function(other) {
520 | if (this.isZero()) {
521 | return exports.Timestamp.ZERO;
522 | } else if (other.isZero()) {
523 | return exports.Timestamp.ZERO;
524 | }
525 |
526 | if (this.equals(exports.Timestamp.MIN_VALUE)) {
527 | return other.isOdd() ? exports.Timestamp.MIN_VALUE : exports.Timestamp.ZERO;
528 | } else if (other.equals(exports.Timestamp.MIN_VALUE)) {
529 | return this.isOdd() ? exports.Timestamp.MIN_VALUE : exports.Timestamp.ZERO;
530 | }
531 |
532 | if (this.isNegative()) {
533 | if (other.isNegative()) {
534 | return this.negate().multiply(other.negate());
535 | } else {
536 | return this.negate().multiply(other).negate();
537 | }
538 | } else if (other.isNegative()) {
539 | return this.multiply(other.negate()).negate();
540 | }
541 |
542 | // If both Timestamps are small, use float multiplication
543 | if (this.lessThan(exports.Timestamp.TWO_PWR_24_) &&
544 | other.lessThan(exports.Timestamp.TWO_PWR_24_)) {
545 | return exports.Timestamp.fromNumber(this.toNumber() * other.toNumber());
546 | }
547 |
548 | // Divide each Timestamp into 4 chunks of 16 bits, and then add up 4x4 products.
549 | // We can skip products that would overflow.
550 |
551 | var a48 = this.high_ >>> 16;
552 | var a32 = this.high_ & 0xFFFF;
553 | var a16 = this.low_ >>> 16;
554 | var a00 = this.low_ & 0xFFFF;
555 |
556 | var b48 = other.high_ >>> 16;
557 | var b32 = other.high_ & 0xFFFF;
558 | var b16 = other.low_ >>> 16;
559 | var b00 = other.low_ & 0xFFFF;
560 |
561 | var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
562 | c00 += a00 * b00;
563 | c16 += c00 >>> 16;
564 | c00 &= 0xFFFF;
565 | c16 += a16 * b00;
566 | c32 += c16 >>> 16;
567 | c16 &= 0xFFFF;
568 | c16 += a00 * b16;
569 | c32 += c16 >>> 16;
570 | c16 &= 0xFFFF;
571 | c32 += a32 * b00;
572 | c48 += c32 >>> 16;
573 | c32 &= 0xFFFF;
574 | c32 += a16 * b16;
575 | c48 += c32 >>> 16;
576 | c32 &= 0xFFFF;
577 | c32 += a00 * b32;
578 | c48 += c32 >>> 16;
579 | c32 &= 0xFFFF;
580 | c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
581 | c48 &= 0xFFFF;
582 | return exports.Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
583 | };
584 |
585 |
586 | /**
587 | * Returns this exports.Timestamp divided by the given one.
588 | * @param {exports.Timestamp} other exports.Timestamp by which to divide.
589 | * @return {exports.Timestamp} This exports.Timestamp divided by the given one.
590 | */
591 | exports.Timestamp.prototype.div = function(other) {
592 | if (other.isZero()) {
593 | throw Error('division by zero');
594 | } else if (this.isZero()) {
595 | return exports.Timestamp.ZERO;
596 | }
597 |
598 | if (this.equals(exports.Timestamp.MIN_VALUE)) {
599 | if (other.equals(exports.Timestamp.ONE) ||
600 | other.equals(exports.Timestamp.NEG_ONE)) {
601 | return exports.Timestamp.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
602 | } else if (other.equals(exports.Timestamp.MIN_VALUE)) {
603 | return exports.Timestamp.ONE;
604 | } else {
605 | // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
606 | var halfThis = this.shiftRight(1);
607 | var approx = halfThis.div(other).shiftLeft(1);
608 | if (approx.equals(exports.Timestamp.ZERO)) {
609 | return other.isNegative() ? exports.Timestamp.ONE : exports.Timestamp.NEG_ONE;
610 | } else {
611 | var rem = this.subtract(other.multiply(approx));
612 | var result = approx.add(rem.div(other));
613 | return result;
614 | }
615 | }
616 | } else if (other.equals(exports.Timestamp.MIN_VALUE)) {
617 | return exports.Timestamp.ZERO;
618 | }
619 |
620 | if (this.isNegative()) {
621 | if (other.isNegative()) {
622 | return this.negate().div(other.negate());
623 | } else {
624 | return this.negate().div(other).negate();
625 | }
626 | } else if (other.isNegative()) {
627 | return this.div(other.negate()).negate();
628 | }
629 |
630 | // Repeat the following until the remainder is less than other: find a
631 | // floating-point that approximates remainder / other *from below*, add this
632 | // into the result, and subtract it from the remainder. It is critical that
633 | // the approximate value is less than or equal to the real value so that the
634 | // remainder never becomes negative.
635 | var res = exports.Timestamp.ZERO;
636 | var rem = this;
637 | while (rem.greaterThanOrEqual(other)) {
638 | // Approximate the result of division. This may be a little greater or
639 | // smaller than the actual value.
640 | var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
641 |
642 | // We will tweak the approximate result by changing it in the 48-th digit or
643 | // the smallest non-fractional digit, whichever is larger.
644 | var log2 = Math.ceil(Math.log(approx) / Math.LN2);
645 | var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
646 |
647 | // Decrease the approximation until it is smaller than the remainder. Note
648 | // that if it is too large, the product overflows and is negative.
649 | var approxRes = exports.Timestamp.fromNumber(approx);
650 | var approxRem = approxRes.multiply(other);
651 | while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
652 | approx -= delta;
653 | approxRes = exports.Timestamp.fromNumber(approx);
654 | approxRem = approxRes.multiply(other);
655 | }
656 |
657 | // We know the answer can't be zero... and actually, zero would cause
658 | // infinite recursion since we would make no progress.
659 | if (approxRes.isZero()) {
660 | approxRes = exports.Timestamp.ONE;
661 | }
662 |
663 | res = res.add(approxRes);
664 | rem = rem.subtract(approxRem);
665 | }
666 | return res;
667 | };
668 |
669 |
670 | /**
671 | * Returns this exports.Timestamp modulo the given one.
672 | * @param {exports.Timestamp} other exports.Timestamp by which to mod.
673 | * @return {exports.Timestamp} This exports.Timestamp modulo the given one.
674 | */
675 | exports.Timestamp.prototype.modulo = function(other) {
676 | return this.subtract(this.div(other).multiply(other));
677 | };
678 |
679 |
680 | /** @return {exports.Timestamp} The bitwise-NOT of this value. */
681 | exports.Timestamp.prototype.not = function() {
682 | return exports.Timestamp.fromBits(~this.low_, ~this.high_);
683 | };
684 |
685 |
686 | /**
687 | * Returns the bitwise-AND of this exports.Timestamp and the given one.
688 | * @param {exports.Timestamp} other The exports.Timestamp with which to AND.
689 | * @return {exports.Timestamp} The bitwise-AND of this and the other.
690 | */
691 | exports.Timestamp.prototype.and = function(other) {
692 | return exports.Timestamp.fromBits(this.low_ & other.low_,
693 | this.high_ & other.high_);
694 | };
695 |
696 |
697 | /**
698 | * Returns the bitwise-OR of this exports.Timestamp and the given one.
699 | * @param {exports.Timestamp} other The exports.Timestamp with which to OR.
700 | * @return {exports.Timestamp} The bitwise-OR of this and the other.
701 | */
702 | exports.Timestamp.prototype.or = function(other) {
703 | return exports.Timestamp.fromBits(this.low_ | other.low_,
704 | this.high_ | other.high_);
705 | };
706 |
707 |
708 | /**
709 | * Returns the bitwise-XOR of this exports.Timestamp and the given one.
710 | * @param {exports.Timestamp} other The exports.Timestamp with which to XOR.
711 | * @return {exports.Timestamp} The bitwise-XOR of this and the other.
712 | */
713 | exports.Timestamp.prototype.xor = function(other) {
714 | return exports.Timestamp.fromBits(this.low_ ^ other.low_,
715 | this.high_ ^ other.high_);
716 | };
717 |
718 |
719 | /**
720 | * Returns this exports.Timestamp with bits shifted to the left by the given amount.
721 | * @param {number} numBits The number of bits by which to shift.
722 | * @return {exports.Timestamp} This shifted to the left by the given amount.
723 | */
724 | exports.Timestamp.prototype.shiftLeft = function(numBits) {
725 | numBits &= 63;
726 | if (numBits == 0) {
727 | return this;
728 | } else {
729 | var low = this.low_;
730 | if (numBits < 32) {
731 | var high = this.high_;
732 | return exports.Timestamp.fromBits(
733 | low << numBits,
734 | (high << numBits) | (low >>> (32 - numBits)));
735 | } else {
736 | return exports.Timestamp.fromBits(0, low << (numBits - 32));
737 | }
738 | }
739 | };
740 |
741 |
742 | /**
743 | * Returns this exports.Timestamp with bits shifted to the right by the given amount.
744 | * @param {number} numBits The number of bits by which to shift.
745 | * @return {exports.Timestamp} This shifted to the right by the given amount.
746 | */
747 | exports.Timestamp.prototype.shiftRight = function(numBits) {
748 | numBits &= 63;
749 | if (numBits == 0) {
750 | return this;
751 | } else {
752 | var high = this.high_;
753 | if (numBits < 32) {
754 | var low = this.low_;
755 | return exports.Timestamp.fromBits(
756 | (low >>> numBits) | (high << (32 - numBits)),
757 | high >> numBits);
758 | } else {
759 | return exports.Timestamp.fromBits(
760 | high >> (numBits - 32),
761 | high >= 0 ? 0 : -1);
762 | }
763 | }
764 | };
765 |
766 |
767 | /**
768 | * Returns this exports.Timestamp with bits shifted to the right by the given amount, with
769 | * the new top bits matching the current sign bit.
770 | * @param {number} numBits The number of bits by which to shift.
771 | * @return {exports.Timestamp} This shifted to the right by the given amount, with
772 | * zeros placed into the new leading bits.
773 | */
774 | exports.Timestamp.prototype.shiftRightUnsigned = function(numBits) {
775 | numBits &= 63;
776 | if (numBits == 0) {
777 | return this;
778 | } else {
779 | var high = this.high_;
780 | if (numBits < 32) {
781 | var low = this.low_;
782 | return exports.Timestamp.fromBits(
783 | (low >>> numBits) | (high << (32 - numBits)),
784 | high >>> numBits);
785 | } else if (numBits == 32) {
786 | return exports.Timestamp.fromBits(high, 0);
787 | } else {
788 | return exports.Timestamp.fromBits(high >>> (numBits - 32), 0);
789 | }
790 | }
791 | };
--------------------------------------------------------------------------------
/cmds.js:
--------------------------------------------------------------------------------
1 | var BinaryParser = require('./bson/binary_parser').BinaryParser;
2 | var BSON = require('./bson/bson').BSON;
3 | var OrderedHash = require('./bson/collections').OrderedHash;
4 |
5 | /**
6 | Base object used for common functionality
7 | **/
8 | var Commands = exports.Commands = function() {
9 | return this.Commands
10 | };
11 |
12 | insert = function(c) {
13 | var command_string = '';
14 | c.checkKeys = c.checkKeys == null ? true : c.checkKeys;
15 | for(var i = 0; i < c.documents.length; i++) {
16 | command_string = command_string + BSON.serialize(c.documents[i], c.checkKeys);
17 | }
18 | // Build the command string
19 | return BinaryParser.fromInt(0) + BinaryParser.encode_cstring(c.collectionName) + command_string;
20 | };
21 |
22 | more = function(c) {
23 | // Generate the command string
24 | return BinaryParser.fromInt(0) + BinaryParser.encode_cstring(c.collectionName) + BinaryParser.fromInt(c.numberToReturn) + BSON.encodeLong(c.cursorID);
25 | };
26 |
27 | kill = function(c) {
28 | // Generate the command string
29 | var command_string = BinaryParser.fromInt(0) + BinaryParser.fromInt(c.cursorIds.length);
30 | c.cursorIds.forEach(function(cursorId) {
31 | command_string = command_string + BSON.encodeLong(cursorId);
32 | });
33 | return command_string;
34 | };
35 |
36 | update = function(c) {
37 | // Generate the command string
38 | var command_string = BinaryParser.fromInt(0) + BinaryParser.encode_cstring(c.collectionName);
39 | return command_string + BinaryParser.fromInt(c.flags) + BSON.serialize(c.spec) + BSON.serialize(c.document, false);
40 | };
41 |
42 | remove = function(c) {
43 | // Generate the command string
44 | var command_string = BinaryParser.fromInt(0) + BinaryParser.encode_cstring(c.collectionName);
45 | return command_string + BinaryParser.fromInt(c.flags) + BSON.serialize(c.spec);
46 | };
47 |
48 | query = function(c) {
49 | // Generate the command string
50 | var command_string = BinaryParser.fromInt(c.queryOptions) + BinaryParser.encode_cstring(c.collectionName);
51 | command_string = command_string + BinaryParser.fromInt(c.numberToSkip) + BinaryParser.fromInt(c.numberToReturn);
52 | command_string = command_string + BSON.serialize(c.query);
53 | if(c.returnFieldSelector != null) {
54 | // && (c.returnFieldSelector != {} ||)
55 | if(c.returnFieldSelector instanceof OrderedHash && c.returnFieldSelector.length > 0) {
56 | command_string = command_string + BSON.serialize(c.returnFieldSelector);
57 | } else if(c.returnFieldSelector.constructor == Object) {
58 | var count = 0; for(var name in c.returnFieldSelector) { count += 1; }
59 | if(count > 0) command_string = command_string + BSON.serialize(c.returnFieldSelector);
60 | }
61 | }
62 | return command_string;
63 | };
64 |
65 | Commands.binary = function(cmd, op, id) {
66 | // Get the command data structure
67 | var command = '';
68 | switch(op) {
69 | case 2001:
70 | command = update(cmd);
71 | break;
72 | case 2002:
73 | command = insert(cmd);
74 | break;
75 | case 2004:
76 | command = query(cmd);
77 | break;
78 | case 2005:
79 | command = more(cmd);
80 | break;
81 | case 2006:
82 | command = remove(cmd);
83 | break;
84 | case 2007:
85 | command = kill(cmd);
86 | break;
87 | }
88 | // Total Size of command
89 | var totalSize = 4*4 + command.length;
90 | // Create the command with the standard header file
91 | //var hd = BinaryParser.fromInt(totalSize) + BinaryParser.fromInt(id) + BinaryParser.fromInt(0) + BinaryParser.fromInt(op);
92 | //var s = hd + command;
93 | //console.log(s.toString());
94 | return BinaryParser.fromInt(totalSize) + BinaryParser.fromInt(id) + BinaryParser.fromInt(0) + BinaryParser.fromInt(op) + command;
95 | };
96 |
97 | // OpCodes
98 | Commands.OP_REPLY = 1;
99 | Commands.OP_MSG = 1000;
100 | Commands.OP_UPDATE = 2001;
101 | Commands.OP_INSERT = 2002;
102 | Commands.OP_GET_BY_OID = 2003;
103 | Commands.OP_QUERY = 2004;
104 | Commands.OP_GET_MORE = 2005;
105 | Commands.OP_DELETE = 2006;
106 | Commands.OP_KILL_CURSORS = 2007;
107 | Commands.documents = [];
108 |
--------------------------------------------------------------------------------
/commands.js:
--------------------------------------------------------------------------------
1 | var BinaryParser = require('./bson/binary_parser').BinaryParser;
2 | var BSON = require('./bson/bson').BSON;
3 | var OrderedHash = require('./bson/collections').OrderedHash;
4 |
5 | /**
6 | Base object used for common functionality
7 | **/
8 | var Commands = exports.Commands = function() {
9 | return (this).Commands
10 | };
11 |
12 | insert = function(c) {
13 | // Calculate total length of the document
14 | var totalLengthOfCommand = 4 + Buffer.byteLength(c.collectionName) + 1 + (4 * 4);
15 | // var docLength = 0
16 | for(var i = 0; i < c.documents.length; i++) {
17 | // Calculate size of document
18 | totalLengthOfCommand += BSON.calculateObjectSize(c.documents[i]);
19 | }
20 |
21 | // Let's build the single pass buffer command
22 | var _index = 0;
23 | var _command = new Buffer(totalLengthOfCommand);
24 | // Write the header information to the buffer
25 | _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
26 | _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
27 | _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
28 | _command[_index] = totalLengthOfCommand & 0xff;
29 | // Adjust index
30 | _index = _index + 4;
31 | // Write the request ID
32 | _command[_index + 3] = (c.requestId >> 24) & 0xff;
33 | _command[_index + 2] = (c.requestId >> 16) & 0xff;
34 | _command[_index + 1] = (c.requestId >> 8) & 0xff;
35 | _command[_index] = c.requestId & 0xff;
36 | // Adjust index
37 | _index = _index + 4;
38 | // Write zero
39 | _command[_index++] = 0;
40 | _command[_index++] = 0;
41 | _command[_index++] = 0;
42 | _command[_index++] = 0;
43 | // Write the op_code for the command
44 | _command[_index + 3] = (Commands.OP_INSERT >> 24) & 0xff;
45 | _command[_index + 2] = (Commands.OP_INSERT >> 16) & 0xff;
46 | _command[_index + 1] = (Commands.OP_INSERT >> 8) & 0xff;
47 | _command[_index] = Commands.OP_INSERT & 0xff;
48 | // Adjust index
49 | _index = _index + 4;
50 | // Write zero
51 | _command[_index++] = 0;
52 | _command[_index++] = 0;
53 | _command[_index++] = 0;
54 | _command[_index++] = 0;
55 | // Write the collection name to the command
56 | _index = _index + _command.write(c.collectionName, _index, 'utf8') + 1;
57 | _command[_index - 1] = 0;
58 |
59 | // Write all the bson documents to the buffer at the index offset
60 | for(var i = 0; i < c.documents.length; i++) {
61 | // Serialize the document straight to the buffer
62 | var documentLength = BSON.serializeWithBufferAndIndex(c.documents[i], c.checkKeys, _command, _index) - _index + 1;
63 | // Write the length to the document
64 | _command[_index + 3] = (documentLength >> 24) & 0xff;
65 | _command[_index + 2] = (documentLength >> 16) & 0xff;
66 | _command[_index + 1] = (documentLength >> 8) & 0xff;
67 | _command[_index] = documentLength & 0xff;
68 | // Update index in buffer
69 | _index = _index + documentLength;
70 | // Add terminating 0 for the object
71 | _command[_index - 1] = 0;
72 | }
73 |
74 | return _command;
75 | };
76 |
77 | more = function(c) {
78 | // debug("======================================================= GETMORE")
79 | // debug("================ " + BSON.calculateObjectSize(c.query))
80 | // Calculate total length of the document
81 | var totalLengthOfCommand = 4 + Buffer.byteLength(c.collectionName) + 1 + 4 + 8 + (4 * 4);
82 | // Let's build the single pass buffer command
83 | var _index = 0;
84 | var _command = new Buffer(totalLengthOfCommand);
85 | // Write the header information to the buffer
86 | _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
87 | _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
88 | _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
89 | _command[_index] = totalLengthOfCommand & 0xff;
90 | // Adjust index
91 | _index = _index + 4;
92 | // Write the request ID
93 | _command[_index + 3] = (c.requestId >> 24) & 0xff;
94 | _command[_index + 2] = (c.requestId >> 16) & 0xff;
95 | _command[_index + 1] = (c.requestId >> 8) & 0xff;
96 | _command[_index] = c.requestId & 0xff;
97 | // Adjust index
98 | _index = _index + 4;
99 | // Write zero
100 | _command[_index++] = 0;
101 | _command[_index++] = 0;
102 | _command[_index++] = 0;
103 | _command[_index++] = 0;
104 | // Write the op_code for the command
105 | _command[_index + 3] = (Commands.OP_GET_MORE >> 24) & 0xff;
106 | _command[_index + 2] = (Commands.OP_GET_MORE >> 16) & 0xff;
107 | _command[_index + 1] = (Commands.OP_GET_MORE >> 8) & 0xff;
108 | _command[_index] = Commands.OP_GET_MORE & 0xff;
109 | // Adjust index
110 | _index = _index + 4;
111 |
112 | // Write zero
113 | _command[_index++] = 0;
114 | _command[_index++] = 0;
115 | _command[_index++] = 0;
116 | _command[_index++] = 0;
117 |
118 | // Write the collection name to the command
119 | _index = _index + _command.write(c.collectionName, _index, 'utf8') + 1;
120 | _command[_index - 1] = 0;
121 |
122 | // Number of documents to return
123 | _command[_index + 3] = (c.numberToReturn >> 24) & 0xff;
124 | _command[_index + 2] = (c.numberToReturn >> 16) & 0xff;
125 | _command[_index + 1] = (c.numberToReturn >> 8) & 0xff;
126 | _command[_index] = c.numberToReturn & 0xff;
127 | // Adjust index
128 | _index = _index + 4;
129 |
130 | // Encode the cursor id
131 | var low_bits = c.cursorID.getLowBits();
132 | // Encode low bits
133 | _command[_index + 3] = (low_bits >> 24) & 0xff;
134 | _command[_index + 2] = (low_bits >> 16) & 0xff;
135 | _command[_index + 1] = (low_bits >> 8) & 0xff;
136 | _command[_index] = low_bits & 0xff;
137 | // Adjust index
138 | _index = _index + 4;
139 |
140 | var high_bits = c.cursorID.getHighBits();
141 | // Encode high bits
142 | _command[_index + 3] = (high_bits >> 24) & 0xff;
143 | _command[_index + 2] = (high_bits >> 16) & 0xff;
144 | _command[_index + 1] = (high_bits >> 8) & 0xff;
145 | _command[_index] = high_bits & 0xff;
146 | // Adjust index
147 | _index = _index + 4;
148 |
149 | return _command;
150 | };
151 |
152 | kill = function(c) {
153 | // Calculate total length of the document
154 | var totalLengthOfCommand = 4 + 4 + (4 * 4) + (c.cursorIDs.length * 8);
155 | // Let's build the single pass buffer command
156 | var _index = 0;
157 | var _command = new Buffer(totalLengthOfCommand);
158 | // Write the header information to the buffer
159 | _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
160 | _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
161 | _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
162 | _command[_index] = totalLengthOfCommand & 0xff;
163 | // Adjust index
164 | _index = _index + 4;
165 | // Write the request ID
166 | _command[_index + 3] = (c.requestId >> 24) & 0xff;
167 | _command[_index + 2] = (c.requestId >> 16) & 0xff;
168 | _command[_index + 1] = (c.requestId >> 8) & 0xff;
169 | _command[_index] = c.requestId & 0xff;
170 | // Adjust index
171 | _index = _index + 4;
172 | // Write zero
173 | _command[_index++] = 0;
174 | _command[_index++] = 0;
175 | _command[_index++] = 0;
176 | _command[_index++] = 0;
177 | // Write the op_code for the command
178 | _command[_index + 3] = (Commands.OP_KILL_CURSORS >> 24) & 0xff;
179 | _command[_index + 2] = (Commands.OP_KILL_CURSORS >> 16) & 0xff;
180 | _command[_index + 1] = (Commands.OP_KILL_CURSORS >> 8) & 0xff;
181 | _command[_index] = Commands.OP_KILL_CURSORS & 0xff;
182 | // Adjust index
183 | _index = _index + 4;
184 |
185 | // Write zero
186 | _command[_index++] = 0;
187 | _command[_index++] = 0;
188 | _command[_index++] = 0;
189 | _command[_index++] = 0;
190 |
191 | // Number of cursors to kill
192 | var numberOfCursors = c.cursorIDs.length;
193 | _command[_index + 3] = (numberOfCursors >> 24) & 0xff;
194 | _command[_index + 2] = (numberOfCursors >> 16) & 0xff;
195 | _command[_index + 1] = (numberOfCursors >> 8) & 0xff;
196 | _command[_index] = numberOfCursors & 0xff;
197 | // Adjust index
198 | _index = _index + 4;
199 |
200 | // Encode all the cursors
201 | for(var i = 0; i < c.cursorIDs.length; i++) {
202 | // Encode the cursor id
203 | var low_bits = c.cursorIDs[i].getLowBits();
204 | // Encode low bits
205 | _command[_index + 3] = (low_bits >> 24) & 0xff;
206 | _command[_index + 2] = (low_bits >> 16) & 0xff;
207 | _command[_index + 1] = (low_bits >> 8) & 0xff;
208 | _command[_index] = low_bits & 0xff;
209 | // Adjust index
210 | _index = _index + 4;
211 |
212 | var high_bits = c.cursorIDs[i].getHighBits();
213 | // Encode high bits
214 | _command[_index + 3] = (high_bits >> 24) & 0xff;
215 | _command[_index + 2] = (high_bits >> 16) & 0xff;
216 | _command[_index + 1] = (high_bits >> 8) & 0xff;
217 | _command[_index] = high_bits & 0xff;
218 | // Adjust index
219 | _index = _index + 4;
220 | }
221 |
222 | return _command;
223 | };
224 |
225 | update = function(c) {
226 | // Calculate total length of the document
227 | var totalLengthOfCommand = 4 + Buffer.byteLength(c.collectionName) + 1 + 4 + BSON.calculateObjectSize(c.spec) +
228 | BSON.calculateObjectSize(c.document) + (4 * 4);
229 |
230 | // Let's build the single pass buffer command
231 | var _index = 0;
232 | var _command = new Buffer(totalLengthOfCommand);
233 | // Write the header information to the buffer
234 | _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
235 | _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
236 | _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
237 | _command[_index] = totalLengthOfCommand & 0xff;
238 | // Adjust index
239 | _index = _index + 4;
240 | // Write the request ID
241 | _command[_index + 3] = (c.requestId >> 24) & 0xff;
242 | _command[_index + 2] = (c.requestId >> 16) & 0xff;
243 | _command[_index + 1] = (c.requestId >> 8) & 0xff;
244 | _command[_index] = c.requestId & 0xff;
245 | // Adjust index
246 | _index = _index + 4;
247 | // Write zero
248 | _command[_index++] = 0;
249 | _command[_index++] = 0;
250 | _command[_index++] = 0;
251 | _command[_index++] = 0;
252 | // Write the op_code for the command
253 | _command[_index + 3] = (Commands.OP_UPDATE >> 24) & 0xff;
254 | _command[_index + 2] = (Commands.OP_UPDATE >> 16) & 0xff;
255 | _command[_index + 1] = (Commands.OP_UPDATE >> 8) & 0xff;
256 | _command[_index] = Commands.OP_UPDATE & 0xff;
257 | // Adjust index
258 | _index = _index + 4;
259 |
260 | // Write zero
261 | _command[_index++] = 0;
262 | _command[_index++] = 0;
263 | _command[_index++] = 0;
264 | _command[_index++] = 0;
265 |
266 | // Write the collection name to the command
267 | _index = _index + _command.write(c.collectionName, _index, 'utf8') + 1;
268 | _command[_index - 1] = 0;
269 |
270 | // Write the update flags
271 | _command[_index + 3] = (c.flags >> 24) & 0xff;
272 | _command[_index + 2] = (c.flags >> 16) & 0xff;
273 | _command[_index + 1] = (c.flags >> 8) & 0xff;
274 | _command[_index] = c.flags & 0xff;
275 | // Adjust index
276 | _index = _index + 4;
277 |
278 | // Serialize the spec document
279 | var documentLength = BSON.serializeWithBufferAndIndex(c.spec, c.checkKeys, _command, _index) - _index + 1;
280 | // Write the length to the document
281 | _command[_index + 3] = (documentLength >> 24) & 0xff;
282 | _command[_index + 2] = (documentLength >> 16) & 0xff;
283 | _command[_index + 1] = (documentLength >> 8) & 0xff;
284 | _command[_index] = documentLength & 0xff;
285 | // Update index in buffer
286 | _index = _index + documentLength;
287 | // Add terminating 0 for the object
288 | _command[_index - 1] = 0;
289 |
290 | // Serialize the document
291 | var documentLength = BSON.serializeWithBufferAndIndex(c.document, c.checkKeys, _command, _index) - _index + 1;
292 | // Write the length to the document
293 | _command[_index + 3] = (documentLength >> 24) & 0xff;
294 | _command[_index + 2] = (documentLength >> 16) & 0xff;
295 | _command[_index + 1] = (documentLength >> 8) & 0xff;
296 | _command[_index] = documentLength & 0xff;
297 | // Update index in buffer
298 | _index = _index + documentLength;
299 | // Add terminating 0 for the object
300 | _command[_index - 1] = 0;
301 |
302 | return _command;
303 | };
304 |
305 | remove = function(c) {
306 | // Calculate total length of the document
307 | var totalLengthOfCommand = 4 + Buffer.byteLength(c.collectionName) + 1 + 4 + BSON.calculateObjectSize(c.spec||c.selector) + (4 * 4);
308 | // Let's build the single pass buffer command
309 | var _index = 0;
310 | var _command = new Buffer(totalLengthOfCommand);
311 | // Write the header information to the buffer
312 | _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
313 | _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
314 | _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
315 | _command[_index] = totalLengthOfCommand & 0xff;
316 | // Adjust index
317 | _index = _index + 4;
318 | // Write the request ID
319 | _command[_index + 3] = (c.requestId >> 24) & 0xff;
320 | _command[_index + 2] = (c.requestId >> 16) & 0xff;
321 | _command[_index + 1] = (c.requestId >> 8) & 0xff;
322 | _command[_index] = c.requestId & 0xff;
323 | // Adjust index
324 | _index = _index + 4;
325 | // Write zero
326 | _command[_index++] = 0;
327 | _command[_index++] = 0;
328 | _command[_index++] = 0;
329 | _command[_index++] = 0;
330 | // Write the op_code for the command
331 | _command[_index + 3] = (Commands.OP_DELETE >> 24) & 0xff;
332 | _command[_index + 2] = (Commands.OP_DELETE >> 16) & 0xff;
333 | _command[_index + 1] = (Commands.OP_DELETE >> 8) & 0xff;
334 | _command[_index] = Commands.OP_DELETE & 0xff;
335 | // Adjust index
336 | _index = _index + 4;
337 |
338 | // Write zero
339 | _command[_index++] = 0;
340 | _command[_index++] = 0;
341 | _command[_index++] = 0;
342 | _command[_index++] = 0;
343 |
344 | // Write the collection name to the command
345 | _index = _index + _command.write(c.collectionName, _index, 'utf8') + 1;
346 | _command[_index - 1] = 0;
347 |
348 | // Write zero
349 | _command[_index++] = 0;
350 | _command[_index++] = 0;
351 | _command[_index++] = 0;
352 | _command[_index++] = 0;
353 |
354 | // Serialize the selector
355 | var documentLength = BSON.serializeWithBufferAndIndex(c.spec||c.selector, c.checkKeys, _command, _index) - _index + 1;
356 | // Write the length to the document
357 | _command[_index + 3] = (documentLength >> 24) & 0xff;
358 | _command[_index + 2] = (documentLength >> 16) & 0xff;
359 | _command[_index + 1] = (documentLength >> 8) & 0xff;
360 | _command[_index] = documentLength & 0xff;
361 | // Update index in buffer
362 | _index = _index + documentLength;
363 | // Add terminating 0 for the object
364 | _command[_index - 1] = 0;
365 | return _command;
366 | };
367 |
368 | query = function(c) {
369 | // debug("======================================================= QUERY")
370 | // debug("================ " + BSON.calculateObjectSize(c.query))
371 |
372 | // Calculate total length of the document
373 | var totalLengthOfCommand = 4 + Buffer.byteLength(c.collectionName) + 1 + 4 + 4 + BSON.calculateObjectSize(c.query) + (4 * 4);
374 | // Calculate extra fields size
375 | if(c.returnFieldSelector != null) {
376 | if(Object.keys(c.returnFieldSelector).length > 0) {
377 | totalLengthOfCommand += BSON.calculateObjectSize(c.returnFieldSelector);
378 | }
379 | }
380 |
381 | // Let's build the single pass buffer command
382 | var _index = 0;
383 | var _command = new Buffer(totalLengthOfCommand);
384 | // Write the header information to the buffer
385 | _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
386 | _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
387 | _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
388 | _command[_index] = totalLengthOfCommand & 0xff;
389 | // Adjust index
390 | _index = _index + 4;
391 | // Write the request ID
392 | _command[_index + 3] = (c.requestId >> 24) & 0xff;
393 | _command[_index + 2] = (c.requestId >> 16) & 0xff;
394 | _command[_index + 1] = (c.requestId >> 8) & 0xff;
395 | _command[_index] = c.requestId & 0xff;
396 | // Adjust index
397 | _index = _index + 4;
398 | // Write zero
399 | _command[_index++] = 0;
400 | _command[_index++] = 0;
401 | _command[_index++] = 0;
402 | _command[_index++] = 0;
403 | // Write the op_code for the command
404 | _command[_index + 3] = (Commands.OP_QUERY >> 24) & 0xff;
405 | _command[_index + 2] = (Commands.OP_QUERY >> 16) & 0xff;
406 | _command[_index + 1] = (Commands.OP_QUERY >> 8) & 0xff;
407 | _command[_index] = Commands.OP_QUERY & 0xff;
408 | // Adjust index
409 | _index = _index + 4;
410 |
411 | // Write the query options
412 | _command[_index + 3] = (c.queryOptions >> 24) & 0xff;
413 | _command[_index + 2] = (c.queryOptions >> 16) & 0xff;
414 | _command[_index + 1] = (c.queryOptions >> 8) & 0xff;
415 | _command[_index] = c.queryOptions & 0xff;
416 | // Adjust index
417 | _index = _index + 4;
418 |
419 | // Write the collection name to the command
420 | _index = _index + _command.write(c.collectionName, _index, 'utf8') + 1;
421 | _command[_index - 1] = 0;
422 |
423 | // Write the number of documents to skip
424 | _command[_index + 3] = (c.numberToSkip >> 24) & 0xff;
425 | _command[_index + 2] = (c.numberToSkip >> 16) & 0xff;
426 | _command[_index + 1] = (c.numberToSkip >> 8) & 0xff;
427 | _command[_index] = c.numberToSkip & 0xff;
428 | // Adjust index
429 | _index = _index + 4;
430 |
431 | // Write the number of documents to return
432 | _command[_index + 3] = (c.numberToReturn >> 24) & 0xff;
433 | _command[_index + 2] = (c.numberToReturn >> 16) & 0xff;
434 | _command[_index + 1] = (c.numberToReturn >> 8) & 0xff;
435 | _command[_index] = c.numberToReturn & 0xff;
436 | // Adjust index
437 | _index = _index + 4;
438 |
439 | // Serialize the query document straight to the buffer
440 | var documentLength = BSON.serializeWithBufferAndIndex(c.query, c.checkKeys, _command, _index) - _index + 1;
441 | // debug(inspect("===================== documentLength :: " + documentLength))
442 |
443 | // Write the length to the document
444 | _command[_index + 3] = (documentLength >> 24) & 0xff;
445 | _command[_index + 2] = (documentLength >> 16) & 0xff;
446 | _command[_index + 1] = (documentLength >> 8) & 0xff;
447 | _command[_index] = documentLength & 0xff;
448 | // Update index in buffer
449 | _index = _index + documentLength;
450 | // Add terminating 0 for the object
451 | _command[_index - 1] = 0;
452 |
453 | // Push field selector if available
454 | if(c.returnFieldSelector != null) {
455 | if(Object.keys(c.returnFieldSelector).length > 0) {
456 | var documentLength = BSON.serializeWithBufferAndIndex(c.returnFieldSelector, c.checkKeys, _command, _index) - _index + 1;
457 | // Write the length to the document
458 | _command[_index + 3] = (documentLength >> 24) & 0xff;
459 | _command[_index + 2] = (documentLength >> 16) & 0xff;
460 | _command[_index + 1] = (documentLength >> 8) & 0xff;
461 | _command[_index] = documentLength & 0xff;
462 | // Update index in buffer
463 | _index = _index + documentLength;
464 | // Add terminating 0 for the object
465 | _command[_index - 1] = 0;
466 | }
467 | }
468 |
469 | // debug("------------------------------------------------------------------------")
470 | // debug(inspect(_command))
471 |
472 | return _command;
473 | };
474 |
475 | Commands.binary = function(cmd, op, id) {
476 | // Get the command data structure
477 | cmd.requestId = id;
478 | cmd.checkKeys = cmd.checkKeys == null ? true : cmd.checkKeys;
479 | var command = '';
480 | switch(op) {
481 | case 2001:
482 | command = update(cmd);
483 | return command;
484 | break;
485 | case 2002:
486 | command = insert(cmd);
487 | return command;
488 | break;
489 | case 2004:
490 | command = query(cmd);
491 | return command;
492 | break;
493 | case 2005:
494 | command = more(cmd);
495 | return command;
496 | break;
497 | case 2006:
498 | command = remove(cmd);
499 | return command;
500 | break;
501 | case 2007:
502 | command = kill(cmd);
503 | return command;
504 | break;
505 | }
506 | // Total Size of command
507 | var totalSize = 4*4 + command.length;
508 | // Create the command with the standard header file
509 | //var hd = BinaryParser.fromInt(totalSize) + BinaryParser.fromInt(id) + BinaryParser.fromInt(0) + BinaryParser.fromInt(op);
510 | //var s = hd + command;
511 | //console.log(s.toString());
512 | return BinaryParser.fromInt(totalSize) + BinaryParser.fromInt(id) + BinaryParser.fromInt(0) + BinaryParser.fromInt(op) + command;
513 | };
514 |
515 | // OpCodes
516 | Commands.OP_REPLY = 1;
517 | Commands.OP_MSG = 1000;
518 | Commands.OP_UPDATE = 2001;
519 | Commands.OP_INSERT = 2002;
520 | Commands.OP_GET_BY_OID = 2003;
521 | Commands.OP_QUERY = 2004;
522 | Commands.OP_GET_MORE = 2005;
523 | Commands.OP_DELETE = 2006;
524 | Commands.OP_KILL_CURSORS = 2007;
525 | Commands.documents = [];
526 |
--------------------------------------------------------------------------------
/crypto/md5.js:
--------------------------------------------------------------------------------
1 | /*
2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
3 | * Digest Algorithm, as defined in RFC 1321.
4 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6 | * Distributed under the BSD License
7 | * See http://pajhome.org.uk/crypt/md5 for more info.
8 | */
9 |
10 | /*
11 | * Configurable variables. You may need to tweak these to be compatible with
12 | * the server-side, but the defaults work in most cases.
13 | */
14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
16 |
17 | /*
18 | * These are the functions you'll usually want to call
19 | * They take string arguments and return either hex or base-64 encoded strings
20 | */
21 | var MD5 = exports.MD5 = function() {};
22 |
23 | MD5.hex_md5 = function(s) { return MD5.rstr2hex(MD5.rstr_md5(MD5.str2rstr_utf8(s))); }
24 | MD5.b64_md5 = function(s) { return MD5.rstr2b64(MD5.rstr_md5(MD5.str2rstr_utf8(s))); }
25 | MD5.any_md5 = function(s, e) { return MD5.rstr2any(MD5.rstr_md5(MD5.str2rstr_utf8(s)), e); }
26 | MD5.hex_hmac_md5 = function(k, d)
27 | { return MD5.rstr2hex(MD5.rstr_hmac_md5(MD5.str2rstr_utf8(k), MD5.str2rstr_utf8(d))); }
28 | MD5.b64_hmac_md5 = function(k, d)
29 | { return MD5.rstr2b64(MD5.rstr_hmac_md5(MD5.str2rstr_utf8(k), MD5.str2rstr_utf8(d))); }
30 | MD5.any_hmac_md5 = function(k, d, e)
31 | { return MD5.rstr2any(MD5.rstr_hmac_md5(MD5.str2rstr_utf8(k), MD5.str2rstr_utf8(d)), e); }
32 |
33 | /*
34 | * Calculate the MD5 of a raw string
35 | */
36 | MD5.rstr_md5 = function(s) {
37 | return MD5.binl2rstr(MD5.binl_md5(MD5.rstr2binl(s), s.length * 8));
38 | }
39 |
40 | /*
41 | * Calculate the HMAC-MD5, of a key and some data (raw strings)
42 | */
43 | MD5.rstr_hmac_md5 = function(key, data) {
44 | var bkey = MD5.rstr2binl(key);
45 | if(bkey.length > 16) bkey = MD5.binl_md5(bkey, key.length * 8);
46 |
47 | var ipad = Array(16), opad = Array(16);
48 | for(var i = 0; i < 16; i++) {
49 | ipad[i] = bkey[i] ^ 0x36363636;
50 | opad[i] = bkey[i] ^ 0x5C5C5C5C;
51 | }
52 |
53 | var hash = MD5.binl_md5(ipad.concat(MD5.rstr2binl(data)), 512 + data.length * 8);
54 | return MD5.binl2rstr(MD5.binl_md5(opad.concat(hash), 512 + 128));
55 | }
56 |
57 | /*
58 | * Convert a raw string to a hex string
59 | */
60 | MD5.rstr2hex = function(input) {
61 | try { hexcase } catch(e) { hexcase=0; }
62 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
63 | var output = "";
64 | var x;
65 | for(var i = 0; i < input.length; i++) {
66 | x = input.charCodeAt(i);
67 | output += hex_tab.charAt((x >>> 4) & 0x0F)
68 | + hex_tab.charAt( x & 0x0F);
69 | }
70 | return output;
71 | }
72 |
73 | /*
74 | * Convert a raw string to a base-64 string
75 | */
76 | MD5.rstr2b64 = function(input) {
77 | try { b64pad } catch(e) { b64pad=''; }
78 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
79 | var output = "";
80 | var len = input.length;
81 | for(var i = 0; i < len; i += 3) {
82 | var triplet = (input.charCodeAt(i) << 16)
83 | | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
84 | | (i + 2 < len ? input.charCodeAt(i+2) : 0);
85 | for(var j = 0; j < 4; j++) {
86 | if(i * 8 + j * 6 > input.length * 8) output += b64pad;
87 | else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
88 | }
89 | }
90 | return output;
91 | }
92 |
93 | /*
94 | * Convert a raw string to an arbitrary string encoding
95 | */
96 | MD5.rstr2any = function(input, encoding) {
97 | var divisor = encoding.length;
98 | var i, j, q, x, quotient;
99 |
100 | /* Convert to an array of 16-bit big-endian values, forming the dividend */
101 | var dividend = Array(Math.ceil(input.length / 2));
102 | for(i = 0; i < dividend.length; i++) {
103 | dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
104 | }
105 |
106 | /*
107 | * Repeatedly perform a long division. The binary array forms the dividend,
108 | * the length of the encoding is the divisor. Once computed, the quotient
109 | * forms the dividend for the next step. All remainders are stored for later
110 | * use.
111 | */
112 | var full_length = Math.ceil(input.length * 8 /
113 | (Math.log(encoding.length) / Math.log(2)));
114 | var remainders = Array(full_length);
115 | for(j = 0; j < full_length; j++) {
116 | quotient = Array();
117 | x = 0;
118 | for(i = 0; i < dividend.length; i++) {
119 | x = (x << 16) + dividend[i];
120 | q = Math.floor(x / divisor);
121 | x -= q * divisor;
122 | if(quotient.length > 0 || q > 0)
123 | quotient[quotient.length] = q;
124 | }
125 | remainders[j] = x;
126 | dividend = quotient;
127 | }
128 |
129 | /* Convert the remainders to the output string */
130 | var output = "";
131 | for(i = remainders.length - 1; i >= 0; i--)
132 | output += encoding.charAt(remainders[i]);
133 |
134 | return output;
135 | }
136 |
137 | /*
138 | * Encode a string as utf-8.
139 | * For efficiency, this assumes the input is valid utf-16.
140 | */
141 | MD5.str2rstr_utf8 = function(input) {
142 | var output = "";
143 | var i = -1;
144 | var x, y;
145 |
146 | while(++i < input.length) {
147 | /* Decode utf-16 surrogate pairs */
148 | x = input.charCodeAt(i);
149 | y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
150 | if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
151 | x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
152 | i++;
153 | }
154 |
155 | /* Encode output as utf-8 */
156 | if(x <= 0x7F)
157 | output += String.fromCharCode(x);
158 | else if(x <= 0x7FF)
159 | output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
160 | 0x80 | ( x & 0x3F));
161 | else if(x <= 0xFFFF)
162 | output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
163 | 0x80 | ((x >>> 6 ) & 0x3F),
164 | 0x80 | ( x & 0x3F));
165 | else if(x <= 0x1FFFFF)
166 | output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
167 | 0x80 | ((x >>> 12) & 0x3F),
168 | 0x80 | ((x >>> 6 ) & 0x3F),
169 | 0x80 | ( x & 0x3F));
170 | }
171 | return output;
172 | }
173 |
174 | /*
175 | * Encode a string as utf-16
176 | */
177 | MD5.str2rstr_utf16le = function(input) {
178 | var output = "";
179 | for(var i = 0; i < input.length; i++)
180 | output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
181 | (input.charCodeAt(i) >>> 8) & 0xFF);
182 | return output;
183 | }
184 |
185 | MD5.str2rstr_utf16be = function(input) {
186 | var output = "";
187 | for(var i = 0; i < input.length; i++)
188 | output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
189 | input.charCodeAt(i) & 0xFF);
190 | return output;
191 | }
192 |
193 | /*
194 | * Convert a raw string to an array of little-endian words
195 | * Characters >255 have their high-byte silently ignored.
196 | */
197 | MD5.rstr2binl = function(input) {
198 | var output = Array(input.length >> 2);
199 | for(var i = 0; i < output.length; i++)
200 | output[i] = 0;
201 | for(var i = 0; i < input.length * 8; i += 8)
202 | output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
203 | return output;
204 | }
205 |
206 | /*
207 | * Convert an array of little-endian words to a string
208 | */
209 | MD5.binl2rstr = function(input) {
210 | var output = "";
211 | for(var i = 0; i < input.length * 32; i += 8)
212 | output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
213 | return output;
214 | }
215 |
216 | /*
217 | * Calculate the MD5 of an array of little-endian words, and a bit length.
218 | */
219 | MD5.binl_md5 = function(x, len) {
220 | /* append padding */
221 | x[len >> 5] |= 0x80 << ((len) % 32);
222 | x[(((len + 64) >>> 9) << 4) + 14] = len;
223 |
224 | var a = 1732584193;
225 | var b = -271733879;
226 | var c = -1732584194;
227 | var d = 271733878;
228 |
229 | for(var i = 0; i < x.length; i += 16) {
230 | var olda = a;
231 | var oldb = b;
232 | var oldc = c;
233 | var oldd = d;
234 |
235 | a = MD5.md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
236 | d = MD5.md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
237 | c = MD5.md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
238 | b = MD5.md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
239 | a = MD5.md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
240 | d = MD5.md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
241 | c = MD5.md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
242 | b = MD5.md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
243 | a = MD5.md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
244 | d = MD5.md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
245 | c = MD5.md5_ff(c, d, a, b, x[i+10], 17, -42063);
246 | b = MD5.md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
247 | a = MD5.md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
248 | d = MD5.md5_ff(d, a, b, c, x[i+13], 12, -40341101);
249 | c = MD5.md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
250 | b = MD5.md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
251 |
252 | a = MD5.md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
253 | d = MD5.md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
254 | c = MD5.md5_gg(c, d, a, b, x[i+11], 14, 643717713);
255 | b = MD5.md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
256 | a = MD5.md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
257 | d = MD5.md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
258 | c = MD5.md5_gg(c, d, a, b, x[i+15], 14, -660478335);
259 | b = MD5.md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
260 | a = MD5.md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
261 | d = MD5.md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
262 | c = MD5.md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
263 | b = MD5.md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
264 | a = MD5.md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
265 | d = MD5.md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
266 | c = MD5.md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
267 | b = MD5.md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
268 |
269 | a = MD5.md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
270 | d = MD5.md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
271 | c = MD5.md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
272 | b = MD5.md5_hh(b, c, d, a, x[i+14], 23, -35309556);
273 | a = MD5.md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
274 | d = MD5.md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
275 | c = MD5.md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
276 | b = MD5.md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
277 | a = MD5.md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
278 | d = MD5.md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
279 | c = MD5.md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
280 | b = MD5.md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
281 | a = MD5.md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
282 | d = MD5.md5_hh(d, a, b, c, x[i+12], 11, -421815835);
283 | c = MD5.md5_hh(c, d, a, b, x[i+15], 16, 530742520);
284 | b = MD5.md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
285 |
286 | a = MD5.md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
287 | d = MD5.md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
288 | c = MD5.md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
289 | b = MD5.md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
290 | a = MD5.md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
291 | d = MD5.md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
292 | c = MD5.md5_ii(c, d, a, b, x[i+10], 15, -1051523);
293 | b = MD5.md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
294 | a = MD5.md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
295 | d = MD5.md5_ii(d, a, b, c, x[i+15], 10, -30611744);
296 | c = MD5.md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
297 | b = MD5.md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
298 | a = MD5.md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
299 | d = MD5.md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
300 | c = MD5.md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
301 | b = MD5.md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
302 |
303 | a = MD5.safe_add(a, olda);
304 | b = MD5.safe_add(b, oldb);
305 | c = MD5.safe_add(c, oldc);
306 | d = MD5.safe_add(d, oldd);
307 | }
308 | return Array(a, b, c, d);
309 | }
310 |
311 | /*
312 | * These functions implement the four basic operations the algorithm uses.
313 | */
314 | MD5.md5_cmn = function(q, a, b, x, s, t) {
315 | return MD5.safe_add(MD5.bit_rol(MD5.safe_add(MD5.safe_add(a, q), MD5.safe_add(x, t)), s),b);
316 | }
317 | MD5.md5_ff = function(a, b, c, d, x, s, t) {
318 | return MD5.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
319 | }
320 | MD5.md5_gg = function(a, b, c, d, x, s, t) {
321 | return MD5.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
322 | }
323 | MD5.md5_hh = function(a, b, c, d, x, s, t) {
324 | return MD5.md5_cmn(b ^ c ^ d, a, b, x, s, t);
325 | }
326 | MD5.md5_ii = function(a, b, c, d, x, s, t) {
327 | return MD5.md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
328 | }
329 |
330 | /*
331 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally
332 | * to work around bugs in some JS interpreters.
333 | */
334 | MD5.safe_add = function(x, y) {
335 | var lsw = (x & 0xFFFF) + (y & 0xFFFF);
336 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
337 | return (msw << 16) | (lsw & 0xFFFF);
338 | }
339 |
340 | /*
341 | * Bitwise rotate a 32-bit number to the left.
342 | */
343 | MD5.bit_rol = function(num, cnt) {
344 | return (num << cnt) | (num >>> (32 - cnt));
345 | }
346 |
--------------------------------------------------------------------------------
/examples/dbjoin.js:
--------------------------------------------------------------------------------
1 | var $ = require("../mongous").Mongous;
2 |
3 | $('test.user').save({id:5, name: 'mark nadal'});
4 | $('test.user').save({id:7, name: 'bob banto'});
5 | $('test.user').save({id:9, name: 'charles carant'});
6 | $('game.tournament').save({title: 'championship', id: 9, where: 'USA'});
7 | $('game.tournament').save({title: 'open', id: 7, where: 'USA'});
8 | $('game.level').save({user:5, time: 99, level: 1, tournament: 7});
9 | $('game.level').save({user:7, time: 95, level: 1, tournament: 9});
10 | $('game.level').save({user:9, time: 96, level: 1, tournament: 9});
11 | $('game.level').save({user:7, time: 93, level: 2, tournament: 7});
12 |
13 | var TS = new Date().getTime();
14 | $('game.level').find({level: 1}
15 | , {}
16 | , {join: {
17 | user: '$test.user.id'
18 | ,tournament: '.tournament.id'
19 | }}
20 | , function(r){
21 | console.log(r.documents, 'in ' + ((new Date().getTime()) - TS) +'ms');
22 |
23 | // remove them.
24 | $('game.level').remove({},{level: 1});
25 | $('game.tournament').remove({},{title: 1});
26 | $('test.user').remove({},{name: 1});
27 | });
28 |
--------------------------------------------------------------------------------
/examples/dbtestjoin.js:
--------------------------------------------------------------------------------
1 | var $ = require("../mongous").Mongous;
2 |
3 | (function(){ // generate data
4 | return;
5 |
6 | for (var i = 0; i < 105; i++){
7 | $('test.user').save({_id: i, name: Math.random().toString(36).substr(2, 20) });
8 | }
9 |
10 | /*for (var i = 0; i < 500; i++){
11 | $('game.tournament').save({_id: i, where: Math.random().toString(36).substr(2, 5), title: Math.random().toString(36).substr(2, 20) });
12 | }*/
13 |
14 | for (var i = 0; i < 105; i++){ // merging on 0 cause problems?
15 | $('game.level').save({
16 | user: i
17 | , time: Math.floor(Math.random() * (99 - 60 + 1)) + 60
18 | , level: 1
19 | });
20 | }
21 | })();
22 |
23 | console.log('done!');
24 | var TS = new Date().getTime();
25 | $('game.level').find({level: 1}
26 | , {}
27 | , {join: {
28 | user: '$test.user._id'
29 | ,tournament: '.tournament._id'
30 | }}
31 | , function(r){
32 | r && r.documents && console.log(r.documents[0]);
33 | r && r.documents && console.log(r.documents[r.documents.length-1]);
34 | r && r.documents && console.log(r.documents.length, 'in', ((new Date().getTime()) - TS), 'ms');
35 |
36 | // remove them.
37 | /*$('game.level').remove({},{level: 1});
38 | $('game.tournament').remove({},{title: 1});
39 | $('test.user').remove({},{name: 1});*/
40 | });
41 |
--------------------------------------------------------------------------------
/examples/tonsdbjoins.js:
--------------------------------------------------------------------------------
1 | var $ = require("../mongous").Mongous;
2 |
3 | (function(){ // generate data. Do this separately (comment out the return)
4 | return;
5 | for (var i = 0; i <= 5000; i++){
6 | $('test.user').save({_id: i, name: Math.random().toString(36).substr(2, 20) });
7 | }
8 |
9 | for (var i = 0; i <= 500; i++){
10 | $('game.tournament').save({_id: i, where: Math.random().toString(36).substr(2, 5), title: Math.random().toString(36).substr(2, 20) });
11 | }
12 |
13 | for (var i = 0, u = 0, t = 0; i <= 10000; i++){ // Let's try this with more deterministic numbers.
14 | $('game.level').save({
15 | _id: i
16 | , user: u
17 | , time: Math.floor(Math.random() * (99 - 60 + 1)) + 60
18 | , level: 1
19 | , tournament: t
20 | });
21 | t = t === 500? 0 : t + 1;
22 | u = u === 5000? 0 : u + 1;
23 | }
24 | console.log('non-async done!');
25 | })();
26 |
27 | (function(){
28 | var TS = new Date().getTime();
29 | $('game.level').find({level: 1}
30 | , {}
31 | , {join: {
32 | user: '$test.user._id'
33 | ,tournament: '.tournament._id'
34 | }}
35 | , function(r){
36 | r && r.documents && console.log(r.documents[r.documents.length-1]);
37 | console.log('in ' + ((new Date().getTime()) - TS) +'ms');
38 |
39 | // remove them.
40 | /*
41 | $('game.level').remove({},{level: 1});
42 | $('game.tournament').remove({},{title: 1});
43 | $('test.user').remove({},{name: 1});*/
44 | });
45 | })();
--------------------------------------------------------------------------------
/goog/math/integer.js:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License, Version 2.0 (the "License");
2 | // you may not use this file except in compliance with the License.
3 | // You may obtain a copy of the License at
4 | //
5 | // http://www.apache.org/licenses/LICENSE-2.0
6 | //
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 |
13 | // Copyright 2009 Google Inc. All Rights Reserved
14 |
15 | /**
16 | * @fileoverview Defines an exports.Integer class for representing (potentially)
17 | * infinite length two's-complement integer values.
18 | *
19 | * For the specific case of 64-bit integers, use Long, which is more
20 | * efficient.
21 | *
22 | */
23 |
24 | var chr = String.fromCharCode;
25 |
26 | /**
27 | * Constructs a two's-complement integer an array containing bits of the
28 | * integer in 32-bit (signed) pieces, given in little-endian order (i.e.,
29 | * lowest-order bits in the first piece), and the sign of -1 or 0.
30 | *
31 | * See the from* functions below for other convenient ways of constructing
32 | * exports.Integers.
33 | *
34 | * The internal representation of an integer is an array of 32-bit signed
35 | * pieces, along with a sign (0 or -1) that indicates the contents of all the
36 | * other 32-bit pieces out to infinity. We use 32-bit pieces because these are
37 | * the size of integers on which Javascript performs bit-operations. For
38 | * operations like addition and multiplication, we split each number into 16-bit
39 | * pieces, which can easily be multiplied within Javascript's floating-point
40 | * representation without overflow or change in sign.
41 | *
42 | * @constructor
43 | * @param {Array.} bits Array containing the bits of the number.
44 | * @param {number} sign The sign of the number: -1 for negative and 0 positive.
45 | */
46 | exports.Integer = function(bits, sign) {
47 | /**
48 | * @type {Array.}
49 | * @private
50 | */
51 | this.bits_ = [];
52 |
53 | /**
54 | * @type {number}
55 | * @private
56 | */
57 | this.sign_ = sign;
58 |
59 | // Copy the 32-bit signed integer values passed in. We prune out those at the
60 | // top that equal the sign since they are redundant.
61 | var top = true;
62 | for (var i = bits.length - 1; i >= 0; i--) {
63 | var val = bits[i] | 0;
64 | if (!top || val != sign) {
65 | this.bits_[i] = val;
66 | top = false;
67 | }
68 | }
69 | };
70 |
71 |
72 | // NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
73 | // from* methods on which they depend.
74 |
75 |
76 | /**
77 | * A cache of the exports.Integer representations of small integer values.
78 | * @type {Object}
79 | * @private
80 | */
81 | exports.Integer.INT_CACHE_ = {};
82 |
83 |
84 | /**
85 | * Returns an exports.Integer representing the given (32-bit) integer value.
86 | * @param {number} value A 32-bit integer value.
87 | * @return {exports.Integer} The corresponding exports.Integer value.
88 | */
89 | exports.Integer.fromInt = function(value) {
90 | if (-128 <= value && value < 128) {
91 | var cachedObj = exports.Integer.INT_CACHE_[value];
92 | if (cachedObj) {
93 | return cachedObj;
94 | }
95 | }
96 |
97 | var obj = new exports.Integer([value | 0], value < 0 ? -1 : 0);
98 | if (-128 <= value && value < 128) {
99 | exports.Integer.INT_CACHE_[value] = obj;
100 | }
101 | return obj;
102 | };
103 |
104 |
105 | /**
106 | * Returns an exports.Integer representing the given value, provided that it is a finite
107 | * number. Otherwise, zero is returned.
108 | * @param {number} value The value in question.
109 | * @return {exports.Integer} The corresponding exports.Integer value.
110 | */
111 | exports.Integer.fromNumber = function(value) {
112 | if (isNaN(value) || !isFinite(value)) {
113 | return exports.Integer.ZERO;
114 | } else if (value < 0) {
115 | return exports.Integer.fromNumber(-value).negate();
116 | } else {
117 | var bits = [];
118 | var pow = 1;
119 | for (var i = 0; value >= pow; i++) {
120 | bits[i] = (value / pow) | 0;
121 | pow *= exports.Integer.TWO_PWR_32_DBL_;
122 | }
123 | return new exports.Integer(bits, 0);
124 | }
125 | };
126 |
127 |
128 | /**
129 | * Returns a exports.Integer representing the value that comes by concatenating the
130 | * given entries, each is assumed to be 32 signed bits, given in little-endian
131 | * order (lowest order bits in the lowest index), and sign-extending the highest
132 | * order 32-bit value.
133 | * @param {Array.} bits The bits of the number, in 32-bit signed pieces,
134 | * in little-endian order.
135 | * @return {exports.Integer} The corresponding exports.Integer value.
136 | */
137 | exports.Integer.fromBits = function(bits) {
138 | var high = bits[bits.length - 1];
139 | return new exports.Integer(bits, high & (1 << 31) ? -1 : 0);
140 | };
141 |
142 | /**
143 | * Returns an exports.Integer representation of the given string, written using the
144 | * given radix.
145 | * @param {string} str The textual representation of the exports.Integer.
146 | * @param {number} opt_radix The radix in which the text is written.
147 | * @return {exports.Integer} The corresponding exports.Integer value.
148 | */
149 | exports.Integer.fromString = function(str, opt_radix) {
150 | if (str.length == 0) {
151 | throw Error('number format error: empty string');
152 | }
153 |
154 | var radix = opt_radix || 10;
155 | if (radix < 2 || 36 < radix) {
156 | throw Error('radix out of range: ' + radix);
157 | }
158 |
159 | if (str.charAt(0) == '-') {
160 | return exports.Integer.fromString(str.substring(1), radix).negate();
161 | } else if (str.indexOf('-') >= 0) {
162 | throw Error('number format error: interior "-" character');
163 | }
164 |
165 | // Do several (8) digits each time through the loop, so as to
166 | // minimize the calls to the very expensive emulated div.
167 | var radixToPower = exports.Integer.fromNumber(Math.pow(radix, 8));
168 |
169 | var result = exports.Integer.ZERO;
170 | for (var i = 0; i < str.length; i += 8) {
171 | var size = Math.min(8, str.length - i);
172 | var value = parseInt(str.substring(i, i + size), radix);
173 | if (size < 8) {
174 | var power = exports.Integer.fromNumber(Math.pow(radix, size));
175 | result = result.multiply(power).add(exports.Integer.fromNumber(value));
176 | } else {
177 | result = result.multiply(radixToPower);
178 | result = result.add(exports.Integer.fromNumber(value));
179 | }
180 | }
181 | return result;
182 | };
183 |
184 |
185 | /**
186 | * A number used repeatedly in calculations. This must appear before the first
187 | * call to the from* functions below.
188 | * @type {number}
189 | * @private
190 | */
191 | exports.Integer.TWO_PWR_32_DBL_ = (1 << 16) * (1 << 16);
192 |
193 |
194 | /** @type {exports.Integer} */
195 | exports.Integer.ZERO = exports.Integer.fromInt(0);
196 |
197 |
198 | /** @type {exports.Integer} */
199 | exports.Integer.ONE = exports.Integer.fromInt(1);
200 |
201 |
202 | /**
203 | * @type {exports.Integer}
204 | * @private
205 | */
206 | exports.Integer.TWO_PWR_24_ = exports.Integer.fromInt(1 << 24);
207 |
208 |
209 | /**
210 | * Returns the value, assuming it is a 32-bit integer.
211 | * @return {number} The corresponding int value.
212 | */
213 | exports.Integer.prototype.toInt = function() {
214 | return this.bits_.length > 0 ? this.bits_[0] : this.sign_;
215 | };
216 |
217 | exports.Integer.prototype.encodeInt32 = function() {
218 | var number = this.toInt()
219 | var a, b, c, d, unsigned;
220 | unsigned = (number < 0) ? (number + 0x100000000) : number;
221 | a = Math.floor(unsigned / 0xffffff);
222 | unsigned &= 0xffffff;
223 | b = Math.floor(unsigned / 0xffff);
224 | unsigned &= 0xffff;
225 | c = Math.floor(unsigned / 0xff);
226 | unsigned &= 0xff;
227 | d = Math.floor(unsigned);
228 | return chr(d) + chr(c) + chr(b) + chr(a);
229 | }
230 |
231 |
232 | /** @return {number} The closest floating-point representation to this value. */
233 | exports.Integer.prototype.toNumber = function() {
234 | if (this.isNegative()) {
235 | return -this.negate().toNumber();
236 | } else {
237 | var val = 0;
238 | var pow = 1;
239 | for (var i = 0; i < this.bits_.length; i++) {
240 | val += this.getBitsUnsigned(i) * pow;
241 | pow *= exports.Integer.TWO_PWR_32_DBL_;
242 | }
243 | return val;
244 | }
245 | };
246 |
247 |
248 | /**
249 | * @param {number} opt_radix The radix in which the text should be written.
250 | * @return {string} The textual representation of this value.
251 | */
252 | exports.Integer.prototype.toString = function(opt_radix) {
253 | var radix = opt_radix || 10;
254 | if (radix < 2 || 36 < radix) {
255 | throw Error('radix out of range: ' + radix);
256 | }
257 |
258 | if (this.isZero()) {
259 | return '0';
260 | } else if (this.isNegative()) {
261 | return '-' + this.negate().toString(radix);
262 | }
263 |
264 | // Do several (6) digits each time through the loop, so as to
265 | // minimize the calls to the very expensive emulated div.
266 | var radixToPower = exports.Integer.fromNumber(Math.pow(radix, 6));
267 |
268 | var rem = this;
269 | var result = '';
270 | while (true) {
271 | var remDiv = rem.divide(radixToPower);
272 | var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt();
273 | var digits = intval.toString(radix);
274 |
275 | rem = remDiv;
276 | if (rem.isZero()) {
277 | return digits + result;
278 | } else {
279 | while (digits.length < 6) {
280 | digits = '0' + digits;
281 | }
282 | result = '' + digits + result;
283 | }
284 | }
285 | };
286 |
287 |
288 | /**
289 | * Returns the index-th 32-bit (signed) piece of the exports.Integer according to
290 | * little-endian order (i.e., index 0 contains the smallest bits).
291 | * @param {number} index The index in question.
292 | * @return {number} The requested 32-bits as a signed number.
293 | */
294 | exports.Integer.prototype.getBits = function(index) {
295 | if (index < 0) {
296 | return 0; // Allowing this simplifies bit shifting operations below...
297 | } else if (index < this.bits_.length) {
298 | return this.bits_[index];
299 | } else {
300 | return this.sign_;
301 | }
302 | };
303 |
304 |
305 | /**
306 | * Returns the index-th 32-bit piece as an unsigned number.
307 | * @param {number} index The index in question.
308 | * @return {number} The requested 32-bits as an unsigned number.
309 | */
310 | exports.Integer.prototype.getBitsUnsigned = function(index) {
311 | var val = this.getBits(index);
312 | return val >= 0 ? val : exports.Integer.TWO_PWR_32_DBL_ + val;
313 | };
314 |
315 |
316 | /** @return {number} The sign bit of this number, -1 or 0. */
317 | exports.Integer.prototype.getSign = function() {
318 | return this.sign_;
319 | };
320 |
321 |
322 | /** @return {boolean} Whether this value is zero. */
323 | exports.Integer.prototype.isZero = function() {
324 | if (this.sign_ != 0) {
325 | return false;
326 | }
327 | for (var i = 0; i < this.bits_.length; i++) {
328 | if (this.bits_[i] != 0) {
329 | return false;
330 | }
331 | }
332 | return true;
333 | };
334 |
335 |
336 | /** @return {boolean} Whether this value is negative. */
337 | exports.Integer.prototype.isNegative = function() {
338 | return this.sign_ == -1;
339 | };
340 |
341 |
342 | /** @return {boolean} Whether this value is odd. */
343 | exports.Integer.prototype.isOdd = function() {
344 | return (this.bits_.length == 0) && (this.sign_ == -1) ||
345 | (this.bits_.length > 0) && ((this.bits_[0] & 1) != 0);
346 | };
347 |
348 |
349 | /**
350 | * @param {exports.Integer} other exports.Integer to compare against.
351 | * @return {boolean} Whether this exports.Integer equals the other.
352 | */
353 | exports.Integer.prototype.equals = function(other) {
354 | if (this.sign_ != other.sign_) {
355 | return false;
356 | }
357 | var len = Math.max(this.bits_.length, other.bits_.length);
358 | for (var i = 0; i < len; i++) {
359 | if (this.getBits(i) != other.getBits(i)) {
360 | return false;
361 | }
362 | }
363 | return true;
364 | };
365 |
366 |
367 | /**
368 | * @param {exports.Integer} other exports.Integer to compare against.
369 | * @return {boolean} Whether this exports.Integer does not equal the other.
370 | */
371 | exports.Integer.prototype.notEquals = function(other) {
372 | return !this.equals(other);
373 | };
374 |
375 |
376 | /**
377 | * @param {exports.Integer} other exports.Integer to compare against.
378 | * @return {boolean} Whether this exports.Integer is greater than the other.
379 | */
380 | exports.Integer.prototype.greaterThan = function(other) {
381 | return this.compare(other) > 0;
382 | };
383 |
384 |
385 | /**
386 | * @param {exports.Integer} other exports.Integer to compare against.
387 | * @return {boolean} Whether this exports.Integer is greater than or equal to the other.
388 | */
389 | exports.Integer.prototype.greaterThanOrEqual = function(other) {
390 | return this.compare(other) >= 0;
391 | };
392 |
393 |
394 | /**
395 | * @param {exports.Integer} other exports.Integer to compare against.
396 | * @return {boolean} Whether this exports.Integer is less than the other.
397 | */
398 | exports.Integer.prototype.lessThan = function(other) {
399 | return this.compare(other) < 0;
400 | };
401 |
402 |
403 | /**
404 | * @param {exports.Integer} other exports.Integer to compare against.
405 | * @return {boolean} Whether this exports.Integer is less than or equal to the other.
406 | */
407 | exports.Integer.prototype.lessThanOrEqual = function(other) {
408 | return this.compare(other) <= 0;
409 | };
410 |
411 |
412 | /**
413 | * Compares this exports.Integer with the given one.
414 | * @param {exports.Integer} other exports.Integer to compare against.
415 | * @return {number} 0 if they are the same, 1 if the this is greater, and -1
416 | * if the given one is greater.
417 | */
418 | exports.Integer.prototype.compare = function(other) {
419 | var diff = this.subtract(other);
420 | if (diff.isNegative()) {
421 | return -1;
422 | } else if (diff.isZero()) {
423 | return 0;
424 | } else {
425 | return +1;
426 | }
427 | };
428 |
429 |
430 | /**
431 | * Returns an integer with only the first numBits bits of this value, sign
432 | * extended from the final bit.
433 | * @param {number} numBits The number of bits by which to shift.
434 | * @return {exports.Integer} The shorted integer value.
435 | */
436 | exports.Integer.prototype.shorten = function(numBits) {
437 | var arr_index = (numBits - 1) >> 5;
438 | var bit_index = (numBits - 1) % 32;
439 | var bits = [];
440 | for (var i = 0; i < arr_index; i++) {
441 | bits[i] = this.getBits(i);
442 | }
443 | var sigBits = bit_index == 31 ? 0xFFFFFFFF : (1 << (bit_index + 1)) - 1;
444 | var val = this.getBits(arr_index) & sigBits;
445 | if (val & (1 << bit_index)) {
446 | val |= 0xFFFFFFFF - sigBits;
447 | bits[arr_index] = val;
448 | return new exports.Integer(bits, -1);
449 | } else {
450 | bits[arr_index] = val;
451 | return new exports.Integer(bits, 0);
452 | }
453 | };
454 |
455 |
456 | /** @return {exports.Integer} The negation of this value. */
457 | exports.Integer.prototype.negate = function() {
458 | return this.not().add(exports.Integer.ONE);
459 | };
460 |
461 |
462 | /**
463 | * Returns the sum of this and the given exports.Integer.
464 | * @param {exports.Integer} other The exports.Integer to add to this.
465 | * @return {exports.Integer} The exports.Integer result.
466 | */
467 | exports.Integer.prototype.add = function(other) {
468 | var len = Math.max(this.bits_.length, other.bits_.length);
469 | var arr = [];
470 | var carry = 0;
471 |
472 | for (var i = 0; i <= len; i++) {
473 | var a1 = this.getBits(i) >>> 16;
474 | var a0 = this.getBits(i) & 0xFFFF;
475 |
476 | var b1 = other.getBits(i) >>> 16;
477 | var b0 = other.getBits(i) & 0xFFFF;
478 |
479 | var c0 = carry + a0 + b0;
480 | var c1 = (c0 >>> 16) + a1 + b1;
481 | carry = c1 >>> 16;
482 | c0 &= 0xFFFF;
483 | c1 &= 0xFFFF;
484 | arr[i] = (c1 << 16) | c0;
485 | }
486 | return exports.Integer.fromBits(arr);
487 | };
488 |
489 |
490 | /**
491 | * Returns the difference of this and the given exports.Integer.
492 | * @param {exports.Integer} other The exports.Integer to subtract from this.
493 | * @return {exports.Integer} The exports.Integer result.
494 | */
495 | exports.Integer.prototype.subtract = function(other) {
496 | return this.add(other.negate());
497 | };
498 |
499 |
500 | /**
501 | * Returns the product of this and the given exports.Integer.
502 | * @param {exports.Integer} other The exports.Integer to multiply against this.
503 | * @return {exports.Integer} The product of this and the other.
504 | */
505 | exports.Integer.prototype.multiply = function(other) {
506 | if (this.isZero()) {
507 | return exports.Integer.ZERO;
508 | } else if (other.isZero()) {
509 | return exports.Integer.ZERO;
510 | }
511 |
512 | if (this.isNegative()) {
513 | if (other.isNegative()) {
514 | return this.negate().multiply(other.negate());
515 | } else {
516 | return this.negate().multiply(other).negate();
517 | }
518 | } else if (other.isNegative()) {
519 | return this.multiply(other.negate()).negate();
520 | }
521 |
522 | // If both numbers are small, use float multiplication
523 | if (this.lessThan(exports.Integer.TWO_PWR_24_) &&
524 | other.lessThan(exports.Integer.TWO_PWR_24_)) {
525 | return exports.Integer.fromNumber(this.toNumber() * other.toNumber());
526 | }
527 |
528 | // Fill in an array of 16-bit products.
529 | var len = this.bits_.length + other.bits_.length;
530 | var arr = [];
531 | for (var i = 0; i < 2 * len; i++) {
532 | arr[i] = 0;
533 | }
534 | for (var i = 0; i < this.bits_.length; i++) {
535 | for (var j = 0; j < other.bits_.length; j++) {
536 | var a1 = this.getBits(i) >>> 16;
537 | var a0 = this.getBits(i) & 0xFFFF;
538 |
539 | var b1 = other.getBits(j) >>> 16;
540 | var b0 = other.getBits(j) & 0xFFFF;
541 |
542 | arr[2 * i + 2 * j] += a0 * b0;
543 | exports.Integer.carry16_(arr, 2 * i + 2 * j);
544 | arr[2 * i + 2 * j + 1] += a1 * b0;
545 | exports.Integer.carry16_(arr, 2 * i + 2 * j + 1);
546 | arr[2 * i + 2 * j + 1] += a0 * b1;
547 | exports.Integer.carry16_(arr, 2 * i + 2 * j + 1);
548 | arr[2 * i + 2 * j + 2] += a1 * b1;
549 | exports.Integer.carry16_(arr, 2 * i + 2 * j + 2);
550 | }
551 | }
552 |
553 | // Combine the 16-bit values into 32-bit values.
554 | for (var i = 0; i < len; i++) {
555 | arr[i] = (arr[2 * i + 1] << 16) | arr[2 * i];
556 | }
557 | for (var i = len; i < 2 * len; i++) {
558 | arr[i] = 0;
559 | }
560 | return new exports.Integer(arr, 0);
561 | };
562 |
563 |
564 | /**
565 | * Carries any overflow from the given index into later entries.
566 | * @param {Array.} bits Array of 16-bit values in little-endian order.
567 | * @param {number} index The index in question.
568 | * @private
569 | */
570 | exports.Integer.carry16_ = function(bits, index) {
571 | while ((bits[index] & 0xFFFF) != bits[index]) {
572 | bits[index + 1] += bits[index] >>> 16;
573 | bits[index] &= 0xFFFF;
574 | }
575 | };
576 |
577 |
578 | /**
579 | * Returns this exports.Integer divided by the given one.
580 | * @param {exports.Integer} other Th exports.Integer to divide this by.
581 | * @return {exports.Integer} This value divided by the given one.
582 | */
583 | exports.Integer.prototype.divide = function(other) {
584 | if (other.isZero()) {
585 | throw Error('division by zero');
586 | } else if (this.isZero()) {
587 | return exports.Integer.ZERO;
588 | }
589 |
590 | if (this.isNegative()) {
591 | if (other.isNegative()) {
592 | return this.negate().divide(other.negate());
593 | } else {
594 | return this.negate().divide(other).negate();
595 | }
596 | } else if (other.isNegative()) {
597 | return this.divide(other.negate()).negate();
598 | }
599 |
600 | // Repeat the following until the remainder is less than other: find a
601 | // floating-point that approximates remainder / other *from below*, add this
602 | // into the result, and subtract it from the remainder. It is critical that
603 | // the approximate value is less than or equal to the real value so that the
604 | // remainder never becomes negative.
605 | var res = exports.Integer.ZERO;
606 | var rem = this;
607 | while (rem.greaterThanOrEqual(other)) {
608 | // Approximate the result of division. This may be a little greater or
609 | // smaller than the actual value.
610 | var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
611 |
612 | // We will tweak the approximate result by changing it in the 48-th digit or
613 | // the smallest non-fractional digit, whichever is larger.
614 | var log2 = Math.ceil(Math.log(approx) / Math.LN2);
615 | var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
616 |
617 | // Decrease the approximation until it is smaller than the remainder. Note
618 | // that if it is too large, the product overflows and is negative.
619 | var approxRes = exports.Integer.fromNumber(approx);
620 | var approxRem = approxRes.multiply(other);
621 | while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
622 | approx -= delta;
623 | approxRes = exports.Integer.fromNumber(approx);
624 | approxRem = approxRes.multiply(other);
625 | }
626 |
627 | // We know the answer can't be zero... and actually, zero would cause
628 | // infinite recursion since we would make no progress.
629 | if (approxRes.isZero()) {
630 | approxRes = exports.Integer.ONE;
631 | }
632 |
633 | res = res.add(approxRes);
634 | rem = rem.subtract(approxRem);
635 | }
636 | return res;
637 | };
638 |
639 |
640 | /**
641 | * Returns this exports.Integer modulo the given one.
642 | * @param {exports.Integer} other The exports.Integer by which to mod.
643 | * @return {exports.Integer} This value modulo the given one.
644 | */
645 | exports.Integer.prototype.modulo = function(other) {
646 | return this.subtract(this.divide(other).multiply(other));
647 | };
648 |
649 |
650 | /** @return {exports.Integer} The bitwise-NOT of this value. */
651 | exports.Integer.prototype.not = function() {
652 | var len = this.bits_.length;
653 | var arr = [];
654 | for (var i = 0; i < len; i++) {
655 | arr[i] = ~this.bits_[i];
656 | }
657 | return new exports.Integer(arr, ~this.sign_);
658 | };
659 |
660 |
661 | /**
662 | * Returns the bitwise-AND of this exports.Integer and the given one.
663 | * @param {exports.Integer} other The exports.Integer to AND with this.
664 | * @return {exports.Integer} The bitwise-AND of this and the other.
665 | */
666 | exports.Integer.prototype.and = function(other) {
667 | var len = Math.max(this.bits_.length, other.bits_.length);
668 | var arr = [];
669 | for (var i = 0; i < len; i++) {
670 | arr[i] = this.getBits(i) & other.getBits(i);
671 | }
672 | return new exports.Integer(arr, this.sign_ & other.sign_);
673 | };
674 |
675 |
676 | /**
677 | * Returns the bitwise-OR of this exports.Integer and the given one.
678 | * @param {exports.Integer} other The exports.Integer to OR with this.
679 | * @return {exports.Integer} The bitwise-OR of this and the other.
680 | */
681 | exports.Integer.prototype.or = function(other) {
682 | var len = Math.max(this.bits_.length, other.bits_.length);
683 | var arr = [];
684 | for (var i = 0; i < len; i++) {
685 | arr[i] = this.getBits(i) | other.getBits(i);
686 | }
687 | return new exports.Integer(arr, this.sign_ | other.sign_);
688 | };
689 |
690 |
691 | /**
692 | * Returns the bitwise-XOR of this exports.Integer and the given one.
693 | * @param {exports.Integer} other The exports.Integer to XOR with this.
694 | * @return {exports.Integer} The bitwise-XOR of this and the other.
695 | */
696 | exports.Integer.prototype.xor = function(other) {
697 | var len = Math.max(this.bits_.length, other.bits_.length);
698 | var arr = [];
699 | for (var i = 0; i < len; i++) {
700 | arr[i] = this.getBits(i) ^ other.getBits(i);
701 | }
702 | return new exports.Integer(arr, this.sign_ ^ other.sign_);
703 | };
704 |
705 |
706 | /**
707 | * Returns this value with bits shifted to the left by the given amount.
708 | * @param {number} numBits The number of bits by which to shift.
709 | * @return {exports.Integer} This shifted to the left by the given amount.
710 | */
711 | exports.Integer.prototype.shiftLeft = function(numBits) {
712 | var arr_delta = numBits >> 5;
713 | var bit_delta = numBits % 32;
714 | var len = this.bits_.length + arr_delta + (bit_delta > 0 ? 1 : 0);
715 | var arr = [];
716 | for (var i = 0; i < len; i++) {
717 | if (bit_delta > 0) {
718 | arr[i] = (this.getBits(i - arr_delta) << bit_delta) |
719 | (this.getBits(i - arr_delta - 1) >>> (32 - bit_delta));
720 | } else {
721 | arr[i] = this.getBits(i - arr_delta);
722 | }
723 | }
724 | return new exports.Integer(arr, this.sign_);
725 | };
726 |
727 |
728 | /**
729 | * Returns this value with bits shifted to the right by the given amount.
730 | * @param {number} numBits The number of bits by which to shift.
731 | * @return {exports.Integer} This shifted to the right by the given amount.
732 | */
733 | exports.Integer.prototype.shiftRight = function(numBits) {
734 | var arr_delta = numBits >> 5;
735 | var bit_delta = numBits % 32;
736 | var len = this.bits_.length - arr_delta;
737 | var arr = [];
738 | for (var i = 0; i < len; i++) {
739 | if (bit_delta > 0) {
740 | arr[i] = (this.getBits(i + arr_delta) >>> bit_delta) |
741 | (this.getBits(i + arr_delta + 1) << (32 - bit_delta));
742 | } else {
743 | arr[i] = this.getBits(i + arr_delta);
744 | }
745 | }
746 | return new exports.Integer(arr, this.sign_);
747 | };
748 |
--------------------------------------------------------------------------------
/goog/math/long.js:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License, Version 2.0 (the "License");
2 | // you may not use this file except in compliance with the License.
3 | // You may obtain a copy of the License at
4 | //
5 | // http://www.apache.org/licenses/LICENSE-2.0
6 | //
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 |
13 | // Copyright 2009 Google Inc. All Rights Reserved
14 |
15 | /**
16 | * @fileoverview Defines a exports.Long class for representing a 64-bit two's-complement
17 | * integer value, which faithfully simulates the behavior of a Java "long". This
18 | * implementation is derived from exports.LongLib in GWT.
19 | *
20 | */
21 |
22 | /**
23 | * Constructs a 64-bit two's-complement integer, given its low and high 32-bit
24 | * values as *signed* integers. See the from* functions below for more
25 | * convenient ways of constructing exports.Longs.
26 | *
27 | * The internal representation of a long is the two given signed, 32-bit values.
28 | * We use 32-bit pieces because these are the size of integers on which
29 | * Javascript performs bit-operations. For operations like addition and
30 | * multiplication, we split each number into 16-bit pieces, which can easily be
31 | * multiplied within Javascript's floating-point representation without overflow
32 | * or change in sign.
33 | *
34 | * In the algorithms below, we frequently reduce the negative case to the
35 | * positive case by negating the input(s) and then post-processing the result.
36 | * Note that we must ALWAYS check specially whether those values are MIN_VALUE
37 | * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
38 | * a positive number, it overflows back into a negative). Not handling this
39 | * case would often result in infinite recursion.
40 | *
41 | * @param {number} low The low (signed) 32 bits of the long.
42 | * @param {number} high The high (signed) 32 bits of the long.
43 | * @constructor
44 | */
45 | exports.Long = function(low, high) {
46 | /**
47 | * @type {number}
48 | * @private
49 | */
50 | this.low_ = low | 0; // force into 32 signed bits.
51 |
52 | /**
53 | * @type {number}
54 | * @private
55 | */
56 | this.high_ = high | 0; // force into 32 signed bits.
57 | };
58 |
59 |
60 | // NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
61 | // from* methods on which they depend.
62 |
63 |
64 | /**
65 | * A cache of the exports.Long representations of small integer values.
66 | * @type {Object}
67 | * @private
68 | */
69 | exports.Long.INT_CACHE_ = {};
70 |
71 |
72 | /**
73 | * Returns a exports.Long representing the given (32-bit) integer value.
74 | * @param {number} value The 32-bit integer in question.
75 | * @return {exports.Long} The corresponding exports.Long value.
76 | */
77 | exports.Long.fromInt = function(value) {
78 | if (-128 <= value && value < 128) {
79 | var cachedObj = exports.Long.INT_CACHE_[value];
80 | if (cachedObj) {
81 | return cachedObj;
82 | }
83 | }
84 |
85 | var obj = new exports.Long(value | 0, value < 0 ? -1 : 0);
86 | if (-128 <= value && value < 128) {
87 | exports.Long.INT_CACHE_[value] = obj;
88 | }
89 | return obj;
90 | };
91 |
92 |
93 | /**
94 | * Returns a exports.Long representing the given value, provided that it is a finite
95 | * number. Otherwise, zero is returned.
96 | * @param {number} value The number in question.
97 | * @return {exports.Long} The corresponding exports.Long value.
98 | */
99 | exports.Long.fromNumber = function(value) {
100 | if (isNaN(value) || !isFinite(value)) {
101 | return exports.Long.ZERO;
102 | } else if (value <= -exports.Long.TWO_PWR_63_DBL_) {
103 | return exports.Long.MIN_VALUE;
104 | } else if (value + 1 >= exports.Long.TWO_PWR_63_DBL_) {
105 | return exports.Long.MAX_VALUE;
106 | } else if (value < 0) {
107 | return exports.Long.fromNumber(-value).negate();
108 | } else {
109 | return new exports.Long(
110 | (value % exports.Long.TWO_PWR_32_DBL_) | 0,
111 | (value / exports.Long.TWO_PWR_32_DBL_) | 0);
112 | }
113 | };
114 |
115 |
116 | /**
117 | * Returns a exports.Long representing the 64-bit integer that comes by concatenating
118 | * the given high and low bits. Each is assumed to use 32 bits.
119 | * @param {number} lowBits The low 32-bits.
120 | * @param {number} highBits The high 32-bits.
121 | * @return {exports.Long} The corresponding exports.Long value.
122 | */
123 | exports.Long.fromBits = function(lowBits, highBits) {
124 | return new exports.Long(lowBits, highBits);
125 | };
126 |
127 |
128 | /**
129 | * Returns a exports.Long representation of the given string, written using the given
130 | * radix.
131 | * @param {string} str The textual representation of the exports.Long.
132 | * @param {number} opt_radix The radix in which the text is written.
133 | * @return {exports.Long} The corresponding exports.Long value.
134 | */
135 | exports.Long.fromString = function(str, opt_radix) {
136 | if (str.length == 0) {
137 | throw Error('number format error: empty string');
138 | }
139 |
140 | var radix = opt_radix || 10;
141 | if (radix < 2 || 36 < radix) {
142 | throw Error('radix out of range: ' + radix);
143 | }
144 |
145 | if (str.charAt(0) == '-') {
146 | return exports.Long.fromString(str.substring(1), radix).negate();
147 | } else if (str.indexOf('-') >= 0) {
148 | throw Error('number format error: interior "-" character: ' + str);
149 | }
150 |
151 | // Do several (8) digits each time through the loop, so as to
152 | // minimize the calls to the very expensive emulated div.
153 | var radixToPower = exports.Long.fromNumber(Math.pow(radix, 8));
154 |
155 | var result = exports.Long.ZERO;
156 | for (var i = 0; i < str.length; i += 8) {
157 | var size = Math.min(8, str.length - i);
158 | var value = parseInt(str.substring(i, i + size), radix);
159 | if (size < 8) {
160 | var power = exports.Long.fromNumber(Math.pow(radix, size));
161 | result = result.multiply(power).add(exports.Long.fromNumber(value));
162 | } else {
163 | result = result.multiply(radixToPower);
164 | result = result.add(exports.Long.fromNumber(value));
165 | }
166 | }
167 | return result;
168 | };
169 |
170 |
171 | // NOTE: the compiler should inline these constant values below and then remove
172 | // these variables, so there should be no runtime penalty for these.
173 |
174 |
175 | /**
176 | * Number used repeated below in calculations. This must appear before the
177 | * first call to any from* function below.
178 | * @type {number}
179 | * @private
180 | */
181 | exports.Long.TWO_PWR_16_DBL_ = 1 << 16;
182 |
183 | /**
184 | * @type {number}
185 | * @private
186 | */
187 | exports.Long.TWO_PWR_24_DBL_ = 1 << 24;
188 |
189 | /**
190 | * @type {number}
191 | * @private
192 | */
193 | exports.Long.TWO_PWR_32_DBL_ =
194 | exports.Long.TWO_PWR_16_DBL_ * exports.Long.TWO_PWR_16_DBL_;
195 |
196 | /**
197 | * @type {number}
198 | * @private
199 | */
200 | exports.Long.TWO_PWR_31_DBL_ =
201 | exports.Long.TWO_PWR_32_DBL_ / 2;
202 |
203 | /**
204 | * @type {number}
205 | * @private
206 | */
207 | exports.Long.TWO_PWR_48_DBL_ =
208 | exports.Long.TWO_PWR_32_DBL_ * exports.Long.TWO_PWR_16_DBL_;
209 |
210 | /**
211 | * @type {number}
212 | * @private
213 | */
214 | exports.Long.TWO_PWR_64_DBL_ =
215 | exports.Long.TWO_PWR_32_DBL_ * exports.Long.TWO_PWR_32_DBL_;
216 |
217 | /**
218 | * @type {number}
219 | * @private
220 | */
221 | exports.Long.TWO_PWR_63_DBL_ =
222 | exports.Long.TWO_PWR_64_DBL_ / 2;
223 |
224 |
225 | /** @type {exports.Long} */
226 | exports.Long.ZERO = exports.Long.fromInt(0);
227 |
228 | /** @type {exports.Long} */
229 | exports.Long.ONE = exports.Long.fromInt(1);
230 |
231 | /** @type {exports.Long} */
232 | exports.Long.NEG_ONE = exports.Long.fromInt(-1);
233 |
234 | /** @type {exports.Long} */
235 | exports.Long.MAX_VALUE =
236 | exports.Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
237 |
238 | /** @type {exports.Long} */
239 | exports.Long.MIN_VALUE = exports.Long.fromBits(0, 0x80000000 | 0);
240 |
241 |
242 | /**
243 | * @type {exports.Long}
244 | * @private
245 | */
246 | exports.Long.TWO_PWR_24_ = exports.Long.fromInt(1 << 24);
247 |
248 |
249 | /** @return {number} The value, assuming it is a 32-bit integer. */
250 | exports.Long.prototype.toInt = function() {
251 | return this.low_;
252 | };
253 |
254 |
255 | /** @return {number} The closest floating-point representation to this value. */
256 | exports.Long.prototype.toNumber = function() {
257 | return this.high_ * exports.Long.TWO_PWR_32_DBL_ +
258 | this.getLowBitsUnsigned();
259 | };
260 |
261 | /** convert code to JSON **/
262 | exports.Long.prototype.toJSON = function() {
263 | return this.toString();
264 | }
265 |
266 | /**
267 | * @param {number} opt_radix The radix in which the text should be written.
268 | * @return {string} The textual representation of this value.
269 | */
270 | exports.Long.prototype.toString = function(opt_radix) {
271 | var radix = opt_radix || 10;
272 | if (radix < 2 || 36 < radix) {
273 | throw Error('radix out of range: ' + radix);
274 | }
275 |
276 | if (this.isZero()) {
277 | return '0';
278 | }
279 |
280 | if (this.isNegative()) {
281 | if (this.equals(exports.Long.MIN_VALUE)) {
282 | // We need to change the exports.Long value before it can be negated, so we remove
283 | // the bottom-most digit in this base and then recurse to do the rest.
284 | var radixLong = exports.Long.fromNumber(radix);
285 | var div = this.div(radixLong);
286 | var rem = div.multiply(radixLong).subtract(this);
287 | return div.toString(radix) + rem.toInt().toString(radix);
288 | } else {
289 | return '-' + this.negate().toString(radix);
290 | }
291 | }
292 |
293 | // Do several (6) digits each time through the loop, so as to
294 | // minimize the calls to the very expensive emulated div.
295 | var radixToPower = exports.Long.fromNumber(Math.pow(radix, 6));
296 |
297 | var rem = this;
298 | var result = '';
299 | while (true) {
300 | var remDiv = rem.div(radixToPower);
301 | var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt();
302 | var digits = intval.toString(radix);
303 |
304 | rem = remDiv;
305 | if (rem.isZero()) {
306 | return digits + result;
307 | } else {
308 | while (digits.length < 6) {
309 | digits = '0' + digits;
310 | }
311 | result = '' + digits + result;
312 | }
313 | }
314 | };
315 |
316 |
317 | /** @return {number} The high 32-bits as a signed value. */
318 | exports.Long.prototype.getHighBits = function() {
319 | return this.high_;
320 | };
321 |
322 |
323 | /** @return {number} The low 32-bits as a signed value. */
324 | exports.Long.prototype.getLowBits = function() {
325 | return this.low_;
326 | };
327 |
328 |
329 | /** @return {number} The low 32-bits as an unsigned value. */
330 | exports.Long.prototype.getLowBitsUnsigned = function() {
331 | return (this.low_ >= 0) ?
332 | this.low_ : exports.Long.TWO_PWR_32_DBL_ + this.low_;
333 | };
334 |
335 |
336 | /**
337 | * @return {number} Returns the number of bits needed to represent the absolute
338 | * value of this exports.Long.
339 | */
340 | exports.Long.prototype.getNumBitsAbs = function() {
341 | if (this.isNegative()) {
342 | if (this.equals(exports.Long.MIN_VALUE)) {
343 | return 64;
344 | } else {
345 | return this.negate().getNumBitsAbs();
346 | }
347 | } else {
348 | var val = this.high_ != 0 ? this.high_ : this.low_;
349 | for (var bit = 31; bit > 0; bit--) {
350 | if ((val & (1 << bit)) != 0) {
351 | break;
352 | }
353 | }
354 | return this.high_ != 0 ? bit + 33 : bit + 1;
355 | }
356 | };
357 |
358 |
359 | /** @return {boolean} Whether this value is zero. */
360 | exports.Long.prototype.isZero = function() {
361 | return this.high_ == 0 && this.low_ == 0;
362 | };
363 |
364 |
365 | /** @return {boolean} Whether this value is negative. */
366 | exports.Long.prototype.isNegative = function() {
367 | return this.high_ < 0;
368 | };
369 |
370 |
371 | /** @return {boolean} Whether this value is odd. */
372 | exports.Long.prototype.isOdd = function() {
373 | return (this.low_ & 1) == 1;
374 | };
375 |
376 |
377 | /**
378 | * @param {exports.Long} other exports.Long to compare against.
379 | * @return {boolean} Whether this exports.Long equals the other.
380 | */
381 | exports.Long.prototype.equals = function(other) {
382 | return (this.high_ == other.high_) && (this.low_ == other.low_);
383 | };
384 |
385 |
386 | /**
387 | * @param {exports.Long} other exports.Long to compare against.
388 | * @return {boolean} Whether this exports.Long does not equal the other.
389 | */
390 | exports.Long.prototype.notEquals = function(other) {
391 | return (this.high_ != other.high_) || (this.low_ != other.low_);
392 | };
393 |
394 |
395 | /**
396 | * @param {exports.Long} other exports.Long to compare against.
397 | * @return {boolean} Whether this exports.Long is less than the other.
398 | */
399 | exports.Long.prototype.lessThan = function(other) {
400 | return this.compare(other) < 0;
401 | };
402 |
403 |
404 | /**
405 | * @param {exports.Long} other exports.Long to compare against.
406 | * @return {boolean} Whether this exports.Long is less than or equal to the other.
407 | */
408 | exports.Long.prototype.lessThanOrEqual = function(other) {
409 | return this.compare(other) <= 0;
410 | };
411 |
412 |
413 | /**
414 | * @param {exports.Long} other exports.Long to compare against.
415 | * @return {boolean} Whether this exports.Long is greater than the other.
416 | */
417 | exports.Long.prototype.greaterThan = function(other) {
418 | return this.compare(other) > 0;
419 | };
420 |
421 |
422 | /**
423 | * @param {exports.Long} other exports.Long to compare against.
424 | * @return {boolean} Whether this exports.Long is greater than or equal to the other.
425 | */
426 | exports.Long.prototype.greaterThanOrEqual = function(other) {
427 | return this.compare(other) >= 0;
428 | };
429 |
430 |
431 | /**
432 | * Compares this exports.Long with the given one.
433 | * @param {exports.Long} other exports.Long to compare against.
434 | * @return {number} 0 if they are the same, 1 if the this is greater, and -1
435 | * if the given one is greater.
436 | */
437 | exports.Long.prototype.compare = function(other) {
438 | if (this.equals(other)) {
439 | return 0;
440 | }
441 |
442 | var thisNeg = this.isNegative();
443 | var otherNeg = other.isNegative();
444 | if (thisNeg && !otherNeg) {
445 | return -1;
446 | }
447 | if (!thisNeg && otherNeg) {
448 | return 1;
449 | }
450 |
451 | // at this point, the signs are the same, so subtraction will not overflow
452 | if (this.subtract(other).isNegative()) {
453 | return -1;
454 | } else {
455 | return 1;
456 | }
457 | };
458 |
459 |
460 | /** @return {exports.Long} The negation of this value. */
461 | exports.Long.prototype.negate = function() {
462 | if (this.equals(exports.Long.MIN_VALUE)) {
463 | return exports.Long.MIN_VALUE;
464 | } else {
465 | return this.not().add(exports.Long.ONE);
466 | }
467 | };
468 |
469 |
470 | /**
471 | * Returns the sum of this and the given exports.Long.
472 | * @param {exports.Long} other exports.Long to add to this one.
473 | * @return {exports.Long} The sum of this and the given exports.Long.
474 | */
475 | exports.Long.prototype.add = function(other) {
476 | // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
477 |
478 | var a48 = this.high_ >>> 16;
479 | var a32 = this.high_ & 0xFFFF;
480 | var a16 = this.low_ >>> 16;
481 | var a00 = this.low_ & 0xFFFF;
482 |
483 | var b48 = other.high_ >>> 16;
484 | var b32 = other.high_ & 0xFFFF;
485 | var b16 = other.low_ >>> 16;
486 | var b00 = other.low_ & 0xFFFF;
487 |
488 | var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
489 | c00 += a00 + b00;
490 | c16 += c00 >>> 16;
491 | c00 &= 0xFFFF;
492 | c16 += a16 + b16;
493 | c32 += c16 >>> 16;
494 | c16 &= 0xFFFF;
495 | c32 += a32 + b32;
496 | c48 += c32 >>> 16;
497 | c32 &= 0xFFFF;
498 | c48 += a48 + b48;
499 | c48 &= 0xFFFF;
500 | return exports.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
501 | };
502 |
503 |
504 | /**
505 | * Returns the difference of this and the given exports.Long.
506 | * @param {exports.Long} other exports.Long to subtract from this.
507 | * @return {exports.Long} The difference of this and the given exports.Long.
508 | */
509 | exports.Long.prototype.subtract = function(other) {
510 | return this.add(other.negate());
511 | };
512 |
513 |
514 | /**
515 | * Returns the product of this and the given long.
516 | * @param {exports.Long} other exports.Long to multiply with this.
517 | * @return {exports.Long} The product of this and the other.
518 | */
519 | exports.Long.prototype.multiply = function(other) {
520 | if (this.isZero()) {
521 | return exports.Long.ZERO;
522 | } else if (other.isZero()) {
523 | return exports.Long.ZERO;
524 | }
525 |
526 | if (this.equals(exports.Long.MIN_VALUE)) {
527 | return other.isOdd() ? exports.Long.MIN_VALUE : exports.Long.ZERO;
528 | } else if (other.equals(exports.Long.MIN_VALUE)) {
529 | return this.isOdd() ? exports.Long.MIN_VALUE : exports.Long.ZERO;
530 | }
531 |
532 | if (this.isNegative()) {
533 | if (other.isNegative()) {
534 | return this.negate().multiply(other.negate());
535 | } else {
536 | return this.negate().multiply(other).negate();
537 | }
538 | } else if (other.isNegative()) {
539 | return this.multiply(other.negate()).negate();
540 | }
541 |
542 | // If both longs are small, use float multiplication
543 | if (this.lessThan(exports.Long.TWO_PWR_24_) &&
544 | other.lessThan(exports.Long.TWO_PWR_24_)) {
545 | return exports.Long.fromNumber(this.toNumber() * other.toNumber());
546 | }
547 |
548 | // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
549 | // We can skip products that would overflow.
550 |
551 | var a48 = this.high_ >>> 16;
552 | var a32 = this.high_ & 0xFFFF;
553 | var a16 = this.low_ >>> 16;
554 | var a00 = this.low_ & 0xFFFF;
555 |
556 | var b48 = other.high_ >>> 16;
557 | var b32 = other.high_ & 0xFFFF;
558 | var b16 = other.low_ >>> 16;
559 | var b00 = other.low_ & 0xFFFF;
560 |
561 | var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
562 | c00 += a00 * b00;
563 | c16 += c00 >>> 16;
564 | c00 &= 0xFFFF;
565 | c16 += a16 * b00;
566 | c32 += c16 >>> 16;
567 | c16 &= 0xFFFF;
568 | c16 += a00 * b16;
569 | c32 += c16 >>> 16;
570 | c16 &= 0xFFFF;
571 | c32 += a32 * b00;
572 | c48 += c32 >>> 16;
573 | c32 &= 0xFFFF;
574 | c32 += a16 * b16;
575 | c48 += c32 >>> 16;
576 | c32 &= 0xFFFF;
577 | c32 += a00 * b32;
578 | c48 += c32 >>> 16;
579 | c32 &= 0xFFFF;
580 | c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
581 | c48 &= 0xFFFF;
582 | return exports.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
583 | };
584 |
585 |
586 | /**
587 | * Returns this exports.Long divided by the given one.
588 | * @param {exports.Long} other exports.Long by which to divide.
589 | * @return {exports.Long} This exports.Long divided by the given one.
590 | */
591 | exports.Long.prototype.div = function(other) {
592 | if (other.isZero()) {
593 | throw Error('division by zero');
594 | } else if (this.isZero()) {
595 | return exports.Long.ZERO;
596 | }
597 |
598 | if (this.equals(exports.Long.MIN_VALUE)) {
599 | if (other.equals(exports.Long.ONE) ||
600 | other.equals(exports.Long.NEG_ONE)) {
601 | return exports.Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
602 | } else if (other.equals(exports.Long.MIN_VALUE)) {
603 | return exports.Long.ONE;
604 | } else {
605 | // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
606 | var halfThis = this.shiftRight(1);
607 | var approx = halfThis.div(other).shiftLeft(1);
608 | if (approx.equals(exports.Long.ZERO)) {
609 | return other.isNegative() ? exports.Long.ONE : exports.Long.NEG_ONE;
610 | } else {
611 | var rem = this.subtract(other.multiply(approx));
612 | var result = approx.add(rem.div(other));
613 | return result;
614 | }
615 | }
616 | } else if (other.equals(exports.Long.MIN_VALUE)) {
617 | return exports.Long.ZERO;
618 | }
619 |
620 | if (this.isNegative()) {
621 | if (other.isNegative()) {
622 | return this.negate().div(other.negate());
623 | } else {
624 | return this.negate().div(other).negate();
625 | }
626 | } else if (other.isNegative()) {
627 | return this.div(other.negate()).negate();
628 | }
629 |
630 | // Repeat the following until the remainder is less than other: find a
631 | // floating-point that approximates remainder / other *from below*, add this
632 | // into the result, and subtract it from the remainder. It is critical that
633 | // the approximate value is less than or equal to the real value so that the
634 | // remainder never becomes negative.
635 | var res = exports.Long.ZERO;
636 | var rem = this;
637 | while (rem.greaterThanOrEqual(other)) {
638 | // Approximate the result of division. This may be a little greater or
639 | // smaller than the actual value.
640 | var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
641 |
642 | // We will tweak the approximate result by changing it in the 48-th digit or
643 | // the smallest non-fractional digit, whichever is larger.
644 | var log2 = Math.ceil(Math.log(approx) / Math.LN2);
645 | var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
646 |
647 | // Decrease the approximation until it is smaller than the remainder. Note
648 | // that if it is too large, the product overflows and is negative.
649 | var approxRes = exports.Long.fromNumber(approx);
650 | var approxRem = approxRes.multiply(other);
651 | while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
652 | approx -= delta;
653 | approxRes = exports.Long.fromNumber(approx);
654 | approxRem = approxRes.multiply(other);
655 | }
656 |
657 | // We know the answer can't be zero... and actually, zero would cause
658 | // infinite recursion since we would make no progress.
659 | if (approxRes.isZero()) {
660 | approxRes = exports.Long.ONE;
661 | }
662 |
663 | res = res.add(approxRes);
664 | rem = rem.subtract(approxRem);
665 | }
666 | return res;
667 | };
668 |
669 |
670 | /**
671 | * Returns this exports.Long modulo the given one.
672 | * @param {exports.Long} other exports.Long by which to mod.
673 | * @return {exports.Long} This exports.Long modulo the given one.
674 | */
675 | exports.Long.prototype.modulo = function(other) {
676 | return this.subtract(this.div(other).multiply(other));
677 | };
678 |
679 |
680 | /** @return {exports.Long} The bitwise-NOT of this value. */
681 | exports.Long.prototype.not = function() {
682 | return exports.Long.fromBits(~this.low_, ~this.high_);
683 | };
684 |
685 |
686 | /**
687 | * Returns the bitwise-AND of this exports.Long and the given one.
688 | * @param {exports.Long} other The exports.Long with which to AND.
689 | * @return {exports.Long} The bitwise-AND of this and the other.
690 | */
691 | exports.Long.prototype.and = function(other) {
692 | return exports.Long.fromBits(this.low_ & other.low_,
693 | this.high_ & other.high_);
694 | };
695 |
696 |
697 | /**
698 | * Returns the bitwise-OR of this exports.Long and the given one.
699 | * @param {exports.Long} other The exports.Long with which to OR.
700 | * @return {exports.Long} The bitwise-OR of this and the other.
701 | */
702 | exports.Long.prototype.or = function(other) {
703 | return exports.Long.fromBits(this.low_ | other.low_,
704 | this.high_ | other.high_);
705 | };
706 |
707 |
708 | /**
709 | * Returns the bitwise-XOR of this exports.Long and the given one.
710 | * @param {exports.Long} other The exports.Long with which to XOR.
711 | * @return {exports.Long} The bitwise-XOR of this and the other.
712 | */
713 | exports.Long.prototype.xor = function(other) {
714 | return exports.Long.fromBits(this.low_ ^ other.low_,
715 | this.high_ ^ other.high_);
716 | };
717 |
718 |
719 | /**
720 | * Returns this exports.Long with bits shifted to the left by the given amount.
721 | * @param {number} numBits The number of bits by which to shift.
722 | * @return {exports.Long} This shifted to the left by the given amount.
723 | */
724 | exports.Long.prototype.shiftLeft = function(numBits) {
725 | numBits &= 63;
726 | if (numBits == 0) {
727 | return this;
728 | } else {
729 | var low = this.low_;
730 | if (numBits < 32) {
731 | var high = this.high_;
732 | return exports.Long.fromBits(
733 | low << numBits,
734 | (high << numBits) | (low >>> (32 - numBits)));
735 | } else {
736 | return exports.Long.fromBits(0, low << (numBits - 32));
737 | }
738 | }
739 | };
740 |
741 |
742 | /**
743 | * Returns this exports.Long with bits shifted to the right by the given amount.
744 | * @param {number} numBits The number of bits by which to shift.
745 | * @return {exports.Long} This shifted to the right by the given amount.
746 | */
747 | exports.Long.prototype.shiftRight = function(numBits) {
748 | numBits &= 63;
749 | if (numBits == 0) {
750 | return this;
751 | } else {
752 | var high = this.high_;
753 | if (numBits < 32) {
754 | var low = this.low_;
755 | return exports.Long.fromBits(
756 | (low >>> numBits) | (high << (32 - numBits)),
757 | high >> numBits);
758 | } else {
759 | return exports.Long.fromBits(
760 | high >> (numBits - 32),
761 | high >= 0 ? 0 : -1);
762 | }
763 | }
764 | };
765 |
766 |
767 | /**
768 | * Returns this exports.Long with bits shifted to the right by the given amount, with
769 | * the new top bits matching the current sign bit.
770 | * @param {number} numBits The number of bits by which to shift.
771 | * @return {exports.Long} This shifted to the right by the given amount, with
772 | * zeros placed into the new leading bits.
773 | */
774 | exports.Long.prototype.shiftRightUnsigned = function(numBits) {
775 | numBits &= 63;
776 | if (numBits == 0) {
777 | return this;
778 | } else {
779 | var high = this.high_;
780 | if (numBits < 32) {
781 | var low = this.low_;
782 | return exports.Long.fromBits(
783 | (low >>> numBits) | (high << (32 - numBits)),
784 | high >>> numBits);
785 | } else if (numBits == 32) {
786 | return exports.Long.fromBits(high, 0);
787 | } else {
788 | return exports.Long.fromBits(high >>> (numBits - 32), 0);
789 | }
790 | }
791 | };
--------------------------------------------------------------------------------
/gridfs/chunk.js:
--------------------------------------------------------------------------------
1 | var BinaryParser = require('../bson/binary_parser').BinaryParser,
2 | OrderedHash = require('../bson/collections').OrderedHash,
3 | BSON = require('../bson/bson'),
4 | ObjectID = BSON.ObjectID,
5 | Binary = BSON.Binary;
6 |
7 | var Chunk = exports.Chunk = function(file, mongoObject) {
8 | this.file = file;
9 | var mongoObjectFinal = mongoObject == null ? new OrderedHash() : mongoObject;
10 | this.objectId = mongoObjectFinal._id == null ? new ObjectID() : mongoObjectFinal._id;
11 | this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n;
12 | this.data = new Binary();
13 |
14 | if(mongoObjectFinal.data == null) {
15 | } else if(mongoObjectFinal.data.constructor == String) {
16 | var buffer = new Buffer(mongoObjectFinal.data.length);
17 | buffer.write(mongoObjectFinal.data, 'binary', 0);
18 | this.data = new Binary(buffer);
19 | } else if(mongoObjectFinal.data.constructor == Array) {
20 | var buffer = new Buffer(mongoObjectFinal.data.length);
21 | buffer.write(mongoObjectFinal.data.join(''), 'binary', 0);
22 | this.data = new Binary(buffer);
23 | } else if(mongoObjectFinal.data instanceof Binary) {
24 | this.data = mongoObjectFinal.data;
25 | } else {
26 | throw Error("Illegal chunk format");
27 | }
28 | // Update position
29 | this.internalPosition = 0;
30 | // Getters and Setters
31 | this.__defineGetter__("position", function() { return this.internalPosition; });
32 | this.__defineSetter__("position", function(value) { this.internalPosition = value; });
33 | };
34 |
35 | Chunk.prototype.write = function(data, callback) {
36 | this.data.write(data, this.internalPosition);
37 | this.internalPosition = this.data.length();
38 | callback(null, this);
39 | };
40 |
41 | Chunk.prototype.read = function(length) {
42 | if(this.length() - this.internalPosition + 1 >= length) {
43 | var data = this.data.read(this.internalPosition, length);
44 | this.internalPosition = this.internalPosition + length;
45 | return data;
46 | } else {
47 | return '';
48 | }
49 | };
50 |
51 | Chunk.prototype.eof = function() {
52 | return this.internalPosition == this.length() ? true : false;
53 | };
54 |
55 | Chunk.prototype.getc = function() {
56 | return this.read(1);
57 | };
58 |
59 | Chunk.prototype.rewind = function() {
60 | this.internalPosition = 0;
61 | this.data = new Binary();
62 | };
63 |
64 | Chunk.prototype.save = function(callback) {
65 | var self = this;
66 |
67 | self.file.chunkCollection(function(err, collection) {
68 | collection.remove({'_id':self.objectId}, function(err, collection) {
69 | if(self.data.length() > 0) {
70 | self.buildMongoObject(function(mongoObject) {
71 | collection.insert(mongoObject, function(collection) {
72 | callback(null, self);
73 | });
74 | });
75 | } else {
76 | callback(null, self);
77 | }
78 | });
79 | });
80 | };
81 |
82 | Chunk.prototype.buildMongoObject = function(callback) {
83 | var mongoObject = {'_id': this.objectId,
84 | 'files_id': this.file.fileId,
85 | 'n': this.chunkNumber,
86 | 'data': this.data};
87 | callback(mongoObject);
88 | };
89 |
90 | Chunk.prototype.length = function() {
91 | return this.data.length();
92 | };
93 |
94 | Chunk.DEFAULT_CHUNK_SIZE = 1024 * 256;
--------------------------------------------------------------------------------
/gridfs/gridstore.js:
--------------------------------------------------------------------------------
1 | var BinaryParser = require('../bson/binary_parser').BinaryParser,
2 | Chunk = require('./chunk').Chunk,
3 | DbCommand = require('../commands/db_command').DbCommand,
4 | OrderedHash = require('../bson/collections').OrderedHash,
5 | Integer = require('../goog/math/integer').Integer,
6 | Long = require('../goog/math/long').Long,
7 | ObjectID = require('../bson/bson').ObjectID,
8 | Buffer = require('buffer').Buffer;
9 |
10 | var GridStore = exports.GridStore = function(db, filename, mode, options) {
11 | this.db = db;
12 | this.filename = filename;
13 | this.mode = mode == null ? "r" : mode;
14 | this.options = options == null ? {} : options;
15 | this.root = this.options['root'] == null ? exports.GridStore.DEFAULT_ROOT_COLLECTION : this.options['root'];
16 | this.position = 0;
17 | // Getters and Setters
18 | this.__defineGetter__("chunkSize", function() { return this.internalChunkSize; });
19 | this.__defineSetter__("chunkSize", function(value) {
20 | if(!(this.mode[0] == "w" && this.position == 0 && this.uploadDate == null)) {
21 | this.internalChunkSize = this.internalChunkSize;
22 | } else {
23 | this.internalChunkSize = value;
24 | }
25 | });
26 | this.__defineGetter__("md5", function() { return this.internalMd5; });
27 | this.__defineSetter__("md5", function(value) {});
28 | };
29 |
30 | GridStore.prototype.open = function(callback) {
31 | var self = this;
32 |
33 | this.collection(function(err, collection) {
34 | collection.find({'filename':self.filename}, function(err, cursor) {
35 | cursor.nextObject(function(err, doc) {
36 | // Chek if the collection for the files exists otherwise prepare the new one
37 | if(doc != null) {
38 | self.fileId = doc._id;
39 | self.contentType = doc.contentType;
40 | self.internalChunkSize = doc.chunkSize;
41 | self.uploadDate = doc.uploadDate;
42 | self.aliases = doc.aliases;
43 | self.length = doc.length;
44 | self.metadata = doc.metadata;
45 | self.internalMd5 = doc.md5;
46 | } else {
47 | self.fileId = new ObjectID();
48 | self.contentType = exports.GridStore.DEFAULT_CONTENT_TYPE;
49 | self.internalChunkSize = Chunk.DEFAULT_CHUNK_SIZE;
50 | self.length = 0;
51 | }
52 |
53 | // Process the mode of the object
54 | if(self.mode == "r") {
55 | self.nthChunk(0, function(err, chunk) {
56 | self.currentChunk = chunk;
57 | self.position = 0;
58 | callback(null, self);
59 | });
60 | } else if(self.mode == "w") {
61 | self.chunkCollection(function(err, collection2) {
62 | // Create index for the chunks
63 | collection.createIndex([['files_id', 1], ['n', 1]], function(err, index) {
64 | // Delete any existing chunks
65 | self.deleteChunks(function(err, result) {
66 | self.currentChunk = new Chunk(self, {'n':0});
67 | self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type'];
68 | self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size'];
69 | self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
70 | self.position = 0;
71 | callback(null, self);
72 | });
73 | });
74 | });
75 | } else if(self.mode == "w+") {
76 | self.chunkCollection(function(err, collection) {
77 | // Create index for the chunks
78 | collection.createIndex([['files_id', 1], ['n', 1]], function(err, index) {
79 | self.nthChunk(self.lastChunkNumber, function(err, chunk) {
80 | // Set the current chunk
81 | self.currentChunk = chunk == null ? new Chunk(self, {'n':0}) : chunk;
82 | self.currentChunk.position = self.currentChunk.data.length();
83 | self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
84 | self.position = self.length;
85 | callback(null, self);
86 | });
87 | });
88 | });
89 | } else {
90 | callback(new Error("Illegal mode " + self.mode), null);
91 | }
92 | });
93 | });
94 | });
95 | };
96 |
97 | GridStore.prototype.write = function(string, close, callback) {
98 | if(typeof close === "function") { callback = close; close = null; }
99 | var self = this;
100 | var finalClose = close == null ? false : close;
101 | string = string instanceof Buffer ? string.toString() : string;
102 |
103 | if(self.mode[0] != "w") {
104 | callback(new Error(self.filename + " not opened for writing"), null);
105 | } else {
106 | if((self.currentChunk.position + string.length) > self.chunkSize) {
107 | var previousChunkNumber = self.currentChunk.chunkNumber;
108 | var leftOverDataSize = self.chunkSize - self.currentChunk.position;
109 | var previousChunkData = string.substr(0, leftOverDataSize);
110 | var leftOverData = string.substr(leftOverData, (string.length - leftOverDataSize));
111 | // Let's finish the current chunk and then call write again for the remaining data
112 | self.currentChunk.write(previousChunkData, function(err, chunk) {
113 | chunk.save(function(err, result) {
114 | self.currentChunk = new Chunk(self, {'n': (previousChunkNumber + 1)});
115 | self.position = self.position + leftOverDataSize;
116 | // Write the remaining data
117 | self.write(leftOverData, function(err, gridStore) {
118 | if(finalClose) {
119 | self.close(function(err, result) {
120 | callback(null, gridStore);
121 | });
122 | } else {
123 | callback(null, gridStore);
124 | }
125 | });
126 | });
127 | });
128 | } else {
129 | self.currentChunk.write(string, function(err, chunk) {
130 | self.position = self.position + string.length;
131 | if(finalClose) {
132 | self.close(function(err, result) {
133 | callback(null, self);
134 | });
135 | } else {
136 | callback(null, self);
137 | }
138 | });
139 | }
140 | }
141 | };
142 |
143 | GridStore.prototype.buildMongoObject = function(callback) {
144 | // var mongoObject = new OrderedHash();
145 | var length = this.currentChunk != null ? (this.currentChunk.chunkNumber * this.chunkSize + this.currentChunk.position) : 0;
146 | var mongoObject = {
147 | '_id': this.fileId,
148 | 'filename': this.filename,
149 | 'contentType': this.contentType,
150 | 'length': length < 0 ? 0 : length,
151 | 'chunkSize': this.chunkSize,
152 | 'uploadDate': this.uploadDate,
153 | 'aliases': this.aliases,
154 | 'metadata': this.metadata
155 | };
156 |
157 | var md5Command = new OrderedHash();
158 | md5Command.add('filemd5', this.fileId).add('root', this.root);
159 |
160 | this.db.command(md5Command, function(err, results) {
161 | mongoObject.md5 = results.md5;
162 | callback(mongoObject);
163 | });
164 | };
165 |
166 | GridStore.prototype.close = function(callback) {
167 | var self = this;
168 |
169 | if(self.mode[0] == "w") {
170 | if(self.currentChunk != null && self.currentChunk.position > 0) {
171 | self.currentChunk.save(function(err, chuck) {
172 | self.collection(function(err, files) {
173 | // Build the mongo object
174 | if(self.uploadDate != null) {
175 | files.remove({'_id':self.fileId}, function(err, collection) {
176 | self.buildMongoObject(function(mongoObject) {
177 | files.save(mongoObject, function(err, doc) {
178 | callback(err, doc);
179 | });
180 | });
181 | });
182 | } else {
183 | self.uploadDate = new Date();
184 | self.buildMongoObject(function(mongoObject) {
185 | files.save( mongoObject, function(err, doc) {
186 | callback(err, doc);
187 | });
188 | });
189 | }
190 | });
191 | });
192 | } else {
193 | self.collection(function(err, files) {
194 | self.uploadDate = new Date();
195 | self.buildMongoObject(function(mongoObject) {
196 | files.save(mongoObject, function(err, doc) {
197 | callback(err, doc);
198 | });
199 | });
200 | });
201 | }
202 | } else {
203 | callback(new Error("Illegal mode " + self.mode), null);
204 | }
205 | };
206 |
207 | GridStore.prototype.nthChunk = function(chunkNumber, callback) {
208 | var self = this;
209 |
210 | self.chunkCollection(function(err, collection) {
211 | collection.find({'files_id':self.fileId, 'n':chunkNumber}, function(err, cursor) {
212 | cursor.nextObject(function(err, chunk) {
213 | var finalChunk = chunk == null ? {} : chunk;
214 | callback(null, new Chunk(self, finalChunk));
215 | });
216 | });
217 | });
218 | };
219 |
220 | GridStore.prototype.lastChunkNumber = function() {
221 | return Integer.fromNumber((self.length/self.chunkSize)).toInt();
222 | };
223 |
224 | GridStore.prototype.chunkCollection = function(callback) {
225 | this.db.collection((this.root + ".chunks"), callback);
226 | };
227 |
228 | GridStore.prototype.deleteChunks = function(callback) {
229 | var self = this;
230 |
231 | if(self.fileId != null) {
232 | self.chunkCollection(function(err, collection) {
233 | collection.remove({'files_id':self.fileId}, function(err, result) {
234 | callback(null, true);
235 | });
236 | });
237 | } else {
238 | callback(null, true);
239 | }
240 | };
241 |
242 | GridStore.prototype.collection = function(callback) {
243 | this.db.collection(this.root + ".files", function(err, collection) {
244 | callback(err, collection);
245 | });
246 | };
247 |
248 | GridStore.prototype.readlines = function(separator, callback) {
249 | var args = Array.prototype.slice.call(arguments, 0);
250 | callback = args.pop();
251 | separator = args.length ? args.shift() : null;
252 |
253 | this.read(function(err, data) {
254 | var items = data.split(separator);
255 | items = items.length > 0 ? items.splice(0, items.length - 1) : [];
256 | for(var i = 0; i < items.length; i++) {
257 | items[i] = items[i] + separator;
258 | }
259 | callback(null, items);
260 | });
261 | };
262 |
263 | GridStore.prototype.rewind = function(callback) {
264 | var self = this;
265 |
266 | if(this.currentChunk.chunkNumber != 0) {
267 | if(this.mode[0] == "w") {
268 | self.deleteChunks(function(err, gridStore) {
269 | self.currentChunk = new Chunk(self, {'n': 0});
270 | self.position = 0;
271 | callback(null, self);
272 | });
273 | } else {
274 | self.currentChunk(0, function(err, chunk) {
275 | self.currentChunk = chunk;
276 | self.currentChunk.rewind();
277 | self.position = 0;
278 | callback(null, self);
279 | });
280 | }
281 | } else {
282 | self.currentChunk.rewind();
283 | self.position = 0;
284 | callback(null, self);
285 | }
286 | };
287 |
288 | GridStore.prototype.read = function(length, buffer, callback) {
289 | var self = this;
290 |
291 | var args = Array.prototype.slice.call(arguments, 0);
292 | callback = args.pop();
293 | length = args.length ? args.shift() : null;
294 | buffer = args.length ? args.shift() : null;
295 |
296 | // The data is a c-terminated string and thus the length - 1
297 | var finalBuffer = buffer == null ? '' : buffer;
298 | var finalLength = length == null ? self.length - self.position : length;
299 | var numberToRead = finalLength;
300 |
301 | if((self.currentChunk.length() - self.currentChunk.position + 1 + finalBuffer.length) >= finalLength) {
302 | finalBuffer = finalBuffer + self.currentChunk.read(finalLength - finalBuffer.length);
303 | numberToRead = numberToRead - finalLength;
304 | self.position = finalBuffer.length;
305 | callback(null, finalBuffer);
306 | } else {
307 | finalBuffer = finalBuffer + self.currentChunk.read(self.currentChunk.length());
308 | numberToRead = numberToRead - self.currentChunk.length();
309 | // Load the next chunk and read some more
310 | self.nthChunk(self.currentChunk.chunkNumber + 1, function(err, chunk) {
311 | self.currentChunk = chunk;
312 | self.read(length, finalBuffer, callback);
313 | });
314 | }
315 | };
316 |
317 | GridStore.prototype.tell = function(callback) {
318 | callback(null, this.position);
319 | };
320 |
321 | GridStore.prototype.seek = function(position, seekLocation, callback) {
322 | var self = this;
323 |
324 | var args = Array.prototype.slice.call(arguments, 1);
325 | callback = args.pop();
326 | seekLocation = args.length ? args.shift() : null;
327 |
328 | var seekLocationFinal = seekLocation == null ? exports.GridStore.IO_SEEK_SET : seekLocation;
329 | var finalPosition = position;
330 | var targetPosition = 0;
331 | if(seekLocationFinal == exports.GridStore.IO_SEEK_CUR) {
332 | targetPosition = self.position + finalPosition;
333 | } else if(seekLocationFinal == exports.GridStore.IO_SEEK_END) {
334 | targetPosition = self.length + finalPosition;
335 | } else {
336 | targetPosition = finalPosition;
337 | }
338 |
339 | var newChunkNumber = Integer.fromNumber((targetPosition/self.chunkSize)).toInt();
340 | if(newChunkNumber != self.currentChunk.chunkNumber) {
341 | if(self.mode[0] == 'w') {
342 | self.currentChunk.save(function(err, chunk) {
343 | self.nthChunk(newChunkNumber, function(err, chunk) {
344 | self.currentChunk = chunk;
345 | self.position = targetPosition;
346 | self.currentChunk.position = (self.position % self.chunkSize);
347 | callback(null, self);
348 | });
349 | });
350 | }
351 | } else {
352 | self.position = targetPosition;
353 | self.currentChunk.position = (self.position % self.chunkSize);
354 | callback(null, self);
355 | }
356 | };
357 |
358 | GridStore.prototype.eof = function() {
359 | return this.position == this.length ? true : false;
360 | };
361 |
362 | GridStore.prototype.getc = function(callback) {
363 | var self = this;
364 |
365 | if(self.eof()) {
366 | callback(null, null);
367 | } else if(self.currentChunk.eof()) {
368 | self.nthChunk(self.currentChunk.chunkNumber + 1, function(err, chunk) {
369 | self.currentChunk = chunk;
370 | self.position = self.position + 1;
371 | callback(null, self.currentChunk.getc());
372 | });
373 | } else {
374 | self.position = self.position + 1;
375 | callback(null, self.currentChunk.getc());
376 | }
377 | };
378 |
379 | GridStore.prototype.puts = function(string, callback) {
380 | var finalString = string.match(/\n$/) == null ? string + "\n" : string;
381 | this.write(finalString, callback);
382 | };
383 |
384 | GridStore.DEFAULT_ROOT_COLLECTION = 'fs';
385 | GridStore.DEFAULT_CONTENT_TYPE = 'text/plain';
386 | GridStore.IO_SEEK_SET = 0;
387 | GridStore.IO_SEEK_CUR = 1;
388 | GridStore.IO_SEEK_END = 2;
389 |
390 | GridStore.exist = function(db, name, rootCollection, callback) {
391 | var args = Array.prototype.slice.call(arguments, 2);
392 | callback = args.pop();
393 | rootCollection = args.length ? args.shift() : null;
394 |
395 | var rootCollectionFinal = rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION;
396 | db.collection(rootCollectionFinal + ".files", function(err, collection) {
397 | collection.find({'filename':name}, function(err, cursor) {
398 | cursor.nextObject(function(err, item) {
399 | callback(null, item == null ? false : true);
400 | });
401 | });
402 | });
403 | };
404 |
405 | GridStore.list = function(db, rootCollection, callback) {
406 | var args = Array.prototype.slice.call(arguments, 1);
407 | callback = args.pop();
408 | rootCollection = args.length ? args.shift() : null;
409 |
410 | var rootCollectionFinal = rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION;
411 | var items = [];
412 | db.collection((rootCollectionFinal + ".files"), function(err, collection) {
413 | collection.find(function(err, cursor) {
414 | cursor.each(function(err, item) {
415 | if(item != null) {
416 | items.push(item.filename);
417 | } else {
418 | callback(null, items);
419 | }
420 | });
421 | });
422 | });
423 | };
424 |
425 | GridStore.read = function(db, name, length, offset, options, callback) {
426 | var args = Array.prototype.slice.call(arguments, 2);
427 | callback = args.pop();
428 | length = args.length ? args.shift() : null;
429 | offset = args.length ? args.shift() : null;
430 | options = args.length ? args.shift() : null;
431 |
432 | new GridStore(db, name, "r", options).open(function(err, gridStore) {
433 | // Make sure we are not reading out of bounds
434 | if(offset && offset >= gridStore.length) return callback("offset larger than size of file", null);
435 | if(length && length > gridStore.length) return callback("length is larger than the size of the file", null);
436 | if(offset && length && (offset + length) > gridStore.length) return callback("offset and length is larger than the size of the file", null);
437 |
438 | if(offset != null) {
439 | gridStore.seek(offset, function(err, gridStore) {
440 | gridStore.read(length, function(err, data) {
441 | callback(err, data);
442 | });
443 | });
444 | } else {
445 | gridStore.read(length, function(err, data) {
446 | callback(err, data);
447 | });
448 | }
449 | });
450 | };
451 |
452 | GridStore.readlines = function(db, name, separator, options, callback) {
453 | var args = Array.prototype.slice.call(arguments, 2);
454 | callback = args.pop();
455 | separator = args.length ? args.shift() : null;
456 | options = args.length ? args.shift() : null;
457 |
458 | var finalSeperator = separator == null ? "\n" : separator;
459 | new GridStore(db, name, "r", options).open(function(err, gridStore) {
460 | gridStore.readlines(finalSeperator, function(err, lines) {
461 | callback(err, lines);
462 | });
463 | });
464 | };
465 |
466 | GridStore.unlink = function(db, names, options, callback) {
467 | var self = this;
468 | var args = Array.prototype.slice.call(arguments, 2);
469 | callback = args.pop();
470 | options = args.length ? args.shift() : null;
471 |
472 | if(names.constructor == Array) {
473 | for(var i = 0; i < names.length; i++) {
474 | self.unlink(function(result) {
475 | if(i == (names.length - 1)) callback(null, self);
476 | }, db, names[i]);
477 | }
478 | } else {
479 | new GridStore(db, names, "w", options).open(function(err, gridStore) {
480 | gridStore.deleteChunks(function(err, result) {
481 | gridStore.collection(function(err, collection) {
482 | collection.remove({'_id':gridStore.fileId}, function(err, collection) {
483 | callback(err, self);
484 | });
485 | });
486 | });
487 | });
488 | }
489 | };
490 |
--------------------------------------------------------------------------------
/mongous.js:
--------------------------------------------------------------------------------
1 | var Long, bp, com, con, db, ee, mongous, mr, net;
2 | var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
3 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
4 | function ctor() { this.constructor = child; }
5 | ctor.prototype = parent.prototype;
6 | child.prototype = new ctor;
7 | child.__super__ = parent.prototype;
8 | return child;
9 | }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __slice = Array.prototype.slice;
10 | net = require('net');
11 | bp = require('./bson/binary_parser').BinaryParser;
12 | bu = require('./bson/binary_utils'),
13 | ee = require('events').EventEmitter;
14 | com = require('./commands').Commands;
15 | mr = require('./responses/mongo_reply').MongoReply;
16 | reply = require('./reply');
17 | Long = require('./goog/math/long').Long;
18 | MD5 = require('./crypto/md5').MD5;
19 | ObjectID = require('./bson/objectid').ObjectID;
20 |
21 | var log = function(s){
22 | process.stderr.write(s + '\n');
23 | };
24 | con = function() {
25 | function con() {
26 | con.__super__.constructor.apply(this, arguments);
27 | }
28 | __extends(con, ee);
29 | con.c = null;
30 | con.r = null;
31 | con.s = false;
32 | con.d = true;
33 | con.msg = [];
34 | con.reply = {};
35 | con.ms = 0;
36 | con.byt = 0;
37 | con.b = '';
38 | con.bb = '';
39 | con.port = 27017;
40 | con.host = '127.0.0.1';
41 | con.recon = true;
42 | con.config = {};
43 | con.depend = false;
44 |
45 | con.prototype.open = function(host, port, recon) {
46 | if(typeof host === 'string'){
47 | con.port = port || con.port;
48 | con.host = host || con.host;
49 | con.recon = recon ? recon : con.recon;
50 | } else {
51 | con.port = host.port || con.port;
52 | con.host = host.host || con.host;
53 | con.recon = host.recon ? host.recon : host.recon;
54 | con.config = host.config || con.config;
55 | con.depend = host.depend || con.depend;
56 | }
57 | con.r = function(res){ // function to handle all responses from Mongo
58 | reply(con,res);
59 | };
60 | con.c = new net.createConnection(con.port, con.host); //creates the connection
61 | con.c.addListener('connect', function() { // Mongo responds for the first time
62 | var MasterCmd;
63 | con.c.setTimeout(0);
64 | con.c.setNoDelay();
65 |
66 | MasterCmd = {
67 | collectionName: 'mongous.$cmd',
68 | queryOptions: 16,
69 | numberToSkip: 0,
70 | numberToReturn: -1,
71 | query: {
72 | ismaster: 1 // TODO!!!!! Check for replica-sets with 'ismaster' command! Then connect to primary.
73 | },
74 | returnFieldSelector: null
75 | };
76 | return con.c.write(com.binary(MasterCmd, 2004, 0), 'binary'); // this makes us the master of Mongo
77 |
78 | });
79 | function start(m){
80 | var spawn = require('child_process').spawn,
81 | config = [];
82 | con.config.port = con.config.port || con.port;
83 | con.config.bind_ip = con.config.bind_ip || con.config.host || con.host;
84 | for(var i in con.config){
85 | if(__hasProp.call(con.config,i)){
86 | config.push('--'+i);
87 | if(con.config[i] !== true){
88 | config.push(con.config[i]);
89 | }
90 | }
91 | }
92 | con.local = (con.config.bind_ip.toLowerCase() === 'localhost' || con.config.bind_ip === '127.0.0.1')? true : false;
93 | if(!con.local || con.depend){ return; }
94 | if(process.env.MONGOUS_LOCK != undefined
95 | && process.env.MONGOUS_LOCK != process.pid){
96 | return setTimeout(function(){ m.open(con.host,con.port) }, 100);
97 | }
98 | process.env.MONGOUS_LOCK = process.pid;
99 | if(!start.count){
100 | start.count += 1;
101 | return setTimeout(function(){ start(m) }, 50);
102 | }
103 | var mongod = spawn('mongod',config);
104 | mongod.on('exit',function(c,s){
105 | if(process.env.MONGOUS_LOCK == process.pid){
106 | process.env.MONGOUS_LOCK = ''; // 0 and false don't work, cause they are cast to strings!
107 | }
108 | log("Mongod exited");
109 | start(m); // don't want auto-restart? Set depend = true.
110 | });
111 | mongod.stderr.on('data',function(d){
112 | log(d.toString());
113 | });
114 | mongod.stdout.setEncoding('utf8');
115 | mongod.stdout.on('data', __bind(function (data) {
116 | if (/\[initandlisten\] waiting for connections on port/.test(data)){
117 | m.open(con.host,con.port);
118 | }
119 | }, m));
120 | };
121 | start.count = 0;
122 | con.c.addListener('error', __bind(function(e) {
123 | if(e && e.code == 'ECONNREFUSED'){
124 | if((require('fs').existsSync||require('path').existsSync)('/usr/local/bin/mongod')) start(this);
125 | } else {
126 | log('Mongous : '+e);
127 | //return con.c.emit('error', e);
128 | }
129 | }, this));
130 | con.c.addListener('close', __bind(function() {
131 | //return con.c.emit('close');
132 | }, this));
133 | con.c.som = 0;
134 | con.c.br = 0;
135 | con.c.b = new Buffer(0);
136 | con.c.sb = '';
137 | con.c.addListener('data', con.r); // listen for it!
138 | return con.c;
139 | };
140 |
141 | con.prototype.close = function() {
142 | if (con.c) {
143 | return con.c.end();
144 | }
145 | };
146 | con.prototype.send = function(cmd) { // receive BSON command
147 | var nc, send = (function(e){
148 | if(con.c._connecting) { // if we are in the middle of connecting
149 | con.msg.push(cmd); // queue the commands in order
150 | con.ccc = (function(c) { // listen for when we are connected
151 | var _results;
152 | _results = [];
153 | while (con.msg.length > 0) { //then shuffle them out to Mongo
154 | _results.push(c.write(con.msg.shift(), 'binary'));
155 | }
156 | return _results;
157 | });
158 | } else if (con.recon) { // n-m-n thing, was broken. I assume it does the same as above, except during reconnect
159 | con.msg.push(cmd);
160 | if (con.c.currently_reconnecting === null) {
161 | con.c.currently_reconnecting = true;
162 | nc = net.createConnection(con.port, con.host);
163 | return nc.addListener('connect', __bind(function() {
164 | var _results;
165 | this.setTimeout(0);
166 | this.setNoDelay();
167 | this.addListener('data', con.r);
168 | con.c = this;
169 | _results = [];
170 | while (con.msg.length > 0) {
171 | _results.push(this.write(con.msg.shift(), 'binary'));
172 | }
173 | return _results;
174 | }, this));
175 | }
176 | } else {
177 | //console.log(con.c);
178 | process.stderr.write('Error: readyState not defined\n');
179 | return false;
180 | }
181 | });
182 | if(con.s){
183 | try {
184 | return con.c.write(cmd, 'binary'); // send it to Mongo
185 | }catch(e) {
186 | process.stderr.write("MONGOUS.con.send -> con.c.write fail\n");
187 | send();
188 | }
189 | } else {
190 | send();
191 | }
192 | };
193 | con.prototype.log = function(info) {
194 | process.stderr.write('log', " - " + info + '\n');
195 | return false;
196 | };
197 | con.prototype.leg = function(error) {
198 | process.stderr.write(" - Error: " + error.toString().replace(/error:/i, '') + '\n');
199 | return false;
200 | };
201 | return con;
202 | }();
203 | mongous = function() {
204 | __extends(mongous, con);
205 | function mongous(s) { // checks for a valid db and collection name
206 | if(!s) return false;
207 | var e, p;
208 | e = false;
209 | if (con.c === null) { // if we haven't connected yet, then connect
210 | this.open(con.host,con.port);
211 | }
212 | if (s.length >= 80) {
213 | process.stderr.write("Error: '" + s + "' - Database name and collection exceed 80 character limit.\n");
214 | e = true;
215 | }
216 | p = s.search(/\./);
217 | if (p <= 0) {
218 | process.stderr.write("Error: '" + s + "' - Database.collection nomenclature required\n");
219 | e = true;
220 | }
221 | this.db = s.slice(0, p);
222 | this.col = s.substr(p + 1);
223 | if(this.col != '$cmd') {
224 | if (this.col.search(/\$/) >= 0) {
225 | if (this.col.search(/\$cmd/i) < 0) {
226 | process.stderr.write("Error: '" + s + "' - cannot use '$' unless for commands.\n");
227 | e = true;
228 | } else {
229 | process.stderr.write("Error: '" + s + "' - silent.\n");
230 | e = true;
231 | }
232 | } else
233 | if (this.col.search(/^[a-z|\_]/i) < 0) {
234 | process.stderr.write("Error: '" + s + "' - Collection must start with a letter or an underscore.\n");
235 | e = true;
236 | }
237 | }
238 | if (e) {
239 | this.db = '!';
240 | this.col = '$';
241 | }
242 | this;
243 | }
244 | mongous.prototype.auth = function() {
245 | var usr, pwd, self, fn;
246 | usr = arguments[0], pwd = arguments[1], fn = arguments[2];
247 | if(!usr || !pwd) {
248 | process.stderr.write("User and password required.\n");
249 | return false;
250 | }
251 | self = this;
252 | this.find({getnonce:1}, function(r) {
253 | var n = r.documents[0].nonce;
254 | self.find({
255 | authenticate: 1,
256 | user: usr,
257 | nonce: n,
258 | key: MD5.hex_md5(n+usr+MD5.hex_md5(usr+":mongo:"+pwd))
259 | }, function(res) {
260 | if(fn) {
261 | return fn(res);
262 | }
263 | }, 1);
264 | }, 1);
265 | }
266 | mongous.prototype.open = function() {
267 | return mongous.__super__.open.apply(this, arguments);
268 | };
269 | mongous.prototype.send = function(cmd, op, id) {
270 | if (cmd.collectionName === '!.$') { // YIPES! Invalid db and col!
271 | return false;
272 | } else { // safe :)
273 | id || (id = this.id());
274 |
275 | return mongous.__super__.send.call(this, com.binary(cmd, op, id)); // convert to binary, send to connection
276 | }
277 | };
278 | mongous.prototype.update = function() {
279 | var a, b, c, cmd, m, u;
280 | a = arguments[0], b = arguments[1], c = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
281 | if (!a || !b) {
282 | process.stderr.write("Query and document required.\n");
283 | }
284 | if (c[0] || c.length === 2) {
285 | if (c[0] instanceof Object) {
286 | m = c[0].multi ? 1 : 0;
287 | u = c[0].upsert ? 1 : 0;
288 | } else {
289 | u = c[0] ? 1 : 0;
290 | m = c[1] ? 1 : 0;
291 | }
292 | } else {
293 | m = u = 0;
294 | }
295 | cmd = {
296 | collectionName: this.db + '.' + this.col,
297 | flags: parseInt(m.toString() + u.toString()),
298 | spec: a,
299 | document: b
300 | };
301 | return this.send(cmd, 2001);
302 | };
303 | var CID = 0;
304 | mongous.prototype.find = function() {
305 | var a, cmd, docs, f, fn, i, id, it, num, o, obj, q, _i, _len;
306 | a = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
307 | if (!a) {
308 | this.leg("Callback required");
309 | }
310 | obj = [];
311 | num = [];
312 | for (_i = 0, _len = a.length; _i < _len; _i++) {
313 | i = a[_i];
314 | if (Object.prototype.toString.call(i) === "[object Function]") {
315 | fn = i;
316 | } else if (Object.prototype.toString.call(i) === "[object Object]") {
317 | obj.push(i);
318 | } else if (!isNaN(i)) {
319 | num.push(i);
320 | }
321 | }
322 | q = obj[0] ? obj[0] : {};
323 | f = obj[1] ? obj[1] : null;
324 | o = obj[2] ? obj[2] : {};
325 | if(o.join != void 0) {
326 |
327 | }
328 | if(o.sort != void 0) {
329 | q = {$query: q, $orderby: o.sort};
330 | }
331 | // auto convert from _id string to ObjectID
332 | if(q._id && typeof q._id === 'string' && /^[0-9a-f]{24}$/.test(q._id)){
333 | q._id = new ObjectID(q._id);
334 | }
335 | o.lim = o.lim !== void 0 ? o.lim : num[0] ? num[0] : 0;
336 | o.skip = o.skip !== void 0 ? o.skip : num[1] ? num[1] : 0;
337 | cmd = {
338 | collectionName: (o.$db || this.db) + '.' + (o.$col || this.col),
339 | numberToSkip: o.skip,
340 | numberToReturn: o.lim,
341 | query: q,
342 | returnFieldSelector: f
343 | };
344 | id = this.id();
345 | docs = [];
346 | it = 0;
347 | con.reply[id.toString()] = __bind(function(msg){
348 | var lim;
349 | it += msg.numberReturned;
350 | if (msg.more && o.lim == 0) {
351 | //lim = o.lim - it < 500 ? 500 : o.lim - it;
352 | this.more(cmd.collectionName, 500, msg.cursorID, id);
353 | } else {
354 | delete con.reply[id.toString()];
355 | }
356 | var next = __bind(function(wait, a){
357 | if(o.join && wait && a) {
358 | if(a.obj(wait).each(function(v,i){
359 | if(v) return v;
360 | })){ return }
361 | }
362 | if (fn) {
363 | return fn(msg);
364 | }
365 | },this);
366 | var self = this;
367 | if(o.join && msg.documents && msg.documents.length){
368 | var a = require('theory')()
369 | , docs = msg.documents
370 | , wait = {};
371 | a.obj(o.join).each(function(to, on, t){
372 | wait[on] = 1;
373 | var q = {}, db, col;
374 | if(to[0] === '$'){
375 | to = to.split('.');
376 | db = to.shift().replace('$','');
377 | to = '.' + to.join('.');
378 | }
379 | if(to[0] === '.'){
380 | to = to.split('.');
381 | to.shift(); // get rid of empty ''.
382 | col = to.shift();
383 | to = to.join('.');
384 | }
385 | q[to] = {$in:[]};
386 | a.list(docs).each(function(doc,i){
387 | if(doc && (i = a(doc, on)) !== undefined){
388 | q[to].$in.push(i);
389 | }
390 | });
391 | self.find(q, {}, {$db: db, $col: col}, function(m){
392 | if(m && m.documents && m.documents.length){
393 | a.list(m.documents).each(function(doc,val,t){
394 | if(doc && (val = a(doc,to)) !== undefined){
395 | a.list(docs).each(function(at){
396 | var w = {
397 | l: on.split('.').length
398 | ,f: a.text(on).clip('.',-1)
399 | ,p: a.text(on).clip('.',0,-1)
400 | };
401 | w.o = w.l === 1? at : a(at, o.p);
402 | if(w.o[w.f] === val){
403 | w.o[w.f] = doc;
404 | }
405 | });
406 | }
407 | });
408 | }
409 | wait[on] = 0;
410 | next(wait, a);
411 | });
412 | });
413 | } else {
414 | next();
415 | }
416 | },this);
417 | return this.send(cmd, 2004, id);
418 | };
419 | mongous.prototype.remove = function() {
420 | var a, b, cmd, m, r = 0; // r=reserved & must be 0 (as per the spec)
421 | a = arguments[0], b = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
422 | if (!a) {
423 | process.stderr.write("Query required.\n");
424 | }
425 | if (b[0] || b.length === 1) {
426 | m = b[0] ? 1 : 0; // atomic
427 | } else {
428 | m = 0;
429 | }
430 | cmd = {
431 | collectionName: this.db + '.' + this.col,
432 | flags: parseInt(m.toString() + r.toString()),
433 | spec: a
434 | };
435 | return this.send(cmd, 2006);
436 | };
437 | mongous.prototype.more = function(a, b, c, d) {
438 | var cmd;
439 | cmd = {
440 | collectionName: a,
441 | numberToReturn: b,
442 | cursorID: c
443 | };
444 | return this.send(cmd, 2005, d);
445 | };
446 | mongous.prototype.insert = function() {
447 | var a, cmd, docs;
448 | a = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
449 | docs = a[0] instanceof Array ? a[0] : a;
450 | cmd = {
451 | collectionName: this.db + '.' + this.col,
452 | documents: docs
453 | };
454 | return this.send(cmd, 2002);
455 | };
456 | mongous.prototype.save = function(a) {
457 | return this.update(a, a, 1);
458 | };
459 | mongous.prototype.log = function(info) {
460 | return this.emit('log', " - " + info);
461 | };
462 | mongous.prototype.leg = function(error) {
463 | return this.emit('log', " - Error: " + error.toString().replace(/error:/i, ''));
464 | };
465 | mongous.prototype.id = function() {
466 | return Math.round(Math.random() * 80000);
467 | };
468 | return mongous;
469 | }();
470 | db = function() {
471 | function db(s) {
472 | return new mongous(s);
473 | }
474 | return db;
475 | }();
476 | exports.Mongous = db;
477 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | { "name": "mongous"
2 | , "version": "0.2.7"
3 | , "author": "Mark Nadal"
4 | , "description": "Simple MongoDB driver"
5 | , "homepage": "http://github.com/amark/mongous"
6 | , "engines": ["node >= 0.2.2"]
7 | , "main": "mongous"
8 | }
9 |
--------------------------------------------------------------------------------
/reply.js:
--------------------------------------------------------------------------------
1 | var mr = require('./responses/mongo_reply').MongoReply;
2 | module.exports = (function(con,res){
3 | if(con.c.br > 0 && con.c.som > 0){
4 | var rb = con.c.som - con.c.br;
5 | if(rb > res.length) {
6 | var b = new Buffer(con.c.b.length + res.length);
7 | con.c.b.copy(b, 0,0, con.c.b.length);
8 | res.copy(b, con.c.b.length,0, res.length);
9 | con.c.b = b;
10 | con.c.br = con.c.br + res.length
11 | } else {
12 | var b = new Buffer(con.c.b.length + res.length);
13 | con.c.b.copy(b, 0,0, con.c.b.length);
14 | res.copy(b, con.c.b.length,0, rb);
15 | var r = new mr(b), rts;
16 | rts = r.responseTo.toString();
17 | if(con.reply[rts]){
18 | con.reply[rts](r);
19 | } else {
20 | con.c.emit(rts,r);
21 | }
22 | con.c.b = new Buffer(0);
23 | con.c.br = 0;
24 | con.c.som = 0;
25 | if(rb < res.length){
26 | con.r(res.slice(rb, res.length));
27 | }
28 | }
29 | } else {
30 | if(con.c.sb.length > 0){
31 | var b = new Buffer(con.c.sb.length + res.length);
32 | con.c.sb.copy(b, 0,0, con.c.sb.length);
33 | res.copy(b, con.c.sb.length,0, res.length);
34 | res = b;
35 | con.c.sb = new Buffer(0);
36 | }
37 | if(res.length > 4){
38 | var som = bu.decodeUInt32(res, 0);
39 | if(som > res.length){
40 | var b = new Buffer(con.c.b.length + res.length);
41 | con.c.b.copy(b, 0,0, con.c.b.length);
42 | res.copy(b, con.c.b.length,0, res.length);
43 | con.c.b = b;
44 | con.c.br = res.length;
45 | con.c.som = som;
46 | } else if(som <= res.length){
47 | var r = new mr(res.slice(0,som));
48 | if(con.s){
49 | var rts = r.responseTo.toString();
50 | if(con.reply[rts]){
51 | con.reply[rts](r);
52 | } else {
53 | con.c.emit(rts,r);
54 | }
55 | } else {
56 | if(r.documents.length && r.documents[0].ismaster){
57 | con.s = true;
58 | con.c.emit('connected',con.s);
59 | if(con.ccc) con.ccc(con.c);
60 | } else {
61 | con.s = false;
62 | }
63 | }
64 | if(som < res.length) {
65 | con.r(res.slice(som,res.length));
66 | }
67 | }
68 | } else {
69 | con.c.sb = res;
70 | }
71 | }
72 | });
73 |
--------------------------------------------------------------------------------
/responses/mongo_reply.js:
--------------------------------------------------------------------------------
1 | var Long = require('../goog/math/long').Long,
2 | //debug = require('util').debug,
3 | //inspect = require('util').inspect,
4 | binaryutils = require('../bson/binary_utils'),
5 | BSON = require('../bson/bson').BSON;
6 |
7 | /**
8 | Reply message from mongo db
9 | **/
10 | var MongoReply = exports.MongoReply = function(binary_reply) {
11 | // debug("------------------------------------------------------------------------- 1")
12 | // debug(inspect(binary_reply.length))
13 | // // debug(inspect(data))
14 | // for(var j = 0; j < binary_reply.length; j++) {
15 | // // debug("------")
16 | // debug(binary_reply[j] + " :: " + binary_reply.toString('ascii', j, j + 1))
17 | // }
18 |
19 | this.documents = [];
20 | var index = 0;
21 | // Unpack the standard header first
22 | var messageLength = binaryutils.decodeUInt32(binary_reply, index);
23 | index = index + 4;
24 | // Fetch the request id for this reply
25 | this.requestId = binaryutils.decodeUInt32(binary_reply, index);
26 | index = index + 4;
27 | // Fetch the id of the request that triggered the response
28 | this.responseTo = binaryutils.decodeUInt32(binary_reply, index);
29 | // Skip op-code field
30 | index = index + 4 + 4;
31 | // Unpack the reply message
32 | this.responseFlag = binaryutils.decodeUInt32(binary_reply, index);
33 | index = index + 4;
34 | // Unpack the cursor id (a 64 bit long integer)
35 | var low_bits = binaryutils.decodeUInt32(binary_reply, index);
36 | var high_bits = binaryutils.decodeUInt32(binary_reply, index + 4);
37 |
38 | this.cursorID = new Long(low_bits, high_bits);
39 | if (this.cursorID.greaterThan(Long.fromInt(0)))
40 | this.more = true
41 | index = index + 8;
42 | // Unpack the starting from
43 | this.startingFrom = binaryutils.decodeUInt32(binary_reply, index);
44 | index = index + 4;
45 | // Unpack the number of objects returned
46 | this.numberReturned = binaryutils.decodeUInt32(binary_reply, index);
47 | index = index + 4;
48 |
49 | // Let's unpack all the bson document, deserialize them and store them
50 | for(var object_index = 0; object_index < this.numberReturned; object_index++) {
51 | // Read the size of the bson object
52 | var bsonObjectSize = binaryutils.decodeUInt32(binary_reply, index);
53 |
54 | // debug("================================================================== bsonObjectSize = " + bsonObjectSize)
55 | // Deserialize the object and add to the documents array
56 | this.documents.push(BSON.deserialize(binary_reply.slice(index, index + bsonObjectSize)));
57 | MRnumify(this.documents[this.documents.length-1])
58 | // Adjust binary index to point to next block of binary bson data
59 | index = index + bsonObjectSize;
60 | }
61 | // debug("--------------------------------------------------- docs")
62 | // debug(inspect(this.documents))
63 | };
64 |
65 | var MRnumify = function(doc){
66 | for(var i in doc){
67 | if(doc[i] instanceof Long){
68 | doc[i] = doc[i].toNumber();
69 | } else if(typeof doc[i] == 'object' || doc[i] instanceof Array){
70 | MRnumify(doc[i]);
71 | }
72 | }
73 | }
74 |
75 | MongoReply.prototype.is_error = function(){
76 | if(this.documents.length == 1) {
77 | return this.documents[0].ok == 1 ? false : true;
78 | }
79 | return false;
80 | };
81 |
82 | MongoReply.prototype.error_message = function() {
83 | return this.documents.length == 1 && this.documents[0].ok == 1 ? '' : this.documents[0].errmsg;
84 | };
--------------------------------------------------------------------------------
/responses/mongo_reply_old.js:
--------------------------------------------------------------------------------
1 | var BinaryParser = require('../bson/binary_parser').BinaryParser,
2 | Integer = require('../goog/math/integer').Integer,
3 | Long = require('../goog/math/long').Long,
4 | BSON = require('../bson/bson').BSON;
5 |
6 | /**
7 | Reply message from mongo db
8 | **/
9 | var MongoReply = exports.MongoReply = function(binary_reply) {
10 | this.documents = [];
11 | var index = 0;
12 | // Unpack the standard header first
13 | var messageLength = BinaryParser.toInt(binary_reply.substr(index, 4));
14 | index = index + 4;
15 | // Fetch the request id for this reply
16 | this.requestId = BinaryParser.toInt(binary_reply.substr(index, 4));
17 | index = index + 4;
18 | // Fetch the id of the request that triggered the response
19 | this.responseTo = BinaryParser.toInt(binary_reply.substr(index, 4));
20 | // Skip op-code field
21 | index = index + 4 + 4;
22 | // Unpack the reply message
23 | this.responseFlag = BinaryParser.toInt(binary_reply.substr(index, 4));
24 | index = index + 4;
25 | // Unpack the cursor id (a 64 bit long integer)
26 | var low_bits = Integer.fromInt(BinaryParser.toInt(binary_reply.substr(index, 4)));
27 | var high_bits = Integer.fromInt(BinaryParser.toInt(binary_reply.substr(index + 4, 4)));
28 | this.cursorId = new Long(low_bits, high_bits);
29 | if (this.cursorId.greaterThan(Long.fromInt(0)))
30 | this.more = true
31 | index = index + 8;
32 | // Unpack the starting from
33 | this.startingFrom = BinaryParser.toInt(binary_reply.substr(index, 4));
34 | index = index + 4;
35 | // Unpack the number of objects returned
36 | this.numberReturned = BinaryParser.toInt(binary_reply.substr(index, 4));
37 | index = index + 4;
38 | // Let's unpack all the bson document, deserialize them and store them
39 | for(var object_index = 0; object_index < this.numberReturned; object_index++) {
40 | // Read the size of the bson object
41 | var bsonObjectSize = BinaryParser.toInt(binary_reply.substr(index, 4));
42 | // Read the entire object and deserialize it
43 | this.documents.push(BSON.deserialize(binary_reply.substr(index, bsonObjectSize)));
44 | // Adjust for next object
45 | index = index + bsonObjectSize;
46 | var numint = this.documents[this.documents.length-1].when;
47 | console.log(numint);
48 | //console.log(Long((numint||{}).low_,(numint||{}).high_));
49 | //console.log(numint.toInt());
50 | }
51 | };
52 |
53 | MongoReply.prototype.is_error = function(){
54 | if(this.documents.length == 1) {
55 | return this.documents[0].ok == 1 ? false : true;
56 | }
57 | return false;
58 | };
59 |
60 | MongoReply.prototype.error_message = function() {
61 | return this.documents.length == 1 && this.documents[0].ok == 1 ? '' : this.documents[0].errmsg;
62 | };
--------------------------------------------------------------------------------
/responses/mr.js:
--------------------------------------------------------------------------------
1 | var Long = require('../goog/math/long').Long,
2 | //debug = require('util').debug,
3 | //inspect = require('util').inspect,
4 | binaryutils = require('../bson/binary_utils');
5 |
6 | /**
7 | Reply message from mongo db
8 | **/
9 | var MongoReply = exports.MongoReply = function(db, binary_reply) {
10 | // debug("------------------------------------------------------------------------- 1")
11 | // debug(inspect(binary_reply.length))
12 | // // debug(inspect(data))
13 | // for(var j = 0; j < binary_reply.length; j++) {
14 | // // debug("------")
15 | // debug(binary_reply[j] + " :: " + binary_reply.toString('ascii', j, j + 1))
16 | // }
17 |
18 | this.documents = [];
19 | var index = 0;
20 | // Unpack the standard header first
21 | var messageLength = binaryutils.decodeUInt32(binary_reply, index);
22 | index = index + 4;
23 | // Fetch the request id for this reply
24 | this.requestId = binaryutils.decodeUInt32(binary_reply, index);
25 | index = index + 4;
26 | // Fetch the id of the request that triggered the response
27 | this.responseTo = binaryutils.decodeUInt32(binary_reply, index);
28 | // Skip op-code field
29 | index = index + 4 + 4;
30 | // Unpack the reply message
31 | this.responseFlag = binaryutils.decodeUInt32(binary_reply, index);
32 | index = index + 4;
33 | // Unpack the cursor id (a 64 bit long integer)
34 | var low_bits = binaryutils.decodeUInt32(binary_reply, index);
35 | var high_bits = binaryutils.decodeUInt32(binary_reply, index + 4);
36 |
37 | this.cursorId = new db.bson_deserializer.Long(low_bits, high_bits);
38 | if (this.cursorId.greaterThan(Long.fromInt(0)))
39 | this.more = true
40 | index = index + 8;
41 | // Unpack the starting from
42 | this.startingFrom = binaryutils.decodeUInt32(binary_reply, index);
43 | index = index + 4;
44 | // Unpack the number of objects returned
45 | this.numberReturned = binaryutils.decodeUInt32(binary_reply, index);
46 | index = index + 4;
47 |
48 | // Let's unpack all the bson document, deserialize them and store them
49 | for(var object_index = 0; object_index < this.numberReturned; object_index++) {
50 | // Read the size of the bson object
51 | var bsonObjectSize = binaryutils.decodeUInt32(binary_reply, index);
52 |
53 | // debug("================================================================== bsonObjectSize = " + bsonObjectSize)
54 | // Deserialize the object and add to the documents array
55 | this.documents.push(db.bson_deserializer.BSON.deserialize(binary_reply.slice(index, index + bsonObjectSize)));
56 | // Adjust binary index to point to next block of binary bson data
57 | index = index + bsonObjectSize;
58 | }
59 | // debug("--------------------------------------------------- docs")
60 | // debug(inspect(this.documents))
61 | };
62 |
63 | MongoReply.prototype.is_error = function(){
64 | if(this.documents.length == 1) {
65 | return this.documents[0].ok == 1 ? false : true;
66 | }
67 | return false;
68 | };
69 |
70 | MongoReply.prototype.error_message = function() {
71 | return this.documents.length == 1 && this.documents[0].ok == 1 ? '' : this.documents[0].errmsg;
72 | };
--------------------------------------------------------------------------------