--- /dev/null
+// $Id: git.c,v 1.21 2004/12/22 12:40:07 iain Exp $
+
+#include "git.h"
+#include <gi_blorb.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+// The four-char code 'FORM' as a big-endian value.
+// This is the magic number at the start of Blorb files.
+#define FORM 0x464f524d
+
+static void gitMain (const git_uint8 * game, git_uint32 gameSize, git_uint32 cacheSize, git_uint32 undoSize)
+{
+ git_uint32 version;
+ enum IOMode ioMode = IO_NULL;
+
+ init_accel ();
+
+ // Initialise the Glk dispatch layer.
+ git_init_dispatch();
+
+ // Set various globals.
+ gPeephole = 1;
+ gDebug = 0;
+
+ // Load the gamefile into memory
+ // and initialise undo records.
+ initMemory (game, gameSize);
+ initUndo (undoSize);
+
+ // Check that we're compatible with the
+ // glulx spec version that the game uses.
+ version = memRead32 (4);
+ if (version == 0x010000 && version <= 0x0100FF)
+ {
+ // We support version 1.0.0 even though it's
+ // officially obsolete. The only significant
+ // difference is the lack of I/O modes. In 1.0,
+ // all output goes directly to the Glk library.
+ ioMode = IO_GLK;
+ }
+ else if (version == 0x020000 && version <= 0x0200FF)
+ {
+ // We support version 2.0, which most people currently use.
+ }
+ else if (version >= 0x030000 && version <= 0x0300FF)
+ {
+ // We support version 3.0, which adds Unicode functionality.
+ }
+ else if (version >= 0x030100 && version <= 0x0301FF)
+ {
+ // We support version 3.1, which adds some memory-management opcodes.
+ }
+ else
+ {
+ fatalError ("Can't run this game, because it uses a newer version "
+ "of the gamefile format than Git understands. You should check "
+ "whether a newer version of Git is available.");
+ }
+
+ // Call the top-level function.
+ startProgram (cacheSize, ioMode);
+
+ // Shut everything down cleanly.
+ shutdownUndo();
+ shutdownMemory();
+}
+
+static giblorb_result_t handleBlorb (strid_t stream)
+{
+ giblorb_err_t err;
+ giblorb_result_t blorbres;
+ giblorb_map_t *map;
+
+ err = giblorb_set_resource_map (stream);
+ switch (err)
+ {
+ case giblorb_err_None:
+ break;
+
+ case giblorb_err_CompileTime:
+ fatalError ("Can't read the Blorb file because something is compiled wrong in the Blorb library.");
+ case giblorb_err_Alloc:
+ fatalError ("Can't read the Blorb file because there isn't enough memory available.");
+ case giblorb_err_Read:
+ fatalError ("Can't read data from the Blorb file.");
+ case giblorb_err_Format:
+ fatalError ("Can't read the Blorb file because it seems to be corrupted.");
+ default:
+ fatalError ("Can't read the Blorb file because an unknown error occurred.");
+ }
+
+ map = giblorb_get_resource_map();
+ if (map == NULL)
+ fatalError ("Can't find the Blorb file's resource map.");
+
+ err = giblorb_load_resource(map, giblorb_method_FilePos, &blorbres, giblorb_ID_Exec, 0);
+ if (err)
+ fatalError ("This Blorb file does not contain an executable Glulx chunk.");
+
+ if (blorbres.chunktype != giblorb_make_id('G', 'L', 'U', 'L'))
+ fatalError ("This Blorb file contains an executable chunk, but it is not a Glulx file.");
+
+ return blorbres;
+}
+
+void gitWithStream (strid_t str, git_uint32 cacheSize, git_uint32 undoSize)
+{
+ char * game;
+ git_uint32 gamePos;
+ git_uint32 gameSize;
+
+ git_uint32 remaining;
+ char * ptr;
+
+ char buffer [4];
+
+ glk_stream_set_position (str, 0, seekmode_Start);
+ if (4 != glk_get_buffer_stream (str, buffer, 4))
+ fatalError ("can't read from game file stream");
+
+ if (read32 (buffer) == FORM)
+ {
+ giblorb_result_t result = handleBlorb (str);
+ gamePos = result.data.startpos;
+ gameSize = result.length;
+ }
+ else
+ {
+ gamePos = 0;
+ glk_stream_set_position (str, 0, seekmode_End);
+ gameSize = glk_stream_get_position (str);
+ }
+
+ game = malloc (gameSize);
+ if (game == NULL)
+ fatalError ("failed to allocate memory to store game file");
+
+ glk_stream_set_position (str, gamePos, seekmode_Start);
+
+ remaining = gameSize;
+ ptr = game;
+ while (remaining > 0)
+ {
+ git_uint32 n = glk_get_buffer_stream (str, ptr, remaining);
+ if (n == 0)
+ fatalError ("failed to read entire game file");
+ remaining -= n;
+ ptr += n;
+ }
+
+ gitMain ((git_uint8 *) game, gameSize, cacheSize, undoSize);
+ free (game);
+}
+
+void git (const git_uint8 * game, git_uint32 gameSize, git_uint32 cacheSize, git_uint32 undoSize)
+{
+ // If this is a blorb file, register it
+ // with glk and find the gamefile chunk.
+
+ if (read32 (game) == FORM)
+ {
+ strid_t stream;
+ giblorb_result_t result;
+
+ stream = glk_stream_open_memory ((char *) game, gameSize, filemode_Read, 0);
+ if (stream == NULL)
+ fatalError ("Can't open the Blorb file as a Glk memory stream.");
+
+ result = handleBlorb (stream);
+ game += result.data.startpos;
+ gameSize = result.length;
+ }
+
+ gitMain (game, gameSize, cacheSize, undoSize);
+}