-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathgit.c
175 lines (144 loc) · 5.15 KB
/
git.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// $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;
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.
gIoMode = 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 more 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);
// 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 (readtag (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);
}