|
|
// Protocol.cpp -- Implementation for class CIOITnetProtocol
#include "StdAfx.h"
// Creation:
HRESULT CIOITnetProtocol::Create (IUnknown *punkOuter, REFIID riid, PPVOID ppv) { CIOITnetProtocol *pNP = New CIOITnetProtocol(punkOuter);
return FinishSetup(pNP? pNP->m_ImpIOITnetProtocol.Init() : STG_E_INSUFFICIENTMEMORY, pNP, riid, (PPVOID) ppv ); }
// Constructor and Destructor:
CIOITnetProtocol::CImpIOITnetProtocol::CImpIOITnetProtocol (CIOITnetProtocol *pBackObj, IUnknown *pUnkOuter) : IOITnetProtocol(pBackObj, pUnkOuter) , IOITnetProtocolInfo(pBackObj, pUnkOuter) { m_grfSTI = 0; m_grfBINDF = 0; m_szTempPath[0] = 0;
ZeroMemory(&m_BindInfo, sizeof(m_BindInfo));
m_pwcsURL = NULL; m_pcsDisplayName = NULL; m_pOIProtSink = NULL; m_pOIBindInfo = NULL; m_pStream = NULL; }
CIOITnetProtocol::CImpIOITnetProtocol::~CImpIOITnetProtocol(void) { if (m_pcsDisplayName) { UnlockUrlCacheEntryFile(m_pcsDisplayName, 0);
delete [] m_pcsDisplayName; } if (m_pwcsURL) delete [] m_pwcsURL; if (m_pOIProtSink) m_pOIProtSink->Release();
if (m_pOIBindInfo) m_pOIBindInfo->Release();
if (m_pStream) m_pStream->Release();
if (m_szTempPath[0]) DeleteFile(m_szTempPath); }
// Initialing routine:
HRESULT CIOITnetProtocol::CImpIOITnetProtocol::Init() { return NO_ERROR; }
// IOITnetProtocolRoot interfaces:
void STDMETHODCALLTYPE MapSurrogateCharacters (PWCHAR pwcsBuffer) { PWCHAR pwcsDest = pwcsBuffer;
for (;;) { WCHAR wc = *pwcsBuffer++; *pwcsDest++ = wc;
if (!wc) break;
if (wc == L'%' && pwcsBuffer[0] && pwcsBuffer[1]) { WCHAR wcSurrogate = 0; WCHAR wcFirst = pwcsBuffer[0]; WCHAR wcSecond = pwcsBuffer[1]; if (wcFirst >= L'0' && wcFirst <= L'9') wcSurrogate = wcFirst - L'0'; else if (wcFirst >= L'A' && wcFirst <= L'F') wcSurrogate = 10 + wcFirst - L'A'; else if (wcFirst >= L'a' && wcFirst <= L'f') wcSurrogate = 10 + wcFirst - L'a'; else continue;
wcSurrogate <<= 4;
if (wcSecond >= L'0' && wcSecond <= L'9') wcSurrogate |= wcSecond - L'0'; else if (wcSecond >= L'A' && wcSecond <= L'F') wcSurrogate |= 10 + wcSecond - L'A'; else if (wcSecond >= L'a' && wcSecond <= L'f') wcSurrogate |= 10 + wcSecond - L'a'; else continue;
pwcsDest[-1] = wcSurrogate; pwcsBuffer += 2; } } }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Start ( /* [in] */ LPCWSTR szUrl, /* [in] */ IOInetProtocolSink __RPC_FAR *pOIProtSink, /* [in] */ IOInetBindInfo __RPC_FAR *pOIBindInfo, /* [in] */ DWORD grfSTI, /* [in] */ DWORD dwReserved ) { DWORD cwc = wcsLen(szUrl);
PWCHAR pwcsBuffer = PWCHAR(_alloca((cwc + 1) * sizeof(WCHAR)));
if (!pwcsBuffer) return E_OUTOFMEMORY;
CopyMemory(pwcsBuffer, szUrl, sizeof(WCHAR) * (cwc + 1));
PWCHAR pwcsExternalPath = NULL; PWCHAR pwcsInternalPath = NULL;
HRESULT hr = DisectUrl(pwcsBuffer, NULL, &pwcsExternalPath, &pwcsInternalPath); if (!SUCCEEDED(hr)) { if (hr != INET_E_DEFAULT_ACTION && (grfSTI & PI_PARSE_URL)) return S_FALSE; else return hr; }
hr = AssembleUrl(NULL, 0, &cwc, L"ms-its", pwcsExternalPath, pwcsInternalPath); RonM_ASSERT(hr == E_OUTOFMEMORY);
m_pwcsURL = New WCHAR[cwc];
if (!m_pwcsURL) return E_OUTOFMEMORY;
DWORD cwcRequired = 0;
hr = AssembleUrl(m_pwcsURL, cwc, &cwcRequired, L"ms-its", pwcsExternalPath, pwcsInternalPath);
RonM_ASSERT(hr == S_OK); m_pOIProtSink = pOIProtSink; m_pOIBindInfo = pOIBindInfo; m_grfSTI = grfSTI;
m_pOIProtSink->AddRef(); m_pOIBindInfo->AddRef();
m_BindInfo.cbSize = sizeof(BINDINFO);
hr = GetBindInfo(&m_grfBINDF, &m_BindInfo);
if (!SUCCEEDED(hr)) return hr;
if (grfSTI & PI_PARSE_URL) return ParseAndBind(FALSE);
if (!(grfSTI & PI_FORCE_ASYNC)) return ParseAndBind(TRUE);
PROTOCOLDATA protdata;
protdata.grfFlags = PI_FORCE_ASYNC; protdata.dwState = ITS_BIND_DATA; protdata.pData = NULL; protdata.cbData = 0;
Switch(&protdata);
return E_PENDING; }
HRESULT STDMETHODCALLTYPE CopyStreamToFile(const WCHAR *pwcsFilePath, IStream *pStreamSrc) {
IStream *pStream;
IFSStorage *pFSS = NULL;
HRESULT hr = CFileSystemStorage::Create(NULL, IID_IFSStorage, (VOID **) &pFSS);
if (!SUCCEEDED(hr)) return hr;
hr = pFSS->FSOpenStream((const WCHAR *) pwcsFilePath, STGM_READWRITE | STGM_SHARE_DENY_NONE, &pStream );
pFSS->Release();
if (!SUCCEEDED(hr)) return hr;
RonM_ASSERT(pStreamSrc);
STATSTG statstg;
hr = pStreamSrc->Stat(&statstg, STATFLAG_NONAME);
if (!SUCCEEDED(hr)) return hr;
#ifdef _DEBUG
hr = #endif // _DEBUG
pStreamSrc->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
RonM_ASSERT(hr == S_OK);
hr = pStreamSrc->CopyTo(pStream, statstg.cbSize, NULL, NULL);
pStream->Release();
if (!SUCCEEDED(hr)) return hr;
#ifdef _DEBUG
hr = #endif // _DEBUG
pStreamSrc->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
RonM_ASSERT(hr == S_OK);
return hr; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ParseAndBind(BOOL fBind) { WCHAR *pwcsURL = m_pwcsURL; WCHAR *pwcsURLActual = NULL;
BOOL fNoFile = (m_grfBINDF & BINDF_NEEDFILE) == 0; // FALSE;
BOOL fNoReadCache = m_grfBINDF & (BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE | BINDF_PRAGMA_NO_CACHE | BINDF_DIRECT_READ );
BOOL fNoWriteCache = m_grfBINDF & (BINDF_NOWRITECACHE | BINDF_PRAGMA_NO_CACHE | BINDF_DIRECT_READ ); IBindCtx *pBCtx = NULL; IMoniker *pMK = NULL; PWCHAR pwcsExtension = NULL; PWCHAR pwcsMimeType = NULL; PWCHAR pwcsStreamName = NULL; ULONG chEaten = 0; DWORD cbSample = 0;
HRESULT hr = CreateBindCtx(0, &pBCtx);
if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
hr = CStorageMoniker::CreateStorageMoniker(NULL, pBCtx, pwcsURL, &chEaten, &pMK);
if (!fBind) { if (hr != S_OK) hr = S_FALSE;
goto exit_ParseAndBind; } if (!SUCCEEDED(hr)) goto exit_ParseAndBind; hr = pMK->BindToStorage(pBCtx, NULL, IID_IStream, (VOID **) &m_pStream);
if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
hr = pMK->GetDisplayName(NULL, NULL, &pwcsURLActual);
RonM_ASSERT(hr == S_OK);
{ UINT cwc = wcsLen(pwcsURLActual);
WCHAR *pwc = pwcsURLActual + cwc;
for (;;) { WCHAR wc = *--pwc;
if (!pwcsExtension && wc == L'.') pwcsExtension = pwc + 1;
if (wc == L':' || wc == L'/' || wc == L'\\') { pwc++;
break; }
RonM_ASSERT(--cwc); }
pwcsStreamName = pwc;
ReportProgress(BINDSTATUS_SENDINGREQUEST, (const WCHAR *) pwc); }
STATSTG statstg;
hr = m_pStream->Stat(&statstg, STATFLAG_NONAME);
if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
RonM_ASSERT(statstg.cbSize.HighPart == 0);
BYTE abSample[CB_SAMPLE];
if (pwcsExtension && pwcsExtension[0]) { UINT cwc = wcsLen(pwcsExtension-1); UINT cb = sizeof(WCHAR) * (cwc + 1);
char *pcsExtension = PCHAR(_alloca(cb));
if (!pcsExtension) { hr = E_OUTOFMEMORY; goto exit_ParseAndBind; }
cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsExtension-1, cwc + 1, pcsExtension, cb, NULL, NULL );
if (!cb) { hr = E_FAIL; goto exit_ParseAndBind; }
HKEY hkeyMime; if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pcsExtension, 0, KEY_QUERY_VALUE, &hkeyMime) == ERROR_SUCCESS ) { cb = CB_SAMPLE; if (RegQueryValueEx(hkeyMime, "Content Type", NULL, NULL, abSample, (DWORD *) &cb) == ERROR_SUCCESS && cb > 0 ) { PWCHAR pwc = (PWCHAR) (OLEHeap()->Alloc(cb * sizeof(WCHAR)));
if (pwc) { UINT cwc = MultiByteToWideChar (GetACP(), MB_PRECOMPOSED, (const char *) abSample, cb, pwc, cb ); if (cwc) pwcsMimeType = pwc; else OLEHeap()->Free(pwc); } }
RegCloseKey(hkeyMime); } } if (!pwcsMimeType) { DWORD cbRead;
cbSample = statstg.cbSize.LowPart < CB_SAMPLE? statstg.cbSize.LowPart : CB_SAMPLE;
hr = m_pStream->Read(abSample, cbSample, &cbRead);
if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
if (cbRead != cbSample) { hr = E_FAIL;
goto exit_ParseAndBind; }
m_pStream->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
hr = pFindMimeFromData(NULL, pwcsStreamName, abSample, cbSample, NULL, 0, &pwcsMimeType, 0);
if (!SUCCEEDED(hr)) goto exit_ParseAndBind; }
if (pwcsMimeType) { // The test below is a hack to get around a bug in UrlMon.
// UrlMon incorrectly tells us we need to copy HTML files into the cache.
if (!wcsicmp_0x0409(pwcsMimeType, L"text/html")) fNoFile = TRUE; ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, pwcsMimeType); } if (!fNoFile) { CHAR acsFilePath[MAX_PATH]; WCHAR awcsFilePath[MAX_PATH];
hr = StreamToIEFile(m_pStream, m_pwcsURL, m_pcsDisplayName, acsFilePath, awcsFilePath, m_szTempPath, pMK, fNoWriteCache, fNoReadCache );
if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
hr = ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE, awcsFilePath);
if (!SUCCEEDED(hr)) goto exit_ParseAndBind; }
hr = ReportData(BSCF_FIRSTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, statstg.cbSize.LowPart, statstg.cbSize.LowPart );
// The call to ReportData may indirectly call the Terminate method. So we have
// to be very careful about references to m_pOIProtSink afterwards.
if (SUCCEEDED(hr) && m_pOIProtSink) hr = ReportProgress(BSCF_LASTDATANOTIFICATION, NULL);
if (SUCCEEDED(hr) && m_pOIProtSink) ReportResult(hr, 0, 0);
exit_ParseAndBind:
if (pwcsURLActual) OLEHeap()->Free(pwcsURLActual); if (pMK) pMK->Release(); if (pBCtx) pBCtx->Release();
if (hr != NO_ERROR) ReportResult(hr, 0, 0); return hr; }
HRESULT STDMETHODCALLTYPE StreamToIEFile (IStream *pStreamSrc, PWCHAR pwcsDisplayName, PCHAR &pcsDisplayName, PCHAR pcsFileName, PWCHAR pwcsFileName, PCHAR pcsTempFile, IMoniker *pmk, BOOL fNoWriteCache, BOOL fNoReadCache ) { HRESULT hr = NO_ERROR; PWCHAR pwcsExtension = NULL; PWCHAR pwc = NULL; PCHAR pcsExtension = "";
STATSTG statstg;
hr = pStreamSrc->Stat(&statstg, STATFLAG_NONAME);
if (!SUCCEEDED(hr)) goto exit_StreamToIEFile;
RonM_ASSERT(statstg.cbSize.HighPart == 0);
FILETIME ftLastModified;
ftLastModified.dwLowDateTime = 0; ftLastModified.dwHighDateTime = 0;
// pmk->GetTimeOfLastChange(pBCtx, NULL, &ftLastModified);
pwc = pwcsDisplayName + wcsLen(pwcsDisplayName);
for (;;) { WCHAR wc = *--pwc;
if (!pwcsExtension && wc == L'.') pwcsExtension = pwc + 1;
if (wc == L':' || wc == L'/' || wc == L'\\') { pwc++;
break; }
RonM_ASSERT(pwc > pwcsDisplayName); } if (pwcsExtension && pwcsExtension[0]) { UINT cwc = wcsLen(pwcsExtension); UINT cb = sizeof(WCHAR) * (cwc + 1);
pcsExtension = PCHAR(_alloca(cb));
if (!pcsExtension) { hr = E_OUTOFMEMORY; goto exit_StreamToIEFile; }
cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsExtension, cwc + 1, pcsExtension, cb, NULL, NULL );
if (!cb) { hr = E_FAIL; goto exit_StreamToIEFile; } }
if (fNoWriteCache) { DWORD cbPath= GetTempPath(MAX_PATH, pcsTempFile);
if (!cbPath) lstrcpyA(pcsTempFile, ".\\");
char szPrefix[4] = "IMT"; // BugBug! May need to make this a random string.
char szFullPath[MAX_PATH];
if (!GetTempFileName(pcsTempFile, szPrefix, 0, szFullPath)) { hr = CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError()); pcsTempFile[0] = 0; goto exit_StreamToIEFile; }
lstrcpyA(pcsTempFile, szFullPath);
char *pch = pcsTempFile + lstrlenA(pcsTempFile);
for (;;) { if (pch == pcsTempFile) { RonM_ASSERT(FALSE); hr = E_UNEXPECTED; DeleteFile(pcsTempFile); pcsTempFile[0] = 0; goto exit_StreamToIEFile; }
if ('.' == *--pch) { ++pch; break; } }
UINT cbExtension = lstrlenA(pcsExtension);
if (pch + cbExtension - pcsTempFile >= MAX_PATH) { hr = E_UNEXPECTED; DeleteFile(pcsTempFile); pcsTempFile[0] = 0; goto exit_StreamToIEFile; }
CopyMemory(pch, pcsExtension, cbExtension + 1);
if (!MoveFileEx(szFullPath, pcsTempFile, MOVEFILE_REPLACE_EXISTING)) { hr = E_UNEXPECTED; DeleteFile(szFullPath); pcsTempFile[0] = 0; goto exit_StreamToIEFile; }
UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, pcsTempFile, 1 + lstrlenA(pcsTempFile), pwcsFileName, MAX_PATH );
if (cwc == 0) { hr = E_FAIL;
DeleteFile(pcsTempFile); pcsTempFile [0] = 0; pwcsFileName[0] = 0;
goto exit_StreamToIEFile; }
hr = CopyStreamToFile((const WCHAR *)pwcsFileName, pStreamSrc); if (!SUCCEEDED(hr)) { DeleteFile(pcsTempFile); pcsTempFile[0] = 0; pwcsFileName[0] = 0; goto exit_StreamToIEFile; }
lstrcpyA(pcsFileName, pcsTempFile); } else { UINT cwc = wcsLen(pwcsDisplayName); UINT cb = sizeof(WCHAR) * (cwc + 1); pcsDisplayName = New char[cb];
if (!pcsDisplayName) { hr = E_OUTOFMEMORY; goto exit_StreamToIEFile; }
cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsDisplayName, cwc + 1, pcsDisplayName, cb, NULL, NULL );
if (!cb) { hr = INET_E_DOWNLOAD_FAILURE; delete [] pcsDisplayName; pcsDisplayName = NULL; goto exit_StreamToIEFile; }
BOOL fResult = FALSE; DWORD dwCEISize = 0; ULONG ulErr = 0;
if (!fNoReadCache) { RonM_ASSERT(dwCEISize == 0); fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, NULL, &dwCEISize, 0); RonM_ASSERT(!fResult);
ulErr= GetLastError();
if (ulErr == ERROR_INSUFFICIENT_BUFFER) { dwCEISize += 4; // To work around a bug in the RetrieveUrlCacheEntryFile;
// It sometimes gives an incorrect size immediately after
// data has been copied to the cache.
INTERNET_CACHE_ENTRY_INFOA *pCEI = (INTERNET_CACHE_ENTRY_INFOA *) _alloca(dwCEISize); if (!pCEI) { hr = E_OUTOFMEMORY;
goto exit_StreamToIEFile; } pCEI->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOA);
fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, pCEI, &dwCEISize, 0);
ulErr = GetLastError();
if (fResult) if ( pCEI->LastModifiedTime.dwLowDateTime == ftLastModified.dwLowDateTime && pCEI->LastModifiedTime.dwHighDateTime == ftLastModified.dwHighDateTime && pCEI->dwSizeLow == statstg.cbSize.LowPart && pCEI->dwSizeHigh == statstg.cbSize.HighPart ) { lstrcpyA(pcsFileName, pCEI->lpszLocalFileName); cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, pcsFileName, 1 + lstrlenA(pcsFileName), pwcsFileName, MAX_PATH );
RonM_ASSERT(cwc != 0); } else { UnlockUrlCacheEntryFile(pcsDisplayName, 0); fResult = FALSE; } } }
if (!fResult) { fResult = CreateUrlCacheEntryA(pcsDisplayName, statstg.cbSize.LowPart, pcsExtension, pcsFileName, 0 );
if (!fResult) { hr = INET_E_CANNOT_INSTANTIATE_OBJECT; delete [] pcsDisplayName; pcsDisplayName = NULL; goto exit_StreamToIEFile; }
cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, pcsFileName, 1 + lstrlenA(pcsFileName), pwcsFileName, MAX_PATH );
hr = CopyStreamToFile((const WCHAR *) pwcsFileName, pStreamSrc);
if (!fResult) { hr = INET_E_CANNOT_INSTANTIATE_OBJECT; delete [] pcsDisplayName; pcsDisplayName = NULL; pcsFileName[0] = 0; pwcsFileName[0] = 0; goto exit_StreamToIEFile; }
FILETIME ftExpire;
ftExpire.dwLowDateTime = 0; ftExpire.dwHighDateTime = 0;
fResult = CommitUrlCacheEntryA(pcsDisplayName, pcsFileName, ftExpire, ftLastModified, NORMAL_CACHE_ENTRY, NULL, 0, pcsExtension, 0 );
if (!fResult) { ulErr= GetLastError(); hr = INET_E_CANNOT_INSTANTIATE_OBJECT; delete [] pcsDisplayName; pcsDisplayName = NULL; pcsFileName[0] = 0; pwcsFileName[0] = 0; goto exit_StreamToIEFile; }
dwCEISize = 0;
fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, NULL, &dwCEISize, 0); RonM_ASSERT(!fResult);
ulErr= GetLastError();
if (ulErr == ERROR_INSUFFICIENT_BUFFER) { dwCEISize += 4; // To work around a bug in the RetrieveUrlCacheEntryFile;
// It sometimes gives an incorrect size immediately after
// data has been copied to the cache.
INTERNET_CACHE_ENTRY_INFOA *pCEI = (INTERNET_CACHE_ENTRY_INFOA *) _alloca(dwCEISize); if (!pCEI) { hr = E_OUTOFMEMORY; delete [] pcsDisplayName; pcsDisplayName = NULL; pcsFileName[0] = 0; pwcsFileName[0] = 0; goto exit_StreamToIEFile; } pCEI->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOA);
fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, pCEI, &dwCEISize, 0);
if (!fResult) { ulErr= GetLastError();
RonM_ASSERT(FALSE);
hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
delete [] pcsDisplayName; pcsDisplayName = NULL; pcsFileName[0] = 0; pwcsFileName[0] = 0; goto exit_StreamToIEFile; } } } }
return NO_ERROR;
exit_StreamToIEFile:
return hr; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Continue (/* [in] */ PROTOCOLDATA __RPC_FAR *pProtocolData) { switch (pProtocolData->dwState) { case ITS_BIND_DATA: return ParseAndBind(TRUE);
default: RonM_ASSERT(FALSE);
return INET_E_INVALID_REQUEST; } }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Abort ( /* [in] */ HRESULT hrReason, /* [in] */ DWORD dwOptions ) { return ReportResult(E_ABORT, 0, 0); }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Terminate (/* [in] */ DWORD dwOptions) { if (m_pwcsURL) { delete [] m_pwcsURL; m_pwcsURL = NULL; }
if (m_pOIProtSink) { m_pOIProtSink->Release(); m_pOIProtSink = NULL; }
if (m_pOIBindInfo) { m_pOIBindInfo->Release(); m_pOIBindInfo = NULL; }
return NO_ERROR; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Suspend(void) { return NO_ERROR; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Resume(void) { return NO_ERROR; }
// IOITnetProtocol interfaces:
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Read ( /* [length_is][size_is][out] */ void __RPC_FAR *pv, /* [in] */ ULONG cb, /* [out] */ ULONG __RPC_FAR *pcbRead ) { if (m_pStream) return m_pStream->Read(pv, cb, pcbRead); else return INET_E_DATA_NOT_AVAILABLE; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Seek ( /* [in] */ LARGE_INTEGER dlibMove, /* [in] */ DWORD dwOrigin, /* [out] */ ULARGE_INTEGER __RPC_FAR *plibNewPosition ) { if (m_pStream) return m_pStream->Seek(dlibMove, dwOrigin, plibNewPosition); else return INET_E_DATA_NOT_AVAILABLE; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::LockRequest (/* [in] */ DWORD dwOptions) { return NO_ERROR; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::UnlockRequest(void) { return NO_ERROR; }
HRESULT STDMETHODCALLTYPE DisectUrl (PWCHAR pwcsUrlBuffer, PWCHAR *ppwcProtocolName, PWCHAR *ppwcExternalPath, PWCHAR *ppwcInternalPath ) { PWCHAR pwcProtocolName = NULL, pwcExternalPath = NULL, pwcInternalPath = NULL;
MapSurrogateCharacters(pwcsUrlBuffer); PWCHAR pwc = wcsChr((const WCHAR *) pwcsUrlBuffer, L':');
if (!pwc) return URL_E_INVALID_SYNTAX;
*pwc++ = 0;
pwcProtocolName = pwcsUrlBuffer;
if ( L'@' == *pwcProtocolName && !wcsicmp_0x0409((const WCHAR *) (pwcProtocolName+1), L"msitstore") ) { pwcProtocolName = L"mk:@msitstore"; } else if (!wcsicmp_0x0409((const WCHAR *)pwcProtocolName, L"mk")) { // This URL begins with "mk:". We handle entries which
// begin with "mk:@MSITStore:"
// We treat the @<classid> as part of the protocol name.
// So we must first put the colon separator back.
pwc[-1] = L':'; if (L'@' != *pwc) return URL_E_INVALID_SYNTAX;
PWCHAR pwcClassName = pwc + 1;
pwc = wcsChr((const WCHAR *) pwcClassName, L':');
if (!pwc) return URL_E_INVALID_SYNTAX;
*pwc++ = 0;
if (wcsicmp_0x0409((const WCHAR *)pwcClassName, L"msitstore")) return INET_E_DEFAULT_ACTION; } else if (!wcsicmp_0x0409((const WCHAR *)pwcsUrlBuffer, L"its")) { } else if (!wcsicmp_0x0409((const WCHAR *)pwcsUrlBuffer, L"ms-its")) { } else return INET_E_DEFAULT_ACTION;
pwcExternalPath = pwc;
pwc += wcsLen(pwc);
for (; pwc > pwcExternalPath; ) { WCHAR wc = *--pwc;
if (wc == L':') if (pwc > pwcExternalPath && L':' == *--pwc) { *pwc = 0; pwc += 2;
break; } }
if (pwc == pwcExternalPath) pwc += wcsLen(pwc);
if (!*pwcExternalPath || wcsLen(pwcExternalPath) >= MAX_PATH) return URL_E_INVALID_SYNTAX;
pwcInternalPath = pwc;
for (;*pwc; pwc++);
if (pwcInternalPath == pwc) pwcInternalPath = L"/";
if (wcsLen(pwcInternalPath) >= MAX_PATH) return URL_E_INVALID_SYNTAX;
if (ppwcProtocolName) *ppwcProtocolName = pwcProtocolName; if (ppwcExternalPath) *ppwcExternalPath = pwcExternalPath; if (ppwcInternalPath) *ppwcInternalPath = pwcInternalPath;
return NO_ERROR; }
HRESULT STDMETHODCALLTYPE AssembleUrl (PWCHAR pwcsResult, DWORD cwcBuffer, DWORD *pcwcRequired, PWCHAR pwcsProtocolName, PWCHAR pwcsExternalPath, PWCHAR pwcsInternalPath ) { UINT cwc = wcsLen(pwcsProtocolName) + wcsLen(pwcsExternalPath) + wcsLen(pwcsInternalPath) + 4;
*pcwcRequired = cwc; if (cwc > cwcBuffer) return E_OUTOFMEMORY;
wcsCpy(pwcsResult, pwcsProtocolName); wcsCat(pwcsResult, L":"); wcsCat(pwcsResult, pwcsExternalPath); wcsCat(pwcsResult, L"::"); wcsCat(pwcsResult, pwcsInternalPath); return NO_ERROR; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ParseUrl ( /* [in] */ LPCWSTR pwzUrl, /* [in] */ PARSEACTION ParseAction, /* [in] */ DWORD dwParseFlags, /* [out] */ LPWSTR pwzResult, /* [in] */ DWORD cchResult, /* [out] */ DWORD __RPC_FAR *pcchResult, /* [in] */ DWORD dwReserved ) { switch (ParseAction) { case PARSE_CANONICALIZE: case PARSE_SECURITY_URL:
{ // First we make a working copy of the URL.
UINT cwc = wcsLen(pwzUrl); UINT cb = sizeof(WCHAR) * (cwc + 1);
PWCHAR pwcsUrl = PWCHAR(_alloca(cb));
if (!pwcsUrl) return E_OUTOFMEMORY;
CopyMemory(pwcsUrl, pwzUrl, cb);
PWCHAR pwcProtocolName = NULL, pwcExternalPath = NULL, pwcInternalPath = NULL;
BOOL fLocalFilePath = FALSE;
HRESULT hr = DisectUrl(pwcsUrl, &pwcProtocolName, &pwcExternalPath, &pwcInternalPath);
if (!SUCCEEDED(hr)) return hr;
// Here we copy the external path string to a buffer because
// it may be a partial local path which needs to be mapped into
// a full path.
WCHAR awcsExternalPath[MAX_PATH];
RonM_ASSERT(wcsLen(pwcExternalPath) < MAX_PATH);
wcsCpy(awcsExternalPath, pwcExternalPath); PWCHAR pwc = wcsChr((const WCHAR *) awcsExternalPath, L':');
if (pwc && pwc[1] == L':') // Ignore a "::" separator
pwc = NULL;
// Here we're special casing non-protocol references to a file.
// We recognize those situations by looking for a protocol prefix.
// Protocol prefixes have the form <Protocol Name> :
// where <Protocol Name> is always longer than one character.
if (!pwc || (pwc - awcsExternalPath == 1)) { fLocalFilePath = TRUE;
if (FindRootStorageFile(awcsExternalPath) == S_OK) pwcExternalPath = awcsExternalPath; }
if (ParseAction == PARSE_SECURITY_URL) {
UINT cwcExt = 1 + wcsLen(pwcExternalPath);
if (fLocalFilePath) { // It's a local file. Got to prefix the result with
// "File://".
RonM_ASSERT(7 == wcsLen(L"File://"));
*pcchResult = cwcExt + 7;
if (cchResult < (cwcExt + 7)) return E_OUTOFMEMORY;
CopyMemory(pwzResult, L"File://", 7 * sizeof(WCHAR));
pwzResult += 7; } else { *pcchResult = cwcExt;
if (cwcExt > cchResult) return E_OUTOFMEMORY; }
CopyMemory(pwzResult, pwcExternalPath, cwcExt * sizeof(WCHAR));
return NO_ERROR; }
cwc = wcsLen(pwcInternalPath);
BOOL fStorage = pwcInternalPath[cwc-1] == L'/' || pwcInternalPath[cwc-1] == L'\\';
WCHAR awcsInternalPath[MAX_PATH];
hr = ResolvePath(awcsInternalPath, L"/", (const WCHAR *) pwcInternalPath, fStorage);
if (!SUCCEEDED(hr)) return hr;
hr = AssembleUrl(pwzResult, cchResult, pcchResult, pwcProtocolName, pwcExternalPath, awcsInternalPath );
return hr; }
case PARSE_FRIENDLY:
case PARSE_ROOTDOCUMENT:
case PARSE_DOCUMENT:
case PARSE_ANCHOR:
case PARSE_ENCODE: case PARSE_DECODE: case PARSE_PATH_FROM_URL: case PARSE_URL_FROM_PATH: case PARSE_LOCATION: case PARSE_MIME: case PARSE_SECURITY_DOMAIN:
default: return INET_E_DEFAULT_ACTION; } }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::CombineUrl ( /* [in] */ LPCWSTR pwzBaseUrl, /* [in] */ LPCWSTR pwzRelativeUrl, /* [in] */ DWORD dwCombineFlags, /* [out] */ LPWSTR pwzResult, /* [in] */ DWORD cchResult, /* [out] */ DWORD __RPC_FAR *pcchResult, /* [in] */ DWORD dwReserved ) { // First we make a working copy of the URL.
UINT cwc = wcsLen(pwzBaseUrl); UINT cb = sizeof(WCHAR) * (cwc + 1);
PWCHAR pwcsUrl = PWCHAR(_alloca(cb));
if (!pwcsUrl) return E_OUTOFMEMORY;
CopyMemory(pwcsUrl, pwzBaseUrl, cb);
PWCHAR pwcProtocolName = NULL, pwcExternalPath = NULL, pwcInternalPath = NULL;
HRESULT hr = DisectUrl(pwcsUrl, &pwcProtocolName, &pwcExternalPath, &pwcInternalPath);
if (!SUCCEEDED(hr)) return hr;
WCHAR awcsInternalPath[MAX_PATH];
if (*pwzRelativeUrl == L'#') { // Special case for intra page relative URLs.
// BugBug! How many other special case do we need to add to match
// the behavior of file:// and html:// ??
if (wcsLen(pwcInternalPath) + wcsLen(pwzRelativeUrl) >= MAX_PATH) return INET_E_INVALID_URL; wcsCpy(awcsInternalPath, pwcInternalPath); wcsCat(awcsInternalPath, pwzRelativeUrl); } else { // Here we assume that the relative url is a stream path suffix.
// Since we'll be combining with pwzRelativeUrl we must first
// truncate the internal path at the last storage name separator.
PWCHAR pwc = pwcInternalPath + wcsLen(pwcInternalPath);
for (;;) { WCHAR wc = *--pwc; if (wc == L'/' || wc == L'\\') break; }
*++pwc = 0;
cwc = wcsLen(pwzRelativeUrl);
if (!cwc) return URL_E_INVALID_SYNTAX;
WCHAR wc = pwzRelativeUrl[cwc - 1];
hr = ResolvePath(awcsInternalPath, (const WCHAR *) pwcInternalPath, (const WCHAR *) pwzRelativeUrl, (wc == L'/' || wc == L'\\') );
if (!SUCCEEDED(hr)) return hr; }
hr = AssembleUrl(pwzResult, cchResult, pcchResult, pwcProtocolName, pwcExternalPath, awcsInternalPath );
return hr; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::CompareUrl ( /* [in] */ LPCWSTR pwzUrl1, /* [in] */ LPCWSTR pwzUrl2, /* [in] */ DWORD dwCompareFlags ) { DWORD cwc1 = wcsLen(pwzUrl1);
PWCHAR pwcsBuffer1 = PWCHAR(_alloca((cwc1 + 1) * sizeof(WCHAR)));
if (!pwcsBuffer1) return E_OUTOFMEMORY;
CopyMemory(pwcsBuffer1, pwzUrl1, sizeof(WCHAR) * (cwc1 + 1));
PWCHAR pwcsExternalPath1 = NULL; PWCHAR pwcsInternalPath1 = NULL;
HRESULT hr = DisectUrl(pwcsBuffer1, NULL, &pwcsExternalPath1, &pwcsInternalPath1); if (!SUCCEEDED(hr)) return hr;
WCHAR awcsExternalPath1[MAX_PATH];
if (wcsLen(pwcsExternalPath1) < MAX_PATH) { wcsCpy(awcsExternalPath1, pwcsExternalPath1); PWCHAR pwc = wcsChr((const WCHAR *) awcsExternalPath1, L':');
if (pwc && pwc[1] == L':') // Ignore a "::" separator
pwc = NULL;
// Here we're special casing non-protocol references to a file.
// We recognize those situations by looking for a protocol prefix.
// Protocol prefixes have the form <Protocol Name> :
// where <Protocol Name> is always longer than one character.
if (!pwc || (pwc - awcsExternalPath1 == 1)) { if (FindRootStorageFile(awcsExternalPath1) == S_OK) pwcsExternalPath1 = awcsExternalPath1; } } DWORD cwc2 = wcsLen(pwzUrl2);
PWCHAR pwcsBuffer2 = PWCHAR(_alloca((cwc2 + 1) * sizeof(WCHAR)));
if (!pwcsBuffer2) return E_OUTOFMEMORY;
CopyMemory(pwcsBuffer2, pwzUrl2, sizeof(WCHAR) * (cwc2 + 1));
PWCHAR pwcsExternalPath2 = NULL; PWCHAR pwcsInternalPath2 = NULL;
hr = DisectUrl(pwcsBuffer2, NULL, &pwcsExternalPath2, &pwcsInternalPath2); if (!SUCCEEDED(hr)) return hr;
WCHAR awcsExternalPath2[MAX_PATH];
if (wcsLen(pwcsExternalPath2) < MAX_PATH) { wcsCpy(awcsExternalPath2, pwcsExternalPath2); PWCHAR pwc = wcsChr((const WCHAR *) awcsExternalPath2, L':');
if (pwc && pwc[1] == L':') // Ignore a "::" separator
pwc = NULL;
// Here we're special casing non-protocol references to a file.
// We recognize those situations by looking for a protocol prefix.
// Protocol prefixes have the form <Protocol Name> :
// where <Protocol Name> is always longer than one character.
if (!pwc || (pwc - awcsExternalPath2 == 1)) { if (FindRootStorageFile(awcsExternalPath2) == S_OK) pwcsExternalPath2 = awcsExternalPath2; } }
if (wcsicmp_0x0409((const WCHAR *) pwcsExternalPath1, (const WCHAR *) pwcsExternalPath2)) return S_FALSE;
if (wcsicmp_0x0409((const WCHAR *) pwcsInternalPath1, (const WCHAR *) pwcsInternalPath2)) return S_FALSE;
return S_OK; }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::QueryInfo ( /* [in] */ LPCWSTR pwzUrl, /* [in] */ QUERYOPTION QueryOption, /* [in] */ DWORD dwQueryFlags, /* [size_is][out][in] */ LPVOID pBuffer, /* [in] */ DWORD cbBuffer, /* [out][in] */ DWORD __RPC_FAR *pcbBuf, /* [in] */ DWORD dwReserved ) { switch (QueryOption) { case QUERY_CAN_NAVIGATE: // What does this really mean?
if (pcbBuf) *pcbBuf = sizeof(DWORD); if (cbBuffer < sizeof(DWORD)) return E_FAIL;
*(DWORD *) pBuffer = TRUE;
return NO_ERROR;
case QUERY_EXPIRATION_DATE: case QUERY_TIME_OF_LAST_CHANGE: // case QUERY_CONTEXT_ENCODING:
case QUERY_REFRESH: case QUERY_RECOMBINE:
default: // RonM_ASSERT(FALSE);
return E_NOTIMPL; } }
#ifdef PROFILING
// These wrapper functions are defined for the profiling version
// of the code so that we can measure how much time is consumed
// by callbacks into URLMON.
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Switch (PROTOCOLDATA __RPC_FAR *pProtocolData) { return m_pOIProtSink->Switch(pProtocolData); }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ReportProgress (ULONG ulStatusCode, LPCWSTR szStatusText) { return m_pOIProtSink->ReportProgress(ulStatusCode, szStatusText); }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ReportData (DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) { return m_pOIProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax); }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ReportResult (HRESULT hrResult, DWORD dwError, LPCWSTR szResult) { return m_pOIProtSink->ReportResult(hrResult, dwError, szResult); }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::GetBindInfo (DWORD __RPC_FAR *grfBINDF, BINDINFO __RPC_FAR *pbindinfo ) { return m_pOIBindInfo->GetBindInfo(grfBINDF, pbindinfo); }
HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::GetBindString (ULONG ulStringType, LPOLESTR __RPC_FAR *ppwzStr, ULONG cEl, ULONG __RPC_FAR *pcElFetched ) { return m_pOIBindInfo->GetBindString(ulStringType, ppwzStr, cEl, pcElFetched); }
#endif // PROFILING
|