File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / expat / xmlwf / xmlwin32url.cxx
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:00:54 2012 UTC (12 years, 4 months ago) by misho
Branches: expat, MAIN
CVS tags: v2_1_0, v2_0_1p0, v2_0_1, HEAD
expat

    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>