// 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 __ATLCORE_H__
#define __ATLCORE_H__

// ORIG: #pragma once

#ifdef _ATL_ALL_WARNINGS
#ifndef UNIX
#pragma warning( push )
#endif
#endif

#ifndef UNIX
#pragma warning(disable: 4786) // identifier was truncated in the debug information
#endif

#include <atldef.h>
// ORIG: #include <windows.h>
#include "CSP_WinDef.h"
// ORIG: #include <ole2.h>

#if defined(LINUX) && defined(PROCESSOR_TYPE) && PROCESSOR_TYPE == PROC_TYPE_ARM64
#undef __reserved
#endif

#include "reader/support.h"

#if defined(LINUX) && defined(PROCESSOR_TYPE) && PROCESSOR_TYPE == PROC_TYPE_ARM64
#define __reserved
#endif

#include <limits.h>
// ORIG: #include <tchar.h>
#include <reader/tchar.h>
#include <mbstring.h>

#include <atlchecked.h>
#include <atlsimpcoll.h>

#include<stdarg.h>
#if defined(__GNUC__) && !defined(va_list)
#define va_list __gnuc_va_list
#endif

#if defined(AIX)
#pragma pack( 8 /* _ATL_PACKING */)
#elif !defined(SOLARIS) && !defined(FREEBSD)
#pragma pack(push, 8 /* _ATL_PACKING */)
#endif
namespace ATL
{
/////////////////////////////////////////////////////////////////////////////
// Verify that a null-terminated string points to valid memory
inline BOOL AtlIsValidString(LPCWSTR psz, size_t nMaxLength = INT_MAX)
{
	((void)nMaxLength);
	return (psz != NULL);
}

// Verify that a null-terminated string points to valid memory
inline BOOL AtlIsValidString(LPCSTR psz, size_t nMaxLength = UINT_MAX)
{
	((void)nMaxLength);
	return (psz != NULL);
}

// Verify that a pointer points to valid memory
inline BOOL AtlIsValidAddress(const void* p, size_t nBytes,
	BOOL bReadWrite = TRUE)
{
	((void)bReadWrite);
	((void)nBytes);
	return (p != NULL);
}

template<typename T>
inline void AtlAssertValidObject(const T *pOb)
{
	ATLASSERT(pOb);
	ATLASSERT(AtlIsValidAddress(pOb, sizeof(T)));
	if(pOb)
		pOb->AssertValid();
}
#ifdef _DEBUG
#define ATLASSERT_VALID(x) ATL::AtlAssertValidObject(x)
#else
#define ATLASSERT_VALID(x) __noop;
#endif

// COM Sync Classes
class CComCriticalSection
{
public:
	CComCriticalSection() throw()
	{
// ORIG:		memset(&m_sec, 0, sizeof(CRITICAL_SECTION));
		memset(&m_sec, 0, sizeof(m_sec));
	}
	~CComCriticalSection()
	{
	}
	HRESULT Lock() throw()
	{
// ORIG:		EnterCriticalSection(&m_sec);
// ORIG: 		return S_OK;
		int res = support_section_enter(m_sec);
		return MapToHresult(res);
	}
	HRESULT Unlock() throw()
	{
// ORIG: 		LeaveCriticalSection(&m_sec);
// ORIG: 		return S_OK;
		int res = support_section_leave(m_sec);
		return MapToHresult(res);
	}
	HRESULT Init() throw()
	{
// ORIG: 		HRESULT hRes = E_FAIL;
// ORIG: 		__try
// ORIG: 		{
// ORIG: 			InitializeCriticalSection(&m_sec);
// ORIG: 			hRes = S_OK;
// ORIG: 		}
// ORIG: 		// structured exception may be raised in low memory situations
// ORIG: 		__except(STATUS_NO_MEMORY == GetExceptionCode())
// ORIG: 		{			
// ORIG: 			hRes = E_OUTOFMEMORY;		
// ORIG: 		}
// ORIG: 		return hRes;
		int res = support_section_init(&m_sec,0);
		return MapToHresult(res);
	}

	HRESULT Term() throw()
	{
// ORIG:		DeleteCriticalSection(&m_sec);
// ORIG: 		return S_OK;
		int res = support_section_done(&m_sec);
		return MapToHresult(res);
	}	
// ORIG:	CRITICAL_SECTION m_sec;
	TSupportCriticalSection m_sec;
private:
	HRESULT MapToHresult( int errorcode ) {
		switch (errorcode) {
			case 0:
				return S_OK;
			case EINVAL:
				return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
			case EDEADLK:
				return HRESULT_FROM_WIN32(ERROR_POSSIBLE_DEADLOCK);
			case EBUSY:
				return HRESULT_FROM_WIN32(ERROR_BUSY);
			case EPERM:
				return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
			default:
				return E_FAIL;
		}
	}
};

class CComAutoCriticalSection : public CComCriticalSection
{
public:
	CComAutoCriticalSection()
	{
		HRESULT hr = CComCriticalSection::Init();
		if (FAILED(hr))
			AtlThrow(hr);
	}
	~CComAutoCriticalSection() throw()
	{
		CComCriticalSection::Term();
	}
private :
	HRESULT Init(); // Not implemented. CComAutoCriticalSection::Init should never be called
	HRESULT Term(); // Not implemented. CComAutoCriticalSection::Term should never be called
};

class CComSafeDeleteCriticalSection : public CComCriticalSection
{
public:
	CComSafeDeleteCriticalSection(): m_bInitialized(false) 
	{
	}

	~CComSafeDeleteCriticalSection() throw()
	{
		if (!m_bInitialized)
		{
			return;
		}
		m_bInitialized = false;
		CComCriticalSection::Term();
	}

	HRESULT Init() throw()
	{
		ATLASSERT( !m_bInitialized );
		HRESULT hr = CComCriticalSection::Init();
		if (SUCCEEDED(hr))
		{
			m_bInitialized = true;
		}
		return hr;
	}

	HRESULT Term() throw()
	{
		if (!m_bInitialized)
		{
			return S_OK;
		}
		m_bInitialized = false;
		return CComCriticalSection::Term();
	}

	HRESULT Lock()
	{
		// CComSafeDeleteCriticalSection::Init or CComAutoDeleteCriticalSection::Init
		// not called or failed.
		// m_critsec member of CComObjectRootEx is now of type 
		// CComAutoDeleteCriticalSection. It has to be initialized
		// by calling CComObjectRootEx::_AtlInitialConstruct
		ATLASSUME(m_bInitialized);
		return CComCriticalSection::Lock();
	}

private:
	bool m_bInitialized;
};

class CComAutoDeleteCriticalSection : public CComSafeDeleteCriticalSection
{
private:
	// CComAutoDeleteCriticalSection::Term should never be called
	HRESULT Term() throw();
};

class CComFakeCriticalSection
{
public:
	HRESULT Lock() throw() { return S_OK; }
	HRESULT Unlock() throw() { return S_OK; }
	HRESULT Init() throw() { return S_OK; }
	HRESULT Term() throw() { return S_OK; }
};

/////////////////////////////////////////////////////////////////////////////
// Module 

// Used by any project that uses ATL
// ORIG: struct _ATL_BASE_MODULE70
// ORIG: {
// ORIG: 	UINT cbSize;
// ORIG: 	HINSTANCE m_hInst;
// ORIG: 	HINSTANCE m_hInstResource;
// ORIG: 	bool m_bNT5orWin98;
// ORIG: 	DWORD dwAtlBuildVer;
// ORIG: 	const GUID* pguidVer;
// ORIG: 	CComCriticalSection m_csResource;
// ORIG: 	CSimpleArray<HINSTANCE> m_rgResourceInstance;
// ORIG: };
// ORIG: typedef _ATL_BASE_MODULE70 _ATL_BASE_MODULE;

// ORIG: class CAtlBaseModule : public _ATL_BASE_MODULE
// ORIG: {
// ORIG: public :
// ORIG: 	static bool m_bInitFailed;
// ORIG: 	CAtlBaseModule() throw();
// ORIG: 	~CAtlBaseModule() throw ();
// ORIG: 
// ORIG: 	HINSTANCE GetModuleInstance() throw()
// ORIG: 	{
// ORIG: 		return m_hInst;
// ORIG: 	}
// ORIG: 	HINSTANCE GetResourceInstance() throw()
// ORIG: 	{
// ORIG: 		return m_hInstResource;
// ORIG: 	}
// ORIG: 	HINSTANCE SetResourceInstance(HINSTANCE hInst) throw()
// ORIG: 	{
// ORIG: 		return static_cast< HINSTANCE >(InterlockedExchangePointer((void**)&m_hInstResource, hInst));
// ORIG: 	}
// ORIG: 
// ORIG: 	bool AddResourceInstance(HINSTANCE hInst) throw();
// ORIG: 	bool RemoveResourceInstance(HINSTANCE hInst) throw();
// ORIG: 	HINSTANCE GetHInstanceAt(int i) throw();
// ORIG: };

// ORIG: __declspec(selectany) bool CAtlBaseModule::m_bInitFailed = false;
// ORIG: extern CAtlBaseModule _AtlBaseModule;

/////////////////////////////////////////////////////////////////////////////
// String resource helpers

// ORIG: #pragma warning(push)
// ORIG: #pragma warning(disable: 4200)
// ORIG: 	struct ATLSTRINGRESOURCEIMAGE
// ORIG: 	{
// ORIG: 		WORD nLength;
// ORIG: 		WCHAR achString[];
// ORIG: 	};
// ORIG: #pragma warning(pop)	// C4200
// ORIG: 
// ORIG: inline const ATLSTRINGRESOURCEIMAGE* _AtlGetStringResourceImage( HINSTANCE hInstance, HRSRC hResource, UINT id ) throw()
// ORIG: {
// ORIG: 	const ATLSTRINGRESOURCEIMAGE* pImage;
// ORIG: 	const ATLSTRINGRESOURCEIMAGE* pImageEnd;
// ORIG: 	ULONG nResourceSize;
// ORIG: 	HGLOBAL hGlobal;
// ORIG: 	UINT iIndex;
// ORIG: 
// ORIG: 	hGlobal = ::LoadResource( hInstance, hResource );
// ORIG: 	if( hGlobal == NULL )
// ORIG: 	{
// ORIG: 		return( NULL );
// ORIG: 	}
// ORIG: 
// ORIG: 	pImage = (const ATLSTRINGRESOURCEIMAGE*)::LockResource( hGlobal );
// ORIG: 	if( pImage == NULL )
// ORIG: 	{
// ORIG: 		return( NULL );
// ORIG: 	}
// ORIG: 
// ORIG: 	nResourceSize = ::SizeofResource( hInstance, hResource );
// ORIG: 	pImageEnd = (const ATLSTRINGRESOURCEIMAGE*)(LPBYTE( pImage )+nResourceSize);
// ORIG: 	iIndex = id&0x000f;
// ORIG: 
// ORIG: 	while( (iIndex > 0) && (pImage < pImageEnd) )
// ORIG: 	{
// ORIG: 		pImage = (const ATLSTRINGRESOURCEIMAGE*)(LPBYTE( pImage )+(sizeof( ATLSTRINGRESOURCEIMAGE )+(pImage->nLength*sizeof( WCHAR ))));
// ORIG: 		iIndex--;
// ORIG: 	}
// ORIG: 	if( pImage >= pImageEnd )
// ORIG: 	{
// ORIG: 		return( NULL );
// ORIG: 	}
// ORIG: 	if( pImage->nLength == 0 )
// ORIG: 	{
// ORIG: 		return( NULL );
// ORIG: 	}
// ORIG: 
// ORIG: 	return( pImage );
// ORIG: }
// ORIG: 
// ORIG: inline const ATLSTRINGRESOURCEIMAGE* AtlGetStringResourceImage( HINSTANCE hInstance, UINT id ) throw()
// ORIG: {
// ORIG: 	HRSRC hResource;
// ORIG: 
// ORIG: 	hResource = ::FindResource( hInstance, MAKEINTRESOURCE( ((id>>4)+1) ), RT_STRING );
// ORIG: 	if( hResource == NULL )
// ORIG: 	{
// ORIG: 		return( NULL );
// ORIG: 	}
// ORIG: 
// ORIG: 	return _AtlGetStringResourceImage( hInstance, hResource, id );
// ORIG: }
// ORIG: 
// ORIG: inline const ATLSTRINGRESOURCEIMAGE* AtlGetStringResourceImage( HINSTANCE hInstance, UINT id, WORD wLanguage ) throw()
// ORIG: {
// ORIG: 	HRSRC hResource;
// ORIG: 
// ORIG: 	hResource = ::FindResourceEx( hInstance, RT_STRING, MAKEINTRESOURCE( ((id>>4)+1) ), wLanguage );
// ORIG: 	if( hResource == NULL )
// ORIG: 	{
// ORIG: 		return( NULL );
// ORIG: 	}
// ORIG: 
// ORIG: 	return _AtlGetStringResourceImage( hInstance, hResource, id );
// ORIG: }
// ORIG: 
// ORIG: inline const ATLSTRINGRESOURCEIMAGE* AtlGetStringResourceImage( UINT id ) throw()
// ORIG: {
// ORIG: 	const ATLSTRINGRESOURCEIMAGE* p = NULL;
// ORIG: 	HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0);
// ORIG: 
// ORIG: 	for (int i = 1; hInst != NULL && p == NULL; hInst = _AtlBaseModule.GetHInstanceAt(i++))
// ORIG: 	{
// ORIG: 		p = AtlGetStringResourceImage(hInst, id);
// ORIG: 	}
// ORIG: 	return p;
// ORIG: }
// ORIG: 
// ORIG: inline const ATLSTRINGRESOURCEIMAGE* AtlGetStringResourceImage( UINT id, WORD wLanguage ) throw()
// ORIG: {
// ORIG: 	const ATLSTRINGRESOURCEIMAGE* p = NULL;
// ORIG: 	HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0);
// ORIG: 
// ORIG: 	for (int i = 1; hInst != NULL && p == NULL; hInst = _AtlBaseModule.GetHInstanceAt(i++))
// ORIG: 	{
// ORIG: 		p = AtlGetStringResourceImage(hInst, id, wLanguage);
// ORIG: 	}
// ORIG: 	return p;
// ORIG: }
// ORIG: 
// ORIG: inline int AtlLoadString(__in UINT nID, __out_ecount_part_z(nBufferMax, return + 1) LPTSTR lpBuffer, __in int nBufferMax) throw()
// ORIG: {
// ORIG: 	HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0);
// ORIG: 	int nRet = 0;
// ORIG: 
// ORIG: 	for (int i = 1; hInst != NULL && nRet == 0; hInst = _AtlBaseModule.GetHInstanceAt(i++))
// ORIG: 	{
// ORIG: 		nRet = LoadString(hInst, nID, lpBuffer, nBufferMax);
// ORIG: 	}
// ORIG: 	return nRet;
// ORIG: }
// ORIG: 
// ORIG: inline HINSTANCE AtlFindResourceInstance(LPCTSTR lpName, LPCTSTR lpType, WORD wLanguage = 0) throw()
// ORIG: {
// ORIG: 	ATLASSERT(lpType != RT_STRING);	// Call AtlFindStringResourceInstance to find the string
// ORIG: 	if (lpType == RT_STRING)
// ORIG: 		return NULL;
// ORIG: 
// ORIG: 	if (ATL_IS_INTRESOURCE(lpType))
// ORIG: 	{
// ORIG: 		/* Prefast false warnings caused by bad-shaped definition of MAKEINTRESOURCE macro from PSDK */
// ORIG: 		if (lpType == ATL_RT_ICON)
// ORIG: 		{
// ORIG: 			lpType = ATL_RT_GROUP_ICON;
// ORIG: 		}
// ORIG: 		else if (lpType == ATL_RT_CURSOR)
// ORIG: 		{
// ORIG: 			lpType = ATL_RT_GROUP_CURSOR;
// ORIG: 		}
// ORIG: 	}
// ORIG: 
// ORIG: 	HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0);
// ORIG: 	HRSRC hResource = NULL;
// ORIG: 
// ORIG: 	for (int i = 1; hInst != NULL; hInst = _AtlBaseModule.GetHInstanceAt(i++))
// ORIG: 	{
// ORIG: 		hResource = ::FindResourceEx(hInst, lpType, lpName, wLanguage);
// ORIG: 		if (hResource != NULL)
// ORIG: 		{
// ORIG: 			return hInst;
// ORIG: 		}
// ORIG: 	}
// ORIG: 
// ORIG: 	return NULL;
// ORIG: }
// ORIG: 
// ORIG: inline HINSTANCE AtlFindResourceInstance(UINT nID, LPCTSTR lpType, WORD wLanguage = 0) throw()
// ORIG: {
// ORIG: 	return AtlFindResourceInstance(MAKEINTRESOURCE(nID), lpType, wLanguage);
// ORIG: }
// ORIG: 
// ORIG: inline HINSTANCE AtlFindStringResourceInstance(UINT nID, WORD wLanguage = 0) throw()
// ORIG: {
// ORIG: 	const ATLSTRINGRESOURCEIMAGE* p = NULL;
// ORIG: 	HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0);
// ORIG: 
// ORIG: 	for (int i = 1; hInst != NULL && p == NULL; hInst = _AtlBaseModule.GetHInstanceAt(i++))
// ORIG: 	{
// ORIG: 		p = AtlGetStringResourceImage(hInst, nID, wLanguage);
// ORIG: 		if (p != NULL)
// ORIG: 			return hInst;
// ORIG: 	}
// ORIG: 
// ORIG: 	return NULL;
// ORIG: }

/* 
Needed by both atlcomcli and atlsafe, so needs to be in here 
*/
// ORIG: inline HRESULT AtlSafeArrayGetActualVartype
// ORIG: (
// ORIG:     SAFEARRAY *psaArray,
// ORIG:     VARTYPE *pvtType
// ORIG: )
// ORIG: {
// ORIG:     HRESULT hrSystem=::SafeArrayGetVartype(psaArray, pvtType);
// ORIG: 
// ORIG:     if(FAILED(hrSystem))
// ORIG:     {
// ORIG:         return hrSystem;
// ORIG:     }

    /* 
    When Windows has a SAFEARRAY of type VT_DISPATCH with FADF_HAVEIID,
    it returns VT_UNKNOWN instead of VT_DISPATCH. We patch the value to be correct
    */
// ORIG:     if(pvtType && *pvtType==VT_UNKNOWN)
// ORIG:     {
// ORIG:         if(psaArray && ((psaArray->fFeatures & FADF_HAVEIID)!=0))
// ORIG:         {
// ORIG:             if(psaArray->fFeatures & FADF_DISPATCH)
// ORIG:             {
// ORIG:                 *pvtType=VT_DISPATCH;
// ORIG:             }
// ORIG:         }
// ORIG:     }
// ORIG: 
// ORIG:     return hrSystem;
// ORIG: }
template <typename _CharType>
inline _CharType* AtlCharNext(const _CharType* p) throw()
{
	ATLASSUME(p != NULL);	// Too expensive to check separately here 
	return const_cast<_CharType*>(p+1);
// ORIG: 	if (*p == '\0')  // ::CharNextA won't increment if we're at a \0 already
// ORIG: 		return const_cast<_CharType*>(p+1);
// ORIG: 	else
// ORIG: 		return ::CharNextA(p);
}

template <>
inline wchar_t* AtlCharNext<wchar_t>(const wchar_t* p) throw()
{
	return const_cast< wchar_t* >( p+1 );
}
template<typename CharType>
inline const CharType* AtlstrchrT(const CharType* p, CharType ch) throw()
{
	ATLASSERT(p != NULL);	
	if(p==NULL)
	{
		return NULL;
	}
	while( *p != 0 )
	{
		if (*p == ch)
		{
			return p;
		}
		p = AtlCharNext(p);
	}
	//strchr for '\0' should succeed - the while loop terminates 
	//*p == 0, but ch also == 0, so NULL terminator address is returned
	return (*p == ch) ? p : NULL;
}
//Ansi and Unicode versions of printf, used with templated CharType trait classes.
#pragma warning(push)
#pragma warning(disable : 4793)
template<typename CharType>
inline int AtlprintfT(const CharType* pszFormat,... ) throw()
{
	int retval=0;
	va_list argList;
	va_start( argList, pszFormat );
	retval=vprintf(pszFormat,argList);
	va_end( argList );
	return retval;
}
#ifndef UNIX
#pragma warning(pop)

#pragma warning(push)
#pragma warning(disable : 4793)
#endif
/* template<>
inline int AtlprintfT(const wchar_t* pszFormat,... ) throw()
{
	int retval=0;
	va_list argList;
	va_start( argList, pszFormat );
	retval=vwprintf(pszFormat,	argList);
	va_end( argList );
	return retval;
}
*/
#ifndef UNIX
#pragma warning(pop)
#endif

// ORIG: inline BOOL AtlConvertSystemTimeToVariantTime(const SYSTEMTIME& systimeSrc,double* pVarDtTm)
// ORIG: {
// ORIG: 	ATLENSURE(pVarDtTm!=NULL);
// ORIG: 	//Convert using ::SystemTimeToVariantTime and store the result in pVarDtTm then
// ORIG: 	//convert variant time back to system time and compare to original system time.	
// ORIG: 	BOOL ok = ::SystemTimeToVariantTime(const_cast<SYSTEMTIME*>(&systimeSrc), pVarDtTm);
// ORIG: 	SYSTEMTIME sysTime;
// ORIG: 	::ZeroMemory(&sysTime, sizeof(SYSTEMTIME));
// ORIG: 
// ORIG: 	ok = ok && ::VariantTimeToSystemTime(*pVarDtTm, &sysTime);
// ORIG: 	ok = ok && (systimeSrc.wYear == sysTime.wYear &&
// ORIG: 			systimeSrc.wMonth == sysTime.wMonth &&
// ORIG: 			systimeSrc.wDay == sysTime.wDay &&
// ORIG: 			systimeSrc.wHour == sysTime.wHour &&
// ORIG: 			systimeSrc.wMinute == sysTime.wMinute && 
// ORIG: 			systimeSrc.wSecond == sysTime.wSecond);
// ORIG: 
// ORIG: 	return ok;
// ORIG: }
/////////////////////////////////////////////////////////////////////////////

}	// namespace ATL
#if !defined(SOLARIS) && !defined(FREEBSD)
#pragma pack(pop)
#endif

#ifdef _ATL_ALL_WARNINGS
#pragma warning( pop )
#endif

#endif	// __ATLCORE_H__
