1/* eslint-disable */ 2/** 3 * Classic Web Worker that runs the qpdf CLI compiled to WebAssembly locally in 4 * the browser. 5 * 6 * Why local: the edge function runs the same WASM, but an edge worker has a 7 * small fixed memory budget and qpdf needs the whole document addressable in 8 * memory (the encryption key is document-wide and the xref must be parsed 9 * first, so decryption cannot be chunked). Multi-MB files therefore died with 10 * WORKER_RESOURCE_LIMIT. A browser tab has orders of magnitude more heap, so we 11 * run it here and keep the server only as a fallback. 12 * 13 * Protocol: 14 * in { id, args: string[], bytes: ArrayBuffer } 15 * out { id, ok: true, bytes: ArrayBuffer } | { id, ok: false, error, exitCode } 16 */ 17self.importScripts("/qpdf/qpdf.js"); 18 19self.onmessage = async (ev) => { 20 const { id, args, bytes } = ev.data || {}; 21 const stderr = []; 22 let exitCode = 0; 23 let module; 24 25 try { 26 module = await self.Module({ 27 locateFile: (p) => (p.endsWith(".wasm") ? "/qpdf/qpdf.wasm" : "/qpdf/" + p), 28 noInitialRun: true, 29 print: () => {}, 30 printErr: (s) => { stderr.push(String(s)); }, 31 quit: (code) => { exitCode = code; }, 32 }); 33 } catch (e) { 34 self.postMessage({ id, ok: false, error: "engine-init: " + (e && e.message ? e.message : String(e)) }); 35 return; 36 } 37 38 try { 39 // Some Emscripten builds capture their logging hooks before the factory 40 // options are merged, so re-assign them on the live module too. 41 module.printErr = (s) => { stderr.push(String(s)); }; 42 module.print = () => {}; 43 // This qpdf build is minified and writes some diagnostics straight to the 44 // console, so tap the console as well to recover the real reason. 45 const realError = console.error; 46 const realWarn = console.warn; 47 console.error = (...a) => { stderr.push(a.join(" ")); }; 48 console.warn = (...a) => { stderr.push(a.join(" ")); }; 49 const restore = () => { console.error = realError; console.warn = realWarn; }; 50 module.FS.writeFile("/in.pdf", new Uint8Array(bytes)); 51 try { 52 module.callMain(args); 53 } catch (e) { 54 if (e && typeof e.status === "number") exitCode = e.status; 55 else if (e) stderr.push("threw: " + (e.message || String(e))); 56 } 57 58 restore(); 59 60 let out = null; 61 try { out = module.FS.readFile("/out.pdf"); } catch (_) { out = null; } 62 63 // qpdf exit 3 means "completed with warnings" â the output is written and 64 // usable, which is the normal case for damaged documents. 65 if (out && out.length > 100 && (exitCode === 0 || exitCode === 3)) { 66 const buf = out.buffer.slice(out.byteOffset, out.byteOffset + out.byteLength); 67 self.postMessage({ id, ok: true, bytes: buf }, [buf]); 68 } else { 69 self.postMessage({ 70 id, 71 ok: false, 72 exitCode, 73 error: stderr.join("\n").slice(0, 500), 74 }); 75 } 76 } catch (e) { 77 self.postMessage({ id, ok: false, error: (e && e.message) || String(e) }); 78 } finally { 79 try { module.FS.unlink("/in.pdf"); } catch (_) {} 80 try { module.FS.unlink("/out.pdf"); } catch (_) {} 81 // A fresh module per run keeps the WASM heap from growing across files. 82 module = null; 83 } 84};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.