/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: stralign.h Abstract: This module contains macros and prototypes to expose the unaligned wide character interfaces. Public interfaces created or declared here include: ua_CharUpper() ua_CharUpperW() ua_lstrcmp() ua_lstrcmpW() ua_lstrcmpi() ua_lstrcmpiW() ua_lstrlen() ua_lstrlenW() ua_tcscpy() ua_wcschr() ua_wcscpy() ua_wcslen() ua_wcsrchr() STRUC_ALIGNED_STACK_COPY() TSTR_ALIGNED() TSTR_ALIGNED_STACK_COPY() WSTR_ALIGNED() WSTR_ALIGNED_STACK_COPY() Revision History: --*/ #if !defined(__STRALIGN_H_) && !defined(MIDL_PASS) #define __STRALIGN_H_ #ifdef __cplusplus extern "C" { #endif #if defined(_X86_) // // Alignment of unicode strings is not necessary on X86. // #define WSTR_ALIGNED(s) TRUE #define ua_CharUpperW CharUpperW #define ua_lstrcmpiW lstrcmpiW #define ua_lstrcmpW lstrcmpW #define ua_lstrlenW lstrlenW #define ua_wcschr wcschr #define ua_wcscpy wcscpy #define ua_wcslen wcslen #define ua_wcsrchr wcsrchr #else // // The C runtime libraries expect aligned string pointers. Following are the // prototypes for our own, slower worker functions that accept unaligned // UNICODE strings. // // // Macro to determine whether a pointer to a unicode character is naturally // aligned. // #define WSTR_ALIGNED(s) (((DWORD_PTR)(s) & (sizeof(WCHAR)-1)) == 0) // // Platform-specific prototypes for worker functions exported from kernel32. // Do not call these directly, they do not exist on all platforms. Instead // use the equivalent ua_xxx() routines. // LPUWSTR WINAPI uaw_CharUpperW( IN OUT LPUWSTR String ); int APIENTRY uaw_lstrcmpW( IN PCUWSTR String1, IN PCUWSTR String2 ); int APIENTRY uaw_lstrcmpiW( IN PCUWSTR String1, IN PCUWSTR String2 ); int WINAPI uaw_lstrlenW( IN LPCUWSTR String ); PUWSTR __cdecl uaw_wcschr( IN PCUWSTR String, IN WCHAR Character ); PUWSTR _cdecl uaw_wcscpy( IN PUWSTR Destination, IN PCUWSTR Source ); size_t __cdecl uaw_wcslen( IN PCUWSTR String ); PUWSTR __cdecl uaw_wcsrchr( IN PCUWSTR String, IN WCHAR Character ); // // Following are the inline wrappers that determine the optimal worker function // to call based on the alignment of the UNICODE string arguments. Their // behavior is otherwise identical to the corresponding standard run-time // routiunes. // #if defined(CharUpper) __inline LPUWSTR static ua_CharUpperW( LPUWSTR String ) { if (WSTR_ALIGNED(String)) { return CharUpperW( (PWSTR)String ); } else { return uaw_CharUpperW( String ); } } #endif #if defined(lstrcmp) __inline int static ua_lstrcmpW( IN LPCUWSTR String1, IN LPCUWSTR String2 ) { if (WSTR_ALIGNED(String1) && WSTR_ALIGNED(String2)) { return lstrcmpW( (LPCWSTR)String1, (LPCWSTR)String2); } else { return uaw_lstrcmpW( String1, String2 ); } } #endif #if defined(lstrcmpi) __inline int static ua_lstrcmpiW( IN LPCUWSTR String1, IN LPCUWSTR String2 ) { if (WSTR_ALIGNED(String1) && WSTR_ALIGNED(String2)) { return lstrcmpiW( (LPCWSTR)String1, (LPCWSTR)String2 ); } else { return uaw_lstrcmpiW( String1, String2 ); } } #endif #if defined(lstrlen) __inline int static ua_lstrlenW( IN LPCUWSTR String ) { if (WSTR_ALIGNED(String)) { return lstrlenW( (PCWSTR)String ); } else { return uaw_lstrlenW( String ); } } #endif #if defined(_WSTRING_DEFINED) // // Certain run-time string functions are overloaded in C++, to avoid // inadvertent stripping of the const attribute. // // The functions of interest here include: wcschr and wcsrchr. // // There are three flavors of these functions: // // Flavor Returns Parameter // // 1 PWSTR PCWSTR // 2 PCWSTR PCWSTR // 3 PWSTR PWSTR // // string.h declares flavor 1 whether for C or C++. This is the non-ANSI, // backward compatible mode. // // wchar.h declares flavor 1 if C, or flavors 2 and 3 if C++. This is the // ANSI method. // // Our corresponding functions need to match what was declared. The way // we can tell is by looking at _WConst_return... if it is defined then // we want to match the prototypes in wchar.h, otherwise we'll match // the prototypes in string.h. // #if defined(_WConst_return) typedef _WConst_return WCHAR UNALIGNED *PUWSTR_C; #else typedef WCHAR UNALIGNED *PUWSTR_C; #endif // // Here is flavor 1 or 2 // __inline PUWSTR_C static ua_wcschr( IN PCUWSTR String, IN WCHAR Character ) { if (WSTR_ALIGNED(String)) { return wcschr((PCWSTR)String, Character); } else { return (PUWSTR_C)uaw_wcschr(String, Character); } } __inline PUWSTR_C static ua_wcsrchr( IN PCUWSTR String, IN WCHAR Character ) { if (WSTR_ALIGNED(String)) { return wcsrchr((PCWSTR)String, Character); } else { return (PUWSTR_C)uaw_wcsrchr(String, Character); } } #if defined(__cplusplus) && defined(_WConst_Return) // // Here is flavor 3 // __inline PUWSTR static ua_wcschr( IN PUWSTR String, IN WCHAR Character ) { if (WSTR_ALIGNED(String)) { return wcschr(String, Character); } else { return uaw_wcschr((PCUWSTR)String, Character); } } __inline PUWSTR static ua_wcsrchr( IN PUWSTR String, IN WCHAR Character ) { if (WSTR_ALIGNED(String)) { return wcsrchr(String, Character); } else { return uaw_wcsrchr((PCUWSTR)String, Character); } } #endif // __cplusplus && _WConst_Return __inline PUWSTR static ua_wcscpy( IN PUWSTR Destination, IN PCUWSTR Source ) { if (WSTR_ALIGNED(Source) && WSTR_ALIGNED(Destination)) { return wcscpy( (PWSTR)Destination, (PCWSTR)Source ); } else { return uaw_wcscpy( Destination, Source ); } } __inline size_t static ua_wcslen( IN PCUWSTR String ) { if (WSTR_ALIGNED(String)) { return wcslen( (PCWSTR)String ); } else { return uaw_wcslen( String ); } } #endif // _WSTRING_DEFINED #endif // _X86_ //++ // // VOID // WSTR_ALIGNED_STACK_COPY ( // OUT PCWSTR *TargetString, // IN PCUWSTR SourceString OPTIONAL // ) // // VOID // TSTR_ALIGNED_STACK_COPY ( // OUT PCTSTR *TargetString, // IN PCUTSTR SourceString OPTIONAL // ) // // Routine Description: // // These macros set TargetString to an aligned pointer to the string // represented by SourceString. If necessary, an aligned copy of // SourceString is copied onto the stack. // // Arguments: // // TargetString - Supplies a pointer to a pointer to the resultant // string. This may be the same as SourceString if // that argument is aligned. // // SourceString - Supplies a pointer to the possibly unaligned UNICODE // string. // // Return Value: // // None. // // Note: // // These macros may allocate memory on the stack via the CRT function // _alloca(). This memory is "freed" when the calling function exits. // As a result, do not use these macros inside of a loop that may execute // a large number of times - instead, use a wrapper function, or use // an explicit buffer like this: // // TCHAR AlignedStringBuffer[ MAX_FOOSTR_CHARS ]; // PTSTR AlignedString; // // while (a < b) { // ... // if (TSTR_ALIGNED(s) { // AlignedString = s; // } else { // AlignedString = (PTSTR)ua_tcscpy(AlignedStringBuffer,s); // } // SomeSystemFunction(AlignedString); // ... // } // // //-- // // __UA_WSTRSIZE returns the number of bytes required to store the // supplied null-terminated UNICODE string. // // __UA_LOCALCOPY accepts a pointer to unaligned data and a size. It // allocates an aligned buffer on the stack and copies the data into // it, returning a pointer to the buffer. // #if !defined(__UA_WCSLEN) #define __UA_WCSLEN ua_wcslen #endif #define __UA_WSTRSIZE(s) ((__UA_WCSLEN(s)+1)*sizeof(WCHAR)) #define __UA_STACKCOPY(p,s) memcpy(_alloca(s),p,s) // // Note that NULL is aligned. // #if defined(_X86_) #define WSTR_ALIGNED_STACK_COPY(d,s) (*(d) = (PCWSTR)(s)) #else // // Use of an inline function here is not possible, as the results of // the _alloca() will not be preserved upon return from the function. // #define WSTR_ALIGNED_STACK_COPY(d,s) \ { \ PCUWSTR __ua_src; \ ULONG __ua_size; \ PWSTR __ua_dst; \ \ __ua_src = (s); \ if (WSTR_ALIGNED(__ua_src)) { \ __ua_dst = (PWSTR)__ua_src; \ } else { \ __ua_size = __UA_WSTRSIZE(__ua_src); \ __ua_dst = (PWSTR)_alloca(__ua_size); \ memcpy(__ua_dst,__ua_src,__ua_size); \ } \ *(d) = (PCWSTR)__ua_dst; \ } #endif #define ASTR_ALIGNED_STACK_COPY(d,s) (*(d) = (PCSTR)(s)) //++ // // CONST * // STRUC_ALIGNED_STACK_COPY ( // IN , // IN PVOID Struc OPTIONAL // ) // // Routine Description: // // This macro returns an aligned pointer to Struc, creating a local // copy on the stack if necessary. // // This should be used only for relatively small structures, and efforts // should be made to align the structure properly in the first place. Use // this macro only as a last resort. // // Arguments: // // - The type specifier of Struc // // Struc - Supplies a pointer to the structure in question. // // Return Value: // // Returns a const pointer to Struc if it is properly aligned, or a pointer // to a stack-allocated copy of Struc if it is not. // //-- #if !defined(_X86_) #define __UA_STRUC_ALIGNED(t,s) \ (((DWORD_PTR)(s) & (TYPE_ALIGNMENT(t)-1)) == 0) #define STRUC_ALIGNED_STACK_COPY(t,s) \ __UA_STRUC_ALIGNED(t,s) ? \ ((t const *)(s)) : \ ((t const *)__UA_STACKCOPY((s),sizeof(t))) #else #define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s)) #endif #if defined(UNICODE) #define TSTR_ALIGNED_STACK_COPY(d,s) WSTR_ALIGNED_STACK_COPY(d,s) #define TSTR_ALIGNED(x) WSTR_ALIGNED(x) #define ua_CharUpper ua_CharUpperW #define ua_lstrcmp ua_lstrcmpW #define ua_lstrcmpi ua_lstrcmpiW #define ua_lstrlen ua_lstrlenW #define ua_tcscpy ua_wcscpy #else #define TSTR_ALIGNED_STACK_COPY(d,s) ASTR_ALIGNED_STACK_COPY(d,s) #define TSTR_ALIGNED(x) TRUE #define ua_CharUpper CharUpperA #define ua_lstrcmp lstrcmpA #define ua_lstrcmpi lstrcmpiA #define ua_lstrlen lstrlenA #define ua_tcscpy strcpy #endif // UNICODE #ifdef __cplusplus } #endif #endif // __STRALIGN_H_