idlize

Форк
0
214 строк · 7.4 Кб
1
/*
2
 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3
 * Licensed under the Apache License, Version 2.0 (the "License");
4
 * you may not use this file except in compliance with the License.
5
 * You may obtain a copy of the License at
6
 *
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software
10
 * distributed under the License is distributed on an "AS IS" BASIS,
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 * See the License for the specific language governing permissions and
13
 * limitations under the License.
14
 */
15

16
import { int32, uint8 } from "./types"
17
import { Array_from_int32 } from "./array"
18

19

20
interface SystemTextEncoder {
21
    encode(input?: string): Uint8Array;
22
    encodeInto(src: string, dest: Uint8Array): void;
23
}
24

25
interface WithStreamOption {
26
    stream: Boolean | undefined;
27
}
28

29
interface SystemTextDecoder {
30
    decode(
31
        input: ArrayBuffer | null | undefined | Uint8Array,
32
        options: WithStreamOption | undefined
33
    ): string;
34
}
35

36
export class CustomTextEncoder {
37
    static readonly HeaderLen: int32 = Int32Array.BYTES_PER_ELEMENT
38

39
    constructor(encoder:SystemTextEncoder|undefined = undefined) {
40
        this.encoder = encoder
41
    }
42

43
    private readonly encoder: SystemTextEncoder|undefined
44

45
    public static stringLength(input: string): int32 {
46
        let length = 0
47
        for (let i = 0; i < input.length; i++) {
48
            length++
49
            let cp = input.codePointAt(i)
50
            if (cp >= 0x10000) {
51
                i++
52
            }
53
        }
54
        return length
55
    }
56

57
    encodedLength(input: string): int32 {
58
        let length = 0
59
        for (let i = 0; i < input.length; i++) {
60
            let cp = input.codePointAt(i)
61
            if (cp < 0x80) {
62
                length += 1
63
            } else if (cp < 0x800) {
64
                length += 2
65
            } else if (cp < 0x10000) {
66
                length += 3
67
            } else {
68
                length += 4
69
                i++
70
            }
71
        }
72
        return length
73
    }
74

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)
81
    }
82

83
    static getHeaderLength(array: Uint8Array, offset: int32 = 0): int32 {
84
        return (
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)
89
    }
90

91
    // Produces array of bytes with encoded string headed by 4 bytes (little endian) size information:
92
    // [s0][s1][s2][s3] [c_0] ... [c_size-1]
93
    encode(input: string | undefined, addLength: boolean = true): Uint8Array {
94
        let headerLen = addLength ? CustomTextEncoder.HeaderLen : 0
95
        let result: Uint8Array
96
        if (!input) {
97
            result = new Uint8Array(headerLen)
98
        } else if (this.encoder !== undefined) {
99
            result = this.encoder!.encode('s'.repeat(headerLen) + input)
100
        } else {
101
            let length = this.encodedLength(input)
102
            result = new Uint8Array(length + headerLen)
103
            this.encodeInto(input, result, headerLen)
104
        }
105
        if (addLength) {
106
            this.addLength(result, 0, (result.length - headerLen) as int32)
107
        }
108
        return result
109
    }
110

111
    // Produces encoded array of strings with size information.
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])
117
            lengths[i] = len
118
            totalBytes += len + CustomTextEncoder.HeaderLen
119
        }
120
        let array = new Uint8Array(totalBytes)
121
        let position = 0
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]
129
        }
130
        return array
131
    }
132

133
    encodeInto(input: string, result: Uint8Array, position: int32): Uint8Array {
134
        if (this.encoder !== undefined) {
135
            this.encoder!.encodeInto(input, result.subarray(position, result.length))
136
            return result
137
        }
138
        let index = position
139
        for (let stringPosition = 0; stringPosition < input.length; stringPosition++) {
140
            let cp = input.codePointAt(stringPosition) as number
141
            if (cp < 0x80) {
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)
150
            } else {
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)
155
                stringPosition++
156
            }
157
        }
158
        result[index] = 0
159
        return result
160
    }
161
}
162

163
export class CustomTextDecoder {
164
    static cpArrayMaxSize = 128
165
    constructor(decoder: SystemTextDecoder|undefined = undefined) {
166
        this.decoder = decoder
167
    }
168

169
    private readonly decoder: SystemTextDecoder|undefined
170

171
    decode(input: Uint8Array): string {
172
        if (this.decoder !== undefined) {
173
            return this.decoder!.decode(input, undefined)
174
        }
175

176
        const cpSize = Math.min(CustomTextDecoder.cpArrayMaxSize, input.length)
177
        let codePoints = new Int32Array(cpSize)
178
        let cpIndex = 0;
179
        let index = 0
180
        let result = ""
181
        while (index < input.length) {
182
            let elem = input[index] as uint8
183
            let lead = elem & 0xff
184
            let count = 0
185
            let value = 0
186
            if (lead < 0x80) {
187
                count = 1
188
                value = elem
189
            } else if ((lead >> 5) == 0x6) {
190
                value = (((elem << 6) & 0x7ff) + (input[index + 1] & 0x3f)) as int32
191
                count = 2
192
            } else if ((lead >> 4) == 0xe) {
193
                value = (((elem << 12) & 0xffff) + ((input[index + 1] << 6) & 0xfff) +
194
                    (input[index + 2] & 0x3f)) as int32
195
                count = 3
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
199
                count = 4
200
            }
201
            codePoints[cpIndex++] = value
202
            if (cpIndex == cpSize) {
203
                cpIndex = 0
204
                //result += String.fromCodePoint(...codePoints)
205
                result += String.fromCodePoint(...Array_from_int32(codePoints))
206
            }
207
            index += count
208
        }
209
        if (cpIndex > 0) {
210
            result += String.fromCodePoint(...Array_from_int32(codePoints.slice(0, cpIndex)))
211
        }
212
        return result
213
    }
214
}
215

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.