mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
472 lines
9.5 KiB
C++
472 lines
9.5 KiB
C++
|
#include "main.h"
|
||
|
#include "./cacheGroup.h"
|
||
|
#include "./cacheRecord.h"
|
||
|
#include "./cacheManager.h"
|
||
|
|
||
|
#include <wininet.h>
|
||
|
#include <shlwapi.h>
|
||
|
#include <strsafe.h>
|
||
|
#include <algorithm>
|
||
|
|
||
|
CacheGroup::CacheGroup(LPCWSTR pszName)
|
||
|
: ref(1), name(NULL), owner(NULL)
|
||
|
{
|
||
|
name = Plugin_CopyString(pszName);
|
||
|
}
|
||
|
|
||
|
CacheGroup::~CacheGroup()
|
||
|
{
|
||
|
Clear();
|
||
|
|
||
|
Plugin_FreeString(name);
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::CreateInstance(LPCWSTR pszName, CacheGroup **instance)
|
||
|
{
|
||
|
if (NULL == instance) return E_POINTER;
|
||
|
*instance = NULL;
|
||
|
|
||
|
*instance = new CacheGroup(pszName);
|
||
|
if (NULL == *instance) return E_OUTOFMEMORY;
|
||
|
|
||
|
return S_OK;
|
||
|
|
||
|
}
|
||
|
|
||
|
size_t CacheGroup::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement((LONG*)&ref);
|
||
|
}
|
||
|
|
||
|
size_t CacheGroup::Release()
|
||
|
{
|
||
|
if (0 == ref)
|
||
|
return ref;
|
||
|
|
||
|
LONG r = InterlockedDecrement((LONG*)&ref);
|
||
|
if (0 == r)
|
||
|
delete(this);
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
int CacheGroup::QueryInterface(GUID interface_guid, void **object)
|
||
|
{
|
||
|
if (NULL == object) return E_POINTER;
|
||
|
|
||
|
if (IsEqualIID(interface_guid, IFC_OmCacheGroup))
|
||
|
*object = static_cast<ifc_omcachegroup*>(this);
|
||
|
else
|
||
|
{
|
||
|
*object = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
if (NULL == *object)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::SetOwner(CacheManager *group)
|
||
|
{
|
||
|
owner = group;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::GetName(LPWSTR pszBuffer, UINT cchBufferMax)
|
||
|
{
|
||
|
if (NULL == pszBuffer || 0 == cchBufferMax)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
return StringCchCopyEx(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS);
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::IsEqualName(LPCWSTR pszGroup)
|
||
|
{
|
||
|
if (NULL == pszGroup)
|
||
|
return (NULL == name) ? S_OK : S_FALSE;
|
||
|
|
||
|
if (NULL == name) return S_FALSE;
|
||
|
|
||
|
INT result = CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszGroup, -1, name, -1);
|
||
|
if (0 == result)
|
||
|
{
|
||
|
DWORD error = GetLastError();
|
||
|
return HRESULT_FROM_WIN32(error);
|
||
|
}
|
||
|
return (CSTR_EQUAL == result) ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::IsEqual(CacheGroup *group)
|
||
|
{
|
||
|
return (NULL != group) ? IsEqualName(group->name) : E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::IsEmpty()
|
||
|
{
|
||
|
return (0 == recordList.size()) ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::Delete(LPCWSTR pszName)
|
||
|
{
|
||
|
HRESULT hr = S_FALSE;
|
||
|
size_t index = recordList.size();
|
||
|
|
||
|
while(index--)
|
||
|
{
|
||
|
CacheRecord *record = recordList[index];
|
||
|
if (NULL != record && S_OK == record->IsEqualName(pszName))
|
||
|
{
|
||
|
recordList.erase(recordList.begin() + index);
|
||
|
record->Release();
|
||
|
hr = S_OK;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::Clear()
|
||
|
{
|
||
|
size_t index = recordList.size();
|
||
|
|
||
|
while(index--)
|
||
|
{
|
||
|
CacheRecord *record = recordList[index];
|
||
|
if (NULL != record) record->Release();
|
||
|
}
|
||
|
|
||
|
recordList.clear();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
__inline static int __cdecl CacheGroup_RecordSearch(const void *elem1, const void *elem2)
|
||
|
{
|
||
|
int r = ((CacheRecord*)elem2)->CompareTo((LPCWSTR)elem1);
|
||
|
return -r;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::Find(LPCWSTR pszName, BOOL fInsertMissing, CacheRecord **recordOut, BOOL *created)
|
||
|
{
|
||
|
if (NULL != created)
|
||
|
*created = FALSE;
|
||
|
|
||
|
if (NULL == recordOut)
|
||
|
return E_POINTER;
|
||
|
|
||
|
HRESULT hr = S_FALSE;
|
||
|
size_t index = recordList.size();
|
||
|
if (0 != index)
|
||
|
{
|
||
|
//CacheRecord *rec = (CacheRecord*)bsearch(pszName, recordList.at(0), recordList.size(), sizeof(CacheRecord*), CacheGroup_RecordSearch);
|
||
|
auto it = std::find_if(recordList.begin(), recordList.end(),
|
||
|
[&](CacheRecord* upT) -> bool
|
||
|
{
|
||
|
return upT->CompareTo(pszName) == 0;
|
||
|
}
|
||
|
);
|
||
|
if (it != recordList.end())
|
||
|
{
|
||
|
*recordOut = *it;
|
||
|
(*recordOut)->AddRef();
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (S_FALSE == hr && FALSE != fInsertMissing)
|
||
|
{
|
||
|
hr = CacheRecord::CreateInstance(pszName, NULL, 0, recordOut);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
recordList.push_back(*recordOut);
|
||
|
Sort();
|
||
|
|
||
|
(*recordOut)->AddRef();
|
||
|
(*recordOut)->SetOwner(this);
|
||
|
|
||
|
if (NULL != created)
|
||
|
*created = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
*recordOut = NULL;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::GetPath(LPWSTR pszBuffer, UINT cchBufferMax)
|
||
|
{
|
||
|
if (NULL == pszBuffer || 0 == cchBufferMax)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL != owner)
|
||
|
{
|
||
|
hr = owner->GetPath(pszBuffer, cchBufferMax);
|
||
|
if (SUCCEEDED(hr) && NULL != name)
|
||
|
{
|
||
|
if (FALSE == PathAppend(pszBuffer, name))
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*pszBuffer = L'\0';
|
||
|
hr = E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
static HRESULT CacheGroup_FormatStoreData(LPWSTR pszBuffer, size_t cchBufferMax, LPCWSTR pszPath, UINT *cchLength)
|
||
|
{
|
||
|
if (NULL == pszBuffer)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
size_t remaining = cchBufferMax;
|
||
|
HRESULT hr;
|
||
|
hr = StringCchCopyEx(pszBuffer, remaining, L"path=", &pszBuffer, &remaining, 0);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
|
||
|
hr = StringCchCopyEx(pszBuffer, remaining, pszPath, &pszBuffer, &remaining, 0);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
|
||
|
if (0 == remaining)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
remaining--;
|
||
|
pszBuffer++;
|
||
|
*pszBuffer = L'\0';
|
||
|
|
||
|
if (NULL != cchLength)
|
||
|
*cchLength = (UINT)(cchBufferMax - remaining) + 1;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::Store(LPCWSTR pszName, LPCWSTR pszPath)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
WCHAR szBuffer[2048] = {0};
|
||
|
|
||
|
hr = GetPath(szBuffer, ARRAYSIZE(szBuffer));
|
||
|
if (FAILED(hr)) return hr;
|
||
|
|
||
|
Plugin_EnsurePathExist(szBuffer);
|
||
|
|
||
|
if (FALSE == PathAppend(szBuffer, L"cache.ini"))
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
LPSTR pathAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, szBuffer, -1, NULL, NULL);
|
||
|
if (NULL == pathAnsi) return E_OUTOFMEMORY;
|
||
|
|
||
|
LPSTR nameAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, pszName, -1, NULL, NULL);
|
||
|
if (NULL == nameAnsi) return E_OUTOFMEMORY;
|
||
|
|
||
|
LPSTR dataAnsi = NULL;
|
||
|
if (NULL != pszPath)
|
||
|
{
|
||
|
UINT cchData;
|
||
|
hr = CacheGroup_FormatStoreData(szBuffer, ARRAYSIZE(szBuffer), pszPath, &cchData);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
dataAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, szBuffer, cchData, NULL, NULL);
|
||
|
if (NULL == dataAnsi)
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr) && 0 == WritePrivateProfileSectionA(nameAnsi, dataAnsi, pathAnsi))
|
||
|
{
|
||
|
DWORD error = GetLastError();
|
||
|
hr = HRESULT_FROM_WIN32(error);
|
||
|
}
|
||
|
|
||
|
Plugin_FreeAnsiString(dataAnsi);
|
||
|
Plugin_FreeAnsiString(nameAnsi);
|
||
|
Plugin_FreeAnsiString(pathAnsi);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::Load()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
WCHAR szBuffer[4096] = {0};
|
||
|
|
||
|
hr = GetPath(szBuffer, ARRAYSIZE(szBuffer));
|
||
|
if (FAILED(hr)) return hr;
|
||
|
|
||
|
if (FALSE == PathAppend(szBuffer, L"cache.ini"))
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
HANDLE hFile = CreateFile(szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||
|
if (INVALID_HANDLE_VALUE == hFile)
|
||
|
{
|
||
|
DWORD error = GetLastError();
|
||
|
return HRESULT_FROM_WIN32(error);
|
||
|
}
|
||
|
|
||
|
DWORD read = 0;
|
||
|
CHAR szLine[INTERNET_MAX_URL_LENGTH + 3] = {0};
|
||
|
WCHAR szUnicode[ARRAYSIZE(szLine)] = {0};
|
||
|
UINT lineIndex = 0;
|
||
|
CacheRecord *record = NULL;
|
||
|
UINT recordSet = 0;
|
||
|
size_t inserted = 0;
|
||
|
|
||
|
RecordList cleanupList;
|
||
|
|
||
|
while (0 != ReadFile(hFile, szBuffer, sizeof(szBuffer), &read, NULL))
|
||
|
{
|
||
|
LPCSTR cursor = (LPCSTR)szBuffer;
|
||
|
LPCSTR end = cursor + read;
|
||
|
|
||
|
for(;;)
|
||
|
{
|
||
|
if (cursor >= end)
|
||
|
break;
|
||
|
|
||
|
if (cursor == end || ('\r' == *cursor && '\n' == *(cursor+1)))
|
||
|
{
|
||
|
szLine[lineIndex] = '\0';
|
||
|
|
||
|
if (lineIndex > 0)
|
||
|
{
|
||
|
if ('[' == szLine[0] && ']' == szLine[lineIndex-1])
|
||
|
{
|
||
|
if (NULL != record)
|
||
|
{
|
||
|
if (0 != (0x00000001 & recordSet))
|
||
|
{
|
||
|
recordList.push_back(record);
|
||
|
inserted++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cleanupList.push_back(record);
|
||
|
}
|
||
|
|
||
|
record = NULL;
|
||
|
}
|
||
|
|
||
|
szLine[lineIndex-1] = '\0';
|
||
|
if (0 != MultiByteToWideChar(CP_UTF8, 0, szLine + 1, -1, szUnicode, ARRAYSIZE(szUnicode)) &&
|
||
|
SUCCEEDED(CacheRecord::CreateInstance(szUnicode, NULL, 0, &record)))
|
||
|
{
|
||
|
record->SetOwner(this);
|
||
|
recordSet = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const char kw_path[] = "path=";
|
||
|
UINT cchKey = ARRAYSIZE(kw_path) - 1;
|
||
|
if (NULL != record &&
|
||
|
lineIndex > cchKey &&
|
||
|
CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, kw_path, cchKey, szLine, cchKey) &&
|
||
|
0 != MultiByteToWideChar(CP_UTF8, 0, szLine + cchKey, -1, szUnicode, ARRAYSIZE(szUnicode)))
|
||
|
{
|
||
|
if(SUCCEEDED(record->SetPath(szUnicode)) &&
|
||
|
SUCCEEDED(record->GetPath(szUnicode, ARRAYSIZE(szUnicode))) &&
|
||
|
FALSE != PathFileExists(szUnicode))
|
||
|
{
|
||
|
recordSet |= 0x00000001;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
lineIndex = 0;
|
||
|
cursor += 2;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (lineIndex < ARRAYSIZE(szLine) - 2)
|
||
|
{
|
||
|
szLine[lineIndex++] = *cursor;
|
||
|
}
|
||
|
|
||
|
cursor++;
|
||
|
}
|
||
|
|
||
|
if (0 == read)
|
||
|
{
|
||
|
if (NULL != record)
|
||
|
{
|
||
|
if (0 != (0x00000001 & recordSet))
|
||
|
{
|
||
|
recordList.push_back(record);
|
||
|
inserted++;
|
||
|
}
|
||
|
else
|
||
|
record->Release();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
CloseHandle(hFile);
|
||
|
|
||
|
if (0 != inserted)
|
||
|
{
|
||
|
Sort();
|
||
|
}
|
||
|
|
||
|
size_t i = cleanupList.size();
|
||
|
if (0 != i)
|
||
|
{
|
||
|
while (i--)
|
||
|
{
|
||
|
aTRACE_LINE("ADD CACHE CLEANUP!!!!");
|
||
|
cleanupList[i]->Release();
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
__inline static int __cdecl CacheGroup_RecordComparer(const void *elem1, const void *elem2)
|
||
|
{
|
||
|
return CacheRecord::Compare((CacheRecord*)elem1, (CacheRecord*)elem2);
|
||
|
}
|
||
|
|
||
|
__inline static bool __cdecl CacheGroup_RecordComparer_V2(const void* elem1, const void* elem2)
|
||
|
{
|
||
|
return CacheGroup_RecordComparer(elem1, elem2) < 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CacheGroup::Sort()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
if (0 == recordList.size())
|
||
|
{
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//qsort(recordList.first(), recordList.size(), sizeof(CacheRecord*), CacheGroup_RecordComparer);
|
||
|
std::sort(recordList.begin(), recordList.end(), CacheGroup_RecordComparer_V2);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
#define CBCLASS CacheGroup
|
||
|
START_DISPATCH;
|
||
|
CB(ADDREF, AddRef)
|
||
|
CB(RELEASE, Release)
|
||
|
CB(QUERYINTERFACE, QueryInterface)
|
||
|
CB(API_GETNAME, GetName)
|
||
|
CB(API_FIND, Find)
|
||
|
CB(API_DELETE, Delete)
|
||
|
CB(API_CLEAR, Clear)
|
||
|
|
||
|
END_DISPATCH;
|
||
|
#undef CBCLASS
|