yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
message_data.cc
Go to the documentation of this file.
1#include "message_data.h"
2
3#include <optional>
4#include <string>
5
6#include "app/snes.h"
7#include "util/hex.h"
8#include "util/log.h"
9
10namespace yaze {
11namespace editor {
12
13uint8_t FindMatchingCharacter(char value) {
14 for (const auto [key, char_value] : CharEncoder) {
15 if (value == char_value) {
16 return key;
17 }
18 }
19 return 0xFF;
20}
21
22int8_t FindDictionaryEntry(uint8_t value) {
23 if (value < DICTOFF || value == 0xFF) {
24 return -1;
25 }
26 return value - DICTOFF;
27}
28
29std::optional<TextElement> FindMatchingCommand(uint8_t b) {
30 for (const auto &text_element : TextCommands) {
31 if (text_element.ID == b) {
32 return text_element;
33 }
34 }
35 return std::nullopt;
36}
37
38std::optional<TextElement> FindMatchingSpecial(uint8_t value) {
39 auto it = std::find_if(SpecialChars.begin(), SpecialChars.end(),
40 [value](const TextElement &text_element) {
41 return text_element.ID == value;
42 });
43 if (it != SpecialChars.end()) {
44 return *it;
45 }
46 return std::nullopt;
47}
48
49ParsedElement FindMatchingElement(const std::string &str) {
50 std::smatch match;
51 std::vector<TextElement> commands_and_chars = TextCommands;
52 commands_and_chars.insert(commands_and_chars.end(), SpecialChars.begin(),
53 SpecialChars.end());
54 for (auto &text_element : commands_and_chars) {
55 match = text_element.MatchMe(str);
56 if (match.size() > 0) {
57 if (text_element.HasArgument) {
58 std::string arg = match[1].str().substr(1);
59 return ParsedElement(text_element, std::stoi(arg, nullptr, 16));
60 } else {
61 return ParsedElement(text_element, 0);
62 }
63 }
64 }
65
66 const auto dictionary_element =
67 TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary");
68
69 match = dictionary_element.MatchMe(str);
70 if (match.size() > 0) {
71 return ParsedElement(dictionary_element,
72 DICTOFF + std::stoi(match[1].str(), nullptr, 16));
73 }
74 return ParsedElement();
75}
76
77std::string ParseTextDataByte(uint8_t value) {
78 if (CharEncoder.contains(value)) {
79 char c = CharEncoder.at(value);
80 std::string str = "";
81 str.push_back(c);
82 return str;
83 }
84
85 // Check for command.
86 auto text_element = FindMatchingCommand(value);
87 if (text_element != std::nullopt) {
88 return text_element->GenericToken;
89 }
90
91 // Check for special characters.
92 auto special_element = FindMatchingSpecial(value);
93 if (special_element != std::nullopt) {
94 return text_element->GenericToken;
95 }
96
97 // Check for dictionary.
98 int dictionary = FindDictionaryEntry(value);
99 if (dictionary >= 0) {
100 return absl::StrFormat("[%s:%02X]", DICTIONARYTOKEN, dictionary);
101 }
102
103 return "";
104}
105
106std::vector<uint8_t> ParseMessageToData(std::string str) {
107 std::vector<uint8_t> bytes;
108 std::string temp_string = str;
109 int pos = 0;
110 while (pos < temp_string.size()) {
111 // Get next text fragment.
112 if (temp_string[pos] == '[') {
113 int next = temp_string.find(']', pos);
114 if (next == -1) {
115 break;
116 }
117
118 ParsedElement parsedElement =
119 FindMatchingElement(temp_string.substr(pos, next - pos + 1));
120
121 const auto dictionary_element =
122 TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary");
123
124 if (!parsedElement.Active) {
125 util::logf("Error parsing message: %s", temp_string);
126 break;
127 } else if (parsedElement.Parent == dictionary_element) {
128 bytes.push_back(parsedElement.Value);
129 } else {
130 bytes.push_back(parsedElement.Parent.ID);
131
132 if (parsedElement.Parent.HasArgument) {
133 bytes.push_back(parsedElement.Value);
134 }
135 }
136
137 pos = next + 1;
138 continue;
139 } else {
140 uint8_t bb = FindMatchingCharacter(temp_string[pos++]);
141
142 if (bb != 0xFF) {
143 bytes.push_back(bb);
144 }
145 }
146 }
147
148 return bytes;
149}
150
151std::vector<DictionaryEntry> BuildDictionaryEntries(Rom *rom) {
152 std::vector<DictionaryEntry> AllDictionaries;
153 for (int i = 0; i < kNumDictionaryEntries; i++) {
154 std::vector<uint8_t> bytes;
155 std::stringstream stringBuilder;
156
157 int address = SnesToPc(
158 kTextData + (rom->data()[kPointersDictionaries + (i * 2) + 1] << 8) +
159 rom->data()[kPointersDictionaries + (i * 2)]);
160
161 int temppush_backress =
163 (rom->data()[kPointersDictionaries + ((i + 1) * 2) + 1] << 8) +
164 rom->data()[kPointersDictionaries + ((i + 1) * 2)]);
165
166 while (address < temppush_backress) {
167 uint8_t uint8_tDictionary = rom->data()[address++];
168 bytes.push_back(uint8_tDictionary);
169 stringBuilder << ParseTextDataByte(uint8_tDictionary);
170 }
171
172 AllDictionaries.push_back(DictionaryEntry{(uint8_t)i, stringBuilder.str()});
173 }
174
175 std::sort(AllDictionaries.begin(), AllDictionaries.end(),
176 [](const DictionaryEntry &a, const DictionaryEntry &b) {
177 return a.Contents.size() > b.Contents.size();
178 });
179
180 return AllDictionaries;
181}
182
183std::string ReplaceAllDictionaryWords(std::string str,
184 std::vector<DictionaryEntry> dictionary) {
185 std::string temp = str;
186 for (const auto &entry : dictionary) {
187 if (entry.ContainedInString(temp)) {
188 temp = entry.ReplaceInstancesOfIn(temp);
189 }
190 }
191 return temp;
192}
193
195 uint8_t value, std::vector<DictionaryEntry> dictionary) {
196 for (const auto &entry : dictionary) {
197 if (entry.ID + DICTOFF == value) {
198 return entry;
199 }
200 }
201 return DictionaryEntry();
202}
203
204absl::StatusOr<MessageData> ParseSingleMessage(
205 const std::vector<uint8_t> &rom_data, int *current_pos) {
206 MessageData message_data;
207 int pos = *current_pos;
208 uint8_t current_byte;
209 std::vector<uint8_t> temp_bytes_raw;
210 std::vector<uint8_t> temp_bytes_parsed;
211 std::string current_message_raw;
212 std::string current_message_parsed;
213
214 // Read the message data
215 while (true) {
216 current_byte = rom_data[pos++];
217
218 if (current_byte == kMessageTerminator) {
219 message_data.ID = message_data.ID + 1;
220 message_data.Address = pos;
221 message_data.RawString = current_message_raw;
222 message_data.Data = temp_bytes_raw;
223 message_data.DataParsed = temp_bytes_parsed;
224 message_data.ContentsParsed = current_message_parsed;
225
226 temp_bytes_raw.clear();
227 temp_bytes_parsed.clear();
228 current_message_raw.clear();
229 current_message_parsed.clear();
230
231 break;
232 } else if (current_byte == 0xFF) {
233 break;
234 }
235
236 temp_bytes_raw.push_back(current_byte);
237
238 // Check for command.
239 auto text_element = FindMatchingCommand(current_byte);
240 if (text_element != std::nullopt) {
241 current_message_raw.append(text_element->GetParamToken());
242 current_message_parsed.append(text_element->GetParamToken());
243 temp_bytes_parsed.push_back(current_byte);
244 continue;
245 }
246
247 // Check for dictionary.
248 int dictionary = FindDictionaryEntry(current_byte);
249 if (dictionary >= 0) {
250 current_message_raw.append("[");
251 current_message_raw.append(DICTIONARYTOKEN);
252 current_message_raw.append(":");
253 current_message_raw.append(util::HexWord(dictionary));
254 current_message_raw.append("]");
255
256 auto mutable_rom_data = const_cast<uint8_t *>(rom_data.data());
257 uint32_t address = Get24LocalFromPC(
258 mutable_rom_data, kPointersDictionaries + (dictionary * 2));
259 uint32_t address_end = Get24LocalFromPC(
260 mutable_rom_data, kPointersDictionaries + ((dictionary + 1) * 2));
261
262 for (uint32_t i = address; i < address_end; i++) {
263 temp_bytes_parsed.push_back(rom_data[i]);
264 current_message_parsed.append(ParseTextDataByte(rom_data[i]));
265 }
266
267 continue;
268 }
269
270 // Everything else.
271 if (CharEncoder.contains(current_byte)) {
272 std::string str = "";
273 str.push_back(CharEncoder.at(current_byte));
274 current_message_raw.append(str);
275 current_message_parsed.append(str);
276 temp_bytes_parsed.push_back(current_byte);
277 }
278 }
279
280 *current_pos = pos;
281 return message_data;
282}
283
284std::vector<std::string> ParseMessageData(
285 std::vector<MessageData> &message_data,
286 const std::vector<DictionaryEntry> &dictionary_entries) {
287 std::vector<std::string> parsed_messages;
288
289 for (auto &message : message_data) {
290 std::string parsed_message = "";
291 int pos = 0;
292 for (const uint8_t &byte : message.Data) {
293 if (CharEncoder.contains(byte)) {
294 parsed_message.push_back(CharEncoder.at(byte));
295 } else {
296 if (byte >= DICTOFF && byte < (DICTOFF + 97)) {
297 DictionaryEntry dic_entry;
298 for (const auto &entry : dictionary_entries) {
299 if (entry.ID == byte - DICTOFF) {
300 dic_entry = entry;
301 break;
302 }
303 }
304 parsed_message.append(dic_entry.Contents);
305 } else {
306 auto text_element = FindMatchingCommand(byte);
307 if (text_element != std::nullopt) {
308 if (text_element->ID == kScrollVertical ||
309 text_element->ID == kLine2 || text_element->ID == kLine3) {
310 parsed_message.append("\n");
311 }
312 // If there is a param, add it to the message using GetParamToken.
313 if (text_element->HasArgument) {
314 // The next byte is the param.
315 parsed_message.append(
316 text_element->GetParamToken(message.Data[pos + 1]));
317 pos++;
318 } else {
319 parsed_message.append(text_element->GetParamToken());
320 }
321 }
322 }
323 }
324 pos++;
325 }
326 parsed_messages.push_back(parsed_message);
327 }
328
329 return parsed_messages;
330}
331
332std::vector<MessageData> ReadAllTextData(uint8_t *rom, int pos) {
333 std::vector<MessageData> list_of_texts;
334 int message_id = 0;
335
336 std::vector<uint8_t> raw_message;
337 std::vector<uint8_t> parsed_message;
338 std::string current_raw_message;
339 std::string current_parsed_message;
340
341 uint8_t current_byte = 0;
342 while (current_byte != 0xFF) {
343 current_byte = rom[pos++];
344 if (current_byte == kMessageTerminator) {
345 list_of_texts.push_back(
346 MessageData(message_id++, pos, current_raw_message, raw_message,
347 current_parsed_message, parsed_message));
348 raw_message.clear();
349 parsed_message.clear();
350 current_raw_message.clear();
351 current_parsed_message.clear();
352 continue;
353 } else if (current_byte == 0xFF) {
354 break;
355 }
356
357 raw_message.push_back(current_byte);
358
359 auto text_element = FindMatchingCommand(current_byte);
360 if (text_element != std::nullopt) {
361 parsed_message.push_back(current_byte);
362 if (text_element->HasArgument) {
363 current_byte = rom[pos++];
364 raw_message.push_back(current_byte);
365 parsed_message.push_back(current_byte);
366 }
367
368 current_raw_message.append(text_element->GetParamToken(current_byte));
369 current_parsed_message.append(text_element->GetParamToken(current_byte));
370
371 if (text_element->Token == kBankToken) {
372 pos = kTextData2;
373 }
374
375 continue;
376 }
377
378 // Check for special characters.
379 auto special_element = FindMatchingSpecial(current_byte);
380 if (special_element != std::nullopt) {
381 current_raw_message.append(special_element->GetParamToken());
382 current_parsed_message.append(special_element->GetParamToken());
383 parsed_message.push_back(current_byte);
384 continue;
385 }
386
387 // Check for dictionary.
388 int dictionary = FindDictionaryEntry(current_byte);
389 if (dictionary >= 0) {
390 current_raw_message.append(absl::StrFormat("[%s:%s]", DICTIONARYTOKEN,
391 util::HexByte(dictionary)));
392
393 uint32_t address =
394 Get24LocalFromPC(rom, kPointersDictionaries + (dictionary * 2));
395 uint32_t address_end =
396 Get24LocalFromPC(rom, kPointersDictionaries + ((dictionary + 1) * 2));
397
398 for (uint32_t i = address; i < address_end; i++) {
399 parsed_message.push_back(rom[i]);
400 current_parsed_message.append(ParseTextDataByte(rom[i]));
401 }
402
403 continue;
404 }
405
406 // Everything else.
407 if (CharEncoder.contains(current_byte)) {
408 std::string str = "";
409 str.push_back(CharEncoder.at(current_byte));
410 current_raw_message.append(str);
411 current_parsed_message.append(str);
412 parsed_message.push_back(current_byte);
413 }
414 }
415
416 return list_of_texts;
417}
418
419} // namespace editor
420} // namespace yaze
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:58
auto data() const
Definition rom.h:177
Editors are the view controllers for the application.
std::vector< MessageData > ReadAllTextData(uint8_t *rom, int pos)
uint8_t FindMatchingCharacter(char value)
const std::string kBankToken
const uint8_t kMessageTerminator
const std::string DICTIONARYTOKEN
constexpr uint8_t kScrollVertical
std::string ParseTextDataByte(uint8_t value)
constexpr int kTextData
DictionaryEntry FindRealDictionaryEntry(uint8_t value, std::vector< DictionaryEntry > dictionary)
constexpr int kTextData2
constexpr uint8_t kLine2
std::string ReplaceAllDictionaryWords(std::string str, std::vector< DictionaryEntry > dictionary)
constexpr int kPointersDictionaries
constexpr int kNumDictionaryEntries
absl::StatusOr< MessageData > ParseSingleMessage(const std::vector< uint8_t > &rom_data, int *current_pos)
std::vector< std::string > ParseMessageData(std::vector< MessageData > &message_data, const std::vector< DictionaryEntry > &dictionary_entries)
std::optional< TextElement > FindMatchingSpecial(uint8_t value)
std::vector< DictionaryEntry > BuildDictionaryEntries(Rom *rom)
std::vector< uint8_t > ParseMessageToData(std::string str)
constexpr uint8_t DICTOFF
std::optional< TextElement > FindMatchingCommand(uint8_t b)
ParsedElement FindMatchingElement(const std::string &str)
constexpr uint8_t kLine3
int8_t FindDictionaryEntry(uint8_t value)
std::string HexWord(uint16_t word, HexStringParams params)
Definition hex.cc:43
std::string HexByte(uint8_t byte, HexStringParams params)
Definition hex.cc:30
Main namespace for the application.
Definition controller.cc:18
uint32_t Get24LocalFromPC(uint8_t *data, int addr, bool pc=true)
Definition snes.h:30
uint32_t SnesToPc(uint32_t addr) noexcept
Definition snes.h:8
std::vector< uint8_t > Data
std::vector< uint8_t > DataParsed