1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of RLVM, a RealLive virtual machine clone.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (C) 2007 Elliot Glaysher
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25 //
26 // -----------------------------------------------------------------------
27 
28 #include "machine/memory.h"
29 
30 #include <iostream>
31 #include <map>
32 #include <string>
33 
34 #include "libreallive/gameexe.h"
35 #include "libreallive/intmemref.h"
36 #include "machine/rlmachine.h"
37 #include "utilities/exception.h"
38 #include "utilities/string_utilities.h"
39 
40 using std::make_pair;
41 
42 const IntegerBank_t LOCAL_INTEGER_BANKS = {
43     make_pair(libreallive::INTA_LOCATION, 'A'),
44     make_pair(libreallive::INTB_LOCATION, 'B'),
45     make_pair(libreallive::INTC_LOCATION, 'C'),
46     make_pair(libreallive::INTD_LOCATION, 'D'),
47     make_pair(libreallive::INTE_LOCATION, 'E'),
48     make_pair(libreallive::INTF_LOCATION, 'F')};
49 
50 const IntegerBank_t GLOBAL_INTEGER_BANKS = {
51   make_pair(libreallive::INTG_LOCATION, 'G'),
52   make_pair(libreallive::INTZ_LOCATION, 'Z')};
53 
54 // -----------------------------------------------------------------------
55 // GlobalMemory
56 // -----------------------------------------------------------------------
GlobalMemory()57 GlobalMemory::GlobalMemory() {
58   memset(intG, 0, sizeof(intG));
59   memset(intZ, 0, sizeof(intZ));
60 }
61 
62 // -----------------------------------------------------------------------
63 // LocalMemory
64 // -----------------------------------------------------------------------
LocalMemory()65 LocalMemory::LocalMemory() { reset(); }
66 
LocalMemory(dont_initialize)67 LocalMemory::LocalMemory(dont_initialize) {}
68 
reset()69 void LocalMemory::reset() {
70   memset(intA, 0, sizeof(intA));
71   memset(intB, 0, sizeof(intB));
72   memset(intC, 0, sizeof(intC));
73   memset(intD, 0, sizeof(intD));
74   memset(intE, 0, sizeof(intE));
75   memset(intF, 0, sizeof(intF));
76 
77   for (int i = 0; i < SIZE_OF_MEM_BANK; ++i)
78     strS[i].clear();
79   for (int i = 0; i < SIZE_OF_NAME_BANK; ++i)
80     local_names[i].clear();
81 }
82 
83 // -----------------------------------------------------------------------
84 // Memory
85 // -----------------------------------------------------------------------
Memory(RLMachine & machine,Gameexe & gameexe)86 Memory::Memory(RLMachine& machine, Gameexe& gameexe)
87     : global_(new GlobalMemory), local_(), machine_(machine) {
88   ConnectIntVarPointers();
89 
90   InitializeDefaultValues(gameexe);
91 }
92 
Memory(RLMachine & machine,int slot)93 Memory::Memory(RLMachine& machine, int slot)
94     : global_(machine.memory().global_),
95       local_(dont_initialize()),
96       machine_(machine) {
97   ConnectIntVarPointers();
98 }
99 
~Memory()100 Memory::~Memory() {}
101 
ConnectIntVarPointers()102 void Memory::ConnectIntVarPointers() {
103   int_var[0] = local_.intA;
104   int_var[1] = local_.intB;
105   int_var[2] = local_.intC;
106   int_var[3] = local_.intD;
107   int_var[4] = local_.intE;
108   int_var[5] = local_.intF;
109   int_var[6] = global_->intG;
110   int_var[7] = global_->intZ;
111 
112   original_int_var[0] = &local_.original_intA;
113   original_int_var[1] = &local_.original_intB;
114   original_int_var[2] = &local_.original_intC;
115   original_int_var[3] = &local_.original_intD;
116   original_int_var[4] = &local_.original_intE;
117   original_int_var[5] = &local_.original_intF;
118   original_int_var[6] = NULL;
119   original_int_var[7] = NULL;
120 }
121 
GetStringValue(int type,int location)122 const std::string& Memory::GetStringValue(int type, int location) {
123   if (location > (SIZE_OF_MEM_BANK - 1))
124     throw rlvm::Exception(
125         "Invalid range access in RLMachine::set_string_value");
126 
127   switch (type) {
128     case libreallive::STRK_LOCATION:
129       if ((location + 1) > machine_.CurrentStrKBank().size())
130         machine_.CurrentStrKBank().resize(location + 1);
131       return machine_.CurrentStrKBank()[location];
132     case libreallive::STRM_LOCATION:
133       return global_->strM[location];
134     case libreallive::STRS_LOCATION:
135       return local_.strS[location];
136     default:
137       throw rlvm::Exception("Invalid type in RLMachine::get_string_value");
138   }
139 }
140 
SetStringValue(int type,int number,const std::string & value)141 void Memory::SetStringValue(int type, int number, const std::string& value) {
142   if (number > (SIZE_OF_MEM_BANK - 1))
143     throw rlvm::Exception(
144         "Invalid range access in RLMachine::set_string_value");
145 
146   switch (type) {
147     case libreallive::STRK_LOCATION:
148       if ((number + 1) > machine_.CurrentStrKBank().size())
149         machine_.CurrentStrKBank().resize(number + 1);
150       machine_.CurrentStrKBank()[number] = value;
151       break;
152     case libreallive::STRM_LOCATION:
153       global_->strM[number] = value;
154       break;
155     case libreallive::STRS_LOCATION: {
156       // Possibly record the original value for a piece of local memory.
157       std::map<int, std::string>::iterator it =
158           local_.original_strS.find(number);
159       if (it == local_.original_strS.end()) {
160         local_.original_strS.insert(
161             std::make_pair(number, local_.strS[number]));
162       }
163       local_.strS[number] = value;
164       break;
165     }
166     default:
167       throw rlvm::Exception("Invalid type in RLMachine::set_string_value");
168   }
169 }
170 
CheckNameIndex(int index,const std::string & name) const171 void Memory::CheckNameIndex(int index, const std::string& name) const {
172   if (index > (SIZE_OF_NAME_BANK - 1)) {
173     std::ostringstream oss;
174     oss << "Invalid index " << index << " in " << name;
175     throw rlvm::Exception(oss.str());
176   }
177 }
178 
SetName(int index,const std::string & name)179 void Memory::SetName(int index, const std::string& name) {
180   CheckNameIndex(index, "Memory::set_name");
181   global_->global_names[index] = name;
182 }
183 
GetName(int index) const184 const std::string& Memory::GetName(int index) const {
185   CheckNameIndex(index, "Memory::get_name");
186   return global_->global_names[index];
187 }
188 
SetLocalName(int index,const std::string & name)189 void Memory::SetLocalName(int index, const std::string& name) {
190   CheckNameIndex(index, "Memory::set_local_name");
191   local_.local_names[index] = name;
192 }
193 
GetLocalName(int index) const194 const std::string& Memory::GetLocalName(int index) const {
195   CheckNameIndex(index, "Memory::set_local_name");
196   return local_.local_names[index];
197 }
198 
HasBeenRead(int scenario,int kidoku) const199 bool Memory::HasBeenRead(int scenario, int kidoku) const {
200   std::map<int, boost::dynamic_bitset<>>::const_iterator it =
201       global_->kidoku_data.find(scenario);
202 
203   if ((it != global_->kidoku_data.end()) &&
204       (static_cast<size_t>(kidoku) < it->second.size()))
205     return it->second.test(kidoku);
206 
207   return false;
208 }
209 
RecordKidoku(int scenario,int kidoku)210 void Memory::RecordKidoku(int scenario, int kidoku) {
211   boost::dynamic_bitset<>& bitset = global_->kidoku_data[scenario];
212   if (bitset.size() <= static_cast<size_t>(kidoku))
213     bitset.resize(kidoku + 1, false);
214 
215   bitset[kidoku] = true;
216 }
217 
TakeSavepointSnapshot()218 void Memory::TakeSavepointSnapshot() {
219   local_.original_intA.clear();
220   local_.original_intB.clear();
221   local_.original_intC.clear();
222   local_.original_intD.clear();
223   local_.original_intE.clear();
224   local_.original_intF.clear();
225   local_.original_strS.clear();
226 }
227 
228 // static
ConvertLetterIndexToInt(const std::string & value)229 int Memory::ConvertLetterIndexToInt(const std::string& value) {
230   int total = 0;
231 
232   if (value.size() == 1) {
233     total += (value[0] - 'A');
234   } else if (value.size() == 2) {
235     total += 26 * ((value[0] - 'A') + 1);
236     total += (value[1] - 'A');
237   } else {
238     throw rlvm::Exception("Invalid value in convert_name_var!");
239   }
240 
241   return total;
242 }
243 
InitializeDefaultValues(Gameexe & gameexe)244 void Memory::InitializeDefaultValues(Gameexe& gameexe) {
245   // Note: We ignore the \#NAME_MAXLEN variable because manual allocation is
246   // error prone and for losers.
247   GameexeFilteringIterator end = gameexe.filtering_end();
248   for (GameexeFilteringIterator it = gameexe.filtering_begin("NAME.");
249        it != end;
250        ++it) {
251     try {
252       SetName(ConvertLetterIndexToInt(it->GetKeyParts().at(1)),
253               RemoveQuotes(it->ToString()));
254     }
255     catch (...) {
256       std::cerr << "WARNING: Invalid format for key " << it->key() << std::endl;
257     }
258   }
259 
260   for (GameexeFilteringIterator it = gameexe.filtering_begin("LOCALNAME.");
261        it != end;
262        ++it) {
263     try {
264       SetLocalName(ConvertLetterIndexToInt(it->GetKeyParts().at(1)),
265                    RemoveQuotes(it->ToString()));
266     }
267     catch (...) {
268       std::cerr << "WARNING: Invalid format for key " << it->key() << std::endl;
269     }
270   }
271 }
272