BOOL CPOFile::ParseFile(LPCTSTR szPath, BOOL bUpdateExisting, bool bAdjustEOLs) { if (!PathFileExists(szPath)) return FALSE; m_bAdjustEOLs = bAdjustEOLs; if (!m_bQuiet) _ftprintf(stdout, L"parsing file %s...\n", szPath); int nEntries = 0; int nDeleted = 0; int nTranslated = 0; //since stream classes still expect the filepath in char and not wchar_t //we need to convert the filepath to multibyte char filepath[MAX_PATH + 1] = { 0 }; WideCharToMultiByte(CP_ACP, 0, szPath, -1, filepath, _countof(filepath) - 1, nullptr, nullptr); std::wifstream File; File.imbue(std::locale(std::locale(), new utf8_conversion())); File.open(filepath); if (!File.good()) { _ftprintf(stderr, L"can't open input file %s\n", szPath); return FALSE; } auto line = std::make_unique<TCHAR[]>(2 * MAX_STRING_LENGTH); std::vector<std::wstring> entry; do { File.getline(line.get(), 2*MAX_STRING_LENGTH); if (line.get()[0]==0) { //empty line means end of entry! RESOURCEENTRY resEntry = {0}; std::wstring msgid; std::wstring regexsearch, regexreplace; int type = 0; for (auto I = entry.cbegin(); I != entry.cend(); ++I) { if (StartsWith(I->c_str(), L"# ")) { //user comment if (StartsWith(I->c_str(), L"# regexsearch=")) regexsearch = I->substr(14); else if (StartsWith(I->c_str(), L"# regexreplace=")) regexreplace = I->substr(15); else resEntry.translatorcomments.push_back(I->c_str()); if (!regexsearch.empty() && !regexreplace.empty()) { m_regexes.push_back(std::make_tuple(regexsearch, regexreplace)); regexsearch.clear(); regexreplace.clear(); } type = 0; } if (StartsWith(I->c_str(), L"#.")) { //automatic comments resEntry.automaticcomments.push_back(I->c_str()); type = 0; } if (StartsWith(I->c_str(), L"#,")) { //flag resEntry.flag = I->c_str(); type = 0; } if (StartsWith(I->c_str(), L"msgid")) { //message id msgid = I->c_str(); msgid = std::wstring(msgid.substr(7, msgid.size() - 8)); std::wstring s = msgid; s.erase(s.cbegin(), std::find_if(s.cbegin(), s.cend(), std::not1(std::ptr_fun<wint_t, int>(iswspace)))); if (s.size()) nEntries++; type = 1; } if (StartsWith(I->c_str(), L"msgstr")) { //message string resEntry.msgstr = I->c_str(); resEntry.msgstr = resEntry.msgstr.substr(8, resEntry.msgstr.length() - 9); if (!resEntry.msgstr.empty()) nTranslated++; type = 2; } if (StartsWith(I->c_str(), L"\"")) { if (type == 1) { std::wstring temp = I->c_str(); temp = temp.substr(1, temp.length()-2); msgid += temp; } if (type == 2) { if (resEntry.msgstr.empty()) nTranslated++; std::wstring temp = I->c_str(); temp = temp.substr(1, temp.length()-2); resEntry.msgstr += temp; } } } entry.clear(); if ((bUpdateExisting)&&(this->count(msgid) == 0)) nDeleted++; else { if ((m_bAdjustEOLs)&&(msgid.find(L"\\r\\n") != std::string::npos)) { AdjustEOLs(resEntry.msgstr); } // always use the new data for generated comments/flags auto newEntry = (*this)[msgid]; resEntry.automaticcomments = newEntry.automaticcomments; resEntry.flag = newEntry.flag; resEntry.resourceIDs = newEntry.resourceIDs; (*this)[msgid] = resEntry; } msgid.clear(); } else { entry.push_back(line.get()); } } while (File.gcount() > 0); printf("%s", File.getloc().name().c_str()); File.close(); RESOURCEENTRY emptyentry = {0}; (*this)[std::wstring(L"")] = emptyentry; if (!m_bQuiet) _ftprintf(stdout, L"%d Entries found, %d were already translated and %d got deleted\n", nEntries, nTranslated, nDeleted); return TRUE; }
BOOL CPOFile::ParseFile(LPCTSTR szPath, BOOL bUpdateExisting, bool bAdjustEOLs) { if (!PathFileExists(szPath)) return FALSE; m_bAdjustEOLs = bAdjustEOLs; if (!m_bQuiet) _ftprintf(stdout, _T("parsing file %s...\n"), szPath); int nEntries = 0; int nDeleted = 0; int nTranslated = 0; //since stream classes still expect the filepath in char and not wchar_t //we need to convert the filepath to multibyte char filepath[MAX_PATH+1]; SecureZeroMemory(filepath, sizeof(filepath)); WideCharToMultiByte(CP_ACP, NULL, szPath, -1, filepath, _countof(filepath)-1, NULL, NULL); std::wifstream File; File.imbue(std::locale(std::locale(), new utf8_conversion())); File.open(filepath); if (!File.good()) { _ftprintf(stderr, _T("can't open input file %s\n"), szPath); return FALSE; } std::unique_ptr<TCHAR[]> line(new TCHAR[2*MAX_STRING_LENGTH]); std::vector<std::wstring> entry; do { File.getline(line.get(), 2*MAX_STRING_LENGTH); if (line.get()[0]==0) { //empty line means end of entry! RESOURCEENTRY resEntry; std::wstring msgid; int type = 0; for (std::vector<std::wstring>::iterator I = entry.begin(); I != entry.end(); ++I) { if (_tcsncmp(I->c_str(), _T("# "), 2)==0) { //user comment resEntry.translatorcomments.push_back(I->c_str()); type = 0; } if (_tcsncmp(I->c_str(), _T("#."), 2)==0) { //automatic comments resEntry.automaticcomments.push_back(I->c_str()); type = 0; } if (_tcsncmp(I->c_str(), _T("#,"), 2)==0) { //flag resEntry.flag = I->c_str(); type = 0; } if (_tcsncmp(I->c_str(), _T("msgid"), 5)==0) { //message id msgid = I->c_str(); msgid = std::wstring(msgid.substr(7, msgid.size() - 8)); std::wstring s = msgid; s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<wint_t, int>(iswspace)))); if (s.size()) nEntries++; type = 1; } if (_tcsncmp(I->c_str(), _T("msgstr"), 6)==0) { //message string resEntry.msgstr = I->c_str(); resEntry.msgstr = resEntry.msgstr.substr(8, resEntry.msgstr.length() - 9); if (!resEntry.msgstr.empty()) nTranslated++; type = 2; } if (_tcsncmp(I->c_str(), _T("\""), 1)==0) { if (type == 1) { std::wstring temp = I->c_str(); temp = temp.substr(1, temp.length()-2); msgid += temp; } if (type == 2) { if (resEntry.msgstr.empty()) nTranslated++; std::wstring temp = I->c_str(); temp = temp.substr(1, temp.length()-2); resEntry.msgstr += temp; } } } entry.clear(); if ((bUpdateExisting)&&(this->count(msgid) == 0)) nDeleted++; else { if ((m_bAdjustEOLs)&&(msgid.find(L"\\r\\n") != std::string::npos)) { AdjustEOLs(resEntry.msgstr); } (*this)[msgid] = resEntry; } msgid.clear(); } else { entry.push_back(line.get()); } } while (File.gcount() > 0); printf(File.getloc().name().c_str()); File.close(); RESOURCEENTRY emptyentry = {0}; (*this)[std::wstring(_T(""))] = emptyentry; if (!m_bQuiet) _ftprintf(stdout, _T("%d Entries found, %d were already translated and %d got deleted\n"), nEntries, nTranslated, nDeleted); return TRUE; }