Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
utf32.js308 linesDownload Raw Back to encodings
1"use strict"
2
3var Buffer = require("safer-buffer").Buffer
4
5// == UTF32-LE/BE codec. ==========================================================
6
7exports._utf32 = Utf32Codec
8
9function Utf32Codec (codecOptions, iconv) {
10  this.iconv = iconv
11  this.bomAware = true
12  this.isLE = codecOptions.isLE
13}
14
15exports.utf32le = { type: "_utf32", isLE: true }
16exports.utf32be = { type: "_utf32", isLE: false }
17
18// Aliases
19exports.ucs4le = "utf32le"
20exports.ucs4be = "utf32be"
21
22Utf32Codec.prototype.encoder = Utf32Encoder
23Utf32Codec.prototype.decoder = Utf32Decoder
24
25// -- Encoding
26
27function Utf32Encoder (options, codec) {
28  this.isLE = codec.isLE
29  this.highSurrogate = 0
30}
31
32Utf32Encoder.prototype.write = function (str) {
33  var src = Buffer.from(str, "ucs2")
34  var dst = Buffer.alloc(src.length * 2)
35  var write32 = this.isLE ? dst.writeUInt32LE : dst.writeUInt32BE
36  var offset = 0
37
38  for (var i = 0; i < src.length; i += 2) {
39    var code = src.readUInt16LE(i)
40    var isHighSurrogate = (code >= 0xD800 && code < 0xDC00)
41    var isLowSurrogate = (code >= 0xDC00 && code < 0xE000)
42
43    if (this.highSurrogate) {
44      if (isHighSurrogate || !isLowSurrogate) {
45        // There shouldn't be two high surrogates in a row, nor a high surrogate which isn't followed by a low
46        // surrogate. If this happens, keep the pending high surrogate as a stand-alone semi-invalid character
47        // (technically wrong, but expected by some applications, like Windows file names).
48        write32.call(dst, this.highSurrogate, offset)
49        offset += 4
50      } else {
51        // Create 32-bit value from high and low surrogates;
52        var codepoint = (((this.highSurrogate - 0xD800) << 10) | (code - 0xDC00)) + 0x10000
53
54        write32.call(dst, codepoint, offset)
55        offset += 4
56        this.highSurrogate = 0
57
58        continue
59      }
60    }
61
62    if (isHighSurrogate) { this.highSurrogate = code } else {
63      // Even if the current character is a low surrogate, with no previous high surrogate, we'll
64      // encode it as a semi-invalid stand-alone character for the same reasons expressed above for
65      // unpaired high surrogates.
66      write32.call(dst, code, offset)
67      offset += 4
68      this.highSurrogate = 0
69    }
70  }
71
72  if (offset < dst.length) { dst = dst.slice(0, offset) }
73
74  return dst
75}
76
77Utf32Encoder.prototype.end = function () {
78  // Treat any leftover high surrogate as a semi-valid independent character.
79  if (!this.highSurrogate) { return }
80
81  var buf = Buffer.alloc(4)
82
83  if (this.isLE) { buf.writeUInt32LE(this.highSurrogate, 0) } else { buf.writeUInt32BE(this.highSurrogate, 0) }
84
85  this.highSurrogate = 0
86
87  return buf
88}
89
90// -- Decoding
91
92function Utf32Decoder (options, codec) {
93  this.isLE = codec.isLE
94  this.badChar = codec.iconv.defaultCharUnicode.charCodeAt(0)
95  this.overflow = []
96}
97
98Utf32Decoder.prototype.write = function (src) {
99  if (src.length === 0) { return "" }
100
101  var i = 0
102  var codepoint = 0
103  var dst = Buffer.alloc(src.length + 4)
104  var offset = 0
105  var isLE = this.isLE
106  var overflow = this.overflow
107  var badChar = this.badChar
108
109  if (overflow.length > 0) {
110    for (; i < src.length && overflow.length < 4; i++) { overflow.push(src[i]) }
111
112    if (overflow.length === 4) {
113      // NOTE: codepoint is a signed int32 and can be negative.
114      // NOTE: We copied this block from below to help V8 optimize it (it works with array, not buffer).
115      if (isLE) {
116        codepoint = overflow[i] | (overflow[i + 1] << 8) | (overflow[i + 2] << 16) | (overflow[i + 3] << 24)
117      } else {
118        codepoint = overflow[i + 3] | (overflow[i + 2] << 8) | (overflow[i + 1] << 16) | (overflow[i] << 24)
119      }
120      overflow.length = 0
121
122      offset = _writeCodepoint(dst, offset, codepoint, badChar)
123    }
124  }
125
126  // Main loop. Should be as optimized as possible.
127  for (; i < src.length - 3; i += 4) {
128    // NOTE: codepoint is a signed int32 and can be negative.
129    if (isLE) {
130      codepoint = src[i] | (src[i + 1] << 8) | (src[i + 2] << 16) | (src[i + 3] << 24)
131    } else {
132      codepoint = src[i + 3] | (src[i + 2] << 8) | (src[i + 1] << 16) | (src[i] << 24)
133    }
134    offset = _writeCodepoint(dst, offset, codepoint, badChar)
135  }
136
137  // Keep overflowing bytes.
138  for (; i < src.length; i++) {
139    overflow.push(src[i])
140  }
141
142  return dst.slice(0, offset).toString("ucs2")
143}
144
145function _writeCodepoint (dst, offset, codepoint, badChar) {
146  // NOTE: codepoint is signed int32 and can be negative. We keep it that way to help V8 with optimizations.
147  if (codepoint < 0 || codepoint > 0x10FFFF) {
148    // Not a valid Unicode codepoint
149    codepoint = badChar
150  }
151
152  // Ephemeral Planes: Write high surrogate.
153  if (codepoint >= 0x10000) {
154    codepoint -= 0x10000
155
156    var high = 0xD800 | (codepoint >> 10)
157    dst[offset++] = high & 0xff
158    dst[offset++] = high >> 8
159
160    // Low surrogate is written below.
161    var codepoint = 0xDC00 | (codepoint & 0x3FF)
162  }
163
164  // Write BMP char or low surrogate.
165  dst[offset++] = codepoint & 0xff
166  dst[offset++] = codepoint >> 8
167
168  return offset
169};
170
171Utf32Decoder.prototype.end = function () {
172  this.overflow.length = 0
173}
174
175// == UTF-32 Auto codec =============================================================
176// Decoder chooses automatically from UTF-32LE and UTF-32BE using BOM and space-based heuristic.
177// Defaults to UTF-32LE. http://en.wikipedia.org/wiki/UTF-32
178// Encoder/decoder default can be changed: iconv.decode(buf, 'utf32', {defaultEncoding: 'utf-32be'});
179
180// Encoder prepends BOM (which can be overridden with (addBOM: false}).
181
182exports.utf32 = Utf32AutoCodec
183exports.ucs4 = "utf32"
184
185function Utf32AutoCodec (options, iconv) {
186  this.iconv = iconv
187}
188
189Utf32AutoCodec.prototype.encoder = Utf32AutoEncoder
190Utf32AutoCodec.prototype.decoder = Utf32AutoDecoder
191
192// -- Encoding
193
194function Utf32AutoEncoder (options, codec) {
195  options = options || {}
196
197  if (options.addBOM === undefined) {
198    options.addBOM = true
199  }
200
201  this.encoder = codec.iconv.getEncoder(options.defaultEncoding || "utf-32le", options)
202}
203
204Utf32AutoEncoder.prototype.write = function (str) {
205  return this.encoder.write(str)
206}
207
208Utf32AutoEncoder.prototype.end = function () {
209  return this.encoder.end()
210}
211
212// -- Decoding
213
214function Utf32AutoDecoder (options, codec) {
215  this.decoder = null
216  this.initialBufs = []
217  this.initialBufsLen = 0
218  this.options = options || {}
219  this.iconv = codec.iconv
220}
221
222Utf32AutoDecoder.prototype.write = function (buf) {
223  if (!this.decoder) {
224    // Codec is not chosen yet. Accumulate initial bytes.
225    this.initialBufs.push(buf)
226    this.initialBufsLen += buf.length
227
228    if (this.initialBufsLen < 32) // We need more bytes to use space heuristic (see below)
229    { return "" }
230
231    // We have enough bytes -> detect endianness.
232    var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding)
233    this.decoder = this.iconv.getDecoder(encoding, this.options)
234
235    var resStr = ""
236    for (var i = 0; i < this.initialBufs.length; i++) { resStr += this.decoder.write(this.initialBufs[i]) }
237
238    this.initialBufs.length = this.initialBufsLen = 0
239    return resStr
240  }
241
242  return this.decoder.write(buf)
243}
244
245Utf32AutoDecoder.prototype.end = function () {
246  if (!this.decoder) {
247    var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding)
248    this.decoder = this.iconv.getDecoder(encoding, this.options)
249
250    var resStr = ""
251    for (var i = 0; i < this.initialBufs.length; i++) { resStr += this.decoder.write(this.initialBufs[i]) }
252
253    var trail = this.decoder.end()
254    if (trail) { resStr += trail }
255
256    this.initialBufs.length = this.initialBufsLen = 0
257    return resStr
258  }
259
260  return this.decoder.end()
261}
262
263function detectEncoding (bufs, defaultEncoding) {
264  var b = []
265  var charsProcessed = 0
266  var invalidLE = 0; var invalidBE = 0   // Number of invalid chars when decoded as LE or BE.
267  var bmpCharsLE = 0; var bmpCharsBE = 0 // Number of BMP chars when decoded as LE or BE.
268
269  outerLoop:
270  for (var i = 0; i < bufs.length; i++) {
271    var buf = bufs[i]
272    for (var j = 0; j < buf.length; j++) {
273      b.push(buf[j])
274      if (b.length === 4) {
275        if (charsProcessed === 0) {
276          // Check BOM first.
277          if (b[0] === 0xFF && b[1] === 0xFE && b[2] === 0 && b[3] === 0) {
278            return "utf-32le"
279          }
280          if (b[0] === 0 && b[1] === 0 && b[2] === 0xFE && b[3] === 0xFF) {
281            return "utf-32be"
282          }
283        }
284
285        if (b[0] !== 0 || b[1] > 0x10) invalidBE++
286        if (b[3] !== 0 || b[2] > 0x10) invalidLE++
287
288        if (b[0] === 0 && b[1] === 0 && (b[2] !== 0 || b[3] !== 0)) bmpCharsBE++
289        if ((b[0] !== 0 || b[1] !== 0) && b[2] === 0 && b[3] === 0) bmpCharsLE++
290
291        b.length = 0
292        charsProcessed++
293
294        if (charsProcessed >= 100) {
295          break outerLoop
296        }
297      }
298    }
299  }
300
301  // Make decisions.
302  if (bmpCharsBE - invalidBE > bmpCharsLE - invalidLE) return "utf-32be"
303  if (bmpCharsBE - invalidBE < bmpCharsLE - invalidLE) return "utf-32le"
304
305  // Couldn't decide (likely all zeros or not enough data).
306  return defaultEncoding || "utf-32le"
307}
308 
codekingpro/portable-devtools · Team Ai