cacheGroup.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. #include "main.h"
  2. #include "./cacheGroup.h"
  3. #include "./cacheRecord.h"
  4. #include "./cacheManager.h"
  5. #include <wininet.h>
  6. #include <shlwapi.h>
  7. #include <strsafe.h>
  8. #include <algorithm>
  9. CacheGroup::CacheGroup(LPCWSTR pszName)
  10. : ref(1), name(NULL), owner(NULL)
  11. {
  12. name = Plugin_CopyString(pszName);
  13. }
  14. CacheGroup::~CacheGroup()
  15. {
  16. Clear();
  17. Plugin_FreeString(name);
  18. }
  19. HRESULT CacheGroup::CreateInstance(LPCWSTR pszName, CacheGroup **instance)
  20. {
  21. if (NULL == instance) return E_POINTER;
  22. *instance = NULL;
  23. *instance = new CacheGroup(pszName);
  24. if (NULL == *instance) return E_OUTOFMEMORY;
  25. return S_OK;
  26. }
  27. size_t CacheGroup::AddRef()
  28. {
  29. return InterlockedIncrement((LONG*)&ref);
  30. }
  31. size_t CacheGroup::Release()
  32. {
  33. if (0 == ref)
  34. return ref;
  35. LONG r = InterlockedDecrement((LONG*)&ref);
  36. if (0 == r)
  37. delete(this);
  38. return r;
  39. }
  40. int CacheGroup::QueryInterface(GUID interface_guid, void **object)
  41. {
  42. if (NULL == object) return E_POINTER;
  43. if (IsEqualIID(interface_guid, IFC_OmCacheGroup))
  44. *object = static_cast<ifc_omcachegroup*>(this);
  45. else
  46. {
  47. *object = NULL;
  48. return E_NOINTERFACE;
  49. }
  50. if (NULL == *object)
  51. return E_UNEXPECTED;
  52. AddRef();
  53. return S_OK;
  54. }
  55. HRESULT CacheGroup::SetOwner(CacheManager *group)
  56. {
  57. owner = group;
  58. return S_OK;
  59. }
  60. HRESULT CacheGroup::GetName(LPWSTR pszBuffer, UINT cchBufferMax)
  61. {
  62. if (NULL == pszBuffer || 0 == cchBufferMax)
  63. return E_INVALIDARG;
  64. return StringCchCopyEx(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS);
  65. }
  66. HRESULT CacheGroup::IsEqualName(LPCWSTR pszGroup)
  67. {
  68. if (NULL == pszGroup)
  69. return (NULL == name) ? S_OK : S_FALSE;
  70. if (NULL == name) return S_FALSE;
  71. INT result = CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszGroup, -1, name, -1);
  72. if (0 == result)
  73. {
  74. DWORD error = GetLastError();
  75. return HRESULT_FROM_WIN32(error);
  76. }
  77. return (CSTR_EQUAL == result) ? S_OK : S_FALSE;
  78. }
  79. HRESULT CacheGroup::IsEqual(CacheGroup *group)
  80. {
  81. return (NULL != group) ? IsEqualName(group->name) : E_INVALIDARG;
  82. }
  83. HRESULT CacheGroup::IsEmpty()
  84. {
  85. return (0 == recordList.size()) ? S_OK : S_FALSE;
  86. }
  87. HRESULT CacheGroup::Delete(LPCWSTR pszName)
  88. {
  89. HRESULT hr = S_FALSE;
  90. size_t index = recordList.size();
  91. while(index--)
  92. {
  93. CacheRecord *record = recordList[index];
  94. if (NULL != record && S_OK == record->IsEqualName(pszName))
  95. {
  96. recordList.erase(recordList.begin() + index);
  97. record->Release();
  98. hr = S_OK;
  99. break;
  100. }
  101. }
  102. return hr;
  103. }
  104. HRESULT CacheGroup::Clear()
  105. {
  106. size_t index = recordList.size();
  107. while(index--)
  108. {
  109. CacheRecord *record = recordList[index];
  110. if (NULL != record) record->Release();
  111. }
  112. recordList.clear();
  113. return S_OK;
  114. }
  115. __inline static int __cdecl CacheGroup_RecordSearch(const void *elem1, const void *elem2)
  116. {
  117. int r = ((CacheRecord*)elem2)->CompareTo((LPCWSTR)elem1);
  118. return -r;
  119. }
  120. HRESULT CacheGroup::Find(LPCWSTR pszName, BOOL fInsertMissing, CacheRecord **recordOut, BOOL *created)
  121. {
  122. if (NULL != created)
  123. *created = FALSE;
  124. if (NULL == recordOut)
  125. return E_POINTER;
  126. HRESULT hr = S_FALSE;
  127. size_t index = recordList.size();
  128. if (0 != index)
  129. {
  130. //CacheRecord *rec = (CacheRecord*)bsearch(pszName, recordList.at(0), recordList.size(), sizeof(CacheRecord*), CacheGroup_RecordSearch);
  131. auto it = std::find_if(recordList.begin(), recordList.end(),
  132. [&](CacheRecord* upT) -> bool
  133. {
  134. return upT->CompareTo(pszName) == 0;
  135. }
  136. );
  137. if (it != recordList.end())
  138. {
  139. *recordOut = *it;
  140. (*recordOut)->AddRef();
  141. hr = S_OK;
  142. }
  143. }
  144. if (S_FALSE == hr && FALSE != fInsertMissing)
  145. {
  146. hr = CacheRecord::CreateInstance(pszName, NULL, 0, recordOut);
  147. if (SUCCEEDED(hr))
  148. {
  149. recordList.push_back(*recordOut);
  150. Sort();
  151. (*recordOut)->AddRef();
  152. (*recordOut)->SetOwner(this);
  153. if (NULL != created)
  154. *created = TRUE;
  155. }
  156. }
  157. if (S_OK != hr)
  158. *recordOut = NULL;
  159. return hr;
  160. }
  161. HRESULT CacheGroup::GetPath(LPWSTR pszBuffer, UINT cchBufferMax)
  162. {
  163. if (NULL == pszBuffer || 0 == cchBufferMax)
  164. return E_INVALIDARG;
  165. HRESULT hr;
  166. if (NULL != owner)
  167. {
  168. hr = owner->GetPath(pszBuffer, cchBufferMax);
  169. if (SUCCEEDED(hr) && NULL != name)
  170. {
  171. if (FALSE == PathAppend(pszBuffer, name))
  172. hr = E_OUTOFMEMORY;
  173. }
  174. }
  175. else
  176. {
  177. *pszBuffer = L'\0';
  178. hr = E_UNEXPECTED;
  179. }
  180. return hr;
  181. }
  182. static HRESULT CacheGroup_FormatStoreData(LPWSTR pszBuffer, size_t cchBufferMax, LPCWSTR pszPath, UINT *cchLength)
  183. {
  184. if (NULL == pszBuffer)
  185. return E_INVALIDARG;
  186. size_t remaining = cchBufferMax;
  187. HRESULT hr;
  188. hr = StringCchCopyEx(pszBuffer, remaining, L"path=", &pszBuffer, &remaining, 0);
  189. if (FAILED(hr)) return hr;
  190. hr = StringCchCopyEx(pszBuffer, remaining, pszPath, &pszBuffer, &remaining, 0);
  191. if (FAILED(hr)) return hr;
  192. if (0 == remaining)
  193. return E_OUTOFMEMORY;
  194. remaining--;
  195. pszBuffer++;
  196. *pszBuffer = L'\0';
  197. if (NULL != cchLength)
  198. *cchLength = (UINT)(cchBufferMax - remaining) + 1;
  199. return S_OK;
  200. }
  201. HRESULT CacheGroup::Store(LPCWSTR pszName, LPCWSTR pszPath)
  202. {
  203. HRESULT hr;
  204. WCHAR szBuffer[2048] = {0};
  205. hr = GetPath(szBuffer, ARRAYSIZE(szBuffer));
  206. if (FAILED(hr)) return hr;
  207. Plugin_EnsurePathExist(szBuffer);
  208. if (FALSE == PathAppend(szBuffer, L"cache.ini"))
  209. return E_OUTOFMEMORY;
  210. LPSTR pathAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, szBuffer, -1, NULL, NULL);
  211. if (NULL == pathAnsi) return E_OUTOFMEMORY;
  212. LPSTR nameAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, pszName, -1, NULL, NULL);
  213. if (NULL == nameAnsi) return E_OUTOFMEMORY;
  214. LPSTR dataAnsi = NULL;
  215. if (NULL != pszPath)
  216. {
  217. UINT cchData;
  218. hr = CacheGroup_FormatStoreData(szBuffer, ARRAYSIZE(szBuffer), pszPath, &cchData);
  219. if (SUCCEEDED(hr))
  220. {
  221. dataAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, szBuffer, cchData, NULL, NULL);
  222. if (NULL == dataAnsi)
  223. hr = E_OUTOFMEMORY;
  224. }
  225. }
  226. if (SUCCEEDED(hr) && 0 == WritePrivateProfileSectionA(nameAnsi, dataAnsi, pathAnsi))
  227. {
  228. DWORD error = GetLastError();
  229. hr = HRESULT_FROM_WIN32(error);
  230. }
  231. Plugin_FreeAnsiString(dataAnsi);
  232. Plugin_FreeAnsiString(nameAnsi);
  233. Plugin_FreeAnsiString(pathAnsi);
  234. return hr;
  235. }
  236. HRESULT CacheGroup::Load()
  237. {
  238. HRESULT hr;
  239. WCHAR szBuffer[4096] = {0};
  240. hr = GetPath(szBuffer, ARRAYSIZE(szBuffer));
  241. if (FAILED(hr)) return hr;
  242. if (FALSE == PathAppend(szBuffer, L"cache.ini"))
  243. return E_OUTOFMEMORY;
  244. HANDLE hFile = CreateFile(szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  245. if (INVALID_HANDLE_VALUE == hFile)
  246. {
  247. DWORD error = GetLastError();
  248. return HRESULT_FROM_WIN32(error);
  249. }
  250. DWORD read = 0;
  251. CHAR szLine[INTERNET_MAX_URL_LENGTH + 3] = {0};
  252. WCHAR szUnicode[ARRAYSIZE(szLine)] = {0};
  253. UINT lineIndex = 0;
  254. CacheRecord *record = NULL;
  255. UINT recordSet = 0;
  256. size_t inserted = 0;
  257. RecordList cleanupList;
  258. while (0 != ReadFile(hFile, szBuffer, sizeof(szBuffer), &read, NULL))
  259. {
  260. LPCSTR cursor = (LPCSTR)szBuffer;
  261. LPCSTR end = cursor + read;
  262. for(;;)
  263. {
  264. if (cursor >= end)
  265. break;
  266. if (cursor == end || ('\r' == *cursor && '\n' == *(cursor+1)))
  267. {
  268. szLine[lineIndex] = '\0';
  269. if (lineIndex > 0)
  270. {
  271. if ('[' == szLine[0] && ']' == szLine[lineIndex-1])
  272. {
  273. if (NULL != record)
  274. {
  275. if (0 != (0x00000001 & recordSet))
  276. {
  277. recordList.push_back(record);
  278. inserted++;
  279. }
  280. else
  281. {
  282. cleanupList.push_back(record);
  283. }
  284. record = NULL;
  285. }
  286. szLine[lineIndex-1] = '\0';
  287. if (0 != MultiByteToWideChar(CP_UTF8, 0, szLine + 1, -1, szUnicode, ARRAYSIZE(szUnicode)) &&
  288. SUCCEEDED(CacheRecord::CreateInstance(szUnicode, NULL, 0, &record)))
  289. {
  290. record->SetOwner(this);
  291. recordSet = 0;
  292. }
  293. }
  294. else
  295. {
  296. const char kw_path[] = "path=";
  297. UINT cchKey = ARRAYSIZE(kw_path) - 1;
  298. if (NULL != record &&
  299. lineIndex > cchKey &&
  300. CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, kw_path, cchKey, szLine, cchKey) &&
  301. 0 != MultiByteToWideChar(CP_UTF8, 0, szLine + cchKey, -1, szUnicode, ARRAYSIZE(szUnicode)))
  302. {
  303. if(SUCCEEDED(record->SetPath(szUnicode)) &&
  304. SUCCEEDED(record->GetPath(szUnicode, ARRAYSIZE(szUnicode))) &&
  305. FALSE != PathFileExists(szUnicode))
  306. {
  307. recordSet |= 0x00000001;
  308. }
  309. }
  310. }
  311. }
  312. lineIndex = 0;
  313. cursor += 2;
  314. continue;
  315. }
  316. if (lineIndex < ARRAYSIZE(szLine) - 2)
  317. {
  318. szLine[lineIndex++] = *cursor;
  319. }
  320. cursor++;
  321. }
  322. if (0 == read)
  323. {
  324. if (NULL != record)
  325. {
  326. if (0 != (0x00000001 & recordSet))
  327. {
  328. recordList.push_back(record);
  329. inserted++;
  330. }
  331. else
  332. record->Release();
  333. }
  334. break;
  335. }
  336. }
  337. CloseHandle(hFile);
  338. if (0 != inserted)
  339. {
  340. Sort();
  341. }
  342. size_t i = cleanupList.size();
  343. if (0 != i)
  344. {
  345. while (i--)
  346. {
  347. aTRACE_LINE("ADD CACHE CLEANUP!!!!");
  348. cleanupList[i]->Release();
  349. }
  350. }
  351. return S_OK;
  352. }
  353. __inline static int __cdecl CacheGroup_RecordComparer(const void *elem1, const void *elem2)
  354. {
  355. return CacheRecord::Compare((CacheRecord*)elem1, (CacheRecord*)elem2);
  356. }
  357. __inline static bool __cdecl CacheGroup_RecordComparer_V2(const void* elem1, const void* elem2)
  358. {
  359. return CacheGroup_RecordComparer(elem1, elem2) < 0;
  360. }
  361. HRESULT CacheGroup::Sort()
  362. {
  363. HRESULT hr;
  364. if (0 == recordList.size())
  365. {
  366. hr = S_FALSE;
  367. }
  368. else
  369. {
  370. //qsort(recordList.first(), recordList.size(), sizeof(CacheRecord*), CacheGroup_RecordComparer);
  371. std::sort(recordList.begin(), recordList.end(), CacheGroup_RecordComparer_V2);
  372. hr = S_OK;
  373. }
  374. return hr;
  375. }
  376. #define CBCLASS CacheGroup
  377. START_DISPATCH;
  378. CB(ADDREF, AddRef)
  379. CB(RELEASE, Release)
  380. CB(QUERYINTERFACE, QueryInterface)
  381. CB(API_GETNAME, GetName)
  382. CB(API_FIND, Find)
  383. CB(API_DELETE, Delete)
  384. CB(API_CLEAR, Clear)
  385. END_DISPATCH;
  386. #undef CBCLASS