Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

binary.js 11KB

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