--- /dev/null
+/*
+ * PROJECT: ReactOS kernel-mode tests
+ * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: Test for ntstrsafe.h functions
+ * COPYRIGHT: Copyright 2018 Hernán Di Pietro <hernan.di.pietro@gmail.com>
+ */
+
+#define KMT_EMULATE_KERNEL
+#include <kmt_test.h>
+#include <ntstrsafe.h>
+#include <ntdef.h>
+#include <ndk/rtlfuncs.h>
+
+#define TESTAPI static void
+
+TESTAPI
+Test_RtlUnicodeStringPrintf()
+{
+ WCHAR Buffer[1024];
+ WCHAR OvrBuffer[1024];
+ WCHAR BufferSmall[2];
+ WCHAR BufferSmall2[7];
+ UNICODE_STRING UsString;
+ const WCHAR FormatStringInts[] = L"%d %d %d";
+ const WCHAR FormatStringStrs[] = L"%s %s %s";
+ const WCHAR Result[] = L"1 2 3";
+ UNICODE_STRING UsStringNull;
+
+ /* No zeros (Don't assume UNICODE_STRINGS are NULL terminated) */
+
+ RtlFillMemory(Buffer, sizeof(Buffer), 0xAA);
+ RtlFillMemory(BufferSmall, sizeof(BufferSmall), 0xAA);
+ RtlFillMemory(BufferSmall2, sizeof(BufferSmall2), 0xAA);
+
+ /* STATUS_SUCCESS test */
+
+ UsString.Buffer = Buffer;
+ UsString.Length = 0;
+ UsString.MaximumLength = sizeof(Buffer);
+
+ ok_eq_hex(RtlUnicodeStringPrintf(&UsString, FormatStringInts, 1, 2, 3), STATUS_SUCCESS);
+ ok_eq_uint(UsString.Length, sizeof(Result) - sizeof(WCHAR));
+ ok_eq_uint(UsString.MaximumLength, sizeof(Buffer));
+ ok_eq_wchar(UsString.Buffer[0], L'1');
+ ok_eq_wchar(UsString.Buffer[1], L' ');
+ ok_eq_wchar(UsString.Buffer[2], L'2');
+ ok_eq_wchar(UsString.Buffer[3], L' ');
+ ok_eq_wchar(UsString.Buffer[4], L'3');
+ ok_eq_wchar(UsString.Buffer[5], (WCHAR) 0);
+
+ /* STATUS_BUFFER_OVERFLOW tests */
+
+ UsString.Buffer = BufferSmall;
+ UsString.Length = 0;
+ UsString.MaximumLength = sizeof(BufferSmall);
+
+ ok_eq_hex(RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"AAA", L"BBB", L"CCC"), STATUS_BUFFER_OVERFLOW);
+ ok_eq_uint(UsString.Length, UsString.MaximumLength);
+ ok_eq_char(UsString.Buffer[0], L'A');
+ ok_eq_char(UsString.Buffer[1], (WCHAR)0);
+
+ UsString.Buffer = BufferSmall2;
+ UsString.Length = 0;
+ UsString.MaximumLength = sizeof(BufferSmall2);
+
+ ok_eq_hex(RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"0123", L"4567", L"89AB"), STATUS_BUFFER_OVERFLOW);
+ ok_eq_uint(UsString.Length, UsString.MaximumLength);
+ ok_eq_char(UsString.Buffer[0], L'0');
+ ok_eq_char(UsString.Buffer[1], L'1');
+ ok_eq_char(UsString.Buffer[2], L'2');
+ ok_eq_char(UsString.Buffer[3], L'3');
+ ok_eq_char(UsString.Buffer[4], L' ');
+ ok_eq_char(UsString.Buffer[5], L'4');
+ ok_eq_char(UsString.Buffer[6], (WCHAR) 0);
+
+ ///* STATUS_INVALID_PARAMETER tests */
+
+ ok_eq_hex(RtlUnicodeStringPrintf(NULL, FormatStringStrs, L"AAA", L"BBB", L"CCC"), STATUS_INVALID_PARAMETER);
+ ok_eq_hex(RtlUnicodeStringPrintf(&UsString, NULL, L"AAA", L"BBB", L"CCC"), STATUS_INVALID_PARAMETER);
+
+ UsStringNull.Buffer = (PWCH)NULL;
+ UsStringNull.Length = 0;
+ UsStringNull.MaximumLength = 0;
+ ok_eq_bool(RtlUnicodeStringPrintf(&UsStringNull, FormatStringStrs, L"AAA", L"BBB", L"CCC"), STATUS_INVALID_PARAMETER);
+
+ /* Test for buffer overruns */
+
+ RtlFillMemory(Buffer, sizeof(Buffer), 0xAA);
+ RtlFillMemory(OvrBuffer, sizeof(OvrBuffer), 0xAA);
+ UsString.Buffer = Buffer;
+ UsString.Length = 0;
+ UsString.MaximumLength = 16 * sizeof(WCHAR);
+
+ ok_eq_hex(RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"abc", L"def", L"ghi"), STATUS_SUCCESS);
+ ok_eq_uint(UsString.Length, sizeof(L"abc def ghi") -sizeof(WCHAR));
+ ok_eq_char(UsString.Buffer[11], (WCHAR)0);
+ ok_eq_uint(0, memcmp(OvrBuffer + 12, Buffer + 12, sizeof(Buffer) - (12 * sizeof(WCHAR))));
+}
+
+TESTAPI
+Test_RtlUnicodeStringPrintfEx()
+{
+ WCHAR Buffer[32];
+ WCHAR BufferSmall[8] = { 0 };
+ WCHAR OvrBuffer[1024];
+ UNICODE_STRING UsString, RemString;
+ const WCHAR FormatStringInts[] = L"%d %d %d";
+ const WCHAR FormatStringStrs[] = L"%s %s %s";
+ const WCHAR Result[] = L"1 2 3";
+
+ /* No zeros (Don't assume UNICODE_STRINGS are NULL terminated) */
+
+ RtlFillMemory(Buffer, sizeof(Buffer), 0xAA);
+
+ UsString.Buffer = Buffer;
+ UsString.Length = 0;
+ UsString.MaximumLength = sizeof(Buffer);
+
+ RemString.Buffer = (PWCH)NULL;
+ RemString.Length = 0;
+ RemString.MaximumLength = 0;
+
+ /* STATUS_SUCCESS test, fill behind flag: low-byte as fill character */
+
+ ok_eq_hex(RtlUnicodeStringPrintfEx(&UsString, &RemString, STRSAFE_FILL_BEHIND | 0xFF, FormatStringInts, 1, 2, 3), STATUS_SUCCESS);
+
+ ok_eq_uint(UsString.Length, sizeof(Result) - sizeof(WCHAR));
+ ok_eq_uint(UsString.MaximumLength, sizeof(Buffer));
+ ok_eq_uint(memcmp(UsString.Buffer, Result, sizeof(Result) - sizeof(WCHAR)), 0);
+
+ ok_eq_pointer(RemString.Buffer, UsString.Buffer + (UsString.Length / sizeof(WCHAR)));
+ ok_eq_uint(RemString.Length, 0);
+ ok_eq_uint(RemString.MaximumLength, UsString.MaximumLength - UsString.Length);
+
+ /* STATUS_BUFFER_OVERFLOW test */
+
+ UsString.Buffer = BufferSmall;
+ UsString.Length = 0;
+ UsString.MaximumLength = sizeof(BufferSmall);
+
+ RemString.Buffer = (PWCH)NULL;
+ RemString.Length = 0;
+ RemString.MaximumLength = 0;
+
+ ok_eq_hex(RtlUnicodeStringPrintfEx(&UsString, &RemString, 0, FormatStringStrs, L"AAA", L"BBB", L"CCC"), STATUS_BUFFER_OVERFLOW);
+ ok_eq_uint(UsString.Length, UsString.MaximumLength);
+ ok_eq_char(UsString.Buffer[0], L'A');
+ ok_eq_char(UsString.Buffer[1], L'A');
+ ok_eq_char(UsString.Buffer[2], L'A');
+ ok_eq_char(UsString.Buffer[3], L' ');
+ ok_eq_char(UsString.Buffer[4], L'B');
+ ok_eq_char(UsString.Buffer[5], L'B');
+ ok_eq_char(UsString.Buffer[6], L'B');
+ ok_eq_char(UsString.Buffer[7], (WCHAR)0);
+
+ // Takes \0 into account
+ ok_eq_pointer(RemString.Buffer, UsString.Buffer + (UsString.Length - 1) / sizeof(WCHAR));
+ ok_eq_uint(RemString.Length, 0);
+ ok_eq_uint(RemString.MaximumLength, 2);
+
+ /* Test for buffer overruns */
+
+ RtlFillMemory(Buffer, sizeof(Buffer), 0xAA);
+ RtlFillMemory(OvrBuffer, sizeof(OvrBuffer), 0xAA);
+ UsString.Buffer = Buffer;
+ UsString.Length = 0;
+ UsString.MaximumLength = 16 * sizeof(WCHAR);
+
+ ok_eq_hex(RtlUnicodeStringPrintfEx(&UsString, &RemString, 0, FormatStringStrs, L"abc", L"def", L"ghi"), STATUS_SUCCESS);
+ ok_eq_uint(UsString.Length, sizeof(L"abc def ghi") - sizeof(WCHAR));
+ ok_eq_char(UsString.Buffer[11], (WCHAR)0);
+ ok_eq_uint(0, memcmp(OvrBuffer + 12, Buffer + 12, sizeof(Buffer) - (12 * sizeof(WCHAR))));
+}
+
+START_TEST(RtlStrSafe)
+{
+ Test_RtlUnicodeStringPrintf();
+ Test_RtlUnicodeStringPrintfEx();
+}
#define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)((dwFlags) & 0x000000FF))
#endif
+#define STRSAFE_FILL_BEHIND STRSAFE_FILL_BEHIND_NULL
+#define STRSAFE_ZERO_LENGTH_ON_FAILURE STRSAFE_NULL_ON_FAILURE
+
typedef char *STRSAFE_LPSTR;
typedef const char *STRSAFE_LPCSTR;
typedef wchar_t *STRSAFE_LPWSTR;
NTSTRSAFEAPI RtlStringCatNExWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCWSTR pszSrc,size_t cchToAppend,STRSAFE_LPWSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags);
NTSTRSAFEAPI RtlStringVPrintfWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,STRSAFE_LPCSTR pszFormat,va_list argList);
NTSTRSAFEAPI RtlStringVPrintfWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,STRSAFE_LPCWSTR pszFormat,va_list argList);
+NTSTRSAFEAPI RtlStringVPrintfWorkerLenW(STRSAFE_LPWSTR pszDest,size_t cchDest,STRSAFE_LPCWSTR pszFormat,size_t* pcchDestNewLen, va_list argList);
NTSTRSAFEAPI RtlStringVPrintfExWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags,STRSAFE_LPCSTR pszFormat,va_list argList);
NTSTRSAFEAPI RtlStringVPrintfExWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPWSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags,STRSAFE_LPCWSTR pszFormat,va_list argList);
+NTSTRSAFEAPI RtlStringVPrintfExWorkerLenW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCWSTR pszFormat, size_t* pcchDestNewLen, va_list argList);
+NTSTRSAFEAPI RtlUnicodeStringValidate(PCUNICODE_STRING SourceString);
NTSTRSAFEAPI
RtlStringLengthWorkerA(
return Status;
}
-NTSTRSAFEAPI RtlStringCopyWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,STRSAFE_LPCSTR pszSrc)
+NTSTRSAFEAPI RtlStringCopyWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCSTR pszSrc)
{
NTSTATUS Status = STATUS_SUCCESS;
if (cchDest==0)
return Status;
}
-NTSTRSAFEAPI RtlStringCopyWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,STRSAFE_LPCWSTR pszSrc)
+NTSTRSAFEAPI RtlStringCopyWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCWSTR pszSrc)
{
NTSTATUS Status = STATUS_SUCCESS;
if (cchDest==0)
return Status;
}
-NTSTRSAFEAPI RtlStringCopyExWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCSTR pszSrc,STRSAFE_LPSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags)
+NTSTRSAFEAPI RtlStringCopyExWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPCSTR pszSrc,
+ STRSAFE_LPSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPSTR pszDestEnd = pszDest;
return Status;
}
-NTSTRSAFEAPI RtlStringCopyExWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCWSTR pszSrc,STRSAFE_LPWSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags)
+NTSTRSAFEAPI RtlStringCopyExWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPCWSTR pszSrc,
+ STRSAFE_LPWSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPWSTR pszDestEnd = pszDest;
return Status;
}
-NTSTRSAFEAPI RtlStringCopyNWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,STRSAFE_LPCSTR pszSrc,size_t cchSrc)
+NTSTRSAFEAPI RtlStringCopyNWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCSTR pszSrc,size_t cchSrc)
{
NTSTATUS Status = STATUS_SUCCESS;
if (cchDest==0)
return Status;
}
-NTSTRSAFEAPI RtlStringCopyNWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,STRSAFE_LPCWSTR pszSrc,size_t cchToCopy)
+NTSTRSAFEAPI RtlStringCopyNWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCWSTR pszSrc,
+ size_t cchToCopy)
{
NTSTATUS Status = STATUS_SUCCESS;
if (cchDest==0)
return Status;
}
-NTSTRSAFEAPI RtlStringCopyNExWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCSTR pszSrc,size_t cchToCopy,STRSAFE_LPSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags)
+NTSTRSAFEAPI RtlStringCopyNExWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPCSTR pszSrc,
+ size_t cchToCopy,
+ STRSAFE_LPSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPSTR pszDestEnd = pszDest;
return Status;
}
-NTSTRSAFEAPI RtlStringCopyNExWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCWSTR pszSrc,size_t cchToCopy,STRSAFE_LPWSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags)
+NTSTRSAFEAPI RtlStringCopyNExWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPCWSTR pszSrc,
+ size_t cchToCopy,
+ STRSAFE_LPWSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPWSTR pszDestEnd = pszDest;
return Status;
}
-NTSTRSAFEAPI RtlStringCatWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,STRSAFE_LPCSTR pszSrc)
+NTSTRSAFEAPI RtlStringCatWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCSTR pszSrc)
{
NTSTATUS Status;
size_t cchDestLength;
return Status;
}
-NTSTRSAFEAPI RtlStringCatWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,STRSAFE_LPCWSTR pszSrc)
+NTSTRSAFEAPI RtlStringCatWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCWSTR pszSrc)
{
NTSTATUS Status;
size_t cchDestLength;
return Status;
}
-NTSTRSAFEAPI RtlStringCatExWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCSTR pszSrc,STRSAFE_LPSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags)
+NTSTRSAFEAPI RtlStringCatExWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPCSTR pszSrc,
+ STRSAFE_LPSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPSTR pszDestEnd = pszDest;
return Status;
}
-NTSTRSAFEAPI RtlStringCatExWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCWSTR pszSrc,STRSAFE_LPWSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags)
+NTSTRSAFEAPI RtlStringCatExWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPCWSTR pszSrc,
+ STRSAFE_LPWSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPWSTR pszDestEnd = pszDest;
return Status;
}
-NTSTRSAFEAPI RtlStringCatNWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,STRSAFE_LPCSTR pszSrc,size_t cchToAppend)
+NTSTRSAFEAPI RtlStringCatNWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCSTR pszSrc,
+ size_t cchToAppend)
{
NTSTATUS Status;
size_t cchDestLength;
return Status;
}
-NTSTRSAFEAPI RtlStringCatNWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,STRSAFE_LPCWSTR pszSrc,size_t cchToAppend)
+NTSTRSAFEAPI RtlStringCatNWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCWSTR pszSrc,
+ size_t cchToAppend)
{
NTSTATUS Status;
size_t cchDestLength;
return Status;
}
-NTSTRSAFEAPI RtlStringCatNExWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCSTR pszSrc,size_t cchToAppend,STRSAFE_LPSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags)
+NTSTRSAFEAPI RtlStringCatNExWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPCSTR pszSrc,
+ size_t cchToAppend,
+ STRSAFE_LPSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPSTR pszDestEnd = pszDest;
return Status;
}
-NTSTRSAFEAPI RtlStringCatNExWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPCWSTR pszSrc,size_t cchToAppend,STRSAFE_LPWSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags)
+NTSTRSAFEAPI RtlStringCatNExWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPCWSTR pszSrc,
+ size_t cchToAppend,
+ STRSAFE_LPWSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPWSTR pszDestEnd = pszDest;
return Status;
}
-NTSTRSAFEAPI RtlStringVPrintfWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,STRSAFE_LPCSTR pszFormat,va_list argList)
+NTSTRSAFEAPI RtlStringVPrintfWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCSTR pszFormat,
+ va_list argList)
{
NTSTATUS Status = STATUS_SUCCESS;
if (cchDest==0)
return Status;
}
-NTSTRSAFEAPI RtlStringVPrintfWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,STRSAFE_LPCWSTR pszFormat,va_list argList)
+NTSTRSAFEAPI RtlpStringVPrintfWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCWSTR pszFormat,
+ size_t* pcchDestNewLen,
+ va_list argList)
{
NTSTATUS Status = STATUS_SUCCESS;
- if (cchDest==0)
- Status = STATUS_INVALID_PARAMETER;
- else
+ int iRet;
+ size_t cchMax;
+ cchMax = cchDest - 1;
+ iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
+ if ((iRet < 0) || (((size_t) iRet) > cchMax))
{
- int iRet;
- size_t cchMax;
- cchMax = cchDest - 1;
- iRet = _vsnwprintf(pszDest,cchMax,pszFormat,argList);
- if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ pszDest += cchMax;
+ *pszDest = L'\0';
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ if (((size_t) iRet) == cchMax)
{
pszDest += cchMax;
*pszDest = L'\0';
- Status = STATUS_BUFFER_OVERFLOW;
}
- else
- if (((size_t)iRet)==cchMax)
- {
- pszDest += cchMax;
- *pszDest = L'\0';
- }
- }
+
+ if (pcchDestNewLen)
+ *pcchDestNewLen = (iRet == -1) ? cchDest : iRet;
+
return Status;
}
-NTSTRSAFEAPI RtlStringVPrintfExWorkerA(STRSAFE_LPSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags,STRSAFE_LPCSTR pszFormat,va_list argList)
+NTSTRSAFEAPI RtlStringVPrintfWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCWSTR pszFormat,
+ va_list argList)
+{
+ if (cchDest==0)
+ return STATUS_INVALID_PARAMETER;
+
+ return RtlpStringVPrintfWorkerW(pszDest, cchDest, pszFormat, NULL, argList);
+}
+
+NTSTRSAFEAPI RtlStringVPrintfWorkerLenW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ STRSAFE_LPCWSTR pszFormat,
+ size_t* pcchDestNewLen,
+ va_list argList)
+{
+ if (cchDest == 0 || pcchDestNewLen == 0)
+ return STATUS_INVALID_PARAMETER;
+
+ return RtlpStringVPrintfWorkerW(pszDest, cchDest, pszFormat, pcchDestNewLen, argList);
+}
+
+NTSTRSAFEAPI RtlStringVPrintfExWorkerA(STRSAFE_LPSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags,
+ STRSAFE_LPCSTR pszFormat,
+ va_list argList)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPSTR pszDestEnd = pszDest;
}
return Status;
}
-
-NTSTRSAFEAPI RtlStringVPrintfExWorkerW(STRSAFE_LPWSTR pszDest,size_t cchDest,size_t cbDest,STRSAFE_LPWSTR *ppszDestEnd,size_t *pcchRemaining,STRSAFE_DWORD dwFlags,STRSAFE_LPCWSTR pszFormat,va_list argList)
+NTSTRSAFEAPI RtlpStringVPrintfExWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPWSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags,
+ STRSAFE_LPCWSTR pszFormat,
+ size_t* pcchDestNewLen,
+ va_list argList)
{
NTSTATUS Status = STATUS_SUCCESS;
STRSAFE_LPWSTR pszDestEnd = pszDest;
memset(pszDestEnd + 1,STRSAFE_GET_FILL_PATTERN(dwFlags),((cchRemaining - 1)*sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
}
}
+
+ if (pcchDestNewLen)
+ *pcchDestNewLen = iRet == -1 ? cchDest : iRet;
}
}
}
return Status;
}
+NTSTRSAFEAPI RtlStringVPrintfExWorkerW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPWSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags,
+ STRSAFE_LPCWSTR pszFormat,
+ va_list argList)
+{
+ return RtlpStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, NULL, argList);
+}
+
+NTSTRSAFEAPI RtlStringVPrintfExWorkerLenW(STRSAFE_LPWSTR pszDest,
+ size_t cchDest,
+ size_t cbDest,
+ STRSAFE_LPWSTR *ppszDestEnd,
+ size_t *pcchRemaining,
+ STRSAFE_DWORD dwFlags,
+ STRSAFE_LPCWSTR pszFormat,
+ size_t* pcchDestNewLen,
+ va_list argList)
+{
+ if (pcchDestNewLen == 0)
+ return STATUS_INVALID_PARAMETER;
+
+ return RtlpStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, pcchDestNewLen, argList);
+}
+
+
NTSTRSAFEAPI
RtlStringLengthWorkerA(
_In_reads_or_z_(cchMax) STRSAFE_LPCSTR psz,
return Status;
}
+NTSTRSAFEAPI
+RtlpUnicodeStringValidate(_In_opt_ PCUNICODE_STRING SourceString,
+ _In_ STRSAFE_DWORD dwFlags)
+{
+ if (SourceString)
+ {
+ if (SourceString->Length % sizeof(WCHAR) != 0 ||
+ SourceString->MaximumLength % sizeof(WCHAR) != 0 ||
+ SourceString->Length > SourceString->MaximumLength ||
+ SourceString->MaximumLength > NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR) ||
+ (SourceString->Buffer == NULL && (SourceString->Length != 0 || SourceString->MaximumLength != 0)))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ if (!(dwFlags & STRSAFE_IGNORE_NULLS))
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTRSAFEAPI
+RtlUnicodeStringValidate(_In_opt_ PCUNICODE_STRING SourceString)
+{
+ return RtlpUnicodeStringValidate(SourceString, 0);
+}
+
+NTSTRSAFEAPI
+RtlUnicodeStringValidateEx(_In_opt_ PCUNICODE_STRING SourceString,
+ _In_ STRSAFE_DWORD dwFlags)
+{
+ if (dwFlags & ~(STRSAFE_UNICODE_STRING_VALID_FLAGS))
+ return STATUS_INVALID_PARAMETER;
+
+ return RtlpUnicodeStringValidate(SourceString, dwFlags);
+}
+
+static
+NTSTATUS
+__cdecl
+RtlUnicodeStringPrintf(_In_ PUNICODE_STRING DestinationString,
+ _In_ NTSTRSAFE_PCWSTR pszFormat, ...)
+{
+ NTSTATUS Status;
+ size_t cchFinalLength;
+ va_list argList;
+
+ if (DestinationString == NULL || pszFormat == NULL || DestinationString->Buffer == NULL)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ Status = RtlUnicodeStringValidate(DestinationString);
+ if (NT_SUCCESS(Status))
+ {
+ va_start(argList, pszFormat);
+
+ Status = RtlStringVPrintfWorkerLenW(DestinationString->Buffer,
+ DestinationString->MaximumLength / sizeof(WCHAR),
+ pszFormat,
+ &cchFinalLength,
+ argList);
+
+ if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
+ {
+ DestinationString->Length = (USHORT)(cchFinalLength * sizeof(WCHAR));
+ }
+
+ va_end(argList);
+ }
+ }
+
+ return Status;
+}
+
+static
+NTSTATUS
+__cdecl
+RtlUnicodeStringPrintfEx(_In_opt_ PUNICODE_STRING DestinationString,
+ _In_opt_ PUNICODE_STRING RemainingString,
+ _In_ STRSAFE_DWORD dwFlags,
+ _In_ NTSTRSAFE_PCWSTR pszFormat, ...)
+{
+ NTSTATUS Status;
+ size_t cchFinalLength;
+ size_t cchRemaining;
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ Status = RtlStringVPrintfExWorkerLenW(DestinationString->Buffer,
+ DestinationString->MaximumLength / sizeof(WCHAR),
+ DestinationString->MaximumLength,
+ &RemainingString->Buffer,
+ &cchRemaining,
+ dwFlags,
+ pszFormat,
+ &cchFinalLength,
+ argList);
+
+ va_end(argList);
+
+ if (Status == STATUS_BUFFER_OVERFLOW || NT_SUCCESS(Status))
+ {
+ DestinationString->Length = (USHORT)(cchFinalLength * sizeof(WCHAR));
+
+ if (RemainingString)
+ {
+ RemainingString->Length = 0;
+ RemainingString->MaximumLength = (USHORT)cchRemaining * sizeof(WCHAR);
+ }
+ }
+
+ return Status;
+}
+
#define RtlStringCopyWorkerA RtlStringCopyWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
#define RtlStringCopyWorkerW RtlStringCopyWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
#define RtlStringCopyExWorkerA RtlStringCopyExWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;