Tuesday, February 22, 2022

Playing German “Marathon 2: Durandal” with Aleph One

Or: How to extract “Resource Forks” on Linux

Or: What happens if you want to access Mac data from a game disc without a Mac? A self experiment.

Intro

You may know the Marathon series: Three first person shooters games, which may be seen as a predecessor of the later “Halo” series by the same company. There is one caveat though: Back then, developer Bungie Software was a very Mac centric company, and most of their games didn’t even have ports to Windows or other platforms.

The exception in the Marathon series is the second part, “Marathon 2: Durandal”, which is the only one that was also ported to Windows. But not just that, the game was even localized into German (and probably a few other languages as well).

Fast forward: In 2000, something wonderful happened. The source code of the game engine was released as Open Source, and in 2005 the games themselves were released as freeware. That is: The Mac version of the game engine was open-sourced, and the Mac version of the games were released as freeware. And just the English versions of them.

So now I’m looking at my beautiful German box of Marathon 2 and am wondering: Can I also play that German version on Linux?

Of course that’s possible, but it turned out that getting the data files is more complicated than expected…

Mounting the Mac part

So let’s have a look at the disc: It contains both an ISO9660 part for the Windows version and a HFS part for the Mac version.

The source code, meanwhile curated by the wonderful people of the Aleph One project, is - of course - only compatible with the Mac game data, so let’s try to mount the HFS part of the disc (by default the ISO9660 part would be mounted):

mount /dev/sr0 -t hfs /media/cdrom

If that command fails for you, your distribution probably didn’t include the hfs kernel module - but don’t worry, you won’t need it anyway. Apart from some strange characters (the kernel hfs module doesn’t seem to be very good with special characters - you can see the output in the “HFS” link above) all files seem to be there.

So: Let’s try to start the game:

$ alephone /media/cdrom/Marathon 2 �/
[...]
fatal alert (ID=-1): Please be sure the files 'Map', 'Shapes', 'Images' and 'Sounds' are correctly installed and try again. (csalerts_sdl.cpp:202)

OK, the manual mentions that you can start the Mac version directly from CD, so something seems to be off.

$ ls -l /media/cdrom/Marathon 2 �/
total 33648
-rw-r--r-- 1 root root        0 Nov  6  1995 Iconr
-rw-r--r-- 1 root root        0 Oct 10  1996 Images
-rw-r--r-- 1 root root        0 Nov  6  1995 Manual (english)
-rw-r--r-- 1 root root  5704325 Oct 14  1996 Map
-rw-r--r-- 1 root root   407802 Oct 21  1996 Marathon 2
-rw-r--r-- 1 root root  4136840 Jul 13  1995 Music
drwxr-xr-x 1 root root        4 Dec 10  1996 Physics Models/
-rw-r--r-- 1 root root 10016800 Nov  6  1995 Shapes
-rw-r--r-- 1 root root 14183536 Nov  6  1995 Sounds

What’s that? The Images file is empty? What happened here?

(One may wonder: How did I enter the unprintable character if tab completion stops at exactly that place because of another directory starting with the same name? cd /media/cdrom/Marathon 2 [^S], followed by pressing tab. I know zsh users will probably laugh now because they can simply cycle through the directories with tab by default…)

Exporting Resource Forks

It was clear now that either the kernel driver had a bug here, or that the information would be stored elsewhere. To exclude a kernel driver bug I decided to cross-check with another open source tool: HFSExplorer also promises to be able to view HFS file systems.

And surprise: HFSExplorer is able to decode the special file name characters, so we now know that the game is stored in folder called “Marathon 2 ƒ”, but the Images file is also shown with a size of 0 byte here.

The HFSExplorer download however does also include a command line utility called unhfs, and Heureka! The following command revealed the mystery:

unhfs -resforks APPLEDOUBLE /dev/sr0

Now there are suddenly two files: Images and ._Images - with a size of 4,8M that seems to be the file we are looking for. file ._Images reveals that this is a AppleDouble encoded Macintosh file. So: what the heck is this again?

Decoding AppleDouble encoded Macintosh files

For a short description of what the AppleDouble format is see e.g. the AppleDouble documentation of the Archive Team. In short: It’s a Metadata store - basically some parts of the data is stored as metadata, while other parts are stored in the actual file.

Unfortunately HFSExplorer can only export the metadata in AppleDouble format, while Aleph One can only read AppleSingle, MacBinary and RAW data. One option may be to convert the data to AppleSingle or MacBinary, but I haven’t found a tool which would create working files. So let’s create RAW files instead.

Analyzing the metadata is possible with several tools: apple_dump (from the Netatalk project / package will print some information, including an offset of 38 and a raw dump in hex and ASCII.

$ apple_dump Images | less
"Images" is not AppleSingle/AppleDouble format.
"/xxx/Marathon 2 ƒ/._Images" is found.
Dumping "/xxx/Marathon 2 ƒ/._Images"...
-------------------------------------------------------------------------------
MagicNumber: 00051607                                        : AppleDouble
Version    : 00020000                                        : Version 2
Filler     : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X        
Num. of ent: 0001                                            : 1

-------------------------------------------------------------------------------
Entry ID   : 00000002 : Resource Fork
Offset     : 00000026 : 38 
Length     : 004C21F8 : 4989432

-RAW DUMP--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)
00000000   : 00 00 01 00 00 4C 20 F2 00 4C 1F F2 00 00 01 06 : .....L ..L......
00000010   : 00 00 23 4C 0B 74 72 6F 6F 70 65 72 2E 72 61 77 : ..#L.trooper.raw
00000020   : 02 00 00 00 72 73 72 63 52 53 45 44 01 00 FF FF : ....rsrcRSED....
00000030   : 06 49 6D 61 67 65 73 49 02 00 00 00 69 6D 67 32 : .ImagesI....img2
00000040   : 35 32 2E 34 01 00 00 35 00 2B 00 00 00 00 1E A7 : 52.4...5.+......
00000050   : 00 00 69 6D 67 32 35 32 2E 34 01 00 00 35 00 2B : ..img252.4...5.+
00000060   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
00000070   : 00 02 AC 28 59 B0 00 00 00 00 00 4C 21 F8 00 00 : ...(Y......L!...
00000080   : 00 00 00 00 00 00 1B 00 00 00 23 4C 15 77 65 61 : ..........#L.wea
00000090   : 70 6F 6E 73 2D 69 6E 2D 68 61 6E 64 2E 70 6C 61 : pons-in-hand.pla
000000A0   : 74 65 02 00 00 00 50 49 43 54 38 42 49 4D 05 00 : te....PICT8BIM..
[...]

Despite of its name I ironically couldn’t find a way to just dump the data with apple_dump instead of printing the nicely formatted output.

Similarly Lsar from The Unarchiver (a collection of unpackers for various typical Macintosh formats) will also print the offset:

$ lsar -L ._Images
._Images: AppleSingle
._Images: 
  Name:                      ._Images
  Size:                      4.99 MB (4.989.432 bytes)
  Compressed size:           4.99 MB (4.989.432 bytes)
  Is a Mac OS resource fork: Yes
  Index in file:             0
  Start of data:             38
  Length of data:            4989432

But also unar, the extraction part, didn’t want to dump the actual data.

But if it’s really just an offset of 38: dd to the rescue ;-)

dd if=._Images of=Images.rsrc bs=38 skip=1

In case you are wondering about the extension: .rsrc is used by Aleph One to look for the RAW resource data.

Repeat that for the Map file:

dd if=._Map of=Map.rsrc bs=38 skip=1

And voilà: Alph One will now accept the data files, and most components, including the main menu and the ingame texts are localized now! Just the UI itself seems to be hardcoded.

Saturday, August 28, 2021

Recover boot sector from floppy disks with Parity Boot Virus

I recently found some old floppies, back from the times when I was young, was using Microsoft DOS and didn’t have any real clue about computers. As a result, almost all of my floppy disks were infected with the Parity Boot Virus.

The Parity Boot Virus had the habit of overwriting the complete boot sector, i.e. the first sector of the floppy disk (if it wasn’t write protected at least). BUT it was also fair enough to create a backup copy of the boot sector and - on 3,5′’ floppy disks - put it into sector 32. See the Parity Boot Virus page on the Malware Wiki for more information.

25 years later I wanted to mount one of my floppy disk images I had backed up back then on my Linux machine and was surprised to see a lot garbage files like |úI|ë?K|.╕ - certainly not a valid file name. It turned out that sector 32 is the last sector to contain the root directory¹. And it also turned out that Linux reads all clusters and scans them for directory entries, while Windows seems to stop earlier, probably as soon as it encounters an empty file entry.

So how can you restore the original boot sector and get a clean root directory again? Simple, just call

file=myfloppy
dd if=$file count=1 skip=31 of=$file conv=notrunc seek=0
dd if=/dev/zero count=1 of=$file conv=notrunc seek=31

myfloppy can either be a physical floppy drive (e.g. /dev/fd0) or the file name of an image.

Please just make sure that sector 32 really does contain a valid boot sector - you can view the disk’s contents with hexdump -C myfloppy, check the contents between 00003e00 - 00004000. It should at least contain the label and the file system (e.g. NO NAME FAT12 in lines 3 and 4.


¹ usually, on a 3,5′’ HD floppy disk at least - see this website for an excellent disassembly of the FAT12 file system (German) and this Wikipedia article about the actual default sector size for the directory on a given floppy type if you want to know more.

Thursday, December 10, 2020

Konverting Kopete chat history to libpurple (Pidgin)

When I recently migrated from KDE4 to KDE5 (yes, Slackware did that update just a few days ago ;-)) I had to discover that no migration was done for my Kopete profile. And not only that, I suddenly had to suffer from various display errors - which had happened a few years ago already, but I forgot the solution to fix this. To make things short: I decided to finally migrate to Pidgin.

Now of course I didn’t want to loose all my chat history, but import it into Pidgin.

Fortunately Kopete is storing the log files as plain XML files, though very strange ones - who thought it was a good idea to safe something like “11 9:5:0” as a time field? Also guessing what that is supposed to say? That’s nine o’ clock and five minutes on the eleventh day of a month. Which month you ask? That’s stored in a dedicated field of course ;-)
Anyway: I’ve just written an XSLT converter again. This time it will also include a small Bash script wrapper for creating the correct directories.

Note that it will only convert Jabber and ICQ out of the box - those were the only protocols I’ve been using with Kopete. It should be trivial to add other protocols though - basically you’ll just have to find out the correct source and target directory names.

The script including a small README file can be found on https://gitlab.com/laenion/kopete2purplelog.

Thursday, December 5, 2019

Getting SimCity 3000 for Linux run on modern systems

SimCity 3000 was originally ported by Loki Games to Linux, but over time the original binaries became incompatible with modern systems. For that purpose the Loki Compatibility Libraries were introduced, the linked site also contains tons of information to get other Loki to run again. Another option are the Linux Installers for Linux Gamers, which provide updated installers for a lot of old games, and - like in the case of SimCity 3000 - include all the necessary compatibility libraries already.

With SimCity I had one problem additional though. It still wouldn’t start with the following message:

Graphic System: Could not init SDL: No available video device

The problem

After some debugging with strace I noticed that the old version of SDL tries to connect to the local X server via TCP, a feature that was disabled on most distributions in the last few years; if you type ps aux | grep Xorg you will most likely see -nolisten tcp somewhere in the options, which will prevent opening that TCP port.

The solution

If you are using the LIFLG installer from above you can find a very useful helper script that allows you to play the game in a separate X server instead. Just open the file sc3u.sh in your installation directory and uncomment all the XSERVER, XSERVER_OPTIONS and XSERVER_DISPLAY lines, and in the XSERVER_OPTIONS line change -nolisten tcp to -listen tcp. You will probably also have to create a file called /etc/X11/Xwrapper.config with a line allowed_users = anybody to be able to start the X server as a user (see man Xwrapper.config for details).

Otherwise you could explicitly start your X server with -listen tcp instead. How that is done depends on your display manager. For KDM for example you can find the X options in /etc/kde/kdm/kdmrc[X-:*-Core]ServerArgsLocal, other display managers should have similar configuration files. This may not be the best option for security reasons though.

Saturday, January 5, 2019

Importing Android SMS on your Jolla / Sailfish device

Short version:
Just visit the project’s website and follow the 5 simple instructions (sounds like clickbait, doesn’t it? ;-)) in the file README.md.

Motivation

When I accidentally messed up my installation of Sailfish OS on my Gemini phone I had to use Android as a backup until I found the time to fix the issue. In the meantime several SMS arrived, which I obviously also wanted to see in Sailfish OS. So I started to investigate the possible options.

Development

My naive attempts to just export the database from the Android partition failed miserably due to Android’s security mechanisms. In the end I settled by using SMS Backup & Restore to get a backup of my messages. Not only does this app seem to be the de-facto standard for SMS backups, but it also provides good documentation on the format of the generated XML file.

I already used commhistory-tool to import my SMS history from Firefox OS, so commhistory-tool’s JSON format was set as the target format. And with an XML file as the source: What would be suited better for conversion than an XSL Transformations (XSLT)?

Already preinstalled on my (Linux) system is one of the most commonly used XSLT processors - xsltproc, so I decided to use that one. Unfortunately I had to find out this processor only supports XSLT 1.0, so is missing a lot of convenience functions. On the positive side it supports several EXSLT commands instead, e.g. for dates, strings and functions, which are used extensively.

I later found out that using xsltproc also has another advantage: It is also preinstalled on Sailfish OS! This completely eliminates the need for a separate PC to convert the files - you can do that directly on your Jolla / Sailfish OS phone. In the case of the Gemini I was able to just export the file to the memory card in Android, reboot into Sailfish, generate the JSON file and import it. Could this be any easier?

The XSLT file can be found on https://gitlab.com/laenion/android-sms-backup-restore-2-jolla-commhistory-tool/blob/master/android-sms-backuprestore-2-jolla-commhistory-tool.xsl, the project’s README.md file contains detailed instructions on how to use this file.