569 lines
12 KiB
C++
569 lines
12 KiB
C++
|
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
|
||
|
//
|
||
|
// 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)
|
||
|
{
|
||
|
LPTSTR szURLCopy = (LPTSTR)new TCHAR[(StrLen(szURL) + 1)];
|
||
|
|
||
|
if (szURLCopy)
|
||
|
{
|
||
|
//
|
||
|
// 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();
|
||
|
}*/
|
||
|
|
||
|
StrCpy(szURLCopy, szURL);
|
||
|
|
||
|
pIXMLDocument->AddRef();
|
||
|
|
||
|
pNewItem->szURL = szURLCopy;
|
||
|
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;
|
||
|
}
|