-
Notifications
You must be signed in to change notification settings - Fork 0
MAC File Formats
All fields are little endian (unless otherwise specified)
- bool 8/32: Byte/bytes-width boolean (0/1 for False/True)
- [u]int 8/16/32: Integer [unsigned]
- cint16: CompressedUInt16 in code. The high bit of the first byte is used to indicate whether or not a second byte follows. Big endian.
- float32: Floating point number (IEEE754).
- byte[N]: Array of N bytes.
- cstring: Null-terminated string.
- pstring: Length-prefixed string. Uses a cint16 to indicate length.
- 0: void
- 1: int
- 2: float
- 3: bool
- 4: char
- 5: vector2i
- 6: vector2f
- 7: UNIMP
- 8: vector3f
- 9: quaternion
- 10: entity
- 11: string
For Linux, two packages containing various files are used to set up scenes, scripts, etc.
The file format for these .pkg files is:
- uint32: Four byte LE integer giving file count (FC).
- (uint32, uint32, uint32) * FC: File information 3-tuples – (CRC32 of filename, offset from end of header, length of file)
- …: Files, concatenated with each other according to the header specifiers.
File names vary wildly and do not all appear in an easy fashion inside of the binary. Some examples in limbo_mac_boot.pkg:
- autorun.txt, init.txt, materials_list.txt, atlases.txt (from binary)
- data/texture/atlas/atlas_blur.txt (from atlases.txt)
- derived/mac/data/levels/limbo.scene.d (derived from file paths in atlases.txt)
Most files that end with a .d prefix can be assumed to be compressed using zlib (python’s zlib library can easily uncompress files using zlib.decompressobj().decompress(data))
The first field of every file is a uint32 indicating what type of resource it is:
- uint32: Identifier (0×1)
- uint32: Count (number of strings in file)
-
COUNT times:
- uint32: Length of string (LEN)
- byte[LEN]: String (NOT null-terminated)
Text resources appear to have been useful for the Xbox, as all other text in the game is rendered ahead of time as texture buffers.
- uint32: Identifier (0×7)
- uint32: Bone count (BC)
- uint32: Frame count (FC)
-
BC times:
- int32: Bone name length
- byte[LEN]: Bone name
- (float32, float32, float32): Starting x_pos, y_pos, and z_rot (“I-frame”)
- (uint8, uint8, uint8): Precision of following deltas, in byte width (XW,YW,ZW)
-
FC-1 times: (“P-frames”)
- int XW: x_delta
- int YW: y_delta
- int ZW: z_delta
To find the position of a given frame number N, take the N-1th p_frame, scalar multiply by 0.001, and add it to frame number 0 (not cumulative). There are two formats of animation files offered by the binary – anim format, which are the binary packed format above, and source format, which are human readable strings. The .anim files provided in this repository are not exactly that format, but are similar.
These are not pngs.
- uint32: Identifier (0xd)
- uint32: UNKNOWN_A
- uint32: UNKNOWN_B
- pstring: Path name (does not exactly match with .pkg path)
-
…: TextureBuffer
- uint32: Identifier(0×9)
- uint8: UNKNOWN_C
- uint8: UNKNOWN_D
- uint16: RenderBuffer_Width
- uint16: RenderBuffer_Height
- uint16: UNKNOWN_E
- uint16: UNKNOWN_F
- uint8: UNKNOWN_G (byte) (unidentified OpenGL field)
- uint8: OpenGL_Texture_Max_Level
- uint8: OpenGL_Filter_Flags(??)
- uint8: Internal PixelFormatType (0xa is the only recorded value, which indicates L8A8 “LUMINANCE 8, ALPHA 8” (b&w w/ alpha))
- …: Image (for L8A8, two-byte pixels, of size RenderBuffer_Width*RenderBuffer_Height*4//3) (the extra quarter at the end has currently unknown purpose.)
Many details above are irrelevant to get at least a working PNG rendered, and so are currently left unknown. The images rendered are imperfect, but sufficient to understand what the image is.
Branch files, regardless of the fact that their file extension ends with a “.d”, are not zlib compressed.
The purpose of branch files are currently unclear, but the format containing them was reversed and demonstrated below:
- uint32: Identifier(0×15)
- uint32: GoCheckSum(0×8587fdab) (may be different for different versions of limbo? TODO?)
- uint32: padding
- cstring: GlobalID (32 hex digit identifier for unknown purpose, null-terminated)
- uint32: UNKNOWN_A
- uint32: UNKNOWN_B
- uint8: UNKNOWN_C
- bool8: BOOLEAN_D
- if BOOLEAN_D:
- pstring: Custom Declaration String (currently has unknown purpose)
- uint32: Branch Length (remainder of file in bytes)
- cint16: Object Count (OC)
-
OC times:
- cint16: Identifier
- pstring: Name
- cint16: Subobject Count (SC)
-
SC times:
- cint16: UNKNOWN_UA
- uint8: UNKNOWN_UB
- pstring: Alternate String 1
- if UNKNOWN_UA == 0×7fff:
- pstring: Alternate String 2
These are not compressed using zlib. These also lack an identifier field.
- uint32: Symbol Type 1 Count (S1C)
-
S1C times:
- pstring: Name
- pstring: Alternate String 1
- pstring: Alternate String 2
- byte[44]: Full bytes of the internal SymbolStruct structure. (SYMSTRUCT)
- if( SYMSTRUCT[8:12]==2 ):
- uint32: Parameter count (PC)
-
PC times:
- uint32: Parameter type (see Script Variable Types)
- bool32: BOOLEAN_A
- if BOOLEAN_A:
- uint32: UNKNOWN_B
Symbols are used in conjunction with the .script file adjacent to them.
.fx files are pure text without the above header that are some form of OpenGL C file skullduggerey with currently unknown motives.
The inclusion of these files is unclear, as it seems like they do not get loaded in standard gameplay. The paths for these files, then, are also unknown, and currently dumped in the limbo_mac_boot/UNKNOWN directory.