index.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. 'use strict';
  2. var Buffer = require('safe-buffer').Buffer;
  3. var isArray = require('isarray');
  4. var typedArrayBuffer = require('typed-array-buffer');
  5. var isView = ArrayBuffer.isView || function isView(obj) {
  6. try {
  7. typedArrayBuffer(obj);
  8. return true;
  9. } catch (e) {
  10. return false;
  11. }
  12. };
  13. var useUint8Array = typeof Uint8Array !== 'undefined';
  14. var useArrayBuffer = typeof ArrayBuffer !== 'undefined'
  15. && typeof Uint8Array !== 'undefined';
  16. var useFromArrayBuffer = useArrayBuffer && (Buffer.prototype instanceof Uint8Array || Buffer.TYPED_ARRAY_SUPPORT);
  17. module.exports = function toBuffer(data, encoding) {
  18. if (Buffer.isBuffer(data)) {
  19. if (data.constructor && !('isBuffer' in data)) {
  20. // probably a SlowBuffer
  21. return Buffer.from(data);
  22. }
  23. return data;
  24. }
  25. if (typeof data === 'string') {
  26. return Buffer.from(data, encoding);
  27. }
  28. /*
  29. * Wrap any TypedArray instances and DataViews
  30. * Makes sense only on engines with full TypedArray support -- let Buffer detect that
  31. */
  32. if (useArrayBuffer && isView(data)) {
  33. // Bug in Node.js <6.3.1, which treats this as out-of-bounds
  34. if (data.byteLength === 0) {
  35. return Buffer.alloc(0);
  36. }
  37. // When Buffer is based on Uint8Array, we can just construct it from ArrayBuffer
  38. if (useFromArrayBuffer) {
  39. var res = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
  40. /*
  41. * Recheck result size, as offset/length doesn't work on Node.js <5.10
  42. * We just go to Uint8Array case if this fails
  43. */
  44. if (res.byteLength === data.byteLength) {
  45. return res;
  46. }
  47. }
  48. // Convert to Uint8Array bytes and then to Buffer
  49. var uint8 = data instanceof Uint8Array ? data : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
  50. var result = Buffer.from(uint8);
  51. /*
  52. * Let's recheck that conversion succeeded
  53. * We have .length but not .byteLength when useFromArrayBuffer is false
  54. */
  55. if (result.length === data.byteLength) {
  56. return result;
  57. }
  58. }
  59. /*
  60. * Uint8Array in engines where Buffer.from might not work with ArrayBuffer, just copy over
  61. * Doesn't make sense with other TypedArray instances
  62. */
  63. if (useUint8Array && data instanceof Uint8Array) {
  64. return Buffer.from(data);
  65. }
  66. var isArr = isArray(data);
  67. if (isArr) {
  68. for (var i = 0; i < data.length; i += 1) {
  69. var x = data[i];
  70. if (
  71. typeof x !== 'number'
  72. || x < 0
  73. || x > 255
  74. || ~~x !== x // NaN and integer check
  75. ) {
  76. throw new RangeError('Array items must be numbers in the range 0-255.');
  77. }
  78. }
  79. }
  80. /*
  81. * Old Buffer polyfill on an engine that doesn't have TypedArray support
  82. * Also, this is from a different Buffer polyfill implementation then we have, as instanceof check failed
  83. * Convert to our current Buffer implementation
  84. */
  85. if (
  86. isArr || (
  87. Buffer.isBuffer(data)
  88. && data.constructor
  89. && typeof data.constructor.isBuffer === 'function'
  90. && data.constructor.isBuffer(data)
  91. )
  92. ) {
  93. return Buffer.from(data);
  94. }
  95. throw new TypeError('The "data" argument must be a string, an Array, a Buffer, a Uint8Array, or a DataView.');
  96. };