core/expat-2.0.1/xmlwf/xmlwin32url.cxx
changeset 300 b6d834208d33
parent 296 ea3dbc023c80
equal deleted inserted replaced
299:f06c5eba524d 300:b6d834208d33
       
     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 }