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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>