DAT Format (Fury of the Furries)
Format type | Archive |
---|---|
Max files | Unlimited |
File Allocation Table (FAT) | Beginning |
Filenames? | Yes, 8.3 |
Metadata? | None |
Supports compression? | Yes |
Supports encryption? | No |
Supports subdirectories? | No |
Hidden data? | No |
Games |
The Fury of the Furries DAT Format is used by Fury of the Furries for storing data. The data is NOT used by the game itself, but is used by the two executables that typically run before the game itself. INTRO.EXE runs an animation that illustrates the backstory to the game and LANG.EXE allows the user to select the language they wish to play the game in, and also asks for a copy-protection password. The data used by these two executables is stored in INTRO.DAT and LANG.DAT respectively.
The format is an archive storing many files, each of which can be optionally compressed.
File format
Signature
There is no signature, and the fields must be checked to correctly detect files.
Header
The header is very simple.
Data type | Name | Description |
---|---|---|
UINT16LE | fileCount | The number of files stored in the archive. |
The header is immediately followed by the first file entry.
File entry
The header is followed by one or more file entries in the following structure.
Data type | Name | Description |
---|---|---|
char[13] | filename | Filename in 8.3 format, null-terminated. |
UINT32LE | uncompressedSize | Size of the file when uncompressed. |
UINT32LE | compressedSize | Size of the file when compressed. If the file is not compressed, this value is the same as the previous value. |
UINT8 | compressionFlag | 0 if the file is compressed. 1 if the file is not compressed. |
BYTE[compressedSize] | data | The content of the file, either plain or compressed. |
The next file header follows immediately after the data.
Compressed structure
If the file is compressed, it has the following structure.
First is a byte containing 8 flags, these flags should be read from lsb (least significant bit) to msb.
If the flag is 1, then read 1 byte and copy it to the output.
If the flag is 0, then read 2 bytes and use them to determine a sequence of bytes already in the output which can be copied to the output.
The length of the sequence to copy is given by the 3 plus the 4 lsb of the 2nd byte. (i.e. a length between 3 and 18).
The start of the sequence to copy is given by the remaining 12 bits. The 4 msb of the start address is given by the 4 msb of the second byte. And the 8 lsb of the address is given by the first byte. Add 18 (0x12) to this 12-bit number. The address is an offset from the start of the output stream, BUT it always falls within the most recent 4096 bytes written. Therefore if the output streams is large, you may need to increase the address by adding 4096 to it until it is no more that 4096 bytes from the current position in the output stream.
If the address is before the start of the output stream, then you should assume the space character (0x20) should be output. Probably this can be achieved by writing the output stream to a block of memory that immediately follows 18 spaces.
NOTE that the sequence to be copied can be less than length bytes from the current output position, the source and destination for the copy will therefore overlap, and all the bytes in the overlapping region will have the same value.
Pseudo-code
while writtenLength < uncompressedSize { compressionFlags = readByte() foreach compressionFlag in compressionFlags { if compressionFlag is set { // not compressed copy 1 byte from input to output } else { byte1 = readByte() byte2 = readByte() length = (byte2 & 0x0f) + 3; offset = ((byte2 >> 4) << 8) + byte1; offset += 0x12; adjust offset to be within most recent 4096 bytes of output copy length bytes from (offsetlocation in output) to output } stop if writtenLength = uncompressedSize } }
Example taken from within LANG.DAT
This is a cut down section of PROT.ENG. The full file is longer and as a result the compressed file is shorter than the raw file.
Hex
00000000 50 52 4F 54 2E 45 4E 47 00 00 00 00 14 1E 00 00 PROT.ENG.....=..
00000010 00 21 00 00 00 00 FF 45 4E 54 45 52 20 50 41 FF .<.....ENTER PA.
00000020 53 53 57 4F 52 44 20 46 DF 4F 52 20 43 4F F9 F0 SSWORD F.OR CO..
00000030 49 4E FF 41 54 45 53 IN.ATES
Structure
50 52 4F 54 2E 45 4E 47 00 00 00 00 14 | filename | PROT.ENG |
1E 00 00 00 | uncompressedSize | 30 bytes |
21 00 00 00 | compressedSize | 33 bytes |
00 | isCompressed | file is compressed |
FF | bit flags | all plain text |
45 4E 54 45 52 20 50 41 | raw text | ENTER PA |
FF | bit flags | all plain text |
53 53 57 4F 52 44 20 46 | raw text | SSWORD F |
DF | bit flags | 5 plain text, 1 compressed, 2 plain text |
4F 52 20 43 4F | raw text | OR CO |
F9 F0 | lengthAndOffset | 3 bytes to be copied from position 11 |
49 4E | raw text | IN |
FF | bit flags | all plain text |
41 54 45 53 | raw text | ATES |
Final Output
ENTER PASSWORD FOR COORDINATES
Tools
The following tools are able to work with files in this format.
Name | Platform | Extract files? | Decompress on extract? | Create new? | Modify? | Compress on insert? | Access hidden data? | Edit metadata? | Notes |
---|---|---|---|---|---|---|---|---|---|
FuryUtils | x64Windows, Linux | Yes | Yes | Yes | No | Yes | N/A | N/A |
Credits
This file format was reverse engineered by carbon14. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)