]> git.saurik.com Git - wxWidgets.git/blame - src/expat/xmlwf/xmlwin32url.cxx
Add class factories for filter streams. Also filters now follow the convention
[wxWidgets.git] / src / expat / xmlwf / xmlwin32url.cxx
CommitLineData
5e9f2524
VS
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
13static int
14processURL(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *url);
15
16typedef void (*StopHandler)(void *, HRESULT);
17
18class Callback : public IBindStatusCallback {
19public:
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);
37private:
38 XML_Parser parser_;
39 IMoniker *baseMoniker_;
40 DWORD totalRead_;
41 ULONG ref_;
42 IBinding *pBinding_;
43 StopHandler stopHandler_;
44 void *stopArg_;
45};
46
47STDMETHODIMP_(ULONG)
48Callback::AddRef()
49{
50 return ref_++;
51}
52
53STDMETHODIMP_(ULONG)
54Callback::Release()
55{
56 if (--ref_ == 0) {
57 delete this;
58 return 0;
59 }
60 return ref_;
61}
62
63STDMETHODIMP
64Callback::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
76STDMETHODIMP
77Callback::OnStartBinding(DWORD, IBinding* pBinding)
78{
79 pBinding_ = pBinding;
80 pBinding->AddRef();
81 return S_OK;
82}
83
84STDMETHODIMP
85Callback::GetPriority(LONG *)
86{
87 return E_NOTIMPL;
88}
89
90STDMETHODIMP
91Callback::OnLowResource(DWORD)
92{
93 return E_NOTIMPL;
94}
95
96STDMETHODIMP
97Callback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR)
98{
99 return S_OK;
100}
101
102STDMETHODIMP
103Callback::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
117STDMETHODIMP
118Callback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo)
119{
120 *pgrfBINDF = BINDF_ASYNCHRONOUS;
121 return S_OK;
122}
123
124static void
125reportError(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
140STDMETHODIMP
141Callback::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
206STDMETHODIMP
207Callback::OnObjectAvailable(REFIID, IUnknown *)
208{
209 return S_OK;
210}
211
212int
213Callback::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
224Callback::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
238Callback::~Callback()
239{
240 if (pBinding_)
241 pBinding_->Release();
242 if (baseMoniker_)
243 baseMoniker_->Release();
244}
245
246static int
247externalEntityRef(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
257static HRESULT
258openStream(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
305struct QuitInfo {
306 const XML_Char *url;
307 HRESULT hr;
308 int stop;
309};
310
311static void
312winPerror(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
340static void
341threadQuit(void *p, HRESULT hr)
342{
343 QuitInfo *qi = (QuitInfo *)p;
344 qi->hr = hr;
345 qi->stop = 1;
346}
347
348extern "C"
349int
350XML_URLInit(void)
351{
352 return SUCCEEDED(CoInitialize(0));
353}
354
355extern "C"
356void
357XML_URLUninit(void)
358{
359 CoUninitialize();
360}
361
362static int
363processURL(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
388extern "C"
389int
390XML_ProcessURL(XML_Parser parser,
391 const XML_Char *url,
392 unsigned flags)
393{
394 return processURL(parser, 0, url);
395}