// DatPrintOption.opt memory table, as documented in ESTX_파일구조.md. function readPrintOptions(buffer, onRow) { if (buffer.length < 24 || buffer.readUInt32LE(0) !== 0xbde01996) throw Error("인쇄 설정 헤더 오류"); const count = buffer.readUInt16LE(12), rows = buffer.readUInt16LE(14), start = buffer.readUInt16LE(22); if (count > 1024 || rows > 1000 || start > buffer.length) throw Error("인쇄 설정 크기 오류"); const decoder = new TextDecoder("euc-kr", { fatal: true }); let at = 24; const take = (n) => { if (n < 0 || at + n > buffer.length) throw Error("인쇄 설정 범위 오류"); const result = buffer.subarray(at, at + n); at += n; return result; }; const byte = () => take(1)[0]; const short = () => take(2).readUInt16LE(); const fields = []; for (let i = 0; i < count; i++) { const name = take(byte()).toString("ascii"), width = short(), kind = short(); take(2); const attributes = short(); for (let j = 0; j < attributes; j++) { take(byte()); const size = short(), type = short(); if (type === 73) take(short()); else take(size); } if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(name)) throw Error("인쇄 설정 필드명 오류"); fields.push({ name, width, kind }); } if (at > start) throw Error("인쇄 설정 설명자 범위 오류"); at = start; const result = []; for (let r = 0; r < rows; r++) { take(1); const status = take(Math.ceil(count / 4)), row = {}, positions = {}; for (let i = 0; i < count; i++) { const { name, width, kind } = fields[i], state = (status[i >> 2] >> ((i % 4) * 2)) & 3; if (state === 1 || state === 2) continue; if (state !== 0) throw Error("인쇄 설정 필드 상태 오류"); if (["PrintTop", "PrintBottom", "PrintLeft", "PrintRight", "PrintLineCount"].includes(name)) positions[name] = { at, kind, width }; if (kind === 1 && width === 4) row[name] = take(4).readInt32LE(); else if (kind === 3 && width === 2) row[name] = take(2).readInt16LE(); else if (kind === 4 && width === 8) row[name] = take(8).readDoubleLE(); else if (kind === 73 && width === 1) row[name] = decoder.decode(take(byte())); else if (kind === 75 && width === 4) take(take(4).readUInt32LE()); else throw Error(`인쇄 설정 필드형 오류: ${name}/${kind}/${width}`); } result.push(row); if (onRow) onRow(row, positions); } if (at !== buffer.length) throw Error("인쇄 설정 잔여 데이터 오류"); return result; } module.exports = { readPrintOptions };