Houjie
2025-07-24 52a3ff1bce1417b39f6872d8e8cb378e9c2ccc6f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
import { decoderError } from "../../encoding/encodings";
import { finished } from "../../encoding/finished";
import { index, indexCodePointFor } from "../../encoding/indexes";
import { end_of_stream } from "../../encoding/terminology";
import { inRange } from "../../encoding/utilities";
var states;
(function (states) {
    states[states["ASCII"] = 0] = "ASCII";
    states[states["Roman"] = 1] = "Roman";
    states[states["Katakana"] = 2] = "Katakana";
    states[states["LeadByte"] = 3] = "LeadByte";
    states[states["TrailByte"] = 4] = "TrailByte";
    states[states["EscapeStart"] = 5] = "EscapeStart";
    states[states["Escape"] = 6] = "Escape";
})(states || (states = {}));
export class ISO2022JPDecoder {
    /**
     * @constructor
     * @implements {Decoder}
     * @param {{fatal: boolean}} options
     */
    constructor(options) {
        this.fatal = options.fatal;
        // iso-2022-jp's decoder has an associated iso-2022-jp decoder
        // state (initially ASCII), iso-2022-jp decoder output state
        // (initially ASCII), iso-2022-jp lead (initially 0x00), and
        // iso-2022-jp output flag (initially unset).
        /** @type {number} */ this.iso2022jp_decoder_state = states.ASCII,
            /** @type {number} */ this.iso2022jp_decoder_output_state = states.ASCII,
            /** @type {number} */ this.iso2022jp_lead = 0x00,
            /** @type {boolean} */ this.iso2022jp_output_flag = false;
    }
    /**
     * @param {Stream} stream The stream of bytes being decoded.
     * @param {number} bite The next byte read from the stream.
     * @return {?(number|!Array.<number>)} The next code point(s)
     *     decoded, or null if not enough data exists in the input
     *     stream to decode a complete code point.
     */
    handler(stream, bite) {
        // switching on iso-2022-jp decoder state:
        switch (this.iso2022jp_decoder_state) {
            default:
            case states.ASCII:
                // ASCII
                // Based on byte:
                // 0x1B
                if (bite === 0x1B) {
                    // Set iso-2022-jp decoder state to escape start and return
                    // continue.
                    this.iso2022jp_decoder_state = states.EscapeStart;
                    return null;
                }
                // 0x00 to 0x7F, excluding 0x0E, 0x0F, and 0x1B
                if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E
                    && bite !== 0x0F && bite !== 0x1B) {
                    // Unset the iso-2022-jp output flag and return a code point
                    // whose value is byte.
                    this.iso2022jp_output_flag = false;
                    return bite;
                }
                // end-of-stream
                if (bite === end_of_stream) {
                    // Return finished.
                    return finished;
                }
                // Otherwise
                // Unset the iso-2022-jp output flag and return error.
                this.iso2022jp_output_flag = false;
                return decoderError(this.fatal);
            case states.Roman:
                // Roman
                // Based on byte:
                // 0x1B
                if (bite === 0x1B) {
                    // Set iso-2022-jp decoder state to escape start and return
                    // continue.
                    this.iso2022jp_decoder_state = states.EscapeStart;
                    return null;
                }
                // 0x5C
                if (bite === 0x5C) {
                    // Unset the iso-2022-jp output flag and return code point
                    // U+00A5.
                    this.iso2022jp_output_flag = false;
                    return 0x00A5;
                }
                // 0x7E
                if (bite === 0x7E) {
                    // Unset the iso-2022-jp output flag and return code point
                    // U+203E.
                    this.iso2022jp_output_flag = false;
                    return 0x203E;
                }
                // 0x00 to 0x7F, excluding 0x0E, 0x0F, 0x1B, 0x5C, and 0x7E
                if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E && bite !== 0x0F
                    && bite !== 0x1B && bite !== 0x5C && bite !== 0x7E) {
                    // Unset the iso-2022-jp output flag and return a code point
                    // whose value is byte.
                    this.iso2022jp_output_flag = false;
                    return bite;
                }
                // end-of-stream
                if (bite === end_of_stream) {
                    // Return finished.
                    return finished;
                }
                // Otherwise
                // Unset the iso-2022-jp output flag and return error.
                this.iso2022jp_output_flag = false;
                return decoderError(this.fatal);
            case states.Katakana:
                // Katakana
                // Based on byte:
                // 0x1B
                if (bite === 0x1B) {
                    // Set iso-2022-jp decoder state to escape start and return
                    // continue.
                    this.iso2022jp_decoder_state = states.EscapeStart;
                    return null;
                }
                // 0x21 to 0x5F
                if (inRange(bite, 0x21, 0x5F)) {
                    // Unset the iso-2022-jp output flag and return a code point
                    // whose value is 0xFF61 − 0x21 + byte.
                    this.iso2022jp_output_flag = false;
                    return 0xFF61 - 0x21 + bite;
                }
                // end-of-stream
                if (bite === end_of_stream) {
                    // Return finished.
                    return finished;
                }
                // Otherwise
                // Unset the iso-2022-jp output flag and return error.
                this.iso2022jp_output_flag = false;
                return decoderError(this.fatal);
            case states.LeadByte:
                // Lead byte
                // Based on byte:
                // 0x1B
                if (bite === 0x1B) {
                    // Set iso-2022-jp decoder state to escape start and return
                    // continue.
                    this.iso2022jp_decoder_state = states.EscapeStart;
                    return null;
                }
                // 0x21 to 0x7E
                if (inRange(bite, 0x21, 0x7E)) {
                    // Unset the iso-2022-jp output flag, set iso-2022-jp lead
                    // to byte, iso-2022-jp decoder state to trail byte, and
                    // return continue.
                    this.iso2022jp_output_flag = false;
                    this.iso2022jp_lead = bite;
                    this.iso2022jp_decoder_state = states.TrailByte;
                    return null;
                }
                // end-of-stream
                if (bite === end_of_stream) {
                    // Return finished.
                    return finished;
                }
                // Otherwise
                // Unset the iso-2022-jp output flag and return error.
                this.iso2022jp_output_flag = false;
                return decoderError(this.fatal);
            case states.TrailByte:
                // Trail byte
                // Based on byte:
                // 0x1B
                if (bite === 0x1B) {
                    // Set iso-2022-jp decoder state to escape start and return
                    // continue.
                    this.iso2022jp_decoder_state = states.EscapeStart;
                    return decoderError(this.fatal);
                }
                // 0x21 to 0x7E
                if (inRange(bite, 0x21, 0x7E)) {
                    // 1. Set the iso-2022-jp decoder state to lead byte.
                    this.iso2022jp_decoder_state = states.LeadByte;
                    // 2. Let pointer be (iso-2022-jp lead − 0x21) × 94 + byte − 0x21.
                    const pointer = (this.iso2022jp_lead - 0x21) * 94 + bite - 0x21;
                    // 3. Let code point be the index code point for pointer in
                    // index jis0208.
                    const code_point = indexCodePointFor(pointer, index('jis0208'));
                    // 4. If code point is null, return error.
                    if (code_point === null)
                        return decoderError(this.fatal);
                    // 5. Return a code point whose value is code point.
                    return code_point;
                }
                // end-of-stream
                if (bite === end_of_stream) {
                    // Set the iso-2022-jp decoder state to lead byte, prepend
                    // byte to stream, and return error.
                    this.iso2022jp_decoder_state = states.LeadByte;
                    stream.prepend(bite);
                    return decoderError(this.fatal);
                }
                // Otherwise
                // Set iso-2022-jp decoder state to lead byte and return
                // error.
                this.iso2022jp_decoder_state = states.LeadByte;
                return decoderError(this.fatal);
            case states.EscapeStart:
                // Escape start
                // 1. If byte is either 0x24 or 0x28, set iso-2022-jp lead to
                // byte, iso-2022-jp decoder state to escape, and return
                // continue.
                if (bite === 0x24 || bite === 0x28) {
                    this.iso2022jp_lead = bite;
                    this.iso2022jp_decoder_state = states.Escape;
                    return null;
                }
                // 2. Prepend byte to stream.
                stream.prepend(bite);
                // 3. Unset the iso-2022-jp output flag, set iso-2022-jp
                // decoder state to iso-2022-jp decoder output state, and
                // return error.
                this.iso2022jp_output_flag = false;
                this.iso2022jp_decoder_state = this.iso2022jp_decoder_output_state;
                return decoderError(this.fatal);
            case states.Escape:
                // Escape
                // 1. Let lead be iso-2022-jp lead and set iso-2022-jp lead to
                // 0x00.
                const lead = this.iso2022jp_lead;
                this.iso2022jp_lead = 0x00;
                // 2. Let state be null.
                let state = null;
                // 3. If lead is 0x28 and byte is 0x42, set state to ASCII.
                if (lead === 0x28 && bite === 0x42)
                    state = states.ASCII;
                // 4. If lead is 0x28 and byte is 0x4A, set state to Roman.
                if (lead === 0x28 && bite === 0x4A)
                    state = states.Roman;
                // 5. If lead is 0x28 and byte is 0x49, set state to Katakana.
                if (lead === 0x28 && bite === 0x49)
                    state = states.Katakana;
                // 6. If lead is 0x24 and byte is either 0x40 or 0x42, set
                // state to lead byte.
                if (lead === 0x24 && (bite === 0x40 || bite === 0x42))
                    state = states.LeadByte;
                // 7. If state is non-null, run these substeps:
                if (state !== null) {
                    // 1. Set iso-2022-jp decoder state and iso-2022-jp decoder
                    // output state to states.
                    this.iso2022jp_decoder_state = this.iso2022jp_decoder_state = state;
                    // 2. Let output flag be the iso-2022-jp output flag.
                    const output_flag = this.iso2022jp_output_flag;
                    // 3. Set the iso-2022-jp output flag.
                    this.iso2022jp_output_flag = true;
                    // 4. Return continue, if output flag is unset, and error
                    // otherwise.
                    return !output_flag ? null : decoderError(this.fatal);
                }
                // 8. Prepend lead and byte to stream.
                stream.prepend([lead, bite]);
                // 9. Unset the iso-2022-jp output flag, set iso-2022-jp
                // decoder state to iso-2022-jp decoder output state and
                // return error.
                this.iso2022jp_output_flag = false;
                this.iso2022jp_decoder_state = this.iso2022jp_decoder_output_state;
                return decoderError(this.fatal);
        }
    }
}
//# sourceMappingURL=ISO2022JPDecoder.js.map