Crusader_Decomp/scripts/_tmp_probe_sections.js

111 lines
2.8 KiB
JavaScript
Raw Permalink Normal View History

2026-04-07 00:15:44 +02:00
const fs = require("fs");
const ALLOWED_U5 = new Set([0x20, 0x22, 0x30]);
function readU32LE(buffer, offset) {
return buffer.readUInt32LE(offset);
}
function readU16LE(buffer, offset) {
return buffer.readUInt16LE(offset);
}
function isStructuredCandidate(record) {
if (record[0] >= 0x200) {
return false;
}
if (record[1] === 0 && record[2] === 0) {
return false;
}
if (record[1] >= 0x4000 || record[2] >= 0x4000) {
return false;
}
if (record[3] > 0x20 || record[4] > 0x04) {
return false;
}
return ALLOWED_U5.has(record[5]);
}
function probeFile(filePath) {
const data = fs.readFileSync(filePath);
const headerSize = readU32LE(data, 0);
const audioSize = readU32LE(data, 4);
const sectionSizes = [];
for (let offset = 8; offset < 0x38; offset += 4) {
sectionSizes.push(readU32LE(data, offset));
}
let cursor = headerSize + audioSize;
const sections = [];
for (let index = 0; index < sectionSizes.length; index += 1) {
const size = sectionSizes[index];
const start = cursor;
const end = start + size;
const bytes = data.subarray(start, end);
cursor = end;
let rowCount = null;
let rootHits = 0;
let bulkHits = 0;
if (bytes.length >= 4) {
rowCount = readU32LE(bytes, 0);
for (let rowIndex = 0; rowIndex < Math.min(rowCount, 5000); rowIndex += 1) {
const base = 4 + rowIndex * 24;
if (base + 24 > bytes.length) {
break;
}
const words = [];
for (let wordIndex = 0; wordIndex < 12; wordIndex += 1) {
words.push(readU16LE(bytes, base + wordIndex * 2));
}
const left = [words[4], words[5], words[0], words[1], words[2], words[3]];
const right = [words[10], words[11], words[6], words[7], words[8], words[9]];
if (isStructuredCandidate(left)) {
rootHits += 1;
}
if (isStructuredCandidate(right)) {
rootHits += 1;
}
}
}
const usableSize = bytes.length - (bytes.length % 24);
for (let offset = 0; offset < usableSize; offset += 24) {
for (const sideOffset of [0, 12]) {
const base = offset + sideOffset;
const record = [
readU16LE(bytes, base),
readU16LE(bytes, base + 2),
readU16LE(bytes, base + 4),
readU16LE(bytes, base + 6),
readU16LE(bytes, base + 8),
readU16LE(bytes, base + 10)
];
if (isStructuredCandidate(record)) {
bulkHits += 1;
}
}
}
sections.push({
index,
start,
size,
rowCount,
rootHits,
bulkHits
});
}
return {
filePath,
headerSize,
audioSize,
sections
};
}
for (const filePath of process.argv.slice(2)) {
console.log(JSON.stringify(probeFile(filePath), null, 2));
}