extend-node.js 8.4 KB

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