1 /* 2 * PROJECT: ReactOS Applications Manager 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Config parser 5 * COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org) 6 * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com) 7 * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) 8 * Copyright 2021 Mark Jansen <mark.jansen@reactos.org> 9 */ 10 #include "rapps.h" 11 #include <debug.h> 12 13 struct CLocaleSections 14 { 15 CStringW Locale; 16 CStringW LocaleNeutral; 17 CStringW Section; 18 }; 19 20 struct CSectionNames 21 { 22 CLocaleSections ArchSpecific; 23 CLocaleSections ArchNeutral; 24 }; 25 static CSectionNames g_Names; 26 27 28 static 29 ATL::CStringW GetINIFullPath(const ATL::CStringW& FileName) 30 { 31 ATL::CStringW szDir; 32 ATL::CStringW szBuffer; 33 34 GetStorageDirectory(szDir); 35 szBuffer.Format(L"%ls\\rapps\\%ls", szDir.GetString(), FileName.GetString()); 36 37 return szBuffer; 38 } 39 40 CConfigParser::CConfigParser(const ATL::CStringW& FileName) 41 : szConfigPath(GetINIFullPath(FileName)) 42 { 43 CacheINI(); 44 } 45 46 void CConfigParser::ReadSection(ATL::CStringW& Buffer, const ATL::CStringW& Section, BOOL isArch) 47 { 48 DWORD len = 512; 49 DWORD result; 50 51 do 52 { 53 len *= 2; 54 55 result = GetPrivateProfileSectionW(Section, Buffer.GetBuffer(len), len, szConfigPath); 56 Buffer.ReleaseBuffer(result); 57 } while (result == len - 2); 58 59 len = 0; 60 while (len < result) 61 { 62 // Explicitly use the null terminator! 63 CString tmp = Buffer.GetBuffer() + len; 64 if (tmp.GetLength() > 0) 65 { 66 len += tmp.GetLength() + 1; 67 68 int idx = tmp.Find('='); 69 if (idx >= 0) 70 { 71 CString key = tmp.Left(idx); 72 73 #ifndef _M_IX86 74 // On non-x86 architecture we need the architecture specific URL 75 if (!isArch && key == "URLDownload") 76 { 77 continue; 78 } 79 #endif 80 81 // Is this key already present from a more specific translation? 82 if (m_Keys.FindKey(key) >= 0) 83 { 84 continue; 85 } 86 87 CString value = tmp.Mid(idx+1); 88 m_Keys.Add(key, value); 89 } 90 else 91 { 92 DPRINT1("ERROR: invalid key/value pair: '%S'\n", tmp.GetString()); 93 } 94 } 95 else 96 { 97 break; 98 } 99 } 100 } 101 102 VOID CConfigParser::CacheINI() 103 { 104 // Cache section names 105 if (g_Names.ArchSpecific.Locale.IsEmpty()) 106 { 107 CString szLocaleID; 108 const INT cchLocaleSize = 5; 109 110 GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE, szLocaleID.GetBuffer(cchLocaleSize), cchLocaleSize); 111 szLocaleID.ReleaseBuffer(); 112 CString INISectionLocale = L"Section." + szLocaleID; 113 114 g_Names.ArchSpecific.Locale = INISectionLocale + L"." CurrentArchitecture; 115 g_Names.ArchNeutral.Locale = INISectionLocale; 116 117 // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part 118 if (szLocaleID.GetLength() >= 2) 119 { 120 g_Names.ArchSpecific.LocaleNeutral = L"Section." + szLocaleID.Right(2) + L"." CurrentArchitecture; 121 g_Names.ArchNeutral.LocaleNeutral = L"Section." + szLocaleID.Right(2); 122 } 123 124 g_Names.ArchSpecific.Section = L"Section." CurrentArchitecture; 125 g_Names.ArchNeutral.Section = L"Section"; 126 } 127 128 // Use a shared buffer so that we don't have to re-allocate it every time 129 CStringW Buffer; 130 131 ReadSection(Buffer, g_Names.ArchSpecific.Locale, TRUE); 132 if (!g_Names.ArchSpecific.LocaleNeutral.IsEmpty()) 133 { 134 ReadSection(Buffer, g_Names.ArchSpecific.LocaleNeutral, TRUE); 135 } 136 ReadSection(Buffer, g_Names.ArchSpecific.Section, TRUE); 137 138 139 ReadSection(Buffer, g_Names.ArchNeutral.Locale, FALSE); 140 if (!g_Names.ArchNeutral.LocaleNeutral.IsEmpty()) 141 { 142 ReadSection(Buffer, g_Names.ArchNeutral.LocaleNeutral, FALSE); 143 } 144 ReadSection(Buffer, g_Names.ArchNeutral.Section, FALSE); 145 } 146 147 BOOL CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString) 148 { 149 int nIndex = m_Keys.FindKey(KeyName); 150 if (nIndex >= 0) 151 { 152 ResultString = m_Keys.GetValueAt(nIndex); 153 return TRUE; 154 } 155 156 ResultString.Empty(); 157 return FALSE; 158 } 159 160 BOOL CConfigParser::GetInt(const ATL::CStringW& KeyName, INT& iResult) 161 { 162 ATL::CStringW Buffer; 163 164 iResult = 0; 165 166 // grab the text version of our entry 167 if (!GetString(KeyName, Buffer)) 168 return FALSE; 169 170 if (Buffer.IsEmpty()) 171 return FALSE; 172 173 // convert it to an actual integer 174 iResult = StrToIntW(Buffer.GetString()); 175 176 // we only care about values > 0 177 return (iResult > 0); 178 } 179