Annotation of embedaddon/expat/xmlwf/xmlwin32url.cxx, revision 1.1
1.1 ! misho 1: #include "expat.h"
! 2: #ifdef XML_UNICODE
! 3: #define UNICODE
! 4: #endif
! 5: #include <windows.h>
! 6: #include <urlmon.h>
! 7: #include <wininet.h>
! 8: #include <stdio.h>
! 9: #include <tchar.h>
! 10: #include "xmlurl.h"
! 11: #include "xmlmime.h"
! 12:
! 13: static int
! 14: processURL(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *url);
! 15:
! 16: typedef void (*StopHandler)(void *, HRESULT);
! 17:
! 18: class Callback : public IBindStatusCallback {
! 19: public:
! 20: // IUnknown methods
! 21: STDMETHODIMP QueryInterface(REFIID,void **);
! 22: STDMETHODIMP_(ULONG) AddRef();
! 23: STDMETHODIMP_(ULONG) Release();
! 24: // IBindStatusCallback methods
! 25: STDMETHODIMP OnStartBinding(DWORD, IBinding *);
! 26: STDMETHODIMP GetPriority(LONG *);
! 27: STDMETHODIMP OnLowResource(DWORD);
! 28: STDMETHODIMP OnProgress(ULONG, ULONG, ULONG, LPCWSTR);
! 29: STDMETHODIMP OnStopBinding(HRESULT, LPCWSTR);
! 30: STDMETHODIMP GetBindInfo(DWORD *, BINDINFO *);
! 31: STDMETHODIMP OnDataAvailable(DWORD, DWORD, FORMATETC *, STGMEDIUM *);
! 32: STDMETHODIMP OnObjectAvailable(REFIID, IUnknown *);
! 33: Callback(XML_Parser, IMoniker *, StopHandler, void *);
! 34: ~Callback();
! 35: int externalEntityRef(const XML_Char *context,
! 36: const XML_Char *systemId, const XML_Char *publicId);
! 37: private:
! 38: XML_Parser parser_;
! 39: IMoniker *baseMoniker_;
! 40: DWORD totalRead_;
! 41: ULONG ref_;
! 42: IBinding *pBinding_;
! 43: StopHandler stopHandler_;
! 44: void *stopArg_;
! 45: };
! 46:
! 47: STDMETHODIMP_(ULONG)
! 48: Callback::AddRef()
! 49: {
! 50: return ref_++;
! 51: }
! 52:
! 53: STDMETHODIMP_(ULONG)
! 54: Callback::Release()
! 55: {
! 56: if (--ref_ == 0) {
! 57: delete this;
! 58: return 0;
! 59: }
! 60: return ref_;
! 61: }
! 62:
! 63: STDMETHODIMP
! 64: Callback::QueryInterface(REFIID riid, void** ppv)
! 65: {
! 66: if (IsEqualGUID(riid, IID_IUnknown))
! 67: *ppv = (IUnknown *)this;
! 68: else if (IsEqualGUID(riid, IID_IBindStatusCallback))
! 69: *ppv = (IBindStatusCallback *)this;
! 70: else
! 71: return E_NOINTERFACE;
! 72: ((LPUNKNOWN)*ppv)->AddRef();
! 73: return S_OK;
! 74: }
! 75:
! 76: STDMETHODIMP
! 77: Callback::OnStartBinding(DWORD, IBinding* pBinding)
! 78: {
! 79: pBinding_ = pBinding;
! 80: pBinding->AddRef();
! 81: return S_OK;
! 82: }
! 83:
! 84: STDMETHODIMP
! 85: Callback::GetPriority(LONG *)
! 86: {
! 87: return E_NOTIMPL;
! 88: }
! 89:
! 90: STDMETHODIMP
! 91: Callback::OnLowResource(DWORD)
! 92: {
! 93: return E_NOTIMPL;
! 94: }
! 95:
! 96: STDMETHODIMP
! 97: Callback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR)
! 98: {
! 99: return S_OK;
! 100: }
! 101:
! 102: STDMETHODIMP
! 103: Callback::OnStopBinding(HRESULT hr, LPCWSTR szError)
! 104: {
! 105: if (pBinding_) {
! 106: pBinding_->Release();
! 107: pBinding_ = 0;
! 108: }
! 109: if (baseMoniker_) {
! 110: baseMoniker_->Release();
! 111: baseMoniker_ = 0;
! 112: }
! 113: stopHandler_(stopArg_, hr);
! 114: return S_OK;
! 115: }
! 116:
! 117: STDMETHODIMP
! 118: Callback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo)
! 119: {
! 120: *pgrfBINDF = BINDF_ASYNCHRONOUS;
! 121: return S_OK;
! 122: }
! 123:
! 124: static void
! 125: reportError(XML_Parser parser)
! 126: {
! 127: int code = XML_GetErrorCode(parser);
! 128: const XML_Char *message = XML_ErrorString(code);
! 129: if (message)
! 130: _ftprintf(stderr, _T("%s:%d:%ld: %s\n"),
! 131: XML_GetBase(parser),
! 132: XML_GetErrorLineNumber(parser),
! 133: XML_GetErrorColumnNumber(parser),
! 134: message);
! 135: else
! 136: _ftprintf(stderr, _T("%s: (unknown message %d)\n"),
! 137: XML_GetBase(parser), code);
! 138: }
! 139:
! 140: STDMETHODIMP
! 141: Callback::OnDataAvailable(DWORD grfBSCF,
! 142: DWORD dwSize,
! 143: FORMATETC *pfmtetc,
! 144: STGMEDIUM* pstgmed)
! 145: {
! 146: if (grfBSCF & BSCF_FIRSTDATANOTIFICATION) {
! 147: IWinInetHttpInfo *hp;
! 148: HRESULT hr = pBinding_->QueryInterface(IID_IWinInetHttpInfo,
! 149: (void **)&hp);
! 150: if (SUCCEEDED(hr)) {
! 151: char contentType[1024];
! 152: DWORD bufSize = sizeof(contentType);
! 153: DWORD flags = 0;
! 154: contentType[0] = 0;
! 155: hr = hp->QueryInfo(HTTP_QUERY_CONTENT_TYPE, contentType,
! 156: &bufSize, 0, NULL);
! 157: if (SUCCEEDED(hr)) {
! 158: char charset[CHARSET_MAX];
! 159: getXMLCharset(contentType, charset);
! 160: if (charset[0]) {
! 161: #ifdef XML_UNICODE
! 162: XML_Char wcharset[CHARSET_MAX];
! 163: XML_Char *p1 = wcharset;
! 164: const char *p2 = charset;
! 165: while ((*p1++ = (unsigned char)*p2++) != 0)
! 166: ;
! 167: XML_SetEncoding(parser_, wcharset);
! 168: #else
! 169: XML_SetEncoding(parser_, charset);
! 170: #endif
! 171: }
! 172: }
! 173: hp->Release();
! 174: }
! 175: }
! 176: if (!parser_)
! 177: return E_ABORT;
! 178: if (pstgmed->tymed == TYMED_ISTREAM) {
! 179: while (totalRead_ < dwSize) {
! 180: #define READ_MAX (64*1024)
! 181: DWORD nToRead = dwSize - totalRead_;
! 182: if (nToRead > READ_MAX)
! 183: nToRead = READ_MAX;
! 184: void *buf = XML_GetBuffer(parser_, nToRead);
! 185: if (!buf) {
! 186: _ftprintf(stderr, _T("out of memory\n"));
! 187: return E_ABORT;
! 188: }
! 189: DWORD nRead;
! 190: HRESULT hr = pstgmed->pstm->Read(buf, nToRead, &nRead);
! 191: if (SUCCEEDED(hr)) {
! 192: totalRead_ += nRead;
! 193: if (!XML_ParseBuffer(parser_,
! 194: nRead,
! 195: (grfBSCF & BSCF_LASTDATANOTIFICATION) != 0
! 196: && totalRead_ == dwSize)) {
! 197: reportError(parser_);
! 198: return E_ABORT;
! 199: }
! 200: }
! 201: }
! 202: }
! 203: return S_OK;
! 204: }
! 205:
! 206: STDMETHODIMP
! 207: Callback::OnObjectAvailable(REFIID, IUnknown *)
! 208: {
! 209: return S_OK;
! 210: }
! 211:
! 212: int
! 213: Callback::externalEntityRef(const XML_Char *context,
! 214: const XML_Char *systemId,
! 215: const XML_Char *publicId)
! 216: {
! 217: XML_Parser entParser = XML_ExternalEntityParserCreate(parser_, context, 0);
! 218: XML_SetBase(entParser, systemId);
! 219: int ret = processURL(entParser, baseMoniker_, systemId);
! 220: XML_ParserFree(entParser);
! 221: return ret;
! 222: }
! 223:
! 224: Callback::Callback(XML_Parser parser, IMoniker *baseMoniker,
! 225: StopHandler stopHandler, void *stopArg)
! 226: : parser_(parser),
! 227: baseMoniker_(baseMoniker),
! 228: ref_(0),
! 229: pBinding_(0),
! 230: totalRead_(0),
! 231: stopHandler_(stopHandler),
! 232: stopArg_(stopArg)
! 233: {
! 234: if (baseMoniker_)
! 235: baseMoniker_->AddRef();
! 236: }
! 237:
! 238: Callback::~Callback()
! 239: {
! 240: if (pBinding_)
! 241: pBinding_->Release();
! 242: if (baseMoniker_)
! 243: baseMoniker_->Release();
! 244: }
! 245:
! 246: static int
! 247: externalEntityRef(void *arg,
! 248: const XML_Char *context,
! 249: const XML_Char *base,
! 250: const XML_Char *systemId,
! 251: const XML_Char *publicId)
! 252: {
! 253: return ((Callback *)arg)->externalEntityRef(context, systemId, publicId);
! 254: }
! 255:
! 256:
! 257: static HRESULT
! 258: openStream(XML_Parser parser,
! 259: IMoniker *baseMoniker,
! 260: const XML_Char *uri,
! 261: StopHandler stopHandler, void *stopArg)
! 262: {
! 263: if (!XML_SetBase(parser, uri))
! 264: return E_OUTOFMEMORY;
! 265: HRESULT hr;
! 266: IMoniker *m;
! 267: #ifdef XML_UNICODE
! 268: hr = CreateURLMoniker(0, uri, &m);
! 269: #else
! 270: LPWSTR uriw = new wchar_t[strlen(uri) + 1];
! 271: for (int i = 0;; i++) {
! 272: uriw[i] = uri[i];
! 273: if (uriw[i] == 0)
! 274: break;
! 275: }
! 276: hr = CreateURLMoniker(baseMoniker, uriw, &m);
! 277: delete [] uriw;
! 278: #endif
! 279: if (FAILED(hr))
! 280: return hr;
! 281: IBindStatusCallback *cb = new Callback(parser, m, stopHandler, stopArg);
! 282: XML_SetExternalEntityRefHandler(parser, externalEntityRef);
! 283: XML_SetExternalEntityRefHandlerArg(parser, cb);
! 284: cb->AddRef();
! 285: IBindCtx *b;
! 286: if (FAILED(hr = CreateAsyncBindCtx(0, cb, 0, &b))) {
! 287: cb->Release();
! 288: m->Release();
! 289: return hr;
! 290: }
! 291: cb->Release();
! 292: IStream *pStream;
! 293: hr = m->BindToStorage(b, 0, IID_IStream, (void **)&pStream);
! 294: if (SUCCEEDED(hr)) {
! 295: if (pStream)
! 296: pStream->Release();
! 297: }
! 298: if (hr == MK_S_ASYNCHRONOUS)
! 299: hr = S_OK;
! 300: m->Release();
! 301: b->Release();
! 302: return hr;
! 303: }
! 304:
! 305: struct QuitInfo {
! 306: const XML_Char *url;
! 307: HRESULT hr;
! 308: int stop;
! 309: };
! 310:
! 311: static void
! 312: winPerror(const XML_Char *url, HRESULT hr)
! 313: {
! 314: LPVOID buf;
! 315: if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
! 316: | FORMAT_MESSAGE_FROM_HMODULE,
! 317: GetModuleHandleA("urlmon.dll"),
! 318: hr,
! 319: MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
! 320: (LPTSTR) &buf,
! 321: 0,
! 322: NULL)
! 323: || FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
! 324: | FORMAT_MESSAGE_FROM_SYSTEM,
! 325: 0,
! 326: hr,
! 327: MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
! 328: (LPTSTR) &buf,
! 329: 0,
! 330: NULL)) {
! 331: /* The system error messages seem to end with a newline. */
! 332: _ftprintf(stderr, _T("%s: %s"), url, buf);
! 333: fflush(stderr);
! 334: LocalFree(buf);
! 335: }
! 336: else
! 337: _ftprintf(stderr, _T("%s: error %x\n"), url, hr);
! 338: }
! 339:
! 340: static void
! 341: threadQuit(void *p, HRESULT hr)
! 342: {
! 343: QuitInfo *qi = (QuitInfo *)p;
! 344: qi->hr = hr;
! 345: qi->stop = 1;
! 346: }
! 347:
! 348: extern "C"
! 349: int
! 350: XML_URLInit(void)
! 351: {
! 352: return SUCCEEDED(CoInitialize(0));
! 353: }
! 354:
! 355: extern "C"
! 356: void
! 357: XML_URLUninit(void)
! 358: {
! 359: CoUninitialize();
! 360: }
! 361:
! 362: static int
! 363: processURL(XML_Parser parser, IMoniker *baseMoniker,
! 364: const XML_Char *url)
! 365: {
! 366: QuitInfo qi;
! 367: qi.stop = 0;
! 368: qi.url = url;
! 369:
! 370: XML_SetBase(parser, url);
! 371: HRESULT hr = openStream(parser, baseMoniker, url, threadQuit, &qi);
! 372: if (FAILED(hr)) {
! 373: winPerror(url, hr);
! 374: return 0;
! 375: }
! 376: else if (FAILED(qi.hr)) {
! 377: winPerror(url, qi.hr);
! 378: return 0;
! 379: }
! 380: MSG msg;
! 381: while (!qi.stop && GetMessage (&msg, NULL, 0, 0)) {
! 382: TranslateMessage (&msg);
! 383: DispatchMessage (&msg);
! 384: }
! 385: return 1;
! 386: }
! 387:
! 388: extern "C"
! 389: int
! 390: XML_ProcessURL(XML_Parser parser,
! 391: const XML_Char *url,
! 392: unsigned flags)
! 393: {
! 394: return processURL(parser, 0, url);
! 395: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>