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)); }