1104349Sphk#include "expat.h"
2104349Sphk#ifdef XML_UNICODE
3104349Sphk#define UNICODE
4104349Sphk#endif
5104349Sphk#include <windows.h>
6104349Sphk#include <urlmon.h>
7104349Sphk#include <wininet.h>
8104349Sphk#include <stdio.h>
9104349Sphk#include <tchar.h>
10104349Sphk#include "xmlurl.h"
11104349Sphk#include "xmlmime.h"
12104349Sphk
13104349Sphkstatic int
14104349SphkprocessURL(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *url);
15104349Sphk
16104349Sphktypedef void (*StopHandler)(void *, HRESULT);
17104349Sphk
18104349Sphkclass Callback : public IBindStatusCallback {
19104349Sphkpublic:
20104349Sphk  // IUnknown methods
21104349Sphk  STDMETHODIMP QueryInterface(REFIID,void **);
22104349Sphk  STDMETHODIMP_(ULONG) AddRef();
23104349Sphk  STDMETHODIMP_(ULONG) Release();
24104349Sphk  // IBindStatusCallback methods
25104349Sphk  STDMETHODIMP OnStartBinding(DWORD, IBinding *);
26104349Sphk  STDMETHODIMP GetPriority(LONG *);
27104349Sphk  STDMETHODIMP OnLowResource(DWORD);
28104349Sphk  STDMETHODIMP OnProgress(ULONG, ULONG, ULONG, LPCWSTR);
29104349Sphk  STDMETHODIMP OnStopBinding(HRESULT, LPCWSTR);
30104349Sphk  STDMETHODIMP GetBindInfo(DWORD *, BINDINFO *);
31104349Sphk  STDMETHODIMP OnDataAvailable(DWORD, DWORD, FORMATETC *, STGMEDIUM *);
32104349Sphk  STDMETHODIMP OnObjectAvailable(REFIID, IUnknown *);
33104349Sphk  Callback(XML_Parser, IMoniker *, StopHandler, void *);
34104349Sphk  ~Callback();
35104349Sphk  int externalEntityRef(const XML_Char *context,
36104349Sphk                        const XML_Char *systemId, const XML_Char *publicId);
37104349Sphkprivate:
38104349Sphk  XML_Parser parser_;
39104349Sphk  IMoniker *baseMoniker_;
40104349Sphk  DWORD totalRead_;
41104349Sphk  ULONG ref_;
42104349Sphk  IBinding *pBinding_;
43104349Sphk  StopHandler stopHandler_;
44104349Sphk  void *stopArg_;
45104349Sphk};
46104349Sphk
47104349SphkSTDMETHODIMP_(ULONG)
48104349SphkCallback::AddRef()
49104349Sphk{
50104349Sphk  return ref_++;
51104349Sphk}
52104349Sphk
53104349SphkSTDMETHODIMP_(ULONG)
54104349SphkCallback::Release()
55104349Sphk{
56104349Sphk  if (--ref_ == 0) {
57104349Sphk    delete this;
58104349Sphk    return 0;
59104349Sphk  }
60104349Sphk  return ref_;
61104349Sphk}
62104349Sphk
63104349SphkSTDMETHODIMP
64104349SphkCallback::QueryInterface(REFIID riid, void** ppv)
65104349Sphk{
66104349Sphk  if (IsEqualGUID(riid, IID_IUnknown))
67104349Sphk    *ppv = (IUnknown *)this;
68104349Sphk  else if (IsEqualGUID(riid, IID_IBindStatusCallback))
69104349Sphk    *ppv = (IBindStatusCallback *)this;
70104349Sphk  else
71104349Sphk    return E_NOINTERFACE;
72104349Sphk  ((LPUNKNOWN)*ppv)->AddRef();
73104349Sphk  return S_OK;
74104349Sphk}
75104349Sphk
76104349SphkSTDMETHODIMP
77104349SphkCallback::OnStartBinding(DWORD, IBinding* pBinding)
78104349Sphk{
79104349Sphk  pBinding_ = pBinding;
80104349Sphk  pBinding->AddRef();
81104349Sphk  return S_OK;
82104349Sphk}
83104349Sphk
84104349SphkSTDMETHODIMP
85104349SphkCallback::GetPriority(LONG *)
86104349Sphk{
87104349Sphk  return E_NOTIMPL;
88104349Sphk}
89104349Sphk
90104349SphkSTDMETHODIMP
91104349SphkCallback::OnLowResource(DWORD)
92104349Sphk{
93104349Sphk  return E_NOTIMPL;
94104349Sphk}
95104349Sphk
96104349SphkSTDMETHODIMP
97104349SphkCallback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR)
98104349Sphk{
99104349Sphk  return S_OK;
100104349Sphk}
101104349Sphk
102104349SphkSTDMETHODIMP
103104349SphkCallback::OnStopBinding(HRESULT hr, LPCWSTR szError)
104104349Sphk{
105104349Sphk  if (pBinding_) {
106104349Sphk    pBinding_->Release();
107104349Sphk    pBinding_ = 0;
108104349Sphk  }
109104349Sphk  if (baseMoniker_) {
110104349Sphk    baseMoniker_->Release();
111104349Sphk    baseMoniker_ = 0;
112104349Sphk  }
113104349Sphk  stopHandler_(stopArg_, hr);
114104349Sphk  return S_OK;
115104349Sphk}
116104349Sphk
117104349SphkSTDMETHODIMP
118104349SphkCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo)
119104349Sphk{
120104349Sphk  *pgrfBINDF = BINDF_ASYNCHRONOUS;
121104349Sphk  return S_OK;
122104349Sphk}
123104349Sphk
124104349Sphkstatic void
125104349SphkreportError(XML_Parser parser)
126104349Sphk{
127104349Sphk  int code = XML_GetErrorCode(parser);
128104349Sphk  const XML_Char *message = XML_ErrorString(code);
129104349Sphk  if (message)
130104349Sphk    _ftprintf(stderr, _T("%s:%d:%ld: %s\n"),
131104349Sphk	     XML_GetBase(parser),
132104349Sphk	     XML_GetErrorLineNumber(parser),
133104349Sphk	     XML_GetErrorColumnNumber(parser),
134104349Sphk	     message);
135104349Sphk  else
136104349Sphk    _ftprintf(stderr, _T("%s: (unknown message %d)\n"),
137104349Sphk              XML_GetBase(parser), code);
138104349Sphk}
139104349Sphk
140104349SphkSTDMETHODIMP
141104349SphkCallback::OnDataAvailable(DWORD grfBSCF,
142104349Sphk                          DWORD dwSize,
143104349Sphk                          FORMATETC *pfmtetc,
144104349Sphk                          STGMEDIUM* pstgmed)
145104349Sphk{
146104349Sphk  if (grfBSCF & BSCF_FIRSTDATANOTIFICATION) {
147104349Sphk    IWinInetHttpInfo *hp;
148104349Sphk    HRESULT hr = pBinding_->QueryInterface(IID_IWinInetHttpInfo,
149104349Sphk                                           (void **)&hp);
150104349Sphk    if (SUCCEEDED(hr)) {
151104349Sphk      char contentType[1024];
152104349Sphk      DWORD bufSize = sizeof(contentType);
153104349Sphk      DWORD flags = 0;
154104349Sphk      contentType[0] = 0;
155104349Sphk      hr = hp->QueryInfo(HTTP_QUERY_CONTENT_TYPE, contentType,
156104349Sphk                         &bufSize, 0, NULL);
157104349Sphk      if (SUCCEEDED(hr)) {
158104349Sphk	char charset[CHARSET_MAX];
159104349Sphk	getXMLCharset(contentType, charset);
160104349Sphk	if (charset[0]) {
161104349Sphk#ifdef XML_UNICODE
162104349Sphk	  XML_Char wcharset[CHARSET_MAX];
163104349Sphk	  XML_Char *p1 = wcharset;
164104349Sphk	  const char *p2 = charset;
165104349Sphk	  while ((*p1++ = (unsigned char)*p2++) != 0)
166104349Sphk	    ;
167104349Sphk	  XML_SetEncoding(parser_, wcharset);
168104349Sphk#else
169104349Sphk	  XML_SetEncoding(parser_, charset);
170104349Sphk#endif
171104349Sphk	}
172104349Sphk      }
173104349Sphk      hp->Release();
174104349Sphk    }
175104349Sphk  }
176104349Sphk  if (!parser_)
177104349Sphk    return E_ABORT;
178104349Sphk  if (pstgmed->tymed == TYMED_ISTREAM) {
179104349Sphk    while (totalRead_ < dwSize) {
180104349Sphk#define READ_MAX (64*1024)
181104349Sphk      DWORD nToRead = dwSize - totalRead_;
182104349Sphk      if (nToRead > READ_MAX)
183104349Sphk	nToRead = READ_MAX;
184104349Sphk      void *buf = XML_GetBuffer(parser_, nToRead);
185104349Sphk      if (!buf) {
186104349Sphk	_ftprintf(stderr, _T("out of memory\n"));
187104349Sphk	return E_ABORT;
188104349Sphk      }
189104349Sphk      DWORD nRead;
190104349Sphk      HRESULT hr = pstgmed->pstm->Read(buf, nToRead, &nRead);
191104349Sphk      if (SUCCEEDED(hr)) {
192104349Sphk	totalRead_ += nRead;
193104349Sphk	if (!XML_ParseBuffer(parser_,
194104349Sphk			     nRead,
195104349Sphk			     (grfBSCF & BSCF_LASTDATANOTIFICATION) != 0
196104349Sphk			     && totalRead_ == dwSize)) {
197104349Sphk	  reportError(parser_);
198104349Sphk	  return E_ABORT;
199104349Sphk	}
200104349Sphk      }
201104349Sphk    }
202104349Sphk  }
203104349Sphk  return S_OK;
204104349Sphk}
205104349Sphk
206104349SphkSTDMETHODIMP
207104349SphkCallback::OnObjectAvailable(REFIID, IUnknown *)
208104349Sphk{
209104349Sphk  return S_OK;
210104349Sphk}
211104349Sphk
212104349Sphkint
213104349SphkCallback::externalEntityRef(const XML_Char *context,
214104349Sphk                            const XML_Char *systemId,
215104349Sphk                            const XML_Char *publicId)
216104349Sphk{
217104349Sphk  XML_Parser entParser = XML_ExternalEntityParserCreate(parser_, context, 0);
218104349Sphk  XML_SetBase(entParser, systemId);
219104349Sphk  int ret = processURL(entParser, baseMoniker_, systemId);
220104349Sphk  XML_ParserFree(entParser);
221104349Sphk  return ret;
222104349Sphk}
223104349Sphk
224104349SphkCallback::Callback(XML_Parser parser, IMoniker *baseMoniker,
225104349Sphk                   StopHandler stopHandler, void *stopArg)
226104349Sphk: parser_(parser),
227104349Sphk  baseMoniker_(baseMoniker),
228104349Sphk  ref_(0),
229104349Sphk  pBinding_(0),
230104349Sphk  totalRead_(0),
231104349Sphk  stopHandler_(stopHandler),
232104349Sphk  stopArg_(stopArg)
233104349Sphk{
234104349Sphk  if (baseMoniker_)
235104349Sphk    baseMoniker_->AddRef();
236104349Sphk}
237104349Sphk
238104349SphkCallback::~Callback()
239104349Sphk{
240104349Sphk  if (pBinding_)
241104349Sphk    pBinding_->Release();
242104349Sphk  if (baseMoniker_)
243104349Sphk    baseMoniker_->Release();
244104349Sphk}
245104349Sphk
246104349Sphkstatic int
247104349SphkexternalEntityRef(void *arg,
248104349Sphk                  const XML_Char *context,
249104349Sphk                  const XML_Char *base,
250104349Sphk                  const XML_Char *systemId,
251104349Sphk                  const XML_Char *publicId)
252104349Sphk{
253104349Sphk  return ((Callback *)arg)->externalEntityRef(context, systemId, publicId);
254104349Sphk}
255104349Sphk
256104349Sphk
257104349Sphkstatic HRESULT
258104349SphkopenStream(XML_Parser parser,
259104349Sphk           IMoniker *baseMoniker,
260104349Sphk           const XML_Char *uri,
261104349Sphk           StopHandler stopHandler, void *stopArg)
262104349Sphk{
263104349Sphk  if (!XML_SetBase(parser, uri))
264104349Sphk    return E_OUTOFMEMORY;
265104349Sphk  HRESULT hr;
266104349Sphk  IMoniker *m;
267104349Sphk#ifdef XML_UNICODE
268104349Sphk  hr = CreateURLMoniker(0, uri, &m);
269104349Sphk#else
270104349Sphk  LPWSTR uriw = new wchar_t[strlen(uri) + 1];
271104349Sphk  for (int i = 0;; i++) {
272104349Sphk    uriw[i] = uri[i];
273104349Sphk    if (uriw[i] == 0)
274104349Sphk      break;
275104349Sphk  }
276104349Sphk  hr = CreateURLMoniker(baseMoniker, uriw, &m);
277104349Sphk  delete [] uriw;
278104349Sphk#endif
279104349Sphk  if (FAILED(hr))
280104349Sphk    return hr;
281104349Sphk  IBindStatusCallback *cb = new Callback(parser, m, stopHandler, stopArg);
282104349Sphk  XML_SetExternalEntityRefHandler(parser, externalEntityRef);
283104349Sphk  XML_SetExternalEntityRefHandlerArg(parser, cb);
284104349Sphk  cb->AddRef();
285104349Sphk  IBindCtx *b;
286104349Sphk  if (FAILED(hr = CreateAsyncBindCtx(0, cb, 0, &b))) {
287104349Sphk    cb->Release();
288104349Sphk    m->Release();
289104349Sphk    return hr;
290104349Sphk  }
291104349Sphk  cb->Release();
292104349Sphk  IStream *pStream;
293104349Sphk  hr = m->BindToStorage(b, 0, IID_IStream, (void **)&pStream);
294104349Sphk  if (SUCCEEDED(hr)) {
295104349Sphk    if (pStream)
296104349Sphk      pStream->Release();
297104349Sphk  }
298104349Sphk  if (hr == MK_S_ASYNCHRONOUS)
299104349Sphk    hr = S_OK;
300104349Sphk  m->Release();
301104349Sphk  b->Release();
302104349Sphk  return hr;
303104349Sphk}
304104349Sphk
305104349Sphkstruct QuitInfo {
306104349Sphk  const XML_Char *url;
307104349Sphk  HRESULT hr;
308104349Sphk  int stop;
309104349Sphk};
310104349Sphk
311104349Sphkstatic void
312104349SphkwinPerror(const XML_Char *url, HRESULT hr)
313104349Sphk{
314104349Sphk  LPVOID buf;
315104349Sphk  if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
316104349Sphk		    | FORMAT_MESSAGE_FROM_HMODULE,
317104349Sphk		    GetModuleHandleA("urlmon.dll"),
318104349Sphk		    hr,
319104349Sphk		    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
320104349Sphk		    (LPTSTR) &buf,
321104349Sphk		    0,
322104349Sphk		    NULL)
323104349Sphk      || FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
324104349Sphk		      | FORMAT_MESSAGE_FROM_SYSTEM,
325104349Sphk		      0,
326104349Sphk		      hr,
327104349Sphk		      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
328104349Sphk		      (LPTSTR) &buf,
329104349Sphk		      0,
330104349Sphk		      NULL)) {
331104349Sphk    /* The system error messages seem to end with a newline. */
332104349Sphk    _ftprintf(stderr, _T("%s: %s"), url, buf);
333104349Sphk    fflush(stderr);
334104349Sphk    LocalFree(buf);
335104349Sphk  }
336104349Sphk  else
337104349Sphk    _ftprintf(stderr, _T("%s: error %x\n"), url, hr);
338104349Sphk}
339104349Sphk
340104349Sphkstatic void
341104349SphkthreadQuit(void *p, HRESULT hr)
342104349Sphk{
343104349Sphk  QuitInfo *qi = (QuitInfo *)p;
344104349Sphk  qi->hr = hr;
345104349Sphk  qi->stop = 1;
346104349Sphk}
347104349Sphk
348104349Sphkextern "C"
349104349Sphkint
350104349SphkXML_URLInit(void)
351104349Sphk{
352104349Sphk  return SUCCEEDED(CoInitialize(0));
353104349Sphk}
354104349Sphk
355104349Sphkextern "C"
356104349Sphkvoid
357104349SphkXML_URLUninit(void)
358104349Sphk{
359104349Sphk  CoUninitialize();
360104349Sphk}
361104349Sphk
362104349Sphkstatic int
363104349SphkprocessURL(XML_Parser parser, IMoniker *baseMoniker,
364104349Sphk           const XML_Char *url)
365104349Sphk{
366104349Sphk  QuitInfo qi;
367104349Sphk  qi.stop = 0;
368104349Sphk  qi.url = url;
369104349Sphk
370104349Sphk  XML_SetBase(parser, url);
371104349Sphk  HRESULT hr = openStream(parser, baseMoniker, url, threadQuit, &qi);
372104349Sphk  if (FAILED(hr)) {
373104349Sphk    winPerror(url, hr);
374104349Sphk    return 0;
375104349Sphk  }
376104349Sphk  else if (FAILED(qi.hr)) {
377104349Sphk    winPerror(url, qi.hr);
378104349Sphk    return 0;
379104349Sphk  }
380104349Sphk  MSG msg;
381104349Sphk  while (!qi.stop && GetMessage (&msg, NULL, 0, 0)) {
382104349Sphk    TranslateMessage (&msg);
383104349Sphk    DispatchMessage (&msg);
384104349Sphk  }
385104349Sphk  return 1;
386104349Sphk}
387104349Sphk
388104349Sphkextern "C"
389104349Sphkint
390104349SphkXML_ProcessURL(XML_Parser parser,
391104349Sphk               const XML_Char *url,
392104349Sphk               unsigned flags)
393104349Sphk{
394104349Sphk  return processURL(parser, 0, url);
395104349Sphk}
396