diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..491f984 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +CFLAGS += -s -O3 + +ifeq ($(shell uname -s), Darwin) + CC = gcc-8 + CXX = g++-8 +else + CLIBS += -static +endif + +all: obj bin ReplaceLanguage + +ReplaceLanguage: ReplaceLanguage.o + $(CXX) $(CFLAGS) -o bin/ReplaceLanguage obj/ReplaceLanguage.o $(CLIBS) +ReplaceLanguage.o: ReplaceLanguage.cpp + $(CXX) $(CFLAGS) -c ReplaceLanguage.cpp -o obj/ReplaceLanguage.o $(CLIBS) + +obj: + mkdir -p obj +bin: + mkdir -p bin + +clean: + rm obj/ReplaceLanguage.o bin/ReplaceLanguage + \ No newline at end of file diff --git a/ReplaceLanguage-Mobile.cpp b/ReplaceLanguage-Mobile.cpp new file mode 100644 index 0000000..104ba4b --- /dev/null +++ b/ReplaceLanguage-Mobile.cpp @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct DataRow { + unsigned long sheet; + unsigned long id1; + unsigned long id2; + unsigned long id3; + unsigned long id4; + std::wstring loc; + + ///overloading operator < because of std::sort function + bool operator < (const DataRow& row) const { + if (sheet == row.sheet) { + if (id1 == row.id1) { + if (id2 == row.id2) { + if (id3 == row.id3) { + return (id4 < row.id4); + } + return (id3 < row.id3); + } + return (id2 < row.id2); + } + return (id1 < row.id1); + } + return (sheet < row.sheet); + } + + friend std::wistream& operator>>(std::wistream& in, DataRow& data); + friend std::wofstream& operator<<(std::wofstream& out, DataRow& data); +}; + +///overloading operator >>, so I can use it to read DataRow type +std::wistream& operator>>(std::wistream& is, DataRow& data) +{ + is >> data.sheet; + is >> data.id1; + is >> data.id2; + is >> data.id3; + is >> data.id4; + is >> std::ws; //discard whitespace + std::getline(is, data.loc); + + return is; +} + +///overloading operator <<, so I can use it to write DataRow type +std::wofstream& operator<<(std::wofstream& os, DataRow& data) +{ + os << data.sheet << L'\t'; + os << data.id1 << L'\t'; + os << data.id2 << L'\t'; + os << data.id3 << L'\t'; + os << data.id4 << L'\t'; + os << data.loc; + + return os; +} + + +int main(int argc, char *argv[]) +{ + if (argc < 4) + { + std::cerr << "Usage: " << argv[0] << " \n\n" + << "\t: file which contains translated/modified strings\n" + << "\t: original file with string table\n" + << "\t: output file" << std::endl; + return 1; + } + + std::string replace_name = argv[1]; + std::string original_name = argv[2]; + std::string target_name = argv[3]; + + std::ofstream file(target_name, std::ios::binary); + unsigned char BOM_UTF8[] = { 0xEF,0xBB,0xBF }; + file.write((char*)BOM_UTF8, sizeof(BOM_UTF8)); + file.close(); + + std::wifstream replace(replace_name, std::ios::binary); + if (replace.fail()){ + std::cerr << "Error opening " << replace_name << std::endl; + return 1; + } + + std::wifstream original(original_name, std::ios::binary); + if (original.fail()){ + std::cerr << "Error opening " << original_name << std::endl; + return 1; + } + + std::wofstream target(target_name, std::ios::binary); + if (target.fail()){ + std::cerr << "Error opening " << target_name << std::endl; + return 1; + } + + replace.ignore(3); + original.ignore(3); + target.seekp(3); + + ///create lookup table + std::vector lookup; + std::wstring row; + + std::cout << "Reading \"" << replace_name << "\"..." ; + while (std::getline(replace, row)){ + DataRow dataRow; + std::wstringstream ss; + + ss.str(row); + ss >> dataRow; + + lookup.push_back(dataRow); + } + std::cout << " (" << lookup.size() << " lines found)" << std::endl; + + ///sorting is necessary so I can speed up searching using a map (lookupHelper) + std::sort(lookup.begin(), lookup.end()); + + ///lookupHelper is a map which assigns pair of pointers, start and end (something like row numbers), + ///to the sheet number (first number on the row in text file) + std::map::iterator, std::vector::iterator> > lookupHelper; + std::vector::iterator it, first, last; + first = lookup.begin(); + int sheet = first->sheet; + for (it = lookup.begin(); it != lookup.end(); ++it) { + last = it; + if (sheet < it->sheet){ + lookupHelper[sheet] = std::make_pair(first, --last); ///last is now the first line of the new sheet, so we need to get previous value + first = it; + sheet = it->sheet; + } + } + lookupHelper[sheet] = std::make_pair(first, last); ///write the last one + + //main loop + std::cout << "Copying lines from \"" << original_name << "\" to \"" << target_name << "\"..." << std::endl; + + bool found = false; + unsigned int changed = 0, unchanged = 0; + std::map::iterator, std::vector::iterator> >::iterator iHelp; ///I love this type! + + while (std::getline(original, row)){ + DataRow originalRow; + std::wstringstream ss; + + ss.str(row); + ss >> originalRow; + + found = false; + iHelp = lookupHelper.find(originalRow.sheet); + if (iHelp != lookupHelper.end()){ + it = iHelp->second.first; ///I don't want to search for key multiple times using map[key], so I'm using less comprehensible + while (it <= iHelp->second.second) { ///dereferencing form iterator. It points to map pair and I have stored in value + if (originalRow.sheet == it->sheet && ///another pair. It looks like this: pair> + originalRow.id1 == it->id1 && ///Pair members are accessible as .first and .second, so I have to use: pointer->second.first + originalRow.id2 == it->id2 && + originalRow.id3 == it->id3 && + originalRow.id4 == it->id4){ + + found = true; + break; + } else { + it++; + } + } + } + + if (found){ + originalRow.loc = it->loc; + changed++; + } else { + unchanged++; + } + target << originalRow << '\n'; + } + + std::cout << "Processed lines: " << changed + unchanged << " (replaced: " << changed << ", original: " << unchanged << ")\nDone!" << std::endl; + + return 0; +}