Source: node_modules/bson/lib/bson/binary.js

  1. /**
  2. * Module dependencies.
  3. * @ignore
  4. */
  5. // Test if we're in Node via presence of "global" not absence of "window"
  6. // to support hybrid environments like Electron
  7. if(typeof global !== 'undefined') {
  8. var Buffer = require('buffer').Buffer; // TODO just use global Buffer
  9. }
  10. /**
  11. * A class representation of the BSON Binary type.
  12. *
  13. * Sub types
  14. * - **BSON.BSON_BINARY_SUBTYPE_DEFAULT**, default BSON type.
  15. * - **BSON.BSON_BINARY_SUBTYPE_FUNCTION**, BSON function type.
  16. * - **BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY**, BSON byte array type.
  17. * - **BSON.BSON_BINARY_SUBTYPE_UUID**, BSON uuid type.
  18. * - **BSON.BSON_BINARY_SUBTYPE_MD5**, BSON md5 type.
  19. * - **BSON.BSON_BINARY_SUBTYPE_USER_DEFINED**, BSON user defined type.
  20. *
  21. * @class
  22. * @param {Buffer} buffer a buffer object containing the binary data.
  23. * @param {Number} [subType] the option binary type.
  24. * @return {Binary}
  25. */
  26. function Binary(buffer, subType) {
  27. if(!(this instanceof Binary)) return new Binary(buffer, subType);
  28. this._bsontype = 'Binary';
  29. if(buffer instanceof Number) {
  30. this.sub_type = buffer;
  31. this.position = 0;
  32. } else {
  33. this.sub_type = subType == null ? BSON_BINARY_SUBTYPE_DEFAULT : subType;
  34. this.position = 0;
  35. }
  36. if(buffer != null && !(buffer instanceof Number)) {
  37. // Only accept Buffer, Uint8Array or Arrays
  38. if(typeof buffer == 'string') {
  39. // Different ways of writing the length of the string for the different types
  40. if(typeof Buffer != 'undefined') {
  41. this.buffer = new Buffer(buffer);
  42. } else if(typeof Uint8Array != 'undefined' || (Object.prototype.toString.call(buffer) == '[object Array]')) {
  43. this.buffer = writeStringToArray(buffer);
  44. } else {
  45. throw new Error("only String, Buffer, Uint8Array or Array accepted");
  46. }
  47. } else {
  48. this.buffer = buffer;
  49. }
  50. this.position = buffer.length;
  51. } else {
  52. if(typeof Buffer != 'undefined') {
  53. this.buffer = new Buffer(Binary.BUFFER_SIZE);
  54. } else if(typeof Uint8Array != 'undefined'){
  55. this.buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE));
  56. } else {
  57. this.buffer = new Array(Binary.BUFFER_SIZE);
  58. }
  59. // Set position to start of buffer
  60. this.position = 0;
  61. }
  62. };
  63. /**
  64. * Updates this binary with byte_value.
  65. *
  66. * @method
  67. * @param {string} byte_value a single byte we wish to write.
  68. */
  69. Binary.prototype.put = function put(byte_value) {
  70. // If it's a string and a has more than one character throw an error
  71. if(byte_value['length'] != null && typeof byte_value != 'number' && byte_value.length != 1) throw new Error("only accepts single character String, Uint8Array or Array");
  72. 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");
  73. // Decode the byte value once
  74. var decoded_byte = null;
  75. if(typeof byte_value == 'string') {
  76. decoded_byte = byte_value.charCodeAt(0);
  77. } else if(byte_value['length'] != null) {
  78. decoded_byte = byte_value[0];
  79. } else {
  80. decoded_byte = byte_value;
  81. }
  82. if(this.buffer.length > this.position) {
  83. this.buffer[this.position++] = decoded_byte;
  84. } else {
  85. if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) {
  86. // Create additional overflow buffer
  87. var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length);
  88. // Combine the two buffers together
  89. this.buffer.copy(buffer, 0, 0, this.buffer.length);
  90. this.buffer = buffer;
  91. this.buffer[this.position++] = decoded_byte;
  92. } else {
  93. var buffer = null;
  94. // Create a new buffer (typed or normal array)
  95. if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') {
  96. buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE + this.buffer.length));
  97. } else {
  98. buffer = new Array(Binary.BUFFER_SIZE + this.buffer.length);
  99. }
  100. // We need to copy all the content to the new array
  101. for(var i = 0; i < this.buffer.length; i++) {
  102. buffer[i] = this.buffer[i];
  103. }
  104. // Reassign the buffer
  105. this.buffer = buffer;
  106. // Write the byte
  107. this.buffer[this.position++] = decoded_byte;
  108. }
  109. }
  110. };
  111. /**
  112. * Writes a buffer or string to the binary.
  113. *
  114. * @method
  115. * @param {(Buffer|string)} string a string or buffer to be written to the Binary BSON object.
  116. * @param {number} offset specify the binary of where to write the content.
  117. * @return {null}
  118. */
  119. Binary.prototype.write = function write(string, offset) {
  120. offset = typeof offset == 'number' ? offset : this.position;
  121. // If the buffer is to small let's extend the buffer
  122. if(this.buffer.length < offset + string.length) {
  123. var buffer = null;
  124. // If we are in node.js
  125. if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) {
  126. buffer = new Buffer(this.buffer.length + string.length);
  127. this.buffer.copy(buffer, 0, 0, this.buffer.length);
  128. } else if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') {
  129. // Create a new buffer
  130. buffer = new Uint8Array(new ArrayBuffer(this.buffer.length + string.length))
  131. // Copy the content
  132. for(var i = 0; i < this.position; i++) {
  133. buffer[i] = this.buffer[i];
  134. }
  135. }
  136. // Assign the new buffer
  137. this.buffer = buffer;
  138. }
  139. if(typeof Buffer != 'undefined' && Buffer.isBuffer(string) && Buffer.isBuffer(this.buffer)) {
  140. string.copy(this.buffer, offset, 0, string.length);
  141. this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position;
  142. // offset = string.length
  143. } else if(typeof Buffer != 'undefined' && typeof string == 'string' && Buffer.isBuffer(this.buffer)) {
  144. this.buffer.write(string, offset, 'binary');
  145. this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position;
  146. // offset = string.length;
  147. } else if(Object.prototype.toString.call(string) == '[object Uint8Array]'
  148. || Object.prototype.toString.call(string) == '[object Array]' && typeof string != 'string') {
  149. for(var i = 0; i < string.length; i++) {
  150. this.buffer[offset++] = string[i];
  151. }
  152. this.position = offset > this.position ? offset : this.position;
  153. } else if(typeof string == 'string') {
  154. for(var i = 0; i < string.length; i++) {
  155. this.buffer[offset++] = string.charCodeAt(i);
  156. }
  157. this.position = offset > this.position ? offset : this.position;
  158. }
  159. };
  160. /**
  161. * Reads **length** bytes starting at **position**.
  162. *
  163. * @method
  164. * @param {number} position read from the given position in the Binary.
  165. * @param {number} length the number of bytes to read.
  166. * @return {Buffer}
  167. */
  168. Binary.prototype.read = function read(position, length) {
  169. length = length && length > 0
  170. ? length
  171. : this.position;
  172. // Let's return the data based on the type we have
  173. if(this.buffer['slice']) {
  174. return this.buffer.slice(position, position + length);
  175. } else {
  176. // Create a buffer to keep the result
  177. var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(length)) : new Array(length);
  178. for(var i = 0; i < length; i++) {
  179. buffer[i] = this.buffer[position++];
  180. }
  181. }
  182. // Return the buffer
  183. return buffer;
  184. };
  185. /**
  186. * Returns the value of this binary as a string.
  187. *
  188. * @method
  189. * @return {string}
  190. */
  191. Binary.prototype.value = function value(asRaw) {
  192. asRaw = asRaw == null ? false : asRaw;
  193. // Optimize to serialize for the situation where the data == size of buffer
  194. if(asRaw && typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer) && this.buffer.length == this.position)
  195. return this.buffer;
  196. // If it's a node.js buffer object
  197. if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) {
  198. return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position);
  199. } else {
  200. if(asRaw) {
  201. // we support the slice command use it
  202. if(this.buffer['slice'] != null) {
  203. return this.buffer.slice(0, this.position);
  204. } else {
  205. // Create a new buffer to copy content to
  206. var newBuffer = Object.prototype.toString.call(this.buffer) == '[object Uint8Array]' ? new Uint8Array(new ArrayBuffer(this.position)) : new Array(this.position);
  207. // Copy content
  208. for(var i = 0; i < this.position; i++) {
  209. newBuffer[i] = this.buffer[i];
  210. }
  211. // Return the buffer
  212. return newBuffer;
  213. }
  214. } else {
  215. return convertArraytoUtf8BinaryString(this.buffer, 0, this.position);
  216. }
  217. }
  218. };
  219. /**
  220. * Length.
  221. *
  222. * @method
  223. * @return {number} the length of the binary.
  224. */
  225. Binary.prototype.length = function length() {
  226. return this.position;
  227. };
  228. /**
  229. * @ignore
  230. */
  231. Binary.prototype.toJSON = function() {
  232. return this.buffer != null ? this.buffer.toString('base64') : '';
  233. }
  234. /**
  235. * @ignore
  236. */
  237. Binary.prototype.toString = function(format) {
  238. return this.buffer != null ? this.buffer.slice(0, this.position).toString(format) : '';
  239. }
  240. /**
  241. * Binary default subtype
  242. * @ignore
  243. */
  244. var BSON_BINARY_SUBTYPE_DEFAULT = 0;
  245. /**
  246. * @ignore
  247. */
  248. var writeStringToArray = function(data) {
  249. // Create a buffer
  250. var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(data.length)) : new Array(data.length);
  251. // Write the content to the buffer
  252. for(var i = 0; i < data.length; i++) {
  253. buffer[i] = data.charCodeAt(i);
  254. }
  255. // Write the string to the buffer
  256. return buffer;
  257. }
  258. /**
  259. * Convert Array ot Uint8Array to Binary String
  260. *
  261. * @ignore
  262. */
  263. var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) {
  264. var result = "";
  265. for(var i = startIndex; i < endIndex; i++) {
  266. result = result + String.fromCharCode(byteArray[i]);
  267. }
  268. return result;
  269. };
  270. Binary.BUFFER_SIZE = 256;
  271. /**
  272. * Default BSON type
  273. *
  274. * @classconstant SUBTYPE_DEFAULT
  275. **/
  276. Binary.SUBTYPE_DEFAULT = 0;
  277. /**
  278. * Function BSON type
  279. *
  280. * @classconstant SUBTYPE_DEFAULT
  281. **/
  282. Binary.SUBTYPE_FUNCTION = 1;
  283. /**
  284. * Byte Array BSON type
  285. *
  286. * @classconstant SUBTYPE_DEFAULT
  287. **/
  288. Binary.SUBTYPE_BYTE_ARRAY = 2;
  289. /**
  290. * OLD UUID BSON type
  291. *
  292. * @classconstant SUBTYPE_DEFAULT
  293. **/
  294. Binary.SUBTYPE_UUID_OLD = 3;
  295. /**
  296. * UUID BSON type
  297. *
  298. * @classconstant SUBTYPE_DEFAULT
  299. **/
  300. Binary.SUBTYPE_UUID = 4;
  301. /**
  302. * MD5 BSON type
  303. *
  304. * @classconstant SUBTYPE_DEFAULT
  305. **/
  306. Binary.SUBTYPE_MD5 = 5;
  307. /**
  308. * User BSON type
  309. *
  310. * @classconstant SUBTYPE_DEFAULT
  311. **/
  312. Binary.SUBTYPE_USER_DEFINED = 128;
  313. /**
  314. * Expose.
  315. */
  316. module.exports = Binary;
  317. module.exports.Binary = Binary;