diff --git a/src/Main.cc b/src/Main.cc index c391897b..618b1600 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -146,7 +146,7 @@ void write_output_data(Arguments& args, const void* data, size_t size, const cha // If the output is to a specified file, write it there save_file(output_filename, data, size); - } else if (output_filename.empty() && !input_filename.empty() && (input_filename != "-")) { + } else if (output_filename.empty() && (output_filename != "-") && !input_filename.empty() && (input_filename != "-")) { // If no output filename is given and an input filename is given, write to // . if (!extension) { @@ -1033,7 +1033,8 @@ Action a_disassemble_quest_script( if (!args.get("decompressed")) { data = prs_decompress(data); } - string result = disassemble_quest_script(data.data(), data.size(), version, 1); + uint8_t language = args.get("japanese") ? 0 : 1; + string result = disassemble_quest_script(data.data(), data.size(), version, language); write_output_data(args, result.data(), result.size(), "txt"); }); Action a_disassemble_quest_map( diff --git a/src/QuestScript.cc b/src/QuestScript.cc index 8e4076a8..9b0e4dbd 100644 --- a/src/QuestScript.cc +++ b/src/QuestScript.cc @@ -34,6 +34,54 @@ ToT as_type(const FromT& v) { return ret; } +static TextEncoding encoding_for_language(uint8_t language) { + return (language ? TextEncoding::ISO8859 : TextEncoding::SJIS); +} + +static string escape_string(const string& data, TextEncoding encoding = TextEncoding::UTF8) { + string decoded; + switch (encoding) { + case TextEncoding::UTF8: + decoded = data; + break; + case TextEncoding::UTF16: + decoded = tt_utf16_to_utf8(data); + break; + case TextEncoding::SJIS: + decoded = tt_sjis_to_utf8(data); + break; + case TextEncoding::ISO8859: + decoded = tt_8859_to_utf8(data); + break; + case TextEncoding::ASCII: + decoded = tt_ascii_to_utf8(data); + break; + default: + return format_data_string(data); + } + + string ret = "\""; + for (char ch : decoded) { + if (ch == '\n') { + ret += "\\n"; + } else if (ch == '\r') { + ret += "\\r"; + } else if (ch == '\t') { + ret += "\\t"; + } else if (ch >= 0x00 && ch < 0x20) { + ret += string_printf("\\x%02hhX", ch); + } else if (ch == '\'') { + ret += "\\\'"; + } else if (ch == '\"') { + ret += "\\\""; + } else { + ret += ch; + } + } + ret += "\""; + return ret; +} + static string format_and_indent_data(const void* data, size_t size, uint64_t start_address) { struct iovec iov; iov.iov_base = const_cast(data); @@ -809,7 +857,8 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers const auto& header = r.get(); code_offset = header.code_offset; function_table_offset = header.function_table_offset; - lines.emplace_back(".name " + JSON(header.name.decode(0)).serialize()); + language = 0; + lines.emplace_back(".name " + escape_string(header.name.decode(0))); break; } case Version::DC_V1_12_2000_PROTOTYPE: @@ -818,11 +867,12 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers const auto& header = r.get(); code_offset = header.code_offset; function_table_offset = header.function_table_offset; + language = header.language; lines.emplace_back(string_printf(".quest_num %hu", header.quest_number.load())); lines.emplace_back(string_printf(".language %hhu", header.language)); - lines.emplace_back(".name " + JSON(header.name.decode(language)).serialize()); - lines.emplace_back(".short_desc " + JSON(header.short_description.decode(language)).serialize()); - lines.emplace_back(".long_desc " + JSON(header.long_description.decode(language)).serialize()); + lines.emplace_back(".name " + escape_string(header.name.decode(language))); + lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language))); + lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language))); break; } case Version::PC_V2: { @@ -830,11 +880,12 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers const auto& header = r.get(); code_offset = header.code_offset; function_table_offset = header.function_table_offset; + language = header.language; lines.emplace_back(string_printf(".quest_num %hu", header.quest_number.load())); lines.emplace_back(string_printf(".language %hhu", header.language)); - lines.emplace_back(".name " + JSON(header.name.decode(language)).serialize()); - lines.emplace_back(".short_desc " + JSON(header.short_description.decode(language)).serialize()); - lines.emplace_back(".long_desc " + JSON(header.long_description.decode(language)).serialize()); + lines.emplace_back(".name " + escape_string(header.name.decode(language))); + lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language))); + lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language))); break; } case Version::GC_NTE: @@ -845,12 +896,13 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers const auto& header = r.get(); code_offset = header.code_offset; function_table_offset = header.function_table_offset; + language = header.language; lines.emplace_back(string_printf(".quest_num %hhu", header.quest_number)); lines.emplace_back(string_printf(".language %hhu", header.language)); lines.emplace_back(string_printf(".episode %hhu", header.episode)); - lines.emplace_back(".name " + JSON(header.name.decode(language)).serialize()); - lines.emplace_back(".short_desc " + JSON(header.short_description.decode(language)).serialize()); - lines.emplace_back(".long_desc " + JSON(header.long_description.decode(language)).serialize()); + lines.emplace_back(".name " + escape_string(header.name.decode(language))); + lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language))); + lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language))); break; } case Version::BB_V4: { @@ -864,9 +916,9 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers if (header.joinable_in_progress) { lines.emplace_back(".joinable_in_progress"); } - lines.emplace_back(".name " + JSON(header.name.decode(language)).serialize()); - lines.emplace_back(".short_desc " + JSON(header.short_description.decode(language)).serialize()); - lines.emplace_back(".long_desc " + JSON(header.long_description.decode(language)).serialize()); + lines.emplace_back(".name " + escape_string(header.name.decode(language))); + lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language))); + lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language))); break; } default: @@ -1115,13 +1167,13 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers if (def->flags & F_PASS) { arg_stack_values.emplace_back(tt_utf16_to_utf8(w.str())); } - dasm_arg = JSON(w.str()).serialize(); + dasm_arg = escape_string(w.str(), TextEncoding::UTF16); } else { string s = cmd_r.get_cstr(); if (def->flags & F_PASS) { - arg_stack_values.emplace_back(s); + arg_stack_values.emplace_back(language ? tt_8859_to_utf8(s) : tt_sjis_to_utf8(s)); } - dasm_arg = JSON(s).serialize(); + dasm_arg = escape_string(s, encoding_for_language(language)); } break; default: @@ -1227,7 +1279,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers break; case Arg::Type::CSTRING: if (arg_value.type == ArgStackValue::Type::CSTRING) { - dasm_arg = format_data_string(arg_value.as_string); + dasm_arg = escape_string(arg_value.as_string); } else { dasm_arg = "/* invalid-type */"; } @@ -1331,12 +1383,12 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers } str_data = tt_utf16_to_utf8(str_data); } - string formatted = format_data_string(str_data); + string formatted = escape_string(str_data, use_wstrs ? TextEncoding::UTF16 : encoding_for_language(language)); lines.emplace_back(string_printf(" %04" PRIX32 " %s", l->offset, formatted.c_str())); } print_as_struct.template operator()([&](const PlayerVisualConfig& visual) -> void { lines.emplace_back(" // As PlayerVisualConfig"); - string name = format_data_string(visual.name.decode(language)); + string name = escape_string(visual.name.decode(language)); lines.emplace_back(string_printf(" %04zX name %s", l->offset + offsetof(PlayerVisualConfig, name), name.c_str())); lines.emplace_back(string_printf(" %04zX name_color %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, name_color), visual.name_color.load())); string a2_str = format_data_string(visual.unknown_a2.data(), sizeof(visual.unknown_a2));