16
import { int32, uint8 } from "./types"
17
import { Array_from_int32 } from "./array"
20
interface SystemTextEncoder {
21
encode(input?: string): Uint8Array;
22
encodeInto(src: string, dest: Uint8Array): void;
25
interface WithStreamOption {
26
stream: Boolean | undefined;
29
interface SystemTextDecoder {
31
input: ArrayBuffer | null | undefined | Uint8Array,
32
options: WithStreamOption | undefined
36
export class CustomTextEncoder {
37
static readonly HeaderLen: int32 = Int32Array.BYTES_PER_ELEMENT
39
constructor(encoder:SystemTextEncoder|undefined = undefined) {
40
this.encoder = encoder
43
private readonly encoder: SystemTextEncoder|undefined
45
public static stringLength(input: string): int32 {
47
for (let i = 0; i < input.length; i++) {
49
let cp = input.codePointAt(i)
57
encodedLength(input: string): int32 {
59
for (let i = 0; i < input.length; i++) {
60
let cp = input.codePointAt(i)
63
} else if (cp < 0x800) {
65
} else if (cp < 0x10000) {
75
private addLength(array: Uint8Array, offset: int32, length: int32 | number): void {
76
const len = length as int32
77
array.set(offset, len & 0xff)
78
array.set(offset + 1, (len >> 8) & 0xff)
79
array.set(offset + 2, (len >> 16) & 0xff)
80
array.set(offset + 3, (len >> 24) & 0xff)
83
static getHeaderLength(array: Uint8Array, offset: int32 = 0): int32 {
85
(array.at(offset) as int32) |
86
(array.at(((offset + 1) << 8)) as int32) |
87
(array.at((offset + 2) << 16) as int32) |
88
(array.at((offset + 3) << 24)) as int32)
93
encode(input: string | undefined, addLength: boolean = true): Uint8Array {
94
let headerLen = addLength ? CustomTextEncoder.HeaderLen : 0
95
let result: Uint8Array
97
result = new Uint8Array(headerLen)
98
} else if (this.encoder !== undefined) {
99
result = this.encoder!.encode('s'.repeat(headerLen) + input)
101
let length = this.encodedLength(input)
102
result = new Uint8Array(length + headerLen)
103
this.encodeInto(input, result, headerLen)
106
this.addLength(result, 0, (result.length - headerLen) as int32)
112
encodeArray(strings: Array<string>): Uint8Array {
113
let totalBytes = CustomTextEncoder.HeaderLen
114
let lengths = new Int32Array(strings.length)
115
for (let i = 0; i < lengths.length; i++) {
116
let len = this.encodedLength(strings[i])
118
totalBytes += len + CustomTextEncoder.HeaderLen
120
let array = new Uint8Array(totalBytes)
122
this.addLength(array, position, lengths.length as int32)
123
position += CustomTextEncoder.HeaderLen
124
for (let i = 0; i < lengths.length; i++) {
125
this.addLength(array, position, lengths[i] as int32)
126
position += CustomTextEncoder.HeaderLen
127
this.encodeInto(strings[i], array, position)
128
position += lengths[i]
133
encodeInto(input: string, result: Uint8Array, position: int32): Uint8Array {
134
if (this.encoder !== undefined) {
135
this.encoder!.encodeInto(input, result.subarray(position, result.length))
139
for (let stringPosition = 0; stringPosition < input.length; stringPosition++) {
140
let cp = input.codePointAt(stringPosition) as number
142
result[index++] = (cp | 0)
143
} else if (cp < 0x800) {
144
result[index++] = ((cp >> 6) | 0xc0)
145
result[index++] = ((cp & 0x3f) | 0x80)
146
} else if (cp < 0x10000) {
147
result[index++] = ((cp >> 12) | 0xe0)
148
result[index++] = (((cp >> 6) & 0x3f) | 0x80)
149
result[index++] = ((cp & 0x3f) | 0x80)
151
result[index++] = ((cp >> 18) | 0xf0)
152
result[index++] = (((cp >> 12) & 0x3f) | 0x80)
153
result[index++] = (((cp >> 6) & 0x3f) | 0x80)
154
result[index++] = ((cp & 0x3f) | 0x80)
163
export class CustomTextDecoder {
164
static cpArrayMaxSize = 128
165
constructor(decoder: SystemTextDecoder|undefined = undefined) {
166
this.decoder = decoder
169
private readonly decoder: SystemTextDecoder|undefined
171
decode(input: Uint8Array): string {
172
if (this.decoder !== undefined) {
173
return this.decoder!.decode(input, undefined)
176
const cpSize = Math.min(CustomTextDecoder.cpArrayMaxSize, input.length)
177
let codePoints = new Int32Array(cpSize)
181
while (index < input.length) {
182
let elem = input[index] as uint8
183
let lead = elem & 0xff
189
} else if ((lead >> 5) == 0x6) {
190
value = (((elem << 6) & 0x7ff) + (input[index + 1] & 0x3f)) as int32
192
} else if ((lead >> 4) == 0xe) {
193
value = (((elem << 12) & 0xffff) + ((input[index + 1] << 6) & 0xfff) +
194
(input[index + 2] & 0x3f)) as int32
196
} else if ((lead >> 3) == 0x1e) {
197
value = (((elem << 18) & 0x1fffff) + ((input[index + 1] << 12) & 0x3ffff) +
198
((input[index + 2] << 6) & 0xfff) + (input[index + 3] & 0x3f)) as int32
201
codePoints[cpIndex++] = value
202
if (cpIndex == cpSize) {
205
result += String.fromCodePoint(...Array_from_int32(codePoints))
210
result += String.fromCodePoint(...Array_from_int32(codePoints.slice(0, cpIndex)))