123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- #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 int
- processURL(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_;
- }
- STDMETHODIMP
- Callback::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;
- }
- STDMETHODIMP
- Callback::OnStartBinding(DWORD, IBinding* pBinding)
- {
- pBinding_ = pBinding;
- pBinding->AddRef();
- return S_OK;
- }
- STDMETHODIMP
- Callback::GetPriority(LONG *)
- {
- return E_NOTIMPL;
- }
- STDMETHODIMP
- Callback::OnLowResource(DWORD)
- {
- return E_NOTIMPL;
- }
- STDMETHODIMP
- Callback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR)
- {
- return S_OK;
- }
- STDMETHODIMP
- Callback::OnStopBinding(HRESULT hr, LPCWSTR szError)
- {
- if (pBinding_) {
- pBinding_->Release();
- pBinding_ = 0;
- }
- if (baseMoniker_) {
- baseMoniker_->Release();
- baseMoniker_ = 0;
- }
- stopHandler_(stopArg_, hr);
- return S_OK;
- }
- STDMETHODIMP
- Callback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo)
- {
- *pgrfBINDF = BINDF_ASYNCHRONOUS;
- return S_OK;
- }
- static void
- reportError(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);
- }
- STDMETHODIMP
- Callback::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;
- }
- STDMETHODIMP
- Callback::OnObjectAvailable(REFIID, IUnknown *)
- {
- return S_OK;
- }
- int
- Callback::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 int
- externalEntityRef(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 HRESULT
- openStream(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 void
- winPerror(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 void
- threadQuit(void *p, HRESULT hr)
- {
- QuitInfo *qi = (QuitInfo *)p;
- qi->hr = hr;
- qi->stop = 1;
- }
- extern "C"
- int
- XML_URLInit(void)
- {
- return SUCCEEDED(CoInitialize(0));
- }
- extern "C"
- void
- XML_URLUninit(void)
- {
- CoUninitialize();
- }
- static int
- processURL(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"
- int
- XML_ProcessURL(XML_Parser parser,
- const XML_Char *url,
- unsigned flags)
- {
- return processURL(parser, 0, url);
- }
|