index.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. "use strict"
  2. var Buffer = require("safer-buffer").Buffer
  3. var bomHandling = require("./bom-handling")
  4. var mergeModules = require("./helpers/merge-exports")
  5. // All codecs and aliases are kept here, keyed by encoding name/alias.
  6. // They are lazy loaded in `iconv.getCodec` from `encodings/index.js`.
  7. // Cannot initialize with { __proto__: null } because Boolean({ __proto__: null }) === true
  8. module.exports.encodings = null
  9. // Characters emitted in case of error.
  10. module.exports.defaultCharUnicode = "�"
  11. module.exports.defaultCharSingleByte = "?"
  12. // Public API.
  13. module.exports.encode = function encode (str, encoding, options) {
  14. str = "" + (str || "") // Ensure string.
  15. var encoder = module.exports.getEncoder(encoding, options)
  16. var res = encoder.write(str)
  17. var trail = encoder.end()
  18. return (trail && trail.length > 0) ? Buffer.concat([res, trail]) : res
  19. }
  20. module.exports.decode = function decode (buf, encoding, options) {
  21. if (typeof buf === "string") {
  22. if (!module.exports.skipDecodeWarning) {
  23. console.error("Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding")
  24. module.exports.skipDecodeWarning = true
  25. }
  26. buf = Buffer.from("" + (buf || ""), "binary") // Ensure buffer.
  27. }
  28. var decoder = module.exports.getDecoder(encoding, options)
  29. var res = decoder.write(buf)
  30. var trail = decoder.end()
  31. return trail ? (res + trail) : res
  32. }
  33. module.exports.encodingExists = function encodingExists (enc) {
  34. try {
  35. module.exports.getCodec(enc)
  36. return true
  37. } catch (e) {
  38. return false
  39. }
  40. }
  41. // Legacy aliases to convert functions
  42. module.exports.toEncoding = module.exports.encode
  43. module.exports.fromEncoding = module.exports.decode
  44. // Search for a codec in iconv.encodings. Cache codec data in iconv._codecDataCache.
  45. module.exports._codecDataCache = { __proto__: null }
  46. module.exports.getCodec = function getCodec (encoding) {
  47. if (!module.exports.encodings) {
  48. var raw = require("../encodings")
  49. // TODO: In future versions when old nodejs support is removed can use object.assign
  50. module.exports.encodings = { __proto__: null } // Initialize as empty object.
  51. mergeModules(module.exports.encodings, raw)
  52. }
  53. // Canonicalize encoding name: strip all non-alphanumeric chars and appended year.
  54. var enc = module.exports._canonicalizeEncoding(encoding)
  55. // Traverse iconv.encodings to find actual codec.
  56. var codecOptions = {}
  57. while (true) {
  58. var codec = module.exports._codecDataCache[enc]
  59. if (codec) { return codec }
  60. var codecDef = module.exports.encodings[enc]
  61. switch (typeof codecDef) {
  62. case "string": // Direct alias to other encoding.
  63. enc = codecDef
  64. break
  65. case "object": // Alias with options. Can be layered.
  66. for (var key in codecDef) { codecOptions[key] = codecDef[key] }
  67. if (!codecOptions.encodingName) { codecOptions.encodingName = enc }
  68. enc = codecDef.type
  69. break
  70. case "function": // Codec itself.
  71. if (!codecOptions.encodingName) { codecOptions.encodingName = enc }
  72. // The codec function must load all tables and return object with .encoder and .decoder methods.
  73. // It'll be called only once (for each different options object).
  74. //
  75. codec = new codecDef(codecOptions, module.exports)
  76. module.exports._codecDataCache[codecOptions.encodingName] = codec // Save it to be reused later.
  77. return codec
  78. default:
  79. throw new Error("Encoding not recognized: '" + encoding + "' (searched as: '" + enc + "')")
  80. }
  81. }
  82. }
  83. module.exports._canonicalizeEncoding = function (encoding) {
  84. // Canonicalize encoding name: strip all non-alphanumeric chars and appended year.
  85. return ("" + encoding).toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, "")
  86. }
  87. module.exports.getEncoder = function getEncoder (encoding, options) {
  88. var codec = module.exports.getCodec(encoding)
  89. var encoder = new codec.encoder(options, codec)
  90. if (codec.bomAware && options && options.addBOM) { encoder = new bomHandling.PrependBOM(encoder, options) }
  91. return encoder
  92. }
  93. module.exports.getDecoder = function getDecoder (encoding, options) {
  94. var codec = module.exports.getCodec(encoding)
  95. var decoder = new codec.decoder(options, codec)
  96. if (codec.bomAware && !(options && options.stripBOM === false)) { decoder = new bomHandling.StripBOM(decoder, options) }
  97. return decoder
  98. }
  99. // Streaming API
  100. // NOTE: Streaming API naturally depends on 'stream' module from Node.js. Unfortunately in browser environments this module can add
  101. // up to 100Kb to the output bundle. To avoid unnecessary code bloat, we don't enable Streaming API in browser by default.
  102. // If you would like to enable it explicitly, please add the following code to your app:
  103. // > iconv.enableStreamingAPI(require('stream'));
  104. module.exports.enableStreamingAPI = function enableStreamingAPI (streamModule) {
  105. if (module.exports.supportsStreams) { return }
  106. // Dependency-inject stream module to create IconvLite stream classes.
  107. var streams = require("./streams")(streamModule)
  108. // Not public API yet, but expose the stream classes.
  109. module.exports.IconvLiteEncoderStream = streams.IconvLiteEncoderStream
  110. module.exports.IconvLiteDecoderStream = streams.IconvLiteDecoderStream
  111. // Streaming API.
  112. module.exports.encodeStream = function encodeStream (encoding, options) {
  113. return new module.exports.IconvLiteEncoderStream(module.exports.getEncoder(encoding, options), options)
  114. }
  115. module.exports.decodeStream = function decodeStream (encoding, options) {
  116. return new module.exports.IconvLiteDecoderStream(module.exports.getDecoder(encoding, options), options)
  117. }
  118. module.exports.supportsStreams = true
  119. }
  120. // Enable Streaming API automatically if 'stream' module is available and non-empty (the majority of environments).
  121. var streamModule
  122. try {
  123. streamModule = require("stream")
  124. } catch (e) {}
  125. if (streamModule && streamModule.Transform) {
  126. module.exports.enableStreamingAPI(streamModule)
  127. } else {
  128. // In rare cases where 'stream' module is not available by default, throw a helpful exception.
  129. module.exports.encodeStream = module.exports.decodeStream = function () {
  130. throw new Error("iconv-lite Streaming API is not enabled. Use iconv.enableStreamingAPI(require('stream')); to enable it.")
  131. }
  132. }
  133. // Some environments, such as browsers, may not load JavaScript files as UTF-8
  134. // eslint-disable-next-line no-constant-condition
  135. if ("Ā" !== "\u0100") {
  136. console.error("iconv-lite warning: js files use non-utf8 encoding. See https://github.com/ashtuchkin/iconv-lite/wiki/Javascript-source-file-encodings for more info.")
  137. }