#include #include #include #include #include #include #include struct compareKeyValueItem { inline bool operator() (CIniFileBase::KeyValueItem & struct1, const CIniFileBase::KeyValueItem & struct2) { std::string a = *struct1.first; std::string b = *struct2.first; if (_stricmp(a.c_str(), "Name") == 0) { return true; } if (_stricmp(b.c_str(), "Name") == 0) { return false; } if (a.length() > 5 && _strnicmp(a.c_str(), "cheat", 5) == 0 && b.length() > 5 && _strnicmp(b.c_str(), "cheat", 5) == 0) { int i1 = atoi(&(*struct1.first)[5]); int i2 = atoi(&(*struct2.first)[5]); if (i1 != i2) { return i1 < i2; } char Buffer[40]; int number_len = strlen(_itoa(i1, Buffer, 10)); if (strlen(&a[5 + number_len]) == 0) { return true; } if (strlen(&b[5 + number_len]) == 0) { return false; } return _stricmp(&a[5 + number_len], &b[5 + number_len]) <= 0; } return _stricmp(a.c_str(), b.c_str()) <= 0; } }; void CustomSortData(CIniFileBase::KeyValueVector & data) { std::sort(data.begin(), data.end(), compareKeyValueItem()); } void SplitFile(const char * FileName, const char * Target) { if (!CPath(Target,"").DirectoryCreate()) { return; } CPath SearchDir(Target, "*.*"); if (SearchDir.FindFirst()) { do { SearchDir.Delete(); } while (SearchDir.FindNext()); } CIniFile::SectionList Sections; CIniFile CheatIniFile(FileName); CheatIniFile.GetVectorOfSections(Sections); for (size_t i = 0, n = Sections.size(); i < n; i++) { const char * Section = Sections[i].c_str(); CIniFile::KeyValueData data; CheatIniFile.GetKeyValueData(Section, data); stdstr Name = CheatIniFile.GetString(Section, "Name", ""); Name.Trim("\t ="); if (Name.length() == 0) { Name = CheatIniFile.GetString(Section, "Good Name", Section); Name.Trim("\t ="); } Name.Replace("\\", "-"); Name.Replace("/", "-"); Name.Replace(":", " -"); if (Name.length() == 0) { continue; } CPath GameFileName(Target, stdstr_f("%s.%s", Name.c_str(), CPath(FileName).GetExtension().c_str()).c_str()); CIniFile GameIniFile(GameFileName); if (!GameIniFile.IsFileOpen()) { continue; } GameIniFile.SetAutoFlush(false); GameIniFile.SetCustomSort(CustomSortData); for (CIniFile::KeyValueData::const_iterator itr = data.begin(); itr != data.end(); itr++) { stdstr DataLine(itr->second); DataLine.Trim("\t ="); if (strcmp(itr->first.c_str(), "Good Name") == 0) { GameIniFile.SaveString(Section, "Name", DataLine.c_str()); } else { GameIniFile.SaveString(Section, itr->first.c_str(), DataLine.c_str()); } } GameIniFile.FlushChanges(); } } typedef std::map Files; void RegionSection(CFile &TargetIniFile, Files &files, const char * Region, const char * RegionCode) { stdstr_f LineData = stdstr_f("//--------------- %s Region Cheat Codes ---------------\r\n\r\n", Region); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); bool first = true; for (Files::const_iterator itr = files.begin(); itr != files.end(); itr++) { CIniFile GameIniFile(itr->second.c_str()); GameIniFile.SetCustomSort(CustomSortData); CIniFile::SectionList Sections; GameIniFile.GetVectorOfSections(Sections); bool found = false; stdstr_f searchStr(":%s", RegionCode); for (size_t i = 0, n = Sections.size(); i < n; i++) { const char * Section = Sections[i].c_str(); const char * pos = strstr(Section, searchStr.c_str()); if (pos == NULL) { continue; } found = true; break; } if (!found) { continue; } for (size_t i = 0, n = Sections.size(); i < n; i++) { const char * Section = Sections[i].c_str(); CIniFile::KeyValueData data; GameIniFile.GetKeyValueData(Section, data); CIniFile::KeyValueVector data2; for (CIniFile::KeyValueData::const_iterator DataItr = data.begin(); DataItr != data.end(); DataItr++) { data2.push_back(CIniFile::KeyValueItem(&DataItr->first, &DataItr->second)); } std::sort(data2.begin(), data2.end(), compareKeyValueItem()); if (first) { first = false; } else { LineData = stdstr_f("\r\n//----\r\n\r\n"); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); } LineData = stdstr_f("[%s]\r\n", Section); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); for (CIniFile::KeyValueVector::const_iterator DataItr = data2.begin(); DataItr != data2.end(); DataItr++) { LineData = stdstr_f("%s=%s\r\n", DataItr->first->c_str(), DataItr->second->c_str()); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); } } } } void JoinFile(const char * Directory, const char * Target) { Files files; CPath SearchDir(Directory, "*.*"); if (SearchDir.FindFirst()) { do { CIniFile GameIniFile(SearchDir); CIniFile::SectionList Sections; GameIniFile.GetVectorOfSections(Sections); for (size_t i = 0, n = Sections.size(); i < n; i++) { const char * Section = Sections[i].c_str(); stdstr Name = GameIniFile.GetString(Section, "Name", Section); Name.Trim("\t ="); if (Name.size() > 0) { files.insert(Files::value_type(Name, SearchDir)); break; } } } while (SearchDir.FindNext()); } if (CPath(Target).Exists()) { CPath(Target).Delete(); }; CFile TargetIniFile; if (!TargetIniFile.Open(Target, CFileBase::modeReadWrite | CFileBase::modeCreate | CFileBase::shareDenyWrite)) { return; } if (strcmp(CPath(Target).GetExtension().c_str(), "cht") == 0) { stdstr_f LineData = stdstr_f("// Project64 Official Cheats Database\r\n"); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); LineData = stdstr_f("// Not for use with PJ64 v1.6 or previous\r\n"); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); LineData = stdstr_f("// ----------------------------------------------------\r\n\r\n"); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); CPath MetaFileName(Directory, "Meta.cht"); CIniFile MetaIniFile(MetaFileName); if (MetaIniFile.IsFileOpen()) { CIniFile::KeyValueData data; MetaIniFile.GetKeyValueData("Meta", data); LineData = stdstr_f("[Meta]\r\n"); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); for (CIniFile::KeyValueData::const_iterator itr = data.begin(); itr != data.end(); itr++) { stdstr DataLine(itr->second); DataLine.Trim("\t ="); LineData = stdstr_f("%s=%s\r\n",itr->first.c_str(), DataLine.c_str()); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); } LineData = stdstr_f("\r\n"); TargetIniFile.Write(LineData.c_str(), (int)LineData.length()); } } RegionSection(TargetIniFile, files, "(J)", "4A"); RegionSection(TargetIniFile, files, "(JU)", "41"); RegionSection(TargetIniFile, files, "(U)", "45"); RegionSection(TargetIniFile, files, "PAL (E)", "50"); RegionSection(TargetIniFile, files, "PAL (A)", "55"); RegionSection(TargetIniFile, files, "PAL (F)", "46"); RegionSection(TargetIniFile, files, "PAL (G)", "44"); RegionSection(TargetIniFile, files, "PAL (I)", "49"); RegionSection(TargetIniFile, files, "PAL (S)", "53"); RegionSection(TargetIniFile, files, "PAL(FGD)", "58"); RegionSection(TargetIniFile, files, "Demo", "0"); } void UpdateNames(const char* Directory, const char* RdbFile) { CIniFile RdbIni(RdbFile); Files files; CPath SearchDir(Directory, "*.cht"); if (SearchDir.FindFirst()) { do { CIniFile CheatFile(SearchDir); CIniFile::SectionList Sections; CheatFile.GetVectorOfSections(Sections); CheatFile.SetCustomSort(CustomSortData); for (size_t i = 0, n = Sections.size(); i < n; i++) { const char * Section = Sections[i].c_str(); std::string Name = RdbIni.GetString(Section, "Good Name", ""); if (Name.empty()) { Name = RdbIni.GetString(Section, "Internal Name", ""); } if (Name.empty()) { continue; } CheatFile.SaveString(Section, "Name", Name.c_str()); } } while (SearchDir.FindNext()); } } uint32_t ConvertXP64Address(uint32_t Address) { uint32_t tmpAddress; tmpAddress = (Address ^ 0x68000000) & 0xFF000000; tmpAddress += ((Address + 0x002B0000) ^ 0x00810000) & 0x00FF0000; tmpAddress += ((Address + 0x00002B00) ^ 0x00008200) & 0x0000FF00; tmpAddress += ((Address + 0x0000002B) ^ 0x00000083) & 0x000000FF; return tmpAddress; } uint8_t ConvertXP64ValueHi(uint8_t Value) { return (Value + 0x2B) ^ 0x84; } uint8_t ConvertXP64ValueLo(uint8_t Value) { return (Value + 0x2B) ^ 0x85; } uint16_t ConvertXP64Value(uint16_t Value) { uint16_t tmpValue; tmpValue = ((Value + 0x2B00) ^ 0x8400) & 0xFF00; tmpValue += ((Value + 0x002B) ^ 0x0085) & 0x00FF; return tmpValue; } bool ConvertCheatOptions(const char * OptionValue, std::string& Options) { const char * ReadPos = strchr(Options.c_str(), '$'); std::string NewOptions; if (ReadPos) { ReadPos += 1; do { NewOptions += NewOptions.empty() ? "$" : ",$"; const char* End = strchr(ReadPos, ','); std::string Item = End != NULL ? std::string(ReadPos, End - ReadPos) : ReadPos; ReadPos = strchr(ReadPos, '$'); if (ReadPos != NULL) { ReadPos += 1; } const char* Name = strchr(Item.c_str(), ' '); if (Name == NULL) { return false; } Name += 1; if (strcmp(OptionValue, "????") == 0) { uint16_t CodeValue = ConvertXP64Value((uint16_t)strtoul(Item.c_str(), 0, 16)); NewOptions += stdstr_f("%04X %s", CodeValue, stdstr(Name).Trim().c_str()); } else if (strcmp(OptionValue, "??XX") == 0) { uint8_t CodeValue = ConvertXP64ValueHi((uint8_t)strtoul(Item.c_str(), 0, 16)); NewOptions += stdstr_f("%02X %s", CodeValue, stdstr(Name).Trim().c_str()); } else if (strcmp(OptionValue, "XX??") == 0) { uint8_t CodeValue = ConvertXP64ValueLo((uint8_t)strtoul(Item.c_str(), 0, 16)); NewOptions += stdstr_f("%02X %s", CodeValue, stdstr(Name).Trim().c_str()); } else { return false; } } while (ReadPos); } Options = NewOptions; return true; } bool ConvertCheatEntry(std::string& CheatEntry, std::string& CheatOptions) { typedef std::vector CodeEntries; size_t StartOfName = CheatEntry.find("\""); if (StartOfName == std::string::npos) { return false; } size_t EndOfName = CheatEntry.find("\"", StartOfName + 1); if (EndOfName == std::string::npos) { return false; } std::string Name = stdstr(CheatEntry.substr(StartOfName + 1, EndOfName - StartOfName - 1)).Trim("\t ,"); CodeEntries Entries; const char* CheatString = &CheatEntry.c_str()[EndOfName + 2]; const char* ReadPos = CheatString; bool ConvertOptions = false; std::string OptionValue; while (ReadPos) { uint32_t CodeCommand = strtoul(ReadPos, 0, 16); ReadPos = strchr(ReadPos, ' '); if (ReadPos == NULL) { break; } ReadPos += 1; std::string ValueStr = ReadPos; const char* ValuePos = ReadPos; ReadPos = strchr(ReadPos, ','); if (ReadPos != NULL) { ValueStr.resize(ReadPos - ValuePos); ReadPos++; } switch (CodeCommand & 0xFF000000) { case 0xE8000000: CodeCommand = (ConvertXP64Address(CodeCommand) & 0xFFFFFF) | 0x80000000; if (strchr(ValueStr.c_str(), '?') != NULL) { if (strncmp(ValueStr.c_str(), "????", 4) == 0) { Entries.push_back(stdstr_f("%08X ????", CodeCommand)); if (!OptionValue.empty() && OptionValue != "????") { return false; } OptionValue = "????"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[2], "??", 2) == 0) { Entries.push_back(stdstr_f("%08X %02X??", CodeCommand, ConvertXP64ValueHi((uint8_t)strtoul(ValueStr.c_str(), 0, 16)))); if (!OptionValue.empty() && OptionValue != "XX??") { return false; } OptionValue = "XX??"; } else { return false; } ConvertOptions = true; } else { Entries.push_back(stdstr_f("%08X %04X", CodeCommand, ConvertXP64Value((uint16_t)strtoul(ValueStr.c_str(), 0, 16)))); } break; case 0xE9000000: CodeCommand = (ConvertXP64Address(CodeCommand) & 0xFFFFFF) | 0x81000000; if (strchr(ValueStr.c_str(), '?') != NULL) { if (strncmp(ValueStr.c_str(), "????", 4) == 0) { Entries.push_back(stdstr_f("%08X ????", CodeCommand)); if (!OptionValue.empty() && OptionValue != "????") { return false; } OptionValue = "????"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[2], "??", 2) == 0) { Entries.push_back(stdstr_f("%08X %02X??", CodeCommand, ConvertXP64ValueHi((uint8_t)strtoul(ValueStr.c_str(), 0, 16)))); if (!OptionValue.empty() && OptionValue != "XX??") { return false; } OptionValue = "XX??"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[0], "??", 2) == 0) { Entries.push_back(stdstr_f("%08X ??%02X", CodeCommand, ConvertXP64ValueLo((uint8_t)strtoul(&(ValueStr.c_str()[2]), 0, 16)))); if (!OptionValue.empty() && OptionValue != "??XX") { return false; } OptionValue = "??XX"; } else { return false; } ConvertOptions = true; } else { Entries.push_back(stdstr_f("%08X %04X", CodeCommand, ConvertXP64Value((uint16_t)strtoul(ValueStr.c_str(), 0, 16)))); } break; case 0x10000000: Entries.push_back(stdstr_f("%08X %s", (CodeCommand & 0xFFFFFF) | 0x80000000, ValueStr.c_str())); if (strchr(ValueStr.c_str(), '?') != NULL) { if (strncmp(ValueStr.c_str(), "????", 4) == 0) { if (!OptionValue.empty() && OptionValue != "????") { return false; } OptionValue = "????"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[2], "??", 2) == 0) { if (!OptionValue.empty() && OptionValue != "XX??") { return false; } OptionValue = "XX??"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[0], "??", 2) == 0) { if (!OptionValue.empty() && OptionValue != "??XX") { return false; } OptionValue = "??XX"; } else { return false; } ConvertOptions = true; } break; case 0x11000000: Entries.push_back(stdstr_f("%08X %s", (CodeCommand & 0xFFFFFF) | 0x81000000, ValueStr.c_str())); if (strchr(ValueStr.c_str(), '?') != NULL) { if (strncmp(ValueStr.c_str(), "????", 4) == 0) { if (!OptionValue.empty() && OptionValue != "????") { return false; } OptionValue = "????"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[2], "??", 2) == 0) { if (!OptionValue.empty() && OptionValue != "XX??") { return false; } OptionValue = "XX??"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[0], "??", 2) == 0) { if (!OptionValue.empty() && OptionValue != "??XX") { return false; } OptionValue = "??XX"; } else { return false; } ConvertOptions = true; return false; } break; case 0x80000000: case 0x81000000: case 0x88000000: case 0x89000000: case 0xA0000000: case 0xA1000000: case 0x50000000: case 0xD0000000: case 0xD1000000: case 0xD2000000: case 0xD3000000: Entries.push_back(stdstr_f("%08X %s", CodeCommand, ValueStr.c_str())); break; default: return false; } } if (Name.length() == 0 || Entries.size() == 0) { return false; } if (ConvertOptions && !ConvertCheatOptions(OptionValue.c_str(), CheatOptions)) { return false; } CheatEntry = stdstr_f("\"%s\"", Name.c_str()); for (CodeEntries::const_iterator itr = Entries.begin(); itr != Entries.end(); itr++) { CheatEntry += stdstr_f(",%s", itr->c_str()); } return true; } void convertGS(const char* Directory) { enum { MaxCheats = 50000, }; CPath SearchDir(Directory, "*.cht"); if (SearchDir.FindFirst()) { do { CIniFile CheatFile(SearchDir); CIniFile::SectionList Sections; CheatFile.GetVectorOfSections(Sections); CheatFile.SetCustomSort(CustomSortData); for (size_t i = 0, n = Sections.size(); i < n; i++) { const char * Section = Sections[i].c_str(); for (uint32_t cheat = 0; cheat < MaxCheats; cheat++) { std::string CheatEntry = CheatFile.GetString(Section, stdstr_f("Cheat%d", cheat).c_str(), ""); if (CheatEntry.empty()) { break; } std::string CheatOptions = CheatFile.GetString(Section, stdstr_f("Cheat%d_O", cheat).c_str(), ""); if (ConvertCheatEntry(CheatEntry, CheatOptions)) { CheatFile.SaveString(Section, stdstr_f("Cheat%d", cheat).c_str(), CheatEntry.c_str()); if (!CheatOptions.empty()) { CheatFile.SaveString(Section, stdstr_f("Cheat%d_O", cheat).c_str(), CheatOptions.c_str()); } } } } } while (SearchDir.FindNext()); } } bool ParseCheatEntry(const stdstr & CheatEntry, const stdstr& CheatOptions, CCheatDetails & Details) { bool HaveOptions; size_t StartOfName = CheatEntry.find("\""); if (StartOfName == std::string::npos) { return false; } size_t EndOfName = CheatEntry.find("\"", StartOfName + 1); if (EndOfName == std::string::npos) { return false; } Details.SetName(CheatEntry.substr(StartOfName + 1, EndOfName - StartOfName - 1).c_str()); const char * CheatString = &CheatEntry.c_str()[EndOfName + 2]; HaveOptions = false; const char * ReadPos = CheatString; bool FirstEntry = true; CCheatDetails::CodeEntries Entries; CCheatDetails::CodeOptions Options; std::string OptionValue; while (ReadPos) { uint32_t CodeCommand = strtoul(ReadPos, 0, 16); ReadPos = strchr(ReadPos, ' '); if (ReadPos == NULL) { break; } ReadPos += 1; std::string ValueStr = ReadPos; const char * ValuePos = ReadPos; ReadPos = strchr(ReadPos, ','); if (ReadPos != NULL) { ValueStr.resize(ReadPos - ValuePos); ReadPos++; } //validate Code Entry switch (CodeCommand & 0xFF000000) { case 0x80000000: case 0x81000000: case 0x88000000: case 0x89000000: case 0xA0000000: case 0xA1000000: case 0xD0000000: case 0xD1000000: case 0xD2000000: case 0xD3000000: if (strchr(ValueStr.c_str(), '?') != NULL) { if (CheatOptions.empty()) { DebugBreak(); return false; } if (strncmp(ValueStr.c_str(), "????", 4) == 0) { if (!OptionValue.empty() && OptionValue != "????") { return false; } OptionValue = "????"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[2], "??", 2) == 0) { if (!OptionValue.empty() && OptionValue != "XX??") { return false; } OptionValue = "XX??"; } else if (ValueStr.length() == 4 && strncmp(&ValueStr.c_str()[0], "??", 2) == 0) { if (!OptionValue.empty() && OptionValue != "??XX") { return false; } OptionValue = "??XX"; } else { return false; } } break; case 0x50000000: if (strchr(ValueStr.c_str(), '?') != NULL) { DebugBreak(); return false; } break; default: DebugBreak(); return false; } CCheatDetails::CodeEntry Entry; Entry.Command = CodeCommand; Entry.Value = ValueStr; Entries.push_back(Entry); FirstEntry = false; } if (!OptionValue.empty()) { uint32_t OptionLen = OptionValue == "????" ? 4 : 2; ReadPos = strchr(CheatOptions.c_str(), '$'); if (ReadPos) { ReadPos += 1; do { const char* End = strchr(ReadPos, ','); std::string Item = End != NULL ? std::string(ReadPos, End - ReadPos) : ReadPos; ReadPos = strchr(ReadPos, '$'); if (ReadPos != NULL) { ReadPos += 1; } const char* Name = strchr(Item.c_str(), ' '); if (Name == NULL) { return false; } if (((uint32_t)(Name - Item.c_str())) != OptionLen) { DebugBreak(); return false; } Name += 1; CCheatDetails::CodeOption Option; Option.Name = stdstr(Name).Trim().c_str(); if (OptionValue == "????") { Option.Value = (uint16_t)strtoul(Item.c_str(), 0, 16); } else if (OptionValue == "??XX" || OptionValue == "XX??") { Option.Value = (uint8_t)strtoul(Item.c_str(), 0, 16); } else { DebugBreak(); return false; } Options.push_back(Option); } while (ReadPos); } } if (!Details.SetEntries(Entries)) { DebugBreak(); return false; } Details.SetOptions(Options); return true; } void ConvertNew(const char * Src, const char * Dest) { CPath SrcDir(Src, ""), DestDir(Dest, ""); if (SrcDir == DestDir) { return; } if (DestDir.DirectoryExists()) { DestDir.Delete(); }; DestDir.DirectoryCreate(); CPath SearchDir(Src, "*.cht"); if (SearchDir.FindFirst()) { do { CPath OutFile(Dest, SearchDir.GetNameExtension()); if (OutFile.Exists()) { OutFile.Delete(); } CCheatFile DstCheatFile(OutFile); CIniFile SrcIniFile(SearchDir); CIniFile::SectionList Sections; SrcIniFile.GetVectorOfSections(Sections); enum { MaxCheats = 50000, }; for (size_t i = 0, n = Sections.size(); i < n; i++) { const char * Section = Sections[i].c_str(); std::string GameName = SrcIniFile.GetString(Section, "Name", ""); DstCheatFile.SetName(Section, GameName.c_str()); for (uint32_t cheat = 0; cheat < MaxCheats; cheat++) { std::string CheatEntry = SrcIniFile.GetString(Section, stdstr_f("Cheat%d", cheat).c_str(), ""); if (CheatEntry.empty()) { break; } std::string CheatOptions = SrcIniFile.GetString(Section, stdstr_f("Cheat%d_O", cheat).c_str(), ""); CCheatDetails Details; if (!ParseCheatEntry(CheatEntry, CheatOptions, Details)) { continue; } std::string CheatNote = SrcIniFile.GetString(Section, stdstr_f("Cheat%d_N", cheat).c_str(), ""); if (!CheatNote.empty()) { Details.SetNote(CheatNote.c_str()); } DstCheatFile.SetCode(Section, Details); } } } while (SearchDir.FindNext()); } } int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpszArgs*/, int /*nWinMode*/) { if (__argc == 4 && strcmp(__argv[1], "-split") == 0 && CPath(__argv[2]).Exists()) { SplitFile(__argv[2], __argv[3]); } if (__argc == 4 && strcmp(__argv[1], "-join") == 0 && CPath(__argv[2],"").DirectoryExists()) { JoinFile(__argv[2], __argv[3]); } if (__argc == 4 && strcmp(__argv[1], "-updateNames") == 0 && CPath(__argv[2], "").DirectoryExists() && CPath(__argv[3]).Exists()) { UpdateNames(__argv[2], __argv[3]); } if (__argc == 3 && strcmp(__argv[1], "-convertGS") == 0 && CPath(__argv[2], "").DirectoryExists()) { convertGS(__argv[2]); } if (__argc == 4 && strcmp(__argv[1], "-convertNew") == 0 && CPath(__argv[2], "").DirectoryExists()) { ConvertNew(__argv[2], __argv[3]); } return 0; }