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.
2147 lines
39 KiB
2147 lines
39 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
strings.c
|
|
|
|
Abstract:
|
|
|
|
String routines
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 03-Aug-2001
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "commonp.h"
|
|
|
|
PSTR
|
|
SzCopyA (
|
|
OUT PSTR Destination,
|
|
IN PCSTR Source
|
|
)
|
|
{
|
|
while (*Source) {
|
|
*Destination++ = *Source++;
|
|
}
|
|
|
|
*Destination = 0;
|
|
|
|
return Destination;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SzCopyW (
|
|
OUT PWSTR Destination,
|
|
IN PCWSTR Source
|
|
)
|
|
{
|
|
while (*Source) {
|
|
*Destination++ = *Source++;
|
|
}
|
|
|
|
*Destination = 0;
|
|
|
|
return Destination;
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzNextCharA (
|
|
IN PCSTR CurrentPointer
|
|
)
|
|
{
|
|
PCSTR next;
|
|
|
|
next = _mbsinc (CurrentPointer);
|
|
switch (next - CurrentPointer) {
|
|
|
|
case 3:
|
|
if (CurrentPointer[2] == 0) {
|
|
next = CurrentPointer + 2;
|
|
break;
|
|
}
|
|
case 2:
|
|
if (CurrentPointer[1] == 0) {
|
|
next = CurrentPointer + 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return (PSTR) next;
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzCopyBytesA (
|
|
OUT PSTR Destination,
|
|
IN PCSTR Source,
|
|
IN UINT MaxBytesToCopyIncNul
|
|
)
|
|
{
|
|
PCSTR maxEnd;
|
|
PCSTR sourceEndPlusOne;
|
|
PCSTR sourceEnd;
|
|
UINT_PTR bytes;
|
|
|
|
if (!MaxBytesToCopyIncNul) {
|
|
//
|
|
// Buffer can't fit anything
|
|
//
|
|
|
|
return Destination;
|
|
}
|
|
|
|
//
|
|
// Find the nul terminator, or the last character that
|
|
// will fit in the buffer.
|
|
//
|
|
|
|
maxEnd = (PCSTR) ((PBYTE) Source + MaxBytesToCopyIncNul);
|
|
sourceEndPlusOne = Source;
|
|
|
|
do {
|
|
sourceEnd = sourceEndPlusOne;
|
|
|
|
if (!(*sourceEndPlusOne)) {
|
|
break;
|
|
}
|
|
|
|
sourceEndPlusOne = SzNextCharA (sourceEndPlusOne);
|
|
|
|
} while (sourceEndPlusOne < maxEnd);
|
|
|
|
bytes = (PBYTE) sourceEnd - (PBYTE) Source;
|
|
CopyMemory (Destination, Source, bytes);
|
|
|
|
Destination = (PSTR) ((PBYTE) Destination + bytes);
|
|
*Destination = 0;
|
|
|
|
return Destination;
|
|
}
|
|
|
|
PWSTR
|
|
SzCopyBytesW (
|
|
OUT PWSTR Destination,
|
|
IN PCWSTR Source,
|
|
IN UINT MaxBytesToCopyIncNul
|
|
)
|
|
{
|
|
PCWSTR sourceMax;
|
|
PCWSTR sourceEnd;
|
|
UINT_PTR bytes;
|
|
|
|
if (MaxBytesToCopyIncNul < sizeof (WCHAR)) {
|
|
//
|
|
// Buffer can't fit anything
|
|
//
|
|
|
|
return Destination;
|
|
}
|
|
|
|
sourceMax = (PCWSTR) ((PBYTE) Source + (MaxBytesToCopyIncNul & (~1)) - sizeof (WCHAR));
|
|
sourceEnd = Source;
|
|
|
|
do {
|
|
if (!(*sourceEnd)) {
|
|
break;
|
|
}
|
|
|
|
sourceEnd++;
|
|
} while (sourceEnd < sourceMax);
|
|
|
|
bytes = (PBYTE) sourceEnd - (PBYTE) Source;
|
|
CopyMemory (Destination, Source, bytes);
|
|
|
|
Destination = (PWSTR) ((PBYTE) Destination + bytes);
|
|
*Destination = 0;
|
|
|
|
return Destination;
|
|
}
|
|
|
|
PSTR
|
|
SzCopyBytesABA (
|
|
OUT PSTR Destination,
|
|
IN PCSTR Start,
|
|
IN PCSTR End,
|
|
IN UINT MaxBytesToCopyIncNul
|
|
)
|
|
{
|
|
UINT width;
|
|
|
|
width = ((PBYTE) End - (PBYTE) Start) + sizeof (CHAR);
|
|
|
|
return SzCopyBytesA (Destination, Start, min (width, MaxBytesToCopyIncNul));
|
|
}
|
|
|
|
PWSTR
|
|
SzCopyBytesABW (
|
|
OUT PWSTR Destination,
|
|
IN PCWSTR Start,
|
|
IN PCWSTR End,
|
|
IN UINT MaxBytesToCopyIncNul
|
|
)
|
|
{
|
|
UINT width;
|
|
|
|
width = ((PBYTE) End - (PBYTE) Start) + sizeof (WCHAR);
|
|
|
|
return SzCopyBytesW (Destination, Start, min (width, MaxBytesToCopyIncNul));
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzCatA (
|
|
OUT PSTR Destination,
|
|
IN PCSTR Source
|
|
)
|
|
{
|
|
Destination = SzGetEndA (Destination);
|
|
return SzCopyA (Destination, Source);
|
|
}
|
|
|
|
PWSTR
|
|
SzCatW (
|
|
OUT PWSTR Destination,
|
|
IN PCWSTR Source
|
|
)
|
|
{
|
|
Destination = SzGetEndW (Destination);
|
|
return SzCopyW (Destination, Source);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SzMatchA (
|
|
IN PCSTR String1,
|
|
IN PCSTR String2
|
|
)
|
|
{
|
|
while (*String1) {
|
|
if (*String1++ != *String2++) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return *String2 == 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SzMemMatchA (
|
|
IN PCSTR Buffer1,
|
|
IN PCSTR Buffer2,
|
|
IN SIZE_T ByteCount
|
|
)
|
|
{
|
|
SIZE_T u;
|
|
PCSTR end;
|
|
|
|
end = (PCSTR) ((PBYTE) Buffer1 + ByteCount);
|
|
|
|
while (Buffer1 < end) {
|
|
|
|
if (*Buffer1 != *Buffer2++) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (*Buffer1++ == 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SzMemMatchW (
|
|
IN PCWSTR Buffer1,
|
|
IN PCWSTR Buffer2,
|
|
IN SIZE_T ByteCount
|
|
)
|
|
{
|
|
SIZE_T u;
|
|
PCWSTR end;
|
|
|
|
end = (PCWSTR) ((PBYTE) Buffer1 + ByteCount);
|
|
|
|
while (Buffer1 < end) {
|
|
|
|
if (*Buffer1 != *Buffer2++) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (*Buffer1++ == 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
INT
|
|
SzCompareBytesA (
|
|
IN PCSTR String1,
|
|
IN PCSTR String2,
|
|
IN SIZE_T ByteCount
|
|
)
|
|
{
|
|
PCSTR end;
|
|
INT bytesLeft;
|
|
INT thisCharBytes;
|
|
UINT ch1;
|
|
UINT ch2;
|
|
PCSTR maxString1;
|
|
PCSTR maxString2;
|
|
|
|
if (!ByteCount) {
|
|
return 0;
|
|
}
|
|
|
|
bytesLeft = (INT) ByteCount;
|
|
MYASSERT ((SIZE_T) bytesLeft == ByteCount);
|
|
|
|
maxString1 = (PCSTR) ((PBYTE) String1 + ByteCount);
|
|
maxString2 = (PCSTR) ((PBYTE) String2 + ByteCount);
|
|
|
|
do {
|
|
//
|
|
// Compute ch1. We use this code instead of _mbsnextc, so we can
|
|
// support mismatched code pages.
|
|
//
|
|
|
|
end = SzNextCharA (String1);
|
|
if (end > maxString1) {
|
|
end = maxString1;
|
|
}
|
|
|
|
ch1 = 0;
|
|
do {
|
|
ch1 = (ch1 << 8) | *String1++;
|
|
} while (String1 < end);
|
|
|
|
//
|
|
// Compute ch2.
|
|
//
|
|
|
|
end = SzNextCharA (String2);
|
|
if (end > maxString2) {
|
|
end = maxString2;
|
|
}
|
|
|
|
ch2 = 0;
|
|
do {
|
|
ch2 = (ch2 << 8) | *String2++;
|
|
} while (String2 < end);
|
|
|
|
//
|
|
// Compare
|
|
//
|
|
|
|
if (ch1 != ch2) {
|
|
return (INT) ch1 - (INT) ch2;
|
|
}
|
|
|
|
} while (String1 < maxString1 && String2 < maxString2);
|
|
|
|
//
|
|
// One or both strings terminated
|
|
//
|
|
|
|
if (String1 < maxString1) {
|
|
return -1;
|
|
}
|
|
|
|
if (String2 < maxString2) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
INT
|
|
SzICompareBytesA (
|
|
IN PCSTR String1,
|
|
IN PCSTR String2,
|
|
IN SIZE_T ByteCount
|
|
)
|
|
{
|
|
PCSTR end;
|
|
INT bytesLeft;
|
|
INT thisCharBytes;
|
|
UINT ch1;
|
|
UINT ch2;
|
|
PCSTR maxString1;
|
|
PCSTR maxString2;
|
|
|
|
if (!ByteCount) {
|
|
return 0;
|
|
}
|
|
|
|
bytesLeft = (INT) ByteCount;
|
|
MYASSERT ((SIZE_T) bytesLeft == ByteCount);
|
|
|
|
maxString1 = (PCSTR) ((PBYTE) String1 + ByteCount);
|
|
maxString2 = (PCSTR) ((PBYTE) String2 + ByteCount);
|
|
|
|
do {
|
|
//
|
|
// Compute ch1. We use this code instead of _mbsnextc, so we can
|
|
// support mismatched code pages.
|
|
//
|
|
|
|
end = SzNextCharA (String1);
|
|
if (end > maxString1) {
|
|
end = maxString1;
|
|
}
|
|
|
|
ch1 = 0;
|
|
do {
|
|
ch1 = (ch1 << 8) | (*String1++);
|
|
} while (String1 < end);
|
|
|
|
ch1 = tolower (ch1);
|
|
|
|
//
|
|
// Compute ch2.
|
|
//
|
|
|
|
end = SzNextCharA (String2);
|
|
if (end > maxString2) {
|
|
end = maxString2;
|
|
}
|
|
|
|
ch2 = 0;
|
|
do {
|
|
ch2 = (ch2 << 8) | (*String2++);
|
|
} while (String2 < end);
|
|
|
|
ch2 = tolower (ch2);
|
|
|
|
//
|
|
// Compare
|
|
//
|
|
|
|
if (ch1 != ch2) {
|
|
return (INT) ch1 - (INT) ch2;
|
|
}
|
|
|
|
//
|
|
// If this is the end of the string, then we're done
|
|
//
|
|
|
|
if (!ch1) {
|
|
return 0;
|
|
}
|
|
|
|
} while (String1 < maxString1 && String2 < maxString2);
|
|
|
|
//
|
|
// One or both strings terminated
|
|
//
|
|
|
|
if (String1 < maxString1) {
|
|
return -1;
|
|
}
|
|
|
|
if (String2 < maxString2) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzUnsignedToHexA (
|
|
IN ULONG_PTR Number,
|
|
OUT PSTR String
|
|
)
|
|
{
|
|
PSTR p;
|
|
|
|
*String++ = '0';
|
|
*String++ = 'x';
|
|
|
|
p = String + (sizeof (Number) * 2);
|
|
*p = 0;
|
|
|
|
while (p > String) {
|
|
p--;
|
|
*p = ((CHAR) Number & 0x0F) + '0';
|
|
if (*p > '9') {
|
|
*p += 'A' - ('9' + 1);
|
|
}
|
|
|
|
Number >>= 4;
|
|
}
|
|
|
|
return String + (sizeof (Number) * 2);
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SzUnsignedToHexW (
|
|
IN ULONG_PTR Number,
|
|
OUT PWSTR String
|
|
)
|
|
{
|
|
PWSTR p;
|
|
|
|
*String++ = L'0';
|
|
*String++ = L'x';
|
|
|
|
p = String + (sizeof (Number) * 2);
|
|
*p = 0;
|
|
|
|
while (p > String) {
|
|
p--;
|
|
*p = ((WCHAR) Number & 0x0F) + L'0';
|
|
if (*p > L'9') {
|
|
*p += L'A' - (L'9' + 1);
|
|
}
|
|
|
|
Number >>= 4;
|
|
}
|
|
|
|
return String + (sizeof (Number) * 2);
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzUnsignedToDecA (
|
|
IN ULONG_PTR Number,
|
|
OUT PSTR String
|
|
)
|
|
{
|
|
UINT digits;
|
|
ULONG_PTR temp;
|
|
PSTR p;
|
|
|
|
temp = Number;
|
|
digits = 1;
|
|
|
|
while (temp > 9) {
|
|
digits++;
|
|
temp /= 10;
|
|
}
|
|
|
|
p = String + digits;
|
|
*p = 0;
|
|
|
|
while (p > String) {
|
|
p--;
|
|
*p = (CHAR) (Number % 10) + '0';
|
|
Number /= 10;
|
|
}
|
|
|
|
return String + digits;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SzUnsignedToDecW (
|
|
IN ULONG_PTR Number,
|
|
OUT PWSTR String
|
|
)
|
|
{
|
|
UINT digits;
|
|
ULONG_PTR temp;
|
|
PWSTR p;
|
|
|
|
temp = Number;
|
|
digits = 1;
|
|
|
|
while (temp > 9) {
|
|
digits++;
|
|
temp /= 10;
|
|
}
|
|
|
|
p = String + digits;
|
|
*p = 0;
|
|
|
|
while (p > String) {
|
|
p--;
|
|
*p = (WCHAR) (Number % 10) + L'0';
|
|
Number /= 10;
|
|
}
|
|
|
|
return String + digits;
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzSignedToDecA (
|
|
IN LONG_PTR Number,
|
|
OUT PSTR String
|
|
)
|
|
{
|
|
if (Number < 0) {
|
|
*String++ = '-';
|
|
Number = -Number;
|
|
}
|
|
|
|
return SzUnsignedToDecA (Number, String);
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SzSignedToDecW (
|
|
IN LONG_PTR Number,
|
|
OUT PWSTR String
|
|
)
|
|
{
|
|
if (Number < 0) {
|
|
*String++ = L'-';
|
|
Number = -Number;
|
|
}
|
|
|
|
return SzUnsignedToDecW (Number, String);
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzFindPrevCharA (
|
|
IN PCSTR StartStr,
|
|
IN PCSTR CurrPtr,
|
|
IN MBCHAR SearchChar
|
|
)
|
|
{
|
|
PCSTR ptr = CurrPtr;
|
|
|
|
while (ptr > StartStr) {
|
|
|
|
ptr = _mbsdec (StartStr, ptr);
|
|
if (!ptr) {
|
|
ptr = StartStr;
|
|
}
|
|
|
|
if (_mbsnextc (ptr) == SearchChar) {
|
|
return (PSTR) ptr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SzFindPrevCharW (
|
|
IN PCWSTR StartStr,
|
|
IN PCWSTR CurrPtr,
|
|
IN WCHAR SearchChar
|
|
)
|
|
{
|
|
PCWSTR ptr = CurrPtr;
|
|
|
|
while (ptr > StartStr) {
|
|
ptr--;
|
|
|
|
if (*ptr == SearchChar) {
|
|
return (PWSTR) ptr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
INT
|
|
pGetHexDigit (
|
|
IN INT c
|
|
)
|
|
{
|
|
if (c >= '0' && c <= '9') {
|
|
return (c - '0');
|
|
}
|
|
|
|
if (c >= 'a' && c <= 'f') {
|
|
return (c - 'a' + 10);
|
|
}
|
|
|
|
if (c >= 'A' && c <= 'F') {
|
|
return (c - 'A' + 10);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
ULONG
|
|
SzToNumberA (
|
|
IN PCSTR String,
|
|
OUT PCSTR *EndOfNumber OPTIONAL
|
|
)
|
|
{
|
|
ULONG d = 0;
|
|
INT v;
|
|
|
|
if (_mbsnextc (String) == '0' &&
|
|
tolower (_mbsnextc (SzNextCharA (String))) == 'x'
|
|
) {
|
|
//
|
|
// Get hex value
|
|
//
|
|
|
|
String = SzNextCharA (String);
|
|
String = SzNextCharA (String);
|
|
|
|
for (;;) {
|
|
v = pGetHexDigit ((INT) _mbsnextc (String));
|
|
if (v == -1) {
|
|
break;
|
|
}
|
|
d = (d * 16) + v;
|
|
|
|
String = SzNextCharA (String);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Get decimal value
|
|
//
|
|
|
|
while (_mbsnextc (String) >= '0' && _mbsnextc (String) <= '9') {
|
|
d = (d * 10) + (_mbsnextc (String) - '0');
|
|
String = SzNextCharA (String);
|
|
}
|
|
}
|
|
|
|
if (EndOfNumber) {
|
|
*EndOfNumber = String;
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
|
|
ULONG
|
|
SzToNumberW (
|
|
IN PCWSTR String,
|
|
OUT PCWSTR *EndOfNumber OPTIONAL
|
|
)
|
|
{
|
|
ULONG d = 0;
|
|
INT v;
|
|
|
|
if (String[0] == L'0' && towlower (String[1]) == L'x') {
|
|
//
|
|
// Get hex value
|
|
//
|
|
|
|
String += 2;
|
|
|
|
for (;;) {
|
|
v = pGetHexDigit ((INT) (*String));
|
|
if (v == -1) {
|
|
break;
|
|
}
|
|
d = (d * 16) + v;
|
|
|
|
String++;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Get decimal value
|
|
//
|
|
|
|
while (*String >= L'0' && *String <= L'9') {
|
|
d = (d * 10) + (*String - L'0');
|
|
String++;
|
|
}
|
|
}
|
|
|
|
if (EndOfNumber) {
|
|
*EndOfNumber = String;
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
SzToULongLongA (
|
|
IN PCSTR String,
|
|
OUT PCSTR *EndOfNumber OPTIONAL
|
|
)
|
|
{
|
|
ULONGLONG d = 0;
|
|
INT v;
|
|
|
|
if (_mbsnextc (String) == '0' &&
|
|
tolower (_mbsnextc (SzNextCharA (String))) == 'x'
|
|
) {
|
|
//
|
|
// Get hex value
|
|
//
|
|
|
|
String = SzNextCharA (String);
|
|
String = SzNextCharA (String);
|
|
|
|
for (;;) {
|
|
v = pGetHexDigit ((INT) _mbsnextc (String));
|
|
if (v == -1) {
|
|
break;
|
|
}
|
|
d = (d * 16) + (ULONGLONG) v;
|
|
|
|
String = SzNextCharA (String);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Get decimal value
|
|
//
|
|
|
|
while (_mbsnextc (String) >= '0' && _mbsnextc (String) <= '9') {
|
|
d = (d * 10) + (ULONGLONG) (_mbsnextc (String) - '0');
|
|
String = SzNextCharA (String);
|
|
}
|
|
}
|
|
|
|
if (EndOfNumber) {
|
|
*EndOfNumber = String;
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
ULONGLONG
|
|
SzToULongLongW (
|
|
IN PCWSTR String,
|
|
OUT PCWSTR *EndOfNumber OPTIONAL
|
|
)
|
|
{
|
|
ULONGLONG d = 0;
|
|
INT v;
|
|
|
|
if (String[0] == L'0' && tolower (String[1]) == L'x') {
|
|
//
|
|
// Get hex value
|
|
//
|
|
|
|
String += 2;
|
|
|
|
for (;;) {
|
|
v = pGetHexDigit ((INT) (*String));
|
|
if (v == -1) {
|
|
break;
|
|
}
|
|
d = (d * 16) + (ULONGLONG) v;
|
|
|
|
String++;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Get decimal value
|
|
//
|
|
|
|
while (*String >= L'0' && *String <= L'9') {
|
|
d = (d * 10) + (ULONGLONG) (*String - L'0');
|
|
String++;
|
|
}
|
|
}
|
|
|
|
if (EndOfNumber) {
|
|
*EndOfNumber = String;
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
LONGLONG
|
|
SzToLongLongA (
|
|
IN PCSTR String,
|
|
OUT PCSTR *EndOfNumber OPTIONAL
|
|
)
|
|
{
|
|
LONGLONG l;
|
|
|
|
if (_mbsnextc (String) == '-') {
|
|
String = SzNextCharA (String);
|
|
|
|
//
|
|
// Get decimal value
|
|
//
|
|
|
|
l = 0;
|
|
|
|
while (_mbsnextc (String) >= '0' && _mbsnextc (String) <= '9') {
|
|
l = (l * 10) + (LONGLONG) (_mbsnextc (String) - '0');
|
|
String = SzNextCharA (String);
|
|
}
|
|
|
|
l = -l;
|
|
|
|
if (EndOfNumber) {
|
|
*EndOfNumber = String;
|
|
}
|
|
|
|
return l;
|
|
|
|
} else {
|
|
return (LONGLONG) SzToULongLongA (String, EndOfNumber);
|
|
}
|
|
}
|
|
|
|
LONGLONG
|
|
SzToLongLongW (
|
|
IN PCWSTR String,
|
|
OUT PCWSTR *EndOfNumber OPTIONAL
|
|
)
|
|
{
|
|
LONGLONG l;
|
|
|
|
if (*String == L'-') {
|
|
String++;
|
|
|
|
//
|
|
// Get decimal value
|
|
//
|
|
|
|
l = 0;
|
|
|
|
while (*String >= L'0' && *String <= L'9') {
|
|
l = (l * 10) + (LONGLONG) (*String - L'0');
|
|
String++;
|
|
}
|
|
|
|
l = -l;
|
|
|
|
if (EndOfNumber) {
|
|
*EndOfNumber = String;
|
|
}
|
|
|
|
return l;
|
|
|
|
} else {
|
|
return (LONGLONG) SzToULongLongW (String, EndOfNumber);
|
|
}
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzCopyNextCharA (
|
|
OUT PSTR Dest,
|
|
IN PCSTR Source
|
|
)
|
|
{
|
|
PCSTR nextSrc;
|
|
|
|
nextSrc = SzNextCharA (Source);
|
|
switch (nextSrc - Source) {
|
|
case 3:
|
|
*Dest++ = *Source++;
|
|
case 2:
|
|
*Dest++ = *Source++;
|
|
case 1:
|
|
*Dest++ = *Source;
|
|
break;
|
|
}
|
|
|
|
return Dest;
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzTrimLastCharA (
|
|
IN OUT PSTR String,
|
|
IN MBCHAR LogChar
|
|
)
|
|
{
|
|
PSTR end;
|
|
|
|
end = SzGetEndA (String);
|
|
end = _mbsdec (String, end);
|
|
|
|
if ((end >= String) && (_mbsnextc (end) == LogChar)) {
|
|
do {
|
|
*end = 0;
|
|
end = _mbsdec (String, end);
|
|
} while ((end >= String) && (_mbsnextc (end) == LogChar));
|
|
|
|
return end < String ? String : end;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SzTrimLastCharW (
|
|
IN OUT PWSTR String,
|
|
IN WCHAR LogChar
|
|
)
|
|
{
|
|
PWSTR end;
|
|
|
|
end = SzGetEndW (String);
|
|
end--;
|
|
|
|
if ((end >= String) && (*end == LogChar)) {
|
|
do {
|
|
*end = 0;
|
|
end--;
|
|
} while ((end >= String) && (*end == LogChar));
|
|
|
|
return end < String ? String : end;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzAppendWackA (
|
|
IN PSTR String
|
|
)
|
|
{
|
|
PCSTR last;
|
|
|
|
if (!String) {
|
|
return NULL;
|
|
}
|
|
|
|
last = String;
|
|
|
|
while (*String) {
|
|
last = String;
|
|
String = SzNextCharA (String);
|
|
}
|
|
|
|
if (_mbsnextc (last) != '\\') {
|
|
*String = '\\';
|
|
String++;
|
|
*String = 0;
|
|
}
|
|
|
|
return String;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SzAppendWackW (
|
|
IN PWSTR String
|
|
)
|
|
{
|
|
PCWSTR last;
|
|
|
|
if (!String) {
|
|
return NULL;
|
|
}
|
|
|
|
if (*String) {
|
|
String = SzGetEndW (String);
|
|
last = String - 1;
|
|
} else {
|
|
last = String;
|
|
}
|
|
|
|
if (*last != '\\') {
|
|
*String = L'\\';
|
|
String++;
|
|
*String = 0;
|
|
}
|
|
|
|
return String;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
SzGetFileNameFromPathA (
|
|
IN PCSTR Path
|
|
)
|
|
{
|
|
PCSTR p;
|
|
|
|
p = _mbsrchr (Path, '\\');
|
|
if (p) {
|
|
p = SzNextCharA (p);
|
|
} else {
|
|
p = Path;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
PCWSTR
|
|
SzGetFileNameFromPathW (
|
|
IN PCWSTR Path
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
|
|
p = wcsrchr (Path, L'\\');
|
|
if (p) {
|
|
p++;
|
|
} else {
|
|
p = Path;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
SzGetFileExtensionFromPathA (
|
|
IN PCSTR Path
|
|
)
|
|
{
|
|
PCSTR p;
|
|
MBCHAR ch;
|
|
PCSTR returnPtr = NULL;
|
|
|
|
p = Path;
|
|
|
|
while (*p) {
|
|
ch = _mbsnextc (p);
|
|
|
|
if (ch == '.') {
|
|
returnPtr = SzNextCharA (p);
|
|
} else if (ch == '\\') {
|
|
returnPtr = NULL;
|
|
}
|
|
|
|
p = SzNextCharA (p);
|
|
}
|
|
|
|
return returnPtr;
|
|
}
|
|
|
|
PCWSTR
|
|
SzGetFileExtensionFromPathW (
|
|
IN PCWSTR Path
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
PCWSTR returnPtr = NULL;
|
|
|
|
p = Path;
|
|
|
|
while (*p) {
|
|
if (*p == L'.') {
|
|
returnPtr = p + 1;
|
|
} else if (*p == L'\\') {
|
|
returnPtr = NULL;
|
|
}
|
|
|
|
p++;
|
|
}
|
|
|
|
return returnPtr;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
SzGetDotExtensionFromPathA (
|
|
IN PCSTR Path
|
|
)
|
|
{
|
|
PCSTR p;
|
|
MBCHAR ch;
|
|
PCSTR returnPtr = NULL;
|
|
|
|
p = Path;
|
|
|
|
while (*p) {
|
|
ch = _mbsnextc (p);
|
|
|
|
if (ch == '.') {
|
|
returnPtr = p;
|
|
} else if (ch == '\\') {
|
|
returnPtr = NULL;
|
|
}
|
|
|
|
p = SzNextCharA (p);
|
|
}
|
|
|
|
if (!returnPtr) {
|
|
return p;
|
|
}
|
|
|
|
return returnPtr;
|
|
}
|
|
|
|
PCWSTR
|
|
SzGetDotExtensionFromPathW (
|
|
IN PCWSTR Path
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
PCWSTR returnPtr = NULL;
|
|
|
|
p = Path;
|
|
|
|
while (*p) {
|
|
if (*p == L'.') {
|
|
returnPtr = p;
|
|
} else if (*p == L'\\') {
|
|
returnPtr = NULL;
|
|
}
|
|
|
|
p++;
|
|
}
|
|
|
|
if (!returnPtr) {
|
|
return p;
|
|
}
|
|
|
|
return returnPtr;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
SzSkipSpaceA (
|
|
IN PCSTR String
|
|
)
|
|
{
|
|
if (!String) {
|
|
return NULL;
|
|
}
|
|
|
|
while (_ismbcspace (_mbsnextc (String))) {
|
|
String = SzNextCharA (String);
|
|
}
|
|
|
|
return String;
|
|
}
|
|
|
|
PCWSTR
|
|
SzSkipSpaceW (
|
|
IN PCWSTR String
|
|
)
|
|
{
|
|
if (!String) {
|
|
return NULL;
|
|
}
|
|
|
|
while (iswspace (*String)) {
|
|
String++;
|
|
}
|
|
|
|
return String;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
SzSkipSpaceRA (
|
|
IN PCSTR BaseString,
|
|
IN PCSTR String OPTIONAL
|
|
)
|
|
{
|
|
if (!String) {
|
|
String = SzGetEndA (BaseString);
|
|
}
|
|
|
|
if (*String == 0) {
|
|
String = _mbsdec (BaseString, String);
|
|
}
|
|
|
|
while (String >= BaseString) {
|
|
|
|
if (!_ismbcspace (_mbsnextc (String))) {
|
|
return String;
|
|
}
|
|
|
|
String = _mbsdec (BaseString, String);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PCWSTR
|
|
SzSkipSpaceRW (
|
|
IN PCWSTR BaseString,
|
|
IN PCWSTR String // can be any char along BaseString
|
|
)
|
|
{
|
|
if (!String) {
|
|
String = SzGetEndW (BaseString);
|
|
}
|
|
|
|
if (*String == 0) {
|
|
String--;
|
|
}
|
|
|
|
while (String >= BaseString) {
|
|
|
|
if (!iswspace (*String)) {
|
|
return String;
|
|
}
|
|
|
|
String--;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PSTR
|
|
SzTruncateTrailingSpaceA (
|
|
IN OUT PSTR String
|
|
)
|
|
{
|
|
PSTR end;
|
|
MBCHAR ch;
|
|
|
|
end = String;
|
|
|
|
while (*String) {
|
|
ch = _mbsnextc (String);
|
|
String = SzNextCharA (String);
|
|
|
|
if (!_ismbcspace (ch)) {
|
|
end = String;
|
|
}
|
|
}
|
|
|
|
*end = 0;
|
|
|
|
return end;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SzTruncateTrailingSpaceW (
|
|
IN OUT PWSTR String
|
|
)
|
|
{
|
|
PWSTR end;
|
|
WCHAR ch;
|
|
|
|
end = String;
|
|
|
|
while (*String) {
|
|
ch = *String++;
|
|
|
|
if (!iswspace (ch)) {
|
|
end = String;
|
|
}
|
|
}
|
|
|
|
*end = 0;
|
|
|
|
return end;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SzIsPrintA (
|
|
IN PCSTR String
|
|
)
|
|
|
|
{
|
|
while (*String && _ismbcprint (_mbsnextc (String))) {
|
|
String = SzNextCharA (String);
|
|
}
|
|
|
|
return *String == 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SzIsPrintW (
|
|
IN PCWSTR String
|
|
)
|
|
|
|
{
|
|
while (*String && iswprint (*String)) {
|
|
String++;
|
|
}
|
|
|
|
return *String == 0;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
SzIFindSubStringA (
|
|
IN PCSTR String,
|
|
IN PCSTR SubString
|
|
)
|
|
|
|
{
|
|
PCSTR start;
|
|
PCSTR middle;
|
|
PCSTR subStrMiddle;
|
|
PCSTR end;
|
|
|
|
end = (PSTR) ((PBYTE) String + SzByteCountA (String) - SzByteCountA (SubString));
|
|
|
|
for (start = String ; start <= end ; start = SzNextCharA (start)) {
|
|
middle = start;
|
|
subStrMiddle = SubString;
|
|
|
|
while (*subStrMiddle &&
|
|
_mbctolower (_mbsnextc (subStrMiddle)) == _mbctolower (_mbsnextc (middle))
|
|
) {
|
|
middle = SzNextCharA (middle);
|
|
subStrMiddle = SzNextCharA (subStrMiddle);
|
|
}
|
|
|
|
if (!(*subStrMiddle)) {
|
|
return start;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PCWSTR
|
|
SzIFindSubStringW (
|
|
IN PCWSTR String,
|
|
IN PCWSTR SubString
|
|
)
|
|
|
|
{
|
|
PCWSTR start;
|
|
PCWSTR middle;
|
|
PCWSTR subStrMiddle;
|
|
PCWSTR end;
|
|
|
|
end = (PWSTR) ((PBYTE) String + SzByteCountW (String) - SzByteCountW (SubString));
|
|
|
|
for (start = String ; start <= end ; start++) {
|
|
middle = start;
|
|
subStrMiddle = SubString;
|
|
|
|
while (*subStrMiddle && (towlower (*subStrMiddle) == towlower (*middle))) {
|
|
middle++;
|
|
subStrMiddle++;
|
|
}
|
|
|
|
if (!(*subStrMiddle)) {
|
|
return start;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
UINT
|
|
SzCountInstancesOfLcharA (
|
|
IN PCSTR String,
|
|
IN MBCHAR LogChar
|
|
)
|
|
{
|
|
UINT count;
|
|
|
|
if (!String) {
|
|
return 0;
|
|
}
|
|
|
|
count = 0;
|
|
while (*String) {
|
|
if (_mbsnextc (String) == LogChar) {
|
|
count++;
|
|
}
|
|
|
|
String = SzNextCharA (String);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
UINT
|
|
SzCountInstancesOfLcharW (
|
|
IN PCWSTR String,
|
|
IN WCHAR LogChar
|
|
)
|
|
{
|
|
UINT count;
|
|
|
|
if (!String) {
|
|
return 0;
|
|
}
|
|
|
|
count = 0;
|
|
while (*String) {
|
|
if (*String == LogChar) {
|
|
count++;
|
|
}
|
|
|
|
String++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
UINT
|
|
SzICountInstancesOfLcharA (
|
|
IN PCSTR String,
|
|
IN MBCHAR LogChar
|
|
)
|
|
{
|
|
UINT count;
|
|
|
|
if (!String) {
|
|
return 0;
|
|
}
|
|
|
|
LogChar = _mbctolower (LogChar);
|
|
|
|
count = 0;
|
|
while (*String) {
|
|
if (_mbctolower (_mbsnextc (String)) == LogChar) {
|
|
count++;
|
|
}
|
|
|
|
String = SzNextCharA (String);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
UINT
|
|
SzICountInstancesOfLcharW (
|
|
IN PCWSTR String,
|
|
IN WCHAR LogChar
|
|
)
|
|
{
|
|
UINT count;
|
|
|
|
if (!String) {
|
|
return 0;
|
|
}
|
|
|
|
LogChar = towlower (LogChar);
|
|
|
|
count = 0;
|
|
while (*String) {
|
|
if (towlower (*String) == LogChar) {
|
|
count++;
|
|
}
|
|
|
|
String++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SzReplaceA (
|
|
IN OUT PSTR Buffer,
|
|
IN SIZE_T MaxSize,
|
|
IN PSTR ReplaceStartPos, // within Buffer
|
|
IN PSTR ReplaceEndPos,
|
|
IN PCSTR NewString
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
SIZE_T oldSubStringLength;
|
|
SIZE_T newSubStringLength;
|
|
SIZE_T currentStringLength;
|
|
SIZE_T offset;
|
|
SIZE_T bytesToMove;
|
|
|
|
//
|
|
// Check assumptions.
|
|
//
|
|
MYASSERT(Buffer);
|
|
MYASSERT(ReplaceStartPos && ReplaceStartPos >= Buffer);
|
|
MYASSERT(ReplaceEndPos && ReplaceEndPos >= ReplaceStartPos); //lint !e613
|
|
MYASSERT(ReplaceEndPos <= Buffer + MaxSize); //lint !e613
|
|
MYASSERT(NewString);
|
|
|
|
//
|
|
// Compute sizes.
|
|
//
|
|
oldSubStringLength = (PBYTE) ReplaceEndPos - (PBYTE) ReplaceStartPos;
|
|
newSubStringLength = SzByteCountA (NewString);
|
|
currentStringLength = SzSizeA (Buffer);
|
|
offset = newSubStringLength - oldSubStringLength;
|
|
|
|
//
|
|
// Make sure there is enough room in the buffer to perform the replace
|
|
// operation.
|
|
//
|
|
if (currentStringLength + offset > MaxSize) {
|
|
DEBUGMSG((DBG_WARNING, "ERROR: Buffer to small to perform string replacement."));
|
|
} else {
|
|
|
|
//
|
|
// Shift the rest of the buffer to adjust it to the size of the new string.
|
|
//
|
|
if (offset != 0) {
|
|
|
|
//
|
|
// Shift right side of string to make room for new data.
|
|
//
|
|
|
|
bytesToMove = currentStringLength;
|
|
bytesToMove -= (PBYTE) ReplaceEndPos - (PBYTE) Buffer;
|
|
|
|
MoveMemory (
|
|
(PBYTE) ReplaceEndPos + offset,
|
|
(PBYTE) ReplaceEndPos,
|
|
bytesToMove
|
|
);
|
|
}
|
|
|
|
//
|
|
// Now, copy in the string.
|
|
//
|
|
CopyMemory (ReplaceStartPos, NewString, newSubStringLength); //lint !e668
|
|
|
|
//
|
|
// String replacement completed successfully.
|
|
//
|
|
result = TRUE;
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SzReplaceW (
|
|
IN OUT PWSTR Buffer,
|
|
IN SIZE_T MaxSize,
|
|
IN PWSTR ReplaceStartPos, // within Buffer
|
|
IN PWSTR ReplaceEndPos,
|
|
IN PCWSTR NewString
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
SIZE_T oldSubStringLength;
|
|
SIZE_T newSubStringLength;
|
|
SIZE_T currentStringLength;
|
|
SIZE_T offset;
|
|
SIZE_T bytesToMove;
|
|
|
|
//
|
|
// Check assumptions.
|
|
//
|
|
MYASSERT(Buffer);
|
|
MYASSERT(ReplaceStartPos && ReplaceStartPos >= Buffer);
|
|
MYASSERT(ReplaceEndPos && ReplaceEndPos >= ReplaceStartPos); //lint !e613
|
|
MYASSERT(ReplaceEndPos <= Buffer + MaxSize); //lint !e613
|
|
MYASSERT(NewString);
|
|
|
|
//
|
|
// Compute sizes.
|
|
//
|
|
oldSubStringLength = (PBYTE) ReplaceEndPos - (PBYTE) ReplaceStartPos;
|
|
newSubStringLength = SzByteCountW (NewString);
|
|
currentStringLength = SzSizeW (Buffer);
|
|
offset = newSubStringLength - oldSubStringLength;
|
|
|
|
//
|
|
// Make sure there is enough room in the buffer to perform the replace
|
|
// operation.
|
|
//
|
|
if (currentStringLength + offset > MaxSize) {
|
|
DEBUGMSG((DBG_WARNING, "ERROR: Buffer to small to perform string replacement."));
|
|
} else {
|
|
|
|
//
|
|
// Shift the rest of the buffer to adjust it to the size of the new string.
|
|
//
|
|
if (offset != 0) {
|
|
|
|
//
|
|
// Shift right side of string to make room for new data.
|
|
//
|
|
|
|
bytesToMove = currentStringLength;
|
|
bytesToMove -= (PBYTE) ReplaceEndPos - (PBYTE) Buffer;
|
|
|
|
MoveMemory (
|
|
(PBYTE) ReplaceEndPos + offset,
|
|
(PBYTE) ReplaceEndPos,
|
|
bytesToMove
|
|
);
|
|
}
|
|
|
|
//
|
|
// Now, copy in the string.
|
|
//
|
|
CopyMemory (ReplaceStartPos, NewString, newSubStringLength); //lint !e668
|
|
|
|
//
|
|
// String replacement completed successfully.
|
|
//
|
|
result = TRUE;
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
UINT
|
|
SzCountInstancesOfSubStringA (
|
|
IN PCSTR SourceString,
|
|
IN PCSTR SearchString
|
|
)
|
|
{
|
|
PCSTR p;
|
|
UINT count;
|
|
UINT searchTchars;
|
|
|
|
count = 0;
|
|
p = SourceString;
|
|
searchTchars = SzTcharCountA (SearchString);
|
|
|
|
if (!searchTchars) {
|
|
return 0;
|
|
}
|
|
|
|
while (p = SzFindSubStringA (p, SearchString)) { //lint !e720
|
|
count++;
|
|
p += searchTchars;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
UINT
|
|
SzCountInstancesOfSubStringW (
|
|
IN PCWSTR SourceString,
|
|
IN PCWSTR SearchString
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
UINT count;
|
|
UINT searchTchars;
|
|
|
|
count = 0;
|
|
p = SourceString;
|
|
searchTchars = SzTcharCountW (SearchString);
|
|
|
|
if (!searchTchars) {
|
|
return 0;
|
|
}
|
|
|
|
while (p = SzFindSubStringW (p, SearchString)) { //lint !e720
|
|
count++;
|
|
p += searchTchars;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
UINT
|
|
SzICountInstancesOfSubStringA (
|
|
IN PCSTR SourceString,
|
|
IN PCSTR SearchString
|
|
)
|
|
{
|
|
PCSTR p;
|
|
UINT count;
|
|
UINT searchTchars;
|
|
|
|
count = 0;
|
|
p = SourceString;
|
|
searchTchars = SzTcharCountA (SearchString);
|
|
|
|
if (!searchTchars) {
|
|
return 0;
|
|
}
|
|
|
|
while (p = SzIFindSubStringA (p, SearchString)) { //lint !e720
|
|
count++;
|
|
p += searchTchars;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
UINT
|
|
SzICountInstancesOfSubStringW (
|
|
IN PCWSTR SourceString,
|
|
IN PCWSTR SearchString
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
UINT count;
|
|
UINT searchTchars;
|
|
|
|
count = 0;
|
|
p = SourceString;
|
|
searchTchars = SzTcharCountW (SearchString);
|
|
|
|
if (!searchTchars) {
|
|
return 0;
|
|
}
|
|
|
|
while (p = SzIFindSubStringW (p, SearchString)) { //lint !e720
|
|
count++;
|
|
p += searchTchars;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MszEnumFirstA (
|
|
OUT PMULTISZ_ENUMA MultiSzEnum,
|
|
IN PCSTR MultiSzStr
|
|
)
|
|
{
|
|
ZeroMemory (MultiSzEnum, sizeof (MULTISZ_ENUMA));
|
|
MultiSzEnum->Buffer = MultiSzStr;
|
|
|
|
if ((MultiSzStr == NULL) || (MultiSzStr [0] == 0)) {
|
|
return FALSE;
|
|
}
|
|
|
|
MultiSzEnum->CurrentString = MultiSzStr;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MszEnumFirstW (
|
|
OUT PMULTISZ_ENUMW MultiSzEnum,
|
|
IN PCWSTR MultiSzStr
|
|
)
|
|
{
|
|
ZeroMemory (MultiSzEnum, sizeof (MULTISZ_ENUMA));
|
|
MultiSzEnum->Buffer = MultiSzStr;
|
|
|
|
if ((MultiSzStr == NULL) || (MultiSzStr [0] == 0)) {
|
|
return FALSE;
|
|
}
|
|
|
|
MultiSzEnum->CurrentString = MultiSzStr;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MszEnumNextA (
|
|
IN OUT PMULTISZ_ENUMA MultiSzEnum
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
|
|
if (MultiSzEnum->CurrentString && (*MultiSzEnum->CurrentString)) {
|
|
MultiSzEnum->CurrentString = SzGetEndA (MultiSzEnum->CurrentString) + 1;
|
|
result = (MultiSzEnum->CurrentString [0] != 0);
|
|
|
|
if (!result) {
|
|
MultiSzEnum->CurrentString = NULL;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MszEnumNextW (
|
|
IN OUT PMULTISZ_ENUMW MultiSzEnum
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
|
|
if (MultiSzEnum->CurrentString && (*MultiSzEnum->CurrentString)) {
|
|
MultiSzEnum->CurrentString = SzGetEndW (MultiSzEnum->CurrentString) + 1;
|
|
result = (MultiSzEnum->CurrentString [0] != 0);
|
|
|
|
if (!result) {
|
|
MultiSzEnum->CurrentString = NULL;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
PCSTR
|
|
MszFindStringA (
|
|
IN PCSTR MultiSz,
|
|
IN PCSTR String
|
|
)
|
|
{
|
|
MULTISZ_ENUMA multiSzEnum;
|
|
|
|
ZeroMemory (&multiSzEnum, sizeof (multiSzEnum));
|
|
if (!String || *String == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MszEnumFirstA (&multiSzEnum, MultiSz)) {
|
|
do {
|
|
if (SzMatchA (String, multiSzEnum.CurrentString)) {
|
|
break;
|
|
}
|
|
} while (MszEnumNextA (&multiSzEnum));
|
|
}
|
|
|
|
return multiSzEnum.CurrentString;
|
|
}
|
|
|
|
|
|
PCWSTR
|
|
MszFindStringW (
|
|
IN PCWSTR MultiSz,
|
|
IN PCWSTR String
|
|
)
|
|
{
|
|
MULTISZ_ENUMW multiSzEnum;
|
|
|
|
ZeroMemory (&multiSzEnum, sizeof (multiSzEnum));
|
|
if (!String || *String == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MszEnumFirstW (&multiSzEnum, MultiSz)) {
|
|
do {
|
|
if (SzMatchW (String, multiSzEnum.CurrentString)) {
|
|
break;
|
|
}
|
|
} while (MszEnumNextW (&multiSzEnum));
|
|
}
|
|
|
|
return multiSzEnum.CurrentString;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
MszIFindStringA (
|
|
IN PCSTR MultiSz,
|
|
IN PCSTR String
|
|
)
|
|
{
|
|
MULTISZ_ENUMA multiSzEnum;
|
|
|
|
ZeroMemory (&multiSzEnum, sizeof (multiSzEnum));
|
|
if (!String || *String == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MszEnumFirstA (&multiSzEnum, MultiSz)) {
|
|
do {
|
|
if (SzIMatchA (String, multiSzEnum.CurrentString)) {
|
|
break;
|
|
}
|
|
} while (MszEnumNextA (&multiSzEnum));
|
|
}
|
|
|
|
return multiSzEnum.CurrentString;
|
|
}
|
|
|
|
|
|
PCWSTR
|
|
MszIFindStringW (
|
|
IN PCWSTR MultiSz,
|
|
IN PCWSTR String
|
|
)
|
|
{
|
|
MULTISZ_ENUMW multiSzEnum;
|
|
|
|
ZeroMemory (&multiSzEnum, sizeof (multiSzEnum));
|
|
if (!String || *String == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MszEnumFirstW (&multiSzEnum, MultiSz)) {
|
|
do {
|
|
if (SzIMatchW (String, multiSzEnum.CurrentString)) {
|
|
break;
|
|
}
|
|
} while (MszEnumNextW (&multiSzEnum));
|
|
}
|
|
|
|
return multiSzEnum.CurrentString;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
SzConcatenatePathsA (
|
|
IN OUT PSTR PathBuffer,
|
|
IN PCSTR PathSuffix, OPTIONAL
|
|
IN UINT BufferTchars
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Concatenate two path strings together, supplying a path separator character
|
|
(\) if necessary between the two parts.
|
|
|
|
Arguments:
|
|
|
|
PathBuffer - Specifies the base path, which can end with a backslash.
|
|
Receives the joined path.
|
|
|
|
PathSuffix - Specifies the suffix to concatinate to the base path
|
|
specified by PathBuffer. It can start with a backslash. If NULL is
|
|
specified, then PathBuffer will be terminated with a backslash.
|
|
|
|
BufferTchars - Specifies the size, in CHARs (ANSI) or WCHARs (Unicode), of
|
|
PathBuffer. The inbound PathBuffer string must fit within this size.
|
|
If the result is truncated, it will fill the buffer as much as
|
|
possible.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the end of the string in PathBuffer.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTR p;
|
|
PSTR q;
|
|
PSTR end;
|
|
PSTR lastChar;
|
|
PCSTR srcEnd;
|
|
PCSTR nextChar;
|
|
PCSTR srcMax;
|
|
|
|
if (!PathBuffer || !BufferTchars) {
|
|
return NULL;
|
|
}
|
|
|
|
MYASSERT (BufferTchars > 128); // BUGBUG -- temporary porting aide
|
|
|
|
p = SzGetEndA (PathBuffer);
|
|
end = PathBuffer + BufferTchars;
|
|
|
|
MYASSERT (p < end); // inbound string must always fit in the buffer
|
|
end--;
|
|
if (p == end) {
|
|
return p; // inbound path fills buffer completely
|
|
}
|
|
|
|
lastChar = _mbsdec (PathBuffer, p);
|
|
if ((lastChar < PathBuffer) || (*lastChar != '\\')) {
|
|
*p++ = '\\';
|
|
}
|
|
|
|
if (PathSuffix) {
|
|
if (*PathSuffix == '\\') {
|
|
PathSuffix++;
|
|
}
|
|
|
|
srcEnd = PathSuffix;
|
|
srcMax = PathSuffix + (end - p);
|
|
|
|
while (*srcEnd) {
|
|
nextChar = SzNextCharA (srcEnd);
|
|
if (nextChar > srcMax) {
|
|
break;
|
|
}
|
|
|
|
srcEnd = nextChar;
|
|
}
|
|
|
|
while (PathSuffix < srcEnd) {
|
|
*p++ = *PathSuffix++;
|
|
}
|
|
}
|
|
|
|
*p = 0;
|
|
return p;
|
|
}
|
|
|
|
|
|
PCWSTR
|
|
SzConcatenatePathsW (
|
|
IN OUT PWSTR PathBuffer,
|
|
IN PCWSTR PathSuffix, OPTIONAL
|
|
IN UINT BufferTchars
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Concatenate two path strings together, supplying a path separator character
|
|
(\) if necessary between the two parts.
|
|
|
|
Arguments:
|
|
|
|
PathBuffer - Specifies the base path, which can end with a backslash.
|
|
Receives the joined path.
|
|
|
|
PathSuffix - Specifies the suffix to concatinate to the base path
|
|
specified by PathBuffer. It can start with a backslash. If NULL is
|
|
specified, then PathBuffer will be terminated with a backslash.
|
|
|
|
BufferTchars - Specifies the size, in CHARs (ANSI) or WCHARs (Unicode), of
|
|
PathBuffer. The inbound PathBuffer string must fit within this size.
|
|
If the result is truncated, it will fill the buffer as much as
|
|
possible.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the end of the string in PathBuffer.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR p;
|
|
PWSTR q;
|
|
PWSTR end;
|
|
PWSTR lastChar;
|
|
PCWSTR srcEnd;
|
|
PCWSTR srcMax;
|
|
|
|
if (!PathBuffer || !BufferTchars) {
|
|
return NULL;
|
|
}
|
|
|
|
MYASSERT (BufferTchars > 128); // BUGBUG -- temporary porting aide
|
|
|
|
p = SzGetEndW (PathBuffer);
|
|
end = PathBuffer + BufferTchars;
|
|
|
|
MYASSERT (p < end); // inbound string must always fit in the buffer
|
|
end--;
|
|
if (p == end) {
|
|
return p; // inbound path fills buffer completely
|
|
}
|
|
|
|
lastChar = p - 1;
|
|
if ((lastChar < PathBuffer) || (*lastChar != L'\\')) {
|
|
*p++ = L'\\';
|
|
}
|
|
|
|
if (PathSuffix) {
|
|
if (*PathSuffix == L'\\') {
|
|
PathSuffix++;
|
|
}
|
|
|
|
srcEnd = SzGetEndW (PathSuffix);
|
|
srcMax = PathSuffix + (end - p);
|
|
srcEnd = min (srcEnd, srcMax);
|
|
|
|
while (PathSuffix < srcEnd) {
|
|
*p++ = *PathSuffix++;
|
|
}
|
|
}
|
|
|
|
*p = 0;
|
|
return p;
|
|
}
|
|
|
|
|