@aptre/v86 0.5.0

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 (111) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.MIT +22 -0
  3. package/Readme.md +237 -0
  4. package/dist/v86.browser.js +26666 -0
  5. package/dist/v86.browser.js.map +7 -0
  6. package/dist/v86.js +26632 -0
  7. package/dist/v86.js.map +7 -0
  8. package/gen/generate_analyzer.ts +512 -0
  9. package/gen/generate_interpreter.ts +522 -0
  10. package/gen/generate_jit.ts +624 -0
  11. package/gen/rust_ast.ts +107 -0
  12. package/gen/util.ts +35 -0
  13. package/gen/x86_table.ts +1836 -0
  14. package/lib/9p.ts +1547 -0
  15. package/lib/filesystem.ts +1879 -0
  16. package/lib/marshall.ts +168 -0
  17. package/lib/softfloat/softfloat.c +32501 -0
  18. package/lib/zstd/zstddeclib.c +13520 -0
  19. package/package.json +75 -0
  20. package/src/acpi.ts +267 -0
  21. package/src/browser/dummy_screen.ts +106 -0
  22. package/src/browser/fake_network.ts +1771 -0
  23. package/src/browser/fetch_network.ts +361 -0
  24. package/src/browser/filestorage.ts +124 -0
  25. package/src/browser/inbrowser_network.ts +57 -0
  26. package/src/browser/keyboard.ts +564 -0
  27. package/src/browser/main.ts +3415 -0
  28. package/src/browser/mouse.ts +255 -0
  29. package/src/browser/network.ts +142 -0
  30. package/src/browser/print_stats.ts +336 -0
  31. package/src/browser/screen.ts +978 -0
  32. package/src/browser/serial.ts +316 -0
  33. package/src/browser/speaker.ts +1223 -0
  34. package/src/browser/starter.ts +1688 -0
  35. package/src/browser/wisp_network.ts +332 -0
  36. package/src/browser/worker_bus.ts +64 -0
  37. package/src/buffer.ts +652 -0
  38. package/src/bus.ts +78 -0
  39. package/src/const.ts +128 -0
  40. package/src/cpu.ts +2891 -0
  41. package/src/dma.ts +474 -0
  42. package/src/elf.ts +251 -0
  43. package/src/floppy.ts +1778 -0
  44. package/src/ide.ts +3455 -0
  45. package/src/io.ts +504 -0
  46. package/src/iso9660.ts +317 -0
  47. package/src/kernel.ts +250 -0
  48. package/src/lib.ts +645 -0
  49. package/src/log.ts +149 -0
  50. package/src/main.ts +199 -0
  51. package/src/ne2k.ts +1589 -0
  52. package/src/pci.ts +815 -0
  53. package/src/pit.ts +406 -0
  54. package/src/ps2.ts +820 -0
  55. package/src/rtc.ts +537 -0
  56. package/src/rust/analysis.rs +101 -0
  57. package/src/rust/codegen.rs +2660 -0
  58. package/src/rust/config.rs +3 -0
  59. package/src/rust/control_flow.rs +425 -0
  60. package/src/rust/cpu/apic.rs +658 -0
  61. package/src/rust/cpu/arith.rs +1207 -0
  62. package/src/rust/cpu/call_indirect.rs +2 -0
  63. package/src/rust/cpu/cpu.rs +4501 -0
  64. package/src/rust/cpu/fpu.rs +923 -0
  65. package/src/rust/cpu/global_pointers.rs +112 -0
  66. package/src/rust/cpu/instructions.rs +2486 -0
  67. package/src/rust/cpu/instructions_0f.rs +5261 -0
  68. package/src/rust/cpu/ioapic.rs +316 -0
  69. package/src/rust/cpu/memory.rs +351 -0
  70. package/src/rust/cpu/misc_instr.rs +613 -0
  71. package/src/rust/cpu/mod.rs +16 -0
  72. package/src/rust/cpu/modrm.rs +133 -0
  73. package/src/rust/cpu/pic.rs +402 -0
  74. package/src/rust/cpu/sse_instr.rs +361 -0
  75. package/src/rust/cpu/string.rs +701 -0
  76. package/src/rust/cpu/vga.rs +175 -0
  77. package/src/rust/cpu_context.rs +69 -0
  78. package/src/rust/dbg.rs +98 -0
  79. package/src/rust/gen/analyzer.rs +3807 -0
  80. package/src/rust/gen/analyzer0f.rs +3992 -0
  81. package/src/rust/gen/interpreter.rs +4447 -0
  82. package/src/rust/gen/interpreter0f.rs +5404 -0
  83. package/src/rust/gen/jit.rs +5080 -0
  84. package/src/rust/gen/jit0f.rs +5547 -0
  85. package/src/rust/gen/mod.rs +14 -0
  86. package/src/rust/jit.rs +2443 -0
  87. package/src/rust/jit_instructions.rs +7881 -0
  88. package/src/rust/js_api.rs +6 -0
  89. package/src/rust/leb.rs +46 -0
  90. package/src/rust/lib.rs +29 -0
  91. package/src/rust/modrm.rs +330 -0
  92. package/src/rust/opstats.rs +249 -0
  93. package/src/rust/page.rs +15 -0
  94. package/src/rust/paging.rs +25 -0
  95. package/src/rust/prefix.rs +15 -0
  96. package/src/rust/profiler.rs +155 -0
  97. package/src/rust/regs.rs +38 -0
  98. package/src/rust/softfloat.rs +286 -0
  99. package/src/rust/state_flags.rs +27 -0
  100. package/src/rust/wasmgen/mod.rs +2 -0
  101. package/src/rust/wasmgen/wasm_builder.rs +1047 -0
  102. package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
  103. package/src/rust/zstd.rs +105 -0
  104. package/src/sb16.ts +1928 -0
  105. package/src/state.ts +359 -0
  106. package/src/uart.ts +472 -0
  107. package/src/vga.ts +2791 -0
  108. package/src/virtio.ts +1756 -0
  109. package/src/virtio_balloon.ts +273 -0
  110. package/src/virtio_console.ts +372 -0
  111. package/src/virtio_net.ts +326 -0
package/src/lib.ts ADDED
@@ -0,0 +1,645 @@
1
+ declare let DEBUG: boolean
2
+
3
+ import { dbg_assert } from './log.js'
4
+
5
+ // pad string with spaces on the right
6
+ export function pads(
7
+ str: string | number | undefined | null,
8
+ len: number,
9
+ ): string {
10
+ const s = str || str === 0 ? str + '' : ''
11
+ return s.padEnd(len, ' ')
12
+ }
13
+
14
+ // pad string with zeros on the left
15
+ export function pad0(
16
+ str: string | number | undefined | null,
17
+ len: number,
18
+ ): string {
19
+ const s = str || str === 0 ? str + '' : ''
20
+ return s.padStart(len, '0')
21
+ }
22
+
23
+ export const view = function (
24
+ constructor: any,
25
+ memory: { buffer: ArrayBuffer },
26
+ offset: number,
27
+ length: number,
28
+ ): any {
29
+ dbg_assert(offset >= 0)
30
+ return new Proxy(
31
+ {},
32
+ {
33
+ get: function (_target, property) {
34
+ const b = new constructor(memory.buffer, offset, length)
35
+ const x = b[property]
36
+ if (typeof x === 'function') {
37
+ return x.bind(b)
38
+ }
39
+ dbg_assert(
40
+ /^\d+$/.test(String(property)) ||
41
+ property === 'buffer' ||
42
+ property === 'length' ||
43
+ property === 'BYTES_PER_ELEMENT' ||
44
+ property === 'byteOffset',
45
+ )
46
+ return x
47
+ },
48
+ set: function (_target, property, value) {
49
+ dbg_assert(/^\d+$/.test(String(property)))
50
+ new constructor(memory.buffer, offset, length)[property] = value
51
+ return true
52
+ },
53
+ },
54
+ )
55
+ }
56
+
57
+ export function h(n: number, len?: number): string {
58
+ let str: string
59
+ if (!n) {
60
+ str = ''
61
+ } else {
62
+ str = n.toString(16)
63
+ }
64
+
65
+ return '0x' + pad0(str.toUpperCase(), len || 1)
66
+ }
67
+
68
+ export function hex_dump(buffer: Uint8Array | number[]): string {
69
+ function hex(n: number, len: number): string {
70
+ return pad0(n.toString(16).toUpperCase(), len)
71
+ }
72
+
73
+ const result: string[] = []
74
+ let offset = 0
75
+
76
+ for (; offset + 15 < buffer.length; offset += 16) {
77
+ let line = hex(offset, 5) + ' '
78
+
79
+ for (let j = 0; j < 0x10; j++) {
80
+ line += hex(buffer[offset + j], 2) + ' '
81
+ }
82
+
83
+ line += ' '
84
+
85
+ for (let j = 0; j < 0x10; j++) {
86
+ const x = buffer[offset + j]
87
+ line +=
88
+ x >= 33 && x !== 34 && x !== 92 && x <= 126
89
+ ? String.fromCharCode(x)
90
+ : '.'
91
+ }
92
+
93
+ result.push(line)
94
+ }
95
+
96
+ let line = hex(offset, 5) + ' '
97
+
98
+ for (; offset < buffer.length; offset++) {
99
+ line += hex(buffer[offset], 2) + ' '
100
+ }
101
+
102
+ const remainder = offset & 0xf
103
+ line += ' '.repeat(0x10 - remainder)
104
+ line += ' '
105
+
106
+ for (let j = 0; j < remainder; j++) {
107
+ const x = buffer[offset + j]
108
+ line +=
109
+ x >= 33 && x !== 34 && x !== 92 && x <= 126
110
+ ? String.fromCharCode(x)
111
+ : '.'
112
+ }
113
+
114
+ result.push(line)
115
+
116
+ return '\n' + result.join('\n') + '\n'
117
+ }
118
+
119
+ /* global require */
120
+ export let get_rand_int: () => number
121
+ if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
122
+ const rand_data = new Int32Array(1)
123
+
124
+ get_rand_int = function () {
125
+ crypto.getRandomValues(rand_data)
126
+ return rand_data[0]
127
+ }
128
+ } else if (typeof require !== 'undefined') {
129
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
130
+ const nodeCrypto = require('crypto')
131
+
132
+ get_rand_int = function () {
133
+ return nodeCrypto.randomBytes(4).readInt32LE(0)
134
+ }
135
+ } else if (typeof process !== 'undefined') {
136
+ import('node:' + 'crypto').then((nodeCrypto) => {
137
+ get_rand_int = function () {
138
+ return nodeCrypto['randomBytes'](4).readInt32LE(0)
139
+ }
140
+ })
141
+ } else {
142
+ dbg_assert(false, 'Unsupported platform: No cryptographic random values')
143
+ }
144
+
145
+ export let int_log2: (x: number) => number
146
+
147
+ if (
148
+ typeof Math.clz32 === 'function' &&
149
+ Math.clz32(0) === 32 &&
150
+ Math.clz32(0x12345) === 15 &&
151
+ Math.clz32(-1) === 0
152
+ ) {
153
+ int_log2 = function (x: number): number {
154
+ dbg_assert(x > 0)
155
+
156
+ return 31 - Math.clz32(x)
157
+ }
158
+ } else {
159
+ const int_log2_table = new Int8Array(256)
160
+
161
+ for (let i = 0, b = -2; i < 256; i++) {
162
+ if (!(i & (i - 1))) b++
163
+
164
+ int_log2_table[i] = b
165
+ }
166
+
167
+ int_log2 = function (x: number): number {
168
+ x >>>= 0
169
+ dbg_assert(x > 0)
170
+
171
+ // http://jsperf.com/integer-log2/6
172
+ const tt = x >>> 16
173
+
174
+ if (tt) {
175
+ const t = tt >>> 8
176
+ if (t) {
177
+ return 24 + int_log2_table[t]
178
+ } else {
179
+ return 16 + int_log2_table[tt]
180
+ }
181
+ } else {
182
+ const t = x >>> 8
183
+ if (t) {
184
+ return 8 + int_log2_table[t]
185
+ } else {
186
+ return int_log2_table[x]
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+ export const round_up_to_next_power_of_2 = function (x: number): number {
193
+ dbg_assert(x >= 0)
194
+ return x <= 1 ? 1 : 1 << (1 + int_log2(x - 1))
195
+ }
196
+
197
+ if (typeof DEBUG !== 'undefined' && DEBUG) {
198
+ dbg_assert(int_log2(1) === 0)
199
+ dbg_assert(int_log2(2) === 1)
200
+ dbg_assert(int_log2(7) === 2)
201
+ dbg_assert(int_log2(8) === 3)
202
+ dbg_assert(int_log2(123456789) === 26)
203
+
204
+ dbg_assert(round_up_to_next_power_of_2(0) === 1)
205
+ dbg_assert(round_up_to_next_power_of_2(1) === 1)
206
+ dbg_assert(round_up_to_next_power_of_2(2) === 2)
207
+ dbg_assert(round_up_to_next_power_of_2(7) === 8)
208
+ dbg_assert(round_up_to_next_power_of_2(8) === 8)
209
+ dbg_assert(round_up_to_next_power_of_2(123456789) === 134217728)
210
+ }
211
+
212
+ export class ByteQueue {
213
+ length: number = 0
214
+ private data: Uint8Array
215
+ private start: number = 0
216
+ private end: number = 0
217
+ private size: number
218
+
219
+ constructor(size: number) {
220
+ this.size = size
221
+ this.data = new Uint8Array(size)
222
+
223
+ dbg_assert((size & (size - 1)) === 0)
224
+ }
225
+
226
+ push(item: number): void {
227
+ if (this.length === this.size) {
228
+ // intentional overwrite
229
+ } else {
230
+ this.length++
231
+ }
232
+
233
+ this.data[this.end] = item
234
+ this.end = (this.end + 1) & (this.size - 1)
235
+ }
236
+
237
+ shift(): number {
238
+ if (!this.length) {
239
+ return -1
240
+ } else {
241
+ const item = this.data[this.start]
242
+
243
+ this.start = (this.start + 1) & (this.size - 1)
244
+ this.length--
245
+
246
+ return item
247
+ }
248
+ }
249
+
250
+ peek(): number {
251
+ if (!this.length) {
252
+ return -1
253
+ } else {
254
+ return this.data[this.start]
255
+ }
256
+ }
257
+
258
+ clear(): void {
259
+ this.start = 0
260
+ this.end = 0
261
+ this.length = 0
262
+ }
263
+ }
264
+
265
+ export class FloatQueue {
266
+ size: number
267
+ data: Float32Array
268
+ start: number = 0
269
+ end: number = 0
270
+ length: number = 0
271
+
272
+ constructor(size: number) {
273
+ this.size = size
274
+ this.data = new Float32Array(size)
275
+
276
+ dbg_assert((size & (size - 1)) === 0)
277
+ }
278
+
279
+ push(item: number): void {
280
+ if (this.length === this.size) {
281
+ // intentional overwrite
282
+ this.start = (this.start + 1) & (this.size - 1)
283
+ } else {
284
+ this.length++
285
+ }
286
+
287
+ this.data[this.end] = item
288
+ this.end = (this.end + 1) & (this.size - 1)
289
+ }
290
+
291
+ shift(): number | undefined {
292
+ if (!this.length) {
293
+ return undefined
294
+ } else {
295
+ const item = this.data[this.start]
296
+
297
+ this.start = (this.start + 1) & (this.size - 1)
298
+ this.length--
299
+
300
+ return item
301
+ }
302
+ }
303
+
304
+ shift_block(count: number): Float32Array {
305
+ const slice = new Float32Array(count)
306
+
307
+ if (count > this.length) {
308
+ count = this.length
309
+ }
310
+ let slice_end = this.start + count
311
+
312
+ const partial = this.data.subarray(this.start, slice_end)
313
+
314
+ slice.set(partial)
315
+ if (slice_end >= this.size) {
316
+ slice_end -= this.size
317
+ slice.set(this.data.subarray(0, slice_end), partial.length)
318
+ }
319
+ this.start = slice_end
320
+
321
+ this.length -= count
322
+
323
+ return slice
324
+ }
325
+
326
+ peek(): number | undefined {
327
+ if (!this.length) {
328
+ return undefined
329
+ } else {
330
+ return this.data[this.start]
331
+ }
332
+ }
333
+
334
+ clear(): void {
335
+ this.start = 0
336
+ this.end = 0
337
+ this.length = 0
338
+ }
339
+ }
340
+
341
+ export function dump_file(ab: BlobPart | BlobPart[], name: string): void {
342
+ if (!Array.isArray(ab)) {
343
+ ab = [ab]
344
+ }
345
+
346
+ const blob = new Blob(ab)
347
+ download(blob, name)
348
+ }
349
+
350
+ export function download(file_or_blob: Blob | File, name: string): void {
351
+ const a = document.createElement('a')
352
+ a['download'] = name
353
+ a.href = window.URL.createObjectURL(file_or_blob)
354
+ a.dataset['downloadurl'] = [
355
+ 'application/octet-stream',
356
+ a['download'],
357
+ a.href,
358
+ ].join(':')
359
+
360
+ if (document.createEvent) {
361
+ const ev = document.createEvent('MouseEvent')
362
+ ev.initMouseEvent(
363
+ 'click',
364
+ true,
365
+ true,
366
+ window,
367
+ 0,
368
+ 0,
369
+ 0,
370
+ 0,
371
+ 0,
372
+ false,
373
+ false,
374
+ false,
375
+ false,
376
+ 0,
377
+ null,
378
+ )
379
+ a.dispatchEvent(ev)
380
+ } else {
381
+ a.click()
382
+ }
383
+
384
+ window.URL.revokeObjectURL(a.href)
385
+ }
386
+
387
+ export class Bitmap {
388
+ view: Uint8Array
389
+
390
+ constructor(length_or_buffer: number | ArrayBuffer) {
391
+ if (typeof length_or_buffer === 'number') {
392
+ this.view = new Uint8Array((length_or_buffer + 7) >> 3)
393
+ } else if (length_or_buffer instanceof ArrayBuffer) {
394
+ this.view = new Uint8Array(length_or_buffer)
395
+ } else {
396
+ dbg_assert(false, 'Bitmap: Invalid argument')
397
+ this.view = new Uint8Array(0)
398
+ }
399
+ }
400
+
401
+ set(index: number, value: number): void {
402
+ const bit_index = index & 7
403
+ const byte_index = index >> 3
404
+ const bit_mask = 1 << bit_index
405
+
406
+ this.view[byte_index] = value
407
+ ? this.view[byte_index] | bit_mask
408
+ : this.view[byte_index] & ~bit_mask
409
+ }
410
+
411
+ get(index: number): number {
412
+ const bit_index = index & 7
413
+ const byte_index = index >> 3
414
+
415
+ return (this.view[byte_index] >> bit_index) & 1
416
+ }
417
+
418
+ get_buffer(): ArrayBufferLike {
419
+ return this.view.buffer
420
+ }
421
+ }
422
+
423
+ export interface LoadFileOptions {
424
+ done?: (result: any, http?: XMLHttpRequest) => void
425
+ progress?: (e: ProgressEvent) => void
426
+ as_json?: boolean
427
+ method?: string
428
+ headers?: Record<string, string>
429
+ range?: { start: number; length: number }
430
+ }
431
+
432
+ export let load_file: (
433
+ filename: string,
434
+ options: LoadFileOptions,
435
+ n_tries?: number,
436
+ ) => Promise<void>
437
+ export let get_file_size: (path: string) => Promise<number>
438
+
439
+ if (
440
+ typeof XMLHttpRequest === 'undefined' ||
441
+ (typeof process !== 'undefined' &&
442
+ process.versions &&
443
+ process.versions.node)
444
+ ) {
445
+ let fs: any
446
+
447
+ load_file = async function (
448
+ filename: string,
449
+ options: LoadFileOptions,
450
+ _n_tries?: number,
451
+ ) {
452
+ if (!fs) {
453
+ // string concat to work around closure compiler 'Invalid module path "node:fs/promises" for resolution mode'
454
+ fs = await import('node:' + 'fs/promises')
455
+ }
456
+
457
+ if (options.range) {
458
+ dbg_assert(!options.as_json)
459
+
460
+ const fd = await fs['open'](filename, 'r')
461
+
462
+ const length = options.range.length
463
+ const buffer = Buffer.allocUnsafe(length)
464
+
465
+ try {
466
+ const result = await fd['read']({
467
+ buffer,
468
+ position: options.range.start,
469
+ })
470
+ dbg_assert(result.bytesRead === length)
471
+ } finally {
472
+ await fd['close']()
473
+ }
474
+
475
+ if (options.done) {
476
+ options.done(new Uint8Array(buffer))
477
+ }
478
+ } else {
479
+ const o = {
480
+ encoding: options.as_json ? 'utf-8' : null,
481
+ }
482
+
483
+ const data = await fs['readFile'](filename, o)
484
+ if (options.as_json) {
485
+ options.done!(JSON.parse(data))
486
+ } else {
487
+ options.done!(new Uint8Array(data).buffer)
488
+ }
489
+ }
490
+ }
491
+
492
+ get_file_size = async function (path: string) {
493
+ if (!fs) {
494
+ // string concat to work around closure compiler 'Invalid module path "node:fs/promises" for resolution mode'
495
+ fs = await import('node:' + 'fs/promises')
496
+ }
497
+ const stat = await fs['stat'](path)
498
+ return stat.size
499
+ }
500
+ } else {
501
+ load_file = async function (
502
+ filename: string,
503
+ options: LoadFileOptions,
504
+ n_tries?: number,
505
+ ) {
506
+ const http = new XMLHttpRequest()
507
+
508
+ http.open(options.method || 'get', filename, true)
509
+
510
+ if (options.as_json) {
511
+ http.responseType = 'json'
512
+ } else {
513
+ http.responseType = 'arraybuffer'
514
+ }
515
+
516
+ if (options.headers) {
517
+ const header_names = Object.keys(options.headers)
518
+
519
+ for (let i = 0; i < header_names.length; i++) {
520
+ const name = header_names[i]
521
+ http.setRequestHeader(name, options.headers[name])
522
+ }
523
+ }
524
+
525
+ if (options.range) {
526
+ const start = options.range.start
527
+ const end = start + options.range.length - 1
528
+ http.setRequestHeader('Range', 'bytes=' + start + '-' + end)
529
+ http.setRequestHeader('X-Accept-Encoding', 'identity')
530
+
531
+ // Abort if server responds with complete file in response to range
532
+ // request, to prevent downloading large files from broken http servers
533
+ http.onreadystatechange = function () {
534
+ if (http.status === 200) {
535
+ console.error(
536
+ 'Server sent full file in response to ranged request, aborting',
537
+ { filename },
538
+ )
539
+ http.abort()
540
+ }
541
+ }
542
+ }
543
+
544
+ http.onload = function (_e) {
545
+ if (http.readyState === 4) {
546
+ if (http.status !== 200 && http.status !== 206) {
547
+ console.error(
548
+ 'Loading the image ' + filename + ' failed (status %d)',
549
+ http.status,
550
+ )
551
+ if (http.status >= 500 && http.status < 600) {
552
+ retry()
553
+ }
554
+ } else if (http.response) {
555
+ if (options.range) {
556
+ const enc = http.getResponseHeader('Content-Encoding')
557
+ if (enc && enc !== 'identity') {
558
+ console.error(
559
+ 'Server sent Content-Encoding in response to ranged request',
560
+ { filename, enc },
561
+ )
562
+ }
563
+ }
564
+ if (options.done) {
565
+ options.done(http.response, http)
566
+ }
567
+ }
568
+ }
569
+ }
570
+
571
+ http.onerror = function (e) {
572
+ console.error('Loading the image ' + filename + ' failed', e)
573
+ retry()
574
+ }
575
+
576
+ if (options.progress) {
577
+ http.onprogress = function (e) {
578
+ options.progress!(e)
579
+ }
580
+ }
581
+
582
+ http.send(null)
583
+
584
+ function retry() {
585
+ const number_of_tries = n_tries || 0
586
+ const timeout = [1, 1, 2, 3, 5, 8, 13, 21][number_of_tries] || 34
587
+ setTimeout(() => {
588
+ load_file(filename, options, number_of_tries + 1)
589
+ }, 1000 * timeout)
590
+ }
591
+ }
592
+
593
+ get_file_size = async function (url: string) {
594
+ return new Promise((resolve, reject) => {
595
+ load_file(url, {
596
+ done: (_buffer, http) => {
597
+ const header =
598
+ http!.getResponseHeader('Content-Range') || ''
599
+ const match = header.match(/\/(\d+)\s*$/)
600
+
601
+ if (match) {
602
+ resolve(+match[1])
603
+ } else {
604
+ const error = new Error(
605
+ '`Range: bytes=...` header not supported (Got `' +
606
+ header +
607
+ '`)',
608
+ )
609
+ reject(error)
610
+ }
611
+ },
612
+ headers: {
613
+ Range: 'bytes=0-0',
614
+ 'X-Accept-Encoding': 'identity',
615
+ },
616
+ })
617
+ })
618
+ }
619
+ }
620
+
621
+ // Reads len characters at offset from Memory object mem as a JS string
622
+ export function read_sized_string_from_mem(
623
+ mem: { buffer: ArrayBuffer },
624
+ offset: number,
625
+ len: number,
626
+ ): string {
627
+ offset >>>= 0
628
+ len >>>= 0
629
+ return String.fromCharCode(...new Uint8Array(mem.buffer, offset, len))
630
+ }
631
+
632
+ const CHARMAPS: Record<string, string> = {
633
+ cp437: ' \u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\u00B6\u00A7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\u00C7\u00FC\u00E9\u00E2\u00E4\u00E0\u00E5\u00E7\u00EA\u00EB\u00E8\u00EF\u00EE\u00EC\u00C4\u00C5\u00C9\u00E6\u00C6\u00F4\u00F6\u00F2\u00FB\u00F9\u00FF\u00D6\u00DC\u00A2\u00A3\u00A5\u20A7\u0192\u00E1\u00ED\u00F3\u00FA\u00F1\u00D1\u00AA\u00BA\u00BF\u2310\u00AC\u00BD\u00BC\u00A1\u00AB\u00BB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\u00DF\u0393\u03C0\u03A3\u03C3\u00B5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\u00B1\u2265\u2264\u2320\u2321\u00F7\u2248\u00B0\u2219\u00B7\u221A\u207F\u00B2\u25A0 ',
634
+ cp858: '\u00C7\u00FC\u00E9\u00E2\u00E4\u00E0\u00E5\u00E7\u00EA\u00EB\u00E8\u00EF\u00EE\u00EC\u00C4\u00C5\u00C9\u00E6\u00C6\u00F4\u00F6\u00F2\u00FB\u00F9\u00FF\u00D6\u00DC\u00F8\u00A3\u00D8\u00D7\u0192\u00E1\u00ED\u00F3\u00FA\u00F1\u00D1\u00AA\u00BA\u00BF\u00AE\u00AC\u00BD\u00BC\u00A1\u00AB\u00BB\u2591\u2592\u2593\u2502\u2524\u00C1\u00C2\u00C0\u00A9\u2563\u2551\u2557\u255D\u00A2\u00A5\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u00E3\u00C3\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u00A4\u00F0\u00D0\u00CA\u00CB\u00C8\u20AC\u00CD\u00CE\u00CF\u2518\u250C\u2588\u2584\u00A6\u00CC\u2580\u00D3\u00DF\u00D4\u00D2\u00F5\u00D5\u00B5\u00FE\u00DE\u00DA\u00DB\u00D9\u00FD\u00DD\u00AF\u00B4\u00AD\u00B1\u2017\u00BE\u00B6\u00A7\u00F7\u00B8\u00B0\u00A8\u00B7\u00B9\u00B3\u00B2\u25A0 ',
635
+ }
636
+
637
+ CHARMAPS.cp858 = CHARMAPS.cp437.slice(0, 128) + CHARMAPS.cp858
638
+ CHARMAPS.ascii = CHARMAPS.cp437
639
+ .split('')
640
+ .map((c, i) => (i > 31 && i < 128 ? c : '.'))
641
+ .join('')
642
+
643
+ export function get_charmap(encoding: string): string {
644
+ return encoding && CHARMAPS[encoding] ? CHARMAPS[encoding] : CHARMAPS.cp437
645
+ }