2025-11-28 00:35:46 +09:00

272 lines
7.0 KiB
C++

#include "RssReader.hpp"
CRssReader::CRssReader()
{
_ulRef = 1;
_spXmlReader = NULL;
}
CRssReader::~CRssReader()
{
ASSERT(_ulRef == 1);
SAFE_RELEASE(_spXmlReader);
}
HRESULT CRssReader::ReadAsync(LPCWSTR pwszUrl)
{
HRESULT hr = S_OK;
IBindCtx* spBindCtx = NULL;
IMoniker* spMoniker = NULL;
IStream* spStream = NULL;
_bAsync = true;
CHKHR(::CreateURLMonikerEx(NULL, pwszUrl, &spMoniker, URL_MK_UNIFORM));
CHKHR(::CreateAsyncBindCtx(0, static_cast<IBindStatusCallback*>(this), NULL, &spBindCtx));
CHKHR(::CreateXmlReader(IID_IXmlReader, (void**) &_spXmlReader, NULL));
// Kicks off the binding.
#pragma warning(suppress: 6011) //spMoniker wouldn't be null if CreateURLMonikerEx() succeeds.
CHKHR(spMoniker->BindToStorage(spBindCtx, NULL, IID_IStream, (void **)&spStream));
// Pumps message until the download is finished.
MSG msg;
while (_bCompleted == false)
{
if (::PeekMessage(&msg, 0, 0 ,0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
CHKHR(::RevokeBindStatusCallback(spBindCtx, static_cast<IBindStatusCallback*>(this)));
CleanUp:
SAFE_RELEASE(spBindCtx);
SAFE_RELEASE(spMoniker);
SAFE_RELEASE(spStream);
SAFE_RELEASE(_spXmlReader);
return hr;
}
HRESULT CRssReader::ReadSync(LPCWSTR pwszUrl)
{
HRESULT hr = S_OK;
IBindCtx* spBindCtx = NULL;
IMoniker* spMoniker = NULL;
IStream* spStream = NULL;
_bAsync = false;
CHKHR(URLOpenBlockingStream(NULL, pwszUrl, &spStream, NULL, NULL));
CHKHR(::CreateXmlReader(IID_IXmlReader, (void**) &_spXmlReader, NULL));
CHKHR(_spXmlReader->SetInput(spStream));
CHKHR(Parse());
CleanUp:
SAFE_RELEASE(spBindCtx);
SAFE_RELEASE(spMoniker);
SAFE_RELEASE(spStream);
SAFE_RELEASE(_spXmlReader);
return hr;
}
HRESULT STDMETHODCALLTYPE CRssReader::QueryInterface(REFIID riid, void **ppvObject)
{
if (ppvObject == NULL)
return E_INVALIDARG;
if (riid == IID_IUnknown || riid == IID_IBindStatusCallback)
{
*ppvObject = dynamic_cast<IBindStatusCallback*>(this);
return S_OK;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
}
ULONG STDMETHODCALLTYPE CRssReader::AddRef(void)
{
_ulRef++;
return _ulRef;
}
ULONG STDMETHODCALLTYPE CRssReader::Release(void)
{
_ulRef--;
return _ulRef;
}
HRESULT STDMETHODCALLTYPE CRssReader::OnStartBinding(DWORD , __RPC__in_opt IBinding*)
{
_bCompleted = false;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CRssReader::GetPriority(__RPC__out LONG *pnPriority)
{
*pnPriority = NORMAL_PRIORITY_CLASS;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CRssReader::OnLowResource(DWORD )
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE CRssReader::OnProgress(ULONG , ULONG , ULONG , __RPC__in_opt LPCWSTR )
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE CRssReader::OnStopBinding(HRESULT , __RPC__in_opt LPCWSTR )
{
_bCompleted = true;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CRssReader::GetBindInfo(DWORD *grfBINDF, BINDINFO *pbindinfo)
{
// Describes how the bind process is handled.
*grfBINDF = BINDF_NOWRITECACHE | BINDF_RESYNCHRONIZE;
if (_bAsync)
*grfBINDF |= BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
// Describes how we want the binding to occur.
DWORD cbSize;
cbSize = pbindinfo->cbSize;
memset(pbindinfo, 0, cbSize);
pbindinfo->cbSize = cbSize;
pbindinfo->dwBindVerb = BINDVERB_GET;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CRssReader::OnDataAvailable(DWORD , DWORD , FORMATETC *, STGMEDIUM *pstgmed)
{
HRESULT hr = S_OK;
static BOOL firstDataNotification = TRUE;
if (firstDataNotification)
{
hr = _spXmlReader->SetInput(pstgmed->pstm);
if (SUCCEEDED(hr))
{
firstDataNotification = FALSE;
hr = Parse();
// Expects only partial data is available.
if (hr == E_PENDING)
hr = S_OK;
}
}
else
{
hr = Parse();
// Expects only partial data is available.
if (hr == E_PENDING)
hr = S_OK;
}
return hr;
}
HRESULT STDMETHODCALLTYPE CRssReader::OnObjectAvailable(__RPC__in REFIID , __RPC__in_opt IUnknown* )
{
return S_OK;
}
HRESULT CRssReader::Parse()
{
HRESULT hr;
XmlNodeType nodeType;
const wchar_t* pwszPrefix;
const wchar_t* pwszLocalName;
const wchar_t* pwszValue;
UINT cwchPrefix;
// Parses the stream with XmlLite when progressing.
while (S_OK == (hr = _spXmlReader->Read(&nodeType)))
{
const UINT buffSize = 8;
wchar_t buff[buffSize];
UINT charsRead = 0;
switch (nodeType)
{
case XmlNodeType_XmlDeclaration:
wprintf(L"XmlDeclaration\n");
break;
case XmlNodeType_Element:
CHKHR(_spXmlReader->GetPrefix(&pwszPrefix, &cwchPrefix));
CHKHR(_spXmlReader->GetLocalName(&pwszLocalName, NULL));
if (cwchPrefix > 0)
wprintf(L"Element: %s:%s\n", pwszPrefix, pwszLocalName);
else
wprintf(L"Element: %s\n", pwszLocalName);
if (_spXmlReader->IsEmptyElement() )
wprintf(L" (empty)");
break;
case XmlNodeType_EndElement:
CHKHR(_spXmlReader->GetPrefix(&pwszPrefix, &cwchPrefix));
CHKHR(_spXmlReader->GetLocalName(&pwszLocalName, NULL));
if (cwchPrefix > 0)
wprintf(L"End Element: %s:%s\n", pwszPrefix, pwszLocalName);
else
wprintf(L"End Element: %s\n", pwszLocalName);
break;
case XmlNodeType_Text:
CHKHR(_spXmlReader->GetValue(&pwszValue, NULL));
wprintf(L"Text: %s\n", pwszValue);
break;
case XmlNodeType_Whitespace:
wprintf(L"Whitespace: ");
while (true)
{
CHKHR(_spXmlReader->ReadValueChunk(buff, buffSize - 1, &charsRead));
if (S_FALSE == hr || 0 == charsRead)
break;
buff[charsRead] = NULL;
wprintf(L"%s", buff);
}
wprintf(L"\n");
break;
case XmlNodeType_CDATA:
CHKHR(_spXmlReader->GetValue(&pwszValue, NULL));
wprintf(L"CDATA: %s\n", pwszValue);
break;
case XmlNodeType_ProcessingInstruction:
CHKHR(_spXmlReader->GetLocalName(&pwszLocalName, NULL));
CHKHR(_spXmlReader->GetValue(&pwszValue, NULL));
wprintf(L"Processing Instruction name:%s value:%s\n", pwszLocalName, pwszValue);
break;
case XmlNodeType_Comment:
CHKHR(_spXmlReader->GetValue(&pwszValue, NULL));
wprintf(L"Comment: %s\n", pwszValue);
break;
case XmlNodeType_DocumentType:
wprintf(L"DOCTYPE is not printed\n");
break;
default:
wprintf(L"Unknown node type\n");
break;
}
}
CleanUp:
return hr;
}