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