You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1228 lines
31 KiB
1228 lines
31 KiB
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Microsoft Windows
|
|
|
|
Copyright (C) Microsoft Corporation, 1995 - 1999.
|
|
|
|
File: Convert.cpp
|
|
|
|
Contents: Implementation of encoding conversion routines.
|
|
|
|
History: 11-15-99 dsie created
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#define _CRYPT32_ // This is required to statically link in pkifmt.lib.
|
|
|
|
#include "StdAfx.h"
|
|
#include "CAPICOM.h"
|
|
#include "Convert.h"
|
|
#include "Base64.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : UnicodeToAnsi
|
|
|
|
Synopsis : Convert an array of unicode character to ANSI.
|
|
|
|
Parameter: LPWSTR pwszUnicodeString - Pointer to Unicode string to be
|
|
converted to ANSI string.
|
|
|
|
int cchWideChar - Number of characters, or -1 if
|
|
pwszUnicodeString is NULL terminated.
|
|
|
|
LPSTR * ppszAnsiString - Pointer to LPSTR to received the
|
|
converted ANSI string.
|
|
|
|
int * pcchAnsiChar (Optional) - Pointer to int to receive
|
|
the number of characters
|
|
translated.
|
|
|
|
Remark : Caller must call CoTaskMemFree to free the returned ANSI string.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT UnicodeToAnsi (LPWSTR pwszUnicodeString,
|
|
int cchWideChar,
|
|
LPSTR * ppszAnsiString,
|
|
int * pcchAnsiChar)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int cchAnsiChar = 0;
|
|
LPSTR pszAnsiString = NULL;
|
|
|
|
DebugTrace("Entering UnicodeToAnsi().\n");
|
|
|
|
//
|
|
// Make sure parameter is valid.
|
|
//
|
|
if (NULL == pwszUnicodeString || NULL == ppszAnsiString)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: pwszUnicodeString = %#x, ppszAnsiString = %#x.\n",
|
|
hr, pwszUnicodeString, ppszAnsiString);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Determine ANSI length.
|
|
//
|
|
cchAnsiChar = ::WideCharToMultiByte(CP_ACP, // code page
|
|
0, // performance and mapping flags
|
|
pwszUnicodeString, // wide-character string
|
|
cchWideChar, // number of chars in string
|
|
NULL, // buffer for new string
|
|
0, // size of buffer
|
|
NULL, // default for unmappable chars
|
|
NULL); // set when default char used
|
|
if (0 == cchAnsiChar)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: WideCharToMultiByte() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for ANSI string.
|
|
//
|
|
if (!(pszAnsiString = (LPSTR) ::CoTaskMemAlloc(cchAnsiChar)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Conver to ANSI.
|
|
//
|
|
cchAnsiChar = ::WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
pwszUnicodeString,
|
|
cchWideChar,
|
|
pszAnsiString,
|
|
cchAnsiChar,
|
|
NULL,
|
|
NULL);
|
|
if (0 == cchAnsiChar)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: WideCharToMultiByte() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return values to caller.
|
|
//
|
|
if (pcchAnsiChar)
|
|
{
|
|
*pcchAnsiChar = cchAnsiChar;
|
|
}
|
|
|
|
*ppszAnsiString = pszAnsiString;
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving UnicodeToAnsi().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pszAnsiString)
|
|
{
|
|
::CoTaskMemFree(pszAnsiString);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
#if (0)
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : AnsiToUnicode
|
|
|
|
Synopsis : Convert a array of ANSI character to Unicode.
|
|
|
|
Parameter: LPSTR pszAnsiString - Pointer to ANSI string to be converted to
|
|
ANSI string.
|
|
|
|
DWORD cchAnsiChar - Number of characters, or -1 if pszAnsiString
|
|
is NULL terminated.
|
|
|
|
LPWSTR * ppwszUnicodeString - Pointer to LPWSTR to received the
|
|
converted Unicode string.
|
|
|
|
DWORD * pcchUnicodeChar (Optional) - Pointer to DWORD to receive
|
|
the number of characters
|
|
translated.
|
|
|
|
Remark : Caller must call CoTaskMemFree to free the returned Unicode string.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT AnsiToUnicode (LPSTR pszAnsiString,
|
|
DWORD cchAnsiChar,
|
|
LPWSTR * ppwszUnicodeString,
|
|
DWORD * pcchUnicodeChar)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD cchUnicodeChar = 0;
|
|
LPWSTR pwszUnicodeString = NULL;
|
|
|
|
DebugTrace("Entering AnsiToUnicode().\n");
|
|
|
|
//
|
|
// Make sure parameter is valid.
|
|
//
|
|
if (NULL == pszAnsiString || NULL == ppwszUnicodeString)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: pszAnsiString = %#x, ppwszUnicodeString = %#x.\n",
|
|
hr, pszAnsiString, ppwszUnicodeString);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Determine Unicode length.
|
|
//
|
|
cchUnicodeChar = ::MultiByteToWideChar(CP_ACP, // code page
|
|
0, // performance and mapping flags
|
|
pszAnsiString, // ANSI string
|
|
cchAnsiChar, // number of chars in string
|
|
NULL, // buffer for new Unicode string
|
|
0); // size of buffer
|
|
if (0 == cchUnicodeChar)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: MultiByteToWideChar() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for Unicode string.
|
|
//
|
|
if (!(pwszUnicodeString = (LPWSTR) ::CoTaskMemAlloc(cchUnicodeChar * sizeof(WCHAR))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Conver to ANSI.
|
|
//
|
|
cchUnicodeChar = ::MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
pszAnsiString,
|
|
cchAnsiChar,
|
|
pwszUnicodeString,
|
|
cchUnicodeChar);
|
|
if (0 == cchUnicodeChar)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: MultiByteToWideChar() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return values to caller.
|
|
//
|
|
if (pcchUnicodeChar)
|
|
{
|
|
*pcchUnicodeChar = cchUnicodeChar;
|
|
}
|
|
|
|
*ppwszUnicodeString = pwszUnicodeString;
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving AnsiToUnicode().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pwszUnicodeString)
|
|
{
|
|
::CoTaskMemFree(pwszUnicodeString);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
#endif
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : ByteToHex
|
|
|
|
Synopsis : Convert a byte to hex character.
|
|
|
|
Parameter: BYTE byte - Byte to be converted.
|
|
|
|
Remark : Data must be valid, i.e. 0 through 15.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static inline WCHAR ByteToHex (BYTE byte)
|
|
{
|
|
ATLASSERT(byte < 16);
|
|
|
|
if(byte < 10)
|
|
{
|
|
return (WCHAR) (byte + L'0');
|
|
}
|
|
else
|
|
{
|
|
return (WCHAR) ((byte - 10) + L'A');
|
|
}
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : HexToByte
|
|
|
|
Synopsis : Convert a hex character to byte.
|
|
|
|
Parameter: WCHAR wc - Hex character to be converted.
|
|
|
|
Remark : 0xff is returned if wc is not a hex character.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static inline BYTE HexToByte (WCHAR wc)
|
|
{
|
|
BYTE b;
|
|
|
|
if (!iswxdigit(wc))
|
|
{
|
|
return (BYTE) 0xff;
|
|
}
|
|
|
|
if (iswdigit(wc))
|
|
{
|
|
b = (BYTE) (wc - L'0');
|
|
}
|
|
else if (iswupper(wc))
|
|
{
|
|
b = (BYTE) (wc - L'A' + 10);
|
|
}
|
|
else
|
|
{
|
|
b = (BYTE) (wc - L'a' + 10);
|
|
}
|
|
|
|
return (b);
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : IntBlobToHexString
|
|
|
|
Synopsis : Convert an interger blob to hex string.
|
|
|
|
Parameter: BYTE byte - Byte to be converted.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT IntBlobToHexString (CRYPT_INTEGER_BLOB * pBlob, BSTR * pbstrHex)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pwszStr = NULL;
|
|
LPWSTR pwszTemp = NULL;
|
|
DWORD cbData = 0;
|
|
|
|
DebugTrace("Entering IntBlobToHexString().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pBlob);
|
|
ATLASSERT(pbstrHex);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
if (!pBlob->cbData || !pBlob->pbData)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error: invalid parameter, empty integer blob.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Allocate memory (Need 2 wchars for each byte, plus a NULL character).
|
|
//
|
|
if (NULL == (pwszStr = (LPWSTR) ::CoTaskMemAlloc((pBlob->cbData * 2 + 1) * sizeof(WCHAR))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now convert it to hex string (Remember data is stored in little-endian).
|
|
//
|
|
pwszTemp = pwszStr;
|
|
cbData = pBlob->cbData;
|
|
|
|
while (cbData--)
|
|
{
|
|
//
|
|
// Get the byte.
|
|
//
|
|
BYTE byte = pBlob->pbData[cbData];
|
|
|
|
//
|
|
// Convert upper nibble.
|
|
//
|
|
*pwszTemp++ = ::ByteToHex((BYTE) ((byte & 0xf0) >> 4));
|
|
|
|
//
|
|
// Conver lower nibble.
|
|
//
|
|
*pwszTemp++ = ::ByteToHex((BYTE) (byte & 0x0f));
|
|
}
|
|
|
|
//
|
|
// NULL terminate it.
|
|
//
|
|
*pwszTemp = L'\0';
|
|
|
|
//
|
|
// Return BSTR to caller.
|
|
//
|
|
if (NULL == (*pbstrHex = ::SysAllocString(pwszStr)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pwszStr)
|
|
{
|
|
::CoTaskMemFree(pwszStr);
|
|
}
|
|
|
|
DebugTrace("Leaving IntBlobToHexString().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : BinaryToHexString
|
|
|
|
Synopsis : Convert binary data to hex string.
|
|
|
|
Parameter: BYTE * pbBytes - Bytes to be converted.
|
|
|
|
DWORD cBytes - Number of bytes to be converted.
|
|
|
|
BSTR * pbstrHex - Pointer to BSTR to received converted hex string.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT BinaryToHexString (BYTE * pbBytes, DWORD cBytes, BSTR * pbstrHex)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pwszTemp = NULL;
|
|
LPWSTR pwszStr = NULL;
|
|
|
|
DebugTrace("Entering BinaryToHexString().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pbBytes);
|
|
ATLASSERT(pbstrHex);
|
|
|
|
//
|
|
// Allocate memory. (Need 2 wchars for each byte, plus a NULL character).
|
|
//
|
|
if (NULL == (pwszStr = (LPWSTR) ::CoTaskMemAlloc((cBytes * 2 + 1) * sizeof(WCHAR))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now convert it to hex string.
|
|
//
|
|
pwszTemp = pwszStr;
|
|
|
|
while (cBytes--)
|
|
{
|
|
//
|
|
// Get the byte.
|
|
//
|
|
BYTE byte = *pbBytes++;
|
|
|
|
//
|
|
// Convert upper nibble.
|
|
//
|
|
*pwszTemp++ = ::ByteToHex((BYTE) ((byte & 0xf0) >> 4));
|
|
|
|
//
|
|
// Conver lower nibble.
|
|
//
|
|
*pwszTemp++ = ::ByteToHex((BYTE) (byte & 0x0f));
|
|
}
|
|
|
|
//
|
|
// NULL terminate it.
|
|
//
|
|
*pwszTemp = L'\0';
|
|
|
|
//
|
|
// Return BSTR to caller.
|
|
//
|
|
if (NULL == (*pbstrHex = ::SysAllocString(pwszStr)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: SysAllocString() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pwszStr)
|
|
{
|
|
::CoTaskMemFree(pwszStr);
|
|
}
|
|
|
|
DebugTrace("Leaving BinaryToHexString().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : HexToBinaryString
|
|
|
|
Synopsis : Convert hex string to binary data.
|
|
|
|
Parameter: BSTR bstrHex - Hex string to be converted.
|
|
|
|
BSTR * pbstrBinary - Pointer to BSTR to received converted string.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT HexToBinaryString (BSTR bstrHex, BSTR * pbstrBinary)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pwszHex = NULL;
|
|
LPSTR pbBinary = NULL;
|
|
|
|
DebugTrace("Entering HexToBinaryString().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(bstrHex);
|
|
ATLASSERT(pbstrBinary);
|
|
|
|
DWORD i;
|
|
DWORD cchHex = ::SysStringLen(bstrHex);
|
|
|
|
//
|
|
// Make sure even number of hex chars.
|
|
//
|
|
if (cchHex & 0x00000001)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: bstrHex does not contain even number of characters.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Allocate memory. (Need 1 byte for two hex chars).
|
|
//
|
|
cchHex /= 2;
|
|
if (NULL == (pbBinary = (LPSTR) ::CoTaskMemAlloc(cchHex)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now convert it to binary.
|
|
//
|
|
pwszHex = bstrHex;
|
|
for (i = 0; i < cchHex; i++)
|
|
{
|
|
//
|
|
// Convert upper and lower nibbles.
|
|
//
|
|
#if (0) // DSIE - Work around compiler's bug.
|
|
pbBinary[i] = (BYTE) ((::HexToByte(*pwszHex++) << 4) | ::HexToByte(*pwszHex++));
|
|
#else
|
|
pbBinary[i] = (BYTE) ((::HexToByte(*pwszHex) << 4) | ::HexToByte(*(pwszHex + 1)));
|
|
pwszHex += 2;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Return BSTR to caller.
|
|
//
|
|
if (NULL == (*pbstrBinary = ::SysAllocStringByteLen(pbBinary, cchHex)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: SysAllocStringByteLen() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pbBinary)
|
|
{
|
|
::CoTaskMemFree(pbBinary);
|
|
}
|
|
|
|
DebugTrace("Leaving HexToBinaryString().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : StringToBinary
|
|
|
|
Synopsis : Convert a formatted string to binary value.
|
|
|
|
Parameter: LPCWSTR pwszString - Pointer to string to be converted.
|
|
|
|
DWORD cchString - Number of characters in pwszString.
|
|
|
|
DWORD dwFormat - Conversion format (See WinCrypt.h).
|
|
|
|
PBYTE * ppbBinary - Pointer to pointer to buffer to hold binary
|
|
data.
|
|
|
|
DWORD * pdwBinary - Number of bytes in the binary buffer.
|
|
|
|
Remark : Caller free the buffer by calling CoTaskMemFree().
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT StringToBinary (LPCWSTR pwszString,
|
|
DWORD cchString,
|
|
DWORD dwFormat,
|
|
PBYTE * ppbBinary,
|
|
DWORD * pdwBinary)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PBYTE pbBinary = NULL;
|
|
DWORD dwBinary = 0;
|
|
|
|
DebugTrace("Entering StringToBinary().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pwszString);
|
|
|
|
if (!::CryptStringToBinaryW(pwszString,
|
|
cchString,
|
|
dwFormat,
|
|
NULL,
|
|
&dwBinary,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptStringToBinaryW() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (pdwBinary)
|
|
{
|
|
*pdwBinary = dwBinary;
|
|
}
|
|
|
|
if (ppbBinary)
|
|
{
|
|
if (NULL == (pbBinary = (PBYTE) ::CoTaskMemAlloc(dwBinary)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!::CryptStringToBinaryW(pwszString,
|
|
cchString,
|
|
dwFormat,
|
|
pbBinary,
|
|
&dwBinary,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptStringToBinaryW() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
*ppbBinary = pbBinary;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving StringToBinary().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pbBinary)
|
|
{
|
|
::CoTaskMemFree(pbBinary);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : BinaryToString
|
|
|
|
Synopsis : Convert a binary value to formatted string.
|
|
|
|
Parameter: PBYTE pbBinary - Pointer to buffer of binary data.
|
|
|
|
DWORD cbBinary - Number of bytes in the binary buffer.
|
|
|
|
DWORD dwFormat - Conversion format (See WinCrypt.h).
|
|
|
|
BSTR * pbstrString - Pointer to BSTR to receive converted
|
|
string.
|
|
|
|
DWORD * pcchString - Number of characters in *pbstrString.
|
|
|
|
Remark : Caller free the string by calling SysFreeString().
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT BinaryToString (PBYTE pbBinary,
|
|
DWORD cbBinary,
|
|
DWORD dwFormat,
|
|
BSTR * pbstrString,
|
|
DWORD * pcchString)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD cchString = 0;
|
|
PWSTR pwszString = NULL;
|
|
|
|
DebugTrace("Entering BinaryToString().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pbBinary);
|
|
|
|
if (!::CryptBinaryToStringW(pbBinary,
|
|
cbBinary,
|
|
dwFormat,
|
|
NULL,
|
|
&cchString))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptBinaryToStringW() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (pbstrString)
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(cchString);
|
|
|
|
//
|
|
// Allocate memory.
|
|
//
|
|
if (NULL == (pwszString = (LPWSTR) ::CoTaskMemAlloc(cchString * sizeof(WCHAR))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!::CryptBinaryToStringW(pbBinary,
|
|
cbBinary,
|
|
dwFormat,
|
|
pwszString,
|
|
&cchString))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptBinaryToStringW() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return base64 encoded string to caller.
|
|
//
|
|
if (NULL == (*pbstrString = ::SysAllocString(pwszString)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: SysAllocString() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
if (pcchString)
|
|
{
|
|
*pcchString = cchString;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pwszString)
|
|
{
|
|
::CoTaskMemFree((LPVOID) pwszString);
|
|
}
|
|
|
|
DebugTrace("Leaving BinaryToString().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : BlobToBstr
|
|
|
|
Synopsis : Convert a blob to BSTR.
|
|
|
|
Parameter: DATA_BLOB * pDataBlob - Pointer to blob to be converted to BSTR.
|
|
|
|
BSTR * lpBstr - Pointer to BSTR to receive the converted BSTR.
|
|
|
|
Remark : Caller free allocated memory for the returned BSTR.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT BlobToBstr (DATA_BLOB * pDataBlob,
|
|
BSTR * lpBstr)
|
|
{
|
|
//
|
|
// Return NULL if requested.
|
|
//
|
|
if (!lpBstr)
|
|
{
|
|
DebugTrace("Error: invalid parameter, lpBstr is NULL.\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Make sure parameter is valid.
|
|
//
|
|
if (!pDataBlob->cbData || !pDataBlob->pbData)
|
|
{
|
|
*lpBstr = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Convert to BSTR without code page conversion.
|
|
//
|
|
if (!(*lpBstr = ::SysAllocStringByteLen((LPCSTR) pDataBlob->pbData, pDataBlob->cbData)))
|
|
{
|
|
DebugTrace("Error: out of memory.\n");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : BstrToBlob
|
|
|
|
Synopsis : Convert a BSTR to blob.
|
|
|
|
Parameter: BSTR bstr - BSTR to be converted to blob.
|
|
|
|
DATA_BLOB * lpBlob - Pointer to DATA_BLOB to receive converted blob.
|
|
|
|
Remark : Caller free allocated memory for the returned BLOB.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT BstrToBlob (BSTR bstr,
|
|
DATA_BLOB * lpBlob)
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(lpBlob);
|
|
|
|
//
|
|
// Return NULL if requested.
|
|
//
|
|
if (0 == ::SysStringByteLen(bstr))
|
|
{
|
|
lpBlob->cbData = 0;
|
|
lpBlob->pbData = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Allocate memory.
|
|
//
|
|
lpBlob->cbData = ::SysStringByteLen(bstr);
|
|
if (!(lpBlob->pbData = (LPBYTE) ::CoTaskMemAlloc(lpBlob->cbData)))
|
|
{
|
|
DebugTrace("Error: out of memory.\n");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Convert to blob without code page conversion.
|
|
//
|
|
::CopyMemory(lpBlob->pbData, (LPBYTE) bstr, lpBlob->cbData);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : ExportData
|
|
|
|
Synopsis : Export binary data to a BSTR with specified encoding type.
|
|
|
|
Parameter: DATA_BLOB DataBlob - Binary data blob.
|
|
|
|
CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
|
|
|
|
BSTR * pbstrEncoded - Pointer to BSTR to receive the encoded data.
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT ExportData (DATA_BLOB DataBlob,
|
|
CAPICOM_ENCODING_TYPE EncodingType,
|
|
BSTR * pbstrEncoded)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering ExportData().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pbstrEncoded);
|
|
|
|
//
|
|
// Intialize.
|
|
//
|
|
*pbstrEncoded = NULL;
|
|
|
|
//
|
|
// Make sure there is something to convert.
|
|
//
|
|
if (DataBlob.cbData)
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(DataBlob.pbData);
|
|
|
|
//
|
|
// Determine encoding type.
|
|
//
|
|
switch (EncodingType)
|
|
{
|
|
case CAPICOM_ENCODE_ANY:
|
|
{
|
|
//
|
|
// Fall through to base64.
|
|
//
|
|
}
|
|
|
|
case CAPICOM_ENCODE_BASE64:
|
|
{
|
|
//
|
|
// Base64 encode.
|
|
//
|
|
if (FAILED(hr = ::Base64Encode(DataBlob, pbstrEncoded)))
|
|
{
|
|
DebugTrace("Error [%#x]: Base64Encode() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_ENCODE_BINARY:
|
|
{
|
|
//
|
|
// No encoding needed, simply convert blob to bstr.
|
|
//
|
|
if (FAILED(hr = ::BlobToBstr(&DataBlob, pbstrEncoded)))
|
|
{
|
|
DebugTrace("Error [%#x]: BlobToBstr() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = CAPICOM_E_ENCODE_INVALID_TYPE;
|
|
|
|
DebugTrace("Error [%#x]: invalid CAPICOM_ENCODING_TYPE.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving ExportData().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : ImportData
|
|
|
|
Synopsis : Import encoded data.
|
|
|
|
Parameter: BSTR bstrEncoded - BSTR containing the data to be imported.
|
|
|
|
CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
|
|
|
|
DATA_BLOB * pDataBlob - Pointer to DATA_BLOB to receive the
|
|
decoded data.
|
|
|
|
Remark : There is no need for encoding type parameter, as the encoding type
|
|
will be determined automatically by this routine.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT ImportData (BSTR bstrEncoded,
|
|
CAPICOM_ENCODING_TYPE EncodingType,
|
|
DATA_BLOB * pDataBlob)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering ImportData().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pDataBlob);
|
|
ATLASSERT(bstrEncoded);
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
::ZeroMemory((void *) pDataBlob, sizeof(DATA_BLOB));
|
|
|
|
//
|
|
// Which encoding type?
|
|
//
|
|
switch (EncodingType)
|
|
{
|
|
case CAPICOM_ENCODE_BASE64:
|
|
{
|
|
//
|
|
// Decode data.
|
|
//
|
|
if (FAILED(hr = ::Base64Decode(bstrEncoded, pDataBlob)))
|
|
{
|
|
DebugTrace("Error [%#x]: Base64Decode() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_ENCODE_BINARY:
|
|
{
|
|
//
|
|
// Decode data.
|
|
//
|
|
if (FAILED(hr = ::BstrToBlob(bstrEncoded, pDataBlob)))
|
|
{
|
|
DebugTrace("Error [%#x]: BstrToBlob() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_ENCODE_ANY:
|
|
{
|
|
//
|
|
// Try base64 first.
|
|
//
|
|
if (FAILED(hr = ::Base64Decode(bstrEncoded, pDataBlob)))
|
|
{
|
|
//
|
|
// Try HEX.
|
|
//
|
|
hr = S_OK;
|
|
DebugTrace("Info [%#x]: Base64Decode() failed, try HEX.\n", hr);
|
|
|
|
if (FAILED(hr = ::StringToBinary(bstrEncoded,
|
|
::SysStringLen(bstrEncoded),
|
|
CRYPT_STRING_HEX,
|
|
&pDataBlob->pbData,
|
|
&pDataBlob->cbData)))
|
|
{
|
|
//
|
|
// Try binary.
|
|
//
|
|
hr = S_OK;
|
|
DebugTrace("Info [%#x]: All known decoding failed, so assume binary.\n", hr);
|
|
|
|
if (FAILED(hr = ::BstrToBlob(bstrEncoded, pDataBlob)))
|
|
{
|
|
DebugTrace("Error [%#x]: BstrToBlob() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: invalid encoding type (%d).\n", hr, EncodingType);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving ImportData().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|