text_decoder_index.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { end_of_stream } from './text_decoder_utils.js'
  2. import { label_to_encoding } from './table.js'
  3. export default class Stream {
  4. /**
  5. * A stream represents an ordered sequence of tokens.
  6. * @param {!(Array.<number>|Uint8Array)} tokens Array of tokens that provide
  7. * the stream.
  8. */
  9. constructor(tokens) {
  10. this.tokens = [...tokens]
  11. // Reversed as push/pop is more efficient than shift/unshift.
  12. this.tokens.reverse()
  13. }
  14. /**
  15. * @returns True if end-of-stream has been hit.
  16. */
  17. endOfStream() {
  18. return !this.tokens.length
  19. }
  20. /**
  21. * When a token is read from a stream, the first token in the
  22. * stream must be returned and subsequently removed, and
  23. * end-of-stream must be returned otherwise.
  24. *
  25. * @return Get the next token from the stream, or end_of_stream.
  26. */
  27. read() {
  28. if (!this.tokens.length)
  29. return end_of_stream
  30. return this.tokens.pop()
  31. }
  32. /**
  33. * When one or more tokens are prepended to a stream, those tokens
  34. * must be inserted, in given order, before the first token in the
  35. * stream.
  36. *
  37. * @param {(number|!Array.<number>)} token The token(s) to prepend to the
  38. * stream.
  39. */
  40. prepend(token) {
  41. if (Array.isArray(token)) {
  42. var tokens = /**@type {!Array.<number>}*/(token)
  43. while (tokens.length)
  44. this.tokens.push(tokens.pop())
  45. } else {
  46. this.tokens.push(token)
  47. }
  48. }
  49. /**
  50. * When one or more tokens are pushed to a stream, those tokens
  51. * must be inserted, in given order, after the last token in the
  52. * stream.
  53. *
  54. * @param {(number|!Array.<number>)} token The tokens(s) to push to the
  55. * stream.
  56. */
  57. push(token) {
  58. if (Array.isArray(token)) {
  59. const tokens = /**@type {!Array.<number>}*/(token)
  60. while (tokens.length)
  61. this.tokens.unshift(tokens.shift())
  62. } else {
  63. this.tokens.unshift(token)
  64. }
  65. }
  66. }
  67. export const DEFAULT_ENCODING = 'utf-8'
  68. /**
  69. * Returns the encoding for the label.
  70. * @param {string} label The encoding label.
  71. */
  72. export function getEncoding(label) {
  73. // 1. Remove any leading and trailing ASCII whitespace from label.
  74. label = String(label).trim().toLowerCase()
  75. // 2. If label is an ASCII case-insensitive match for any of the
  76. // labels listed in the table below, return the corresponding
  77. // encoding, and failure otherwise.
  78. if (Object.prototype.hasOwnProperty.call(label_to_encoding, label)) {
  79. return label_to_encoding[label]
  80. }
  81. return null
  82. }
  83. //
  84. // 5. Encodings
  85. //
  86. // 5.1 Encoders and decoders
  87. // /** @interface */
  88. // function Decoder() {}
  89. // Decoder.prototype = {
  90. // /**
  91. // * @param {Stream} stream The stream of bytes being decoded.
  92. // * @param {number} bite The next byte read from the stream.
  93. // * @return {?(number|!Array.<number>)} The next code point(s)
  94. // * decoded, or null if not enough data exists in the input
  95. // * stream to decode a complete code point, or |finished|.
  96. // */
  97. // handler: function(stream, bite) {},
  98. // }
  99. // /** @interface */
  100. // function Encoder() {}
  101. // Encoder.prototype = {
  102. // /**
  103. // * @param {Stream} stream The stream of code points being encoded.
  104. // * @param {number} code_point Next code point read from the stream.
  105. // * @return {(number|!Array.<number>)} Byte(s) to emit, or |finished|.
  106. // */
  107. // handler: function(stream, code_point) {},
  108. // }