quickwin 3.0.1 → 3.0.3

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 (163) hide show
  1. package/README.en.md +3 -0
  2. package/README.md +2 -0
  3. package/package.json +2 -3
  4. package/qwin-nowasm-x86.exe +0 -0
  5. package/qwin-nowasm.exe +0 -0
  6. package/qwin-x86.exe +0 -0
  7. package/qwin.exe +0 -0
  8. package/examples/PdfCanvas.js +0 -38
  9. package/examples/PdfCanvas.tsx +0 -54
  10. package/examples/execd/main.js +0 -23379
  11. package/examples/execd/tray.js +0 -192
  12. package/examples/execd/worker.js +0 -122
  13. package/examples/pdf_preview2.js +0 -398
  14. package/examples/pdf_preview2.ts +0 -353
  15. package/examples/pdf_viewer.js +0 -22515
  16. package/examples/pdf_viewer.tsx +0 -228
  17. package/examples/test_gallery.js +0 -18692
  18. package/examples/test_gallery.tsx +0 -291
  19. package/examples/test_react_lazy.js +0 -18560
  20. package/examples/test_react_lazy.tsx +0 -65
  21. package/examples/test_react_listbox.js +0 -18562
  22. package/examples/test_react_listbox.tsx +0 -73
  23. package/examples/test_root_window.js +0 -18532
  24. package/examples/test_root_window.tsx +0 -41
  25. package/examples/test_tab.js +0 -18563
  26. package/examples/test_tab.tsx +0 -77
  27. package/examples/tray_demo.js +0 -86
  28. package/examples/tray_demo.tsx +0 -89
  29. package/test/add.wasm +0 -0
  30. package/test/bench_ffi_callraw.js +0 -235
  31. package/test/bench_ffi_callraw.ts +0 -235
  32. package/test/bench_ffi_overhead.js +0 -139
  33. package/test/bench_ffi_overhead.ts +0 -141
  34. package/test/bench_sendmessage.js +0 -104
  35. package/test/bench_sendmessage.ts +0 -100
  36. package/test/bench_sendmessage_nonnull.js +0 -187
  37. package/test/bench_sendmessage_nonnull.ts +0 -188
  38. package/test/complex.wasm +0 -0
  39. package/test/complex_imports.wasm +0 -0
  40. package/test/debug/http_server_e2e.js +0 -31
  41. package/test/debug/minwasm.js +0 -52
  42. package/test/debug/mupdf_debug.js +0 -86
  43. package/test/debug/wasm.js +0 -122
  44. package/test/debug/wasm_export_debug.js +0 -54
  45. package/test/debug/wasm_names.js +0 -36
  46. package/test/example.pdf +0 -0
  47. package/test/global_imports.wasm +0 -0
  48. package/test/import_func.wasm +0 -0
  49. package/test/imports.wasm +0 -0
  50. package/test/mupdf-cdn.js +0 -40
  51. package/test/mupdf-cdn.ts +0 -43
  52. package/test/run.js +0 -111
  53. package/test/run.ts +0 -116
  54. package/test/sjlj.wasm +0 -0
  55. package/test/test_basic.js +0 -7
  56. package/test/test_basic.ts +0 -9
  57. package/test/test_basic_fetch.js +0 -63
  58. package/test/test_basic_fetch.ts +0 -59
  59. package/test/test_brotli.js +0 -48
  60. package/test/test_brotli.ts +0 -52
  61. package/test/test_fetch_cache.js +0 -169
  62. package/test/test_fetch_cache.ts +0 -187
  63. package/test/test_ffi.js +0 -157
  64. package/test/test_ffi.ts +0 -170
  65. package/test/test_ffi_abi.js +0 -290
  66. package/test/test_ffi_abi.ts +0 -274
  67. package/test/test_ffi_array.js +0 -116
  68. package/test/test_ffi_array.ts +0 -141
  69. package/test/test_ffi_bind.js +0 -656
  70. package/test/test_ffi_bind.ts +0 -670
  71. package/test/test_ffi_struct.js +0 -779
  72. package/test/test_ffi_struct.ts +0 -828
  73. package/test/test_ffi_struct_layout.js +0 -495
  74. package/test/test_ffi_struct_layout.ts +0 -543
  75. package/test/test_ffi_user32.js +0 -103
  76. package/test/test_ffi_user32.ts +0 -113
  77. package/test/test_ffi_windows.js +0 -172
  78. package/test/test_ffi_windows.ts +0 -187
  79. package/test/test_files.js +0 -102
  80. package/test/test_files.ts +0 -121
  81. package/test/test_frame_encoding.js +0 -128
  82. package/test/test_frame_encoding.ts +0 -132
  83. package/test/test_gdi_draw.js +0 -681
  84. package/test/test_gdi_draw.ts +0 -725
  85. package/test/test_helper.js +0 -91
  86. package/test/test_helper.ts +0 -88
  87. package/test/test_http_import.js +0 -96
  88. package/test/test_http_import.ts +0 -93
  89. package/test/test_http_server.js +0 -214
  90. package/test/test_http_server.ts +0 -211
  91. package/test/test_import_dir.js +0 -4
  92. package/test/test_import_dir.ts +0 -5
  93. package/test/test_ipv6.js +0 -134
  94. package/test/test_ipv6.ts +0 -130
  95. package/test/test_jsx.js +0 -1314
  96. package/test/test_meta_url.js +0 -3
  97. package/test/test_meta_url.ts +0 -4
  98. package/test/test_mupdf_render.js +0 -51
  99. package/test/test_mupdf_render.ts +0 -55
  100. package/test/test_mupdf_twice.js +0 -62
  101. package/test/test_mupdf_twice.ts +0 -65
  102. package/test/test_mupdf_wasm.js +0 -39
  103. package/test/test_mupdf_wasm.ts +0 -32
  104. package/test/test_net_event.js +0 -57
  105. package/test/test_net_event.ts +0 -56
  106. package/test/test_net_fetch.js +0 -384
  107. package/test/test_net_fetch.ts +0 -373
  108. package/test/test_net_websocket.js +0 -180
  109. package/test/test_net_websocket.ts +0 -164
  110. package/test/test_polyfill.js +0 -144
  111. package/test/test_polyfill.ts +0 -159
  112. package/test/test_printer.js +0 -137
  113. package/test/test_printer.ts +0 -148
  114. package/test/test_proc.js +0 -141
  115. package/test/test_proc.ts +0 -163
  116. package/test/test_react_complex.js +0 -18678
  117. package/test/test_react_counter.js +0 -18555
  118. package/test/test_react_flex.js +0 -18871
  119. package/test/test_react_hidden.js +0 -18560
  120. package/test/test_react_listview_link.js +0 -18590
  121. package/test/test_react_notify.js +0 -18797
  122. package/test/test_react_render.js +0 -18550
  123. package/test/test_registry.js +0 -74
  124. package/test/test_registry.ts +0 -95
  125. package/test/test_sysinfo.js +0 -122
  126. package/test/test_sysinfo.ts +0 -141
  127. package/test/test_url.js +0 -173
  128. package/test/test_url.ts +0 -183
  129. package/test/test_wasm_basic.js +0 -85
  130. package/test/test_wasm_basic.ts +0 -73
  131. package/test/test_wasm_import_global.js +0 -41
  132. package/test/test_wasm_import_global.ts +0 -45
  133. package/test/test_wasm_sjlj.js +0 -145
  134. package/test/test_wasm_sjlj.ts +0 -125
  135. package/test/test_wasm_types.js +0 -97
  136. package/test/test_wasm_types.ts +0 -124
  137. package/test/test_wolfssl_read.js +0 -203
  138. package/test/test_wolfssl_read.ts +0 -184
  139. package/test/test_worker.js +0 -21
  140. package/test/test_worker.ts +0 -24
  141. package/test/test_worker_concurrent.js +0 -45
  142. package/test/test_worker_concurrent.ts +0 -56
  143. package/test/test_worker_data_url.js +0 -46
  144. package/test/test_worker_data_url.ts +0 -51
  145. package/test/test_worker_fetch.js +0 -26
  146. package/test/test_worker_fetch.ts +0 -27
  147. package/test/test_worker_net.js +0 -69
  148. package/test/test_worker_net.ts +0 -66
  149. package/test/test_worker_wasm_concurrent.js +0 -44
  150. package/test/test_worker_wasm_concurrent.ts +0 -45
  151. package/test/types.wasm +0 -0
  152. package/test/worker_fetch.js +0 -13
  153. package/test/worker_fetch.ts +0 -13
  154. package/test/worker_helper.js +0 -1
  155. package/test/worker_helper.ts +0 -1
  156. package/test/worker_http.js +0 -18
  157. package/test/worker_http.ts +0 -20
  158. package/test/worker_import_lib.js +0 -12
  159. package/test/worker_import_lib.ts +0 -13
  160. package/test/worker_module.js +0 -16
  161. package/test/worker_module.ts +0 -17
  162. package/test/worker_wasm_concurrent.js +0 -22
  163. package/test/worker_wasm_concurrent.ts +0 -22
@@ -1,164 +0,0 @@
1
- import '../lib/websocket.js'
2
- import * as std from 'std'
3
- import * as os from 'os'
4
- import { Tester } from './test_helper.js'
5
-
6
- export const suite = {
7
- name: 'net-websocket',
8
- run: async (t: Tester) => {
9
- function assert(name: string, ok: boolean): void {
10
- if (ok) { t.ok++; std.printf(' PASS: %s\n', name) }
11
- else { t.fail++; std.printf(' FAIL: %s\n', name) }
12
- }
13
-
14
- let testId = 0
15
- const resolvers: Record<number, () => void> = {}
16
-
17
- function waitForTest(): { promise: Promise<void>; id: number } {
18
- const id = ++testId
19
- const promise = new Promise<void>((resolve) => { resolvers[id] = resolve })
20
- return { promise, id }
21
- }
22
-
23
- function finishTest(id: number) {
24
- const r = resolvers[id]
25
- if (r) { delete resolvers[id]; r() }
26
- }
27
-
28
- // ── wss basic ──
29
- t.section('wss basic text message')
30
- const p1 = waitForTest()
31
- let opened = false, received = false, closed = false
32
- const ws1 = new WebSocket("ws://localhost:18923")
33
- ws1.onopen = () => { opened = true; ws1.send("Hello WebSocket!") }
34
- ws1.onmessage = () => { received = true; ws1.close(1000, "done") }
35
- ws1.onclose = (e) => {
36
- closed = true
37
- assert('onopen fired', opened)
38
- assert('onmessage received', received)
39
- assert('close code=1000', e.code === 1000)
40
- assert('wasClean', e.wasClean)
41
- finishTest(p1.id)
42
- }
43
- ws1.onerror = () => { assert('no error', false); finishTest(p1.id) }
44
- const timer1 = os.setTimeout(() => { if (!closed) { assert('no timeout', false); finishTest(p1.id) } }, 10000)
45
- await p1.promise
46
- os.clearTimeout(timer1)
47
-
48
- // ── binary send ──
49
- t.section('binary message (ArrayBuffer)')
50
- const pBin = waitForTest()
51
- const wsBin = new WebSocket("ws://localhost:18923")
52
- let binClose = false
53
- wsBin.onopen = () => {
54
- const buf = new ArrayBuffer(5)
55
- const v = new Uint8Array(buf)
56
- v[0] = 0x48; v[1] = 0x65; v[2] = 0x6C; v[3] = 0x6C; v[4] = 0x6F
57
- wsBin.send(buf)
58
- wsBin.send("binary-send-check")
59
- }
60
- let binMsgCount = 0
61
- wsBin.onmessage = () => { binMsgCount++; if (binMsgCount >= 2) wsBin.close(1000, "done") }
62
- wsBin.onclose = () => { binClose = true; assert('binary send completed', true); finishTest(pBin.id) }
63
- wsBin.onerror = () => { assert('no error', false); finishTest(pBin.id) }
64
- const timerBin = os.setTimeout(() => { if (!binClose) assert('binary no crash (timeout)', true); finishTest(pBin.id) }, 10000)
65
- await pBin.promise
66
- os.clearTimeout(timerBin)
67
-
68
- // ── extended length frame ──
69
- t.section('extended length frame (>65535 bytes)')
70
- const pExt = waitForTest()
71
- const wsExt = new WebSocket("ws://localhost:18923")
72
- let extClose = false
73
- wsExt.onopen = () => { wsExt.send("X".repeat(66000)) }
74
- wsExt.onmessage = () => { wsExt.close(1000, "done") }
75
- wsExt.onclose = () => { extClose = true; assert('extended frame sent', true); finishTest(pExt.id) }
76
- wsExt.onerror = () => { assert('no error', false); finishTest(pExt.id) }
77
- const timerExt = os.setTimeout(() => { if (!extClose) assert('extended frame timeout', true); finishTest(pExt.id) }, 10000)
78
- await pExt.promise
79
- os.clearTimeout(timerExt)
80
-
81
- // ── large message ──
82
- t.section('large message (>125 bytes)')
83
- const p2 = waitForTest()
84
- const ws2 = new WebSocket("ws://localhost:18923")
85
- let largeOk = false, closed2 = false
86
- const largeStr = "A".repeat(1000)
87
- ws2.onopen = () => { ws2.send(largeStr) }
88
- ws2.onmessage = (e) => { largeOk = (e.data as string).length === 1000; ws2.close(1000, "done") }
89
- ws2.onclose = () => { closed2 = true; assert('large msg echo 1000 bytes', largeOk); finishTest(p2.id) }
90
- ws2.onerror = () => { assert('no error', false); finishTest(p2.id) }
91
- const timer2 = os.setTimeout(() => { if (!closed2) { assert('large msg no timeout', false); finishTest(p2.id) } }, 15000)
92
- await p2.promise
93
- os.clearTimeout(timer2)
94
-
95
- // ── multiple messages ──
96
- t.section('multiple messages')
97
- const p3 = waitForTest()
98
- const ws3 = new WebSocket("ws://localhost:18923")
99
- let count = 0, closed3 = false
100
- ws3.onopen = () => { ws3.send("a"); ws3.send("b"); ws3.send("c") }
101
- ws3.onmessage = () => { count++; if (count === 3) ws3.close(1000, "done") }
102
- ws3.onclose = () => { closed3 = true; assert('received 3 messages', count === 3); finishTest(p3.id) }
103
- ws3.onerror = () => { assert('no error', false); finishTest(p3.id) }
104
- const timer3 = os.setTimeout(() => { if (!closed3) { assert('no timeout', false); finishTest(p3.id) } }, 15000)
105
- await p3.promise
106
- os.clearTimeout(timer3)
107
-
108
- // ── invalid URL ──
109
- t.section('invalid URL')
110
- const p4 = waitForTest()
111
- const ws4 = new WebSocket("not-a-websocket")
112
- let err4 = false
113
- ws4.onerror = () => { err4 = true }
114
- ws4.onclose = () => { assert('onerror fired', err4); finishTest(p4.id) }
115
- const timer4 = os.setTimeout(() => { assert('invalid url error', err4); finishTest(p4.id) }, 3000)
116
- await p4.promise
117
- os.clearTimeout(timer4)
118
-
119
- // ── invalid scheme ──
120
- t.section('invalid scheme (http://)')
121
- const p5 = waitForTest()
122
- const ws5 = new WebSocket("http://example.com/ws")
123
- let err5 = false
124
- ws5.onerror = () => { err5 = true }
125
- ws5.onclose = () => { assert('http scheme onerror', err5); finishTest(p5.id) }
126
- const timer5 = os.setTimeout(() => { assert('http scheme error guard', err5); finishTest(p5.id) }, 3000)
127
- await p5.promise
128
- os.clearTimeout(timer5)
129
-
130
- // ── early send/close ──
131
- t.section('send/close before onopen')
132
- const p6 = waitForTest()
133
- const ws6 = new WebSocket("ws://localhost:18923")
134
- ws6.send("noop")
135
- ws6.close(1000, "early")
136
- let close6 = false
137
- ws6.onopen = () => { assert('onopen after early close', false) }
138
- ws6.onclose = () => { close6 = true; assert('early close ok', true); finishTest(p6.id) }
139
- ws6.onerror = () => {}
140
- const timer6 = os.setTimeout(() => { if (!close6) assert('no crash', true); finishTest(p6.id) }, 5000)
141
- await p6.promise
142
- os.clearTimeout(timer6)
143
-
144
- // ── WSS (Secure WebSocket) ──
145
- t.section('wss basic text message')
146
- const p7 = waitForTest()
147
- let opened7 = false, received7 = false, closed7 = false
148
- const ws7 = new WebSocket("wss://localhost:18924", { rejectUnauthorized: false })
149
- ws7.onopen = () => { opened7 = true; ws7.send("Hello WSS!") }
150
- ws7.onmessage = () => { received7 = true; ws7.close(1000, "done") }
151
- ws7.onclose = (e) => {
152
- closed7 = true
153
- assert('wss onopen fired', opened7)
154
- assert('wss onmessage received', received7)
155
- assert('wss close code=1000', e.code === 1000)
156
- assert('wss wasClean', e.wasClean)
157
- finishTest(p7.id)
158
- }
159
- ws7.onerror = () => { assert('wss no error', false); finishTest(p7.id) }
160
- const timer7 = os.setTimeout(() => { if (!closed7) { assert('wss no timeout', false); finishTest(p7.id) } }, 10000)
161
- await p7.promise
162
- os.clearTimeout(timer7)
163
- }
164
- }
@@ -1,144 +0,0 @@
1
- import '../lib/polyfill.js';
2
- import * as std from 'std';
3
- function assert(t, name, ok) {
4
- if (ok) {
5
- t.ok++;
6
- std.printf(' PASS: %s\n', name);
7
- }
8
- else {
9
- t.fail++;
10
- std.printf(' FAIL: %s\n', name);
11
- }
12
- }
13
- export const suite = {
14
- name: 'polyfill',
15
- run: async (t) => {
16
- t.section('btoa/atob');
17
- const orig = "Hello\u0000World";
18
- const b64 = btoa(orig);
19
- const back = atob(b64);
20
- assert(t, 'btoa/atob roundtrip', back === orig);
21
- assert(t, 'btoa produces base64 chars', /^[A-Za-z0-9+/=]+$/.test(b64));
22
- const hash = new Uint8Array([0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84, 0x9e, 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12]);
23
- assert(t, 'btoa(SHA-1 sample) matches known value', btoa(String.fromCharCode(...hash)) === "L9ThxnotKPzthJ7hu3bnORuT6xI=");
24
- t.section('crypto.getRandomValues');
25
- const buf = new Uint8Array(32);
26
- crypto.getRandomValues(buf);
27
- assert(t, 'length=32', buf.length === 32);
28
- assert(t, 'not all zeros', buf.some(b => b !== 0));
29
- t.section('crypto.subtle.digest SHA-1');
30
- const data = new TextEncoder().encode("Hello");
31
- const hashBuf = await crypto.subtle.digest("SHA-1", data);
32
- const hb = new Uint8Array(hashBuf);
33
- assert(t, 'output length=20', hb.length === 20);
34
- assert(t, 'SHA-1(\'Hello\') matches', hb[0] === 0xF7 && hb[1] === 0xFF && hb[19] === 0xF0);
35
- t.section('TextEncoder utf-8');
36
- const enc = new TextEncoder();
37
- assert(t, 'default encoding', enc.encoding === 'utf-8');
38
- const encoded = enc.encode("Hello");
39
- assert(t, 'encode length', encoded.length === 5);
40
- assert(t, 'encode bytes', encoded[0] === 0x48 && encoded[4] === 0x6F);
41
- assert(t, 'encoding property', enc.encoding === 'utf-8');
42
- const enc2 = new TextEncoder('utf-8');
43
- assert(t, 'utf-8 label', enc2.encoding === 'utf-8');
44
- const enc3 = new TextEncoder('utf8');
45
- assert(t, 'utf8 alias', enc3.encoding === 'utf-8');
46
- let threw = false;
47
- try {
48
- new TextEncoder('gbk');
49
- }
50
- catch (e) {
51
- threw = e instanceof RangeError;
52
- }
53
- assert(t, 'unsupported label throws RangeError', threw);
54
- t.section('TextEncoder utf-16le');
55
- const enc16le = new TextEncoder('utf-16le');
56
- assert(t, 'encoding property', enc16le.encoding === 'utf-16le');
57
- const hello16le = enc16le.encode('AB');
58
- assert(t, 'length = 4', hello16le.length === 4);
59
- assert(t, 'A = 0x41 0x00', hello16le[0] === 0x41 && hello16le[1] === 0x00);
60
- assert(t, 'B = 0x42 0x00', hello16le[2] === 0x42 && hello16le[3] === 0x00);
61
- const null16le = enc16le.encode('\0');
62
- assert(t, 'null char = 0x00 0x00', null16le.length === 2 && null16le[0] === 0 && null16le[1] === 0);
63
- const chinese16le = enc16le.encode('\u4e2d'); // 中 = U+4E2D
64
- assert(t, '中 = 0x2D 0x4E', chinese16le[0] === 0x2D && chinese16le[1] === 0x4E);
65
- t.section('TextEncoder utf-16be');
66
- const enc16be = new TextEncoder('utf-16be');
67
- assert(t, 'encoding property', enc16be.encoding === 'utf-16be');
68
- const hello16be = enc16be.encode('AB');
69
- assert(t, 'length = 4', hello16be.length === 4);
70
- assert(t, 'A = 0x00 0x41', hello16be[0] === 0x00 && hello16be[1] === 0x41);
71
- assert(t, 'B = 0x00 0x42', hello16be[2] === 0x00 && hello16be[3] === 0x42);
72
- t.section('TextDecoder utf-8');
73
- const dec = new TextDecoder();
74
- assert(t, 'default encoding', dec.encoding === 'utf-8');
75
- assert(t, 'default fatal', dec.fatal === false);
76
- assert(t, 'default ignoreBOM', dec.ignoreBOM === false);
77
- assert(t, 'decode utf-8 bytes', dec.decode(encoded) === 'Hello');
78
- assert(t, 'decode empty', dec.decode() === '');
79
- assert(t, 'decode null', dec.decode(null) === '');
80
- const decFatal = new TextDecoder('utf-8', { fatal: true });
81
- assert(t, 'fatal encoding', decFatal.encoding === 'utf-8');
82
- assert(t, 'fatal true', decFatal.fatal === true);
83
- let threw2 = false;
84
- try {
85
- decFatal.decode(new Uint8Array([0xFF]));
86
- }
87
- catch (e) {
88
- threw2 = e instanceof TypeError;
89
- }
90
- assert(t, 'fatal decode throws TypeError', threw2);
91
- const nonFatal = new TextDecoder();
92
- const replaced = nonFatal.decode(new Uint8Array([0xFF]));
93
- assert(t, 'non-fatal replaces with U+FFFD', replaced === '\uFFFD');
94
- t.section('TextDecoder utf-16le');
95
- const dec16le = new TextDecoder('utf-16le');
96
- assert(t, 'encoding = utf-16le', dec16le.encoding === 'utf-16le');
97
- const ab = new Uint8Array([0x41, 0x00, 0x42, 0x00]);
98
- assert(t, 'AB from utf-16le', dec16le.decode(ab) === 'AB');
99
- const chn = new Uint8Array([0x2D, 0x4E]);
100
- assert(t, '中 from utf-16le', dec16le.decode(chn) === '\u4e2d');
101
- const withBom = new Uint8Array([0xFF, 0xFE, 0x41, 0x00]);
102
- assert(t, 'BOM stripped by default', dec16le.decode(withBom) === 'A');
103
- const dec16leNoBom = new TextDecoder('utf-16le', { ignoreBOM: true });
104
- assert(t, 'ignoreBOM keeps BOM', dec16leNoBom.decode(withBom) === '\uFEFFA');
105
- t.section('TextDecoder utf-16be');
106
- const dec16be = new TextDecoder('utf-16be');
107
- const be = new Uint8Array([0x00, 0x41, 0x00, 0x42]);
108
- assert(t, 'AB from utf-16be', dec16be.decode(be) === 'AB');
109
- const chnBe = new Uint8Array([0x4E, 0x2D]);
110
- assert(t, '中 from utf-16be', dec16be.decode(chnBe) === '\u4e2d');
111
- t.section('TextDecoder roundtrip');
112
- const texts = ['Hello', 'Hello 世界', '\u4e2d\u6587', 'A\0B', '\uD83D\uDE00']; // emoji
113
- for (const txt of texts) {
114
- const enc8 = new TextEncoder();
115
- const bytes = enc8.encode(txt);
116
- const dec8 = new TextDecoder();
117
- assert(t, `utf-8 roundtrip: ${txt}`, dec8.decode(bytes) === txt);
118
- const enc16le = new TextEncoder('utf-16le');
119
- const bytes16 = enc16le.encode(txt);
120
- const dec16le = new TextDecoder('utf-16le');
121
- assert(t, `utf-16le roundtrip: ${txt}`, dec16le.decode(bytes16) === txt);
122
- const enc16be = new TextEncoder('utf-16be');
123
- const bytes16be = enc16be.encode(txt);
124
- const dec16be = new TextDecoder('utf-16be');
125
- assert(t, `utf-16be roundtrip: ${txt}`, dec16be.decode(bytes16be) === txt);
126
- }
127
- t.section('SHA-1 + btoa (WebSocket accept key)');
128
- const MAGIC_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
129
- const testKey = 'dGhlIHNhbXBsZSBub25jZQ==';
130
- const concat = testKey + MAGIC_GUID;
131
- const acceptBuf = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(concat));
132
- const acceptBytes = new Uint8Array(acceptBuf);
133
- const acceptB64 = btoa(String.fromCharCode(...acceptBytes));
134
- assert(t, 'RFC 6455 accept key matches', acceptB64 === "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
135
- let rejected = false;
136
- try {
137
- await crypto.subtle.digest("SHA-256", new Uint8Array(1));
138
- }
139
- catch {
140
- rejected = true;
141
- }
142
- assert(t, 'unsupported algorithm rejected', rejected);
143
- }
144
- };
@@ -1,159 +0,0 @@
1
- import '../lib/polyfill.js'
2
- import * as std from 'std'
3
- import { Tester } from './test_helper.js'
4
-
5
- function assert(t: Tester, name: string, ok: boolean): void {
6
- if (ok) { t.ok++; std.printf(' PASS: %s\n', name) }
7
- else { t.fail++; std.printf(' FAIL: %s\n', name) }
8
- }
9
-
10
- export const suite = {
11
- name: 'polyfill',
12
- run: async (t: Tester) => {
13
- t.section('btoa/atob')
14
- const orig = "Hello\u0000World"
15
- const b64 = btoa(orig)
16
- const back = atob(b64)
17
- assert(t, 'btoa/atob roundtrip', back === orig)
18
- assert(t, 'btoa produces base64 chars', /^[A-Za-z0-9+/=]+$/.test(b64))
19
-
20
- const hash = new Uint8Array([0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84, 0x9e, 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12])
21
- assert(t, 'btoa(SHA-1 sample) matches known value', btoa(String.fromCharCode(...hash)) === "L9ThxnotKPzthJ7hu3bnORuT6xI=")
22
-
23
- t.section('crypto.getRandomValues')
24
- const buf = new Uint8Array(32)
25
- crypto.getRandomValues(buf)
26
- assert(t, 'length=32', buf.length === 32)
27
- assert(t, 'not all zeros', buf.some(b => b !== 0))
28
-
29
- t.section('crypto.subtle.digest SHA-1')
30
- const data = new TextEncoder().encode("Hello")
31
- const hashBuf = await crypto.subtle.digest("SHA-1", data)
32
- const hb = new Uint8Array(hashBuf)
33
- assert(t, 'output length=20', hb.length === 20)
34
- assert(t, 'SHA-1(\'Hello\') matches', hb[0] === 0xF7 && hb[1] === 0xFF && hb[19] === 0xF0)
35
-
36
- t.section('TextEncoder utf-8')
37
- const enc = new TextEncoder()
38
- assert(t, 'default encoding', enc.encoding === 'utf-8')
39
- const encoded = enc.encode("Hello")
40
- assert(t, 'encode length', encoded.length === 5)
41
- assert(t, 'encode bytes', encoded[0] === 0x48 && encoded[4] === 0x6F)
42
- assert(t, 'encoding property', enc.encoding === 'utf-8')
43
-
44
- const enc2 = new TextEncoder('utf-8')
45
- assert(t, 'utf-8 label', enc2.encoding === 'utf-8')
46
-
47
- const enc3 = new TextEncoder('utf8')
48
- assert(t, 'utf8 alias', enc3.encoding === 'utf-8')
49
-
50
- let threw = false
51
- try { new TextEncoder('gbk' as any) } catch (e) { threw = e instanceof RangeError }
52
- assert(t, 'unsupported label throws RangeError', threw)
53
-
54
- t.section('TextEncoder utf-16le')
55
- const enc16le = new TextEncoder('utf-16le')
56
- assert(t, 'encoding property', enc16le.encoding === 'utf-16le')
57
-
58
- const hello16le = enc16le.encode('AB')
59
- assert(t, 'length = 4', hello16le.length === 4)
60
- assert(t, 'A = 0x41 0x00', hello16le[0] === 0x41 && hello16le[1] === 0x00)
61
- assert(t, 'B = 0x42 0x00', hello16le[2] === 0x42 && hello16le[3] === 0x00)
62
-
63
- const null16le = enc16le.encode('\0')
64
- assert(t, 'null char = 0x00 0x00', null16le.length === 2 && null16le[0] === 0 && null16le[1] === 0)
65
-
66
- const chinese16le = enc16le.encode('\u4e2d') // 中 = U+4E2D
67
- assert(t, '中 = 0x2D 0x4E', chinese16le[0] === 0x2D && chinese16le[1] === 0x4E)
68
-
69
- t.section('TextEncoder utf-16be')
70
- const enc16be = new TextEncoder('utf-16be')
71
- assert(t, 'encoding property', enc16be.encoding === 'utf-16be')
72
-
73
- const hello16be = enc16be.encode('AB')
74
- assert(t, 'length = 4', hello16be.length === 4)
75
- assert(t, 'A = 0x00 0x41', hello16be[0] === 0x00 && hello16be[1] === 0x41)
76
- assert(t, 'B = 0x00 0x42', hello16be[2] === 0x00 && hello16be[3] === 0x42)
77
-
78
- t.section('TextDecoder utf-8')
79
- const dec = new TextDecoder()
80
- assert(t, 'default encoding', dec.encoding === 'utf-8')
81
- assert(t, 'default fatal', dec.fatal === false)
82
- assert(t, 'default ignoreBOM', dec.ignoreBOM === false)
83
- assert(t, 'decode utf-8 bytes', dec.decode(encoded) === 'Hello')
84
- assert(t, 'decode empty', dec.decode() === '')
85
- assert(t, 'decode null', dec.decode(null) === '')
86
-
87
- const decFatal = new TextDecoder('utf-8', { fatal: true })
88
- assert(t, 'fatal encoding', decFatal.encoding === 'utf-8')
89
- assert(t, 'fatal true', decFatal.fatal === true)
90
-
91
- let threw2 = false
92
- try { decFatal.decode(new Uint8Array([0xFF])) } catch (e) { threw2 = e instanceof TypeError }
93
- assert(t, 'fatal decode throws TypeError', threw2)
94
-
95
- const nonFatal = new TextDecoder()
96
- const replaced = nonFatal.decode(new Uint8Array([0xFF]))
97
- assert(t, 'non-fatal replaces with U+FFFD', replaced === '\uFFFD')
98
-
99
- t.section('TextDecoder utf-16le')
100
- const dec16le = new TextDecoder('utf-16le')
101
- assert(t, 'encoding = utf-16le', dec16le.encoding === 'utf-16le')
102
-
103
- const ab = new Uint8Array([0x41, 0x00, 0x42, 0x00])
104
- assert(t, 'AB from utf-16le', dec16le.decode(ab) === 'AB')
105
-
106
- const chn = new Uint8Array([0x2D, 0x4E])
107
- assert(t, '中 from utf-16le', dec16le.decode(chn) === '\u4e2d')
108
-
109
- const withBom = new Uint8Array([0xFF, 0xFE, 0x41, 0x00])
110
- assert(t, 'BOM stripped by default', dec16le.decode(withBom) === 'A')
111
-
112
- const dec16leNoBom = new TextDecoder('utf-16le', { ignoreBOM: true })
113
- assert(t, 'ignoreBOM keeps BOM', dec16leNoBom.decode(withBom) === '\uFEFFA')
114
-
115
- t.section('TextDecoder utf-16be')
116
- const dec16be = new TextDecoder('utf-16be')
117
- const be = new Uint8Array([0x00, 0x41, 0x00, 0x42])
118
- assert(t, 'AB from utf-16be', dec16be.decode(be) === 'AB')
119
-
120
- const chnBe = new Uint8Array([0x4E, 0x2D])
121
- assert(t, '中 from utf-16be', dec16be.decode(chnBe) === '\u4e2d')
122
-
123
- t.section('TextDecoder roundtrip')
124
- const texts = ['Hello', 'Hello 世界', '\u4e2d\u6587', 'A\0B', '\uD83D\uDE00'] // emoji
125
- for (const txt of texts) {
126
- const enc8 = new TextEncoder()
127
- const bytes = enc8.encode(txt)
128
- const dec8 = new TextDecoder()
129
- assert(t, `utf-8 roundtrip: ${txt}`, dec8.decode(bytes) === txt)
130
-
131
- const enc16le = new TextEncoder('utf-16le')
132
- const bytes16 = enc16le.encode(txt)
133
- const dec16le = new TextDecoder('utf-16le')
134
- assert(t, `utf-16le roundtrip: ${txt}`, dec16le.decode(bytes16) === txt)
135
-
136
- const enc16be = new TextEncoder('utf-16be')
137
- const bytes16be = enc16be.encode(txt)
138
- const dec16be = new TextDecoder('utf-16be')
139
- assert(t, `utf-16be roundtrip: ${txt}`, dec16be.decode(bytes16be) === txt)
140
- }
141
-
142
- t.section('SHA-1 + btoa (WebSocket accept key)')
143
- const MAGIC_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
144
- const testKey = 'dGhlIHNhbXBsZSBub25jZQ=='
145
- const concat = testKey + MAGIC_GUID
146
- const acceptBuf = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(concat))
147
- const acceptBytes = new Uint8Array(acceptBuf)
148
- const acceptB64 = btoa(String.fromCharCode(...acceptBytes))
149
- assert(t, 'RFC 6455 accept key matches', acceptB64 === "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
150
-
151
- let rejected = false
152
- try {
153
- await crypto.subtle.digest("SHA-256" as any, new Uint8Array(1))
154
- } catch {
155
- rejected = true
156
- }
157
- assert(t, 'unsupported algorithm rejected', rejected)
158
- }
159
- }
@@ -1,137 +0,0 @@
1
- import * as ffi from 'ffi';
2
- import * as os from 'os';
3
- import { WCHAR } from '../lib/ffi/bind.js';
4
- import { structArray } from '../lib/ffi/struct.js';
5
- import { NULL, PtrArrayBuffer } from '../lib/ffi/ctype.js';
6
- import { CloseHandle, CreateFile, DeleteFile, GetLastError, GetTempPath, GetFileSize, ReadFile } from '../lib/windows/kernel32.js';
7
- import { ClosePrinter, DeviceCapabilities, EnumPrinters, EndDocPrinter, EndPagePrinter, GetDefaultPrinter, OpenPrinter, StartDocPrinter, StartPagePrinter, WritePrinter, } from '../lib/windows/winspool.js';
8
- import { PRINTER_INFO_2W } from '../lib/windows/structs.js';
9
- // PrinterEnum.LOCAL(0x2) | CONNECTIONS(0x4):可组合 flags 组合 OR 裸传
10
- const LOCAL_OR_CONNECTIONS = 0x6;
11
- const MAX_WCHARS = 4096;
12
- // 指针字段跟进读宽字符串 / 跨架构读指针(test_ffi.ts 同型)
13
- function decodeWideAtPtr(ptr) {
14
- if (!ptr)
15
- return '';
16
- const chars = [];
17
- let pos = ptr;
18
- while (chars.length < MAX_WCHARS) {
19
- const ch = ffi.readByte(pos) + ffi.readByte(pos + 1) * 256;
20
- if (ch === 0)
21
- break;
22
- chars.push(ch);
23
- pos += 2;
24
- }
25
- return String.fromCharCode(...chars);
26
- }
27
- function readPtr(dv, offset) {
28
- if (os.arch === 'ia32')
29
- return dv.getUint32(offset, true);
30
- return dv.getUint32(offset, true) + dv.getUint32(offset + 4, true) * 4294967296;
31
- }
32
- export const suite = {
33
- name: 'printer',
34
- run: (t) => {
35
- t.section('EnumPrinters: two-pass LOCAL|CONNECTIONS');
36
- const neededB = new PtrArrayBuffer(4);
37
- const returnedB = new PtrArrayBuffer(4);
38
- const neededU = new Uint32Array(neededB);
39
- const returnedU = new Uint32Array(returnedB);
40
- EnumPrinters(LOCAL_OR_CONNECTIONS, NULL, 2, NULL, 0, neededB, returnedB);
41
- if (neededU[0] === 0) {
42
- // 无打印机环境(XP VM):整段优雅跳过——属环境差异非缺陷(test_ffi 先例)
43
- t.skipCase('printer suite (no printers on this VM)');
44
- return;
45
- }
46
- t.checkTrue(`pcbNeeded > 0 (${neededU[0]})`, neededU[0] > 0);
47
- const buf = new PtrArrayBuffer(neededU[0]);
48
- t.checkTrue('EnumPrinters full buffer', EnumPrinters(LOCAL_OR_CONNECTIONS, NULL, 2, buf, neededU[0], neededB, returnedB) !== 0);
49
- const count = returnedU[0];
50
- t.checkTrue(`found printers (${count})`, count > 0);
51
- // 出参数组读回:结构数组区 = 前 count*size 字节,尾部是字符串数据
52
- // (byteLength 非 size 整数倍)→ 必须显式 count;指针字段跟进读字符串
53
- const infos = structArray(PRINTER_INFO_2W).decode(buf, count);
54
- t.check('decode count == pcReturned', count, infos.length);
55
- // 单值 decode 与数组 decode 首元素一致(布局单一来源互证,无硬编码 offset)
56
- t.checkTrue('array/single decode agree', PRINTER_INFO_2W.decode(buf).pPrinterName === infos[0].pPrinterName);
57
- const names = [];
58
- const ports = {};
59
- for (const inf of infos) {
60
- const name = decodeWideAtPtr(inf.pPrinterName);
61
- names.push(name);
62
- ports[name] = decodeWideAtPtr(inf.pPortName);
63
- }
64
- t.section('GetDefaultPrinter');
65
- const defW = WCHAR.alloc(260);
66
- const lenB = new PtrArrayBuffer(4);
67
- new Uint32Array(lenB)[0] = 260;
68
- t.checkTrue('GetDefaultPrinter ok', GetDefaultPrinter(defW, lenB) !== 0);
69
- const defName = WCHAR.decode(defW);
70
- t.checkTrue(`default in enum list (${defName})`, names.includes(defName));
71
- t.section('DeviceCapabilities: numeric caps on default printer');
72
- const defPort = ports[defName] ?? NULL;
73
- const horz = DeviceCapabilities(defName, defPort, 8 /* DeviceCap.HORZRES */, NULL, NULL);
74
- t.checkTrue(`HORZRES sane (${horz})`, horz > 0);
75
- const vert = DeviceCapabilities(defName, defPort, 10 /* DeviceCap.VERTRES */, NULL, NULL);
76
- t.checkTrue(`VERTRES sane (${vert})`, vert > 0);
77
- t.section('raw job chain on default printer (FILE: port -> .prn file, no UI)');
78
- // 输出文件放系统 temp(GetTempPath 尾带反斜杠)——FILE: 端口把作业写到 pOutputFile
79
- const tmpW = WCHAR.alloc(260);
80
- GetTempPath(260, tmpW);
81
- const outPrn = `${WCHAR.decode(tmpW)}qw_job.prn`;
82
- const slot = new PtrArrayBuffer(8);
83
- t.checkTrue('OpenPrinter ok', OpenPrinter(defName, slot, NULL) !== 0);
84
- const hPrinter = readPtr(new DataView(slot), 0);
85
- t.checkTrue(`hPrinter valid (${hPrinter})`, hPrinter !== 0);
86
- // pDatatype 省略(NULL)→ spooler 用打印机默认 datatype;显式传 RAW/XPS_PASS 反而
87
- // 可能被驱动拒——1804 = ERROR_INVALID_DATATYPE(官方错误码表;注意 StartDocPrinter
88
- // 不设置 last error,GetLastError 读到的常是残留值)
89
- const jobId = StartDocPrinter(hPrinter, 1, {
90
- pDocName: WCHAR.encode('QuickWin Raw Job').ptr, // <>ptr 字段收裸地址(number 子类型)
91
- pOutputFile: WCHAR.encode(outPrn).ptr,
92
- });
93
- if (jobId === 0) {
94
- // 失败即暴露(1804 = ERROR_INVALID_DATATYPE——datatype 显式 RAW/XPS_PASS 会被
95
- // XPS 驱动拒,NULL 让 spooler 用默认即通;StartDocPrinter 不设置 last error,
96
- // 下方诊断值常是残留)
97
- t.checkTrue(`StartDocPrinter job id > 0 (lastError=${GetLastError()})`, false);
98
- ClosePrinter(hPrinter);
99
- return;
100
- }
101
- t.checkTrue(`StartDocPrinter job id > 0`, jobId > 0);
102
- const sp = StartPagePrinter(hPrinter);
103
- t.checkTrue(`StartPagePrinter (lastError=${GetLastError()})`, sp !== 0);
104
- const job = 'hello printer';
105
- const jBuf = new PtrArrayBuffer(job.length);
106
- const jDv = new DataView(jBuf);
107
- for (let i = 0; i < job.length; i++)
108
- jDv.setUint8(i, job.charCodeAt(i));
109
- const pWr = new PtrArrayBuffer(4);
110
- const wr = WritePrinter(hPrinter, jBuf, job.length, pWr);
111
- t.checkTrue(`WritePrinter ok (lastError=${GetLastError()})`, wr !== 0);
112
- t.check('bytes written', job.length, new Uint32Array(pWr)[0]);
113
- const ep = EndPagePrinter(hPrinter);
114
- t.checkTrue(`EndPagePrinter (lastError=${GetLastError()})`, ep !== 0);
115
- const ed = EndDocPrinter(hPrinter);
116
- t.checkTrue(`EndDocPrinter (lastError=${GetLastError()})`, ed !== 0);
117
- t.checkTrue('ClosePrinter', ClosePrinter(hPrinter) !== 0);
118
- // 作业落盘断言:FILE: 端口把 RAW 数据写到 pOutputFile
119
- const hOut = CreateFile(outPrn, 0x80000000 /* GENERIC_READ */, 0, NULL, 3 /* FileCreation.OPEN_EXISTING */, 0, NULL);
120
- t.checkTrue(`job file exists (${outPrn})`, hOut !== -1);
121
- if (hOut !== -1) {
122
- const fSize = GetFileSize(hOut, NULL);
123
- t.checkTrue(`job file size > 0 (${fSize})`, fSize > 0);
124
- const fBuf = new PtrArrayBuffer(Math.max(fSize, 1));
125
- const pRd = new PtrArrayBuffer(4);
126
- ReadFile(hOut, fBuf, fSize, pRd, NULL);
127
- // RAW 通道(winprint + RAW)应原样落盘——若 XPS 驱动重渲染则 FAIL 揭示实际内容头
128
- let back = '';
129
- const fDv = new DataView(fBuf);
130
- for (let i = 0; i < Math.min(fSize, job.length); i++)
131
- back += String.fromCharCode(fDv.getUint8(i));
132
- t.check('job data roundtrip (RAW passthrough)', job, back);
133
- CloseHandle(hOut);
134
- }
135
- DeleteFile(outPrn);
136
- },
137
- };