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