@gjsify/string_decoder 0.3.13 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/esm/index.js +399 -378
  2. package/package.json +4 -4
package/lib/esm/index.js CHANGED
@@ -1,402 +1,423 @@
1
- import { normalizeEncoding, checkEncoding, base64Encode as bytesToBase64 } from "@gjsify/utils";
1
+ import { base64Encode, checkEncoding, normalizeEncoding } from "@gjsify/utils";
2
+
3
+ //#region src/index.ts
2
4
  function normalizeAndValidateEncoding(enc) {
3
- if (enc) checkEncoding(enc);
4
- return normalizeEncoding(enc);
5
+ if (enc) checkEncoding(enc);
6
+ return normalizeEncoding(enc);
5
7
  }
6
- function utf8DecodeMaximalSubpart(bytes, start, end2) {
7
- let result = "";
8
- let i = start;
9
- while (i < end2) {
10
- const b0 = bytes[i];
11
- if (b0 <= 127) {
12
- result += String.fromCharCode(b0);
13
- i++;
14
- continue;
15
- }
16
- if (b0 >= 194 && b0 <= 223) {
17
- if (i + 1 < end2 && bytes[i + 1] >= 128 && bytes[i + 1] <= 191) {
18
- result += String.fromCharCode((b0 & 31) << 6 | bytes[i + 1] & 63);
19
- i += 2;
20
- } else {
21
- result += "\uFFFD";
22
- i++;
23
- }
24
- continue;
25
- }
26
- if (b0 >= 224 && b0 <= 239) {
27
- let lo2, hi2;
28
- if (b0 === 224) {
29
- lo2 = 160;
30
- hi2 = 191;
31
- } else if (b0 === 237) {
32
- lo2 = 128;
33
- hi2 = 159;
34
- } else {
35
- lo2 = 128;
36
- hi2 = 191;
37
- }
38
- if (i + 1 >= end2) {
39
- result += "\uFFFD";
40
- i++;
41
- continue;
42
- }
43
- const b1 = bytes[i + 1];
44
- if (b1 < lo2 || b1 > hi2) {
45
- result += "\uFFFD";
46
- i++;
47
- continue;
48
- }
49
- if (i + 2 >= end2) {
50
- result += "\uFFFD";
51
- i += 2;
52
- continue;
53
- }
54
- const b2 = bytes[i + 2];
55
- if (b2 < 128 || b2 > 191) {
56
- result += "\uFFFD";
57
- i += 2;
58
- continue;
59
- }
60
- const cp = (b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63;
61
- result += String.fromCharCode(cp);
62
- i += 3;
63
- continue;
64
- }
65
- if (b0 >= 240 && b0 <= 244) {
66
- let lo2, hi2;
67
- if (b0 === 240) {
68
- lo2 = 144;
69
- hi2 = 191;
70
- } else if (b0 === 244) {
71
- lo2 = 128;
72
- hi2 = 143;
73
- } else {
74
- lo2 = 128;
75
- hi2 = 191;
76
- }
77
- if (i + 1 >= end2) {
78
- result += "\uFFFD";
79
- i++;
80
- continue;
81
- }
82
- const b1 = bytes[i + 1];
83
- if (b1 < lo2 || b1 > hi2) {
84
- result += "\uFFFD";
85
- i++;
86
- continue;
87
- }
88
- if (i + 2 >= end2) {
89
- result += "\uFFFD";
90
- i += 2;
91
- continue;
92
- }
93
- const b2 = bytes[i + 2];
94
- if (b2 < 128 || b2 > 191) {
95
- result += "\uFFFD";
96
- i += 2;
97
- continue;
98
- }
99
- if (i + 3 >= end2) {
100
- result += "\uFFFD";
101
- i += 3;
102
- continue;
103
- }
104
- const b3 = bytes[i + 3];
105
- if (b3 < 128 || b3 > 191) {
106
- result += "\uFFFD";
107
- i += 3;
108
- continue;
109
- }
110
- const cp = (b0 & 7) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63;
111
- result += String.fromCharCode(
112
- 55296 + (cp - 65536 >> 10),
113
- 56320 + (cp - 65536 & 1023)
114
- );
115
- i += 4;
116
- continue;
117
- }
118
- result += "\uFFFD";
119
- i++;
120
- }
121
- return result;
8
+ /**
9
+ * Decode a complete (non-streaming) chunk of UTF-8 bytes into a string,
10
+ * using the W3C "maximal subpart" replacement algorithm (Unicode 3.9 D93b).
11
+ *
12
+ * This avoids relying on TextDecoder which may produce incorrect replacement
13
+ * counts on older SpiderMonkey versions (e.g., GJS 1.80 / SpiderMonkey 115).
14
+ *
15
+ * Valid UTF-8 byte ranges per position:
16
+ * 1-byte: 00-7F
17
+ * 2-byte: C2-DF, 80-BF
18
+ * 3-byte: E0 A0-BF 80-BF | E1-EC 80-BF 80-BF | ED 80-9F 80-BF | EE-EF 80-BF 80-BF
19
+ * 4-byte: F0 90-BF 80-BF 80-BF | F1-F3 80-BF 80-BF 80-BF | F4 80-8F 80-BF 80-BF
20
+ */
21
+ function utf8DecodeMaximalSubpart(bytes, start, end) {
22
+ let result = "";
23
+ let i = start;
24
+ while (i < end) {
25
+ const b0 = bytes[i];
26
+ if (b0 <= 127) {
27
+ result += String.fromCharCode(b0);
28
+ i++;
29
+ continue;
30
+ }
31
+ if (b0 >= 194 && b0 <= 223) {
32
+ if (i + 1 < end && bytes[i + 1] >= 128 && bytes[i + 1] <= 191) {
33
+ result += String.fromCharCode((b0 & 31) << 6 | bytes[i + 1] & 63);
34
+ i += 2;
35
+ } else {
36
+ result += "�";
37
+ i++;
38
+ }
39
+ continue;
40
+ }
41
+ if (b0 >= 224 && b0 <= 239) {
42
+ let lo2, hi2;
43
+ if (b0 === 224) {
44
+ lo2 = 160;
45
+ hi2 = 191;
46
+ } else if (b0 === 237) {
47
+ lo2 = 128;
48
+ hi2 = 159;
49
+ } else {
50
+ lo2 = 128;
51
+ hi2 = 191;
52
+ }
53
+ if (i + 1 >= end) {
54
+ result += "�";
55
+ i++;
56
+ continue;
57
+ }
58
+ const b1 = bytes[i + 1];
59
+ if (b1 < lo2 || b1 > hi2) {
60
+ result += "�";
61
+ i++;
62
+ continue;
63
+ }
64
+ if (i + 2 >= end) {
65
+ result += "�";
66
+ i += 2;
67
+ continue;
68
+ }
69
+ const b2 = bytes[i + 2];
70
+ if (b2 < 128 || b2 > 191) {
71
+ result += "�";
72
+ i += 2;
73
+ continue;
74
+ }
75
+ const cp = (b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63;
76
+ result += String.fromCharCode(cp);
77
+ i += 3;
78
+ continue;
79
+ }
80
+ if (b0 >= 240 && b0 <= 244) {
81
+ let lo2, hi2;
82
+ if (b0 === 240) {
83
+ lo2 = 144;
84
+ hi2 = 191;
85
+ } else if (b0 === 244) {
86
+ lo2 = 128;
87
+ hi2 = 143;
88
+ } else {
89
+ lo2 = 128;
90
+ hi2 = 191;
91
+ }
92
+ if (i + 1 >= end) {
93
+ result += "�";
94
+ i++;
95
+ continue;
96
+ }
97
+ const b1 = bytes[i + 1];
98
+ if (b1 < lo2 || b1 > hi2) {
99
+ result += "�";
100
+ i++;
101
+ continue;
102
+ }
103
+ if (i + 2 >= end) {
104
+ result += "�";
105
+ i += 2;
106
+ continue;
107
+ }
108
+ const b2 = bytes[i + 2];
109
+ if (b2 < 128 || b2 > 191) {
110
+ result += "�";
111
+ i += 2;
112
+ continue;
113
+ }
114
+ if (i + 3 >= end) {
115
+ result += "�";
116
+ i += 3;
117
+ continue;
118
+ }
119
+ const b3 = bytes[i + 3];
120
+ if (b3 < 128 || b3 > 191) {
121
+ result += "�";
122
+ i += 3;
123
+ continue;
124
+ }
125
+ const cp = (b0 & 7) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63;
126
+ result += String.fromCharCode(55296 + (cp - 65536 >> 10), 56320 + (cp - 65536 & 1023));
127
+ i += 4;
128
+ continue;
129
+ }
130
+ result += "�";
131
+ i++;
132
+ }
133
+ return result;
122
134
  }
135
+ /**
136
+ * Returns the expected total byte length of a UTF-8 character given its first byte,
137
+ * and validates the lead byte is in a valid range.
138
+ * Returns 0 for invalid lead bytes.
139
+ */
123
140
  function utf8CharLength(byte) {
124
- if ((byte & 128) === 0) return 1;
125
- if (byte >= 194 && byte <= 223) return 2;
126
- if (byte >= 224 && byte <= 239) return 3;
127
- if (byte >= 240 && byte <= 244) return 4;
128
- return 0;
141
+ if ((byte & 128) === 0) return 1;
142
+ if (byte >= 194 && byte <= 223) return 2;
143
+ if (byte >= 224 && byte <= 239) return 3;
144
+ if (byte >= 240 && byte <= 244) return 4;
145
+ return 0;
129
146
  }
147
+ /**
148
+ * Check if a continuation byte is valid for its position in a multi-byte sequence.
149
+ * Returns true if the byte is in the expected range for that position.
150
+ */
130
151
  function isValidContinuation(leadByte, charLen, position, byte) {
131
- if (position === 1) {
132
- if (charLen === 3) {
133
- if (leadByte === 224) return byte >= 160 && byte <= 191;
134
- if (leadByte === 237) return byte >= 128 && byte <= 159;
135
- return byte >= 128 && byte <= 191;
136
- }
137
- if (charLen === 4) {
138
- if (leadByte === 240) return byte >= 144 && byte <= 191;
139
- if (leadByte === 244) return byte >= 128 && byte <= 143;
140
- return byte >= 128 && byte <= 191;
141
- }
142
- }
143
- return byte >= 128 && byte <= 191;
152
+ if (position === 1) {
153
+ if (charLen === 3) {
154
+ if (leadByte === 224) return byte >= 160 && byte <= 191;
155
+ if (leadByte === 237) return byte >= 128 && byte <= 159;
156
+ return byte >= 128 && byte <= 191;
157
+ }
158
+ if (charLen === 4) {
159
+ if (leadByte === 240) return byte >= 144 && byte <= 191;
160
+ if (leadByte === 244) return byte >= 128 && byte <= 143;
161
+ return byte >= 128 && byte <= 191;
162
+ }
163
+ }
164
+ return byte >= 128 && byte <= 191;
144
165
  }
145
- const StringDecoder = function StringDecoder2(encoding) {
146
- this.encoding = normalizeAndValidateEncoding(encoding);
147
- this._lastNeed = 0;
148
- this._lastTotal = 0;
149
- this._lastLeadByte = 0;
150
- if (this.encoding === "utf8") {
151
- this._lastChar = new Uint8Array(4);
152
- } else if (this.encoding === "utf16le") {
153
- this._lastChar = new Uint8Array(4);
154
- } else if (this.encoding === "base64") {
155
- this._lastChar = new Uint8Array(3);
156
- } else {
157
- this._lastChar = new Uint8Array(0);
158
- }
166
+ /**
167
+ * StringDecoder provides an interface for efficiently decoding Buffer data
168
+ * into strings while preserving multi-byte characters that are split across
169
+ * Buffer boundaries.
170
+ *
171
+ * Implemented as a function constructor (not ES6 class) for compatibility
172
+ * with legacy CJS patterns that use StringDecoder.call(this, enc).
173
+ */
174
+ const StringDecoder = function StringDecoder(encoding) {
175
+ this.encoding = normalizeAndValidateEncoding(encoding);
176
+ this._lastNeed = 0;
177
+ this._lastTotal = 0;
178
+ this._lastLeadByte = 0;
179
+ if (this.encoding === "utf8") {
180
+ this._lastChar = new Uint8Array(4);
181
+ } else if (this.encoding === "utf16le") {
182
+ this._lastChar = new Uint8Array(4);
183
+ } else if (this.encoding === "base64") {
184
+ this._lastChar = new Uint8Array(3);
185
+ } else {
186
+ this._lastChar = new Uint8Array(0);
187
+ }
159
188
  };
160
189
  StringDecoder.prototype.write = function write(buf) {
161
- if (buf.length === 0) return "";
162
- switch (this.encoding) {
163
- case "utf8":
164
- return writeUtf8(this, buf);
165
- case "utf16le":
166
- return writeUtf16le(this, buf);
167
- case "base64":
168
- return writeBase64(this, buf);
169
- case "ascii":
170
- return decodeAscii(buf);
171
- case "latin1":
172
- return decodeLatin1(buf);
173
- case "hex":
174
- return decodeHex(buf);
175
- default:
176
- return decodeAscii(buf);
177
- }
190
+ if (buf.length === 0) return "";
191
+ switch (this.encoding) {
192
+ case "utf8": return writeUtf8(this, buf);
193
+ case "utf16le": return writeUtf16le(this, buf);
194
+ case "base64": return writeBase64(this, buf);
195
+ case "ascii": return decodeAscii(buf);
196
+ case "latin1": return decodeLatin1(buf);
197
+ case "hex": return decodeHex(buf);
198
+ default: return decodeAscii(buf);
199
+ }
178
200
  };
179
201
  StringDecoder.prototype.end = function end(buf) {
180
- let result = "";
181
- if (buf && buf.length > 0) {
182
- result = this.write(buf);
183
- }
184
- if (this.encoding === "utf8" && this._lastNeed > 0) {
185
- result += "\uFFFD";
186
- this._lastNeed = 0;
187
- this._lastTotal = 0;
188
- } else if (this.encoding === "utf16le" && this._lastNeed > 0) {
189
- const stored = this._lastTotal - this._lastNeed;
190
- for (let i = 0; i + 1 < stored; i += 2) {
191
- result += String.fromCharCode(this._lastChar[i] | this._lastChar[i + 1] << 8);
192
- }
193
- this._lastNeed = 0;
194
- this._lastTotal = 0;
195
- } else if (this.encoding === "base64" && this._lastNeed > 0) {
196
- const remaining = this._lastChar.subarray(0, this._lastTotal - this._lastNeed);
197
- result += bytesToBase64(remaining);
198
- this._lastNeed = 0;
199
- this._lastTotal = 0;
200
- }
201
- return result;
202
+ let result = "";
203
+ if (buf && buf.length > 0) {
204
+ result = this.write(buf);
205
+ }
206
+ if (this.encoding === "utf8" && this._lastNeed > 0) {
207
+ result += "";
208
+ this._lastNeed = 0;
209
+ this._lastTotal = 0;
210
+ } else if (this.encoding === "utf16le" && this._lastNeed > 0) {
211
+ const stored = this._lastTotal - this._lastNeed;
212
+ for (let i = 0; i + 1 < stored; i += 2) {
213
+ result += String.fromCharCode(this._lastChar[i] | this._lastChar[i + 1] << 8);
214
+ }
215
+ this._lastNeed = 0;
216
+ this._lastTotal = 0;
217
+ } else if (this.encoding === "base64" && this._lastNeed > 0) {
218
+ const remaining = this._lastChar.subarray(0, this._lastTotal - this._lastNeed);
219
+ result += base64Encode(remaining);
220
+ this._lastNeed = 0;
221
+ this._lastTotal = 0;
222
+ }
223
+ return result;
202
224
  };
203
225
  function writeUtf8(self, buf) {
204
- let i = 0;
205
- let result = "";
206
- if (self._lastNeed > 0) {
207
- while (i < buf.length && self._lastNeed > 0) {
208
- const byte = buf[i];
209
- const position = self._lastTotal - self._lastNeed;
210
- if (isValidContinuation(self._lastLeadByte, self._lastTotal, position, byte)) {
211
- self._lastChar[position] = byte;
212
- self._lastNeed--;
213
- i++;
214
- } else {
215
- result += "\uFFFD";
216
- self._lastNeed = 0;
217
- self._lastTotal = 0;
218
- self._lastLeadByte = 0;
219
- break;
220
- }
221
- }
222
- if (self._lastNeed === 0 && self._lastTotal > 0) {
223
- result += utf8DecodeMaximalSubpart(self._lastChar, 0, self._lastTotal);
224
- self._lastTotal = 0;
225
- self._lastLeadByte = 0;
226
- }
227
- if (self._lastNeed > 0) {
228
- return result;
229
- }
230
- }
231
- let completeEnd = buf.length;
232
- for (let j = 0; j < Math.min(4, buf.length - i); j++) {
233
- const idx = buf.length - 1 - j;
234
- if (idx < i) break;
235
- const byte = buf[idx];
236
- if ((byte & 192) !== 128) {
237
- const charLen = utf8CharLength(byte);
238
- if (charLen > 0 && byte >= 128) {
239
- const available = buf.length - idx;
240
- if (available < charLen) {
241
- let allValid = true;
242
- for (let k = 1; k < available; k++) {
243
- if (!isValidContinuation(byte, charLen, k, buf[idx + k])) {
244
- allValid = false;
245
- break;
246
- }
247
- }
248
- if (allValid) {
249
- completeEnd = idx;
250
- for (let k = 0; k < available; k++) {
251
- self._lastChar[k] = buf[idx + k];
252
- }
253
- self._lastNeed = charLen - available;
254
- self._lastTotal = charLen;
255
- self._lastLeadByte = byte;
256
- }
257
- }
258
- }
259
- break;
260
- }
261
- }
262
- if (completeEnd > i) {
263
- result += utf8DecodeMaximalSubpart(buf, i, completeEnd);
264
- }
265
- return result;
226
+ let i = 0;
227
+ let result = "";
228
+ if (self._lastNeed > 0) {
229
+ while (i < buf.length && self._lastNeed > 0) {
230
+ const byte = buf[i];
231
+ const position = self._lastTotal - self._lastNeed;
232
+ if (isValidContinuation(self._lastLeadByte, self._lastTotal, position, byte)) {
233
+ self._lastChar[position] = byte;
234
+ self._lastNeed--;
235
+ i++;
236
+ } else {
237
+ result += "";
238
+ self._lastNeed = 0;
239
+ self._lastTotal = 0;
240
+ self._lastLeadByte = 0;
241
+ break;
242
+ }
243
+ }
244
+ if (self._lastNeed === 0 && self._lastTotal > 0) {
245
+ result += utf8DecodeMaximalSubpart(self._lastChar, 0, self._lastTotal);
246
+ self._lastTotal = 0;
247
+ self._lastLeadByte = 0;
248
+ }
249
+ if (self._lastNeed > 0) {
250
+ return result;
251
+ }
252
+ }
253
+ let completeEnd = buf.length;
254
+ for (let j = 0; j < Math.min(4, buf.length - i); j++) {
255
+ const idx = buf.length - 1 - j;
256
+ if (idx < i) break;
257
+ const byte = buf[idx];
258
+ if ((byte & 192) !== 128) {
259
+ const charLen = utf8CharLength(byte);
260
+ if (charLen > 0 && byte >= 128) {
261
+ const available = buf.length - idx;
262
+ if (available < charLen) {
263
+ let allValid = true;
264
+ for (let k = 1; k < available; k++) {
265
+ if (!isValidContinuation(byte, charLen, k, buf[idx + k])) {
266
+ allValid = false;
267
+ break;
268
+ }
269
+ }
270
+ if (allValid) {
271
+ completeEnd = idx;
272
+ for (let k = 0; k < available; k++) {
273
+ self._lastChar[k] = buf[idx + k];
274
+ }
275
+ self._lastNeed = charLen - available;
276
+ self._lastTotal = charLen;
277
+ self._lastLeadByte = byte;
278
+ }
279
+ }
280
+ }
281
+ break;
282
+ }
283
+ }
284
+ if (completeEnd > i) {
285
+ result += utf8DecodeMaximalSubpart(buf, i, completeEnd);
286
+ }
287
+ return result;
266
288
  }
267
289
  function writeUtf16le(self, buf) {
268
- let result = "";
269
- let i = 0;
270
- if (self._lastNeed > 0) {
271
- const offset = self._lastTotal - self._lastNeed;
272
- const needed = Math.min(self._lastNeed, buf.length);
273
- for (let j2 = 0; j2 < needed; j2++) {
274
- self._lastChar[offset + j2] = buf[j2];
275
- }
276
- self._lastNeed -= needed;
277
- i = needed;
278
- if (self._lastNeed > 0) return "";
279
- const stored = self._lastTotal;
280
- let j = 0;
281
- while (j + 1 < stored) {
282
- const code = self._lastChar[j] | self._lastChar[j + 1] << 8;
283
- j += 2;
284
- if (code >= 55296 && code <= 56319) {
285
- if (j + 1 < stored) {
286
- const nextCode = self._lastChar[j] | self._lastChar[j + 1] << 8;
287
- if (nextCode >= 56320 && nextCode <= 57343) {
288
- result += String.fromCharCode(code, nextCode);
289
- j += 2;
290
- continue;
291
- }
292
- }
293
- if (i + 1 < buf.length) {
294
- const nextCode = buf[i] | buf[i + 1] << 8;
295
- if (nextCode >= 56320 && nextCode <= 57343) {
296
- result += String.fromCharCode(code, nextCode);
297
- i += 2;
298
- continue;
299
- }
300
- } else if (i >= buf.length) {
301
- self._lastChar[0] = self._lastChar[j - 2];
302
- self._lastChar[1] = self._lastChar[j - 1];
303
- self._lastNeed = 2;
304
- self._lastTotal = 4;
305
- return result;
306
- }
307
- }
308
- result += String.fromCharCode(code);
309
- }
310
- self._lastTotal = 0;
311
- }
312
- while (i + 1 < buf.length) {
313
- const code = buf[i] | buf[i + 1] << 8;
314
- i += 2;
315
- if (code >= 55296 && code <= 56319) {
316
- if (i + 1 < buf.length) {
317
- const nextCode = buf[i] | buf[i + 1] << 8;
318
- if (nextCode >= 56320 && nextCode <= 57343) {
319
- result += String.fromCharCode(code, nextCode);
320
- i += 2;
321
- continue;
322
- }
323
- } else if (i < buf.length) {
324
- result += String.fromCharCode(code);
325
- self._lastChar[0] = buf[i];
326
- self._lastNeed = 1;
327
- self._lastTotal = 2;
328
- return result;
329
- } else {
330
- self._lastChar[0] = buf[i - 2];
331
- self._lastChar[1] = buf[i - 1];
332
- self._lastNeed = 2;
333
- self._lastTotal = 4;
334
- return result;
335
- }
336
- }
337
- result += String.fromCharCode(code);
338
- }
339
- if (i < buf.length) {
340
- self._lastChar[0] = buf[i];
341
- self._lastNeed = 1;
342
- self._lastTotal = 2;
343
- }
344
- return result;
290
+ let result = "";
291
+ let i = 0;
292
+ if (self._lastNeed > 0) {
293
+ const offset = self._lastTotal - self._lastNeed;
294
+ const needed = Math.min(self._lastNeed, buf.length);
295
+ for (let j = 0; j < needed; j++) {
296
+ self._lastChar[offset + j] = buf[j];
297
+ }
298
+ self._lastNeed -= needed;
299
+ i = needed;
300
+ if (self._lastNeed > 0) return "";
301
+ const stored = self._lastTotal;
302
+ let j = 0;
303
+ while (j + 1 < stored) {
304
+ const code = self._lastChar[j] | self._lastChar[j + 1] << 8;
305
+ j += 2;
306
+ if (code >= 55296 && code <= 56319) {
307
+ if (j + 1 < stored) {
308
+ const nextCode = self._lastChar[j] | self._lastChar[j + 1] << 8;
309
+ if (nextCode >= 56320 && nextCode <= 57343) {
310
+ result += String.fromCharCode(code, nextCode);
311
+ j += 2;
312
+ continue;
313
+ }
314
+ }
315
+ if (i + 1 < buf.length) {
316
+ const nextCode = buf[i] | buf[i + 1] << 8;
317
+ if (nextCode >= 56320 && nextCode <= 57343) {
318
+ result += String.fromCharCode(code, nextCode);
319
+ i += 2;
320
+ continue;
321
+ }
322
+ } else if (i >= buf.length) {
323
+ self._lastChar[0] = self._lastChar[j - 2];
324
+ self._lastChar[1] = self._lastChar[j - 1];
325
+ self._lastNeed = 2;
326
+ self._lastTotal = 4;
327
+ return result;
328
+ }
329
+ }
330
+ result += String.fromCharCode(code);
331
+ }
332
+ self._lastTotal = 0;
333
+ }
334
+ while (i + 1 < buf.length) {
335
+ const code = buf[i] | buf[i + 1] << 8;
336
+ i += 2;
337
+ if (code >= 55296 && code <= 56319) {
338
+ if (i + 1 < buf.length) {
339
+ const nextCode = buf[i] | buf[i + 1] << 8;
340
+ if (nextCode >= 56320 && nextCode <= 57343) {
341
+ result += String.fromCharCode(code, nextCode);
342
+ i += 2;
343
+ continue;
344
+ }
345
+ } else if (i < buf.length) {
346
+ result += String.fromCharCode(code);
347
+ self._lastChar[0] = buf[i];
348
+ self._lastNeed = 1;
349
+ self._lastTotal = 2;
350
+ return result;
351
+ } else {
352
+ self._lastChar[0] = buf[i - 2];
353
+ self._lastChar[1] = buf[i - 1];
354
+ self._lastNeed = 2;
355
+ self._lastTotal = 4;
356
+ return result;
357
+ }
358
+ }
359
+ result += String.fromCharCode(code);
360
+ }
361
+ if (i < buf.length) {
362
+ self._lastChar[0] = buf[i];
363
+ self._lastNeed = 1;
364
+ self._lastTotal = 2;
365
+ }
366
+ return result;
345
367
  }
346
368
  function writeBase64(self, buf) {
347
- let start = 0;
348
- if (self._lastNeed > 0) {
349
- const needed = Math.min(self._lastNeed, buf.length);
350
- for (let i = 0; i < needed; i++) {
351
- self._lastChar[self._lastTotal - self._lastNeed + i] = buf[i];
352
- self._lastNeed--;
353
- }
354
- start = needed;
355
- if (self._lastNeed > 0) return "";
356
- }
357
- const remaining = buf.length - start;
358
- const complete = remaining - remaining % 3;
359
- let result = "";
360
- if (self._lastTotal > 0 && self._lastNeed === 0) {
361
- result += bytesToBase64(self._lastChar.subarray(0, self._lastTotal));
362
- self._lastTotal = 0;
363
- }
364
- if (complete > 0) {
365
- result += bytesToBase64(buf.subarray(start, start + complete));
366
- }
367
- const leftover = remaining - complete;
368
- if (leftover > 0) {
369
- for (let i = 0; i < leftover; i++) {
370
- self._lastChar[i] = buf[start + complete + i];
371
- }
372
- self._lastNeed = 3 - leftover;
373
- self._lastTotal = 3;
374
- }
375
- return result;
369
+ let start = 0;
370
+ if (self._lastNeed > 0) {
371
+ const needed = Math.min(self._lastNeed, buf.length);
372
+ for (let i = 0; i < needed; i++) {
373
+ self._lastChar[self._lastTotal - self._lastNeed + i] = buf[i];
374
+ self._lastNeed--;
375
+ }
376
+ start = needed;
377
+ if (self._lastNeed > 0) return "";
378
+ }
379
+ const remaining = buf.length - start;
380
+ const complete = remaining - remaining % 3;
381
+ let result = "";
382
+ if (self._lastTotal > 0 && self._lastNeed === 0) {
383
+ result += base64Encode(self._lastChar.subarray(0, self._lastTotal));
384
+ self._lastTotal = 0;
385
+ }
386
+ if (complete > 0) {
387
+ result += base64Encode(buf.subarray(start, start + complete));
388
+ }
389
+ const leftover = remaining - complete;
390
+ if (leftover > 0) {
391
+ for (let i = 0; i < leftover; i++) {
392
+ self._lastChar[i] = buf[start + complete + i];
393
+ }
394
+ self._lastNeed = 3 - leftover;
395
+ self._lastTotal = 3;
396
+ }
397
+ return result;
376
398
  }
377
399
  function decodeAscii(buf) {
378
- let result = "";
379
- for (let i = 0; i < buf.length; i++) {
380
- result += String.fromCharCode(buf[i] & 127);
381
- }
382
- return result;
400
+ let result = "";
401
+ for (let i = 0; i < buf.length; i++) {
402
+ result += String.fromCharCode(buf[i] & 127);
403
+ }
404
+ return result;
383
405
  }
384
406
  function decodeLatin1(buf) {
385
- let result = "";
386
- for (let i = 0; i < buf.length; i++) {
387
- result += String.fromCharCode(buf[i]);
388
- }
389
- return result;
407
+ let result = "";
408
+ for (let i = 0; i < buf.length; i++) {
409
+ result += String.fromCharCode(buf[i]);
410
+ }
411
+ return result;
390
412
  }
391
413
  function decodeHex(buf) {
392
- let result = "";
393
- for (let i = 0; i < buf.length; i++) {
394
- result += buf[i].toString(16).padStart(2, "0");
395
- }
396
- return result;
414
+ let result = "";
415
+ for (let i = 0; i < buf.length; i++) {
416
+ result += buf[i].toString(16).padStart(2, "0");
417
+ }
418
+ return result;
397
419
  }
398
- var index_default = { StringDecoder };
399
- export {
400
- StringDecoder,
401
- index_default as default
402
- };
420
+ var src_default = { StringDecoder };
421
+
422
+ //#endregion
423
+ export { StringDecoder, src_default as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/string_decoder",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "Node.js string_decoder module for Gjs",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -30,12 +30,12 @@
30
30
  "string_decoder"
31
31
  ],
32
32
  "devDependencies": {
33
- "@gjsify/cli": "^0.3.13",
34
- "@gjsify/unit": "^0.3.13",
33
+ "@gjsify/cli": "^0.3.15",
34
+ "@gjsify/unit": "^0.3.15",
35
35
  "@types/node": "^25.6.0",
36
36
  "typescript": "^6.0.3"
37
37
  },
38
38
  "dependencies": {
39
- "@gjsify/utils": "^0.3.13"
39
+ "@gjsify/utils": "^0.3.15"
40
40
  }
41
41
  }