Compare commits
15 Commits
SHJS-XXX/f
...
main
Author | SHA1 | Date | |
---|---|---|---|
5636a455fc | |||
ff281f9311 | |||
c04812f839 | |||
ba9c776731 | |||
8ed1b0bdc0 | |||
2f3bd1eef9 | |||
1b7dde139d | |||
74312fbaf4 | |||
27e1e66da5 | |||
c76b5be2a9 | |||
a087c06552 | |||
990fa5880b | |||
4b4d1dbd8a | |||
9974f85e6d | |||
e71d278673 |
@ -1,3 +1,4 @@
|
||||
/* eslint-env commonjs */
|
||||
module.exports = {
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
@ -9,6 +10,9 @@ module.exports = {
|
||||
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'react-hooks/exhaustive-deps': 'off',
|
||||
'react-refresh/only-export-components': 'warn',
|
||||
'no-regex-spaces': 'off',
|
||||
},
|
||||
}
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
package-lock.json
|
||||
deno.lock
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
14
Makefile
14
Makefile
@ -4,12 +4,22 @@ build:
|
||||
|
||||
.PHONY: dev
|
||||
dev:
|
||||
npm run dev
|
||||
npm run dev -- --host
|
||||
|
||||
.PHONY: init
|
||||
init:
|
||||
npm i
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
deps: deps-protos deps-messages
|
||||
|
||||
.PHONY: deps-protos
|
||||
deps-protos:
|
||||
# protos
|
||||
deno run -rA misc/otorp.ts > public/protos
|
||||
|
||||
.PHONY: deps-messages
|
||||
deps-messages:
|
||||
# src/messages
|
||||
deno run -rA misc/dump_registry.ts /Applications/Numbers.app/Contents/MacOS/Numbers > src/messages/numbers.ts
|
||||
deno run -rA misc/dump_registry.ts /Applications/Keynote.app/Contents/MacOS/Keynote > src/messages/keynote.ts
|
||||
|
177
README.md
177
README.md
@ -4,22 +4,189 @@ source for <https://sheetjs.com/tools/iwa-inspector>
|
||||
|
||||
`iwa-inspector` is a tool for inspecting iWork archives.
|
||||
|
||||
When a file is loaded, a table will display the messages in the file.
|
||||
<https://oss.sheetjs.com/notes/iwa/> covers the high-level structure of files.
|
||||
This inspector performs the top-level extraction of messages and parses using
|
||||
extracted Protocol Buffer definitions.
|
||||
|
||||
When a message is selected, the page will display the Protocol Buffers
|
||||
definition for the message as well as an inspector for the message and metadata.
|
||||
## Usage
|
||||
|
||||
The sections are separated by a light gray horizontal line and a light gray
|
||||
vertical line. Panels can be resized by click-dragging the line.
|
||||
|
||||
### Selecting a File
|
||||
|
||||
The file input element in the top-left corner of the page is limited to the IWA
|
||||
file types: `.numbers`, `.key`, and `.pages`.
|
||||
|
||||
The site automatically fetches a sample file on load.
|
||||
|
||||
### Message Table
|
||||
|
||||
The message table is shown just below the header bar. The column headers are:
|
||||
|
||||
| name | description |
|
||||
|:----------|:----------------------|
|
||||
| `id` | Message ID |
|
||||
| `type` | Numeric Message Type |
|
||||
| `message` | Absolute Message Type |
|
||||
| `path` | Location of Message |
|
||||
|
||||
The table can be sorted by clicking on the column headers.
|
||||
|
||||
### Searching for Messages
|
||||
|
||||
The search text box in the top-right corner of the page is a plaintext search
|
||||
over the parsed messages. Searches will match field names, string values and
|
||||
UUID fields of message type `.TSP.UUID`.
|
||||
|
||||
### Selecting a Message
|
||||
|
||||
When a row in the table is selected, the bottom-left panel will display the
|
||||
Protocol Buffers definition for the message and the bottom-right panel will
|
||||
display the parsed contents.
|
||||
|
||||
### Message Structure
|
||||
|
||||
The bottom-right panel shows the following information:
|
||||
|
||||
- "Message": parsed information following the message definition
|
||||
- "Metadata": parsed information from the message metadata
|
||||
- "Dependents": list of messages that list the current message as a dependency.
|
||||
|
||||
Clicking on a message name in the inspector will show the message definition in
|
||||
the left pane. A "Return" link returns to the base message definition.
|
||||
|
||||
Clicking on a `.TSP.Reference` ID will jump to the referenced message.
|
||||
|
||||
### Exporting Data
|
||||
|
||||
Right-clicking a custom message type will show a context menu with options to
|
||||
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 data
|
||||
`make init` installs dependencies.
|
||||
|
||||
`make deps` requires a SIP-disabled Intel Mac. The last run used v13.0 apps.
|
||||
### Protos and Messages
|
||||
|
||||
`make deps` requires a SIP-disabled Mac with Keynote + Numbers + Pages.
|
||||
|
||||
The dependencies were refreshed on 2024-12-18 against version 14.3 (7042.0.76).
|
||||
|
||||
Due to breaking changes, Deno must be rolled back to version 1.46.3. The scripts
|
||||
are not compatible with Deno 2!
|
||||
|
||||
14.2 deprecated message 0x847 (`.TSWP.UpdateDateTimeFieldCommandArchive`).
|
||||
Curiously the message definition was retained in the protobuf definitions. The
|
||||
message type has been preserved in the messages list.
|
||||
|
||||
#### Software License Agreements
|
||||
|
||||
Before refreshing, each app must be launched once and the software license
|
||||
agreements must be accepted.
|
||||
|
||||
In the 14.3 update, Keynote and Pages clearly state:
|
||||
|
||||
> By clicking Continue you agree to the terms of the Keynote Software License Agreement
|
||||
|
||||
#### 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
|
||||
|
||||
Note: Runs may fail with an error like
|
||||
|
||||
```
|
||||
error: Uncaught (in promise) "Could not find map!"
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
Note that the `message` field is absolute. For example, `TSTArchives.proto`
|
||||
specifies the `.TST.TileStorage` as follows:
|
||||
|
||||
```proto
|
||||
package TST;
|
||||
|
||||
message TileStorage {
|
||||
message Tile {
|
||||
required uint32 tileid = 1;
|
||||
required .TSP.Reference tile = 2;
|
||||
}
|
||||
repeated .TST.TileStorage.Tile tiles = 1;
|
||||
optional uint32 tile_size = 2;
|
||||
optional bool should_use_wide_rows = 3;
|
||||
}
|
||||
```
|
||||
|
||||
The protobuf extractor rewrites the message names using the absolute form:
|
||||
|
||||
```proto
|
||||
message .TST.TileStorage {
|
||||
message Tile {
|
||||
required uint32 tileid = 1;
|
||||
required .TSP.Reference tile = 2;
|
||||
}
|
||||
repeated .TST.TileStorage.Tile tiles = 1;
|
||||
optional uint32 tile_size = 2;
|
||||
optional bool should_use_wide_rows = 3;
|
||||
}
|
||||
```
|
||||
|
@ -4,8 +4,10 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/png" href="https://sheetjs.com/favico/favicon-196x196.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>SheetJS IWA Inspector</title>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-title" content="IWA Inspector">
|
||||
<link rel="canonical" href="https://sheetjs.com/tools/iwa-inspector" />
|
||||
<title>SheetJS IWA Inspector</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
@ -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")));
|
||||
|
10892
package-lock.json
generated
10892
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@ -14,26 +14,26 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"cfb": "1.2.2",
|
||||
"printj": "1.3.1",
|
||||
"react": "18.2.0",
|
||||
"printj": "https://cdn.sheetjs.com/printj-1.3.2/printj-1.3.2.tgz",
|
||||
"react": "18.3.1",
|
||||
"react-contexify": "6.0.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-inspector": "6.0.1",
|
||||
"react-resizable-panels": "0.0.45",
|
||||
"react-dom": "18.3.1",
|
||||
"react-inspector": "6.0.2",
|
||||
"react-resizable-panels": "2.0.19",
|
||||
"react-toastify": "9.1.3",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz"
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "18.2.6",
|
||||
"@types/react-dom": "18.2.4",
|
||||
"@typescript-eslint/eslint-plugin": "5.59.5",
|
||||
"@typescript-eslint/parser": "5.59.5",
|
||||
"@vitejs/plugin-react": "4.0.0",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-react-refresh": "0.3.5",
|
||||
"typescript": "5.0.4",
|
||||
"vite": "4.3.5",
|
||||
"vite-plugin-pwa": "0.14.7"
|
||||
"@types/react": "18.3.3",
|
||||
"@types/react-dom": "18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "7.13.0",
|
||||
"@typescript-eslint/parser": "7.13.0",
|
||||
"@vitejs/plugin-react": "4.3.1",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-plugin-react-hooks": "4.6.2",
|
||||
"eslint-plugin-react-refresh": "0.4.7",
|
||||
"typescript": "5.4.5",
|
||||
"vite": "5.3.0",
|
||||
"vite-plugin-pwa": "0.20.0"
|
||||
}
|
||||
}
|
||||
|
878
public/protos
878
public/protos
File diff suppressed because it is too large
Load Diff
@ -2,13 +2,13 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100vw;
|
||||
html, body {
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100vw;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
@ -34,7 +34,7 @@ th {
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
max-width: 100%;
|
||||
position: sticky;
|
||||
position: sticky;
|
||||
box-shadow: 0 -5px 15px 0 #ced4da;
|
||||
background: white;
|
||||
z-index: 10;
|
||||
|
278
src/App.tsx
278
src/App.tsx
@ -1,20 +1,22 @@
|
||||
/* TODO:
|
||||
- history
|
||||
- find example and correctly handle "merge" messages
|
||||
- messages referencing selected msg
|
||||
- sort and filter table
|
||||
- filter table by message type or path
|
||||
- loading icons
|
||||
- expand referenced object in place
|
||||
- expand referenced object in place or accordian
|
||||
- paste bytes -> analyze
|
||||
- edit fields / files?
|
||||
- different menu for message / enum / extend / literal
|
||||
- display integers in base16 and base10
|
||||
- search bytes?
|
||||
- highlight results in inspector
|
||||
*/
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import type { MouseEvent as ReactMouseEvent, ChangeEventHandler, ChangeEvent } from 'react';
|
||||
import './App.css';
|
||||
import { ObjectInspector, ObjectLabel, ObjectName, ObjectValue } from 'react-inspector';
|
||||
import { PanelGroup, Panel, PanelResizeHandle } from 'react-resizable-panels';
|
||||
import { process, read, ParsedFile } from './iwa';
|
||||
import { process, read, ParsedFile, TableItem } from './iwa';
|
||||
import { parse_protos, ProtoMap } from './messages';
|
||||
import type { $_TSP_MessageInfo, $_TSP_Reference } from './messages';
|
||||
import { Menu, Item, Separator, useContextMenu } from 'react-contexify';
|
||||
@ -22,24 +24,47 @@ import 'react-contexify/dist/ReactContexify.css';
|
||||
import { ToastContainer, toast } from 'react-toastify';
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
|
||||
const uuid2str = (l: bigint, u: bigint): string => [
|
||||
((l >> 0n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((l >> 8n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((l >> 16n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((l >> 24n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
"-",
|
||||
((l >> 32n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((l >> 40n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
"-",
|
||||
((l >> 48n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((l >> 56n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
"-",
|
||||
((u >> 0n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((u >> 8n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
"-",
|
||||
((u >> 16n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((u >> 24n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((u >> 32n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((u >> 40n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((u >> 48n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
((u >> 56n) & 0xFFn).toString(16).padStart(2, "0"),
|
||||
].join("").toUpperCase();
|
||||
|
||||
//#region Xxd
|
||||
|
||||
//import { vsprintf } from 'printj';
|
||||
/*const X = "%02hhx", Y = X + X + " ";
|
||||
import { vsprintf } from 'printj';
|
||||
const X = "%02hhx", Y = X + X + " ";
|
||||
const FMT = [...Array.from({length:16}).map((_,i) =>
|
||||
Y.repeat(i>>1) + (i%2 ? X:" ") + " " + " ".repeat(7 - (i >> 1)) + "|" + "%c".repeat(i) + " ".repeat(16-i) + "|\n"
|
||||
), Y.repeat(8) + "|" + "%c".repeat(16) + "|\n"];
|
||||
|
||||
const xxd = (u8: Uint8Array): string => {
|
||||
let out: string[] = [];
|
||||
const out: string[] = [];
|
||||
for(let i = 0; i < u8.length; i+=16) {
|
||||
let d = [...u8.slice(i, i+16)];
|
||||
const d = [...u8.slice(i, i+16)];
|
||||
out.push(vsprintf(`%04x: ${FMT[d.length]}`, [i, ...d, ...d.map(x => String.fromCharCode(x).replace(/[^\x20-\x7E]/g,"."))]))
|
||||
}
|
||||
return out.join("");
|
||||
}
|
||||
|
||||
type XxdProps = {
|
||||
/*type XxdProps = {
|
||||
data?: Uint8Array;
|
||||
};
|
||||
|
||||
@ -56,19 +81,23 @@ type TableViewProps = {
|
||||
id?: string;
|
||||
data: any[];
|
||||
cols: string[];
|
||||
sort?: string;
|
||||
desc?: boolean;
|
||||
filter?: (row: any, R: number) => boolean;
|
||||
rowclick?: (row: any, R: number, e: ReactMouseEvent<HTMLTableRowElement, MouseEvent>) => void;
|
||||
cellclick?: (value: any, R: number, C: number, e: ReactMouseEvent<HTMLTableCellElement, MouseEvent>) => void;
|
||||
onsort?: (sort: string) => void;
|
||||
};
|
||||
|
||||
function TableView({id, data, cols, rowclick, cellclick}: TableViewProps) {
|
||||
function TableView({id, data, cols, filter, rowclick, cellclick, sort, desc, onsort}: TableViewProps) {
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>{cols.map((c,idx) => (
|
||||
<th key={idx}>{c}</th>
|
||||
<th key={idx} onClick={()=>{ if(onsort) onsort(c); }}>{c} {sort == c ? (desc ? "\u25BC" : "\u25B2") : ""}</th>
|
||||
))}</tr>
|
||||
</thead>
|
||||
<tbody>{data.map((row, R) => (
|
||||
<tbody>{data.filter(filter || (()=>true)).map((row, R) => (
|
||||
<tr id={`tr-${R}`} key={R}
|
||||
{...(rowclick ? {onClick: (e) => {e.preventDefault(); e.stopPropagation(); rowclick(row, R, e)}} : {})}
|
||||
{...(row["id"] == id ? {style: {backgroundColor: "#646cff", color: "#FFFFFF" }} : {})}
|
||||
@ -97,8 +126,9 @@ interface ContextMenuProps {
|
||||
onClickCopyByteArray?: ({props}: any)=>void;
|
||||
onClickCopyJSON: ({props}: any)=>void;
|
||||
showProtoDef: ({props}: any)=>void;
|
||||
showXXD: ({props}: any) => void;
|
||||
}
|
||||
const ContextMenu = ({ID, menuType, menuField, menuId, onClickId, onClickCopyByteArray, onClickCopyJSON, showProtoDef}: ContextMenuProps) => (
|
||||
const ContextMenu = ({ID, menuType, menuField, menuId, onClickId, onClickCopyByteArray, onClickCopyJSON, showProtoDef, showXXD}: ContextMenuProps) => (
|
||||
<Menu id={ID}>
|
||||
{menuField && (<Item disabled><b>{menuField}</b></Item>)}
|
||||
<Item disabled><b>{menuType}</b></Item>
|
||||
@ -106,11 +136,53 @@ const ContextMenu = ({ID, menuType, menuField, menuId, onClickId, onClickCopyByt
|
||||
<Separator />
|
||||
<Item onClick={onClickCopyByteArray}>Copy byte array</Item>
|
||||
<Item onClick={onClickCopyJSON}>Copy JSON</Item>
|
||||
<Item onClick={showProtoDef}>Show Definition</Item>
|
||||
<Item hidden={()=>menuType == "bytes"} onClick={showProtoDef}>Show Definition</Item>
|
||||
<Item hidden={()=>menuType != "bytes"} onClick={showXXD}>Dump XXD to console</Item>
|
||||
</Menu> );
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region preparse
|
||||
|
||||
const replacer = (_: string, v: any): any => {
|
||||
switch(true) {
|
||||
case (typeof v == "bigint"): return v.toString();
|
||||
case (v instanceof Uint8Array): return [...v];
|
||||
case (v != null && typeof v.lower == "bigint" && typeof v.upper == "bigint"): return uuid2str(v.lower, v.upper);
|
||||
}
|
||||
return v;
|
||||
};
|
||||
|
||||
/* parse if message has not been parsed */
|
||||
const preparse = (id: any, message: string, f: ParsedFile, p: ProtoMap) => {
|
||||
const item = f.space[+id][0];
|
||||
if(!item.parsed) {
|
||||
item.parsed = process(item.data, message, p);
|
||||
item.pre = JSON.stringify(item.parsed, replacer);
|
||||
}
|
||||
if(!item.parsedmeta) {
|
||||
const m: $_TSP_MessageInfo = item.parsedmeta = process(item.rawmeta, ".TSP.MessageInfo", p);
|
||||
/* .TSP.MessageInfo */
|
||||
if(m.object_references) m.$object_references = m.object_references.map((n: bigint) => {
|
||||
/* create a fake reference for the inspector */
|
||||
const o: $_TSP_Reference = ({ identifier: n });
|
||||
Object.defineProperty(o, "PB_TYPE", {value: ".TSP.Reference", enumerable: false});
|
||||
return o;
|
||||
});
|
||||
if(m.field_infos) m.field_infos.forEach((fi) => {
|
||||
/* .TSP.FieldInfo */
|
||||
if(fi.object_references) fi.$object_references = fi.object_references.map((n: bigint) => {
|
||||
/* create a fake reference for the inspector */
|
||||
const o: $_TSP_Reference = ({ identifier: n });
|
||||
Object.defineProperty(o, "PB_TYPE", {value: ".TSP.Reference", enumerable: false});
|
||||
return o;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
function App() {
|
||||
/* selected message ID */
|
||||
const [id, setId] = useState<string>("0");
|
||||
@ -120,6 +192,8 @@ function App() {
|
||||
const [obj, setObj] = useState<any>({});
|
||||
/* current meta */
|
||||
const [meta, setMeta] = useState<$_TSP_MessageInfo>({} as any);
|
||||
/* current deps */
|
||||
const [deps, setDeps] = useState<any[]>([]);
|
||||
/* protobuf definitions */
|
||||
const [protos, setProtos] = useState<ProtoMap>({});
|
||||
/* selected message type */
|
||||
@ -128,6 +202,12 @@ function App() {
|
||||
const [__html, setProto] = useState<string>("Select a Row");
|
||||
/* "dirty" if inspecting a subfield */
|
||||
const [dirty, setDirty] = useState<boolean>(false);
|
||||
/* loading */
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
/* search */
|
||||
const [search, setSearch] = useState<string>("");
|
||||
/* level */
|
||||
const [level, setLevel] = useState<number>(1);
|
||||
/* history stack */
|
||||
const [stack, setStack] = useState<string[]>([]);
|
||||
/* react-contexify */
|
||||
@ -137,13 +217,44 @@ function App() {
|
||||
const [menuType, setMenuType] = useState<string>("");
|
||||
const [menuId, setMenuId] = useState<string>("");
|
||||
const tblRef = useRef<HTMLDivElement>(null);
|
||||
/* sorting */
|
||||
const [ sort, setSort ] = useState<string>("");
|
||||
const [ desc, setDesc ] = useState<boolean>(false);
|
||||
|
||||
/* scroll to selected row */
|
||||
const tblScroll = (R: number) => {
|
||||
if(R == -1) return;
|
||||
const rowelt = document.getElementById(`tr-${R}`);
|
||||
const top = rowelt?.offsetTop || 0;
|
||||
if(tblRef.current) {
|
||||
const tbl = tblRef.current;
|
||||
if(top > tbl.scrollTop + tbl.clientHeight - (rowelt?.clientHeight||0) || top < tbl.scrollTop + (rowelt?.clientHeight||0)) tbl.scrollTop = Math.max(0, top - tbl.clientHeight/2 - (rowelt?.clientHeight||0)/2);
|
||||
}
|
||||
};
|
||||
|
||||
/* Sorting machinations */
|
||||
const onsort = (s: string) => {
|
||||
let d = false;
|
||||
console.log(sort == s, desc);
|
||||
if(sort == s) setDesc(d = !desc);
|
||||
else {
|
||||
setDesc(d = false);
|
||||
setSort(s);
|
||||
}
|
||||
file.tbl.sort((x: any, y: any) => (typeof x[s] == "number" ? x[s] - y[s] : String(x[s]).localeCompare(String(y[s]))) * (d ? -1 : 1));
|
||||
};
|
||||
useEffect(() => {
|
||||
if(id) tblScroll(file.tbl.findIndex(row => row["id"] == +id));
|
||||
}, [sort, desc]);
|
||||
|
||||
/* update selection based on table row */
|
||||
const doitRow = (row: any, R: number, reset?: boolean) => {
|
||||
const doitRow = (row: TableItem, R: number, reset?: boolean) => {
|
||||
let obj: any, meta: $_TSP_MessageInfo;
|
||||
try {
|
||||
obj = process(file.space[+row.id][0].data, row.message, protos);
|
||||
meta = process(file.space[+row.id][0].rawmeta, ".TSP.MessageInfo", protos);
|
||||
preparse(row.id, row.message, file, protos);
|
||||
const item = file.space[+row.id][0];
|
||||
obj = item.parsed;
|
||||
meta = item.parsedmeta as $_TSP_MessageInfo;
|
||||
} catch(e) {
|
||||
console.error(row, e); toast.error(`Could not parse ${row.id} (${row.type})`, {position: toast.POSITION.TOP_CENTER}); return;
|
||||
}
|
||||
@ -152,36 +263,19 @@ function App() {
|
||||
setProto(protos[row.message] || "");
|
||||
setDirty(false);
|
||||
setObj(obj);
|
||||
/* .TSP.MessageInfo */
|
||||
if(meta.object_references) meta.$object_references = meta.object_references.map((n: BigInt) => {
|
||||
/* create a fake reference for the inspector */
|
||||
var o: $_TSP_Reference = ({ identifier: n });
|
||||
Object.defineProperty(o, "PB_TYPE", {value: ".TSP.Reference", enumerable: false});
|
||||
return o;
|
||||
});
|
||||
if(meta.field_infos) meta.field_infos.forEach((fi) => {
|
||||
/* .TSP.FieldInfo */
|
||||
if(fi.object_references) fi.$object_references = fi.object_references.map((n: BigInt) => {
|
||||
/* create a fake reference for the inspector */
|
||||
var o: $_TSP_Reference = ({ identifier: n });
|
||||
Object.defineProperty(o, "PB_TYPE", {value: ".TSP.Reference", enumerable: false});
|
||||
return o;
|
||||
});
|
||||
})
|
||||
setMeta(meta);
|
||||
setDeps(file.tbl.filter(r => ((file.space[+r.id][0].parsedmeta?.object_references||[])?.indexOf(BigInt(row.id)) > -1)).map(v => {
|
||||
/* this copy uses non-enumerable fields */
|
||||
const o = {}; Object.entries(v).forEach(([k,v])=> Object.defineProperty(o, k, { enumerable: false, value: v })); return o;
|
||||
}));
|
||||
setId(String(row.id));
|
||||
var rowelt = document.getElementById(`tr-${R}`);
|
||||
var top = rowelt?.offsetTop || 0;
|
||||
if(tblRef.current) {
|
||||
let tbl = tblRef.current;
|
||||
if(top > tbl.scrollTop + tbl.clientHeight - (rowelt?.clientHeight||0) || top < tbl.scrollTop + (rowelt?.clientHeight||0)) tbl.scrollTop = Math.max(0, top - tbl.clientHeight/2 - (rowelt?.clientHeight||0)/2);
|
||||
}
|
||||
tblScroll(R);
|
||||
};
|
||||
/* click event handler for the messages table */
|
||||
const rowclick = (row: any, R: number) => { doitRow(row, R, true); };
|
||||
/* helper for .TSP.Reference */
|
||||
const gotoRef = (id: string) => {
|
||||
var R = file.tbl.findIndex(t => +t.id == +id);
|
||||
const R = file.tbl.findIndex(t => +t.id == +id);
|
||||
if (R == -1) throw new Error(`Message ${id} not found`);
|
||||
doitRow(file.tbl[R], R, false);
|
||||
};
|
||||
@ -191,34 +285,61 @@ function App() {
|
||||
const pop = () => {
|
||||
const oldId = stack.pop()||"0";
|
||||
setStack([...stack]);
|
||||
var R = file.tbl.findIndex(t => +t.id == +oldId);
|
||||
const R = file.tbl.findIndex(t => +t.id == +oldId);
|
||||
if (R == -1) throw new Error(`Message ${oldId} not found`);
|
||||
doitRow(file.tbl[R], R);
|
||||
};
|
||||
|
||||
/* on load, get protobuf definitions and process the test file */
|
||||
/* filter message table */
|
||||
const filter = (row: any) => {
|
||||
if(!search) return true;
|
||||
preparse(row.id, row.message, file, protos);
|
||||
return (file.space[+row.id][0].pre||"").toLowerCase().indexOf(search.toLowerCase()) > -1;
|
||||
//return row.message == ".TN.SheetArchive";
|
||||
}
|
||||
|
||||
/* load file */
|
||||
const process_ab = (ab: ArrayBuffer, p: ProtoMap = protos) => {
|
||||
const f = read(ab);
|
||||
f.tbl.forEach(row => preparse(row.id, row.message, f, p));
|
||||
setFile(f);
|
||||
};
|
||||
|
||||
/* on page load, get protobuf definitions and process the test file */
|
||||
useEffect(() => {
|
||||
const id = toast.loading(`Processing test.numbers`);
|
||||
let ignore = false;
|
||||
(async () => {
|
||||
await new Promise((res) => setTimeout(res, 100)); // "sleep" to give toast a chance to shine
|
||||
const protos = await (await fetch("protos")).text();
|
||||
const testfile = await (await fetch("test.numbers")).arrayBuffer();
|
||||
if(ignore) return;
|
||||
setProtos(parse_protos(protos));
|
||||
setFile(read(testfile));
|
||||
const p = parse_protos(protos);
|
||||
setProtos(p);
|
||||
process_ab(testfile, p);
|
||||
toast.dismiss(id);
|
||||
setLoading(false);
|
||||
})();
|
||||
return () => { ignore = true; }
|
||||
return () => { ignore = true; toast.dismiss(id); }
|
||||
}, []);
|
||||
useEffect(() => { if(file.tbl[0]) doitRow(file.tbl[0], 0, true); }, [file]);
|
||||
|
||||
const onChange: ChangeEventHandler<HTMLInputElement> = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if(!e.target.files) { toast.error("must select a file!"); throw new Error("No file selected!"); }
|
||||
let data: ParsedFile;
|
||||
try { data = read(await e.target.files?.[0].arrayBuffer()); } catch(e) {
|
||||
setLoading(true);
|
||||
if(!e.target.files) { toast.error("must select a file!"); throw new Error("No file selected!"); setLoading(false); }
|
||||
try {
|
||||
const id = toast.loading(`Processing ${e.target.files[0].name}`);
|
||||
await new Promise((res) => setTimeout(res, 100)); // "sleep" to give toast a chance to shine
|
||||
process_ab(await e.target.files?.[0].arrayBuffer());
|
||||
toast.dismiss(id);
|
||||
} catch(e) {
|
||||
if((e as any).message?.includes("Failed to read archive")) toast.error("Please select an iWork file", { position: toast.POSITION.TOP_CENTER });
|
||||
else toast.error(e && (e as any).message || e, { position: toast.POSITION.TOP_CENTER });
|
||||
console.error(e); return;
|
||||
console.error(e);
|
||||
} finally {
|
||||
e.target.value = "";
|
||||
setLoading(false);
|
||||
}
|
||||
setFile(data);
|
||||
}
|
||||
|
||||
/* Menu machinations */
|
||||
@ -236,7 +357,7 @@ function App() {
|
||||
}
|
||||
function onClickId(){ gotoRef(menuId); }
|
||||
function onClickCopyByteArray({ props }: {props: MenuProps}){
|
||||
var _data = props?.data?.PB_RAW?.data || (+props.id == +id) && file.space[+id][0].data;
|
||||
const _data = props?.data?.PB_RAW?.data || (+props.id == +id) && file.space[+id][0].data;
|
||||
if(!_data) throw new Error("Could not find raw data");
|
||||
navigator.clipboard.writeText("[" + [..._data].map(x => "0x" + x.toString(16).toUpperCase().padStart(2,"0")).join(", ") + "]");
|
||||
}
|
||||
@ -245,7 +366,9 @@ function App() {
|
||||
navigator.clipboard.writeText(JSON.stringify(props.data, (_,v) => typeof v == "bigint" ? v.toString() : v instanceof Uint8Array ? [...v]: v));
|
||||
}
|
||||
function showProtoDef({props}: {props: MenuProps}) { selectProto(props.type); }
|
||||
function showXXD({props}: {props: MenuProps}) { console.log(xxd(props.data)); }
|
||||
|
||||
/* Inspector machinations */
|
||||
type NodeRendererProps = {
|
||||
depth: number;
|
||||
name: string;
|
||||
@ -264,15 +387,30 @@ function App() {
|
||||
<b>{data.PB_ENUM && <> = {data.PB_ENUM}</>} [{data.PB_TYPE}]</b>
|
||||
</a> );
|
||||
if(data.PB_TYPE == ".TSP.Reference") {
|
||||
let id = String(data?.identifier);
|
||||
const id = String(data?.identifier);
|
||||
return ( <span onContextMenu={(e) => {displayMenu(e, { type: data.PB_TYPE, id, data, field: data.PB_FIELD })}}>
|
||||
<ObjectName name={name} />: <b>{frag} -> <a onClick={() => {gotoRef(id)}}><b>{id}</b></a></b>
|
||||
</span> );
|
||||
}
|
||||
if(data.PB_TYPE == ".TSP.UUID") {
|
||||
const uuid = uuid2str(data.lower, data.upper);
|
||||
return ( <span onContextMenu={(e) => {displayMenu(e, { type: data.PB_TYPE, id, data, field: data.PB_FIELD })}}>
|
||||
<ObjectName name={name} />: <b>{frag} -> {uuid}</b>
|
||||
</span> );
|
||||
}
|
||||
return ( <span onContextMenu={(e) => {displayMenu(e, { type: data.PB_TYPE, id, data, field: data.PB_FIELD })}}>
|
||||
<ObjectName name={name} />: {frag}
|
||||
</span> );
|
||||
}
|
||||
if(data instanceof Uint8Array) return (
|
||||
<span onContextMenu={(e) => {displayMenu(e, { type: "bytes", id, data, field: (data as any).PB_FIELD })}}>
|
||||
<ObjectLabel name={name} data={data} isNonenumerable={isNonenumerable} />
|
||||
</span>
|
||||
);
|
||||
// Uncomment to show hex representation of unsigned 32-bit ints
|
||||
//if(typeof data == "number" && (data>>>0) == data) return ( <>
|
||||
// <ObjectName name={name} />: <ObjectValue object={data} /> 0x{data.toString(16)}
|
||||
//</>);
|
||||
return ( <ObjectLabel name={name} data={data} isNonenumerable={isNonenumerable} /> );
|
||||
};
|
||||
const metaRenderer = ({ depth, name, data, isNonenumerable }: NodeRendererProps) => {
|
||||
@ -286,7 +424,7 @@ function App() {
|
||||
<b>{data.PB_ENUM && <> = {data.PB_ENUM}</>} [{data.PB_TYPE}]</b>
|
||||
</a> );
|
||||
if(data.PB_TYPE == ".TSP.Reference") {
|
||||
let id = String(data?.identifier);
|
||||
const id = String(data?.identifier);
|
||||
return ( <span onContextMenu={(e) => {displayMenu(e, { type: data.PB_TYPE, id, data, field: data.PB_FIELD })}}>
|
||||
<ObjectName name={name} />: <b>{frag} -> <a onClick={() => {gotoRef(id)}}><b>{id}</b></a></b>
|
||||
</span> );
|
||||
@ -297,28 +435,37 @@ function App() {
|
||||
}
|
||||
return ( <ObjectLabel name={name} data={data} isNonenumerable={isNonenumerable} /> );
|
||||
};
|
||||
const depsRenderer = ({ depth, data, isNonenumerable }: NodeRendererProps) => {
|
||||
if(depth === 0) return ( <b>Dependents</b> );
|
||||
return ( <a onClick={()=>gotoRef(data.id)}><ObjectLabel name={data.id} data={data.message} isNonenumerable={isNonenumerable} /></a> );
|
||||
};
|
||||
|
||||
const showHelp = () => { toast.info(<a href="https://git.sheetjs.com/sheetjs/iwa-inspector" target="_blank">Click for more info</a>); }
|
||||
|
||||
return ( <>
|
||||
{/* header */}
|
||||
<div id="header" className="header"><b><a href="https://sheetjs.com">SheetJS</a> IWA Inspector <input type="file" id="file" onChange={onChange} /></b></div>
|
||||
<div id="header" className="header" style={{display: "grid", gridTemplateColumns: "repeat(3, 1fr)", alignItems:"center"}}>
|
||||
<div style={{display: "flex", justifyContent: "flex-start"}}><input type="file" id="file" onChange={onChange} disabled={loading} accept=".numbers,.key,.pages"/></div>
|
||||
<div><b><a href="https://sheetjs.com">SheetJS</a> IWA Inspector</b> <b onClick={showHelp}>(?)</b></div>
|
||||
<div style={{display: "flex", justifyContent: "flex-end"}}><input type="text" value={search} placeholder="search for text" onChange={(e)=>setSearch(e.target.value)}/></div>
|
||||
</div>
|
||||
|
||||
<div className="page">
|
||||
<PanelGroup direction='vertical'>
|
||||
<Panel defaultSize={25}><div className="overflow" ref={tblRef}>
|
||||
|
||||
{/* message table */}
|
||||
<TableView data={file.tbl} cols={["id", "type", "message", "path"]} id={id} rowclick={rowclick} />
|
||||
<TableView data={file.tbl} cols={["id", "type", "message", "path"]} filter={filter} id={id} rowclick={rowclick} sort={sort} desc={desc} onsort={onsort}/>
|
||||
|
||||
</div></Panel>
|
||||
<PanelResizeHandle style={{ height: "3px", backgroundColor: "#EEEEEE" }} />
|
||||
<Panel><div className="overflow">
|
||||
|
||||
<Panel><div className="overflow" style={{display: "grid", gridTemplateColumns: "1fr", gridTemplateRows: "max-content 1fr"}}>
|
||||
{/* selected message bar */}
|
||||
<div style={{boxShadow: "0 2px 2px -1px rgba(0, 0, 0, 0.4)", height: "24px"}}>{sel ? (<>
|
||||
<b>Selected message {(stack.length > 4 ? [...stack.slice(0,2), "...", ...stack.slice(-1)] : stack).map(i => i + " > ").join("")} {id} ({sel}) {file.space[+id]?.[0]?.data?.length || 0} bytes {stack.length && <a onClick={pop}>Return to {stack[stack.length - 1]}</a> || ""}</b>
|
||||
</>) : "Select a message to see the contents"}</div>
|
||||
|
||||
<div style={{width: "100%", height: "calc(100% - 24px)", overflow: "auto"}}><PanelGroup direction='horizontal'>
|
||||
<div className='overflow'><PanelGroup direction='horizontal'>
|
||||
<Panel><div className='overflow'>
|
||||
|
||||
{/* proto definition */}
|
||||
@ -333,13 +480,18 @@ function App() {
|
||||
|
||||
</div></Panel>
|
||||
<PanelResizeHandle style={{ width: "2px", backgroundColor: "#EEEEEE" }} />
|
||||
<Panel><div className="overflow" style={{textAlign: "left", marginTop: "13px", marginLeft: "10px", marginBottom: "13px", "paddingBottom": "12px"}}>
|
||||
<Panel><div className="overflow" style={{textAlign: "left", marginTop: "5px", paddingLeft: "5px"}}>
|
||||
|
||||
{/* inspector */}
|
||||
<b>Message</b>
|
||||
<ObjectInspector data={obj} expandLevel={1} nodeRenderer={nodeRenderer} />
|
||||
<>
|
||||
<b>Message</b> (showing {level} level{level > 1 ? "s" : ""})
|
||||
{ level >= 5 ? void 0 : <span onClick={() => setLevel(level + 1)}> (+) </span> }
|
||||
{ level <= 1 ? void 0 : <span onClick={() => setLevel(level - 1)}> (-) </span> }
|
||||
</>
|
||||
<ObjectInspector data={obj} expandLevel={level} nodeRenderer={nodeRenderer} key={level} />
|
||||
<b>Meta</b>
|
||||
<ObjectInspector data={meta} expandLevel={1} nodeRenderer={metaRenderer} />
|
||||
{deps.length && <ObjectInspector data={deps} expandLevel={1} nodeRenderer={depsRenderer} /> || void 0}
|
||||
<div style={{height:"13px"}}></div>
|
||||
|
||||
</div></Panel>
|
||||
@ -348,7 +500,7 @@ function App() {
|
||||
</PanelGroup>
|
||||
|
||||
{/* Menu */}
|
||||
<ContextMenu ID={MENU_ID} menuField={menuField} menuType={menuType} menuId={menuId} onClickId={onClickId} onClickCopyByteArray={onClickCopyByteArray} onClickCopyJSON={onClickCopyJSON} showProtoDef={showProtoDef} />
|
||||
<ContextMenu ID={MENU_ID} menuField={menuField} menuType={menuType} menuId={menuId} onClickId={onClickId} onClickCopyByteArray={onClickCopyByteArray} onClickCopyJSON={onClickCopyJSON} showProtoDef={showProtoDef} showXXD={showXXD} />
|
||||
|
||||
{/* Toast */}
|
||||
<ToastContainer />
|
||||
@ -356,4 +508,4 @@ function App() {
|
||||
</> );
|
||||
}
|
||||
|
||||
export default App
|
||||
export default App;
|
||||
|
165
src/iwa.ts
165
src/iwa.ts
@ -1,10 +1,10 @@
|
||||
import * as CFB from 'cfb';
|
||||
|
||||
import Messages, { MessageTypes } from "./messages/";
|
||||
import Messages, { $_TSP_MessageInfo, MessageTypes } from "./messages/";
|
||||
|
||||
/* see https://bugs.webkit.org/show_bug.cgi?id=243148 -- affects iOS Safari */
|
||||
declare var Buffer: any; // Buffer is typeof-guarded but TS still needs this :(
|
||||
var subarray: "subarray" | "slice" = (() => {
|
||||
declare const Buffer: any; // Buffer is typeof-guarded but TS still needs this :(
|
||||
const subarray: "subarray" | "slice" = (() => {
|
||||
try {
|
||||
if(typeof Uint8Array == "undefined") return "slice";
|
||||
if(typeof Uint8Array.prototype.subarray == "undefined") return "slice";
|
||||
@ -20,13 +20,13 @@ var subarray: "subarray" | "slice" = (() => {
|
||||
|
||||
/** Concatenate Uint8Arrays */
|
||||
function u8concat(u8a: Uint8Array[]): Uint8Array {
|
||||
var len = 0;
|
||||
for(var i = 0; i < u8a.length; ++i) len += u8a[i].length;
|
||||
var out = new Uint8Array(len);
|
||||
var off = 0;
|
||||
for(i = 0; i < u8a.length; ++i) {
|
||||
var u8 = u8a[i], L = u8.length;
|
||||
if(L < 250) { for(var j = 0; j < L; ++j) out[off++] = u8[j]; }
|
||||
let len = 0;
|
||||
for(let i = 0; i < u8a.length; ++i) len += u8a[i].length;
|
||||
const out = new Uint8Array(len);
|
||||
let off = 0;
|
||||
for(let i = 0; i < u8a.length; ++i) {
|
||||
const u8 = u8a[i], L = u8.length;
|
||||
if(L < 250) { for(let j = 0; j < L; ++j) out[off++] = u8[j]; }
|
||||
else { out.set(u8, off); off += L; }
|
||||
}
|
||||
return out;
|
||||
@ -36,8 +36,8 @@ interface Ptr { l: number; }
|
||||
|
||||
/** Parse an integer from the varint that can be exactly stored in a double */
|
||||
function parse_varint49(buf: Uint8Array, ptr: Ptr): number {
|
||||
var l = ptr.l;
|
||||
var usz = buf[l] & 0x7F;
|
||||
let l = ptr.l;
|
||||
let usz = buf[l] & 0x7F;
|
||||
varint: if(buf[l++] >= 0x80) {
|
||||
usz |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) break varint;
|
||||
usz |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) break varint;
|
||||
@ -51,15 +51,15 @@ function parse_varint49(buf: Uint8Array, ptr: Ptr): number {
|
||||
}
|
||||
/** Parse a repeated varint [packed = true] field */
|
||||
function parse_packed_varints(buf: Uint8Array): number[] {
|
||||
var ptr: Ptr = {l: 0};
|
||||
var out: number[] = [];
|
||||
const ptr: Ptr = {l: 0};
|
||||
const out: number[] = [];
|
||||
while(ptr.l < buf.length) out.push(parse_varint49(buf, ptr));
|
||||
return out;
|
||||
}
|
||||
/** Parse a BigInt from the varint */
|
||||
function parse_varint64(buf: Uint8Array, ptr: Ptr): BigInt {
|
||||
var l = ptr.l;
|
||||
var usz = BigInt(buf[l] & 0x7F);
|
||||
function parse_varint64(buf: Uint8Array, ptr: Ptr): bigint {
|
||||
let l = ptr.l;
|
||||
let usz = BigInt(buf[l] & 0x7F);
|
||||
varint: if(buf[l++] >= 0x80) {
|
||||
usz += BigInt(buf[l] & 0x7F) << 7n; if(buf[l++] < 0x80) break varint;
|
||||
usz += BigInt(buf[l] & 0x7F) << 14n; if(buf[l++] < 0x80) break varint;
|
||||
@ -75,15 +75,15 @@ function parse_varint64(buf: Uint8Array, ptr: Ptr): BigInt {
|
||||
return usz;
|
||||
}
|
||||
/** Parse a repeated varint [packed = true] field */
|
||||
function parse_packed_varint64(buf: Uint8Array): BigInt[] {
|
||||
var ptr: Ptr = {l: 0};
|
||||
var out: BigInt[] = [];
|
||||
function parse_packed_varint64(buf: Uint8Array): bigint[] {
|
||||
const ptr: Ptr = {l: 0};
|
||||
const out: bigint[] = [];
|
||||
while(ptr.l < buf.length) out.push(parse_varint64(buf, ptr));
|
||||
return out;
|
||||
}
|
||||
/** Parse a 32-bit signed integer from the raw varint */
|
||||
function varint_to_i32(buf: Uint8Array): number {
|
||||
var l = 0,
|
||||
let l = 0,
|
||||
i32 = (buf[l] & 0x7F) ; if(buf[l++] < 0x80) return i32;
|
||||
i32 |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) return i32;
|
||||
i32 |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) return i32;
|
||||
@ -92,7 +92,7 @@ function varint_to_i32(buf: Uint8Array): number {
|
||||
}
|
||||
/** Parse a 64-bit unsigned integer as a pair */
|
||||
function varint_to_u64(buf: Uint8Array): [number, number] {
|
||||
var l = 0, lo = buf[l] & 0x7F, hi = 0;
|
||||
let l = 0, lo = buf[l] & 0x7F, hi = 0;
|
||||
varint: if(buf[l++] >= 0x80) {
|
||||
lo |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) break varint;
|
||||
lo |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) break varint;
|
||||
@ -119,6 +119,9 @@ interface IWAMessage {
|
||||
meta: ProtoMessage;
|
||||
rawmeta: Uint8Array;
|
||||
data: Uint8Array;
|
||||
pre?: string;
|
||||
parsed?: any;
|
||||
parsedmeta?: $_TSP_MessageInfo;
|
||||
}
|
||||
interface IWAArchiveInfo {
|
||||
id: number;
|
||||
@ -127,13 +130,14 @@ interface IWAArchiveInfo {
|
||||
}
|
||||
/** Shallow parse of a Protobuf message */
|
||||
function parse_shallow(buf: Uint8Array): ProtoMessage {
|
||||
var out: ProtoMessage = [], ptr: Ptr = {l: 0};
|
||||
const out: ProtoMessage = [], ptr: Ptr = {l: 0};
|
||||
while(ptr.l < buf.length) {
|
||||
var off = ptr.l;
|
||||
var num = parse_varint49(buf, ptr);
|
||||
var type = num & 0x07; num = (num / 8)|0;
|
||||
var data: Uint8Array;
|
||||
var l = ptr.l;
|
||||
const off = ptr.l;
|
||||
let num = parse_varint49(buf, ptr);
|
||||
const type = num & 0x07;
|
||||
num = (num / 8)|0;
|
||||
let data: Uint8Array;
|
||||
let l = ptr.l;
|
||||
switch(type) {
|
||||
case 0: {
|
||||
while(buf[l++] >= 0x80);
|
||||
@ -142,14 +146,14 @@ function parse_shallow(buf: Uint8Array): ProtoMessage {
|
||||
} break;
|
||||
case 1: { data = buf[subarray](l, l + 8); ptr.l = l + 8; } break;
|
||||
case 2: {
|
||||
var len = parse_varint49(buf, ptr);
|
||||
const len = parse_varint49(buf, ptr);
|
||||
data = buf[subarray](ptr.l, ptr.l + len);
|
||||
ptr.l += len;
|
||||
} break;
|
||||
case 5: { data = buf[subarray](l, l + 4); ptr.l = l + 4; } break;
|
||||
default: throw new Error(`PB Type ${type} for Field ${num} at offset ${off}`);
|
||||
}
|
||||
var v: ProtoItem = { data, type };
|
||||
const v: ProtoItem = { data, type };
|
||||
if(out[num] == null) out[num] = [];
|
||||
out[num].push(v);
|
||||
}
|
||||
@ -158,21 +162,21 @@ function parse_shallow(buf: Uint8Array): ProtoMessage {
|
||||
|
||||
/** Extract all messages from a IWA file */
|
||||
function parse_iwa_file(buf: Uint8Array): IWAArchiveInfo[] {
|
||||
var out: IWAArchiveInfo[] = [], ptr: Ptr = {l: 0};
|
||||
const out: IWAArchiveInfo[] = [], ptr: Ptr = {l: 0};
|
||||
while(ptr.l < buf.length) {
|
||||
/* .TSP.ArchiveInfo */
|
||||
var len = parse_varint49(buf, ptr);
|
||||
var ai = parse_shallow(buf[subarray](ptr.l, ptr.l + len));
|
||||
const len = parse_varint49(buf, ptr);
|
||||
const ai = parse_shallow(buf[subarray](ptr.l, ptr.l + len));
|
||||
ptr.l += len;
|
||||
|
||||
var res: IWAArchiveInfo = {
|
||||
const res: IWAArchiveInfo = {
|
||||
/* TODO: technically ID is optional */
|
||||
id: varint_to_i32(ai[1][0].data),
|
||||
messages: []
|
||||
};
|
||||
ai[2].forEach(b => {
|
||||
var mi = parse_shallow(b.data);
|
||||
var fl = varint_to_i32(mi[3][0].data);
|
||||
const mi = parse_shallow(b.data);
|
||||
const fl = varint_to_i32(mi[3][0].data);
|
||||
res.messages.push({
|
||||
meta: mi,
|
||||
rawmeta: b.data,
|
||||
@ -189,18 +193,18 @@ function parse_iwa_file(buf: Uint8Array): IWAArchiveInfo[] {
|
||||
/** Decompress a snappy chunk */
|
||||
function parse_snappy_chunk(type: number, buf: Uint8Array): Uint8Array[] {
|
||||
if(type != 0) throw new Error(`Unexpected Snappy chunk type ${type}`);
|
||||
var ptr: Ptr = {l: 0};
|
||||
const ptr: Ptr = {l: 0};
|
||||
|
||||
var usz = parse_varint49(buf, ptr);
|
||||
var chunks: Uint8Array[] = [];
|
||||
var l = ptr.l;
|
||||
const usz = parse_varint49(buf, ptr);
|
||||
let chunks: Uint8Array[] = [];
|
||||
let l = ptr.l;
|
||||
while(l < buf.length) {
|
||||
var tag = buf[l] & 0x3;
|
||||
const tag = buf[l] & 0x3;
|
||||
if(tag == 0) {
|
||||
var len = buf[l++] >> 2;
|
||||
let len = buf[l++] >> 2;
|
||||
if(len < 60) ++len;
|
||||
else {
|
||||
var c = len - 59;
|
||||
const c = len - 59;
|
||||
len = buf[l];
|
||||
if(c > 1) len |= (buf[l+1]<<8);
|
||||
if(c > 2) len |= (buf[l+2]<<16);
|
||||
@ -210,7 +214,7 @@ function parse_snappy_chunk(type: number, buf: Uint8Array): Uint8Array[] {
|
||||
}
|
||||
chunks.push(buf[subarray](l, l + len)); l += len; continue;
|
||||
} else {
|
||||
var offset = 0, length = 0;
|
||||
let offset = 0, length = 0;
|
||||
if(tag == 1) {
|
||||
length = ((buf[l] >> 2) & 0x7) + 4;
|
||||
offset = (buf[l++] & 0xE0) << 3;
|
||||
@ -221,7 +225,7 @@ function parse_snappy_chunk(type: number, buf: Uint8Array): Uint8Array[] {
|
||||
else { offset = (buf[l] | (buf[l+1]<<8) | (buf[l+2]<<16) | (buf[l+3]<<24))>>>0; l += 4; }
|
||||
}
|
||||
if(offset == 0) throw new Error("Invalid offset 0");
|
||||
var j = chunks.length - 1, off = offset;
|
||||
let j = chunks.length - 1, off = offset;
|
||||
while(j >=0 && off >= chunks[j].length) { off -= chunks[j].length; --j; }
|
||||
if(j < 0) {
|
||||
if(off == 0) off = chunks[(j = 0)].length;
|
||||
@ -237,7 +241,7 @@ function parse_snappy_chunk(type: number, buf: Uint8Array): Uint8Array[] {
|
||||
if(chunks.length > 25) chunks = [u8concat(chunks)];
|
||||
}
|
||||
}
|
||||
var clen = 0; for(var u8i = 0; u8i < chunks.length; ++u8i) clen += chunks[u8i].length;
|
||||
let clen = 0; for(let u8i = 0; u8i < chunks.length; ++u8i) clen += chunks[u8i].length;
|
||||
if(clen != usz) throw new Error(`Unexpected length: ${clen} != ${usz}`);
|
||||
return chunks;
|
||||
}
|
||||
@ -245,12 +249,12 @@ function parse_snappy_chunk(type: number, buf: Uint8Array): Uint8Array[] {
|
||||
/** Decompress IWA file */
|
||||
function decompress_iwa_file(buf: Uint8Array): Uint8Array {
|
||||
if(Array.isArray(buf)) buf = new Uint8Array(buf);
|
||||
var out: Uint8Array[] = [];
|
||||
var l = 0;
|
||||
const out: Uint8Array[] = [];
|
||||
let l = 0;
|
||||
while(l < buf.length) {
|
||||
var t = buf[l++];
|
||||
var len = buf[l] | (buf[l+1]<<8) | (buf[l+2] << 16); l += 3;
|
||||
out.push.apply(out, parse_snappy_chunk(t, buf[subarray](l, l + len)));
|
||||
const t = buf[l++];
|
||||
const len = buf[l] | (buf[l+1]<<8) | (buf[l+2] << 16); l += 3;
|
||||
out.push(...parse_snappy_chunk(t, buf[subarray](l, l + len)));
|
||||
l += len;
|
||||
}
|
||||
if(l !== buf.length) throw new Error("data is not a valid framed stream!");
|
||||
@ -267,21 +271,21 @@ interface ParsedFile {
|
||||
}
|
||||
|
||||
function parse_iwa(cfb: CFB.CFB$Container): ParsedFile {
|
||||
var M: MessageSpace = {}, indices: number[] = [], tbl: TableItem[] = [];
|
||||
const M: MessageSpace = {}, indices: number[] = [], tbl: TableItem[] = [];
|
||||
cfb.FullPaths.forEach(p => { if(p.match(/\.iwpv2/)) throw new Error(`Unsupported password protection`); });
|
||||
|
||||
var root!: TableItem, rootmsg!: IWAMessage;
|
||||
let root!: TableItem, rootmsg!: IWAMessage;
|
||||
/* collect entire message space */
|
||||
cfb.FileIndex.forEach((s, idx) => {
|
||||
if(!s.name.match(/\.iwa$/)) return;
|
||||
if(s.content[0] != 0) return; // TODO: this should test if the iwa follows the framing format
|
||||
var o: Uint8Array;
|
||||
let o: Uint8Array;
|
||||
try { o = decompress_iwa_file(s.content as Uint8Array); } catch(e: any) { return console.log("?? " + s.content.length + " " + ((e as Error).message || e)); }
|
||||
var packets: IWAArchiveInfo[];
|
||||
let packets: IWAArchiveInfo[];
|
||||
try { packets = parse_iwa_file(o); } catch(e: any) { return console.log("## " + ((e as Error).message || e)); }
|
||||
packets.forEach(packet => { M[packet.id] = packet.messages; indices.push(packet.id);
|
||||
var type = varint_to_i32(packet.messages[0].meta[1][0].data);
|
||||
var item = {
|
||||
const type = varint_to_i32(packet.messages[0].meta[1][0].data);
|
||||
const item = {
|
||||
id: packet.id,
|
||||
type,
|
||||
path:cfb.FullPaths[idx].replace(/Root Entry/, ""),
|
||||
@ -293,7 +297,7 @@ function parse_iwa(cfb: CFB.CFB$Container): ParsedFile {
|
||||
});
|
||||
if(!indices.length) throw new Error("File has no messages");
|
||||
if(!root) throw new Error(`Root element (id 1) missing!`);
|
||||
var type: MessageTypes = "N";
|
||||
let type: MessageTypes = "N";
|
||||
if(root.type == 10000) type = "P";
|
||||
else if(parse_shallow(rootmsg.data)?.[2]?.[0]) type = "K";
|
||||
|
||||
@ -304,17 +308,18 @@ function parse_iwa(cfb: CFB.CFB$Container): ParsedFile {
|
||||
|
||||
function process_item(item: {data: Uint8Array; type: number}, type: string, protos: any) {
|
||||
switch(item.type) {
|
||||
case 0:
|
||||
var varint = parse_varint49(item.data, {l:0});
|
||||
case 0: {
|
||||
const varint = parse_varint49(item.data, {l:0});
|
||||
switch(type) {
|
||||
case "bool": return !!+varint;
|
||||
case "uint32": return varint;
|
||||
case "int32": return varint | 0;
|
||||
case "sint32": return (-(varint&1))^(varint>>1);
|
||||
case "uint64": var u64 = varint_to_u64(item.data); return (BigInt(u64[1])<<32n) + BigInt(u64[0]);
|
||||
case "int64": var u64 = varint_to_u64(item.data); return new BigInt64Array([(BigInt(u64[1])<<32n) + BigInt(u64[0])])[0];
|
||||
case "sint64": var u64 = varint_to_u64(item.data); var bi = (BigInt(u64[1])<<32n) + BigInt(u64[0]); return (-(bi&1n))^(bi>>1n);
|
||||
} break;
|
||||
case "uint64": { const u64 = varint_to_u64(item.data); return (BigInt(u64[1])<<32n) + BigInt(u64[0]); }
|
||||
case "int64": { const u64 = varint_to_u64(item.data); return new BigInt64Array([(BigInt(u64[1])<<32n) + BigInt(u64[0])])[0]; }
|
||||
case "sint64": { const u64 = varint_to_u64(item.data); const bi = (BigInt(u64[1])<<32n) + BigInt(u64[0]); return (-(bi&1n))^(bi>>1n); }
|
||||
}
|
||||
} break;
|
||||
case 1: switch(type) {
|
||||
case "fixed64": return new BigUint64Array(new Uint8Array([...item.data]).buffer)[0];
|
||||
case "sfixed64": return new BigInt64Array(new Uint8Array([...item.data]).buffer)[0];
|
||||
@ -336,15 +341,15 @@ function process_item(item: {data: Uint8Array; type: number}, type: string, prot
|
||||
}
|
||||
|
||||
function process_enum(data: Uint8Array, message: string, protos: any) {
|
||||
var val = parse_varint49(data, {l: 0});
|
||||
let val = parse_varint49(data, {l: 0});
|
||||
if(val >= 4294967296) val |= 0;
|
||||
var msg = protos[message].split("\n");
|
||||
for(let m of msg) {
|
||||
const msg = protos[message].split("\n");
|
||||
for(const m of msg) {
|
||||
if(m.startsWith("enum")) continue;
|
||||
if(m.indexOf("=")> -1) {
|
||||
let [field, , value] = m.trim().split(" ");
|
||||
const [field, , value] = m.trim().split(" ");
|
||||
if(val == parseInt(value, 10)) {
|
||||
var res = {}
|
||||
const res = {}
|
||||
Object.defineProperty(res, "value", { get: () => val});
|
||||
Object.defineProperty(res, "PB_ENUM", { value: field, enumerable: false})
|
||||
return res;
|
||||
@ -356,20 +361,20 @@ function process_enum(data: Uint8Array, message: string, protos: any) {
|
||||
|
||||
function process(data: Uint8Array, message: string, protos: any) {
|
||||
if(!protos[message]) return parse_shallow(data);
|
||||
var shallow = parse_shallow(data);
|
||||
var proto: string[] = protos[message].split("\n");
|
||||
var out: any = {};
|
||||
const shallow = parse_shallow(data);
|
||||
const proto: string[] = protos[message].split("\n");
|
||||
const out: any = {};
|
||||
if(proto[0].startsWith("enum")) return process_enum(data, message, protos);
|
||||
proto.forEach(line => {
|
||||
if(!line.startsWith(" ") || line.indexOf("=") == -1 || line.startsWith(" ")) return;
|
||||
const [freq, type, name, , idx] = line.trim().split(/\s+/);
|
||||
var i = parseInt(idx, 10);
|
||||
const i = parseInt(idx, 10);
|
||||
if(isNaN(i)) return;
|
||||
if(!shallow[i]?.length) return;
|
||||
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;
|
||||
@ -384,16 +389,16 @@ function process(data: Uint8Array, message: string, protos: any) {
|
||||
default: throw `unsupported frequency ${freq}`;
|
||||
}
|
||||
if(type.startsWith(".")) {
|
||||
if(freq == "repeated") out[name].forEach((n: any) => {try { Object.defineProperty(n, "PB_TYPE", {value: type, enumerable: false}); } catch(e){}});
|
||||
else try { Object.defineProperty(out[name], "PB_TYPE", {value: type, enumerable: false}); } catch(e) {}
|
||||
if(freq == "repeated") out[name].forEach((n: any) => {try { Object.defineProperty(n, "PB_TYPE", {value: type, enumerable: false}); } catch(e){/*empty*/}});
|
||||
else try { Object.defineProperty(out[name], "PB_TYPE", {value: type, enumerable: false}); } catch(e) {/*empty*/}
|
||||
}
|
||||
try {
|
||||
if(freq == "repeated") out[name].forEach((n: any, idx:number) => {try { Object.defineProperty(n, "PB_RAW", {value: shallow[i][idx], enumerable: false}); } catch(e){}});
|
||||
else try { Object.defineProperty(out[name], "PB_RAW", {value: shallow[i][0], enumerable: false}); } catch(e) {}
|
||||
if(freq == "repeated") out[name].forEach((n: any, idx:number) => {try { Object.defineProperty(n, "PB_RAW", {value: shallow[i][idx], enumerable: false}); } catch(e){/*empty*/}});
|
||||
else try { Object.defineProperty(out[name], "PB_RAW", {value: shallow[i][0], enumerable: false}); } catch(e) {/*empty*/}
|
||||
} catch(e){console.log(e);}
|
||||
try {
|
||||
if(freq == "repeated") out[name].forEach((n: any, idx:number) => {try { Object.defineProperty(n, "PB_FIELD", {value: `${name}[${idx}]` , enumerable: false}); } catch(e){}});
|
||||
else try { Object.defineProperty(out[name], "PB_FIELD", {value: name, enumerable: false}); } catch(e) {}
|
||||
if(freq == "repeated") out[name].forEach((n: any, idx:number) => {try { Object.defineProperty(n, "PB_FIELD", {value: `${name}[${idx}]` , enumerable: false}); } catch(e){/*empty*/}});
|
||||
else try { Object.defineProperty(out[name], "PB_FIELD", {value: name, enumerable: false}); } catch(e) {/*empty*/}
|
||||
} catch(e){console.log(e);}
|
||||
})
|
||||
return out;
|
||||
|
@ -14,7 +14,7 @@ export default Messages;
|
||||
type ProtoMap = {[key: string]: string};
|
||||
|
||||
const post_process = (buf: string, key: string, out: ProtoMap) => {
|
||||
var payload = "", nested = false;
|
||||
let payload = "", nested = false;
|
||||
buf.split("\n").forEach(row => {
|
||||
if(row.startsWith(" message") || row.startsWith(" enum")) {
|
||||
nested = true
|
||||
@ -23,12 +23,13 @@ const post_process = (buf: string, key: string, out: ProtoMap) => {
|
||||
payload += row + "\n";
|
||||
nested = false;
|
||||
payload = payload.replace(/^ /mg, "");
|
||||
var new_key = "";
|
||||
let new_key = "";
|
||||
payload = payload.replace(/^(message|enum) ([\S]*)/, (_, $1, $2) => {
|
||||
new_key = key + "." + $2;
|
||||
return $1 + " " + key + "." + $2
|
||||
});
|
||||
out[new_key] = payload;
|
||||
post_process(payload, new_key, out);
|
||||
payload = "";
|
||||
} else if(nested) payload += row + "\n";
|
||||
});
|
||||
@ -48,7 +49,7 @@ const parse_protos = (text: string): ProtoMap => {
|
||||
out[key] = buf;
|
||||
post_process(buf, key, out);
|
||||
}
|
||||
else if(!line){}
|
||||
else if(!line){/*empty*/}
|
||||
else if(line.startsWith("extend")) {
|
||||
key = line.split(" ")[1];
|
||||
buf = out[key] + "\n" + line + "\n";
|
||||
@ -62,7 +63,7 @@ export { parse_protos };
|
||||
export type { ProtoMap };
|
||||
|
||||
interface $_TSP_Reference {
|
||||
identifier: BigInt;
|
||||
identifier: bigint;
|
||||
}
|
||||
interface $_TSP_FieldPath {
|
||||
path?: number[];
|
||||
@ -71,8 +72,8 @@ interface $_TSP_FieldInfo {
|
||||
path: $_TSP_FieldPath;
|
||||
type?: number;
|
||||
unknown_field_rule?: number;
|
||||
object_references?: BigInt[];
|
||||
data_references?: BigInt[];
|
||||
object_references?: bigint[];
|
||||
data_references?: bigint[];
|
||||
known_field_rule?: number;
|
||||
known_field_version?: number[];
|
||||
known_field_feature_identifier?: string;
|
||||
@ -83,8 +84,8 @@ interface $_TSP_MessageInfo {
|
||||
version: number[];
|
||||
length: number;
|
||||
field_infos?: $_TSP_FieldInfo[];
|
||||
object_references?: BigInt[];
|
||||
data_references?: BigInt[];
|
||||
object_references?: bigint[];
|
||||
data_references?: bigint[];
|
||||
base_message_index?: number;
|
||||
diff_merge_version?: number[];
|
||||
diff_field_path?: $_TSP_FieldPath;
|
||||
|
@ -107,8 +107,8 @@ export default {
|
||||
211: ".TSK.DocumentSupportArchive",
|
||||
212: ".TSK.AnnotationAuthorArchive",
|
||||
213: ".TSK.AnnotationAuthorStorageArchive",
|
||||
215: ".TSK.SetAnnotationAuthorColorCommandArchive",
|
||||
218: ".TSK.CollaborationCommandHistory",
|
||||
215: ".TSCK.SetAnnotationAuthorColorCommandArchive",
|
||||
218: ".TSCK.CollaborationCommandHistory",
|
||||
219: ".TSK.DocumentSelectionArchive",
|
||||
220: ".TSK.CommandSelectionBehaviorArchive",
|
||||
221: ".TSK.NullCommandArchive",
|
||||
@ -116,54 +116,54 @@ export default {
|
||||
223: ".TSK.GroupCommitCommandArchive",
|
||||
224: ".TSK.InducedCommandCollectionArchive",
|
||||
225: ".TSK.InducedCommandCollectionCommitCommandArchive",
|
||||
226: ".TSK.CollaborationDocumentSessionState",
|
||||
227: ".TSK.CollaborationCommandHistoryCoalescingGroup",
|
||||
228: ".TSK.CollaborationCommandHistoryCoalescingGroupNode",
|
||||
229: ".TSK.CollaborationCommandHistoryOriginatingCommandAcknowledgementObserver",
|
||||
230: ".TSK.DocumentSupportCollaborationState",
|
||||
226: ".TSCK.CollaborationDocumentSessionState",
|
||||
227: ".TSCK.CollaborationCommandHistoryCoalescingGroup",
|
||||
228: ".TSCK.CollaborationCommandHistoryCoalescingGroupNode",
|
||||
229: ".TSCK.CollaborationCommandHistoryOriginatingCommandAcknowledgementObserver",
|
||||
230: ".TSCK.DocumentSupportCollaborationState",
|
||||
231: ".TSK.ChangeDocumentPackageTypeCommandArchive",
|
||||
232: ".TSK.UpgradeDocPostProcessingCommandArchive",
|
||||
233: ".TSK.FinalCommandPairArchive",
|
||||
234: ".TSK.OutgoingCommandQueueItem",
|
||||
235: ".TSK.TransformerEntry",
|
||||
238: ".TSK.CreateLocalStorageSnapshotCommandArchive",
|
||||
235: ".TSCK.TransformerEntry",
|
||||
238: ".TSCK.CreateLocalStorageSnapshotCommandArchive",
|
||||
240: ".TSK.SelectionPathTransformerArchive",
|
||||
241: ".TSK.NativeContentDescription",
|
||||
242: ".TSD.PencilAnnotationStorageArchive",
|
||||
245: ".TSK.OperationStorage",
|
||||
246: ".TSK.OperationStorageEntryArray",
|
||||
247: ".TSK.OperationStorageEntryArraySegment",
|
||||
248: ".TSK.BlockDiffsAtCurrentRevisionCommand",
|
||||
249: ".TSK.OutgoingCommandQueue",
|
||||
250: ".TSK.OutgoingCommandQueueSegment",
|
||||
245: ".TSCK.OperationStorage",
|
||||
246: ".TSCK.OperationStorageEntryArray",
|
||||
247: ".TSCK.OperationStorageEntryArraySegment",
|
||||
248: ".TSCK.BlockDiffsAtCurrentRevisionCommand",
|
||||
249: ".TSCK.OutgoingCommandQueue",
|
||||
250: ".TSCK.OutgoingCommandQueueSegment",
|
||||
251: ".TSK.PropagatedCommandCollectionArchive",
|
||||
252: ".TSK.LocalCommandHistoryItem",
|
||||
253: ".TSK.LocalCommandHistoryArray",
|
||||
254: ".TSK.LocalCommandHistoryArraySegment",
|
||||
255: ".TSK.CollaborationCommandHistoryItem",
|
||||
256: ".TSK.CollaborationCommandHistoryArray",
|
||||
257: ".TSK.CollaborationCommandHistoryArraySegment",
|
||||
255: ".TSCK.CollaborationCommandHistoryItem",
|
||||
256: ".TSCK.CollaborationCommandHistoryArray",
|
||||
257: ".TSCK.CollaborationCommandHistoryArraySegment",
|
||||
258: ".TSK.PencilAnnotationUIState",
|
||||
259: ".TSKSOS.FixCorruptedDataCommandArchive",
|
||||
260: ".TSK.CommandAssetChunkArchive",
|
||||
261: ".TSK.AssetUploadStatusCommandArchive",
|
||||
262: ".TSK.AssetUnmaterializedOnServerCommandArchive",
|
||||
259: ".TSCKSOS.FixCorruptedDataCommandArchive",
|
||||
260: ".TSCK.CommandAssetChunkArchive",
|
||||
261: ".TSCK.AssetUploadStatusCommandArchive",
|
||||
262: ".TSCK.AssetUnmaterializedOnServerCommandArchive",
|
||||
263: ".TSK.CommandBehaviorArchive",
|
||||
264: ".TSK.CommandBehaviorSelectionPathStorageArchive",
|
||||
265: ".TSK.CommandActivityBehaviorArchive",
|
||||
273: ".TSK.ActivityOnlyCommandArchive",
|
||||
275: ".TSK.SetActivityAuthorShareParticipantIDCommandArchive",
|
||||
279: ".TSK.ActivityAuthorCacheArchive",
|
||||
280: ".TSK.ActivityStreamArchive",
|
||||
281: ".TSK.ActivityArchive",
|
||||
282: ".TSK.ActivityCommitCommandArchive",
|
||||
283: ".TSK.ActivityStreamActivityArray",
|
||||
284: ".TSK.ActivityStreamActivityArraySegment",
|
||||
285: ".TSK.ActivityStreamRemovedAuthorAuditorPendingStateArchive",
|
||||
286: ".TSK.ActivityAuthorArchive",
|
||||
287: ".TSKSOS.ResetActivityStreamCommandArchive",
|
||||
288: ".TSKSOS.RemoveAuthorIdentifiersCommandArchive",
|
||||
289: ".TSK.ActivityCursorCollectionPersistenceWrapperArchive",
|
||||
265: ".TSCK.CommandActivityBehaviorArchive",
|
||||
273: ".TSCK.ActivityOnlyCommandArchive",
|
||||
275: ".TSCK.SetActivityAuthorShareParticipantIDCommandArchive",
|
||||
279: ".TSCK.ActivityAuthorCacheArchive",
|
||||
280: ".TSCK.ActivityStreamArchive",
|
||||
281: ".TSCK.ActivityArchive",
|
||||
282: ".TSCK.ActivityCommitCommandArchive",
|
||||
283: ".TSCK.ActivityStreamActivityArray",
|
||||
284: ".TSCK.ActivityStreamActivityArraySegment",
|
||||
285: ".TSCK.ActivityStreamRemovedAuthorAuditorPendingStateArchive",
|
||||
286: ".TSCK.ActivityAuthorArchive",
|
||||
287: ".TSCKSOS.ResetActivityStreamCommandArchive",
|
||||
288: ".TSCKSOS.RemoveAuthorIdentifiersCommandArchive",
|
||||
289: ".TSCK.ActivityCursorCollectionPersistenceWrapperArchive",
|
||||
400: ".TSS.StyleArchive",
|
||||
401: ".TSS.StylesheetArchive",
|
||||
402: ".TSS.ThemeArchive",
|
||||
@ -208,6 +208,9 @@ export default {
|
||||
637: ".TSA.GalleryInfoRemoveItemsCommandArchive",
|
||||
638: ".TSASOS.VerifyActivityStreamWithServerCommandArchive",
|
||||
639: ".TSASOS.InducedVerifyActivityStreamWithServerCommandArchive",
|
||||
640: ".TSASOS.VerifyTransformHistoryWithServerCommandArchive",
|
||||
641: ".TSA.Object3DInfoSetValueCommandArchive",
|
||||
642: ".TSA.Object3DInfoCommandArchive",
|
||||
2001: ".TSWP.StorageArchive",
|
||||
2002: ".TSWP.SelectionArchive",
|
||||
2003: ".TSWP.DrawableAttachmentArchive",
|
||||
@ -280,6 +283,7 @@ export default {
|
||||
2410: ".TSWP.FlowInfoArchive",
|
||||
2411: ".TSWP.FlowInfoContainerArchive",
|
||||
2412: ".TSWP.PencilAnnotationSelectionTransformerArchive",
|
||||
2413: ".TSWP.DateTimeSelectionArchive",
|
||||
3002: ".TSD.DrawableArchive",
|
||||
3003: ".TSD.ContainerArchive",
|
||||
3004: ".TSD.ShapeArchive",
|
||||
|
@ -12,8 +12,8 @@ export default {
|
||||
211: ".TSK.DocumentSupportArchive",
|
||||
212: ".TSK.AnnotationAuthorArchive",
|
||||
213: ".TSK.AnnotationAuthorStorageArchive",
|
||||
215: ".TSK.SetAnnotationAuthorColorCommandArchive",
|
||||
218: ".TSK.CollaborationCommandHistory",
|
||||
215: ".TSCK.SetAnnotationAuthorColorCommandArchive",
|
||||
218: ".TSCK.CollaborationCommandHistory",
|
||||
219: ".TSK.DocumentSelectionArchive",
|
||||
220: ".TSK.CommandSelectionBehaviorArchive",
|
||||
221: ".TSK.NullCommandArchive",
|
||||
@ -21,54 +21,54 @@ export default {
|
||||
223: ".TSK.GroupCommitCommandArchive",
|
||||
224: ".TSK.InducedCommandCollectionArchive",
|
||||
225: ".TSK.InducedCommandCollectionCommitCommandArchive",
|
||||
226: ".TSK.CollaborationDocumentSessionState",
|
||||
227: ".TSK.CollaborationCommandHistoryCoalescingGroup",
|
||||
228: ".TSK.CollaborationCommandHistoryCoalescingGroupNode",
|
||||
229: ".TSK.CollaborationCommandHistoryOriginatingCommandAcknowledgementObserver",
|
||||
230: ".TSK.DocumentSupportCollaborationState",
|
||||
226: ".TSCK.CollaborationDocumentSessionState",
|
||||
227: ".TSCK.CollaborationCommandHistoryCoalescingGroup",
|
||||
228: ".TSCK.CollaborationCommandHistoryCoalescingGroupNode",
|
||||
229: ".TSCK.CollaborationCommandHistoryOriginatingCommandAcknowledgementObserver",
|
||||
230: ".TSCK.DocumentSupportCollaborationState",
|
||||
231: ".TSK.ChangeDocumentPackageTypeCommandArchive",
|
||||
232: ".TSK.UpgradeDocPostProcessingCommandArchive",
|
||||
233: ".TSK.FinalCommandPairArchive",
|
||||
234: ".TSK.OutgoingCommandQueueItem",
|
||||
235: ".TSK.TransformerEntry",
|
||||
238: ".TSK.CreateLocalStorageSnapshotCommandArchive",
|
||||
235: ".TSCK.TransformerEntry",
|
||||
238: ".TSCK.CreateLocalStorageSnapshotCommandArchive",
|
||||
240: ".TSK.SelectionPathTransformerArchive",
|
||||
241: ".TSK.NativeContentDescription",
|
||||
242: ".TSD.PencilAnnotationStorageArchive",
|
||||
245: ".TSK.OperationStorage",
|
||||
246: ".TSK.OperationStorageEntryArray",
|
||||
247: ".TSK.OperationStorageEntryArraySegment",
|
||||
248: ".TSK.BlockDiffsAtCurrentRevisionCommand",
|
||||
249: ".TSK.OutgoingCommandQueue",
|
||||
250: ".TSK.OutgoingCommandQueueSegment",
|
||||
245: ".TSCK.OperationStorage",
|
||||
246: ".TSCK.OperationStorageEntryArray",
|
||||
247: ".TSCK.OperationStorageEntryArraySegment",
|
||||
248: ".TSCK.BlockDiffsAtCurrentRevisionCommand",
|
||||
249: ".TSCK.OutgoingCommandQueue",
|
||||
250: ".TSCK.OutgoingCommandQueueSegment",
|
||||
251: ".TSK.PropagatedCommandCollectionArchive",
|
||||
252: ".TSK.LocalCommandHistoryItem",
|
||||
253: ".TSK.LocalCommandHistoryArray",
|
||||
254: ".TSK.LocalCommandHistoryArraySegment",
|
||||
255: ".TSK.CollaborationCommandHistoryItem",
|
||||
256: ".TSK.CollaborationCommandHistoryArray",
|
||||
257: ".TSK.CollaborationCommandHistoryArraySegment",
|
||||
255: ".TSCK.CollaborationCommandHistoryItem",
|
||||
256: ".TSCK.CollaborationCommandHistoryArray",
|
||||
257: ".TSCK.CollaborationCommandHistoryArraySegment",
|
||||
258: ".TSK.PencilAnnotationUIState",
|
||||
259: ".TSKSOS.FixCorruptedDataCommandArchive",
|
||||
260: ".TSK.CommandAssetChunkArchive",
|
||||
261: ".TSK.AssetUploadStatusCommandArchive",
|
||||
262: ".TSK.AssetUnmaterializedOnServerCommandArchive",
|
||||
259: ".TSCKSOS.FixCorruptedDataCommandArchive",
|
||||
260: ".TSCK.CommandAssetChunkArchive",
|
||||
261: ".TSCK.AssetUploadStatusCommandArchive",
|
||||
262: ".TSCK.AssetUnmaterializedOnServerCommandArchive",
|
||||
263: ".TSK.CommandBehaviorArchive",
|
||||
264: ".TSK.CommandBehaviorSelectionPathStorageArchive",
|
||||
265: ".TSK.CommandActivityBehaviorArchive",
|
||||
273: ".TSK.ActivityOnlyCommandArchive",
|
||||
275: ".TSK.SetActivityAuthorShareParticipantIDCommandArchive",
|
||||
279: ".TSK.ActivityAuthorCacheArchive",
|
||||
280: ".TSK.ActivityStreamArchive",
|
||||
281: ".TSK.ActivityArchive",
|
||||
282: ".TSK.ActivityCommitCommandArchive",
|
||||
283: ".TSK.ActivityStreamActivityArray",
|
||||
284: ".TSK.ActivityStreamActivityArraySegment",
|
||||
285: ".TSK.ActivityStreamRemovedAuthorAuditorPendingStateArchive",
|
||||
286: ".TSK.ActivityAuthorArchive",
|
||||
287: ".TSKSOS.ResetActivityStreamCommandArchive",
|
||||
288: ".TSKSOS.RemoveAuthorIdentifiersCommandArchive",
|
||||
289: ".TSK.ActivityCursorCollectionPersistenceWrapperArchive",
|
||||
265: ".TSCK.CommandActivityBehaviorArchive",
|
||||
273: ".TSCK.ActivityOnlyCommandArchive",
|
||||
275: ".TSCK.SetActivityAuthorShareParticipantIDCommandArchive",
|
||||
279: ".TSCK.ActivityAuthorCacheArchive",
|
||||
280: ".TSCK.ActivityStreamArchive",
|
||||
281: ".TSCK.ActivityArchive",
|
||||
282: ".TSCK.ActivityCommitCommandArchive",
|
||||
283: ".TSCK.ActivityStreamActivityArray",
|
||||
284: ".TSCK.ActivityStreamActivityArraySegment",
|
||||
285: ".TSCK.ActivityStreamRemovedAuthorAuditorPendingStateArchive",
|
||||
286: ".TSCK.ActivityAuthorArchive",
|
||||
287: ".TSCKSOS.ResetActivityStreamCommandArchive",
|
||||
288: ".TSCKSOS.RemoveAuthorIdentifiersCommandArchive",
|
||||
289: ".TSCK.ActivityCursorCollectionPersistenceWrapperArchive",
|
||||
400: ".TSS.StyleArchive",
|
||||
401: ".TSS.StylesheetArchive",
|
||||
402: ".TSS.ThemeArchive",
|
||||
@ -113,6 +113,9 @@ export default {
|
||||
637: ".TSA.GalleryInfoRemoveItemsCommandArchive",
|
||||
638: ".TSASOS.VerifyActivityStreamWithServerCommandArchive",
|
||||
639: ".TSASOS.InducedVerifyActivityStreamWithServerCommandArchive",
|
||||
640: ".TSASOS.VerifyTransformHistoryWithServerCommandArchive",
|
||||
641: ".TSA.Object3DInfoSetValueCommandArchive",
|
||||
642: ".TSA.Object3DInfoCommandArchive",
|
||||
2001: ".TSWP.StorageArchive",
|
||||
2002: ".TSWP.SelectionArchive",
|
||||
2003: ".TSWP.DrawableAttachmentArchive",
|
||||
@ -185,6 +188,7 @@ export default {
|
||||
2410: ".TSWP.FlowInfoArchive",
|
||||
2411: ".TSWP.FlowInfoContainerArchive",
|
||||
2412: ".TSWP.PencilAnnotationSelectionTransformerArchive",
|
||||
2413: ".TSWP.DateTimeSelectionArchive",
|
||||
3002: ".TSD.DrawableArchive",
|
||||
3003: ".TSD.ContainerArchive",
|
||||
3004: ".TSD.ShapeArchive",
|
||||
|
@ -9,8 +9,8 @@ export default {
|
||||
211: ".TSK.DocumentSupportArchive",
|
||||
212: ".TSK.AnnotationAuthorArchive",
|
||||
213: ".TSK.AnnotationAuthorStorageArchive",
|
||||
215: ".TSK.SetAnnotationAuthorColorCommandArchive",
|
||||
218: ".TSK.CollaborationCommandHistory",
|
||||
215: ".TSCK.SetAnnotationAuthorColorCommandArchive",
|
||||
218: ".TSCK.CollaborationCommandHistory",
|
||||
219: ".TSK.DocumentSelectionArchive",
|
||||
220: ".TSK.CommandSelectionBehaviorArchive",
|
||||
221: ".TSK.NullCommandArchive",
|
||||
@ -18,54 +18,54 @@ export default {
|
||||
223: ".TSK.GroupCommitCommandArchive",
|
||||
224: ".TSK.InducedCommandCollectionArchive",
|
||||
225: ".TSK.InducedCommandCollectionCommitCommandArchive",
|
||||
226: ".TSK.CollaborationDocumentSessionState",
|
||||
227: ".TSK.CollaborationCommandHistoryCoalescingGroup",
|
||||
228: ".TSK.CollaborationCommandHistoryCoalescingGroupNode",
|
||||
229: ".TSK.CollaborationCommandHistoryOriginatingCommandAcknowledgementObserver",
|
||||
230: ".TSK.DocumentSupportCollaborationState",
|
||||
226: ".TSCK.CollaborationDocumentSessionState",
|
||||
227: ".TSCK.CollaborationCommandHistoryCoalescingGroup",
|
||||
228: ".TSCK.CollaborationCommandHistoryCoalescingGroupNode",
|
||||
229: ".TSCK.CollaborationCommandHistoryOriginatingCommandAcknowledgementObserver",
|
||||
230: ".TSCK.DocumentSupportCollaborationState",
|
||||
231: ".TSK.ChangeDocumentPackageTypeCommandArchive",
|
||||
232: ".TSK.UpgradeDocPostProcessingCommandArchive",
|
||||
233: ".TSK.FinalCommandPairArchive",
|
||||
234: ".TSK.OutgoingCommandQueueItem",
|
||||
235: ".TSK.TransformerEntry",
|
||||
238: ".TSK.CreateLocalStorageSnapshotCommandArchive",
|
||||
235: ".TSCK.TransformerEntry",
|
||||
238: ".TSCK.CreateLocalStorageSnapshotCommandArchive",
|
||||
240: ".TSK.SelectionPathTransformerArchive",
|
||||
241: ".TSK.NativeContentDescription",
|
||||
242: ".TSD.PencilAnnotationStorageArchive",
|
||||
245: ".TSK.OperationStorage",
|
||||
246: ".TSK.OperationStorageEntryArray",
|
||||
247: ".TSK.OperationStorageEntryArraySegment",
|
||||
248: ".TSK.BlockDiffsAtCurrentRevisionCommand",
|
||||
249: ".TSK.OutgoingCommandQueue",
|
||||
250: ".TSK.OutgoingCommandQueueSegment",
|
||||
245: ".TSCK.OperationStorage",
|
||||
246: ".TSCK.OperationStorageEntryArray",
|
||||
247: ".TSCK.OperationStorageEntryArraySegment",
|
||||
248: ".TSCK.BlockDiffsAtCurrentRevisionCommand",
|
||||
249: ".TSCK.OutgoingCommandQueue",
|
||||
250: ".TSCK.OutgoingCommandQueueSegment",
|
||||
251: ".TSK.PropagatedCommandCollectionArchive",
|
||||
252: ".TSK.LocalCommandHistoryItem",
|
||||
253: ".TSK.LocalCommandHistoryArray",
|
||||
254: ".TSK.LocalCommandHistoryArraySegment",
|
||||
255: ".TSK.CollaborationCommandHistoryItem",
|
||||
256: ".TSK.CollaborationCommandHistoryArray",
|
||||
257: ".TSK.CollaborationCommandHistoryArraySegment",
|
||||
255: ".TSCK.CollaborationCommandHistoryItem",
|
||||
256: ".TSCK.CollaborationCommandHistoryArray",
|
||||
257: ".TSCK.CollaborationCommandHistoryArraySegment",
|
||||
258: ".TSK.PencilAnnotationUIState",
|
||||
259: ".TSKSOS.FixCorruptedDataCommandArchive",
|
||||
260: ".TSK.CommandAssetChunkArchive",
|
||||
261: ".TSK.AssetUploadStatusCommandArchive",
|
||||
262: ".TSK.AssetUnmaterializedOnServerCommandArchive",
|
||||
259: ".TSCKSOS.FixCorruptedDataCommandArchive",
|
||||
260: ".TSCK.CommandAssetChunkArchive",
|
||||
261: ".TSCK.AssetUploadStatusCommandArchive",
|
||||
262: ".TSCK.AssetUnmaterializedOnServerCommandArchive",
|
||||
263: ".TSK.CommandBehaviorArchive",
|
||||
264: ".TSK.CommandBehaviorSelectionPathStorageArchive",
|
||||
265: ".TSK.CommandActivityBehaviorArchive",
|
||||
273: ".TSK.ActivityOnlyCommandArchive",
|
||||
275: ".TSK.SetActivityAuthorShareParticipantIDCommandArchive",
|
||||
279: ".TSK.ActivityAuthorCacheArchive",
|
||||
280: ".TSK.ActivityStreamArchive",
|
||||
281: ".TSK.ActivityArchive",
|
||||
282: ".TSK.ActivityCommitCommandArchive",
|
||||
283: ".TSK.ActivityStreamActivityArray",
|
||||
284: ".TSK.ActivityStreamActivityArraySegment",
|
||||
285: ".TSK.ActivityStreamRemovedAuthorAuditorPendingStateArchive",
|
||||
286: ".TSK.ActivityAuthorArchive",
|
||||
287: ".TSKSOS.ResetActivityStreamCommandArchive",
|
||||
288: ".TSKSOS.RemoveAuthorIdentifiersCommandArchive",
|
||||
289: ".TSK.ActivityCursorCollectionPersistenceWrapperArchive",
|
||||
265: ".TSCK.CommandActivityBehaviorArchive",
|
||||
273: ".TSCK.ActivityOnlyCommandArchive",
|
||||
275: ".TSCK.SetActivityAuthorShareParticipantIDCommandArchive",
|
||||
279: ".TSCK.ActivityAuthorCacheArchive",
|
||||
280: ".TSCK.ActivityStreamArchive",
|
||||
281: ".TSCK.ActivityArchive",
|
||||
282: ".TSCK.ActivityCommitCommandArchive",
|
||||
283: ".TSCK.ActivityStreamActivityArray",
|
||||
284: ".TSCK.ActivityStreamActivityArraySegment",
|
||||
285: ".TSCK.ActivityStreamRemovedAuthorAuditorPendingStateArchive",
|
||||
286: ".TSCK.ActivityAuthorArchive",
|
||||
287: ".TSCKSOS.ResetActivityStreamCommandArchive",
|
||||
288: ".TSCKSOS.RemoveAuthorIdentifiersCommandArchive",
|
||||
289: ".TSCK.ActivityCursorCollectionPersistenceWrapperArchive",
|
||||
400: ".TSS.StyleArchive",
|
||||
401: ".TSS.StylesheetArchive",
|
||||
402: ".TSS.ThemeArchive",
|
||||
@ -110,6 +110,9 @@ export default {
|
||||
637: ".TSA.GalleryInfoRemoveItemsCommandArchive",
|
||||
638: ".TSASOS.VerifyActivityStreamWithServerCommandArchive",
|
||||
639: ".TSASOS.InducedVerifyActivityStreamWithServerCommandArchive",
|
||||
640: ".TSASOS.VerifyTransformHistoryWithServerCommandArchive",
|
||||
641: ".TSA.Object3DInfoSetValueCommandArchive",
|
||||
642: ".TSA.Object3DInfoCommandArchive",
|
||||
2001: ".TSWP.StorageArchive",
|
||||
2002: ".TSWP.SelectionArchive",
|
||||
2003: ".TSWP.DrawableAttachmentArchive",
|
||||
@ -182,6 +185,7 @@ export default {
|
||||
2410: ".TSWP.FlowInfoArchive",
|
||||
2411: ".TSWP.FlowInfoContainerArchive",
|
||||
2412: ".TSWP.PencilAnnotationSelectionTransformerArchive",
|
||||
2413: ".TSWP.DateTimeSelectionArchive",
|
||||
3002: ".TSD.DrawableArchive",
|
||||
3003: ".TSD.ContainerArchive",
|
||||
3004: ".TSD.ShapeArchive",
|
||||
|
65
types.ts
65
types.ts
@ -1,65 +0,0 @@
|
||||
/// <reference path="../../types/index.d.ts"/>
|
||||
|
||||
declare type RawData = Uint8Array | number[];
|
||||
interface BinaryRecord {
|
||||
n?: string;
|
||||
f: any;
|
||||
T?: -1 | 1;
|
||||
p?: number;
|
||||
r?: number;
|
||||
}
|
||||
declare function recordhopper(data: RawData, cb:(val: any, R: BinaryRecord, RT: number)=>void): void;
|
||||
declare interface ReadableData {
|
||||
l: number;
|
||||
read_shift(t: 4): number;
|
||||
read_shift(t: any): any;
|
||||
}
|
||||
declare type ParseFunc<T> = (data: ReadableData, length: number) => T;
|
||||
declare var parse_XLWideString: ParseFunc<string>;
|
||||
|
||||
declare interface WritableData {
|
||||
l: number;
|
||||
write_shift(t: 4, val: number): void;
|
||||
write_shift(t: number, val: string|number, f?: string): any;
|
||||
}
|
||||
declare type WritableRawData = WritableData & RawData;
|
||||
interface BufArray {
|
||||
end(): RawData;
|
||||
next(sz: number): WritableData;
|
||||
push(buf: RawData): void;
|
||||
}
|
||||
declare function buf_array(): BufArray;
|
||||
declare function write_record(ba: BufArray, type: number, payload?: RawData, length?: number): void;
|
||||
declare function new_buf(sz: number): RawData & WritableData & ReadableData;
|
||||
|
||||
declare var tagregex: RegExp;
|
||||
declare var XML_HEADER: string;
|
||||
declare var RELS: any;
|
||||
declare function parsexmltag(tag: string, skip_root?: boolean, skip_LC?: boolean): object;
|
||||
declare function strip_ns(x: string): string;
|
||||
declare function write_UInt32LE(x: number, o?: WritableData): RawData;
|
||||
declare function write_XLWideString(data: string, o?: WritableData): RawData;
|
||||
declare function writeuint16(x: number): RawData;
|
||||
|
||||
declare function utf8read(x: string): string;
|
||||
declare function utf8write(x: string): string;
|
||||
|
||||
declare function a2s(a: RawData): string;
|
||||
declare function s2a(s: string): RawData;
|
||||
|
||||
interface ParseXLMetaOptions {
|
||||
WTF?: number|boolean;
|
||||
}
|
||||
interface XLMDT {
|
||||
name: string;
|
||||
offsets?: number[];
|
||||
}
|
||||
interface XLMetaRef {
|
||||
type: string;
|
||||
index: number;
|
||||
}
|
||||
interface XLMeta {
|
||||
Types: XLMDT[];
|
||||
Cell: XLMetaRef[];
|
||||
Value: XLMetaRef[];
|
||||
}
|
Loading…
Reference in New Issue
Block a user