diff --git a/Project64.sln b/Project64.sln index ebdc9b92f..cc7aedee8 100644 --- a/Project64.sln +++ b/Project64.sln @@ -64,6 +64,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project64-audio", "Source\P EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdateVersion", "Source\UpdateVersion\UpdateVersion.vcxproj", "{1968162C-0793-491D-91A1-81645A24D399}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JoinSettings", "Source\JoinSettings\JoinSettings.vcxproj", "{B2E592F2-F416-4049-BD22-9CA9090242BB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -207,6 +209,14 @@ Global {1968162C-0793-491D-91A1-81645A24D399}.Release|Win32.Build.0 = Release|Win32 {1968162C-0793-491D-91A1-81645A24D399}.Release|x64.ActiveCfg = Release|x64 {1968162C-0793-491D-91A1-81645A24D399}.Release|x64.Build.0 = Release|x64 + {B2E592F2-F416-4049-BD22-9CA9090242BB}.Debug|Win32.ActiveCfg = Debug|Win32 + {B2E592F2-F416-4049-BD22-9CA9090242BB}.Debug|Win32.Build.0 = Debug|Win32 + {B2E592F2-F416-4049-BD22-9CA9090242BB}.Debug|x64.ActiveCfg = Debug|x64 + {B2E592F2-F416-4049-BD22-9CA9090242BB}.Debug|x64.Build.0 = Debug|x64 + {B2E592F2-F416-4049-BD22-9CA9090242BB}.Release|Win32.ActiveCfg = Release|Win32 + {B2E592F2-F416-4049-BD22-9CA9090242BB}.Release|Win32.Build.0 = Release|Win32 + {B2E592F2-F416-4049-BD22-9CA9090242BB}.Release|x64.ActiveCfg = Release|x64 + {B2E592F2-F416-4049-BD22-9CA9090242BB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Common/IniFileClass.cpp b/Source/Common/IniFileClass.cpp index 9c1afda72..9e15a0e87 100644 --- a/Source/Common/IniFileClass.cpp +++ b/Source/Common/IniFileClass.cpp @@ -9,7 +9,8 @@ CIniFileBase::CIniFileBase(CFileBase & FileObject, const char * FileName) : m_InstantFlush(true), m_File(FileObject), m_FileName(FileName), - m_CurrentSectionDirty(false) + m_CurrentSectionDirty(false), + m_SortFunction(NULL) { } @@ -243,16 +244,40 @@ void CIniFileBase::SaveCurrentSection(void) AUTO_PTR LineData(NULL); int len = 0; - for (KeyValueList::iterator iter = m_CurrentSectionData.begin(); iter != m_CurrentSectionData.end(); iter++) + if (m_SortFunction != NULL) { - int newLen = (int)iter->first.length() + (int)iter->second.length() + lineFeedLen + 5; - if (newLen > len) + KeyValueVector data; + for (KeyValueList::iterator iter = m_CurrentSectionData.begin(); iter != m_CurrentSectionData.end(); iter++) { - LineData.reset(new char[newLen]); - len = newLen; + data.push_back(KeyValueItem(&iter->first, &iter->second)); + } + m_SortFunction(data); + for (size_t i = 0, n = data.size(); i < n; i++) + { + KeyValueItem & item = data[i]; + int newLen = (int)(item.first->length()) + (int)item.second->length() + lineFeedLen + 5; + if (newLen > len) + { + LineData.reset(new char[newLen]); + len = newLen; + } + sprintf(LineData.get(), "%s=%s%s", item.first->c_str(), item.second->c_str(), m_LineFeed); + m_File.Write(LineData.get(), (int)strlen(LineData.get())); + } + } + else + { + for (KeyValueList::iterator iter = m_CurrentSectionData.begin(); iter != m_CurrentSectionData.end(); iter++) + { + int newLen = (int)iter->first.length() + (int)iter->second.length() + lineFeedLen + 5; + if (newLen > len) + { + LineData.reset(new char[newLen]); + len = newLen; + } + sprintf(LineData.get(), "%s=%s%s", iter->first.c_str(), iter->second.c_str(), m_LineFeed); + m_File.Write(LineData.get(), (int)strlen(LineData.get())); } - sprintf(LineData.get(), "%s=%s%s", iter->first.c_str(), iter->second.c_str(), m_LineFeed); - m_File.Write(LineData.get(), (int)strlen(LineData.get())); } } m_File.Flush(); @@ -808,6 +833,12 @@ void CIniFileBase::GetKeyValueData(const char * lpSectionName, KeyValueData & Li } while (result >= 0); } +void CIniFileBase::SetCustomSort(SortData SortFunction) +{ + CGuard Guard(m_CS); + m_SortFunction = SortFunction; +} + void CIniFileBase::ClearSectionPosList(long FilePos) { if (FilePos <= 0) diff --git a/Source/Common/IniFileClass.h b/Source/Common/IniFileClass.h index 47236724e..6dc143d58 100644 --- a/Source/Common/IniFileClass.h +++ b/Source/Common/IniFileClass.h @@ -16,6 +16,47 @@ class CIniFileBase { +public: + typedef std::map KeyValueData; + typedef std::vector SectionList; + typedef std::list strlist; + typedef std::pair KeyValueItem; + typedef std::vector KeyValueVector; + typedef void(*SortData)(KeyValueVector &); + + CIniFileBase(CFileBase & FileObject, const char * FileName); + virtual ~CIniFileBase(void); + + bool IsEmpty(); + bool IsFileOpen(void); + bool DeleteSection(const char * lpSectionName); + bool GetString(const char * lpSectionName, const char * lpKeyName, const char * lpDefault, std::string & Value); + std::string GetString(const char * lpSectionName, const char * lpKeyName, const char * lpDefault); + uint32_t GetString(const char * lpSectionName, const char * lpKeyName, const char * lpDefault, char * lpReturnedString, uint32_t nSize); + uint32_t GetNumber(const char * lpSectionName, const char * lpKeyName, uint32_t nDefault); + bool GetNumber(const char * lpSectionName, const char * lpKeyName, uint32_t nDefault, uint32_t & Value); + + virtual void SaveString(const char * lpSectionName, const char * lpKeyName, const char * lpString); + virtual void SaveNumber(const char * lpSectionName, const char * lpKeyName, uint32_t Value); + void SetAutoFlush(bool AutoFlush); + void FlushChanges(void); + bool EntryExists(const char * lpSectionName, const char * lpKeyName); + void GetKeyList(const char * lpSectionName, strlist &List); + void GetKeyValueData(const char * lpSectionName, KeyValueData & List); + void SetCustomSort(SortData SortFunction); + + void GetVectorOfSections(SectionList & sections); + const std::string &GetFileName() { return m_FileName; } + +protected: + void OpenIniFileReadOnly(); + void OpenIniFile(bool bCreate = true); + void SaveCurrentSection(void); + + CFileBase & m_File; + std::string m_FileName; + +private: struct insensitive_compare { bool operator() (const std::string & a, const std::string & b) const @@ -27,17 +68,7 @@ class CIniFileBase typedef std::map FILELOC; typedef FILELOC::iterator FILELOC_ITR; typedef std::map KeyValueList; - -public: - typedef std::map KeyValueData; - typedef std::vector SectionList; - typedef std::list strlist; - -protected: - CFileBase & m_File; - std::string m_FileName; - -private: + std::string m_CurrentSection; bool m_CurrentSectionDirty; int m_CurrentSectionFilePos; // Where in the file is the current Section @@ -51,6 +82,7 @@ private: CriticalSection m_CS; FILELOC m_SectionsPos; + SortData m_SortFunction; void fInsertSpaces(int Pos, int NoOfSpaces); int GetStringFromFile(char * & String, AUTO_PTR &Data, int & MaxDataSize, int & DataSize, int & ReadPos); @@ -58,34 +90,6 @@ private: const char * CleanLine(char * Line); void ClearSectionPosList(long FilePos); -protected: - void OpenIniFileReadOnly(); - void OpenIniFile(bool bCreate = true); - void SaveCurrentSection(void); - -public: - CIniFileBase(CFileBase & FileObject, const char * FileName); - virtual ~CIniFileBase(void); - - bool IsEmpty(); - bool IsFileOpen(void); - bool DeleteSection(const char * lpSectionName); - bool GetString(const char * lpSectionName, const char * lpKeyName, const char * lpDefault, std::string & Value); - std::string GetString(const char * lpSectionName, const char * lpKeyName, const char * lpDefault); - uint32_t GetString(const char * lpSectionName, const char * lpKeyName, const char * lpDefault, char * lpReturnedString, uint32_t nSize); - uint32_t GetNumber(const char * lpSectionName, const char * lpKeyName, uint32_t nDefault); - bool GetNumber(const char * lpSectionName, const char * lpKeyName, uint32_t nDefault, uint32_t & Value); - - virtual void SaveString(const char * lpSectionName, const char * lpKeyName, const char * lpString); - virtual void SaveNumber(const char * lpSectionName, const char * lpKeyName, uint32_t Value); - void SetAutoFlush(bool AutoFlush); - void FlushChanges(void); - bool EntryExists(const char * lpSectionName, const char * lpKeyName); - void GetKeyList(const char * lpSectionName, strlist &List); - void GetKeyValueData(const char * lpSectionName, KeyValueData & List); - - void GetVectorOfSections(SectionList & sections); - const std::string &GetFileName() { return m_FileName; } }; template diff --git a/Source/JoinSettings/JoinSettings.vcxproj b/Source/JoinSettings/JoinSettings.vcxproj new file mode 100644 index 000000000..1366d1b13 --- /dev/null +++ b/Source/JoinSettings/JoinSettings.vcxproj @@ -0,0 +1,53 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {B2E592F2-F416-4049-BD22-9CA9090242BB} + JoinSettings + Win32Proj + + + + Application + + + + + + + + + + Windows + + + NotUsing + + + + + + + + {b4a4b994-9111-42b1-93c2-6f1ca8bc4421} + + + + \ No newline at end of file diff --git a/Source/JoinSettings/JoinSettings.vcxproj.filters b/Source/JoinSettings/JoinSettings.vcxproj.filters new file mode 100644 index 000000000..0d8d9e457 --- /dev/null +++ b/Source/JoinSettings/JoinSettings.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Source/JoinSettings/main.cpp b/Source/JoinSettings/main.cpp new file mode 100644 index 000000000..04a0180ea --- /dev/null +++ b/Source/JoinSettings/main.cpp @@ -0,0 +1,280 @@ +#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("/", "-"); + 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"); +} + +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]); + } + return 0; +}