11e81652ec957cd963d564dea9a3a15e8e3a55c1715713db43730188a3665053b0843f9cf22c49b6e8311c8d2bc2a9dac39a655d20060b551a1462b21db19c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import * as strings from '../../../base/common/strings.js';
  6. import * as platform from '../../../base/common/platform.js';
  7. import * as buffer from '../../../base/common/buffer.js';
  8. let _utf16LE_TextDecoder;
  9. function getUTF16LE_TextDecoder() {
  10. if (!_utf16LE_TextDecoder) {
  11. _utf16LE_TextDecoder = new TextDecoder('UTF-16LE');
  12. }
  13. return _utf16LE_TextDecoder;
  14. }
  15. let _utf16BE_TextDecoder;
  16. function getUTF16BE_TextDecoder() {
  17. if (!_utf16BE_TextDecoder) {
  18. _utf16BE_TextDecoder = new TextDecoder('UTF-16BE');
  19. }
  20. return _utf16BE_TextDecoder;
  21. }
  22. let _platformTextDecoder;
  23. export function getPlatformTextDecoder() {
  24. if (!_platformTextDecoder) {
  25. _platformTextDecoder = platform.isLittleEndian() ? getUTF16LE_TextDecoder() : getUTF16BE_TextDecoder();
  26. }
  27. return _platformTextDecoder;
  28. }
  29. export const hasTextDecoder = (typeof TextDecoder !== 'undefined');
  30. export let createStringBuilder;
  31. export let decodeUTF16LE;
  32. if (hasTextDecoder) {
  33. createStringBuilder = (capacity) => new StringBuilder(capacity);
  34. decodeUTF16LE = standardDecodeUTF16LE;
  35. }
  36. else {
  37. createStringBuilder = (capacity) => new CompatStringBuilder();
  38. decodeUTF16LE = compatDecodeUTF16LE;
  39. }
  40. function standardDecodeUTF16LE(source, offset, len) {
  41. const view = new Uint16Array(source.buffer, offset, len);
  42. if (len > 0 && (view[0] === 0xFEFF || view[0] === 0xFFFE)) {
  43. // UTF16 sometimes starts with a BOM https://de.wikipedia.org/wiki/Byte_Order_Mark
  44. // It looks like TextDecoder.decode will eat up a leading BOM (0xFEFF or 0xFFFE)
  45. // We don't want that behavior because we know the string is UTF16LE and the BOM should be maintained
  46. // So we use the manual decoder
  47. return compatDecodeUTF16LE(source, offset, len);
  48. }
  49. return getUTF16LE_TextDecoder().decode(view);
  50. }
  51. function compatDecodeUTF16LE(source, offset, len) {
  52. const result = [];
  53. let resultLen = 0;
  54. for (let i = 0; i < len; i++) {
  55. const charCode = buffer.readUInt16LE(source, offset);
  56. offset += 2;
  57. result[resultLen++] = String.fromCharCode(charCode);
  58. }
  59. return result.join('');
  60. }
  61. class StringBuilder {
  62. constructor(capacity) {
  63. this._capacity = capacity | 0;
  64. this._buffer = new Uint16Array(this._capacity);
  65. this._completedStrings = null;
  66. this._bufferLength = 0;
  67. }
  68. reset() {
  69. this._completedStrings = null;
  70. this._bufferLength = 0;
  71. }
  72. build() {
  73. if (this._completedStrings !== null) {
  74. this._flushBuffer();
  75. return this._completedStrings.join('');
  76. }
  77. return this._buildBuffer();
  78. }
  79. _buildBuffer() {
  80. if (this._bufferLength === 0) {
  81. return '';
  82. }
  83. const view = new Uint16Array(this._buffer.buffer, 0, this._bufferLength);
  84. return getPlatformTextDecoder().decode(view);
  85. }
  86. _flushBuffer() {
  87. const bufferString = this._buildBuffer();
  88. this._bufferLength = 0;
  89. if (this._completedStrings === null) {
  90. this._completedStrings = [bufferString];
  91. }
  92. else {
  93. this._completedStrings[this._completedStrings.length] = bufferString;
  94. }
  95. }
  96. write1(charCode) {
  97. const remainingSpace = this._capacity - this._bufferLength;
  98. if (remainingSpace <= 1) {
  99. if (remainingSpace === 0 || strings.isHighSurrogate(charCode)) {
  100. this._flushBuffer();
  101. }
  102. }
  103. this._buffer[this._bufferLength++] = charCode;
  104. }
  105. appendASCII(charCode) {
  106. if (this._bufferLength === this._capacity) {
  107. // buffer is full
  108. this._flushBuffer();
  109. }
  110. this._buffer[this._bufferLength++] = charCode;
  111. }
  112. appendASCIIString(str) {
  113. const strLen = str.length;
  114. if (this._bufferLength + strLen >= this._capacity) {
  115. // This string does not fit in the remaining buffer space
  116. this._flushBuffer();
  117. this._completedStrings[this._completedStrings.length] = str;
  118. return;
  119. }
  120. for (let i = 0; i < strLen; i++) {
  121. this._buffer[this._bufferLength++] = str.charCodeAt(i);
  122. }
  123. }
  124. }
  125. class CompatStringBuilder {
  126. constructor() {
  127. this._pieces = [];
  128. this._piecesLen = 0;
  129. }
  130. reset() {
  131. this._pieces = [];
  132. this._piecesLen = 0;
  133. }
  134. build() {
  135. return this._pieces.join('');
  136. }
  137. write1(charCode) {
  138. this._pieces[this._piecesLen++] = String.fromCharCode(charCode);
  139. }
  140. appendASCII(charCode) {
  141. this._pieces[this._piecesLen++] = String.fromCharCode(charCode);
  142. }
  143. appendASCIIString(str) {
  144. this._pieces[this._piecesLen++] = str;
  145. }
  146. }