Distinguishing Between Glulx Blorb and ZCode Blorb

Probably the easiest way to frame this question is to show you the code I have:

def determine_format(self, story_data: BufferedReader):

        # Read the first four bytes. This will be enough to get the format
        # regardless of the actual type of story file.
        data_format = story_data.read(4)

        print(f"Data Format: {data_format} ({data_format.decode('latin-1')})")

        if data_format.decode("latin-1") == "FORM":
            # Change the stream position to the given byte offset, in this
            # case, relative to SEEK_SET, which is considered to be the start
            # of the stream. The goal here is to take the pointer beyond the
            # chunk ID and the chunk length. That will take us to the chunk
            # data itself.

            # From the start of the chunk data, we can read the first four
            # bytes to get the type identifier.
            if story_data.read(4).decode("latin-1") == "IFRS":
                self.format = FORMAT.BLORB
                self.format = FORMAT.UNKNOWN

        if data_format.decode("latin-1") == "Glul":
            self.format = FORMAT.GLULX
            eprint(f"\nQuendor is unable to interpret Glulx files.")

        if data_format[0] >= 1 and data_format[0] <= 8:
            self.format = FORMAT.ZCODE

        if self.format == FORMAT.UNKNOWN:
                f"\nQuendor could not determine the story file type.\n"
                f"File being read was: {self.story_file_path()}"

So I distinguish between BLORB, GLULX, and ZCODE. The Glulx and Zcode parts are easy. So, actually, is the blorb part.

However, Quendor will not be initially supporting Glulx at all. But “blb” files or “glorb” files are recognized simply as blorbs, just as is the case with a “zblorb” file. So my above logic treats all three as a “Blorb” even though there is a distinction.

You can see how I’m looking in the byte stream to get the information I need to determine the format of the story file. Is there a more refined way I can make the above logic more sensitive in terms of determining if I’m dealing with with a Glulx-style blorb?

I realize I could just use the filename extension. Maybe it’s just that simple? Any file with a “gblorb” or “blb” extension is Glulx-based.

Technically a .blb file can contain any sort of game, and the file extension isn’t always reliable. Finding the actual type of a blorb is harder, but possible.

The first chunk inside a Blorb is the “resource index chunk”, which contains a series of resource indices: a four-byte “usage”, a four-byte value you don’t care about, and a four-byte offset into the file. You’ll want to run through these indices until you find one with the usage “Exec”. There should be one and only one.

Once you’ve found that, seek to the provided offset, and read the first four bytes. If those aren’t “ZCOD”, it’s not a Z-code file, so you don’t need to handle it. (It’ll usually be either “ZCOD” or “GLUL”, but other types are possible too.)

1 Like

I looked around for some compact sample code that demonstrates this. Turns out that I’ve written “analyze the Blorb file” in at least three languages, but none of them are exactly built to do this job.

https://github.com/erkyrath/quixe/blob/c64f1d322763ee347e55708d25ec1bb0c70e50b4/src/quixe/gi_load.js#L588 might be easiest to adapt. Obviously it does a bunch of stuff that you don’t care about. It’s also set up to verify that the Exec chunk is a given type, rather than being set up to find that information out and return it. But the basic logic is there.

You’ll also need to find the “Exec” resource anyway in order to run the game at all, so you can tie this logic in there—if the file is a blorb, then find the exec resource, if it’s “ZCOD” then start playing, otherwise error.

Thank you all for the replies. This is quite helpful. The gi_load.js promises to give me a basic roadmap to refine my own functionality.

Eventually I’m hoping to evolve this Python-based solution to support Glulx as well, so getting ready to use Quixe as a guide may be a good head start on that.