genie-drs
Genie Engine DRS file reader/writer for Node.js and the browser
.DRS files are archive files used in the Age of Empires 1 and 2 and Star Wars: Galactic Battlegrounds games. A format specification is available in the openage project.
Usage Example
Read a palette file and a unit graphic from the Age of Empires 2 data files:
var DRS = var Palette = var SLP = var PNG = PNG // using Age of Empires 2 filesvar int = gra = // id 50500 is the main in-game palette.int { // 3088 is the 'Champion Dying' graphic. gra} { var frame = slp var png = width: framewidth height: frameheight pngdata = Buffer png}
Create a new DRS file:
var DRS = var after = var drs = var cb = fsfsfs { drsarchive}
API
DRS([options])
Create a new DRS file. Options can be:
isSWGB
- Whether this is a file for Star Wars: Galactic Battlegrounds. Defaultfalse
.copyright
- Copyright string to use, uses the Age of Empires or Star Wars: Galactic Battlegrounds string by default. This should be exactly 40 characters long for DRS files intended for AoE and exactly 60 characters long for DRS files for SWGB.fileVersion
- Version number as a 4-character string, default '1.00'.fileType
- File type as a 12-character string, pad with NUL bytes. Default 'tribe\0\0\0\0\0\0\0' like in Age of Empires 2 files.
DRS(filename: string)
Node only!
Creates a new DRS instance for the .DRS file filename
.
DRS(blob: Blob)
Browser only!
Creates a new DRS instance for the given Blob instance.
DRS#read(callback)
Reads the DRS table headers.
This only needs to be called manually if getFiles()
or getSize()
is used.
Otherwise, genie-drs
will call it automatically when necessary.
DRS#getSize(): number
Returns the size of the DRS file. Includes any unsaved modifications. Won't work if the file hasn't been .read()
yet.
DRS#getFiles(): Array<{id, type, size, offset}>
Returns an array of all the file entries in this DRS file. Format:
id: Number // internal file ID type: String // 4-character, space-padded type of file: "wav ", "slp ", "bina" size: Number // file size in bytes offset: Number // file offset in the main DRS, in bytes
Won't work if the file hasn't been .read()
yet.
DRS#getFile(id: number): { id, type, size, offset }
Finds one file entry by its file ID. See DRS#getFiles()
DRS#putFile(type: string, id: number, buffer: Buffer, callback)
Replaces one file in the DRS.
type
is the file type, i.e. the table in which to store the file.
If a file type is given for which a table does not exist, a new table is created.
id
is the new file ID.
buffer
is a Buffer or string with the new file contents.
DRS#readFile(id: number[, options], callback)
Reads a file's contents for ID id
. The callback gets an err
and a Buffer
containing the file contents.
Optionally, provide an options
object to read only part of the file:
start
- Byte offset inside the file to start reading at.end
- Byte offset inside the file to stop reading at.
DRS#createReadStream(id: number[, options]): Readable
Returns a Readable stream of the file contents for file ID id
.
The returned stream also emits a meta
event with information about the file, like in getFiles()
.
Optionally, provide an options
object to read only part of the file:
start
- Byte offset inside the file to start reading at.end
- Byte offset inside the file to stop reading at.
DRS#createWriteStream(type: string, id: number): Writable
Returns a stream, stuff that is written to it will be saved in the DRS file.
Note that this method works in-memory, use the archive()
method to flush changes back to disk.
The returned stream emits a meta
event with information about the new file, like in getFiles()
.
type
is the file type, i.e. the table in which to store the file.
If a file type is given for which a table does not exist, a new table is created.
id
is the new file ID.
DRS#archive(): Readable
Returns the entire DRS file as a stream.
If the DRS instance was initialized from an existing DRS file, this method may attempt to read data from that file--it's not safe to pipe the stream straight back to the original DRS file.
If that is necessary, use a module like fs-write-stream-atomic
, which will not touch the initial file until everything has been read.
var createWriteStream = var drs = fs { drsarchive}