//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // cache.cpp // // XML document cache. // // History: // // 4/15/97 edwardp Created. // //////////////////////////////////////////////////////////////////////////////// // // Includes // #include "stdinc.h" #include "persist.h" #include "cache.h" #include "cdfidl.h" #include "xmlutil.h" #include "dll.h" // // Cache functions. // //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_Initialize *** // // Prepare the XML document cache for use. // //////////////////////////////////////////////////////////////////////////////// void Cache_Initialize( void ) { ASSERT(NULL == g_pCache); InitializeCriticalSection(&g_csCache); return; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_Initialize *** // // Deactivate the cache. // //////////////////////////////////////////////////////////////////////////////// void Cache_Deinitialize( void ) { // MSXML has gone away at this point // Cache_FreeAll(); DeleteCriticalSection(&g_csCache); return; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_EnterWriteLock *** // // Obtain exclusive use of the XML document cache. // //////////////////////////////////////////////////////////////////////////////// void Cache_EnterWriteLock( void ) { EnterCriticalSection(&g_csCache); return; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_EnterWriteLock *** // // Release exclusive use of the XML document cache. // //////////////////////////////////////////////////////////////////////////////// void Cache_LeaveWriteLock( void ) { LeaveCriticalSection(&g_csCache); return; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_EnterReadLock *** // // Exclude writes to the the items list. Currently this also excludes other // reads. If need be this can be modified to allow multiple reads while // still excluding writes. // //////////////////////////////////////////////////////////////////////////////// void Cache_EnterReadLock( void ) { EnterCriticalSection(&g_csCache); return; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_LeaveReadLock *** // // Release a read hold on the use of the XML document cache. // //////////////////////////////////////////////////////////////////////////////// void Cache_LeaveReadLock( void ) { LeaveCriticalSection(&g_csCache); return; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_AddItem *** // // // Description: // Add an xml document to the cache. // // Parameters: // [In] szURL - The URL of the cdf file. // [In] pIXMLDocument - The already parsed xml document. // // Return: // S_OK if the document was added to the cache. // E_OUTOFMEMORY if the document couldn't be aded to the cache. // // Comments: // The xml document is AddRefed when inserted into the cache and // Released on removal from the cache. // //////////////////////////////////////////////////////////////////////////////// HRESULT Cache_AddItem( LPTSTR szURL, IXMLDocument* pIXMLDocument, DWORD dwParseFlags, FILETIME ftLastMod, DWORD dwCacheCount ) { ASSERT(szURL); ASSERT(pIXMLDocument); Cache_EnterWriteLock(); HRESULT hr; PCACHEITEM pNewItem = new CACHEITEM; if (pNewItem) { size_t cch = StrLen(szURL) + 1; LPTSTR pszURLCopy = (LPTSTR)new TCHAR[cch]; if (pszURLCopy) { // // Limit the cache to one item by freeing all current items. // Cache_FreeAll(); // // Remove an old cache entry for this url if it exists. // // Check no longer needed since we just cleared the cache. /*IXMLDocument* pIXMLDocumentOld; if (SUCCEEDED(Cache_QueryItem(szURL, &pIXMLDocumentOld, PARSE_LOCAL))) { ASSERT(pIXMLDocumentOld); Cache_RemoveItem(szURL); pIXMLDocumentOld->Release(); }*/ StrCpyN(pszURLCopy, szURL, cch); pIXMLDocument->AddRef(); pNewItem->szURL = pszURLCopy; pNewItem->dwParseFlags = dwParseFlags; pNewItem->ftLastMod = ftLastMod; pNewItem->dwCacheCount = dwCacheCount; pNewItem->pIXMLDocument = pIXMLDocument; // // REVIEW: Check for duplicate cache items? // pNewItem->pNext = g_pCache; g_pCache = pNewItem; hr = S_OK; } else { delete pNewItem; hr = E_OUTOFMEMORY; } } else { hr = E_OUTOFMEMORY; } Cache_LeaveWriteLock(); return hr; } // // // BOOL IsEmptyTime( FILETIME ft ) { return (0 == ft.dwLowDateTime && 0 == ft.dwHighDateTime); } BOOL IsEqualTime( FILETIME ft1, FILETIME ft2 ) { return ((ft1.dwLowDateTime == ft2.dwLowDateTime) && (ft1.dwHighDateTime == ft2.dwHighDateTime)); } void Cache_RefreshItem( CACHEITEM* pItem, LPTSTR pszLocalFile, FILETIME ftLastMod ) { ASSERT(pItem); // // Try and parse the cdf from the wininet cache. // IXMLDocument* pIXMLDocument; HRESULT hr; DLL_ForcePreloadDlls(PRELOAD_MSXML); hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDocument, (void**)&pIXMLDocument); BOOL bCoInit = FALSE; if ((CO_E_NOTINITIALIZED == hr || REGDB_E_IIDNOTREG == hr) && SUCCEEDED(CoInitialize(NULL))) { bCoInit = TRUE; hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDocument, (void**)&pIXMLDocument); } if (SUCCEEDED(hr)) { ASSERT(pIXMLDocument); hr = XML_SynchronousParse(pIXMLDocument, pszLocalFile); if (FAILED(hr)) pIXMLDocument->Release(); } if (bCoInit) CoUninitialize(); // // If the new cdf was parsed, replace the old one. // if (SUCCEEDED(hr)) { pItem->pIXMLDocument->Release(); pItem->pIXMLDocument = pIXMLDocument; pItem->ftLastMod = ftLastMod; } return; } BOOL Cache_IsItemFresh( CACHEITEM* pItem, DWORD dwParseFlags ) { ASSERT(pItem); BOOL fRet; DWORD dwCurrentCacheCount = g_dwCacheCount; // // If the caller asked for "Net" quality data and we only have "Local" data // then throw the "Local" data away. The resultant cache miss will cause // the caller to pick up fresher data. // if ((dwParseFlags & PARSE_NET) && (pItem->dwParseFlags & PARSE_LOCAL)) { fRet = FALSE; } else { fRet = TRUE; // // If the global cache counter is greater than the counter for this // item, then a cdf has been added to the cache. // if (dwCurrentCacheCount > pItem->dwCacheCount) { // // Get the last mod time from the the cdf in the wininet cache. // FILETIME ftLastMod; TCHAR szLocalFile[MAX_PATH]; if (SUCCEEDED(URLGetLocalFileName(pItem->szURL, szLocalFile, ARRAYSIZE(szLocalFile), &ftLastMod))) { // // If the last mod times are different then the cdf in the // wininet cache is newer, pick it up. // If there are no last modified times then do the conservative // thing and pick up the cdf from the wininet cache. // if ((IsEmptyTime(ftLastMod) && IsEmptyTime(pItem->ftLastMod)) || !IsEqualTime(ftLastMod, pItem->ftLastMod)) { Cache_RefreshItem(pItem, szLocalFile, ftLastMod); } } pItem->dwCacheCount = dwCurrentCacheCount; } } return fRet; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_QueryItem *** // // // Description: // Returns a xml document from the cache if it is found. // // Parameters: // [In] szURL - The URL associated with the xml document. // [Out] ppIXMLDocument - A pointer that receives the xml document. // // Return: // S_OK if the document associtaed with the given URL is found in the cache. // E_FAIL if the document isn't in the cache. // // Comments: // The returned pointer is AddRefed. The caller isresposible for releasing // this pointer. // //////////////////////////////////////////////////////////////////////////////// HRESULT Cache_QueryItem( LPTSTR szURL, IXMLDocument** ppIXMLDocument, DWORD dwParseFlags ) { ASSERT(szURL); ASSERT(ppIXMLDocument); HRESULT hr = E_FAIL; Cache_EnterReadLock(); PCACHEITEM pItem = g_pCache; // // REVIEW: Use CompareUrl from shlwapip? // while (pItem && !StrEql(szURL, pItem->szURL)) pItem = pItem->pNext; if (pItem) { if (Cache_IsItemFresh(pItem, dwParseFlags)) { ASSERT(pItem->pIXMLDocument); pItem->pIXMLDocument->AddRef(); *ppIXMLDocument = pItem->pIXMLDocument; hr = S_OK; } else { Cache_RemoveItem(szURL); } } Cache_LeaveReadLock(); ASSERT(SUCCEEDED(hr) && ppIXMLDocument || FAILED(hr)); return hr; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_FreeAll *** // // // Description: // Frees all items from the xml document cache. // // Parameters: // None. // // Return: // None. // // Comments: // Frees all memory held in the xml document cache. // //////////////////////////////////////////////////////////////////////////////// void Cache_FreeAll( void ) { Cache_EnterWriteLock(); PCACHEITEM pItem = g_pCache; g_pCache = NULL; Cache_LeaveWriteLock(); while (pItem) { PCACHEITEM pNext = pItem->pNext; ASSERT(pItem->szURL); ASSERT(pItem->pIXMLDocument); pItem->pIXMLDocument->Release(); delete [] pItem->szURL; delete pItem; pItem = pNext; } return; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // *** Cache_FreeItem *** // // // Description: // Frees item associated with given URL from the xml document cache. // // Parameters: // LPTSTR szURL // // Return: // HRESULT S_OK if item in cache and deleted, E_FAIL if item not in cache // //////////////////////////////////////////////////////////////////////////////// HRESULT Cache_RemoveItem( LPCTSTR szURL ) { ASSERT(szURL); HRESULT hr; Cache_EnterWriteLock(); PCACHEITEM pItem = g_pCache; PCACHEITEM pItemPrev = NULL; // // REVIEW: Use CompareUrl from slwapip?. // while (pItem && !StrEql(szURL, pItem->szURL)) { pItemPrev = pItem; pItem = pItem->pNext; } if (pItem) { ASSERT(pItem->pIXMLDocument); if (pItemPrev) { pItemPrev->pNext = pItem->pNext; } else { g_pCache = pItem->pNext; // handle remove first item case } pItem->pIXMLDocument->Release(); delete [] pItem->szURL; delete pItem; hr = S_OK; } else { hr = E_FAIL; } Cache_LeaveWriteLock(); return hr; }