/libras

An implementation of the RAS archive format for Max Payne games

Primary LanguageCGNU General Public License v3.0GPL-3.0

Building

  1. Set up the build:
    meson setup . build
  2. Build the library:
    meson compile -C build

Running the example archiver

./build/test/test-file --decompress <file.ras>

Compressing is not yet implemented.

File format

All integer and floating-point values are little-endian unless otherwise noted, the latter of which you might want to consider reading as an integer on non-x86 platforms. Storing versions as floats is stupid, anyway.

Overview

Overview

Header

Offset Length Purpose
00 4 Magic1
04 4 Encryption seed2
08 4 File count
0C 4 Directory count
10 4 File table size
14 4 Directory table size
18 4 Archive version3 4
1C 4 Header checksum5
20 4 File table checksum5
24 4 Directory table checksum5
28 4 Format version6

1. 52 41 53 00 or RAS\0 in ASCII.
2. Decryption code in C:

void
decode (size_t  count,
        uint8_t buffer[static count],
        int32_t seed)
{
    if (seed == 0)
    {
        seed = 1;
    }

    for (size_t i = 0; i < count; i++)
    {
        seed = (seed * 171) - ((seed / 177) * 30269);

        buffer[i] = (buffer[i] << (i % 5)) | (buffer[i] >> (8 - (i % 5)));
        buffer[i] = (buffer[i] ^ ((i + 3) * 6)) + (seed & 0xFF);
    }
}

3. Encoded in binary32.
4. Corresponds with the version of the archiver and is used for compatibility reasons. MAX-FX tools and Max Payne 2 modification tools ship RasMaker 1.2, so expect 3F99999A.
5. CRC-32 (x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1)
6. 3 for the original Max Payne archives, 4 for Max Payne 2 archives.

File table

Entry

Length Purpose
Variable Name
4 File size
4 File entry size
4 ?
4 Parent directory index
4 ?
4 Compression method1
16 Creation time2

1. Possible values:

1 - compressed
2 - ? (possibly a dummy value, identical to 3, in theory)
3 - stored

2. Stored as a SYSTEMTIME.

Directory table

Entry

Length Purpose
Variable Full path
16 Creation time1 2

1. Stored as a SYSTEMTIME.
2. With two exceptions:

  1. the root directory has all fields set to 0;
  2. the source directory (when not using -p) has the creation time of 1601-01-01 00:00:00.000.

File data

Stored file entry

Uncompressed entries only contain the individual file data.

Compressed file entry

Compressed entries, along with the individual file data, also contain information about the file size. They are recognizable by the prefix RA->.

Length Purpose
4 Identifier1
4 File size
4 Compressed file size
Compressed data

1. 52 41 2D 3E or RA-> in ASCII.

Compression method

The Haruhiko Okumura’s public domain implementation of LZSS is used.

Encrypted file entry

Encrypted entries don’t exist in the wild. They are recognizable by the prefix RC->.