home *** CD-ROM | disk | FTP | other *** search
/ Netrunner 2004 October / NETRUNNER0410.ISO / regular / ActivePerl-5.8.4.810-MSWin32-x86.msi / _055df69222bf6c6934bba96ab20d9385 < prev    next >
Text File  |  2004-06-01  |  9KB  |  396 lines

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