mirror of https://github.com/tongzx/nt5src
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.
1347 lines
29 KiB
1347 lines
29 KiB
/*++
|
|
|
|
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
|
|
//
|