diff --git a/.gitignore b/.gitignore index a547bf3..4294bde 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +package-lock.json + # Logs logs *.log diff --git a/Makefile b/Makefile index a13b31e..822b95d 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,10 @@ build: dev: npm run dev -- --host +.PHONY: init +init: + npm i + .PHONY: deps deps: # protos diff --git a/README.md b/README.md index 6878fc5..8fec4e7 100644 --- a/README.md +++ b/README.md @@ -65,17 +65,81 @@ copy the raw byte representation (array of numbers) or parsed object (JSON). ## Development +### Website + `make dev` starts the dev server. `make build` generates the static site. -## Refreshing Protos and Messages +`make init` installs dependencies. -`make deps` requires a SIP-disabled Intel Mac with Keynote + Numbers + Pages. +### Protos and Messages + +`make deps` requires a SIP-disabled Mac with Keynote + Numbers + Pages. The last run was on 2023-09-24 against version 13.2 (7038.0.87) -Each app should be run at least once before refreshing artifacts. +#### Software License Agreements + +Before refreshing, each app must be launched once and the software license +agreements must be accepted. + +In the 13.2 update, Keynote clearly states + +> By clicking Continue you agree to the terms of the Keynote Software License Agreement + +Curiously, the Numbers "What's New in Numbers" popup does not have a similar +disclaimer. It is suspected that clicking "Continue" in Numbers and Pages serves +a similar purpose. + +#### Disabling SIP + +1) Enter Recovery mode: + +On Intel Macs, shut down and restart while holding down Command+R keys. + +On Apple Silicon Macs, shut down and restart while holding down the Touch ID. +It will display a message "Continue holding for startup options". Let go once +the message changes to "Loading startup options" + +Select "Options" in the boot window and click the "Continue" button. + +2) Open a terminal window (Utilities > Terminal) and run the following command: + +``` +csrutil disable +``` + +If there is no error, restart the machine. + +**Apple Silicon Extra Steps** + +If the command fails with a message like + +``` +csrutil: The OS environment does not allow changing security configuration options. +Ensure that the system was booted into Recovery OS via the standard user action. +``` + +3) Run the following command: + +``` +csrutil clear +``` + +4) Open the "Startup Security Utility" (in the Utilities menu) + +5) Click "Security Policy..." and select "Permissive Security". Click "OK". + +6) Reboot into recovery mode (explained in Step 1) + +7) Open a terminal window (Utilities > Terminal) and run: + +``` +csrutil disable +``` + +**Remember to re-enable SIP after updating messages!** #### Developer Tools error @@ -85,10 +149,13 @@ Note: Runs may fail with an error like error: Uncaught (in promise) "Could not find map!" ``` -Developer tools permissions must be granted. Running the command a second time -typically shows a popup asking for Touch ID or password. After authorization, -the build should run successfully. +Running the command a second time typically shows a popup: +""" +Developer Tools Access needs to take control of another process for debugging to continue +""" + +It will ask for Touch ID or password. After authorization, the build should run. ## Protocol Buffer Details diff --git a/misc/dump_registry.ts b/misc/dump_registry.ts index 4b6e4ea..f18b27e 100644 --- a/misc/dump_registry.ts +++ b/misc/dump_registry.ts @@ -2,26 +2,36 @@ /*! dump_registry.ts (C) 2022-present SheetJS LLC -- https://sheetjs.com */ /* -NOTE: this script requires an Intel Mac, Numbers, LLDB, and Deno +NOTE: this script requires a SIP-disabled Mac, Numbers, LLDB, and Deno USAGE: deno run -A https://oss.sheetjs.com/notes/iwa/dump_registry.ts */ if(Deno.build.os != "darwin") throw `Must run in macOS!`; -if(Deno.build.arch != "x86_64") throw `Must run on Intel Mac (Apple Silicon currently unsupported)`; +const arch_map = { + "x86_64": "x86_64", + "aarch64": "arm64" +}; + +if(!arch_map[Deno.build.arch]) throw `Unsupported architecture ${Deno.build.arch}`; + +const cmd = Deno?.args?.[0] || "/Applications/Numbers.app/Contents/MacOS/Numbers"; +try { Deno.statSync(cmd); } catch(e) { throw `Could not find ${cmd}!`; } + +/* test if SIP is disabled */ { const p = Deno.run({cmd:["csrutil","status"],stdin:"piped",stdout:"piped" }); const [status, stdout] = await Promise.all([ p.status(), p.output() ]); await p.close(); const data = new TextDecoder().decode(stdout); - //if(data.includes("enabled")) throw `SIP must be disabled!`; + if(!data.includes("disabled")) throw `SIP must be disabled!`; } -const p = Deno.run({ cmd: `lldb ${Deno?.args?.[0] || "/Applications/Numbers.app/Contents/MacOS/Numbers"} -a x86_64`.split(" "), - stdin: "piped", stdout: "piped" -}); +/* start debugger */ +const p = Deno.run({ cmd: `lldb ${cmd} -a ${arch_map[Deno.build.arch]}`.split(" "), stdin: "piped", stdout: "piped" }); +/* run commands */ const doit = (x: string) => p?.stdin?.write(new TextEncoder().encode(x)) const cmds = [ @@ -37,21 +47,26 @@ const cmds = [ for(const cmd of cmds) await doit(cmd + "\n"); /* LLDB does not exit normally, setTimeout workaround */ -setTimeout(() => p.kill("SIGKILL"), 15000) +setTimeout(() => p.kill("SIGKILL"), 30000) +/* wait for debugger */ const [status, stdout] = await Promise.all([ p.status(), p.output() ]); await p.close(); +/* search for _messageTypeToPrototypeMap */ const data = new TextDecoder().decode(stdout); const res = data.match(/_messageTypeToPrototypeMap = {([^]*?)}/m)?.[1]; -if(!res) throw `Could not find map!` +if(!res) throw `Could not find map!`; + +/* extract records and sort by ID */ const rows = res.split(/[\r\n]+/).map(r => r.trim().split(/\s+/)).filter(x => x.length > 1); rows.sort((l, r) => +l[0] - +r[0]); + +/* emit code */ console.log(`export default {`); rows.forEach(r => { + /* setDeprecatedMessageType */ if(r[3] == "null") return; console.log(` ${r[0]}: ".${r[3]}",`); }); console.log(`} as {[key: number]: string};`); - -//console.log(Object.fromEntries(rows.map(r => [r[0], r[3]]).filter(r => r[1] != "null"))); diff --git a/src/iwa.ts b/src/iwa.ts index cb3e0c5..fa03c04 100644 --- a/src/iwa.ts +++ b/src/iwa.ts @@ -372,7 +372,7 @@ function process(data: Uint8Array, message: string, protos: any) { switch(freq) { case "repeated": { if(/packed\s*=\s*true/.test(line)) { - /* these are the known types as of iwa 13.0 */ + /* these are the known types as of iwa 13.2 */ switch(type) { case "uint32": out[name] = parse_packed_varints(shallow[i][0].data); break; case "uint64": out[name] = parse_packed_varint64(shallow[i][0].data); break;