/*++ MangleObjectNameW Mangle an object name to be side-by-side with other Rotors lplpObjectName - [in out] pointer to pointer to object name to mangle lpMangledObjectName - buffer of MAX_PATH characters to store the mangled object name in Returns TRUE on success. On failure, returns FALSE with LastError set. --*/ BOOL MangleObjectNameW(LPCWSTR *lplpObjectName, LPWSTR lpMangledObjectName) { size_t ObjectNameLength; LPCWSTR lpObjectName; WCHAR *pSlash; lpObjectName = *lplpObjectName; if (!lpObjectName) { // No object name, so no work to do. return TRUE; } ObjectNameLength = PAL_wcslen(lpObjectName); if (ObjectNameLength+NameManglerLength+1 >= MAX_PATH) { SetLastError(ERROR_FILENAME_EXCED_RANGE); return FALSE; } *lplpObjectName = lpMangledObjectName; pSlash = PAL_wcschr(lpObjectName, L'\\'); if (pSlash) { size_t PathPartLength; // The mangling needs to be done after the Global\\ or Local\\ portion PathPartLength = pSlash-lpObjectName+1; memcpy(lpMangledObjectName, lpObjectName, PathPartLength*sizeof(WCHAR)); lpObjectName+=PathPartLength; lpMangledObjectName+=PathPartLength; } PAL_wcsncpy(lpMangledObjectName, NameManglerW, NameManglerLength); PAL_wcscpy(lpMangledObjectName+NameManglerLength, lpObjectName); return TRUE; }
__cdecl PAL_wcspbrk( const wchar_16 *string, const wchar_16 *strCharSet) { PERF_ENTRY(wcspbrk); ENTRY("wcspbrk (string=%p (%S), strCharSet=%p (%S))\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING); while (*string) { if (PAL_wcschr(strCharSet, *string) != NULL) { LOGEXIT("wcspbrk returning wchar_t %p (%S)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING); PERF_EXIT(wcspbrk); return (wchar_16 *) string; } string++; } LOGEXIT("wcspbrk returning wchar_t NULL\n"); PERF_EXIT(wcspbrk); return NULL; }
/*++ Function: PathFindFileNameW See MSDN doc. --*/ LPWSTR PALAPI PathFindFileNameW( IN LPCWSTR pPath ) { PERF_ENTRY(PathFindFileNameW); ENTRY("PathFindFileNameW(pPath=%p (%S))\n", pPath?pPath:W16_NULLSTRING, pPath?pPath:W16_NULLSTRING); LPWSTR ret = (LPWSTR)pPath; if (ret != NULL && *ret != W('\0')) { ret = PAL_wcschr(ret, W('\0')) - 1; if (ret > pPath && *ret == W('/')) { ret--; } while (ret > pPath && *ret != W('/')) { ret--; } if (*ret == W('/') && *(ret + 1) != W('\0')) { ret++; } } LOGEXIT("PathFindFileNameW returns %S\n", ret); PERF_EXIT(PathFindFileNameW); return ret; }
/*++ Function: UTIL_inverse_wcspbrk Opposite of wcspbrk : searches a string for the first character NOT in the given set Parameters : LPWSTR lpwstr : string to search LPCWSTR charset : list of characters to search for Return value : pointer to first character of lpwstr that isn't in the set NULL if all characters are in the set --*/ LPWSTR UTIL_inverse_wcspbrk(LPWSTR lpwstr, LPCWSTR charset) { while(*lpwstr) { if(NULL == PAL_wcschr(charset,*lpwstr)) { return lpwstr; } lpwstr++; } return NULL; }
/*++ Function: FormatMessageW See MSDN doc. --*/ DWORD PALAPI FormatMessageW( IN DWORD dwFlags, IN LPCVOID lpSource, IN DWORD dwMessageId, IN DWORD dwLanguageId, OUT LPWSTR lpBuffer, IN DWORD nSize, IN va_list *Arguments) { BOOL bIgnoreInserts = FALSE; BOOL bIsVaList = TRUE; BOOL bIsLocalAlloced = FALSE; LPWSTR lpSourceString = NULL; UINT nCount = 0; LPWSTR lpReturnString = NULL; LPWSTR lpWorkingString = NULL; PERF_ENTRY(FormatMessageW); ENTRY( "FormatMessageW(dwFlags=%#x, lpSource=%p, dwMessageId=%#x, " "dwLanguageId=%#x, lpBuffer=%p, nSize=%u, va_list=%p)\n", dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); /* Sanity checks. */ if ( dwFlags & FORMAT_MESSAGE_FROM_STRING && !lpSource ) { /* This behavior is different then in Windows. Windows would just crash.*/ ERROR( "lpSource cannot be NULL.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } if ( !(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER ) && !lpBuffer ) { /* This behavior is different then in Windows. Windows would just crash.*/ ERROR( "lpBuffer cannot be NULL, if " " FORMAT_MESSAGE_ALLOCATE_BUFFER is not specified.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } if ( ( dwFlags & FORMAT_MESSAGE_FROM_STRING ) && ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM ) ) { ERROR( "These flags cannot co-exist. You can either " "specify FORMAT_MESSAGE_FROM_STRING, or " "FORMAT_MESSAGE_FROM_SYSTEM.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } if ( !( dwFlags & FORMAT_MESSAGE_FROM_STRING ) && ( dwLanguageId != 0 #if ENABLE_DOWNLEVEL_FOR_NLS && dwLanguageId != MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) #endif ) ) { ERROR( "Invalid language indentifier.\n" ); SetLastError( ERROR_RESOURCE_LANG_NOT_FOUND ); goto exit; } /* Parameter processing. */ if ( dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER ) { TRACE( "Allocated %d TCHARs. Don't forget to call LocalFree to " "free the memory when done.\n", nSize ); bIsLocalAlloced = TRUE; } if ( dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS ) { bIgnoreInserts = TRUE; } if ( dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY ) { if ( !Arguments && !bIgnoreInserts ) { ERROR( "The va_list cannot be NULL.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } else { bIsVaList = FALSE; } } if ( dwFlags & FORMAT_MESSAGE_FROM_STRING ) { lpSourceString = (LPWSTR)lpSource; } else if ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM ) { if ((dwMessageId & 0xFFFF0000) == 0x80070000) { // This message has been produced by HRESULT_FROM_WIN32. Undo its work. dwMessageId &= 0xFFFF; } lpWorkingString = lpReturnString = FMTMSG_GetMessageString( dwMessageId ); if ( !lpWorkingString ) { ERROR( "Unable to find the message %d.\n", dwMessageId ); SetLastError( ERROR_INTERNAL_ERROR ); nCount = 0; goto exit; } nCount = PAL_wcslen( lpWorkingString ); if ( !bIsLocalAlloced && nCount > nSize ) { ERROR( "Insufficient buffer.\n" ); SetLastError( ERROR_INSUFFICIENT_BUFFER ); lpWorkingString = NULL; nCount = 0; goto exit; } if ( !lpWorkingString ) { ERROR( "Invalid error indentifier.\n" ); SetLastError( ERROR_INVALID_ADDRESS ); } goto exit; } else { ERROR( "Unknown flag.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } if ( nSize == 0 && bIsLocalAlloced ) { nSize = 1; } lpWorkingString = static_cast<WCHAR *>( LocalAlloc( LMEM_FIXED, nSize * sizeof( WCHAR ) ) ); if ( !lpWorkingString ) { ERROR( "Unable to allocate memory for the working string.\n" ); SetLastError( ERROR_INSUFFICIENT_BUFFER ); goto exit; } /* Process the string. */ lpReturnString = lpWorkingString; while ( *lpSourceString ) { if ( *lpSourceString == '%' && !bIgnoreInserts ) { lpSourceString++; /* Escape sequences. */ if ( *lpSourceString == '0' ) { /* Terminates a message without a newline character. */ *lpWorkingString = '\0'; goto exit; } else if ( PAL_iswdigit( *lpSourceString ) ) { /* Get the insert number. */ WCHAR Number[] = { '\0', '\0', '\0' }; SIZE_T Index = 0; Number[ 0 ] = *lpSourceString; lpSourceString++; if ( PAL_iswdigit( *lpSourceString ) ) { Number[ 1 ] = *lpSourceString; lpSourceString++; if ( PAL_iswdigit( *lpSourceString ) ) { ERROR( "Invalid insert indentifier.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); lpWorkingString = NULL; nCount = 0; goto exit; } } Index = FMTMSG__watoi( Number ); if ( Index == 0 ) { ERROR( "Invalid insert indentifier.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); lpWorkingString = NULL; nCount = 0; goto exit; } if ( *lpSourceString == '!' ) { LPWSTR lpInsertString = NULL; LPWSTR lpPrintfString = NULL; LPWSTR lpStartOfFormattedString = NULL; UINT nPrintfLength = 0; LPWSTR lpFormattedString = NULL; UINT nFormattedLength = 0; if ( !bIsVaList ) { lpInsertString = (LPWSTR)Arguments[ Index - 1 ]; } else { va_list TheArgs; va_copy(TheArgs, *Arguments); UINT i = 0; for ( ; i < Index; i++ ) { lpInsertString = va_arg( TheArgs, LPWSTR ); } } /* Calculate the length, and extract the printf string.*/ lpSourceString++; { LPWSTR p = PAL_wcschr( lpSourceString, '!' ); if ( NULL == p ) { nPrintfLength = 0; } else { nPrintfLength = p - lpSourceString; } } lpPrintfString = (LPWSTR)PAL_malloc( ( nPrintfLength + 1 ) * sizeof( WCHAR ) ); if ( !lpPrintfString ) { ERROR( "Unable to allocate memory.\n" ); SetLastError( ERROR_NOT_ENOUGH_MEMORY ); lpWorkingString = NULL; nCount = 0; goto exit; } PAL_wcsncpy( lpPrintfString, lpSourceString, nPrintfLength ); *( lpPrintfString + nPrintfLength ) = '\0'; lpStartOfFormattedString = lpFormattedString = FMTMSG_ProcessPrintf( *lpPrintfString, lpPrintfString, lpInsertString); if ( !lpFormattedString ) { ERROR( "Unable to process the format string.\n" ); /* Function will set the error code. */ PAL_free( lpPrintfString ); lpWorkingString = NULL; goto exit; } nFormattedLength = PAL_wcslen( lpFormattedString ); /* Append the processed printf string into the working string */ while ( *lpFormattedString ) { _CHECKED_ADD_TO_STRING( *lpFormattedString ); lpFormattedString++; } lpSourceString += nPrintfLength + 1; PAL_free( lpPrintfString ); PAL_free( lpStartOfFormattedString ); lpPrintfString = lpFormattedString = NULL; } else { /* The printf format string defaults to 's'.*/ LPWSTR lpInsert = NULL; if ( !bIsVaList ) { lpInsert = (LPWSTR)Arguments[ Index - 1 ]; } else { va_list TheArgs; va_copy(TheArgs, *Arguments); UINT i = 0; for ( ; i < Index; i++ ) { lpInsert = va_arg( TheArgs, LPWSTR ); } } while ( *lpInsert ) { _CHECKED_ADD_TO_STRING( *lpInsert ); lpInsert++; } } } /* Format specifiers. */ else if ( *lpSourceString == '%' ) { _CHECKED_ADD_TO_STRING( '%' ); lpSourceString++; } else if ( *lpSourceString == 'n' ) { /* Hard line break. */ _CHECKED_ADD_TO_STRING( '\n' ); lpSourceString++; } else if ( *lpSourceString == '.' ) { _CHECKED_ADD_TO_STRING( '.' ); lpSourceString++; } else if ( *lpSourceString == '!' ) { _CHECKED_ADD_TO_STRING( '!' ); lpSourceString++; } else if ( !*lpSourceString ) { ERROR( "Invalid parameter.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); lpWorkingString = NULL; nCount = 0; goto exit; } else /* Append the character. */ { _CHECKED_ADD_TO_STRING( *lpSourceString ); lpSourceString++; } }/* END if ( *lpSourceString == '%' ) */ else { /* In Windows if FormatMessage is called with ignore inserts, then FormatMessage strips %1!s! down to %1, since string is the default. */ if ( bIgnoreInserts && *lpSourceString == '!' && *( lpSourceString + 1 ) == 's' ) { LPWSTR lpLastBang = PAL_wcschr( lpSourceString + 1, '!' ); if ( lpLastBang && ( 2 == lpLastBang - lpSourceString ) ) { lpSourceString = lpLastBang + 1; } else { ERROR( "Mal-formed string\n" ); SetLastError( ERROR_INVALID_PARAMETER ); lpWorkingString = NULL; nCount = 0; goto exit; } } else { /* Append to the string. */ _CHECKED_ADD_TO_STRING( *lpSourceString ); lpSourceString++; } } } /* Terminate the message. */ _CHECKED_ADD_TO_STRING( '\0' ); /* NULL does not count. */ nCount--; exit: /* Function clean-up and exit. */ if ( lpWorkingString ) { if ( bIsLocalAlloced ) { TRACE( "Assigning the buffer to the pointer.\n" ); // when FORMAT_MESSAGE_ALLOCATE_BUFFER is specified, nSize // does not specify the size of lpBuffer, rather it specifies // the minimum size of the string // as such we have to blindly assume that lpBuffer has enough space to // store PVOID // might cause a prefast warning, but there is no good way to suppress it yet _ASSERTE(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER); *((LPVOID*)lpBuffer) = (LPVOID)lpReturnString; } else /* Only delete lpReturnString if the caller has their own buffer.*/ { TRACE( "Copying the string into the buffer.\n" ); PAL_wcsncpy( lpBuffer, lpReturnString, nCount + 1 ); LocalFree( lpReturnString ); } } else /* Error, something occured. */ { if ( lpReturnString ) { LocalFree( lpReturnString ); } } LOGEXIT( "FormatMessageW returns %d.\n", nCount ); PERF_EXIT(FormatMessageW); return nCount; }
/*++ Function: SearchPathW See MSDN doc. PAL-specific notes : -lpPath must be non-NULL; path delimiters are platform-dependent (':' for Unix) -lpFileName must be non-NULL, may be an absolute path -lpExtension must be NULL -lpFilePart (if non-NULL) doesn't need to be used (but we do) --*/ DWORD PALAPI SearchPathW( IN LPCWSTR lpPath, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart ) { DWORD nRet = 0; WCHAR FullPath[MAX_PATH]; LPCWSTR pPathStart; LPCWSTR pPathEnd; size_t PathLength; size_t FileNameLength; DWORD dw; char AnsiPath[MAX_PATH]; WCHAR CanonicalPath[MAX_PATH]; PERF_ENTRY(SearchPathW); ENTRY("SearchPathW(lpPath=%p (%S), lpFileName=%p (%S), lpExtension=%p, " "nBufferLength=%u, lpBuffer=%p, lpFilePart=%p)\n", lpPath, lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart); /* validate parameters */ if(NULL == lpPath) { ASSERT("lpPath may not be NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto done; } if(NULL == lpFileName) { ASSERT("lpFileName may not be NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto done; } if(NULL != lpExtension) { ASSERT("lpExtension must be NULL, is %p instead\n", lpExtension); SetLastError(ERROR_INVALID_PARAMETER); goto done; } /* special case : if file name contains absolute path, don't search the provided path */ if('\\' == lpFileName[0] || '/' == lpFileName[0]) { /* Canonicalize the path to deal with back-to-back '/', etc. */ dw = GetFullPathNameW(lpFileName, MAX_PATH, CanonicalPath, NULL); if (dw == 0 || dw >= MAX_PATH) { WARN("couldn't canonicalize path <%S>, error is %#x. failing.\n", lpPath, GetLastError()); SetLastError(ERROR_INVALID_PARAMETER); goto done; } /* see if the file exists */ WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1, AnsiPath, MAX_PATH, NULL, NULL); if(0 == access(AnsiPath, F_OK)) { /* found it */ nRet = dw; } } else { LPCWSTR pNextPath; pNextPath = lpPath; FileNameLength = PAL_wcslen(lpFileName); while (*pNextPath) { pPathStart = pNextPath; /* get a pointer to the end of the first path in pPathStart */ pPathEnd = PAL_wcschr(pPathStart, ':'); if (!pPathEnd) { pPathEnd = pPathStart + PAL_wcslen(pPathStart); /* we want to break out of the loop after this pass, so let *pNextPath be '\0' */ pNextPath = pPathEnd; } else { /* point to the next component in the path string */ pNextPath = pPathEnd+1; } PathLength = pPathEnd-pPathStart; if (PathLength+FileNameLength+1 >= MAX_PATH) { /* The path+'/'+file length is too long. Skip it. */ WARN("path component %.*S is too long, skipping it\n", (int)PathLength, pPathStart); continue; } else if(0 == PathLength) { /* empty component : there were 2 consecutive ':' */ continue; } /* Construct a pathname by concatenating one path from lpPath, '/' and lpFileName */ memcpy(FullPath, pPathStart, PathLength*sizeof(WCHAR)); FullPath[PathLength] = '/'; PAL_wcscpy(&FullPath[PathLength+1], lpFileName); /* Canonicalize the path to deal with back-to-back '/', etc. */ dw = GetFullPathNameW(FullPath, MAX_PATH, CanonicalPath, NULL); if (dw == 0 || dw >= MAX_PATH) { /* Call failed - possibly low memory. Skip the path */ WARN("couldn't canonicalize path <%S>, error is %#x. " "skipping it\n", FullPath, GetLastError()); continue; } /* see if the file exists */ WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1, AnsiPath, MAX_PATH, NULL, NULL); if(0 == access(AnsiPath, F_OK)) { /* found it */ nRet = dw; break; } } } if (nRet == 0) { /* file not found anywhere; say so. in Windows, this always seems to say FILE_NOT_FOUND, even if path doesn't exist */ SetLastError(ERROR_FILE_NOT_FOUND); } else { /* find out the required buffer size, copy path to buffer if it's large enough */ nRet = PAL_wcslen(CanonicalPath)+1; if(nRet <= nBufferLength) { if(NULL == lpBuffer) { /* Windows merily crashes here, but let's not */ ERROR("caller told us buffer size was %d, but buffer is NULL\n", nBufferLength); SetLastError(ERROR_INVALID_PARAMETER); nRet = 0; goto done; } PAL_wcscpy(lpBuffer, CanonicalPath); /* don't include the null-terminator in the count if buffer was large enough */ nRet--; if(NULL != lpFilePart) { *lpFilePart = PAL_wcsrchr(lpBuffer, '/'); if(NULL == *lpFilePart) { ASSERT("no '/' in full path!\n"); } else { /* point to character after last '/' */ (*lpFilePart)++; } } } } done: LOGEXIT("SearchPathW returns DWORD %u\n", nRet); PERF_EXIT(SearchPathW); return nRet; }
__cdecl PAL_wcstok(wchar_16 *strToken, const wchar_16 *strDelimit) { wchar_16 *retval = NULL; wchar_16 *delim_ptr; wchar_16 *next_context; /* string to save in TLS for future calls */ int ret; ENTRY("wcstok (strToken=%p (%S), strDelimit=%p (%S))\n", strToken?strToken:W16_NULLSTRING, strToken?strToken:W16_NULLSTRING, strDelimit?strDelimit:W16_NULLSTRING, strDelimit?strDelimit:W16_NULLSTRING); if(NULL == strDelimit) { ERROR("delimiter string is NULL\n"); goto done; } /* get token string from TLS if none is provided */ if(NULL == strToken) { TRACE("wcstok() called with NULL string, using previous string\n"); strToken = pthread_getspecific(wcstokKey); if(NULL == strToken) { ERROR("wcstok called with NULL string without a previous call\n"); goto done; } } /* first, skip all leading delimiters */ while(PAL_wcschr(strDelimit,*strToken)) { strToken++; } /* if there were only delimiters, there's no string */ if('\0' == strToken[0]) { TRACE("end of string already reached, returning NULL\n"); goto done; } /* we're now at the beginning of the token; look for the first delimiter */ delim_ptr = PAL_wcspbrk(strToken,strDelimit); if(NULL == delim_ptr) { TRACE("no delimiters found, this is the last token\n"); /* place the next context at the end of the string, so that subsequent calls will return NULL */ next_context = strToken+PAL_wcslen(strToken); retval = strToken; } else { /* null-terminate current token */ *delim_ptr=0; /* place the next context right after the delimiter */ next_context = delim_ptr+1; retval = strToken; TRACE("found delimiter; next token will be %p\n",next_context); } if ((ret = pthread_setspecific(wcstokKey, next_context)) != 0) { ERROR("pthread_setspecific() failed error:%d (%s)\n", ret, strerror(ret)); retval = NULL; } done: LOGEXIT("wcstok() returns %p (%S)\n", retval?retval:W16_NULLSTRING, retval?retval:W16_NULLSTRING); return(retval); }