quickwin 3.0.0 → 3.0.2

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 (253) hide show
  1. package/README.en.md +3 -0
  2. package/README.md +2 -0
  3. package/lib/abort.d.ts +21 -0
  4. package/lib/assert.d.ts +2 -0
  5. package/lib/bitmap.d.ts +7 -0
  6. package/lib/cache-utils.d.ts +6 -0
  7. package/lib/certs.d.ts +1 -0
  8. package/lib/dpi.d.ts +9 -0
  9. package/lib/dumpRects.d.ts +2 -0
  10. package/lib/exec-log.d.ts +23 -0
  11. package/lib/fetch.d.ts +4 -0
  12. package/lib/ffi/bind.d.ts +70 -0
  13. package/lib/ffi/ctype.d.ts +117 -0
  14. package/lib/ffi/index.d.ts +2 -0
  15. package/lib/ffi/struct.d.ts +174 -0
  16. package/lib/http-common.d.ts +143 -0
  17. package/lib/http-server.d.ts +59 -0
  18. package/lib/polyfill.d.ts +22 -0
  19. package/lib/react-qw/components/Button.d.ts +9 -0
  20. package/lib/react-qw/components/CheckBox.d.ts +11 -0
  21. package/lib/react-qw/components/ComboBox.d.ts +11 -0
  22. package/lib/react-qw/components/DateTimePicker.d.ts +15 -0
  23. package/lib/react-qw/components/Input.d.ts +15 -0
  24. package/lib/react-qw/components/Link.d.ts +12 -0
  25. package/lib/react-qw/components/ListBox.d.ts +13 -0
  26. package/lib/react-qw/components/ListView.d.ts +37 -0
  27. package/lib/react-qw/components/PathPicker.d.ts +23 -0
  28. package/lib/react-qw/components/ProgressBar.d.ts +9 -0
  29. package/lib/react-qw/components/RadioButton.d.ts +11 -0
  30. package/lib/react-qw/components/ScrollView.d.ts +9 -0
  31. package/lib/react-qw/components/Slider.d.ts +12 -0
  32. package/lib/react-qw/components/Tab.d.ts +14 -0
  33. package/lib/react-qw/components/Tooltip.d.ts +7 -0
  34. package/lib/react-qw/components/TreeView.d.ts +18 -0
  35. package/lib/react-qw/components/index.d.ts +16 -0
  36. package/lib/react-qw/index.d.ts +24 -0
  37. package/lib/react-qw/layout.d.ts +29 -0
  38. package/lib/react-qw/nmhdr.d.ts +1 -0
  39. package/lib/react-qw/props.d.ts +2 -0
  40. package/lib/react-qw/reconciler.d.ts +21 -0
  41. package/lib/stream.d.ts +20 -0
  42. package/lib/text-codec.d.ts +39 -0
  43. package/lib/text-measure.d.ts +14 -0
  44. package/lib/url.d.ts +54 -0
  45. package/lib/websocket.d.ts +73 -0
  46. package/lib/windows/{advapi32.ts → advapi32.d.ts} +6 -21
  47. package/lib/windows/comctl32.d.ts +14 -0
  48. package/lib/windows/comdlg32.d.ts +4 -0
  49. package/lib/windows/{gdi32.ts → gdi32.d.ts} +161 -98
  50. package/lib/windows/{kernel32.ts → kernel32.d.ts} +138 -115
  51. package/lib/windows/{msimg32.ts → msimg32.d.ts} +11 -14
  52. package/lib/windows/ntdll.d.ts +5 -0
  53. package/lib/windows/ole32.d.ts +3 -0
  54. package/lib/windows/{psapi.ts → psapi.d.ts} +9 -18
  55. package/lib/windows/{shell32.ts → shell32.d.ts} +25 -24
  56. package/lib/windows/structs.d.ts +3141 -0
  57. package/lib/windows/{user32.ts → user32.d.ts} +196 -193
  58. package/lib/windows/version.d.ts +27 -0
  59. package/lib/windows/{winspool.ts → winspool.d.ts} +18 -32
  60. package/package.json +15 -8
  61. package/qwin-nowasm-x86.exe +0 -0
  62. package/qwin-nowasm.exe +0 -0
  63. package/qwin-x86.exe +0 -0
  64. package/qwin.exe +0 -0
  65. package/examples/PdfCanvas.js +0 -38
  66. package/examples/PdfCanvas.tsx +0 -54
  67. package/examples/execd/main.js +0 -23379
  68. package/examples/execd/tray.js +0 -192
  69. package/examples/execd/worker.js +0 -122
  70. package/examples/pdf_preview2.js +0 -398
  71. package/examples/pdf_preview2.ts +0 -353
  72. package/examples/pdf_viewer.js +0 -22515
  73. package/examples/pdf_viewer.tsx +0 -228
  74. package/examples/test_gallery.js +0 -18692
  75. package/examples/test_gallery.tsx +0 -291
  76. package/examples/test_react_lazy.js +0 -18560
  77. package/examples/test_react_lazy.tsx +0 -65
  78. package/examples/test_react_listbox.js +0 -18562
  79. package/examples/test_react_listbox.tsx +0 -73
  80. package/examples/test_root_window.js +0 -18532
  81. package/examples/test_root_window.tsx +0 -41
  82. package/examples/test_tab.js +0 -18563
  83. package/examples/test_tab.tsx +0 -77
  84. package/examples/tray_demo.js +0 -86
  85. package/examples/tray_demo.tsx +0 -89
  86. package/lib/abort.ts +0 -69
  87. package/lib/assert.ts +0 -7
  88. package/lib/bitmap.ts +0 -39
  89. package/lib/cache-utils.ts +0 -40
  90. package/lib/certs.ts +0 -258
  91. package/lib/dpi.ts +0 -31
  92. package/lib/dumpRects.ts +0 -34
  93. package/lib/exec-log.ts +0 -30
  94. package/lib/fetch.ts +0 -589
  95. package/lib/ffi/bind.ts +0 -540
  96. package/lib/ffi/ctype.ts +0 -371
  97. package/lib/ffi/index.ts +0 -6
  98. package/lib/ffi/struct.ts +0 -780
  99. package/lib/http-common.ts +0 -441
  100. package/lib/http-server.ts +0 -604
  101. package/lib/polyfill.ts +0 -171
  102. package/lib/react-qw/components/index.ts +0 -17
  103. package/lib/react-qw/index.ts +0 -96
  104. package/lib/react-qw/layout.ts +0 -111
  105. package/lib/react-qw/nmhdr.ts +0 -7
  106. package/lib/react-qw/props.ts +0 -41
  107. package/lib/react-qw/reconciler.ts +0 -379
  108. package/lib/stream.ts +0 -22
  109. package/lib/text-codec.ts +0 -171
  110. package/lib/text-measure.ts +0 -44
  111. package/lib/url.ts +0 -201
  112. package/lib/websocket.ts +0 -600
  113. package/lib/windows/comctl32.ts +0 -20
  114. package/lib/windows/comdlg32.ts +0 -10
  115. package/lib/windows/ntdll.ts +0 -11
  116. package/lib/windows/ole32.ts +0 -9
  117. package/lib/windows/structs.ts +0 -807
  118. package/lib/windows/version.ts +0 -35
  119. package/test/add.wasm +0 -0
  120. package/test/bench_ffi_callraw.js +0 -235
  121. package/test/bench_ffi_callraw.ts +0 -235
  122. package/test/bench_ffi_overhead.js +0 -139
  123. package/test/bench_ffi_overhead.ts +0 -141
  124. package/test/bench_sendmessage.js +0 -104
  125. package/test/bench_sendmessage.ts +0 -100
  126. package/test/bench_sendmessage_nonnull.js +0 -187
  127. package/test/bench_sendmessage_nonnull.ts +0 -188
  128. package/test/complex.wasm +0 -0
  129. package/test/complex_imports.wasm +0 -0
  130. package/test/debug/http_server_e2e.js +0 -31
  131. package/test/debug/minwasm.js +0 -52
  132. package/test/debug/mupdf_debug.js +0 -86
  133. package/test/debug/wasm.js +0 -122
  134. package/test/debug/wasm_export_debug.js +0 -54
  135. package/test/debug/wasm_names.js +0 -36
  136. package/test/example.pdf +0 -0
  137. package/test/global_imports.wasm +0 -0
  138. package/test/import_func.wasm +0 -0
  139. package/test/imports.wasm +0 -0
  140. package/test/mupdf-cdn.js +0 -40
  141. package/test/mupdf-cdn.ts +0 -43
  142. package/test/run.js +0 -111
  143. package/test/run.ts +0 -116
  144. package/test/sjlj.wasm +0 -0
  145. package/test/test_basic.js +0 -7
  146. package/test/test_basic.ts +0 -9
  147. package/test/test_basic_fetch.js +0 -63
  148. package/test/test_basic_fetch.ts +0 -59
  149. package/test/test_brotli.js +0 -48
  150. package/test/test_brotli.ts +0 -52
  151. package/test/test_fetch_cache.js +0 -169
  152. package/test/test_fetch_cache.ts +0 -187
  153. package/test/test_ffi.js +0 -157
  154. package/test/test_ffi.ts +0 -170
  155. package/test/test_ffi_abi.js +0 -290
  156. package/test/test_ffi_abi.ts +0 -274
  157. package/test/test_ffi_array.js +0 -116
  158. package/test/test_ffi_array.ts +0 -141
  159. package/test/test_ffi_bind.js +0 -656
  160. package/test/test_ffi_bind.ts +0 -670
  161. package/test/test_ffi_struct.js +0 -779
  162. package/test/test_ffi_struct.ts +0 -828
  163. package/test/test_ffi_struct_layout.js +0 -495
  164. package/test/test_ffi_struct_layout.ts +0 -543
  165. package/test/test_ffi_user32.js +0 -103
  166. package/test/test_ffi_user32.ts +0 -113
  167. package/test/test_ffi_windows.js +0 -172
  168. package/test/test_ffi_windows.ts +0 -187
  169. package/test/test_files.js +0 -102
  170. package/test/test_files.ts +0 -121
  171. package/test/test_frame_encoding.js +0 -128
  172. package/test/test_frame_encoding.ts +0 -132
  173. package/test/test_gdi_draw.js +0 -681
  174. package/test/test_gdi_draw.ts +0 -725
  175. package/test/test_helper.js +0 -91
  176. package/test/test_helper.ts +0 -88
  177. package/test/test_http_import.js +0 -96
  178. package/test/test_http_import.ts +0 -93
  179. package/test/test_http_server.js +0 -214
  180. package/test/test_http_server.ts +0 -211
  181. package/test/test_import_dir.js +0 -4
  182. package/test/test_import_dir.ts +0 -5
  183. package/test/test_ipv6.js +0 -134
  184. package/test/test_ipv6.ts +0 -130
  185. package/test/test_jsx.js +0 -1314
  186. package/test/test_meta_url.js +0 -3
  187. package/test/test_meta_url.ts +0 -4
  188. package/test/test_mupdf_render.js +0 -51
  189. package/test/test_mupdf_render.ts +0 -55
  190. package/test/test_mupdf_twice.js +0 -62
  191. package/test/test_mupdf_twice.ts +0 -65
  192. package/test/test_mupdf_wasm.js +0 -39
  193. package/test/test_mupdf_wasm.ts +0 -32
  194. package/test/test_net_event.js +0 -57
  195. package/test/test_net_event.ts +0 -56
  196. package/test/test_net_fetch.js +0 -384
  197. package/test/test_net_fetch.ts +0 -373
  198. package/test/test_net_websocket.js +0 -180
  199. package/test/test_net_websocket.ts +0 -164
  200. package/test/test_polyfill.js +0 -144
  201. package/test/test_polyfill.ts +0 -159
  202. package/test/test_printer.js +0 -137
  203. package/test/test_printer.ts +0 -148
  204. package/test/test_proc.js +0 -141
  205. package/test/test_proc.ts +0 -163
  206. package/test/test_react_complex.js +0 -18678
  207. package/test/test_react_counter.js +0 -18555
  208. package/test/test_react_flex.js +0 -18871
  209. package/test/test_react_hidden.js +0 -18560
  210. package/test/test_react_listview_link.js +0 -18590
  211. package/test/test_react_notify.js +0 -18797
  212. package/test/test_react_render.js +0 -18550
  213. package/test/test_registry.js +0 -74
  214. package/test/test_registry.ts +0 -95
  215. package/test/test_sysinfo.js +0 -122
  216. package/test/test_sysinfo.ts +0 -141
  217. package/test/test_url.js +0 -173
  218. package/test/test_url.ts +0 -183
  219. package/test/test_wasm_basic.js +0 -85
  220. package/test/test_wasm_basic.ts +0 -73
  221. package/test/test_wasm_import_global.js +0 -41
  222. package/test/test_wasm_import_global.ts +0 -45
  223. package/test/test_wasm_sjlj.js +0 -145
  224. package/test/test_wasm_sjlj.ts +0 -125
  225. package/test/test_wasm_types.js +0 -97
  226. package/test/test_wasm_types.ts +0 -124
  227. package/test/test_wolfssl_read.js +0 -203
  228. package/test/test_wolfssl_read.ts +0 -184
  229. package/test/test_worker.js +0 -21
  230. package/test/test_worker.ts +0 -24
  231. package/test/test_worker_concurrent.js +0 -45
  232. package/test/test_worker_concurrent.ts +0 -56
  233. package/test/test_worker_data_url.js +0 -46
  234. package/test/test_worker_data_url.ts +0 -51
  235. package/test/test_worker_fetch.js +0 -26
  236. package/test/test_worker_fetch.ts +0 -27
  237. package/test/test_worker_net.js +0 -69
  238. package/test/test_worker_net.ts +0 -66
  239. package/test/test_worker_wasm_concurrent.js +0 -44
  240. package/test/test_worker_wasm_concurrent.ts +0 -45
  241. package/test/types.wasm +0 -0
  242. package/test/worker_fetch.js +0 -13
  243. package/test/worker_fetch.ts +0 -13
  244. package/test/worker_helper.js +0 -1
  245. package/test/worker_helper.ts +0 -1
  246. package/test/worker_http.js +0 -18
  247. package/test/worker_http.ts +0 -20
  248. package/test/worker_import_lib.js +0 -12
  249. package/test/worker_import_lib.ts +0 -13
  250. package/test/worker_module.js +0 -16
  251. package/test/worker_module.ts +0 -17
  252. package/test/worker_wasm_concurrent.js +0 -22
  253. 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
- };