// Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995. // File: CMimeFt.cxx // Contents: // Classes: // Functions: // History: 04-16-97 DanpoZ (Danpo Zhang) Created #include PerfDbgTag(tagMft, "Pluggable MF ", "Log CMimeFt", DEB_PROT) DbgTag(tagMftErr,"Pluggable MF", "Log CMimeFt Errors", DEB_PROT|DEB_ERROR) PerfDbgTag(tagPF, "Pluggable MF ", "Log Perf", DEB_PROT) #ifndef unix #define JOB_MINS_PER_HOUR 60i64 #define JOB_HOURS_PER_DAY 24i64 #define JOB_MILLISECONDS_PER_SECOND 1000i64 #define JOB_MILLISECONDS_PER_MINUTE (60i64 * JOB_MILLISECONDS_PER_SECOND) #define FILETIMES_PER_MILLISECOND 10000i64 #define FILETIMES_PER_MINUTE (FILETIMES_PER_MILLISECOND * JOB_MILLISECONDS_PER_MINUTE) #define FILETIMES_PER_DAY (FILETIMES_PER_MINUTE * JOB_MINS_PER_HOUR * JOB_HOURS_PER_DAY) #else #define JOB_MINS_PER_HOUR 60LL #define JOB_HOURS_PER_DAY 24LL #define JOB_MILLISECONDS_PER_SECOND 1000LL #define JOB_MILLISECONDS_PER_MINUTE (60LL * JOB_MILLISECONDS_PER_SECOND) #define FILETIMES_PER_MILLISECOND 10000LL #define FILETIMES_PER_MINUTE (FILETIMES_PER_MILLISECOND * JOB_MILLISECONDS_PER_MINUTE) #define FILETIMES_PER_DAY (FILETIMES_PER_MINUTE * JOB_MINS_PER_HOUR * JOB_HOURS_PER_DAY) #endif /* unix */ void AddDaysToFileTime(LPFILETIME pft, WORD Days) { if (!Days) { return; // Nothing to do. } // ft = ft + Days * FILETIMES_PER_DAY; ULARGE_INTEGER uli, uliSum; uli.LowPart = pft->dwLowDateTime; uli.HighPart = pft->dwHighDateTime; #ifndef unix uliSum.QuadPart = uli.QuadPart + (__int64)Days * FILETIMES_PER_DAY; #else U_QUAD_PART(uliSum) = U_QUAD_PART(uli) + (__int64)Days * FILETIMES_PER_DAY; #endif /* unix */ pft->dwLowDateTime = uliSum.LowPart; pft->dwHighDateTime = uliSum.HighPart; } // helper from transapi.cxx HRESULT GetMimeFileExtension(LPSTR, LPSTR, DWORD); // Method: CMimeFt::QueryInterface // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::QueryInterface(REFIID riid, void **ppvObj) { PerfDbgLog(tagMft, this, "+CMimeFt::QueryInterface"); VDATEPTROUT(ppvObj, void*); VDATETHIS(this); HRESULT hr = NOERROR; *ppvObj = NULL; if( (riid == IID_IUnknown) || (riid == IID_IOInetProtocol) || (riid == IID_IOInetProtocolRoot)) { *ppvObj = (IOInetProtocol*) this; AddRef(); } else if (riid == IID_IOInetProtocolSink ) { *ppvObj = (IOInetProtocolSink*) this; AddRef(); } else if (riid == IID_IOInetProtocolSinkStackable ) { *ppvObj = (IOInetProtocolSinkStackable*) this; AddRef(); } else hr = E_NOINTERFACE; PerfDbgLog1(tagMft, this, "-CMimeFt::QueryInterface(hr:%1x)", hr); return hr; } // Method: CMimeFt::AddRef // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP_(ULONG) CMimeFt::AddRef(void) { PerfDbgLog(tagMft, this, "+CMimeFt::AddRef"); LONG lRet = ++_CRefs; PerfDbgLog1(tagMft, this, "-CMimeFt::AddRef (cRef:%1d)", lRet); return lRet; } // Method: CMimeFt::Release // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP_(ULONG) CMimeFt::Release(void) { PerfDbgLog(tagMft, this, "+CMimeFt::Release"); LONG lRet = --_CRefs; if( !lRet ) delete this; PerfDbgLog1(tagMft, this, "-CMimeFt::Release (cRef:%1d)", lRet); return lRet; } // Method: CMimeFt::Start // Synopsis: // Arguments: [pwzUrl] -- // [pProtSink] -- // [pOIBindInfo] -- // [grfSTI] -- // [dwReserved] -- // Returns: E_PENDING indicating the current filter is not empty // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Start( LPCWSTR pwzUrl, IOInetProtocolSink *pProtSink, IOInetBindInfo *pOIBindInfo, DWORD grfPI, DWORD_PTR dwReserved) { PerfDbgLog(tagMft, this, "+CMimeFt::Start"); PerfDbgLog(tagPF, this, "*************CMimeFt::Start"); PProtAssert( pwzUrl && (!_pProtSink) && pProtSink && dwReserved ); HRESULT hr = NOERROR; PProtAssert((grfPI & PI_FILTER_MODE)); if( !(grfPI & PI_FILTER_MODE) ) hr = E_INVALIDARG; // download or upload? from the rrfPI flag... if( !hr ) { //get the Prot pointer here PROTOCOLFILTERDATA* FiltData = (PROTOCOLFILTERDATA*) dwReserved; _pProt = FiltData->pProtocol; _pProt->AddRef(); //get the sink pointer here _pProtSink = pProtSink; _pProtSink->AddRef(); // create or reload the data filter if( _pDF ) { _pDF->Release(); _pDF = NULL; } // this piece needs some more work // 1. pEFtFac will be CoCreated according to reg setting // 2. We will keep a linked list for existing EFFactory IEncodingFilterFactory* pEFtFac = new CEncodingFilterFactory; if( pEFtFac ) { // should we use enum or string value? hr = pEFtFac->GetDefaultFilter( pwzUrl, L"text", &_pDF); PProtAssert(_pDF); // don't need the factory anymore, // but later, we will keep it on the list pEFtFac->Release(); // reset all internal counter _ulCurSizeFmtIn = 0; _ulCurSizeFmtOut = 0; _ulTotalSizeFmtIn = 0; _ulTotalSizeFmtOut = 0; _ulOutAvailable = 0; _ulContentLength = 0; hr = _pProtSink->ReportProgress(BINDSTATUS_DECODING, pwzUrl); } else hr = E_OUTOFMEMORY; BOOL fNeedCache = TRUE; if( hr == NOERROR ) { DWORD dwBINDF; BINDINFO bindInfo; bindInfo.cbSize = sizeof(BINDINFO); hr = pOIBindInfo->GetBindInfo(&dwBINDF, &bindInfo); // not generate cache file if user specifies BINDF_NOWRITECACHE if( hr == NOERROR) { if( dwBINDF & BINDF_NOWRITECACHE ) { fNeedCache = FALSE; } // BINDINFO_FIX(LaszloG) 8/15/96 ReleaseBindInfo(&bindInfo); } } if( hr == NOERROR && fNeedCache ) { // Create cache file entry // 1. get url name ULONG ulCount; LPWSTR rgwzStr[1] = {NULL}; LPSTR pszURL = NULL; hr = pOIBindInfo->GetBindString( BINDSTRING_URL, (LPWSTR*)rgwzStr, 1, &ulCount); if( hr == NOERROR && ulCount == 1 ) { pszURL = DupW2A(rgwzStr[0]); if( pszURL ) { strncpy(_szURL, pszURL, MAX_PATH); } else { _szURL[0] = '\0'; } } delete [] rgwzStr[0]; delete [] pszURL; /******** move to ::Read to get accurate file ext ****** // 2. get cache file name and create file handle if( hr == NOERROR && _szURL[0] != '\0' ) { LPSTR pszExt = NULL; pszExt = FindFileExtension(_szURL); if( pszExt && *pszExt == '.' ) { // FindFileExtion will return ".htm" but wininet is // expecting "htm", so remove the extra "." pszExt++; } if( CreateUrlCacheEntry(_szURL, 0, pszExt, _szFileName, 0) ) { if( _szFileName[0] != '\0' ) { _hFile = CreateFile(_szFileName, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if( _hFile == INVALID_HANDLE_VALUE ) { _hFile = NULL; } } } } // Report the CACHE file name LPWSTR pwzFileName = NULL; if( _szFileName[0] != '\0' ) { pwzFileName = DupA2W(_szFileName); } if( pwzFileName ) { ReportProgress( BINDSTATUS_CACHEFILENAMEAVAILABLE, pwzFileName); delete [] pwzFileName; } ******** move to ::Read to get accurate file ext ******/ } } PerfDbgLog1(tagMft, this, "-CMimeFt::Start (hr:%1x)", hr); return hr; } // Method: CMimeFt::Continue // Synopsis: // Arguments: [pStateInfo] -- // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Continue( PROTOCOLDATA *pStateInfo) { PerfDbgLog(tagMft, this, "+CMimeFt::Continue"); PProtAssert( _pProt ); HRESULT hr = _pProt->Continue(pStateInfo); PerfDbgLog1(tagMft, this, "-CMimeFt::Continue(hr:%1x)", hr); return hr; } // Method: CMimeFt::Abort // Synopsis: // Arguments: [hrReason] -- // [dwOptions] -- // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Abort( HRESULT hrReason, DWORD dwOptions) { PerfDbgLog(tagMft, this, "+CMimeFt::Abort"); PProtAssert( _pProt ); HRESULT hr = _pProt->Abort(hrReason, dwOptions); PerfDbgLog1(tagMft, this, "-CMimeFt::Abort(hr:%1x)", hr); return hr; } // Method: CMimeFt::Terminate // Synopsis: // Arguments: [dwOptions] -- // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Terminate( DWORD dwOptions) { PerfDbgLog(tagMft, this, "+CMimeFt::Terminate"); PProtAssert( _pProt ); HRESULT hr = NOERROR; // release the sink if( _pProtSink ) { _pProtSink->Release(); //_pProtSink = NULL; } // unload the data filter if( _pDF ) { _pDF->Release(); _pDF = NULL; } // get expire and lastmodified time from wininet INTERNET_CACHE_TIMESTAMPS st; DWORD cbSt = sizeof(st); memset(&st, 0, cbSt); if (_pProt) { IWinInetHttpInfo* pWin = NULL; hr = _pProt->QueryInterface(IID_IWinInetHttpInfo, (void**)&pWin); if( hr == NOERROR && pWin ) { pWin->QueryOption( INTERNET_OPTION_CACHE_TIMESTAMPS, &st, &cbSt); pWin->Release(); } } // close the file handle if( _hFile ) { CloseHandle(_hFile); _hFile = NULL; } // Commit ( or delete) cache file entry if( _szFileName[0] != '\0' && _szURL[0] != '\0' ) { char szHeader[256]; char szMime[64]; W2A(_pwzMimeSuggested, szMime, 64); wsprintf(szHeader, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: %s\r\n\r\n", _ulContentLength, szMime); DWORD dwLen = strlen(szHeader); CommitUrlCacheEntry( _szURL, _szFileName, st.ftExpires, st.ftLastModified, NORMAL_CACHE_ENTRY, (LPBYTE)szHeader, dwLen, NULL, 0); } if (_pProt) { hr = _pProt->Terminate(dwOptions); } PerfDbgLog1(tagMft, this, "-CMimeFt::Terminate(hr:%1x)", hr); PerfDbgLog(tagPF, this, "*************CMimeFt::Terminate"); return hr; } // Method: CMimeFt::Suspend // Synopsis: // Arguments: [none] // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Suspend() { PerfDbgLog(tagMft, this, "+CMimeFt::Suspend"); PProtAssert( _pProt ); HRESULT hr = _pProt->Suspend(); PerfDbgLog1(tagMft, this, "-CMimeFt::Suspend(hr:%1x)", hr); return hr; } // Method: CMimeFt::Resume // Synopsis: // Arguments: [none] // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Resume() { PerfDbgLog(tagMft, this, "+CMimeFt::Resume"); PProtAssert( _pProt ); HRESULT hr = _pProt->Resume(); PerfDbgLog1(tagMft, this, "-CMimeFt::Suspend(hr:%1x)", hr); return hr; } // Method: CMimeFt::Read // Synopsis: The real read is implemented in SmartRead, which also // serves as a data sniffer // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Read(void *pv, ULONG cb, ULONG *pcbRead) { HRESULT hr = NOERROR; hr = SmartRead(pv, cb, pcbRead, FALSE); // do delay report result if( hr == S_FALSE && _fDelayReport ) { ReportResult(_hrResult, _dwError, _wzResult); } return hr; } // Method: CMimeFt::SmartRead // Synopsis: implementation of ::Read, we add one parameter indicating // if this read is for data sniffing purpose, // (the goal datasniff read is to ReportProgress(MIME), // data is not returned to the user buffer, this is to overcome // the problem that if you do data sniffing in the real Read and // report progress from a free thread, the message won't get // to the apartment thread until it finishs the read, which // might be too late for BindToObject) // Arguments: // Returns: // History: 11-24-97 DanpoZ (Danpo Zhang) Created // Notes: HRESULT CMimeFt::SmartRead(void *pv, ULONG cb, ULONG *pcbRead, BOOL fSniff) { PerfDbgLog(tagMft, this, "+CMimeFt::Read"); if(fSniff) { PerfDbgLog(tagMft, this, "+CMimeFt::Read - sniffing"); } else { PProtAssert( pv && _pOutBuf && pcbRead ); } HRESULT hr = NOERROR; LONG lRead = 0; HRESULT hrRead = E_FAIL; HRESULT hrCode = NOERROR; BOOL fPullData = FALSE; // no data, I have to pull more if( _ulOutAvailable == 0 ) { if( _ulInBufferLeft == 0) { hrRead = _pProt->Read(_pInBuf, FT_IBUF_SIZE-2, (ULONG*)&lRead); PerfDbgLog2(tagMft, this, " CMimeFt::Read-Pull %u bytes (hr %1x)", lRead, hrRead); fPullData = TRUE; } else { lRead = _ulInBufferLeft; } } if( lRead ) { LONG lInUsed = 0; LONG lOutUsed = 0; BYTE* pInBuf = _pInBuf; if( _bEncoding ) hrCode = _pDF->DoEncode( 0, FT_IBUF_SIZE, pInBuf, FT_OBUF_SIZE, _pOutBuf, lRead, &lInUsed, &lOutUsed, 0); else { hrCode = _pDF->DoDecode( 0, FT_IBUF_SIZE, pInBuf, FT_OBUF_SIZE, _pOutBuf, lRead, &lInUsed, &lOutUsed, 0); } if( hrCode != NOERROR ) { // error msg from winerr.h _pProtSink->ReportResult(hr, CRYPT_E_BAD_ENCODE, NULL); // make sure we clean up the filter _ulOutAvailable = 0; _ulInBufferLeft = 0; PerfDbgLog(tagMft, this, " CMimeFt::Read-Encode/Decode Failed"); } else { // update _ulCurSizeFmtOut += lOutUsed; _ulOutAvailable = lOutUsed; // do we get all the data? if( lInUsed < lRead ) { // move mem to front memcpy(_pInBuf, _pInBuf+lInUsed, lRead-lInUsed); _ulInBufferLeft = lRead - lInUsed; } else { _ulInBufferLeft = 0; } if( !_bMimeVerified ) { _bMimeVerified = TRUE; LPWSTR pwzStr = NULL; LPWSTR pwzFileName = NULL; if( _szFileName[0] != '\0' ) { pwzFileName = DupA2W(_szFileName); } FindMimeFromData(NULL, pwzFileName, _pOutBuf, lOutUsed, _pwzMimeSuggested, 0, &pwzStr, 0); pwzFileName = NULL; if( !_bMimeReported && !_bEncoding ) { _bMimeReported = TRUE; if( pwzStr ) { hr = _pProtSink->ReportProgress( BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, pwzStr); } else { hr = _pProtSink->ReportProgress( BINDSTATUS_MIMETYPEAVAILABLE, L"text/html"); } } if( pwzStr ) { delete [] _pwzMimeSuggested; _pwzMimeSuggested = pwzStr; pwzStr = NULL; } //------- moved from ::Start to get accurate file ext if( hr == NOERROR && _szURL[0] != '\0' ) { LPSTR pszExt = NULL; pszExt = FindFileExtension(_szURL); // HACK... need some API to tell if ext is valid... // here we assume ext with 3 chars // including the ".", it will be 4 char if( pszExt && strlen(pszExt) > 5 ) { LPSTR pszMime = DupW2A(_pwzMimeSuggested); GetMimeFileExtension( pszMime, pszExt, 20); delete [] pszMime; } if( pszExt && *pszExt == '.' ) { // FindFileExtion will return ".htm" but wininet is // expecting "htm", so remove the extra "." pszExt++; } if( CreateUrlCacheEntry(_szURL, 0, pszExt, _szFileName, 0) ) { if( _szFileName[0] != '\0' ) { _hFile = CreateFile(_szFileName, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if( _hFile == INVALID_HANDLE_VALUE ) { _hFile = NULL; } } } } // Report the CACHE file name if( _szFileName[0] != '\0' ) { pwzFileName = DupA2W(_szFileName); } if( pwzFileName ) { ReportProgress( BINDSTATUS_CACHEFILENAMEAVAILABLE, pwzFileName); delete [] pwzFileName; } //------- moved from ::Start to get accurate file ext } // write to the file if( _hFile ) { DWORD dwBytesWritten; WriteFile(_hFile, _pOutBuf, lOutUsed, &dwBytesWritten, NULL); if( lOutUsed != (LONG)dwBytesWritten ) { // write failed, clean up everything CloseHandle(_hFile); _hFile = NULL; DeleteUrlCacheEntry( _szURL ); _szFileName[0] = '\0'; _szURL[0] = '\0'; } } PerfDbgLog2(tagMft, this, " CMimeFt::Read-Encode/Decode %u bytes-> %u bytes", lInUsed, lOutUsed); } } else PerfDbgLog(tagMft, this, " CMimeFt::Read-in buffer empty"); // copy over (only for the purpose of non-sniffing) if( !fSniff && (hrCode == NOERROR) && _ulOutAvailable ) { if( cb >= _ulOutAvailable ) { // client has bigger buffer memcpy(pv, _pOutBuf, _ulOutAvailable); *pcbRead = _ulOutAvailable; _ulOutAvailable = 0; hr = S_OK; PerfDbgLog1(tagMft, this, " CMimeFt::Read-enough buffer copied %u bytes", *pcbRead); } else { // client have smaller buffer memcpy(pv, _pOutBuf, cb); *pcbRead = cb; // move mem to front memcpy(_pOutBuf, _pOutBuf+cb, _ulOutAvailable-cb); _ulOutAvailable -= cb; hr = S_OK; PerfDbgLog1(tagMft, this, " CMimeFt::Read-not enough buffer copied %u bytes", cb); } // keep the total (content-length) _ulContentLength += *pcbRead; } // If we pulled the data, we should report that hr if( fPullData ) hr = hrRead; // if encode-decode error occurs, we report it if( hrCode != NOERROR ) hr = hrCode; // if all data are gone and LASTNOTIFICATION, we should return S_FALSE if(_grfBSCF & BSCF_LASTDATANOTIFICATION && (_ulOutAvailable == 0) ) { PerfDbgLog(tagMft, this, " CMimeFt::Read-Last Notification, set hr --> 1" ); hr = S_FALSE; } PerfDbgLog1(tagMft, this, "-CMimeFt::Read (hr:%1x)", hr); return hr; } // Method: CMimeFt::Seek // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { PerfDbgLog(tagMft, this, "+CMimeFt::Seek"); // Seek will be available later HRESULT hr = E_NOTIMPL; PerfDbgLog1(tagMft, this, "-CMimeFt::Seek (hr:%1x)", hr); return hr; } // Method: CMimeFt::LockRequest // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::LockRequest(DWORD dwOptions) { PerfDbgLog(tagMft, this, "+CMimeFt::LockRequest"); PProtAssert(_pProt); HRESULT hr = _pProt->LockRequest(dwOptions); PerfDbgLog1(tagMft, this, "-CMimeFt::LockRequest(hr:%1x)", hr); return hr; } // Method: CMimeFt::UnlockRequest // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::UnlockRequest() { PerfDbgLog(tagMft, this, "+CMimeFt::UnLockRequest"); PProtAssert(_pProt); HRESULT hr = _pProt->UnlockRequest(); PerfDbgLog1(tagMft, this, "-CMimeFt::UnLockRequest(hr:%1x)", hr); return hr; } // Method: CMimeFt::Switch // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::Switch(PROTOCOLDATA *pStateInfo) { PerfDbgLog(tagMft, this, "+CMimeFt::Switch"); PProtAssert(_pProtSink); HRESULT hr = _pProtSink->Switch(pStateInfo); PerfDbgLog1(tagMft, this, "-CMimeFt::Switch (hr:%1x)", hr); return hr; } // Method: CMimeFt::ReportProgress // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::ReportProgress( ULONG ulStatusCode, LPCWSTR szStatusText) { PerfDbgLog(tagMft, this, "+CMimeFt::ReportProgress"); PProtAssert(_pProtSink); HRESULT hr = NOERROR; if( ulStatusCode == BINDSTATUS_MIMETYPEAVAILABLE ) { delete [] _pwzMimeSuggested; _pwzMimeSuggested = OLESTRDuplicate(szStatusText); if( !_pwzMimeSuggested ) { hr = E_OUTOFMEMORY; } } else { hr = _pProtSink->ReportProgress(ulStatusCode, szStatusText); } PerfDbgLog1(tagMft, this, "-CMimeFt::ReportProgress(hr:%1x)", hr); return hr; } // Method: CMimeFt::ReportData // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: E_PENDING returned if the filter is not empty STDMETHODIMP CMimeFt::ReportData( DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) { PerfDbgLog(tagMft, this, "+CMimeFt::ReportData"); HRESULT hr = NOERROR; // Do a data sniffing Read to get the mime type out of the buffer // reason for _fSniffed, _fSniffInProgress and _fDelayReport // is that if the data sniffing SmartRead() reaches EOF, the protocol // will do ReportResult() which we want to delay until the Real Read // finishs if( !_fSniffed && !_fSniffInProgress ) { _fSniffInProgress = TRUE; hr = SmartRead( NULL, 0, 0, TRUE); _fSniffInProgress = FALSE; _fSniffed = TRUE; } if( _fSniffed ) { hr = _pProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax); } PerfDbgLog1(tagMft, this, "-CMimeFt::ReportData(hr:%1x)", hr); return hr; } // Method: CMimeFt::ReportResult // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::ReportResult(HRESULT hrResult, DWORD dwError, LPCWSTR wzResult) { PerfDbgLog(tagMft, this, "+CMimeFt::ReportResult"); // REVISIT PProtAssert(_pProtSink); HRESULT hr = NOERROR; if( _fSniffInProgress ) { // keep it and report it after read completes _hrResult = hrResult; _dwError = dwError; _wzResult = wzResult; // should be OLEDuplicateStr() _fDelayReport = TRUE; } else { hr = _pProtSink->ReportResult(hrResult, dwError, wzResult); } PerfDbgLog1(tagMft, this, "-CMimeFt::ReportResult(hr:%1x)", hr); return hr; } // Method: CMimeFt::SwitchSink // Synopsis: // Arguments: // Returns: // History: 11-24-97 DanpoZ (Danpo Zhang) Created // Notes: STDMETHODIMP CMimeFt::SwitchSink(IOInetProtocolSink* pSink) { PerfDbgLog(tagMft, this, "+CMimeFt::SwitchSink"); // REVISIT PProtAssert(_pProtSink && pSink); HRESULT hr = NOERROR; // keep track the existing sink (support for Commit/Rollback) // the release of the old sink will be done at the Commit time _pProtSinkOld = _pProtSink; // BUG: remove this block once enable the Commit-Rollback func // release the old sink if( _pProtSinkOld ) { _pProtSinkOld->Release(); } // Change the sink _pProtSink = pSink; _pProtSink->AddRef(); PerfDbgLog1(tagMft, this, "-CMimeFt::SwitchSink(hr:%1x)", hr); return hr; } // Method: CMimeFt::CommitSwitch // Synopsis: // Arguments: // Returns: // History: 11-24-97 DanpoZ (Danpo Zhang) Created // Notes: Commit the sink switch, what we are doing here is // Release the old sink (old sink is coming from the // Start method and AddRef'ed there STDMETHODIMP CMimeFt::CommitSwitch() { PerfDbgLog(tagMft, this, "+CMimeFt::CommitSwitch"); // release the old sink //if( _pProtSinkOld ) //{ // _pProtSinkOld->Release(); //} // reset //_pProtSinkOld = NULL; PerfDbgLog(tagMft, this, "-CMimeFt::CommitSwitch"); return NOERROR; } // Method: CMimeFt::RollbackSwitch // Synopsis: // Arguments: // Returns: // History: 11-24-97 DanpoZ (Danpo Zhang) Created // Notes: Error occured (most possibly the StackFilter() call failed, // we have to rollback the sink switch, what we are doing // here is releasing the switched sink (AddRef'ed at SwitchSink // time), and set the original sink back, no ref count work on // the original sink STDMETHODIMP CMimeFt::RollbackSwitch() { PerfDbgLog(tagMft, this, "+CMimeFt::RollbackSwitch"); // copy the old sink back, release the new sink // (new sink is AddRef'ed at SwitchSink time) //if( _pProtSink ) //{ // _pProtSink->Release(); //} //_pProtSink = _pProtSinkOld; // reset //_pProtSinkOld = NULL; PerfDbgLog(tagMft, this, "-CMimeFt::RollbackSwitch"); return NOERROR; } // Method: CMimeFt::Create // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: HRESULT CMimeFt::Create(CMimeFt** ppv) { PerfDbgLog(tagMft, NULL, "+CMimeFt::Create"); HRESULT hr = NOERROR; // pProt can not be NULL PProtAssert(ppv); *ppv = NULL; *ppv = new CMimeFt; if( *ppv == NULL ) hr = E_OUTOFMEMORY; else hr = (*ppv)->CreateBuffer(); PerfDbgLog1(tagMft, NULL, "-CMimeFt::Create(hr:%1x)", hr); return hr; } // Method: CMimeFt::CMimeFt // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: CMimeFt::CMimeFt() : _CRefs() { PerfDbgLog(tagMft, this, "+CMimeFt::CMimeFt"); _pProtSink = NULL; _pProt = NULL; _pProtSinkOld = NULL; _pDF = NULL; _ulCurSizeFmtIn = 0; _ulCurSizeFmtOut = 0; _ulTotalSizeFmtIn = 0; _ulTotalSizeFmtOut = 0; _ulOutAvailable = 0; _ulInBufferLeft = 0; _pInBuf = NULL; _pOutBuf = NULL; _grfBSCF = 0x00; _bMimeReported = FALSE; _bMimeVerified = FALSE; _szFileName[0] = '\0'; _szURL[0] = '\0'; _hFile = NULL; _pwzMimeSuggested = NULL; _fDelayReport = FALSE; _fSniffed = FALSE; _fSniffInProgress = FALSE; _hrResult = NOERROR; _dwError = 0; _wzResult = NULL; DllAddRef(); PerfDbgLog(tagMft, this, "-CMimeFt::CMimeFt"); } // Method: CMimeFt::CreateBuffer // Synopsis: // Arguments: // Returns: // History: 04-30-97 DanpoZ (Danpo Zhang) Created // Notes: HRESULT CMimeFt::CreateBuffer() { PerfDbgLog(tagMft, this, "+CMimeFt::CreateBuffer"); HRESULT hr = NOERROR; _pInBuf = new BYTE[FT_IBUF_SIZE]; _pOutBuf = new BYTE[FT_OBUF_SIZE]; PProtAssert(_pInBuf && _pOutBuf); if( !_pInBuf || !_pOutBuf ) hr = E_OUTOFMEMORY; PerfDbgLog1(tagMft, this, "-CMimeFt::CreateBuffer(hr:%1x)", hr); return hr; } // Method: CMimeFt::~CMimeFt // Synopsis: // Arguments: // Returns: // History: 04-16-97 DanpoZ (Danpo Zhang) Created // Notes: CMimeFt::~CMimeFt() { PerfDbgLog(tagMft, this, "+CMimeFt::~CMimeFt"); if( _pInBuf ) delete [] _pInBuf; if( _pOutBuf ) delete [] _pOutBuf; delete [] _pwzMimeSuggested; if( _pProt ) _pProt->Release(); if( _pDF) _pDF->Release(); if( _hFile ) CloseHandle(_hFile); DllRelease(); PerfDbgLog(tagMft, this, "-CMimeFt::~CMimeFt"); }