extend-node.js 7.7 KB

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