core/expat-2.0.1/xmlwf/xmlwin32url.cxx
changeset 300 b6d834208d33
parent 296 ea3dbc023c80
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/expat-2.0.1/xmlwf/xmlwin32url.cxx	Tue Feb 02 21:49:24 2016 +0000
@@ -0,0 +1,395 @@
+#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);
+}