c879ad5dfd30acc963cd556692d735f639563557
[aai/esr-gui.git] /
1 "use strict"
2
3 var writeIEEE754 = require('../float_parser').writeIEEE754,
4         readIEEE754 = require('../float_parser').readIEEE754,
5         f = require('util').format,
6         Long = require('../long').Long,
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   MinKey = require('../min_key').MinKey,
13   MaxKey = require('../max_key').MaxKey,
14   DBRef = require('../db_ref').DBRef,
15   BSONRegExp = require('../regexp').BSONRegExp,
16   Binary = require('../binary').Binary;
17
18 var BSON = {};
19
20 /**
21  * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5
22  *
23  * @ignore
24  * @api private
25  */
26 var functionCache = BSON.functionCache = {};
27
28 /**
29  * Number BSON Type
30  *
31  * @classconstant BSON_DATA_NUMBER
32  **/
33 BSON.BSON_DATA_NUMBER = 1;
34 /**
35  * String BSON Type
36  *
37  * @classconstant BSON_DATA_STRING
38  **/
39 BSON.BSON_DATA_STRING = 2;
40 /**
41  * Object BSON Type
42  *
43  * @classconstant BSON_DATA_OBJECT
44  **/
45 BSON.BSON_DATA_OBJECT = 3;
46 /**
47  * Array BSON Type
48  *
49  * @classconstant BSON_DATA_ARRAY
50  **/
51 BSON.BSON_DATA_ARRAY = 4;
52 /**
53  * Binary BSON Type
54  *
55  * @classconstant BSON_DATA_BINARY
56  **/
57 BSON.BSON_DATA_BINARY = 5;
58 /**
59  * ObjectID BSON Type
60  *
61  * @classconstant BSON_DATA_OID
62  **/
63 BSON.BSON_DATA_OID = 7;
64 /**
65  * Boolean BSON Type
66  *
67  * @classconstant BSON_DATA_BOOLEAN
68  **/
69 BSON.BSON_DATA_BOOLEAN = 8;
70 /**
71  * Date BSON Type
72  *
73  * @classconstant BSON_DATA_DATE
74  **/
75 BSON.BSON_DATA_DATE = 9;
76 /**
77  * null BSON Type
78  *
79  * @classconstant BSON_DATA_NULL
80  **/
81 BSON.BSON_DATA_NULL = 10;
82 /**
83  * RegExp BSON Type
84  *
85  * @classconstant BSON_DATA_REGEXP
86  **/
87 BSON.BSON_DATA_REGEXP = 11;
88 /**
89  * Code BSON Type
90  *
91  * @classconstant BSON_DATA_CODE
92  **/
93 BSON.BSON_DATA_CODE = 13;
94 /**
95  * Symbol BSON Type
96  *
97  * @classconstant BSON_DATA_SYMBOL
98  **/
99 BSON.BSON_DATA_SYMBOL = 14;
100 /**
101  * Code with Scope BSON Type
102  *
103  * @classconstant BSON_DATA_CODE_W_SCOPE
104  **/
105 BSON.BSON_DATA_CODE_W_SCOPE = 15;
106 /**
107  * 32 bit Integer BSON Type
108  *
109  * @classconstant BSON_DATA_INT
110  **/
111 BSON.BSON_DATA_INT = 16;
112 /**
113  * Timestamp BSON Type
114  *
115  * @classconstant BSON_DATA_TIMESTAMP
116  **/
117 BSON.BSON_DATA_TIMESTAMP = 17;
118 /**
119  * Long BSON Type
120  *
121  * @classconstant BSON_DATA_LONG
122  **/
123 BSON.BSON_DATA_LONG = 18;
124 /**
125  * MinKey BSON Type
126  *
127  * @classconstant BSON_DATA_MIN_KEY
128  **/
129 BSON.BSON_DATA_MIN_KEY = 0xff;
130 /**
131  * MaxKey BSON Type
132  *
133  * @classconstant BSON_DATA_MAX_KEY
134  **/
135 BSON.BSON_DATA_MAX_KEY = 0x7f;
136
137 /**
138  * Binary Default Type
139  *
140  * @classconstant BSON_BINARY_SUBTYPE_DEFAULT
141  **/
142 BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
143 /**
144  * Binary Function Type
145  *
146  * @classconstant BSON_BINARY_SUBTYPE_FUNCTION
147  **/
148 BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
149 /**
150  * Binary Byte Array Type
151  *
152  * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY
153  **/
154 BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
155 /**
156  * Binary UUID Type
157  *
158  * @classconstant BSON_BINARY_SUBTYPE_UUID
159  **/
160 BSON.BSON_BINARY_SUBTYPE_UUID = 3;
161 /**
162  * Binary MD5 Type
163  *
164  * @classconstant BSON_BINARY_SUBTYPE_MD5
165  **/
166 BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
167 /**
168  * Binary User Defined Type
169  *
170  * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED
171  **/
172 BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
173
174 // BSON MAX VALUES
175 BSON.BSON_INT32_MAX = 0x7FFFFFFF;
176 BSON.BSON_INT32_MIN = -0x80000000;
177
178 BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1;
179 BSON.BSON_INT64_MIN = -Math.pow(2, 63);
180
181 // JS MAX PRECISE VALUES
182 BSON.JS_INT_MAX = 0x20000000000000;  // Any integer up to 2^53 can be precisely represented by a double.
183 BSON.JS_INT_MIN = -0x20000000000000;  // Any integer down to -2^53 can be precisely represented by a double.
184
185 // Internal long versions
186 var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000);  // Any integer up to 2^53 can be precisely represented by a double.
187 var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000);  // Any integer down to -2^53 can be precisely represented by a double.
188
189 var deserialize = function(buffer, options, isArray) {
190         var index = 0;
191         // Read the document size
192   var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
193
194         // Ensure buffer is valid size
195   if(size < 5 || buffer.length < size) {
196                 throw new Error("corrupt bson message");
197         }
198
199         // Illegal end value
200         if(buffer[size - 1] != 0) {
201                 throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00");
202         }
203
204         // Start deserializtion
205         return deserializeObject(buffer, options, isArray);
206 }
207
208 // // Reads in a C style string
209 // var readCStyleStringSpecial = function(buffer, index) {
210 //      // Get the start search index
211 //      var i = index;
212 //      // Locate the end of the c string
213 //      while(buffer[i] !== 0x00 && i < buffer.length) {
214 //              i++
215 //      }
216 //      // If are at the end of the buffer there is a problem with the document
217 //      if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString")
218 //      // Grab utf8 encoded string
219 //      var string = buffer.toString('utf8', index, i);
220 //      // Update index position
221 //      index = i + 1;
222 //      // Return string
223 //      return {s: string, i: index};
224 // }
225
226 // Reads in a C style string
227 var readCStyleStringSpecial = function(buffer, index) {
228         // Get the start search index
229         var i = index;
230         // Locate the end of the c string
231         while(buffer[i] !== 0x00 && i < buffer.length) {
232                 i++
233         }
234         // If are at the end of the buffer there is a problem with the document
235         if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString")
236         // Grab utf8 encoded string
237         return buffer.toString('utf8', index, i);
238 }
239
240 var DeserializationMethods = {}
241 DeserializationMethods[BSON.BSON_DATA_OID] = function(name, object, buffer, index) {
242         var string = buffer.toString('binary', index, index + 12);
243         object[name] = new ObjectID(string);
244         return index + 12;
245 }
246
247 DeserializationMethods[BSON.BSON_DATA_NUMBER] = function(name, object, buffer, index) {
248         object[name] = buffer.readDoubleLE(index);
249   return index + 8;
250 }
251
252 DeserializationMethods[BSON.BSON_DATA_INT] = function(name, object, buffer, index) {
253         object[name] = buffer.readInt32LE(index);
254         return index + 4;
255 }
256
257 DeserializationMethods[BSON.BSON_DATA_TIMESTAMP] = function(name, object, buffer, index) {
258   var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
259   var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
260   object[name] = new Timestamp(lowBits, highBits);
261         return index;
262 }
263
264 DeserializationMethods[BSON.BSON_DATA_STRING] = function(name, object, buffer, index) {
265   var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
266         if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson");
267   object[name] = buffer.toString('utf8', index, index + stringSize - 1);
268   return index + stringSize;
269 }
270
271 DeserializationMethods[BSON.BSON_DATA_BOOLEAN] = function(name, object, buffer, index) {
272   object[name] = buffer[index++] == 1;
273         return index;
274 }
275
276 var deserializeObject = function(buffer, options, isArray) {
277   // Options
278   options = options == null ? {} : options;
279   var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions'];
280   var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions'];
281   var cacheFunctionsCrc32 = options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32'];
282   var promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
283         var fieldsAsRaw = options['fieldsAsRaw'] == null ? {} : options['fieldsAsRaw'];
284   // Return BSONRegExp objects instead of native regular expressions
285   var bsonRegExp = typeof options['bsonRegExp'] == 'boolean' ? options['bsonRegExp'] : false;
286   var promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
287
288   // Validate that we have at least 4 bytes of buffer
289   if(buffer.length < 5) throw new Error("corrupt bson message < 5 bytes long");
290
291   // Set up index
292   var index = typeof options['index'] == 'number' ? options['index'] : 0;
293
294         // Read the document size
295   var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
296
297         // Ensure buffer is valid size
298   if(size < 5 || size > buffer.length) throw new Error("corrupt bson message");
299
300   // Create holding object
301   var object = isArray ? [] : {};
302
303   // While we have more left data left keep parsing
304   while(true) {
305     // Read the type
306     var elementType = buffer[index++];
307     // If we get a zero it's the last byte, exit
308     if(elementType == 0) break;
309     var name = readCStyleStringSpecial(buffer, index);
310                 index = index + name.length + 1;
311
312                 // console.log("----------- 0 " + elementType + " :: " + name)
313                 index = DeserializationMethods[elementType](name, object, buffer, index);
314                 // console.log('--------------- 1')
315   }
316
317   // Check if we have a db ref object
318   if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
319
320   // Return the final objects
321   return object;
322 }
323
324 /**
325  * Ensure eval is isolated.
326  *
327  * @ignore
328  * @api private
329  */
330 var isolateEvalWithHash = function(functionCache, hash, functionString, object) {
331   // Contains the value we are going to set
332   var value = null;
333
334   // Check for cache hit, eval if missing and return cached function
335   if(functionCache[hash] == null) {
336     eval("value = " + functionString);
337     functionCache[hash] = value;
338   }
339   // Set the object
340   return functionCache[hash].bind(object);
341 }
342
343 /**
344  * Ensure eval is isolated.
345  *
346  * @ignore
347  * @api private
348  */
349 var isolateEval = function(functionString) {
350   // Contains the value we are going to set
351   var value = null;
352   // Eval the function
353   eval("value = " + functionString);
354   return value;
355 }
356
357 module.exports = deserialize