MHPF Format - CookiePLMonster/TDUModTools GitHub Wiki

MHPF (Melbourne House Pack File)

Generic container format used to store files in filesystem-like structure. Present in Test Drive Unlimited PS2/PSP with a .PCK extension.

Format specification

  • One sector is 2048 bytes.
  • Format can be both little endian or big endian. Endianness is specified by the magic string in the header. No games are known to use the big endian format, but TDU's MHPF parser proves they existed.

Header

char[4] - 'MHPF' (for little endian archives) or 'FPHM' (for big endian archives)
uint16 - version (1)
uint16 - version (2)
uint32 - total archive size (in bytes)
uint32 - total number of resources
uint32 - hash prime (for resource path hashes), default 31

uint32 - absolute offset to the Resource Table (in bytes)
uint32 - size of the Resource Table (in bytes)

uint32 - absolute offset to the Files Data (in bytes)
uint32 - size of the Files Data (in bytes)

uint32 - absolute offset to the File Name Offsets Table (in bytes)
uint32 - size of the File Name Offsets Table (in bytes)

uint32 - absolute offset to the File Names Data (in bytes)
uint32 - size of the File Names Data (in bytes)

Resource Table

  • Section offset must be sector-aligned. Section size has no alignment requirements.
  • Entries must be ordered by the hash value, in ascending order.
For every resource:

uint32 - hash of the file path
uint32 - absolute offset to the file data (in bytes)
uint32 - size of the file data (in bytes)

Paths are hashed with the following algorithm:

def pathHash(path, prime):
    result = 0
    separator = True
    for c in path:
        if c == '/' or c == '\\':
            if separator:
                continue
            c = '/'
            separator = True
        else:
            separator = False
        result = (result * prime) + ord(chr(c).lower())
    return result & 0xffffffff

Files Data

  • Every file must be sector-aligned, therefore the section offset must be sector-aligned. Files must be padded to the sector size, therefore the section size must be sector-aligned.
  • Files are ordered manually to optimize loading speeds. Their ordering does not have to match the order of entries in the Resource Table.
  • File data is not compressed or encrypted in any way.
For every resource:

byte[] - raw file data

File Name Offsets Table

  • Sector has no offset or size alignment requirements.
  • All offsets are relative to the start of the File Names Data.
  • Entries are ordered accordingly to the ordering of entries in the Resource Table.
For every resource:

uint32 - offset to the file name (relative)

File Names Data

  • Sector has no offset or size alignment requirements.
  • Entries do not have to follow a specific order.
For every resource:

char[] - null terminated file path

Other resources