import test from "node:test"; import assert from "node:assert/strict"; import { parseWowAdtTerrain } from "./wow-adt-terrain-audit.mjs"; import { decodeWowAdtAlphaMap } from "./wow-adt-terrain-material.mjs"; function chunk(name, payload) { const header = Buffer.alloc(8); Buffer.from(name, "ascii").reverse().copy(header); header.writeUInt32LE(payload.length, 4); return Buffer.concat([header, payload]); } function rleFill(value) { const bytes = []; let remaining = 4096; while (remaining) { const count = Math.min(127, remaining); bytes.push(0x80 | count, value); remaining -= count; } return Buffer.from(bytes); } function zeroSizedMcalAdt({ declaredPayloadBytes = null } = {}) { const mtex = Buffer.from("Base.blp\0Overlay.blp\0", "utf8"); const layers = Buffer.alloc(32); layers.writeUInt32LE(0, 0); layers.writeUInt32LE(0, 4); layers.writeUInt32LE(1, 16); layers.writeUInt32LE(0x300, 20); layers.writeUInt32LE(0, 24); const alpha = rleFill(91); const payloadLength = declaredPayloadBytes ?? alpha.length; const alphaSubchunk = Buffer.alloc(8 + alpha.length); Buffer.from("MCAL", "ascii").reverse().copy(alphaSubchunk); alphaSubchunk.writeUInt32LE(0, 4); alpha.copy(alphaSubchunk, 8); const mcnkHeader = Buffer.alloc(128); mcnkHeader.writeUInt32LE(0, 4); mcnkHeader.writeUInt32LE(0, 8); mcnkHeader.writeUInt32LE(2, 12); mcnkHeader.writeUInt32LE(136, 28); mcnkHeader.writeUInt32LE(176, 36); mcnkHeader.writeUInt32LE(8 + payloadLength, 40); mcnkHeader.writeUInt16LE(0xa55a, 60); mcnkHeader.writeUInt16LE(0x1234, 62); mcnkHeader.writeUInt16LE(0xabcd, 64); const mcnk = Buffer.concat([mcnkHeader, chunk("MCLY", layers), alphaSubchunk]); const mver = Buffer.alloc(4); mver.writeUInt32LE(18); return Buffer.concat([chunk("MVER", mver), chunk("MTEX", mtex), chunk("MCNK", mcnk)]); } test("MVER 18 zero-sized MCAL headers use the enclosing MCNK size span", () => { const source = zeroSizedMcalAdt(); const parsed = parseWowAdtTerrain(source, { label: "zero-sized MCAL fixture" }); const target = parsed.chunks[0]; const overlay = target.layers[1]; assert.equal(target.alphaChunkHeaderSize, 0); assert.equal(target.alphaChunkSizeSource, "mcnk-header"); assert.equal(target.holeMask, 0xa55a); assert.equal(target.highResolutionHoles, false); assert.equal(target.lowResolutionTextureMap[0], 0xabcd); assert.equal(target.alphaSizeMatchesHeader, true); assert.equal(target.alphaChunkWithinMcnk, true); assert.equal(overlay.alphaMapEncoding, "rle-8"); assert.equal(overlay.alphaMapAvailable, true); assert.equal(overlay.alphaMapBytes, target.alphaBytes); const decoded = decodeWowAdtAlphaMap(source, target, overlay); assert.equal(decoded.length, 4096); assert.equal(decoded[0], 91); assert.equal(decoded[4095], 91); }); test("MVER 18 MCAL spans still fail closed when the declared payload leaves MCNK", () => { const source = zeroSizedMcalAdt({ declaredPayloadBytes: 0xffff }); const parsed = parseWowAdtTerrain(source, { label: "overrun MCAL fixture" }); const target = parsed.chunks[0]; assert.equal(target.alphaChunkWithinMcnk, false); assert.equal(target.layers[1].alphaMapAvailable, false); assert.throws(() => decodeWowAdtAlphaMap(source, target, target.layers[1]), /unsupported or invalid MCAL span/); });