windows-nt/Source/XPSP1/NT/shell/ext/cdfview/cache.cpp
2020-09-26 16:20:57 +08:00

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