|
|
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// 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; }
|