正在显示
37 个修改的文件
包含
6603 行增加
和
28 行删除
| @@ -12,23 +12,46 @@ var userController =function (){ | @@ -12,23 +12,46 @@ var userController =function (){ | ||
| 12 | userController.prototype.addUser = async(ctx, next) =>{ | 12 | userController.prototype.addUser = async(ctx, next) =>{ |
| 13 | var params = ctx.request.body; | 13 | var params = ctx.request.body; |
| 14 | const pw = saitMd5.md5AddSalt(params.password) | 14 | const pw = saitMd5.md5AddSalt(params.password) |
| 15 | + console.dir(params.password.length,7) | ||
| 16 | + console.dir(params.password.length<6) | ||
| 17 | + | ||
| 15 | 18 | ||
| 16 | if(!params.loginName){ | 19 | if(!params.loginName){ |
| 17 | return status.paramError('loginName'); | 20 | return status.paramError('loginName'); |
| 18 | }else if(!params.password){ | 21 | }else if(!params.password){ |
| 19 | - return status.paramError('password',' 不能为空'); | 22 | + return status.paramError('password','不能为空'); |
| 23 | + }if(params.password.length < 6){ | ||
| 24 | + return status.paramError('password','不得小于6位'); | ||
| 20 | } | 25 | } |
| 21 | - | ||
| 22 | var user = { | 26 | var user = { |
| 23 | loginName:params.loginName, | 27 | loginName:params.loginName, |
| 24 | password:pw.md5Pass, | 28 | password:pw.md5Pass, |
| 25 | - salt:pw.salt | 29 | + salt:pw.salt, |
| 30 | + userType:params.type | ||
| 26 | } | 31 | } |
| 27 | try{ | 32 | try{ |
| 28 | return await userService.addUser(user) | 33 | return await userService.addUser(user) |
| 29 | - }catch (we){ | 34 | + }catch (e){ |
| 35 | + throw new Error(e); | ||
| 36 | + } | ||
| 37 | +} | ||
| 38 | +userController.prototype.login = async(ctx, next) =>{ | ||
| 39 | + const body = ctx.request.body; | ||
| 40 | + if(!body.name){ | ||
| 41 | + return status.paramError('name'); | ||
| 42 | + }else if(!body.password){ | ||
| 43 | + return status.paramError('password'); | ||
| 44 | + } | ||
| 30 | 45 | ||
| 46 | + try{ | ||
| 47 | + // let userData = await userService.login(body.name ,body.password); | ||
| 48 | + // delete userData.password; | ||
| 49 | + // delete userData.salt; | ||
| 50 | + return await userService.login(body.name ,body.password); | ||
| 51 | + | ||
| 52 | + }catch (we){ | ||
| 53 | + throw new Error(we) | ||
| 31 | } | 54 | } |
| 32 | - | 55 | + |
| 33 | } | 56 | } |
| 34 | module.exports = new userController(); | 57 | module.exports = new userController(); |
docs/api.md
0 → 100644
| 1 | +# 网校接口文档 | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +## 用户管理 | ||
| 5 | + | ||
| 6 | +### 用户注册 | ||
| 7 | + | ||
| 8 | +请求url: | ||
| 9 | + | ||
| 10 | + POST /users/addUser | ||
| 11 | + | ||
| 12 | +请求参数: | ||
| 13 | + | ||
| 14 | +名称|类型|描述 | ||
| 15 | +:--|:--|:-- | ||
| 16 | +|loginName |string |必须, 登录名 | | ||
| 17 | +|password |string |必须,密码 | | ||
| 18 | +|type | int |用户类型:0管理员 1监课 2老师 4学生 | | ||
| 19 | + | ||
| 20 | +请求示例: | ||
| 21 | + | ||
| 22 | + localhost:3000/users/addUser | ||
| 23 | + | ||
| 24 | + body | ||
| 25 | + { | ||
| 26 | + "loginName": "admin", | ||
| 27 | + "telephone": 11112112, | ||
| 28 | + "password": "123456", | ||
| 29 | + "type":1 | ||
| 30 | + } | ||
| 31 | +返回参数: | ||
| 32 | + | ||
| 33 | + { | ||
| 34 | + "id": "XWBreEM4OK0a5jQB2Q1bpkNlyq9AVmvd",// 用户ID | ||
| 35 | + "createTime": "2017-08-22T08:51:59.000Z", //创建时间 | ||
| 36 | + "endTime": "2017-08-22T08:51:59.000Z", | ||
| 37 | + "loginName": "admin", //登录名 | ||
| 38 | + "userType": 1 // 用户类型 | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +### 用户登录 | ||
| 42 | + | ||
| 43 | +请求url | ||
| 44 | + | ||
| 45 | + POST /users/login | ||
| 46 | + | ||
| 47 | +请求参数: | ||
| 48 | + | ||
| 49 | +名称|类型|描述 | ||
| 50 | +:--|:--|:-- | ||
| 51 | +|name |string |必须, 登录名 | | ||
| 52 | +|password |string |必须,密码 | | ||
| 53 | + | ||
| 54 | + | ||
| 55 | +请求示例: | ||
| 56 | + | ||
| 57 | + localhost:3000/users/login | ||
| 58 | + | ||
| 59 | + body | ||
| 60 | + { | ||
| 61 | + "name":"admin", | ||
| 62 | + "password":"123456" | ||
| 63 | + } | ||
| 64 | +返回参数: | ||
| 65 | + | ||
| 66 | + | ||
| 67 | + |
| 1 | +Tue Aug 22 2017 18:52:38 GMT+0800 (CST) |
node_modules/_bson@1.0.4@bson/HISTORY.md
0 → 100644
| 1 | +1.0.4 2016-01-11 | ||
| 2 | +---------------- | ||
| 3 | +- #204 remove Buffer.from as it's partially broken in early 4.x.x. series of node releases. | ||
| 4 | + | ||
| 5 | +1.0.3 2016-01-03 | ||
| 6 | +---------------- | ||
| 7 | +- Fixed toString for ObjectId so it will work with inspect. | ||
| 8 | + | ||
| 9 | +1.0.2 2016-01-02 | ||
| 10 | +---------------- | ||
| 11 | +- Minor optimizations for ObjectID to use Buffer.from where available. | ||
| 12 | + | ||
| 13 | +1.0.1 2016-12-06 | ||
| 14 | +---------------- | ||
| 15 | +- Reverse behavior for undefined to be serialized as NULL. MongoDB 3.4 does not allow for undefined comparisons. | ||
| 16 | + | ||
| 17 | +1.0.0 2016-12-06 | ||
| 18 | +---------------- | ||
| 19 | +- Introduced new BSON API and documentation. | ||
| 20 | + | ||
| 21 | +0.5.7 2016-11-18 | ||
| 22 | +----------------- | ||
| 23 | +- NODE-848 BSON Regex flags must be alphabetically ordered. | ||
| 24 | + | ||
| 25 | +0.5.6 2016-10-19 | ||
| 26 | +----------------- | ||
| 27 | +- NODE-833, Detects cyclic dependencies in documents and throws error if one is found. | ||
| 28 | +- Fix(deserializer): corrected the check for (size + index) comparison… (Issue #195, https://github.com/JoelParke). | ||
| 29 | + | ||
| 30 | +0.5.5 2016-09-15 | ||
| 31 | +----------------- | ||
| 32 | +- Added DBPointer up conversion to DBRef | ||
| 33 | + | ||
| 34 | +0.5.4 2016-08-23 | ||
| 35 | +----------------- | ||
| 36 | +- Added promoteValues flag (default to true) allowing user to specify if deserialization should be into wrapper classes only. | ||
| 37 | + | ||
| 38 | +0.5.3 2016-07-11 | ||
| 39 | +----------------- | ||
| 40 | +- Throw error if ObjectId is not a string or a buffer. | ||
| 41 | + | ||
| 42 | +0.5.2 2016-07-11 | ||
| 43 | +----------------- | ||
| 44 | +- All values encoded big-endian style for ObjectId. | ||
| 45 | + | ||
| 46 | +0.5.1 2016-07-11 | ||
| 47 | +----------------- | ||
| 48 | +- Fixed encoding/decoding issue in ObjectId timestamp generation. | ||
| 49 | +- Removed BinaryParser dependency from the serializer/deserializer. | ||
| 50 | + | ||
| 51 | +0.5.0 2016-07-05 | ||
| 52 | +----------------- | ||
| 53 | +- Added Decimal128 type and extended test suite to include entire bson corpus. | ||
| 54 | + | ||
| 55 | +0.4.23 2016-04-08 | ||
| 56 | +----------------- | ||
| 57 | +- Allow for proper detection of ObjectId or objects that look like ObjectId, improving compatibility across third party libraries. | ||
| 58 | +- Remove one package from dependency due to having been pulled from NPM. | ||
| 59 | + | ||
| 60 | +0.4.22 2016-03-04 | ||
| 61 | +----------------- | ||
| 62 | +- Fix "TypeError: data.copy is not a function" in Electron (Issue #170, https://github.com/kangas). | ||
| 63 | +- Fixed issue with undefined type on deserializing. | ||
| 64 | + | ||
| 65 | +0.4.21 2016-01-12 | ||
| 66 | +----------------- | ||
| 67 | +- Minor optimizations to avoid non needed object creation. | ||
| 68 | + | ||
| 69 | +0.4.20 2015-10-15 | ||
| 70 | +----------------- | ||
| 71 | +- Added bower file to repository. | ||
| 72 | +- Fixed browser pid sometimes set greater than 0xFFFF on browsers (Issue #155, https://github.com/rahatarmanahmed) | ||
| 73 | + | ||
| 74 | +0.4.19 2015-10-15 | ||
| 75 | +----------------- | ||
| 76 | +- Remove all support for bson-ext. | ||
| 77 | + | ||
| 78 | +0.4.18 2015-10-15 | ||
| 79 | +----------------- | ||
| 80 | +- ObjectID equality check should return boolean instead of throwing exception for invalid oid string #139 | ||
| 81 | +- add option for deserializing binary into Buffer object #116 | ||
| 82 | + | ||
| 83 | +0.4.17 2015-10-15 | ||
| 84 | +----------------- | ||
| 85 | +- Validate regexp string for null bytes and throw if there is one. | ||
| 86 | + | ||
| 87 | +0.4.16 2015-10-07 | ||
| 88 | +----------------- | ||
| 89 | +- Fixed issue with return statement in Map.js. | ||
| 90 | + | ||
| 91 | +0.4.15 2015-10-06 | ||
| 92 | +----------------- | ||
| 93 | +- Exposed Map correctly via index.js file. | ||
| 94 | + | ||
| 95 | +0.4.14 2015-10-06 | ||
| 96 | +----------------- | ||
| 97 | +- Exposed Map correctly via bson.js file. | ||
| 98 | + | ||
| 99 | +0.4.13 2015-10-06 | ||
| 100 | +----------------- | ||
| 101 | +- Added ES6 Map type serialization as well as a polyfill for ES5. | ||
| 102 | + | ||
| 103 | +0.4.12 2015-09-18 | ||
| 104 | +----------------- | ||
| 105 | +- Made ignore undefined an optional parameter. | ||
| 106 | + | ||
| 107 | +0.4.11 2015-08-06 | ||
| 108 | +----------------- | ||
| 109 | +- Minor fix for invalid key checking. | ||
| 110 | + | ||
| 111 | +0.4.10 2015-08-06 | ||
| 112 | +----------------- | ||
| 113 | +- NODE-38 Added new BSONRegExp type to allow direct serialization to MongoDB type. | ||
| 114 | +- Some performance improvements by in lining code. | ||
| 115 | + | ||
| 116 | +0.4.9 2015-08-06 | ||
| 117 | +---------------- | ||
| 118 | +- Undefined fields are omitted from serialization in objects. | ||
| 119 | + | ||
| 120 | +0.4.8 2015-07-14 | ||
| 121 | +---------------- | ||
| 122 | +- Fixed size validation to ensure we can deserialize from dumped files. | ||
| 123 | + | ||
| 124 | +0.4.7 2015-06-26 | ||
| 125 | +---------------- | ||
| 126 | +- Added ability to instruct deserializer to return raw BSON buffers for named array fields. | ||
| 127 | +- Minor deserialization optimization by moving inlined function out. | ||
| 128 | + | ||
| 129 | +0.4.6 2015-06-17 | ||
| 130 | +---------------- | ||
| 131 | +- Fixed serializeWithBufferAndIndex bug. | ||
| 132 | + | ||
| 133 | +0.4.5 2015-06-17 | ||
| 134 | +---------------- | ||
| 135 | +- Removed any references to the shared buffer to avoid non GC collectible bson instances. | ||
| 136 | + | ||
| 137 | +0.4.4 2015-06-17 | ||
| 138 | +---------------- | ||
| 139 | +- Fixed rethrowing of error when not RangeError. | ||
| 140 | + | ||
| 141 | +0.4.3 2015-06-17 | ||
| 142 | +---------------- | ||
| 143 | +- Start buffer at 64K and double as needed, meaning we keep a low memory profile until needed. | ||
| 144 | + | ||
| 145 | +0.4.2 2015-06-16 | ||
| 146 | +---------------- | ||
| 147 | +- More fixes for corrupt Bson | ||
| 148 | + | ||
| 149 | +0.4.1 2015-06-16 | ||
| 150 | +---------------- | ||
| 151 | +- More fixes for corrupt Bson | ||
| 152 | + | ||
| 153 | +0.4.0 2015-06-16 | ||
| 154 | +---------------- | ||
| 155 | +- New JS serializer serializing into a single buffer then copying out the new buffer. Performance is similar to current C++ parser. | ||
| 156 | +- Removed bson-ext extension dependency for now. | ||
| 157 | + | ||
| 158 | +0.3.2 2015-03-27 | ||
| 159 | +---------------- | ||
| 160 | +- Removed node-gyp from install script in package.json. | ||
| 161 | + | ||
| 162 | +0.3.1 2015-03-27 | ||
| 163 | +---------------- | ||
| 164 | +- Return pure js version on native() call if failed to initialize. | ||
| 165 | + | ||
| 166 | +0.3.0 2015-03-26 | ||
| 167 | +---------------- | ||
| 168 | +- Pulled out all C++ code into bson-ext and made it an optional dependency. | ||
| 169 | + | ||
| 170 | +0.2.21 2015-03-21 | ||
| 171 | +----------------- | ||
| 172 | +- Updated Nan to 1.7.0 to support io.js and node 0.12.0 | ||
| 173 | + | ||
| 174 | +0.2.19 2015-02-16 | ||
| 175 | +----------------- | ||
| 176 | +- Updated Nan to 1.6.2 to support io.js and node 0.12.0 | ||
| 177 | + | ||
| 178 | +0.2.18 2015-01-20 | ||
| 179 | +----------------- | ||
| 180 | +- Updated Nan to 1.5.1 to support io.js | ||
| 181 | + | ||
| 182 | +0.2.16 2014-12-17 | ||
| 183 | +----------------- | ||
| 184 | +- Made pid cycle on 0xffff to avoid weird overflows on creation of ObjectID's | ||
| 185 | + | ||
| 186 | +0.2.12 2014-08-24 | ||
| 187 | +----------------- | ||
| 188 | +- Fixes for fortify review of c++ extension | ||
| 189 | +- toBSON correctly allows returns of non objects | ||
| 190 | + | ||
| 191 | +0.2.3 2013-10-01 | ||
| 192 | +---------------- | ||
| 193 | +- Drying of ObjectId code for generation of id (Issue #54, https://github.com/moredip) | ||
| 194 | +- Fixed issue where corrupt CString's could cause endless loop | ||
| 195 | +- Support for Node 0.11.X > (Issue #49, https://github.com/kkoopa) | ||
| 196 | + | ||
| 197 | +0.1.4 2012-09-25 | ||
| 198 | +---------------- | ||
| 199 | +- Added precompiled c++ native extensions for win32 ia32 and x64 |
node_modules/_bson@1.0.4@bson/LICENSE.md
0 → 100644
| 1 | + Apache License | ||
| 2 | + Version 2.0, January 2004 | ||
| 3 | + http://www.apache.org/licenses/ | ||
| 4 | + | ||
| 5 | + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||
| 6 | + | ||
| 7 | + 1. Definitions. | ||
| 8 | + | ||
| 9 | + "License" shall mean the terms and conditions for use, reproduction, | ||
| 10 | + and distribution as defined by Sections 1 through 9 of this document. | ||
| 11 | + | ||
| 12 | + "Licensor" shall mean the copyright owner or entity authorized by | ||
| 13 | + the copyright owner that is granting the License. | ||
| 14 | + | ||
| 15 | + "Legal Entity" shall mean the union of the acting entity and all | ||
| 16 | + other entities that control, are controlled by, or are under common | ||
| 17 | + control with that entity. For the purposes of this definition, | ||
| 18 | + "control" means (i) the power, direct or indirect, to cause the | ||
| 19 | + direction or management of such entity, whether by contract or | ||
| 20 | + otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||
| 21 | + outstanding shares, or (iii) beneficial ownership of such entity. | ||
| 22 | + | ||
| 23 | + "You" (or "Your") shall mean an individual or Legal Entity | ||
| 24 | + exercising permissions granted by this License. | ||
| 25 | + | ||
| 26 | + "Source" form shall mean the preferred form for making modifications, | ||
| 27 | + including but not limited to software source code, documentation | ||
| 28 | + source, and configuration files. | ||
| 29 | + | ||
| 30 | + "Object" form shall mean any form resulting from mechanical | ||
| 31 | + transformation or translation of a Source form, including but | ||
| 32 | + not limited to compiled object code, generated documentation, | ||
| 33 | + and conversions to other media types. | ||
| 34 | + | ||
| 35 | + "Work" shall mean the work of authorship, whether in Source or | ||
| 36 | + Object form, made available under the License, as indicated by a | ||
| 37 | + copyright notice that is included in or attached to the work | ||
| 38 | + (an example is provided in the Appendix below). | ||
| 39 | + | ||
| 40 | + "Derivative Works" shall mean any work, whether in Source or Object | ||
| 41 | + form, that is based on (or derived from) the Work and for which the | ||
| 42 | + editorial revisions, annotations, elaborations, or other modifications | ||
| 43 | + represent, as a whole, an original work of authorship. For the purposes | ||
| 44 | + of this License, Derivative Works shall not include works that remain | ||
| 45 | + separable from, or merely link (or bind by name) to the interfaces of, | ||
| 46 | + the Work and Derivative Works thereof. | ||
| 47 | + | ||
| 48 | + "Contribution" shall mean any work of authorship, including | ||
| 49 | + the original version of the Work and any modifications or additions | ||
| 50 | + to that Work or Derivative Works thereof, that is intentionally | ||
| 51 | + submitted to Licensor for inclusion in the Work by the copyright owner | ||
| 52 | + or by an individual or Legal Entity authorized to submit on behalf of | ||
| 53 | + the copyright owner. For the purposes of this definition, "submitted" | ||
| 54 | + means any form of electronic, verbal, or written communication sent | ||
| 55 | + to the Licensor or its representatives, including but not limited to | ||
| 56 | + communication on electronic mailing lists, source code control systems, | ||
| 57 | + and issue tracking systems that are managed by, or on behalf of, the | ||
| 58 | + Licensor for the purpose of discussing and improving the Work, but | ||
| 59 | + excluding communication that is conspicuously marked or otherwise | ||
| 60 | + designated in writing by the copyright owner as "Not a Contribution." | ||
| 61 | + | ||
| 62 | + "Contributor" shall mean Licensor and any individual or Legal Entity | ||
| 63 | + on behalf of whom a Contribution has been received by Licensor and | ||
| 64 | + subsequently incorporated within the Work. | ||
| 65 | + | ||
| 66 | + 2. Grant of Copyright License. Subject to the terms and conditions of | ||
| 67 | + this License, each Contributor hereby grants to You a perpetual, | ||
| 68 | + worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| 69 | + copyright license to reproduce, prepare Derivative Works of, | ||
| 70 | + publicly display, publicly perform, sublicense, and distribute the | ||
| 71 | + Work and such Derivative Works in Source or Object form. | ||
| 72 | + | ||
| 73 | + 3. Grant of Patent License. Subject to the terms and conditions of | ||
| 74 | + this License, each Contributor hereby grants to You a perpetual, | ||
| 75 | + worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| 76 | + (except as stated in this section) patent license to make, have made, | ||
| 77 | + use, offer to sell, sell, import, and otherwise transfer the Work, | ||
| 78 | + where such license applies only to those patent claims licensable | ||
| 79 | + by such Contributor that are necessarily infringed by their | ||
| 80 | + Contribution(s) alone or by combination of their Contribution(s) | ||
| 81 | + with the Work to which such Contribution(s) was submitted. If You | ||
| 82 | + institute patent litigation against any entity (including a | ||
| 83 | + cross-claim or counterclaim in a lawsuit) alleging that the Work | ||
| 84 | + or a Contribution incorporated within the Work constitutes direct | ||
| 85 | + or contributory patent infringement, then any patent licenses | ||
| 86 | + granted to You under this License for that Work shall terminate | ||
| 87 | + as of the date such litigation is filed. | ||
| 88 | + | ||
| 89 | + 4. Redistribution. You may reproduce and distribute copies of the | ||
| 90 | + Work or Derivative Works thereof in any medium, with or without | ||
| 91 | + modifications, and in Source or Object form, provided that You | ||
| 92 | + meet the following conditions: | ||
| 93 | + | ||
| 94 | + (a) You must give any other recipients of the Work or | ||
| 95 | + Derivative Works a copy of this License; and | ||
| 96 | + | ||
| 97 | + (b) You must cause any modified files to carry prominent notices | ||
| 98 | + stating that You changed the files; and | ||
| 99 | + | ||
| 100 | + (c) You must retain, in the Source form of any Derivative Works | ||
| 101 | + that You distribute, all copyright, patent, trademark, and | ||
| 102 | + attribution notices from the Source form of the Work, | ||
| 103 | + excluding those notices that do not pertain to any part of | ||
| 104 | + the Derivative Works; and | ||
| 105 | + | ||
| 106 | + (d) If the Work includes a "NOTICE" text file as part of its | ||
| 107 | + distribution, then any Derivative Works that You distribute must | ||
| 108 | + include a readable copy of the attribution notices contained | ||
| 109 | + within such NOTICE file, excluding those notices that do not | ||
| 110 | + pertain to any part of the Derivative Works, in at least one | ||
| 111 | + of the following places: within a NOTICE text file distributed | ||
| 112 | + as part of the Derivative Works; within the Source form or | ||
| 113 | + documentation, if provided along with the Derivative Works; or, | ||
| 114 | + within a display generated by the Derivative Works, if and | ||
| 115 | + wherever such third-party notices normally appear. The contents | ||
| 116 | + of the NOTICE file are for informational purposes only and | ||
| 117 | + do not modify the License. You may add Your own attribution | ||
| 118 | + notices within Derivative Works that You distribute, alongside | ||
| 119 | + or as an addendum to the NOTICE text from the Work, provided | ||
| 120 | + that such additional attribution notices cannot be construed | ||
| 121 | + as modifying the License. | ||
| 122 | + | ||
| 123 | + You may add Your own copyright statement to Your modifications and | ||
| 124 | + may provide additional or different license terms and conditions | ||
| 125 | + for use, reproduction, or distribution of Your modifications, or | ||
| 126 | + for any such Derivative Works as a whole, provided Your use, | ||
| 127 | + reproduction, and distribution of the Work otherwise complies with | ||
| 128 | + the conditions stated in this License. | ||
| 129 | + | ||
| 130 | + 5. Submission of Contributions. Unless You explicitly state otherwise, | ||
| 131 | + any Contribution intentionally submitted for inclusion in the Work | ||
| 132 | + by You to the Licensor shall be under the terms and conditions of | ||
| 133 | + this License, without any additional terms or conditions. | ||
| 134 | + Notwithstanding the above, nothing herein shall supersede or modify | ||
| 135 | + the terms of any separate license agreement you may have executed | ||
| 136 | + with Licensor regarding such Contributions. | ||
| 137 | + | ||
| 138 | + 6. Trademarks. This License does not grant permission to use the trade | ||
| 139 | + names, trademarks, service marks, or product names of the Licensor, | ||
| 140 | + except as required for reasonable and customary use in describing the | ||
| 141 | + origin of the Work and reproducing the content of the NOTICE file. | ||
| 142 | + | ||
| 143 | + 7. Disclaimer of Warranty. Unless required by applicable law or | ||
| 144 | + agreed to in writing, Licensor provides the Work (and each | ||
| 145 | + Contributor provides its Contributions) on an "AS IS" BASIS, | ||
| 146 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
| 147 | + implied, including, without limitation, any warranties or conditions | ||
| 148 | + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||
| 149 | + PARTICULAR PURPOSE. You are solely responsible for determining the | ||
| 150 | + appropriateness of using or redistributing the Work and assume any | ||
| 151 | + risks associated with Your exercise of permissions under this License. | ||
| 152 | + | ||
| 153 | + 8. Limitation of Liability. In no event and under no legal theory, | ||
| 154 | + whether in tort (including negligence), contract, or otherwise, | ||
| 155 | + unless required by applicable law (such as deliberate and grossly | ||
| 156 | + negligent acts) or agreed to in writing, shall any Contributor be | ||
| 157 | + liable to You for damages, including any direct, indirect, special, | ||
| 158 | + incidental, or consequential damages of any character arising as a | ||
| 159 | + result of this License or out of the use or inability to use the | ||
| 160 | + Work (including but not limited to damages for loss of goodwill, | ||
| 161 | + work stoppage, computer failure or malfunction, or any and all | ||
| 162 | + other commercial damages or losses), even if such Contributor | ||
| 163 | + has been advised of the possibility of such damages. | ||
| 164 | + | ||
| 165 | + 9. Accepting Warranty or Additional Liability. While redistributing | ||
| 166 | + the Work or Derivative Works thereof, You may choose to offer, | ||
| 167 | + and charge a fee for, acceptance of support, warranty, indemnity, | ||
| 168 | + or other liability obligations and/or rights consistent with this | ||
| 169 | + License. However, in accepting such obligations, You may act only | ||
| 170 | + on Your own behalf and on Your sole responsibility, not on behalf | ||
| 171 | + of any other Contributor, and only if You agree to indemnify, | ||
| 172 | + defend, and hold each Contributor harmless for any liability | ||
| 173 | + incurred by, or claims asserted against, such Contributor by reason | ||
| 174 | + of your accepting any such warranty or additional liability. | ||
| 175 | + | ||
| 176 | + END OF TERMS AND CONDITIONS | ||
| 177 | + | ||
| 178 | + APPENDIX: How to apply the Apache License to your work. | ||
| 179 | + | ||
| 180 | + To apply the Apache License to your work, attach the following | ||
| 181 | + boilerplate notice, with the fields enclosed by brackets "[]" | ||
| 182 | + replaced with your own identifying information. (Don't include | ||
| 183 | + the brackets!) The text should be enclosed in the appropriate | ||
| 184 | + comment syntax for the file format. We also recommend that a | ||
| 185 | + file or class name and description of purpose be included on the | ||
| 186 | + same "printed page" as the copyright notice for easier | ||
| 187 | + identification within third-party archives. | ||
| 188 | + | ||
| 189 | + Copyright [yyyy] [name of copyright owner] | ||
| 190 | + | ||
| 191 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 192 | + you may not use this file except in compliance with the License. | ||
| 193 | + You may obtain a copy of the License at | ||
| 194 | + | ||
| 195 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
| 196 | + | ||
| 197 | + Unless required by applicable law or agreed to in writing, software | ||
| 198 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
| 199 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 200 | + See the License for the specific language governing permissions and | ||
| 201 | + limitations under the License. |
node_modules/_bson@1.0.4@bson/README.md
0 → 100644
| 1 | +# BSON parser | ||
| 2 | + | ||
| 3 | +If you don't yet know what BSON actually is, read [the spec](http://bsonspec.org). | ||
| 4 | + | ||
| 5 | +The browser version of the BSON parser is compiled using webpack and the current | ||
| 6 | +version is pre-compiled in the browser_build directory. To build a new version perform the following operation. | ||
| 7 | + | ||
| 8 | +``` | ||
| 9 | +npm install | ||
| 10 | +npm run build | ||
| 11 | +``` | ||
| 12 | + | ||
| 13 | +A simple example of how to use BSON in the browser: | ||
| 14 | + | ||
| 15 | +```html | ||
| 16 | +<script src="./browser_build/bson.js"></script> | ||
| 17 | + | ||
| 18 | +<script> | ||
| 19 | + function start() { | ||
| 20 | + // Get the Long type | ||
| 21 | + var Long = BSON.Long; | ||
| 22 | + // Create a bson parser instance | ||
| 23 | + var bson = new BSON(); | ||
| 24 | + | ||
| 25 | + // Serialize document | ||
| 26 | + var doc = { long: Long.fromNumber(100) } | ||
| 27 | + | ||
| 28 | + // Serialize a document | ||
| 29 | + var data = bson.serialize(doc) | ||
| 30 | + // De serialize it again | ||
| 31 | + var doc_2 = bson.deserialize(data) | ||
| 32 | + } | ||
| 33 | +</script> | ||
| 34 | +``` | ||
| 35 | + | ||
| 36 | +A simple example of how to use BSON in `node.js`: | ||
| 37 | + | ||
| 38 | +```js | ||
| 39 | +// Get BSON parser class | ||
| 40 | +var BSON = require('bson') | ||
| 41 | +// Get the Long type | ||
| 42 | +var Long = BSON.Long; | ||
| 43 | +// Create a bson parser instance | ||
| 44 | +var bson = new BSON(); | ||
| 45 | + | ||
| 46 | +// Serialize document | ||
| 47 | +var doc = { long: Long.fromNumber(100) } | ||
| 48 | + | ||
| 49 | +// Serialize a document | ||
| 50 | +var data = bson.serialize(doc) | ||
| 51 | +console.log('data:', data) | ||
| 52 | + | ||
| 53 | +// Deserialize the resulting Buffer | ||
| 54 | +var doc_2 = bson.deserialize(data) | ||
| 55 | +console.log('doc_2:', doc_2) | ||
| 56 | +``` | ||
| 57 | + | ||
| 58 | +## Installation | ||
| 59 | + | ||
| 60 | +`npm install bson` | ||
| 61 | + | ||
| 62 | +## API | ||
| 63 | + | ||
| 64 | +### BSON types | ||
| 65 | + | ||
| 66 | +For all BSON types documentation, please refer to the documentation for the mongodb driver. | ||
| 67 | + | ||
| 68 | +https://github.com/mongodb/node-mongodb-native | ||
| 69 | + | ||
| 70 | +### BSON serialization and deserialiation | ||
| 71 | + | ||
| 72 | +**`new BSON()`** - Creates a new BSON seralizer/deserializer you can use to serialize and deserialize BSON. | ||
| 73 | + | ||
| 74 | +#### BSON.serialize | ||
| 75 | + | ||
| 76 | +The BSON serialize method takes a javascript object and an optional options object and returns a Node.js Buffer. | ||
| 77 | + | ||
| 78 | + * BSON.serialize(object, options) | ||
| 79 | + * @param {Object} object the Javascript object to serialize. | ||
| 80 | + * @param {Boolean} [options.checkKeys=false] the serializer will check if keys are valid. | ||
| 81 | + * @param {Boolean} [options.serializeFunctions=false] serialize the javascript. functions. | ||
| 82 | + * @param {Boolean} [options.ignoreUndefined=true] | ||
| 83 | + * @return {Buffer} returns a Buffer instance. | ||
| 84 | + | ||
| 85 | +#### BSON.serializeWithBufferAndIndex | ||
| 86 | + | ||
| 87 | +The BSON serializeWithBufferAndIndex method takes an object, a target buffer instance and an optional options object and returns the end serialization index in the final buffer. | ||
| 88 | + | ||
| 89 | + * BSON.serializeWithBufferAndIndex(object, buffer, options) | ||
| 90 | + * @param {Object} object the Javascript object to serialize. | ||
| 91 | + * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object. | ||
| 92 | + * @param {Boolean} [options.checkKeys=false] the serializer will check if keys are valid. | ||
| 93 | + * @param {Boolean} [options.serializeFunctions=false] serialize the javascript functions. | ||
| 94 | + * @param {Boolean} [options.ignoreUndefined=true] ignore undefined fields. | ||
| 95 | + * @param {Number} [options.index=0] the index in the buffer where we wish to start serializing into. | ||
| 96 | + * @return {Number} returns the index pointing to the last written byte in the buffer. | ||
| 97 | + | ||
| 98 | +#### BSON.calculateObjectSize | ||
| 99 | + | ||
| 100 | +The BSON calculateObjectSize method takes a javascript object and an optional options object and returns the size of the BSON object. | ||
| 101 | + | ||
| 102 | + * BSON.calculateObjectSize(object, options) | ||
| 103 | + * @param {Object} object the Javascript object to serialize. | ||
| 104 | + * @param {Boolean} [options.serializeFunctions=false] serialize the javascript. functions. | ||
| 105 | + * @param {Boolean} [options.ignoreUndefined=true] | ||
| 106 | + * @return {Buffer} returns a Buffer instance. | ||
| 107 | + | ||
| 108 | +#### BSON.deserialize | ||
| 109 | + | ||
| 110 | +The BSON deserialize method takes a node.js Buffer and an optional options object and returns a deserialized Javascript object. | ||
| 111 | + | ||
| 112 | + * BSON.deserialize(buffer, options) | ||
| 113 | + * @param {Object} [options.evalFunctions=false] evaluate functions in the BSON document scoped to the object deserialized. | ||
| 114 | + * @param {Object} [options.cacheFunctions=false] cache evaluated functions for reuse. | ||
| 115 | + * @param {Object} [options.cacheFunctionsCrc32=false] use a crc32 code for caching, otherwise use the string of the function. | ||
| 116 | + * @param {Object} [options.promoteLongs=true] when deserializing a Long will fit it into a Number if it's smaller than 53 bits | ||
| 117 | + * @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a node.js Buffer instance. | ||
| 118 | + * @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types. | ||
| 119 | + * @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer. | ||
| 120 | + * @param {Object} [options.bsonRegExp=false] return BSON regular expressions as BSONRegExp instances. | ||
| 121 | + * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents. | ||
| 122 | + | ||
| 123 | +#### BSON.deserializeStream | ||
| 124 | + | ||
| 125 | +The BSON deserializeStream method takes a node.js Buffer, startIndex and allow more control over deserialization of a Buffer containing concatenated BSON documents. | ||
| 126 | + | ||
| 127 | + * BSON.deserializeStream(buffer, startIndex, numberOfDocuments, documents, docStartIndex, options) | ||
| 128 | + * @param {Buffer} buffer the buffer containing the serialized set of BSON documents. | ||
| 129 | + * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start. | ||
| 130 | + * @param {Number} numberOfDocuments number of documents to deserialize. | ||
| 131 | + * @param {Array} documents an array where to store the deserialized documents. | ||
| 132 | + * @param {Number} docStartIndex the index in the documents array from where to start inserting documents. | ||
| 133 | + * @param {Object} [options.evalFunctions=false] evaluate functions in the BSON document scoped to the object deserialized. | ||
| 134 | + * @param {Object} [options.cacheFunctions=false] cache evaluated functions for reuse. | ||
| 135 | + * @param {Object} [options.cacheFunctionsCrc32=false] use a crc32 code for caching, otherwise use the string of the function. | ||
| 136 | + * @param {Object} [options.promoteLongs=true] when deserializing a Long will fit it into a Number if it's smaller than 53 bits | ||
| 137 | + * @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a node.js Buffer instance. | ||
| 138 | + * @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types. | ||
| 139 | + * @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer. | ||
| 140 | + * @param {Object} [options.bsonRegExp=false] return BSON regular expressions as BSONRegExp instances. | ||
| 141 | + * @return {Object} returns the deserialized Javascript Object. |
node_modules/_bson@1.0.4@bson/bower.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "bson", | ||
| 3 | + "description": "A bson parser for node.js and the browser", | ||
| 4 | + "keywords": [ | ||
| 5 | + "mongodb", | ||
| 6 | + "bson", | ||
| 7 | + "parser" | ||
| 8 | + ], | ||
| 9 | + "author": "Christian Amor Kvalheim <christkv@gmail.com>", | ||
| 10 | + "main": "./browser_build/bson.js", | ||
| 11 | + "license": "Apache-2.0", | ||
| 12 | + "moduleType": [ | ||
| 13 | + "globals", | ||
| 14 | + "node" | ||
| 15 | + ], | ||
| 16 | + "ignore": [ | ||
| 17 | + "**/.*", | ||
| 18 | + "alternate_parsers", | ||
| 19 | + "benchmarks", | ||
| 20 | + "bower_components", | ||
| 21 | + "node_modules", | ||
| 22 | + "test", | ||
| 23 | + "tools" | ||
| 24 | + ] | ||
| 25 | +} |
此 diff 太大无法显示。
| 1 | +{ "name" : "bson" | ||
| 2 | +, "description" : "A bson parser for node.js and the browser" | ||
| 3 | +, "main": "../" | ||
| 4 | +, "directories" : { "lib" : "../lib/bson" } | ||
| 5 | +, "engines" : { "node" : ">=0.6.0" } | ||
| 6 | +, "licenses" : [ { "type" : "Apache License, Version 2.0" | ||
| 7 | + , "url" : "http://www.apache.org/licenses/LICENSE-2.0" } ] | ||
| 8 | +} |
node_modules/_bson@1.0.4@bson/index.js
0 → 100644
| 1 | +var BSON = require('./lib/bson/bson'), | ||
| 2 | + Binary = require('./lib/bson/binary'), | ||
| 3 | + Code = require('./lib/bson/code'), | ||
| 4 | + DBRef = require('./lib/bson/db_ref'), | ||
| 5 | + Decimal128 = require('./lib/bson/decimal128'), | ||
| 6 | + Double = require('./lib/bson/double'), | ||
| 7 | + Int32 = require('./lib/bson/int_32'), | ||
| 8 | + Long = require('./lib/bson/long'), | ||
| 9 | + Map = require('./lib/bson/map'), | ||
| 10 | + MaxKey = require('./lib/bson/max_key'), | ||
| 11 | + MinKey = require('./lib/bson/min_key'), | ||
| 12 | + ObjectId = require('./lib/bson/objectid'), | ||
| 13 | + BSONRegExp = require('./lib/bson/regexp'), | ||
| 14 | + Symbol = require('./lib/bson/symbol'), | ||
| 15 | + Timestamp = require('./lib/bson/timestamp'); | ||
| 16 | + | ||
| 17 | +// BSON MAX VALUES | ||
| 18 | +BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
| 19 | +BSON.BSON_INT32_MIN = -0x80000000; | ||
| 20 | + | ||
| 21 | +BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1; | ||
| 22 | +BSON.BSON_INT64_MIN = -Math.pow(2, 63); | ||
| 23 | + | ||
| 24 | +// JS MAX PRECISE VALUES | ||
| 25 | +BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
| 26 | +BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
| 27 | + | ||
| 28 | +// Add BSON types to function creation | ||
| 29 | +BSON.Binary = Binary; | ||
| 30 | +BSON.Code = Code; | ||
| 31 | +BSON.DBRef = DBRef; | ||
| 32 | +BSON.Decimal128 = Decimal128; | ||
| 33 | +BSON.Double = Double; | ||
| 34 | +BSON.Int32 = Int32; | ||
| 35 | +BSON.Long = Long; | ||
| 36 | +BSON.Map = Map; | ||
| 37 | +BSON.MaxKey = MaxKey; | ||
| 38 | +BSON.MinKey = MinKey; | ||
| 39 | +BSON.ObjectId = ObjectId; | ||
| 40 | +BSON.ObjectID = ObjectId; | ||
| 41 | +BSON.BSONRegExp = BSONRegExp; | ||
| 42 | +BSON.Symbol = Symbol; | ||
| 43 | +BSON.Timestamp = Timestamp; | ||
| 44 | + | ||
| 45 | +// Return the BSON | ||
| 46 | +module.exports = BSON; |
| 1 | +/** | ||
| 2 | + * Module dependencies. | ||
| 3 | + * @ignore | ||
| 4 | + */ | ||
| 5 | + | ||
| 6 | +// Test if we're in Node via presence of "global" not absence of "window" | ||
| 7 | +// to support hybrid environments like Electron | ||
| 8 | +if(typeof global !== 'undefined') { | ||
| 9 | + var Buffer = require('buffer').Buffer; // TODO just use global Buffer | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * A class representation of the BSON Binary type. | ||
| 14 | + * | ||
| 15 | + * Sub types | ||
| 16 | + * - **BSON.BSON_BINARY_SUBTYPE_DEFAULT**, default BSON type. | ||
| 17 | + * - **BSON.BSON_BINARY_SUBTYPE_FUNCTION**, BSON function type. | ||
| 18 | + * - **BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY**, BSON byte array type. | ||
| 19 | + * - **BSON.BSON_BINARY_SUBTYPE_UUID**, BSON uuid type. | ||
| 20 | + * - **BSON.BSON_BINARY_SUBTYPE_MD5**, BSON md5 type. | ||
| 21 | + * - **BSON.BSON_BINARY_SUBTYPE_USER_DEFINED**, BSON user defined type. | ||
| 22 | + * | ||
| 23 | + * @class | ||
| 24 | + * @param {Buffer} buffer a buffer object containing the binary data. | ||
| 25 | + * @param {Number} [subType] the option binary type. | ||
| 26 | + * @return {Binary} | ||
| 27 | + */ | ||
| 28 | +function Binary(buffer, subType) { | ||
| 29 | + if(!(this instanceof Binary)) return new Binary(buffer, subType); | ||
| 30 | + | ||
| 31 | + this._bsontype = 'Binary'; | ||
| 32 | + | ||
| 33 | + if(buffer instanceof Number) { | ||
| 34 | + this.sub_type = buffer; | ||
| 35 | + this.position = 0; | ||
| 36 | + } else { | ||
| 37 | + this.sub_type = subType == null ? BSON_BINARY_SUBTYPE_DEFAULT : subType; | ||
| 38 | + this.position = 0; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + if(buffer != null && !(buffer instanceof Number)) { | ||
| 42 | + // Only accept Buffer, Uint8Array or Arrays | ||
| 43 | + if(typeof buffer == 'string') { | ||
| 44 | + // Different ways of writing the length of the string for the different types | ||
| 45 | + if(typeof Buffer != 'undefined') { | ||
| 46 | + this.buffer = new Buffer(buffer); | ||
| 47 | + } else if(typeof Uint8Array != 'undefined' || (Object.prototype.toString.call(buffer) == '[object Array]')) { | ||
| 48 | + this.buffer = writeStringToArray(buffer); | ||
| 49 | + } else { | ||
| 50 | + throw new Error("only String, Buffer, Uint8Array or Array accepted"); | ||
| 51 | + } | ||
| 52 | + } else { | ||
| 53 | + this.buffer = buffer; | ||
| 54 | + } | ||
| 55 | + this.position = buffer.length; | ||
| 56 | + } else { | ||
| 57 | + if(typeof Buffer != 'undefined') { | ||
| 58 | + this.buffer = new Buffer(Binary.BUFFER_SIZE); | ||
| 59 | + } else if(typeof Uint8Array != 'undefined'){ | ||
| 60 | + this.buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE)); | ||
| 61 | + } else { | ||
| 62 | + this.buffer = new Array(Binary.BUFFER_SIZE); | ||
| 63 | + } | ||
| 64 | + // Set position to start of buffer | ||
| 65 | + this.position = 0; | ||
| 66 | + } | ||
| 67 | +}; | ||
| 68 | + | ||
| 69 | +/** | ||
| 70 | + * Updates this binary with byte_value. | ||
| 71 | + * | ||
| 72 | + * @method | ||
| 73 | + * @param {string} byte_value a single byte we wish to write. | ||
| 74 | + */ | ||
| 75 | +Binary.prototype.put = function put(byte_value) { | ||
| 76 | + // If it's a string and a has more than one character throw an error | ||
| 77 | + if(byte_value['length'] != null && typeof byte_value != 'number' && byte_value.length != 1) throw new Error("only accepts single character String, Uint8Array or Array"); | ||
| 78 | + if(typeof byte_value != 'number' && byte_value < 0 || byte_value > 255) throw new Error("only accepts number in a valid unsigned byte range 0-255"); | ||
| 79 | + | ||
| 80 | + // Decode the byte value once | ||
| 81 | + var decoded_byte = null; | ||
| 82 | + if(typeof byte_value == 'string') { | ||
| 83 | + decoded_byte = byte_value.charCodeAt(0); | ||
| 84 | + } else if(byte_value['length'] != null) { | ||
| 85 | + decoded_byte = byte_value[0]; | ||
| 86 | + } else { | ||
| 87 | + decoded_byte = byte_value; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + if(this.buffer.length > this.position) { | ||
| 91 | + this.buffer[this.position++] = decoded_byte; | ||
| 92 | + } else { | ||
| 93 | + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
| 94 | + // Create additional overflow buffer | ||
| 95 | + var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length); | ||
| 96 | + // Combine the two buffers together | ||
| 97 | + this.buffer.copy(buffer, 0, 0, this.buffer.length); | ||
| 98 | + this.buffer = buffer; | ||
| 99 | + this.buffer[this.position++] = decoded_byte; | ||
| 100 | + } else { | ||
| 101 | + var buffer = null; | ||
| 102 | + // Create a new buffer (typed or normal array) | ||
| 103 | + if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') { | ||
| 104 | + buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE + this.buffer.length)); | ||
| 105 | + } else { | ||
| 106 | + buffer = new Array(Binary.BUFFER_SIZE + this.buffer.length); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + // We need to copy all the content to the new array | ||
| 110 | + for(var i = 0; i < this.buffer.length; i++) { | ||
| 111 | + buffer[i] = this.buffer[i]; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + // Reassign the buffer | ||
| 115 | + this.buffer = buffer; | ||
| 116 | + // Write the byte | ||
| 117 | + this.buffer[this.position++] = decoded_byte; | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | +}; | ||
| 121 | + | ||
| 122 | +/** | ||
| 123 | + * Writes a buffer or string to the binary. | ||
| 124 | + * | ||
| 125 | + * @method | ||
| 126 | + * @param {(Buffer|string)} string a string or buffer to be written to the Binary BSON object. | ||
| 127 | + * @param {number} offset specify the binary of where to write the content. | ||
| 128 | + * @return {null} | ||
| 129 | + */ | ||
| 130 | +Binary.prototype.write = function write(string, offset) { | ||
| 131 | + offset = typeof offset == 'number' ? offset : this.position; | ||
| 132 | + | ||
| 133 | + // If the buffer is to small let's extend the buffer | ||
| 134 | + if(this.buffer.length < offset + string.length) { | ||
| 135 | + var buffer = null; | ||
| 136 | + // If we are in node.js | ||
| 137 | + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
| 138 | + buffer = new Buffer(this.buffer.length + string.length); | ||
| 139 | + this.buffer.copy(buffer, 0, 0, this.buffer.length); | ||
| 140 | + } else if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') { | ||
| 141 | + // Create a new buffer | ||
| 142 | + buffer = new Uint8Array(new ArrayBuffer(this.buffer.length + string.length)) | ||
| 143 | + // Copy the content | ||
| 144 | + for(var i = 0; i < this.position; i++) { | ||
| 145 | + buffer[i] = this.buffer[i]; | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + // Assign the new buffer | ||
| 150 | + this.buffer = buffer; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + if(typeof Buffer != 'undefined' && Buffer.isBuffer(string) && Buffer.isBuffer(this.buffer)) { | ||
| 154 | + string.copy(this.buffer, offset, 0, string.length); | ||
| 155 | + this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; | ||
| 156 | + // offset = string.length | ||
| 157 | + } else if(typeof Buffer != 'undefined' && typeof string == 'string' && Buffer.isBuffer(this.buffer)) { | ||
| 158 | + this.buffer.write(string, offset, 'binary'); | ||
| 159 | + this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; | ||
| 160 | + // offset = string.length; | ||
| 161 | + } else if(Object.prototype.toString.call(string) == '[object Uint8Array]' | ||
| 162 | + || Object.prototype.toString.call(string) == '[object Array]' && typeof string != 'string') { | ||
| 163 | + for(var i = 0; i < string.length; i++) { | ||
| 164 | + this.buffer[offset++] = string[i]; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + this.position = offset > this.position ? offset : this.position; | ||
| 168 | + } else if(typeof string == 'string') { | ||
| 169 | + for(var i = 0; i < string.length; i++) { | ||
| 170 | + this.buffer[offset++] = string.charCodeAt(i); | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + this.position = offset > this.position ? offset : this.position; | ||
| 174 | + } | ||
| 175 | +}; | ||
| 176 | + | ||
| 177 | +/** | ||
| 178 | + * Reads **length** bytes starting at **position**. | ||
| 179 | + * | ||
| 180 | + * @method | ||
| 181 | + * @param {number} position read from the given position in the Binary. | ||
| 182 | + * @param {number} length the number of bytes to read. | ||
| 183 | + * @return {Buffer} | ||
| 184 | + */ | ||
| 185 | +Binary.prototype.read = function read(position, length) { | ||
| 186 | + length = length && length > 0 | ||
| 187 | + ? length | ||
| 188 | + : this.position; | ||
| 189 | + | ||
| 190 | + // Let's return the data based on the type we have | ||
| 191 | + if(this.buffer['slice']) { | ||
| 192 | + return this.buffer.slice(position, position + length); | ||
| 193 | + } else { | ||
| 194 | + // Create a buffer to keep the result | ||
| 195 | + var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(length)) : new Array(length); | ||
| 196 | + for(var i = 0; i < length; i++) { | ||
| 197 | + buffer[i] = this.buffer[position++]; | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + // Return the buffer | ||
| 201 | + return buffer; | ||
| 202 | +}; | ||
| 203 | + | ||
| 204 | +/** | ||
| 205 | + * Returns the value of this binary as a string. | ||
| 206 | + * | ||
| 207 | + * @method | ||
| 208 | + * @return {string} | ||
| 209 | + */ | ||
| 210 | +Binary.prototype.value = function value(asRaw) { | ||
| 211 | + asRaw = asRaw == null ? false : asRaw; | ||
| 212 | + | ||
| 213 | + // Optimize to serialize for the situation where the data == size of buffer | ||
| 214 | + if(asRaw && typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer) && this.buffer.length == this.position) | ||
| 215 | + return this.buffer; | ||
| 216 | + | ||
| 217 | + // If it's a node.js buffer object | ||
| 218 | + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
| 219 | + return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position); | ||
| 220 | + } else { | ||
| 221 | + if(asRaw) { | ||
| 222 | + // we support the slice command use it | ||
| 223 | + if(this.buffer['slice'] != null) { | ||
| 224 | + return this.buffer.slice(0, this.position); | ||
| 225 | + } else { | ||
| 226 | + // Create a new buffer to copy content to | ||
| 227 | + var newBuffer = Object.prototype.toString.call(this.buffer) == '[object Uint8Array]' ? new Uint8Array(new ArrayBuffer(this.position)) : new Array(this.position); | ||
| 228 | + // Copy content | ||
| 229 | + for(var i = 0; i < this.position; i++) { | ||
| 230 | + newBuffer[i] = this.buffer[i]; | ||
| 231 | + } | ||
| 232 | + // Return the buffer | ||
| 233 | + return newBuffer; | ||
| 234 | + } | ||
| 235 | + } else { | ||
| 236 | + return convertArraytoUtf8BinaryString(this.buffer, 0, this.position); | ||
| 237 | + } | ||
| 238 | + } | ||
| 239 | +}; | ||
| 240 | + | ||
| 241 | +/** | ||
| 242 | + * Length. | ||
| 243 | + * | ||
| 244 | + * @method | ||
| 245 | + * @return {number} the length of the binary. | ||
| 246 | + */ | ||
| 247 | +Binary.prototype.length = function length() { | ||
| 248 | + return this.position; | ||
| 249 | +}; | ||
| 250 | + | ||
| 251 | +/** | ||
| 252 | + * @ignore | ||
| 253 | + */ | ||
| 254 | +Binary.prototype.toJSON = function() { | ||
| 255 | + return this.buffer != null ? this.buffer.toString('base64') : ''; | ||
| 256 | +} | ||
| 257 | + | ||
| 258 | +/** | ||
| 259 | + * @ignore | ||
| 260 | + */ | ||
| 261 | +Binary.prototype.toString = function(format) { | ||
| 262 | + return this.buffer != null ? this.buffer.slice(0, this.position).toString(format) : ''; | ||
| 263 | +} | ||
| 264 | + | ||
| 265 | +/** | ||
| 266 | + * Binary default subtype | ||
| 267 | + * @ignore | ||
| 268 | + */ | ||
| 269 | +var BSON_BINARY_SUBTYPE_DEFAULT = 0; | ||
| 270 | + | ||
| 271 | +/** | ||
| 272 | + * @ignore | ||
| 273 | + */ | ||
| 274 | +var writeStringToArray = function(data) { | ||
| 275 | + // Create a buffer | ||
| 276 | + var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(data.length)) : new Array(data.length); | ||
| 277 | + // Write the content to the buffer | ||
| 278 | + for(var i = 0; i < data.length; i++) { | ||
| 279 | + buffer[i] = data.charCodeAt(i); | ||
| 280 | + } | ||
| 281 | + // Write the string to the buffer | ||
| 282 | + return buffer; | ||
| 283 | +} | ||
| 284 | + | ||
| 285 | +/** | ||
| 286 | + * Convert Array ot Uint8Array to Binary String | ||
| 287 | + * | ||
| 288 | + * @ignore | ||
| 289 | + */ | ||
| 290 | +var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) { | ||
| 291 | + var result = ""; | ||
| 292 | + for(var i = startIndex; i < endIndex; i++) { | ||
| 293 | + result = result + String.fromCharCode(byteArray[i]); | ||
| 294 | + } | ||
| 295 | + return result; | ||
| 296 | +}; | ||
| 297 | + | ||
| 298 | +Binary.BUFFER_SIZE = 256; | ||
| 299 | + | ||
| 300 | +/** | ||
| 301 | + * Default BSON type | ||
| 302 | + * | ||
| 303 | + * @classconstant SUBTYPE_DEFAULT | ||
| 304 | + **/ | ||
| 305 | +Binary.SUBTYPE_DEFAULT = 0; | ||
| 306 | +/** | ||
| 307 | + * Function BSON type | ||
| 308 | + * | ||
| 309 | + * @classconstant SUBTYPE_DEFAULT | ||
| 310 | + **/ | ||
| 311 | +Binary.SUBTYPE_FUNCTION = 1; | ||
| 312 | +/** | ||
| 313 | + * Byte Array BSON type | ||
| 314 | + * | ||
| 315 | + * @classconstant SUBTYPE_DEFAULT | ||
| 316 | + **/ | ||
| 317 | +Binary.SUBTYPE_BYTE_ARRAY = 2; | ||
| 318 | +/** | ||
| 319 | + * OLD UUID BSON type | ||
| 320 | + * | ||
| 321 | + * @classconstant SUBTYPE_DEFAULT | ||
| 322 | + **/ | ||
| 323 | +Binary.SUBTYPE_UUID_OLD = 3; | ||
| 324 | +/** | ||
| 325 | + * UUID BSON type | ||
| 326 | + * | ||
| 327 | + * @classconstant SUBTYPE_DEFAULT | ||
| 328 | + **/ | ||
| 329 | +Binary.SUBTYPE_UUID = 4; | ||
| 330 | +/** | ||
| 331 | + * MD5 BSON type | ||
| 332 | + * | ||
| 333 | + * @classconstant SUBTYPE_DEFAULT | ||
| 334 | + **/ | ||
| 335 | +Binary.SUBTYPE_MD5 = 5; | ||
| 336 | +/** | ||
| 337 | + * User BSON type | ||
| 338 | + * | ||
| 339 | + * @classconstant SUBTYPE_DEFAULT | ||
| 340 | + **/ | ||
| 341 | +Binary.SUBTYPE_USER_DEFINED = 128; | ||
| 342 | + | ||
| 343 | +/** | ||
| 344 | + * Expose. | ||
| 345 | + */ | ||
| 346 | +module.exports = Binary; | ||
| 347 | +module.exports.Binary = Binary; |
| 1 | +"use strict" | ||
| 2 | + | ||
| 3 | +var writeIEEE754 = require('./float_parser').writeIEEE754, | ||
| 4 | + readIEEE754 = require('./float_parser').readIEEE754, | ||
| 5 | + Map = require('./map'), | ||
| 6 | + Long = require('./long'), | ||
| 7 | + Double = require('./double'), | ||
| 8 | + Timestamp = require('./timestamp'), | ||
| 9 | + ObjectID = require('./objectid'), | ||
| 10 | + BSONRegExp = require('./regexp'), | ||
| 11 | + Symbol = require('./symbol'), | ||
| 12 | + Int32 = require('./int_32'), | ||
| 13 | + Code = require('./code'), | ||
| 14 | + Decimal128 = require('./decimal128'), | ||
| 15 | + MinKey = require('./min_key'), | ||
| 16 | + MaxKey = require('./max_key'), | ||
| 17 | + DBRef = require('./db_ref'), | ||
| 18 | + Binary = require('./binary'); | ||
| 19 | + | ||
| 20 | +// Parts of the parser | ||
| 21 | +var deserialize = require('./parser/deserializer'), | ||
| 22 | + serializer = require('./parser/serializer'), | ||
| 23 | + calculateObjectSize = require('./parser/calculate_size'); | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * @ignore | ||
| 27 | + * @api private | ||
| 28 | + */ | ||
| 29 | +// Max Size | ||
| 30 | +var MAXSIZE = (1024*1024*17); | ||
| 31 | +// Max Document Buffer size | ||
| 32 | +var buffer = new Buffer(MAXSIZE); | ||
| 33 | + | ||
| 34 | +var BSON = function() { | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +/** | ||
| 38 | + * Serialize a Javascript object. | ||
| 39 | + * | ||
| 40 | + * @param {Object} object the Javascript object to serialize. | ||
| 41 | + * @param {Boolean} [options.checkKeys] the serializer will check if keys are valid. | ||
| 42 | + * @param {Boolean} [options.serializeFunctions=false] serialize the javascript functions **(default:false)**. | ||
| 43 | + * @param {Boolean} [options.ignoreUndefined=true] ignore undefined fields **(default:true)**. | ||
| 44 | + * @return {Buffer} returns the Buffer object containing the serialized object. | ||
| 45 | + * @api public | ||
| 46 | + */ | ||
| 47 | +BSON.prototype.serialize = function serialize(object, options) { | ||
| 48 | + options = options || {}; | ||
| 49 | + // Unpack the options | ||
| 50 | + var checkKeys = typeof options.checkKeys == 'boolean' | ||
| 51 | + ? options.checkKeys : false; | ||
| 52 | + var serializeFunctions = typeof options.serializeFunctions == 'boolean' | ||
| 53 | + ? options.serializeFunctions : false; | ||
| 54 | + var ignoreUndefined = typeof options.ignoreUndefined == 'boolean' | ||
| 55 | + ? options.ignoreUndefined : true; | ||
| 56 | + | ||
| 57 | + // Attempt to serialize | ||
| 58 | + var serializationIndex = serializer(buffer, object, checkKeys, 0, 0, serializeFunctions, ignoreUndefined, []); | ||
| 59 | + // Create the final buffer | ||
| 60 | + var finishedBuffer = new Buffer(serializationIndex); | ||
| 61 | + // Copy into the finished buffer | ||
| 62 | + buffer.copy(finishedBuffer, 0, 0, finishedBuffer.length); | ||
| 63 | + // Return the buffer | ||
| 64 | + return finishedBuffer; | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +/** | ||
| 68 | + * Serialize a Javascript object using a predefined Buffer and index into the buffer, useful when pre-allocating the space for serialization. | ||
| 69 | + * | ||
| 70 | + * @param {Object} object the Javascript object to serialize. | ||
| 71 | + * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object. | ||
| 72 | + * @param {Boolean} [options.checkKeys] the serializer will check if keys are valid. | ||
| 73 | + * @param {Boolean} [options.serializeFunctions=false] serialize the javascript functions **(default:false)**. | ||
| 74 | + * @param {Boolean} [options.ignoreUndefined=true] ignore undefined fields **(default:true)**. | ||
| 75 | + * @param {Number} [options.index] the index in the buffer where we wish to start serializing into. | ||
| 76 | + * @return {Number} returns the index pointing to the last written byte in the buffer. | ||
| 77 | + * @api public | ||
| 78 | + */ | ||
| 79 | +BSON.prototype.serializeWithBufferAndIndex = function(object, finalBuffer, options) { | ||
| 80 | + options = options || {}; | ||
| 81 | + // Unpack the options | ||
| 82 | + var checkKeys = typeof options.checkKeys == 'boolean' | ||
| 83 | + ? options.checkKeys : false; | ||
| 84 | + var serializeFunctions = typeof options.serializeFunctions == 'boolean' | ||
| 85 | + ? options.serializeFunctions : false; | ||
| 86 | + var ignoreUndefined = typeof options.ignoreUndefined == 'boolean' | ||
| 87 | + ? options.ignoreUndefined : true; | ||
| 88 | + var startIndex = typeof options.index == 'number' | ||
| 89 | + ? options.index : 0; | ||
| 90 | + | ||
| 91 | + // Attempt to serialize | ||
| 92 | + var serializationIndex = serializer(buffer, object, checkKeys, startIndex || 0, 0, serializeFunctions, ignoreUndefined); | ||
| 93 | + buffer.copy(finalBuffer, startIndex, 0, serializationIndex); | ||
| 94 | + | ||
| 95 | + // Return the index | ||
| 96 | + return serializationIndex - 1; | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +/** | ||
| 100 | + * Deserialize data as BSON. | ||
| 101 | + * | ||
| 102 | + * @param {Buffer} buffer the buffer containing the serialized set of BSON documents. | ||
| 103 | + * @param {Object} [options.evalFunctions=false] evaluate functions in the BSON document scoped to the object deserialized. | ||
| 104 | + * @param {Object} [options.cacheFunctions=false] cache evaluated functions for reuse. | ||
| 105 | + * @param {Object} [options.cacheFunctionsCrc32=false] use a crc32 code for caching, otherwise use the string of the function. | ||
| 106 | + * @param {Object} [options.promoteLongs=true] when deserializing a Long will fit it into a Number if it's smaller than 53 bits | ||
| 107 | + * @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a node.js Buffer instance. | ||
| 108 | + * @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types. | ||
| 109 | + * @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer. | ||
| 110 | + * @param {Object} [options.bsonRegExp=false] return BSON regular expressions as BSONRegExp instances. | ||
| 111 | + * @return {Object} returns the deserialized Javascript Object. | ||
| 112 | + * @api public | ||
| 113 | + */ | ||
| 114 | +BSON.prototype.deserialize = function(buffer, options) { | ||
| 115 | + return deserialize(buffer, options); | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | +/** | ||
| 119 | + * Calculate the bson size for a passed in Javascript object. | ||
| 120 | + * | ||
| 121 | + * @param {Object} object the Javascript object to calculate the BSON byte size for. | ||
| 122 | + * @param {Boolean} [options.serializeFunctions=false] serialize the javascript functions **(default:false)**. | ||
| 123 | + * @param {Boolean} [options.ignoreUndefined=true] ignore undefined fields **(default:true)**. | ||
| 124 | + * @return {Number} returns the number of bytes the BSON object will take up. | ||
| 125 | + * @api public | ||
| 126 | + */ | ||
| 127 | +BSON.prototype.calculateObjectSize = function(object, options) { | ||
| 128 | + options = options || {}; | ||
| 129 | + | ||
| 130 | + var serializeFunctions = typeof options.serializeFunctions == 'boolean' | ||
| 131 | + ? options.serializeFunctions : false; | ||
| 132 | + var ignoreUndefined = typeof options.ignoreUndefined == 'boolean' | ||
| 133 | + ? options.ignoreUndefined : true; | ||
| 134 | + | ||
| 135 | + return calculateObjectSize(object, serializeFunctions, ignoreUndefined); | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +/** | ||
| 139 | + * Deserialize stream data as BSON documents. | ||
| 140 | + * | ||
| 141 | + * @param {Buffer} data the buffer containing the serialized set of BSON documents. | ||
| 142 | + * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start. | ||
| 143 | + * @param {Number} numberOfDocuments number of documents to deserialize. | ||
| 144 | + * @param {Array} documents an array where to store the deserialized documents. | ||
| 145 | + * @param {Number} docStartIndex the index in the documents array from where to start inserting documents. | ||
| 146 | + * @param {Object} [options] additional options used for the deserialization. | ||
| 147 | + * @param {Object} [options.evalFunctions=false] evaluate functions in the BSON document scoped to the object deserialized. | ||
| 148 | + * @param {Object} [options.cacheFunctions=false] cache evaluated functions for reuse. | ||
| 149 | + * @param {Object} [options.cacheFunctionsCrc32=false] use a crc32 code for caching, otherwise use the string of the function. | ||
| 150 | + * @param {Object} [options.promoteLongs=true] when deserializing a Long will fit it into a Number if it's smaller than 53 bits | ||
| 151 | + * @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a node.js Buffer instance. | ||
| 152 | + * @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types. | ||
| 153 | + * @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer. | ||
| 154 | + * @param {Object} [options.bsonRegExp=false] return BSON regular expressions as BSONRegExp instances. | ||
| 155 | + * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents. | ||
| 156 | + * @api public | ||
| 157 | + */ | ||
| 158 | +BSON.prototype.deserializeStream = function(data, startIndex, numberOfDocuments, documents, docStartIndex, options) { | ||
| 159 | + options = options != null ? options : {}; | ||
| 160 | + var index = startIndex; | ||
| 161 | + // Loop over all documents | ||
| 162 | + for(var i = 0; i < numberOfDocuments; i++) { | ||
| 163 | + // Find size of the document | ||
| 164 | + var size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; | ||
| 165 | + // Update options with index | ||
| 166 | + options['index'] = index; | ||
| 167 | + // Parse the document at this point | ||
| 168 | + documents[docStartIndex + i] = this.deserialize(data, options); | ||
| 169 | + // Adjust index by the document size | ||
| 170 | + index = index + size; | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + // Return object containing end index of parsing and list of documents | ||
| 174 | + return index; | ||
| 175 | +} | ||
| 176 | + | ||
| 177 | +/** | ||
| 178 | + * @ignore | ||
| 179 | + * @api private | ||
| 180 | + */ | ||
| 181 | +// BSON MAX VALUES | ||
| 182 | +BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
| 183 | +BSON.BSON_INT32_MIN = -0x80000000; | ||
| 184 | + | ||
| 185 | +BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1; | ||
| 186 | +BSON.BSON_INT64_MIN = -Math.pow(2, 63); | ||
| 187 | + | ||
| 188 | +// JS MAX PRECISE VALUES | ||
| 189 | +BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
| 190 | +BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
| 191 | + | ||
| 192 | +// Internal long versions | ||
| 193 | +var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
| 194 | +var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
| 195 | + | ||
| 196 | +/** | ||
| 197 | + * Number BSON Type | ||
| 198 | + * | ||
| 199 | + * @classconstant BSON_DATA_NUMBER | ||
| 200 | + **/ | ||
| 201 | +BSON.BSON_DATA_NUMBER = 1; | ||
| 202 | +/** | ||
| 203 | + * String BSON Type | ||
| 204 | + * | ||
| 205 | + * @classconstant BSON_DATA_STRING | ||
| 206 | + **/ | ||
| 207 | +BSON.BSON_DATA_STRING = 2; | ||
| 208 | +/** | ||
| 209 | + * Object BSON Type | ||
| 210 | + * | ||
| 211 | + * @classconstant BSON_DATA_OBJECT | ||
| 212 | + **/ | ||
| 213 | +BSON.BSON_DATA_OBJECT = 3; | ||
| 214 | +/** | ||
| 215 | + * Array BSON Type | ||
| 216 | + * | ||
| 217 | + * @classconstant BSON_DATA_ARRAY | ||
| 218 | + **/ | ||
| 219 | +BSON.BSON_DATA_ARRAY = 4; | ||
| 220 | +/** | ||
| 221 | + * Binary BSON Type | ||
| 222 | + * | ||
| 223 | + * @classconstant BSON_DATA_BINARY | ||
| 224 | + **/ | ||
| 225 | +BSON.BSON_DATA_BINARY = 5; | ||
| 226 | +/** | ||
| 227 | + * ObjectID BSON Type | ||
| 228 | + * | ||
| 229 | + * @classconstant BSON_DATA_OID | ||
| 230 | + **/ | ||
| 231 | +BSON.BSON_DATA_OID = 7; | ||
| 232 | +/** | ||
| 233 | + * Boolean BSON Type | ||
| 234 | + * | ||
| 235 | + * @classconstant BSON_DATA_BOOLEAN | ||
| 236 | + **/ | ||
| 237 | +BSON.BSON_DATA_BOOLEAN = 8; | ||
| 238 | +/** | ||
| 239 | + * Date BSON Type | ||
| 240 | + * | ||
| 241 | + * @classconstant BSON_DATA_DATE | ||
| 242 | + **/ | ||
| 243 | +BSON.BSON_DATA_DATE = 9; | ||
| 244 | +/** | ||
| 245 | + * null BSON Type | ||
| 246 | + * | ||
| 247 | + * @classconstant BSON_DATA_NULL | ||
| 248 | + **/ | ||
| 249 | +BSON.BSON_DATA_NULL = 10; | ||
| 250 | +/** | ||
| 251 | + * RegExp BSON Type | ||
| 252 | + * | ||
| 253 | + * @classconstant BSON_DATA_REGEXP | ||
| 254 | + **/ | ||
| 255 | +BSON.BSON_DATA_REGEXP = 11; | ||
| 256 | +/** | ||
| 257 | + * Code BSON Type | ||
| 258 | + * | ||
| 259 | + * @classconstant BSON_DATA_CODE | ||
| 260 | + **/ | ||
| 261 | +BSON.BSON_DATA_CODE = 13; | ||
| 262 | +/** | ||
| 263 | + * Symbol BSON Type | ||
| 264 | + * | ||
| 265 | + * @classconstant BSON_DATA_SYMBOL | ||
| 266 | + **/ | ||
| 267 | +BSON.BSON_DATA_SYMBOL = 14; | ||
| 268 | +/** | ||
| 269 | + * Code with Scope BSON Type | ||
| 270 | + * | ||
| 271 | + * @classconstant BSON_DATA_CODE_W_SCOPE | ||
| 272 | + **/ | ||
| 273 | +BSON.BSON_DATA_CODE_W_SCOPE = 15; | ||
| 274 | +/** | ||
| 275 | + * 32 bit Integer BSON Type | ||
| 276 | + * | ||
| 277 | + * @classconstant BSON_DATA_INT | ||
| 278 | + **/ | ||
| 279 | +BSON.BSON_DATA_INT = 16; | ||
| 280 | +/** | ||
| 281 | + * Timestamp BSON Type | ||
| 282 | + * | ||
| 283 | + * @classconstant BSON_DATA_TIMESTAMP | ||
| 284 | + **/ | ||
| 285 | +BSON.BSON_DATA_TIMESTAMP = 17; | ||
| 286 | +/** | ||
| 287 | + * Long BSON Type | ||
| 288 | + * | ||
| 289 | + * @classconstant BSON_DATA_LONG | ||
| 290 | + **/ | ||
| 291 | +BSON.BSON_DATA_LONG = 18; | ||
| 292 | +/** | ||
| 293 | + * MinKey BSON Type | ||
| 294 | + * | ||
| 295 | + * @classconstant BSON_DATA_MIN_KEY | ||
| 296 | + **/ | ||
| 297 | +BSON.BSON_DATA_MIN_KEY = 0xff; | ||
| 298 | +/** | ||
| 299 | + * MaxKey BSON Type | ||
| 300 | + * | ||
| 301 | + * @classconstant BSON_DATA_MAX_KEY | ||
| 302 | + **/ | ||
| 303 | +BSON.BSON_DATA_MAX_KEY = 0x7f; | ||
| 304 | + | ||
| 305 | +/** | ||
| 306 | + * Binary Default Type | ||
| 307 | + * | ||
| 308 | + * @classconstant BSON_BINARY_SUBTYPE_DEFAULT | ||
| 309 | + **/ | ||
| 310 | +BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0; | ||
| 311 | +/** | ||
| 312 | + * Binary Function Type | ||
| 313 | + * | ||
| 314 | + * @classconstant BSON_BINARY_SUBTYPE_FUNCTION | ||
| 315 | + **/ | ||
| 316 | +BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1; | ||
| 317 | +/** | ||
| 318 | + * Binary Byte Array Type | ||
| 319 | + * | ||
| 320 | + * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY | ||
| 321 | + **/ | ||
| 322 | +BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; | ||
| 323 | +/** | ||
| 324 | + * Binary UUID Type | ||
| 325 | + * | ||
| 326 | + * @classconstant BSON_BINARY_SUBTYPE_UUID | ||
| 327 | + **/ | ||
| 328 | +BSON.BSON_BINARY_SUBTYPE_UUID = 3; | ||
| 329 | +/** | ||
| 330 | + * Binary MD5 Type | ||
| 331 | + * | ||
| 332 | + * @classconstant BSON_BINARY_SUBTYPE_MD5 | ||
| 333 | + **/ | ||
| 334 | +BSON.BSON_BINARY_SUBTYPE_MD5 = 4; | ||
| 335 | +/** | ||
| 336 | + * Binary User Defined Type | ||
| 337 | + * | ||
| 338 | + * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED | ||
| 339 | + **/ | ||
| 340 | +BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; | ||
| 341 | + | ||
| 342 | +// Return BSON | ||
| 343 | +module.exports = BSON; | ||
| 344 | +module.exports.Code = Code; | ||
| 345 | +module.exports.Map = Map; | ||
| 346 | +module.exports.Symbol = Symbol; | ||
| 347 | +module.exports.BSON = BSON; | ||
| 348 | +module.exports.DBRef = DBRef; | ||
| 349 | +module.exports.Binary = Binary; | ||
| 350 | +module.exports.ObjectID = ObjectID; | ||
| 351 | +module.exports.Long = Long; | ||
| 352 | +module.exports.Timestamp = Timestamp; | ||
| 353 | +module.exports.Double = Double; | ||
| 354 | +module.exports.Int32 = Int32; | ||
| 355 | +module.exports.MinKey = MinKey; | ||
| 356 | +module.exports.MaxKey = MaxKey; | ||
| 357 | +module.exports.BSONRegExp = BSONRegExp; | ||
| 358 | +module.exports.Decimal128 = Decimal128; |
| 1 | +/** | ||
| 2 | + * A class representation of the BSON Code type. | ||
| 3 | + * | ||
| 4 | + * @class | ||
| 5 | + * @param {(string|function)} code a string or function. | ||
| 6 | + * @param {Object} [scope] an optional scope for the function. | ||
| 7 | + * @return {Code} | ||
| 8 | + */ | ||
| 9 | +var Code = function Code(code, scope) { | ||
| 10 | + if(!(this instanceof Code)) return new Code(code, scope); | ||
| 11 | + this._bsontype = 'Code'; | ||
| 12 | + this.code = code; | ||
| 13 | + this.scope = scope; | ||
| 14 | +}; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * @ignore | ||
| 18 | + */ | ||
| 19 | +Code.prototype.toJSON = function() { | ||
| 20 | + return {scope:this.scope, code:this.code}; | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +module.exports = Code; | ||
| 24 | +module.exports.Code = Code; |
| 1 | +/** | ||
| 2 | + * A class representation of the BSON DBRef type. | ||
| 3 | + * | ||
| 4 | + * @class | ||
| 5 | + * @param {string} namespace the collection name. | ||
| 6 | + * @param {ObjectID} oid the reference ObjectID. | ||
| 7 | + * @param {string} [db] optional db name, if omitted the reference is local to the current db. | ||
| 8 | + * @return {DBRef} | ||
| 9 | + */ | ||
| 10 | +function DBRef(namespace, oid, db) { | ||
| 11 | + if(!(this instanceof DBRef)) return new DBRef(namespace, oid, db); | ||
| 12 | + | ||
| 13 | + this._bsontype = 'DBRef'; | ||
| 14 | + this.namespace = namespace; | ||
| 15 | + this.oid = oid; | ||
| 16 | + this.db = db; | ||
| 17 | +}; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * @ignore | ||
| 21 | + * @api private | ||
| 22 | + */ | ||
| 23 | +DBRef.prototype.toJSON = function() { | ||
| 24 | + return { | ||
| 25 | + '$ref':this.namespace, | ||
| 26 | + '$id':this.oid, | ||
| 27 | + '$db':this.db == null ? '' : this.db | ||
| 28 | + }; | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +module.exports = DBRef; | ||
| 32 | +module.exports.DBRef = DBRef; |
| 1 | +"use strict" | ||
| 2 | + | ||
| 3 | +var Long = require('./long'); | ||
| 4 | + | ||
| 5 | +var PARSE_STRING_REGEXP = /^(\+|\-)?(\d+|(\d*\.\d*))?(E|e)?([\-\+])?(\d+)?$/; | ||
| 6 | +var PARSE_INF_REGEXP = /^(\+|\-)?(Infinity|inf)$/i; | ||
| 7 | +var PARSE_NAN_REGEXP = /^(\+|\-)?NaN$/i; | ||
| 8 | + | ||
| 9 | +var EXPONENT_MAX = 6111; | ||
| 10 | +var EXPONENT_MIN = -6176; | ||
| 11 | +var EXPONENT_BIAS = 6176; | ||
| 12 | +var MAX_DIGITS = 34; | ||
| 13 | + | ||
| 14 | +// Nan value bits as 32 bit values (due to lack of longs) | ||
| 15 | +var NAN_BUFFER = [0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse(); | ||
| 16 | +// Infinity value bits 32 bit values (due to lack of longs) | ||
| 17 | +var INF_NEGATIVE_BUFFER = [0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse(); | ||
| 18 | +var INF_POSITIVE_BUFFER = [0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse(); | ||
| 19 | + | ||
| 20 | +var EXPONENT_REGEX = /^([\-\+])?(\d+)?$/; | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +// Detect if the value is a digit | ||
| 24 | +var isDigit = function(value) { | ||
| 25 | + return !isNaN(parseInt(value, 10)); | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +// Divide two uint128 values | ||
| 29 | +var divideu128 = function(value) { | ||
| 30 | + var DIVISOR = Long.fromNumber(1000 * 1000 * 1000); | ||
| 31 | + var _rem = Long.fromNumber(0); | ||
| 32 | + var i = 0; | ||
| 33 | + | ||
| 34 | + if(!value.parts[0] && !value.parts[1] && | ||
| 35 | + !value.parts[2] && !value.parts[3]) { | ||
| 36 | + return { quotient: value, rem: _rem }; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + for(var i = 0; i <= 3; i++) { | ||
| 40 | + // Adjust remainder to match value of next dividend | ||
| 41 | + _rem = _rem.shiftLeft(32); | ||
| 42 | + // Add the divided to _rem | ||
| 43 | + _rem = _rem.add(new Long(value.parts[i], 0)); | ||
| 44 | + value.parts[i] = _rem.div(DIVISOR).low_; | ||
| 45 | + _rem = _rem.modulo(DIVISOR); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + return { quotient: value, rem: _rem }; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +// Multiply two Long values and return the 128 bit value | ||
| 52 | +var multiply64x2 = function(left, right) { | ||
| 53 | + if(!left && !right) { | ||
| 54 | + return {high: Long.fromNumber(0), low: Long.fromNumber(0)}; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + var leftHigh = left.shiftRightUnsigned(32); | ||
| 58 | + var leftLow = new Long(left.getLowBits(), 0); | ||
| 59 | + var rightHigh = right.shiftRightUnsigned(32); | ||
| 60 | + var rightLow = new Long(right.getLowBits(), 0); | ||
| 61 | + | ||
| 62 | + var productHigh = leftHigh.multiply(rightHigh); | ||
| 63 | + var productMid = leftHigh.multiply(rightLow); | ||
| 64 | + var productMid2 = leftLow.multiply(rightHigh); | ||
| 65 | + var productLow = leftLow.multiply(rightLow); | ||
| 66 | + | ||
| 67 | + productHigh = productHigh.add(productMid.shiftRightUnsigned(32)); | ||
| 68 | + productMid = new Long(productMid.getLowBits(), 0) | ||
| 69 | + .add(productMid2) | ||
| 70 | + .add(productLow.shiftRightUnsigned(32)); | ||
| 71 | + | ||
| 72 | + productHigh = productHigh.add(productMid.shiftRightUnsigned(32)); | ||
| 73 | + productLow = productMid.shiftLeft(32).add(new Long(productLow.getLowBits(), 0)); | ||
| 74 | + | ||
| 75 | + // Return the 128 bit result | ||
| 76 | + return {high: productHigh, low: productLow}; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +var lessThan = function(left, right) { | ||
| 80 | + // Make values unsigned | ||
| 81 | + var uhleft = left.high_ >>> 0; | ||
| 82 | + var uhright = right.high_ >>> 0; | ||
| 83 | + | ||
| 84 | + // Compare high bits first | ||
| 85 | + if(uhleft < uhright) { | ||
| 86 | + return true | ||
| 87 | + } else if(uhleft == uhright) { | ||
| 88 | + var ulleft = left.low_ >>> 0; | ||
| 89 | + var ulright = right.low_ >>> 0; | ||
| 90 | + if(ulleft < ulright) return true; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + return false; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +var longtoHex = function(value) { | ||
| 97 | + var buffer = new Buffer(8); | ||
| 98 | + var index = 0; | ||
| 99 | + // Encode the low 64 bits of the decimal | ||
| 100 | + // Encode low bits | ||
| 101 | + buffer[index++] = value.low_ & 0xff; | ||
| 102 | + buffer[index++] = (value.low_ >> 8) & 0xff; | ||
| 103 | + buffer[index++] = (value.low_ >> 16) & 0xff; | ||
| 104 | + buffer[index++] = (value.low_ >> 24) & 0xff; | ||
| 105 | + // Encode high bits | ||
| 106 | + buffer[index++] = value.high_ & 0xff; | ||
| 107 | + buffer[index++] = (value.high_ >> 8) & 0xff; | ||
| 108 | + buffer[index++] = (value.high_ >> 16) & 0xff; | ||
| 109 | + buffer[index++] = (value.high_ >> 24) & 0xff; | ||
| 110 | + return buffer.reverse().toString('hex'); | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | +var int32toHex = function(value) { | ||
| 114 | + var buffer = new Buffer(4); | ||
| 115 | + var index = 0; | ||
| 116 | + // Encode the low 64 bits of the decimal | ||
| 117 | + // Encode low bits | ||
| 118 | + buffer[index++] = value & 0xff; | ||
| 119 | + buffer[index++] = (value >> 8) & 0xff; | ||
| 120 | + buffer[index++] = (value >> 16) & 0xff; | ||
| 121 | + buffer[index++] = (value >> 24) & 0xff; | ||
| 122 | + return buffer.reverse().toString('hex'); | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +var Decimal128 = function(bytes) { | ||
| 126 | + this._bsontype = 'Decimal128'; | ||
| 127 | + this.bytes = bytes; | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +Decimal128.fromString = function(string) { | ||
| 131 | + // Parse state tracking | ||
| 132 | + var isNegative = false; | ||
| 133 | + var sawRadix = false; | ||
| 134 | + var foundNonZero = false; | ||
| 135 | + | ||
| 136 | + // Total number of significant digits (no leading or trailing zero) | ||
| 137 | + var significantDigits = 0; | ||
| 138 | + // Total number of significand digits read | ||
| 139 | + var nDigitsRead = 0; | ||
| 140 | + // Total number of digits (no leading zeros) | ||
| 141 | + var nDigits = 0; | ||
| 142 | + // The number of the digits after radix | ||
| 143 | + var radixPosition = 0; | ||
| 144 | + // The index of the first non-zero in *str* | ||
| 145 | + var firstNonZero = 0; | ||
| 146 | + | ||
| 147 | + // Digits Array | ||
| 148 | + var digits = [0]; | ||
| 149 | + // The number of digits in digits | ||
| 150 | + var nDigitsStored = 0; | ||
| 151 | + // Insertion pointer for digits | ||
| 152 | + var digitsInsert = 0; | ||
| 153 | + // The index of the first non-zero digit | ||
| 154 | + var firstDigit = 0; | ||
| 155 | + // The index of the last digit | ||
| 156 | + var lastDigit = 0; | ||
| 157 | + | ||
| 158 | + // Exponent | ||
| 159 | + var exponent = 0; | ||
| 160 | + // loop index over array | ||
| 161 | + var i = 0; | ||
| 162 | + // The high 17 digits of the significand | ||
| 163 | + var significandHigh = [0, 0]; | ||
| 164 | + // The low 17 digits of the significand | ||
| 165 | + var significandLow = [0, 0]; | ||
| 166 | + // The biased exponent | ||
| 167 | + var biasedExponent = 0; | ||
| 168 | + | ||
| 169 | + // Read index | ||
| 170 | + var index = 0; | ||
| 171 | + | ||
| 172 | + // Trim the string | ||
| 173 | + string = string.trim(); | ||
| 174 | + | ||
| 175 | + // Results | ||
| 176 | + var stringMatch = string.match(PARSE_STRING_REGEXP); | ||
| 177 | + var infMatch = string.match(PARSE_INF_REGEXP); | ||
| 178 | + var nanMatch = string.match(PARSE_NAN_REGEXP); | ||
| 179 | + | ||
| 180 | + // Validate the string | ||
| 181 | + if(!stringMatch | ||
| 182 | + && ! infMatch | ||
| 183 | + && ! nanMatch || string.length == 0) { | ||
| 184 | + throw new Error("" + string + " not a valid Decimal128 string"); | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + // Check if we have an illegal exponent format | ||
| 188 | + if(stringMatch && stringMatch[4] && stringMatch[2] === undefined) { | ||
| 189 | + throw new Error("" + string + " not a valid Decimal128 string"); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + // Get the negative or positive sign | ||
| 193 | + if(string[index] == '+' || string[index] == '-') { | ||
| 194 | + isNegative = string[index++] == '-'; | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + // Check if user passed Infinity or NaN | ||
| 198 | + if(!isDigit(string[index]) && string[index] != '.') { | ||
| 199 | + if(string[index] == 'i' || string[index] == 'I') { | ||
| 200 | + return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)); | ||
| 201 | + } else if(string[index] == 'N') { | ||
| 202 | + return new Decimal128(new Buffer(NAN_BUFFER)); | ||
| 203 | + } | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + // Read all the digits | ||
| 207 | + while(isDigit(string[index]) || string[index] == '.') { | ||
| 208 | + if(string[index] == '.') { | ||
| 209 | + if(sawRadix) { | ||
| 210 | + return new Decimal128(new Buffer(NAN_BUFFER)); | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + sawRadix = true; | ||
| 214 | + index = index + 1; | ||
| 215 | + continue; | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + if(nDigitsStored < 34) { | ||
| 219 | + if(string[index] != '0' || foundNonZero) { | ||
| 220 | + if(!foundNonZero) { | ||
| 221 | + firstNonZero = nDigitsRead; | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + foundNonZero = true; | ||
| 225 | + | ||
| 226 | + // Only store 34 digits | ||
| 227 | + digits[digitsInsert++] = parseInt(string[index], 10); | ||
| 228 | + nDigitsStored = nDigitsStored + 1; | ||
| 229 | + } | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + if(foundNonZero) { | ||
| 233 | + nDigits = nDigits + 1; | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + if(sawRadix) { | ||
| 237 | + radixPosition = radixPosition + 1; | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + nDigitsRead = nDigitsRead + 1; | ||
| 241 | + index = index + 1; | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + if(sawRadix && !nDigitsRead) { | ||
| 245 | + throw new Error("" + string + " not a valid Decimal128 string"); | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + // Read exponent if exists | ||
| 249 | + if(string[index] == 'e' || string[index] == 'E') { | ||
| 250 | + // Read exponent digits | ||
| 251 | + var match = string.substr(++index).match(EXPONENT_REGEX); | ||
| 252 | + | ||
| 253 | + // No digits read | ||
| 254 | + if(!match || !match[2]) { | ||
| 255 | + return new Decimal128(new Buffer(NAN_BUFFER)); | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + // Get exponent | ||
| 259 | + exponent = parseInt(match[0], 10); | ||
| 260 | + | ||
| 261 | + // Adjust the index | ||
| 262 | + index = index + match[0].length; | ||
| 263 | + } | ||
| 264 | + | ||
| 265 | + // Return not a number | ||
| 266 | + if(string[index]) { | ||
| 267 | + return new Decimal128(new Buffer(NAN_BUFFER)); | ||
| 268 | + } | ||
| 269 | + | ||
| 270 | + // Done reading input | ||
| 271 | + // Find first non-zero digit in digits | ||
| 272 | + firstDigit = 0; | ||
| 273 | + | ||
| 274 | + if(!nDigitsStored) { | ||
| 275 | + firstDigit = 0; | ||
| 276 | + lastDigit = 0; | ||
| 277 | + digits[0] = 0; | ||
| 278 | + nDigits = 1; | ||
| 279 | + nDigitsStored = 1; | ||
| 280 | + significantDigits = 0; | ||
| 281 | + } else { | ||
| 282 | + lastDigit = nDigitsStored - 1; | ||
| 283 | + significantDigits = nDigits; | ||
| 284 | + | ||
| 285 | + if(exponent != 0 && significantDigits != 1) { | ||
| 286 | + while(string[firstNonZero + significantDigits - 1] == '0') { | ||
| 287 | + significantDigits = significantDigits - 1; | ||
| 288 | + } | ||
| 289 | + } | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + // Normalization of exponent | ||
| 293 | + // Correct exponent based on radix position, and shift significand as needed | ||
| 294 | + // to represent user input | ||
| 295 | + | ||
| 296 | + // Overflow prevention | ||
| 297 | + if(exponent <= radixPosition && radixPosition - exponent > (1 << 14)) { | ||
| 298 | + exponent = EXPONENT_MIN; | ||
| 299 | + } else { | ||
| 300 | + exponent = exponent - radixPosition; | ||
| 301 | + } | ||
| 302 | + | ||
| 303 | + // Attempt to normalize the exponent | ||
| 304 | + while(exponent > EXPONENT_MAX) { | ||
| 305 | + // Shift exponent to significand and decrease | ||
| 306 | + lastDigit = lastDigit + 1; | ||
| 307 | + | ||
| 308 | + if(lastDigit - firstDigit > MAX_DIGITS) { | ||
| 309 | + // Check if we have a zero then just hard clamp, otherwise fail | ||
| 310 | + var digitsString = digits.join(''); | ||
| 311 | + if(digitsString.match(/^0+$/)) { | ||
| 312 | + exponent = EXPONENT_MAX; | ||
| 313 | + break; | ||
| 314 | + } else { | ||
| 315 | + return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)); | ||
| 316 | + } | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + exponent = exponent - 1; | ||
| 320 | + } | ||
| 321 | + | ||
| 322 | + while(exponent < EXPONENT_MIN || nDigitsStored < nDigits) { | ||
| 323 | + // Shift last digit | ||
| 324 | + if(lastDigit == 0) { | ||
| 325 | + exponent = EXPONENT_MIN; | ||
| 326 | + significantDigits = 0; | ||
| 327 | + break; | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + if(nDigitsStored < nDigits) { | ||
| 331 | + // adjust to match digits not stored | ||
| 332 | + nDigits = nDigits - 1; | ||
| 333 | + } else { | ||
| 334 | + // adjust to round | ||
| 335 | + lastDigit = lastDigit - 1; | ||
| 336 | + } | ||
| 337 | + | ||
| 338 | + if(exponent < EXPONENT_MAX) { | ||
| 339 | + exponent = exponent + 1; | ||
| 340 | + } else { | ||
| 341 | + // Check if we have a zero then just hard clamp, otherwise fail | ||
| 342 | + var digitsString = digits.join(''); | ||
| 343 | + if(digitsString.match(/^0+$/)) { | ||
| 344 | + exponent = EXPONENT_MAX; | ||
| 345 | + break; | ||
| 346 | + } else { | ||
| 347 | + return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)) | ||
| 348 | + } | ||
| 349 | + } | ||
| 350 | + } | ||
| 351 | + | ||
| 352 | + | ||
| 353 | + // Round | ||
| 354 | + // We've normalized the exponent, but might still need to round. | ||
| 355 | + if((lastDigit - firstDigit + 1 < significantDigits) && string[significantDigits] != '0') { | ||
| 356 | + var endOfString = nDigitsRead; | ||
| 357 | + | ||
| 358 | + // If we have seen a radix point, 'string' is 1 longer than we have | ||
| 359 | + // documented with ndigits_read, so inc the position of the first nonzero | ||
| 360 | + // digit and the position that digits are read to. | ||
| 361 | + if(sawRadix && exponent == EXPONENT_MIN) { | ||
| 362 | + firstNonZero = firstNonZero + 1; | ||
| 363 | + endOfString = endOfString + 1; | ||
| 364 | + } | ||
| 365 | + | ||
| 366 | + var roundDigit = parseInt(string[firstNonZero + lastDigit + 1], 10); | ||
| 367 | + var roundBit = 0; | ||
| 368 | + | ||
| 369 | + if(roundDigit >= 5) { | ||
| 370 | + roundBit = 1; | ||
| 371 | + | ||
| 372 | + if(roundDigit == 5) { | ||
| 373 | + roundBit = digits[lastDigit] % 2 == 1; | ||
| 374 | + | ||
| 375 | + for(var i = firstNonZero + lastDigit + 2; i < endOfString; i++) { | ||
| 376 | + if(parseInt(string[i], 10)) { | ||
| 377 | + roundBit = 1; | ||
| 378 | + break; | ||
| 379 | + } | ||
| 380 | + } | ||
| 381 | + } | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + if(roundBit) { | ||
| 385 | + var dIdx = lastDigit; | ||
| 386 | + | ||
| 387 | + for(; dIdx >= 0; dIdx--) { | ||
| 388 | + if(++digits[dIdx] > 9) { | ||
| 389 | + digits[dIdx] = 0; | ||
| 390 | + | ||
| 391 | + // overflowed most significant digit | ||
| 392 | + if(dIdx == 0) { | ||
| 393 | + if(exponent < EXPONENT_MAX) { | ||
| 394 | + exponent = exponent + 1; | ||
| 395 | + digits[dIdx] = 1; | ||
| 396 | + } else { | ||
| 397 | + return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)) | ||
| 398 | + } | ||
| 399 | + } | ||
| 400 | + } else { | ||
| 401 | + break; | ||
| 402 | + } | ||
| 403 | + } | ||
| 404 | + } | ||
| 405 | + } | ||
| 406 | + | ||
| 407 | + // Encode significand | ||
| 408 | + // The high 17 digits of the significand | ||
| 409 | + significandHigh = Long.fromNumber(0); | ||
| 410 | + // The low 17 digits of the significand | ||
| 411 | + significandLow = Long.fromNumber(0); | ||
| 412 | + | ||
| 413 | + // read a zero | ||
| 414 | + if(significantDigits == 0) { | ||
| 415 | + significandHigh = Long.fromNumber(0); | ||
| 416 | + significandLow = Long.fromNumber(0); | ||
| 417 | + } else if(lastDigit - firstDigit < 17) { | ||
| 418 | + var dIdx = firstDigit; | ||
| 419 | + significandLow = Long.fromNumber(digits[dIdx++]); | ||
| 420 | + significandHigh = new Long(0, 0); | ||
| 421 | + | ||
| 422 | + for(; dIdx <= lastDigit; dIdx++) { | ||
| 423 | + significandLow = significandLow.multiply(Long.fromNumber(10)); | ||
| 424 | + significandLow = significandLow.add(Long.fromNumber(digits[dIdx])); | ||
| 425 | + } | ||
| 426 | + } else { | ||
| 427 | + var dIdx = firstDigit; | ||
| 428 | + significandHigh = Long.fromNumber(digits[dIdx++]); | ||
| 429 | + | ||
| 430 | + for(; dIdx <= lastDigit - 17; dIdx++) { | ||
| 431 | + significandHigh = significandHigh.multiply(Long.fromNumber(10)); | ||
| 432 | + significandHigh = significandHigh.add(Long.fromNumber(digits[dIdx])); | ||
| 433 | + } | ||
| 434 | + | ||
| 435 | + significandLow = Long.fromNumber(digits[dIdx++]); | ||
| 436 | + | ||
| 437 | + for(; dIdx <= lastDigit; dIdx++) { | ||
| 438 | + significandLow = significandLow.multiply(Long.fromNumber(10)); | ||
| 439 | + significandLow = significandLow.add(Long.fromNumber(digits[dIdx])); | ||
| 440 | + } | ||
| 441 | + } | ||
| 442 | + | ||
| 443 | + var significand = multiply64x2(significandHigh, Long.fromString("100000000000000000")); | ||
| 444 | + | ||
| 445 | + significand.low = significand.low.add(significandLow); | ||
| 446 | + | ||
| 447 | + if(lessThan(significand.low, significandLow)) { | ||
| 448 | + significand.high = significand.high.add(Long.fromNumber(1)); | ||
| 449 | + } | ||
| 450 | + | ||
| 451 | + // Biased exponent | ||
| 452 | + var biasedExponent = (exponent + EXPONENT_BIAS); | ||
| 453 | + var dec = { low: Long.fromNumber(0), high: Long.fromNumber(0) }; | ||
| 454 | + | ||
| 455 | + // Encode combination, exponent, and significand. | ||
| 456 | + if(significand.high.shiftRightUnsigned(49).and(Long.fromNumber(1)).equals(Long.fromNumber)) { | ||
| 457 | + // Encode '11' into bits 1 to 3 | ||
| 458 | + dec.high = dec.high.or(Long.fromNumber(0x3).shiftLeft(61)); | ||
| 459 | + dec.high = dec.high.or(Long.fromNumber(biasedExponent).and(Long.fromNumber(0x3fff).shiftLeft(47))); | ||
| 460 | + dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x7fffffffffff))); | ||
| 461 | + } else { | ||
| 462 | + dec.high = dec.high.or(Long.fromNumber(biasedExponent & 0x3fff).shiftLeft(49)); | ||
| 463 | + dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x1ffffffffffff))); | ||
| 464 | + } | ||
| 465 | + | ||
| 466 | + dec.low = significand.low; | ||
| 467 | + | ||
| 468 | + // Encode sign | ||
| 469 | + if(isNegative) { | ||
| 470 | + dec.high = dec.high.or(Long.fromString('9223372036854775808')); | ||
| 471 | + } | ||
| 472 | + | ||
| 473 | + // Encode into a buffer | ||
| 474 | + var buffer = new Buffer(16); | ||
| 475 | + var index = 0; | ||
| 476 | + | ||
| 477 | + // Encode the low 64 bits of the decimal | ||
| 478 | + // Encode low bits | ||
| 479 | + buffer[index++] = dec.low.low_ & 0xff; | ||
| 480 | + buffer[index++] = (dec.low.low_ >> 8) & 0xff; | ||
| 481 | + buffer[index++] = (dec.low.low_ >> 16) & 0xff; | ||
| 482 | + buffer[index++] = (dec.low.low_ >> 24) & 0xff; | ||
| 483 | + // Encode high bits | ||
| 484 | + buffer[index++] = dec.low.high_ & 0xff; | ||
| 485 | + buffer[index++] = (dec.low.high_ >> 8) & 0xff; | ||
| 486 | + buffer[index++] = (dec.low.high_ >> 16) & 0xff; | ||
| 487 | + buffer[index++] = (dec.low.high_ >> 24) & 0xff; | ||
| 488 | + | ||
| 489 | + // Encode the high 64 bits of the decimal | ||
| 490 | + // Encode low bits | ||
| 491 | + buffer[index++] = dec.high.low_ & 0xff; | ||
| 492 | + buffer[index++] = (dec.high.low_ >> 8) & 0xff; | ||
| 493 | + buffer[index++] = (dec.high.low_ >> 16) & 0xff; | ||
| 494 | + buffer[index++] = (dec.high.low_ >> 24) & 0xff; | ||
| 495 | + // Encode high bits | ||
| 496 | + buffer[index++] = dec.high.high_ & 0xff; | ||
| 497 | + buffer[index++] = (dec.high.high_ >> 8) & 0xff; | ||
| 498 | + buffer[index++] = (dec.high.high_ >> 16) & 0xff; | ||
| 499 | + buffer[index++] = (dec.high.high_ >> 24) & 0xff; | ||
| 500 | + | ||
| 501 | + // Return the new Decimal128 | ||
| 502 | + return new Decimal128(buffer); | ||
| 503 | +} | ||
| 504 | + | ||
| 505 | +// Extract least significant 5 bits | ||
| 506 | +var COMBINATION_MASK = 0x1f; | ||
| 507 | +// Extract least significant 14 bits | ||
| 508 | +var EXPONENT_MASK = 0x3fff; | ||
| 509 | +// Value of combination field for Inf | ||
| 510 | +var COMBINATION_INFINITY = 30; | ||
| 511 | +// Value of combination field for NaN | ||
| 512 | +var COMBINATION_NAN = 31; | ||
| 513 | +// Value of combination field for NaN | ||
| 514 | +var COMBINATION_SNAN = 32; | ||
| 515 | +// decimal128 exponent bias | ||
| 516 | +var EXPONENT_BIAS = 6176; | ||
| 517 | + | ||
| 518 | +Decimal128.prototype.toString = function() { | ||
| 519 | + // Note: bits in this routine are referred to starting at 0, | ||
| 520 | + // from the sign bit, towards the coefficient. | ||
| 521 | + | ||
| 522 | + // bits 0 - 31 | ||
| 523 | + var high; | ||
| 524 | + // bits 32 - 63 | ||
| 525 | + var midh; | ||
| 526 | + // bits 64 - 95 | ||
| 527 | + var midl; | ||
| 528 | + // bits 96 - 127 | ||
| 529 | + var low; | ||
| 530 | + // bits 1 - 5 | ||
| 531 | + var combination; | ||
| 532 | + // decoded biased exponent (14 bits) | ||
| 533 | + var biased_exponent; | ||
| 534 | + // the number of significand digits | ||
| 535 | + var significand_digits = 0; | ||
| 536 | + // the base-10 digits in the significand | ||
| 537 | + var significand = new Array(36); | ||
| 538 | + for(var i = 0; i < significand.length; i++) significand[i] = 0; | ||
| 539 | + // read pointer into significand | ||
| 540 | + var index = 0; | ||
| 541 | + | ||
| 542 | + // unbiased exponent | ||
| 543 | + var exponent; | ||
| 544 | + // the exponent if scientific notation is used | ||
| 545 | + var scientific_exponent; | ||
| 546 | + | ||
| 547 | + // true if the number is zero | ||
| 548 | + var is_zero = false; | ||
| 549 | + | ||
| 550 | + // the most signifcant significand bits (50-46) | ||
| 551 | + var significand_msb; | ||
| 552 | + // temporary storage for significand decoding | ||
| 553 | + var significand128 = {parts: new Array(4)}; | ||
| 554 | + // indexing variables | ||
| 555 | + var i; | ||
| 556 | + var j, k; | ||
| 557 | + | ||
| 558 | + // Output string | ||
| 559 | + var string = []; | ||
| 560 | + | ||
| 561 | + // Unpack index | ||
| 562 | + var index = 0; | ||
| 563 | + | ||
| 564 | + // Buffer reference | ||
| 565 | + var buffer = this.bytes; | ||
| 566 | + | ||
| 567 | + // Unpack the low 64bits into a long | ||
| 568 | + low = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 569 | + midl = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 570 | + | ||
| 571 | + // Unpack the high 64bits into a long | ||
| 572 | + midh = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 573 | + high = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 574 | + | ||
| 575 | + // Unpack index | ||
| 576 | + var index = 0; | ||
| 577 | + | ||
| 578 | + // Create the state of the decimal | ||
| 579 | + var dec = { | ||
| 580 | + low: new Long(low, midl), | ||
| 581 | + high: new Long(midh, high) }; | ||
| 582 | + | ||
| 583 | + if(dec.high.lessThan(Long.ZERO)) { | ||
| 584 | + string.push('-'); | ||
| 585 | + } | ||
| 586 | + | ||
| 587 | + // Decode combination field and exponent | ||
| 588 | + combination = (high >> 26) & COMBINATION_MASK; | ||
| 589 | + | ||
| 590 | + if((combination >> 3) == 3) { | ||
| 591 | + // Check for 'special' values | ||
| 592 | + if(combination == COMBINATION_INFINITY) { | ||
| 593 | + return string.join('') + "Infinity"; | ||
| 594 | + } else if(combination == COMBINATION_NAN) { | ||
| 595 | + return "NaN"; | ||
| 596 | + } else { | ||
| 597 | + biased_exponent = (high >> 15) & EXPONENT_MASK; | ||
| 598 | + significand_msb = 0x08 + ((high >> 14) & 0x01); | ||
| 599 | + } | ||
| 600 | + } else { | ||
| 601 | + significand_msb = (high >> 14) & 0x07; | ||
| 602 | + biased_exponent = (high >> 17) & EXPONENT_MASK; | ||
| 603 | + } | ||
| 604 | + | ||
| 605 | + exponent = biased_exponent - EXPONENT_BIAS; | ||
| 606 | + | ||
| 607 | + // Create string of significand digits | ||
| 608 | + | ||
| 609 | + // Convert the 114-bit binary number represented by | ||
| 610 | + // (significand_high, significand_low) to at most 34 decimal | ||
| 611 | + // digits through modulo and division. | ||
| 612 | + significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14); | ||
| 613 | + significand128.parts[1] = midh; | ||
| 614 | + significand128.parts[2] = midl; | ||
| 615 | + significand128.parts[3] = low; | ||
| 616 | + | ||
| 617 | + if(significand128.parts[0] == 0 && significand128.parts[1] == 0 | ||
| 618 | + && significand128.parts[2] == 0 && significand128.parts[3] == 0) { | ||
| 619 | + is_zero = true; | ||
| 620 | + } else { | ||
| 621 | + for(var k = 3; k >= 0; k--) { | ||
| 622 | + var least_digits = 0; | ||
| 623 | + // Peform the divide | ||
| 624 | + var result = divideu128(significand128); | ||
| 625 | + significand128 = result.quotient; | ||
| 626 | + least_digits = result.rem.low_; | ||
| 627 | + | ||
| 628 | + // We now have the 9 least significant digits (in base 2). | ||
| 629 | + // Convert and output to string. | ||
| 630 | + if(!least_digits) continue; | ||
| 631 | + | ||
| 632 | + for(var j = 8; j >= 0; j--) { | ||
| 633 | + // significand[k * 9 + j] = Math.round(least_digits % 10); | ||
| 634 | + significand[k * 9 + j] = least_digits % 10; | ||
| 635 | + // least_digits = Math.round(least_digits / 10); | ||
| 636 | + least_digits = Math.floor(least_digits / 10); | ||
| 637 | + } | ||
| 638 | + } | ||
| 639 | + } | ||
| 640 | + | ||
| 641 | + // Output format options: | ||
| 642 | + // Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd | ||
| 643 | + // Regular - ddd.ddd | ||
| 644 | + | ||
| 645 | + if(is_zero) { | ||
| 646 | + significand_digits = 1; | ||
| 647 | + significand[index] = 0; | ||
| 648 | + } else { | ||
| 649 | + significand_digits = 36; | ||
| 650 | + var i = 0; | ||
| 651 | + | ||
| 652 | + while(!significand[index]) { | ||
| 653 | + i++; | ||
| 654 | + significand_digits = significand_digits - 1; | ||
| 655 | + index = index + 1; | ||
| 656 | + } | ||
| 657 | + } | ||
| 658 | + | ||
| 659 | + scientific_exponent = significand_digits - 1 + exponent; | ||
| 660 | + | ||
| 661 | + // The scientific exponent checks are dictated by the string conversion | ||
| 662 | + // specification and are somewhat arbitrary cutoffs. | ||
| 663 | + // | ||
| 664 | + // We must check exponent > 0, because if this is the case, the number | ||
| 665 | + // has trailing zeros. However, we *cannot* output these trailing zeros, | ||
| 666 | + // because doing so would change the precision of the value, and would | ||
| 667 | + // change stored data if the string converted number is round tripped. | ||
| 668 | + | ||
| 669 | + if(scientific_exponent >= 34 || scientific_exponent <= -7 || | ||
| 670 | + exponent > 0) { | ||
| 671 | + // Scientific format | ||
| 672 | + string.push(significand[index++]); | ||
| 673 | + significand_digits = significand_digits - 1; | ||
| 674 | + | ||
| 675 | + if(significand_digits) { | ||
| 676 | + string.push('.'); | ||
| 677 | + } | ||
| 678 | + | ||
| 679 | + for(var i = 0; i < significand_digits; i++) { | ||
| 680 | + string.push(significand[index++]); | ||
| 681 | + } | ||
| 682 | + | ||
| 683 | + // Exponent | ||
| 684 | + string.push('E'); | ||
| 685 | + if(scientific_exponent > 0) { | ||
| 686 | + string.push('+' + scientific_exponent); | ||
| 687 | + } else { | ||
| 688 | + string.push(scientific_exponent); | ||
| 689 | + } | ||
| 690 | + } else { | ||
| 691 | + // Regular format with no decimal place | ||
| 692 | + if(exponent >= 0) { | ||
| 693 | + for(var i = 0; i < significand_digits; i++) { | ||
| 694 | + string.push(significand[index++]); | ||
| 695 | + } | ||
| 696 | + } else { | ||
| 697 | + var radix_position = significand_digits + exponent; | ||
| 698 | + | ||
| 699 | + // non-zero digits before radix | ||
| 700 | + if(radix_position > 0) { | ||
| 701 | + for(var i = 0; i < radix_position; i++) { | ||
| 702 | + string.push(significand[index++]); | ||
| 703 | + } | ||
| 704 | + } else { | ||
| 705 | + string.push('0'); | ||
| 706 | + } | ||
| 707 | + | ||
| 708 | + string.push('.'); | ||
| 709 | + // add leading zeros after radix | ||
| 710 | + while(radix_position++ < 0) { | ||
| 711 | + string.push('0'); | ||
| 712 | + } | ||
| 713 | + | ||
| 714 | + for(var i = 0; i < significand_digits - Math.max(radix_position - 1, 0); i++) { | ||
| 715 | + string.push(significand[index++]); | ||
| 716 | + } | ||
| 717 | + } | ||
| 718 | + } | ||
| 719 | + | ||
| 720 | + return string.join(''); | ||
| 721 | +} | ||
| 722 | + | ||
| 723 | +Decimal128.prototype.toJSON = function() { | ||
| 724 | + return { "$numberDecimal": this.toString() }; | ||
| 725 | +} | ||
| 726 | + | ||
| 727 | +module.exports = Decimal128; | ||
| 728 | +module.exports.Decimal128 = Decimal128; |
| 1 | +/** | ||
| 2 | + * A class representation of the BSON Double type. | ||
| 3 | + * | ||
| 4 | + * @class | ||
| 5 | + * @param {number} value the number we want to represent as a double. | ||
| 6 | + * @return {Double} | ||
| 7 | + */ | ||
| 8 | +function Double(value) { | ||
| 9 | + if(!(this instanceof Double)) return new Double(value); | ||
| 10 | + | ||
| 11 | + this._bsontype = 'Double'; | ||
| 12 | + this.value = value; | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * Access the number value. | ||
| 17 | + * | ||
| 18 | + * @method | ||
| 19 | + * @return {number} returns the wrapped double number. | ||
| 20 | + */ | ||
| 21 | +Double.prototype.valueOf = function() { | ||
| 22 | + return this.value; | ||
| 23 | +}; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * @ignore | ||
| 27 | + */ | ||
| 28 | +Double.prototype.toJSON = function() { | ||
| 29 | + return this.value; | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +module.exports = Double; | ||
| 33 | +module.exports.Double = Double; |
| 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 | +var 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 | +var 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 | + | ||
| 120 | +exports.readIEEE754 = readIEEE754; | ||
| 121 | +exports.writeIEEE754 = writeIEEE754; |
| 1 | +var Int32 = function(value) { | ||
| 2 | + if(!(this instanceof Int32)) return new Int32(value); | ||
| 3 | + | ||
| 4 | + this._bsontype = 'Int32'; | ||
| 5 | + this.value = value; | ||
| 6 | +} | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Access the number value. | ||
| 10 | + * | ||
| 11 | + * @method | ||
| 12 | + * @return {number} returns the wrapped int32 number. | ||
| 13 | + */ | ||
| 14 | +Int32.prototype.valueOf = function() { | ||
| 15 | + return this.value; | ||
| 16 | +}; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * @ignore | ||
| 20 | + */ | ||
| 21 | +Int32.prototype.toJSON = function() { | ||
| 22 | + return this.value; | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +module.exports = Int32; | ||
| 26 | +module.exports.Int32 = Int32; |
| 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 | + * Defines a 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 LongLib in GWT. | ||
| 19 | + * | ||
| 20 | + * Constructs a 64-bit two's-complement integer, given its low and high 32-bit | ||
| 21 | + * values as *signed* integers. See the from* functions below for more | ||
| 22 | + * convenient ways of constructing Longs. | ||
| 23 | + * | ||
| 24 | + * The internal representation of a Long is the two given signed, 32-bit values. | ||
| 25 | + * We use 32-bit pieces because these are the size of integers on which | ||
| 26 | + * Javascript performs bit-operations. For operations like addition and | ||
| 27 | + * multiplication, we split each number into 16-bit pieces, which can easily be | ||
| 28 | + * multiplied within Javascript's floating-point representation without overflow | ||
| 29 | + * or change in sign. | ||
| 30 | + * | ||
| 31 | + * In the algorithms below, we frequently reduce the negative case to the | ||
| 32 | + * positive case by negating the input(s) and then post-processing the result. | ||
| 33 | + * Note that we must ALWAYS check specially whether those values are MIN_VALUE | ||
| 34 | + * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as | ||
| 35 | + * a positive number, it overflows back into a negative). Not handling this | ||
| 36 | + * case would often result in infinite recursion. | ||
| 37 | + * | ||
| 38 | + * @class | ||
| 39 | + * @param {number} low the low (signed) 32 bits of the Long. | ||
| 40 | + * @param {number} high the high (signed) 32 bits of the Long. | ||
| 41 | + * @return {Long} | ||
| 42 | + */ | ||
| 43 | +function Long(low, high) { | ||
| 44 | + if(!(this instanceof Long)) return new Long(low, high); | ||
| 45 | + | ||
| 46 | + this._bsontype = 'Long'; | ||
| 47 | + /** | ||
| 48 | + * @type {number} | ||
| 49 | + * @ignore | ||
| 50 | + */ | ||
| 51 | + this.low_ = low | 0; // force into 32 signed bits. | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * @type {number} | ||
| 55 | + * @ignore | ||
| 56 | + */ | ||
| 57 | + this.high_ = high | 0; // force into 32 signed bits. | ||
| 58 | +}; | ||
| 59 | + | ||
| 60 | +/** | ||
| 61 | + * Return the int value. | ||
| 62 | + * | ||
| 63 | + * @method | ||
| 64 | + * @return {number} the value, assuming it is a 32-bit integer. | ||
| 65 | + */ | ||
| 66 | +Long.prototype.toInt = function() { | ||
| 67 | + return this.low_; | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +/** | ||
| 71 | + * Return the Number value. | ||
| 72 | + * | ||
| 73 | + * @method | ||
| 74 | + * @return {number} the closest floating-point representation to this value. | ||
| 75 | + */ | ||
| 76 | +Long.prototype.toNumber = function() { | ||
| 77 | + return this.high_ * Long.TWO_PWR_32_DBL_ + | ||
| 78 | + this.getLowBitsUnsigned(); | ||
| 79 | +}; | ||
| 80 | + | ||
| 81 | +/** | ||
| 82 | + * Return the JSON value. | ||
| 83 | + * | ||
| 84 | + * @method | ||
| 85 | + * @return {string} the JSON representation. | ||
| 86 | + */ | ||
| 87 | +Long.prototype.toJSON = function() { | ||
| 88 | + return this.toString(); | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +/** | ||
| 92 | + * Return the String value. | ||
| 93 | + * | ||
| 94 | + * @method | ||
| 95 | + * @param {number} [opt_radix] the radix in which the text should be written. | ||
| 96 | + * @return {string} the textual representation of this value. | ||
| 97 | + */ | ||
| 98 | +Long.prototype.toString = function(opt_radix) { | ||
| 99 | + var radix = opt_radix || 10; | ||
| 100 | + if (radix < 2 || 36 < radix) { | ||
| 101 | + throw Error('radix out of range: ' + radix); | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + if (this.isZero()) { | ||
| 105 | + return '0'; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + if (this.isNegative()) { | ||
| 109 | + if (this.equals(Long.MIN_VALUE)) { | ||
| 110 | + // We need to change the Long value before it can be negated, so we remove | ||
| 111 | + // the bottom-most digit in this base and then recurse to do the rest. | ||
| 112 | + var radixLong = Long.fromNumber(radix); | ||
| 113 | + var div = this.div(radixLong); | ||
| 114 | + var rem = div.multiply(radixLong).subtract(this); | ||
| 115 | + return div.toString(radix) + rem.toInt().toString(radix); | ||
| 116 | + } else { | ||
| 117 | + return '-' + this.negate().toString(radix); | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + // Do several (6) digits each time through the loop, so as to | ||
| 122 | + // minimize the calls to the very expensive emulated div. | ||
| 123 | + var radixToPower = Long.fromNumber(Math.pow(radix, 6)); | ||
| 124 | + | ||
| 125 | + var rem = this; | ||
| 126 | + var result = ''; | ||
| 127 | + while (true) { | ||
| 128 | + var remDiv = rem.div(radixToPower); | ||
| 129 | + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); | ||
| 130 | + var digits = intval.toString(radix); | ||
| 131 | + | ||
| 132 | + rem = remDiv; | ||
| 133 | + if (rem.isZero()) { | ||
| 134 | + return digits + result; | ||
| 135 | + } else { | ||
| 136 | + while (digits.length < 6) { | ||
| 137 | + digits = '0' + digits; | ||
| 138 | + } | ||
| 139 | + result = '' + digits + result; | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | +}; | ||
| 143 | + | ||
| 144 | +/** | ||
| 145 | + * Return the high 32-bits value. | ||
| 146 | + * | ||
| 147 | + * @method | ||
| 148 | + * @return {number} the high 32-bits as a signed value. | ||
| 149 | + */ | ||
| 150 | +Long.prototype.getHighBits = function() { | ||
| 151 | + return this.high_; | ||
| 152 | +}; | ||
| 153 | + | ||
| 154 | +/** | ||
| 155 | + * Return the low 32-bits value. | ||
| 156 | + * | ||
| 157 | + * @method | ||
| 158 | + * @return {number} the low 32-bits as a signed value. | ||
| 159 | + */ | ||
| 160 | +Long.prototype.getLowBits = function() { | ||
| 161 | + return this.low_; | ||
| 162 | +}; | ||
| 163 | + | ||
| 164 | +/** | ||
| 165 | + * Return the low unsigned 32-bits value. | ||
| 166 | + * | ||
| 167 | + * @method | ||
| 168 | + * @return {number} the low 32-bits as an unsigned value. | ||
| 169 | + */ | ||
| 170 | +Long.prototype.getLowBitsUnsigned = function() { | ||
| 171 | + return (this.low_ >= 0) ? | ||
| 172 | + this.low_ : Long.TWO_PWR_32_DBL_ + this.low_; | ||
| 173 | +}; | ||
| 174 | + | ||
| 175 | +/** | ||
| 176 | + * Returns the number of bits needed to represent the absolute value of this Long. | ||
| 177 | + * | ||
| 178 | + * @method | ||
| 179 | + * @return {number} Returns the number of bits needed to represent the absolute value of this Long. | ||
| 180 | + */ | ||
| 181 | +Long.prototype.getNumBitsAbs = function() { | ||
| 182 | + if (this.isNegative()) { | ||
| 183 | + if (this.equals(Long.MIN_VALUE)) { | ||
| 184 | + return 64; | ||
| 185 | + } else { | ||
| 186 | + return this.negate().getNumBitsAbs(); | ||
| 187 | + } | ||
| 188 | + } else { | ||
| 189 | + var val = this.high_ != 0 ? this.high_ : this.low_; | ||
| 190 | + for (var bit = 31; bit > 0; bit--) { | ||
| 191 | + if ((val & (1 << bit)) != 0) { | ||
| 192 | + break; | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + return this.high_ != 0 ? bit + 33 : bit + 1; | ||
| 196 | + } | ||
| 197 | +}; | ||
| 198 | + | ||
| 199 | +/** | ||
| 200 | + * Return whether this value is zero. | ||
| 201 | + * | ||
| 202 | + * @method | ||
| 203 | + * @return {boolean} whether this value is zero. | ||
| 204 | + */ | ||
| 205 | +Long.prototype.isZero = function() { | ||
| 206 | + return this.high_ == 0 && this.low_ == 0; | ||
| 207 | +}; | ||
| 208 | + | ||
| 209 | +/** | ||
| 210 | + * Return whether this value is negative. | ||
| 211 | + * | ||
| 212 | + * @method | ||
| 213 | + * @return {boolean} whether this value is negative. | ||
| 214 | + */ | ||
| 215 | +Long.prototype.isNegative = function() { | ||
| 216 | + return this.high_ < 0; | ||
| 217 | +}; | ||
| 218 | + | ||
| 219 | +/** | ||
| 220 | + * Return whether this value is odd. | ||
| 221 | + * | ||
| 222 | + * @method | ||
| 223 | + * @return {boolean} whether this value is odd. | ||
| 224 | + */ | ||
| 225 | +Long.prototype.isOdd = function() { | ||
| 226 | + return (this.low_ & 1) == 1; | ||
| 227 | +}; | ||
| 228 | + | ||
| 229 | +/** | ||
| 230 | + * Return whether this Long equals the other | ||
| 231 | + * | ||
| 232 | + * @method | ||
| 233 | + * @param {Long} other Long to compare against. | ||
| 234 | + * @return {boolean} whether this Long equals the other | ||
| 235 | + */ | ||
| 236 | +Long.prototype.equals = function(other) { | ||
| 237 | + return (this.high_ == other.high_) && (this.low_ == other.low_); | ||
| 238 | +}; | ||
| 239 | + | ||
| 240 | +/** | ||
| 241 | + * Return whether this Long does not equal the other. | ||
| 242 | + * | ||
| 243 | + * @method | ||
| 244 | + * @param {Long} other Long to compare against. | ||
| 245 | + * @return {boolean} whether this Long does not equal the other. | ||
| 246 | + */ | ||
| 247 | +Long.prototype.notEquals = function(other) { | ||
| 248 | + return (this.high_ != other.high_) || (this.low_ != other.low_); | ||
| 249 | +}; | ||
| 250 | + | ||
| 251 | +/** | ||
| 252 | + * Return whether this Long is less than the other. | ||
| 253 | + * | ||
| 254 | + * @method | ||
| 255 | + * @param {Long} other Long to compare against. | ||
| 256 | + * @return {boolean} whether this Long is less than the other. | ||
| 257 | + */ | ||
| 258 | +Long.prototype.lessThan = function(other) { | ||
| 259 | + return this.compare(other) < 0; | ||
| 260 | +}; | ||
| 261 | + | ||
| 262 | +/** | ||
| 263 | + * Return whether this Long is less than or equal to the other. | ||
| 264 | + * | ||
| 265 | + * @method | ||
| 266 | + * @param {Long} other Long to compare against. | ||
| 267 | + * @return {boolean} whether this Long is less than or equal to the other. | ||
| 268 | + */ | ||
| 269 | +Long.prototype.lessThanOrEqual = function(other) { | ||
| 270 | + return this.compare(other) <= 0; | ||
| 271 | +}; | ||
| 272 | + | ||
| 273 | +/** | ||
| 274 | + * Return whether this Long is greater than the other. | ||
| 275 | + * | ||
| 276 | + * @method | ||
| 277 | + * @param {Long} other Long to compare against. | ||
| 278 | + * @return {boolean} whether this Long is greater than the other. | ||
| 279 | + */ | ||
| 280 | +Long.prototype.greaterThan = function(other) { | ||
| 281 | + return this.compare(other) > 0; | ||
| 282 | +}; | ||
| 283 | + | ||
| 284 | +/** | ||
| 285 | + * Return whether this Long is greater than or equal to the other. | ||
| 286 | + * | ||
| 287 | + * @method | ||
| 288 | + * @param {Long} other Long to compare against. | ||
| 289 | + * @return {boolean} whether this Long is greater than or equal to the other. | ||
| 290 | + */ | ||
| 291 | +Long.prototype.greaterThanOrEqual = function(other) { | ||
| 292 | + return this.compare(other) >= 0; | ||
| 293 | +}; | ||
| 294 | + | ||
| 295 | +/** | ||
| 296 | + * Compares this Long with the given one. | ||
| 297 | + * | ||
| 298 | + * @method | ||
| 299 | + * @param {Long} other Long to compare against. | ||
| 300 | + * @return {boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. | ||
| 301 | + */ | ||
| 302 | +Long.prototype.compare = function(other) { | ||
| 303 | + if (this.equals(other)) { | ||
| 304 | + return 0; | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + var thisNeg = this.isNegative(); | ||
| 308 | + var otherNeg = other.isNegative(); | ||
| 309 | + if (thisNeg && !otherNeg) { | ||
| 310 | + return -1; | ||
| 311 | + } | ||
| 312 | + if (!thisNeg && otherNeg) { | ||
| 313 | + return 1; | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + // at this point, the signs are the same, so subtraction will not overflow | ||
| 317 | + if (this.subtract(other).isNegative()) { | ||
| 318 | + return -1; | ||
| 319 | + } else { | ||
| 320 | + return 1; | ||
| 321 | + } | ||
| 322 | +}; | ||
| 323 | + | ||
| 324 | +/** | ||
| 325 | + * The negation of this value. | ||
| 326 | + * | ||
| 327 | + * @method | ||
| 328 | + * @return {Long} the negation of this value. | ||
| 329 | + */ | ||
| 330 | +Long.prototype.negate = function() { | ||
| 331 | + if (this.equals(Long.MIN_VALUE)) { | ||
| 332 | + return Long.MIN_VALUE; | ||
| 333 | + } else { | ||
| 334 | + return this.not().add(Long.ONE); | ||
| 335 | + } | ||
| 336 | +}; | ||
| 337 | + | ||
| 338 | +/** | ||
| 339 | + * Returns the sum of this and the given Long. | ||
| 340 | + * | ||
| 341 | + * @method | ||
| 342 | + * @param {Long} other Long to add to this one. | ||
| 343 | + * @return {Long} the sum of this and the given Long. | ||
| 344 | + */ | ||
| 345 | +Long.prototype.add = function(other) { | ||
| 346 | + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. | ||
| 347 | + | ||
| 348 | + var a48 = this.high_ >>> 16; | ||
| 349 | + var a32 = this.high_ & 0xFFFF; | ||
| 350 | + var a16 = this.low_ >>> 16; | ||
| 351 | + var a00 = this.low_ & 0xFFFF; | ||
| 352 | + | ||
| 353 | + var b48 = other.high_ >>> 16; | ||
| 354 | + var b32 = other.high_ & 0xFFFF; | ||
| 355 | + var b16 = other.low_ >>> 16; | ||
| 356 | + var b00 = other.low_ & 0xFFFF; | ||
| 357 | + | ||
| 358 | + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
| 359 | + c00 += a00 + b00; | ||
| 360 | + c16 += c00 >>> 16; | ||
| 361 | + c00 &= 0xFFFF; | ||
| 362 | + c16 += a16 + b16; | ||
| 363 | + c32 += c16 >>> 16; | ||
| 364 | + c16 &= 0xFFFF; | ||
| 365 | + c32 += a32 + b32; | ||
| 366 | + c48 += c32 >>> 16; | ||
| 367 | + c32 &= 0xFFFF; | ||
| 368 | + c48 += a48 + b48; | ||
| 369 | + c48 &= 0xFFFF; | ||
| 370 | + return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
| 371 | +}; | ||
| 372 | + | ||
| 373 | +/** | ||
| 374 | + * Returns the difference of this and the given Long. | ||
| 375 | + * | ||
| 376 | + * @method | ||
| 377 | + * @param {Long} other Long to subtract from this. | ||
| 378 | + * @return {Long} the difference of this and the given Long. | ||
| 379 | + */ | ||
| 380 | +Long.prototype.subtract = function(other) { | ||
| 381 | + return this.add(other.negate()); | ||
| 382 | +}; | ||
| 383 | + | ||
| 384 | +/** | ||
| 385 | + * Returns the product of this and the given Long. | ||
| 386 | + * | ||
| 387 | + * @method | ||
| 388 | + * @param {Long} other Long to multiply with this. | ||
| 389 | + * @return {Long} the product of this and the other. | ||
| 390 | + */ | ||
| 391 | +Long.prototype.multiply = function(other) { | ||
| 392 | + if (this.isZero()) { | ||
| 393 | + return Long.ZERO; | ||
| 394 | + } else if (other.isZero()) { | ||
| 395 | + return Long.ZERO; | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + if (this.equals(Long.MIN_VALUE)) { | ||
| 399 | + return other.isOdd() ? Long.MIN_VALUE : Long.ZERO; | ||
| 400 | + } else if (other.equals(Long.MIN_VALUE)) { | ||
| 401 | + return this.isOdd() ? Long.MIN_VALUE : Long.ZERO; | ||
| 402 | + } | ||
| 403 | + | ||
| 404 | + if (this.isNegative()) { | ||
| 405 | + if (other.isNegative()) { | ||
| 406 | + return this.negate().multiply(other.negate()); | ||
| 407 | + } else { | ||
| 408 | + return this.negate().multiply(other).negate(); | ||
| 409 | + } | ||
| 410 | + } else if (other.isNegative()) { | ||
| 411 | + return this.multiply(other.negate()).negate(); | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + // If both Longs are small, use float multiplication | ||
| 415 | + if (this.lessThan(Long.TWO_PWR_24_) && | ||
| 416 | + other.lessThan(Long.TWO_PWR_24_)) { | ||
| 417 | + return Long.fromNumber(this.toNumber() * other.toNumber()); | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + // Divide each Long into 4 chunks of 16 bits, and then add up 4x4 products. | ||
| 421 | + // We can skip products that would overflow. | ||
| 422 | + | ||
| 423 | + var a48 = this.high_ >>> 16; | ||
| 424 | + var a32 = this.high_ & 0xFFFF; | ||
| 425 | + var a16 = this.low_ >>> 16; | ||
| 426 | + var a00 = this.low_ & 0xFFFF; | ||
| 427 | + | ||
| 428 | + var b48 = other.high_ >>> 16; | ||
| 429 | + var b32 = other.high_ & 0xFFFF; | ||
| 430 | + var b16 = other.low_ >>> 16; | ||
| 431 | + var b00 = other.low_ & 0xFFFF; | ||
| 432 | + | ||
| 433 | + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
| 434 | + c00 += a00 * b00; | ||
| 435 | + c16 += c00 >>> 16; | ||
| 436 | + c00 &= 0xFFFF; | ||
| 437 | + c16 += a16 * b00; | ||
| 438 | + c32 += c16 >>> 16; | ||
| 439 | + c16 &= 0xFFFF; | ||
| 440 | + c16 += a00 * b16; | ||
| 441 | + c32 += c16 >>> 16; | ||
| 442 | + c16 &= 0xFFFF; | ||
| 443 | + c32 += a32 * b00; | ||
| 444 | + c48 += c32 >>> 16; | ||
| 445 | + c32 &= 0xFFFF; | ||
| 446 | + c32 += a16 * b16; | ||
| 447 | + c48 += c32 >>> 16; | ||
| 448 | + c32 &= 0xFFFF; | ||
| 449 | + c32 += a00 * b32; | ||
| 450 | + c48 += c32 >>> 16; | ||
| 451 | + c32 &= 0xFFFF; | ||
| 452 | + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; | ||
| 453 | + c48 &= 0xFFFF; | ||
| 454 | + return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
| 455 | +}; | ||
| 456 | + | ||
| 457 | +/** | ||
| 458 | + * Returns this Long divided by the given one. | ||
| 459 | + * | ||
| 460 | + * @method | ||
| 461 | + * @param {Long} other Long by which to divide. | ||
| 462 | + * @return {Long} this Long divided by the given one. | ||
| 463 | + */ | ||
| 464 | +Long.prototype.div = function(other) { | ||
| 465 | + if (other.isZero()) { | ||
| 466 | + throw Error('division by zero'); | ||
| 467 | + } else if (this.isZero()) { | ||
| 468 | + return Long.ZERO; | ||
| 469 | + } | ||
| 470 | + | ||
| 471 | + if (this.equals(Long.MIN_VALUE)) { | ||
| 472 | + if (other.equals(Long.ONE) || | ||
| 473 | + other.equals(Long.NEG_ONE)) { | ||
| 474 | + return Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE | ||
| 475 | + } else if (other.equals(Long.MIN_VALUE)) { | ||
| 476 | + return Long.ONE; | ||
| 477 | + } else { | ||
| 478 | + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. | ||
| 479 | + var halfThis = this.shiftRight(1); | ||
| 480 | + var approx = halfThis.div(other).shiftLeft(1); | ||
| 481 | + if (approx.equals(Long.ZERO)) { | ||
| 482 | + return other.isNegative() ? Long.ONE : Long.NEG_ONE; | ||
| 483 | + } else { | ||
| 484 | + var rem = this.subtract(other.multiply(approx)); | ||
| 485 | + var result = approx.add(rem.div(other)); | ||
| 486 | + return result; | ||
| 487 | + } | ||
| 488 | + } | ||
| 489 | + } else if (other.equals(Long.MIN_VALUE)) { | ||
| 490 | + return Long.ZERO; | ||
| 491 | + } | ||
| 492 | + | ||
| 493 | + if (this.isNegative()) { | ||
| 494 | + if (other.isNegative()) { | ||
| 495 | + return this.negate().div(other.negate()); | ||
| 496 | + } else { | ||
| 497 | + return this.negate().div(other).negate(); | ||
| 498 | + } | ||
| 499 | + } else if (other.isNegative()) { | ||
| 500 | + return this.div(other.negate()).negate(); | ||
| 501 | + } | ||
| 502 | + | ||
| 503 | + // Repeat the following until the remainder is less than other: find a | ||
| 504 | + // floating-point that approximates remainder / other *from below*, add this | ||
| 505 | + // into the result, and subtract it from the remainder. It is critical that | ||
| 506 | + // the approximate value is less than or equal to the real value so that the | ||
| 507 | + // remainder never becomes negative. | ||
| 508 | + var res = Long.ZERO; | ||
| 509 | + var rem = this; | ||
| 510 | + while (rem.greaterThanOrEqual(other)) { | ||
| 511 | + // Approximate the result of division. This may be a little greater or | ||
| 512 | + // smaller than the actual value. | ||
| 513 | + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); | ||
| 514 | + | ||
| 515 | + // We will tweak the approximate result by changing it in the 48-th digit or | ||
| 516 | + // the smallest non-fractional digit, whichever is larger. | ||
| 517 | + var log2 = Math.ceil(Math.log(approx) / Math.LN2); | ||
| 518 | + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); | ||
| 519 | + | ||
| 520 | + // Decrease the approximation until it is smaller than the remainder. Note | ||
| 521 | + // that if it is too large, the product overflows and is negative. | ||
| 522 | + var approxRes = Long.fromNumber(approx); | ||
| 523 | + var approxRem = approxRes.multiply(other); | ||
| 524 | + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { | ||
| 525 | + approx -= delta; | ||
| 526 | + approxRes = Long.fromNumber(approx); | ||
| 527 | + approxRem = approxRes.multiply(other); | ||
| 528 | + } | ||
| 529 | + | ||
| 530 | + // We know the answer can't be zero... and actually, zero would cause | ||
| 531 | + // infinite recursion since we would make no progress. | ||
| 532 | + if (approxRes.isZero()) { | ||
| 533 | + approxRes = Long.ONE; | ||
| 534 | + } | ||
| 535 | + | ||
| 536 | + res = res.add(approxRes); | ||
| 537 | + rem = rem.subtract(approxRem); | ||
| 538 | + } | ||
| 539 | + return res; | ||
| 540 | +}; | ||
| 541 | + | ||
| 542 | +/** | ||
| 543 | + * Returns this Long modulo the given one. | ||
| 544 | + * | ||
| 545 | + * @method | ||
| 546 | + * @param {Long} other Long by which to mod. | ||
| 547 | + * @return {Long} this Long modulo the given one. | ||
| 548 | + */ | ||
| 549 | +Long.prototype.modulo = function(other) { | ||
| 550 | + return this.subtract(this.div(other).multiply(other)); | ||
| 551 | +}; | ||
| 552 | + | ||
| 553 | +/** | ||
| 554 | + * The bitwise-NOT of this value. | ||
| 555 | + * | ||
| 556 | + * @method | ||
| 557 | + * @return {Long} the bitwise-NOT of this value. | ||
| 558 | + */ | ||
| 559 | +Long.prototype.not = function() { | ||
| 560 | + return Long.fromBits(~this.low_, ~this.high_); | ||
| 561 | +}; | ||
| 562 | + | ||
| 563 | +/** | ||
| 564 | + * Returns the bitwise-AND of this Long and the given one. | ||
| 565 | + * | ||
| 566 | + * @method | ||
| 567 | + * @param {Long} other the Long with which to AND. | ||
| 568 | + * @return {Long} the bitwise-AND of this and the other. | ||
| 569 | + */ | ||
| 570 | +Long.prototype.and = function(other) { | ||
| 571 | + return Long.fromBits(this.low_ & other.low_, this.high_ & other.high_); | ||
| 572 | +}; | ||
| 573 | + | ||
| 574 | +/** | ||
| 575 | + * Returns the bitwise-OR of this Long and the given one. | ||
| 576 | + * | ||
| 577 | + * @method | ||
| 578 | + * @param {Long} other the Long with which to OR. | ||
| 579 | + * @return {Long} the bitwise-OR of this and the other. | ||
| 580 | + */ | ||
| 581 | +Long.prototype.or = function(other) { | ||
| 582 | + return Long.fromBits(this.low_ | other.low_, this.high_ | other.high_); | ||
| 583 | +}; | ||
| 584 | + | ||
| 585 | +/** | ||
| 586 | + * Returns the bitwise-XOR of this Long and the given one. | ||
| 587 | + * | ||
| 588 | + * @method | ||
| 589 | + * @param {Long} other the Long with which to XOR. | ||
| 590 | + * @return {Long} the bitwise-XOR of this and the other. | ||
| 591 | + */ | ||
| 592 | +Long.prototype.xor = function(other) { | ||
| 593 | + return Long.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); | ||
| 594 | +}; | ||
| 595 | + | ||
| 596 | +/** | ||
| 597 | + * Returns this Long with bits shifted to the left by the given amount. | ||
| 598 | + * | ||
| 599 | + * @method | ||
| 600 | + * @param {number} numBits the number of bits by which to shift. | ||
| 601 | + * @return {Long} this shifted to the left by the given amount. | ||
| 602 | + */ | ||
| 603 | +Long.prototype.shiftLeft = function(numBits) { | ||
| 604 | + numBits &= 63; | ||
| 605 | + if (numBits == 0) { | ||
| 606 | + return this; | ||
| 607 | + } else { | ||
| 608 | + var low = this.low_; | ||
| 609 | + if (numBits < 32) { | ||
| 610 | + var high = this.high_; | ||
| 611 | + return Long.fromBits( | ||
| 612 | + low << numBits, | ||
| 613 | + (high << numBits) | (low >>> (32 - numBits))); | ||
| 614 | + } else { | ||
| 615 | + return Long.fromBits(0, low << (numBits - 32)); | ||
| 616 | + } | ||
| 617 | + } | ||
| 618 | +}; | ||
| 619 | + | ||
| 620 | +/** | ||
| 621 | + * Returns this Long with bits shifted to the right by the given amount. | ||
| 622 | + * | ||
| 623 | + * @method | ||
| 624 | + * @param {number} numBits the number of bits by which to shift. | ||
| 625 | + * @return {Long} this shifted to the right by the given amount. | ||
| 626 | + */ | ||
| 627 | +Long.prototype.shiftRight = function(numBits) { | ||
| 628 | + numBits &= 63; | ||
| 629 | + if (numBits == 0) { | ||
| 630 | + return this; | ||
| 631 | + } else { | ||
| 632 | + var high = this.high_; | ||
| 633 | + if (numBits < 32) { | ||
| 634 | + var low = this.low_; | ||
| 635 | + return Long.fromBits( | ||
| 636 | + (low >>> numBits) | (high << (32 - numBits)), | ||
| 637 | + high >> numBits); | ||
| 638 | + } else { | ||
| 639 | + return Long.fromBits( | ||
| 640 | + high >> (numBits - 32), | ||
| 641 | + high >= 0 ? 0 : -1); | ||
| 642 | + } | ||
| 643 | + } | ||
| 644 | +}; | ||
| 645 | + | ||
| 646 | +/** | ||
| 647 | + * Returns this Long with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. | ||
| 648 | + * | ||
| 649 | + * @method | ||
| 650 | + * @param {number} numBits the number of bits by which to shift. | ||
| 651 | + * @return {Long} this shifted to the right by the given amount, with zeros placed into the new leading bits. | ||
| 652 | + */ | ||
| 653 | +Long.prototype.shiftRightUnsigned = function(numBits) { | ||
| 654 | + numBits &= 63; | ||
| 655 | + if (numBits == 0) { | ||
| 656 | + return this; | ||
| 657 | + } else { | ||
| 658 | + var high = this.high_; | ||
| 659 | + if (numBits < 32) { | ||
| 660 | + var low = this.low_; | ||
| 661 | + return Long.fromBits( | ||
| 662 | + (low >>> numBits) | (high << (32 - numBits)), | ||
| 663 | + high >>> numBits); | ||
| 664 | + } else if (numBits == 32) { | ||
| 665 | + return Long.fromBits(high, 0); | ||
| 666 | + } else { | ||
| 667 | + return Long.fromBits(high >>> (numBits - 32), 0); | ||
| 668 | + } | ||
| 669 | + } | ||
| 670 | +}; | ||
| 671 | + | ||
| 672 | +/** | ||
| 673 | + * Returns a Long representing the given (32-bit) integer value. | ||
| 674 | + * | ||
| 675 | + * @method | ||
| 676 | + * @param {number} value the 32-bit integer in question. | ||
| 677 | + * @return {Long} the corresponding Long value. | ||
| 678 | + */ | ||
| 679 | +Long.fromInt = function(value) { | ||
| 680 | + if (-128 <= value && value < 128) { | ||
| 681 | + var cachedObj = Long.INT_CACHE_[value]; | ||
| 682 | + if (cachedObj) { | ||
| 683 | + return cachedObj; | ||
| 684 | + } | ||
| 685 | + } | ||
| 686 | + | ||
| 687 | + var obj = new Long(value | 0, value < 0 ? -1 : 0); | ||
| 688 | + if (-128 <= value && value < 128) { | ||
| 689 | + Long.INT_CACHE_[value] = obj; | ||
| 690 | + } | ||
| 691 | + return obj; | ||
| 692 | +}; | ||
| 693 | + | ||
| 694 | +/** | ||
| 695 | + * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. | ||
| 696 | + * | ||
| 697 | + * @method | ||
| 698 | + * @param {number} value the number in question. | ||
| 699 | + * @return {Long} the corresponding Long value. | ||
| 700 | + */ | ||
| 701 | +Long.fromNumber = function(value) { | ||
| 702 | + if (isNaN(value) || !isFinite(value)) { | ||
| 703 | + return Long.ZERO; | ||
| 704 | + } else if (value <= -Long.TWO_PWR_63_DBL_) { | ||
| 705 | + return Long.MIN_VALUE; | ||
| 706 | + } else if (value + 1 >= Long.TWO_PWR_63_DBL_) { | ||
| 707 | + return Long.MAX_VALUE; | ||
| 708 | + } else if (value < 0) { | ||
| 709 | + return Long.fromNumber(-value).negate(); | ||
| 710 | + } else { | ||
| 711 | + return new Long( | ||
| 712 | + (value % Long.TWO_PWR_32_DBL_) | 0, | ||
| 713 | + (value / Long.TWO_PWR_32_DBL_) | 0); | ||
| 714 | + } | ||
| 715 | +}; | ||
| 716 | + | ||
| 717 | +/** | ||
| 718 | + * Returns a Long representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. | ||
| 719 | + * | ||
| 720 | + * @method | ||
| 721 | + * @param {number} lowBits the low 32-bits. | ||
| 722 | + * @param {number} highBits the high 32-bits. | ||
| 723 | + * @return {Long} the corresponding Long value. | ||
| 724 | + */ | ||
| 725 | +Long.fromBits = function(lowBits, highBits) { | ||
| 726 | + return new Long(lowBits, highBits); | ||
| 727 | +}; | ||
| 728 | + | ||
| 729 | +/** | ||
| 730 | + * Returns a Long representation of the given string, written using the given radix. | ||
| 731 | + * | ||
| 732 | + * @method | ||
| 733 | + * @param {string} str the textual representation of the Long. | ||
| 734 | + * @param {number} opt_radix the radix in which the text is written. | ||
| 735 | + * @return {Long} the corresponding Long value. | ||
| 736 | + */ | ||
| 737 | +Long.fromString = function(str, opt_radix) { | ||
| 738 | + if (str.length == 0) { | ||
| 739 | + throw Error('number format error: empty string'); | ||
| 740 | + } | ||
| 741 | + | ||
| 742 | + var radix = opt_radix || 10; | ||
| 743 | + if (radix < 2 || 36 < radix) { | ||
| 744 | + throw Error('radix out of range: ' + radix); | ||
| 745 | + } | ||
| 746 | + | ||
| 747 | + if (str.charAt(0) == '-') { | ||
| 748 | + return Long.fromString(str.substring(1), radix).negate(); | ||
| 749 | + } else if (str.indexOf('-') >= 0) { | ||
| 750 | + throw Error('number format error: interior "-" character: ' + str); | ||
| 751 | + } | ||
| 752 | + | ||
| 753 | + // Do several (8) digits each time through the loop, so as to | ||
| 754 | + // minimize the calls to the very expensive emulated div. | ||
| 755 | + var radixToPower = Long.fromNumber(Math.pow(radix, 8)); | ||
| 756 | + | ||
| 757 | + var result = Long.ZERO; | ||
| 758 | + for (var i = 0; i < str.length; i += 8) { | ||
| 759 | + var size = Math.min(8, str.length - i); | ||
| 760 | + var value = parseInt(str.substring(i, i + size), radix); | ||
| 761 | + if (size < 8) { | ||
| 762 | + var power = Long.fromNumber(Math.pow(radix, size)); | ||
| 763 | + result = result.multiply(power).add(Long.fromNumber(value)); | ||
| 764 | + } else { | ||
| 765 | + result = result.multiply(radixToPower); | ||
| 766 | + result = result.add(Long.fromNumber(value)); | ||
| 767 | + } | ||
| 768 | + } | ||
| 769 | + return result; | ||
| 770 | +}; | ||
| 771 | + | ||
| 772 | +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the | ||
| 773 | +// from* methods on which they depend. | ||
| 774 | + | ||
| 775 | + | ||
| 776 | +/** | ||
| 777 | + * A cache of the Long representations of small integer values. | ||
| 778 | + * @type {Object} | ||
| 779 | + * @ignore | ||
| 780 | + */ | ||
| 781 | +Long.INT_CACHE_ = {}; | ||
| 782 | + | ||
| 783 | +// NOTE: the compiler should inline these constant values below and then remove | ||
| 784 | +// these variables, so there should be no runtime penalty for these. | ||
| 785 | + | ||
| 786 | +/** | ||
| 787 | + * Number used repeated below in calculations. This must appear before the | ||
| 788 | + * first call to any from* function below. | ||
| 789 | + * @type {number} | ||
| 790 | + * @ignore | ||
| 791 | + */ | ||
| 792 | +Long.TWO_PWR_16_DBL_ = 1 << 16; | ||
| 793 | + | ||
| 794 | +/** | ||
| 795 | + * @type {number} | ||
| 796 | + * @ignore | ||
| 797 | + */ | ||
| 798 | +Long.TWO_PWR_24_DBL_ = 1 << 24; | ||
| 799 | + | ||
| 800 | +/** | ||
| 801 | + * @type {number} | ||
| 802 | + * @ignore | ||
| 803 | + */ | ||
| 804 | +Long.TWO_PWR_32_DBL_ = Long.TWO_PWR_16_DBL_ * Long.TWO_PWR_16_DBL_; | ||
| 805 | + | ||
| 806 | +/** | ||
| 807 | + * @type {number} | ||
| 808 | + * @ignore | ||
| 809 | + */ | ||
| 810 | +Long.TWO_PWR_31_DBL_ = Long.TWO_PWR_32_DBL_ / 2; | ||
| 811 | + | ||
| 812 | +/** | ||
| 813 | + * @type {number} | ||
| 814 | + * @ignore | ||
| 815 | + */ | ||
| 816 | +Long.TWO_PWR_48_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_16_DBL_; | ||
| 817 | + | ||
| 818 | +/** | ||
| 819 | + * @type {number} | ||
| 820 | + * @ignore | ||
| 821 | + */ | ||
| 822 | +Long.TWO_PWR_64_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_32_DBL_; | ||
| 823 | + | ||
| 824 | +/** | ||
| 825 | + * @type {number} | ||
| 826 | + * @ignore | ||
| 827 | + */ | ||
| 828 | +Long.TWO_PWR_63_DBL_ = Long.TWO_PWR_64_DBL_ / 2; | ||
| 829 | + | ||
| 830 | +/** @type {Long} */ | ||
| 831 | +Long.ZERO = Long.fromInt(0); | ||
| 832 | + | ||
| 833 | +/** @type {Long} */ | ||
| 834 | +Long.ONE = Long.fromInt(1); | ||
| 835 | + | ||
| 836 | +/** @type {Long} */ | ||
| 837 | +Long.NEG_ONE = Long.fromInt(-1); | ||
| 838 | + | ||
| 839 | +/** @type {Long} */ | ||
| 840 | +Long.MAX_VALUE = | ||
| 841 | + Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); | ||
| 842 | + | ||
| 843 | +/** @type {Long} */ | ||
| 844 | +Long.MIN_VALUE = Long.fromBits(0, 0x80000000 | 0); | ||
| 845 | + | ||
| 846 | +/** | ||
| 847 | + * @type {Long} | ||
| 848 | + * @ignore | ||
| 849 | + */ | ||
| 850 | +Long.TWO_PWR_24_ = Long.fromInt(1 << 24); | ||
| 851 | + | ||
| 852 | +/** | ||
| 853 | + * Expose. | ||
| 854 | + */ | ||
| 855 | +module.exports = Long; | ||
| 856 | +module.exports.Long = Long; |
| 1 | +"use strict" | ||
| 2 | + | ||
| 3 | +// We have an ES6 Map available, return the native instance | ||
| 4 | +if(typeof global.Map !== 'undefined') { | ||
| 5 | + module.exports = global.Map; | ||
| 6 | + module.exports.Map = global.Map; | ||
| 7 | +} else { | ||
| 8 | + // We will return a polyfill | ||
| 9 | + var Map = function(array) { | ||
| 10 | + this._keys = []; | ||
| 11 | + this._values = {}; | ||
| 12 | + | ||
| 13 | + for(var i = 0; i < array.length; i++) { | ||
| 14 | + if(array[i] == null) continue; // skip null and undefined | ||
| 15 | + var entry = array[i]; | ||
| 16 | + var key = entry[0]; | ||
| 17 | + var value = entry[1]; | ||
| 18 | + // Add the key to the list of keys in order | ||
| 19 | + this._keys.push(key); | ||
| 20 | + // Add the key and value to the values dictionary with a point | ||
| 21 | + // to the location in the ordered keys list | ||
| 22 | + this._values[key] = {v: value, i: this._keys.length - 1}; | ||
| 23 | + } | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + Map.prototype.clear = function() { | ||
| 27 | + this._keys = []; | ||
| 28 | + this._values = {}; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + Map.prototype.delete = function(key) { | ||
| 32 | + var value = this._values[key]; | ||
| 33 | + if(value == null) return false; | ||
| 34 | + // Delete entry | ||
| 35 | + delete this._values[key]; | ||
| 36 | + // Remove the key from the ordered keys list | ||
| 37 | + this._keys.splice(value.i, 1); | ||
| 38 | + return true; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + Map.prototype.entries = function() { | ||
| 42 | + var self = this; | ||
| 43 | + var index = 0; | ||
| 44 | + | ||
| 45 | + return { | ||
| 46 | + next: function() { | ||
| 47 | + var key = self._keys[index++]; | ||
| 48 | + return { | ||
| 49 | + value: key !== undefined ? [key, self._values[key].v] : undefined, | ||
| 50 | + done: key !== undefined ? false : true | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + }; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + Map.prototype.forEach = function(callback, self) { | ||
| 57 | + self = self || this; | ||
| 58 | + | ||
| 59 | + for(var i = 0; i < this._keys.length; i++) { | ||
| 60 | + var key = this._keys[i]; | ||
| 61 | + // Call the forEach callback | ||
| 62 | + callback.call(self, this._values[key].v, key, self); | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + Map.prototype.get = function(key) { | ||
| 67 | + return this._values[key] ? this._values[key].v : undefined; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + Map.prototype.has = function(key) { | ||
| 71 | + return this._values[key] != null; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + Map.prototype.keys = function(key) { | ||
| 75 | + var self = this; | ||
| 76 | + var index = 0; | ||
| 77 | + | ||
| 78 | + return { | ||
| 79 | + next: function() { | ||
| 80 | + var key = self._keys[index++]; | ||
| 81 | + return { | ||
| 82 | + value: key !== undefined ? key : undefined, | ||
| 83 | + done: key !== undefined ? false : true | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + }; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + Map.prototype.set = function(key, value) { | ||
| 90 | + if(this._values[key]) { | ||
| 91 | + this._values[key].v = value; | ||
| 92 | + return this; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + // Add the key to the list of keys in order | ||
| 96 | + this._keys.push(key); | ||
| 97 | + // Add the key and value to the values dictionary with a point | ||
| 98 | + // to the location in the ordered keys list | ||
| 99 | + this._values[key] = {v: value, i: this._keys.length - 1}; | ||
| 100 | + return this; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + Map.prototype.values = function(key, value) { | ||
| 104 | + var self = this; | ||
| 105 | + var index = 0; | ||
| 106 | + | ||
| 107 | + return { | ||
| 108 | + next: function() { | ||
| 109 | + var key = self._keys[index++]; | ||
| 110 | + return { | ||
| 111 | + value: key !== undefined ? self._values[key].v : undefined, | ||
| 112 | + done: key !== undefined ? false : true | ||
| 113 | + } | ||
| 114 | + } | ||
| 115 | + }; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + // Last ismaster | ||
| 119 | + Object.defineProperty(Map.prototype, 'size', { | ||
| 120 | + enumerable:true, | ||
| 121 | + get: function() { return this._keys.length; } | ||
| 122 | + }); | ||
| 123 | + | ||
| 124 | + module.exports = Map; | ||
| 125 | + module.exports.Map = Map; | ||
| 126 | +} |
| 1 | +/** | ||
| 2 | + * A class representation of the BSON MaxKey type. | ||
| 3 | + * | ||
| 4 | + * @class | ||
| 5 | + * @return {MaxKey} A MaxKey instance | ||
| 6 | + */ | ||
| 7 | +function MaxKey() { | ||
| 8 | + if(!(this instanceof MaxKey)) return new MaxKey(); | ||
| 9 | + | ||
| 10 | + this._bsontype = 'MaxKey'; | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +module.exports = MaxKey; | ||
| 14 | +module.exports.MaxKey = MaxKey; |
| 1 | +/** | ||
| 2 | + * A class representation of the BSON MinKey type. | ||
| 3 | + * | ||
| 4 | + * @class | ||
| 5 | + * @return {MinKey} A MinKey instance | ||
| 6 | + */ | ||
| 7 | +function MinKey() { | ||
| 8 | + if(!(this instanceof MinKey)) return new MinKey(); | ||
| 9 | + | ||
| 10 | + this._bsontype = 'MinKey'; | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +module.exports = MinKey; | ||
| 14 | +module.exports.MinKey = MinKey; |
| 1 | +/** | ||
| 2 | + * Machine id. | ||
| 3 | + * | ||
| 4 | + * Create a random 3-byte value (i.e. unique for this | ||
| 5 | + * process). Other drivers use a md5 of the machine id here, but | ||
| 6 | + * that would mean an asyc call to gethostname, so we don't bother. | ||
| 7 | + * @ignore | ||
| 8 | + */ | ||
| 9 | +var MACHINE_ID = parseInt(Math.random() * 0xFFFFFF, 10); | ||
| 10 | + | ||
| 11 | +// Regular expression that checks for hex value | ||
| 12 | +var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$"); | ||
| 13 | +var hasBufferType = false; | ||
| 14 | + | ||
| 15 | +// Check if buffer exists | ||
| 16 | +try { | ||
| 17 | + if(Buffer && Buffer.from) hasBufferType = true; | ||
| 18 | +} catch(err) {}; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | +* Create a new ObjectID instance | ||
| 22 | +* | ||
| 23 | +* @class | ||
| 24 | +* @param {(string|number)} id Can be a 24 byte hex string, 12 byte binary string or a Number. | ||
| 25 | +* @property {number} generationTime The generation time of this ObjectId instance | ||
| 26 | +* @return {ObjectID} instance of ObjectID. | ||
| 27 | +*/ | ||
| 28 | +var ObjectID = function ObjectID(id) { | ||
| 29 | + // Duck-typing to support ObjectId from different npm packages | ||
| 30 | + if(id instanceof ObjectID) return id; | ||
| 31 | + if(!(this instanceof ObjectID)) return new ObjectID(id); | ||
| 32 | + | ||
| 33 | + this._bsontype = 'ObjectID'; | ||
| 34 | + | ||
| 35 | + // The most common usecase (blank id, new objectId instance) | ||
| 36 | + if(id == null || typeof id == 'number') { | ||
| 37 | + // Generate a new id | ||
| 38 | + this.id = this.generate(id); | ||
| 39 | + // If we are caching the hex string | ||
| 40 | + if(ObjectID.cacheHexString) this.__id = this.toString('hex'); | ||
| 41 | + // Return the object | ||
| 42 | + return; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + // Check if the passed in id is valid | ||
| 46 | + var valid = ObjectID.isValid(id); | ||
| 47 | + | ||
| 48 | + // Throw an error if it's not a valid setup | ||
| 49 | + if(!valid && id != null){ | ||
| 50 | + throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); | ||
| 51 | + } else if(valid && typeof id == 'string' && id.length == 24 && hasBufferType) { | ||
| 52 | + return new ObjectID(new Buffer(id, 'hex')); | ||
| 53 | + } else if(valid && typeof id == 'string' && id.length == 24) { | ||
| 54 | + return ObjectID.createFromHexString(id); | ||
| 55 | + } else if(id != null && id.length === 12) { | ||
| 56 | + // assume 12 byte string | ||
| 57 | + this.id = id; | ||
| 58 | + } else if(id != null && id.toHexString) { | ||
| 59 | + // Duck-typing to support ObjectId from different npm packages | ||
| 60 | + return id; | ||
| 61 | + } else { | ||
| 62 | + throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + if(ObjectID.cacheHexString) this.__id = this.toString('hex'); | ||
| 66 | +}; | ||
| 67 | + | ||
| 68 | +// Allow usage of ObjectId as well as ObjectID | ||
| 69 | +var ObjectId = ObjectID; | ||
| 70 | + | ||
| 71 | +// Precomputed hex table enables speedy hex string conversion | ||
| 72 | +var hexTable = []; | ||
| 73 | +for (var i = 0; i < 256; i++) { | ||
| 74 | + hexTable[i] = (i <= 15 ? '0' : '') + i.toString(16); | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +/** | ||
| 78 | +* Return the ObjectID id as a 24 byte hex string representation | ||
| 79 | +* | ||
| 80 | +* @method | ||
| 81 | +* @return {string} return the 24 byte hex string representation. | ||
| 82 | +*/ | ||
| 83 | +ObjectID.prototype.toHexString = function() { | ||
| 84 | + if(ObjectID.cacheHexString && this.__id) return this.__id; | ||
| 85 | + | ||
| 86 | + var hexString = ''; | ||
| 87 | + if(!this.id || !this.id.length) { | ||
| 88 | + throw new Error('invalid ObjectId, ObjectId.id must be either a string or a Buffer, but is [' + JSON.stringify(this.id) + ']'); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + if(this.id instanceof _Buffer) { | ||
| 92 | + hexString = convertToHex(this.id); | ||
| 93 | + if(ObjectID.cacheHexString) this.__id = hexString; | ||
| 94 | + return hexString; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + for (var i = 0; i < this.id.length; i++) { | ||
| 98 | + hexString += hexTable[this.id.charCodeAt(i)]; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + if(ObjectID.cacheHexString) this.__id = hexString; | ||
| 102 | + return hexString; | ||
| 103 | +}; | ||
| 104 | + | ||
| 105 | +/** | ||
| 106 | +* Update the ObjectID index used in generating new ObjectID's on the driver | ||
| 107 | +* | ||
| 108 | +* @method | ||
| 109 | +* @return {number} returns next index value. | ||
| 110 | +* @ignore | ||
| 111 | +*/ | ||
| 112 | +ObjectID.prototype.get_inc = function() { | ||
| 113 | + return ObjectID.index = (ObjectID.index + 1) % 0xFFFFFF; | ||
| 114 | +}; | ||
| 115 | + | ||
| 116 | +/** | ||
| 117 | +* Update the ObjectID index used in generating new ObjectID's on the driver | ||
| 118 | +* | ||
| 119 | +* @method | ||
| 120 | +* @return {number} returns next index value. | ||
| 121 | +* @ignore | ||
| 122 | +*/ | ||
| 123 | +ObjectID.prototype.getInc = function() { | ||
| 124 | + return this.get_inc(); | ||
| 125 | +}; | ||
| 126 | + | ||
| 127 | +/** | ||
| 128 | +* Generate a 12 byte id buffer used in ObjectID's | ||
| 129 | +* | ||
| 130 | +* @method | ||
| 131 | +* @param {number} [time] optional parameter allowing to pass in a second based timestamp. | ||
| 132 | +* @return {Buffer} return the 12 byte id buffer string. | ||
| 133 | +*/ | ||
| 134 | +ObjectID.prototype.generate = function(time) { | ||
| 135 | + if ('number' != typeof time) { | ||
| 136 | + time = ~~(Date.now()/1000); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + // Use pid | ||
| 140 | + var pid = (typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid) % 0xFFFF; | ||
| 141 | + var inc = this.get_inc(); | ||
| 142 | + // Buffer used | ||
| 143 | + var buffer = new Buffer(12); | ||
| 144 | + // Encode time | ||
| 145 | + buffer[3] = time & 0xff; | ||
| 146 | + buffer[2] = (time >> 8) & 0xff; | ||
| 147 | + buffer[1] = (time >> 16) & 0xff; | ||
| 148 | + buffer[0] = (time >> 24) & 0xff; | ||
| 149 | + // Encode machine | ||
| 150 | + buffer[6] = MACHINE_ID & 0xff; | ||
| 151 | + buffer[5] = (MACHINE_ID >> 8) & 0xff; | ||
| 152 | + buffer[4] = (MACHINE_ID >> 16) & 0xff; | ||
| 153 | + // Encode pid | ||
| 154 | + buffer[8] = pid & 0xff; | ||
| 155 | + buffer[7] = (pid >> 8) & 0xff; | ||
| 156 | + // Encode index | ||
| 157 | + buffer[11] = inc & 0xff; | ||
| 158 | + buffer[10] = (inc >> 8) & 0xff; | ||
| 159 | + buffer[9] = (inc >> 16) & 0xff; | ||
| 160 | + // Return the buffer | ||
| 161 | + return buffer; | ||
| 162 | +}; | ||
| 163 | + | ||
| 164 | +/** | ||
| 165 | +* Converts the id into a 24 byte hex string for printing | ||
| 166 | +* | ||
| 167 | +* @param {String} format The Buffer toString format parameter. | ||
| 168 | +* @return {String} return the 24 byte hex string representation. | ||
| 169 | +* @ignore | ||
| 170 | +*/ | ||
| 171 | +ObjectID.prototype.toString = function(format) { | ||
| 172 | + // Is the id a buffer then use the buffer toString method to return the format | ||
| 173 | + if(this.id && this.id.copy) { | ||
| 174 | + return this.id.toString(typeof format === 'string' ? format : 'hex'); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + // if(this.buffer ) | ||
| 178 | + return this.toHexString(); | ||
| 179 | +}; | ||
| 180 | + | ||
| 181 | +/** | ||
| 182 | +* Converts to a string representation of this Id. | ||
| 183 | +* | ||
| 184 | +* @return {String} return the 24 byte hex string representation. | ||
| 185 | +* @ignore | ||
| 186 | +*/ | ||
| 187 | +ObjectID.prototype.inspect = ObjectID.prototype.toString; | ||
| 188 | + | ||
| 189 | +/** | ||
| 190 | +* Converts to its JSON representation. | ||
| 191 | +* | ||
| 192 | +* @return {String} return the 24 byte hex string representation. | ||
| 193 | +* @ignore | ||
| 194 | +*/ | ||
| 195 | +ObjectID.prototype.toJSON = function() { | ||
| 196 | + return this.toHexString(); | ||
| 197 | +}; | ||
| 198 | + | ||
| 199 | +/** | ||
| 200 | +* Compares the equality of this ObjectID with `otherID`. | ||
| 201 | +* | ||
| 202 | +* @method | ||
| 203 | +* @param {object} otherID ObjectID instance to compare against. | ||
| 204 | +* @return {boolean} the result of comparing two ObjectID's | ||
| 205 | +*/ | ||
| 206 | +ObjectID.prototype.equals = function equals (otherId) { | ||
| 207 | + var id; | ||
| 208 | + | ||
| 209 | + if(otherId instanceof ObjectID) { | ||
| 210 | + return this.toString() == otherId.toString(); | ||
| 211 | + } else if(typeof otherId == 'string' && ObjectID.isValid(otherId) && otherId.length == 12 && this.id instanceof _Buffer) { | ||
| 212 | + return otherId === this.id.toString('binary'); | ||
| 213 | + } else if(typeof otherId == 'string' && ObjectID.isValid(otherId) && otherId.length == 24) { | ||
| 214 | + return otherId.toLowerCase() === this.toHexString(); | ||
| 215 | + } else if(typeof otherId == 'string' && ObjectID.isValid(otherId) && otherId.length == 12) { | ||
| 216 | + return otherId === this.id; | ||
| 217 | + } else if(otherId != null && (otherId instanceof ObjectID || otherId.toHexString)) { | ||
| 218 | + return otherId.toHexString() === this.toHexString(); | ||
| 219 | + } else { | ||
| 220 | + return false; | ||
| 221 | + } | ||
| 222 | +} | ||
| 223 | + | ||
| 224 | +/** | ||
| 225 | +* Returns the generation date (accurate up to the second) that this ID was generated. | ||
| 226 | +* | ||
| 227 | +* @method | ||
| 228 | +* @return {date} the generation date | ||
| 229 | +*/ | ||
| 230 | +ObjectID.prototype.getTimestamp = function() { | ||
| 231 | + var timestamp = new Date(); | ||
| 232 | + var time = this.id[3] | this.id[2] << 8 | this.id[1] << 16 | this.id[0] << 24; | ||
| 233 | + timestamp.setTime(Math.floor(time) * 1000); | ||
| 234 | + return timestamp; | ||
| 235 | +} | ||
| 236 | + | ||
| 237 | +/** | ||
| 238 | +* @ignore | ||
| 239 | +*/ | ||
| 240 | +ObjectID.index = ~~(Math.random() * 0xFFFFFF); | ||
| 241 | + | ||
| 242 | +/** | ||
| 243 | +* @ignore | ||
| 244 | +*/ | ||
| 245 | +ObjectID.createPk = function createPk () { | ||
| 246 | + return new ObjectID(); | ||
| 247 | +}; | ||
| 248 | + | ||
| 249 | +/** | ||
| 250 | +* Creates an ObjectID from a second based number, with the rest of the ObjectID zeroed out. Used for comparisons or sorting the ObjectID. | ||
| 251 | +* | ||
| 252 | +* @method | ||
| 253 | +* @param {number} time an integer number representing a number of seconds. | ||
| 254 | +* @return {ObjectID} return the created ObjectID | ||
| 255 | +*/ | ||
| 256 | +ObjectID.createFromTime = function createFromTime (time) { | ||
| 257 | + var buffer = new Buffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); | ||
| 258 | + // Encode time into first 4 bytes | ||
| 259 | + buffer[3] = time & 0xff; | ||
| 260 | + buffer[2] = (time >> 8) & 0xff; | ||
| 261 | + buffer[1] = (time >> 16) & 0xff; | ||
| 262 | + buffer[0] = (time >> 24) & 0xff; | ||
| 263 | + // Return the new objectId | ||
| 264 | + return new ObjectID(buffer); | ||
| 265 | +}; | ||
| 266 | + | ||
| 267 | +// Lookup tables | ||
| 268 | +var encodeLookup = '0123456789abcdef'.split('') | ||
| 269 | +var decodeLookup = [] | ||
| 270 | +var i = 0 | ||
| 271 | +while (i < 10) decodeLookup[0x30 + i] = i++ | ||
| 272 | +while (i < 16) decodeLookup[0x41 - 10 + i] = decodeLookup[0x61 - 10 + i] = i++ | ||
| 273 | + | ||
| 274 | +var _Buffer = Buffer; | ||
| 275 | +var convertToHex = function(bytes) { | ||
| 276 | + return bytes.toString('hex'); | ||
| 277 | +} | ||
| 278 | + | ||
| 279 | +/** | ||
| 280 | +* Creates an ObjectID from a hex string representation of an ObjectID. | ||
| 281 | +* | ||
| 282 | +* @method | ||
| 283 | +* @param {string} hexString create a ObjectID from a passed in 24 byte hexstring. | ||
| 284 | +* @return {ObjectID} return the created ObjectID | ||
| 285 | +*/ | ||
| 286 | +ObjectID.createFromHexString = function createFromHexString (string) { | ||
| 287 | + // Throw an error if it's not a valid setup | ||
| 288 | + if(typeof string === 'undefined' || string != null && string.length != 24) { | ||
| 289 | + throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + // Use Buffer.from method if available | ||
| 293 | + if(hasBufferType) return new ObjectID(new Buffer(string, 'hex')); | ||
| 294 | + | ||
| 295 | + // Calculate lengths | ||
| 296 | + var array = new _Buffer(12); | ||
| 297 | + var n = 0; | ||
| 298 | + var i = 0; | ||
| 299 | + | ||
| 300 | + while (i < 24) { | ||
| 301 | + array[n++] = decodeLookup[string.charCodeAt(i++)] << 4 | decodeLookup[string.charCodeAt(i++)] | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + return new ObjectID(array); | ||
| 305 | +}; | ||
| 306 | + | ||
| 307 | +/** | ||
| 308 | +* Checks if a value is a valid bson ObjectId | ||
| 309 | +* | ||
| 310 | +* @method | ||
| 311 | +* @return {boolean} return true if the value is a valid bson ObjectId, return false otherwise. | ||
| 312 | +*/ | ||
| 313 | +ObjectID.isValid = function isValid(id) { | ||
| 314 | + if(id == null) return false; | ||
| 315 | + | ||
| 316 | + if(typeof id == 'number') { | ||
| 317 | + return true; | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + if(typeof id == 'string') { | ||
| 321 | + return id.length == 12 || (id.length == 24 && checkForHexRegExp.test(id)); | ||
| 322 | + } | ||
| 323 | + | ||
| 324 | + if(id instanceof ObjectID) { | ||
| 325 | + return true; | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + if(id instanceof _Buffer) { | ||
| 329 | + return true; | ||
| 330 | + } | ||
| 331 | + | ||
| 332 | + // Duck-Typing detection of ObjectId like objects | ||
| 333 | + if(id.toHexString) { | ||
| 334 | + return id.id.length == 12 || (id.id.length == 24 && checkForHexRegExp.test(id.id)); | ||
| 335 | + } | ||
| 336 | + | ||
| 337 | + return false; | ||
| 338 | +}; | ||
| 339 | + | ||
| 340 | +/** | ||
| 341 | +* @ignore | ||
| 342 | +*/ | ||
| 343 | +Object.defineProperty(ObjectID.prototype, "generationTime", { | ||
| 344 | + enumerable: true | ||
| 345 | + , get: function () { | ||
| 346 | + return this.id[3] | this.id[2] << 8 | this.id[1] << 16 | this.id[0] << 24; | ||
| 347 | + } | ||
| 348 | + , set: function (value) { | ||
| 349 | + // Encode time into first 4 bytes | ||
| 350 | + this.id[3] = value & 0xff; | ||
| 351 | + this.id[2] = (value >> 8) & 0xff; | ||
| 352 | + this.id[1] = (value >> 16) & 0xff; | ||
| 353 | + this.id[0] = (value >> 24) & 0xff; | ||
| 354 | + } | ||
| 355 | +}); | ||
| 356 | + | ||
| 357 | +/** | ||
| 358 | + * Expose. | ||
| 359 | + */ | ||
| 360 | +module.exports = ObjectID; | ||
| 361 | +module.exports.ObjectID = ObjectID; | ||
| 362 | +module.exports.ObjectId = ObjectID; |
| 1 | +"use strict" | ||
| 2 | + | ||
| 3 | +var writeIEEE754 = require('../float_parser').writeIEEE754 | ||
| 4 | + , readIEEE754 = require('../float_parser').readIEEE754 | ||
| 5 | + , Long = require('../long').Long | ||
| 6 | + , Double = require('../double').Double | ||
| 7 | + , Timestamp = require('../timestamp').Timestamp | ||
| 8 | + , ObjectID = require('../objectid').ObjectID | ||
| 9 | + , Symbol = require('../symbol').Symbol | ||
| 10 | + , BSONRegExp = require('../regexp').BSONRegExp | ||
| 11 | + , Code = require('../code').Code | ||
| 12 | + , Decimal128 = require('../decimal128') | ||
| 13 | + , MinKey = require('../min_key').MinKey | ||
| 14 | + , MaxKey = require('../max_key').MaxKey | ||
| 15 | + , DBRef = require('../db_ref').DBRef | ||
| 16 | + , Binary = require('../binary').Binary; | ||
| 17 | + | ||
| 18 | +// To ensure that 0.4 of node works correctly | ||
| 19 | +var isDate = function isDate(d) { | ||
| 20 | + return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]'; | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +var calculateObjectSize = function calculateObjectSize(object, serializeFunctions, ignoreUndefined) { | ||
| 24 | + var totalLength = (4 + 1); | ||
| 25 | + | ||
| 26 | + if(Array.isArray(object)) { | ||
| 27 | + for(var i = 0; i < object.length; i++) { | ||
| 28 | + totalLength += calculateElement(i.toString(), object[i], serializeFunctions, true, ignoreUndefined) | ||
| 29 | + } | ||
| 30 | + } else { | ||
| 31 | + // If we have toBSON defined, override the current object | ||
| 32 | + if(object.toBSON) { | ||
| 33 | + object = object.toBSON(); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + // Calculate size | ||
| 37 | + for(var key in object) { | ||
| 38 | + totalLength += calculateElement(key, object[key], serializeFunctions, false, ignoreUndefined) | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + return totalLength; | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +/** | ||
| 46 | + * @ignore | ||
| 47 | + * @api private | ||
| 48 | + */ | ||
| 49 | +function calculateElement(name, value, serializeFunctions, isArray, ignoreUndefined) { | ||
| 50 | + // If we have toBSON defined, override the current object | ||
| 51 | + if(value && value.toBSON){ | ||
| 52 | + value = value.toBSON(); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + switch(typeof value) { | ||
| 56 | + case 'string': | ||
| 57 | + return 1 + Buffer.byteLength(name, 'utf8') + 1 + 4 + Buffer.byteLength(value, 'utf8') + 1; | ||
| 58 | + case 'number': | ||
| 59 | + if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
| 60 | + if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { // 32 bit | ||
| 61 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (4 + 1); | ||
| 62 | + } else { | ||
| 63 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (8 + 1); | ||
| 64 | + } | ||
| 65 | + } else { // 64 bit | ||
| 66 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (8 + 1); | ||
| 67 | + } | ||
| 68 | + case 'undefined': | ||
| 69 | + if(isArray || !ignoreUndefined) return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (1); | ||
| 70 | + return 0; | ||
| 71 | + case 'boolean': | ||
| 72 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (1 + 1); | ||
| 73 | + case 'object': | ||
| 74 | + if(value == null || value instanceof MinKey || value instanceof MaxKey || value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { | ||
| 75 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (1); | ||
| 76 | + } else if(value instanceof ObjectID || value['_bsontype'] == 'ObjectID') { | ||
| 77 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (12 + 1); | ||
| 78 | + } else if(value instanceof Date || isDate(value)) { | ||
| 79 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (8 + 1); | ||
| 80 | + } else if(typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { | ||
| 81 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (1 + 4 + 1) + value.length; | ||
| 82 | + } else if(value instanceof Long || value instanceof Double || value instanceof Timestamp | ||
| 83 | + || value['_bsontype'] == 'Long' || value['_bsontype'] == 'Double' || value['_bsontype'] == 'Timestamp') { | ||
| 84 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (8 + 1); | ||
| 85 | + } else if(value instanceof Decimal128 || value['_bsontype'] == 'Decimal128') { | ||
| 86 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (16 + 1); | ||
| 87 | + } else if(value instanceof Code || value['_bsontype'] == 'Code') { | ||
| 88 | + // Calculate size depending on the availability of a scope | ||
| 89 | + if(value.scope != null && Object.keys(value.scope).length > 0) { | ||
| 90 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + 4 + 4 + Buffer.byteLength(value.code.toString(), 'utf8') + 1 + calculateObjectSize(value.scope, serializeFunctions, ignoreUndefined); | ||
| 91 | + } else { | ||
| 92 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + 4 + Buffer.byteLength(value.code.toString(), 'utf8') + 1; | ||
| 93 | + } | ||
| 94 | + } else if(value instanceof Binary || value['_bsontype'] == 'Binary') { | ||
| 95 | + // Check what kind of subtype we have | ||
| 96 | + if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) { | ||
| 97 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (value.position + 1 + 4 + 1 + 4); | ||
| 98 | + } else { | ||
| 99 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (value.position + 1 + 4 + 1); | ||
| 100 | + } | ||
| 101 | + } else if(value instanceof Symbol || value['_bsontype'] == 'Symbol') { | ||
| 102 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + Buffer.byteLength(value.value, 'utf8') + 4 + 1 + 1; | ||
| 103 | + } else if(value instanceof DBRef || value['_bsontype'] == 'DBRef') { | ||
| 104 | + // Set up correct object for serialization | ||
| 105 | + var ordered_values = { | ||
| 106 | + '$ref': value.namespace | ||
| 107 | + , '$id' : value.oid | ||
| 108 | + }; | ||
| 109 | + | ||
| 110 | + // Add db reference if it exists | ||
| 111 | + if(null != value.db) { | ||
| 112 | + ordered_values['$db'] = value.db; | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + calculateObjectSize(ordered_values, serializeFunctions, ignoreUndefined); | ||
| 116 | + } else if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]') { | ||
| 117 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + Buffer.byteLength(value.source, 'utf8') + 1 | ||
| 118 | + + (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1 | ||
| 119 | + } else if(value instanceof BSONRegExp || value['_bsontype'] == 'BSONRegExp') { | ||
| 120 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + Buffer.byteLength(value.pattern, 'utf8') + 1 | ||
| 121 | + + Buffer.byteLength(value.options, 'utf8') + 1 | ||
| 122 | + } else { | ||
| 123 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + calculateObjectSize(value, serializeFunctions, ignoreUndefined) + 1; | ||
| 124 | + } | ||
| 125 | + case 'function': | ||
| 126 | + // WTF for 0.4.X where typeof /someregexp/ === 'function' | ||
| 127 | + if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]' || String.call(value) == '[object RegExp]') { | ||
| 128 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + Buffer.byteLength(value.source, 'utf8') + 1 | ||
| 129 | + + (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1 | ||
| 130 | + } else { | ||
| 131 | + if(serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) { | ||
| 132 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + 4 + 4 + Buffer.byteLength(value.toString(), 'utf8') + 1 + calculateObjectSize(value.scope, serializeFunctions, ignoreUndefined); | ||
| 133 | + } else if(serializeFunctions) { | ||
| 134 | + return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + 4 + Buffer.byteLength(value.toString(), 'utf8') + 1; | ||
| 135 | + } | ||
| 136 | + } | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + return 0; | ||
| 140 | +} | ||
| 141 | + | ||
| 142 | +var BSON = {}; | ||
| 143 | + | ||
| 144 | +// BSON MAX VALUES | ||
| 145 | +BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
| 146 | +BSON.BSON_INT32_MIN = -0x80000000; | ||
| 147 | + | ||
| 148 | +// JS MAX PRECISE VALUES | ||
| 149 | +BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
| 150 | +BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
| 151 | + | ||
| 152 | +module.exports = calculateObjectSize; |
| 1 | +"use strict" | ||
| 2 | + | ||
| 3 | +var readIEEE754 = require('../float_parser').readIEEE754, | ||
| 4 | + f = require('util').format, | ||
| 5 | + Long = require('../long').Long, | ||
| 6 | + Double = require('../double').Double, | ||
| 7 | + Timestamp = require('../timestamp').Timestamp, | ||
| 8 | + ObjectID = require('../objectid').ObjectID, | ||
| 9 | + Symbol = require('../symbol').Symbol, | ||
| 10 | + Code = require('../code').Code, | ||
| 11 | + MinKey = require('../min_key').MinKey, | ||
| 12 | + MaxKey = require('../max_key').MaxKey, | ||
| 13 | + Decimal128 = require('../decimal128'), | ||
| 14 | + Int32 = require('../int_32'), | ||
| 15 | + DBRef = require('../db_ref').DBRef, | ||
| 16 | + BSONRegExp = require('../regexp').BSONRegExp, | ||
| 17 | + Binary = require('../binary').Binary; | ||
| 18 | + | ||
| 19 | +var deserialize = function(buffer, options, isArray) { | ||
| 20 | + options = options == null ? {} : options; | ||
| 21 | + var index = options && options.index ? options.index : 0; | ||
| 22 | + // Read the document size | ||
| 23 | + var size = buffer[index] | buffer[index+1] << 8 | buffer[index+2] << 16 | buffer[index+3] << 24; | ||
| 24 | + | ||
| 25 | + // Ensure buffer is valid size | ||
| 26 | + if(size < 5 || buffer.length < size || (size + index) > buffer.length) { | ||
| 27 | + throw new Error("corrupt bson message"); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + // Illegal end value | ||
| 31 | + if(buffer[index + size - 1] != 0) { | ||
| 32 | + throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00"); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + // Start deserializtion | ||
| 36 | + return deserializeObject(buffer, index, options, isArray); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +var deserializeObject = function(buffer, index, options, isArray) { | ||
| 40 | + var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions']; | ||
| 41 | + var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions']; | ||
| 42 | + var cacheFunctionsCrc32 = options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32']; | ||
| 43 | + var fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw']; | ||
| 44 | + | ||
| 45 | + // Return raw bson buffer instead of parsing it | ||
| 46 | + var raw = options['raw'] == null ? false : options['raw']; | ||
| 47 | + | ||
| 48 | + // Return BSONRegExp objects instead of native regular expressions | ||
| 49 | + var bsonRegExp = typeof options['bsonRegExp'] == 'boolean' ? options['bsonRegExp'] : false; | ||
| 50 | + | ||
| 51 | + // Controls the promotion of values vs wrapper classes | ||
| 52 | + var promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers']; | ||
| 53 | + var promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs']; | ||
| 54 | + var promoteValues = options['promoteValues'] == null ? true : options['promoteValues']; | ||
| 55 | + | ||
| 56 | + // Set the start index | ||
| 57 | + var startIndex = index; | ||
| 58 | + | ||
| 59 | + // Validate that we have at least 4 bytes of buffer | ||
| 60 | + if(buffer.length < 5) throw new Error("corrupt bson message < 5 bytes long"); | ||
| 61 | + | ||
| 62 | + // Read the document size | ||
| 63 | + var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 64 | + | ||
| 65 | + // Ensure buffer is valid size | ||
| 66 | + if(size < 5 || size > buffer.length) throw new Error("corrupt bson message"); | ||
| 67 | + | ||
| 68 | + // Create holding object | ||
| 69 | + var object = isArray ? [] : {}; | ||
| 70 | + // Used for arrays to skip having to perform utf8 decoding | ||
| 71 | + var arrayIndex = 0; | ||
| 72 | + | ||
| 73 | + // While we have more left data left keep parsing | ||
| 74 | + while(true) { | ||
| 75 | + // Read the type | ||
| 76 | + var elementType = buffer[index++]; | ||
| 77 | + // If we get a zero it's the last byte, exit | ||
| 78 | + if(elementType == 0) { | ||
| 79 | + break; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + // Get the start search index | ||
| 83 | + var i = index; | ||
| 84 | + // Locate the end of the c string | ||
| 85 | + while(buffer[i] !== 0x00 && i < buffer.length) { | ||
| 86 | + i++ | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + // If are at the end of the buffer there is a problem with the document | ||
| 90 | + if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
| 91 | + var name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i); | ||
| 92 | + | ||
| 93 | + index = i + 1; | ||
| 94 | + | ||
| 95 | + if(elementType == BSON.BSON_DATA_STRING) { | ||
| 96 | + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 97 | + if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
| 98 | + object[name] = buffer.toString('utf8', index, index + stringSize - 1); | ||
| 99 | + index = index + stringSize; | ||
| 100 | + } else if(elementType == BSON.BSON_DATA_OID) { | ||
| 101 | + var oid = new Buffer(12); | ||
| 102 | + buffer.copy(oid, 0, index, index + 12); | ||
| 103 | + object[name] = new ObjectID(oid); | ||
| 104 | + index = index + 12; | ||
| 105 | + } else if(elementType == BSON.BSON_DATA_INT && promoteValues == false) { | ||
| 106 | + object[name] = new Int32(buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24); | ||
| 107 | + } else if(elementType == BSON.BSON_DATA_INT) { | ||
| 108 | + object[name] = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 109 | + } else if(elementType == BSON.BSON_DATA_NUMBER && promoteValues == false) { | ||
| 110 | + object[name] = new Double(buffer.readDoubleLE(index)); | ||
| 111 | + index = index + 8; | ||
| 112 | + } else if(elementType == BSON.BSON_DATA_NUMBER) { | ||
| 113 | + object[name] = buffer.readDoubleLE(index); | ||
| 114 | + index = index + 8; | ||
| 115 | + } else if(elementType == BSON.BSON_DATA_DATE) { | ||
| 116 | + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 117 | + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 118 | + object[name] = new Date(new Long(lowBits, highBits).toNumber()); | ||
| 119 | + } else if(elementType == BSON.BSON_DATA_BOOLEAN) { | ||
| 120 | + if(buffer[index] != 0 && buffer[index] != 1) throw new Error('illegal boolean type value'); | ||
| 121 | + object[name] = buffer[index++] == 1; | ||
| 122 | + } else if(elementType == BSON.BSON_DATA_OBJECT) { | ||
| 123 | + var _index = index; | ||
| 124 | + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; | ||
| 125 | + if(objectSize <= 0 || objectSize > (buffer.length - index)) throw new Error("bad embedded document length in bson"); | ||
| 126 | + | ||
| 127 | + // We have a raw value | ||
| 128 | + if(raw) { | ||
| 129 | + object[name] = buffer.slice(index, index + objectSize); | ||
| 130 | + } else { | ||
| 131 | + object[name] = deserializeObject(buffer, _index, options, false); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + index = index + objectSize; | ||
| 135 | + } else if(elementType == BSON.BSON_DATA_ARRAY) { | ||
| 136 | + var _index = index; | ||
| 137 | + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; | ||
| 138 | + var arrayOptions = options; | ||
| 139 | + | ||
| 140 | + // Stop index | ||
| 141 | + var stopIndex = index + objectSize; | ||
| 142 | + | ||
| 143 | + // All elements of array to be returned as raw bson | ||
| 144 | + if(fieldsAsRaw && fieldsAsRaw[name]) { | ||
| 145 | + arrayOptions = {}; | ||
| 146 | + for(var n in options) arrayOptions[n] = options[n]; | ||
| 147 | + arrayOptions['raw'] = true; | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + object[name] = deserializeObject(buffer, _index, arrayOptions, true); | ||
| 151 | + index = index + objectSize; | ||
| 152 | + | ||
| 153 | + if(buffer[index - 1] != 0) throw new Error('invalid array terminator byte'); | ||
| 154 | + if(index != stopIndex) throw new Error('corrupted array bson'); | ||
| 155 | + } else if(elementType == BSON.BSON_DATA_UNDEFINED) { | ||
| 156 | + object[name] = undefined; | ||
| 157 | + } else if(elementType == BSON.BSON_DATA_NULL) { | ||
| 158 | + object[name] = null; | ||
| 159 | + } else if(elementType == BSON.BSON_DATA_LONG) { | ||
| 160 | + // Unpack the low and high bits | ||
| 161 | + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 162 | + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 163 | + var long = new Long(lowBits, highBits); | ||
| 164 | + // Promote the long if possible | ||
| 165 | + if(promoteLongs && promoteValues == true) { | ||
| 166 | + object[name] = long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG) ? long.toNumber() : long; | ||
| 167 | + } else { | ||
| 168 | + object[name] = long; | ||
| 169 | + } | ||
| 170 | + } else if(elementType == BSON.BSON_DATA_DECIMAL128) { | ||
| 171 | + // Buffer to contain the decimal bytes | ||
| 172 | + var bytes = new Buffer(16); | ||
| 173 | + // Copy the next 16 bytes into the bytes buffer | ||
| 174 | + buffer.copy(bytes, 0, index, index + 16); | ||
| 175 | + // Update index | ||
| 176 | + index = index + 16; | ||
| 177 | + // Assign the new Decimal128 value | ||
| 178 | + var decimal128 = new Decimal128(bytes); | ||
| 179 | + // If we have an alternative mapper use that | ||
| 180 | + object[name] = decimal128.toObject ? decimal128.toObject() : decimal128; | ||
| 181 | + } else if(elementType == BSON.BSON_DATA_BINARY) { | ||
| 182 | + var binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 183 | + var totalBinarySize = binarySize; | ||
| 184 | + var subType = buffer[index++]; | ||
| 185 | + | ||
| 186 | + // Did we have a negative binary size, throw | ||
| 187 | + if(binarySize < 0) throw new Error('Negative binary type element size found'); | ||
| 188 | + | ||
| 189 | + // Is the length longer than the document | ||
| 190 | + if(binarySize > buffer.length) throw new Error('Binary type size larger than document size'); | ||
| 191 | + | ||
| 192 | + // Decode as raw Buffer object if options specifies it | ||
| 193 | + if(buffer['slice'] != null) { | ||
| 194 | + // If we have subtype 2 skip the 4 bytes for the size | ||
| 195 | + if(subType == Binary.SUBTYPE_BYTE_ARRAY) { | ||
| 196 | + binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 197 | + if(binarySize < 0) throw new Error('Negative binary type element size found for subtype 0x02'); | ||
| 198 | + if(binarySize > (totalBinarySize - 4)) throw new Error('Binary type with subtype 0x02 contains to long binary size'); | ||
| 199 | + if(binarySize < (totalBinarySize - 4)) throw new Error('Binary type with subtype 0x02 contains to short binary size'); | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + if(promoteBuffers && promoteValues) { | ||
| 203 | + object[name] = buffer.slice(index, index + binarySize); | ||
| 204 | + } else { | ||
| 205 | + object[name] = new Binary(buffer.slice(index, index + binarySize), subType); | ||
| 206 | + } | ||
| 207 | + } else { | ||
| 208 | + var _buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(binarySize)) : new Array(binarySize); | ||
| 209 | + // If we have subtype 2 skip the 4 bytes for the size | ||
| 210 | + if(subType == Binary.SUBTYPE_BYTE_ARRAY) { | ||
| 211 | + binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 212 | + if(binarySize < 0) throw new Error('Negative binary type element size found for subtype 0x02'); | ||
| 213 | + if(binarySize > (totalBinarySize - 4)) throw new Error('Binary type with subtype 0x02 contains to long binary size'); | ||
| 214 | + if(binarySize < (totalBinarySize - 4)) throw new Error('Binary type with subtype 0x02 contains to short binary size'); | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + // Copy the data | ||
| 218 | + for(var i = 0; i < binarySize; i++) { | ||
| 219 | + _buffer[i] = buffer[index + i]; | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + if(promoteBuffers && promoteValues) { | ||
| 223 | + object[name] = _buffer; | ||
| 224 | + } else { | ||
| 225 | + object[name] = new Binary(_buffer, subType); | ||
| 226 | + } | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + // Update the index | ||
| 230 | + index = index + binarySize; | ||
| 231 | + } else if(elementType == BSON.BSON_DATA_REGEXP && bsonRegExp == false) { | ||
| 232 | + // Get the start search index | ||
| 233 | + var i = index; | ||
| 234 | + // Locate the end of the c string | ||
| 235 | + while(buffer[i] !== 0x00 && i < buffer.length) { | ||
| 236 | + i++ | ||
| 237 | + } | ||
| 238 | + // If are at the end of the buffer there is a problem with the document | ||
| 239 | + if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
| 240 | + // Return the C string | ||
| 241 | + var source = buffer.toString('utf8', index, i); | ||
| 242 | + // Create the regexp | ||
| 243 | + index = i + 1; | ||
| 244 | + | ||
| 245 | + // Get the start search index | ||
| 246 | + var i = index; | ||
| 247 | + // Locate the end of the c string | ||
| 248 | + while(buffer[i] !== 0x00 && i < buffer.length) { | ||
| 249 | + i++ | ||
| 250 | + } | ||
| 251 | + // If are at the end of the buffer there is a problem with the document | ||
| 252 | + if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
| 253 | + // Return the C string | ||
| 254 | + var regExpOptions = buffer.toString('utf8', index, i); | ||
| 255 | + index = i + 1; | ||
| 256 | + | ||
| 257 | + // For each option add the corresponding one for javascript | ||
| 258 | + var optionsArray = new Array(regExpOptions.length); | ||
| 259 | + | ||
| 260 | + // Parse options | ||
| 261 | + for(var i = 0; i < regExpOptions.length; i++) { | ||
| 262 | + switch(regExpOptions[i]) { | ||
| 263 | + case 'm': | ||
| 264 | + optionsArray[i] = 'm'; | ||
| 265 | + break; | ||
| 266 | + case 's': | ||
| 267 | + optionsArray[i] = 'g'; | ||
| 268 | + break; | ||
| 269 | + case 'i': | ||
| 270 | + optionsArray[i] = 'i'; | ||
| 271 | + break; | ||
| 272 | + } | ||
| 273 | + } | ||
| 274 | + | ||
| 275 | + object[name] = new RegExp(source, optionsArray.join('')); | ||
| 276 | + } else if(elementType == BSON.BSON_DATA_REGEXP && bsonRegExp == true) { | ||
| 277 | + // Get the start search index | ||
| 278 | + var i = index; | ||
| 279 | + // Locate the end of the c string | ||
| 280 | + while(buffer[i] !== 0x00 && i < buffer.length) { | ||
| 281 | + i++ | ||
| 282 | + } | ||
| 283 | + // If are at the end of the buffer there is a problem with the document | ||
| 284 | + if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
| 285 | + // Return the C string | ||
| 286 | + var source = buffer.toString('utf8', index, i); | ||
| 287 | + index = i + 1; | ||
| 288 | + | ||
| 289 | + // Get the start search index | ||
| 290 | + var i = index; | ||
| 291 | + // Locate the end of the c string | ||
| 292 | + while(buffer[i] !== 0x00 && i < buffer.length) { | ||
| 293 | + i++ | ||
| 294 | + } | ||
| 295 | + // If are at the end of the buffer there is a problem with the document | ||
| 296 | + if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
| 297 | + // Return the C string | ||
| 298 | + var regExpOptions = buffer.toString('utf8', index, i); | ||
| 299 | + index = i + 1; | ||
| 300 | + | ||
| 301 | + // Set the object | ||
| 302 | + object[name] = new BSONRegExp(source, regExpOptions); | ||
| 303 | + } else if(elementType == BSON.BSON_DATA_SYMBOL) { | ||
| 304 | + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 305 | + if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
| 306 | + object[name] = new Symbol(buffer.toString('utf8', index, index + stringSize - 1)); | ||
| 307 | + index = index + stringSize; | ||
| 308 | + } else if(elementType == BSON.BSON_DATA_TIMESTAMP) { | ||
| 309 | + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 310 | + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 311 | + object[name] = new Timestamp(lowBits, highBits); | ||
| 312 | + } else if(elementType == BSON.BSON_DATA_MIN_KEY) { | ||
| 313 | + object[name] = new MinKey(); | ||
| 314 | + } else if(elementType == BSON.BSON_DATA_MAX_KEY) { | ||
| 315 | + object[name] = new MaxKey(); | ||
| 316 | + } else if(elementType == BSON.BSON_DATA_CODE) { | ||
| 317 | + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 318 | + if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
| 319 | + var functionString = buffer.toString('utf8', index, index + stringSize - 1); | ||
| 320 | + | ||
| 321 | + // If we are evaluating the functions | ||
| 322 | + if(evalFunctions) { | ||
| 323 | + var value = null; | ||
| 324 | + // If we have cache enabled let's look for the md5 of the function in the cache | ||
| 325 | + if(cacheFunctions) { | ||
| 326 | + var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; | ||
| 327 | + // Got to do this to avoid V8 deoptimizing the call due to finding eval | ||
| 328 | + object[name] = isolateEvalWithHash(functionCache, hash, functionString, object); | ||
| 329 | + } else { | ||
| 330 | + object[name] = isolateEval(functionString); | ||
| 331 | + } | ||
| 332 | + } else { | ||
| 333 | + object[name] = new Code(functionString); | ||
| 334 | + } | ||
| 335 | + | ||
| 336 | + // Update parse index position | ||
| 337 | + index = index + stringSize; | ||
| 338 | + } else if(elementType == BSON.BSON_DATA_CODE_W_SCOPE) { | ||
| 339 | + var totalSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 340 | + | ||
| 341 | + // Element cannot be shorter than totalSize + stringSize + documentSize + terminator | ||
| 342 | + if(totalSize < (4 + 4 + 4 + 1)) { | ||
| 343 | + throw new Error("code_w_scope total size shorter minimum expected length"); | ||
| 344 | + } | ||
| 345 | + | ||
| 346 | + // Get the code string size | ||
| 347 | + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 348 | + // Check if we have a valid string | ||
| 349 | + if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
| 350 | + | ||
| 351 | + // Javascript function | ||
| 352 | + var functionString = buffer.toString('utf8', index, index + stringSize - 1); | ||
| 353 | + // Update parse index position | ||
| 354 | + index = index + stringSize; | ||
| 355 | + // Parse the element | ||
| 356 | + var _index = index; | ||
| 357 | + // Decode the size of the object document | ||
| 358 | + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; | ||
| 359 | + // Decode the scope object | ||
| 360 | + var scopeObject = deserializeObject(buffer, _index, options, false); | ||
| 361 | + // Adjust the index | ||
| 362 | + index = index + objectSize; | ||
| 363 | + | ||
| 364 | + // Check if field length is to short | ||
| 365 | + if(totalSize < (4 + 4 + objectSize + stringSize)) { | ||
| 366 | + throw new Error('code_w_scope total size is to short, truncating scope'); | ||
| 367 | + } | ||
| 368 | + | ||
| 369 | + // Check if totalSize field is to long | ||
| 370 | + if(totalSize > (4 + 4 + objectSize + stringSize)) { | ||
| 371 | + throw new Error('code_w_scope total size is to long, clips outer document'); | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + // If we are evaluating the functions | ||
| 375 | + if(evalFunctions) { | ||
| 376 | + // Contains the value we are going to set | ||
| 377 | + var value = null; | ||
| 378 | + // If we have cache enabled let's look for the md5 of the function in the cache | ||
| 379 | + if(cacheFunctions) { | ||
| 380 | + var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; | ||
| 381 | + // Got to do this to avoid V8 deoptimizing the call due to finding eval | ||
| 382 | + object[name] = isolateEvalWithHash(functionCache, hash, functionString, object); | ||
| 383 | + } else { | ||
| 384 | + object[name] = isolateEval(functionString); | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + object[name].scope = scopeObject; | ||
| 388 | + } else { | ||
| 389 | + object[name] = new Code(functionString, scopeObject); | ||
| 390 | + } | ||
| 391 | + } else if(elementType == BSON.BSON_DATA_DBPOINTER) { | ||
| 392 | + // Get the code string size | ||
| 393 | + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
| 394 | + // Check if we have a valid string | ||
| 395 | + if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
| 396 | + // Namespace | ||
| 397 | + var namespace = buffer.toString('utf8', index, index + stringSize - 1); | ||
| 398 | + // Update parse index position | ||
| 399 | + index = index + stringSize; | ||
| 400 | + | ||
| 401 | + // Read the oid | ||
| 402 | + var oidBuffer = new Buffer(12); | ||
| 403 | + buffer.copy(oidBuffer, 0, index, index + 12); | ||
| 404 | + var oid = new ObjectID(oidBuffer); | ||
| 405 | + | ||
| 406 | + // Update the index | ||
| 407 | + index = index + 12; | ||
| 408 | + | ||
| 409 | + // Split the namespace | ||
| 410 | + var parts = namespace.split('.'); | ||
| 411 | + var db = parts.shift(); | ||
| 412 | + var collection = parts.join('.'); | ||
| 413 | + // Upgrade to DBRef type | ||
| 414 | + object[name] = new DBRef(collection, oid, db); | ||
| 415 | + } else { | ||
| 416 | + throw new Error("Detected unknown BSON type " + elementType.toString(16) + " for fieldname \"" + name + "\", are you using the latest BSON parser"); | ||
| 417 | + } | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + // Check if the deserialization was against a valid array/object | ||
| 421 | + if(size != (index - startIndex)) { | ||
| 422 | + if(isArray) throw new Error('corrupt array bson'); | ||
| 423 | + throw new Error('corrupt object bson'); | ||
| 424 | + } | ||
| 425 | + | ||
| 426 | + // Check if we have a db ref object | ||
| 427 | + if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']); | ||
| 428 | + return object; | ||
| 429 | +} | ||
| 430 | + | ||
| 431 | +/** | ||
| 432 | + * Ensure eval is isolated. | ||
| 433 | + * | ||
| 434 | + * @ignore | ||
| 435 | + * @api private | ||
| 436 | + */ | ||
| 437 | +var isolateEvalWithHash = function(functionCache, hash, functionString, object) { | ||
| 438 | + // Contains the value we are going to set | ||
| 439 | + var value = null; | ||
| 440 | + | ||
| 441 | + // Check for cache hit, eval if missing and return cached function | ||
| 442 | + if(functionCache[hash] == null) { | ||
| 443 | + eval("value = " + functionString); | ||
| 444 | + functionCache[hash] = value; | ||
| 445 | + } | ||
| 446 | + // Set the object | ||
| 447 | + return functionCache[hash].bind(object); | ||
| 448 | +} | ||
| 449 | + | ||
| 450 | +/** | ||
| 451 | + * Ensure eval is isolated. | ||
| 452 | + * | ||
| 453 | + * @ignore | ||
| 454 | + * @api private | ||
| 455 | + */ | ||
| 456 | +var isolateEval = function(functionString) { | ||
| 457 | + // Contains the value we are going to set | ||
| 458 | + var value = null; | ||
| 459 | + // Eval the function | ||
| 460 | + eval("value = " + functionString); | ||
| 461 | + return value; | ||
| 462 | +} | ||
| 463 | + | ||
| 464 | +var BSON = {}; | ||
| 465 | + | ||
| 466 | +/** | ||
| 467 | + * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5 | ||
| 468 | + * | ||
| 469 | + * @ignore | ||
| 470 | + * @api private | ||
| 471 | + */ | ||
| 472 | +var functionCache = BSON.functionCache = {}; | ||
| 473 | + | ||
| 474 | +/** | ||
| 475 | + * Number BSON Type | ||
| 476 | + * | ||
| 477 | + * @classconstant BSON_DATA_NUMBER | ||
| 478 | + **/ | ||
| 479 | +BSON.BSON_DATA_NUMBER = 1; | ||
| 480 | +/** | ||
| 481 | + * String BSON Type | ||
| 482 | + * | ||
| 483 | + * @classconstant BSON_DATA_STRING | ||
| 484 | + **/ | ||
| 485 | +BSON.BSON_DATA_STRING = 2; | ||
| 486 | +/** | ||
| 487 | + * Object BSON Type | ||
| 488 | + * | ||
| 489 | + * @classconstant BSON_DATA_OBJECT | ||
| 490 | + **/ | ||
| 491 | +BSON.BSON_DATA_OBJECT = 3; | ||
| 492 | +/** | ||
| 493 | + * Array BSON Type | ||
| 494 | + * | ||
| 495 | + * @classconstant BSON_DATA_ARRAY | ||
| 496 | + **/ | ||
| 497 | +BSON.BSON_DATA_ARRAY = 4; | ||
| 498 | +/** | ||
| 499 | + * Binary BSON Type | ||
| 500 | + * | ||
| 501 | + * @classconstant BSON_DATA_BINARY | ||
| 502 | + **/ | ||
| 503 | +BSON.BSON_DATA_BINARY = 5; | ||
| 504 | +/** | ||
| 505 | + * Binary BSON Type | ||
| 506 | + * | ||
| 507 | + * @classconstant BSON_DATA_UNDEFINED | ||
| 508 | + **/ | ||
| 509 | +BSON.BSON_DATA_UNDEFINED = 6; | ||
| 510 | +/** | ||
| 511 | + * ObjectID BSON Type | ||
| 512 | + * | ||
| 513 | + * @classconstant BSON_DATA_OID | ||
| 514 | + **/ | ||
| 515 | +BSON.BSON_DATA_OID = 7; | ||
| 516 | +/** | ||
| 517 | + * Boolean BSON Type | ||
| 518 | + * | ||
| 519 | + * @classconstant BSON_DATA_BOOLEAN | ||
| 520 | + **/ | ||
| 521 | +BSON.BSON_DATA_BOOLEAN = 8; | ||
| 522 | +/** | ||
| 523 | + * Date BSON Type | ||
| 524 | + * | ||
| 525 | + * @classconstant BSON_DATA_DATE | ||
| 526 | + **/ | ||
| 527 | +BSON.BSON_DATA_DATE = 9; | ||
| 528 | +/** | ||
| 529 | + * null BSON Type | ||
| 530 | + * | ||
| 531 | + * @classconstant BSON_DATA_NULL | ||
| 532 | + **/ | ||
| 533 | +BSON.BSON_DATA_NULL = 10; | ||
| 534 | +/** | ||
| 535 | + * RegExp BSON Type | ||
| 536 | + * | ||
| 537 | + * @classconstant BSON_DATA_REGEXP | ||
| 538 | + **/ | ||
| 539 | +BSON.BSON_DATA_REGEXP = 11; | ||
| 540 | +/** | ||
| 541 | + * Code BSON Type | ||
| 542 | + * | ||
| 543 | + * @classconstant BSON_DATA_DBPOINTER | ||
| 544 | + **/ | ||
| 545 | +BSON.BSON_DATA_DBPOINTER = 12; | ||
| 546 | +/** | ||
| 547 | + * Code BSON Type | ||
| 548 | + * | ||
| 549 | + * @classconstant BSON_DATA_CODE | ||
| 550 | + **/ | ||
| 551 | +BSON.BSON_DATA_CODE = 13; | ||
| 552 | +/** | ||
| 553 | + * Symbol BSON Type | ||
| 554 | + * | ||
| 555 | + * @classconstant BSON_DATA_SYMBOL | ||
| 556 | + **/ | ||
| 557 | +BSON.BSON_DATA_SYMBOL = 14; | ||
| 558 | +/** | ||
| 559 | + * Code with Scope BSON Type | ||
| 560 | + * | ||
| 561 | + * @classconstant BSON_DATA_CODE_W_SCOPE | ||
| 562 | + **/ | ||
| 563 | +BSON.BSON_DATA_CODE_W_SCOPE = 15; | ||
| 564 | +/** | ||
| 565 | + * 32 bit Integer BSON Type | ||
| 566 | + * | ||
| 567 | + * @classconstant BSON_DATA_INT | ||
| 568 | + **/ | ||
| 569 | +BSON.BSON_DATA_INT = 16; | ||
| 570 | +/** | ||
| 571 | + * Timestamp BSON Type | ||
| 572 | + * | ||
| 573 | + * @classconstant BSON_DATA_TIMESTAMP | ||
| 574 | + **/ | ||
| 575 | +BSON.BSON_DATA_TIMESTAMP = 17; | ||
| 576 | +/** | ||
| 577 | + * Long BSON Type | ||
| 578 | + * | ||
| 579 | + * @classconstant BSON_DATA_LONG | ||
| 580 | + **/ | ||
| 581 | +BSON.BSON_DATA_LONG = 18; | ||
| 582 | +/** | ||
| 583 | + * Long BSON Type | ||
| 584 | + * | ||
| 585 | + * @classconstant BSON_DATA_DECIMAL128 | ||
| 586 | + **/ | ||
| 587 | +BSON.BSON_DATA_DECIMAL128 = 19; | ||
| 588 | +/** | ||
| 589 | + * MinKey BSON Type | ||
| 590 | + * | ||
| 591 | + * @classconstant BSON_DATA_MIN_KEY | ||
| 592 | + **/ | ||
| 593 | +BSON.BSON_DATA_MIN_KEY = 0xff; | ||
| 594 | +/** | ||
| 595 | + * MaxKey BSON Type | ||
| 596 | + * | ||
| 597 | + * @classconstant BSON_DATA_MAX_KEY | ||
| 598 | + **/ | ||
| 599 | +BSON.BSON_DATA_MAX_KEY = 0x7f; | ||
| 600 | + | ||
| 601 | +/** | ||
| 602 | + * Binary Default Type | ||
| 603 | + * | ||
| 604 | + * @classconstant BSON_BINARY_SUBTYPE_DEFAULT | ||
| 605 | + **/ | ||
| 606 | +BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0; | ||
| 607 | +/** | ||
| 608 | + * Binary Function Type | ||
| 609 | + * | ||
| 610 | + * @classconstant BSON_BINARY_SUBTYPE_FUNCTION | ||
| 611 | + **/ | ||
| 612 | +BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1; | ||
| 613 | +/** | ||
| 614 | + * Binary Byte Array Type | ||
| 615 | + * | ||
| 616 | + * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY | ||
| 617 | + **/ | ||
| 618 | +BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; | ||
| 619 | +/** | ||
| 620 | + * Binary UUID Type | ||
| 621 | + * | ||
| 622 | + * @classconstant BSON_BINARY_SUBTYPE_UUID | ||
| 623 | + **/ | ||
| 624 | +BSON.BSON_BINARY_SUBTYPE_UUID = 3; | ||
| 625 | +/** | ||
| 626 | + * Binary MD5 Type | ||
| 627 | + * | ||
| 628 | + * @classconstant BSON_BINARY_SUBTYPE_MD5 | ||
| 629 | + **/ | ||
| 630 | +BSON.BSON_BINARY_SUBTYPE_MD5 = 4; | ||
| 631 | +/** | ||
| 632 | + * Binary User Defined Type | ||
| 633 | + * | ||
| 634 | + * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED | ||
| 635 | + **/ | ||
| 636 | +BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; | ||
| 637 | + | ||
| 638 | +// BSON MAX VALUES | ||
| 639 | +BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
| 640 | +BSON.BSON_INT32_MIN = -0x80000000; | ||
| 641 | + | ||
| 642 | +BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1; | ||
| 643 | +BSON.BSON_INT64_MIN = -Math.pow(2, 63); | ||
| 644 | + | ||
| 645 | +// JS MAX PRECISE VALUES | ||
| 646 | +BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
| 647 | +BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
| 648 | + | ||
| 649 | +// Internal long versions | ||
| 650 | +var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
| 651 | +var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
| 652 | + | ||
| 653 | +module.exports = deserialize |
| 1 | +"use strict" | ||
| 2 | + | ||
| 3 | +var writeIEEE754 = require('../float_parser').writeIEEE754, | ||
| 4 | + readIEEE754 = require('../float_parser').readIEEE754, | ||
| 5 | + Long = require('../long').Long, | ||
| 6 | + Map = require('../map'), | ||
| 7 | + Double = require('../double').Double, | ||
| 8 | + Timestamp = require('../timestamp').Timestamp, | ||
| 9 | + ObjectID = require('../objectid').ObjectID, | ||
| 10 | + Symbol = require('../symbol').Symbol, | ||
| 11 | + Code = require('../code').Code, | ||
| 12 | + BSONRegExp = require('../regexp').BSONRegExp, | ||
| 13 | + Int32 = require('../int_32').Int32, | ||
| 14 | + MinKey = require('../min_key').MinKey, | ||
| 15 | + MaxKey = require('../max_key').MaxKey, | ||
| 16 | + Decimal128 = require('../decimal128'), | ||
| 17 | + DBRef = require('../db_ref').DBRef, | ||
| 18 | + Binary = require('../binary').Binary; | ||
| 19 | + | ||
| 20 | +try { | ||
| 21 | + var _Buffer = Uint8Array; | ||
| 22 | +} catch(e) { | ||
| 23 | + var _Buffer = Buffer; | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +var regexp = /\x00/ | ||
| 27 | + | ||
| 28 | +// To ensure that 0.4 of node works correctly | ||
| 29 | +var isDate = function isDate(d) { | ||
| 30 | + return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]'; | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +var isRegExp = function isRegExp(d) { | ||
| 34 | + return Object.prototype.toString.call(d) === '[object RegExp]'; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +var serializeString = function(buffer, key, value, index, isArray) { | ||
| 38 | + // Encode String type | ||
| 39 | + buffer[index++] = BSON.BSON_DATA_STRING; | ||
| 40 | + // Number of written bytes | ||
| 41 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 42 | + // Encode the name | ||
| 43 | + index = index + numberOfWrittenBytes + 1; | ||
| 44 | + buffer[index - 1] = 0; | ||
| 45 | + // Write the string | ||
| 46 | + var size = buffer.write(value, index + 4, 'utf8'); | ||
| 47 | + // Write the size of the string to buffer | ||
| 48 | + buffer[index + 3] = (size + 1 >> 24) & 0xff; | ||
| 49 | + buffer[index + 2] = (size + 1 >> 16) & 0xff; | ||
| 50 | + buffer[index + 1] = (size + 1 >> 8) & 0xff; | ||
| 51 | + buffer[index] = size + 1 & 0xff; | ||
| 52 | + // Update index | ||
| 53 | + index = index + 4 + size; | ||
| 54 | + // Write zero | ||
| 55 | + buffer[index++] = 0; | ||
| 56 | + return index; | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +var serializeNumber = function(buffer, key, value, index, isArray) { | ||
| 60 | + // We have an integer value | ||
| 61 | + if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
| 62 | + // If the value fits in 32 bits encode as int, if it fits in a double | ||
| 63 | + // encode it as a double, otherwise long | ||
| 64 | + if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { | ||
| 65 | + // Set int type 32 bits or less | ||
| 66 | + buffer[index++] = BSON.BSON_DATA_INT; | ||
| 67 | + // Number of written bytes | ||
| 68 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 69 | + // Encode the name | ||
| 70 | + index = index + numberOfWrittenBytes; | ||
| 71 | + buffer[index++] = 0; | ||
| 72 | + // Write the int value | ||
| 73 | + buffer[index++] = value & 0xff; | ||
| 74 | + buffer[index++] = (value >> 8) & 0xff; | ||
| 75 | + buffer[index++] = (value >> 16) & 0xff; | ||
| 76 | + buffer[index++] = (value >> 24) & 0xff; | ||
| 77 | + } else if(value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
| 78 | + // Encode as double | ||
| 79 | + buffer[index++] = BSON.BSON_DATA_NUMBER; | ||
| 80 | + // Number of written bytes | ||
| 81 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 82 | + // Encode the name | ||
| 83 | + index = index + numberOfWrittenBytes; | ||
| 84 | + buffer[index++] = 0; | ||
| 85 | + // Write float | ||
| 86 | + writeIEEE754(buffer, value, index, 'little', 52, 8); | ||
| 87 | + // Ajust index | ||
| 88 | + index = index + 8; | ||
| 89 | + } else { | ||
| 90 | + // Set long type | ||
| 91 | + buffer[index++] = BSON.BSON_DATA_LONG; | ||
| 92 | + // Number of written bytes | ||
| 93 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 94 | + // Encode the name | ||
| 95 | + index = index + numberOfWrittenBytes; | ||
| 96 | + buffer[index++] = 0; | ||
| 97 | + var longVal = Long.fromNumber(value); | ||
| 98 | + var lowBits = longVal.getLowBits(); | ||
| 99 | + var highBits = longVal.getHighBits(); | ||
| 100 | + // Encode low bits | ||
| 101 | + buffer[index++] = lowBits & 0xff; | ||
| 102 | + buffer[index++] = (lowBits >> 8) & 0xff; | ||
| 103 | + buffer[index++] = (lowBits >> 16) & 0xff; | ||
| 104 | + buffer[index++] = (lowBits >> 24) & 0xff; | ||
| 105 | + // Encode high bits | ||
| 106 | + buffer[index++] = highBits & 0xff; | ||
| 107 | + buffer[index++] = (highBits >> 8) & 0xff; | ||
| 108 | + buffer[index++] = (highBits >> 16) & 0xff; | ||
| 109 | + buffer[index++] = (highBits >> 24) & 0xff; | ||
| 110 | + } | ||
| 111 | + } else { | ||
| 112 | + // Encode as double | ||
| 113 | + buffer[index++] = BSON.BSON_DATA_NUMBER; | ||
| 114 | + // Number of written bytes | ||
| 115 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 116 | + // Encode the name | ||
| 117 | + index = index + numberOfWrittenBytes; | ||
| 118 | + buffer[index++] = 0; | ||
| 119 | + // Write float | ||
| 120 | + writeIEEE754(buffer, value, index, 'little', 52, 8); | ||
| 121 | + // Ajust index | ||
| 122 | + index = index + 8; | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + return index; | ||
| 126 | +} | ||
| 127 | + | ||
| 128 | +var serializeNull = function(buffer, key, value, index, isArray) { | ||
| 129 | + // Set long type | ||
| 130 | + buffer[index++] = BSON.BSON_DATA_NULL; | ||
| 131 | + // Number of written bytes | ||
| 132 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 133 | + // Encode the name | ||
| 134 | + index = index + numberOfWrittenBytes; | ||
| 135 | + buffer[index++] = 0; | ||
| 136 | + return index; | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | +var serializeBoolean = function(buffer, key, value, index, isArray) { | ||
| 140 | + // Write the type | ||
| 141 | + buffer[index++] = BSON.BSON_DATA_BOOLEAN; | ||
| 142 | + // Number of written bytes | ||
| 143 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 144 | + // Encode the name | ||
| 145 | + index = index + numberOfWrittenBytes; | ||
| 146 | + buffer[index++] = 0; | ||
| 147 | + // Encode the boolean value | ||
| 148 | + buffer[index++] = value ? 1 : 0; | ||
| 149 | + return index; | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +var serializeDate = function(buffer, key, value, index, isArray) { | ||
| 153 | + // Write the type | ||
| 154 | + buffer[index++] = BSON.BSON_DATA_DATE; | ||
| 155 | + // Number of written bytes | ||
| 156 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 157 | + // Encode the name | ||
| 158 | + index = index + numberOfWrittenBytes; | ||
| 159 | + buffer[index++] = 0; | ||
| 160 | + | ||
| 161 | + // Write the date | ||
| 162 | + var dateInMilis = Long.fromNumber(value.getTime()); | ||
| 163 | + var lowBits = dateInMilis.getLowBits(); | ||
| 164 | + var highBits = dateInMilis.getHighBits(); | ||
| 165 | + // Encode low bits | ||
| 166 | + buffer[index++] = lowBits & 0xff; | ||
| 167 | + buffer[index++] = (lowBits >> 8) & 0xff; | ||
| 168 | + buffer[index++] = (lowBits >> 16) & 0xff; | ||
| 169 | + buffer[index++] = (lowBits >> 24) & 0xff; | ||
| 170 | + // Encode high bits | ||
| 171 | + buffer[index++] = highBits & 0xff; | ||
| 172 | + buffer[index++] = (highBits >> 8) & 0xff; | ||
| 173 | + buffer[index++] = (highBits >> 16) & 0xff; | ||
| 174 | + buffer[index++] = (highBits >> 24) & 0xff; | ||
| 175 | + return index; | ||
| 176 | +} | ||
| 177 | + | ||
| 178 | +var serializeRegExp = function(buffer, key, value, index, isArray) { | ||
| 179 | + // Write the type | ||
| 180 | + buffer[index++] = BSON.BSON_DATA_REGEXP; | ||
| 181 | + // Number of written bytes | ||
| 182 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 183 | + // Encode the name | ||
| 184 | + index = index + numberOfWrittenBytes; | ||
| 185 | + buffer[index++] = 0; | ||
| 186 | + if (value.source && value.source.match(regexp) != null) { | ||
| 187 | + throw Error("value " + value.source + " must not contain null bytes"); | ||
| 188 | + } | ||
| 189 | + // Adjust the index | ||
| 190 | + index = index + buffer.write(value.source, index, 'utf8'); | ||
| 191 | + // Write zero | ||
| 192 | + buffer[index++] = 0x00; | ||
| 193 | + // Write the parameters | ||
| 194 | + if(value.global) buffer[index++] = 0x73; // s | ||
| 195 | + if(value.ignoreCase) buffer[index++] = 0x69; // i | ||
| 196 | + if(value.multiline) buffer[index++] = 0x6d; // m | ||
| 197 | + // Add ending zero | ||
| 198 | + buffer[index++] = 0x00; | ||
| 199 | + return index; | ||
| 200 | +} | ||
| 201 | + | ||
| 202 | +var serializeBSONRegExp = function(buffer, key, value, index, isArray) { | ||
| 203 | + // Write the type | ||
| 204 | + buffer[index++] = BSON.BSON_DATA_REGEXP; | ||
| 205 | + // Number of written bytes | ||
| 206 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 207 | + // Encode the name | ||
| 208 | + index = index + numberOfWrittenBytes; | ||
| 209 | + buffer[index++] = 0; | ||
| 210 | + | ||
| 211 | + // Check the pattern for 0 bytes | ||
| 212 | + if (value.pattern.match(regexp) != null) { | ||
| 213 | + // The BSON spec doesn't allow keys with null bytes because keys are | ||
| 214 | + // null-terminated. | ||
| 215 | + throw Error("pattern " + value.pattern + " must not contain null bytes"); | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + // Adjust the index | ||
| 219 | + index = index + buffer.write(value.pattern, index, 'utf8'); | ||
| 220 | + // Write zero | ||
| 221 | + buffer[index++] = 0x00; | ||
| 222 | + // Write the options | ||
| 223 | + index = index + buffer.write(value.options.split('').sort().join(''), index, 'utf8'); | ||
| 224 | + // Add ending zero | ||
| 225 | + buffer[index++] = 0x00; | ||
| 226 | + return index; | ||
| 227 | +} | ||
| 228 | + | ||
| 229 | +var serializeMinMax = function(buffer, key, value, index, isArray) { | ||
| 230 | + // Write the type of either min or max key | ||
| 231 | + if(value === null) { | ||
| 232 | + buffer[index++] = BSON.BSON_DATA_NULL; | ||
| 233 | + } else if(value instanceof MinKey) { | ||
| 234 | + buffer[index++] = BSON.BSON_DATA_MIN_KEY; | ||
| 235 | + } else { | ||
| 236 | + buffer[index++] = BSON.BSON_DATA_MAX_KEY; | ||
| 237 | + } | ||
| 238 | + | ||
| 239 | + // Number of written bytes | ||
| 240 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 241 | + // Encode the name | ||
| 242 | + index = index + numberOfWrittenBytes; | ||
| 243 | + buffer[index++] = 0; | ||
| 244 | + return index; | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +var serializeObjectId = function(buffer, key, value, index, isArray) { | ||
| 248 | + // Write the type | ||
| 249 | + buffer[index++] = BSON.BSON_DATA_OID; | ||
| 250 | + // Number of written bytes | ||
| 251 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 252 | + | ||
| 253 | + // Encode the name | ||
| 254 | + index = index + numberOfWrittenBytes; | ||
| 255 | + buffer[index++] = 0; | ||
| 256 | + | ||
| 257 | + // Write the objectId into the shared buffer | ||
| 258 | + if(typeof value.id == 'string') { | ||
| 259 | + buffer.write(value.id, index, 'binary') | ||
| 260 | + } else if(value.id && value.id.copy){ | ||
| 261 | + value.id.copy(buffer, index, 0, 12); | ||
| 262 | + } else { | ||
| 263 | + throw new Error('object [' + JSON.stringify(value) + "] is not a valid ObjectId"); | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + // Ajust index | ||
| 267 | + return index + 12; | ||
| 268 | +} | ||
| 269 | + | ||
| 270 | +var serializeBuffer = function(buffer, key, value, index, isArray) { | ||
| 271 | + // Write the type | ||
| 272 | + buffer[index++] = BSON.BSON_DATA_BINARY; | ||
| 273 | + // Number of written bytes | ||
| 274 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 275 | + // Encode the name | ||
| 276 | + index = index + numberOfWrittenBytes; | ||
| 277 | + buffer[index++] = 0; | ||
| 278 | + // Get size of the buffer (current write point) | ||
| 279 | + var size = value.length; | ||
| 280 | + // Write the size of the string to buffer | ||
| 281 | + buffer[index++] = size & 0xff; | ||
| 282 | + buffer[index++] = (size >> 8) & 0xff; | ||
| 283 | + buffer[index++] = (size >> 16) & 0xff; | ||
| 284 | + buffer[index++] = (size >> 24) & 0xff; | ||
| 285 | + // Write the default subtype | ||
| 286 | + buffer[index++] = BSON.BSON_BINARY_SUBTYPE_DEFAULT; | ||
| 287 | + // Copy the content form the binary field to the buffer | ||
| 288 | + value.copy(buffer, index, 0, size); | ||
| 289 | + // Adjust the index | ||
| 290 | + index = index + size; | ||
| 291 | + return index; | ||
| 292 | +} | ||
| 293 | + | ||
| 294 | +var serializeObject = function(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, isArray, path) { | ||
| 295 | + for(var i = 0; i < path.length; i++) { | ||
| 296 | + if(path[i] === value) throw new Error('cyclic dependency detected'); | ||
| 297 | + } | ||
| 298 | + | ||
| 299 | + // Push value to stack | ||
| 300 | + path.push(value); | ||
| 301 | + // Write the type | ||
| 302 | + buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT; | ||
| 303 | + // Number of written bytes | ||
| 304 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 305 | + // Encode the name | ||
| 306 | + index = index + numberOfWrittenBytes; | ||
| 307 | + buffer[index++] = 0; | ||
| 308 | + var endIndex = serializeInto(buffer, value, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path); | ||
| 309 | + // Pop stack | ||
| 310 | + path.pop(); | ||
| 311 | + // Write size | ||
| 312 | + var size = endIndex - index; | ||
| 313 | + return endIndex; | ||
| 314 | +} | ||
| 315 | + | ||
| 316 | +var serializeDecimal128 = function(buffer, key, value, index, isArray) { | ||
| 317 | + buffer[index++] = BSON.BSON_DATA_DECIMAL128; | ||
| 318 | + // Number of written bytes | ||
| 319 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 320 | + // Encode the name | ||
| 321 | + index = index + numberOfWrittenBytes; | ||
| 322 | + buffer[index++] = 0; | ||
| 323 | + // Write the data from the value | ||
| 324 | + value.bytes.copy(buffer, index, 0, 16); | ||
| 325 | + return index + 16; | ||
| 326 | +} | ||
| 327 | + | ||
| 328 | +var serializeLong = function(buffer, key, value, index, isArray) { | ||
| 329 | + // Write the type | ||
| 330 | + buffer[index++] = value._bsontype == 'Long' ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_TIMESTAMP; | ||
| 331 | + // Number of written bytes | ||
| 332 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 333 | + // Encode the name | ||
| 334 | + index = index + numberOfWrittenBytes; | ||
| 335 | + buffer[index++] = 0; | ||
| 336 | + // Write the date | ||
| 337 | + var lowBits = value.getLowBits(); | ||
| 338 | + var highBits = value.getHighBits(); | ||
| 339 | + // Encode low bits | ||
| 340 | + buffer[index++] = lowBits & 0xff; | ||
| 341 | + buffer[index++] = (lowBits >> 8) & 0xff; | ||
| 342 | + buffer[index++] = (lowBits >> 16) & 0xff; | ||
| 343 | + buffer[index++] = (lowBits >> 24) & 0xff; | ||
| 344 | + // Encode high bits | ||
| 345 | + buffer[index++] = highBits & 0xff; | ||
| 346 | + buffer[index++] = (highBits >> 8) & 0xff; | ||
| 347 | + buffer[index++] = (highBits >> 16) & 0xff; | ||
| 348 | + buffer[index++] = (highBits >> 24) & 0xff; | ||
| 349 | + return index; | ||
| 350 | +} | ||
| 351 | + | ||
| 352 | +var serializeInt32 = function(buffer, key, value, index, isArray) { | ||
| 353 | + // Set int type 32 bits or less | ||
| 354 | + buffer[index++] = BSON.BSON_DATA_INT; | ||
| 355 | + // Number of written bytes | ||
| 356 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 357 | + // Encode the name | ||
| 358 | + index = index + numberOfWrittenBytes; | ||
| 359 | + buffer[index++] = 0; | ||
| 360 | + // Write the int value | ||
| 361 | + buffer[index++] = value & 0xff; | ||
| 362 | + buffer[index++] = (value >> 8) & 0xff; | ||
| 363 | + buffer[index++] = (value >> 16) & 0xff; | ||
| 364 | + buffer[index++] = (value >> 24) & 0xff; | ||
| 365 | + return index; | ||
| 366 | +} | ||
| 367 | + | ||
| 368 | +var serializeDouble = function(buffer, key, value, index, isArray) { | ||
| 369 | + // Encode as double | ||
| 370 | + buffer[index++] = BSON.BSON_DATA_NUMBER; | ||
| 371 | + // Number of written bytes | ||
| 372 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 373 | + // Encode the name | ||
| 374 | + index = index + numberOfWrittenBytes; | ||
| 375 | + buffer[index++] = 0; | ||
| 376 | + // Write float | ||
| 377 | + writeIEEE754(buffer, value, index, 'little', 52, 8); | ||
| 378 | + // Ajust index | ||
| 379 | + index = index + 8; | ||
| 380 | + return index; | ||
| 381 | +} | ||
| 382 | + | ||
| 383 | +var serializeFunction = function(buffer, key, value, index, checkKeys, depth, isArray) { | ||
| 384 | + buffer[index++] = BSON.BSON_DATA_CODE; | ||
| 385 | + // Number of written bytes | ||
| 386 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 387 | + // Encode the name | ||
| 388 | + index = index + numberOfWrittenBytes; | ||
| 389 | + buffer[index++] = 0; | ||
| 390 | + // Function string | ||
| 391 | + var functionString = value.toString(); | ||
| 392 | + // Write the string | ||
| 393 | + var size = buffer.write(functionString, index + 4, 'utf8') + 1; | ||
| 394 | + // Write the size of the string to buffer | ||
| 395 | + buffer[index] = size & 0xff; | ||
| 396 | + buffer[index + 1] = (size >> 8) & 0xff; | ||
| 397 | + buffer[index + 2] = (size >> 16) & 0xff; | ||
| 398 | + buffer[index + 3] = (size >> 24) & 0xff; | ||
| 399 | + // Update index | ||
| 400 | + index = index + 4 + size - 1; | ||
| 401 | + // Write zero | ||
| 402 | + buffer[index++] = 0; | ||
| 403 | + return index; | ||
| 404 | +} | ||
| 405 | + | ||
| 406 | +var serializeCode = function(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, isArray) { | ||
| 407 | + if(value.scope && typeof value.scope == 'object') { | ||
| 408 | + // Write the type | ||
| 409 | + buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE; | ||
| 410 | + // Number of written bytes | ||
| 411 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 412 | + // Encode the name | ||
| 413 | + index = index + numberOfWrittenBytes; | ||
| 414 | + buffer[index++] = 0; | ||
| 415 | + | ||
| 416 | + // Starting index | ||
| 417 | + var startIndex = index; | ||
| 418 | + | ||
| 419 | + // Serialize the function | ||
| 420 | + // Get the function string | ||
| 421 | + var functionString = typeof value.code == 'string' ? value.code : value.code.toString(); | ||
| 422 | + // Index adjustment | ||
| 423 | + index = index + 4; | ||
| 424 | + // Write string into buffer | ||
| 425 | + var codeSize = buffer.write(functionString, index + 4, 'utf8') + 1; | ||
| 426 | + // Write the size of the string to buffer | ||
| 427 | + buffer[index] = codeSize & 0xff; | ||
| 428 | + buffer[index + 1] = (codeSize >> 8) & 0xff; | ||
| 429 | + buffer[index + 2] = (codeSize >> 16) & 0xff; | ||
| 430 | + buffer[index + 3] = (codeSize >> 24) & 0xff; | ||
| 431 | + // Write end 0 | ||
| 432 | + buffer[index + 4 + codeSize - 1] = 0; | ||
| 433 | + // Write the | ||
| 434 | + index = index + codeSize + 4; | ||
| 435 | + | ||
| 436 | + // | ||
| 437 | + // Serialize the scope value | ||
| 438 | + var endIndex = serializeInto(buffer, value.scope, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined) | ||
| 439 | + index = endIndex - 1; | ||
| 440 | + | ||
| 441 | + // Writ the total | ||
| 442 | + var totalSize = endIndex - startIndex; | ||
| 443 | + | ||
| 444 | + // Write the total size of the object | ||
| 445 | + buffer[startIndex++] = totalSize & 0xff; | ||
| 446 | + buffer[startIndex++] = (totalSize >> 8) & 0xff; | ||
| 447 | + buffer[startIndex++] = (totalSize >> 16) & 0xff; | ||
| 448 | + buffer[startIndex++] = (totalSize >> 24) & 0xff; | ||
| 449 | + // Write trailing zero | ||
| 450 | + buffer[index++] = 0; | ||
| 451 | + } else { | ||
| 452 | + buffer[index++] = BSON.BSON_DATA_CODE; | ||
| 453 | + // Number of written bytes | ||
| 454 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 455 | + // Encode the name | ||
| 456 | + index = index + numberOfWrittenBytes; | ||
| 457 | + buffer[index++] = 0; | ||
| 458 | + // Function string | ||
| 459 | + var functionString = value.code.toString(); | ||
| 460 | + // Write the string | ||
| 461 | + var size = buffer.write(functionString, index + 4, 'utf8') + 1; | ||
| 462 | + // Write the size of the string to buffer | ||
| 463 | + buffer[index] = size & 0xff; | ||
| 464 | + buffer[index + 1] = (size >> 8) & 0xff; | ||
| 465 | + buffer[index + 2] = (size >> 16) & 0xff; | ||
| 466 | + buffer[index + 3] = (size >> 24) & 0xff; | ||
| 467 | + // Update index | ||
| 468 | + index = index + 4 + size - 1; | ||
| 469 | + // Write zero | ||
| 470 | + buffer[index++] = 0; | ||
| 471 | + } | ||
| 472 | + | ||
| 473 | + return index; | ||
| 474 | +} | ||
| 475 | + | ||
| 476 | +var serializeBinary = function(buffer, key, value, index, isArray) { | ||
| 477 | + // Write the type | ||
| 478 | + buffer[index++] = BSON.BSON_DATA_BINARY; | ||
| 479 | + // Number of written bytes | ||
| 480 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 481 | + // Encode the name | ||
| 482 | + index = index + numberOfWrittenBytes; | ||
| 483 | + buffer[index++] = 0; | ||
| 484 | + // Extract the buffer | ||
| 485 | + var data = value.value(true); | ||
| 486 | + // Calculate size | ||
| 487 | + var size = value.position; | ||
| 488 | + // Add the deprecated 02 type 4 bytes of size to total | ||
| 489 | + if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) size = size + 4; | ||
| 490 | + // Write the size of the string to buffer | ||
| 491 | + buffer[index++] = size & 0xff; | ||
| 492 | + buffer[index++] = (size >> 8) & 0xff; | ||
| 493 | + buffer[index++] = (size >> 16) & 0xff; | ||
| 494 | + buffer[index++] = (size >> 24) & 0xff; | ||
| 495 | + // Write the subtype to the buffer | ||
| 496 | + buffer[index++] = value.sub_type; | ||
| 497 | + | ||
| 498 | + // If we have binary type 2 the 4 first bytes are the size | ||
| 499 | + if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) { | ||
| 500 | + size = size - 4; | ||
| 501 | + buffer[index++] = size & 0xff; | ||
| 502 | + buffer[index++] = (size >> 8) & 0xff; | ||
| 503 | + buffer[index++] = (size >> 16) & 0xff; | ||
| 504 | + buffer[index++] = (size >> 24) & 0xff; | ||
| 505 | + } | ||
| 506 | + | ||
| 507 | + // Write the data to the object | ||
| 508 | + data.copy(buffer, index, 0, value.position); | ||
| 509 | + // Adjust the index | ||
| 510 | + index = index + value.position; | ||
| 511 | + return index; | ||
| 512 | +} | ||
| 513 | + | ||
| 514 | +var serializeSymbol = function(buffer, key, value, index, isArray) { | ||
| 515 | + // Write the type | ||
| 516 | + buffer[index++] = BSON.BSON_DATA_SYMBOL; | ||
| 517 | + // Number of written bytes | ||
| 518 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 519 | + // Encode the name | ||
| 520 | + index = index + numberOfWrittenBytes; | ||
| 521 | + buffer[index++] = 0; | ||
| 522 | + // Write the string | ||
| 523 | + var size = buffer.write(value.value, index + 4, 'utf8') + 1; | ||
| 524 | + // Write the size of the string to buffer | ||
| 525 | + buffer[index] = size & 0xff; | ||
| 526 | + buffer[index + 1] = (size >> 8) & 0xff; | ||
| 527 | + buffer[index + 2] = (size >> 16) & 0xff; | ||
| 528 | + buffer[index + 3] = (size >> 24) & 0xff; | ||
| 529 | + // Update index | ||
| 530 | + index = index + 4 + size - 1; | ||
| 531 | + // Write zero | ||
| 532 | + buffer[index++] = 0x00; | ||
| 533 | + return index; | ||
| 534 | +} | ||
| 535 | + | ||
| 536 | +var serializeDBRef = function(buffer, key, value, index, depth, serializeFunctions, isArray) { | ||
| 537 | + // Write the type | ||
| 538 | + buffer[index++] = BSON.BSON_DATA_OBJECT; | ||
| 539 | + // Number of written bytes | ||
| 540 | + var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
| 541 | + | ||
| 542 | + // Encode the name | ||
| 543 | + index = index + numberOfWrittenBytes; | ||
| 544 | + buffer[index++] = 0; | ||
| 545 | + | ||
| 546 | + var startIndex = index; | ||
| 547 | + var endIndex; | ||
| 548 | + | ||
| 549 | + // Serialize object | ||
| 550 | + if(null != value.db) { | ||
| 551 | + endIndex = serializeInto(buffer, { | ||
| 552 | + '$ref': value.namespace | ||
| 553 | + , '$id' : value.oid | ||
| 554 | + , '$db' : value.db | ||
| 555 | + }, false, index, depth + 1, serializeFunctions); | ||
| 556 | + } else { | ||
| 557 | + endIndex = serializeInto(buffer, { | ||
| 558 | + '$ref': value.namespace | ||
| 559 | + , '$id' : value.oid | ||
| 560 | + }, false, index, depth + 1, serializeFunctions); | ||
| 561 | + } | ||
| 562 | + | ||
| 563 | + // Calculate object size | ||
| 564 | + var size = endIndex - startIndex; | ||
| 565 | + // Write the size | ||
| 566 | + buffer[startIndex++] = size & 0xff; | ||
| 567 | + buffer[startIndex++] = (size >> 8) & 0xff; | ||
| 568 | + buffer[startIndex++] = (size >> 16) & 0xff; | ||
| 569 | + buffer[startIndex++] = (size >> 24) & 0xff; | ||
| 570 | + // Set index | ||
| 571 | + return endIndex; | ||
| 572 | +} | ||
| 573 | + | ||
| 574 | +var serializeInto = function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializeFunctions, ignoreUndefined, path) { | ||
| 575 | + startingIndex = startingIndex || 0; | ||
| 576 | + path = path || []; | ||
| 577 | + | ||
| 578 | + // Push the object to the path | ||
| 579 | + path.push(object); | ||
| 580 | + | ||
| 581 | + // Start place to serialize into | ||
| 582 | + var index = startingIndex + 4; | ||
| 583 | + var self = this; | ||
| 584 | + | ||
| 585 | + // Special case isArray | ||
| 586 | + if(Array.isArray(object)) { | ||
| 587 | + // Get object keys | ||
| 588 | + for(var i = 0; i < object.length; i++) { | ||
| 589 | + var key = "" + i; | ||
| 590 | + var value = object[i]; | ||
| 591 | + | ||
| 592 | + // Is there an override value | ||
| 593 | + if(value && value.toBSON) { | ||
| 594 | + if(typeof value.toBSON != 'function') throw new Error("toBSON is not a function"); | ||
| 595 | + value = value.toBSON(); | ||
| 596 | + } | ||
| 597 | + | ||
| 598 | + var type = typeof value; | ||
| 599 | + if(type == 'string') { | ||
| 600 | + index = serializeString(buffer, key, value, index, true); | ||
| 601 | + } else if(type == 'number') { | ||
| 602 | + index = serializeNumber(buffer, key, value, index, true); | ||
| 603 | + } else if(type == 'boolean') { | ||
| 604 | + index = serializeBoolean(buffer, key, value, index, true); | ||
| 605 | + } else if(value instanceof Date || isDate(value)) { | ||
| 606 | + index = serializeDate(buffer, key, value, index, true); | ||
| 607 | + } else if(value === undefined) { | ||
| 608 | + index = serializeNull(buffer, key, value, index, true); | ||
| 609 | + } else if(value === null) { | ||
| 610 | + index = serializeNull(buffer, key, value, index, true); | ||
| 611 | + } else if(value['_bsontype'] == 'ObjectID') { | ||
| 612 | + index = serializeObjectId(buffer, key, value, index, true); | ||
| 613 | + } else if(Buffer.isBuffer(value)) { | ||
| 614 | + index = serializeBuffer(buffer, key, value, index, true); | ||
| 615 | + } else if(value instanceof RegExp || isRegExp(value)) { | ||
| 616 | + index = serializeRegExp(buffer, key, value, index, true); | ||
| 617 | + } else if(type == 'object' && value['_bsontype'] == null) { | ||
| 618 | + index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, true, path); | ||
| 619 | + } else if(type == 'object' && value['_bsontype'] == 'Decimal128') { | ||
| 620 | + index = serializeDecimal128(buffer, key, value, index, true); | ||
| 621 | + } else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') { | ||
| 622 | + index = serializeLong(buffer, key, value, index, true); | ||
| 623 | + } else if(value['_bsontype'] == 'Double') { | ||
| 624 | + index = serializeDouble(buffer, key, value, index, true); | ||
| 625 | + } else if(typeof value == 'function' && serializeFunctions) { | ||
| 626 | + index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions, true); | ||
| 627 | + } else if(value['_bsontype'] == 'Code') { | ||
| 628 | + index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, true); | ||
| 629 | + } else if(value['_bsontype'] == 'Binary') { | ||
| 630 | + index = serializeBinary(buffer, key, value, index, true); | ||
| 631 | + } else if(value['_bsontype'] == 'Symbol') { | ||
| 632 | + index = serializeSymbol(buffer, key, value, index, true); | ||
| 633 | + } else if(value['_bsontype'] == 'DBRef') { | ||
| 634 | + index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, true); | ||
| 635 | + } else if(value['_bsontype'] == 'BSONRegExp') { | ||
| 636 | + index = serializeBSONRegExp(buffer, key, value, index, true); | ||
| 637 | + } else if(value['_bsontype'] == 'Int32') { | ||
| 638 | + index = serializeInt32(buffer, key, value, index, true); | ||
| 639 | + } else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { | ||
| 640 | + index = serializeMinMax(buffer, key, value, index, true); | ||
| 641 | + } | ||
| 642 | + } | ||
| 643 | + } else if(object instanceof Map) { | ||
| 644 | + var iterator = object.entries(); | ||
| 645 | + var done = false; | ||
| 646 | + | ||
| 647 | + while(!done) { | ||
| 648 | + // Unpack the next entry | ||
| 649 | + var entry = iterator.next(); | ||
| 650 | + done = entry.done; | ||
| 651 | + // Are we done, then skip and terminate | ||
| 652 | + if(done) continue; | ||
| 653 | + | ||
| 654 | + // Get the entry values | ||
| 655 | + var key = entry.value[0]; | ||
| 656 | + var value = entry.value[1]; | ||
| 657 | + | ||
| 658 | + // Check the type of the value | ||
| 659 | + var type = typeof value; | ||
| 660 | + | ||
| 661 | + // Check the key and throw error if it's illegal | ||
| 662 | + if(key != '$db' && key != '$ref' && key != '$id') { | ||
| 663 | + if (key.match(regexp) != null) { | ||
| 664 | + // The BSON spec doesn't allow keys with null bytes because keys are | ||
| 665 | + // null-terminated. | ||
| 666 | + throw Error("key " + key + " must not contain null bytes"); | ||
| 667 | + } | ||
| 668 | + | ||
| 669 | + if (checkKeys) { | ||
| 670 | + if('$' == key[0]) { | ||
| 671 | + throw Error("key " + key + " must not start with '$'"); | ||
| 672 | + } else if (!!~key.indexOf('.')) { | ||
| 673 | + throw Error("key " + key + " must not contain '.'"); | ||
| 674 | + } | ||
| 675 | + } | ||
| 676 | + } | ||
| 677 | + | ||
| 678 | + if(type == 'string') { | ||
| 679 | + index = serializeString(buffer, key, value, index); | ||
| 680 | + } else if(type == 'number') { | ||
| 681 | + index = serializeNumber(buffer, key, value, index); | ||
| 682 | + } else if(type == 'boolean') { | ||
| 683 | + index = serializeBoolean(buffer, key, value, index); | ||
| 684 | + } else if(value instanceof Date || isDate(value)) { | ||
| 685 | + index = serializeDate(buffer, key, value, index); | ||
| 686 | + } else if(value === undefined && ignoreUndefined == true) { | ||
| 687 | + } else if(value === null || value === undefined) { | ||
| 688 | + index = serializeNull(buffer, key, value, index); | ||
| 689 | + } else if(value['_bsontype'] == 'ObjectID') { | ||
| 690 | + index = serializeObjectId(buffer, key, value, index); | ||
| 691 | + } else if(Buffer.isBuffer(value)) { | ||
| 692 | + index = serializeBuffer(buffer, key, value, index); | ||
| 693 | + } else if(value instanceof RegExp || isRegExp(value)) { | ||
| 694 | + index = serializeRegExp(buffer, key, value, index); | ||
| 695 | + } else if(type == 'object' && value['_bsontype'] == null) { | ||
| 696 | + index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, false, path); | ||
| 697 | + } else if(type == 'object' && value['_bsontype'] == 'Decimal128') { | ||
| 698 | + index = serializeDecimal128(buffer, key, value, index); | ||
| 699 | + } else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') { | ||
| 700 | + index = serializeLong(buffer, key, value, index); | ||
| 701 | + } else if(value['_bsontype'] == 'Double') { | ||
| 702 | + index = serializeDouble(buffer, key, value, index); | ||
| 703 | + } else if(value['_bsontype'] == 'Code') { | ||
| 704 | + index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined); | ||
| 705 | + } else if(typeof value == 'function' && serializeFunctions) { | ||
| 706 | + index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions); | ||
| 707 | + } else if(value['_bsontype'] == 'Binary') { | ||
| 708 | + index = serializeBinary(buffer, key, value, index); | ||
| 709 | + } else if(value['_bsontype'] == 'Symbol') { | ||
| 710 | + index = serializeSymbol(buffer, key, value, index); | ||
| 711 | + } else if(value['_bsontype'] == 'DBRef') { | ||
| 712 | + index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions); | ||
| 713 | + } else if(value['_bsontype'] == 'BSONRegExp') { | ||
| 714 | + index = serializeBSONRegExp(buffer, key, value, index); | ||
| 715 | + } else if(value['_bsontype'] == 'Int32') { | ||
| 716 | + index = serializeInt32(buffer, key, value, index); | ||
| 717 | + } else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { | ||
| 718 | + index = serializeMinMax(buffer, key, value, index); | ||
| 719 | + } | ||
| 720 | + } | ||
| 721 | + } else { | ||
| 722 | + // Did we provide a custom serialization method | ||
| 723 | + if(object.toBSON) { | ||
| 724 | + if(typeof object.toBSON != 'function') throw new Error("toBSON is not a function"); | ||
| 725 | + object = object.toBSON(); | ||
| 726 | + if(object != null && typeof object != 'object') throw new Error("toBSON function did not return an object"); | ||
| 727 | + } | ||
| 728 | + | ||
| 729 | + // Iterate over all the keys | ||
| 730 | + for(var key in object) { | ||
| 731 | + var value = object[key]; | ||
| 732 | + // Is there an override value | ||
| 733 | + if(value && value.toBSON) { | ||
| 734 | + if(typeof value.toBSON != 'function') throw new Error("toBSON is not a function"); | ||
| 735 | + value = value.toBSON(); | ||
| 736 | + } | ||
| 737 | + | ||
| 738 | + // Check the type of the value | ||
| 739 | + var type = typeof value; | ||
| 740 | + | ||
| 741 | + // Check the key and throw error if it's illegal | ||
| 742 | + if(key != '$db' && key != '$ref' && key != '$id') { | ||
| 743 | + if (key.match(regexp) != null) { | ||
| 744 | + // The BSON spec doesn't allow keys with null bytes because keys are | ||
| 745 | + // null-terminated. | ||
| 746 | + throw Error("key " + key + " must not contain null bytes"); | ||
| 747 | + } | ||
| 748 | + | ||
| 749 | + if (checkKeys) { | ||
| 750 | + if('$' == key[0]) { | ||
| 751 | + throw Error("key " + key + " must not start with '$'"); | ||
| 752 | + } else if (!!~key.indexOf('.')) { | ||
| 753 | + throw Error("key " + key + " must not contain '.'"); | ||
| 754 | + } | ||
| 755 | + } | ||
| 756 | + } | ||
| 757 | + | ||
| 758 | + if(type == 'string') { | ||
| 759 | + index = serializeString(buffer, key, value, index); | ||
| 760 | + } else if(type == 'number') { | ||
| 761 | + index = serializeNumber(buffer, key, value, index); | ||
| 762 | + } else if(type == 'boolean') { | ||
| 763 | + index = serializeBoolean(buffer, key, value, index); | ||
| 764 | + } else if(value instanceof Date || isDate(value)) { | ||
| 765 | + index = serializeDate(buffer, key, value, index); | ||
| 766 | + } else if(value === undefined && ignoreUndefined == true) { | ||
| 767 | + } else if(value === null || value === undefined) { | ||
| 768 | + index = serializeNull(buffer, key, value, index); | ||
| 769 | + } else if(value['_bsontype'] == 'ObjectID') { | ||
| 770 | + index = serializeObjectId(buffer, key, value, index); | ||
| 771 | + } else if(Buffer.isBuffer(value)) { | ||
| 772 | + index = serializeBuffer(buffer, key, value, index); | ||
| 773 | + } else if(value instanceof RegExp || isRegExp(value)) { | ||
| 774 | + index = serializeRegExp(buffer, key, value, index); | ||
| 775 | + } else if(type == 'object' && value['_bsontype'] == null) { | ||
| 776 | + index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, false, path); | ||
| 777 | + } else if(type == 'object' && value['_bsontype'] == 'Decimal128') { | ||
| 778 | + index = serializeDecimal128(buffer, key, value, index); | ||
| 779 | + } else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') { | ||
| 780 | + index = serializeLong(buffer, key, value, index); | ||
| 781 | + } else if(value['_bsontype'] == 'Double') { | ||
| 782 | + index = serializeDouble(buffer, key, value, index); | ||
| 783 | + } else if(value['_bsontype'] == 'Code') { | ||
| 784 | + index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined); | ||
| 785 | + } else if(typeof value == 'function' && serializeFunctions) { | ||
| 786 | + index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions); | ||
| 787 | + } else if(value['_bsontype'] == 'Binary') { | ||
| 788 | + index = serializeBinary(buffer, key, value, index); | ||
| 789 | + } else if(value['_bsontype'] == 'Symbol') { | ||
| 790 | + index = serializeSymbol(buffer, key, value, index); | ||
| 791 | + } else if(value['_bsontype'] == 'DBRef') { | ||
| 792 | + index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions); | ||
| 793 | + } else if(value['_bsontype'] == 'BSONRegExp') { | ||
| 794 | + index = serializeBSONRegExp(buffer, key, value, index); | ||
| 795 | + } else if(value['_bsontype'] == 'Int32') { | ||
| 796 | + index = serializeInt32(buffer, key, value, index); | ||
| 797 | + } else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { | ||
| 798 | + index = serializeMinMax(buffer, key, value, index); | ||
| 799 | + } | ||
| 800 | + } | ||
| 801 | + } | ||
| 802 | + | ||
| 803 | + // Remove the path | ||
| 804 | + path.pop(); | ||
| 805 | + | ||
| 806 | + // Final padding byte for object | ||
| 807 | + buffer[index++] = 0x00; | ||
| 808 | + | ||
| 809 | + // Final size | ||
| 810 | + var size = index - startingIndex; | ||
| 811 | + // Write the size of the object | ||
| 812 | + buffer[startingIndex++] = size & 0xff; | ||
| 813 | + buffer[startingIndex++] = (size >> 8) & 0xff; | ||
| 814 | + buffer[startingIndex++] = (size >> 16) & 0xff; | ||
| 815 | + buffer[startingIndex++] = (size >> 24) & 0xff; | ||
| 816 | + return index; | ||
| 817 | +} | ||
| 818 | + | ||
| 819 | +var BSON = {}; | ||
| 820 | + | ||
| 821 | +/** | ||
| 822 | + * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5 | ||
| 823 | + * | ||
| 824 | + * @ignore | ||
| 825 | + * @api private | ||
| 826 | + */ | ||
| 827 | +var functionCache = BSON.functionCache = {}; | ||
| 828 | + | ||
| 829 | +/** | ||
| 830 | + * Number BSON Type | ||
| 831 | + * | ||
| 832 | + * @classconstant BSON_DATA_NUMBER | ||
| 833 | + **/ | ||
| 834 | +BSON.BSON_DATA_NUMBER = 1; | ||
| 835 | +/** | ||
| 836 | + * String BSON Type | ||
| 837 | + * | ||
| 838 | + * @classconstant BSON_DATA_STRING | ||
| 839 | + **/ | ||
| 840 | +BSON.BSON_DATA_STRING = 2; | ||
| 841 | +/** | ||
| 842 | + * Object BSON Type | ||
| 843 | + * | ||
| 844 | + * @classconstant BSON_DATA_OBJECT | ||
| 845 | + **/ | ||
| 846 | +BSON.BSON_DATA_OBJECT = 3; | ||
| 847 | +/** | ||
| 848 | + * Array BSON Type | ||
| 849 | + * | ||
| 850 | + * @classconstant BSON_DATA_ARRAY | ||
| 851 | + **/ | ||
| 852 | +BSON.BSON_DATA_ARRAY = 4; | ||
| 853 | +/** | ||
| 854 | + * Binary BSON Type | ||
| 855 | + * | ||
| 856 | + * @classconstant BSON_DATA_BINARY | ||
| 857 | + **/ | ||
| 858 | +BSON.BSON_DATA_BINARY = 5; | ||
| 859 | +/** | ||
| 860 | + * ObjectID BSON Type, deprecated | ||
| 861 | + * | ||
| 862 | + * @classconstant BSON_DATA_UNDEFINED | ||
| 863 | + **/ | ||
| 864 | +BSON.BSON_DATA_UNDEFINED = 6; | ||
| 865 | +/** | ||
| 866 | + * ObjectID BSON Type | ||
| 867 | + * | ||
| 868 | + * @classconstant BSON_DATA_OID | ||
| 869 | + **/ | ||
| 870 | +BSON.BSON_DATA_OID = 7; | ||
| 871 | +/** | ||
| 872 | + * Boolean BSON Type | ||
| 873 | + * | ||
| 874 | + * @classconstant BSON_DATA_BOOLEAN | ||
| 875 | + **/ | ||
| 876 | +BSON.BSON_DATA_BOOLEAN = 8; | ||
| 877 | +/** | ||
| 878 | + * Date BSON Type | ||
| 879 | + * | ||
| 880 | + * @classconstant BSON_DATA_DATE | ||
| 881 | + **/ | ||
| 882 | +BSON.BSON_DATA_DATE = 9; | ||
| 883 | +/** | ||
| 884 | + * null BSON Type | ||
| 885 | + * | ||
| 886 | + * @classconstant BSON_DATA_NULL | ||
| 887 | + **/ | ||
| 888 | +BSON.BSON_DATA_NULL = 10; | ||
| 889 | +/** | ||
| 890 | + * RegExp BSON Type | ||
| 891 | + * | ||
| 892 | + * @classconstant BSON_DATA_REGEXP | ||
| 893 | + **/ | ||
| 894 | +BSON.BSON_DATA_REGEXP = 11; | ||
| 895 | +/** | ||
| 896 | + * Code BSON Type | ||
| 897 | + * | ||
| 898 | + * @classconstant BSON_DATA_CODE | ||
| 899 | + **/ | ||
| 900 | +BSON.BSON_DATA_CODE = 13; | ||
| 901 | +/** | ||
| 902 | + * Symbol BSON Type | ||
| 903 | + * | ||
| 904 | + * @classconstant BSON_DATA_SYMBOL | ||
| 905 | + **/ | ||
| 906 | +BSON.BSON_DATA_SYMBOL = 14; | ||
| 907 | +/** | ||
| 908 | + * Code with Scope BSON Type | ||
| 909 | + * | ||
| 910 | + * @classconstant BSON_DATA_CODE_W_SCOPE | ||
| 911 | + **/ | ||
| 912 | +BSON.BSON_DATA_CODE_W_SCOPE = 15; | ||
| 913 | +/** | ||
| 914 | + * 32 bit Integer BSON Type | ||
| 915 | + * | ||
| 916 | + * @classconstant BSON_DATA_INT | ||
| 917 | + **/ | ||
| 918 | +BSON.BSON_DATA_INT = 16; | ||
| 919 | +/** | ||
| 920 | + * Timestamp BSON Type | ||
| 921 | + * | ||
| 922 | + * @classconstant BSON_DATA_TIMESTAMP | ||
| 923 | + **/ | ||
| 924 | +BSON.BSON_DATA_TIMESTAMP = 17; | ||
| 925 | +/** | ||
| 926 | + * Long BSON Type | ||
| 927 | + * | ||
| 928 | + * @classconstant BSON_DATA_LONG | ||
| 929 | + **/ | ||
| 930 | +BSON.BSON_DATA_LONG = 18; | ||
| 931 | +/** | ||
| 932 | + * Long BSON Type | ||
| 933 | + * | ||
| 934 | + * @classconstant BSON_DATA_DECIMAL128 | ||
| 935 | + **/ | ||
| 936 | +BSON.BSON_DATA_DECIMAL128 = 19; | ||
| 937 | +/** | ||
| 938 | + * MinKey BSON Type | ||
| 939 | + * | ||
| 940 | + * @classconstant BSON_DATA_MIN_KEY | ||
| 941 | + **/ | ||
| 942 | +BSON.BSON_DATA_MIN_KEY = 0xff; | ||
| 943 | +/** | ||
| 944 | + * MaxKey BSON Type | ||
| 945 | + * | ||
| 946 | + * @classconstant BSON_DATA_MAX_KEY | ||
| 947 | + **/ | ||
| 948 | +BSON.BSON_DATA_MAX_KEY = 0x7f; | ||
| 949 | +/** | ||
| 950 | + * Binary Default Type | ||
| 951 | + * | ||
| 952 | + * @classconstant BSON_BINARY_SUBTYPE_DEFAULT | ||
| 953 | + **/ | ||
| 954 | +BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0; | ||
| 955 | +/** | ||
| 956 | + * Binary Function Type | ||
| 957 | + * | ||
| 958 | + * @classconstant BSON_BINARY_SUBTYPE_FUNCTION | ||
| 959 | + **/ | ||
| 960 | +BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1; | ||
| 961 | +/** | ||
| 962 | + * Binary Byte Array Type | ||
| 963 | + * | ||
| 964 | + * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY | ||
| 965 | + **/ | ||
| 966 | +BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; | ||
| 967 | +/** | ||
| 968 | + * Binary UUID Type | ||
| 969 | + * | ||
| 970 | + * @classconstant BSON_BINARY_SUBTYPE_UUID | ||
| 971 | + **/ | ||
| 972 | +BSON.BSON_BINARY_SUBTYPE_UUID = 3; | ||
| 973 | +/** | ||
| 974 | + * Binary MD5 Type | ||
| 975 | + * | ||
| 976 | + * @classconstant BSON_BINARY_SUBTYPE_MD5 | ||
| 977 | + **/ | ||
| 978 | +BSON.BSON_BINARY_SUBTYPE_MD5 = 4; | ||
| 979 | +/** | ||
| 980 | + * Binary User Defined Type | ||
| 981 | + * | ||
| 982 | + * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED | ||
| 983 | + **/ | ||
| 984 | +BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; | ||
| 985 | + | ||
| 986 | +// BSON MAX VALUES | ||
| 987 | +BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
| 988 | +BSON.BSON_INT32_MIN = -0x80000000; | ||
| 989 | + | ||
| 990 | +BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1; | ||
| 991 | +BSON.BSON_INT64_MIN = -Math.pow(2, 63); | ||
| 992 | + | ||
| 993 | +// JS MAX PRECISE VALUES | ||
| 994 | +BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
| 995 | +BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
| 996 | + | ||
| 997 | +// Internal long versions | ||
| 998 | +var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
| 999 | +var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
| 1000 | + | ||
| 1001 | +module.exports = serializeInto; |
| 1 | +/** | ||
| 2 | + * A class representation of the BSON RegExp type. | ||
| 3 | + * | ||
| 4 | + * @class | ||
| 5 | + * @return {BSONRegExp} A MinKey instance | ||
| 6 | + */ | ||
| 7 | +function BSONRegExp(pattern, options) { | ||
| 8 | + if(!(this instanceof BSONRegExp)) return new BSONRegExp(); | ||
| 9 | + | ||
| 10 | + // Execute | ||
| 11 | + this._bsontype = 'BSONRegExp'; | ||
| 12 | + this.pattern = pattern || ''; | ||
| 13 | + this.options = options || ''; | ||
| 14 | + | ||
| 15 | + // Validate options | ||
| 16 | + for(var i = 0; i < this.options.length; i++) { | ||
| 17 | + if(!(this.options[i] == 'i' | ||
| 18 | + || this.options[i] == 'm' | ||
| 19 | + || this.options[i] == 'x' | ||
| 20 | + || this.options[i] == 'l' | ||
| 21 | + || this.options[i] == 's' | ||
| 22 | + || this.options[i] == 'u' | ||
| 23 | + )) { | ||
| 24 | + throw new Error('the regular expression options [' + this.options[i] + "] is not supported"); | ||
| 25 | + } | ||
| 26 | + } | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +module.exports = BSONRegExp; | ||
| 30 | +module.exports.BSONRegExp = BSONRegExp; |
| 1 | +/** | ||
| 2 | + * A class representation of the BSON Symbol type. | ||
| 3 | + * | ||
| 4 | + * @class | ||
| 5 | + * @deprecated | ||
| 6 | + * @param {string} value the string representing the symbol. | ||
| 7 | + * @return {Symbol} | ||
| 8 | + */ | ||
| 9 | +function Symbol(value) { | ||
| 10 | + if(!(this instanceof Symbol)) return new Symbol(value); | ||
| 11 | + this._bsontype = 'Symbol'; | ||
| 12 | + this.value = value; | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * Access the wrapped string value. | ||
| 17 | + * | ||
| 18 | + * @method | ||
| 19 | + * @return {String} returns the wrapped string. | ||
| 20 | + */ | ||
| 21 | +Symbol.prototype.valueOf = function() { | ||
| 22 | + return this.value; | ||
| 23 | +}; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * @ignore | ||
| 27 | + */ | ||
| 28 | +Symbol.prototype.toString = function() { | ||
| 29 | + return this.value; | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +/** | ||
| 33 | + * @ignore | ||
| 34 | + */ | ||
| 35 | +Symbol.prototype.inspect = function() { | ||
| 36 | + return this.value; | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +/** | ||
| 40 | + * @ignore | ||
| 41 | + */ | ||
| 42 | +Symbol.prototype.toJSON = function() { | ||
| 43 | + return this.value; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +module.exports = Symbol; | ||
| 47 | +module.exports.Symbol = Symbol; |
| 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 | + * This type is for INTERNAL use in MongoDB only and should not be used in applications. | ||
| 17 | + * The appropriate corresponding type is the JavaScript Date type. | ||
| 18 | + * | ||
| 19 | + * Defines a Timestamp class for representing a 64-bit two's-complement | ||
| 20 | + * integer value, which faithfully simulates the behavior of a Java "Timestamp". This | ||
| 21 | + * implementation is derived from TimestampLib in GWT. | ||
| 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 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 | + * @class | ||
| 42 | + * @param {number} low the low (signed) 32 bits of the Timestamp. | ||
| 43 | + * @param {number} high the high (signed) 32 bits of the Timestamp. | ||
| 44 | + */ | ||
| 45 | +function Timestamp(low, high) { | ||
| 46 | + if(!(this instanceof Timestamp)) return new Timestamp(low, high); | ||
| 47 | + this._bsontype = 'Timestamp'; | ||
| 48 | + /** | ||
| 49 | + * @type {number} | ||
| 50 | + * @ignore | ||
| 51 | + */ | ||
| 52 | + this.low_ = low | 0; // force into 32 signed bits. | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * @type {number} | ||
| 56 | + * @ignore | ||
| 57 | + */ | ||
| 58 | + this.high_ = high | 0; // force into 32 signed bits. | ||
| 59 | +}; | ||
| 60 | + | ||
| 61 | +/** | ||
| 62 | + * Return the int value. | ||
| 63 | + * | ||
| 64 | + * @return {number} the value, assuming it is a 32-bit integer. | ||
| 65 | + */ | ||
| 66 | +Timestamp.prototype.toInt = function() { | ||
| 67 | + return this.low_; | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +/** | ||
| 71 | + * Return the Number value. | ||
| 72 | + * | ||
| 73 | + * @method | ||
| 74 | + * @return {number} the closest floating-point representation to this value. | ||
| 75 | + */ | ||
| 76 | +Timestamp.prototype.toNumber = function() { | ||
| 77 | + return this.high_ * Timestamp.TWO_PWR_32_DBL_ + | ||
| 78 | + this.getLowBitsUnsigned(); | ||
| 79 | +}; | ||
| 80 | + | ||
| 81 | +/** | ||
| 82 | + * Return the JSON value. | ||
| 83 | + * | ||
| 84 | + * @method | ||
| 85 | + * @return {string} the JSON representation. | ||
| 86 | + */ | ||
| 87 | +Timestamp.prototype.toJSON = function() { | ||
| 88 | + return this.toString(); | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +/** | ||
| 92 | + * Return the String value. | ||
| 93 | + * | ||
| 94 | + * @method | ||
| 95 | + * @param {number} [opt_radix] the radix in which the text should be written. | ||
| 96 | + * @return {string} the textual representation of this value. | ||
| 97 | + */ | ||
| 98 | +Timestamp.prototype.toString = function(opt_radix) { | ||
| 99 | + var radix = opt_radix || 10; | ||
| 100 | + if (radix < 2 || 36 < radix) { | ||
| 101 | + throw Error('radix out of range: ' + radix); | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + if (this.isZero()) { | ||
| 105 | + return '0'; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + if (this.isNegative()) { | ||
| 109 | + if (this.equals(Timestamp.MIN_VALUE)) { | ||
| 110 | + // We need to change the Timestamp value before it can be negated, so we remove | ||
| 111 | + // the bottom-most digit in this base and then recurse to do the rest. | ||
| 112 | + var radixTimestamp = Timestamp.fromNumber(radix); | ||
| 113 | + var div = this.div(radixTimestamp); | ||
| 114 | + var rem = div.multiply(radixTimestamp).subtract(this); | ||
| 115 | + return div.toString(radix) + rem.toInt().toString(radix); | ||
| 116 | + } else { | ||
| 117 | + return '-' + this.negate().toString(radix); | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + // Do several (6) digits each time through the loop, so as to | ||
| 122 | + // minimize the calls to the very expensive emulated div. | ||
| 123 | + var radixToPower = Timestamp.fromNumber(Math.pow(radix, 6)); | ||
| 124 | + | ||
| 125 | + var rem = this; | ||
| 126 | + var result = ''; | ||
| 127 | + while (true) { | ||
| 128 | + var remDiv = rem.div(radixToPower); | ||
| 129 | + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); | ||
| 130 | + var digits = intval.toString(radix); | ||
| 131 | + | ||
| 132 | + rem = remDiv; | ||
| 133 | + if (rem.isZero()) { | ||
| 134 | + return digits + result; | ||
| 135 | + } else { | ||
| 136 | + while (digits.length < 6) { | ||
| 137 | + digits = '0' + digits; | ||
| 138 | + } | ||
| 139 | + result = '' + digits + result; | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | +}; | ||
| 143 | + | ||
| 144 | +/** | ||
| 145 | + * Return the high 32-bits value. | ||
| 146 | + * | ||
| 147 | + * @method | ||
| 148 | + * @return {number} the high 32-bits as a signed value. | ||
| 149 | + */ | ||
| 150 | +Timestamp.prototype.getHighBits = function() { | ||
| 151 | + return this.high_; | ||
| 152 | +}; | ||
| 153 | + | ||
| 154 | +/** | ||
| 155 | + * Return the low 32-bits value. | ||
| 156 | + * | ||
| 157 | + * @method | ||
| 158 | + * @return {number} the low 32-bits as a signed value. | ||
| 159 | + */ | ||
| 160 | +Timestamp.prototype.getLowBits = function() { | ||
| 161 | + return this.low_; | ||
| 162 | +}; | ||
| 163 | + | ||
| 164 | +/** | ||
| 165 | + * Return the low unsigned 32-bits value. | ||
| 166 | + * | ||
| 167 | + * @method | ||
| 168 | + * @return {number} the low 32-bits as an unsigned value. | ||
| 169 | + */ | ||
| 170 | +Timestamp.prototype.getLowBitsUnsigned = function() { | ||
| 171 | + return (this.low_ >= 0) ? | ||
| 172 | + this.low_ : Timestamp.TWO_PWR_32_DBL_ + this.low_; | ||
| 173 | +}; | ||
| 174 | + | ||
| 175 | +/** | ||
| 176 | + * Returns the number of bits needed to represent the absolute value of this Timestamp. | ||
| 177 | + * | ||
| 178 | + * @method | ||
| 179 | + * @return {number} Returns the number of bits needed to represent the absolute value of this Timestamp. | ||
| 180 | + */ | ||
| 181 | +Timestamp.prototype.getNumBitsAbs = function() { | ||
| 182 | + if (this.isNegative()) { | ||
| 183 | + if (this.equals(Timestamp.MIN_VALUE)) { | ||
| 184 | + return 64; | ||
| 185 | + } else { | ||
| 186 | + return this.negate().getNumBitsAbs(); | ||
| 187 | + } | ||
| 188 | + } else { | ||
| 189 | + var val = this.high_ != 0 ? this.high_ : this.low_; | ||
| 190 | + for (var bit = 31; bit > 0; bit--) { | ||
| 191 | + if ((val & (1 << bit)) != 0) { | ||
| 192 | + break; | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + return this.high_ != 0 ? bit + 33 : bit + 1; | ||
| 196 | + } | ||
| 197 | +}; | ||
| 198 | + | ||
| 199 | +/** | ||
| 200 | + * Return whether this value is zero. | ||
| 201 | + * | ||
| 202 | + * @method | ||
| 203 | + * @return {boolean} whether this value is zero. | ||
| 204 | + */ | ||
| 205 | +Timestamp.prototype.isZero = function() { | ||
| 206 | + return this.high_ == 0 && this.low_ == 0; | ||
| 207 | +}; | ||
| 208 | + | ||
| 209 | +/** | ||
| 210 | + * Return whether this value is negative. | ||
| 211 | + * | ||
| 212 | + * @method | ||
| 213 | + * @return {boolean} whether this value is negative. | ||
| 214 | + */ | ||
| 215 | +Timestamp.prototype.isNegative = function() { | ||
| 216 | + return this.high_ < 0; | ||
| 217 | +}; | ||
| 218 | + | ||
| 219 | +/** | ||
| 220 | + * Return whether this value is odd. | ||
| 221 | + * | ||
| 222 | + * @method | ||
| 223 | + * @return {boolean} whether this value is odd. | ||
| 224 | + */ | ||
| 225 | +Timestamp.prototype.isOdd = function() { | ||
| 226 | + return (this.low_ & 1) == 1; | ||
| 227 | +}; | ||
| 228 | + | ||
| 229 | +/** | ||
| 230 | + * Return whether this Timestamp equals the other | ||
| 231 | + * | ||
| 232 | + * @method | ||
| 233 | + * @param {Timestamp} other Timestamp to compare against. | ||
| 234 | + * @return {boolean} whether this Timestamp equals the other | ||
| 235 | + */ | ||
| 236 | +Timestamp.prototype.equals = function(other) { | ||
| 237 | + return (this.high_ == other.high_) && (this.low_ == other.low_); | ||
| 238 | +}; | ||
| 239 | + | ||
| 240 | +/** | ||
| 241 | + * Return whether this Timestamp does not equal the other. | ||
| 242 | + * | ||
| 243 | + * @method | ||
| 244 | + * @param {Timestamp} other Timestamp to compare against. | ||
| 245 | + * @return {boolean} whether this Timestamp does not equal the other. | ||
| 246 | + */ | ||
| 247 | +Timestamp.prototype.notEquals = function(other) { | ||
| 248 | + return (this.high_ != other.high_) || (this.low_ != other.low_); | ||
| 249 | +}; | ||
| 250 | + | ||
| 251 | +/** | ||
| 252 | + * Return whether this Timestamp is less than the other. | ||
| 253 | + * | ||
| 254 | + * @method | ||
| 255 | + * @param {Timestamp} other Timestamp to compare against. | ||
| 256 | + * @return {boolean} whether this Timestamp is less than the other. | ||
| 257 | + */ | ||
| 258 | +Timestamp.prototype.lessThan = function(other) { | ||
| 259 | + return this.compare(other) < 0; | ||
| 260 | +}; | ||
| 261 | + | ||
| 262 | +/** | ||
| 263 | + * Return whether this Timestamp is less than or equal to the other. | ||
| 264 | + * | ||
| 265 | + * @method | ||
| 266 | + * @param {Timestamp} other Timestamp to compare against. | ||
| 267 | + * @return {boolean} whether this Timestamp is less than or equal to the other. | ||
| 268 | + */ | ||
| 269 | +Timestamp.prototype.lessThanOrEqual = function(other) { | ||
| 270 | + return this.compare(other) <= 0; | ||
| 271 | +}; | ||
| 272 | + | ||
| 273 | +/** | ||
| 274 | + * Return whether this Timestamp is greater than the other. | ||
| 275 | + * | ||
| 276 | + * @method | ||
| 277 | + * @param {Timestamp} other Timestamp to compare against. | ||
| 278 | + * @return {boolean} whether this Timestamp is greater than the other. | ||
| 279 | + */ | ||
| 280 | +Timestamp.prototype.greaterThan = function(other) { | ||
| 281 | + return this.compare(other) > 0; | ||
| 282 | +}; | ||
| 283 | + | ||
| 284 | +/** | ||
| 285 | + * Return whether this Timestamp is greater than or equal to the other. | ||
| 286 | + * | ||
| 287 | + * @method | ||
| 288 | + * @param {Timestamp} other Timestamp to compare against. | ||
| 289 | + * @return {boolean} whether this Timestamp is greater than or equal to the other. | ||
| 290 | + */ | ||
| 291 | +Timestamp.prototype.greaterThanOrEqual = function(other) { | ||
| 292 | + return this.compare(other) >= 0; | ||
| 293 | +}; | ||
| 294 | + | ||
| 295 | +/** | ||
| 296 | + * Compares this Timestamp with the given one. | ||
| 297 | + * | ||
| 298 | + * @method | ||
| 299 | + * @param {Timestamp} other Timestamp to compare against. | ||
| 300 | + * @return {boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. | ||
| 301 | + */ | ||
| 302 | +Timestamp.prototype.compare = function(other) { | ||
| 303 | + if (this.equals(other)) { | ||
| 304 | + return 0; | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + var thisNeg = this.isNegative(); | ||
| 308 | + var otherNeg = other.isNegative(); | ||
| 309 | + if (thisNeg && !otherNeg) { | ||
| 310 | + return -1; | ||
| 311 | + } | ||
| 312 | + if (!thisNeg && otherNeg) { | ||
| 313 | + return 1; | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + // at this point, the signs are the same, so subtraction will not overflow | ||
| 317 | + if (this.subtract(other).isNegative()) { | ||
| 318 | + return -1; | ||
| 319 | + } else { | ||
| 320 | + return 1; | ||
| 321 | + } | ||
| 322 | +}; | ||
| 323 | + | ||
| 324 | +/** | ||
| 325 | + * The negation of this value. | ||
| 326 | + * | ||
| 327 | + * @method | ||
| 328 | + * @return {Timestamp} the negation of this value. | ||
| 329 | + */ | ||
| 330 | +Timestamp.prototype.negate = function() { | ||
| 331 | + if (this.equals(Timestamp.MIN_VALUE)) { | ||
| 332 | + return Timestamp.MIN_VALUE; | ||
| 333 | + } else { | ||
| 334 | + return this.not().add(Timestamp.ONE); | ||
| 335 | + } | ||
| 336 | +}; | ||
| 337 | + | ||
| 338 | +/** | ||
| 339 | + * Returns the sum of this and the given Timestamp. | ||
| 340 | + * | ||
| 341 | + * @method | ||
| 342 | + * @param {Timestamp} other Timestamp to add to this one. | ||
| 343 | + * @return {Timestamp} the sum of this and the given Timestamp. | ||
| 344 | + */ | ||
| 345 | +Timestamp.prototype.add = function(other) { | ||
| 346 | + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. | ||
| 347 | + | ||
| 348 | + var a48 = this.high_ >>> 16; | ||
| 349 | + var a32 = this.high_ & 0xFFFF; | ||
| 350 | + var a16 = this.low_ >>> 16; | ||
| 351 | + var a00 = this.low_ & 0xFFFF; | ||
| 352 | + | ||
| 353 | + var b48 = other.high_ >>> 16; | ||
| 354 | + var b32 = other.high_ & 0xFFFF; | ||
| 355 | + var b16 = other.low_ >>> 16; | ||
| 356 | + var b00 = other.low_ & 0xFFFF; | ||
| 357 | + | ||
| 358 | + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
| 359 | + c00 += a00 + b00; | ||
| 360 | + c16 += c00 >>> 16; | ||
| 361 | + c00 &= 0xFFFF; | ||
| 362 | + c16 += a16 + b16; | ||
| 363 | + c32 += c16 >>> 16; | ||
| 364 | + c16 &= 0xFFFF; | ||
| 365 | + c32 += a32 + b32; | ||
| 366 | + c48 += c32 >>> 16; | ||
| 367 | + c32 &= 0xFFFF; | ||
| 368 | + c48 += a48 + b48; | ||
| 369 | + c48 &= 0xFFFF; | ||
| 370 | + return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
| 371 | +}; | ||
| 372 | + | ||
| 373 | +/** | ||
| 374 | + * Returns the difference of this and the given Timestamp. | ||
| 375 | + * | ||
| 376 | + * @method | ||
| 377 | + * @param {Timestamp} other Timestamp to subtract from this. | ||
| 378 | + * @return {Timestamp} the difference of this and the given Timestamp. | ||
| 379 | + */ | ||
| 380 | +Timestamp.prototype.subtract = function(other) { | ||
| 381 | + return this.add(other.negate()); | ||
| 382 | +}; | ||
| 383 | + | ||
| 384 | +/** | ||
| 385 | + * Returns the product of this and the given Timestamp. | ||
| 386 | + * | ||
| 387 | + * @method | ||
| 388 | + * @param {Timestamp} other Timestamp to multiply with this. | ||
| 389 | + * @return {Timestamp} the product of this and the other. | ||
| 390 | + */ | ||
| 391 | +Timestamp.prototype.multiply = function(other) { | ||
| 392 | + if (this.isZero()) { | ||
| 393 | + return Timestamp.ZERO; | ||
| 394 | + } else if (other.isZero()) { | ||
| 395 | + return Timestamp.ZERO; | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + if (this.equals(Timestamp.MIN_VALUE)) { | ||
| 399 | + return other.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; | ||
| 400 | + } else if (other.equals(Timestamp.MIN_VALUE)) { | ||
| 401 | + return this.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; | ||
| 402 | + } | ||
| 403 | + | ||
| 404 | + if (this.isNegative()) { | ||
| 405 | + if (other.isNegative()) { | ||
| 406 | + return this.negate().multiply(other.negate()); | ||
| 407 | + } else { | ||
| 408 | + return this.negate().multiply(other).negate(); | ||
| 409 | + } | ||
| 410 | + } else if (other.isNegative()) { | ||
| 411 | + return this.multiply(other.negate()).negate(); | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + // If both Timestamps are small, use float multiplication | ||
| 415 | + if (this.lessThan(Timestamp.TWO_PWR_24_) && | ||
| 416 | + other.lessThan(Timestamp.TWO_PWR_24_)) { | ||
| 417 | + return Timestamp.fromNumber(this.toNumber() * other.toNumber()); | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + // Divide each Timestamp into 4 chunks of 16 bits, and then add up 4x4 products. | ||
| 421 | + // We can skip products that would overflow. | ||
| 422 | + | ||
| 423 | + var a48 = this.high_ >>> 16; | ||
| 424 | + var a32 = this.high_ & 0xFFFF; | ||
| 425 | + var a16 = this.low_ >>> 16; | ||
| 426 | + var a00 = this.low_ & 0xFFFF; | ||
| 427 | + | ||
| 428 | + var b48 = other.high_ >>> 16; | ||
| 429 | + var b32 = other.high_ & 0xFFFF; | ||
| 430 | + var b16 = other.low_ >>> 16; | ||
| 431 | + var b00 = other.low_ & 0xFFFF; | ||
| 432 | + | ||
| 433 | + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
| 434 | + c00 += a00 * b00; | ||
| 435 | + c16 += c00 >>> 16; | ||
| 436 | + c00 &= 0xFFFF; | ||
| 437 | + c16 += a16 * b00; | ||
| 438 | + c32 += c16 >>> 16; | ||
| 439 | + c16 &= 0xFFFF; | ||
| 440 | + c16 += a00 * b16; | ||
| 441 | + c32 += c16 >>> 16; | ||
| 442 | + c16 &= 0xFFFF; | ||
| 443 | + c32 += a32 * b00; | ||
| 444 | + c48 += c32 >>> 16; | ||
| 445 | + c32 &= 0xFFFF; | ||
| 446 | + c32 += a16 * b16; | ||
| 447 | + c48 += c32 >>> 16; | ||
| 448 | + c32 &= 0xFFFF; | ||
| 449 | + c32 += a00 * b32; | ||
| 450 | + c48 += c32 >>> 16; | ||
| 451 | + c32 &= 0xFFFF; | ||
| 452 | + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; | ||
| 453 | + c48 &= 0xFFFF; | ||
| 454 | + return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
| 455 | +}; | ||
| 456 | + | ||
| 457 | +/** | ||
| 458 | + * Returns this Timestamp divided by the given one. | ||
| 459 | + * | ||
| 460 | + * @method | ||
| 461 | + * @param {Timestamp} other Timestamp by which to divide. | ||
| 462 | + * @return {Timestamp} this Timestamp divided by the given one. | ||
| 463 | + */ | ||
| 464 | +Timestamp.prototype.div = function(other) { | ||
| 465 | + if (other.isZero()) { | ||
| 466 | + throw Error('division by zero'); | ||
| 467 | + } else if (this.isZero()) { | ||
| 468 | + return Timestamp.ZERO; | ||
| 469 | + } | ||
| 470 | + | ||
| 471 | + if (this.equals(Timestamp.MIN_VALUE)) { | ||
| 472 | + if (other.equals(Timestamp.ONE) || | ||
| 473 | + other.equals(Timestamp.NEG_ONE)) { | ||
| 474 | + return Timestamp.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE | ||
| 475 | + } else if (other.equals(Timestamp.MIN_VALUE)) { | ||
| 476 | + return Timestamp.ONE; | ||
| 477 | + } else { | ||
| 478 | + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. | ||
| 479 | + var halfThis = this.shiftRight(1); | ||
| 480 | + var approx = halfThis.div(other).shiftLeft(1); | ||
| 481 | + if (approx.equals(Timestamp.ZERO)) { | ||
| 482 | + return other.isNegative() ? Timestamp.ONE : Timestamp.NEG_ONE; | ||
| 483 | + } else { | ||
| 484 | + var rem = this.subtract(other.multiply(approx)); | ||
| 485 | + var result = approx.add(rem.div(other)); | ||
| 486 | + return result; | ||
| 487 | + } | ||
| 488 | + } | ||
| 489 | + } else if (other.equals(Timestamp.MIN_VALUE)) { | ||
| 490 | + return Timestamp.ZERO; | ||
| 491 | + } | ||
| 492 | + | ||
| 493 | + if (this.isNegative()) { | ||
| 494 | + if (other.isNegative()) { | ||
| 495 | + return this.negate().div(other.negate()); | ||
| 496 | + } else { | ||
| 497 | + return this.negate().div(other).negate(); | ||
| 498 | + } | ||
| 499 | + } else if (other.isNegative()) { | ||
| 500 | + return this.div(other.negate()).negate(); | ||
| 501 | + } | ||
| 502 | + | ||
| 503 | + // Repeat the following until the remainder is less than other: find a | ||
| 504 | + // floating-point that approximates remainder / other *from below*, add this | ||
| 505 | + // into the result, and subtract it from the remainder. It is critical that | ||
| 506 | + // the approximate value is less than or equal to the real value so that the | ||
| 507 | + // remainder never becomes negative. | ||
| 508 | + var res = Timestamp.ZERO; | ||
| 509 | + var rem = this; | ||
| 510 | + while (rem.greaterThanOrEqual(other)) { | ||
| 511 | + // Approximate the result of division. This may be a little greater or | ||
| 512 | + // smaller than the actual value. | ||
| 513 | + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); | ||
| 514 | + | ||
| 515 | + // We will tweak the approximate result by changing it in the 48-th digit or | ||
| 516 | + // the smallest non-fractional digit, whichever is larger. | ||
| 517 | + var log2 = Math.ceil(Math.log(approx) / Math.LN2); | ||
| 518 | + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); | ||
| 519 | + | ||
| 520 | + // Decrease the approximation until it is smaller than the remainder. Note | ||
| 521 | + // that if it is too large, the product overflows and is negative. | ||
| 522 | + var approxRes = Timestamp.fromNumber(approx); | ||
| 523 | + var approxRem = approxRes.multiply(other); | ||
| 524 | + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { | ||
| 525 | + approx -= delta; | ||
| 526 | + approxRes = Timestamp.fromNumber(approx); | ||
| 527 | + approxRem = approxRes.multiply(other); | ||
| 528 | + } | ||
| 529 | + | ||
| 530 | + // We know the answer can't be zero... and actually, zero would cause | ||
| 531 | + // infinite recursion since we would make no progress. | ||
| 532 | + if (approxRes.isZero()) { | ||
| 533 | + approxRes = Timestamp.ONE; | ||
| 534 | + } | ||
| 535 | + | ||
| 536 | + res = res.add(approxRes); | ||
| 537 | + rem = rem.subtract(approxRem); | ||
| 538 | + } | ||
| 539 | + return res; | ||
| 540 | +}; | ||
| 541 | + | ||
| 542 | +/** | ||
| 543 | + * Returns this Timestamp modulo the given one. | ||
| 544 | + * | ||
| 545 | + * @method | ||
| 546 | + * @param {Timestamp} other Timestamp by which to mod. | ||
| 547 | + * @return {Timestamp} this Timestamp modulo the given one. | ||
| 548 | + */ | ||
| 549 | +Timestamp.prototype.modulo = function(other) { | ||
| 550 | + return this.subtract(this.div(other).multiply(other)); | ||
| 551 | +}; | ||
| 552 | + | ||
| 553 | +/** | ||
| 554 | + * The bitwise-NOT of this value. | ||
| 555 | + * | ||
| 556 | + * @method | ||
| 557 | + * @return {Timestamp} the bitwise-NOT of this value. | ||
| 558 | + */ | ||
| 559 | +Timestamp.prototype.not = function() { | ||
| 560 | + return Timestamp.fromBits(~this.low_, ~this.high_); | ||
| 561 | +}; | ||
| 562 | + | ||
| 563 | +/** | ||
| 564 | + * Returns the bitwise-AND of this Timestamp and the given one. | ||
| 565 | + * | ||
| 566 | + * @method | ||
| 567 | + * @param {Timestamp} other the Timestamp with which to AND. | ||
| 568 | + * @return {Timestamp} the bitwise-AND of this and the other. | ||
| 569 | + */ | ||
| 570 | +Timestamp.prototype.and = function(other) { | ||
| 571 | + return Timestamp.fromBits(this.low_ & other.low_, this.high_ & other.high_); | ||
| 572 | +}; | ||
| 573 | + | ||
| 574 | +/** | ||
| 575 | + * Returns the bitwise-OR of this Timestamp and the given one. | ||
| 576 | + * | ||
| 577 | + * @method | ||
| 578 | + * @param {Timestamp} other the Timestamp with which to OR. | ||
| 579 | + * @return {Timestamp} the bitwise-OR of this and the other. | ||
| 580 | + */ | ||
| 581 | +Timestamp.prototype.or = function(other) { | ||
| 582 | + return Timestamp.fromBits(this.low_ | other.low_, this.high_ | other.high_); | ||
| 583 | +}; | ||
| 584 | + | ||
| 585 | +/** | ||
| 586 | + * Returns the bitwise-XOR of this Timestamp and the given one. | ||
| 587 | + * | ||
| 588 | + * @method | ||
| 589 | + * @param {Timestamp} other the Timestamp with which to XOR. | ||
| 590 | + * @return {Timestamp} the bitwise-XOR of this and the other. | ||
| 591 | + */ | ||
| 592 | +Timestamp.prototype.xor = function(other) { | ||
| 593 | + return Timestamp.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); | ||
| 594 | +}; | ||
| 595 | + | ||
| 596 | +/** | ||
| 597 | + * Returns this Timestamp with bits shifted to the left by the given amount. | ||
| 598 | + * | ||
| 599 | + * @method | ||
| 600 | + * @param {number} numBits the number of bits by which to shift. | ||
| 601 | + * @return {Timestamp} this shifted to the left by the given amount. | ||
| 602 | + */ | ||
| 603 | +Timestamp.prototype.shiftLeft = function(numBits) { | ||
| 604 | + numBits &= 63; | ||
| 605 | + if (numBits == 0) { | ||
| 606 | + return this; | ||
| 607 | + } else { | ||
| 608 | + var low = this.low_; | ||
| 609 | + if (numBits < 32) { | ||
| 610 | + var high = this.high_; | ||
| 611 | + return Timestamp.fromBits( | ||
| 612 | + low << numBits, | ||
| 613 | + (high << numBits) | (low >>> (32 - numBits))); | ||
| 614 | + } else { | ||
| 615 | + return Timestamp.fromBits(0, low << (numBits - 32)); | ||
| 616 | + } | ||
| 617 | + } | ||
| 618 | +}; | ||
| 619 | + | ||
| 620 | +/** | ||
| 621 | + * Returns this Timestamp with bits shifted to the right by the given amount. | ||
| 622 | + * | ||
| 623 | + * @method | ||
| 624 | + * @param {number} numBits the number of bits by which to shift. | ||
| 625 | + * @return {Timestamp} this shifted to the right by the given amount. | ||
| 626 | + */ | ||
| 627 | +Timestamp.prototype.shiftRight = function(numBits) { | ||
| 628 | + numBits &= 63; | ||
| 629 | + if (numBits == 0) { | ||
| 630 | + return this; | ||
| 631 | + } else { | ||
| 632 | + var high = this.high_; | ||
| 633 | + if (numBits < 32) { | ||
| 634 | + var low = this.low_; | ||
| 635 | + return Timestamp.fromBits( | ||
| 636 | + (low >>> numBits) | (high << (32 - numBits)), | ||
| 637 | + high >> numBits); | ||
| 638 | + } else { | ||
| 639 | + return Timestamp.fromBits( | ||
| 640 | + high >> (numBits - 32), | ||
| 641 | + high >= 0 ? 0 : -1); | ||
| 642 | + } | ||
| 643 | + } | ||
| 644 | +}; | ||
| 645 | + | ||
| 646 | +/** | ||
| 647 | + * Returns this Timestamp with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. | ||
| 648 | + * | ||
| 649 | + * @method | ||
| 650 | + * @param {number} numBits the number of bits by which to shift. | ||
| 651 | + * @return {Timestamp} this shifted to the right by the given amount, with zeros placed into the new leading bits. | ||
| 652 | + */ | ||
| 653 | +Timestamp.prototype.shiftRightUnsigned = function(numBits) { | ||
| 654 | + numBits &= 63; | ||
| 655 | + if (numBits == 0) { | ||
| 656 | + return this; | ||
| 657 | + } else { | ||
| 658 | + var high = this.high_; | ||
| 659 | + if (numBits < 32) { | ||
| 660 | + var low = this.low_; | ||
| 661 | + return Timestamp.fromBits( | ||
| 662 | + (low >>> numBits) | (high << (32 - numBits)), | ||
| 663 | + high >>> numBits); | ||
| 664 | + } else if (numBits == 32) { | ||
| 665 | + return Timestamp.fromBits(high, 0); | ||
| 666 | + } else { | ||
| 667 | + return Timestamp.fromBits(high >>> (numBits - 32), 0); | ||
| 668 | + } | ||
| 669 | + } | ||
| 670 | +}; | ||
| 671 | + | ||
| 672 | +/** | ||
| 673 | + * Returns a Timestamp representing the given (32-bit) integer value. | ||
| 674 | + * | ||
| 675 | + * @method | ||
| 676 | + * @param {number} value the 32-bit integer in question. | ||
| 677 | + * @return {Timestamp} the corresponding Timestamp value. | ||
| 678 | + */ | ||
| 679 | +Timestamp.fromInt = function(value) { | ||
| 680 | + if (-128 <= value && value < 128) { | ||
| 681 | + var cachedObj = Timestamp.INT_CACHE_[value]; | ||
| 682 | + if (cachedObj) { | ||
| 683 | + return cachedObj; | ||
| 684 | + } | ||
| 685 | + } | ||
| 686 | + | ||
| 687 | + var obj = new Timestamp(value | 0, value < 0 ? -1 : 0); | ||
| 688 | + if (-128 <= value && value < 128) { | ||
| 689 | + Timestamp.INT_CACHE_[value] = obj; | ||
| 690 | + } | ||
| 691 | + return obj; | ||
| 692 | +}; | ||
| 693 | + | ||
| 694 | +/** | ||
| 695 | + * Returns a Timestamp representing the given value, provided that it is a finite number. Otherwise, zero is returned. | ||
| 696 | + * | ||
| 697 | + * @method | ||
| 698 | + * @param {number} value the number in question. | ||
| 699 | + * @return {Timestamp} the corresponding Timestamp value. | ||
| 700 | + */ | ||
| 701 | +Timestamp.fromNumber = function(value) { | ||
| 702 | + if (isNaN(value) || !isFinite(value)) { | ||
| 703 | + return Timestamp.ZERO; | ||
| 704 | + } else if (value <= -Timestamp.TWO_PWR_63_DBL_) { | ||
| 705 | + return Timestamp.MIN_VALUE; | ||
| 706 | + } else if (value + 1 >= Timestamp.TWO_PWR_63_DBL_) { | ||
| 707 | + return Timestamp.MAX_VALUE; | ||
| 708 | + } else if (value < 0) { | ||
| 709 | + return Timestamp.fromNumber(-value).negate(); | ||
| 710 | + } else { | ||
| 711 | + return new Timestamp( | ||
| 712 | + (value % Timestamp.TWO_PWR_32_DBL_) | 0, | ||
| 713 | + (value / Timestamp.TWO_PWR_32_DBL_) | 0); | ||
| 714 | + } | ||
| 715 | +}; | ||
| 716 | + | ||
| 717 | +/** | ||
| 718 | + * Returns a Timestamp representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. | ||
| 719 | + * | ||
| 720 | + * @method | ||
| 721 | + * @param {number} lowBits the low 32-bits. | ||
| 722 | + * @param {number} highBits the high 32-bits. | ||
| 723 | + * @return {Timestamp} the corresponding Timestamp value. | ||
| 724 | + */ | ||
| 725 | +Timestamp.fromBits = function(lowBits, highBits) { | ||
| 726 | + return new Timestamp(lowBits, highBits); | ||
| 727 | +}; | ||
| 728 | + | ||
| 729 | +/** | ||
| 730 | + * Returns a Timestamp representation of the given string, written using the given radix. | ||
| 731 | + * | ||
| 732 | + * @method | ||
| 733 | + * @param {string} str the textual representation of the Timestamp. | ||
| 734 | + * @param {number} opt_radix the radix in which the text is written. | ||
| 735 | + * @return {Timestamp} the corresponding Timestamp value. | ||
| 736 | + */ | ||
| 737 | +Timestamp.fromString = function(str, opt_radix) { | ||
| 738 | + if (str.length == 0) { | ||
| 739 | + throw Error('number format error: empty string'); | ||
| 740 | + } | ||
| 741 | + | ||
| 742 | + var radix = opt_radix || 10; | ||
| 743 | + if (radix < 2 || 36 < radix) { | ||
| 744 | + throw Error('radix out of range: ' + radix); | ||
| 745 | + } | ||
| 746 | + | ||
| 747 | + if (str.charAt(0) == '-') { | ||
| 748 | + return Timestamp.fromString(str.substring(1), radix).negate(); | ||
| 749 | + } else if (str.indexOf('-') >= 0) { | ||
| 750 | + throw Error('number format error: interior "-" character: ' + str); | ||
| 751 | + } | ||
| 752 | + | ||
| 753 | + // Do several (8) digits each time through the loop, so as to | ||
| 754 | + // minimize the calls to the very expensive emulated div. | ||
| 755 | + var radixToPower = Timestamp.fromNumber(Math.pow(radix, 8)); | ||
| 756 | + | ||
| 757 | + var result = Timestamp.ZERO; | ||
| 758 | + for (var i = 0; i < str.length; i += 8) { | ||
| 759 | + var size = Math.min(8, str.length - i); | ||
| 760 | + var value = parseInt(str.substring(i, i + size), radix); | ||
| 761 | + if (size < 8) { | ||
| 762 | + var power = Timestamp.fromNumber(Math.pow(radix, size)); | ||
| 763 | + result = result.multiply(power).add(Timestamp.fromNumber(value)); | ||
| 764 | + } else { | ||
| 765 | + result = result.multiply(radixToPower); | ||
| 766 | + result = result.add(Timestamp.fromNumber(value)); | ||
| 767 | + } | ||
| 768 | + } | ||
| 769 | + return result; | ||
| 770 | +}; | ||
| 771 | + | ||
| 772 | +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the | ||
| 773 | +// from* methods on which they depend. | ||
| 774 | + | ||
| 775 | + | ||
| 776 | +/** | ||
| 777 | + * A cache of the Timestamp representations of small integer values. | ||
| 778 | + * @type {Object} | ||
| 779 | + * @ignore | ||
| 780 | + */ | ||
| 781 | +Timestamp.INT_CACHE_ = {}; | ||
| 782 | + | ||
| 783 | +// NOTE: the compiler should inline these constant values below and then remove | ||
| 784 | +// these variables, so there should be no runtime penalty for these. | ||
| 785 | + | ||
| 786 | +/** | ||
| 787 | + * Number used repeated below in calculations. This must appear before the | ||
| 788 | + * first call to any from* function below. | ||
| 789 | + * @type {number} | ||
| 790 | + * @ignore | ||
| 791 | + */ | ||
| 792 | +Timestamp.TWO_PWR_16_DBL_ = 1 << 16; | ||
| 793 | + | ||
| 794 | +/** | ||
| 795 | + * @type {number} | ||
| 796 | + * @ignore | ||
| 797 | + */ | ||
| 798 | +Timestamp.TWO_PWR_24_DBL_ = 1 << 24; | ||
| 799 | + | ||
| 800 | +/** | ||
| 801 | + * @type {number} | ||
| 802 | + * @ignore | ||
| 803 | + */ | ||
| 804 | +Timestamp.TWO_PWR_32_DBL_ = Timestamp.TWO_PWR_16_DBL_ * Timestamp.TWO_PWR_16_DBL_; | ||
| 805 | + | ||
| 806 | +/** | ||
| 807 | + * @type {number} | ||
| 808 | + * @ignore | ||
| 809 | + */ | ||
| 810 | +Timestamp.TWO_PWR_31_DBL_ = Timestamp.TWO_PWR_32_DBL_ / 2; | ||
| 811 | + | ||
| 812 | +/** | ||
| 813 | + * @type {number} | ||
| 814 | + * @ignore | ||
| 815 | + */ | ||
| 816 | +Timestamp.TWO_PWR_48_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_16_DBL_; | ||
| 817 | + | ||
| 818 | +/** | ||
| 819 | + * @type {number} | ||
| 820 | + * @ignore | ||
| 821 | + */ | ||
| 822 | +Timestamp.TWO_PWR_64_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_32_DBL_; | ||
| 823 | + | ||
| 824 | +/** | ||
| 825 | + * @type {number} | ||
| 826 | + * @ignore | ||
| 827 | + */ | ||
| 828 | +Timestamp.TWO_PWR_63_DBL_ = Timestamp.TWO_PWR_64_DBL_ / 2; | ||
| 829 | + | ||
| 830 | +/** @type {Timestamp} */ | ||
| 831 | +Timestamp.ZERO = Timestamp.fromInt(0); | ||
| 832 | + | ||
| 833 | +/** @type {Timestamp} */ | ||
| 834 | +Timestamp.ONE = Timestamp.fromInt(1); | ||
| 835 | + | ||
| 836 | +/** @type {Timestamp} */ | ||
| 837 | +Timestamp.NEG_ONE = Timestamp.fromInt(-1); | ||
| 838 | + | ||
| 839 | +/** @type {Timestamp} */ | ||
| 840 | +Timestamp.MAX_VALUE = | ||
| 841 | + Timestamp.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); | ||
| 842 | + | ||
| 843 | +/** @type {Timestamp} */ | ||
| 844 | +Timestamp.MIN_VALUE = Timestamp.fromBits(0, 0x80000000 | 0); | ||
| 845 | + | ||
| 846 | +/** | ||
| 847 | + * @type {Timestamp} | ||
| 848 | + * @ignore | ||
| 849 | + */ | ||
| 850 | +Timestamp.TWO_PWR_24_ = Timestamp.fromInt(1 << 24); | ||
| 851 | + | ||
| 852 | +/** | ||
| 853 | + * Expose. | ||
| 854 | + */ | ||
| 855 | +module.exports = Timestamp; | ||
| 856 | +module.exports.Timestamp = Timestamp; |
node_modules/_bson@1.0.4@bson/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "bson", | ||
| 3 | + "description": "A bson parser for node.js and the browser", | ||
| 4 | + "keywords": [ | ||
| 5 | + "mongodb", | ||
| 6 | + "bson", | ||
| 7 | + "parser" | ||
| 8 | + ], | ||
| 9 | + "files": [ | ||
| 10 | + "lib", | ||
| 11 | + "index.js", | ||
| 12 | + "browser_build", | ||
| 13 | + "bower.json" | ||
| 14 | + ], | ||
| 15 | + "version": "1.0.4", | ||
| 16 | + "author": "Christian Amor Kvalheim <christkv@gmail.com>", | ||
| 17 | + "contributors": [], | ||
| 18 | + "repository": "mongodb/js-bson", | ||
| 19 | + "bugs": { | ||
| 20 | + "mail": "node-mongodb-native@googlegroups.com", | ||
| 21 | + "url": "https://github.com/mongodb/js-bson/issues" | ||
| 22 | + }, | ||
| 23 | + "devDependencies": { | ||
| 24 | + "benchmark": "1.0.0", | ||
| 25 | + "colors": "1.1.0", | ||
| 26 | + "nodeunit": "0.9.0", | ||
| 27 | + "babel-core": "^6.14.0", | ||
| 28 | + "babel-loader": "^6.2.5", | ||
| 29 | + "babel-polyfill": "^6.13.0", | ||
| 30 | + "babel-preset-es2015": "^6.14.0", | ||
| 31 | + "babel-preset-stage-0": "^6.5.0", | ||
| 32 | + "babel-register": "^6.14.0", | ||
| 33 | + "webpack": "^1.13.2", | ||
| 34 | + "webpack-polyfills-plugin": "0.0.9" | ||
| 35 | + }, | ||
| 36 | + "config": { | ||
| 37 | + "native": false | ||
| 38 | + }, | ||
| 39 | + "main": "./index", | ||
| 40 | + "directories": { | ||
| 41 | + "lib": "./lib/bson" | ||
| 42 | + }, | ||
| 43 | + "engines": { | ||
| 44 | + "node": ">=0.6.19" | ||
| 45 | + }, | ||
| 46 | + "scripts": { | ||
| 47 | + "test": "nodeunit ./test/node", | ||
| 48 | + "build": "webpack --config ./webpack.dist.config.js" | ||
| 49 | + }, | ||
| 50 | + "browser": "lib/bson/bson.js", | ||
| 51 | + "license": "Apache-2.0", | ||
| 52 | + "_from": "bson@1.0.4", | ||
| 53 | + "_resolved": "http://registry.npm.taobao.org/bson/download/bson-1.0.4.tgz" | ||
| 54 | +} |
node_modules/bson
0 → 120000
| 1 | +_bson@1.0.4@bson |
node_modules/jwa
0 → 120000
| 1 | +_jwa@1.1.5@jwa |
| @@ -5,8 +5,22 @@ var status = require('../util/resTemplate') | @@ -5,8 +5,22 @@ var status = require('../util/resTemplate') | ||
| 5 | router.prefix('/users') | 5 | router.prefix('/users') |
| 6 | 6 | ||
| 7 | router.post('/addUser',async (ctx, next) => { | 7 | router.post('/addUser',async (ctx, next) => { |
| 8 | - var data = await userContoller.addUser(ctx, next); | ||
| 9 | - status.res(ctx,200,data); | 8 | + try{ |
| 9 | + var data = await userContoller.addUser(ctx, next); | ||
| 10 | + status.res(ctx,200,data); | ||
| 11 | + }catch(e){ | ||
| 12 | + const err = {code:0,msg:e.message} | ||
| 13 | + status.res(ctx,200,err); | ||
| 14 | + } | ||
| 15 | +}) | ||
| 16 | +router.post('/login',async(ctx, next)=>{ | ||
| 17 | + try{ | ||
| 18 | + var data = await userContoller.login(ctx, next); | ||
| 19 | + status.res(ctx,200,data); | ||
| 20 | + }catch(e){ | ||
| 21 | + const err = {code:0,msg:e.message} | ||
| 22 | + status.res(ctx,200,err); | ||
| 23 | + } | ||
| 10 | }) | 24 | }) |
| 11 | 25 | ||
| 12 | router.get('/bar', function (ctx, next) { | 26 | router.get('/bar', function (ctx, next) { |
| 1 | var userModel = require('../model/userModel'); | 1 | var userModel = require('../model/userModel'); |
| 2 | -var saitMd5 = require('../util/saltMD5') | ||
| 3 | var status = require('../util/resTemplate'); | 2 | var status = require('../util/resTemplate'); |
| 3 | +var saitMd5 = require('../util/saltMD5'); | ||
| 4 | var Sequelize = new require('sequelize'); | 4 | var Sequelize = new require('sequelize'); |
| 5 | +var tokenUtil = require('../util/tokenUtil'); | ||
| 5 | var co = require('co'); | 6 | var co = require('co'); |
| 6 | 7 | ||
| 7 | 8 | ||
| @@ -18,17 +19,38 @@ try{ | @@ -18,17 +19,38 @@ try{ | ||
| 18 | } | 19 | } |
| 19 | }catch (err){ | 20 | }catch (err){ |
| 20 | console.log(err) | 21 | console.log(err) |
| 21 | - return {code:0,msg:err}; | 22 | + throw new Error(err); |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | try{ | 25 | try{ |
| 25 | let newUser = await userModel.create(data) | 26 | let newUser = await userModel.create(data) |
| 26 | return newUser; | 27 | return newUser; |
| 27 | }catch (err){ | 28 | }catch (err){ |
| 28 | - return {code:0,msg:err}; | ||
| 29 | - } | 29 | + throw new Error(err); |
| 30 | +} | ||
| 30 | } | 31 | } |
| 31 | 32 | ||
| 33 | +userService.prototype.login = async(name,pw) => { | ||
| 34 | + try{ | ||
| 35 | + var User = await userModel.find({where:{loginName:name}}) | ||
| 36 | + console.dir(User) | ||
| 37 | + if(!User){ | ||
| 38 | + return {code:0,msg:'用户不存在'} | ||
| 39 | + }else if(User.password != saitMd5.md5Salt(pw,User.salt)){ | ||
| 40 | + return {code:0,msg:'密码不正确'} | ||
| 41 | + } | ||
| 42 | + let token = await tokenUtil.getSession(User); | ||
| 43 | + return token | ||
| 44 | + }catch (err){ | ||
| 45 | + console.log(err) | ||
| 46 | + throw new Error(err); | ||
| 47 | + } | ||
| 48 | + // try{ | ||
| 49 | + | ||
| 50 | + // }catch (err){ | ||
| 51 | + // return {code:0,msg:err}; | ||
| 52 | + // } | ||
| 53 | +} | ||
| 32 | 54 | ||
| 33 | 55 | ||
| 34 | module.exports = new userService(); | 56 | module.exports = new userService(); |
| @@ -4,38 +4,30 @@ | @@ -4,38 +4,30 @@ | ||
| 4 | var jwt = require('jsonwebtoken'); | 4 | var jwt = require('jsonwebtoken'); |
| 5 | var ObjectId = require('objectid'); | 5 | var ObjectId = require('objectid'); |
| 6 | 6 | ||
| 7 | -function JwtSession(opt) { | ||
| 8 | - this.jwtTokenSecret = (opt && opt.jwtTokenSecret) || 'test'; | 7 | +function JwtSession() { |
| 9 | } | 8 | } |
| 10 | 9 | ||
| 11 | -JwtSession = module.exports ; | 10 | +module.exports = new JwtSession() ; |
| 12 | 11 | ||
| 13 | /** | 12 | /** |
| 14 | * 生成token | 13 | * 生成token |
| 15 | * @param users | 14 | * @param users |
| 16 | * @param cb | 15 | * @param cb |
| 17 | */ | 16 | */ |
| 18 | -JwtSession.getSession = function (users ,cb) { | ||
| 19 | - cb = typeof cb === 'function' ? cb : function (){ | ||
| 20 | - }; | 17 | +JwtSession.prototype.getSession = (users) =>{ |
| 21 | var expiresIn = 60 * 60 * 60 * 60 * 60; | 18 | var expiresIn = 60 * 60 * 60 * 60 * 60; |
| 22 | var payload = {}; | 19 | var payload = {}; |
| 23 | payload.id = users.id; | 20 | payload.id = users.id; |
| 24 | - payload.name = users.name; | ||
| 25 | - payload.code =users.code; | ||
| 26 | - payload.category = users.category; | ||
| 27 | - if(users.type){ | ||
| 28 | - payload.type = users.type; | ||
| 29 | - } | 21 | + payload.name = users.loginName; |
| 22 | + payload.code =users.userType; | ||
| 30 | var options = { | 23 | var options = { |
| 31 | "expiresIn": expiresIn | 24 | "expiresIn": expiresIn |
| 32 | }; | 25 | }; |
| 33 | - console.log(options); | ||
| 34 | var token = jwt.sign(payload, '3mang', options); | 26 | var token = jwt.sign(payload, '3mang', options); |
| 35 | users.token = token; | 27 | users.token = token; |
| 36 | users.tokenTime = expiresIn; | 28 | users.tokenTime = expiresIn; |
| 37 | - console.log(users); | ||
| 38 | - cb && cb(null,users); | 29 | + |
| 30 | + return users; | ||
| 39 | 31 | ||
| 40 | }; | 32 | }; |
| 41 | 33 |
-
请 注册 或 登录 后发表评论