Where is the color table?


After a long break I am once again making consistent progress on rewriting Reckless Drivin’.

This week I was porting the code for particle emitters and particle effects to Zig. One of the variables the code references is g16BitClut, which is initialized with data from the resource fork.

g16BitClut=GetResource('Cl16',id);

# Resource forks

I’ve written in detail about resource forks before. In short, a resource fork is an additional storage area in a file on Apple file systems. Resource forks were used in Classic Mac OS, but for backwards compatibility, macOS continues to support resource forks.

Here is a shell session that shows how to copy data to the resource fork of a file on macOS:

$ # the flag -@ is used to display extended attributes on macOS
$ ls -l@
total 8
-rw-r--r--  1 nathan  wheel     0B Jan 23 19:25 a
-rw-r--r--  1 nathan  wheel    10B Jan 23 19:25 b

$ cat b
some data

$ # copy the data in b to the resource fork of a
$ cp b a/..namedfork/rsrc

$ # now the resource fork shows as 10B in the ls output
$ ls -l@
total 16
-rw-r--r--@ 1 nathan  wheel     0B Jan 23 19:26 a
	com.apple.ResourceFork	  10B
-rw-r--r--  1 nathan  wheel    10B Jan 23 19:25 b

Note that resource forks aren’t typically used for storing arbitrary data. The resource fork is more like a key-value storage database used by an application. There is some nice documentation for the resource fork format on Kaitai’s website.

# Missing resource data

Back to g16BitClut.

Based on how this variable was used in the code, I figured it was related to color data, but I wasn’t sure how.

I searched the internet and the Inside Macintosh reference manuals and found some useful information. A “Clut” is a color lookup table used in several parts of the system including QuickDraw. It maps integer values to colors, and from what I can tell was used to save memory when storing color information.

The resource identifier that the code uses is Cl16. I couldn’t find anything on this online, so I assume this is not a standard system color lookup table, and instead a custom table that Jonas made. My best guess is the Cl is for “Clut” or “Color lookup” and 16 indicates it stores colors in 16 bits.

The game data I was using in Reckless Drivin’ was from Jonas Echterhoff’s commit in 2019 in the file Data. In the readme of the repo he says

The resource forks of the rsrc files have been moved to the data fork

Meaning the Data file is the contents of the resource fork from the Reckless Drivin’ binary.

The issue is, I had already extracted all of the resources from that data file, and Cl16 was not included.

# Finding the data

I spent a while searching and trying to figure out why my resource fork data didn’t include the Cl16 resource. After many fruitless searches, I determined my only remaining option was to load the game in a Mac OS 9.0 virtual machine and use a debugger to inspect the memory at runtime. Halfway through setting up the vm, I realized I had missed a very simple possible explanation for the missing data.

The Reckless Drivin’ website hosts two versions of the game:

  • v1.4.4 which uses the native Mac OS QuickDraw library for rendering, and
  • v1.5.4 which was updated to work with OpenGL.

The Reckless Drivin’ source code that Jonas shared on GitHub does not include any OpenGL calls. I realized that it was possible that the source code and resource data were from different versions of the game!

So I downloaded the RecklessDrivin144.sit.bin file from the website. The .sit.bin is a Stuffit file, a proprietary compression format used on Macs in the 90s.

I installed The Unarchiver which supports Stuffit archives, and successfully extracted the Reckless Drivin’.app bundle. Then I opened my terminal and inspected the resource fork using DeRez, a tool to decompile resource fork data.

$ cd Reckless\ Drivin\'.app/Contents/MacOS/

$ DeRez Reckless\ Drivin\' | grep Cl16
data 'Cl16' (8, "16-bit color lookup table") {

Success!

So I extracted the resource fork and I am now using it in my port of the game.

$ cp Reckless\ Drivin\'/..namedfork/rsrc Data

I still don’t know for certain why the resource data Jonas uploaded to GitHub didn’t include all of the data. But this was a great way to learn a little more about resource forks!