- 拆分:tools/split.js 重切新版(1347 模块 / 126 代码模块),主文件 main.7cfa4058.js,语法验证通过 - 修复 split.js 内自动刷新拦截的 \\n 转义:它在模板字符串里,必须写 \\\\n,否则生成的主文件字符串断行、语法报错 - 符号映射:map_symbols.js 对齐旧→新(qyr→ryz、w187→c18o、z4t→jtn、vgt→rkt、Bmt→Ezt、Qjt→Fjt、txt→Gjt、k15b→s15n、azi_1→vzr_1…) - 移植 7 处针对性修改:炮塔摆头不回弹(vSt.ryz)、摆头不过冲(case 0)、精准跟手(case 1/2)、悬浮底盘 raw 两级(Ezt.n36 + Zmt 实际速度)、电磁炮蓄力时长(jtn.c18o) - 重新打包 unpacked.pack.json(127 文件 / 版本 96833eb2b0cf8909)
59 lines
2.0 KiB
JavaScript
59 lines
2.0 KiB
JavaScript
// parse_dsstore.js - 从 macOS .DS_Store 里抽出目录项名字
|
||
// 用法: node parse_dsstore.js <file.ds_store> [--json out.json]
|
||
// 原理: DS_Store 是 B 树,文件/目录名记录以 [type=0x00000005][offset u32][len u32][len×UTF-16BE] 内联存放,
|
||
// 因此用滑动扫描定位 type 标记再读长度即可,无需完整解析 B 树。
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
const Argv = process.argv.slice(2);
|
||
const File = Argv[0];
|
||
const JsonOut = (() => {
|
||
const I = Argv.indexOf('--json');
|
||
return I >= 0 && Argv[I + 1] ? Argv[I + 1] : '';
|
||
})();
|
||
|
||
const Buf = fs.readFileSync(File);
|
||
const Names = new Set();
|
||
|
||
// 主路径:定位 type=5 记录
|
||
for (let I = 0; I + 12 <= Buf.length; I++) {
|
||
if (Buf[I] !== 0 || Buf[I + 1] !== 0 || Buf[I + 2] !== 0 || Buf[I + 3] !== 5) continue;
|
||
const Len = Buf.readUInt32BE(I + 8);
|
||
if (Len === 0 || Len > 1024) continue;
|
||
const Start = I + 12;
|
||
if (Start + Len * 2 > Buf.length) continue;
|
||
const Name = Buf.slice(Start, Start + Len * 2).toString('utf16le');
|
||
// 用 utf16le 读 BE 数据会字节交换;这里改回手工 BE 解码
|
||
let BeName = '';
|
||
for (let K = 0; K < Len; K++) BeName += String.fromCharCode(Buf.readUInt16BE(Start + K * 2));
|
||
if (!BeName || /[\x00-\x08\x0b-\x1f]/.test(BeName)) continue;
|
||
Names.add(BeName);
|
||
void Name;
|
||
}
|
||
|
||
// 兜底:任意可打印 UTF-16BE 串(长度 >= 3)
|
||
if (Names.size === 0) {
|
||
for (let I = 0; I + 6 <= Buf.length; I += 2) {
|
||
let S = '';
|
||
let J = I;
|
||
while (J + 2 <= Buf.length) {
|
||
const C = Buf.readUInt16BE(J);
|
||
if (C < 0x20 || C > 0x7e) break;
|
||
S += String.fromCharCode(C);
|
||
J += 2;
|
||
}
|
||
if (S.length >= 3) {
|
||
Names.add(S);
|
||
I = J - 2;
|
||
}
|
||
}
|
||
}
|
||
|
||
const List = [...Names].sort();
|
||
const Stat = fs.statSync(File);
|
||
console.log('文件: ' + path.basename(File) + ' ' + Stat.size + ' 字节');
|
||
console.log('条目: ' + List.length);
|
||
for (const N of List) console.log(' ' + N);
|
||
|
||
if (JsonOut) fs.writeFileSync(path.resolve(JsonOut), JSON.stringify({ File, Size: Stat.size, Entries: List }, null, 2), 'utf8');
|