DAT Format (Fury of the Furries)

From ModdingWiki
Jump to navigation Jump to search
DAT Format (Fury of the Furries)
Format typeArchive
Max filesUnlimited
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 PlatformExtract files? Decompress on extract? Create new? Modify? Compress on insert? Access hidden data? Edit metadata? Notes
FuryUtils x64Windows, LinuxYesYesYesNoYesN/AN/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!)