TextEncoder.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import { DEFAULT_ENCODING } from "../encoding/defaultEncoding";
  2. import { encoders } from "../encoding/encoding-factory";
  3. import { getEncoding } from "../encoding/encodings";
  4. import { finished } from "../encoding/finished";
  5. import { end_of_stream } from "../encoding/terminology";
  6. import { stringToCodePoints, ToDictionary } from "../encoding/utilities";
  7. import { getGlobalScope } from "../helper/getGlobalScope";
  8. import { Stream } from "./Stream";
  9. /**
  10. * @constructor
  11. * @param {string=} label The label of the encoding. NONSTANDARD.
  12. * @param {Object=} options NONSTANDARD.
  13. */
  14. var TextEncoder = /** @class */ (function () {
  15. function TextEncoder(label, options) {
  16. var optionsMap = ToDictionary(options);
  17. // A TextEncoder object has an associated encoding and encoder.
  18. /** @private */
  19. this._encoding = null;
  20. /** @private @type {?Encoder} */
  21. this._encoder = null;
  22. // Non-standard
  23. /** @private @type {boolean} */
  24. this._do_not_flush = false;
  25. /** @private @type {string} */
  26. this._fatal = Boolean(optionsMap['fatal']) ? 'fatal' : 'replacement';
  27. // 1. Let enc be a new TextEncoder object.
  28. // const enc = this;
  29. // no need to do this as this is a proper class
  30. // now and TSC will handle transpilation to older platforms
  31. // 2. Set enc's encoding to UTF-8's encoder.
  32. if (Boolean(optionsMap['NONSTANDARD_allowLegacyEncoding'])) {
  33. // NONSTANDARD behavior.
  34. label = !!label ? String(label) : DEFAULT_ENCODING;
  35. var encoding = getEncoding(label);
  36. if (encoding === null || encoding.name === 'replacement')
  37. throw RangeError('Unknown encoding: ' + label);
  38. if (!encoders[encoding.name]) {
  39. throw Error('Encoder not present.' +
  40. ' Did you forget to include encoding-indexes.js first?');
  41. }
  42. this._encoding = encoding;
  43. // EXPERIMENTAL_CODE
  44. // } else if (["iso-8859-1", "ISO-8859-1", "latin-1", "latin1", "LATIN-1", "LATIN1"].indexOf(label) !== -1) {
  45. // this._encoding = getEncoding('iso-8859-1');
  46. }
  47. else {
  48. // Standard behavior.
  49. this._encoding = getEncoding('utf-8');
  50. var glo = getGlobalScope() || {};
  51. if (label !== undefined && 'console' in glo) {
  52. console.warn('TextEncoder constructor called with encoding label, '
  53. + 'which is ignored.');
  54. }
  55. }
  56. // For pre-ES5 runtimes:
  57. // if (!Object.defineProperty)
  58. // this.encoding = enc._encoding.name.toLowerCase();
  59. // 3. Return enc.
  60. // return enc;
  61. }
  62. Object.defineProperty(TextEncoder.prototype, "encoding", {
  63. // if(Object.defineProperty) {
  64. // // The encoding attribute's getter must return encoding's name.
  65. // Object.defineProperty(TextEncoder.prototype, 'encoding', {
  66. // /** @this {TextEncoder} */
  67. // get: function () { return this._encoding.name.toLowerCase(); }
  68. // });
  69. // }
  70. get: function () {
  71. return this._encoding.name.toLowerCase();
  72. },
  73. enumerable: true,
  74. configurable: true
  75. });
  76. /**
  77. * @param {string=} opt_string The string to encode.
  78. * @param {Object=} options
  79. * @return {!Uint8Array} Encoded bytes, as a Uint8Array.
  80. */
  81. TextEncoder.prototype.encode = function (opt_string, options) {
  82. opt_string = opt_string === undefined ? '' : String(opt_string);
  83. var optionsMap = ToDictionary(options);
  84. // NOTE: This option is nonstandard. None of the encodings
  85. // permitted for encoding (i.e. UTF-8, UTF-16) are stateful when
  86. // the input is a USVString so streaming is not necessary.
  87. if (!this._do_not_flush)
  88. this._encoder = encoders[this._encoding.name]({
  89. fatal: this._fatal === 'fatal'
  90. });
  91. this._do_not_flush = Boolean(optionsMap['stream']);
  92. // 1. Convert input to a stream.
  93. var input = new Stream(stringToCodePoints(opt_string));
  94. // 2. Let output be a new stream
  95. var output = [];
  96. /** @type {?(number|!Array.<number>)} */
  97. var result;
  98. // 3. While true, run these substeps:
  99. while (true) {
  100. // 1. Let token be the result of reading from input.
  101. var token = input.read();
  102. if (token === end_of_stream)
  103. break;
  104. // 2. Let result be the result of processing token for encoder,
  105. // input, output.
  106. result = this._encoder.handler(input, token);
  107. if (result === finished)
  108. break;
  109. if (Array.isArray(result))
  110. output.push.apply(output, /**@type {!Array.<number>}*/ (result));
  111. else
  112. output.push(result);
  113. }
  114. // TODO: Align with spec algorithm.
  115. if (!this._do_not_flush) {
  116. while (true) {
  117. result = this._encoder.handler(input, input.read());
  118. if (result === finished)
  119. break;
  120. if (Array.isArray(result))
  121. output.push.apply(output, /**@type {!Array.<number>}*/ (result));
  122. else
  123. output.push(result);
  124. }
  125. this._encoder = null;
  126. }
  127. // 3. If result is finished, convert output into a byte sequence,
  128. // and then return a Uint8Array object wrapping an ArrayBuffer
  129. // containing output.
  130. return new Uint8Array(output);
  131. };
  132. return TextEncoder;
  133. }());
  134. export { TextEncoder };
  135. //# sourceMappingURL=TextEncoder.js.map