aboutsummaryrefslogtreecommitdiff
path: root/Src/omBrowser/loaderIni.cpp
diff options
context:
space:
mode:
authorJean-Francois Mauguit <jfmauguit@mac.com>2024-09-24 09:03:25 -0400
committerGitHub <noreply@github.com>2024-09-24 09:03:25 -0400
commitbab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/omBrowser/loaderIni.cpp
parent4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff)
parent20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff)
downloadwinamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/omBrowser/loaderIni.cpp')
-rw-r--r--Src/omBrowser/loaderIni.cpp657
1 files changed, 657 insertions, 0 deletions
diff --git a/Src/omBrowser/loaderIni.cpp b/Src/omBrowser/loaderIni.cpp
new file mode 100644
index 00000000..63c55cad
--- /dev/null
+++ b/Src/omBrowser/loaderIni.cpp
@@ -0,0 +1,657 @@
+#include "main.h"
+#include "./loaderIni.h"
+#include "./service.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omstorage.h"
+#include "./ifc_omstoragehandler.h"
+#include "./ifc_omstoragehandlerenum.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define OMS_GROUP "OnlineService"
+#define OMS_ID "id"
+#define OMS_NAME "name"
+#define OMS_URL "url"
+#define OMS_ICON "icon"
+#define OMS_FLAGS "flags"
+#define OMS_RATING "rating"
+#define OMS_VERSION "version"
+#define OMS_DESCRIPTION "description"
+#define OMS_AUTHORFIRST "authorFirst"
+#define OMS_AUTHORLAST "authorLast"
+#define OMS_PUBLISHED "publishedDate"
+#define OMS_UPDATED "updatedDate"
+#define OMS_THUMBNAIL "thumbnail"
+#define OMS_SCREENSHOT "screenshot"
+#define OMS_GENERATION "generation"
+
+typedef HRESULT (ifc_omservice::*SVCSTRGET)(LPWSTR, UINT);
+typedef HRESULT (ifc_omservice::*SVCUINTGET)(UINT*);
+typedef HRESULT (ifc_omservicedetails::*DETAILGET)(LPWSTR, UINT);
+
+#define WRITE_OBJECT_STR(__mofifiedFlag, __class, __getterType, __object, __getter, __key)\
+ {if (0 != (ifc_omserviceeditor::##__mofifiedFlag & modified)) {\
+ HRESULT r = WriteObjectStr<__class, __getterType>((__key), (__object), &##__class::##__getter);\
+ if (FAILED(r)) {hr = E_FAIL;} else { saved |= ifc_omserviceeditor::##__mofifiedFlag; }}}
+
+#define WRITE_OBJECT_STR_FALLBACK(__mofifiedFlag, __class, __getterType, __object, __getter1, __getter2, __key)\
+ {if (0 != (ifc_omserviceeditor::##__mofifiedFlag & modified)) {\
+ HRESULT r = WriteObjectStr<__class, __getterType>((__key), (__object), &##__class::##__getter1);\
+ if (S_FALSE == r) r = WriteObjectStr<__class, __getterType>((__key), (__object), &##__class::##__getter2);\
+ if (FAILED(r)) {hr = E_FAIL;} else { saved |= ifc_omserviceeditor::##__mofifiedFlag; }}}
+
+#define WRITE_OBJECT_UINT(__mofifiedFlag, __class, __getterType, __object, __getter, __key, __writeFlags)\
+ {if (0 != (ifc_omserviceeditor::##__mofifiedFlag & modified)) {\
+ HRESULT r = WriteObjectUInt<__class, __getterType>((__key), (__object), &##__class::##__getter, __writeFlags);\
+ if (FAILED(r)) {hr = E_FAIL;} else { saved |= ifc_omserviceeditor::##__mofifiedFlag; }}}
+
+#define WRITE_SERVICE_STR(__mofifiedFlag, __getter, __key) WRITE_OBJECT_STR(__mofifiedFlag, ifc_omservice, SVCSTRGET, service, __getter, __key)
+#define WRITE_SERVICE_STR_FALLBACK(__mofifiedFlag, __getter1, __getter2, __key) WRITE_OBJECT_STR_FALLBACK(__mofifiedFlag, ifc_omservice, SVCSTRGET, service, __getter1, __getter2, __key)
+#define WRITE_SERVICE_UINT(__mofifiedFlag, __getter, __key, __writeZero) WRITE_OBJECT_UINT(__mofifiedFlag, ifc_omservice, SVCUINTGET, service, __getter, __key, __writeZero)
+#define WRITE_DETAILS_STR(__mofifiedFlag, __getter, __key) WRITE_OBJECT_STR(__mofifiedFlag, ifc_omservicedetails, DETAILGET, details, __getter, __key)
+
+LoaderIni::LoaderIni()
+ : bufferAnsi(NULL), bufferAnsiMax(0), buffer(NULL), bufferMax(0), handlerEnum(NULL)
+{
+ memset(pathAnsi, 0, sizeof(pathAnsi));
+}
+
+LoaderIni::~LoaderIni()
+{
+ //Plugin_FreeAnsiString(pathAnsi);
+ Plugin_FreeAnsiString(bufferAnsi);
+ Plugin_FreeString(buffer);
+
+ if (NULL != handlerEnum)
+ handlerEnum->Release();
+}
+
+HRESULT LoaderIni::Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omservice **serviceOut)
+{
+ if (NULL == serviceOut)
+ return E_POINTER;
+
+ *serviceOut = NULL;
+
+ HRESULT hr = MakeAnsiPath(pszAddress);
+ if (FAILED(hr)) return hr;
+
+ UINT id = ReadInt(OMS_ID, 0);
+ if (0 == id) return E_UNEXPECTED;
+
+ OmService *service;
+
+ hr = OmService::CreateInstance(id, host, &service);
+ if (FAILED(hr)) return hr;
+
+ ifc_omserviceeditor *editor;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor)))
+ editor->BeginUpdate();
+ else
+ editor = NULL;
+
+ service->SetAddress(pszAddress);
+
+ #define READ_SERVICE_STR(__key, __putter)\
+ { LPCSTR value; HRESULT r = ReadAnsi((__key), NULL, &value);\
+ if (SUCCEEDED(r)) { if ('\0' != *value) r = service->##__putter((LPCWSTR)value, TRUE); }\
+ if (FAILED(r)) hr = E_FAIL;}
+
+ READ_SERVICE_STR(OMS_NAME, SetName);
+ READ_SERVICE_STR(OMS_URL, SetUrl);
+ READ_SERVICE_STR(OMS_ICON, SetIcon);
+
+ UINT val = ReadInt(OMS_FLAGS, 0);
+ if (0 != val) service->SetFlags(val, val & ~ifc_omservice::RuntimeFlagsMask);
+
+ val = ReadInt(OMS_RATING, 0);
+ if (0 != val) service->SetRating(val);
+
+ val = ReadInt(OMS_VERSION, 0);
+ if (0 != val) service->SetVersion(val);
+
+ val = ReadInt(OMS_GENERATION, 0);
+ if (0 != val) service->SetGeneration(val);
+
+ READ_SERVICE_STR(OMS_DESCRIPTION, SetDescription);
+ READ_SERVICE_STR(OMS_AUTHORFIRST, SetAuthorFirst);
+ READ_SERVICE_STR(OMS_AUTHORLAST, SetAuthorLast);
+ READ_SERVICE_STR(OMS_PUBLISHED, SetPublished);
+ READ_SERVICE_STR(OMS_UPDATED, SetUpdated);
+ READ_SERVICE_STR(OMS_THUMBNAIL, SetThumbnail);
+ READ_SERVICE_STR(OMS_SCREENSHOT, SetScreenshot);
+
+ if (NULL != handlerEnum)
+ {
+ handlerEnum->Reset();
+ ifc_omstoragehandler *storageHandler;
+ while (S_OK == handlerEnum->Next(1, &storageHandler, NULL))
+ {
+ LPCWSTR pszKey;
+ if (SUCCEEDED(storageHandler->GetKey(&pszKey)))
+ {
+ if (SUCCEEDED(WideCharToAnsiBuffer(CP_UTF8, 0, pszKey, -1, NULL, NULL)))
+ {
+ LPCSTR keyAnsi = bufferAnsi;
+ LPCSTR valueAnsi;
+ if (SUCCEEDED(ReadAnsi(keyAnsi, NULL, &valueAnsi)) &&
+ NULL != valueAnsi && L'\0' != *valueAnsi)
+ {
+ if (SUCCEEDED(MultiByteToBuffer(CP_UTF8, 0, valueAnsi, -1)))
+ storageHandler->Invoke(service, pszKey, buffer);
+ }
+ }
+ }
+ storageHandler->Release();
+ }
+ }
+
+ if (NULL != editor)
+ {
+ editor->SetModified(0, ((UINT)-1));
+ editor->EndUpdate();
+ editor->Release();
+ }
+
+ *serviceOut = service;
+
+ return hr;
+}
+
+HRESULT LoaderIni::Reload(ifc_omservice *service)
+{
+ if (NULL == service)
+ return E_INVALIDARG;
+
+ HRESULT hr = RequestBuffer(&buffer, &bufferMax, MAX_PATH * 2);
+ if (FAILED(hr)) return hr;
+
+ hr = service->GetAddress(buffer, bufferMax);
+ if (FAILED(hr)) return hr;
+ if (L'\0' == *buffer) return E_UNEXPECTED;
+
+ hr = MakeAnsiPath(buffer);
+ if (FAILED(hr)) return hr;
+
+ UINT id = ReadInt(OMS_ID, 0);
+ if (id != service->GetId()) return E_UNEXPECTED;
+
+ ifc_omserviceeditor *editor;
+ hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor);
+ if (SUCCEEDED(hr))
+ {
+ #define READ_EDITOR_STR(__key, __putter)\
+ { LPCSTR value; HRESULT r = ReadAnsi((__key), NULL, &value);\
+ if (SUCCEEDED(r)) { r = editor->##__putter((LPCWSTR)value, TRUE); }\
+ if (FAILED(r)) hr = E_FAIL;}
+
+ editor->BeginUpdate();
+
+ READ_EDITOR_STR(OMS_NAME, SetName);
+ READ_EDITOR_STR(OMS_URL, SetUrl);
+ READ_EDITOR_STR(OMS_ICON, SetIcon);
+
+ UINT val;
+ val = ReadInt(OMS_FLAGS, 0);
+ editor->SetFlags(val, val & ~ifc_omservice::RuntimeFlagsMask);
+
+ val = ReadInt(OMS_RATING, 0);
+ editor->SetRating(val);
+
+ val = ReadInt(OMS_VERSION, 0);
+ editor->SetVersion(val);
+
+ val = ReadInt(OMS_GENERATION, 0);
+ editor->SetGeneration(val);
+
+ READ_EDITOR_STR(OMS_DESCRIPTION, SetDescription);
+ READ_EDITOR_STR(OMS_AUTHORFIRST, SetAuthorFirst);
+ READ_EDITOR_STR(OMS_AUTHORLAST, SetAuthorLast);
+ READ_EDITOR_STR(OMS_PUBLISHED, SetPublished);
+ READ_EDITOR_STR(OMS_UPDATED, SetUpdated);
+ READ_EDITOR_STR(OMS_THUMBNAIL, SetThumbnail);
+ READ_EDITOR_STR(OMS_SCREENSHOT, SetScreenshot);
+ }
+ else
+ {
+ editor = NULL;
+ }
+
+ if (NULL != handlerEnum)
+ {
+ handlerEnum->Reset();
+ ifc_omstoragehandler *storageHandler;
+ while (S_OK == handlerEnum->Next(1, &storageHandler, NULL))
+ {
+ LPCWSTR pszKey;
+ if (SUCCEEDED(storageHandler->GetKey(&pszKey)))
+ {
+ if (SUCCEEDED(WideCharToAnsiBuffer(CP_UTF8, 0, pszKey, -1, NULL, NULL)))
+ {
+ LPCSTR keyAnsi = bufferAnsi;
+ LPCSTR valueAnsi;
+ if (SUCCEEDED(ReadAnsi(keyAnsi, NULL, &valueAnsi)) &&
+ NULL != valueAnsi && L'\0' != *valueAnsi)
+ {
+ if (SUCCEEDED(MultiByteToBuffer(CP_UTF8, 0, valueAnsi, -1)))
+ storageHandler->Invoke(service, pszKey, buffer);
+ }
+ }
+ }
+ storageHandler->Release();
+ }
+ }
+
+ if (NULL != editor)
+ {
+ editor->EndUpdate();
+ editor->Release();
+ }
+
+ return hr;
+}
+
+HRESULT LoaderIni::Save(ifc_omservice *service, UINT flags)
+{
+ if(NULL == service)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ BOOL generatedName;
+
+ hr = RequestBuffer(&buffer, &bufferMax, MAX_PATH * 2);
+ if (FAILED(hr)) return hr;
+
+ hr = GetServicePath(service, buffer, bufferMax, &generatedName);
+ if (FAILED(hr)) return hr;
+
+ if (FALSE != generatedName)
+ service->SetAddress(buffer);
+
+ hr = MakeAnsiPath(buffer);
+ if (FAILED(hr)) return hr;
+
+ if (0 == (ifc_omstorage::saveModifiedOnly & flags))
+ WritePrivateProfileSectionA(OMS_GROUP, NULL, pathAnsi);
+
+ UINT modified = ((UINT)-1);
+ UINT saved = 0;
+ if (0 != (ifc_omstorage::saveModifiedOnly & flags))
+ {
+ ifc_omserviceeditor *editor;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor)))
+ {
+ editor->GetModified(&modified);
+ editor->Release();
+
+ if (0 == modified)
+ return S_FALSE;
+ }
+ }
+
+ if (FAILED(WriteUint(OMS_ID, service->GetId(), flagWriteZero)))
+ return E_FAIL;
+
+ WRITE_SERVICE_STR(modifiedName, GetName, OMS_NAME);
+ WRITE_SERVICE_STR_FALLBACK(modifiedUrl, GetUrlDirect, GetUrl, OMS_URL);
+ WRITE_SERVICE_STR(modifiedIcon, GetIcon, OMS_ICON);
+
+ if (0 != (ifc_omserviceeditor::modifiedFlags & modified))
+ {
+ UINT val;
+ if (SUCCEEDED(service->GetFlags(&val)) && SUCCEEDED(WriteUint(OMS_FLAGS, val & ~ifc_omservice::RuntimeFlagsMask, flagHexMode)))
+ saved |= ifc_omserviceeditor::modifiedFlags;
+ }
+
+ WRITE_SERVICE_UINT(modifiedRating, GetRating, OMS_RATING, flagWriteNormal);
+ WRITE_SERVICE_UINT(modifiedVersion, GetVersion, OMS_VERSION, flagWriteNormal);
+ WRITE_SERVICE_UINT(modifiedGeneration, GetGeneration, OMS_GENERATION, flagWriteNormal);
+
+ ifc_omservicedetails *details;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceDetails, (void**)&details)))
+ {
+ WRITE_DETAILS_STR(modifiedDescription, GetDescription, OMS_DESCRIPTION);
+ WRITE_DETAILS_STR(modifiedAuthorFirst, GetAuthorFirst, OMS_AUTHORFIRST);
+ WRITE_DETAILS_STR(modifiedAuthorLast, GetAuthorLast, OMS_AUTHORLAST);
+ WRITE_DETAILS_STR(modifiedPublished, GetPublished, OMS_PUBLISHED);
+ WRITE_DETAILS_STR(modifiedUpdated, GetUpdated, OMS_UPDATED);
+ WRITE_DETAILS_STR(modifiedThumbnail, GetThumbnail, OMS_THUMBNAIL);
+ WRITE_DETAILS_STR(modifiedScreenshot, GetScreenshot, OMS_SCREENSHOT);
+ details->Release();
+ }
+
+ if (0 != (ifc_omstorage::saveClearModified & flags) && 0 != saved)
+ {
+ ifc_omserviceeditor *editor;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor)))
+ {
+ editor->SetModified(0, saved);
+ editor->Release();
+ }
+ }
+
+ return hr;
+}
+
+HRESULT LoaderIni::RegisterHandlers(ifc_omstoragehandlerenum *enumerator)
+{
+ if (NULL != handlerEnum)
+ handlerEnum->Release();
+
+ handlerEnum = enumerator;
+ if (NULL != handlerEnum)
+ handlerEnum->AddRef();
+
+ return S_OK;
+}
+
+HRESULT LoaderIni::RequestAnsiBuffer(LPSTR *ppBuffer, UINT *pBufferMax, UINT requestSize)
+{
+ if (*pBufferMax >= requestSize)
+ return S_OK;
+
+ UINT size = (0 != *pBufferMax) ? (*pBufferMax * 2) : 128;
+ while (size < requestSize) size = size*2;
+
+ Plugin_FreeAnsiString(*ppBuffer);
+ *ppBuffer = Plugin_MallocAnsiString(size);
+ if (NULL == *ppBuffer)
+ {
+ *ppBuffer = 0;
+ *pBufferMax = 0;
+ return E_OUTOFMEMORY;
+ }
+
+ *pBufferMax = size;
+ return S_OK;
+}
+
+HRESULT LoaderIni::RequestBuffer(LPWSTR *ppBuffer, UINT *pBufferMax, UINT requestSize)
+{
+ if (*pBufferMax >= requestSize)
+ return S_OK;
+
+ UINT size = (0 != *pBufferMax) ? (*pBufferMax * 2) : 128;
+ while (size < requestSize) size = size*2;
+
+ Plugin_FreeString(*ppBuffer);
+ *ppBuffer = Plugin_MallocString(size);
+ if (NULL == *ppBuffer)
+ {
+ *ppBuffer = 0;
+ *pBufferMax = 0;
+ return E_OUTOFMEMORY;
+ }
+
+ *pBufferMax = size;
+ return S_OK;
+}
+
+HRESULT LoaderIni::MakeAnsiPath(LPCWSTR pszAddress)
+{
+ BOOL fUsedDefaultChar = FALSE;
+ WCHAR szShort[MAX_PATH] = {0};
+
+ UINT cch = WideCharToMultiByte(CP_ACP, 0, pszAddress, -1, NULL, 0, NULL, &fUsedDefaultChar);
+ if (0 == cch || FALSE != fUsedDefaultChar)
+ {
+ cch = GetShortPathName(pszAddress, szShort, ARRAYSIZE(szShort));
+ if (0 != cch)
+ {
+ pszAddress = szShort;
+ cch = WideCharToMultiByte(CP_ACP, 0, pszAddress, -1, NULL, 0, NULL, &fUsedDefaultChar);
+ }
+
+ if (0 == cch || FALSE != fUsedDefaultChar)
+ {
+ if (NULL != pathAnsi) *pathAnsi = L'\0';
+ return E_FAIL;
+ }
+ }
+
+ cch = WideCharToMultiByte(CP_ACP, 0, pszAddress, cch, pathAnsi, MAX_PATH, NULL, NULL);
+ if (0 == cch)
+ {
+ DWORD errorCode = GetLastError();
+ *pathAnsi = L'\0';
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+ pathAnsi[cch] = '\0';
+ return S_OK;
+}
+
+HRESULT LoaderIni::GetServicePath(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax, BOOL *fGenerated)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ pszBuffer[0] = L'\0';
+
+ if (NULL == service) return E_INVALIDARG;
+
+ HRESULT hr;
+ WCHAR szPath[MAX_PATH * 2] = {0};
+ hr = service->GetAddress(szPath, ARRAYSIZE(szPath));
+ if (FAILED(hr)) return hr;
+
+ ifc_omservicehost *host = NULL;
+ ifc_omservicehostext *hostExt;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceHostExt, (void**)&hostExt)))
+ {
+ if (FAILED(hostExt->GetHost(&host)))
+ host = NULL;
+ hostExt->Release();
+ }
+
+ BOOL nameGenerated = FALSE;
+ if (L'\0' == *szPath)
+ {
+ hr = (NULL != host) ?
+ host->GetDefaultName(service, szPath, ARRAYSIZE(szPath)) :
+ StringCchPrintf(szPath, ARRAYSIZE(szPath), L"omService_{%010u}", service->GetId());
+
+ if (L'\0' == *szPath)
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+
+ nameGenerated = TRUE;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = Plugin_ResolveRelativePath(szPath, host, pszBuffer, cchBufferMax);
+ if (SUCCEEDED(hr) && FALSE != nameGenerated)
+ {
+ LPWSTR pExt = PathFindExtension(pszBuffer);
+ if (pExt != pszBuffer && L'.' == *pExt && SUCCEEDED(StringCchCopy(szPath, ARRAYSIZE(szPath), pExt)))
+ {
+ UINT pExtMax = cchBufferMax - (UINT)(pExt - pszBuffer);
+ UINT attempt = 0;
+ while (FALSE != PathFileExists(pszBuffer))
+ {
+ if (FAILED(StringCchPrintf(pExt, pExtMax, L"(%u)%s", ++attempt, szPath)))
+ {
+ StringCchCopy(pExt, pExtMax, szPath);
+ break;
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) && SUCCEEDED(StringCchCopy(szPath, ARRAYSIZE(szPath), pszBuffer)))
+ {
+ PathRemoveFileSpec(szPath);
+ Plugin_EnsurePathExist(szPath);
+ }
+ }
+
+ if (FAILED(hr))
+ pszBuffer[0] = L'\0';
+
+ if (NULL != host)
+ host->Release();
+
+ if (NULL != fGenerated)
+ *fGenerated = nameGenerated;
+
+ return hr;
+}
+
+HRESULT LoaderIni::WideCharToAnsiBuffer(UINT codePage, DWORD flags, LPCWSTR pszWideChar, INT cchWideChar, LPCSTR pDefaultChar, BOOL *pUsedDefaultChar)
+{
+ UINT cch = WideCharToMultiByte(codePage, flags, pszWideChar, cchWideChar, NULL, 0, pDefaultChar, pUsedDefaultChar);
+ if (0 == cch)
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ HRESULT hr = RequestAnsiBuffer(&bufferAnsi, &bufferAnsiMax, cch);
+ if (FAILED(hr)) return hr;
+
+ if (0 == WideCharToMultiByte(codePage, flags, pszWideChar, cchWideChar, bufferAnsi, bufferAnsiMax, pDefaultChar, pUsedDefaultChar))
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ return S_OK;
+}
+
+HRESULT LoaderIni::MultiByteToBuffer(UINT codePage, DWORD flags, LPCSTR pszMultiByte, INT cbMultiByte)
+{
+ UINT cch = MultiByteToWideChar(codePage, flags, pszMultiByte, cbMultiByte, NULL, 0);
+ if (0 == cch)
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ HRESULT hr = RequestBuffer(&buffer, &bufferMax, cch);
+ if (FAILED(hr)) return hr;
+
+ if (0 == MultiByteToWideChar(codePage, flags, pszMultiByte, cbMultiByte, buffer, bufferMax))
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ return S_OK;
+}
+
+HRESULT LoaderIni::Write(LPCSTR pszKey, LPCWSTR pszValue)
+{
+ LPCSTR valueAnsi;
+ if (NULL == pszValue) valueAnsi = NULL;
+ else if (L'\0' == *pszValue) valueAnsi = '\0';
+ else
+ {
+ HRESULT hr = WideCharToAnsiBuffer(CP_UTF8, 0, pszValue, -1, NULL, NULL);
+ if (FAILED(hr)) return hr;
+ valueAnsi = bufferAnsi;
+ }
+
+ return WriteAnsi(pszKey, valueAnsi);
+}
+
+HRESULT LoaderIni::WriteAnsi(LPCSTR pszKey, LPCSTR pszValue)
+{
+ if (FALSE == WritePrivateProfileStringA(OMS_GROUP, pszKey, pszValue, pathAnsi))
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+ return S_OK;
+}
+
+HRESULT LoaderIni::WriteUint(LPCSTR pszKey, UINT uValue, UINT flags)
+{
+ HRESULT hr;
+ CHAR szBuffer[16] = {0}, *pVal;
+
+ if (0 == uValue && 0 == (flagWriteZero & flags))
+ {
+ hr = S_OK;
+ pVal = NULL;
+ }
+ else
+ {
+ hr = StringCchPrintfA(szBuffer, ARRAYSIZE(szBuffer), ((0 == (flagHexMode & flags)) ? "%u" : "0x%08X"), uValue);
+ pVal = szBuffer;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = WriteAnsi(pszKey, pVal);
+ }
+ return hr;
+}
+
+HRESULT LoaderIni::ReadAnsi(LPCSTR pszKey, LPCSTR pszDefault, LPCSTR *ppszValue)
+{
+ HRESULT hr;
+ if (NULL == bufferAnsi)
+ {
+ hr = RequestAnsiBuffer(&bufferAnsi, &bufferAnsiMax, 2);
+ if (FAILED(hr))
+ {
+ *ppszValue = pszDefault;
+ return hr;
+ }
+ }
+
+ for(;;)
+ {
+ UINT copied = GetPrivateProfileStringA(OMS_GROUP, pszKey, pszDefault, bufferAnsi, bufferAnsiMax, pathAnsi);
+ if (copied != bufferAnsiMax - 1) break;
+
+ hr = RequestAnsiBuffer(&bufferAnsi, &bufferAnsiMax, bufferAnsiMax * 2);
+ if (FAILED(hr))
+ {
+ *ppszValue = pszDefault;
+ return hr;
+ }
+
+ }
+ *ppszValue = bufferAnsi;
+ return S_OK;
+}
+
+UINT LoaderIni::ReadInt(LPCSTR pszKey, UINT nDefault)
+{
+ return GetPrivateProfileIntA(OMS_GROUP, pszKey, nDefault, pathAnsi);
+}
+
+template <class Object, class Getter>
+HRESULT LoaderIni::WriteObjectStr(LPCSTR pszKey, Object *object, Getter getter)
+{
+ HRESULT hr;
+
+ if (NULL == buffer)
+ {
+ hr = RequestBuffer(&buffer, &bufferMax, 256);
+ if (FAILED(hr)) return hr;
+ }
+ for (;;)
+ {
+ hr = (object->*getter)(buffer, bufferMax);
+ if (SUCCEEDED(hr)) break;
+ if (E_NOTIMPL == hr) return S_FALSE;
+ if (OMSVC_E_INSUFFICIENT_BUFFER != hr) return hr;
+
+ hr = RequestBuffer(&buffer, &bufferMax, bufferMax * 2);
+ if (FAILED(hr)) return hr;
+ }
+ return Write(pszKey, buffer);
+}
+
+template <class Object, class Getter>
+HRESULT LoaderIni::WriteObjectUInt(LPCSTR pszKey, Object *object, Getter getter, UINT flags)
+{
+ UINT val;
+ HRESULT hr = (object->*getter)(&val);
+ if (FAILED(hr))
+ {
+ return (E_NOTIMPL == hr) ? S_FALSE : hr;
+ }
+ return WriteUint(pszKey, val, flags);
+} \ No newline at end of file