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