1 /*
2 * ucsymtbl.cc - Usecode symbol table
3 *
4 * Copyright (C) 2006 The Exult Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #include <iostream>
22 #include <cassert>
23 #include "ucsymtbl.h"
24 #include "utils.h"
25
26 using std::string;
27 using std::istream;
28 using std::ostream;
29
30 const int curvers = 0;
31
32 /*
33 * Cleanup.
34 */
~Usecode_scope_symbol()35 Usecode_scope_symbol::~Usecode_scope_symbol() {
36 for (auto *sym : symbols) {
37 delete sym;
38 }
39 }
40
41 /*
42 * Read from a file.
43 */
read(istream & in)44 void Usecode_scope_symbol::read(istream &in) {
45 int cnt = Read4(in);
46 Read4(in); // Version.
47 int oldsize = symbols.size();
48 symbols.reserve(oldsize + cnt);
49 for (int i = 0; i < cnt; ++i) {
50 char nm[256];
51 in.getline(nm, sizeof(nm), 0);
52 auto kind =
53 static_cast<Usecode_symbol::Symbol_kind>(Read2(in));
54 int val = Read4(in);
55 Usecode_symbol *sym;
56 if (kind == Usecode_symbol::class_scope) {
57 auto *s = new Usecode_class_symbol(nm, kind, val);
58 s->read(in);
59 assert(static_cast<unsigned>(s->get_val()) == classes.size());
60 classes.push_back(s);
61 sym = s;
62 } else {
63 int shape = 0;
64 // Shape function table:
65 if (kind == Usecode_symbol::shape_fun) {
66 shape = Read4(in);
67 shape_funs[shape] = val;
68 }
69 sym = new Usecode_symbol(nm, kind, val, shape);
70 }
71 symbols.push_back(sym);
72 }
73 if (!by_name.empty())
74 setup_by_name(oldsize);
75 if (!by_val.empty())
76 setup_by_val(oldsize);
77 if (!class_names.empty())
78 setup_class_names(oldsize);
79 }
80
81 /*
82 * Write to a file.
83 */
write(ostream & out)84 void Usecode_scope_symbol::write(ostream &out) {
85 Write4(out, symbols.size());
86 Write4(out, curvers);
87 for (auto *sym : symbols) {
88 const char *nm = sym->get_name();
89 out.write(nm, strlen(nm) + 1);
90 Write2(out, static_cast<int>(sym->get_kind()));
91 Write4(out, sym->get_val());
92 if (sym->get_kind() == class_scope)
93 static_cast<Usecode_class_symbol *>(sym)->write(out);
94 else if (sym->get_kind() == shape_fun)
95 Write4(out, sym->get_extra());
96 }
97 }
98
99 /*
100 * Add a symbol.
101 */
add_sym(Usecode_symbol * sym)102 void Usecode_scope_symbol::add_sym(Usecode_symbol *sym) {
103 int oldsize = symbols.size();
104 symbols.push_back(sym);
105 if (!by_name.empty())
106 setup_by_name(oldsize);
107 if (!by_val.empty())
108 setup_by_val(oldsize);
109 }
110
111 /*
112 * Setup tables.
113 */
setup_by_name(int start)114 void Usecode_scope_symbol::setup_by_name(int start) {
115 for (auto it = symbols.begin() + start;
116 it != symbols.end(); ++it) {
117 Usecode_symbol *sym = *it;
118 by_name[sym->name] = sym;
119 }
120 }
setup_by_val(int start)121 void Usecode_scope_symbol::setup_by_val(int start) {
122 for (auto it = symbols.begin() + start;
123 it != symbols.end(); ++it) {
124 Usecode_symbol *sym = *it;
125 by_val[sym->value] = sym;
126 }
127 }
setup_class_names(int start)128 void Usecode_scope_symbol::setup_class_names(int start) {
129 for (auto
130 it = classes.begin() + start;
131 it != classes.end(); ++it) {
132 Usecode_class_symbol *sym = *it;
133 class_names[sym->name] = sym;
134 }
135 }
136
137 /*
138 * Lookup by name or by value.
139 */
operator [](const char * nm)140 Usecode_symbol *Usecode_scope_symbol::operator[](const char *nm) {
141 if (by_name.empty())
142 setup_by_name();
143 auto it = by_name.find(nm);
144 if (it == by_name.end())
145 return nullptr;
146 else
147 return (*it).second;
148 }
149
operator [](int val)150 Usecode_symbol *Usecode_scope_symbol::operator[](int val) {
151 if (by_val.empty())
152 setup_by_val();
153 auto it = by_val.find(val);
154 if (it == by_val.end())
155 return nullptr;
156 else
157 return (*it).second;
158 }
159
get_class(const char * nm)160 Usecode_class_symbol *Usecode_scope_symbol::get_class(const char *nm) {
161 if (class_names.empty())
162 setup_class_names();
163 auto it = class_names.find(nm);
164 if (it == class_names.end())
165 return nullptr;
166 else
167 return (*it).second;
168 }
169
170 /*
171 * Lookup shape function.
172 */
get_high_shape_fun(int val)173 int Usecode_scope_symbol::get_high_shape_fun(int val) {
174 if (shape_funs.empty())
175 // Default to 'old style' high shape functions.
176 return 0x1000 + (val - 0x400);
177 auto it = shape_funs.find(val);
178 if (it == shape_funs.end())
179 return -1;
180 else
181 return (*it).second;
182 }
183
184 /*
185 * See if the function requires an itemref.
186 */
is_object_fun(int val)187 bool Usecode_scope_symbol::is_object_fun(int val) {
188 if (by_val.empty())
189 setup_by_val();
190 auto it = by_val.find(val);
191 // Symbol not found; default to original behavior
192 if (it == by_val.end())
193 return val < 0x800;
194 Usecode_symbol *sym = (*it).second;
195 return sym &&
196 (sym->get_kind() == shape_fun || sym->get_kind() == object_fun);
197 }
198
199 /*
200 * Read from a file.
201 */
read(istream & in)202 void Usecode_class_symbol::read(istream &in) {
203 Usecode_scope_symbol::read(in);
204 int num_methods = Read2(in);
205 methods.resize(num_methods);
206 for (int i = 0; i < num_methods; ++i)
207 methods[i] = Read2(in);
208 num_vars = Read2(in);
209 }
210
211 /*
212 * Write to a file.
213 */
write(ostream & out)214 void Usecode_class_symbol::write(ostream &out) {
215 Usecode_scope_symbol::write(out);
216 int num_methods = methods.size();
217 Write2(out, num_methods);
218 for (int method : methods)
219 Write2(out, method);
220 Write2(out, num_vars);
221 }
222
has_symbol_table(std::istream & in)223 bool Usecode_symbol_table::has_symbol_table(std::istream &in) {
224 // Test for symbol table.
225 if (Read4(in) == UCSYMTBL_MAGIC0 && Read4(in) == UCSYMTBL_MAGIC1)
226 return true;
227 else {
228 in.seekg(0);
229 return false;
230 }
231 }
232