bmweb-cli 0.1.0
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.
- package/LICENSE +674 -0
- package/README.md +351 -0
- package/dist/bmweb.js +2790 -0
- package/package.json +53 -0
- package/runtime/core/bestvm/codec.js +285 -0
- package/runtime/core/bestvm/environment.js +116 -0
- package/runtime/core/bestvm/executor.js +1483 -0
- package/runtime/core/bestvm/index.js +52 -0
- package/runtime/core/bestvm/machine.js +491 -0
- package/runtime/core/bestvm/operands.js +356 -0
- package/runtime/core/bestvm/registers.js +152 -0
- package/runtime/core/bestvm/write-guard.js +111 -0
- package/runtime/core/ipofile/compile.js +364 -0
- package/runtime/core/ipofile/decls.js +187 -0
- package/runtime/core/ipofile/emit.js +708 -0
- package/runtime/core/ipofile/exec.js +164 -0
- package/runtime/core/ipofile/lex.js +243 -0
- package/runtime/core/ipofile/parse.js +550 -0
- package/runtime/core/ipofile/pool.js +404 -0
- package/runtime/core/ipofile/walk.js +431 -0
- package/runtime/core/ipovm/builtin-helpers.js +182 -0
- package/runtime/core/ipovm/builtins-api.js +610 -0
- package/runtime/core/ipovm/builtins-screen.js +493 -0
- package/runtime/core/ipovm/builtins-table.js +166 -0
- package/runtime/core/ipovm/builtins-text.js +166 -0
- package/runtime/core/ipovm/emissions.js +138 -0
- package/runtime/core/ipovm/hosts.js +191 -0
- package/runtime/core/ipovm/operators.js +229 -0
- package/runtime/core/ipovm/structures.js +250 -0
- package/runtime/core/ipovm/suspensions.js +241 -0
- package/runtime/core/ipovm/tape.js +206 -0
- package/runtime/core/ipovm/values.js +241 -0
- package/runtime/core/ipovm/vm.js +1166 -0
- package/runtime/core/translate.js +526 -0
- package/runtime/core/webshim/api-router.js +592 -0
- package/runtime/core/webshim/bus.js +95 -0
- package/runtime/core/webshim/coding.js +82 -0
- package/runtime/core/webshim/data-fetch.js +66 -0
- package/runtime/core/webshim/exchange.js +288 -0
- package/runtime/core/webshim/framing.js +331 -0
- package/runtime/core/webshim/install.js +30 -0
- package/runtime/core/webshim/job-runner.js +319 -0
- package/runtime/core/webshim/native-bus.js +108 -0
- package/runtime/core/webshim/timers.js +82 -0
- package/runtime/core/webshim/trace.js +205 -0
- package/runtime/core/webshim/transport-base.js +128 -0
- package/runtime/core/webshim/variant-resolver.js +249 -0
- package/runtime/core/webshim/web-serial-bus.js +734 -0
- package/runtime/home/bmweb-home.ips +76 -0
- package/runtime/home/bmweb.h +26 -0
- package/runtime/screens/activations.js +258 -0
- package/runtime/screens/garage/diff.js +331 -0
- package/runtime/screens/garage/share.js +276 -0
- package/runtime/screens/garage/store.js +547 -0
- package/runtime/screens/ipo-runtime/cells.js +176 -0
- package/runtime/screens/ipo-runtime/dialogs.js +254 -0
- package/runtime/screens/ipo-runtime/home.js +358 -0
- package/runtime/screens/ipo-runtime/open.js +393 -0
- package/runtime/screens/ipo-runtime/paint-grid.js +106 -0
- package/runtime/screens/ipo-runtime/paint-modern.js +424 -0
- package/runtime/screens/ipo-runtime/print.js +281 -0
- package/runtime/screens/ipo-runtime/program.js +1337 -0
- package/runtime/screens/ipo-runtime/protocol.js +464 -0
- package/runtime/screens/ipo-runtime/script-scan.js +225 -0
- package/runtime/screens/ipo-runtime/translate-sets.js +130 -0
- package/runtime/screens/ipo-runtime/ui.js +249 -0
- package/runtime/screens/ipo-runtime/wire-policy.js +113 -0
- package/runtime/screens/ir.js +324 -0
- package/runtime/screens/search/data.js +153 -0
- package/runtime/screens/search/match.js +285 -0
- package/runtime/screens/search/open.js +66 -0
- package/runtime/vendor/fflate.min.js +1 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Constant pool of an .IPO, decoded in the browser.
|
|
3
|
+
*
|
|
4
|
+
* Port of tools/decompile/ipo_disasm.py's find_pool / _tok_pool /
|
|
5
|
+
* _find_pool_suffix. The pool is the body of a declaration literally named
|
|
6
|
+
* "Constant Data": a typed literal stream, one entry per source literal, in
|
|
7
|
+
* emission order. The code stream refers to entries by index, so getting the
|
|
8
|
+
* pool's START byte right is what makes every `const` token correct -- a start
|
|
9
|
+
* one entry early shifts every index in the file.
|
|
10
|
+
*
|
|
11
|
+
* Kept byte-for-byte faithful to the Python because the shipped
|
|
12
|
+
* data/inpa-ir/<stem>.ipoexec.json dumps are produced by that code: a dropped
|
|
13
|
+
* script has to decode to the same tokens the shipped ones did, or the same
|
|
14
|
+
* runtime would run two different programs depending on where the file came
|
|
15
|
+
* from.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Bytes a pool string may contain: everything printable-ish except newline. */
|
|
19
|
+
const IPOF_PRINTABLE_LO = 0x09;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Whether a byte may appear inside a pool string.
|
|
23
|
+
*
|
|
24
|
+
* @param {number} c Byte value.
|
|
25
|
+
* @returns {boolean} True when the byte is allowed in a string entry.
|
|
26
|
+
*/
|
|
27
|
+
function ipofPrintable(c) {
|
|
28
|
+
return c >= IPOF_PRINTABLE_LO && c !== 0x0a;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Read a little-endian unsigned integer from a byte array.
|
|
33
|
+
*
|
|
34
|
+
* @param {Uint8Array} data The file bytes.
|
|
35
|
+
* @param {number} at Offset of the first byte.
|
|
36
|
+
* @param {number} n Byte count (1..4).
|
|
37
|
+
* @returns {number} The value.
|
|
38
|
+
*/
|
|
39
|
+
function ipofUint(data, at, n) {
|
|
40
|
+
let v = 0;
|
|
41
|
+
for (let k = n - 1; k >= 0; k -= 1) v = v * 256 + data[at + k];
|
|
42
|
+
return v;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Decode `n` bytes as latin-1 text, the encoding INPA's own tooling uses.
|
|
47
|
+
*
|
|
48
|
+
* @param {Uint8Array} data The file bytes.
|
|
49
|
+
* @param {number} lo First byte offset.
|
|
50
|
+
* @param {number} hi End offset, exclusive.
|
|
51
|
+
* @returns {string} The decoded text.
|
|
52
|
+
*/
|
|
53
|
+
function ipofLatin1(data, lo, hi) {
|
|
54
|
+
let s = '';
|
|
55
|
+
for (let i = lo; i < hi; i += 1) s += String.fromCharCode(data[i]);
|
|
56
|
+
return s;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Index of the next newline in `data` within a window, or -1.
|
|
61
|
+
*
|
|
62
|
+
* @param {Uint8Array} data The file bytes.
|
|
63
|
+
* @param {number} from First offset to look at.
|
|
64
|
+
* @param {number} to End offset, exclusive.
|
|
65
|
+
* @returns {number} The offset of the newline, or -1.
|
|
66
|
+
*/
|
|
67
|
+
function ipofFindNl(data, from, to) {
|
|
68
|
+
const end = Math.min(to, data.length);
|
|
69
|
+
for (let i = Math.max(0, from); i < end; i += 1)
|
|
70
|
+
if (data[i] === 0x0a) return i;
|
|
71
|
+
return -1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Read a 64-bit float, the pool's `real` entry.
|
|
76
|
+
*
|
|
77
|
+
* @param {Uint8Array} data The file bytes.
|
|
78
|
+
* @param {number} at Offset of the first byte.
|
|
79
|
+
* @returns {number} The value.
|
|
80
|
+
*/
|
|
81
|
+
function ipofFloat64(data, at) {
|
|
82
|
+
const dv = new DataView(data.buffer, data.byteOffset + at, 8);
|
|
83
|
+
return dv.getFloat64(0, true);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Tokenize `data[start:end]` as a pure literal stream.
|
|
88
|
+
*
|
|
89
|
+
* Entry types match the Python: 06 string, 03 int, 05 real, 01 bool, 02 byte,
|
|
90
|
+
* 04 long. Each entry becomes `[typeLetter, value]` exactly as the Python
|
|
91
|
+
* tuples do, because the walker inlines both fields into every const token.
|
|
92
|
+
*
|
|
93
|
+
* @param {Uint8Array} data The file bytes.
|
|
94
|
+
* @param {number} start First offset.
|
|
95
|
+
* @param {number} end End offset, exclusive.
|
|
96
|
+
* @returns {Array<Array>|null} The entries, or null when the region is not a
|
|
97
|
+
* clean literal stream.
|
|
98
|
+
*/
|
|
99
|
+
function ipofTokPool(data, start, end) {
|
|
100
|
+
const entries = [];
|
|
101
|
+
let i = start;
|
|
102
|
+
while (i < end) {
|
|
103
|
+
const t = data[i];
|
|
104
|
+
if (t === 0x06) {
|
|
105
|
+
// No length cap: one corpus pool holds a 377-byte string, and the
|
|
106
|
+
// declaration's entry count validates the walk end to end anyway.
|
|
107
|
+
const j = ipofFindNl(data, i + 1, data.length);
|
|
108
|
+
if (j < 0) return null;
|
|
109
|
+
for (let k = i + 1; k < j; k += 1)
|
|
110
|
+
if (!ipofPrintable(data[k])) return null;
|
|
111
|
+
entries.push(['s', ipofLatin1(data, i + 1, j)]);
|
|
112
|
+
i = j + 1;
|
|
113
|
+
} else if (t === 0x03) {
|
|
114
|
+
if (i + 3 > end) return null;
|
|
115
|
+
entries.push(['i', ipofUint(data, i + 1, 2)]);
|
|
116
|
+
i += 3;
|
|
117
|
+
} else if (t === 0x05) {
|
|
118
|
+
if (i + 9 > end) return null;
|
|
119
|
+
entries.push(['d', ipofFloat64(data, i + 1)]);
|
|
120
|
+
i += 9;
|
|
121
|
+
} else if (t === 0x01) {
|
|
122
|
+
if (i + 2 > end) return null;
|
|
123
|
+
entries.push(['b', data[i + 1]]);
|
|
124
|
+
i += 2;
|
|
125
|
+
} else if (t === 0x02) {
|
|
126
|
+
if (i + 2 > end) return null;
|
|
127
|
+
entries.push(['y', data[i + 1]]);
|
|
128
|
+
i += 2;
|
|
129
|
+
} else if (t === 0x04) {
|
|
130
|
+
if (i + 5 > end) return null;
|
|
131
|
+
entries.push(['l', ipofUint(data, i + 1, 4)]);
|
|
132
|
+
i += 5;
|
|
133
|
+
} else {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return entries;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Every offset at which the byte pattern occurs.
|
|
142
|
+
*
|
|
143
|
+
* @param {Uint8Array} data The file bytes.
|
|
144
|
+
* @param {number[]} pat The bytes to find.
|
|
145
|
+
* @param {number} from First offset to search from.
|
|
146
|
+
* @param {number} to End offset, exclusive.
|
|
147
|
+
* @returns {number[]} The matching offsets.
|
|
148
|
+
*/
|
|
149
|
+
function ipofFindAll(data, pat, from, to) {
|
|
150
|
+
const out = [];
|
|
151
|
+
const end = Math.min(to, data.length) - pat.length;
|
|
152
|
+
for (let i = from; i <= end; i += 1) {
|
|
153
|
+
let ok = true;
|
|
154
|
+
for (let k = 0; k < pat.length; k += 1) {
|
|
155
|
+
if (data[i + k] !== pat[k]) {
|
|
156
|
+
ok = false;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (ok) out.push(i);
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** The literal bytes of the pool declaration's name, ".Constant Data\n". */
|
|
166
|
+
const IPOF_POOL_NAME = Array.from('Constant Data').map((c) => c.charCodeAt(0));
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Match the pool declaration header at a candidate name offset.
|
|
170
|
+
*
|
|
171
|
+
* The declaration has the same grammar as every proc:
|
|
172
|
+
* `<type> <name> \n <u32 id> \n [version] \n \x00 <u16 count>`; the u16 is the
|
|
173
|
+
* ENTRY COUNT, which is what validates the walk.
|
|
174
|
+
*
|
|
175
|
+
* @param {Uint8Array} data The file bytes.
|
|
176
|
+
* @param {number} nameAt Offset of the "C" of "Constant Data".
|
|
177
|
+
* @returns {{start: number, declared: number}|null} Body start and declared
|
|
178
|
+
* entry count, or null when the bytes are not a declaration.
|
|
179
|
+
*/
|
|
180
|
+
function ipofPoolHeader(data, nameAt) {
|
|
181
|
+
let i = nameAt + IPOF_POOL_NAME.length;
|
|
182
|
+
if (data[i] !== 0x0a) return null;
|
|
183
|
+
i += 1;
|
|
184
|
+
if (i + 4 > data.length) return null;
|
|
185
|
+
i += 4; // the u32 id
|
|
186
|
+
if (data[i] !== 0x0a) return null;
|
|
187
|
+
i += 1;
|
|
188
|
+
// the optional version string: up to 32 printable bytes, then a newline
|
|
189
|
+
let j = i;
|
|
190
|
+
const cap = Math.min(data.length, i + 33);
|
|
191
|
+
while (j < cap && data[j] !== 0x0a) {
|
|
192
|
+
if (data[j] < 0x20 || data[j] > 0x7e) return null;
|
|
193
|
+
j += 1;
|
|
194
|
+
}
|
|
195
|
+
if (j >= cap || data[j] !== 0x0a) return null;
|
|
196
|
+
i = j + 1;
|
|
197
|
+
if (data[i] !== 0x00 || i + 3 > data.length) return null;
|
|
198
|
+
return { start: i + 3, declared: ipofUint(data, i + 1, 2) };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The constant pool: its start offset and its entries.
|
|
203
|
+
*
|
|
204
|
+
* The LAST "Constant Data" declaration wins, as in the Python -- earlier
|
|
205
|
+
* matches can be a string inside the code region.
|
|
206
|
+
*
|
|
207
|
+
* @param {Uint8Array} data The file bytes.
|
|
208
|
+
* @returns {{start: number|null, entries: Array<Array>}} Pool start (null when
|
|
209
|
+
* the file has none) and the decoded entries.
|
|
210
|
+
*/
|
|
211
|
+
function ipofFindPool(data) {
|
|
212
|
+
const hits = ipofFindAll(data, IPOF_POOL_NAME, 0, data.length);
|
|
213
|
+
for (let k = hits.length - 1; k >= 0; k -= 1) {
|
|
214
|
+
const hdr = ipofPoolHeader(data, hits[k]);
|
|
215
|
+
if (!hdr) continue;
|
|
216
|
+
const entries = ipofTokPool(data, hdr.start, data.length);
|
|
217
|
+
if (entries && (entries.length & 0xffff) === hdr.declared) {
|
|
218
|
+
return { start: hdr.start, entries };
|
|
219
|
+
}
|
|
220
|
+
break; // the last declaration is the pool
|
|
221
|
+
}
|
|
222
|
+
return ipofFindPoolSuffix(data);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Fallback: the longest EOF-suffix that tokenizes as literals AND whose
|
|
227
|
+
* indexing agrees with the code's own references.
|
|
228
|
+
*
|
|
229
|
+
* A too-early start prepends fake entries and shifts every index, so
|
|
230
|
+
* candidates are scored on a semantic anchor: at a sampled
|
|
231
|
+
* `text(row, col, str)` call site, pool[r..r+2] must type-match (int,int,str).
|
|
232
|
+
*
|
|
233
|
+
* @param {Uint8Array} data The file bytes.
|
|
234
|
+
* @returns {{start: number|null, entries: Array<Array>}} Pool start and entries.
|
|
235
|
+
*/
|
|
236
|
+
function ipofFindPoolSuffix(data) {
|
|
237
|
+
const n = data.length;
|
|
238
|
+
// ok[i]: data[i:] tokenizes cleanly to EOF. Computed descending, O(n).
|
|
239
|
+
const ok = new Uint8Array(n + 1);
|
|
240
|
+
ok[n] = 1;
|
|
241
|
+
for (let i = n - 1; i >= 0; i -= 1) {
|
|
242
|
+
const t = data[i];
|
|
243
|
+
if (t === 0x06) {
|
|
244
|
+
const j = ipofFindNl(data, i + 1, i + 221);
|
|
245
|
+
if (j >= 0) {
|
|
246
|
+
let clean = true;
|
|
247
|
+
for (let k = i + 1; k < j; k += 1)
|
|
248
|
+
if (!ipofPrintable(data[k])) {
|
|
249
|
+
clean = false;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
if (clean) ok[i] = ok[j + 1];
|
|
253
|
+
}
|
|
254
|
+
} else if (t === 0x03 && i + 3 <= n) ok[i] = ok[i + 3];
|
|
255
|
+
else if (t === 0x05 && i + 9 <= n) ok[i] = ok[i + 9];
|
|
256
|
+
else if ((t === 0x01 || t === 0x02) && i + 2 <= n) ok[i] = ok[i + 2];
|
|
257
|
+
else if (t === 0x04 && i + 5 <= n) ok[i] = ok[i + 5];
|
|
258
|
+
}
|
|
259
|
+
let good = null;
|
|
260
|
+
let run = 0;
|
|
261
|
+
for (let i = n - 1; i >= 0; i -= 1) {
|
|
262
|
+
if (ok[i]) {
|
|
263
|
+
good = i;
|
|
264
|
+
run = 0;
|
|
265
|
+
} else {
|
|
266
|
+
run += 1;
|
|
267
|
+
if (good !== null && run > 6000) break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (good === null) return { start: null, entries: [] };
|
|
271
|
+
// candidate boundaries: the offset of every entry from `good` forward
|
|
272
|
+
const offs = [];
|
|
273
|
+
let i = good;
|
|
274
|
+
while (i < n) {
|
|
275
|
+
offs.push(i);
|
|
276
|
+
const t = data[i];
|
|
277
|
+
if (t === 0x06) i = ipofFindNl(data, i + 1, n) + 1;
|
|
278
|
+
else if (t === 0x03) i += 3;
|
|
279
|
+
else if (t === 0x05) i += 9;
|
|
280
|
+
else if (t === 0x01 || t === 0x02) i += 2;
|
|
281
|
+
else if (t === 0x04) i += 5;
|
|
282
|
+
else break;
|
|
283
|
+
}
|
|
284
|
+
// sample text-call anchors in the code region [0, good)
|
|
285
|
+
const anchors = [];
|
|
286
|
+
for (let p = 0; p + 15 <= good; p += 1) {
|
|
287
|
+
if (data[p] !== 0x01 || data[p + 1] !== 0x01) continue;
|
|
288
|
+
if (data[p + 4] !== 0x01 || data[p + 5] !== 0x01) continue;
|
|
289
|
+
if (data[p + 8] !== 0x01 || data[p + 9] !== 0x01) continue;
|
|
290
|
+
if (data[p + 12] !== 0x0c || data[p + 13] !== 0x81) continue;
|
|
291
|
+
if (data[p + 14] !== 0x48 || data[p + 15] !== 0x00) continue;
|
|
292
|
+
const r0 = ipofUint(data, p + 2, 2);
|
|
293
|
+
const r1 = ipofUint(data, p + 6, 2);
|
|
294
|
+
const r2 = ipofUint(data, p + 10, 2);
|
|
295
|
+
if (r1 === r0 + 1 && r2 === r0 + 2) anchors.push(r0);
|
|
296
|
+
}
|
|
297
|
+
const entries = ipofTokPool(data, good, n);
|
|
298
|
+
if (!entries) return { start: null, entries: [] };
|
|
299
|
+
const sample = anchors.slice(0, 40);
|
|
300
|
+
let best = null;
|
|
301
|
+
for (let k = 0; k < entries.length; k += 1) {
|
|
302
|
+
let score = 0;
|
|
303
|
+
for (const r of sample) {
|
|
304
|
+
const j = k + r;
|
|
305
|
+
if (
|
|
306
|
+
j + 2 < entries.length &&
|
|
307
|
+
entries[j][0] === 'i' &&
|
|
308
|
+
entries[j + 1][0] === 'i' &&
|
|
309
|
+
entries[j + 2][0] === 's'
|
|
310
|
+
)
|
|
311
|
+
score += 1;
|
|
312
|
+
}
|
|
313
|
+
if (best === null || score > best.score) best = { score, k };
|
|
314
|
+
if (best.score === sample.length && best.score > 0) break;
|
|
315
|
+
}
|
|
316
|
+
const k = best.k;
|
|
317
|
+
return { start: k < offs.length ? offs[k] : good, entries: entries.slice(k) };
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Where PROC CODE ends: at the trailing metadata region, not at the pool.
|
|
322
|
+
*
|
|
323
|
+
* Nearly every file closes its last proc then carries `11 "Global Data"` (the
|
|
324
|
+
* global-slot type table) and `12 "Constant Data"` before the pool proper.
|
|
325
|
+
* Counting that region as the last proc's body buries a file under "unknown
|
|
326
|
+
* code" that was never code.
|
|
327
|
+
*
|
|
328
|
+
* @param {Uint8Array} data The file bytes.
|
|
329
|
+
* @param {number|null} ps The pool start, or null.
|
|
330
|
+
* @returns {number} The end of the code region.
|
|
331
|
+
*/
|
|
332
|
+
function ipofCodeEnd(data, ps) {
|
|
333
|
+
const end = ps || data.length;
|
|
334
|
+
const pat = [0x11].concat(
|
|
335
|
+
Array.from('Global Data').map((c) => c.charCodeAt(0)),
|
|
336
|
+
[0x0a]
|
|
337
|
+
);
|
|
338
|
+
const hits = ipofFindAll(data, pat, 0, end);
|
|
339
|
+
return hits.length ? hits[0] : end;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* The flat const-slot list of a coding dispatcher (the `A_<cabd>` dialect), or
|
|
344
|
+
* null when the file is not one.
|
|
345
|
+
*
|
|
346
|
+
* These share the bytecode with the screen scripts but have no screen-style
|
|
347
|
+
* pool, and their entries are tagged differently (04 string, 02 int, 01 bool).
|
|
348
|
+
* Every record from the header on is a slot INCLUDING the include names and
|
|
349
|
+
* the import signatures: `const n` indexes the whole stream, so skipping them
|
|
350
|
+
* shifts every high index.
|
|
351
|
+
*
|
|
352
|
+
* @param {Uint8Array} data The file bytes.
|
|
353
|
+
* @returns {Array<Array>|null} The entries, or null.
|
|
354
|
+
*/
|
|
355
|
+
function ipofAPool(data) {
|
|
356
|
+
const marker = [0x12].concat(
|
|
357
|
+
Array.from('Constant Data').map((c) => c.charCodeAt(0)),
|
|
358
|
+
[0x0a]
|
|
359
|
+
);
|
|
360
|
+
const hits = ipofFindAll(data, marker, 0, data.length);
|
|
361
|
+
if (!hits.length) return null;
|
|
362
|
+
let p = hits[0] + marker.length;
|
|
363
|
+
if (p + 9 > data.length) return null;
|
|
364
|
+
p += 4; // the u32 id
|
|
365
|
+
while (p < data.length && data[p] === 0x0a) p += 1;
|
|
366
|
+
if (p < data.length && data[p] === 0x00) p += 1;
|
|
367
|
+
p += 2; // the declared count, not relied on
|
|
368
|
+
const pool = [];
|
|
369
|
+
while (p < data.length) {
|
|
370
|
+
const t = data[p];
|
|
371
|
+
if (t === 0x0a) {
|
|
372
|
+
p += 1;
|
|
373
|
+
continue;
|
|
374
|
+
} // a separator, not a slot
|
|
375
|
+
if (t === 0x04) {
|
|
376
|
+
const e = ipofFindNl(data, p + 1, data.length);
|
|
377
|
+
if (e < 0) break;
|
|
378
|
+
pool.push(['s', ipofLatin1(data, p + 1, e)]);
|
|
379
|
+
p = e + 1;
|
|
380
|
+
} else if (t === 0x02) {
|
|
381
|
+
pool.push(['i', ipofUint(data, p + 1, 2)]);
|
|
382
|
+
p += 3;
|
|
383
|
+
} else if (t === 0x01) {
|
|
384
|
+
pool.push(['b', data[p + 1]]);
|
|
385
|
+
p += 2;
|
|
386
|
+
} else {
|
|
387
|
+
break; // the trailing DLL signature table
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return pool;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
394
|
+
module.exports = {
|
|
395
|
+
ipofFindPool,
|
|
396
|
+
ipofCodeEnd,
|
|
397
|
+
ipofTokPool,
|
|
398
|
+
ipofUint,
|
|
399
|
+
ipofLatin1,
|
|
400
|
+
ipofFindNl,
|
|
401
|
+
ipofFindAll,
|
|
402
|
+
ipofAPool,
|
|
403
|
+
};
|
|
404
|
+
}
|