├── 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 | }; --------------------------------------------------------------------------------