whatwg-encoding.js 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. "use strict";
  2. const iconvLite = require("iconv-lite");
  3. const supportedNames = require("./supported-names.json");
  4. const labelsToNames = require("./labels-to-names.json");
  5. const supportedNamesSet = new Set(supportedNames);
  6. // https://encoding.spec.whatwg.org/#concept-encoding-get
  7. exports.labelToName = label => {
  8. label = String(label).trim().toLowerCase();
  9. return labelsToNames[label] || null;
  10. };
  11. // https://encoding.spec.whatwg.org/#decode
  12. exports.decode = (uint8Array, fallbackEncodingName) => {
  13. let encoding = fallbackEncodingName;
  14. if (!exports.isSupported(encoding)) {
  15. throw new RangeError(`"${encoding}" is not a supported encoding name`);
  16. }
  17. const bomEncoding = exports.getBOMEncoding(uint8Array);
  18. if (bomEncoding !== null) {
  19. encoding = bomEncoding;
  20. // iconv-lite will strip BOMs for us, so no need to do the extra byte removal that the spec does.
  21. // Note that we won't end up in the x-user-defined case when there's a bomEncoding.
  22. }
  23. if (encoding === "x-user-defined") {
  24. // https://encoding.spec.whatwg.org/#x-user-defined-decoder
  25. let result = "";
  26. for (const byte of uint8Array) {
  27. if (byte <= 0x7F) {
  28. result += String.fromCodePoint(byte);
  29. } else {
  30. result += String.fromCodePoint(0xF780 + byte - 0x80);
  31. }
  32. }
  33. return result;
  34. }
  35. return iconvLite.decode(uint8Array, encoding);
  36. };
  37. // https://github.com/whatwg/html/issues/1910#issuecomment-254017369
  38. exports.getBOMEncoding = uint8Array => {
  39. if (uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) {
  40. return "UTF-16BE";
  41. } else if (uint8Array[0] === 0xFF && uint8Array[1] === 0xFE) {
  42. return "UTF-16LE";
  43. } else if (uint8Array[0] === 0xEF && uint8Array[1] === 0xBB && uint8Array[2] === 0xBF) {
  44. return "UTF-8";
  45. }
  46. return null;
  47. };
  48. exports.isSupported = name => {
  49. return supportedNamesSet.has(String(name));
  50. };