extend-node.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. "use strict"
  2. // == Extend Node primitives to use iconv-lite =================================
  3. module.exports = function (iconv) {
  4. var original = undefined; // Place to keep original methods.
  5. // Node authors rewrote Buffer internals to make it compatible with
  6. // Uint8Array and we cannot patch key functions since then.
  7. iconv.supportsNodeEncodingsExtension = !(new Buffer(0) instanceof Uint8Array);
  8. iconv.extendNodeEncodings = function extendNodeEncodings() {
  9. if (original) return;
  10. original = {};
  11. if (!iconv.supportsNodeEncodingsExtension) {
  12. console.error("ACTION NEEDED: require('iconv-lite').extendNodeEncodings() is not supported in your version of Node");
  13. console.error("See more info at https://github.com/ashtuchkin/iconv-lite/wiki/Node-v4-compatibility");
  14. return;
  15. }
  16. var nodeNativeEncodings = {
  17. 'hex': true, 'utf8': true, 'utf-8': true, 'ascii': true, 'binary': true,
  18. 'base64': true, 'ucs2': true, 'ucs-2': true, 'utf16le': true, 'utf-16le': true,
  19. };
  20. Buffer.isNativeEncoding = function(enc) {
  21. return enc && nodeNativeEncodings[enc.toLowerCase()];
  22. }
  23. // -- SlowBuffer -----------------------------------------------------------
  24. var SlowBuffer = require('buffer').SlowBuffer;
  25. original.SlowBufferToString = SlowBuffer.prototype.toString;
  26. SlowBuffer.prototype.toString = function(encoding, start, end) {
  27. encoding = String(encoding || 'utf8').toLowerCase();
  28. // Use native conversion when possible
  29. if (Buffer.isNativeEncoding(encoding))
  30. return original.SlowBufferToString.call(this, encoding, start, end);
  31. // Otherwise, use our decoding method.
  32. if (typeof start == 'undefined') start = 0;
  33. if (typeof end == 'undefined') end = this.length;
  34. return iconv.decode(this.slice(start, end), encoding);
  35. }
  36. original.SlowBufferWrite = SlowBuffer.prototype.write;
  37. SlowBuffer.prototype.write = function(string, offset, length, encoding) {
  38. // Support both (string, offset, length, encoding)
  39. // and the legacy (string, encoding, offset, length)
  40. if (isFinite(offset)) {
  41. if (!isFinite(length)) {
  42. encoding = length;
  43. length = undefined;
  44. }
  45. } else { // legacy
  46. var swap = encoding;
  47. encoding = offset;
  48. offset = length;
  49. length = swap;
  50. }
  51. offset = +offset || 0;
  52. var remaining = this.length - offset;
  53. if (!length) {
  54. length = remaining;
  55. } else {
  56. length = +length;
  57. if (length > remaining) {
  58. length = remaining;
  59. }
  60. }
  61. encoding = String(encoding || 'utf8').toLowerCase();
  62. // Use native conversion when possible
  63. if (Buffer.isNativeEncoding(encoding))
  64. return original.SlowBufferWrite.call(this, string, offset, length, encoding);
  65. if (string.length > 0 && (length < 0 || offset < 0))
  66. throw new RangeError('attempt to write beyond buffer bounds');
  67. // Otherwise, use our encoding method.
  68. var buf = iconv.encode(string, encoding);
  69. if (buf.length < length) length = buf.length;
  70. buf.copy(this, offset, 0, length);
  71. return length;
  72. }
  73. // -- Buffer ---------------------------------------------------------------
  74. original.BufferIsEncoding = Buffer.isEncoding;
  75. Buffer.isEncoding = function(encoding) {
  76. return Buffer.isNativeEncoding(encoding) || iconv.encodingExists(encoding);
  77. }
  78. original.BufferByteLength = Buffer.byteLength;
  79. Buffer.byteLength = SlowBuffer.byteLength = function(str, encoding) {
  80. encoding = String(encoding || 'utf8').toLowerCase();
  81. // Use native conversion when possible
  82. if (Buffer.isNativeEncoding(encoding))
  83. return original.BufferByteLength.call(this, str, encoding);
  84. // Slow, I know, but we don't have a better way yet.
  85. return iconv.encode(str, encoding).length;
  86. }
  87. original.BufferToString = Buffer.prototype.toString;
  88. Buffer.prototype.toString = function(encoding, start, end) {
  89. encoding = String(encoding || 'utf8').toLowerCase();
  90. // Use native conversion when possible
  91. if (Buffer.isNativeEncoding(encoding))
  92. return original.BufferToString.call(this, encoding, start, end);
  93. // Otherwise, use our decoding method.
  94. if (typeof start == 'undefined') start = 0;
  95. if (typeof end == 'undefined') end = this.length;
  96. return iconv.decode(this.slice(start, end), encoding);
  97. }
  98. original.BufferWrite = Buffer.prototype.write;
  99. Buffer.prototype.write = function(string, offset, length, encoding) {
  100. var _offset = offset, _length = length, _encoding = encoding;
  101. // Support both (string, offset, length, encoding)
  102. // and the legacy (string, encoding, offset, length)
  103. if (isFinite(offset)) {
  104. if (!isFinite(length)) {
  105. encoding = length;
  106. length = undefined;
  107. }
  108. } else { // legacy
  109. var swap = encoding;
  110. encoding = offset;
  111. offset = length;
  112. length = swap;
  113. }
  114. encoding = String(encoding || 'utf8').toLowerCase();
  115. // Use native conversion when possible
  116. if (Buffer.isNativeEncoding(encoding))
  117. return original.BufferWrite.call(this, string, _offset, _length, _encoding);
  118. offset = +offset || 0;
  119. var remaining = this.length - offset;
  120. if (!length) {
  121. length = remaining;
  122. } else {
  123. length = +length;
  124. if (length > remaining) {
  125. length = remaining;
  126. }
  127. }
  128. if (string.length > 0 && (length < 0 || offset < 0))
  129. throw new RangeError('attempt to write beyond buffer bounds');
  130. // Otherwise, use our encoding method.
  131. var buf = iconv.encode(string, encoding);
  132. if (buf.length < length) length = buf.length;
  133. buf.copy(this, offset, 0, length);
  134. return length;
  135. // TODO: Set _charsWritten.
  136. }
  137. // -- Readable -------------------------------------------------------------
  138. if (iconv.supportsStreams) {
  139. var Readable = require('stream').Readable;
  140. original.ReadableSetEncoding = Readable.prototype.setEncoding;
  141. Readable.prototype.setEncoding = function setEncoding(enc, options) {
  142. // Use our own decoder, it has the same interface.
  143. // We cannot use original function as it doesn't handle BOM-s.
  144. this._readableState.decoder = iconv.getDecoder(enc, options);
  145. this._readableState.encoding = enc;
  146. }
  147. Readable.prototype.collect = iconv._collect;
  148. }
  149. }
  150. // Remove iconv-lite Node primitive extensions.
  151. iconv.undoExtendNodeEncodings = function undoExtendNodeEncodings() {
  152. if (!iconv.supportsNodeEncodingsExtension)
  153. return;
  154. if (!original)
  155. throw new Error("require('iconv-lite').undoExtendNodeEncodings(): Nothing to undo; extendNodeEncodings() is not called.")
  156. delete Buffer.isNativeEncoding;
  157. var SlowBuffer = require('buffer').SlowBuffer;
  158. SlowBuffer.prototype.toString = original.SlowBufferToString;
  159. SlowBuffer.prototype.write = original.SlowBufferWrite;
  160. Buffer.isEncoding = original.BufferIsEncoding;
  161. Buffer.byteLength = original.BufferByteLength;
  162. Buffer.prototype.toString = original.BufferToString;
  163. Buffer.prototype.write = original.BufferWrite;
  164. if (iconv.supportsStreams) {
  165. var Readable = require('stream').Readable;
  166. Readable.prototype.setEncoding = original.ReadableSetEncoding;
  167. delete Readable.prototype.collect;
  168. }
  169. original = undefined;
  170. }
  171. }