move utf32ToString to TextDecoder.ts
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
import { ParserState, ParserAction, IParsingState, IDcsHandler, IEscapeSequenceParser } from './Types';
|
import { ParserState, ParserAction, IParsingState, IDcsHandler, IEscapeSequenceParser } from './Types';
|
||||||
import { IDisposable } from 'xterm';
|
import { IDisposable } from 'xterm';
|
||||||
import { Disposable } from './common/Lifecycle';
|
import { Disposable } from './common/Lifecycle';
|
||||||
import { utf32ToString } from './common/TypedArrayUtils';
|
import { utf32ToString } from './core/input/TextDecoder';
|
||||||
|
|
||||||
interface IHandlerCollection<T> {
|
interface IHandlerCollection<T> {
|
||||||
[key: string]: T[];
|
[key: string]: T[];
|
||||||
|
|||||||
+2
-2
@@ -14,8 +14,8 @@ import { EscapeSequenceParser } from './EscapeSequenceParser';
|
|||||||
import { ICharset } from './core/Types';
|
import { ICharset } from './core/Types';
|
||||||
import { IDisposable } from 'xterm';
|
import { IDisposable } from 'xterm';
|
||||||
import { Disposable } from './common/Lifecycle';
|
import { Disposable } from './common/Lifecycle';
|
||||||
import { concat, utf32ToString } from './common/TypedArrayUtils';
|
import { concat } from './common/TypedArrayUtils';
|
||||||
import { StringToUtf32, stringFromCodePoint } from './core/input/TextDecoder';
|
import { StringToUtf32, stringFromCodePoint, utf32ToString } from './core/input/TextDecoder';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map collect to glevel. Used in `selectCharset`.
|
* Map collect to glevel. Used in `selectCharset`.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { fillFallback, concat, utf32ToString } from './TypedArrayUtils';
|
import { fillFallback, concat } from './TypedArrayUtils';
|
||||||
|
|
||||||
type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
|
type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
|
||||||
| Int8Array | Int16Array | Int32Array
|
| Int8Array | Int16Array | Int32Array
|
||||||
@@ -94,12 +94,4 @@ describe('typed array convenience functions', () => {
|
|||||||
const merged = concat(a, b);
|
const merged = concat(a, b);
|
||||||
deepEquals(merged, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]));
|
deepEquals(merged, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]));
|
||||||
});
|
});
|
||||||
it('utf16ToString', () => {
|
|
||||||
const s = 'abcdefg';
|
|
||||||
const data = new Uint16Array(s.length);
|
|
||||||
for (let i = 0; i < s.length; ++i) {
|
|
||||||
data[i] = s.charCodeAt(i);
|
|
||||||
}
|
|
||||||
assert.equal(utf32ToString(data), s);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,10 +2,7 @@
|
|||||||
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
import { TypedArray } from './Types';
|
||||||
type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
|
|
||||||
| Int8Array | Int16Array | Int32Array
|
|
||||||
| Float32Array | Float64Array;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* polyfill for TypedArray.fill
|
* polyfill for TypedArray.fill
|
||||||
@@ -49,20 +46,3 @@ export function concat<T extends TypedArray>(a: T, b: T): T {
|
|||||||
result.set(b, a.length);
|
result.set(b, a.length);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert UTF32 char codes into JS string.
|
|
||||||
*/
|
|
||||||
export function utf32ToString<T extends TypedArray>(data: T, start: number = 0, end: number = data.length): string {
|
|
||||||
let result = '';
|
|
||||||
let cp;
|
|
||||||
for (let i = start; i < end; ++i) {
|
|
||||||
if ((cp = data[i]) > 0xFFFF) {
|
|
||||||
cp -= 0x10000;
|
|
||||||
result += String.fromCharCode((cp >> 10) + 0xD800) + String.fromCharCode((cp % 0x400) + 0xDC00);
|
|
||||||
} else {
|
|
||||||
result += String.fromCharCode(cp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -35,3 +35,7 @@ export interface ICircularList<T> extends IEventEmitter {
|
|||||||
trimStart(count: number): void;
|
trimStart(count: number): void;
|
||||||
shiftElements(start: number, count: number, offset: number): void;
|
shiftElements(start: number, count: number, offset: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
|
||||||
|
| Int8Array | Int16Array | Int32Array
|
||||||
|
| Float32Array | Float64Array;
|
||||||
|
|||||||
@@ -4,64 +4,64 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { StringToUtf32, stringFromCodePoint } from './TextDecoder';
|
import { StringToUtf32, stringFromCodePoint, utf32ToString } from './TextDecoder';
|
||||||
|
|
||||||
|
describe('text encodings', () => {
|
||||||
// convert UTF32 codepoints to string
|
it('stringFromCodePoint/utf32ToString', () => {
|
||||||
function toString(data: Uint32Array, length: number): string {
|
const s = 'abcdefg';
|
||||||
if ((String as any).fromCodePoint) {
|
const data = new Uint32Array(s.length);
|
||||||
return (String as any).fromCodePoint.apply(null, data.subarray(0, length));
|
for (let i = 0; i < s.length; ++i) {
|
||||||
}
|
data[i] = s.charCodeAt(i);
|
||||||
let result = '';
|
assert.equal(stringFromCodePoint(data[i]), s[i]);
|
||||||
for (let i = 0; i < length; ++i) {
|
}
|
||||||
result += stringFromCodePoint(data[i]);
|
assert.equal(utf32ToString(data), s);
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('StringToUtf32 Decoder', () => {
|
|
||||||
describe('full codepoint test', () => {
|
|
||||||
it('0..65535', () => {
|
|
||||||
const decoder = new StringToUtf32();
|
|
||||||
const target = new Uint32Array(5);
|
|
||||||
for (let i = 0; i < 65536; ++i) {
|
|
||||||
// skip surrogate pairs
|
|
||||||
if (i >= 0xD800 && i <= 0xDFFF) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const length = decoder.decode(String.fromCharCode(i), target);
|
|
||||||
assert.equal(length, 1);
|
|
||||||
assert.equal(target[0], i);
|
|
||||||
assert.equal(toString(target, length), String.fromCharCode(i));
|
|
||||||
decoder.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it('65536..0x10FFFF (surrogates)', function(): void {
|
|
||||||
this.timeout(20000);
|
|
||||||
const decoder = new StringToUtf32();
|
|
||||||
const target = new Uint32Array(5);
|
|
||||||
for (let i = 65536; i < 0x10FFFF; ++i) {
|
|
||||||
const codePoint = i - 0x10000;
|
|
||||||
const s = String.fromCharCode((codePoint >> 10) + 0xD800) + String.fromCharCode((codePoint % 0x400) + 0xDC00);
|
|
||||||
const length = decoder.decode(s, target);
|
|
||||||
assert.equal(length, 1);
|
|
||||||
assert.equal(target[0], i);
|
|
||||||
assert.equal(toString(target, length), s);
|
|
||||||
decoder.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe('stream handling', () => {
|
|
||||||
it('surrogates mixed advance by 1', () => {
|
describe('StringToUtf32 Decoder', () => {
|
||||||
const decoder = new StringToUtf32();
|
describe('full codepoint test', () => {
|
||||||
const target = new Uint32Array(5);
|
it('0..65535', () => {
|
||||||
const input = 'Ä€𝄞Ö𝄞€Ü𝄞€';
|
const decoder = new StringToUtf32();
|
||||||
let decoded = '';
|
const target = new Uint32Array(5);
|
||||||
for (let i = 0; i < input.length; ++i) {
|
for (let i = 0; i < 65536; ++i) {
|
||||||
const written = decoder.decode(input[i], target);
|
// skip surrogate pairs
|
||||||
decoded += toString(target, written);
|
if (i >= 0xD800 && i <= 0xDFFF) {
|
||||||
}
|
continue;
|
||||||
assert(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€');
|
}
|
||||||
|
const length = decoder.decode(String.fromCharCode(i), target);
|
||||||
|
assert.equal(length, 1);
|
||||||
|
assert.equal(target[0], i);
|
||||||
|
assert.equal(utf32ToString(target, 0, length), String.fromCharCode(i));
|
||||||
|
decoder.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('65536..0x10FFFF (surrogates)', function(): void {
|
||||||
|
this.timeout(20000);
|
||||||
|
const decoder = new StringToUtf32();
|
||||||
|
const target = new Uint32Array(5);
|
||||||
|
for (let i = 65536; i < 0x10FFFF; ++i) {
|
||||||
|
const codePoint = i - 0x10000;
|
||||||
|
const s = String.fromCharCode((codePoint >> 10) + 0xD800) + String.fromCharCode((codePoint % 0x400) + 0xDC00);
|
||||||
|
const length = decoder.decode(s, target);
|
||||||
|
assert.equal(length, 1);
|
||||||
|
assert.equal(target[0], i);
|
||||||
|
assert.equal(utf32ToString(target, 0, length), s);
|
||||||
|
decoder.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('stream handling', () => {
|
||||||
|
it('surrogates mixed advance by 1', () => {
|
||||||
|
const decoder = new StringToUtf32();
|
||||||
|
const target = new Uint32Array(5);
|
||||||
|
const input = 'Ä€𝄞Ö𝄞€Ü𝄞€';
|
||||||
|
let decoded = '';
|
||||||
|
for (let i = 0; i < input.length; ++i) {
|
||||||
|
const written = decoder.decode(input[i], target);
|
||||||
|
decoded += utf32ToString(target, written);
|
||||||
|
}
|
||||||
|
assert(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
import { TypedArray } from '../../common/Types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StringToUtf32 - decodes UTF16 sequences into UTF32 codepoints.
|
* StringToUtf32 - decodes UTF16 sequences into UTF32 codepoints.
|
||||||
@@ -73,15 +74,31 @@ export class StringToUtf32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Polyfill - Convert UTF32 codepoint into JS string.
|
* Convert UTF32 codepoint into JS string.
|
||||||
*/
|
*/
|
||||||
export function stringFromCodePoint(codePoint: number): string {
|
export function stringFromCodePoint(codePoint: number): string {
|
||||||
if ((String as any).fromCodePoint) {
|
|
||||||
return (String as any).fromCodePoint(codePoint);
|
|
||||||
}
|
|
||||||
if (codePoint > 0xFFFF) {
|
if (codePoint > 0xFFFF) {
|
||||||
codePoint -= 0x10000;
|
codePoint -= 0x10000;
|
||||||
return String.fromCharCode((codePoint >> 10) + 0xD800) + String.fromCharCode((codePoint % 0x400) + 0xDC00);
|
return String.fromCharCode((codePoint >> 10) + 0xD800) + String.fromCharCode((codePoint % 0x400) + 0xDC00);
|
||||||
}
|
}
|
||||||
return String.fromCharCode(codePoint);
|
return String.fromCharCode(codePoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert UTF32 char codes into JS string.
|
||||||
|
* Basically the same as `stringFromCodePoint` but for multiple codepoints
|
||||||
|
* in a loop (which is a lot faster).
|
||||||
|
*/
|
||||||
|
export function utf32ToString<T extends TypedArray>(data: T, start: number = 0, end: number = data.length): string {
|
||||||
|
let result = '';
|
||||||
|
let cp;
|
||||||
|
for (let i = start; i < end; ++i) {
|
||||||
|
if ((cp = data[i]) > 0xFFFF) {
|
||||||
|
cp -= 0x10000;
|
||||||
|
result += String.fromCharCode((cp >> 10) + 0xD800) + String.fromCharCode((cp % 0x400) + 0xDC00);
|
||||||
|
} else {
|
||||||
|
result += String.fromCharCode(cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user