1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "glk/glulx/glulx.h"
24 #include "common/config-manager.h"
25 #include "common/translation.h"
26
27 namespace Glk {
28 namespace Glulx {
29
30 Glulx *g_vm;
31
Glulx(OSystem * syst,const GlkGameDescription & gameDesc)32 Glulx::Glulx(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
33 vm_exited_cleanly(false), gamefile_start(0), gamefile_len(0), memmap(nullptr), stack(nullptr),
34 ramstart(0), endgamefile(0), origendmem(0), stacksize(0), startfuncaddr(0), checksum(0),
35 stackptr(0), frameptr(0), pc(0), prevpc(0), origstringtable(0), stringtable(0), valstackbase(0),
36 localsbase(0), endmem(0), protectstart(0), protectend(0),
37 stream_char_handler(nullptr), stream_unichar_handler(nullptr),
38 // main
39 library_autorestore_hook(nullptr),
40 // accel
41 classes_table(0), indiv_prop_start(0), class_metaclass(0), object_metaclass(0),
42 routine_metaclass(0), string_metaclass(0), self(0), num_attr_bytes(0), cpv__start(0),
43 accelentries(nullptr),
44 // heap
45 heap_start(0), alloc_count(0), heap_head(nullptr), heap_tail(nullptr),
46 // serial
47 max_undo_level(8), undo_chain_size(0), undo_chain_num(0), undo_chain(nullptr), ramcache(nullptr),
48 // string
49 iosys_mode(0), iosys_rock(0), tablecache_valid(false), glkio_unichar_han_ptr(nullptr) {
50 g_vm = this;
51
52 glkopInit();
53 }
54
runGame()55 void Glulx::runGame() {
56 if (!is_gamefile_valid())
57 return;
58
59 gamefile_start = 0;
60 gamefile_len = _gameFile.size();
61 setup_vm();
62
63 if (!init_dispatch())
64 return;
65
66 if (library_autorestore_hook)
67 library_autorestore_hook();
68
69 execute_loop();
70 finalize_vm();
71
72 gamefile_start = 0;
73 gamefile_len = 0;
74 init_err = nullptr;
75 vm_exited_cleanly = true;
76
77 profile_quit();
78 }
79
is_gamefile_valid()80 bool Glulx::is_gamefile_valid() {
81 if (_gameFile.size() < 8) {
82 GUIErrorMessage(_("This is too short to be a valid Glulx file."));
83 return false;
84 }
85
86 if (_gameFile.readUint32BE() != MKTAG('G', 'l', 'u', 'l')) {
87 GUIErrorMessage(_("This is not a valid Glulx file."));
88 return false;
89 }
90
91 // We support version 2.0 through 3.1.*
92 uint version = _gameFile.readUint32BE();
93 if (version < 0x20000) {
94 GUIErrorMessage(_("This Glulx file is too old a version to execute."));
95 return false;
96 }
97 if (version >= 0x30200) {
98 GUIErrorMessage(_("This Glulx file is too new a version to execute."));
99 return false;
100 }
101
102 return true;
103 }
104
fatal_error_handler(const char * str,const char * arg,bool useVal,int val)105 void Glulx::fatal_error_handler(const char *str, const char *arg, bool useVal, int val) {
106 Common::String msg = Common::String::format("Glulx fatal error: %s", str);
107
108 if (arg || useVal) {
109 msg += " (";
110
111 if (arg)
112 msg += Common::String::format("%s", arg);
113 if (arg && useVal)
114 msg += " ";
115 if (useVal)
116 msg += Common::String::format("%x", val);
117
118 msg += ")";
119 }
120
121 error("%s", msg.c_str());
122 }
123
nonfatal_warning_handler(const char * str,const char * arg,bool useVal,int val)124 void Glulx::nonfatal_warning_handler(const char *str, const char *arg, bool useVal, int val) {
125 Common::String msg = Common::String::format("Glulx warning: %s", str);
126
127 if (arg || useVal) {
128 msg += " (";
129
130 if (arg)
131 msg += Common::String::format("%s", arg);
132 if (arg && useVal)
133 msg += " ";
134 if (useVal)
135 msg += Common::String::format("%x", val);
136
137 msg += ")";
138 }
139
140 warning("%s", msg.c_str());
141 }
142
glulx_sort(void * addr,int count,int size,int (* comparefunc)(const void * p1,const void * p2))143 void Glulx::glulx_sort(void *addr, int count, int size, int(*comparefunc)(const void *p1, const void *p2)) {
144 qsort(addr, count, size, comparefunc);
145 }
146
147 } // End of namespace Glulx
148 } // End of namespace Glk
149