📄 xmlwin32url.cxx
字号:
#include "expat.h"#ifdef XML_UNICODE#define UNICODE#endif#include <windows.h>#include <urlmon.h>#include <wininet.h>#include <stdio.h>#include <tchar.h>#include "xmlurl.h"#include "xmlmime.h"static intprocessURL(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *url);typedef void (*StopHandler)(void *, HRESULT);class Callback : public IBindStatusCallback {public: // IUnknown methods STDMETHODIMP QueryInterface(REFIID,void **); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // IBindStatusCallback methods STDMETHODIMP OnStartBinding(DWORD, IBinding *); STDMETHODIMP GetPriority(LONG *); STDMETHODIMP OnLowResource(DWORD); STDMETHODIMP OnProgress(ULONG, ULONG, ULONG, LPCWSTR); STDMETHODIMP OnStopBinding(HRESULT, LPCWSTR); STDMETHODIMP GetBindInfo(DWORD *, BINDINFO *); STDMETHODIMP OnDataAvailable(DWORD, DWORD, FORMATETC *, STGMEDIUM *); STDMETHODIMP OnObjectAvailable(REFIID, IUnknown *); Callback(XML_Parser, IMoniker *, StopHandler, void *); ~Callback(); int externalEntityRef(const XML_Char *context, const XML_Char *systemId, const XML_Char *publicId);private: XML_Parser parser_; IMoniker *baseMoniker_; DWORD totalRead_; ULONG ref_; IBinding *pBinding_; StopHandler stopHandler_; void *stopArg_;};STDMETHODIMP_(ULONG)Callback::AddRef(){ return ref_++;}STDMETHODIMP_(ULONG)Callback::Release(){ if (--ref_ == 0) { delete this; return 0; } return ref_;}STDMETHODIMPCallback::QueryInterface(REFIID riid, void** ppv){ if (IsEqualGUID(riid, IID_IUnknown)) *ppv = (IUnknown *)this; else if (IsEqualGUID(riid, IID_IBindStatusCallback)) *ppv = (IBindStatusCallback *)this; else return E_NOINTERFACE; ((LPUNKNOWN)*ppv)->AddRef(); return S_OK;}STDMETHODIMPCallback::OnStartBinding(DWORD, IBinding* pBinding){ pBinding_ = pBinding; pBinding->AddRef(); return S_OK;}STDMETHODIMPCallback::GetPriority(LONG *){ return E_NOTIMPL;}STDMETHODIMPCallback::OnLowResource(DWORD){ return E_NOTIMPL;}STDMETHODIMPCallback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR){ return S_OK;}STDMETHODIMPCallback::OnStopBinding(HRESULT hr, LPCWSTR szError){ if (pBinding_) { pBinding_->Release(); pBinding_ = 0; } if (baseMoniker_) { baseMoniker_->Release(); baseMoniker_ = 0; } stopHandler_(stopArg_, hr); return S_OK;}STDMETHODIMPCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo){ *pgrfBINDF = BINDF_ASYNCHRONOUS; return S_OK;}static voidreportError(XML_Parser parser){ int code = XML_GetErrorCode(parser); const XML_Char *message = XML_ErrorString(code); if (message) _ftprintf(stderr, _T("%s:%d:%ld: %s\n"), XML_GetBase(parser), XML_GetErrorLineNumber(parser), XML_GetErrorColumnNumber(parser), message); else _ftprintf(stderr, _T("%s: (unknown message %d)\n"), XML_GetBase(parser), code);}STDMETHODIMPCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pfmtetc, STGMEDIUM* pstgmed){ if (grfBSCF & BSCF_FIRSTDATANOTIFICATION) { IWinInetHttpInfo *hp; HRESULT hr = pBinding_->QueryInterface(IID_IWinInetHttpInfo, (void **)&hp); if (SUCCEEDED(hr)) { char contentType[1024]; DWORD bufSize = sizeof(contentType); DWORD flags = 0; contentType[0] = 0; hr = hp->QueryInfo(HTTP_QUERY_CONTENT_TYPE, contentType, &bufSize, 0, NULL); if (SUCCEEDED(hr)) { char charset[CHARSET_MAX]; getXMLCharset(contentType, charset); if (charset[0]) {#ifdef XML_UNICODE XML_Char wcharset[CHARSET_MAX]; XML_Char *p1 = wcharset; const char *p2 = charset; while ((*p1++ = (unsigned char)*p2++) != 0) ; XML_SetEncoding(parser_, wcharset);#else XML_SetEncoding(parser_, charset);#endif } } hp->Release(); } } if (!parser_) return E_ABORT; if (pstgmed->tymed == TYMED_ISTREAM) { while (totalRead_ < dwSize) {#define READ_MAX (64*1024) DWORD nToRead = dwSize - totalRead_; if (nToRead > READ_MAX) nToRead = READ_MAX; void *buf = XML_GetBuffer(parser_, nToRead); if (!buf) { _ftprintf(stderr, _T("out of memory\n")); return E_ABORT; } DWORD nRead; HRESULT hr = pstgmed->pstm->Read(buf, nToRead, &nRead); if (SUCCEEDED(hr)) { totalRead_ += nRead; if (!XML_ParseBuffer(parser_, nRead, (grfBSCF & BSCF_LASTDATANOTIFICATION) != 0 && totalRead_ == dwSize)) { reportError(parser_); return E_ABORT; } } } } return S_OK;}STDMETHODIMPCallback::OnObjectAvailable(REFIID, IUnknown *){ return S_OK;}intCallback::externalEntityRef(const XML_Char *context, const XML_Char *systemId, const XML_Char *publicId){ XML_Parser entParser = XML_ExternalEntityParserCreate(parser_, context, 0); XML_SetBase(entParser, systemId); int ret = processURL(entParser, baseMoniker_, systemId); XML_ParserFree(entParser); return ret;}Callback::Callback(XML_Parser parser, IMoniker *baseMoniker, StopHandler stopHandler, void *stopArg): parser_(parser), baseMoniker_(baseMoniker), ref_(0), pBinding_(0), totalRead_(0), stopHandler_(stopHandler), stopArg_(stopArg){ if (baseMoniker_) baseMoniker_->AddRef();}Callback::~Callback(){ if (pBinding_) pBinding_->Release(); if (baseMoniker_) baseMoniker_->Release();}static intexternalEntityRef(void *arg, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId){ return ((Callback *)arg)->externalEntityRef(context, systemId, publicId);}static HRESULTopenStream(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *uri, StopHandler stopHandler, void *stopArg){ if (!XML_SetBase(parser, uri)) return E_OUTOFMEMORY; HRESULT hr; IMoniker *m;#ifdef XML_UNICODE hr = CreateURLMoniker(0, uri, &m);#else LPWSTR uriw = new wchar_t[strlen(uri) + 1]; for (int i = 0;; i++) { uriw[i] = uri[i]; if (uriw[i] == 0) break; } hr = CreateURLMoniker(baseMoniker, uriw, &m); delete [] uriw;#endif if (FAILED(hr)) return hr; IBindStatusCallback *cb = new Callback(parser, m, stopHandler, stopArg); XML_SetExternalEntityRefHandler(parser, externalEntityRef); XML_SetExternalEntityRefHandlerArg(parser, cb); cb->AddRef(); IBindCtx *b; if (FAILED(hr = CreateAsyncBindCtx(0, cb, 0, &b))) { cb->Release(); m->Release(); return hr; } cb->Release(); IStream *pStream; hr = m->BindToStorage(b, 0, IID_IStream, (void **)&pStream); if (SUCCEEDED(hr)) { if (pStream) pStream->Release(); } if (hr == MK_S_ASYNCHRONOUS) hr = S_OK; m->Release(); b->Release(); return hr;}struct QuitInfo { const XML_Char *url; HRESULT hr; int stop;};static voidwinPerror(const XML_Char *url, HRESULT hr){ LPVOID buf; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandleA("urlmon.dll"), hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL) || FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL)) { /* The system error messages seem to end with a newline. */ _ftprintf(stderr, _T("%s: %s"), url, buf); fflush(stderr); LocalFree(buf); } else _ftprintf(stderr, _T("%s: error %x\n"), url, hr);}static voidthreadQuit(void *p, HRESULT hr){ QuitInfo *qi = (QuitInfo *)p; qi->hr = hr; qi->stop = 1;}extern "C"intXML_URLInit(void){ return SUCCEEDED(CoInitialize(0));}extern "C"voidXML_URLUninit(void){ CoUninitialize();}static intprocessURL(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *url){ QuitInfo qi; qi.stop = 0; qi.url = url; XML_SetBase(parser, url); HRESULT hr = openStream(parser, baseMoniker, url, threadQuit, &qi); if (FAILED(hr)) { winPerror(url, hr); return 0; } else if (FAILED(qi.hr)) { winPerror(url, qi.hr); return 0; } MSG msg; while (!qi.stop && GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return 1;}extern "C"intXML_ProcessURL(XML_Parser parser, const XML_Char *url, unsigned flags){ return processURL(parser, 0, url);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -