Files
Slnkdwf/ATL90/include/atlsoap.h
Jos Groot Lipman 0e37d774d2 Merge SLNKDWF64 branch
svn path=/Slnkdwf/trunk/; revision=23911
2015-01-21 12:09:31 +00:00

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__