8175 lines
184 KiB
C++
8175 lines
184 KiB
C++
// This is a part of the Active Template Library.
|
|
// Copyright (C) Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Active Template Library Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Active Template Library product.
|
|
|
|
#ifndef __ATLSOAP_H__
|
|
#define __ATLSOAP_H__
|
|
|
|
#pragma once
|
|
|
|
#if (defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_))
|
|
#error require winsock2.h -- include <winsock2.h> before you include <windows.h>
|
|
#endif
|
|
|
|
#if ((_WIN32_WINNT < 0x0400) && (_WIN32_WINDOWS <= 0x0400))
|
|
#error require _WIN32_WINNT >= 0x0400 or _WIN32_WINDOWS > 0x0400
|
|
#endif
|
|
|
|
#ifndef ATLSOAP_TRACE
|
|
#ifdef _ATLSOAP_TRACE_XML
|
|
#define ATLSOAP_TRACE(__data, __len) AtlSoapTraceXML(__data, __len)
|
|
#else
|
|
#define ATLSOAP_TRACE(__data, __len) __noop
|
|
#endif
|
|
#endif // ATLSOAP_TRACE
|
|
|
|
// override this macro to ATL_BASE64_FLAG_NOCRLF if you do
|
|
// not want Base64-encoded binary data to contain CRLFs
|
|
#ifndef ATLSOAP_BASE64_FLAGS
|
|
#define ATLSOAP_BASE64_FLAGS ATL_BASE64_FLAG_NONE
|
|
#endif // ATLSOAP_BASE64_FLAGS
|
|
|
|
[ emitidl(restricted) ];
|
|
#include <winsock2.h>
|
|
#include <atlstr.h>
|
|
#include <atlcoll.h>
|
|
#include <atlbase.h>
|
|
#include <msxml2.h>
|
|
#include <atlenc.h>
|
|
#include <fcntl.h>
|
|
#include <float.h>
|
|
#include <math.h>
|
|
#include <limits>
|
|
#include <atlisapi.h>
|
|
#include <atlstencil.h>
|
|
#include <atlhttp.h>
|
|
#include <atlhttp.inl>
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible
|
|
#pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible
|
|
#pragma warning(disable: 4061) // enumerate 'enum value' in switch of enum 'enum type' is not explicitly handled by a case label
|
|
|
|
#ifndef _CPPUNWIND
|
|
#pragma warning(disable: 4702) // unreachable code
|
|
#endif // _CPPUNWIND
|
|
|
|
#ifndef ATLSOAP_NOWININET
|
|
#include <wininet.h>
|
|
#ifndef ATLSOAPINET_CLIENT
|
|
#define ATLSOAPINET_CLIENT _T("VCSoapClient")
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef _ATL_NO_DEFAULT_LIBS
|
|
#pragma comment(lib, "msxml2.lib")
|
|
#ifndef ATLSOAP_NOWININET
|
|
#pragma comment(lib, "wininet.lib")
|
|
#endif
|
|
#endif
|
|
|
|
#define _ATLSOAP_MAKEWIDESTR( str ) L ## str
|
|
#define ATLSOAP_MAKEWIDESTR( str ) _ATLSOAP_MAKEWIDESTR( str )
|
|
|
|
|
|
#pragma pack(push,_ATL_PACKING)
|
|
namespace ATL
|
|
{
|
|
|
|
ATL_NOINLINE inline void AtlSoapTraceXML(LPBYTE pdwData, DWORD dwLen)
|
|
{
|
|
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (hStdOut != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwWritten;
|
|
WriteFile(hStdOut,
|
|
"\n-----------------------------------------------------------------\n",
|
|
sizeof("\n-----------------------------------------------------------------\n")-1,
|
|
&dwWritten, NULL);
|
|
|
|
WriteFile(hStdOut, pdwData, dwLen, &dwWritten, NULL);
|
|
|
|
WriteFile(hStdOut,
|
|
"\n-----------------------------------------------------------------\n",
|
|
sizeof("\n-----------------------------------------------------------------\n")-1,
|
|
&dwWritten, NULL);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IStreamImpl - stub IStream implementation class
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class IStreamImpl : public IStream
|
|
{
|
|
public:
|
|
|
|
HRESULT __stdcall Read(void * /*pDest*/, ULONG /*nMaxLen*/, ULONG * /*pnRead*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall Write(const void * /*pv*/, ULONG /*cb*/, ULONG * /*pcbWritten*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall Seek(LARGE_INTEGER /*dlibMove*/, DWORD /*dwOrigin*/,
|
|
ULARGE_INTEGER * /*pLibNewPosition*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall SetSize(ULARGE_INTEGER /*libNewSize*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall CopyTo(IStream * /*pStream*/, ULARGE_INTEGER /*cb*/,
|
|
ULARGE_INTEGER * /*pcbRead*/, ULARGE_INTEGER * /*pcbWritten*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall Commit(DWORD /*grfCommitFlags*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall Revert()
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall LockRegion(ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/, DWORD /*dwLockType*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall UnlockRegion(ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/, DWORD /*dwLockType*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall Stat(STATSTG * /*pstatstg*/, DWORD /*grfStatFlag*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall Clone(IStream ** /*ppstm*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
}; // class IStreamImpl
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CStreamOnServerContext
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CStreamOnServerContext : public IStreamImpl
|
|
{
|
|
public:
|
|
|
|
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
|
|
if (InlineIsEqualGUID(riid, IID_IUnknown) ||
|
|
InlineIsEqualGUID(riid, IID_IStream) ||
|
|
InlineIsEqualGUID(riid, IID_ISequentialStream))
|
|
{
|
|
*ppv = static_cast<IStream *>(this);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
private:
|
|
|
|
IHttpServerContext * m_pServerContext;
|
|
DWORD m_dwBytesRead;
|
|
|
|
public:
|
|
|
|
CStreamOnServerContext(IHttpServerContext *pServerContext = NULL)
|
|
: m_pServerContext(pServerContext), m_dwBytesRead(0)
|
|
{
|
|
}
|
|
|
|
void SetServerContext(IHttpServerContext *pServerContext)
|
|
{
|
|
ATLASSUME( m_pServerContext == NULL );
|
|
|
|
m_pServerContext = pServerContext;
|
|
}
|
|
|
|
HRESULT __stdcall Read(void *pDest, ULONG nMaxLen, ULONG *pnRead)
|
|
{
|
|
ATLENSURE( pDest != NULL );
|
|
ATLASSUME( m_pServerContext != NULL );
|
|
|
|
DWORD dwToRead = __min(m_pServerContext->GetTotalBytes()-m_dwBytesRead, nMaxLen);
|
|
if (ReadClientData(m_pServerContext, (LPSTR) pDest, &dwToRead, m_dwBytesRead) != FALSE)
|
|
{
|
|
m_dwBytesRead+= dwToRead;
|
|
|
|
if (pnRead != NULL)
|
|
{
|
|
*pnRead = dwToRead;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
ATLTRACE( _T("ATLSOAP: CStreamOnServerContext::Read -- ReadClientData failed.\r\n") );
|
|
|
|
return E_FAIL;
|
|
}
|
|
}; // class CStreamOnServerContext
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CReadStreamOnSocket
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename TSocketClass>
|
|
class CReadStreamOnSocket : public IStreamImpl
|
|
{
|
|
public:
|
|
|
|
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
|
|
if (InlineIsEqualGUID(riid, IID_IUnknown) ||
|
|
InlineIsEqualGUID(riid, IID_IStream) ||
|
|
InlineIsEqualGUID(riid, IID_ISequentialStream))
|
|
{
|
|
*ppv = static_cast<IStream *>(this);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
private:
|
|
|
|
CAtlHttpClientT<TSocketClass> * m_pSocket;
|
|
LPCSTR m_szBuffer;
|
|
LPCSTR m_szCurr;
|
|
long m_nBodyLen;
|
|
|
|
public:
|
|
|
|
CReadStreamOnSocket()
|
|
: m_pSocket(NULL), m_szBuffer(NULL), m_szCurr(NULL), m_nBodyLen(0)
|
|
{
|
|
}
|
|
|
|
BOOL Init(CAtlHttpClientT<TSocketClass> *pSocket)
|
|
{
|
|
ATLENSURE( pSocket != NULL );
|
|
|
|
m_pSocket = pSocket;
|
|
m_szBuffer = (LPCSTR) pSocket->GetBody();
|
|
|
|
ATLSOAP_TRACE( (LPBYTE) pSocket->GetBody(), pSocket->GetBodyLength() );
|
|
|
|
if (m_szBuffer != NULL)
|
|
{
|
|
m_szCurr = m_szBuffer;
|
|
m_nBodyLen = pSocket->GetBodyLength();
|
|
if (m_nBodyLen != 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
ATLTRACE( _T("ATLSOAP: CReadStreamOnSocket::Init failed.\r\n") );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT __stdcall Read(void *pDest, ULONG nMaxLen, ULONG *pnRead)
|
|
{
|
|
ATLASSERT( pDest != NULL );
|
|
ATLASSUME( m_pSocket != NULL );
|
|
ATLASSUME( m_szBuffer != NULL );
|
|
|
|
if (pnRead != NULL)
|
|
{
|
|
*pnRead = 0;
|
|
}
|
|
|
|
long nRead = (int) (m_szCurr-m_szBuffer);
|
|
if (nRead < m_nBodyLen)
|
|
{
|
|
long nLength = __min((int)(m_nBodyLen-nRead), (LONG) nMaxLen);
|
|
Checked::memcpy_s(pDest, nMaxLen, m_szCurr, nLength);
|
|
m_szCurr+= nLength;
|
|
|
|
if (pnRead != NULL)
|
|
{
|
|
*pnRead = (ULONG) nLength;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
}; // class CReadStreamOnSocket
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CWriteStreamOnCString
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CWriteStreamOnCString : public IWriteStream
|
|
{
|
|
|
|
public:
|
|
CStringA m_str;
|
|
|
|
virtual ~CWriteStreamOnCString()
|
|
{
|
|
}
|
|
|
|
HRESULT WriteStream(LPCSTR szOut, int nLen, LPDWORD pdwWritten)
|
|
{
|
|
ATLENSURE_RETURN( szOut != NULL );
|
|
|
|
if (nLen < 0)
|
|
{
|
|
nLen = (int) strlen(szOut);
|
|
}
|
|
|
|
_ATLTRY
|
|
{
|
|
m_str.Append(szOut, nLen);
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (pdwWritten != NULL)
|
|
{
|
|
*pdwWritten = (DWORD) nLen;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT FlushStream()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
void Cleanup()
|
|
{
|
|
m_str.Empty();
|
|
}
|
|
}; // class CWriteStreamOnCString
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Namespaces
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define SOAPENV_NAMESPACEA "http://schemas.xmlsoap.org/soap/envelope/"
|
|
#define SOAPENV_NAMESPACEW ATLSOAP_MAKEWIDESTR( SOAPENV_NAMESPACEA )
|
|
|
|
#define SOAPENC_NAMESPACEA "http://schemas.xmlsoap.org/soap/encoding/"
|
|
#define SOAPENC_NAMESPACEW ATLSOAP_MAKEWIDESTR( SOAPENC_NAMESPACEA )
|
|
|
|
#define XSI_NAMESPACEA "http://www.w3.org/2001/XMLSchema-instance"
|
|
#define XSI_NAMESPACEW ATLSOAP_MAKEWIDESTR( XSI_NAMESPACEA )
|
|
|
|
#define XSD_NAMESPACEA "http://www.w3.org/2001/XMLSchema"
|
|
#define XSD_NAMESPACEW ATLSOAP_MAKEWIDESTR( XSD_NAMESPACEA )
|
|
|
|
#ifndef ATLSOAP_GENERIC_NAMESPACE
|
|
#define ATLSOAP_GENERIC_NAMESPACE L"http://www.tempuri.org"
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Helpers
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline HRESULT GetAttribute(
|
|
__in ISAXAttributes *pAttributes,
|
|
__in_ecount(cchName) const wchar_t *wszAttrName, __in int cchName,
|
|
__out_ecount_part(*pcchValue, *pcchValue) const wchar_t **pwszValue, __inout int *pcchValue,
|
|
__in_ecount_opt(cchNamespace) wchar_t *wszNamespace = NULL, __in int cchNamespace = 0)
|
|
{
|
|
if (!pAttributes || !wszAttrName || !pwszValue || !pcchValue)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pwszValue = NULL;
|
|
*pcchValue = 0;
|
|
if (!wszNamespace)
|
|
{
|
|
return (pAttributes->getValueFromQName(wszAttrName, cchName, pwszValue, pcchValue) == S_OK ? S_OK : E_FAIL);
|
|
}
|
|
return (pAttributes->getValueFromName(wszNamespace, cchNamespace,
|
|
wszAttrName, cchName, pwszValue, pcchValue) == S_OK ? S_OK : E_FAIL);
|
|
}
|
|
|
|
inline HRESULT GetAttribute(
|
|
__in ISAXAttributes *pAttributes,
|
|
__in_ecount(cchName) const wchar_t *wszAttrName, __in int cchName,
|
|
__inout CStringW &strValue,
|
|
__in_ecount_opt(cchNamespace) wchar_t *wszNamespace = NULL, __in int cchNamespace = 0)
|
|
{
|
|
const wchar_t *wszValue = NULL;
|
|
int cchValue = 0;
|
|
|
|
if (!pAttributes || !wszAttrName)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT hr;
|
|
if (!wszNamespace)
|
|
{
|
|
hr = (pAttributes->getValueFromQName(wszAttrName, cchName, &wszValue, &cchValue) == S_OK ? S_OK : E_FAIL);
|
|
}
|
|
else
|
|
{
|
|
hr = (pAttributes->getValueFromName(wszNamespace, cchNamespace,
|
|
wszAttrName, cchName, &wszValue, &cchValue) == S_OK ? S_OK : E_FAIL);
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
_ATLTRY
|
|
{
|
|
strValue.SetString(wszValue, cchValue);
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: GetAttribute -- out of memory.\r\n") );
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
inline const wchar_t *SkipWhitespace(const wchar_t *wsz)
|
|
{
|
|
while (*wsz && iswspace(*wsz))
|
|
++wsz;
|
|
return wsz;
|
|
}
|
|
|
|
} // namespace ATL
|
|
#pragma pack(pop)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BLOB data type - use this struct when you want to send BLOB data
|
|
// the attribute provider and proxy generator will only properly special
|
|
// case blob data when using this struct.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
[ export ]
|
|
typedef struct _tagATLSOAP_BLOB
|
|
{
|
|
unsigned long size;
|
|
unsigned char *data;
|
|
} ATLSOAP_BLOB;
|
|
|
|
#ifndef _ATL_SOAP_NO_PARAMETER_VALIDATIONS
|
|
#define _ATL_VALIDATE_PARAMETER_END(p)\
|
|
do \
|
|
{ \
|
|
if(*(p) !='\0') \
|
|
return E_FAIL; \
|
|
} while(0)
|
|
#else
|
|
#define _ATL_VALIDATE_PARAMETER_END(p)
|
|
#endif
|
|
|
|
// All non-integral types have specializations which
|
|
// will be called. The following function will be called
|
|
// only for integral types
|
|
|
|
#pragma push_macro("max")
|
|
#pragma push_macro("min")
|
|
#undef max
|
|
#undef min
|
|
template <typename T>
|
|
inline HRESULT AtlGetSAXValue(T * pVal , const wchar_t * wsz , int cch )
|
|
{
|
|
__int64 nVal = *pVal;
|
|
if (FAILED(AtlGetSAXValue(&nVal, wsz, cch)))
|
|
return E_FAIL;
|
|
|
|
#ifndef _ATL_SOAP_NO_PARAMETER_VALIDATIONS
|
|
if(nVal < std::numeric_limits<T>::min() || nVal > std::numeric_limits<T>::max())
|
|
return E_FAIL;
|
|
#endif
|
|
|
|
*pVal = T(nVal);
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
#pragma pop_macro("max")
|
|
#pragma pop_macro("min")
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AtlGetXMLValue (for IXMLDOMDocument) - get the real type from the XML data
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// generic IXMLDOMNode template function
|
|
// delegates to AtlGetSAXValue
|
|
//
|
|
template <typename T>
|
|
inline HRESULT AtlGetXMLValue(IXMLDOMNode *pParam, T *pVal)
|
|
{
|
|
CComBSTR bstrVal;
|
|
HRESULT hr = AtlGetXMLValue(pParam, &bstrVal);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = AtlGetSAXValue(pVal, bstrVal, bstrVal.Length());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// specialization for BSTR
|
|
template <>
|
|
inline HRESULT AtlGetXMLValue<BSTR>(IXMLDOMNode *pParam, BSTR *pbstrVal)
|
|
{
|
|
if (pParam == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
if (pbstrVal == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
CComPtr<IXMLDOMNode> spChild;
|
|
if (pParam->get_firstChild(&spChild) == S_OK)
|
|
{
|
|
CComPtr<IXMLDOMNode> spXmlChild;
|
|
if (spChild->get_firstChild(&spXmlChild) == S_OK)
|
|
{
|
|
return (pParam->get_xml(pbstrVal) == S_OK ? S_OK : E_FAIL);
|
|
}
|
|
}
|
|
|
|
return (pParam->get_text(pbstrVal) == S_OK) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AtlGetSAXValue - (for SAX or generic) get the real type from the XML data
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <>
|
|
inline HRESULT AtlGetSAXValue<bool>(bool *pVal, __in_z const wchar_t *wsz, int cch)
|
|
{
|
|
ATLENSURE( wsz != NULL );
|
|
|
|
if (!pVal)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pVal = false;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
switch (wsz[0])
|
|
{
|
|
case L'1':
|
|
{
|
|
if (cch==1)
|
|
{
|
|
*pVal = true;
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
}
|
|
case L'0':
|
|
{
|
|
if (cch==1)
|
|
{
|
|
*pVal = false;
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
}
|
|
case L't':
|
|
{
|
|
if (cch==sizeof("true")-1 && !wcsncmp(wsz, L"true", cch))
|
|
{
|
|
*pVal = true;
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
}
|
|
case L'f':
|
|
{
|
|
if (cch==sizeof("false")-1 && !wcsncmp(wsz, L"false", cch))
|
|
{
|
|
*pVal = false;
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlGetSAXValue<__int64>(__int64 *pVal, __in_z const wchar_t *wsz, int cch)
|
|
{
|
|
ATLENSURE_RETURN( wsz != NULL );
|
|
|
|
if (!pVal)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
_ATLTRY
|
|
{
|
|
CFixedStringT<CStringW, 1024> wstr(wsz, cch);
|
|
const wchar_t *pStart = ATL::SkipWhitespace(static_cast<LPCWSTR>(wstr));
|
|
const wchar_t *pEnd;
|
|
|
|
__int64 i = 0;
|
|
errno_t errnoValue = AtlStrToNum(&i, pStart, const_cast<wchar_t **>(&pEnd), 10);
|
|
if (errnoValue == ERANGE)
|
|
{
|
|
return E_FAIL;//overflow or underflow case
|
|
}
|
|
pEnd = ATL::SkipWhitespace(pEnd);
|
|
_ATL_VALIDATE_PARAMETER_END(pEnd);
|
|
*pVal = i;
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlGetSAXValue<unsigned __int64>(unsigned __int64 *pVal, __in_z const wchar_t *wsz, int cch)
|
|
{
|
|
ATLENSURE_RETURN( wsz != NULL );
|
|
|
|
if (!pVal)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
_ATLTRY
|
|
{
|
|
CFixedStringT<CStringW, 1024> wstr(wsz, cch);
|
|
const wchar_t *pStart = ATL::SkipWhitespace(static_cast<LPCWSTR>(wstr));
|
|
const wchar_t *pEnd;
|
|
|
|
unsigned __int64 i = 0;
|
|
errno_t errnoValue = AtlStrToNum(&i, pStart, const_cast<wchar_t **>(&pEnd), 10);
|
|
if (errnoValue == ERANGE)
|
|
{
|
|
return E_FAIL;//overflow or underflow case
|
|
}
|
|
pEnd = ATL::SkipWhitespace(pEnd);
|
|
_ATL_VALIDATE_PARAMETER_END(pEnd);
|
|
*pVal = i;
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
template <>
|
|
inline HRESULT AtlGetSAXValue<double>(double *pVal, __in_z const wchar_t *wsz, int cch)
|
|
{
|
|
ATLENSURE_RETURN( wsz != NULL );
|
|
|
|
if (!pVal)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ((cch == 3) && (wsz[0]==L'I') && (!wcsncmp(wsz, L"INF", cch)))
|
|
{
|
|
*(((int *) pVal)+0) = 0x0000000;
|
|
*(((int *) pVal)+1) = 0x7FF00000;
|
|
}
|
|
else if ((cch == 3) && (wsz[0]==L'N') && (!wcsncmp(wsz, L"NaN", cch)))
|
|
{
|
|
*(((int *) pVal)+0) = 0x0000000;
|
|
*(((int *) pVal)+1) = 0xFFF80000;
|
|
}
|
|
else if ((cch == 4) && (wsz[1]==L'I') && (!wcsncmp(wsz, L"-INF", cch)))
|
|
{
|
|
*(((int *) pVal)+0) = 0x0000000;
|
|
*(((int *) pVal)+1) = 0xFFF00000;
|
|
}
|
|
else
|
|
{
|
|
errno_t errnoValue = 0;
|
|
|
|
_ATLTRY
|
|
{
|
|
CFixedStringT<CStringW, 1024> wstr(wsz, cch);
|
|
const wchar_t *pStart = ATL::SkipWhitespace(static_cast<LPCWSTR>(wstr));
|
|
const wchar_t *pEnd;
|
|
double d = 0.0;
|
|
errnoValue = AtlStrToNum(&d, pStart, const_cast<wchar_t **>(&pEnd));
|
|
pEnd = ATL::SkipWhitespace(pEnd);
|
|
_ATL_VALIDATE_PARAMETER_END(pEnd);
|
|
*pVal = d;
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if ((*pVal == -HUGE_VAL) || (*pVal == HUGE_VAL) || (errnoValue == ERANGE))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlGetSAXValue<float>(float *pVal, __in_z const wchar_t *wsz, int cch)
|
|
{
|
|
ATLASSERT( wsz != NULL );
|
|
|
|
if (!pVal)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
double d = *pVal;
|
|
if (SUCCEEDED(AtlGetSAXValue(&d, wsz, cch)))
|
|
{
|
|
#ifdef _ATL_SOAP_PARAMETER_VALIDATIONS
|
|
if(d > FLT_MAX || d < -FLT_MAX)
|
|
return E_FAIL;
|
|
#endif
|
|
*pVal = (float) d;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlGetSAXValue<BSTR>(BSTR *pVal, __in_z const wchar_t *wsz, int cch)
|
|
{
|
|
ATLASSERT( wsz != NULL );
|
|
|
|
if (pVal == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pVal = SysAllocStringLen(wsz, cch);
|
|
|
|
return ((*pVal != NULL) ? S_OK : E_OUTOFMEMORY);
|
|
}
|
|
|
|
inline HRESULT AtlGetSAXBlobValue(
|
|
ATLSOAP_BLOB *pVal,
|
|
const wchar_t *wsz,
|
|
int cch,
|
|
IAtlMemMgr *pMemMgr,
|
|
bool bHex = false)
|
|
{
|
|
ATLENSURE_RETURN( wsz != NULL );
|
|
ATLENSURE_RETURN( pMemMgr != NULL );
|
|
|
|
if (pVal == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (pVal->data != NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
pVal->data = NULL;
|
|
pVal->size = 0;
|
|
|
|
int nLength = AtlUnicodeToUTF8(wsz, cch, NULL, 0);
|
|
|
|
if (nLength != 0)
|
|
{
|
|
char * pSrc = (char *) pMemMgr->Allocate(nLength);
|
|
if (pSrc != NULL)
|
|
{
|
|
nLength = AtlUnicodeToUTF8(wsz, cch, pSrc, nLength);
|
|
if (nLength != 0)
|
|
{
|
|
pVal->data = (unsigned char *) pMemMgr->Allocate(nLength);
|
|
if (pVal->data != NULL)
|
|
{
|
|
BOOL bRet;
|
|
int nDataLength = nLength;
|
|
if (!bHex)
|
|
{
|
|
bRet = Base64Decode(pSrc, nLength, pVal->data, &nDataLength);
|
|
}
|
|
else
|
|
{
|
|
bRet = AtlHexDecode(pSrc, nLength, pVal->data, &nDataLength);
|
|
}
|
|
if (bRet)
|
|
{
|
|
pVal->size = nDataLength;
|
|
}
|
|
}
|
|
}
|
|
|
|
pMemMgr->Free(pSrc);
|
|
}
|
|
}
|
|
|
|
if (pVal->size == 0)
|
|
{
|
|
if (pVal->data != NULL)
|
|
{
|
|
pMemMgr->Free(pVal->data);
|
|
pVal->data = NULL;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AtlGenXMLValue template and specializations
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename T>
|
|
inline HRESULT AtlGenXMLValue(__in IWriteStream *pStream, __in T *pVal)
|
|
{
|
|
if ((pStream == NULL) || (pVal == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// delegate to CWriteStreamHelper
|
|
//
|
|
CWriteStreamHelper s(pStream);
|
|
|
|
return (s.Write(*pVal) == TRUE ? S_OK : E_FAIL);
|
|
}
|
|
|
|
#ifdef _NATIVE_WCHAR_T_DEFINED
|
|
template <>
|
|
inline HRESULT AtlGenXMLValue<wchar_t>(__in IWriteStream *pStream, __in wchar_t *pVal)
|
|
{
|
|
return AtlGenXMLValue(pStream, (unsigned short *)pVal);
|
|
}
|
|
#endif
|
|
|
|
template <>
|
|
inline HRESULT AtlGenXMLValue<wchar_t *>(__in IWriteStream *pStream, __deref_inout_z wchar_t **pVal)
|
|
{
|
|
if ((pStream == NULL) || (*pVal == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
wchar_t *wszWrite = *pVal;
|
|
int nSrcLen = (int)wcslen(*pVal);
|
|
int nCnt = EscapeXML(*pVal, nSrcLen, NULL, 0);
|
|
if (nCnt > nSrcLen)
|
|
{
|
|
nCnt++;
|
|
wszWrite = (wchar_t *)calloc((nCnt),sizeof(wchar_t));
|
|
if (wszWrite == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
nCnt = EscapeXML(*pVal, nSrcLen, wszWrite, nCnt);
|
|
if (nCnt == 0)
|
|
{
|
|
free(wszWrite);
|
|
return E_FAIL;
|
|
}
|
|
wszWrite[nCnt] = L'\0';
|
|
nSrcLen = nCnt;
|
|
}
|
|
|
|
nCnt = AtlUnicodeToUTF8(wszWrite, nSrcLen, NULL, 0);
|
|
HRESULT hr = E_FAIL;
|
|
if ((nCnt == 0) || (nCnt == nSrcLen))
|
|
{
|
|
CWriteStreamHelper s(pStream);
|
|
|
|
hr = (s.Write(wszWrite) == TRUE ? S_OK : E_FAIL);
|
|
}
|
|
else
|
|
{
|
|
nCnt++;
|
|
CHeapPtr<char> szWrite;
|
|
szWrite.AllocateBytes((size_t)(nCnt));
|
|
if (szWrite != NULL)
|
|
{
|
|
nCnt = AtlUnicodeToUTF8(wszWrite, nSrcLen, szWrite, nCnt);
|
|
if (nCnt != 0)
|
|
{
|
|
hr = pStream->WriteStream(szWrite, nCnt, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: AtlGenXMLValue<wchar_t *> -- out of memory.\r\n") );
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if (wszWrite != *pVal)
|
|
{
|
|
free(wszWrite);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlGenXMLValue<double>(IWriteStream *pStream, double *pVal)
|
|
{
|
|
if ((pStream == NULL) || (pVal == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT hr;
|
|
switch (_fpclass(*pVal))
|
|
{
|
|
case _FPCLASS_SNAN:
|
|
case _FPCLASS_QNAN:
|
|
{
|
|
hr = pStream->WriteStream("NaN", 3, NULL);
|
|
break;
|
|
}
|
|
case _FPCLASS_NINF:
|
|
{
|
|
hr = pStream->WriteStream("-INF", 4, NULL);
|
|
break;
|
|
}
|
|
case _FPCLASS_PINF:
|
|
{
|
|
hr = pStream->WriteStream("INF", 3, NULL);
|
|
break;
|
|
}
|
|
case _FPCLASS_NZ:
|
|
{
|
|
hr = pStream->WriteStream("-0", 2, NULL);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
/***
|
|
* 2 = sign + decimal point
|
|
* ndec = decimal digits
|
|
* 5 = exponent letter (e or E), exponent sign, three digits exponent
|
|
* 1 = extra space for rounding
|
|
* 1 = string terminator '\0'
|
|
***/
|
|
const int ndec = 512;
|
|
CHAR szBuf[ndec+9];
|
|
szBuf[0] = '\0';
|
|
Checked::gcvt_s(szBuf, _countof(szBuf), *pVal, ndec);
|
|
size_t nLen = strlen(szBuf);
|
|
if (nLen && szBuf[nLen-1] == '.')
|
|
{
|
|
szBuf[--nLen] = '\0';
|
|
}
|
|
|
|
hr = pStream->WriteStream(szBuf, (int)nLen, NULL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlGenXMLValue<float>(IWriteStream *pStream, float *pVal)
|
|
{
|
|
if ((pStream == NULL) || (pVal == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
double d = *pVal;
|
|
|
|
return AtlGenXMLValue(pStream, &d);
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlGenXMLValue<bool>(IWriteStream *pStream, bool *pVal)
|
|
{
|
|
if ((pStream == NULL) || (pVal == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (*pVal == true)
|
|
{
|
|
return pStream->WriteStream("true", sizeof("true")-1, NULL);
|
|
}
|
|
|
|
return pStream->WriteStream("false", sizeof("false")-1, NULL);
|
|
}
|
|
|
|
inline HRESULT AtlGenXMLBlobValue(
|
|
IWriteStream *pStream,
|
|
ATLSOAP_BLOB *pVal,
|
|
IAtlMemMgr *pMemMgr,
|
|
bool bHex = false)
|
|
{
|
|
if ((pStream == NULL) || (pVal == NULL) || (pMemMgr == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT hr = E_FAIL;
|
|
int nLength;
|
|
if (!bHex)
|
|
{
|
|
nLength = Base64EncodeGetRequiredLength(pVal->size, ATLSOAP_BASE64_FLAGS);
|
|
}
|
|
else
|
|
{
|
|
nLength = AtlHexEncodeGetRequiredLength(pVal->size);
|
|
}
|
|
|
|
char *pEnc = (char *) pMemMgr->Allocate(nLength);
|
|
if (pEnc != NULL)
|
|
{
|
|
BOOL bRet;
|
|
if (!bHex)
|
|
{
|
|
bRet = Base64Encode(pVal->data, pVal->size, pEnc, &nLength, ATLSOAP_BASE64_FLAGS);
|
|
}
|
|
else
|
|
{
|
|
bRet = AtlHexEncode(pVal->data, pVal->size, pEnc, &nLength);
|
|
}
|
|
if (bRet)
|
|
{
|
|
hr = pStream->WriteStream(pEnc, nLength, NULL);
|
|
}
|
|
|
|
pMemMgr->Free(pEnc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <typename T>
|
|
inline HRESULT AtlCleanupValue(T * /*pVal*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
inline HRESULT AtlCleanupBlobValue(ATLSOAP_BLOB *pVal, IAtlMemMgr *pMemMgr)
|
|
{
|
|
if ((pVal == NULL) || (pMemMgr == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (pVal->data != NULL)
|
|
{
|
|
pMemMgr->Free(pVal->data);
|
|
pVal->data = NULL;
|
|
pVal->size = 0;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlCleanupValue<ATLSOAP_BLOB>(ATLSOAP_BLOB *pVal)
|
|
{
|
|
ATLTRACE( _T("Warning: AtlCleanupValue<ATLSOAP_BLOB> was called -- assuming CRT allocator.\r\n") );
|
|
|
|
if (pVal == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (pVal->data != NULL)
|
|
{
|
|
free(pVal->data);
|
|
pVal->data = NULL;
|
|
pVal->size = 0;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlCleanupValue<BSTR>(BSTR *pVal)
|
|
{
|
|
if (pVal == NULL)
|
|
{
|
|
// should never happen
|
|
ATLASSERT( FALSE );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ((*pVal) != NULL)
|
|
{
|
|
// null strings are okay
|
|
SysFreeString(*pVal);
|
|
*pVal = NULL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
template <typename T>
|
|
inline HRESULT AtlCleanupValueEx(T *pVal, IAtlMemMgr *pMemMgr)
|
|
{
|
|
pMemMgr;
|
|
|
|
return AtlCleanupValue(pVal);
|
|
}
|
|
|
|
template <>
|
|
inline HRESULT AtlCleanupValueEx<ATLSOAP_BLOB>(ATLSOAP_BLOB *pVal, IAtlMemMgr *pMemMgr)
|
|
{
|
|
return AtlCleanupBlobValue(pVal, pMemMgr);
|
|
}
|
|
|
|
// single dimensional arrays
|
|
template <typename T>
|
|
inline HRESULT AtlCleanupArray(T *pArray, int nCnt)
|
|
{
|
|
if (pArray == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
for (int i=0; i<nCnt; i++)
|
|
{
|
|
AtlCleanupValue(&pArray[i]);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
inline HRESULT AtlCleanupArrayEx(T *pArray, int nCnt, IAtlMemMgr *pMemMgr)
|
|
{
|
|
if (pArray == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
for (int i=0; i<nCnt; i++)
|
|
{
|
|
AtlCleanupValueEx(&pArray[i], pMemMgr);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// multi-dimensional arrays
|
|
template <typename T>
|
|
inline HRESULT AtlCleanupArrayMD(T *pArray, const int *pDims)
|
|
{
|
|
if ((pArray == NULL) || (pDims == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// calculate size
|
|
int nCnt = 1;
|
|
for (int i=1; i<=pDims[0]; i++)
|
|
{
|
|
nCnt*= pDims[i];
|
|
}
|
|
|
|
return AtlCleanupArray(pArray, nCnt);
|
|
}
|
|
|
|
template <typename T>
|
|
inline HRESULT AtlCleanupArrayMDEx(T *pArray, const int *pDims, IAtlMemMgr *pMemMgr)
|
|
{
|
|
if ((pArray == NULL) || (pDims == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// calculate size
|
|
int nCnt = 1;
|
|
for (int i=1; i<=pDims[0]; i++)
|
|
{
|
|
nCnt*= pDims[i];
|
|
}
|
|
|
|
return AtlCleanupArrayEx(pArray, nCnt, pMemMgr);
|
|
}
|
|
|
|
|
|
#pragma pack(push,_ATL_PACKING)
|
|
namespace ATL
|
|
{
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CSAXSoapErrorHandler
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CSAXSoapErrorHandler : public ISAXErrorHandler
|
|
{
|
|
private:
|
|
|
|
CFixedStringT<CStringW, 256> m_strParseError;
|
|
|
|
public:
|
|
virtual ~CSAXSoapErrorHandler()
|
|
{
|
|
}
|
|
|
|
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (!ppv)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (InlineIsEqualGUID(riid, __uuidof(ISAXErrorHandler)) ||
|
|
InlineIsEqualGUID(riid, __uuidof(IUnknown)))
|
|
{
|
|
*ppv = static_cast<ISAXErrorHandler*>(this);
|
|
return S_OK;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
const CStringW& GetParseError()
|
|
{
|
|
return m_strParseError;
|
|
}
|
|
|
|
HRESULT __stdcall error(
|
|
ISAXLocator *pLocator,
|
|
const wchar_t *wszErrorMessage,
|
|
HRESULT hrErrorCode)
|
|
{
|
|
(pLocator);
|
|
(wszErrorMessage);
|
|
(hrErrorCode);
|
|
|
|
ATLTRACE( _T("ATLSOAP: parse error: %ws\r\n"), wszErrorMessage );
|
|
|
|
_ATLTRY
|
|
{
|
|
m_strParseError = wszErrorMessage;
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return hrErrorCode;
|
|
}
|
|
|
|
HRESULT __stdcall fatalError(
|
|
ISAXLocator *pLocator,
|
|
const wchar_t *wszErrorMessage,
|
|
HRESULT hrErrorCode)
|
|
{
|
|
(pLocator);
|
|
(wszErrorMessage);
|
|
(hrErrorCode);
|
|
|
|
ATLTRACE( _T("ATLSOAP: fatal parse error: %ws\r\n"), wszErrorMessage );
|
|
|
|
_ATLTRY
|
|
{
|
|
m_strParseError = wszErrorMessage;
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return hrErrorCode;
|
|
}
|
|
|
|
HRESULT __stdcall ignorableWarning(
|
|
ISAXLocator *pLocator,
|
|
const wchar_t *wszErrorMessage,
|
|
HRESULT hrErrorCode)
|
|
{
|
|
(pLocator);
|
|
(wszErrorMessage);
|
|
(hrErrorCode);
|
|
|
|
ATLTRACE( _T("ATLSOAP: ignorable warning: %ws\r\n"), wszErrorMessage );
|
|
|
|
return hrErrorCode;
|
|
}
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ISAXContentHandlerImpl
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class ISAXContentHandlerImpl :
|
|
public ISAXContentHandler
|
|
{
|
|
public:
|
|
|
|
//
|
|
// ISAXContentHandler interface
|
|
//
|
|
|
|
HRESULT __stdcall putDocumentLocator(ISAXLocator * /*pLocator*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall startDocument()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall endDocument()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall startPrefixMapping(
|
|
const wchar_t * /*wszPrefix*/,
|
|
int /*cchPrefix*/,
|
|
const wchar_t * /*wszUri*/,
|
|
int /*cchUri*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall endPrefixMapping(
|
|
const wchar_t * /*wszPrefix*/,
|
|
int /*cchPrefix*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall startElement(
|
|
const wchar_t * /*wszNamespaceUri*/,
|
|
int /*cchNamespaceUri*/,
|
|
const wchar_t * /*wszLocalName*/,
|
|
int /*cchLocalName*/,
|
|
const wchar_t * /*wszQName*/,
|
|
int /*cchQName*/,
|
|
ISAXAttributes * /*pAttributes*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall endElement(
|
|
const wchar_t * /*wszNamespaceUri*/,
|
|
int /*cchNamespaceUri*/,
|
|
const wchar_t * /*wszLocalName*/,
|
|
int /*cchLocalName*/,
|
|
const wchar_t * /*wszQName*/,
|
|
int /*cchQName*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall characters(
|
|
const wchar_t * /*wszChars*/,
|
|
int /*cchChars*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall ignorableWhitespace(
|
|
const wchar_t * /*wszChars*/,
|
|
int /*cchChars*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall processingInstruction(
|
|
const wchar_t * /*wszTarget*/,
|
|
int /*cchTarget*/,
|
|
const wchar_t * /*wszData*/,
|
|
int /*cchData*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall skippedEntity(
|
|
const wchar_t * /*wszName*/,
|
|
int /*cchName*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
}; // class ISAXContentHandlerImpl
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SAX skip element handler utility class
|
|
// (skip an element and all its child elements)
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CSkipHandler : public ISAXContentHandlerImpl
|
|
{
|
|
public:
|
|
virtual ~CSkipHandler()
|
|
{
|
|
}
|
|
|
|
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
|
|
if (InlineIsEqualGUID(riid, IID_IUnknown) ||
|
|
InlineIsEqualGUID(riid, IID_ISAXContentHandler))
|
|
{
|
|
*ppv = static_cast<ISAXContentHandler *>(this);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
private:
|
|
|
|
DWORD m_dwReset;
|
|
CComPtr<ISAXXMLReader> m_spReader;
|
|
CComPtr<ISAXContentHandler> m_spParent;
|
|
|
|
DWORD DisableReset(DWORD dwCnt = 1)
|
|
{
|
|
m_dwReset += dwCnt;
|
|
|
|
return m_dwReset;
|
|
}
|
|
|
|
DWORD EnableReset()
|
|
{
|
|
if (m_dwReset > 0)
|
|
{
|
|
--m_dwReset;
|
|
}
|
|
|
|
return m_dwReset;
|
|
}
|
|
|
|
public:
|
|
|
|
CSkipHandler(ISAXContentHandler *pParent = NULL, ISAXXMLReader *pReader = NULL)
|
|
: m_spParent(pParent), m_spReader(pReader), m_dwReset(1)
|
|
{
|
|
}
|
|
|
|
void SetParent(ISAXContentHandler *pParent)
|
|
{
|
|
m_spParent = pParent;
|
|
}
|
|
void DetachParent()
|
|
{
|
|
m_spParent.Detach();
|
|
}
|
|
|
|
void SetReader(ISAXXMLReader *pReader)
|
|
{
|
|
m_spReader = pReader;
|
|
}
|
|
|
|
HRESULT __stdcall startElement(
|
|
const wchar_t * /*wszNamespaceUri*/,
|
|
int /*cchNamespaceUri*/,
|
|
const wchar_t * /*wszLocalName*/,
|
|
int /*cchLocalName*/,
|
|
const wchar_t * /*wszQName*/,
|
|
int /*cchQName*/,
|
|
ISAXAttributes * /*pAttributes*/)
|
|
{
|
|
DisableReset();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall endElement(
|
|
const wchar_t * /*wszNamespaceUri*/,
|
|
int /*cchNamespaceUri*/,
|
|
const wchar_t * /*wszLocalName*/,
|
|
int /*cchLocalName*/,
|
|
const wchar_t * /*wszQName*/,
|
|
int /*cchQName*/)
|
|
{
|
|
if (EnableReset() == 0)
|
|
{
|
|
m_spReader->putContentHandler(m_spParent);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
}; // class CSkipHandler
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SAX string builder class
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CSAXStringBuilder : public ISAXContentHandlerImpl
|
|
{
|
|
public:
|
|
|
|
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
|
|
if (InlineIsEqualGUID(riid, IID_IUnknown) ||
|
|
InlineIsEqualGUID(riid, IID_ISAXContentHandler))
|
|
{
|
|
*ppv = static_cast<ISAXContentHandler *>(this);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
private:
|
|
|
|
ISAXContentHandler * m_pParent;
|
|
ISAXXMLReader * m_pReader;
|
|
DWORD m_dwReset;
|
|
CFixedStringT<CStringW, 64> m_str;
|
|
|
|
DWORD DisableReset(DWORD dwReset = 1)
|
|
{
|
|
m_dwReset+= dwReset;
|
|
|
|
return m_dwReset;
|
|
}
|
|
|
|
DWORD EnableReset()
|
|
{
|
|
if (m_dwReset > 0)
|
|
{
|
|
--m_dwReset;
|
|
}
|
|
|
|
return m_dwReset;
|
|
}
|
|
|
|
public:
|
|
|
|
CSAXStringBuilder(ISAXXMLReader *pReader = NULL, ISAXContentHandler *pParent = NULL)
|
|
:m_pReader(pReader), m_pParent(pParent), m_dwReset(0)
|
|
{
|
|
}
|
|
|
|
virtual ~CSAXStringBuilder()
|
|
{
|
|
}
|
|
|
|
void SetReader(ISAXXMLReader *pReader)
|
|
{
|
|
m_pReader = pReader;
|
|
}
|
|
|
|
void SetParent(ISAXContentHandler *pParent)
|
|
{
|
|
m_pParent = pParent;
|
|
}
|
|
|
|
const CStringW& GetString()
|
|
{
|
|
return m_str;
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
m_str.Empty();
|
|
m_dwReset = 0;
|
|
}
|
|
|
|
HRESULT __stdcall startElement(
|
|
const wchar_t * /*wszNamespaceUri*/,
|
|
int /*cchNamespaceUri*/,
|
|
const wchar_t * /*wszLocalName*/,
|
|
int /*cchLocalName*/,
|
|
const wchar_t *wszQName,
|
|
int cchQName,
|
|
ISAXAttributes *pAttributes)
|
|
{
|
|
if (m_dwReset == 0)
|
|
{
|
|
// if there is unescaped, nested XML, must disable
|
|
// an additional time for the first element
|
|
DisableReset();
|
|
}
|
|
DisableReset();
|
|
|
|
int nAttrs = 0;
|
|
HRESULT hr = pAttributes->getLength(&nAttrs);
|
|
|
|
_ATLTRY
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_str.Append(L"<", 1);
|
|
m_str.Append(wszQName, cchQName);
|
|
|
|
const wchar_t *wszAttrNamespaceUri = NULL;
|
|
const wchar_t *wszAttrLocalName = NULL;
|
|
const wchar_t *wszAttrQName = NULL;
|
|
const wchar_t *wszAttrValue = NULL;
|
|
int cchAttrUri = 0;
|
|
int cchAttrLocalName = 0;
|
|
int cchAttrQName = 0;
|
|
int cchAttrValue = 0;
|
|
|
|
for (int i=0; i<nAttrs; i++)
|
|
{
|
|
hr = pAttributes->getName(i, &wszAttrNamespaceUri, &cchAttrUri,
|
|
&wszAttrLocalName, &cchAttrLocalName, &wszAttrQName, &cchAttrQName);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSAXStringBuilder::startElement -- MSXML error.\r\n") );
|
|
|
|
break;
|
|
}
|
|
|
|
m_str.Append(L" ", 1);
|
|
m_str.Append(wszAttrQName, cchAttrQName);
|
|
|
|
hr = pAttributes->getValue(i, &wszAttrValue, &cchAttrValue);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSAXStringBuilder::startElement -- MSXML error.\r\n") );
|
|
|
|
break;
|
|
}
|
|
|
|
m_str.Append(L"=\"", sizeof("=\"")-1);
|
|
if (cchAttrValue != 0)
|
|
{
|
|
m_str.Append(wszAttrValue, cchAttrValue);
|
|
}
|
|
m_str.Append(L"\"", 1);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_str.Append(L">", 1);
|
|
}
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSAXStringBuilder::startElement -- out of memory.\r\n") );
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall endElement(
|
|
const wchar_t * wszNamespaceUri,
|
|
int cchNamespaceUri,
|
|
const wchar_t * wszLocalName,
|
|
int cchLocalName,
|
|
const wchar_t *wszQName,
|
|
int cchQName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
_ATLTRY
|
|
{
|
|
if (EnableReset() == 0)
|
|
{
|
|
hr = m_pParent->characters((LPCWSTR) m_str, m_str.GetLength());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_pParent->endElement(wszNamespaceUri, cchNamespaceUri,
|
|
wszLocalName, cchLocalName, wszQName, cchQName);
|
|
}
|
|
|
|
m_pReader->putContentHandler(m_pParent);
|
|
}
|
|
|
|
if (m_dwReset > 0)
|
|
{
|
|
m_str.Append(L"</", 2);
|
|
m_str.Append(wszQName, cchQName);
|
|
m_str.Append(L">", 1);
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSAXStringBuilder::endElement -- out of memory.\r\n") );
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall characters(
|
|
const wchar_t *wszChars,
|
|
int cchChars)
|
|
{
|
|
_ATLTRY
|
|
{
|
|
m_str.Append(wszChars, cchChars);
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSAXStringBuilder::characters -- out of memory.\r\n") );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall ignorableWhitespace(
|
|
const wchar_t *wszChars,
|
|
int cchChars)
|
|
{
|
|
_ATLTRY
|
|
{
|
|
m_str.Append(wszChars, cchChars);
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSAXStringBuilder::ignorableWhitespace -- out of memory.\r\n") );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
}; // class CSAXStringBuilder
|
|
|
|
} // namespace ATL
|
|
#pragma pack(pop)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SOAP data structure definitions
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// ***************************** WARNING *****************************
|
|
// THESE STRUCTURES ARE INTERNAL ONLY, FOR USE WITH THE ATL SERVER SOAP
|
|
// ATTRIBUTES. USERS SHOULD NOT USE THESE TYPES DIRECTLY. ABSOLUTELY NO
|
|
// GUARANTEES ARE MADE ABOUT BACKWARD COMPATIBILITY FOR DIRECT USE OF
|
|
// THESE TYPES.
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BEGIN PRIVATE DEFINITIONS
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline HRESULT AtlSoapGetArraySize(ISAXAttributes *pAttributes, size_t *pnSize,
|
|
const wchar_t **pwszTypeStart = NULL, const wchar_t **pwszTypeEnd = NULL)
|
|
{
|
|
if (pnSize == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (pAttributes == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pnSize = 0;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
_ATLTRY
|
|
{
|
|
const wchar_t *wszTmp;
|
|
int cch;
|
|
|
|
hr = GetAttribute(pAttributes, L"arrayType", sizeof("arrayType")-1,
|
|
&wszTmp, &cch, SOAPENC_NAMESPACEW, sizeof(SOAPENC_NAMESPACEA)-1);
|
|
|
|
if ((SUCCEEDED(hr)) && (wszTmp != NULL))
|
|
{
|
|
hr = E_FAIL;
|
|
|
|
CFixedStringT<CStringW, 1024> wstrArrayType(wszTmp, cch);
|
|
const wchar_t *wsz = static_cast<LPCWSTR>(wstrArrayType);
|
|
|
|
const wchar_t *wszTypeStart = NULL;
|
|
const wchar_t *wszTypeEnd = NULL;
|
|
|
|
// skip spaces
|
|
while (iswspace(*wsz) != 0)
|
|
{
|
|
wsz++;
|
|
}
|
|
|
|
// no need to walk the string if the caller is not interested
|
|
if ((pwszTypeStart != NULL) && (pwszTypeEnd != NULL))
|
|
{
|
|
wszTypeStart = wsz;
|
|
wszTypeEnd = wcschr(wszTypeStart, L':');
|
|
if (wszTypeEnd != NULL)
|
|
{
|
|
wszTypeStart = wszTypeEnd+1;
|
|
}
|
|
}
|
|
|
|
// SOAP Section 5 encodings are of the form:
|
|
// <soap_enc namespace>:arrayType="<type_qname>[dim1(,dim_i)*]
|
|
// for example: SOAP-ENC:arrayType="xsd:string[2,4]"
|
|
|
|
wsz = wcschr(wsz, L'[');
|
|
if (wsz != NULL)
|
|
{
|
|
wszTypeEnd = wsz-1;
|
|
if (wsz[1] == ']')
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
*pnSize = 1;
|
|
|
|
// get the size of each dimension
|
|
while (wsz != NULL)
|
|
{
|
|
wsz++;
|
|
int nDim = _wtoi(wsz);
|
|
if (nDim < 0)
|
|
{
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
*pnSize *= (size_t) nDim;
|
|
if (!nDim)
|
|
{
|
|
break;
|
|
}
|
|
|
|
wsz = wcschr(wsz, L',');
|
|
}
|
|
|
|
if ((pwszTypeStart != NULL) && (pwszTypeEnd != NULL))
|
|
{
|
|
*pwszTypeStart = wszTypeStart;
|
|
*pwszTypeEnd = wszTypeEnd;
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// not a section-5 encoding
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
inline size_t AtlSoapGetArrayDims(const int *pDims)
|
|
{
|
|
if (pDims == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t nRet = 1;
|
|
for (int i=1; i<=pDims[0]; i++)
|
|
{
|
|
nRet *= pDims[i];
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
enum SOAPFLAGS
|
|
{
|
|
SOAPFLAG_NONE = 0x00000000,
|
|
SOAPFLAG_IN = 0x00000001,
|
|
SOAPFLAG_OUT = 0x00000002,
|
|
SOAPFLAG_RETVAL = 0x00000004,
|
|
SOAPFLAG_DYNARR = 0x00000008,
|
|
SOAPFLAG_FIXEDARR = 0x00000010,
|
|
SOAPFLAG_MUSTUNDERSTAND = 0x00000020,
|
|
SOAPFLAG_UNKSIZE = 0x00000040,
|
|
SOAPFLAG_READYSTATE = 0x00000080,
|
|
SOAPFLAG_FIELD = 0x00000100,
|
|
SOAPFLAG_NOMARSHAL = 0x00000200,
|
|
SOAPFLAG_NULLABLE = 0x00000400,
|
|
SOAPFLAG_DOCUMENT = 0x00000800,
|
|
SOAPFLAG_RPC = 0x00001000,
|
|
SOAPFLAG_LITERAL = 0x00002000,
|
|
SOAPFLAG_ENCODED = 0x00004000,
|
|
SOAPFLAG_PID = 0x00008000,
|
|
SOAPFLAG_PAD = 0x00010000,
|
|
SOAPFLAG_CHAIN = 0x00020000,
|
|
SOAPFLAG_SIZEIS = 0x00040000,
|
|
SOAPFLAG_DYNARRWRAPPER = 0x00080000
|
|
};
|
|
|
|
enum SOAPMAPTYPE
|
|
{
|
|
SOAPMAP_ERR = 0,
|
|
SOAPMAP_ENUM,
|
|
SOAPMAP_FUNC,
|
|
SOAPMAP_STRUCT,
|
|
SOAPMAP_UNION,
|
|
SOAPMAP_HEADER,
|
|
SOAPMAP_PARAM
|
|
};
|
|
|
|
struct _soapmap;
|
|
|
|
struct _soapmapentry
|
|
{
|
|
ULONG nHash;
|
|
const char * szField;
|
|
const WCHAR * wszField;
|
|
int cchField;
|
|
int nVal;
|
|
DWORD dwFlags;
|
|
|
|
size_t nOffset;
|
|
const int * pDims;
|
|
|
|
const _soapmap * pChain;
|
|
|
|
int nSizeIs;
|
|
|
|
ULONG nNamespaceHash;
|
|
const char *szNamespace;
|
|
const wchar_t *wszNamespace;
|
|
int cchNamespace;
|
|
};
|
|
|
|
struct _soapmap
|
|
{
|
|
ULONG nHash;
|
|
const char * szName;
|
|
const wchar_t * wszName;
|
|
int cchName;
|
|
int cchWName;
|
|
SOAPMAPTYPE mapType;
|
|
const _soapmapentry * pEntries;
|
|
size_t nElementSize;
|
|
size_t nElements;
|
|
int nRetvalIndex;
|
|
|
|
DWORD dwCallFlags;
|
|
|
|
ULONG nNamespaceHash;
|
|
const char *szNamespace;
|
|
const wchar_t *wszNamespace;
|
|
int cchNamespace;
|
|
};
|
|
|
|
enum SOAPTYPES
|
|
{
|
|
SOAPTYPE_ERR = -2,
|
|
SOAPTYPE_UNK = -1,
|
|
SOAPTYPE_STRING = 0,
|
|
SOAPTYPE_BOOLEAN,
|
|
SOAPTYPE_FLOAT,
|
|
SOAPTYPE_DOUBLE,
|
|
SOAPTYPE_DECIMAL,
|
|
SOAPTYPE_DURATION,
|
|
SOAPTYPE_HEXBINARY,
|
|
SOAPTYPE_BASE64BINARY,
|
|
SOAPTYPE_ANYURI,
|
|
SOAPTYPE_ID,
|
|
SOAPTYPE_IDREF,
|
|
SOAPTYPE_ENTITY,
|
|
SOAPTYPE_NOTATION,
|
|
SOAPTYPE_QNAME,
|
|
SOAPTYPE_NORMALIZEDSTRING,
|
|
SOAPTYPE_TOKEN,
|
|
SOAPTYPE_LANGUAGE,
|
|
SOAPTYPE_IDREFS,
|
|
SOAPTYPE_ENTITIES,
|
|
SOAPTYPE_NMTOKEN,
|
|
SOAPTYPE_NMTOKENS,
|
|
SOAPTYPE_NAME,
|
|
SOAPTYPE_NCNAME,
|
|
SOAPTYPE_INTEGER,
|
|
SOAPTYPE_NONPOSITIVEINTEGER,
|
|
SOAPTYPE_NEGATIVEINTEGER,
|
|
SOAPTYPE_LONG,
|
|
SOAPTYPE_INT,
|
|
SOAPTYPE_SHORT,
|
|
SOAPTYPE_BYTE,
|
|
SOAPTYPE_NONNEGATIVEINTEGER,
|
|
SOAPTYPE_UNSIGNEDLONG,
|
|
SOAPTYPE_UNSIGNEDINT,
|
|
SOAPTYPE_UNSIGNEDSHORT,
|
|
SOAPTYPE_UNSIGNEDBYTE,
|
|
SOAPTYPE_POSITIVEINTEGER,
|
|
SOAPTYPE_DATETIME,
|
|
SOAPTYPE_TIME,
|
|
SOAPTYPE_DATE,
|
|
SOAPTYPE_GMONTH,
|
|
SOAPTYPE_GYEARMONTH,
|
|
SOAPTYPE_GYEAR,
|
|
SOAPTYPE_GMONTHDAY,
|
|
SOAPTYPE_GDAY,
|
|
|
|
SOAPTYPE_USERBASE = 0x00001000
|
|
};
|
|
|
|
inline ULONG AtlSoapHashStr(const char * sz)
|
|
{
|
|
ULONG nHash = 0;
|
|
while (*sz != 0)
|
|
{
|
|
nHash = (nHash<<5)+nHash+(*sz);
|
|
sz++;
|
|
}
|
|
|
|
return nHash;
|
|
}
|
|
|
|
inline ULONG AtlSoapHashStr(const wchar_t * sz)
|
|
{
|
|
ULONG nHash = 0;
|
|
while (*sz != 0)
|
|
{
|
|
nHash = (nHash<<5)+nHash+(*sz);
|
|
sz++;
|
|
}
|
|
|
|
return nHash;
|
|
}
|
|
|
|
inline ULONG AtlSoapHashStr(const char * sz, int cch)
|
|
{
|
|
ULONG nHash = 0;
|
|
for (int i=0; i<cch; i++)
|
|
{
|
|
nHash = (nHash<<5)+nHash+(*sz);
|
|
sz++;
|
|
}
|
|
|
|
return nHash;
|
|
}
|
|
|
|
inline ULONG AtlSoapHashStr(const wchar_t * sz, int cch)
|
|
{
|
|
ULONG nHash = 0;
|
|
for (int i=0; i<cch; i++)
|
|
{
|
|
nHash = (nHash<<5)+nHash+(*sz);
|
|
sz++;
|
|
}
|
|
|
|
return nHash;
|
|
}
|
|
|
|
inline size_t AtlSoapGetElementSize(SOAPTYPES type)
|
|
{
|
|
size_t nRet;
|
|
switch (type)
|
|
{
|
|
case SOAPTYPE_BOOLEAN:
|
|
nRet = sizeof(bool);
|
|
break;
|
|
case SOAPTYPE_FLOAT:
|
|
nRet = sizeof(float);
|
|
break;
|
|
case SOAPTYPE_DOUBLE:
|
|
case SOAPTYPE_DECIMAL:
|
|
nRet = sizeof(double);
|
|
break;
|
|
case SOAPTYPE_HEXBINARY:
|
|
case SOAPTYPE_BASE64BINARY:
|
|
nRet = sizeof(ATLSOAP_BLOB);
|
|
break;
|
|
case SOAPTYPE_INTEGER:
|
|
case SOAPTYPE_NONPOSITIVEINTEGER:
|
|
case SOAPTYPE_NEGATIVEINTEGER:
|
|
case SOAPTYPE_LONG:
|
|
nRet = sizeof(__int64);
|
|
break;
|
|
case SOAPTYPE_INT:
|
|
nRet = sizeof(int);
|
|
break;
|
|
case SOAPTYPE_SHORT:
|
|
nRet = sizeof(short);
|
|
break;
|
|
case SOAPTYPE_BYTE:
|
|
nRet = sizeof(char);
|
|
break;
|
|
case SOAPTYPE_POSITIVEINTEGER:
|
|
case SOAPTYPE_NONNEGATIVEINTEGER:
|
|
case SOAPTYPE_UNSIGNEDLONG:
|
|
nRet = sizeof(unsigned __int64);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDINT:
|
|
nRet = sizeof(unsigned int);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDSHORT:
|
|
nRet = sizeof(unsigned short);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDBYTE:
|
|
nRet = sizeof(unsigned char);
|
|
break;
|
|
default:
|
|
if ((type != SOAPTYPE_ERR) && (type != SOAPTYPE_UNK) && (type != SOAPTYPE_USERBASE))
|
|
{
|
|
// treat as string
|
|
nRet = sizeof(BSTR);
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: AtlSoapGetElementSize -- internal error.\r\n") );
|
|
// should never get here
|
|
ATLASSERT( FALSE );
|
|
nRet = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
inline HRESULT AtlSoapGetElementValue(const wchar_t *wsz, int cch,
|
|
void *pVal, SOAPTYPES type, IAtlMemMgr *pMemMgr)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
switch (type)
|
|
{
|
|
case SOAPTYPE_BOOLEAN:
|
|
hr = AtlGetSAXValue((bool *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_FLOAT:
|
|
hr = AtlGetSAXValue((float *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_DOUBLE:
|
|
case SOAPTYPE_DECIMAL:
|
|
hr = AtlGetSAXValue((double *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_HEXBINARY:
|
|
hr = AtlGetSAXBlobValue((ATLSOAP_BLOB *)pVal, wsz, cch, pMemMgr, true);
|
|
break;
|
|
case SOAPTYPE_BASE64BINARY:
|
|
hr = AtlGetSAXBlobValue((ATLSOAP_BLOB *)pVal, wsz, cch, pMemMgr, false);
|
|
break;
|
|
|
|
case SOAPTYPE_INTEGER:
|
|
case SOAPTYPE_NONPOSITIVEINTEGER:
|
|
case SOAPTYPE_NEGATIVEINTEGER:
|
|
case SOAPTYPE_LONG:
|
|
hr = AtlGetSAXValue((__int64 *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_INT:
|
|
hr = AtlGetSAXValue((int *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_SHORT:
|
|
hr = AtlGetSAXValue((short *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_BYTE:
|
|
hr = AtlGetSAXValue((char *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_POSITIVEINTEGER:
|
|
case SOAPTYPE_NONNEGATIVEINTEGER:
|
|
case SOAPTYPE_UNSIGNEDLONG:
|
|
hr = AtlGetSAXValue((unsigned __int64 *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDINT:
|
|
hr = AtlGetSAXValue((unsigned int *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDSHORT:
|
|
hr = AtlGetSAXValue((unsigned short *)pVal, wsz, cch);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDBYTE:
|
|
hr = AtlGetSAXValue((unsigned char *)pVal, wsz, cch);
|
|
break;
|
|
default:
|
|
if ((type != SOAPTYPE_ERR) && (type != SOAPTYPE_UNK) && (type != SOAPTYPE_USERBASE))
|
|
{
|
|
hr = AtlGetSAXValue((BSTR *)pVal, wsz, cch);
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: AtlSoapGetElementValue -- internal error.\r\n") );
|
|
|
|
// should never get here
|
|
ATLASSERT( FALSE );
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
inline HRESULT AtlSoapGenElementValue(void *pVal, IWriteStream *pStream, SOAPTYPES type, IAtlMemMgr *pMemMgr)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
switch (type)
|
|
{
|
|
case SOAPTYPE_BOOLEAN:
|
|
hr = AtlGenXMLValue(pStream, (bool *)pVal);
|
|
break;
|
|
case SOAPTYPE_FLOAT:
|
|
hr = AtlGenXMLValue(pStream, (float *)pVal);
|
|
break;
|
|
case SOAPTYPE_DOUBLE:
|
|
case SOAPTYPE_DECIMAL:
|
|
hr = AtlGenXMLValue(pStream, (double *)pVal);
|
|
break;
|
|
case SOAPTYPE_HEXBINARY:
|
|
hr = AtlGenXMLBlobValue(pStream, (ATLSOAP_BLOB *)pVal, pMemMgr, true);
|
|
break;
|
|
case SOAPTYPE_BASE64BINARY:
|
|
hr = AtlGenXMLBlobValue(pStream, (ATLSOAP_BLOB *)pVal, pMemMgr, false);
|
|
break;
|
|
|
|
case SOAPTYPE_INTEGER:
|
|
case SOAPTYPE_NONPOSITIVEINTEGER:
|
|
case SOAPTYPE_NEGATIVEINTEGER:
|
|
case SOAPTYPE_LONG:
|
|
hr = AtlGenXMLValue(pStream, (__int64 *)pVal);
|
|
break;
|
|
case SOAPTYPE_INT:
|
|
hr = AtlGenXMLValue(pStream, (int *)pVal);
|
|
break;
|
|
case SOAPTYPE_SHORT:
|
|
hr = AtlGenXMLValue(pStream, (short *)pVal);
|
|
break;
|
|
case SOAPTYPE_BYTE:
|
|
hr = AtlGenXMLValue(pStream, (char *)pVal);
|
|
break;
|
|
case SOAPTYPE_POSITIVEINTEGER:
|
|
case SOAPTYPE_NONNEGATIVEINTEGER:
|
|
case SOAPTYPE_UNSIGNEDLONG:
|
|
hr = AtlGenXMLValue(pStream, (unsigned __int64 *)pVal);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDINT:
|
|
hr = AtlGenXMLValue(pStream, (unsigned int *)pVal);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDSHORT:
|
|
hr = AtlGenXMLValue(pStream, (unsigned short *)pVal);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDBYTE:
|
|
hr = AtlGenXMLValue(pStream, (unsigned char *)pVal);
|
|
break;
|
|
default:
|
|
if ((type != SOAPTYPE_ERR) && (type != SOAPTYPE_UNK) && (type != SOAPTYPE_USERBASE))
|
|
{
|
|
hr = AtlGenXMLValue(pStream, (BSTR *)pVal);
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: AtlSoapGenElementValue -- internal error.\r\n" ) );
|
|
|
|
// should never get here
|
|
ATLASSERT( FALSE );
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
inline HRESULT AtlSoapCleanupElement(void *pVal, SOAPTYPES type, IAtlMemMgr *pMemMgr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (type)
|
|
{
|
|
case SOAPTYPE_BOOLEAN:
|
|
case SOAPTYPE_FLOAT:
|
|
case SOAPTYPE_DOUBLE:
|
|
case SOAPTYPE_DECIMAL:
|
|
case SOAPTYPE_INT:
|
|
case SOAPTYPE_INTEGER:
|
|
case SOAPTYPE_NONPOSITIVEINTEGER:
|
|
case SOAPTYPE_NEGATIVEINTEGER:
|
|
case SOAPTYPE_LONG:
|
|
case SOAPTYPE_SHORT:
|
|
case SOAPTYPE_BYTE:
|
|
case SOAPTYPE_POSITIVEINTEGER:
|
|
case SOAPTYPE_NONNEGATIVEINTEGER:
|
|
case SOAPTYPE_UNSIGNEDLONG:
|
|
case SOAPTYPE_UNSIGNEDINT:
|
|
case SOAPTYPE_UNSIGNEDSHORT:
|
|
case SOAPTYPE_UNSIGNEDBYTE:
|
|
break;
|
|
|
|
case SOAPTYPE_HEXBINARY:
|
|
case SOAPTYPE_BASE64BINARY:
|
|
hr = AtlCleanupBlobValue((ATLSOAP_BLOB *)pVal, pMemMgr);
|
|
break;
|
|
|
|
default:
|
|
if ((type != SOAPTYPE_ERR) && (type != SOAPTYPE_UNK) && (type != SOAPTYPE_USERBASE))
|
|
{
|
|
// treat as string
|
|
hr = AtlCleanupValue((BSTR *)pVal);
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: AtlSoapCleanupElement -- internal error.\r\n" ) );
|
|
|
|
// should never get here
|
|
ATLASSERT( FALSE );
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// END PRIVATE DEFINITIONS
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define SOAP_ENVELOPEA "Envelope"
|
|
#define SOAP_ENVELOPEW ATLSOAP_MAKEWIDESTR( SOAP_ENVELOPEA )
|
|
|
|
#define SOAP_HEADERA "Header"
|
|
#define SOAP_HEADERW ATLSOAP_MAKEWIDESTR( SOAP_HEADERA )
|
|
|
|
#define SOAP_BODYA "Body"
|
|
#define SOAP_BODYW ATLSOAP_MAKEWIDESTR( SOAP_BODYA )
|
|
|
|
|
|
#pragma pack(push,_ATL_PACKING)
|
|
namespace ATL
|
|
{
|
|
|
|
//
|
|
// SOAP fault helpers
|
|
//
|
|
|
|
enum SOAP_ERROR_CODE
|
|
{
|
|
SOAP_E_UNK=0,
|
|
SOAP_E_VERSION_MISMATCH=100,
|
|
SOAP_E_MUST_UNDERSTAND=200,
|
|
SOAP_E_CLIENT=300,
|
|
SOAP_E_SERVER=400
|
|
};
|
|
|
|
// forward declaration of CSoapFault
|
|
class CSoapFault;
|
|
|
|
class CSoapFaultParser : public ISAXContentHandlerImpl
|
|
{
|
|
private:
|
|
|
|
CSoapFault *m_pFault;
|
|
|
|
DWORD m_dwState;
|
|
|
|
const static DWORD STATE_ERROR = 0;
|
|
const static DWORD STATE_ENVELOPE = 1;
|
|
const static DWORD STATE_BODY = 2;
|
|
const static DWORD STATE_START = 4;
|
|
const static DWORD STATE_FAULTCODE = 8;
|
|
const static DWORD STATE_FAULTSTRING = 16;
|
|
const static DWORD STATE_FAULTACTOR = 32;
|
|
const static DWORD STATE_DETAIL = 64;
|
|
const static DWORD STATE_RESET = 128;
|
|
const static DWORD STATE_SKIP = 256;
|
|
|
|
|
|
CComPtr<ISAXXMLReader> m_spReader;
|
|
CSAXStringBuilder m_stringBuilder;
|
|
CSkipHandler m_skipHandler;
|
|
|
|
const wchar_t *m_wszSoapPrefix;
|
|
int m_cchSoapPrefix;
|
|
|
|
public:
|
|
virtual ~CSoapFaultParser()
|
|
{
|
|
m_skipHandler.DetachParent();
|
|
}
|
|
|
|
// IUnknown interface
|
|
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
|
|
if (InlineIsEqualGUID(riid, IID_IUnknown) ||
|
|
InlineIsEqualGUID(riid, IID_ISAXContentHandler))
|
|
{
|
|
*ppv = static_cast<ISAXContentHandler *>(this);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// constructor
|
|
|
|
CSoapFaultParser(CSoapFault *pFault, ISAXXMLReader *pReader)
|
|
:m_pFault(pFault), m_dwState(STATE_ERROR), m_spReader(pReader)
|
|
{
|
|
ATLASSERT( pFault != NULL );
|
|
ATLASSERT( pReader != NULL );
|
|
}
|
|
|
|
// ISAXContentHandler interface
|
|
HRESULT __stdcall startElement(
|
|
const wchar_t * wszNamespaceUri,
|
|
int cchNamespaceUri,
|
|
const wchar_t * wszLocalName,
|
|
int cchLocalName,
|
|
const wchar_t * /*wszQName*/,
|
|
int /*cchQName*/,
|
|
ISAXAttributes * /*pAttributes*/)
|
|
{
|
|
struct _faultmap
|
|
{
|
|
const wchar_t *wszTag;
|
|
int cchTag;
|
|
DWORD dwState;
|
|
};
|
|
|
|
const static _faultmap s_faultParseMap[] =
|
|
{
|
|
{ L"Envelope", sizeof("Envelope")-1, CSoapFaultParser::STATE_ENVELOPE },
|
|
{ L"Body", sizeof("Body")-1, CSoapFaultParser::STATE_BODY },
|
|
{ L"Header", sizeof("Header")-1, CSoapFaultParser::STATE_BODY },
|
|
{ L"Fault", sizeof("Fault")-1, CSoapFaultParser::STATE_START },
|
|
{ L"faultcode", sizeof("faultcode")-1, CSoapFaultParser::STATE_FAULTCODE },
|
|
{ L"faultstring", sizeof("faultstring")-1, CSoapFaultParser::STATE_FAULTSTRING },
|
|
{ L"faultactor", sizeof("faultactor")-1, CSoapFaultParser::STATE_FAULTACTOR },
|
|
{ L"detail", sizeof("detail")-1, CSoapFaultParser::STATE_DETAIL }
|
|
};
|
|
|
|
if (m_spReader.p == NULL)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapFaultParser::startElement -- ISAXXMLReader is NULL.\r\n" ) );
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
m_dwState &= ~STATE_RESET;
|
|
for (int i=0; i<(sizeof(s_faultParseMap)/sizeof(s_faultParseMap[0])); i++)
|
|
{
|
|
if ((cchLocalName == s_faultParseMap[i].cchTag) &&
|
|
(!wcsncmp(wszLocalName, s_faultParseMap[i].wszTag, cchLocalName)))
|
|
{
|
|
DWORD dwState = s_faultParseMap[i].dwState;
|
|
if ((dwState & (STATE_START | STATE_ENVELOPE | STATE_BODY)) == 0)
|
|
{
|
|
m_stringBuilder.SetReader(m_spReader);
|
|
m_stringBuilder.SetParent(this);
|
|
|
|
m_stringBuilder.Clear();
|
|
m_spReader->putContentHandler( &m_stringBuilder );
|
|
}
|
|
else
|
|
{
|
|
if ((dwState <= m_dwState) ||
|
|
(cchNamespaceUri != sizeof(SOAPENV_NAMESPACEA)-1) ||
|
|
(wcsncmp(wszNamespaceUri, SOAPENV_NAMESPACEW, cchNamespaceUri)))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapFaultParser::startElement -- malformed SOAP fault.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
m_dwState = dwState;
|
|
return S_OK;
|
|
}
|
|
}
|
|
if (m_dwState > STATE_START)
|
|
{
|
|
m_dwState = STATE_SKIP;
|
|
m_skipHandler.SetReader(m_spReader);
|
|
m_skipHandler.SetParent(this);
|
|
|
|
m_spReader->putContentHandler( &m_skipHandler );
|
|
return S_OK;
|
|
}
|
|
|
|
ATLTRACE( _T("ATLSOAP: CSoapFaultParser::startElement -- malformed SOAP fault.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT __stdcall startPrefixMapping(
|
|
const wchar_t * wszPrefix,
|
|
int cchPrefix,
|
|
const wchar_t * wszUri,
|
|
int cchUri)
|
|
{
|
|
if ((cchUri == sizeof(SOAPENV_NAMESPACEA)-1) &&
|
|
(!wcsncmp(wszUri, SOAPENV_NAMESPACEW, cchUri)))
|
|
{
|
|
m_wszSoapPrefix = wszPrefix;
|
|
m_cchSoapPrefix = cchPrefix;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall characters(
|
|
const wchar_t * wszChars,
|
|
int cchChars);
|
|
};
|
|
|
|
extern __declspec(selectany) const int ATLS_SOAPFAULT_CNT = 4;
|
|
|
|
class CSoapFault
|
|
{
|
|
private:
|
|
|
|
struct _faultcode
|
|
{
|
|
const wchar_t *wsz;
|
|
int cch;
|
|
const wchar_t *wszFaultString;
|
|
int cchFaultString;
|
|
SOAP_ERROR_CODE errCode;
|
|
};
|
|
|
|
static const _faultcode s_faultCodes[];
|
|
|
|
public:
|
|
|
|
// members
|
|
SOAP_ERROR_CODE m_soapErrCode;
|
|
CStringW m_strFaultCode;
|
|
CStringW m_strFaultString;
|
|
CStringW m_strFaultActor;
|
|
CStringW m_strDetail;
|
|
|
|
CSoapFault()
|
|
: m_soapErrCode(SOAP_E_UNK)
|
|
{
|
|
}
|
|
|
|
HRESULT SetErrorCode(
|
|
const wchar_t *wsz,
|
|
const wchar_t *wszSoapPrefix,
|
|
int cch = -1,
|
|
int cchSoapPrefix = -1,
|
|
bool bSetFaultString = true)
|
|
{
|
|
if ((wsz == NULL) || (wszSoapPrefix == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (cch == -1)
|
|
{
|
|
cch = (int) wcslen(wsz);
|
|
}
|
|
|
|
while (*wsz && iswspace(*wsz))
|
|
{
|
|
++wsz;
|
|
--cch;
|
|
}
|
|
|
|
if (cchSoapPrefix == -1)
|
|
{
|
|
cchSoapPrefix = (int) wcslen(wszSoapPrefix);
|
|
}
|
|
|
|
const wchar_t *wszLocalName = wcschr(wsz, L':');
|
|
if (wszLocalName == NULL)
|
|
{
|
|
// faultCode must be QName
|
|
|
|
ATLTRACE( _T("ATLSOAP: CSoapFault::SetErrorCode -- faultCode is not a QName.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
// make sure the namespace of the fault is the
|
|
// SOAPENV namespace
|
|
if ((cchSoapPrefix != (int)(wszLocalName-wsz)) ||
|
|
(wcsncmp(wsz, wszSoapPrefix, cchSoapPrefix)))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapFault::SetErrorCode -- fault namespace is incorrect.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
wszLocalName++;
|
|
cch -= (int) (wszLocalName-wsz);
|
|
|
|
_ATLTRY
|
|
{
|
|
for (int i=0; i<ATLS_SOAPFAULT_CNT; i++)
|
|
{
|
|
if ((cch == s_faultCodes[i].cch) &&
|
|
(!wcsncmp(wszLocalName, s_faultCodes[i].wsz, cch)))
|
|
{
|
|
m_soapErrCode = s_faultCodes[i].errCode;
|
|
if (bSetFaultString != false)
|
|
{
|
|
m_strFaultString.SetString(s_faultCodes[i].wszFaultString, s_faultCodes[i].cchFaultString);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (m_strFaultString.GetLength() == 0)
|
|
{
|
|
m_strFaultCode.SetString(wszLocalName, cch);
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapFault::SetErrorCode -- out of memory.\r\n" ) );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT ParseFault(IStream *pStream, ISAXXMLReader *pReader = NULL)
|
|
{
|
|
if (pStream == NULL)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapFault::ParseFault -- NULL IStream was passed.\r\n" ) );
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
CComPtr<ISAXXMLReader> spReader;
|
|
if (pReader != NULL)
|
|
{
|
|
spReader = pReader;
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(spReader.CoCreateInstance(ATLS_SAXXMLREADER_CLSID, NULL, CLSCTX_INPROC_SERVER)))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapFault::ParseFault -- CoCreateInstance of SAXXMLReader failed.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
Clear();
|
|
CSoapFaultParser parser(const_cast<CSoapFault *>(this), spReader);
|
|
spReader->putContentHandler(&parser);
|
|
|
|
CComVariant varStream;
|
|
varStream = static_cast<IUnknown*>(pStream);
|
|
|
|
HRESULT hr = spReader->parse(varStream);
|
|
spReader->putContentHandler(NULL);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GenerateFault(IWriteStream *pWriteStream)
|
|
{
|
|
if ((pWriteStream == NULL) || (m_soapErrCode == SOAP_E_UNK))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ATLASSERT( (m_soapErrCode == SOAP_E_UNK) ||
|
|
(m_soapErrCode == SOAP_E_VERSION_MISMATCH) ||
|
|
(m_soapErrCode == SOAP_E_MUST_UNDERSTAND) ||
|
|
(m_soapErrCode == SOAP_E_CLIENT) ||
|
|
(m_soapErrCode == SOAP_E_SERVER) );
|
|
|
|
HRESULT hr = S_OK;
|
|
_ATLTRY
|
|
{
|
|
const wchar_t *wszFaultCode = NULL;
|
|
if (m_strFaultCode.GetLength() == 0)
|
|
{
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
if (s_faultCodes[i].errCode == m_soapErrCode)
|
|
{
|
|
if (m_strFaultString.GetLength() == 0)
|
|
{
|
|
m_strFaultString.SetString(s_faultCodes[i].wszFaultString,
|
|
s_faultCodes[i].cchFaultString);
|
|
}
|
|
|
|
wszFaultCode = s_faultCodes[i].wsz;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wszFaultCode == NULL)
|
|
{
|
|
if (m_strFaultCode.GetLength() != 0)
|
|
{
|
|
wszFaultCode = m_strFaultCode;
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE( _T("CSoapFault::GenerateFault -- missing/invalid fault code.\r\n") );
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
const LPCSTR s_szErrorFormat =
|
|
"<SOAP:Envelope xmlns:SOAP=\"" SOAPENV_NAMESPACEA "\">"
|
|
"<SOAP:Body>"
|
|
"<SOAP:Fault>"
|
|
"<faultcode>SOAP:%ws</faultcode>"
|
|
"<faultstring>%ws</faultstring>"
|
|
"%s%ws%s"
|
|
"<detail>%ws</detail>"
|
|
"</SOAP:Fault>"
|
|
"</SOAP:Body>"
|
|
"</SOAP:Envelope>";
|
|
|
|
CStringA strFault;
|
|
strFault.Format(s_szErrorFormat, wszFaultCode, m_strFaultString,
|
|
m_strFaultActor.GetLength() ? "<faultactor>" : "", m_strFaultActor,
|
|
m_strFaultActor.GetLength() ? "</faultactor>" : "",
|
|
m_strDetail);
|
|
|
|
hr = pWriteStream->WriteStream(strFault, strFault.GetLength(), NULL);
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapFault::GenerateFault -- out of memory.\r\n" ) );
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
m_soapErrCode = SOAP_E_UNK;
|
|
m_strFaultCode.Empty();
|
|
m_strFaultString.Empty();
|
|
m_strFaultActor.Empty();
|
|
m_strDetail.Empty();
|
|
}
|
|
}; // class CSoapFault
|
|
|
|
#define DECLARE_SOAP_FAULT(__name, __faultstring, __errcode) \
|
|
{ L ## __name, sizeof(__name)-1, L ## __faultstring, sizeof(__faultstring), __errcode },
|
|
|
|
__declspec(selectany) const CSoapFault::_faultcode CSoapFault::s_faultCodes[] =
|
|
{
|
|
DECLARE_SOAP_FAULT("VersionMismatch", "SOAP Version Mismatch Error", SOAP_E_VERSION_MISMATCH)
|
|
DECLARE_SOAP_FAULT("MustUnderstand", "SOAP Must Understand Error", SOAP_E_MUST_UNDERSTAND)
|
|
DECLARE_SOAP_FAULT("Client", "SOAP Invalid Request", SOAP_E_CLIENT)
|
|
DECLARE_SOAP_FAULT("Server", "SOAP Server Application Faulted", SOAP_E_SERVER)
|
|
};
|
|
|
|
ATL_NOINLINE inline HRESULT __stdcall CSoapFaultParser::characters(
|
|
const wchar_t * wszChars,
|
|
int cchChars)
|
|
{
|
|
if (m_pFault == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (m_dwState & STATE_RESET)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT hr = E_FAIL;
|
|
_ATLTRY
|
|
{
|
|
switch (m_dwState)
|
|
{
|
|
case STATE_FAULTCODE:
|
|
if (m_pFault->m_soapErrCode == SOAP_E_UNK)
|
|
{
|
|
hr = m_pFault->SetErrorCode(wszChars, m_wszSoapPrefix,
|
|
cchChars, m_cchSoapPrefix, false);
|
|
}
|
|
break;
|
|
case STATE_FAULTSTRING:
|
|
if (m_pFault->m_strFaultString.GetLength() == 0)
|
|
{
|
|
m_pFault->m_strFaultString.SetString(wszChars, cchChars);
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
case STATE_FAULTACTOR:
|
|
if (m_pFault->m_strFaultActor.GetLength() == 0)
|
|
{
|
|
m_pFault->m_strFaultActor.SetString(wszChars, cchChars);
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
case STATE_DETAIL:
|
|
if (m_pFault->m_strDetail.GetLength() == 0)
|
|
{
|
|
m_pFault->m_strDetail.SetString(wszChars, cchChars);
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
case STATE_START: case STATE_ENVELOPE : case STATE_BODY : case STATE_SKIP:
|
|
hr = S_OK;
|
|
break;
|
|
default:
|
|
// should never get here
|
|
ATLASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapFaultParser::characters -- out of memory.\r\n" ) );
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
m_dwState |= STATE_RESET;
|
|
|
|
return hr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CSoapRootHandler - the class that does most of the work
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef ATLSOAP_STACKSIZE
|
|
// 16 will be plenty for the 99% case
|
|
#define ATLSOAP_STACKSIZE 16
|
|
#endif
|
|
|
|
#ifndef ATLSOAP_GROWARRAY
|
|
#define ATLSOAP_GROWARRAY 10
|
|
#endif
|
|
|
|
class CSoapRootHandler : public ISAXContentHandlerImpl
|
|
{
|
|
private:
|
|
|
|
friend class _CSDLGenerator;
|
|
|
|
//
|
|
// state constants
|
|
//
|
|
const static DWORD SOAP_START = 0;
|
|
const static DWORD SOAP_ENVELOPE = 1;
|
|
const static DWORD SOAP_HEADERS = 2;
|
|
const static DWORD SOAP_BODY = 3;
|
|
const static DWORD SOAP_PARAMS = 4;
|
|
const static DWORD SOAP_CALLED = 5;
|
|
const static DWORD SOAP_RESPONSE = 6;
|
|
const static DWORD SOAP_HEADERS_DONE = 7;
|
|
|
|
//
|
|
// hash values for SOAP namespaces and elements
|
|
//
|
|
const static ULONG SOAP_ENV = 0x5D3574E2;
|
|
const static ULONG SOAP_ENC = 0xBD62724B;
|
|
const static ULONG ENVELOPE = 0xDBE6009E;
|
|
const static ULONG HEADER = 0xAF4DFFC9;
|
|
const static ULONG BODY = 0x0026168E;
|
|
|
|
//
|
|
// XSD Names
|
|
//
|
|
struct XSDEntry
|
|
{
|
|
wchar_t * wszName;
|
|
char * szName;
|
|
int cchName;
|
|
};
|
|
|
|
const static XSDEntry s_xsdNames[];
|
|
|
|
//
|
|
// CBitVector - a dynamically sized bit vector class
|
|
//
|
|
class CBitVector
|
|
{
|
|
private:
|
|
|
|
// 64 bits will handle the 99% case
|
|
unsigned __int64 m_nBits;
|
|
|
|
// when we need to grow
|
|
unsigned __int64 * m_pBits;
|
|
|
|
size_t m_nSize;
|
|
|
|
bool Grow(size_t nIndex)
|
|
{
|
|
// Think carefully
|
|
// In our current implementation, CHAR_BIT==8, and sizeof(m_nBits)==8. Easy to confuse the two.
|
|
|
|
// We do math in bits, so this is our max size
|
|
ATLENSURE(nIndex<SIZE_MAX/((sizeof(m_nBits)*CHAR_BIT)));
|
|
|
|
// round up to nearest 64 bits
|
|
size_t nAllocSizeBits = nIndex+((sizeof(m_nBits)*CHAR_BIT)-(nIndex%(sizeof(m_nBits)*CHAR_BIT)));
|
|
size_t nAllocSizeBytes = nAllocSizeBits/CHAR_BIT;
|
|
|
|
if (m_pBits != &m_nBits)
|
|
{
|
|
unsigned __int64 * pNewBits=NULL;
|
|
pNewBits = (unsigned __int64 *) realloc(m_pBits, nAllocSizeBytes );
|
|
if(!pNewBits)
|
|
{
|
|
return false;
|
|
}
|
|
m_pBits=pNewBits;
|
|
}
|
|
else
|
|
{
|
|
m_pBits = (unsigned __int64 *) malloc(nAllocSizeBytes );
|
|
if (m_pBits != NULL)
|
|
{
|
|
Checked::memcpy_s(m_pBits, nAllocSizeBytes, &m_nBits, sizeof(m_nBits));
|
|
}
|
|
}
|
|
|
|
if (m_pBits != NULL)
|
|
{
|
|
// set new bits to 0
|
|
memset(m_pBits+(m_nSize/(CHAR_BIT*sizeof(m_nBits))), 0x00, (nAllocSizeBits-m_nSize)/CHAR_BIT);
|
|
m_nSize = nAllocSizeBits;
|
|
return true;
|
|
}
|
|
|
|
ATLTRACE( _T("ATLSOAP: CBitVector::Grow -- out of memory.\r\n" ) );
|
|
|
|
return false;
|
|
}
|
|
|
|
public:
|
|
|
|
CBitVector()
|
|
: m_nBits(0), m_nSize(sizeof(m_nBits)*CHAR_BIT)
|
|
{
|
|
m_pBits = &m_nBits;
|
|
}
|
|
|
|
CBitVector(const CBitVector&)
|
|
{
|
|
m_pBits = &m_nBits;
|
|
}
|
|
|
|
const CBitVector& operator=(const CBitVector& that)
|
|
{
|
|
if (this != &that)
|
|
{
|
|
m_pBits = &m_nBits;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool GetBit(size_t nIndex) const
|
|
{
|
|
if (nIndex >= m_nSize)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
size_t i = nIndex/(sizeof(m_nBits)*CHAR_BIT);
|
|
size_t nBits = nIndex-i*(sizeof(m_nBits)*CHAR_BIT);
|
|
return ((m_pBits[i] >> nBits) & 0x01);
|
|
}
|
|
|
|
bool SetBit(size_t nIndex)
|
|
{
|
|
if (nIndex >= m_nSize)
|
|
{
|
|
if (!Grow(nIndex))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
size_t i = nIndex/(sizeof(m_nBits)*CHAR_BIT);
|
|
size_t nBits = nIndex-i*(sizeof(m_nBits)*CHAR_BIT);
|
|
m_pBits[i] |= (((unsigned __int64) 1) << nBits);
|
|
|
|
return true;
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
if (m_pBits == &m_nBits)
|
|
{
|
|
m_nBits = 0;
|
|
}
|
|
else
|
|
{
|
|
memset(m_pBits, 0x00, (m_nSize/CHAR_BIT));
|
|
}
|
|
}
|
|
|
|
~CBitVector()
|
|
{
|
|
if (m_pBits != &m_nBits)
|
|
{
|
|
free(m_pBits);
|
|
}
|
|
|
|
m_pBits = &m_nBits;
|
|
m_nSize = sizeof(m_nBits)*CHAR_BIT;
|
|
}
|
|
|
|
void RelocateFixup()
|
|
{
|
|
if (m_nSize <= sizeof(m_nBits)*CHAR_BIT)
|
|
{
|
|
m_pBits = &m_nBits;
|
|
}
|
|
}
|
|
}; // class CBitVector
|
|
|
|
//
|
|
// Parsing State
|
|
//
|
|
struct ParseState
|
|
{
|
|
void *pvElement;
|
|
DWORD dwFlags;
|
|
size_t nAllocSize;
|
|
size_t nExpectedElements;
|
|
size_t nElement;
|
|
const _soapmap *pMap;
|
|
const _soapmapentry *pEntry;
|
|
|
|
// mark when we get an item
|
|
CBitVector vec;
|
|
|
|
size_t nDepth;
|
|
|
|
ParseState(void *pvElement_ = NULL, DWORD dwFlags_ = 0,
|
|
size_t nAllocSize_ = 0, size_t nExpectedElements_ = 0,
|
|
size_t nElement_ = 0, const _soapmap *pMap_ = NULL,
|
|
const _soapmapentry *pEntry_ = NULL)
|
|
: pvElement(pvElement_), dwFlags(dwFlags_), nAllocSize(nAllocSize_),
|
|
nExpectedElements(nExpectedElements_), nElement(nElement_), pMap(pMap_),
|
|
pEntry(pEntry_), nDepth(0)
|
|
{
|
|
vec.Clear();
|
|
}
|
|
|
|
ParseState(const ParseState& that)
|
|
{
|
|
pvElement = that.pvElement;
|
|
dwFlags = that.dwFlags;
|
|
nAllocSize = that.nAllocSize;
|
|
nExpectedElements = that.nExpectedElements;
|
|
nElement = that.nElement;
|
|
pMap = that.pMap;
|
|
pEntry = that.pEntry;
|
|
nDepth = that.nDepth;
|
|
vec.Clear();
|
|
}
|
|
|
|
~ParseState()
|
|
{
|
|
pvElement = NULL;
|
|
dwFlags = 0;
|
|
nAllocSize = 0;
|
|
nExpectedElements = 0;
|
|
nElement = 0;
|
|
pMap = NULL;
|
|
pEntry = NULL;
|
|
nDepth = 0;
|
|
vec.Clear();
|
|
}
|
|
|
|
void RelocateFixup()
|
|
{
|
|
vec.RelocateFixup();
|
|
}
|
|
}; // struct ParseState
|
|
|
|
class CParseStateElementTraits : public CDefaultElementTraits<ParseState>
|
|
{
|
|
public:
|
|
// CBitVector relocate fixup
|
|
static void RelocateElements( ParseState* pDest, ParseState* pSrc, size_t nElements )
|
|
{
|
|
CDefaultElementTraits<ParseState>::RelocateElements(pDest, pSrc, nElements);
|
|
|
|
// fixup CBitVector
|
|
for (size_t i=0; i<nElements; i++)
|
|
{
|
|
pDest[i].RelocateFixup();
|
|
}
|
|
}
|
|
};
|
|
|
|
class CResponseGenerator
|
|
{
|
|
public:
|
|
HRESULT StartEnvelope(IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
return pStream->WriteStream("<soap:Envelope "
|
|
"xmlns:soap=\"" SOAPENV_NAMESPACEA "\" "
|
|
"xmlns:xsi=\"" XSI_NAMESPACEA "\" "
|
|
"xmlns:xsd=\"" XSD_NAMESPACEA "\" "
|
|
"xmlns:soapenc=\"" SOAPENC_NAMESPACEA "\">",
|
|
|
|
sizeof("<soap:Envelope "
|
|
"xmlns:soap=\"" SOAPENV_NAMESPACEA "\" "
|
|
"xmlns:xsi=\"" XSI_NAMESPACEA "\" "
|
|
"xmlns:xsd=\"" XSD_NAMESPACEA "\" "
|
|
"xmlns:soapenc=\"" SOAPENC_NAMESPACEA "\">")-1,
|
|
|
|
NULL);
|
|
}
|
|
|
|
HRESULT StartHeaders(IWriteStream *pStream, const _soapmap *pMap)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
|
|
HRESULT hr = pStream->WriteStream("<soap:Header", sizeof("<soap:Header")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((pMap->dwCallFlags & (SOAPFLAG_RPC | SOAPFLAG_ENCODED)) !=
|
|
(SOAPFLAG_RPC | SOAPFLAG_ENCODED))
|
|
{
|
|
// qualify document/literal by default
|
|
// For this version, ATL Server will not respect
|
|
// the elementForm* attributes in an XSD schema
|
|
|
|
hr = pStream->WriteStream(" xmlns=\"", sizeof(" xmlns=\"")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(pMap->szNamespace, pMap->cchNamespace, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream("\">", sizeof("\">")-1, NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// rpc/encoded
|
|
hr = pStream->WriteStream(">", sizeof(">")-1, NULL);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT EndHeaders(IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
return pStream->WriteStream("</soap:Header>", sizeof("</soap:Header>")-1, NULL);
|
|
}
|
|
|
|
virtual HRESULT StartBody(IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
return pStream->WriteStream(
|
|
"<soap:Body>", sizeof("<soap:Body>")-1, NULL);
|
|
}
|
|
|
|
HRESULT EndBody(IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
return pStream->WriteStream("</soap:Body>", sizeof("</soap:Body>")-1, NULL);
|
|
}
|
|
|
|
HRESULT EndEnvelope(IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
return pStream->WriteStream("</soap:Envelope>", sizeof("</soap:Envelope>")-1, NULL);
|
|
}
|
|
|
|
virtual HRESULT StartMap(IWriteStream *pStream, const _soapmap *pMap, bool bClient) = 0;
|
|
virtual HRESULT EndMap(IWriteStream *pStream, const _soapmap *pMap, bool bClient) = 0;
|
|
|
|
virtual HRESULT StartEntry(IWriteStream *pStream, const _soapmap *pMap, const _soapmapentry *pEntry)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
|
|
// output name
|
|
HRESULT hr = pStream->WriteStream("<", 1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
const char *szHeaderNamespace = NULL;
|
|
int cchHeaderNamespace = 0;
|
|
|
|
if ((pMap != NULL) && (pMap->mapType == SOAPMAP_HEADER) &&
|
|
((pEntry->pChain != NULL) &&
|
|
(pEntry->pChain->szNamespace !=NULL)) ||
|
|
(pEntry->szNamespace != NULL))
|
|
{
|
|
hr = pStream->WriteStream("snp:", sizeof("snp:")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
szHeaderNamespace = pEntry->pChain ?
|
|
pEntry->pChain->szNamespace : pEntry->szNamespace;
|
|
|
|
cchHeaderNamespace = pEntry->pChain ?
|
|
pEntry->pChain->cchNamespace : pEntry->cchNamespace;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((pEntry->dwFlags & SOAPFLAG_RETVAL)==0)
|
|
{
|
|
hr = pStream->WriteStream(pEntry->szField, pEntry->cchField, NULL);
|
|
}
|
|
else
|
|
{
|
|
hr = pStream->WriteStream("return", sizeof("return")-1, NULL);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (szHeaderNamespace != NULL)
|
|
{
|
|
ATLASSERT( cchHeaderNamespace != 0 );
|
|
|
|
hr = pStream->WriteStream(" xmlns:snp=\"", sizeof(" xmlns:snp=\"")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(szHeaderNamespace, cchHeaderNamespace, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream("\"", sizeof("\"")-1, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (pEntry->dwFlags & SOAPFLAG_MUSTUNDERSTAND)
|
|
{
|
|
// output mustUnderstand
|
|
hr = pStream->WriteStream(" soap:mustUnderstand=\"1\"", sizeof(" soap:mustUnderstand=\"1\"")-1, NULL);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT EndEntry(IWriteStream *pStream, const _soapmap *pMap, const _soapmapentry *pEntry)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
|
|
HRESULT hr = pStream->WriteStream("</", 2, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((pMap != NULL) &&
|
|
(pMap->mapType == SOAPMAP_HEADER) &&
|
|
((pEntry->pChain != NULL) &&
|
|
(pEntry->pChain->szNamespace !=NULL)) ||
|
|
(pEntry->szNamespace != NULL))
|
|
{
|
|
hr = pStream->WriteStream("snp:", sizeof("snp:")-1, NULL);
|
|
}
|
|
if ((pEntry->dwFlags & SOAPFLAG_RETVAL)==0)
|
|
{
|
|
hr = pStream->WriteStream(pEntry->szField, pEntry->cchField, NULL);
|
|
}
|
|
else
|
|
{
|
|
hr = pStream->WriteStream("return", sizeof("return")-1, NULL);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(">", 1, NULL);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
}; // class CResponseGenerator
|
|
|
|
class CDocLiteralGenerator : public CResponseGenerator
|
|
{
|
|
public:
|
|
|
|
HRESULT StartMap(IWriteStream *pStream, const _soapmap *pMap, bool bClient)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
// output type name
|
|
hr = pStream->WriteStream("<", 1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(pMap->szName, pMap->cchName, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((pMap->mapType == SOAPMAP_FUNC) &&
|
|
(bClient == false) &&
|
|
(pMap->dwCallFlags & SOAPFLAG_PID))
|
|
{
|
|
hr = pStream->WriteStream("Response", sizeof("Response")-1, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if (pMap->mapType == SOAPMAP_FUNC)
|
|
{
|
|
hr = pStream->WriteStream(" xmlns=\"", sizeof(" xmlns=\"")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(pMap->szNamespace, pMap->cchNamespace, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream("\">", sizeof("\">")-1, NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = pStream->WriteStream(">", 1, NULL);
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT EndMap(IWriteStream *pStream, const _soapmap *pMap, bool bClient)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
|
|
HRESULT hr = pStream->WriteStream("</", sizeof("</")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(pMap->szName, pMap->cchName, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((pMap->mapType == SOAPMAP_FUNC) &&
|
|
(bClient == false) &&
|
|
(pMap->dwCallFlags & SOAPFLAG_PID))
|
|
{
|
|
hr = pStream->WriteStream("Response", sizeof("Response")-1, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
hr = pStream->WriteStream(">", 1, NULL);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
}; // class CDocLiteralGenerator
|
|
|
|
class CPIDGenerator : public CDocLiteralGenerator
|
|
{
|
|
};
|
|
|
|
class CPADGenerator : public CDocLiteralGenerator
|
|
{
|
|
public:
|
|
|
|
virtual HRESULT StartEntry(IWriteStream *pStream, const _soapmap *pMap, const _soapmapentry *pEntry)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
|
|
HRESULT hr = __super::StartEntry(pStream, pMap, pEntry);
|
|
if (SUCCEEDED(hr) && (pMap->dwCallFlags & SOAPFLAG_PAD))
|
|
{
|
|
hr = pStream->WriteStream(" xmlns=\"", sizeof(" xmlns=\"")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(pMap->szNamespace, pMap->cchNamespace, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream("\"", sizeof("\"")-1, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
}; // class CPADGenerator
|
|
|
|
class CRpcEncodedGenerator : public CResponseGenerator
|
|
{
|
|
public:
|
|
|
|
HRESULT StartBody(IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
return pStream->WriteStream(
|
|
"<soap:Body soap:encodingStyle=\"" SOAPENC_NAMESPACEA "\">",
|
|
sizeof("<soap:Body soap:encodingStyle=\"" SOAPENC_NAMESPACEA "\">")-1, NULL);
|
|
}
|
|
|
|
HRESULT StartMap(IWriteStream *pStream, const _soapmap *pMap, bool bClient)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
|
|
(bClient); // unused for rpc/encoded
|
|
|
|
HRESULT hr = pStream->WriteStream("<snp:", sizeof("<snp:")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(pMap->szName, pMap->cchName, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (pMap->mapType == SOAPMAP_FUNC)
|
|
{
|
|
hr = pStream->WriteStream(" xmlns:snp=\"", sizeof(" xmlns:snp=\"")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ATLASSERT( pMap->szNamespace != NULL );
|
|
hr = pStream->WriteStream(pMap->szNamespace, pMap->cchNamespace, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream("\">", sizeof("\">")-1, NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = pStream->WriteStream(">", 1, NULL);
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT EndMap(IWriteStream *pStream, const _soapmap *pMap, bool bClient)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
|
|
(bClient); // unused for rpc/encoded
|
|
|
|
HRESULT hr = pStream->WriteStream("</snp:", sizeof("</snp:")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(pMap->szName, pMap->cchName, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(">", 1, NULL);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
}; // class CRpcEncodedGenerator
|
|
|
|
//
|
|
// members
|
|
//
|
|
CAtlArray<ParseState, CParseStateElementTraits> m_stateStack;
|
|
size_t m_nState;
|
|
|
|
DWORD m_dwState;
|
|
|
|
CComPtr<ISAXXMLReader> m_spReader;
|
|
|
|
CSAXStringBuilder m_stringBuilder;
|
|
CSkipHandler m_skipHandler;
|
|
|
|
IAtlMemMgr * m_pMemMgr;
|
|
|
|
static CCRTHeap m_crtHeap;
|
|
|
|
bool m_bClient;
|
|
|
|
void *m_pvParam;
|
|
|
|
bool m_bNullCheck;
|
|
bool m_bChildCheck;
|
|
bool m_bCharacters;
|
|
size_t m_nDepth;
|
|
|
|
typedef CFixedStringT<CStringW, 16> REFSTRING;
|
|
|
|
// used for rpc/encoded messages with href's
|
|
typedef CAtlMap<REFSTRING, ParseState, CStringRefElementTraits<REFSTRING> > REFMAP;
|
|
REFMAP m_refMap;
|
|
|
|
//
|
|
// Implementation helpers
|
|
//
|
|
|
|
HRESULT PushState(void *pvElement = NULL, const _soapmap *pMap = NULL,
|
|
const _soapmapentry *pEntry = NULL, DWORD dwFlags = 0, size_t nAllocSize = 0,
|
|
size_t nExpectedElements = 0, size_t nElement = 0)
|
|
{
|
|
if (m_stateStack.IsEmpty())
|
|
{
|
|
// 16 will be plenty for the 99% case
|
|
if (!m_stateStack.SetCount(0, 16))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::PushState -- out of memory.\r\n" ) );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
size_t nCnt = m_stateStack.GetCount();
|
|
m_nState = m_stateStack.Add();
|
|
if (m_stateStack.GetCount() <= nCnt)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::PushState -- out of memory.\r\n" ) );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
ParseState &state = m_stateStack[m_nState];
|
|
|
|
state.pvElement = pvElement;
|
|
state.dwFlags = dwFlags;
|
|
state.nAllocSize = nAllocSize;
|
|
state.nExpectedElements = nExpectedElements;
|
|
state.nElement = nElement;
|
|
state.pMap = pMap;
|
|
state.pEntry = pEntry;
|
|
state.nDepth = m_nDepth;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
ParseState& GetState()
|
|
{
|
|
return m_stateStack[m_nState];
|
|
}
|
|
|
|
void PopState(bool bForce = false)
|
|
{
|
|
if ((m_nState != 0) || (bForce != false))
|
|
{
|
|
m_stateStack.RemoveAt(m_nState);
|
|
--m_nState;
|
|
}
|
|
}
|
|
|
|
BOOL IsEqualElement(int cchLocalNameCheck, const wchar_t *wszLocalNameCheck,
|
|
int cchNamespaceUriCheck, const wchar_t *wszNamespaceUriCheck,
|
|
int cchLocalName, const wchar_t *wszLocalName,
|
|
int cchNamespaceUri, const wchar_t *wszNamespaceUri)
|
|
{
|
|
ATLENSURE(wszLocalName);
|
|
ATLENSURE(wszLocalNameCheck);
|
|
ATLENSURE(wszNamespaceUri);
|
|
ATLENSURE(wszNamespaceUriCheck);
|
|
|
|
if (cchLocalName == cchLocalNameCheck &&
|
|
cchNamespaceUri == cchNamespaceUriCheck &&
|
|
!wcsncmp(wszLocalName, wszLocalNameCheck, cchLocalName) &&
|
|
!wcsncmp(wszNamespaceUri, wszNamespaceUriCheck, cchNamespaceUri))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
ATL_FORCEINLINE BOOL IsEqualString(const wchar_t *wszStr1, int cchStr1, const wchar_t *wszStr2, int cchStr2)
|
|
{
|
|
ATLENSURE( wszStr1 != NULL );
|
|
ATLENSURE( wszStr2 != NULL );
|
|
ATLENSURE( cchStr1 >= 0 );
|
|
ATLENSURE( cchStr2 >= 0 );
|
|
|
|
if (cchStr1 == cchStr2)
|
|
{
|
|
return !wcsncmp(wszStr1, wszStr2, cchStr2);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
ATL_FORCEINLINE BOOL IsEqualStringHash(const wchar_t *wszStr1, int cchStr1, ULONG nHash1,
|
|
const wchar_t *wszStr2, int cchStr2, ULONG nHash2)
|
|
{
|
|
ATLENSURE( wszStr1 != NULL );
|
|
ATLENSURE( wszStr2 != NULL );
|
|
ATLENSURE( cchStr1 >= 0 );
|
|
ATLENSURE( cchStr2 >= 0 );
|
|
|
|
if (nHash1 == nHash2)
|
|
{
|
|
return IsEqualString(wszStr1, cchStr1, wszStr2, cchStr2);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL IsEqualElement(int cchLocalNameCheck, const wchar_t *wszLocalNameCheck,
|
|
int cchLocalName, const wchar_t *wszLocalName)
|
|
{
|
|
if (cchLocalName == cchLocalNameCheck &&
|
|
!wcsncmp(wszLocalName, wszLocalNameCheck, cchLocalName))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void SetOffsetValue(void *pBase, void *pSrc, size_t nOffset)
|
|
{
|
|
void **ppDest = (void **)(((unsigned char *)pBase)+nOffset);
|
|
*ppDest = pSrc;
|
|
}
|
|
|
|
bool IsRpcEncoded()
|
|
{
|
|
if ((m_stateStack[0].pMap->dwCallFlags & (SOAPFLAG_RPC | SOAPFLAG_ENCODED)) ==
|
|
(SOAPFLAG_RPC | SOAPFLAG_ENCODED))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
HRESULT ValidateArrayEntry(
|
|
ParseState& state,
|
|
const wchar_t *wszLocalName,
|
|
int cchLocalName)
|
|
{
|
|
(cchLocalName);
|
|
(wszLocalName);
|
|
|
|
ATLASSERT( state.pEntry != NULL );
|
|
|
|
// SOAP Section 5.4.2
|
|
|
|
// check number of elements
|
|
if (state.nElement == state.nExpectedElements)
|
|
{
|
|
// too many elements
|
|
if ((state.dwFlags & SOAPFLAG_UNKSIZE)==0)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::ValidateArrayEntry -- too many elements.\r\n" ) );
|
|
return E_FAIL;
|
|
}
|
|
|
|
ATLASSERT( IsRpcEncoded() == false );
|
|
|
|
// see if we need to allocate more
|
|
if (state.nElement == state.nAllocSize)
|
|
{
|
|
unsigned char **ppArr = (unsigned char **)state.pvElement;
|
|
size_t nNewElement=0;
|
|
HRESULT hr=E_FAIL;
|
|
if(FAILED(hr=::ATL::AtlMultiply(&nNewElement, state.nElement, static_cast<size_t>(2))))
|
|
{
|
|
return hr;
|
|
}
|
|
hr = AllocateArray(state.pEntry, (void **)ppArr, __max(nNewElement, ATLSOAP_GROWARRAY), state.nElement);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
state.nAllocSize = __max((state.nElement)*2, ATLSOAP_GROWARRAY);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CheckID(
|
|
const wchar_t *wszNamespaceUri,
|
|
const wchar_t *wszLocalName,
|
|
int cchLocalName,
|
|
ISAXAttributes *pAttributes)
|
|
{
|
|
(cchLocalName);
|
|
(wszLocalName);
|
|
(wszNamespaceUri);
|
|
ATLASSERT( pAttributes != NULL );
|
|
|
|
const wchar_t *wsz = NULL;
|
|
int cch = 0;
|
|
|
|
HRESULT hr = GetAttribute(pAttributes, L"id", sizeof("id")-1, &wsz, &cch);
|
|
if ((hr == S_OK) && (wsz != NULL))
|
|
{
|
|
const REFMAP::CPair *p = NULL;
|
|
_ATLTRY
|
|
{
|
|
REFSTRING strRef(wsz, cch);
|
|
p = m_refMap.Lookup(strRef);
|
|
if (p == NULL)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::CheckID -- out of memory.\r\n" ) );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
ATLASSERT( IsRpcEncoded() == true );
|
|
|
|
const ParseState& state = p->m_value;
|
|
|
|
// disallow href-chaining
|
|
hr = CheckHref(state.pEntry, state.pvElement, pAttributes);
|
|
if (hr != S_FALSE)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
// do array stuff
|
|
if (state.dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR))
|
|
{
|
|
hr = GetSection5Info(state, state.pEntry, pAttributes);
|
|
}
|
|
else
|
|
{
|
|
// only structs and arrays are allowed for hrefs
|
|
ATLASSERT( state.pEntry->pChain != NULL );
|
|
ATLASSERT( state.pEntry->pChain->mapType == SOAPMAP_STRUCT );
|
|
|
|
// structs must have child entries
|
|
m_bChildCheck = state.pEntry->pChain->nElements != 0;
|
|
|
|
if (S_OK != PushState(state.pvElement, state.pEntry->pChain, state.pEntry,
|
|
state.dwFlags, 0, state.pEntry->pChain->nElements))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::CheckID -- out of memory.\n" ) );
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
m_refMap.DisableAutoRehash();
|
|
m_refMap.RemoveAtPos(const_cast<REFMAP::CPair*>(p));
|
|
m_refMap.EnableAutoRehash();
|
|
|
|
return hr;
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT GetElementEntry(
|
|
ParseState& state,
|
|
const wchar_t *wszNamespaceUri,
|
|
const wchar_t *wszLocalName,
|
|
int cchLocalName,
|
|
ISAXAttributes *pAttributes,
|
|
const _soapmapentry **ppEntry)
|
|
{
|
|
ATLENSURE_RETURN( state.pMap != NULL );
|
|
ATLENSURE_RETURN( ppEntry != NULL );
|
|
|
|
*ppEntry = NULL;
|
|
const _soapmapentry *pEntries = state.pMap->pEntries;
|
|
DWORD dwIncludeFlags;
|
|
DWORD dwExcludeFlags;
|
|
|
|
HRESULT hr = CheckID(wszNamespaceUri, wszLocalName, cchLocalName, pAttributes);
|
|
if (hr != S_FALSE)
|
|
{
|
|
if (hr == S_OK)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
if (m_bClient != false)
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_OUT;
|
|
dwExcludeFlags = SOAPFLAG_IN;
|
|
}
|
|
else
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_IN;
|
|
dwExcludeFlags = SOAPFLAG_OUT;
|
|
}
|
|
|
|
ULONG nHash = AtlSoapHashStr(wszLocalName, cchLocalName);
|
|
|
|
for (size_t i=0; pEntries[i].nHash != 0; i++)
|
|
{
|
|
if (nHash == pEntries[i].nHash &&
|
|
((pEntries[i].dwFlags & dwIncludeFlags) ||
|
|
((pEntries[i].dwFlags & dwExcludeFlags) == 0)) &&
|
|
IsEqualElement(pEntries[i].cchField, pEntries[i].wszField,
|
|
cchLocalName, wszLocalName)/* &&
|
|
!wcscmp(wszNamespaceUri, wszNamespace)*/)
|
|
{
|
|
// check bit vector
|
|
|
|
if (state.vec.GetBit(i) == false)
|
|
{
|
|
if (state.vec.SetBit(i) == false)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// already received this element
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::GetElementEntry -- duplicate element was sent.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
state.nElement++;
|
|
*ppEntry = &pEntries[i];
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::GetElementEntry -- element not found: %.*ws.\r\n" ), cchLocalName, wszLocalName );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CheckMustUnderstandHeader(ISAXAttributes *pAttributes)
|
|
{
|
|
ATLASSERT( pAttributes != NULL );
|
|
|
|
const wchar_t* wszMustUnderstand;
|
|
int cchMustUnderstand;
|
|
bool bMustUnderstand= false;
|
|
|
|
if (SUCCEEDED(GetAttribute(pAttributes, L"mustUnderstand", sizeof("mustUnderstand")-1,
|
|
&wszMustUnderstand, &cchMustUnderstand,
|
|
SOAPENV_NAMESPACEW, sizeof(SOAPENV_NAMESPACEA)-1)) &&
|
|
(wszMustUnderstand != NULL))
|
|
{
|
|
if (FAILED(AtlGetSAXValue(&bMustUnderstand, wszMustUnderstand, cchMustUnderstand)))
|
|
{
|
|
bMustUnderstand = true;
|
|
}
|
|
}
|
|
|
|
if (bMustUnderstand == false)
|
|
{
|
|
ATLASSERT( GetReader() != NULL );
|
|
|
|
m_skipHandler.SetReader(GetReader());
|
|
m_skipHandler.SetParent(this);
|
|
|
|
return GetReader()->putContentHandler( &m_skipHandler );
|
|
}
|
|
else
|
|
{
|
|
SoapFault(SOAP_E_MUST_UNDERSTAND, NULL, 0);
|
|
}
|
|
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::CheckMustUnderstandHeader -- unknown \"mustUnderstand\" SOAP Header was received.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT AllocateArray(
|
|
const _soapmapentry *pEntry,
|
|
void **ppArr, size_t nElements,
|
|
size_t nCurrElements = 0)
|
|
{
|
|
ATLENSURE_RETURN( ppArr != NULL );
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
|
|
size_t nElementSize;
|
|
if (pEntry->nVal != SOAPTYPE_UNK)
|
|
{
|
|
nElementSize = AtlSoapGetElementSize((SOAPTYPES) pEntry->nVal);
|
|
}
|
|
else // UDT
|
|
{
|
|
ATLENSURE_RETURN( pEntry->pChain != NULL );
|
|
nElementSize = pEntry->pChain->nElementSize;
|
|
}
|
|
if (nElementSize != 0)
|
|
{
|
|
if (*ppArr == NULL)
|
|
{
|
|
ATLASSERT( nCurrElements == 0 );
|
|
size_t nBytes=0;
|
|
HRESULT hr=S_OK;
|
|
if( FAILED(hr=::ATL::AtlMultiply(&nBytes, nElementSize, nElements)))
|
|
{
|
|
return hr;
|
|
}
|
|
*ppArr = m_pMemMgr->Allocate(nBytes);
|
|
}
|
|
else // *ppArr != NULL
|
|
{
|
|
ATLASSERT( nCurrElements != 0 );
|
|
size_t nBytes=0;
|
|
HRESULT hr=S_OK;
|
|
if( FAILED(hr=::ATL::AtlAdd(&nBytes, nElements, nCurrElements)) ||
|
|
FAILED(hr=::ATL::AtlMultiply(&nBytes, nElementSize, nBytes)))
|
|
{
|
|
return hr;
|
|
}
|
|
*ppArr = m_pMemMgr->Reallocate(*ppArr, nBytes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// internal error
|
|
ATLASSERT( FALSE );
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (*ppArr == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
memset(((unsigned char *)(*ppArr))+(nCurrElements*nElementSize), 0x00, nElements*nElementSize);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT GetSection5Info(
|
|
const ParseState& state,
|
|
const _soapmapentry *pEntry,
|
|
ISAXAttributes *pAttributes)
|
|
{
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
ATLENSURE_RETURN( pAttributes != NULL );
|
|
|
|
HRESULT hr;
|
|
if (IsRpcEncoded() != false)
|
|
{
|
|
// check for href
|
|
// we ONLY do this for rpc/encoded (required for interop)
|
|
// NOTE: ATL Server does not support object graphs, so
|
|
// only single-reference elements are allowed
|
|
hr = CheckHref(pEntry, state.pvElement, pAttributes,
|
|
pEntry->dwFlags, SOAPFLAG_READYSTATE);
|
|
if (hr != S_FALSE)
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
size_t nElements;
|
|
DWORD dwFlags = 0;
|
|
hr = AtlSoapGetArraySize(pAttributes, &nElements);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
size_t nAllocSize = 0;
|
|
size_t nElementsPush = 0;
|
|
|
|
if (pEntry->dwFlags & SOAPFLAG_DYNARR)
|
|
{
|
|
// set size_is value
|
|
ATLENSURE_RETURN( state.pMap != NULL );
|
|
int *pnSizeIs = (int *)(((unsigned char *)state.pvElement)+
|
|
(state.pMap->pEntries[pEntry->nSizeIs].nOffset));
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
if (IsRpcEncoded())
|
|
{
|
|
// rpc/encoded requires soapenc:arrayType attribute
|
|
return E_FAIL;
|
|
}
|
|
|
|
nElements = ATLSOAP_GROWARRAY;
|
|
nAllocSize = ATLSOAP_GROWARRAY;
|
|
dwFlags |= SOAPFLAG_UNKSIZE;
|
|
*pnSizeIs = 0;
|
|
}
|
|
else
|
|
{
|
|
*pnSizeIs = (int)nElements;
|
|
if (nElements == 0)
|
|
{
|
|
// soapenc:arrayType="type[0]"
|
|
// treat as null array
|
|
|
|
m_bNullCheck = true;
|
|
|
|
// push an emtpy state
|
|
return PushState();
|
|
}
|
|
|
|
nElementsPush = nElements;
|
|
}
|
|
void *p = NULL;
|
|
hr = AllocateArray(pEntry, &p, nElements);
|
|
if (hr != S_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
SetOffsetValue(state.pvElement, p, pEntry->nOffset);
|
|
}
|
|
else
|
|
{
|
|
// for fixed-size arrays, we know the number of elements
|
|
ATLASSERT( pEntry->dwFlags & SOAPFLAG_FIXEDARR );
|
|
if (hr == S_OK)
|
|
{
|
|
if (nElements != AtlSoapGetArrayDims(pEntry->pDims))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
nElements = AtlSoapGetArrayDims(pEntry->pDims);
|
|
}
|
|
nElementsPush = nElements;
|
|
}
|
|
|
|
dwFlags |= pEntry->dwFlags;
|
|
|
|
// push element with array flag
|
|
|
|
if (S_OK != PushState(((unsigned char *)state.pvElement)+pEntry->nOffset,
|
|
state.pMap, pEntry, dwFlags & ~SOAPFLAG_READYSTATE, nAllocSize, nElementsPush))
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
m_bChildCheck = true;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void * UpdateArray(ParseState& state, const _soapmapentry *pEntry)
|
|
{
|
|
ATLENSURE(pEntry);
|
|
|
|
size_t nSize;
|
|
void *pVal = NULL;
|
|
|
|
if (pEntry->nVal != SOAPTYPE_UNK)
|
|
{
|
|
nSize = AtlSoapGetElementSize((SOAPTYPES) pEntry->nVal);
|
|
}
|
|
else
|
|
{
|
|
ATLENSURE( pEntry->pChain != NULL );
|
|
|
|
nSize = pEntry->pChain->nElementSize;
|
|
}
|
|
|
|
if (state.dwFlags & SOAPFLAG_FIXEDARR)
|
|
{
|
|
unsigned char *ppArr = (unsigned char *)state.pvElement;
|
|
pVal = ppArr+(state.nElement*nSize);
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( state.dwFlags & SOAPFLAG_DYNARR );
|
|
|
|
unsigned char **ppArr = (unsigned char **)state.pvElement;
|
|
pVal = (*ppArr)+(state.nElement*nSize);
|
|
if (state.dwFlags & SOAPFLAG_UNKSIZE)
|
|
{
|
|
ATLASSERT( IsRpcEncoded() == false );
|
|
|
|
// need to use the previous state's pvElement to update the size_is value
|
|
ATLASSUME( m_nState > 0 );
|
|
int *pnSizeIs = (int *)(((unsigned char *)m_stateStack[m_nState-1].pvElement)+
|
|
(state.pMap->pEntries[pEntry->nSizeIs].nOffset));
|
|
|
|
// update size_is parameter
|
|
*pnSizeIs = (int)(state.nElement+1);
|
|
state.nExpectedElements++;
|
|
}
|
|
}
|
|
state.nElement++;
|
|
|
|
return pVal;
|
|
}
|
|
|
|
HRESULT ProcessString(const _soapmapentry *pEntry, void *pVal)
|
|
{
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
|
|
// set to the string builder class
|
|
|
|
ATLASSERT( GetReader() != NULL );
|
|
|
|
m_stringBuilder.SetReader(GetReader());
|
|
m_stringBuilder.SetParent(this);
|
|
|
|
m_stringBuilder.Clear();
|
|
GetReader()->putContentHandler( &m_stringBuilder );
|
|
|
|
if (S_OK != PushState(pVal, NULL, pEntry, SOAPFLAG_READYSTATE | pEntry->dwFlags))
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CheckHref(
|
|
const _soapmapentry *pEntry,
|
|
void *pVal,
|
|
ISAXAttributes *pAttributes,
|
|
DWORD dwIncludeFlags = 0,
|
|
DWORD dwExcludeFlags = 0)
|
|
{
|
|
ATLASSERT( pEntry != NULL );
|
|
ATLASSERT( pVal != NULL );
|
|
ATLASSERT( pAttributes != NULL );
|
|
|
|
const wchar_t *wsz = NULL;
|
|
int cch = 0;
|
|
|
|
HRESULT hr = GetAttribute(pAttributes, L"href", sizeof("href")-1, &wsz, &cch);
|
|
if ((hr == S_OK) && (wsz != NULL))
|
|
{
|
|
// only allow hrefs on structs and arrays
|
|
if (((pEntry->dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR))==0) &&
|
|
(pEntry->pChain == NULL || pEntry->pChain->mapType != SOAPMAP_STRUCT))
|
|
{
|
|
ATLTRACE( _T("ATL Server only allows href's on arrays and structs.\r\n") );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
ATLASSERT( IsRpcEncoded() == true );
|
|
|
|
_ATLTRY
|
|
{
|
|
if (*wsz == L'#')
|
|
{
|
|
wsz++;
|
|
cch--;
|
|
}
|
|
|
|
REFSTRING strRef(wsz, cch);
|
|
if (m_refMap.Lookup(strRef) != NULL)
|
|
{
|
|
// ATL Server does not support multi-reference objects
|
|
ATLASSERT( FALSE );
|
|
return E_FAIL;
|
|
}
|
|
|
|
ParseState& currState = GetState();
|
|
if ((currState.pEntry != NULL) && (currState.pEntry->dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR)))
|
|
{
|
|
// it is an array item
|
|
ATLASSERT( currState.nElement != 0 );
|
|
|
|
// exclude array flags for href'd array elements
|
|
dwExcludeFlags |= SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR;
|
|
}
|
|
|
|
ParseState state;
|
|
state.pvElement = pVal;
|
|
state.dwFlags = (pEntry->dwFlags | dwIncludeFlags) & ~dwExcludeFlags;
|
|
state.nExpectedElements = 0;
|
|
|
|
state.nElement = 0;
|
|
state.pMap = GetState().pMap;
|
|
state.pEntry = pEntry;
|
|
|
|
if (!m_refMap.SetAt(strRef, state))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::CheckHref -- out of memory.\r\n" ) );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// make sure there are no child elements
|
|
m_bNullCheck = true;
|
|
|
|
// push an emtpy state
|
|
return PushState();
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::CheckHref -- out of memory.\r\n" ) );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT ProcessUDT(
|
|
const _soapmapentry *pEntry,
|
|
void *pVal)
|
|
{
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
ATLENSURE_RETURN( pVal != NULL );
|
|
ATLENSURE_RETURN( pEntry->nVal != SOAPTYPE_ERR );
|
|
ATLENSURE_RETURN( pEntry->nVal != SOAPTYPE_USERBASE );
|
|
|
|
// if it is a complex type, get the chain entry
|
|
// and push the new state on the stack
|
|
|
|
DWORD dwFlags = pEntry->dwFlags;
|
|
if (pEntry->pChain->mapType != SOAPMAP_ENUM)
|
|
{
|
|
// struct
|
|
dwFlags &= ~(SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR);
|
|
m_bChildCheck = pEntry->pChain->nElements != 0;
|
|
}
|
|
else
|
|
{
|
|
// enum
|
|
dwFlags |= SOAPFLAG_READYSTATE;
|
|
|
|
// enums must not have child elements
|
|
m_bNullCheck = true;
|
|
|
|
// enums must be specified
|
|
m_bCharacters = true;
|
|
}
|
|
|
|
if (S_OK != PushState(pVal, pEntry->pChain, pEntry, dwFlags, 0, pEntry->pChain->nElements))
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT ChainEntry(
|
|
const ParseState& state,
|
|
const wchar_t *wszNamespaceUri,
|
|
int cchNamespaceUri,
|
|
const wchar_t *wszLocalName,
|
|
int cchLocalName,
|
|
ISAXAttributes *pAttributes)
|
|
{
|
|
ATLENSURE_RETURN( state.pMap != NULL );
|
|
|
|
// PAD is only supported on the client
|
|
const _soapmap *pMap = state.pMap;
|
|
if ((pMap->dwCallFlags & SOAPFLAG_CHAIN)==0)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
ATLENSURE_RETURN( pMap->dwCallFlags & SOAPFLAG_PAD );
|
|
ATLASSUME( m_bClient == true );
|
|
ATLENSURE_RETURN( pMap->nElements == 1 );
|
|
const _soapmapentry *pEntries = pMap->pEntries;
|
|
ATLENSURE_RETURN( pEntries != NULL );
|
|
|
|
int nIndex;
|
|
if (pEntries[0].dwFlags & SOAPFLAG_OUT)
|
|
{
|
|
nIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
nIndex = 1;
|
|
}
|
|
|
|
const _soapmapentry *pEntry = &pEntries[nIndex];
|
|
ATLENSURE_RETURN( pEntry->nHash != 0 );
|
|
ATLENSURE_RETURN( pEntry->pChain != NULL );
|
|
|
|
if (S_OK != PushState(state.pvElement, pEntry->pChain, pEntry, pEntry->dwFlags, 0, pEntry->pChain->nElements))
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return ProcessParams(wszNamespaceUri, cchNamespaceUri, wszLocalName, cchLocalName, pAttributes);
|
|
}
|
|
|
|
HRESULT IsNullEntry(const _soapmapentry *pEntry, ISAXAttributes *pAttributes)
|
|
{
|
|
ATLASSERT( pEntry != NULL );
|
|
ATLASSERT( pAttributes != NULL );
|
|
|
|
HRESULT hr = E_FAIL;
|
|
bool bNull = false;
|
|
const wchar_t *wszNull = NULL;
|
|
int cchNull = 0;
|
|
hr = GetAttribute(pAttributes, L"nil", sizeof("nil")-1, &wszNull, &cchNull,
|
|
XSI_NAMESPACEW, sizeof(XSI_NAMESPACEA)-1);
|
|
if ((hr == S_OK) && (wszNull != NULL))
|
|
{
|
|
hr = AtlGetSAXValue(&bNull, wszNull, cchNull);
|
|
if (hr == S_OK)
|
|
{
|
|
if (bNull != false)
|
|
{
|
|
if (pEntry->dwFlags & SOAPFLAG_NULLABLE)
|
|
{
|
|
m_bNullCheck = true;
|
|
|
|
// push an emtpy state
|
|
return PushState();
|
|
}
|
|
|
|
// non-nullable element
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT ProcessParams(
|
|
const wchar_t *wszNamespaceUri,
|
|
int cchNamespaceUri,
|
|
const wchar_t *wszLocalName,
|
|
int cchLocalName,
|
|
ISAXAttributes *pAttributes)
|
|
{
|
|
(wszNamespaceUri);
|
|
(cchNamespaceUri);
|
|
|
|
if (m_stateStack.IsEmpty())
|
|
{
|
|
if (m_dwState == SOAP_HEADERS)
|
|
{
|
|
return CheckMustUnderstandHeader(pAttributes);
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
ParseState &state = GetState();
|
|
|
|
ATLASSERT( state.pvElement != NULL );
|
|
HRESULT hr = E_FAIL;
|
|
const _soapmapentry *pEntry = NULL;
|
|
|
|
// if array element
|
|
if (state.dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR))
|
|
{
|
|
hr = ValidateArrayEntry(state, wszLocalName, cchLocalName);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pEntry = state.pEntry;
|
|
}
|
|
else
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
else // not an array element
|
|
{
|
|
// special-case for PAD with type=
|
|
hr = ChainEntry(state, wszNamespaceUri, cchNamespaceUri,
|
|
wszLocalName, cchLocalName, pAttributes);
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
hr = GetElementEntry(state, wszNamespaceUri, wszLocalName, cchLocalName, pAttributes, &pEntry);
|
|
if (hr != S_OK)
|
|
{
|
|
if (hr == S_FALSE)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else if (m_dwState == SOAP_HEADERS)
|
|
{
|
|
hr = CheckMustUnderstandHeader(pAttributes);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
ATLASSERT( pEntry != NULL );
|
|
}
|
|
else
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
hr = IsNullEntry(pEntry, pAttributes);
|
|
if (hr != S_FALSE)
|
|
{
|
|
return hr;
|
|
}
|
|
hr = S_OK;
|
|
ATLENSURE_RETURN(pEntry);
|
|
// if is array
|
|
if (((pEntry->pDims != NULL) || (pEntry->dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR))) &&
|
|
((state.dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR)) == 0))
|
|
{
|
|
// get SOAP section-5 info (if it is there)
|
|
return GetSection5Info(state, pEntry, pAttributes);
|
|
}
|
|
else
|
|
{
|
|
// if it is a simple type, push a new (ready) state on the stack
|
|
void *pVal;
|
|
if (state.dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR))
|
|
{
|
|
pVal = UpdateArray(state, pEntry);
|
|
ATLASSERT( pVal != NULL );
|
|
}
|
|
else
|
|
{
|
|
pVal = (((unsigned char *)state.pvElement)+pEntry->nOffset);
|
|
}
|
|
|
|
if (IsRpcEncoded() != false)
|
|
{
|
|
// check for href
|
|
// we ONLY do this for rpc/encoded (required for interop)
|
|
// NOTE: ATL Server does not support object graphs, so
|
|
// only single-reference elements are allowed
|
|
hr = CheckHref(pEntry, pVal, pAttributes);
|
|
if (hr != S_FALSE)
|
|
{
|
|
return hr;
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (pEntry->nVal != SOAPTYPE_UNK)
|
|
{
|
|
// simple types should not have child elements
|
|
m_bNullCheck = true;
|
|
|
|
// if it is a string
|
|
if ((pEntry->nVal == SOAPTYPE_STRING) || (pEntry->nVal == SOAPTYPE_BASE64BINARY))
|
|
{
|
|
hr = ProcessString(pEntry, pVal);
|
|
}
|
|
else
|
|
{
|
|
// expect characters for all non-string simple types
|
|
m_bCharacters = true;
|
|
|
|
// basic simple type
|
|
if (S_OK != PushState(pVal, NULL, pEntry, SOAPFLAG_READYSTATE | pEntry->dwFlags))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = ProcessUDT(pEntry, pVal);
|
|
if (pEntry->dwFlags & (SOAPFLAG_DYNARRWRAPPER))
|
|
{
|
|
// We're moving to the **first** entry in the dynamic array wrapper.
|
|
// We know it is the first entry because the dynamic array wrapper is created
|
|
// by sproxy and it guarantees this layouts.
|
|
++m_nDepth;
|
|
ProcessParams (wszNamespaceUri, cchNamespaceUri, pEntry->pChain->pEntries[0].wszField,
|
|
pEntry->pChain->pEntries[0].cchField, pAttributes);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
size_t GetSizeIsValue(void *pvParam, const _soapmap *pMap, const _soapmapentry *pEntry)
|
|
{
|
|
ATLENSURE( pvParam != NULL );
|
|
ATLENSURE( pMap != NULL );
|
|
ATLENSURE( pEntry != NULL );
|
|
|
|
int nSizeIs = pEntry->nSizeIs;
|
|
size_t nOffset = pMap->pEntries[nSizeIs].nOffset;
|
|
void *pVal = ((unsigned char *)pvParam)+nOffset;
|
|
|
|
__int64 nVal = 0;
|
|
switch(pMap->pEntries[nSizeIs].nVal)
|
|
{
|
|
case SOAPTYPE_INTEGER:
|
|
case SOAPTYPE_NONPOSITIVEINTEGER:
|
|
case SOAPTYPE_NEGATIVEINTEGER:
|
|
case SOAPTYPE_LONG:
|
|
nVal = *((__int64 *)pVal);
|
|
break;
|
|
case SOAPTYPE_INT:
|
|
nVal = *((int *)pVal);
|
|
break;
|
|
case SOAPTYPE_SHORT:
|
|
nVal = *((short *)pVal);
|
|
break;
|
|
case SOAPTYPE_BYTE:
|
|
nVal = *((char *)pVal);
|
|
break;
|
|
case SOAPTYPE_POSITIVEINTEGER:
|
|
case SOAPTYPE_NONNEGATIVEINTEGER:
|
|
case SOAPTYPE_UNSIGNEDLONG:
|
|
unsigned __int64 n;
|
|
n = *((unsigned __int64 *)pVal);
|
|
if (n > _I64_MAX)
|
|
{
|
|
// come on ...
|
|
nVal = 0;
|
|
}
|
|
else
|
|
{
|
|
nVal = (__int64)n;
|
|
}
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDINT:
|
|
nVal = *((unsigned int *)pVal);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDSHORT:
|
|
nVal = *((unsigned short *)pVal);
|
|
break;
|
|
case SOAPTYPE_UNSIGNEDBYTE:
|
|
nVal = *((unsigned char *)pVal);
|
|
break;
|
|
default:
|
|
nVal = 0;
|
|
}
|
|
|
|
if (nVal < 0)
|
|
{
|
|
nVal = 0;
|
|
}
|
|
|
|
return (size_t) nVal;
|
|
}
|
|
|
|
HRESULT GenerateArrayInfo(const _soapmapentry *pEntry, const int *pDims, IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
if (pEntry->nVal != SOAPTYPE_UNK)
|
|
{
|
|
// xsd type
|
|
hr = pStream->WriteStream(" soapenc:arrayType=\"xsd:",
|
|
sizeof(" soapenc:arrayType=\"xsd:")-1, NULL);
|
|
}
|
|
else
|
|
{
|
|
ATLENSURE_RETURN( pEntry->pChain != NULL );
|
|
|
|
hr = pStream->WriteStream(" xmlns:q1=\"", sizeof(" xmlns:q1=\"")-1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (pEntry->pChain->szNamespace != NULL)
|
|
{
|
|
hr = pStream->WriteStream(pEntry->pChain->szNamespace, pEntry->pChain->cchNamespace, NULL);
|
|
}
|
|
else
|
|
{
|
|
hr = pStream->WriteStream(GetNamespaceUriA(), -1, NULL);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream("\"", 1, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(" soapenc:arrayType=\"q1:",
|
|
sizeof(" soapenc:arrayType=\"q1:")-1, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if (pEntry->nVal != SOAPTYPE_UNK)
|
|
{
|
|
hr = pStream->WriteStream(s_xsdNames[pEntry->nVal].szName ,
|
|
s_xsdNames[pEntry->nVal].cchName, NULL);
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( pEntry->pChain != NULL );
|
|
|
|
hr = pStream->WriteStream(pEntry->pChain->szName, pEntry->pChain->cchName, NULL);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hr = pStream->WriteStream("[", 1, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
CWriteStreamHelper s( pStream );
|
|
for (int i=1; i<=pDims[0]; i++)
|
|
{
|
|
if (!s.Write(pDims[i]) ||
|
|
((i < pDims[0]) && (S_OK != pStream->WriteStream(", ", 2, NULL))))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
hr = pStream->WriteStream("]\"", 2, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT GenerateXSDWrapper(bool bStart, int nVal, bool bNull, IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
HRESULT hr = pStream->WriteStream((bStart != false) ? "<" : "</",
|
|
(bStart != false) ? 1 : 2, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(s_xsdNames[nVal].szName,
|
|
s_xsdNames[nVal].cchName, NULL);
|
|
if ((bNull != false) && (SUCCEEDED(hr)))
|
|
{
|
|
hr = pStream->WriteStream(" xsi:nil=\"1\"", sizeof(" xsi:nil=\"1\"")-1, NULL);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(">", 1, NULL);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GenerateGenericWrapper(bool bStart, const _soapmap *pMap, IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
|
|
HRESULT hr = pStream->WriteStream((bStart != false) ? "<" : "</",
|
|
(bStart != false) ? 1 : 2, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(pMap->szName, pMap->cchName, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStream->WriteStream(">", 1, NULL);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetArrayInformation(
|
|
IWriteStream *pStream,
|
|
const _soapmap *pMap,
|
|
const _soapmapentry *pEntry,
|
|
void *pvParam,
|
|
size_t &nCnt,
|
|
size_t &nElementSize)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
ATLENSURE_RETURN( pvParam != NULL );
|
|
|
|
const int *pDims = NULL;
|
|
int arrDims[2] = { 0 };
|
|
|
|
if (pEntry->dwFlags & SOAPFLAG_FIXEDARR)
|
|
{
|
|
pDims = pEntry->pDims;
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( pEntry->dwFlags & SOAPFLAG_DYNARR );
|
|
nCnt = GetSizeIsValue(pvParam, pMap, pEntry);
|
|
|
|
if (nCnt == 0)
|
|
{
|
|
// array size should only be zero if array is NULL
|
|
// did you forget to set the array size?
|
|
ATLASSERT( FALSE );
|
|
return E_FAIL;
|
|
}
|
|
|
|
arrDims[0] = 1;
|
|
arrDims[1] = (int) nCnt;
|
|
|
|
pDims = arrDims;
|
|
}
|
|
|
|
// output array information
|
|
HRESULT hr = GenerateArrayInfo(pEntry, pDims, pStream);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
nCnt = AtlSoapGetArrayDims(pDims);
|
|
|
|
// did you forget to set the size_is value?
|
|
ATLASSERT( nCnt != 0 );
|
|
|
|
if (pEntry->nVal != SOAPTYPE_UNK)
|
|
{
|
|
nElementSize = AtlSoapGetElementSize((SOAPTYPES) pEntry->nVal);
|
|
}
|
|
else
|
|
{
|
|
ATLENSURE_RETURN( pEntry->pChain != NULL );
|
|
|
|
nElementSize = pEntry->pChain->nElementSize;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GenerateEnum(IWriteStream *pStream, void *pVal, const _soapmapentry *pEntry, bool bArray)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pVal != NULL );
|
|
ATLENSURE_RETURN( pEntry != NULL );
|
|
|
|
int nVal = *((int *)pVal);
|
|
const _soapmapentry *pEnumEntries = pEntry->pChain->pEntries;
|
|
|
|
ATLENSURE_RETURN( pEnumEntries != NULL );
|
|
size_t j;
|
|
HRESULT hr = E_FAIL;
|
|
for (j=0; pEnumEntries[j].nHash != 0; j++)
|
|
{
|
|
if (nVal == pEnumEntries[j].nVal)
|
|
{
|
|
hr = pStream->WriteStream(pEnumEntries[j].szField, pEnumEntries[j].cchField, NULL);
|
|
if ((bArray != false) && (SUCCEEDED(hr)))
|
|
{
|
|
hr = GenerateGenericWrapper(false, pEntry->pChain, pStream);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GenerateHeaders(CResponseGenerator *pGenerator, const _soapmap *pMap, IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
|
|
ATLENSURE_RETURN( pGenerator != NULL );
|
|
|
|
DWORD dwIncludeFlags = SOAPFLAG_OUT;
|
|
if (m_bClient != false)
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_IN;
|
|
}
|
|
|
|
size_t nCnt = 0;
|
|
for (size_t i=0; pMap->pEntries[i].nHash != 0; i++)
|
|
{
|
|
if (pMap->pEntries[i].dwFlags & dwIncludeFlags)
|
|
{
|
|
nCnt++;
|
|
}
|
|
}
|
|
|
|
// no headers to be sent
|
|
if (nCnt == 0)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT hr = pGenerator->StartHeaders(pStream, pMap);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GenerateResponseHelper(pGenerator, pMap, GetHeaderValue(), pStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pGenerator->EndHeaders(pStream);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
bool IsNullElement(const _soapmapentry *pEntry, void *pVal, DWORD dwExcludeFlags=0)
|
|
{
|
|
ATLENSURE( pEntry != NULL );
|
|
ATLENSURE( pVal != NULL );
|
|
|
|
bool bNull = false;
|
|
|
|
DWORD dwFlags = pEntry->dwFlags & ~dwExcludeFlags;
|
|
|
|
if (dwFlags & SOAPFLAG_DYNARR)
|
|
{
|
|
unsigned char **ppArr = (unsigned char **)pVal;
|
|
if (*ppArr == NULL)
|
|
{
|
|
bNull = true;
|
|
}
|
|
}
|
|
else if (pEntry->nVal == SOAPTYPE_STRING)
|
|
{
|
|
BSTR *pBSTR = (BSTR *)pVal;
|
|
if (*pBSTR == NULL)
|
|
{
|
|
bNull = true;
|
|
}
|
|
}
|
|
else if ((pEntry->nVal == SOAPTYPE_BASE64BINARY) || (pEntry->nVal == SOAPTYPE_HEXBINARY))
|
|
{
|
|
if (((ATLSOAP_BLOB *)pVal)->data == NULL)
|
|
{
|
|
bNull = true;
|
|
}
|
|
}
|
|
|
|
return bNull;
|
|
}
|
|
|
|
HRESULT GenerateNull(IWriteStream *pStream)
|
|
{
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
return pStream->WriteStream(" xsi:nil=\"1\"/>", sizeof(" xsi:nil=\"1\"/>")-1, NULL);
|
|
}
|
|
|
|
HRESULT GenerateResponseHelper(CResponseGenerator *pGenerator, const _soapmap *pMap, void *pvParam, IWriteStream *pStream,
|
|
bool bArrayElement = false)
|
|
{
|
|
ATLENSURE_RETURN( pGenerator != NULL );
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
ATLENSURE_RETURN( pStream != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ((bArrayElement != false) &&
|
|
((pMap->dwCallFlags & SOAPFLAG_PAD)==0))
|
|
{
|
|
hr = pGenerator->StartMap(pStream, pMap, m_bClient);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
ATLENSURE_RETURN( pMap->pEntries != NULL );
|
|
|
|
const _soapmapentry *pEntries = pMap->pEntries;
|
|
size_t i;
|
|
|
|
DWORD dwIncludeFlags;
|
|
DWORD dwExcludeFlags;
|
|
if (m_bClient != false)
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_IN;
|
|
dwExcludeFlags = SOAPFLAG_OUT;
|
|
}
|
|
else
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_OUT;
|
|
dwExcludeFlags = SOAPFLAG_IN;
|
|
}
|
|
|
|
for (i=0; pEntries[i].nHash != 0; i++)
|
|
{
|
|
if (((pEntries[i].dwFlags & dwIncludeFlags) ||
|
|
((pEntries[i].dwFlags & dwExcludeFlags)==0)) &&
|
|
((pEntries[i].dwFlags & SOAPFLAG_NOMARSHAL)==0))
|
|
{
|
|
hr = pGenerator->StartEntry(pStream, pMap, &pEntries[i]);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
size_t nElementSize = 0;
|
|
size_t nCnt = 1;
|
|
|
|
ATLASSERT( pvParam != NULL );
|
|
|
|
void *pvCurrent = ((unsigned char *)pvParam)+pEntries[i].nOffset;
|
|
|
|
if (IsNullElement(&pEntries[i], pvCurrent))
|
|
{
|
|
hr = GenerateNull(pStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
continue;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
bool bArray = (pEntries[i].dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR)) != 0;
|
|
if (bArray != false)
|
|
{
|
|
hr = GetArrayInformation(pStream, pMap, &pEntries[i], pvParam, nCnt, nElementSize);
|
|
}
|
|
|
|
hr = pStream->WriteStream(">", 1, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
for (size_t nElement=0; nElement<nCnt; nElement++)
|
|
{
|
|
void *pVal;
|
|
|
|
// get updated value
|
|
if (bArray != false)
|
|
{
|
|
if (pEntries[i].dwFlags & SOAPFLAG_FIXEDARR)
|
|
{
|
|
unsigned char *ppArr = (unsigned char *)pvCurrent;
|
|
pVal = ppArr+(nElement*nElementSize);
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( pEntries[i].dwFlags & SOAPFLAG_DYNARR );
|
|
|
|
unsigned char **ppArr = (unsigned char **)pvCurrent;
|
|
pVal = (*ppArr)+(nElement*nElementSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pVal = pvCurrent;
|
|
}
|
|
|
|
if (pEntries[i].nVal != SOAPTYPE_UNK)
|
|
{
|
|
bool bNull = false;
|
|
if (bArray != false)
|
|
{
|
|
bNull = IsNullElement(&pEntries[i], pVal, SOAPFLAG_DYNARR | SOAPFLAG_FIXEDARR);
|
|
hr = GenerateXSDWrapper(true, pEntries[i].nVal, bNull, pStream);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
if (bNull == false)
|
|
{
|
|
hr = AtlSoapGenElementValue(pVal, pStream, (SOAPTYPES) pEntries[i].nVal, GetMemMgr());
|
|
}
|
|
if ((SUCCEEDED(hr)) && (bArray != false))
|
|
{
|
|
hr = GenerateXSDWrapper(false, pEntries[i].nVal, false, pStream);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( pEntries[i].pChain != NULL );
|
|
|
|
if (pEntries[i].pChain->mapType != SOAPMAP_ENUM)
|
|
{
|
|
// struct
|
|
hr = GenerateResponseHelper(pGenerator, pEntries[i].pChain, pVal, pStream, bArray);
|
|
}
|
|
else
|
|
{
|
|
if (bArray != false)
|
|
{
|
|
hr = GenerateGenericWrapper(true, pEntries[i].pChain, pStream);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
hr = GenerateEnum(pStream, pVal, &pEntries[i], bArray);
|
|
}
|
|
}
|
|
}
|
|
|
|
// output element close
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pGenerator->EndEntry(pStream, pMap, &pEntries[i]);
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if ((bArrayElement != false) &&
|
|
((pMap->dwCallFlags & SOAPFLAG_PAD)==0))
|
|
{
|
|
// output type name
|
|
hr = pGenerator->EndMap(pStream, pMap, m_bClient);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CleanupHelper(const _soapmap *pMap, void *pvParam)
|
|
{
|
|
ATLENSURE( pMap != NULL );
|
|
ATLENSURE( pMap->pEntries != NULL );
|
|
|
|
if (pvParam == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const _soapmapentry *pEntries = pMap->pEntries;
|
|
size_t i;
|
|
|
|
for (i=0; pEntries[i].nHash != 0; i++)
|
|
{
|
|
if ((m_bClient != false) && ((pEntries[i].dwFlags & SOAPFLAG_OUT)==0))
|
|
{
|
|
// skip in-only headers on the client
|
|
continue;
|
|
}
|
|
|
|
void *pvCheck = ((unsigned char *)pvParam)+pEntries[i].nOffset;
|
|
if (IsNullElement(&pEntries[i], pvCheck))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
size_t nElementSize = 0;
|
|
size_t nCnt = 1;
|
|
|
|
const int *pDims = NULL;
|
|
int arrDims[2] = { 0 };
|
|
|
|
bool bArray = (pEntries[i].dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR)) != 0;
|
|
|
|
if (bArray != false)
|
|
{
|
|
if (pEntries[i].dwFlags & SOAPFLAG_FIXEDARR)
|
|
{
|
|
pDims = pEntries[i].pDims;
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( pEntries[i].dwFlags & SOAPFLAG_DYNARR );
|
|
nCnt = GetSizeIsValue(pvParam, pMap, &pEntries[i]);
|
|
|
|
arrDims[0] = 1;
|
|
arrDims[1] = (int) nCnt;
|
|
|
|
pDims = arrDims;
|
|
}
|
|
|
|
nCnt = AtlSoapGetArrayDims(pDims);
|
|
|
|
if (pEntries[i].nVal != SOAPTYPE_UNK)
|
|
{
|
|
nElementSize = AtlSoapGetElementSize((SOAPTYPES) pEntries[i].nVal);
|
|
}
|
|
else
|
|
{
|
|
ATLENSURE( pEntries[i].pChain != NULL );
|
|
|
|
nElementSize = pEntries[i].pChain->nElementSize;
|
|
}
|
|
}
|
|
|
|
void *pvCurrent = ((unsigned char *)pvParam)+pEntries[i].nOffset;
|
|
|
|
for (size_t nElement=0; nElement<nCnt; nElement++)
|
|
{
|
|
void *pVal;
|
|
|
|
// get updated value
|
|
if (bArray != false)
|
|
{
|
|
if (pEntries[i].dwFlags & SOAPFLAG_FIXEDARR)
|
|
{
|
|
unsigned char *ppArr = (unsigned char *)pvCurrent;
|
|
pVal = ppArr+(nElement*nElementSize);
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( pEntries[i].dwFlags & SOAPFLAG_DYNARR );
|
|
|
|
unsigned char **ppArr = (unsigned char **)pvCurrent;
|
|
if (*ppArr == NULL)
|
|
{
|
|
break;
|
|
}
|
|
pVal = (*ppArr)+(nElement*nElementSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pVal = pvCurrent;
|
|
}
|
|
|
|
if (pEntries[i].nVal != SOAPTYPE_UNK)
|
|
{
|
|
AtlSoapCleanupElement(pVal, (SOAPTYPES) pEntries[i].nVal, GetMemMgr());
|
|
}
|
|
else
|
|
{
|
|
ATLENSURE( pEntries[i].pChain != NULL );
|
|
|
|
if (pEntries[i].pChain->mapType != SOAPMAP_ENUM)
|
|
{
|
|
CleanupHelper(pEntries[i].pChain, pVal);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pEntries[i].dwFlags & SOAPFLAG_DYNARR)
|
|
{
|
|
// free it
|
|
unsigned char **ppArr = (unsigned char **)pvCurrent;
|
|
|
|
ATLENSURE( ppArr != NULL );
|
|
|
|
if (*ppArr != NULL)
|
|
{
|
|
m_pMemMgr->Free(*ppArr);
|
|
*ppArr = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const _soapmap * GetSoapMapFromName(
|
|
const wchar_t * wszName,
|
|
int cchName = -1,
|
|
const wchar_t * wszNamespaceUri = NULL,
|
|
int cchNamespaceUri = -1,
|
|
int *pnVal = NULL,
|
|
bool bHeader = false)
|
|
{
|
|
(cchNamespaceUri);
|
|
|
|
const _soapmap ** pEntry = NULL;
|
|
|
|
if (bHeader == false)
|
|
{
|
|
pEntry = GetFunctionMap();
|
|
}
|
|
else
|
|
{
|
|
pEntry = GetHeaderMap();
|
|
}
|
|
|
|
if (pEntry == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (cchName < 0)
|
|
{
|
|
cchName = (int)wcslen(wszName);
|
|
}
|
|
if ((cchNamespaceUri < 0) && (wszNamespaceUri != NULL))
|
|
{
|
|
cchNamespaceUri = (int)wcslen(wszNamespaceUri);
|
|
}
|
|
|
|
ULONG nFunctionHash = AtlSoapHashStr(wszName, cchName);
|
|
ULONG nNamespaceHash = wszNamespaceUri ? AtlSoapHashStr(wszNamespaceUri, cchNamespaceUri) : 0;
|
|
|
|
int i;
|
|
for (i=0; pEntry[i] != NULL; i++)
|
|
{
|
|
if ((IsEqualStringHash(wszName, cchName, nFunctionHash,
|
|
pEntry[i]->wszName, pEntry[i]->cchWName, pEntry[i]->nHash) != FALSE) &&
|
|
(!wszNamespaceUri ||
|
|
IsEqualStringHash(wszNamespaceUri, cchNamespaceUri, nNamespaceHash,
|
|
pEntry[i]->wszNamespace, pEntry[i]->cchNamespace, pEntry[i]->nNamespaceHash) != FALSE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pnVal != NULL)
|
|
{
|
|
*pnVal = i;
|
|
}
|
|
return pEntry[i];
|
|
}
|
|
|
|
HRESULT CheckEndElement(const ParseState& state)
|
|
{
|
|
// check for all elements
|
|
if (state.nElement == state.nExpectedElements)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// error check for fixed arrays
|
|
if (state.dwFlags & SOAPFLAG_FIXEDARR)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// check for dynamic arrays
|
|
if (state.dwFlags & SOAPFLAG_DYNARR)
|
|
{
|
|
// check for dynamic arrays with known size
|
|
// (from soap:arrayType attribute)
|
|
if ((state.dwFlags & SOAPFLAG_UNKSIZE)==0)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
DWORD dwIncludeFlags;
|
|
DWORD dwExcludeFlags;
|
|
|
|
if (m_bClient != false)
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_OUT;
|
|
dwExcludeFlags = SOAPFLAG_IN;
|
|
}
|
|
else
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_IN;
|
|
dwExcludeFlags = SOAPFLAG_OUT;
|
|
}
|
|
|
|
if (state.pMap != NULL)
|
|
{
|
|
// ensure all omitted elements were nullable elements or nomarshal elements
|
|
const _soapmapentry *pEntries = state.pMap->pEntries;
|
|
for (size_t i=0; pEntries[i].nHash != 0; i++)
|
|
{
|
|
if ((pEntries[i].dwFlags & dwIncludeFlags) ||
|
|
((pEntries[i].dwFlags & dwExcludeFlags)==0))
|
|
{
|
|
if (state.vec.GetBit(i) == false)
|
|
{
|
|
if (((pEntries[i].dwFlags & (SOAPFLAG_NULLABLE | SOAPFLAG_NOMARSHAL))==0) && (pEntries[i].nVal != SOAPTYPE_UNK))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::CheckEndElement -- invalid number of elements for parameter/field\r\n") );
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CheckSoapHeaders(const ParseState &state)
|
|
{
|
|
DWORD dwIncludeFlags;
|
|
DWORD dwExcludeFlags;
|
|
|
|
if (m_bClient != false)
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_OUT;
|
|
dwExcludeFlags = SOAPFLAG_IN;
|
|
}
|
|
else
|
|
{
|
|
dwIncludeFlags = SOAPFLAG_IN;
|
|
dwExcludeFlags = SOAPFLAG_OUT;
|
|
}
|
|
|
|
if (state.pMap != NULL)
|
|
{
|
|
ATLASSERT( state.pMap->mapType == SOAPMAP_HEADER );
|
|
|
|
// ensure all omitted elements were nullable elements, nomarshal elements, or non-required elements
|
|
const _soapmapentry *pEntries = state.pMap->pEntries;
|
|
for (size_t i=0; pEntries[i].nHash != 0; i++)
|
|
{
|
|
if ((pEntries[i].dwFlags & dwIncludeFlags) ||
|
|
((pEntries[i].dwFlags & dwExcludeFlags)==0))
|
|
{
|
|
if (state.vec.GetBit(i) == false)
|
|
{
|
|
bool bNoOmit = (pEntries[i].dwFlags & (SOAPFLAG_NULLABLE | SOAPFLAG_NOMARSHAL))==0;
|
|
|
|
if ((bNoOmit != false) ||
|
|
((bNoOmit != false) && (pEntries[i].dwFlags & SOAPFLAG_MUSTUNDERSTAND)))
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::CheckSoapHeaders -- missing header\r\n") );
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CheckEndHeaders(
|
|
const wchar_t * wszNamespaceUri,
|
|
int cchNamespaceUri,
|
|
const wchar_t * wszLocalName,
|
|
int cchLocalName)
|
|
{
|
|
if (IsEqualElement(sizeof(SOAP_HEADERA)-1, SOAP_HEADERW,
|
|
sizeof(SOAPENV_NAMESPACEA)-1, SOAPENV_NAMESPACEW,
|
|
cchLocalName, wszLocalName,
|
|
cchNamespaceUri, wszNamespaceUri))
|
|
{
|
|
m_dwState = SOAP_HEADERS_DONE;
|
|
return S_OK;
|
|
}
|
|
|
|
// some sort of error
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::endElement -- invalid SOAP message format while processing headers.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
protected:
|
|
|
|
ISAXXMLReader * SetReader(ISAXXMLReader *pReader)
|
|
{
|
|
ISAXXMLReader *pPrevRdr = m_spReader;
|
|
m_spReader = pReader;
|
|
|
|
return pPrevRdr;
|
|
}
|
|
|
|
ISAXXMLReader * GetReader()
|
|
{
|
|
return m_spReader;
|
|
}
|
|
|
|
HRESULT SetSoapMapFromName(
|
|
const wchar_t * wszName,
|
|
int cchName = -1,
|
|
const wchar_t * wszNamespaceUri = NULL,
|
|
int cchNamespaceUri = -1,
|
|
bool bHeader = false)
|
|
{
|
|
ATLENSURE_RETURN( wszName != NULL );
|
|
|
|
int nVal;
|
|
const _soapmap *pMap = NULL;
|
|
if (m_stateStack.GetCount() != 0)
|
|
{
|
|
ATLASSUME( m_stateStack[0].pMap != NULL );
|
|
nVal = (int) m_stateStack[0].nAllocSize;
|
|
ATLASSERT( GetFunctionMap() != NULL );
|
|
pMap = GetFunctionMap()[nVal];
|
|
}
|
|
else
|
|
{
|
|
pMap = GetSoapMapFromName(wszName, cchName,
|
|
wszNamespaceUri, cchNamespaceUri, &nVal, bHeader);
|
|
}
|
|
|
|
if (pMap == NULL)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::SetSoapMapFromName -- _soapmap not found for: %.*ws, with namespace %.*ws\r\n"),
|
|
(int)wcslen(wszName), wszName, wszNamespaceUri ? (int)wcslen(wszNamespaceUri) : 0, wszNamespaceUri ? wszNamespaceUri : L"");
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
// allocate the parameter struct
|
|
|
|
void *pvParam = NULL;
|
|
if (bHeader != false)
|
|
{
|
|
pvParam = GetHeaderValue();
|
|
}
|
|
else
|
|
{
|
|
if (m_bClient == false)
|
|
{
|
|
m_pvParam = m_pMemMgr->Allocate(pMap->nElementSize);
|
|
}
|
|
pvParam = m_pvParam;
|
|
}
|
|
|
|
if (pvParam != NULL)
|
|
{
|
|
if (bHeader == false)
|
|
{
|
|
memset(pvParam, 0x00, pMap->nElementSize);
|
|
}
|
|
|
|
// push initial state
|
|
|
|
if (m_stateStack.GetCount() != 0)
|
|
{
|
|
m_stateStack.RemoveAll();
|
|
}
|
|
|
|
hr = PushState(pvParam, pMap, NULL, 0, nVal, pMap->nElements);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if ((m_bClient == false) && (bHeader == false))
|
|
{
|
|
m_pMemMgr->Free(pvParam);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
if (hr == E_OUTOFMEMORY)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::SetSoapMapFromName -- out of memory.\r\n" ) );
|
|
}
|
|
#endif // _DEBUG
|
|
|
|
return hr;
|
|
}
|
|
|
|
// implementation
|
|
virtual const _soapmap ** GetFunctionMap() = 0;
|
|
virtual const _soapmap ** GetHeaderMap() = 0;
|
|
virtual const wchar_t * GetNamespaceUri() = 0;
|
|
virtual const char * GetServiceName() = 0;
|
|
virtual const char * GetNamespaceUriA() = 0;
|
|
virtual HRESULT CallFunction(
|
|
void *pvParam,
|
|
const wchar_t *wszLocalName, int cchLocalName,
|
|
size_t nItem) = 0;
|
|
virtual void * GetHeaderValue() = 0;
|
|
|
|
public:
|
|
|
|
CSoapRootHandler(ISAXXMLReader *pReader = NULL)
|
|
: m_pMemMgr(&m_crtHeap), m_spReader(pReader), m_bClient(false),
|
|
m_nState(0), m_pvParam(NULL), m_nDepth(0)
|
|
{
|
|
InitHandlerState();
|
|
}
|
|
virtual ~CSoapRootHandler()
|
|
{
|
|
m_skipHandler.DetachParent();
|
|
}
|
|
|
|
IAtlMemMgr * SetMemMgr(IAtlMemMgr *pMemMgr)
|
|
{
|
|
IAtlMemMgr *pPrevMgr = m_pMemMgr;
|
|
m_pMemMgr = pMemMgr;
|
|
|
|
return pPrevMgr;
|
|
}
|
|
|
|
IAtlMemMgr * GetMemMgr()
|
|
{
|
|
return m_pMemMgr;
|
|
}
|
|
|
|
// override this function to do SOAP Fault handling
|
|
virtual HRESULT SoapFault(
|
|
SOAP_ERROR_CODE /*errCode*/,
|
|
const wchar_t * /*wszDetail*/,
|
|
int /*cchDetail*/)
|
|
{
|
|
if (m_bClient != false)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// SOAP servers must implement this function
|
|
ATLASSERT( FALSE );
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// implementation
|
|
//
|
|
|
|
void InitHandlerState()
|
|
{
|
|
m_bNullCheck = false;
|
|
m_bCharacters = false;
|
|
m_bChildCheck = false;
|
|
m_dwState = SOAP_START;
|
|
}
|
|
HRESULT __stdcall startDocument()
|
|
{
|
|
InitHandlerState();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall startElement(
|
|
const wchar_t *wszNamespaceUri,
|
|
int cchNamespaceUri,
|
|
const wchar_t *wszLocalName,
|
|
int cchLocalName,
|
|
const wchar_t * wszQName,
|
|
int cchQName,
|
|
ISAXAttributes *pAttributes)
|
|
{
|
|
if (m_bNullCheck || m_bCharacters)
|
|
{
|
|
// make sure elements that aren't supposed to have child elements
|
|
// do not have child elements, and where we were expecting
|
|
// characters, we got them
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_bChildCheck = false;
|
|
++m_nDepth;
|
|
|
|
HRESULT hr = S_OK;
|
|
switch (m_dwState)
|
|
{
|
|
case SOAP_PARAMS: case SOAP_HEADERS:
|
|
{
|
|
hr = ProcessParams(wszNamespaceUri, cchNamespaceUri, wszLocalName,
|
|
cchLocalName, pAttributes);
|
|
|
|
break;
|
|
}
|
|
case SOAP_START: case SOAP_ENVELOPE: case SOAP_HEADERS_DONE:
|
|
{
|
|
ULONG nNamespaceHash = AtlSoapHashStr(wszNamespaceUri,
|
|
cchNamespaceUri);
|
|
if (nNamespaceHash != SOAP_ENV)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::startElement -- incorrect SOAP-ENV namespace.\r\n" ) );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
ULONG nElementHash = AtlSoapHashStr(wszLocalName, cchLocalName);
|
|
|
|
if (nElementHash == ENVELOPE &&
|
|
IsEqualElement(
|
|
sizeof(SOAP_ENVELOPEA)-1, SOAP_ENVELOPEW,
|
|
sizeof(SOAPENV_NAMESPACEA)-1, SOAPENV_NAMESPACEW,
|
|
cchLocalName, wszLocalName,
|
|
cchNamespaceUri, wszNamespaceUri))
|
|
{
|
|
// Envelope must be first element in package
|
|
|
|
if (m_dwState != SOAP_START)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::startElement -- invalid SOAP message format: \"Envelope\" in unexpected location.\r\n" ) );
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
m_dwState = SOAP_ENVELOPE;
|
|
}
|
|
else if (nElementHash == HEADER &&
|
|
IsEqualElement(sizeof(SOAP_HEADERA)-1, SOAP_HEADERW,
|
|
sizeof(SOAPENV_NAMESPACEA)-1, SOAPENV_NAMESPACEW,
|
|
cchLocalName, wszLocalName,
|
|
cchNamespaceUri, wszNamespaceUri))
|
|
{
|
|
if (m_dwState != SOAP_ENVELOPE)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::startElement -- invalid SOAP message format: \"Headers\" in unexpected location.\r\n" ) );
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
m_dwState = SOAP_HEADERS;
|
|
}
|
|
else if (nElementHash == BODY &&
|
|
IsEqualElement(sizeof(SOAP_BODYA)-1, SOAP_BODYW,
|
|
sizeof(SOAPENV_NAMESPACEA)-1, SOAPENV_NAMESPACEW,
|
|
cchLocalName, wszLocalName,
|
|
cchNamespaceUri, wszNamespaceUri))
|
|
{
|
|
if (m_dwState == SOAP_START)
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::startElement -- invalid SOAP message format: \"Body\" in unexpected location.\r\n" ) );
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
m_dwState = SOAP_BODY;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SOAP_BODY:
|
|
{
|
|
hr = DispatchSoapCall(wszNamespaceUri, cchNamespaceUri,
|
|
wszLocalName, cchLocalName);
|
|
|
|
m_dwState = SOAP_PARAMS;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (GetState().pMap->dwCallFlags & SOAPFLAG_PAD)
|
|
{
|
|
hr = startElement(wszNamespaceUri, cchNamespaceUri,
|
|
wszLocalName, cchLocalName, wszQName, cchQName,
|
|
pAttributes);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
default:
|
|
{
|
|
// should never get here -- internal error
|
|
ATLASSERT( FALSE );
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall characters(
|
|
const wchar_t *wszChars,
|
|
int cchChars)
|
|
{
|
|
m_bCharacters = false;
|
|
|
|
// if it is a ready state, get the value
|
|
if (m_stateStack.IsEmpty() == false)
|
|
{
|
|
ParseState& state = GetState();
|
|
if ((state.dwFlags & SOAPFLAG_READYSTATE) &&
|
|
((state.dwFlags & SOAPFLAG_SIZEIS)==0)) // don't marshal struct size_is elements -- should be filled in by array marshaling code
|
|
{
|
|
if ((state.pMap == NULL) || (state.pMap->mapType != SOAPMAP_ENUM))
|
|
{
|
|
return AtlSoapGetElementValue(wszChars, cchChars,
|
|
state.pvElement, (SOAPTYPES)state.pEntry->nVal, GetMemMgr());
|
|
}
|
|
else
|
|
{
|
|
// enum
|
|
|
|
ATLASSERT( state.pMap != NULL );
|
|
ATLASSERT( state.pMap->pEntries != NULL );
|
|
|
|
ULONG nHash = AtlSoapHashStr(wszChars, cchChars);
|
|
const _soapmapentry *pEntries = state.pMap->pEntries;
|
|
|
|
size_t i;
|
|
for (i=0; pEntries[i].nHash != 0; i++)
|
|
{
|
|
if ((nHash == pEntries[i].nHash) &&
|
|
(cchChars == pEntries[i].cchField) &&
|
|
(!wcsncmp(wszChars, pEntries[i].wszField, cchChars)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pEntries[i].nHash != 0)
|
|
{
|
|
*((int *)state.pvElement) = pEntries[i].nVal;
|
|
state.nElement++;
|
|
return S_OK;
|
|
}
|
|
|
|
// no matching enum entry found
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::characters -- no matching enum entry found for: %.*ws.\r\n" ), cchChars, wszChars );
|
|
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// otherwise, ignore
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __stdcall endElement(
|
|
const wchar_t * wszNamespaceUri,
|
|
int cchNamespaceUri,
|
|
const wchar_t * wszLocalName,
|
|
int cchLocalName,
|
|
const wchar_t * /*wszQName*/,
|
|
int /*cchQName*/)
|
|
{
|
|
static bool bDynArrWrapper = false;
|
|
if (m_bCharacters)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_bNullCheck = false;
|
|
|
|
if (m_stateStack.IsEmpty() != false)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
if (!bDynArrWrapper && (m_nState > 1))
|
|
{
|
|
ParseState prevState = m_stateStack.GetAt(m_nState - 1);
|
|
ParseState curState = m_stateStack.GetAt(m_nState);
|
|
if (prevState.dwFlags & SOAPFLAG_DYNARRWRAPPER)
|
|
{
|
|
bDynArrWrapper = true;
|
|
endElement (wszNamespaceUri, cchNamespaceUri, curState.pEntry->wszField,
|
|
curState.pEntry->cchField, NULL, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bDynArrWrapper = false;
|
|
}
|
|
|
|
--m_nDepth;
|
|
|
|
const ParseState& state = GetState();
|
|
|
|
if ((m_dwState == SOAP_HEADERS) && (m_stateStack.GetCount() == 1))
|
|
{
|
|
return CheckEndHeaders(wszNamespaceUri, cchNamespaceUri, wszLocalName, cchLocalName);
|
|
}
|
|
|
|
if (state.dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR))
|
|
{
|
|
if (state.dwFlags & SOAPFLAG_READYSTATE)
|
|
{
|
|
PopState();
|
|
}
|
|
|
|
const ParseState& currstate = GetState();
|
|
ATLENSURE_RETURN( currstate.pEntry != NULL );
|
|
|
|
if (m_nDepth == (currstate.nDepth-1))
|
|
{
|
|
if (S_OK != CheckEndElement(currstate))
|
|
{
|
|
// invalid number of elements
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::endElement -- invalid number of array elements for array parameter %.*ws.\r\n"),
|
|
currstate.pEntry->cchField, currstate.pEntry->wszField );
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
PopState();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (S_OK != CheckEndElement(state))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
PopState();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT SetClientStruct(void *pvParam, int nMapIndex)
|
|
{
|
|
ATLENSURE_RETURN( pvParam != NULL );
|
|
ATLENSURE_RETURN( nMapIndex >= 0 );
|
|
|
|
// this is the params struct
|
|
// store for later use
|
|
m_pvParam = pvParam;
|
|
|
|
const _soapmap ** pEntries = GetHeaderMap();
|
|
ATLENSURE_RETURN( pEntries != NULL );
|
|
|
|
// push header value
|
|
return PushState(GetHeaderValue(), pEntries[nMapIndex], NULL, 0, nMapIndex, pEntries[nMapIndex]->nElements);
|
|
}
|
|
|
|
void ResetClientState(bool bFull = false)
|
|
{
|
|
m_stateStack.RemoveAll();
|
|
m_nState = 0;
|
|
if (bFull != false)
|
|
{
|
|
m_dwState = SOAP_START;
|
|
m_pvParam = NULL;
|
|
}
|
|
}
|
|
|
|
HRESULT CreateReader()
|
|
{
|
|
return m_spReader.CoCreateInstance(ATLS_SAXXMLREADER_CLSID, NULL, CLSCTX_INPROC_SERVER);
|
|
}
|
|
|
|
HRESULT InitializeSOAP(IServiceProvider *pProvider)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_spReader.p == NULL)
|
|
{
|
|
hr = E_FAIL;
|
|
if (pProvider != NULL)
|
|
{
|
|
IAtlMemMgr *pMemMgr = NULL;
|
|
hr = pProvider->QueryService(__uuidof(IAtlMemMgr),
|
|
__uuidof(IAtlMemMgr), (void **)&pMemMgr);
|
|
if ((SUCCEEDED(hr)) && (pMemMgr != NULL))
|
|
{
|
|
SetMemMgr(pMemMgr);
|
|
}
|
|
|
|
hr = pProvider->QueryService(__uuidof(ISAXXMLReader),
|
|
__uuidof(ISAXXMLReader), (void **)&m_spReader);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
hr = CreateReader();
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_spReader->putContentHandler(this);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
else
|
|
{
|
|
ATLTRACE( _T("ATLSOAP: CSoapRootHandler::InitializeSOAP -- failed to get SAXXMLReader.\r\n" ) );
|
|
}
|
|
#endif // _DEBUG
|
|
|
|
return hr;
|
|
}
|
|
|
|
void UninitializeSOAP()
|
|
{
|
|
if (m_spReader.p != NULL)
|
|
{
|
|
m_spReader->putContentHandler(NULL);
|
|
m_spReader.Release();
|
|
}
|
|
}
|
|
|
|
virtual HRESULT DispatchSoapCall(const wchar_t *wszNamespaceUri,
|
|
int cchNamespaceUri, const wchar_t *wszLocalName,
|
|
int cchLocalName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_stateStack.IsEmpty() == false)
|
|
{
|
|
ATLASSUME( m_stateStack[0].pMap != NULL );
|
|
|
|
// check to see if all required and non-nullable SOAP headers were sent
|
|
if (m_stateStack[0].pMap->mapType == SOAPMAP_HEADER)
|
|
{
|
|
hr = CheckSoapHeaders(m_stateStack[0]);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetSoapMapFromName(wszLocalName, cchLocalName,
|
|
wszNamespaceUri, cchNamespaceUri);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// get the appropriate function map
|
|
hr = SetSoapMapFromName(wszLocalName, cchLocalName,
|
|
wszNamespaceUri, cchNamespaceUri);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// set the SOAP Header map for the function
|
|
ATLASSUME( m_stateStack.IsEmpty() == false );
|
|
|
|
const _soapmap **ppHeaderMap = GetHeaderMap();
|
|
ATLENSURE_RETURN( ppHeaderMap != NULL );
|
|
|
|
// create a temporary parse state for checking headers
|
|
ParseState state;
|
|
state.pMap = ppHeaderMap[m_stateStack[0].nAllocSize];
|
|
ATLENSURE_RETURN( state.pMap != NULL );
|
|
|
|
// check to see if all required and non-nullable SOAP headers were sent
|
|
hr = CheckSoapHeaders(state);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
virtual HRESULT BeginParse(IStream *pStream)
|
|
{
|
|
ATLASSERT( pStream != NULL );
|
|
|
|
CComVariant varStream;
|
|
varStream = static_cast<IUnknown*>(pStream);
|
|
|
|
HRESULT hr = m_spReader->parse(varStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (m_refMap.GetCount() != 0)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CallFunctionInternal()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
const ParseState& state = m_stateStack[0];
|
|
hr = CallFunction(
|
|
state.pvElement,
|
|
state.pMap->wszName,
|
|
state.pMap->cchWName,
|
|
state.nAllocSize);
|
|
|
|
return hr;
|
|
}
|
|
|
|
virtual HRESULT GenerateResponse(IWriteStream *pStream)
|
|
{
|
|
ATLASSUME( m_stateStack.IsEmpty() == false );
|
|
ATLASSUME( m_stateStack[0].pMap != NULL );
|
|
ATLASSUME( m_stateStack[0].pvElement != NULL );
|
|
|
|
const ParseState& state = m_stateStack[0];
|
|
|
|
const _soapmap *pHeaderMap = NULL;
|
|
if (m_bClient == false)
|
|
{
|
|
const _soapmap **ppHeaderMap = GetHeaderMap();
|
|
if (ppHeaderMap != NULL)
|
|
{
|
|
pHeaderMap = ppHeaderMap[state.nAllocSize];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pHeaderMap = state.pMap;
|
|
}
|
|
|
|
const _soapmap *pFuncMap = NULL;
|
|
if (m_bClient == false)
|
|
{
|
|
pFuncMap = state.pMap;
|
|
}
|
|
else
|
|
{
|
|
const _soapmap **ppFuncMap = GetFunctionMap();
|
|
ATLENSURE_RETURN( ppFuncMap != NULL );
|
|
pFuncMap = ppFuncMap[state.nAllocSize];
|
|
}
|
|
|
|
ATLENSURE_RETURN( pFuncMap != NULL );
|
|
|
|
CRpcEncodedGenerator rpcGen;
|
|
CPADGenerator padGen;
|
|
CPIDGenerator pidGen;
|
|
|
|
CResponseGenerator *pGenerator = NULL;
|
|
|
|
if ((pFuncMap->dwCallFlags & (SOAPFLAG_RPC | SOAPFLAG_ENCODED)) == (SOAPFLAG_RPC | SOAPFLAG_ENCODED))
|
|
{
|
|
pGenerator = &rpcGen;
|
|
}
|
|
else if (pFuncMap->dwCallFlags & SOAPFLAG_PID)
|
|
{
|
|
ATLASSERT( (pFuncMap->dwCallFlags & (SOAPFLAG_DOCUMENT | SOAPFLAG_LITERAL)) == (SOAPFLAG_DOCUMENT | SOAPFLAG_LITERAL) );
|
|
pGenerator = &pidGen;
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( (pFuncMap->dwCallFlags & (SOAPFLAG_DOCUMENT | SOAPFLAG_LITERAL)) == (SOAPFLAG_DOCUMENT | SOAPFLAG_LITERAL) );
|
|
ATLASSERT( pFuncMap->dwCallFlags & SOAPFLAG_PAD );
|
|
pGenerator = &padGen;
|
|
}
|
|
|
|
HRESULT hr = pGenerator->StartEnvelope(pStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// generate headers if necessary
|
|
hr = GenerateHeaders(pGenerator, pHeaderMap, pStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pGenerator->StartBody(pStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GenerateResponseHelper(pGenerator, pFuncMap, m_pvParam, pStream, true);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pGenerator->EndBody(pStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pGenerator->EndEnvelope(pStream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
virtual void Cleanup()
|
|
{
|
|
// cleanup headers
|
|
CleanupHeaders();
|
|
|
|
if ((m_stateStack.IsEmpty() == false) && (m_pvParam != NULL))
|
|
{
|
|
const _soapmap **ppFuncMap = GetFunctionMap();
|
|
ATLENSURE( ppFuncMap != NULL );
|
|
|
|
const _soapmap *pFuncMap = ppFuncMap[m_stateStack[0].nAllocSize];
|
|
ATLENSURE( pFuncMap != NULL );
|
|
|
|
CleanupHelper(pFuncMap, m_pvParam);
|
|
if (m_bClient == false)
|
|
{
|
|
m_pMemMgr->Free(m_pvParam);
|
|
m_stateStack.RemoveAll();
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual void CleanupHeaders()
|
|
{
|
|
if (m_stateStack.IsEmpty() == false)
|
|
{
|
|
const _soapmap **ppHeaderMap = GetHeaderMap();
|
|
ATLENSURE( ppHeaderMap != NULL );
|
|
|
|
const _soapmap *pHeaderMap = ppHeaderMap[m_stateStack[0].nAllocSize];
|
|
ATLENSURE( pHeaderMap != NULL );
|
|
|
|
CleanupHelper(pHeaderMap, GetHeaderValue());
|
|
}
|
|
}
|
|
|
|
void SetClient(bool bClient)
|
|
{
|
|
m_bClient = bClient;
|
|
}
|
|
|
|
}; // class CSoapRootHandler
|
|
|
|
#define DECLARE_XSD_ENTRY( __name ) \
|
|
{ L ## __name, __name, sizeof(__name)-1 },
|
|
|
|
__declspec(selectany) const CSoapRootHandler::XSDEntry CSoapRootHandler::s_xsdNames[] =
|
|
{
|
|
DECLARE_XSD_ENTRY("string")
|
|
DECLARE_XSD_ENTRY("boolean")
|
|
DECLARE_XSD_ENTRY("float")
|
|
DECLARE_XSD_ENTRY("double")
|
|
DECLARE_XSD_ENTRY("decimal")
|
|
DECLARE_XSD_ENTRY("duration")
|
|
DECLARE_XSD_ENTRY("hexBinary")
|
|
DECLARE_XSD_ENTRY("base64Binary")
|
|
DECLARE_XSD_ENTRY("anyURI")
|
|
DECLARE_XSD_ENTRY("ID")
|
|
DECLARE_XSD_ENTRY("IDREF")
|
|
DECLARE_XSD_ENTRY("ENTITY")
|
|
DECLARE_XSD_ENTRY("NOTATION")
|
|
DECLARE_XSD_ENTRY("QName")
|
|
DECLARE_XSD_ENTRY("normalizedString")
|
|
DECLARE_XSD_ENTRY("token")
|
|
DECLARE_XSD_ENTRY("language")
|
|
DECLARE_XSD_ENTRY("IDREFS")
|
|
DECLARE_XSD_ENTRY("ENTITIES")
|
|
DECLARE_XSD_ENTRY("NMTOKEN")
|
|
DECLARE_XSD_ENTRY("NMTOKENS")
|
|
DECLARE_XSD_ENTRY("Name")
|
|
DECLARE_XSD_ENTRY("NCName")
|
|
DECLARE_XSD_ENTRY("integer")
|
|
DECLARE_XSD_ENTRY("nonPositiveInteger")
|
|
DECLARE_XSD_ENTRY("negativeInteger")
|
|
DECLARE_XSD_ENTRY("long")
|
|
DECLARE_XSD_ENTRY("int")
|
|
DECLARE_XSD_ENTRY("short")
|
|
DECLARE_XSD_ENTRY("byte")
|
|
DECLARE_XSD_ENTRY("nonNegativeInteger")
|
|
DECLARE_XSD_ENTRY("unsignedLong")
|
|
DECLARE_XSD_ENTRY("unsignedInt")
|
|
DECLARE_XSD_ENTRY("unsignedShort")
|
|
DECLARE_XSD_ENTRY("unsignedByte")
|
|
DECLARE_XSD_ENTRY("positiveInteger")
|
|
DECLARE_XSD_ENTRY("dateTime")
|
|
DECLARE_XSD_ENTRY("time")
|
|
DECLARE_XSD_ENTRY("date")
|
|
DECLARE_XSD_ENTRY("gMonth")
|
|
DECLARE_XSD_ENTRY("gYearMonth")
|
|
DECLARE_XSD_ENTRY("gYear")
|
|
DECLARE_XSD_ENTRY("gMonthDay")
|
|
DECLARE_XSD_ENTRY("gDay")
|
|
};
|
|
|
|
__declspec(selectany) CCRTHeap CSoapRootHandler::m_crtHeap;
|
|
|
|
template <typename THandler>
|
|
class CSoapHandler :
|
|
public CSoapRootHandler,
|
|
public CComObjectRootEx<CComMultiThreadModel>,
|
|
public IRequestHandlerImpl<THandler>
|
|
{
|
|
protected:
|
|
|
|
HTTP_CODE m_hcErr;
|
|
CHttpResponse *m_pHttpResponse;
|
|
|
|
// heap for SOAP requests
|
|
CWin32Heap m_heap;
|
|
|
|
// default heap is COM heap (SOAP Servers can double as COM objects)
|
|
CComHeap m_comHeap;
|
|
|
|
public:
|
|
|
|
BEGIN_COM_MAP(CSoapHandler<THandler>)
|
|
COM_INTERFACE_ENTRY(ISAXContentHandler)
|
|
COM_INTERFACE_ENTRY(IRequestHandler)
|
|
END_COM_MAP()
|
|
|
|
CSoapHandler()
|
|
:m_pHttpResponse(NULL), m_hcErr(HTTP_SUCCESS)
|
|
{
|
|
SetMemMgr(&m_comHeap);
|
|
}
|
|
|
|
void SetHttpError(HTTP_CODE hcErr)
|
|
{
|
|
m_hcErr = hcErr;
|
|
}
|
|
|
|
HRESULT SoapFault(
|
|
SOAP_ERROR_CODE errCode,
|
|
const wchar_t *wszDetail,
|
|
int cchDetail)
|
|
{
|
|
ATLASSUME( m_pHttpResponse != NULL );
|
|
|
|
SetHttpError(AtlsHttpError(500, SUBERR_NO_PROCESS));
|
|
|
|
m_pHttpResponse->ClearHeaders();
|
|
m_pHttpResponse->ClearContent();
|
|
m_pHttpResponse->SetContentType("text/xml");
|
|
m_pHttpResponse->SetStatusCode(500);
|
|
|
|
CSoapFault fault;
|
|
if (wszDetail != NULL)
|
|
{
|
|
if (cchDetail < 0)
|
|
{
|
|
cchDetail = (int) wcslen(wszDetail);
|
|
}
|
|
|
|
_ATLTRY
|
|
{
|
|
fault.m_strDetail.SetString(wszDetail, cchDetail);
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
ATLTRACE( _T("CSoapHandler::SoapFault -- out of memory.\r\n" ) );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
fault.m_soapErrCode = errCode;
|
|
fault.GenerateFault(m_pHttpResponse);
|
|
return S_OK;
|
|
}
|
|
|
|
HTTP_CODE InitializeHandler(AtlServerRequest *pRequestInfo, IServiceProvider *pProvider)
|
|
{
|
|
m_hcErr = IRequestHandlerImpl<THandler>::InitializeHandler(pRequestInfo, pProvider);
|
|
if (m_hcErr == HTTP_SUCCESS)
|
|
{
|
|
HRESULT hr = InitializeSOAP(m_spServiceProvider);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// try to use the per-thread heap
|
|
CIsapiWorker *pWorker = pRequestInfo->pExtension->GetThreadWorker();
|
|
if (pWorker != NULL)
|
|
{
|
|
m_heap.Attach(pWorker->m_hHeap, false);
|
|
SetMemMgr(&m_heap);
|
|
}
|
|
|
|
return m_hcErr;
|
|
}
|
|
}
|
|
|
|
// some initialization failure
|
|
CHttpResponse HttpResponse(pRequestInfo->pServerContext);
|
|
m_pHttpResponse = &HttpResponse;
|
|
|
|
SoapFault(SOAP_E_SERVER, NULL, 0);
|
|
|
|
m_pHttpResponse = NULL;
|
|
|
|
return m_hcErr;
|
|
}
|
|
|
|
HTTP_CODE HandleRequest(AtlServerRequest *pRequestInfo, IServiceProvider * /*pProvider*/)
|
|
{
|
|
// SOAPACTION header is required per the SOAP 1.1
|
|
// mainly so firewalls can filter on it.
|
|
char szBuf[ATL_URL_MAX_URL_LENGTH+1];
|
|
szBuf[0] = '\0';
|
|
DWORD dwLen = ATL_URL_MAX_URL_LENGTH;
|
|
if ( m_spServerContext->GetServerVariable("HTTP_SOAPACTION", szBuf, &dwLen) != FALSE )
|
|
{
|
|
if ( dwLen >= 2 )
|
|
{
|
|
// drop the last "
|
|
szBuf[dwLen-2] = '\0';
|
|
char *szMethod = strrchr(szBuf, '#');
|
|
if (szMethod != NULL)
|
|
{
|
|
_ATLTRY
|
|
{
|
|
// ignore return code here
|
|
SetSoapMapFromName(CA2W( szMethod+1 ), -1, GetNamespaceUri(), -1, true);
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// SOAP requestion that use the HTTP transport
|
|
// must have a SOAPACTION header.
|
|
return HTTP_ERROR(500, ISE_SUBERR_SOAPNOSOAPACTION);
|
|
}
|
|
|
|
// set the header map
|
|
CHttpResponse HttpResponse(pRequestInfo->pServerContext);
|
|
m_pHttpResponse = &HttpResponse;
|
|
|
|
CStreamOnServerContext s(pRequestInfo->pServerContext);
|
|
|
|
#ifdef _DEBUG
|
|
|
|
CSAXSoapErrorHandler err;
|
|
GetReader()->putErrorHandler(&err);
|
|
|
|
#endif // _DEBUG
|
|
|
|
HRESULT hr = BeginParse(&s);
|
|
|
|
#ifdef _DEBUG
|
|
// release the error handler
|
|
GetReader()->putErrorHandler(NULL);
|
|
#endif // _DEBUG
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
Cleanup();
|
|
if (m_hcErr == HTTP_SUCCESS)
|
|
{
|
|
SoapFault(SOAP_E_CLIENT, NULL, NULL);
|
|
}
|
|
|
|
return m_hcErr;
|
|
}
|
|
|
|
_ATLTRY
|
|
{
|
|
hr = CallFunctionInternal();
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
// cleanup before propagating user exception
|
|
Cleanup();
|
|
HttpResponse.Detach();
|
|
_ATLRETHROW;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
Cleanup();
|
|
HttpResponse.ClearHeaders();
|
|
HttpResponse.ClearContent();
|
|
if (m_hcErr != HTTP_SUCCESS)
|
|
{
|
|
HttpResponse.SetStatusCode(HTTP_ERROR_CODE(m_hcErr));
|
|
return HTTP_SUCCESS_NO_PROCESS;
|
|
}
|
|
HttpResponse.SetStatusCode(500);
|
|
GenerateAppError(&HttpResponse, hr);
|
|
return AtlsHttpError(500, SUBERR_NO_PROCESS);
|
|
}
|
|
|
|
HttpResponse.SetContentType("text/xml");
|
|
hr = GenerateResponse(&HttpResponse);
|
|
Cleanup();
|
|
if (FAILED(hr))
|
|
{
|
|
SoapFault(SOAP_E_SERVER, NULL, 0);
|
|
return m_hcErr;
|
|
}
|
|
|
|
return HTTP_SUCCESS;
|
|
}
|
|
|
|
virtual ATL_NOINLINE HRESULT GenerateAppError(IWriteStream *pStream, HRESULT hr)
|
|
{
|
|
if (pStream == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
LPWSTR pwszMessage = NULL;
|
|
DWORD dwLen = ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL, hr, 0, (LPWSTR) &pwszMessage, 0, NULL);
|
|
|
|
if (dwLen == 0)
|
|
{
|
|
pwszMessage = L"Application Error";
|
|
}
|
|
|
|
hr = SoapFault(SOAP_E_SERVER, pwszMessage, dwLen ? dwLen : -1);
|
|
if (dwLen != 0)
|
|
{
|
|
::LocalFree(pwszMessage);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void UninitializeHandler()
|
|
{
|
|
UninitializeSOAP();
|
|
}
|
|
};
|
|
|
|
|
|
// client error states
|
|
enum SOAPCLIENT_ERROR
|
|
{
|
|
SOAPCLIENT_SUCCESS=0, // everything succeeded
|
|
SOAPCLIENT_INITIALIZE_ERROR, // initialization failed -- most likely an MSXML installation problem
|
|
SOAPCLIENT_OUTOFMEMORY, // out of memory
|
|
SOAPCLIENT_GENERATE_ERROR, // failed in generating the response
|
|
SOAPCLIENT_CONNECT_ERROR, // failed connecting to server
|
|
SOAPCLIENT_SEND_ERROR, // failed in sending message
|
|
SOAPCLIENT_SERVER_ERROR, // server error
|
|
SOAPCLIENT_SOAPFAULT, // a SOAP Fault was returned by the server
|
|
SOAPCLIENT_PARSEFAULT_ERROR, // failed in parsing SOAP fault
|
|
SOAPCLIENT_READ_ERROR, // failed in reading response
|
|
SOAPCLIENT_PARSE_ERROR // failed in parsing response
|
|
};
|
|
|
|
template <typename TSocketClass = ZEvtSyncSocket>
|
|
class CSoapSocketClientT
|
|
{
|
|
private:
|
|
|
|
CUrl m_url;
|
|
CWriteStreamOnCString m_writeStream;
|
|
CReadStreamOnSocket<TSocketClass> m_readStream;
|
|
DWORD m_dwTimeout;
|
|
|
|
SOAPCLIENT_ERROR m_errorState;
|
|
|
|
protected:
|
|
|
|
virtual HRESULT GetClientReader(ISAXXMLReader **pReader)
|
|
{
|
|
if (pReader == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
*pReader = NULL;
|
|
|
|
CComPtr<ISAXXMLReader> spReader;
|
|
HRESULT hr = spReader.CoCreateInstance(ATLS_SAXXMLREADER_CLSID, NULL, CLSCTX_INPROC_SERVER);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pReader = spReader.Detach();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
public:
|
|
|
|
// note : not shared across stock client implementations
|
|
CAtlHttpClientT<TSocketClass> m_socket;
|
|
|
|
CSoapFault m_fault;
|
|
|
|
// constructor
|
|
CSoapSocketClientT(LPCTSTR szUrl)
|
|
: m_dwTimeout(0), m_errorState(SOAPCLIENT_SUCCESS)
|
|
{
|
|
TCHAR szTmp[ATL_URL_MAX_URL_LENGTH];
|
|
if(AtlEscapeUrl(szUrl,szTmp,0,ATL_URL_MAX_URL_LENGTH-1,ATL_URL_BROWSER_MODE))
|
|
m_url.CrackUrl(szTmp);
|
|
}
|
|
|
|
CSoapSocketClientT(LPCTSTR szServer, LPCTSTR szUri, ATL_URL_PORT nPort=80)
|
|
: m_dwTimeout(0), m_errorState(SOAPCLIENT_SUCCESS)
|
|
{
|
|
ATLASSERT( szServer != NULL );
|
|
ATLASSERT( szUri != NULL );
|
|
|
|
m_url.SetUrlPath(szUri);
|
|
m_url.SetHostName(szServer);
|
|
m_url.SetPortNumber(nPort);
|
|
}
|
|
|
|
~CSoapSocketClientT()
|
|
{
|
|
CleanupClient();
|
|
}
|
|
|
|
SOAPCLIENT_ERROR GetClientError()
|
|
{
|
|
return m_errorState;
|
|
}
|
|
|
|
void SetClientError(SOAPCLIENT_ERROR errorState)
|
|
{
|
|
m_errorState = errorState;
|
|
}
|
|
|
|
IWriteStream * GetWriteStream()
|
|
{
|
|
return &m_writeStream;
|
|
}
|
|
|
|
HRESULT GetReadStream(IStream **ppStream)
|
|
{
|
|
if (ppStream == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppStream = &m_readStream;
|
|
return S_OK;
|
|
}
|
|
|
|
void CleanupClient()
|
|
{
|
|
m_writeStream.Cleanup();
|
|
m_fault.Clear();
|
|
SetClientError(SOAPCLIENT_SUCCESS);
|
|
}
|
|
|
|
HRESULT SendRequest(LPCTSTR szAction)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
_ATLTRY
|
|
{
|
|
// create extra headers to send with request
|
|
CFixedStringT<CString, 256> strExtraHeaders(szAction);
|
|
strExtraHeaders.Append(_T("Accept: text/xml\r\n"), sizeof("Accept: text/xml\r\n")-1);
|
|
CAtlNavigateData navData;
|
|
navData.SetMethod(ATL_HTTP_METHOD_POST);
|
|
navData.SetPort(m_url.GetPortNumber());
|
|
navData.SetExtraHeaders(strExtraHeaders);
|
|
navData.SetPostData((LPBYTE)(LPCSTR) m_writeStream.m_str, m_writeStream.m_str.GetLength(), _T("text/xml; charset=utf-8"));
|
|
|
|
ATLSOAP_TRACE( (LPBYTE)(LPCSTR)m_writeStream.m_str, m_writeStream.m_str.GetLength() );
|
|
|
|
if (m_dwTimeout != 0)
|
|
{
|
|
navData.SetSocketTimeout(m_dwTimeout);
|
|
}
|
|
|
|
if (m_socket.Navigate(&m_url, &navData) != false)
|
|
{
|
|
if (GetStatusCode() == 200)
|
|
{
|
|
hr = (m_readStream.Init(&m_socket) != FALSE ? S_OK : E_FAIL);
|
|
if (hr != S_OK)
|
|
{
|
|
SetClientError(SOAPCLIENT_READ_ERROR);
|
|
}
|
|
}
|
|
else if (GetStatusCode() == 202)
|
|
{
|
|
// for one-way methods
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
SetClientError(SOAPCLIENT_SERVER_ERROR);
|
|
}
|
|
}
|
|
else if (GetStatusCode() == 500)
|
|
{
|
|
SetClientError(SOAPCLIENT_SOAPFAULT);
|
|
|
|
// if returned 500, get the SOAP fault
|
|
if (m_readStream.Init(&m_socket) != FALSE)
|
|
{
|
|
CComPtr<ISAXXMLReader> spReader;
|
|
if (SUCCEEDED(GetClientReader(&spReader)))
|
|
{
|
|
CComPtr<IStream> spReadStream;
|
|
if (SUCCEEDED(GetReadStream(&spReadStream)))
|
|
{
|
|
if (FAILED(m_fault.ParseFault(spReadStream, spReader)))
|
|
{
|
|
SetClientError(SOAPCLIENT_PARSEFAULT_ERROR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetClientError(SOAPCLIENT_SEND_ERROR);
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SetUrl(LPCTSTR szUrl)
|
|
{
|
|
TCHAR szTmp[ATL_URL_MAX_URL_LENGTH];
|
|
if(!AtlEscapeUrl(szUrl,szTmp,0,ATL_URL_MAX_URL_LENGTH-1,ATL_URL_BROWSER_MODE))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return (m_url.CrackUrl(szTmp) != FALSE) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
HRESULT GetUrl(__out_ecount_part_z(*pdwLen, *pdwLen) LPTSTR szUrl, __inout LPDWORD pdwLen)
|
|
{
|
|
if ((szUrl == NULL) || (pdwLen == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return (m_url.CreateUrl(szUrl, pdwLen) != FALSE) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
HRESULT SetProxy(LPCTSTR szProxy = NULL, short nProxyPort = 80)
|
|
{
|
|
BOOL bRet = m_socket.SetProxy(szProxy, nProxyPort);
|
|
return (bRet != FALSE) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
void SetTimeout(DWORD dwTimeout)
|
|
{
|
|
m_dwTimeout = dwTimeout;
|
|
}
|
|
|
|
int GetStatusCode()
|
|
{
|
|
return m_socket.GetStatus();
|
|
}
|
|
|
|
}; // CSoapSocketClientT
|
|
|
|
#ifndef ATLSOAP_NOWININET
|
|
|
|
class CReadStreamOnInet : public IStreamImpl
|
|
{
|
|
public:
|
|
|
|
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
|
|
if (InlineIsEqualGUID(riid, IID_IUnknown) ||
|
|
InlineIsEqualGUID(riid, IID_IStream) ||
|
|
InlineIsEqualGUID(riid, IID_ISequentialStream))
|
|
{
|
|
*ppv = static_cast<IStream *>(this);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
private:
|
|
|
|
HINTERNET m_hFile;
|
|
|
|
public:
|
|
|
|
CReadStreamOnInet()
|
|
:m_hFile(NULL)
|
|
{
|
|
}
|
|
|
|
void Init(HINTERNET hFile)
|
|
{
|
|
m_hFile = hFile;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Read(void *pDest, ULONG dwMaxLen, ULONG *pdwRead)
|
|
{
|
|
BOOL bRet = InternetReadFile(m_hFile, pDest, dwMaxLen, pdwRead);
|
|
return (bRet != FALSE) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
}; // CStreamOnInet
|
|
|
|
class CSoapWininetClient
|
|
{
|
|
private:
|
|
|
|
CUrl m_url;
|
|
CWriteStreamOnCString m_writeStream;
|
|
CReadStreamOnInet m_readStream;
|
|
CString m_strProxy;
|
|
DWORD m_dwTimeout;
|
|
CFixedStringT<CString, ATL_URL_MAX_URL_LENGTH+1> m_strUrl;
|
|
SOAPCLIENT_ERROR m_errorState;
|
|
|
|
void CloseAll()
|
|
{
|
|
if (m_hRequest != NULL)
|
|
{
|
|
InternetCloseHandle(m_hRequest);
|
|
m_hRequest = NULL;
|
|
}
|
|
if (m_hConnection != NULL)
|
|
{
|
|
InternetCloseHandle(m_hConnection);
|
|
m_hConnection = NULL;
|
|
}
|
|
if (m_hInternet != NULL)
|
|
{
|
|
InternetCloseHandle(m_hInternet);
|
|
m_hInternet = NULL;
|
|
}
|
|
}
|
|
|
|
HRESULT ConnectToServer()
|
|
{
|
|
if (m_hConnection != NULL)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
m_hInternet = InternetOpen(
|
|
ATLSOAPINET_CLIENT,
|
|
m_strProxy.GetLength() ? (INTERNET_OPEN_TYPE_PRECONFIG | INTERNET_OPEN_TYPE_PROXY) : INTERNET_OPEN_TYPE_PRECONFIG,
|
|
m_strProxy.GetLength() ? (LPCTSTR) m_strProxy : NULL,
|
|
NULL, 0);
|
|
|
|
if (m_hInternet != NULL)
|
|
{
|
|
if (m_dwTimeout != 0)
|
|
{
|
|
InternetSetOption(m_hInternet, INTERNET_OPTION_CONNECT_TIMEOUT,
|
|
&m_dwTimeout, sizeof(m_dwTimeout));
|
|
InternetSetOption(m_hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT,
|
|
&m_dwTimeout, sizeof(m_dwTimeout));
|
|
InternetSetOption(m_hInternet, INTERNET_OPTION_SEND_TIMEOUT,
|
|
&m_dwTimeout, sizeof(m_dwTimeout));
|
|
}
|
|
m_hConnection = InternetConnect(m_hInternet, m_url.GetHostName(),
|
|
(INTERNET_PORT) m_url.GetPortNumber(), NULL, NULL,
|
|
INTERNET_SERVICE_HTTP, 0, NULL);
|
|
|
|
if (m_hConnection != NULL)
|
|
{
|
|
return S_OK;
|
|
}
|
|
}
|
|
CloseAll();
|
|
return E_FAIL;
|
|
}
|
|
|
|
protected:
|
|
|
|
virtual HRESULT GetClientReader(ISAXXMLReader **pReader)
|
|
{
|
|
if (pReader == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
*pReader = NULL;
|
|
|
|
CComPtr<ISAXXMLReader> spReader;
|
|
HRESULT hr = spReader.CoCreateInstance(ATLS_SAXXMLREADER_CLSID, NULL, CLSCTX_INPROC_SERVER);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pReader = spReader.Detach();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
public:
|
|
|
|
// note : not shared across stock client implementations
|
|
HINTERNET m_hInternet;
|
|
HINTERNET m_hConnection;
|
|
HINTERNET m_hRequest;
|
|
|
|
CSoapFault m_fault;
|
|
|
|
CSoapWininetClient(LPCTSTR szUrl)
|
|
:m_hInternet(NULL), m_hConnection(NULL), m_hRequest(NULL), m_dwTimeout(0), m_errorState(SOAPCLIENT_SUCCESS)
|
|
{
|
|
TCHAR szTmp[ATL_URL_MAX_URL_LENGTH];
|
|
if(AtlEscapeUrl(szUrl,szTmp,0,ATL_URL_MAX_URL_LENGTH-1,ATL_URL_BROWSER_MODE))
|
|
{
|
|
if (m_url.CrackUrl(szTmp) != FALSE)
|
|
{
|
|
SetProxy();
|
|
_ATLTRY
|
|
{
|
|
m_strUrl.SetString(m_url.GetUrlPath(), m_url.GetUrlPathLength());
|
|
m_strUrl.Append(m_url.GetExtraInfo(), m_url.GetExtraInfoLength());
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CSoapWininetClient(LPCTSTR szServer, LPCTSTR szUri, short nPort=80)
|
|
:m_hInternet(NULL), m_hConnection(NULL), m_hRequest(NULL), m_dwTimeout(0), m_errorState(SOAPCLIENT_SUCCESS)
|
|
{
|
|
if (m_url.SetHostName(szServer) != FALSE)
|
|
{
|
|
if (m_url.SetUrlPath(szUri) != FALSE)
|
|
{
|
|
if (m_url.SetPortNumber((ATL_URL_PORT) nPort) != FALSE)
|
|
{
|
|
_ATLTRY
|
|
{
|
|
m_strUrl.SetString(m_url.GetUrlPath(), m_url.GetUrlPathLength());
|
|
m_strUrl.Append(m_url.GetExtraInfo(), m_url.GetExtraInfoLength());
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual ~CSoapWininetClient()
|
|
{
|
|
CleanupClient();
|
|
CloseAll();
|
|
}
|
|
|
|
SOAPCLIENT_ERROR GetClientError()
|
|
{
|
|
return m_errorState;
|
|
}
|
|
|
|
void SetClientError(SOAPCLIENT_ERROR errorState)
|
|
{
|
|
m_errorState = errorState;
|
|
}
|
|
|
|
IWriteStream * GetWriteStream()
|
|
{
|
|
return &m_writeStream;
|
|
}
|
|
|
|
HRESULT GetReadStream(IStream **ppStream)
|
|
{
|
|
if (ppStream == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppStream = &m_readStream;
|
|
return S_OK;
|
|
}
|
|
|
|
void CleanupClient()
|
|
{
|
|
m_writeStream.Cleanup();
|
|
if (m_hRequest != NULL)
|
|
{
|
|
InternetCloseHandle(m_hRequest);
|
|
m_hRequest = NULL;
|
|
}
|
|
m_fault.Clear();
|
|
SetClientError(SOAPCLIENT_SUCCESS);
|
|
}
|
|
|
|
HRESULT SendRequest(LPCTSTR szAction)
|
|
{
|
|
if (ConnectToServer() != S_OK)
|
|
{
|
|
SetClientError(SOAPCLIENT_CONNECT_ERROR);
|
|
return E_FAIL;
|
|
}
|
|
|
|
CString strHeaders;
|
|
_ATLTRY
|
|
{
|
|
strHeaders.Append(szAction);
|
|
strHeaders.Append(_T("Content-Type: text/xml; charset=utf-8\r\n"));
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
static LPCTSTR s_szAcceptTypes[] = { _T("text/*"), NULL };
|
|
m_hRequest = HttpOpenRequest(m_hConnection, _T("POST"),
|
|
m_strUrl, _T("HTTP/1.0"), NULL,
|
|
s_szAcceptTypes,
|
|
INTERNET_FLAG_NO_UI | INTERNET_FLAG_KEEP_CONNECTION | ((m_url.GetScheme() == ATL_URL_SCHEME_HTTPS) ? INTERNET_FLAG_SECURE : 0)
|
|
, NULL);
|
|
|
|
if (m_hRequest != NULL)
|
|
{
|
|
if (FALSE != HttpSendRequest(m_hRequest, strHeaders, (DWORD) strHeaders.GetLength(),
|
|
(void *)(LPCSTR)m_writeStream.m_str, m_writeStream.m_str.GetLength()))
|
|
{
|
|
m_readStream.Init(m_hRequest);
|
|
if (GetStatusCode() != HTTP_STATUS_SERVER_ERROR)
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
SetClientError(SOAPCLIENT_SOAPFAULT);
|
|
|
|
CComPtr<ISAXXMLReader> spReader;
|
|
if (SUCCEEDED(GetClientReader(&spReader)))
|
|
{
|
|
CComPtr<IStream> spReadStream;
|
|
if (SUCCEEDED(GetReadStream(&spReadStream)))
|
|
{
|
|
if (FAILED(m_fault.ParseFault(spReadStream, spReader)))
|
|
{
|
|
SetClientError(SOAPCLIENT_PARSEFAULT_ERROR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetClientError(SOAPCLIENT_SEND_ERROR);
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT SetUrl(LPCTSTR szUrl)
|
|
{
|
|
CloseAll();
|
|
TCHAR szTmp[ATL_URL_MAX_URL_LENGTH];
|
|
if(!AtlEscapeUrl(szUrl,szTmp,0,ATL_URL_MAX_URL_LENGTH-1,ATL_URL_BROWSER_MODE))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (m_url.CrackUrl(szTmp) != FALSE)
|
|
{
|
|
_ATLTRY
|
|
{
|
|
m_strUrl.SetString(m_url.GetUrlPath(), m_url.GetUrlPathLength());
|
|
m_strUrl.Append(m_url.GetExtraInfo(), m_url.GetExtraInfoLength());
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
return S_OK;
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT GetUrl(LPTSTR szUrl, LPDWORD pdwLen)
|
|
{
|
|
if ((szUrl == NULL) || (pdwLen == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return (m_url.CreateUrl(szUrl, pdwLen) != FALSE) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
HRESULT SetProxy(LPCTSTR szProxy = NULL, short nProxyPort = 80)
|
|
{
|
|
_ATLTRY
|
|
{
|
|
if (szProxy && szProxy[0])
|
|
{
|
|
m_strProxy.Format(_T("http=http://%s:%d https=http://%s:%d"), szProxy, nProxyPort, szProxy, nProxyPort);
|
|
}
|
|
else
|
|
{
|
|
m_strProxy.Empty();
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void SetTimeout(DWORD dwTimeout)
|
|
{
|
|
m_dwTimeout = dwTimeout;
|
|
}
|
|
|
|
int GetStatusCode()
|
|
{
|
|
DWORD dwLen = 255;
|
|
TCHAR szBuf[256];
|
|
if (HttpQueryInfo(m_hRequest, HTTP_QUERY_STATUS_CODE, szBuf, &dwLen, NULL))
|
|
{
|
|
szBuf[dwLen] = '\0';
|
|
return _ttoi(szBuf);
|
|
}
|
|
return 0;
|
|
}
|
|
}; // CSoapWininetClient
|
|
#endif
|
|
|
|
#ifndef ATLSOAP_NOMSXML_INET
|
|
class CSoapMSXMLInetClient
|
|
{
|
|
private:
|
|
|
|
CUrl m_url;
|
|
CWriteStreamOnCString m_writeStream;
|
|
DWORD m_dwTimeout;
|
|
SOAPCLIENT_ERROR m_errorState;
|
|
|
|
HRESULT ConnectToServer()
|
|
{
|
|
TCHAR szURL[ATL_URL_MAX_URL_LENGTH];
|
|
DWORD dwLen = ATL_URL_MAX_URL_LENGTH;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (m_spHttpRequest)
|
|
return S_OK;
|
|
|
|
if (!m_url.CreateUrl(szURL, &dwLen))
|
|
return E_FAIL;
|
|
|
|
|
|
hr = m_spHttpRequest.CoCreateInstance(__uuidof(ServerXMLHTTP30));
|
|
if (hr != S_OK)
|
|
return hr;
|
|
|
|
CComVariant vEmpty;
|
|
hr = m_spHttpRequest->open( CComBSTR(L"POST"),
|
|
CComBSTR(szURL),
|
|
CComVariant(VARIANT_BOOL(VARIANT_FALSE)),
|
|
vEmpty,
|
|
vEmpty );
|
|
if (hr != S_OK)
|
|
{
|
|
m_spHttpRequest.Release();
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
protected:
|
|
|
|
virtual HRESULT GetClientReader(ISAXXMLReader **pReader)
|
|
{
|
|
if (pReader == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
*pReader = NULL;
|
|
|
|
CComPtr<ISAXXMLReader> spReader;
|
|
HRESULT hr = spReader.CoCreateInstance(ATLS_SAXXMLREADER_CLSID, NULL, CLSCTX_INPROC_SERVER);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pReader = spReader.Detach();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
public:
|
|
|
|
// note : not shared across stock client implementations
|
|
CComPtr<IServerXMLHTTPRequest> m_spHttpRequest;
|
|
|
|
CSoapFault m_fault;
|
|
|
|
CSoapMSXMLInetClient(LPCTSTR szUrl)
|
|
:m_dwTimeout(0), m_errorState(SOAPCLIENT_SUCCESS)
|
|
{
|
|
m_url.CrackUrl(szUrl);
|
|
}
|
|
|
|
CSoapMSXMLInetClient(LPCTSTR szServer, LPCTSTR szUri, short nPort=80)
|
|
: m_dwTimeout(0), m_errorState(SOAPCLIENT_SUCCESS)
|
|
{
|
|
m_url.SetHostName(szServer);
|
|
m_url.SetUrlPath(szUri);
|
|
m_url.SetPortNumber((ATL_URL_PORT) nPort);
|
|
}
|
|
|
|
virtual ~CSoapMSXMLInetClient()
|
|
{
|
|
CleanupClient();
|
|
}
|
|
|
|
SOAPCLIENT_ERROR GetClientError()
|
|
{
|
|
return m_errorState;
|
|
}
|
|
|
|
void SetClientError(SOAPCLIENT_ERROR errorState)
|
|
{
|
|
m_errorState = errorState;
|
|
}
|
|
|
|
IWriteStream * GetWriteStream()
|
|
{
|
|
return &m_writeStream;
|
|
}
|
|
|
|
HRESULT GetReadStream(IStream **ppStream)
|
|
{
|
|
if (ppStream == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppStream = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (m_spHttpRequest)
|
|
{
|
|
VARIANT vResponseStream;
|
|
VariantInit(&vResponseStream);
|
|
hr = m_spHttpRequest->get_responseStream(&vResponseStream);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = E_FAIL;
|
|
if ((vResponseStream.vt == VT_UNKNOWN) && (vResponseStream.punkVal != NULL))
|
|
{
|
|
// we return the refcount with the pointer!
|
|
hr = vResponseStream.punkVal->QueryInterface(__uuidof(IStream), (void **)ppStream);
|
|
}
|
|
else
|
|
{
|
|
SetClientError(SOAPCLIENT_READ_ERROR);
|
|
}
|
|
}
|
|
VariantClear(&vResponseStream);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
void CleanupClient()
|
|
{
|
|
m_writeStream.Cleanup();
|
|
m_spHttpRequest.Release();
|
|
m_fault.Clear();
|
|
SetClientError(SOAPCLIENT_SUCCESS);
|
|
}
|
|
|
|
HRESULT SendRequest(LPCTSTR szAction)
|
|
{
|
|
if (ConnectToServer() != S_OK)
|
|
{
|
|
SetClientError(SOAPCLIENT_CONNECT_ERROR);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// set the action header
|
|
LPCTSTR szColon = _tcschr(szAction, _T(':'));
|
|
if (szColon != NULL)
|
|
{
|
|
do
|
|
{
|
|
szColon++;
|
|
} while (_istspace(static_cast<unsigned char>(*szColon)));
|
|
|
|
if (FAILED(m_spHttpRequest->setRequestHeader(
|
|
CComBSTR( L"SOAPAction" ), CComBSTR( szColon ))))
|
|
{
|
|
SetClientError(SOAPCLIENT_SEND_ERROR);
|
|
return E_FAIL;
|
|
}
|
|
} // if SOAPAction header not properly formed, attempt to send anyway
|
|
|
|
if (FAILED(m_spHttpRequest->setRequestHeader(CComBSTR( L"Content-Type" ), CComBSTR(L"text/xml; charset=utf-8"))))
|
|
{
|
|
SetClientError(SOAPCLIENT_SEND_ERROR);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// set timeout
|
|
if (m_dwTimeout != 0)
|
|
{
|
|
long nTimeout = (long) m_dwTimeout;
|
|
m_spHttpRequest->setTimeouts(nTimeout, nTimeout, nTimeout, nTimeout);
|
|
// reset timeout
|
|
m_dwTimeout = 0;
|
|
}
|
|
|
|
CComVariant vBody(m_writeStream.m_str);
|
|
HRESULT hr = m_spHttpRequest->send(vBody);
|
|
if ((SUCCEEDED(hr)) && (GetStatusCode() == 500))
|
|
{
|
|
hr = E_FAIL;
|
|
CComPtr<ISAXXMLReader> spReader;
|
|
if (SUCCEEDED(GetClientReader(&spReader)))
|
|
{
|
|
SetClientError(SOAPCLIENT_SOAPFAULT);
|
|
|
|
CComPtr<IStream> spReadStream;
|
|
if (SUCCEEDED(GetReadStream(&spReadStream)))
|
|
{
|
|
if (FAILED(m_fault.ParseFault(spReadStream, spReader)))
|
|
{
|
|
SetClientError(SOAPCLIENT_PARSEFAULT_ERROR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (FAILED(hr))
|
|
{
|
|
SetClientError(SOAPCLIENT_SEND_ERROR);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SetUrl(LPCTSTR szUrl)
|
|
{
|
|
CleanupClient();
|
|
return (m_url.CrackUrl(szUrl) != FALSE ? S_OK : E_FAIL);
|
|
}
|
|
|
|
HRESULT GetUrl(LPTSTR szUrl, LPDWORD pdwLen)
|
|
{
|
|
if ((szUrl == NULL) || (pdwLen == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return (m_url.CreateUrl(szUrl, pdwLen) != FALSE) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
void SetTimeout(DWORD dwTimeout)
|
|
{
|
|
m_dwTimeout = dwTimeout;
|
|
}
|
|
|
|
int GetStatusCode()
|
|
{
|
|
long lStatus;
|
|
if (m_spHttpRequest->get_status(&lStatus) == S_OK)
|
|
{
|
|
return (int) lStatus;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
HRESULT SetProxy(LPCTSTR szProxy = NULL, short nProxyPort = 80)
|
|
{
|
|
(szProxy);
|
|
(nProxyPort);
|
|
|
|
ATLTRACE( _T("CSoapMSXMLInetClient does not support SetProxy") );
|
|
|
|
return S_OK;
|
|
}
|
|
}; // CSoapMSXMLInetClient
|
|
#endif
|
|
|
|
|
|
class _CSDLGenerator : public ITagReplacerImpl<_CSDLGenerator>
|
|
{
|
|
private:
|
|
|
|
typedef CAtlMap<CStringA, const _soapmap *, CStringElementTraits<CStringA> > WSDLMAP;
|
|
typedef CAtlMap<CStringA, const _soapmapentry *, CStringElementTraits<CStringA> > HEADERMAP;
|
|
|
|
HRESULT GenerateWSDLHelper(const _soapmap *pMap, WSDLMAP& structMap, WSDLMAP& enumMap)
|
|
{
|
|
ATLENSURE_RETURN( pMap != NULL );
|
|
|
|
const _soapmapentry *pEntries = pMap->pEntries;
|
|
ATLENSURE_RETURN( pEntries != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
for (int i=0; pEntries[i].nHash != 0; i++)
|
|
{
|
|
if (pEntries[i].nVal == SOAPTYPE_UNK)
|
|
{
|
|
ATLENSURE_RETURN( pEntries[i].pChain != NULL );
|
|
|
|
_ATLTRY
|
|
{
|
|
POSITION pos = NULL;
|
|
CStringA strName(pEntries[i].pChain->szName, pEntries[i].pChain->cchName);
|
|
if (pEntries[i].pChain->mapType == SOAPMAP_STRUCT)
|
|
{
|
|
pos = structMap.SetAt(strName, pEntries[i].pChain);
|
|
}
|
|
else if (pEntries[i].pChain->mapType == SOAPMAP_ENUM)
|
|
{
|
|
pos = enumMap.SetAt(strName, pEntries[i].pChain);
|
|
}
|
|
if (pos == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
hr = GenerateWSDLHelper(pEntries[i].pChain, structMap, enumMap);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HTTP_CODE IsUDT(const _soapmapentry *pEntry)
|
|
{
|
|
ATLENSURE( pEntry != NULL );
|
|
return (pEntry->nVal != SOAPTYPE_UNK) ? HTTP_S_FALSE : HTTP_SUCCESS;
|
|
}
|
|
|
|
HTTP_CODE GetSoapDims(const _soapmapentry *pEntry)
|
|
{
|
|
ATLENSURE( pEntry != NULL );
|
|
if (pEntry->pDims[0] != 0)
|
|
{
|
|
if (SUCCEEDED(m_pWriteStream->WriteStream("[", 1, NULL)))
|
|
{
|
|
for (int i=1; i<=pEntry->pDims[0]; i++)
|
|
{
|
|
if (m_writeHelper.Write(pEntry->pDims[i]) != FALSE)
|
|
{
|
|
if (i < pEntry->pDims[0])
|
|
{
|
|
if (FAILED(m_pWriteStream->WriteStream(", ", 2, NULL)))
|
|
{
|
|
return HTTP_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (SUCCEEDED(m_pWriteStream->WriteStream("]", 1, NULL)))
|
|
{
|
|
return HTTP_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
return HTTP_FAIL;
|
|
}
|
|
|
|
const _soapmap **m_pFuncs;
|
|
const _soapmap **m_pHeaders;
|
|
int m_nFunc;
|
|
int m_nParam;
|
|
int m_nHeader;
|
|
WSDLMAP m_structMap;
|
|
WSDLMAP m_enumMap;
|
|
POSITION m_currUDTPos;
|
|
int m_nCurrUDTField;
|
|
|
|
HEADERMAP m_headerMap;
|
|
POSITION m_currHeaderPos;
|
|
|
|
CWriteStreamHelper m_writeHelper;
|
|
|
|
CStringA m_strServiceName;
|
|
CStringA m_strNamespaceUri;
|
|
|
|
IWriteStream *m_pWriteStream;
|
|
|
|
CComPtr<IHttpServerContext> m_spHttpServerContext;
|
|
|
|
DWORD m_dwCallFlags;
|
|
|
|
protected:
|
|
|
|
void SetWriteStream(IWriteStream *pStream)
|
|
{
|
|
m_pWriteStream = pStream;
|
|
m_writeHelper.Attach(m_pWriteStream);
|
|
}
|
|
|
|
void SetHttpServerContext(IHttpServerContext *pServerContext)
|
|
{
|
|
m_spHttpServerContext = pServerContext;
|
|
}
|
|
|
|
static HTTP_CODE GetSoapType(int nVal, IWriteStream *pStream)
|
|
{
|
|
return (pStream->WriteStream(CSoapRootHandler::s_xsdNames[nVal].szName,
|
|
CSoapRootHandler::s_xsdNames[nVal].cchName, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT InitializeSDL(CSoapRootHandler *pHdlr)
|
|
{
|
|
m_pFuncs = pHdlr->GetFunctionMap();
|
|
|
|
if (m_pFuncs == NULL)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
ATLASSUME( m_pFuncs[0] != NULL );
|
|
|
|
m_dwCallFlags = m_pFuncs[0]->dwCallFlags;
|
|
|
|
size_t i;
|
|
for (i=0; m_pFuncs[i] != NULL; i++)
|
|
{
|
|
const _soapmap *pMap = m_pFuncs[i];
|
|
HRESULT hr = GenerateWSDLHelper(pMap, m_structMap, m_enumMap);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
m_pHeaders = pHdlr->GetHeaderMap();
|
|
if (m_pHeaders != NULL)
|
|
{
|
|
for (i=0; m_pHeaders[i] != NULL; i++)
|
|
{
|
|
const _soapmap *pMap = m_pHeaders[i];
|
|
HRESULT hr = GenerateWSDLHelper(pMap, m_structMap, m_enumMap);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
for (i=0; m_pHeaders[i] != NULL; i++)
|
|
{
|
|
const _soapmap *pMap = m_pHeaders[i];
|
|
for (size_t j=0; pMap->pEntries[j].nHash != 0; j++)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
_ATLTRY
|
|
{
|
|
if (m_headerMap.SetAt(pMap->pEntries[j].szField, &pMap->pEntries[j]) == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_ATLTRY
|
|
{
|
|
m_strServiceName = pHdlr->GetServiceName();
|
|
m_strNamespaceUri = pHdlr->GetNamespaceUriA();
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
virtual const char * GetHandlerName() = 0;
|
|
|
|
public:
|
|
|
|
_CSDLGenerator()
|
|
:m_pFuncs(NULL), m_nFunc(-1), m_nParam(-1),
|
|
m_currUDTPos(NULL), m_nCurrUDTField(-1),
|
|
m_pWriteStream(NULL), m_nHeader(-1), m_currHeaderPos(NULL)
|
|
{
|
|
}
|
|
virtual ~_CSDLGenerator()
|
|
{
|
|
}
|
|
|
|
HTTP_CODE OnGetURL()
|
|
{
|
|
char szURL[ATL_URL_MAX_URL_LENGTH];
|
|
DWORD dwUrlSize = sizeof(szURL);
|
|
char szServer[ATL_URL_MAX_HOST_NAME_LENGTH];
|
|
DWORD dwServerSize = sizeof(szServer);
|
|
char szHttps[16];
|
|
DWORD dwHttpsLen = sizeof(szHttps);
|
|
char szPort[ATL_URL_MAX_PORT_NUMBER_LENGTH+1];
|
|
DWORD dwPortLen = sizeof(szPort);
|
|
|
|
if (m_spHttpServerContext->GetServerVariable("URL", szURL, &dwUrlSize) != FALSE)
|
|
{
|
|
if (m_spHttpServerContext->GetServerVariable("SERVER_NAME", szServer, &dwServerSize) != FALSE)
|
|
{
|
|
bool bHttps = false;
|
|
if ((m_spHttpServerContext->GetServerVariable("HTTPS", szHttps, &dwHttpsLen) != FALSE) &&
|
|
(!_stricmp(szHttps, "ON")))
|
|
{
|
|
bHttps = true;
|
|
}
|
|
|
|
if (m_spHttpServerContext->GetServerVariable("SERVER_PORT", szPort, &dwPortLen) != FALSE)
|
|
{
|
|
_ATLTRY
|
|
{
|
|
CStringA strUrl;
|
|
strUrl.Format("http%s://%s:%s%s?Handler=%s", bHttps ? "s" : "", szServer, szPort, szURL, GetHandlerName());
|
|
|
|
CA2W wszUrl(strUrl);
|
|
wchar_t *pwszUrl = wszUrl;
|
|
HRESULT hr = AtlGenXMLValue(m_pWriteStream, &pwszUrl);
|
|
return SUCCEEDED(hr) ? HTTP_SUCCESS : HTTP_FAIL;
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return HTTP_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return HTTP_FAIL;
|
|
}
|
|
|
|
HTTP_CODE OnGetNamespace()
|
|
{
|
|
return (m_pWriteStream->WriteStream(m_strNamespaceUri,
|
|
m_strNamespaceUri.GetLength(), NULL) == S_OK) ? HTTP_SUCCESS : HTTP_FAIL;
|
|
}
|
|
|
|
HTTP_CODE OnGetNextFunction()
|
|
{
|
|
m_nFunc++;
|
|
if (m_pFuncs[m_nFunc] == NULL)
|
|
{
|
|
m_nFunc = -1;
|
|
return HTTP_S_FALSE;
|
|
}
|
|
return HTTP_SUCCESS;
|
|
}
|
|
|
|
HTTP_CODE OnGetFunctionName()
|
|
{
|
|
return (m_pWriteStream->WriteStream(m_pFuncs[m_nFunc]->szName,
|
|
m_pFuncs[m_nFunc]->cchName, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetNextParameter()
|
|
{
|
|
++m_nParam;
|
|
if (m_pFuncs[m_nFunc]->pEntries[m_nParam].nHash != 0)
|
|
{
|
|
if (m_pFuncs[m_nFunc]->pEntries[m_nParam].dwFlags & SOAPFLAG_NOMARSHAL)
|
|
{
|
|
return OnGetNextParameter();
|
|
}
|
|
return HTTP_SUCCESS;
|
|
}
|
|
m_nParam = -1;
|
|
return HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsInParameter()
|
|
{
|
|
return (m_pFuncs[m_nFunc]->pEntries[m_nParam].dwFlags & SOAPFLAG_IN) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetParameterName()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (m_pFuncs[m_nFunc]->pEntries[m_nParam].dwFlags & SOAPFLAG_RETVAL)
|
|
{
|
|
hr = m_pWriteStream->WriteStream("return", sizeof("return")-1, NULL);
|
|
}
|
|
else
|
|
{
|
|
hr = m_pWriteStream->WriteStream(m_pFuncs[m_nFunc]->pEntries[m_nParam].szField,
|
|
m_pFuncs[m_nFunc]->pEntries[m_nParam].cchField, NULL);
|
|
}
|
|
|
|
return (hr == S_OK) ? HTTP_SUCCESS : HTTP_FAIL;
|
|
}
|
|
|
|
HTTP_CODE OnNotIsArrayParameter()
|
|
{
|
|
return (m_pFuncs[m_nFunc]->pEntries[m_nParam].dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR))
|
|
? HTTP_S_FALSE: HTTP_SUCCESS;
|
|
}
|
|
|
|
HTTP_CODE OnIsParameterUDT()
|
|
{
|
|
return IsUDT(&m_pFuncs[m_nFunc]->pEntries[m_nParam]);
|
|
}
|
|
|
|
HTTP_CODE OnGetParameterSoapType()
|
|
{
|
|
if (m_pFuncs[m_nFunc]->pEntries[m_nParam].nVal != SOAPTYPE_UNK)
|
|
{
|
|
return GetSoapType(m_pFuncs[m_nFunc]->pEntries[m_nParam].nVal, m_pWriteStream);
|
|
}
|
|
ATLASSUME( m_pFuncs[m_nFunc]->pEntries[m_nParam].pChain != NULL );
|
|
return (m_pWriteStream->WriteStream(m_pFuncs[m_nFunc]->pEntries[m_nParam].pChain->szName,
|
|
m_pFuncs[m_nFunc]->pEntries[m_nParam].pChain->cchName, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsParameterDynamicArray()
|
|
{
|
|
return (m_pFuncs[m_nFunc]->pEntries[m_nParam].dwFlags & SOAPFLAG_DYNARR) ? HTTP_SUCCESS: HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsArrayParameter()
|
|
{
|
|
return (OnNotIsArrayParameter() != HTTP_SUCCESS) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsParameterOneDimensional()
|
|
{
|
|
return (m_pFuncs[m_nFunc]->pEntries[m_nParam].pDims[0] == 1) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetParameterArraySize()
|
|
{
|
|
return (m_writeHelper.Write(m_pFuncs[m_nFunc]->pEntries[m_nParam].pDims[1]) != FALSE)
|
|
? HTTP_SUCCESS : HTTP_FAIL;
|
|
}
|
|
|
|
HTTP_CODE OnGetParameterArraySoapDims()
|
|
{
|
|
return GetSoapDims(&m_pFuncs[m_nFunc]->pEntries[m_nParam]);
|
|
}
|
|
|
|
HTTP_CODE OnIsOutParameter()
|
|
{
|
|
return (m_pFuncs[m_nFunc]->pEntries[m_nParam].dwFlags & SOAPFLAG_OUT) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetNextEnum()
|
|
{
|
|
if (m_currUDTPos == NULL)
|
|
{
|
|
m_currUDTPos = m_enumMap.GetStartPosition();
|
|
}
|
|
else
|
|
{
|
|
m_enumMap.GetNext(m_currUDTPos);
|
|
}
|
|
|
|
return (m_currUDTPos != NULL) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetEnumName()
|
|
{
|
|
const _soapmap *pMap = m_enumMap.GetValueAt(m_currUDTPos);
|
|
return (m_pWriteStream->WriteStream(pMap->szName, pMap->cchName, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetNextEnumElement()
|
|
{
|
|
const _soapmap *pMap = m_enumMap.GetValueAt(m_currUDTPos);
|
|
++m_nCurrUDTField;
|
|
if (pMap->pEntries[m_nCurrUDTField].nHash != 0)
|
|
{
|
|
return HTTP_SUCCESS;
|
|
}
|
|
m_nCurrUDTField = -1;
|
|
return HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetEnumElementName()
|
|
{
|
|
const _soapmap *pMap = m_enumMap.GetValueAt(m_currUDTPos);
|
|
return (m_pWriteStream->WriteStream(pMap->pEntries[m_nCurrUDTField].szField,
|
|
pMap->pEntries[m_nCurrUDTField].cchField, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetNextStruct()
|
|
{
|
|
if (m_currUDTPos == NULL)
|
|
{
|
|
m_currUDTPos = m_structMap.GetStartPosition();
|
|
}
|
|
else
|
|
{
|
|
m_structMap.GetNext(m_currUDTPos);
|
|
}
|
|
|
|
return (m_currUDTPos != NULL) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetStructName()
|
|
{
|
|
const _soapmap *pMap = m_enumMap.GetValueAt(m_currUDTPos);
|
|
return (m_pWriteStream->WriteStream(pMap->szName, pMap->cchName, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetNextStructField()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
++m_nCurrUDTField;
|
|
if (pMap->pEntries[m_nCurrUDTField].nHash != 0)
|
|
{
|
|
return HTTP_SUCCESS;
|
|
}
|
|
m_nCurrUDTField = -1;
|
|
return HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetStructFieldName()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
return (m_pWriteStream->WriteStream(pMap->pEntries[m_nCurrUDTField].szField,
|
|
pMap->pEntries[m_nCurrUDTField].cchField, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnNotIsArrayField()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
return (pMap->pEntries[m_nCurrUDTField].dwFlags & (SOAPFLAG_FIXEDARR | SOAPFLAG_DYNARR)) ? HTTP_S_FALSE : HTTP_SUCCESS;
|
|
}
|
|
|
|
HTTP_CODE OnIsFieldUDT()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
return IsUDT(&pMap->pEntries[m_nCurrUDTField]);
|
|
}
|
|
|
|
HTTP_CODE OnGetStructFieldSoapType()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
if (pMap->pEntries[m_nCurrUDTField].nVal != SOAPTYPE_UNK)
|
|
{
|
|
return GetSoapType(pMap->pEntries[m_nCurrUDTField].nVal, m_pWriteStream);
|
|
}
|
|
ATLASSERT( pMap->pEntries[m_nCurrUDTField].pChain != NULL );
|
|
return (m_pWriteStream->WriteStream(pMap->pEntries[m_nCurrUDTField].pChain->szName,
|
|
pMap->pEntries[m_nCurrUDTField].pChain->cchName, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsArrayField()
|
|
{
|
|
return (OnNotIsArrayField() != HTTP_SUCCESS) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsFieldDynamicArray()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
return (pMap->pEntries[m_nCurrUDTField].dwFlags & SOAPFLAG_DYNARR) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetFieldSizeIsName()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
int nIndex = pMap->pEntries[m_nCurrUDTField].nSizeIs;
|
|
ATLASSERT( nIndex >= 0 );
|
|
return (m_pStream->WriteStream(pMap->pEntries[nIndex].szField,
|
|
pMap->pEntries[nIndex].cchField, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsFieldOneDimensional()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
return (pMap->pEntries[m_nCurrUDTField].pDims[0] == 1) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetFieldArraySize()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
return (m_writeHelper.Write(pMap->pEntries[m_nCurrUDTField].pDims[1]) != FALSE) ?
|
|
HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetFieldArraySoapDims()
|
|
{
|
|
const _soapmap *pMap = m_structMap.GetValueAt(m_currUDTPos);
|
|
return GetSoapDims(&pMap->pEntries[m_nCurrUDTField]);
|
|
}
|
|
|
|
HTTP_CODE OnGetServiceName()
|
|
{
|
|
return (m_pWriteStream->WriteStream(m_strServiceName,
|
|
m_strServiceName.GetLength(), NULL) == S_OK) ? HTTP_SUCCESS : HTTP_FAIL;
|
|
}
|
|
|
|
HTTP_CODE OnGetNextHeader()
|
|
{
|
|
if (m_currHeaderPos == NULL)
|
|
{
|
|
m_currHeaderPos = m_headerMap.GetStartPosition();
|
|
}
|
|
else
|
|
{
|
|
m_headerMap.GetNext(m_currHeaderPos);
|
|
}
|
|
|
|
return (m_currHeaderPos != NULL) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsInHeader()
|
|
{
|
|
return (m_pHeaders[m_nFunc]->pEntries[m_nHeader].dwFlags & SOAPFLAG_IN)
|
|
? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsOutHeader()
|
|
{
|
|
return (m_pHeaders[m_nFunc]->pEntries[m_nHeader].dwFlags & SOAPFLAG_OUT)
|
|
? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsRequiredHeader()
|
|
{
|
|
return (m_pHeaders[m_nFunc]->pEntries[m_nHeader].dwFlags & SOAPFLAG_MUSTUNDERSTAND)
|
|
? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetHeaderName()
|
|
{
|
|
const _soapmapentry *pEntry = m_headerMap.GetValueAt(m_currHeaderPos);
|
|
return (m_pWriteStream->WriteStream(pEntry->szField,
|
|
pEntry->cchField, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_FAIL;
|
|
}
|
|
|
|
HTTP_CODE OnNotIsArrayHeader()
|
|
{
|
|
const _soapmapentry *pEntry = m_headerMap.GetValueAt(m_currHeaderPos);
|
|
return (pEntry->dwFlags & SOAPFLAG_FIXEDARR) ? HTTP_S_FALSE : HTTP_SUCCESS;
|
|
}
|
|
|
|
HTTP_CODE OnIsHeaderUDT()
|
|
{
|
|
return IsUDT(m_headerMap.GetValueAt(m_currHeaderPos));
|
|
}
|
|
|
|
HTTP_CODE OnGetHeaderSoapType()
|
|
{
|
|
const _soapmapentry *pEntry = m_headerMap.GetValueAt(m_currHeaderPos);
|
|
if (pEntry->nVal != SOAPTYPE_UNK)
|
|
{
|
|
return GetSoapType(pEntry->nVal, m_pWriteStream);
|
|
}
|
|
ATLENSURE( pEntry->pChain != NULL );
|
|
return (m_pWriteStream->WriteStream(pEntry->pChain->szName,
|
|
pEntry->pChain->cchName, NULL) == S_OK) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsHeaderOneDimensional()
|
|
{
|
|
const _soapmapentry *pEntry = m_headerMap.GetValueAt(m_currHeaderPos);
|
|
return (pEntry->pDims[0] == 1) ? HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetHeaderArraySize()
|
|
{
|
|
const _soapmapentry *pEntry = m_headerMap.GetValueAt(m_currHeaderPos);
|
|
return (m_writeHelper.Write(pEntry->pDims[1]) != FALSE) ?
|
|
HTTP_SUCCESS : HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetHeaderArraySoapDims()
|
|
{
|
|
return GetSoapDims(m_headerMap.GetValueAt(m_currHeaderPos));
|
|
}
|
|
|
|
HTTP_CODE OnGetNextFunctionHeader()
|
|
{
|
|
++m_nHeader;
|
|
if (m_pHeaders[m_nFunc]->pEntries[m_nHeader].nHash != 0)
|
|
{
|
|
if (m_pHeaders[m_nFunc]->pEntries[m_nHeader].dwFlags & SOAPFLAG_NOMARSHAL)
|
|
{
|
|
return OnGetNextHeader();
|
|
}
|
|
return HTTP_SUCCESS;
|
|
}
|
|
m_nHeader = -1;
|
|
return HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnGetFunctionHeaderName()
|
|
{
|
|
return (m_pWriteStream->WriteStream(
|
|
m_pHeaders[m_nFunc]->pEntries[m_nHeader].szField,
|
|
m_pHeaders[m_nFunc]->pEntries[m_nHeader].cchField,
|
|
NULL) == S_OK) ? HTTP_SUCCESS : HTTP_FAIL;
|
|
}
|
|
|
|
HTTP_CODE OnIsArrayHeader()
|
|
{
|
|
return (OnNotIsArrayHeader() == HTTP_SUCCESS) ? HTTP_S_FALSE : HTTP_SUCCESS;
|
|
}
|
|
|
|
HTTP_CODE OnIsDocumentLiteral()
|
|
{
|
|
if ((m_dwCallFlags & (SOAPFLAG_DOCUMENT | SOAPFLAG_LITERAL)) ==
|
|
(SOAPFLAG_DOCUMENT | SOAPFLAG_LITERAL))
|
|
{
|
|
return HTTP_SUCCESS;
|
|
}
|
|
return HTTP_S_FALSE;
|
|
}
|
|
|
|
HTTP_CODE OnIsRpcEncoded()
|
|
{
|
|
if ((m_dwCallFlags & (SOAPFLAG_RPC | SOAPFLAG_ENCODED)) ==
|
|
(SOAPFLAG_RPC | SOAPFLAG_ENCODED))
|
|
{
|
|
return HTTP_SUCCESS;
|
|
}
|
|
return HTTP_S_FALSE;
|
|
}
|
|
|
|
#pragma warning (push)
|
|
#pragma warning (disable : 4640) // construction of local static object is not thread-safe
|
|
|
|
BEGIN_REPLACEMENT_METHOD_MAP(_CSDLGenerator)
|
|
REPLACEMENT_METHOD_ENTRY("GetNamespace", OnGetNamespace)
|
|
REPLACEMENT_METHOD_ENTRY("GetNextFunction", OnGetNextFunction)
|
|
REPLACEMENT_METHOD_ENTRY("GetFunctionName", OnGetFunctionName)
|
|
REPLACEMENT_METHOD_ENTRY("GetNextParameter", OnGetNextParameter)
|
|
REPLACEMENT_METHOD_ENTRY("IsInParameter", OnIsInParameter)
|
|
REPLACEMENT_METHOD_ENTRY("GetParameterName", OnGetParameterName)
|
|
REPLACEMENT_METHOD_ENTRY("NotIsArrayParameter", OnNotIsArrayParameter)
|
|
REPLACEMENT_METHOD_ENTRY("IsParameterUDT", OnIsParameterUDT)
|
|
REPLACEMENT_METHOD_ENTRY("GetParameterSoapType", OnGetParameterSoapType)
|
|
REPLACEMENT_METHOD_ENTRY("IsParameterDynamicArray", OnIsParameterDynamicArray)
|
|
REPLACEMENT_METHOD_ENTRY("IsArrayParameter", OnIsArrayParameter)
|
|
REPLACEMENT_METHOD_ENTRY("IsParameterOneDimensional", OnIsParameterOneDimensional)
|
|
REPLACEMENT_METHOD_ENTRY("GetParameterArraySize", OnGetParameterArraySize)
|
|
REPLACEMENT_METHOD_ENTRY("GetParameterArraySoapDims", OnGetParameterArraySoapDims)
|
|
REPLACEMENT_METHOD_ENTRY("IsOutParameter", OnIsOutParameter)
|
|
REPLACEMENT_METHOD_ENTRY("GetNextEnum", OnGetNextEnum)
|
|
REPLACEMENT_METHOD_ENTRY("GetEnumName", OnGetEnumName)
|
|
REPLACEMENT_METHOD_ENTRY("GetNextEnumElement", OnGetNextEnumElement)
|
|
REPLACEMENT_METHOD_ENTRY("GetEnumElementName", OnGetEnumElementName)
|
|
REPLACEMENT_METHOD_ENTRY("GetNextStruct", OnGetNextStruct)
|
|
REPLACEMENT_METHOD_ENTRY("GetStructName", OnGetStructName)
|
|
REPLACEMENT_METHOD_ENTRY("GetNextStructField", OnGetNextStructField)
|
|
REPLACEMENT_METHOD_ENTRY("GetStructFieldName", OnGetStructFieldName)
|
|
REPLACEMENT_METHOD_ENTRY("NotIsArrayField", OnNotIsArrayField)
|
|
REPLACEMENT_METHOD_ENTRY("IsFieldUDT", OnIsFieldUDT)
|
|
REPLACEMENT_METHOD_ENTRY("GetStructFieldSoapType", OnGetStructFieldSoapType)
|
|
REPLACEMENT_METHOD_ENTRY("IsArrayField", OnIsArrayField)
|
|
REPLACEMENT_METHOD_ENTRY("IsFieldOneDimensional", OnIsFieldOneDimensional)
|
|
REPLACEMENT_METHOD_ENTRY("GetFieldArraySize", OnGetFieldArraySize)
|
|
REPLACEMENT_METHOD_ENTRY("GetFieldArraySoapDims", OnGetFieldArraySoapDims)
|
|
REPLACEMENT_METHOD_ENTRY("GetServiceName", OnGetServiceName)
|
|
REPLACEMENT_METHOD_ENTRY("GetURL", OnGetURL)
|
|
|
|
REPLACEMENT_METHOD_ENTRY("GetNextHeader", OnGetNextHeader)
|
|
REPLACEMENT_METHOD_ENTRY("GetHeaderName", OnGetHeaderName)
|
|
REPLACEMENT_METHOD_ENTRY("NotIsArrayHeader", OnNotIsArrayHeader)
|
|
REPLACEMENT_METHOD_ENTRY("IsArrayHeader", OnIsArrayHeader)
|
|
REPLACEMENT_METHOD_ENTRY("IsHeaderUDT", OnIsHeaderUDT)
|
|
REPLACEMENT_METHOD_ENTRY("GetHeaderSoapType", OnGetHeaderSoapType)
|
|
REPLACEMENT_METHOD_ENTRY("IsHeaderOneDimensional", OnIsHeaderOneDimensional)
|
|
REPLACEMENT_METHOD_ENTRY("GetHeaderArraySize", OnGetHeaderArraySize)
|
|
REPLACEMENT_METHOD_ENTRY("GetHeaderArraySoapDims", OnGetHeaderArraySoapDims)
|
|
REPLACEMENT_METHOD_ENTRY("GetNextFunctionHeader", OnGetNextFunctionHeader)
|
|
REPLACEMENT_METHOD_ENTRY("GetFunctionHeaderName", OnGetFunctionHeaderName)
|
|
REPLACEMENT_METHOD_ENTRY("IsInHeader", OnIsInHeader)
|
|
REPLACEMENT_METHOD_ENTRY("IsOutHeader", OnIsOutHeader)
|
|
REPLACEMENT_METHOD_ENTRY("IsRequiredHeader", OnIsRequiredHeader)
|
|
|
|
REPLACEMENT_METHOD_ENTRY("IsDocumentLiteral", OnIsDocumentLiteral)
|
|
REPLACEMENT_METHOD_ENTRY("IsRpcEncoded", OnIsRpcEncoded)
|
|
REPLACEMENT_METHOD_ENTRY("IsFieldDynamicArray", OnIsFieldDynamicArray)
|
|
REPLACEMENT_METHOD_ENTRY("GetFieldSizeIsName", OnGetFieldSizeIsName)
|
|
END_REPLACEMENT_METHOD_MAP()
|
|
|
|
#pragma warning (pop)
|
|
|
|
}; // class _CSDLGenerator
|
|
|
|
template <class THandler, const char *szHandlerName>
|
|
class CSDLGenerator :
|
|
public _CSDLGenerator,
|
|
public IRequestHandlerImpl< CSDLGenerator<THandler,szHandlerName> >,
|
|
public CComObjectRootEx<CComSingleThreadModel>
|
|
{
|
|
private:
|
|
|
|
public:
|
|
typedef CSDLGenerator<THandler, szHandlerName> _sdlGenerator;
|
|
|
|
BEGIN_COM_MAP(_sdlGenerator)
|
|
COM_INTERFACE_ENTRY(IRequestHandler)
|
|
COM_INTERFACE_ENTRY(ITagReplacer)
|
|
END_COM_MAP()
|
|
|
|
HTTP_CODE InitializeHandler(AtlServerRequest *pRequestInfo, IServiceProvider *pServiceProvider)
|
|
{
|
|
IRequestHandlerImpl<CSDLGenerator>::InitializeHandler(pRequestInfo, pServiceProvider);
|
|
|
|
CComObjectStack<THandler> handler;
|
|
if (FAILED(InitializeSDL(&handler)))
|
|
{
|
|
return HTTP_FAIL;
|
|
}
|
|
|
|
CStencil s;
|
|
HTTP_CODE hcErr = s.LoadFromString(s_szAtlsWSDLSrf, (DWORD) strlen(s_szAtlsWSDLSrf));
|
|
if (hcErr == HTTP_SUCCESS)
|
|
{
|
|
hcErr = HTTP_FAIL;
|
|
CHttpResponse HttpResponse(pRequestInfo->pServerContext);
|
|
HttpResponse.SetContentType("text/xml");
|
|
if (s.ParseReplacements(this) != false)
|
|
{
|
|
s.FinishParseReplacements();
|
|
|
|
SetStream(&HttpResponse);
|
|
SetWriteStream(&HttpResponse);
|
|
SetHttpServerContext(m_spServerContext);
|
|
|
|
ATLASSERT( s.ParseSuccessful() != false );
|
|
|
|
hcErr = s.Render(this, &HttpResponse);
|
|
}
|
|
}
|
|
|
|
return hcErr;
|
|
}
|
|
|
|
const char * GetHandlerName()
|
|
{
|
|
return szHandlerName;
|
|
}
|
|
}; // class CSDLGenerator
|
|
|
|
} // namespace ATL
|
|
#pragma pack(pop)
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif // __ATLSOAP_H__
|