/*++ Copyright (c) 2000-2001, Microsoft Corporation All rights reserved. Module Name: convert.h Abstract: Header over convert.c This seems like an appropriate place to explain Godot's stack strategy. Basically, every time we do an allocation on the stack when _GODOTSAFESTACK is defined (which is currently always), we do not want to take size and perf hit of over 500 SEH blocks and we also do not have the time to try to special case each API to try to find out parameter sizes or do stack probes. At the same time, we cannot be crazy go lucky like VSANSI and simply allow the _alloca call to throw an EXCEPTION_STACK_OVERFLOW, since it is unrealistic to expect callers to wrap every API call in SEH blocks (just as it is for us!). Even if it were realistic, we cannot afford to punish users who do not writ bulletproof code. Failure is okay, but crashes are not. Therefore, in order to satify both our size/perf requirement and our safety requirement, we preface every call to _alloca with a call to our StackAllocCheck function. This function will attempt to call _alloca in a try...except block and will properly fix up the stack on failure. This keeps us from bloating up with hundreds of SEH blocks yet still allows us to have a bit more safety. Note that this is NOT a 100% solution, since it is vaguely possible that a multithreaded application has a (slim) chance of succeeding the StackAllockCheck function but then failing before the official (unguarded) call to _alloca due to another thread's call to _alloca, initiated by the user's code (it would never be one of our calls since all of *ours* use this safe method). There is no real defense against this, but it is a very unlikely type of problem. Revision History: 17 Mar 2001 v-michka Created. 15 Apr 2001 v-michka Put in lots of fun heap/stack stuff --*/ #ifndef CONVERT_H #define CONVERT_H #define _GODOTSAFESTACK // Is this non null and not a user atom? #define FSTRING_VALID(x) ((ULONG_PTR)(x) > 0xffff) // Our function for making sure stack allocations are valid BOOL StackAllocCheck(size_t size); // _alloca, on certain platforms, returns a raw pointer to the // stack rather than NULL on allocations of size zero. Since this // is sub-optimal for code that subsequently calls functions like // strlen on the allocated block of memory, these wrappers are // provided for use. /////////////////////////////////////////////////////////////////////////// // // _STACKALLOC // Do an allocation from the stack. Must be a macro for obvious reasons! // // #define _STACKALLOC_SAFE(siz, mem) \ if(StackAllocCheck(siz)) \ mem = (void *)((siz)?(_alloca(siz)):NULL); \ else \ mem = NULL; #define _STACKALLOC_UNSAFE(siz, mem) \ mem = ((siz)?(_alloca(siz)):NULL) #ifdef _GODOTSAFESTACK #define _STACKALLOC(siz, mem) _STACKALLOC_SAFE(siz, mem) #else #define _STACKALLOC(siz, mem) _STACKALLOC_UNSAFE(siz, mem) #endif /////////////////////////////////////////////////////////////////////////// // // GODOT_TO_ACP_STACKALLOC // Convert from Unicode to ANSI if needed, otherwise copy as if it were an Atom // // #define GODOT_TO_ACP_STACKALLOC_SAFE(src, dst) \ if (FSTRING_VALID((LPWSTR)src)) \ { \ size_t cch = gwcslen((LPWSTR)(src)) + 1; \ _STACKALLOC_SAFE(cch*g_mcs, (LPSTR)dst); \ if(dst) \ WideCharToMultiByte(g_acp, 0, (LPWSTR)(src), cch, (LPSTR)(dst), cch*g_mcs, NULL, NULL); \ else \ (LPSTR)(dst) = (LPSTR)(src); \ } \ else \ (LPSTR)(dst) = (LPSTR)(src) #define GODOT_TO_ACP_STACKALLOC_UNSAFE(src, dst) \ if (FSTRING_VALID((LPWSTR)src)) \ { \ size_t cch = gwcslen((LPWSTR)(src)) + 1; \ _STACKALLOC_UNSAFE(cch*g_mcs, (LPSTR)dst); \ if(dst) \ WideCharToMultiByte(g_acp, 0, (LPWSTR)(src), cch, (LPSTR)(dst), cch*g_mcs, NULL, NULL); \ else \ (LPSTR)(dst) = (LPSTR)(src); \ } \ else \ (LPSTR)(dst) = (LPSTR)(src) #ifdef _GODOTSAFESTACK #define GODOT_TO_ACP_STACKALLOC(src, dst) GODOT_TO_ACP_STACKALLOC_SAFE(src, dst) #else #define GODOT_TO_ACP_STACKALLOC(src, dst) GODOT_TO_ACP_STACKALLOC_UNSAFE(src, dst) #endif /////////////////////////////////////////////////////////////////////////// // // GODOT_TO_CPG_STACKALLOC // Convert from Unicode to ANSI if needed, otherwise copy as if it were an Atom // // #define GODOT_TO_CPG_STACKALLOC_SAFE(src, dst, cpg, mcs) \ if (FSTRING_VALID(src)) \ { \ size_t cch = gwcslen((LPWSTR)(src)) + 1; \ _STACKALLOC_SAFE(cch*mcs, (LPSTR)dst); \ if(dst) \ WideCharToMultiByte(cpg, 0, (LPWSTR)(src), cch, (LPSTR)(dst), cch*mcs, NULL, NULL); \ else \ (LPSTR)(dst) = (LPSTR)(src); \ } \ else \ (LPSTR)(dst) = (LPSTR)(src) #define GODOT_TO_CPG_STACKALLOC_UNSAFE(src, dst, cpg, mcs) \ if (FSTRING_VALID(src)) \ { \ size_t cch = gwcslen((LPWSTR)(src)) + 1; \ _STACKALLOC_UNSAFE(cch*mcs, (LPSTR)dst); \ if(dst) \ WideCharToMultiByte(cpg, 0, (LPWSTR)(src), cch, (LPSTR)(dst), cch*mcs, NULL, NULL); \ else \ (LPSTR)(dst) = (LPSTR)(src); \ } \ else \ (LPSTR)(dst) = (LPSTR)(src) #ifdef _GODOTSAFESTACK #define GODOT_TO_CPG_STACKALLOC(src, dst, cpg, mcs) GODOT_TO_CPG_STACKALLOC_SAFE(src, dst, cpg, mcs) #else #define GODOT_TO_CPG_STACKALLOC(src, dst, cpg, mcs) GODOT_TO_CPG_STACKALLOC_UNSAFE(src, dst, cpg, mcs) #endif /////////////////////////////////////////////////////////////////////////// // // Various enums, macros and functions for heap allocation stuff // // typedef enum { arBadParam = 1, arFailed = 2, arAlloc = 3, arNoAlloc = 4 } ALLOCRETURN; /////////////////////////////////////////////////////////////////////////// // // Our generic heap wrappers // // #define GodotHeapAlloc(mem) ((mem) ? (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem)) : NULL) #define GodotHeapFree(mem) ((mem) ? (HeapFree(GetProcessHeap(), 0, mem)) : FALSE) #define GodotHeapReAlloc(old, mem) ((mem) ? (HeapReAlloc(GetProcessHeap(), 0, old, mem)) : NULL) /////////////////////////////////////////////////////////////////////////// // // wrappers/foward declares around our heap alloc/conversion // functions to handle common cases // // #define GodotToAcpOnHeap(lpwz, lpsz) GodotToCpgCchOnHeap(lpwz, -1, lpsz, g_acp, g_mcs) #define GodotToCpgOnHeap(lpwz, lpsz, cpg, mcs) GodotToCpgCchOnHeap(lpwz, -1, lpsz, cpg, mcs) #define GodotToUnicodeOnHeap(lpsz, lpwz) GodotToUnicodeCpgCchOnHeap(lpsz, -1, lpwz, g_acp) #define GodotToUnicodeCpgOnHeap(lpsz, lpwz, cpg, mcs) GodotToUnicodeCpgCchOnHeap(lpwz, -1, lpsz, cpg) ALLOCRETURN GodotToCpgCchOnHeap(LPCWSTR lpwz, int cchMax, LPSTR * lpsz, UINT cpg, UINT mcs); ALLOCRETURN GodotToUnicodeCpgCchOnHeap(LPCSTR lpsz, int cchMax, LPWSTR * lpwz, UINT cpg); /////////////////////////////////////////////////////////////////////////// // // Additional Forward declares // // void DevModeAfromW(LPDEVMODEA lpdma, LPDEVMODEW lpdmw); void DevModeWfromA(LPDEVMODEW lpdmw, LPDEVMODEA lpdma); HGLOBAL HDevModeAfromW(HGLOBAL * lphdmw, BOOL fFree); HGLOBAL HDevModeWfromA(HGLOBAL * lphdma, BOOL fFree); HGLOBAL HDevNamesAfromW(HGLOBAL * lphdnw, BOOL fFree); HGLOBAL HDevNamesWfromA(HGLOBAL * lphdna, BOOL fFree); void LogFontAfromW(LPLOGFONTA lplfa, LPLOGFONTW lplfw); void LogFontWfromA(LPLOGFONTW lplfw, LPLOGFONTA lplfa); void Win32FindDataWfromA(PWIN32_FIND_DATAW w32fdw, PWIN32_FIND_DATAA w32fda); void TextMetricWfromA(LPTEXTMETRICW lptmw, LPTEXTMETRICA lptma); void NewTextMetricWfromA(LPNEWTEXTMETRICW lpntmw, LPNEWTEXTMETRICA lpntma); void NewTextMetricExWfromA(NEWTEXTMETRICEXW * lpntmew, NEWTEXTMETRICEXA * lpntmea); BOOL MenuItemInfoAfromW(LPMENUITEMINFOA lpmiia, LPCMENUITEMINFOW lpmiiw); int GrszToGrwz(const CHAR* szFrom, WCHAR* wzTo, int cchTo); int SzToWzCch(const CHAR *sz, WCHAR *wz, int cch); #endif // CONVERT_H