406 lines
9.9 KiB
C++
406 lines
9.9 KiB
C++
/********************************************************************
|
|
|
|
Copyright (c) 1999-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
util.cpp
|
|
|
|
Abstract:
|
|
utility functions implementation
|
|
|
|
Revision History:
|
|
DerekM created 05/01/99
|
|
|
|
********************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
#include "util.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// tracing
|
|
|
|
#ifdef THIS_FILE
|
|
#undef THIS_FILE
|
|
#endif
|
|
static char __szTraceSourceFile[] = __FILE__;
|
|
#define THIS_FILE __szTraceSourceFile
|
|
|
|
HANDLE g_hPFPrivateHeap = NULL;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// string stuff
|
|
|
|
// ***************************************************************************
|
|
WCHAR *MyStrStrIW(const WCHAR *wcs1, const WCHAR *wcs2)
|
|
{
|
|
WCHAR *cp = (WCHAR *)wcs1;
|
|
WCHAR *s1, *s2;
|
|
|
|
while (*cp != '\0')
|
|
{
|
|
s1 = cp;
|
|
s2 = (WCHAR *) wcs2;
|
|
|
|
while (*s1 != '\0' && *s2 !='\0' && (towlower(*s1) - towlower(*s2)) == 0)
|
|
s1++, s2++;
|
|
|
|
if (*s2 == '\0')
|
|
return(cp);
|
|
|
|
cp++;
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CHAR *MyStrStrIA(const CHAR *cs1, const CHAR *cs2)
|
|
{
|
|
CHAR *cp = (CHAR *)cs1;
|
|
CHAR *s1, *s2;
|
|
|
|
while (*cp != '\0')
|
|
{
|
|
s1 = cp;
|
|
s2 = (CHAR *) cs2;
|
|
|
|
while (*s1 != '\0' && *s2 !='\0' && (tolower(*s1) - tolower(*s2)) == 0)
|
|
s1++, s2++;
|
|
|
|
if (*s2 == '\0')
|
|
return(cp);
|
|
|
|
cp++;
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
// **************************************************************************
|
|
HRESULT MyURLEncode(LPWSTR wszDest, DWORD cchDest, LPWSTR wszSrc)
|
|
{
|
|
USE_TRACING("URLEncode");
|
|
|
|
HRESULT hr = NOERROR;
|
|
DWORD cb;
|
|
CHAR *pszDest = NULL, *pszSrc;
|
|
CHAR *szSrcBuf, *szDestBuf, ch;
|
|
|
|
VALIDATEPARM(hr, (wszDest == NULL || wszSrc == NULL));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
// alloc enuf space to hold the src array as bytes
|
|
cb = (wcslen(wszSrc) + 1) * sizeof(WCHAR);
|
|
__try
|
|
{
|
|
szSrcBuf = (CHAR *)_alloca(cb);
|
|
szDestBuf = (CHAR *)_alloca(cb * 3);
|
|
_ASSERT(szSrcBuf != NULL);
|
|
}
|
|
__except(1)
|
|
{
|
|
szSrcBuf = NULL;
|
|
szDestBuf = NULL;
|
|
}
|
|
VALIDATEEXPR(hr, (szSrcBuf == NULL || szDestBuf == NULL), E_OUTOFMEMORY);
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
// convert to multibyte so I can properly URL encode the string
|
|
TESTBOOL(hr, (WideCharToMultiByte(CP_ACP, 0, wszSrc, -1, szSrcBuf, cb,
|
|
NULL, NULL) != 0));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
pszDest = szDestBuf;
|
|
for(pszSrc = szSrcBuf; *pszSrc != L'\0'; pszSrc++)
|
|
{
|
|
if (isalpha(*pszSrc) || isdigit(*pszSrc))
|
|
{
|
|
*pszDest++ = *pszSrc;
|
|
}
|
|
|
|
else
|
|
{
|
|
*pszDest++ = L'%';
|
|
|
|
// get the trailing byte
|
|
ch = (*pszSrc >> 4) & 0x0F;
|
|
*pszDest++ = (ch < 10) ? ch + L'0' : (ch - 10) + L'A';
|
|
ch = *pszSrc & 0x0F;
|
|
*pszDest++ = (ch < 10) ? ch + L'0' : (ch - 10) + L'A';
|
|
}
|
|
}
|
|
|
|
*pszDest = '\0';
|
|
|
|
// convert back to unicode
|
|
TESTBOOL(hr, (MultiByteToWideChar(CP_ACP, 0, szDestBuf, -1, wszDest,
|
|
cchDest) != 0));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// File mapping
|
|
|
|
// **************************************************************************
|
|
HRESULT OpenFileMapped(LPWSTR wszFile, LPVOID *ppvFile, DWORD *pcbFile)
|
|
{
|
|
USE_TRACING("OpenFileMapped");
|
|
|
|
HRESULT hr = NOERROR;
|
|
HANDLE hMMF = NULL;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
LPVOID pvFile = NULL;
|
|
DWORD cbFile = 0;
|
|
|
|
VALIDATEPARM(hr, (wszFile == NULL || ppvFile == NULL));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
*ppvFile = NULL;
|
|
if (pcbFile != NULL)
|
|
*pcbFile = 0;
|
|
|
|
hFile = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, 0, NULL);
|
|
TESTBOOL(hr, (hFile != INVALID_HANDLE_VALUE));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
cbFile = GetFileSize(hFile, NULL);
|
|
TESTBOOL(hr, (cbFile != (DWORD)-1));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
hMMF = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, cbFile, NULL);
|
|
TESTBOOL(hr, (hMMF != NULL));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
pvFile = MapViewOfFile(hMMF, FILE_MAP_READ, 0, 0, 0);
|
|
TESTBOOL(hr, (pvFile != NULL));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
*ppvFile = pvFile;
|
|
if (pcbFile != NULL)
|
|
*pcbFile = cbFile;
|
|
|
|
done:
|
|
if (hMMF != NULL)
|
|
CloseHandle(hMMF);
|
|
if (hFile != NULL)
|
|
CloseHandle(hFile);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// **************************************************************************
|
|
HRESULT DeleteTempFile(LPWSTR wszFile)
|
|
{
|
|
USE_TRACING("DeleteTempFile");
|
|
|
|
HRESULT hr = NOERROR;
|
|
WCHAR *pwsz;
|
|
|
|
if (wszFile == NULL)
|
|
return NOERROR;
|
|
|
|
// strip off the extension at the end (if it's not a .tmp)
|
|
for(pwsz = wszFile + wcslen(wszFile); *pwsz != L'.' && pwsz > wszFile; pwsz--);
|
|
if (pwsz > wszFile && _wcsicmp(pwsz, L".tmp") != 0)
|
|
*pwsz = L'\0';
|
|
|
|
if (DeleteFileW(wszFile) == FALSE)
|
|
hr = Err2HR(GetLastError());
|
|
|
|
// can do this even if the extension was a tmp since the value pointed to
|
|
// by pwsz is '.' if it's greater than wszFile...
|
|
if (pwsz > wszFile)
|
|
*pwsz = L'.';
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Registry stuff
|
|
|
|
// **************************************************************************
|
|
HRESULT OpenRegKey(HKEY hkeyMain, LPCWSTR wszSubKey, BOOL fWantWrite,
|
|
HKEY *phkey)
|
|
{
|
|
USE_TRACING("OpenRegKey");
|
|
|
|
HRESULT hr = NOERROR;
|
|
REGSAM samDesired;
|
|
DWORD dwErr;
|
|
|
|
VALIDATEPARM(hr, (hkeyMain == NULL || wszSubKey == NULL || phkey == NULL));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
*phkey = NULL;
|
|
|
|
samDesired = (fWantWrite) ? KEY_ALL_ACCESS : KEY_READ;
|
|
|
|
// first try calling RegCreateKeyEx to make sure we create the key if
|
|
// it doesn't exist
|
|
TESTERR(hr, RegCreateKeyExW(hkeyMain, wszSubKey, 0, NULL, 0, samDesired,
|
|
NULL, phkey, NULL));
|
|
if (FAILED(hr))
|
|
{
|
|
// ok, that didn't work, so try opening the key instead
|
|
TESTERR(hr, RegOpenKeyExW(hkeyMain, wszSubKey, 0, samDesired, phkey));
|
|
}
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
// **************************************************************************
|
|
HRESULT ReadRegEntry(HKEY hkey, LPCWSTR wszValName, DWORD *pdwType,
|
|
PBYTE pbBuffer, DWORD *pcbBuffer, PBYTE pbDefault,
|
|
DWORD cbDefault)
|
|
{
|
|
USE_TRACING("ReadRegEntry");
|
|
|
|
HRESULT hr = NOERROR;
|
|
DWORD dwErr;
|
|
|
|
VALIDATEPARM(hr, (hkey == NULL || wszValName == NULL));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
dwErr = RegQueryValueExW(hkey, wszValName, 0, pdwType, pbBuffer,
|
|
pcbBuffer);
|
|
VALIDATEEXPR(hr, (dwErr != ERROR_PATH_NOT_FOUND &&
|
|
dwErr != ERROR_FILE_NOT_FOUND), Err2HR(dwErr));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
if (dwErr != ERROR_SUCCESS && pbDefault != NULL)
|
|
{
|
|
VALIDATEPARM(hr, (pcbBuffer == NULL && pbBuffer != NULL));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
// if the receiving buffer is NULL, just return the error that
|
|
// RegQueryValueEx gave us cuz the user doesn't really want the
|
|
// value anyway
|
|
VALIDATEEXPR(hr, (pcbBuffer == NULL), Err2HR(dwErr));
|
|
if (FAILED(hr))
|
|
goto done;
|
|
|
|
if (pbBuffer == NULL)
|
|
{
|
|
*pcbBuffer = cbDefault;
|
|
hr = NOERROR;
|
|
goto done;
|
|
}
|
|
else if (cbDefault > *pcbBuffer)
|
|
{
|
|
*pcbBuffer = cbDefault;
|
|
hr = Err2HR(ERROR_MORE_DATA);
|
|
goto done;
|
|
}
|
|
|
|
CopyMemory(pbBuffer, pbDefault, cbDefault);
|
|
*pcbBuffer = cbDefault;
|
|
if (pdwType != NULL)
|
|
*pdwType = REG_BINARY;
|
|
|
|
hr = NOERROR;
|
|
goto done;
|
|
}
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ia64 data alignment workarounds
|
|
|
|
#ifdef _WIN64
|
|
|
|
// ***************************************************************************
|
|
ULONG64 AlignTo8Bytes(PBYTE pb)
|
|
{
|
|
ULONG64 ul;
|
|
|
|
switch((DWORD_PTR)pb & 0x8)
|
|
{
|
|
// yay! already aligned
|
|
case 0:
|
|
ul = *(ULONG64 *)pb;
|
|
break;
|
|
|
|
case 1:
|
|
case 5:
|
|
ul = *pb << 56;
|
|
ul |= *(ULONG32 *)(pb + 1) << 24;
|
|
ul |= *(USHORT *)(pb + 5) << 8;
|
|
ul |= *(pb + 7);
|
|
break;
|
|
|
|
case 2:
|
|
case 6:
|
|
ul = *(USHORT *)pb << 48;
|
|
ul |= *(ULONG32 *)(pb + 2) << 16;
|
|
ul |= *(USHORT *)(pb + 6);
|
|
break;
|
|
|
|
case 3:
|
|
case 7:
|
|
ul = *pb << 56;
|
|
ul |= *(USHORT *)(pb + 1) << 48;
|
|
ul |= *(ULONG32 *)(pb + 3) << 16;
|
|
ul |= *(pb + 7);
|
|
break;
|
|
|
|
case 4:
|
|
ul = *(ULONG32 *)pb << 32;
|
|
ul |= *(ULONG32 *)(pb + 4);
|
|
break;
|
|
}
|
|
|
|
return ul;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
ULONG32 AlignTo4Bytes(PBYTE pb)
|
|
{
|
|
ULONG32 ul;
|
|
|
|
switch((DWORD_PTR)pb & 0x4)
|
|
{
|
|
// yay! already aligned
|
|
case 0:
|
|
ul = *(ULONG32 *)pb;
|
|
break;
|
|
|
|
case 1:
|
|
case 3:
|
|
ul = *pb << 24;
|
|
ul |= *(short *)(pb + 1) << 8;
|
|
ul |= *(pb + 3);
|
|
break;
|
|
|
|
case 2:
|
|
ul = *(short *)pb << 16;
|
|
ul |= *(short *)(pb + 2);
|
|
break;
|
|
}
|
|
|
|
return ul;
|
|
}
|
|
|
|
#endif
|
|
|