1348 lines
29 KiB
C
1348 lines
29 KiB
C
/*++
|
||
|
||
Copyright (c) 1995-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
string.c
|
||
|
||
Abstract:
|
||
|
||
Domain Name System (DNS) Library
|
||
|
||
DNS string routines.
|
||
|
||
Author:
|
||
|
||
Jim Gilroy (jamesg) October 1995
|
||
|
||
Revision History:
|
||
|
||
jamesg Jan 1997 UTF-8, Unicode conversions
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
|
||
|
||
|
||
PSTR
|
||
Dns_CreateStringCopy(
|
||
IN PCHAR pchString,
|
||
IN DWORD cchString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of string.
|
||
|
||
Arguments:
|
||
|
||
pchString -- ptr to string to copy
|
||
|
||
cchString -- length of string, if unknown; if NOT given, then pchString
|
||
MUST be NULL terminated
|
||
|
||
Return Value:
|
||
|
||
Ptr to string copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
LPSTR pstringNew;
|
||
|
||
DNSDBG( TRACE, ( "Dns_CreateStringCopy()\n" ));
|
||
|
||
if ( !pchString )
|
||
{
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return( NULL );
|
||
}
|
||
|
||
// determine string length, if not given
|
||
|
||
if ( !cchString )
|
||
{
|
||
cchString = strlen( pchString );
|
||
}
|
||
|
||
// allocate memory
|
||
|
||
pstringNew = (LPSTR) ALLOCATE_HEAP( cchString+1 );
|
||
if ( !pstringNew )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_MEMORY );
|
||
return( NULL );
|
||
}
|
||
|
||
// copy and NULL terminate
|
||
|
||
RtlCopyMemory(
|
||
pstringNew,
|
||
pchString,
|
||
cchString );
|
||
|
||
pstringNew[cchString] = 0;
|
||
|
||
return( pstringNew );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
Dns_GetBufferLengthForStringCopy(
|
||
IN PCHAR pchString,
|
||
IN DWORD cchString,
|
||
IN DNS_CHARSET CharSetIn,
|
||
IN DNS_CHARSET CharSetOut
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determing length required for copy of string.
|
||
|
||
Arguments:
|
||
|
||
pchString -- ptr to string to get buffer length for
|
||
|
||
cchString -- length of string, if known;
|
||
- if CharSetIn is unicode, then this is length in wide characters
|
||
- if NOT given, then pchString MUST be NULL terminated
|
||
|
||
CharSetIn -- incoming character set
|
||
|
||
CharSetOut -- result character set
|
||
|
||
Return Value:
|
||
|
||
Buffer length (bytes) required for string, includes space for terminating NULL.
|
||
Zero on invalid\unconvertible string. GetLastError() set to ERROR_INVALID_DATA.
|
||
|
||
--*/
|
||
{
|
||
INT length;
|
||
|
||
DNSDBG( TRACE, ( "Dns_GetBufferLengthForStringCopy()\n" ));
|
||
|
||
if ( !pchString )
|
||
{
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return( 0 );
|
||
}
|
||
|
||
//
|
||
// incoming Unicode
|
||
//
|
||
|
||
if ( CharSetIn == DnsCharSetUnicode )
|
||
{
|
||
if ( !cchString )
|
||
{
|
||
cchString = (WORD) wcslen( (PWCHAR)pchString );
|
||
}
|
||
|
||
// unicode to unicode
|
||
|
||
if ( CharSetOut == DnsCharSetUnicode )
|
||
{
|
||
return( (cchString+1) * 2 );
|
||
}
|
||
|
||
// unicode to UTF8
|
||
//
|
||
// use private unicode\utf8 conversion functions
|
||
// - superior to public ones (faster, more robust)
|
||
// - Win95 does not support CP_UTF8
|
||
//
|
||
// for unicode-UTF8 there's no invalid string possible
|
||
|
||
else if ( CharSetOut == DnsCharSetUtf8 )
|
||
{
|
||
#if 0
|
||
length = WideCharToMultiByte(
|
||
CP_UTF8,
|
||
0, // no flags
|
||
(PWCHAR) pchString,
|
||
(INT) cchString,
|
||
NULL,
|
||
0, // call determines required buffer length
|
||
NULL,
|
||
NULL );
|
||
#endif
|
||
length = Dns_UnicodeToUtf8(
|
||
(PWCHAR) pchString,
|
||
(INT) cchString,
|
||
NULL,
|
||
0
|
||
);
|
||
ASSERT( length != 0 || cchString == 0 );
|
||
return( length + 1 );
|
||
}
|
||
|
||
// unicode to ANSI
|
||
// - some chars will NOT convert
|
||
|
||
else if ( CharSetOut == DnsCharSetAnsi )
|
||
{
|
||
length = WideCharToMultiByte(
|
||
CP_ACP,
|
||
0, // no flags
|
||
(PWCHAR) pchString,
|
||
(INT) cchString,
|
||
NULL,
|
||
0, // call determines required buffer length
|
||
NULL,
|
||
NULL
|
||
);
|
||
if ( length == 0 && cchString != 0 )
|
||
{
|
||
goto Failed;
|
||
}
|
||
return( length + 1 );
|
||
}
|
||
|
||
// bad CharSetOut drops to Failed
|
||
}
|
||
|
||
//
|
||
// incoming UTF8
|
||
//
|
||
|
||
else if ( CharSetIn == DnsCharSetUtf8 )
|
||
{
|
||
if ( !cchString )
|
||
{
|
||
cchString = strlen( pchString );
|
||
}
|
||
|
||
// UTF8 to UTF8
|
||
|
||
if ( CharSetOut == DnsCharSetUtf8 )
|
||
{
|
||
return( cchString + 1 );
|
||
}
|
||
|
||
// UTF8 to unicode
|
||
//
|
||
// use private unicode\utf8 conversion functions
|
||
// - superior to public ones (faster, more robust)
|
||
// - Win95 does not support CP_UTF8
|
||
//
|
||
// for UTF8 string can be invalid, catch and return error
|
||
|
||
else if ( CharSetOut == DnsCharSetUnicode )
|
||
{
|
||
#if 0
|
||
length = MultiByteToWideChar(
|
||
CP_UTF8,
|
||
0, // no flags
|
||
pchString,
|
||
(INT) cchString,
|
||
NULL,
|
||
0 // call determines required buffer length
|
||
);
|
||
#endif
|
||
length = Dns_Utf8ToUnicode(
|
||
pchString,
|
||
(INT) cchString,
|
||
NULL,
|
||
0
|
||
);
|
||
if ( length == 0 && cchString != 0 )
|
||
{
|
||
ASSERT( GetLastError() == ERROR_INVALID_DATA );
|
||
return( 0 );
|
||
}
|
||
return( (length+1)*2 );
|
||
}
|
||
|
||
// UTF8 to ANSI
|
||
// - note, result length here is actually buffer length
|
||
|
||
else if ( CharSetOut == DnsCharSetAnsi )
|
||
{
|
||
return Dns_Utf8ToAnsi(
|
||
pchString,
|
||
cchString,
|
||
NULL,
|
||
0 );
|
||
}
|
||
|
||
// bad CharSetOut drops to Failed
|
||
}
|
||
|
||
//
|
||
// incoming ANSI
|
||
//
|
||
|
||
else if ( CharSetIn == DnsCharSetAnsi )
|
||
{
|
||
if ( !cchString )
|
||
{
|
||
cchString = strlen( pchString );
|
||
}
|
||
|
||
// ANSI to ANSI
|
||
|
||
if ( CharSetOut == DnsCharSetAnsi )
|
||
{
|
||
return( cchString + 1 );
|
||
}
|
||
|
||
// ANSI to unicode
|
||
// - should always succeed
|
||
|
||
else if ( CharSetOut == DnsCharSetUnicode )
|
||
{
|
||
length = MultiByteToWideChar(
|
||
CP_ACP,
|
||
0, // no flags
|
||
pchString,
|
||
(INT) cchString,
|
||
NULL,
|
||
0 // call determines required buffer length
|
||
);
|
||
if ( length == 0 && cchString )
|
||
{
|
||
ASSERT( FALSE );
|
||
ASSERT( GetLastError() == ERROR_INVALID_DATA );
|
||
goto Failed;
|
||
}
|
||
return( (length+1) * 2 );
|
||
}
|
||
|
||
// ANSI to UTF8
|
||
// - note, result length here is actually buffer length
|
||
|
||
else if ( CharSetOut == DnsCharSetUtf8 )
|
||
{
|
||
return Dns_AnsiToUtf8(
|
||
pchString,
|
||
cchString,
|
||
NULL,
|
||
0 );
|
||
}
|
||
|
||
// bad CharSetOut drops to Failed
|
||
}
|
||
|
||
// all unhandled cases are failures
|
||
|
||
Failed:
|
||
|
||
DNSDBG( ANY, (
|
||
"ERROR: Dns_GetBufferLengthForStringCopy() failed!\n"
|
||
"\tpchString = %p (%*s)\n"
|
||
"\tcchString = %d\n"
|
||
"\tCharSetIn = %d\n"
|
||
"\tCharSetOut = %d\n",
|
||
pchString,
|
||
cchString, pchString,
|
||
cchString,
|
||
CharSetIn,
|
||
CharSetOut ));
|
||
|
||
SetLastError( ERROR_INVALID_DATA );
|
||
return( 0 );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
Dns_StringCopy(
|
||
OUT PBYTE pBuffer,
|
||
IN OUT PDWORD pdwBufLength,
|
||
IN PCHAR pchString,
|
||
IN DWORD cchString,
|
||
IN DNS_CHARSET CharSetIn,
|
||
IN DNS_CHARSET CharSetOut
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of DNS string.
|
||
|
||
Arguments:
|
||
|
||
pBuffer -- buffer to copy to
|
||
|
||
pdwBufLength -- ptr to length of buffer in bytes;
|
||
if NULL, buffer MUST have adequate length
|
||
if exists, then copy only completed if *pdwBufLength is adequate
|
||
to hold converted result
|
||
|
||
pchString -- ptr to string to copy
|
||
|
||
cchString -- length of string, if known;
|
||
- if CharSetIn is unicode, then this is length in wide characters
|
||
- if NOT given, then pchString MUST be NULL terminated
|
||
|
||
CharSetIn -- incoming character set
|
||
|
||
CharSetOut -- result character set
|
||
|
||
Return Value:
|
||
|
||
Count of bytes written to buffer (includes terminating NULL).
|
||
Zero on error. GetLastError() for status.
|
||
|
||
--*/
|
||
{
|
||
INT length;
|
||
DWORD bufLength;
|
||
|
||
DNSDBG( TRACE, ( "Dns_StringCopy()\n" ));
|
||
DNSDBG( STRING, (
|
||
"Dns_StringCopy()\n"
|
||
"\tpBuffer = %p\n"
|
||
"\tpdwBufLen = %p\n"
|
||
"\tbuf length = %d\n"
|
||
"\tpchString = %p\n"
|
||
"\tcchString = %d\n"
|
||
"\tCharSetIn = %d\n"
|
||
"\tCharSetOut = %d\n",
|
||
pBuffer,
|
||
pdwBufLength,
|
||
pdwBufLength ? *pdwBufLength : 0,
|
||
pchString,
|
||
cchString,
|
||
CharSetIn,
|
||
CharSetOut ));
|
||
|
||
if ( !pchString )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return( 0 );
|
||
}
|
||
|
||
//
|
||
// find string length
|
||
// do this here so don't do it twice if must calculate required buffer length
|
||
//
|
||
|
||
if ( cchString == 0 )
|
||
{
|
||
if ( CharSetIn == DnsCharSetUnicode )
|
||
{
|
||
cchString = (WORD) wcslen( (PWCHAR)pchString );
|
||
}
|
||
else
|
||
{
|
||
cchString = strlen( pchString );
|
||
}
|
||
}
|
||
|
||
//
|
||
// verify adequate buffer length
|
||
//
|
||
// DCR_PERF: ideally make direct copy to buffer and fail if
|
||
// over length, rather than effectively having to convert
|
||
// twice
|
||
//
|
||
|
||
if ( pdwBufLength )
|
||
{
|
||
bufLength = Dns_GetBufferLengthForStringCopy(
|
||
pchString,
|
||
cchString,
|
||
CharSetIn,
|
||
CharSetOut );
|
||
|
||
if ( bufLength == 0 )
|
||
{
|
||
SetLastError( ERROR_INVALID_DATA );
|
||
*pdwBufLength = 0;
|
||
return( 0 );
|
||
}
|
||
if ( bufLength > *pdwBufLength )
|
||
{
|
||
SetLastError( ERROR_MORE_DATA );
|
||
*pdwBufLength = bufLength;
|
||
return( 0 );
|
||
}
|
||
|
||
*pdwBufLength = bufLength;
|
||
}
|
||
|
||
//
|
||
// incoming unicode string
|
||
//
|
||
|
||
if ( CharSetIn == DnsCharSetUnicode )
|
||
{
|
||
// unicode to unicode straight copy
|
||
// - correct for length in wide characters
|
||
|
||
if ( CharSetOut == DnsCharSetUnicode )
|
||
{
|
||
((PWORD)pBuffer)[ cchString ] = 0;
|
||
cchString *= 2;
|
||
RtlCopyMemory(
|
||
pBuffer,
|
||
pchString,
|
||
cchString );
|
||
|
||
return( cchString+2 );
|
||
}
|
||
|
||
// unicode => UTF8
|
||
//
|
||
// use private unicode\utf8 conversion functions
|
||
// - superior to public ones (faster, more robust)
|
||
// - Win95 does not support CP_UTF8
|
||
//
|
||
// for unicode-UTF8 there's no invalid string possible
|
||
|
||
else if ( CharSetOut == DnsCharSetUtf8 )
|
||
{
|
||
#if 0
|
||
length = WideCharToMultiByte(
|
||
CP_UTF8,
|
||
0, // no flags
|
||
(PWCHAR) pchString,
|
||
(INT) cchString,
|
||
pBuffer,
|
||
MAXWORD, // assuming adequate length
|
||
NULL,
|
||
NULL );
|
||
#endif
|
||
length = Dns_UnicodeToUtf8(
|
||
(LPWSTR) pchString,
|
||
cchString,
|
||
pBuffer,
|
||
MAXWORD // assuming adequate length
|
||
);
|
||
ASSERT( length != 0 || cchString == 0 );
|
||
|
||
pBuffer[ length ] = 0;
|
||
return( length + 1 );
|
||
}
|
||
|
||
// unicode => ANSI
|
||
// - this conversion can fail
|
||
|
||
else if ( CharSetOut == DnsCharSetAnsi )
|
||
{
|
||
length = WideCharToMultiByte(
|
||
CP_ACP,
|
||
0, // no flags
|
||
(PWCHAR) pchString,
|
||
(INT) cchString,
|
||
pBuffer,
|
||
MAXWORD, // assuming adequate length
|
||
NULL,
|
||
NULL );
|
||
|
||
if ( length == 0 && cchString != 0 )
|
||
{
|
||
goto Failed;
|
||
}
|
||
pBuffer[ length ] = 0;
|
||
return( length + 1 );
|
||
}
|
||
|
||
// bad CharSetOut drops to Failed
|
||
}
|
||
|
||
//
|
||
// incoming UTF8
|
||
//
|
||
|
||
if ( CharSetIn == DnsCharSetUtf8 )
|
||
{
|
||
// UTF8 to UTF8 straight copy
|
||
|
||
if ( CharSetOut == DnsCharSetUtf8 )
|
||
{
|
||
memcpy(
|
||
pBuffer,
|
||
pchString,
|
||
cchString );
|
||
|
||
pBuffer[cchString] = 0;
|
||
return( cchString + 1 );
|
||
}
|
||
|
||
// UTF8 to unicode conversion
|
||
//
|
||
// use private unicode\utf8 conversion functions
|
||
// - superior to public ones (faster, more robust)
|
||
// - Win95 does not support CP_UTF8
|
||
//
|
||
// UTF8 strings can be invalid, and since sending in "infinite"
|
||
// buffer, this is only possible error
|
||
|
||
else if ( CharSetOut == DnsCharSetUnicode )
|
||
{
|
||
#if 0
|
||
length = MultiByteToWideChar(
|
||
CP_UTF8,
|
||
0, // no flags
|
||
(PCHAR) pchString,
|
||
(INT) cchString,
|
||
(PWCHAR) pBuffer,
|
||
MAXWORD // assuming adequate length
|
||
);
|
||
#endif
|
||
length = Dns_Utf8ToUnicode(
|
||
pchString,
|
||
cchString,
|
||
(LPWSTR) pBuffer,
|
||
MAXWORD
|
||
);
|
||
if ( length == 0 && cchString != 0 )
|
||
{
|
||
ASSERT( GetLastError() == ERROR_INVALID_DATA );
|
||
goto Failed;
|
||
}
|
||
((PWORD)pBuffer)[length] = 0;
|
||
return( (length+1) * 2 );
|
||
}
|
||
|
||
// UTF8 to ANSI
|
||
// - note, result length here is actually buffer length
|
||
|
||
else if ( CharSetOut == DnsCharSetAnsi )
|
||
{
|
||
length = Dns_Utf8ToAnsi(
|
||
pchString,
|
||
cchString,
|
||
pBuffer,
|
||
MAXWORD );
|
||
if ( length == 0 )
|
||
{
|
||
goto Failed;
|
||
}
|
||
return( length );
|
||
}
|
||
|
||
// bad CharSetOut drops to Failed
|
||
}
|
||
|
||
//
|
||
// incoming ANSI
|
||
//
|
||
|
||
if ( CharSetIn == DnsCharSetAnsi )
|
||
{
|
||
// ANSI to ANSI straight copy
|
||
|
||
if ( CharSetOut == DnsCharSetAnsi )
|
||
{
|
||
memcpy(
|
||
pBuffer,
|
||
pchString,
|
||
cchString );
|
||
|
||
pBuffer[cchString] = 0;
|
||
return( cchString + 1 );
|
||
}
|
||
|
||
// ANSI to unicode conversion
|
||
// - ANSI to unicode should not fail
|
||
|
||
else if ( CharSetOut == DnsCharSetUnicode )
|
||
{
|
||
length = MultiByteToWideChar(
|
||
CP_ACP,
|
||
0, // no flags
|
||
(PCHAR) pchString,
|
||
(INT) cchString,
|
||
(PWCHAR) pBuffer,
|
||
MAXWORD // assuming adequate length
|
||
);
|
||
if ( length == 0 && cchString )
|
||
{
|
||
ASSERT( FALSE );
|
||
ASSERT( GetLastError() == ERROR_INVALID_DATA );
|
||
goto Failed;
|
||
}
|
||
((PWORD)pBuffer)[length] = 0;
|
||
return( (length+1) * 2 );
|
||
}
|
||
|
||
// ANSI to UTF8
|
||
// - note, result length here is actually buffer length
|
||
|
||
else if ( CharSetOut == DnsCharSetUtf8 )
|
||
{
|
||
length = Dns_AnsiToUtf8(
|
||
pchString,
|
||
cchString,
|
||
pBuffer,
|
||
MAXWORD );
|
||
if ( length == 0 )
|
||
{
|
||
goto Failed;
|
||
}
|
||
return( length );
|
||
}
|
||
|
||
// bad CharSetOut drops to Failed
|
||
}
|
||
|
||
// all unhandled cases are failures
|
||
|
||
Failed:
|
||
|
||
DNSDBG( ANY, (
|
||
"ERROR: Dns_StringCopy() failed!\n"
|
||
"\tpBuffer = %p\n"
|
||
"\tpdwBufLen = %p\n"
|
||
"\tbuf length = %d\n"
|
||
"\tpchString = %p (%*s)\n"
|
||
"\tcchString = %d\n"
|
||
"\tCharSetIn = %d\n"
|
||
"\tCharSetOut = %d\n",
|
||
pBuffer,
|
||
pdwBufLength,
|
||
pdwBufLength ? *pdwBufLength : 0,
|
||
pchString,
|
||
cchString, pchString,
|
||
cchString,
|
||
CharSetIn,
|
||
CharSetOut ));
|
||
|
||
SetLastError( ERROR_INVALID_DATA );
|
||
return( 0 );
|
||
}
|
||
|
||
|
||
|
||
PVOID
|
||
Dns_StringCopyAllocate(
|
||
IN PCHAR pchString,
|
||
IN DWORD cchString,
|
||
IN DNS_CHARSET CharSetIn,
|
||
IN DNS_CHARSET CharSetOut
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of DNS string
|
||
|
||
Arguments:
|
||
|
||
pchString -- ptr to string to copy
|
||
|
||
cchString -- length of string, if known;
|
||
- if CharSetIn, then this is length in wide characters
|
||
- if NOT given, then pchString MUST be NULL terminated
|
||
|
||
CharSetIn -- flag indicates incoming string is unicode
|
||
|
||
CharSetOut -- flag indicates copy will be in unicode format
|
||
|
||
Return Value:
|
||
|
||
Ptr to string copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PCHAR pnew;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "Dns_StringCopyAllocate()\n" ));
|
||
DNSDBG( STRING, (
|
||
"Dns_StringCopyAllocate( %.*s )\n"
|
||
"\tpchString = %p\n"
|
||
"\tcchString = %d\n"
|
||
"\tUnicodeIn = %d\n"
|
||
"\tUnicodeOut = %d\n",
|
||
cchString,
|
||
pchString,
|
||
pchString,
|
||
cchString,
|
||
CharSetIn,
|
||
CharSetOut ));
|
||
|
||
if ( !pchString )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// determine incoming string length
|
||
// do this explicitly to avoid doing string length operations twice
|
||
//
|
||
|
||
if ( !cchString )
|
||
{
|
||
if ( CharSetIn == DnsCharSetUnicode )
|
||
{
|
||
cchString = (WORD) wcslen( (PWCHAR)pchString );
|
||
}
|
||
else
|
||
{
|
||
cchString = strlen( pchString );
|
||
}
|
||
}
|
||
|
||
//
|
||
// determine required buffer length and allocate
|
||
//
|
||
|
||
length = Dns_GetBufferLengthForStringCopy(
|
||
pchString,
|
||
cchString,
|
||
CharSetIn,
|
||
CharSetOut );
|
||
if ( length == 0 )
|
||
{
|
||
ASSERT( CharSetIn && CharSetOut && GetLastError() == ERROR_INVALID_DATA );
|
||
SetLastError( ERROR_INVALID_DATA );
|
||
return( NULL );
|
||
}
|
||
pnew = (PVOID) ALLOCATE_HEAP( length );
|
||
if ( !pnew )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_MEMORY );
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// copy \ convert string
|
||
// - can fail if conversion not valid
|
||
// (ex. bogus UTF8 string, or attempting
|
||
// conversion from ANSI to UTF8)
|
||
//
|
||
|
||
if ( ! Dns_StringCopy(
|
||
pnew,
|
||
NULL,
|
||
pchString,
|
||
cchString,
|
||
CharSetIn,
|
||
CharSetOut ) )
|
||
{
|
||
FREE_HEAP( pnew );
|
||
return( NULL );
|
||
}
|
||
|
||
return( pnew );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Simple create string copy utilities.
|
||
//
|
||
|
||
PSTR
|
||
Dns_CreateStringCopy_A(
|
||
IN PCSTR pszString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of string.
|
||
|
||
Simple wrapper to handle
|
||
- sizing
|
||
- memory allocation
|
||
- copy of string
|
||
|
||
Arguments:
|
||
|
||
pszString -- ptr to string to copy
|
||
|
||
Return Value:
|
||
|
||
Ptr to string copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSTR pnew;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "Dns_CreateStringCopy_A( %s )\n", pszString ));
|
||
|
||
if ( !pszString )
|
||
{
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return( NULL );
|
||
}
|
||
|
||
// determine string length, if not given
|
||
|
||
length = strlen( pszString ) + 1;
|
||
|
||
// allocate memory
|
||
|
||
pnew = (LPSTR) ALLOCATE_HEAP( length );
|
||
if ( !pnew )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_MEMORY );
|
||
return( NULL );
|
||
}
|
||
|
||
// copy and NULL terminate
|
||
|
||
RtlCopyMemory(
|
||
pnew,
|
||
pszString,
|
||
length );
|
||
|
||
return( pnew );
|
||
}
|
||
|
||
|
||
|
||
PWSTR
|
||
Dns_CreateStringCopy_W(
|
||
IN PCWSTR pwsString
|
||
)
|
||
{
|
||
PWSTR pnew;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "Dns_CreateStringCopy_W( %S )\n", pwsString ));
|
||
|
||
if ( !pwsString )
|
||
{
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return( NULL );
|
||
}
|
||
|
||
// allocate memory
|
||
|
||
length = (wcslen( pwsString ) + 1) * sizeof(WCHAR);
|
||
|
||
pnew = (PWSTR) ALLOCATE_HEAP( length );
|
||
if ( !pnew )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_MEMORY );
|
||
return( NULL );
|
||
}
|
||
|
||
// copy and NULL terminate
|
||
|
||
RtlCopyMemory(
|
||
pnew,
|
||
pwsString,
|
||
length );
|
||
|
||
return( pnew );
|
||
}
|
||
|
||
|
||
|
||
PWSTR
|
||
Dns_CreateConcatenatedString_W(
|
||
IN PCWSTR * pStringArray
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create concatenated string.
|
||
|
||
Arguments:
|
||
|
||
pStringArray -- array of string pointers to concat
|
||
NULL pointer terminates array
|
||
|
||
Return Value:
|
||
|
||
Ptr to concantenated string copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PWSTR pnew;
|
||
PCWSTR pwstr;
|
||
DWORD length;
|
||
DWORD iter;
|
||
|
||
|
||
DNSDBG( TRACE, ( "Dns_CreateConcatenatedString_W()\n" ));
|
||
|
||
if ( !pStringArray )
|
||
{
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// loop determining required length
|
||
//
|
||
|
||
length = 1;
|
||
iter = 0;
|
||
|
||
while ( pwstr = pStringArray[iter++] )
|
||
{
|
||
length += wcslen( pwstr );
|
||
}
|
||
|
||
//
|
||
// allocate
|
||
//
|
||
|
||
pnew = (PWSTR) ALLOCATE_HEAP( length*sizeof(WCHAR) );
|
||
if ( !pnew )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_MEMORY );
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// write concatented string
|
||
//
|
||
|
||
pnew[0] = 0;
|
||
iter = 0;
|
||
|
||
while ( pwstr = pStringArray[iter++] )
|
||
{
|
||
wcscat( pnew, pwstr );
|
||
}
|
||
|
||
DNSDBG( TRACE, ( "Concatented string = %S\n", pnew ));
|
||
return pnew;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// MULTI_SZ routines
|
||
//
|
||
|
||
DWORD
|
||
MultiSz_Length_A(
|
||
IN PCSTR pmszString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine length (size) of MULTI_SZ string.
|
||
|
||
Arguments:
|
||
|
||
pmszString -- ptr to string to size
|
||
|
||
Return Value:
|
||
|
||
Size of MULTI_SZ string (in bytes).
|
||
Includes terminating double NULL.
|
||
|
||
--*/
|
||
{
|
||
PSTR pnext;
|
||
DWORD lengthTotal = 0;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "MultiSz_Length_A( %s )\n", pmszString ));
|
||
|
||
//
|
||
// loop until read at end of strings
|
||
//
|
||
// when we reach the end, we'll be pointing at the second
|
||
// zero in the double null terminator; strlen() will return
|
||
// zero, and we'll add that to our count as 1 and exit
|
||
//
|
||
|
||
pnext = (PSTR) pmszString;
|
||
|
||
while ( pnext )
|
||
{
|
||
length = strlen( pnext ) + 1;
|
||
lengthTotal += length;
|
||
|
||
if ( length == 1 )
|
||
{
|
||
break;
|
||
}
|
||
pnext += length;
|
||
}
|
||
|
||
return lengthTotal;
|
||
}
|
||
|
||
|
||
|
||
PSTR
|
||
MultiSz_NextString_A(
|
||
IN PCSTR pmszString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find next string in MULTI_SZ string
|
||
|
||
Arguments:
|
||
|
||
pmszString -- ptr to multi string
|
||
|
||
Return Value:
|
||
|
||
Next string in MULTI_SZ string.
|
||
NULL if no strings left.
|
||
|
||
--*/
|
||
{
|
||
PSTR pnext;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "MultiSz_NextString_A( %s )\n", pmszString ));
|
||
|
||
//
|
||
// find next string in multi-string
|
||
// - find length of current string
|
||
// - hop over it (inc. null)
|
||
// - if pointing at terminating double-null return
|
||
// NULL to signal end
|
||
//
|
||
|
||
pnext = (PSTR) pmszString;
|
||
if ( !pnext )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
length = strlen( pnext );
|
||
if ( length == 0 )
|
||
{
|
||
DNSDBG( ANY, (
|
||
"ERROR: MultiSz_Next(%p) called on terminator!\n",
|
||
pmszString ));
|
||
return NULL;
|
||
}
|
||
|
||
pnext += length + 1;
|
||
if ( *pnext == 0 )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
return pnext;
|
||
}
|
||
|
||
|
||
|
||
PSTR
|
||
MultiSz_Copy_A(
|
||
IN PCSTR pmszString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of MULTI_SZ string.
|
||
|
||
Simple wrapper to handle
|
||
- sizing
|
||
- memory allocation
|
||
- copy of string
|
||
|
||
Arguments:
|
||
|
||
pmszString -- ptr to string to copy
|
||
|
||
Return Value:
|
||
|
||
Ptr to string copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSTR pnew;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "MultiSz_Copy_A( %s )\n", pmszString ));
|
||
|
||
if ( !pmszString )
|
||
{
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return( NULL );
|
||
}
|
||
|
||
// determine string length, if not given
|
||
|
||
length = MultiSz_Length_A( pmszString );
|
||
|
||
// allocate memory
|
||
|
||
pnew = (LPSTR) ALLOCATE_HEAP( length );
|
||
if ( !pnew )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_MEMORY );
|
||
return( NULL );
|
||
}
|
||
|
||
// copy and NULL terminate
|
||
|
||
RtlCopyMemory(
|
||
pnew,
|
||
pmszString,
|
||
length );
|
||
|
||
return( pnew );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Random
|
||
//
|
||
|
||
INT
|
||
wcsicmp_ThatWorks(
|
||
IN PWSTR pString1,
|
||
IN PWSTR pString2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A version of wcsicmp that actually works.
|
||
|
||
This is just a wrapped on CompareStringW, to hide all the detail
|
||
and give an interface identical to wcsicmp().
|
||
|
||
It uses US English to standardize the comparison.
|
||
|
||
Arguments:
|
||
|
||
pString1 -- first string; must be NULL terminated
|
||
|
||
pString2 -- first second; must be NULL terminated
|
||
|
||
Return Value:
|
||
|
||
-1 -- if string 1 less than string 2
|
||
0 -- strings are equal
|
||
1 -- if string 1 greater than string 2
|
||
|
||
--*/
|
||
{
|
||
INT result;
|
||
|
||
//
|
||
// compare
|
||
// - case conversion done in default DNS locale -- US English
|
||
// this locale correctly matches most non-locale sensitive
|
||
// upper-lower characters
|
||
//
|
||
|
||
result = CompareStringW(
|
||
DNS_DEFAULT_LOCALE,
|
||
NORM_IGNORECASE,
|
||
pString1,
|
||
(-1), // NULL terminated
|
||
pString2,
|
||
(-1) // NULL terminated
|
||
);
|
||
|
||
if ( result == CSTR_EQUAL )
|
||
{
|
||
result = 0;
|
||
}
|
||
else if ( result == CSTR_LESS_THAN )
|
||
{
|
||
result = -1;
|
||
}
|
||
else // greater than or error
|
||
{
|
||
result = 1;
|
||
}
|
||
|
||
return( result );
|
||
}
|
||
|
||
|
||
|
||
LPWSTR
|
||
Dns_GetResourceString(
|
||
IN DWORD dwStringId,
|
||
IN OUT LPWSTR pwszBuffer,
|
||
IN DWORD cbBuffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Loads a string (defined in dnsmsg.mc) from current module
|
||
|
||
Arguments:
|
||
|
||
dwStringId -- The ID of the string to be fetched
|
||
|
||
Return Value:
|
||
|
||
DCR: kill off eyal function
|
||
DEVNOTE: don't understand the value of this return
|
||
-- it's essentially a BOOL, we already know what the ptr is
|
||
it's the buffer passed in
|
||
-- ptr to next byte is useful in continuous write situation
|
||
(ugly and useless in others)
|
||
-- better would just be the same return as LoadString, so we
|
||
both get the success\failure indication and also know
|
||
how many bytes forward we must push our buffer ptr if
|
||
we want to write more
|
||
|
||
Error: NULL
|
||
Success: a pointer to the loaded string
|
||
|
||
--*/
|
||
{
|
||
LPWSTR pStr = NULL;
|
||
DWORD status;
|
||
HANDLE hMod;
|
||
|
||
DNSDBG( TRACE, (
|
||
"Dns_GetStringResource()\n" ));
|
||
|
||
// Get module handle-- No need to close handle, it is just a ptr w/o increment on ref count.
|
||
hMod = GetModuleHandle( NULL );
|
||
if ( !hMod )
|
||
{
|
||
ASSERT( hMod );
|
||
return NULL;
|
||
}
|
||
|
||
status = LoadStringW(
|
||
hMod,
|
||
dwStringId,
|
||
pwszBuffer,
|
||
cbBuffer );
|
||
|
||
if ( status != 0 )
|
||
{
|
||
pStr = pwszBuffer;
|
||
}
|
||
ELSE
|
||
{
|
||
// LoadString returns # of bytes loaded, convert to error.
|
||
status = GetLastError();
|
||
DNSDBG( TRACE, (
|
||
"Error <%lu>: Failed to load string %d\n",
|
||
status, dwStringId ));
|
||
ASSERT ( FALSE );
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"Exit <0x%p> Dns_GetStringResource\n",
|
||
pStr ));
|
||
|
||
return pStr;
|
||
}
|
||
|
||
//
|
||
// End string.c
|
||
//
|