cacheRecord.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. #include "main.h"
  2. #include "./cacheRecord.h"
  3. #include "./cacheDownloader.h"
  4. #include "./cacheGroup.h"
  5. #include "./ifc_omcachecallback.h"
  6. #include <shlwapi.h>
  7. #include <strsafe.h>
  8. CacheRecord::CacheRecord(LPCWSTR pszName, LPCWSTR pszAddress, UINT uFlags)
  9. : ref(1), owner(NULL), name(NULL), path(NULL), flags(uFlags), downloader(NULL), callbackList(NULL)
  10. {
  11. name = Plugin_CopyString(pszName);
  12. path = Plugin_CopyString(pszAddress);
  13. InitializeCriticalSection(&lock);
  14. }
  15. CacheRecord::~CacheRecord()
  16. {
  17. Plugin_FreeString(name);
  18. Plugin_FreeString(path);
  19. EnterCriticalSection(&lock);
  20. if (NULL != downloader)
  21. {
  22. downloader->SetOwner(NULL);
  23. downloader->Release();
  24. }
  25. if (NULL != callbackList)
  26. {
  27. size_t index = callbackList->size();
  28. while(index--)
  29. {
  30. ifc_omcachecallback *callback = callbackList->at(index);
  31. if (NULL != callback) callback->Release();
  32. }
  33. delete(callbackList);
  34. }
  35. LeaveCriticalSection(&lock);
  36. DeleteCriticalSection(&lock);
  37. }
  38. HRESULT CacheRecord::CreateInstance(LPCWSTR pszName, LPCWSTR pszAddress, UINT uFlags, CacheRecord **instance)
  39. {
  40. if (NULL == instance) return E_POINTER;
  41. *instance = NULL;
  42. if (NULL == pszName || L'\0' == *pszName) return E_INVALIDARG;
  43. *instance = new CacheRecord(pszName, pszAddress, uFlags);
  44. if (NULL == *instance) return E_OUTOFMEMORY;
  45. return S_OK;
  46. }
  47. INT CacheRecord::Compare(CacheRecord *record1, CacheRecord *record2)
  48. {
  49. if (NULL == record1 || NULL == record2)
  50. return (INT)(INT_PTR)(record1 - record2);
  51. return record1->CompareTo(record2->name);
  52. }
  53. size_t CacheRecord::AddRef()
  54. {
  55. return InterlockedIncrement((LONG*)&ref);
  56. }
  57. size_t CacheRecord::Release()
  58. {
  59. if (0 == ref)
  60. return ref;
  61. LONG r = InterlockedDecrement((LONG*)&ref);
  62. if (0 == r)
  63. delete(this);
  64. return r;
  65. }
  66. int CacheRecord::QueryInterface(GUID interface_guid, void **object)
  67. {
  68. if (NULL == object) return E_POINTER;
  69. if (IsEqualIID(interface_guid, IFC_OmCacheRecord))
  70. *object = static_cast<ifc_omcacherecord*>(this);
  71. else
  72. {
  73. *object = NULL;
  74. return E_NOINTERFACE;
  75. }
  76. if (NULL == *object)
  77. return E_UNEXPECTED;
  78. AddRef();
  79. return S_OK;
  80. }
  81. HRESULT CacheRecord::SetOwner(CacheGroup *group)
  82. {
  83. EnterCriticalSection(&lock);
  84. owner = group;
  85. LeaveCriticalSection(&lock);
  86. return S_OK;
  87. }
  88. HRESULT CacheRecord::GetName(LPWSTR pszBuffer, UINT cchBufferMax)
  89. {
  90. if (NULL == pszBuffer || 0 == cchBufferMax)
  91. return E_INVALIDARG;
  92. return StringCchCopyEx(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS);
  93. }
  94. HRESULT CacheRecord::GetPath(LPWSTR pszBuffer, UINT cchBufferMax)
  95. {
  96. if (NULL == pszBuffer || 0 == cchBufferMax)
  97. return E_INVALIDARG;
  98. HRESULT hr;
  99. EnterCriticalSection(&lock);
  100. if (NULL == path)
  101. {
  102. *pszBuffer = L'\0';
  103. if (NULL != downloader)
  104. {
  105. hr = E_PENDING;
  106. }
  107. else if (0 != (flagDownloadFailed & flags))
  108. {
  109. hr = E_FAIL;
  110. }
  111. else if (NULL != name && L'\0' != *name && PathIsURL(name) &&
  112. CSTR_EQUAL != CompareString(CSTR_INVARIANT, NORM_IGNORECASE, name, 6, L"res://", 6))
  113. {
  114. hr = Download();
  115. if (SUCCEEDED(hr)) hr = E_PENDING;
  116. }
  117. else
  118. {
  119. hr = E_FAIL;
  120. }
  121. }
  122. else if (FALSE == PathIsRelative(path))
  123. {
  124. hr = StringCchCopy(pszBuffer, cchBufferMax, path);
  125. }
  126. else
  127. {
  128. if (NULL == owner)
  129. {
  130. hr = E_FAIL;
  131. }
  132. else if (FAILED(owner->GetPath(pszBuffer, cchBufferMax)) ||
  133. FALSE == PathAppend(pszBuffer, path))
  134. {
  135. hr = E_OUTOFMEMORY;
  136. }
  137. else
  138. {
  139. hr = S_OK;
  140. }
  141. }
  142. LeaveCriticalSection(&lock);
  143. return hr;
  144. }
  145. HRESULT CacheRecord::SetPath(LPCWSTR pszPath)
  146. {
  147. EnterCriticalSection(&lock);
  148. if (NULL != downloader)
  149. {
  150. downloader->Abort();
  151. downloader->Release();
  152. downloader = NULL;
  153. }
  154. Plugin_FreeString(path);
  155. if (NULL == pszPath)
  156. {
  157. path = NULL;
  158. }
  159. else
  160. {
  161. INT cchCommon = 0;
  162. if (0 != owner)
  163. {
  164. WCHAR szBase[MAX_PATH*2] = {0};
  165. if (SUCCEEDED(owner->GetPath(szBase, ARRAYSIZE(szBase))))
  166. cchCommon = PathCommonPrefix(szBase, pszPath, NULL);
  167. }
  168. if (0 != cchCommon)
  169. {
  170. LPCWSTR p = pszPath + cchCommon;
  171. INT cchSource = lstrlenW(p) + 1/* \0 */;
  172. path = Plugin_MallocString(cchSource + 1 /*to add '.'*/);
  173. if (NULL != path)
  174. {
  175. *path = L'.';
  176. CopyMemory(path + 1, p, sizeof(WCHAR) * cchSource);
  177. }
  178. }
  179. else
  180. {
  181. path = Plugin_CopyString(pszPath);
  182. }
  183. if (NULL == path) return E_OUTOFMEMORY;
  184. }
  185. if (0 == (flagNoStore & flags) && NULL != owner)
  186. owner->Store(name, path);
  187. if (NULL != callbackList)
  188. {
  189. size_t index = callbackList->size();
  190. while(index--)
  191. {
  192. ifc_omcachecallback *cb = callbackList->at(index);
  193. if (NULL != cb) cb->PathChanged(this);
  194. }
  195. }
  196. LeaveCriticalSection(&lock);
  197. return S_OK;
  198. }
  199. HRESULT CacheRecord::Download()
  200. {
  201. HRESULT hr;
  202. EnterCriticalSection(&lock);
  203. if (NULL != downloader)
  204. hr = E_PENDING;
  205. else
  206. {
  207. flags &= ~flagDownloadFailed;
  208. hr = CacheDownloader::CreateInstance(this, name, FALSE, &downloader);
  209. }
  210. LeaveCriticalSection(&lock);
  211. return hr;
  212. }
  213. HRESULT CacheRecord::DownloadCompleted(LPCWSTR pszFile, INT errorCode)
  214. {
  215. HRESULT hr = S_OK;
  216. EnterCriticalSection(&lock);
  217. CacheDownloader *temp = downloader;
  218. downloader = NULL;
  219. if (api_downloadManager::TICK_SUCCESS == errorCode)
  220. {
  221. WCHAR szTarget[MAX_PATH] = {0};
  222. hr = GetBasePath(szTarget, ARRAYSIZE(szTarget));
  223. if(SUCCEEDED(hr))
  224. {
  225. Plugin_EnsurePathExist(szTarget);
  226. LPCWSTR fileName = PathFindFileName(name);
  227. if (NULL == fileName)
  228. {
  229. WCHAR szTemp[32] = {0};
  230. StringCchPrintf(szTemp, ARRAYSIZE(szTemp), L"%08u.cache", GetTickCount());
  231. PathAppend(szTarget, szTemp);
  232. }
  233. else
  234. {
  235. PathAppend(szTarget, fileName);
  236. }
  237. WCHAR szExt[64] = {0};
  238. UINT attempt = 0;
  239. UINT pExtMax = 0;
  240. LPWSTR pExt = PathFindExtension(szTarget);
  241. if (pExt == szTarget || L'.' != *pExt || FAILED(StringCchCopy(szExt, ARRAYSIZE(szExt), pExt)))
  242. {
  243. szExt[0] = L'\0';
  244. }
  245. else
  246. {
  247. pExtMax = ARRAYSIZE(szTarget) - (UINT)(pExt - szTarget);
  248. }
  249. while(FALSE == CopyFile(pszFile, szTarget, TRUE))
  250. {
  251. DWORD error = GetLastError();
  252. if (ERROR_FILE_EXISTS != error)
  253. {
  254. hr = HRESULT_FROM_WIN32(error);
  255. break;
  256. }
  257. hr = StringCchPrintf(pExt, pExtMax, L"(%u)%s", ++attempt, szExt);
  258. if (FAILED(hr)) break;
  259. }
  260. }
  261. if (SUCCEEDED(hr))
  262. {
  263. SetPath(szTarget);
  264. }
  265. }
  266. else
  267. {
  268. flags |= flagDownloadFailed;
  269. }
  270. if (NULL != temp)
  271. temp->Release();
  272. LeaveCriticalSection(&lock);
  273. return S_OK;
  274. }
  275. INT CacheRecord::CompareTo(LPCWSTR pszName)
  276. {
  277. if (NULL == pszName || NULL == name)
  278. return (INT)(INT_PTR)(name - pszName);
  279. return CompareString(CSTR_INVARIANT, NORM_IGNORECASE, name, -1, pszName, -1) - 2;
  280. }
  281. HRESULT CacheRecord::IsEqualName(LPCWSTR pszName)
  282. {
  283. HRESULT hr;
  284. EnterCriticalSection(&lock);
  285. if (NULL == pszName)
  286. {
  287. hr = (NULL == name) ? S_OK : S_FALSE;
  288. }
  289. else if (NULL == name)
  290. {
  291. hr = S_FALSE;
  292. }
  293. else
  294. {
  295. INT result = CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszName, -1, name, -1);
  296. if (0 == result)
  297. {
  298. DWORD error = GetLastError();
  299. hr = HRESULT_FROM_WIN32(error);
  300. }
  301. else
  302. {
  303. hr = (CSTR_EQUAL == result) ? S_OK : S_FALSE;
  304. }
  305. }
  306. LeaveCriticalSection(&lock);
  307. return hr;
  308. }
  309. HRESULT CacheRecord::IsEqual(CacheRecord *record)
  310. {
  311. if (NULL == record) return E_INVALIDARG;
  312. HRESULT hr;
  313. EnterCriticalSection(&record->lock);
  314. hr = IsEqualName(record->name);
  315. LeaveCriticalSection(&record->lock);
  316. return hr;
  317. }
  318. HRESULT CacheRecord::RegisterCallback(ifc_omcachecallback *callback)
  319. {
  320. if (NULL == callback)
  321. return E_INVALIDARG;
  322. HRESULT hr = S_OK;
  323. EnterCriticalSection(&lock);
  324. if (NULL == callbackList)
  325. {
  326. callbackList = new CallbackList();
  327. if (NULL == callbackList) hr = E_OUTOFMEMORY;
  328. }
  329. else
  330. {
  331. size_t index = callbackList->size();
  332. while(index--)
  333. {
  334. if (callbackList->at(index) == callback)
  335. hr = E_FAIL;
  336. }
  337. }
  338. if (SUCCEEDED(hr) && NULL != callbackList)
  339. {
  340. callbackList->push_back(callback);
  341. callback->AddRef();
  342. }
  343. LeaveCriticalSection(&lock);
  344. return hr;
  345. }
  346. HRESULT CacheRecord::UnregisterCallback(ifc_omcachecallback *callback)
  347. {
  348. if (NULL == callback)
  349. return E_INVALIDARG;
  350. HRESULT hr = S_FALSE;
  351. EnterCriticalSection(&lock);
  352. if (NULL != callbackList)
  353. {
  354. size_t index = callbackList->size();
  355. while(index--)
  356. {
  357. ifc_omcachecallback *test = callbackList->at(index);
  358. if (test == callback)
  359. {
  360. callbackList->erase(callbackList->begin() + index);
  361. test->Release();
  362. hr = S_OK;
  363. if (0 == callbackList->size())
  364. {
  365. delete(callbackList);
  366. callbackList = NULL;
  367. }
  368. }
  369. }
  370. }
  371. LeaveCriticalSection(&lock);
  372. return hr;
  373. }
  374. HRESULT CacheRecord::GetFlags(UINT *puFlags)
  375. {
  376. if (NULL == puFlags) return E_POINTER;
  377. *puFlags = flags;
  378. return S_OK;
  379. }
  380. HRESULT CacheRecord::SetFlags(UINT uFlags, UINT uMask)
  381. {
  382. EnterCriticalSection(&lock);
  383. flags = (flags & ~uMask) | (uFlags & uMask);
  384. LeaveCriticalSection(&lock);
  385. return S_OK;
  386. }
  387. HRESULT CacheRecord::GetBasePath(LPWSTR pszBuffer, UINT cchBufferMax)
  388. {
  389. if (NULL == pszBuffer || 0 == cchBufferMax)
  390. return E_INVALIDARG;
  391. HRESULT hr;
  392. EnterCriticalSection(&lock);
  393. if (NULL != owner)
  394. {
  395. hr = owner->GetPath(pszBuffer, cchBufferMax);
  396. }
  397. else
  398. {
  399. *pszBuffer = L'\0';
  400. hr = E_UNEXPECTED;
  401. }
  402. LeaveCriticalSection(&lock);
  403. return hr;
  404. }
  405. #define CBCLASS CacheRecord
  406. START_DISPATCH;
  407. CB(ADDREF, AddRef)
  408. CB(RELEASE, Release)
  409. CB(QUERYINTERFACE, QueryInterface)
  410. CB(API_GETNAME, GetName)
  411. CB(API_GETPATH, GetPath)
  412. CB(API_SETPATH, SetPath)
  413. CB(API_GETFLAGS, GetFlags)
  414. CB(API_SETFLAGS, SetFlags)
  415. CB(API_DOWNLOAD, Download)
  416. CB(API_REGISTERCALLBACK, RegisterCallback)
  417. CB(API_UNREGISTERCALLBACK, UnregisterCallback)
  418. END_DISPATCH;
  419. #undef CBCLASS