@xwordly/xword-parser
Version:
Fast, type-safe TypeScript library for parsing crossword puzzles (PUZ, iPUZ, JPZ, XD)
1 lines • 37.7 kB
Source Map (JSON)
{"version":3,"sources":["../src/binary-reader.ts","../src/puz.ts"],"names":[],"mappings":"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","file":"chunk-YDXBFJGM.mjs","sourcesContent":["/**\n * Generic binary reader for parsing binary file formats\n */\n\nimport { BinaryParseError } from './errors';\n\n/**\n * A utility class for reading binary data from buffers with automatic offset tracking.\n */\nexport class BinaryReader {\n private _buffer: Buffer;\n private _offset: number;\n\n constructor(data: Buffer | ArrayBuffer | Uint8Array) {\n if (data instanceof ArrayBuffer) {\n this._buffer = Buffer.from(data);\n } else if (data instanceof Uint8Array) {\n this._buffer = Buffer.from(data);\n } else {\n this._buffer = data;\n }\n this._offset = 0;\n }\n\n /**\n * Read an unsigned 8-bit integer and advance the offset\n */\n readUInt8(): number {\n if (this._offset + 1 > this._buffer.length) {\n throw new BinaryParseError(\n `Cannot read byte at offset ${this._offset}: buffer too short (length: ${this._buffer.length})`,\n );\n }\n const value = this._buffer.readUInt8(this._offset);\n this._offset += 1;\n return value;\n }\n\n /**\n * Read an unsigned 16-bit integer (little-endian) and advance the offset\n */\n readUInt16LE(): number {\n if (this._offset + 2 > this._buffer.length) {\n throw new BinaryParseError(\n `Cannot read 16-bit value at offset ${this._offset}: buffer too short (length: ${this._buffer.length})`,\n );\n }\n const value = this._buffer.readUInt16LE(this._offset);\n this._offset += 2;\n return value;\n }\n\n /**\n * Read a specified number of bytes and advance the offset\n */\n readBytes(length: number): Buffer {\n if (this._offset + length > this._buffer.length) {\n throw new BinaryParseError(\n `Cannot read ${length} bytes at offset ${this._offset}: buffer too short (length: ${this._buffer.length})`,\n );\n }\n const value = this._buffer.slice(this._offset, this._offset + length);\n this._offset += length;\n return value;\n }\n\n /**\n * Read a string of specified length with optional null trimming\n * @param length Number of bytes to read\n * @param trimNull Whether to trim at first null byte (default: true)\n * @param encoding Character encoding (default: 'latin1')\n */\n readString(\n length: number,\n trimNull: boolean = true,\n encoding: BufferEncoding = 'latin1',\n ): string {\n const bytes = this.readBytes(length);\n if (trimNull) {\n // Remove trailing nulls\n let end = bytes.indexOf(0);\n if (end === -1) end = length;\n return bytes.toString(encoding, 0, end);\n }\n return bytes.toString(encoding);\n }\n\n /**\n * Read a null-terminated string and advance past the null terminator\n * @param encoding Character encoding (default: 'latin1')\n */\n readNullTerminatedString(encoding: BufferEncoding = 'latin1'): string {\n const start = this._offset;\n while (this._offset < this._buffer.length && this._buffer[this._offset] !== 0) {\n this._offset++;\n }\n if (this._offset >= this._buffer.length) {\n throw new BinaryParseError(\n `Cannot read null-terminated string at offset ${start}: buffer ended without null terminator`,\n );\n }\n const str = this._buffer.toString(encoding, start, this._offset);\n this._offset++; // Skip null terminator\n return str;\n }\n\n /**\n * Move the read position to a specific offset\n */\n seek(position: number): void {\n if (position < 0 || position > this._buffer.length) {\n throw new BinaryParseError(\n `Cannot seek to position ${position}: out of bounds (buffer length: ${this._buffer.length})`,\n );\n }\n this._offset = position;\n }\n\n /**\n * Get the current read position\n */\n get position(): number {\n return this._offset;\n }\n\n /**\n * Get the total length of the buffer\n */\n get length(): number {\n return this._buffer.length;\n }\n\n /**\n * Get the underlying buffer\n */\n get buffer(): Buffer {\n return this._buffer;\n }\n\n /**\n * Check if there's more data to read\n */\n hasMore(): boolean {\n return this._offset < this._buffer.length;\n }\n\n /**\n * Get the number of bytes remaining to read\n */\n get remaining(): number {\n return this._buffer.length - this._offset;\n }\n}\n","/**\n * Parser for PUZ crossword format (Across Lite)\n * Based on reverse-engineered specification\n */\n\nimport { InvalidFileError, PuzParseError, BinaryParseError } from './errors';\nimport { ErrorCode } from './types';\nimport type { Puzzle, Grid, Cell as UnifiedCell, Clues, ParseOptions } from './types';\nimport { BinaryReader } from './binary-reader';\nimport {\n MAX_GRID_WIDTH,\n MAX_GRID_HEIGHT,\n PUZ_MAGIC_STRING,\n PUZ_HEADER_SIZE,\n PUZ_SECTION_GRBS,\n PUZ_SECTION_RTBL,\n PUZ_SECTION_GEXT,\n PUZ_SECTION_LTIM,\n PUZ_CIRCLED_CELL_FLAG,\n} from './constants';\n\nexport interface PuzMetadata {\n title?: string;\n author?: string;\n copyright?: string;\n notes?: string;\n}\n\nexport interface PuzClue {\n number: number;\n text: string;\n}\n\nexport interface PuzCell {\n solution?: string;\n playerState?: string;\n isBlack: boolean;\n isCircled?: boolean;\n hasRebus?: boolean;\n rebusKey?: number;\n}\n\nexport interface PuzPuzzle {\n width: number;\n height: number;\n metadata: PuzMetadata;\n grid: PuzCell[][];\n across: PuzClue[];\n down: PuzClue[];\n rebusTable?: Map<number, string>;\n isScrambled?: boolean;\n timer?: {\n elapsed: number;\n running: boolean;\n };\n}\n\n// PUZ file header structure\ninterface PuzHeader {\n checksum: number;\n magic: string;\n cibChecksum: number;\n maskedLowChecksum: number;\n maskedHighChecksum: number;\n version: string;\n reserved1: number;\n scrambledChecksum: number;\n reserved2: Buffer;\n width: number;\n height: number;\n numClues: number;\n puzzleType: number;\n scrambledTag: number;\n}\n\nfunction readHeader(reader: BinaryReader): PuzHeader {\n // Search for the magic string \"ACROSS&DOWN\" in the file\n const magicBytes = Buffer.from(PUZ_MAGIC_STRING, 'latin1');\n let magicOffset = -1;\n\n // Search for the magic string in the buffer\n for (let i = 0; i <= reader.length - magicBytes.length; i++) {\n let found = true;\n for (let j = 0; j < magicBytes.length; j++) {\n if (reader.buffer[i + j] !== magicBytes[j]) {\n found = false;\n break;\n }\n }\n if (found) {\n magicOffset = i;\n break;\n }\n }\n\n if (magicOffset === -1) {\n throw new PuzParseError(\n `Invalid PUZ file: magic string \"${PUZ_MAGIC_STRING}\" not found`,\n ErrorCode.PUZ_INVALID_HEADER,\n );\n }\n\n // Position reader at the start of the actual PUZ data (2 bytes before magic string)\n const headerStart = magicOffset - 2;\n if (headerStart < 0) {\n throw new PuzParseError(\n 'Invalid PUZ file: magic string found too early in file',\n ErrorCode.PUZ_INVALID_HEADER,\n );\n }\n\n // Ensure there's enough data for the full header\n if (headerStart + PUZ_HEADER_SIZE > reader.length) {\n throw new PuzParseError(\n 'Invalid PUZ file: insufficient data for header',\n ErrorCode.PUZ_INVALID_HEADER,\n );\n }\n\n reader.seek(headerStart);\n\n // Read header fields according to PUZ specification\n const checksum = reader.readUInt16LE(); // 0x00-0x01\n const magic = reader.readString(12, true, 'latin1'); // 0x02-0x0D\n const cibChecksum = reader.readUInt16LE(); // 0x0E-0x0F\n const maskedLowChecksum = reader.readUInt16LE(); // 0x10-0x11\n const maskedHighChecksum = reader.readUInt16LE(); // 0x12-0x13\n const version = reader.readString(4, true, 'latin1'); // 0x14-0x17\n const reserved1 = reader.readUInt16LE(); // 0x18-0x19\n const scrambledChecksum = reader.readUInt16LE(); // 0x1A-0x1B\n const reserved2 = reader.readBytes(12); // 0x1C-0x27\n reader.readBytes(4); // 0x28-0x2B (skip unknown bytes)\n const width = reader.readUInt8(); // 0x2C\n const height = reader.readUInt8(); // 0x2D\n const numClues = reader.readUInt16LE(); // 0x2E-0x2F\n const puzzleType = reader.readUInt16LE(); // 0x30-0x31\n const scrambledTag = reader.readUInt16LE(); // 0x32-0x33\n\n const header: PuzHeader = {\n checksum,\n magic,\n cibChecksum,\n maskedLowChecksum,\n maskedHighChecksum,\n version,\n reserved1,\n scrambledChecksum,\n reserved2,\n width,\n height,\n numClues,\n puzzleType,\n scrambledTag,\n };\n\n // Verify we read the magic string correctly\n if (header.magic !== PUZ_MAGIC_STRING) {\n throw new InvalidFileError(\n 'PUZ',\n `magic string mismatch after positioning. Expected \"${PUZ_MAGIC_STRING}\", got \"${header.magic}\"`,\n );\n }\n\n return header;\n}\n\nfunction parseGrid(\n solution: string,\n playerState: string,\n width: number,\n height: number,\n): PuzCell[][] {\n const grid: PuzCell[][] = [];\n\n for (let row = 0; row < height; row++) {\n const cells: PuzCell[] = [];\n for (let col = 0; col < width; col++) {\n const index = row * width + col;\n const solutionChar = solution[index];\n const playerChar = playerState[index];\n\n cells.push({\n solution: solutionChar === '.' ? undefined : solutionChar,\n playerState: playerChar === '-' || playerChar === '.' ? undefined : playerChar,\n isBlack: solutionChar === '.',\n });\n }\n grid.push(cells);\n }\n\n return grid;\n}\n\nfunction assignClueNumbers(grid: PuzCell[][]): Map<string, number> {\n const cluePositions = new Map<string, number>();\n let clueNumber = 1;\n const height = grid.length;\n const width = grid[0]?.length || 0;\n\n for (let row = 0; row < height; row++) {\n for (let col = 0; col < width; col++) {\n if (grid[row]?.[col]?.isBlack) continue;\n\n const hasAcross =\n (col === 0 || grid[row]?.[col - 1]?.isBlack) &&\n col < width - 1 &&\n !grid[row]?.[col + 1]?.isBlack;\n\n const hasDown =\n (row === 0 || grid[row - 1]?.[col]?.isBlack) &&\n row < height - 1 &&\n !grid[row + 1]?.[col]?.isBlack;\n\n if (hasAcross || hasDown) {\n if (hasAcross) {\n cluePositions.set(`A${row},${col}`, clueNumber);\n }\n if (hasDown) {\n cluePositions.set(`D${row},${col}`, clueNumber);\n }\n clueNumber++;\n }\n }\n }\n\n return cluePositions;\n}\n\nfunction parseClues(\n clueStrings: string[],\n cluePositions: Map<string, number>,\n): { across: PuzClue[]; down: PuzClue[] } {\n const across: PuzClue[] = [];\n const down: PuzClue[] = [];\n let clueIndex = 0;\n\n // Sort positions to ensure correct clue assignment\n const sortedPositions = Array.from(cluePositions.entries()).sort((a, b) => {\n const [aType, aPos] = a[0].split(',');\n const [bType, bPos] = b[0].split(',');\n const aRow = parseInt(aType?.substring(1) || '0');\n const bRow = parseInt(bType?.substring(1) || '0');\n const aCol = parseInt(aPos || '0');\n const bCol = parseInt(bPos || '0');\n\n if (aRow !== bRow) return aRow - bRow;\n return aCol - bCol;\n });\n\n // First pass: collect all across clues\n for (const [key, number] of sortedPositions) {\n if (key.startsWith('A') && clueIndex < clueStrings.length) {\n across.push({\n number,\n text: clueStrings[clueIndex++] || '',\n });\n }\n }\n\n // Second pass: collect all down clues\n for (const [key, number] of sortedPositions) {\n if (key.startsWith('D') && clueIndex < clueStrings.length) {\n down.push({\n number,\n text: clueStrings[clueIndex++] || '',\n });\n }\n }\n\n return { across, down };\n}\n\nfunction parseExtraSections(\n reader: BinaryReader,\n grid: PuzCell[][],\n): {\n rebusTable?: Map<number, string>;\n timer?: { elapsed: number; running: boolean };\n} {\n const result: {\n rebusTable?: Map<number, string>;\n timer?: { elapsed: number; running: boolean };\n } = {};\n\n while (reader.hasMore()) {\n // Check if we have enough bytes for a section header\n if (reader.position + 8 > reader.length) break;\n\n // Skip null padding bytes between sections\n while (reader.hasMore() && reader.buffer[reader.position] === 0) {\n reader.readUInt8();\n }\n\n // Check again after skipping padding\n if (reader.position + 8 > reader.length) break;\n\n const sectionTitle = reader.readString(4, true, 'latin1');\n const dataLength = reader.readUInt16LE();\n reader.readUInt16LE(); // checksum (unused)\n\n // Skip if not a valid section\n if (dataLength > reader.length - reader.position) break;\n\n const sectionData = reader.readBytes(dataLength);\n\n switch (sectionTitle) {\n case PUZ_SECTION_GRBS: {\n // Rebus grid - one byte per square\n const height = grid.length;\n const width = grid[0]?.length || 0;\n for (let row = 0; row < height; row++) {\n for (let col = 0; col < width; col++) {\n const index = row * width + col;\n if (index < sectionData.length) {\n const rebusKey = sectionData[index];\n if (rebusKey && rebusKey > 0 && grid[row]?.[col]) {\n grid[row]![col]!.hasRebus = true;\n grid[row]![col]!.rebusKey = rebusKey - 1;\n }\n }\n }\n }\n break;\n }\n\n case PUZ_SECTION_RTBL: {\n // Rebus table - semicolon-separated values with key:value pairs\n const tableStr = sectionData.toString('latin1');\n const entries = tableStr.split(';');\n result.rebusTable = new Map();\n\n for (const entry of entries) {\n if (entry.includes(':')) {\n const [key, value] = entry.split(':');\n const keyNum = Number.parseInt(key || '0', 10);\n if (!Number.isNaN(keyNum)) {\n result.rebusTable.set(keyNum, value || '');\n }\n }\n }\n break;\n }\n\n case PUZ_SECTION_GEXT: {\n // Grid extras - circled squares, etc.\n const height = grid.length;\n const width = grid[0]?.length || 0;\n for (let row = 0; row < height; row++) {\n for (let col = 0; col < width; col++) {\n const index = row * width + col;\n if (index < sectionData.length && grid[row]?.[col]) {\n const flags = sectionData[index];\n if (flags && flags & PUZ_CIRCLED_CELL_FLAG) {\n grid[row]![col]!.isCircled = true;\n }\n }\n }\n }\n break;\n }\n\n case PUZ_SECTION_LTIM: {\n // Timer data\n const timerStr = sectionData.toString('latin1');\n const [elapsed, running] = timerStr.split(',');\n result.timer = {\n elapsed: parseInt(elapsed || '0') || 0,\n running: running === '0' ? false : true,\n };\n break;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Parse a PUZ format crossword puzzle.\n *\n * @param data - The PUZ binary data as Buffer, ArrayBuffer, Uint8Array, or string\n * @param options - Optional parsing options\n * @param options.maxGridSize - Maximum allowed grid dimensions\n * @returns A PuzPuzzle object containing all puzzle data\n * @throws {PuzParseError} When the content is not valid PUZ format\n * @throws {InvalidFileError} When the file is corrupted or has invalid checksums\n *\n * @example\n * ```typescript\n * import { parsePuz } from 'xword-parser';\n * import { readFileSync } from 'fs';\n *\n * const puzData = readFileSync('puzzle.puz');\n * const puzzle = parsePuz(puzData);\n * ```\n */\nexport function parsePuz(\n data: Buffer | ArrayBuffer | Uint8Array | string,\n options?: ParseOptions,\n): PuzPuzzle {\n let buffer: Buffer;\n\n if (typeof data === 'string') {\n // If string is passed, assume it's base64 encoded\n buffer = Buffer.from(data, 'base64');\n } else if (data instanceof Buffer) {\n buffer = data;\n } else {\n buffer = Buffer.from(data as ArrayBuffer);\n }\n\n try {\n const reader = new BinaryReader(buffer);\n const header = readHeader(reader);\n\n // Validate dimensions\n if (header.width <= 0 || header.height <= 0) {\n throw new PuzParseError(\n `Invalid puzzle dimensions: width=${header.width}, height=${header.height}`,\n ErrorCode.PUZ_INVALID_GRID,\n );\n }\n\n // Check against maxGridSize if provided, otherwise use defaults\n const maxWidth = options?.maxGridSize?.width ?? MAX_GRID_WIDTH;\n const maxHeight = options?.maxGridSize?.height ?? MAX_GRID_HEIGHT;\n if (header.width > maxWidth || header.height > maxHeight) {\n throw new PuzParseError(\n `Grid dimensions too large: ${header.width}x${header.height}. Maximum supported size is ${maxWidth}x${maxHeight}`,\n ErrorCode.PUZ_INVALID_GRID,\n );\n }\n\n // Read puzzle data\n const gridSize = header.width * header.height;\n const solution = reader.readString(gridSize, true, 'latin1');\n const playerState = reader.readString(gridSize, true, 'latin1');\n\n // Read strings\n const title = reader.readNullTerminatedString('latin1');\n const author = reader.readNullTerminatedString('latin1');\n const copyright = reader.readNullTerminatedString('latin1');\n\n // Read clues\n const clueStrings: string[] = [];\n for (let i = 0; i < header.numClues; i++) {\n clueStrings.push(reader.readNullTerminatedString('latin1'));\n }\n\n const notes = reader.readNullTerminatedString('latin1');\n\n // Parse grid\n const grid = parseGrid(solution, playerState, header.width, header.height);\n\n // Assign clue numbers and parse clues\n const cluePositions = assignClueNumbers(grid);\n const { across, down } = parseClues(clueStrings, cluePositions);\n\n // Parse extra sections\n const extras = parseExtraSections(reader, grid);\n\n return {\n width: header.width,\n height: header.height,\n metadata: {\n title: title || undefined,\n author: author || undefined,\n copyright: copyright || undefined,\n notes: notes || undefined,\n },\n grid,\n across,\n down,\n rebusTable: extras.rebusTable,\n isScrambled: header.scrambledTag !== 0,\n timer: extras.timer,\n };\n } catch (error) {\n // Convert BinaryParseError to PuzParseError\n if (error instanceof BinaryParseError) {\n throw new PuzParseError(error.message, ErrorCode.PUZ_PARSE_ERROR);\n }\n // Re-throw other errors as-is\n throw error;\n }\n}\n\n/**\n * Convert a PUZ puzzle to the unified Puzzle format.\n *\n * @param puzzle - The PuzPuzzle object to convert\n * @returns A unified Puzzle object\n *\n * @example\n * ```typescript\n * import { parsePuz, convertPuzToUnified } from 'xword-parser';\n * const puzPuzzle = parsePuz(puzData);\n * const unifiedPuzzle = convertPuzToUnified(puzPuzzle);\n * ```\n */\nexport function convertPuzToUnified(puzzle: PuzPuzzle): Puzzle {\n const grid: Grid = {\n width: puzzle.width,\n height: puzzle.height,\n cells: [],\n };\n\n // Convert grid and assign numbers\n let cellNumber = 1;\n for (let y = 0; y < puzzle.height; y++) {\n const row: UnifiedCell[] = [];\n for (let x = 0; x < puzzle.width; x++) {\n const puzCell = puzzle.grid[y]?.[x];\n\n // Determine if this cell should have a number\n let number: number | undefined;\n if (puzCell && !puzCell.isBlack) {\n const needsNumber =\n // Start of across word\n ((x === 0 || puzzle.grid[y]?.[x - 1]?.isBlack) &&\n x < puzzle.width - 1 &&\n !puzzle.grid[y]?.[x + 1]?.isBlack) ||\n // Start of down word\n ((y === 0 || puzzle.grid[y - 1]?.[x]?.isBlack) &&\n y < puzzle.height - 1 &&\n !puzzle.grid[y + 1]?.[x]?.isBlack);\n\n if (needsNumber) {\n number = cellNumber++;\n }\n }\n\n const cell: UnifiedCell = {\n solution: puzCell?.solution,\n number,\n isBlack: puzCell?.isBlack || false,\n };\n\n // Add cell-specific metadata\n if (puzCell?.isCircled) {\n cell.isCircled = true;\n }\n if (puzCell?.hasRebus) {\n cell.hasRebus = true;\n if (puzCell.rebusKey !== undefined) {\n cell.rebusKey = puzCell.rebusKey;\n }\n }\n\n row.push(cell);\n }\n grid.cells.push(row);\n }\n\n // Convert clues\n const clues: Clues = {\n across: puzzle.across.map((c) => ({\n number: c.number,\n text: c.text,\n })),\n down: puzzle.down.map((c) => ({\n number: c.number,\n text: c.text,\n })),\n };\n\n const result: Puzzle = {\n title: puzzle.metadata.title,\n author: puzzle.metadata.author,\n copyright: puzzle.metadata.copyright,\n notes: puzzle.metadata.notes,\n grid,\n clues,\n rebusTable: puzzle.rebusTable,\n };\n\n // Add puzzle-level metadata if present\n const additionalProps: Record<string, unknown> = {};\n if (puzzle.isScrambled) {\n additionalProps.isScrambled = puzzle.isScrambled;\n }\n if (puzzle.timer) {\n additionalProps.timer = puzzle.timer;\n }\n\n if (Object.keys(additionalProps).length > 0) {\n result.additionalProperties = additionalProps;\n }\n\n return result;\n}\n"]}