mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
1f377076d7
Not all files are included, but these are necessary to compile cdrom driver. So far it can only be statically linked with drivers, a proper implementation requires wdfldr helper driver
308 lines
7.6 KiB
C++
308 lines
7.6 KiB
C++
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
StringUtil.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements string utlities in the framework
|
|
|
|
Author:
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
Both kernel and user mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "fxsupportpch.hpp"
|
|
|
|
extern "C" {
|
|
// #include "StringUtil.tmh"
|
|
}
|
|
|
|
size_t
|
|
FxCalculateTotalStringSize(
|
|
__in FxCollectionInternal *StringCollection,
|
|
__in BOOLEAN Verify,
|
|
__out_opt PBOOLEAN ContainsOnlyStrings
|
|
)
|
|
{
|
|
size_t cbLength;
|
|
FxString *pString;
|
|
FxCollectionEntry* cur, *end;
|
|
|
|
cbLength = 0;
|
|
|
|
end = StringCollection->End();
|
|
for (cur = StringCollection->Start();
|
|
cur != end;
|
|
cur = cur->Next()) {
|
|
pString = (FxString *) cur->m_Object;
|
|
|
|
if (Verify && pString->GetType() != FX_TYPE_STRING) {
|
|
*ContainsOnlyStrings = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
cbLength += pString->ByteLength(TRUE);
|
|
}
|
|
|
|
if (ContainsOnlyStrings != NULL) {
|
|
*ContainsOnlyStrings = TRUE;
|
|
}
|
|
|
|
if (StringCollection->Count() == 0) {
|
|
//
|
|
// If there are not entries, we still need 2 NULLs
|
|
//
|
|
cbLength = sizeof(UNICODE_NULL) * 2;
|
|
}
|
|
else {
|
|
//
|
|
// Extra NULL
|
|
//
|
|
cbLength += sizeof(UNICODE_NULL);
|
|
}
|
|
|
|
//
|
|
// ASSERT that we are reporting an integral number of WCHARs in bytes
|
|
//
|
|
ASSERT((cbLength % sizeof(WCHAR)) == 0);
|
|
|
|
return cbLength;
|
|
}
|
|
|
|
size_t
|
|
FxCalculateTotalMultiSzStringSize(
|
|
__in __nullnullterminated PCWSTR MultiSz
|
|
)
|
|
{
|
|
PCWSTR pCur;
|
|
size_t cbSize, cbLength;
|
|
|
|
cbSize = 0;
|
|
|
|
pCur = MultiSz;
|
|
|
|
while (*pCur != NULL) {
|
|
//
|
|
// Compute length of string including terminating NULL
|
|
//
|
|
cbLength = (wcslen(pCur) + 1) * sizeof(WCHAR);
|
|
|
|
cbSize += cbLength;
|
|
pCur = (PWSTR) WDF_PTR_ADD_OFFSET(pCur, cbLength);
|
|
}
|
|
|
|
if (cbSize == 0) {
|
|
//
|
|
// If there are no strings, we still need 2 NULLs
|
|
//
|
|
cbSize = sizeof(UNICODE_NULL);
|
|
}
|
|
|
|
//
|
|
// Final NULL which makes this a multi sz
|
|
//
|
|
cbSize += sizeof(UNICODE_NULL);
|
|
|
|
//
|
|
// ASSERT that we are reporting an integral number of WCHARs in bytes
|
|
//
|
|
ASSERT((cbSize % sizeof(WCHAR)) == 0);
|
|
|
|
return cbSize;
|
|
}
|
|
|
|
#pragma prefast(push)
|
|
// Caller is responsible for allocating the correct amount of memory.
|
|
#pragma prefast(disable:__WARNING_INCORRECT_ANNOTATION_STRING )
|
|
PWSTR
|
|
FxCopyMultiSz(
|
|
__out LPWSTR Buffer,
|
|
__in FxCollectionInternal* StringCollection
|
|
)
|
|
{
|
|
LPWSTR pCur;
|
|
ULONG length;
|
|
FxCollectionEntry* cur, *end;
|
|
|
|
pCur = Buffer;
|
|
end = StringCollection->End();
|
|
|
|
for (cur = StringCollection->Start(); cur != end; cur = cur->Next()) {
|
|
FxString* pSourceString;
|
|
|
|
pSourceString = (FxString *) cur->m_Object;
|
|
|
|
length = pSourceString->ByteLength(TRUE);
|
|
RtlCopyMemory(pCur, pSourceString->Buffer(), length);
|
|
|
|
//
|
|
// Length is expressed in number of bytes, not number of
|
|
// characters.
|
|
//
|
|
// length includes the NULL.
|
|
//
|
|
pCur = WDF_PTR_ADD_OFFSET_TYPE(pCur, length, LPWSTR);
|
|
}
|
|
|
|
//
|
|
// If there are no entries, we still need 2 NULLs.
|
|
//
|
|
if (StringCollection->Count() == 0) {
|
|
*pCur = UNICODE_NULL;
|
|
pCur++;
|
|
}
|
|
|
|
//
|
|
// double NULL terminate the string
|
|
//
|
|
*pCur = UNICODE_NULL;
|
|
|
|
//
|
|
// Return the start of the next location in the buffer
|
|
//
|
|
return pCur + 1;
|
|
}
|
|
#pragma prefast(pop)
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxDuplicateUnicodeString(
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
|
__in const UNICODE_STRING* Source,
|
|
__out PUNICODE_STRING Destination
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Makes a deep copy from Source to Destination.
|
|
|
|
Destination is assumed to have been initialized by the caller, be owned by
|
|
an internal Fx object. Destination could already contain a previously
|
|
allocated buffer. If one exists and is large enough, it will be reused
|
|
for the copy.
|
|
|
|
This function guarantees that the Buffer will be NULL terminated. While
|
|
this is not necessary because Length describes the length of the buffer, the
|
|
resulting buffer can be copied back to the client driver and we cannot trust
|
|
the client driver to treat the string as an unterminated buffer, typically
|
|
the client driver will just extract the buffer and treat it as NULL
|
|
terminated. To be defensive with this type of (mis)use, we always NULL
|
|
terminate the resuling Buffer.
|
|
|
|
Arguments:
|
|
Source - source struct to copy from. This string can originate from the
|
|
client driver.
|
|
|
|
Destination - destination struct to copy to. This struct is assumed to be
|
|
internal and is not given to the outside caller
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
USHORT srcCbLength, srcCbLengthAndNull, dstMaxCbLength;
|
|
|
|
//
|
|
// NOTE: We assume the sources string will be smaller than 64k.
|
|
//
|
|
srcCbLength = Source->Length;
|
|
dstMaxCbLength = Destination->MaximumLength;
|
|
|
|
status = RtlUShortAdd(srcCbLength,
|
|
sizeof(UNICODE_NULL),
|
|
&srcCbLengthAndNull);
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
|
"Interger overflow occured when duplicating string %!STATUS!",
|
|
status);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// First see if we already have enough memory to hold the string + a NULL
|
|
//
|
|
if (dstMaxCbLength < srcCbLengthAndNull) {
|
|
//
|
|
// Allocate enough memory for the source string and a NULL character
|
|
//
|
|
dstMaxCbLength = srcCbLengthAndNull;
|
|
|
|
//
|
|
// We need to allocate memory. Free any old memory first.
|
|
//
|
|
if (Destination->Buffer != NULL) {
|
|
FxPoolFree(Destination->Buffer);
|
|
|
|
RtlZeroMemory(Destination, sizeof(UNICODE_STRING));
|
|
}
|
|
|
|
Destination->Buffer = (PWSTR) FxPoolAllocate(
|
|
FxDriverGlobals, PagedPool, dstMaxCbLength);
|
|
|
|
if (Destination->Buffer == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
DoTraceLevelMessage(
|
|
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
|
"Failed to allocate memory when duplicating string %!STATUS!",
|
|
status);
|
|
return status;
|
|
}
|
|
|
|
Destination->MaximumLength = dstMaxCbLength;
|
|
}
|
|
|
|
//
|
|
// If we get here and we have a buffer, then we can just copy the
|
|
// string into the buffer.
|
|
//
|
|
RtlCopyMemory(Destination->Buffer, Source->Buffer, srcCbLength);
|
|
Destination->Length = srcCbLength;
|
|
|
|
//
|
|
// Make sure the string is NULL terminated and there is room for the NULL
|
|
//
|
|
ASSERT(Destination->Length + sizeof(UNICODE_NULL) <=
|
|
Destination->MaximumLength);
|
|
Destination->Buffer[Destination->Length/sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
PWCHAR
|
|
FxDuplicateUnicodeStringToString(
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
|
__in const UNICODE_STRING* Source
|
|
)
|
|
{
|
|
PWSTR pDuplicate;
|
|
|
|
pDuplicate = (PWSTR) FxPoolAllocate(
|
|
FxDriverGlobals, PagedPool, Source->Length + sizeof(UNICODE_NULL));
|
|
|
|
if (pDuplicate != NULL) {
|
|
RtlCopyMemory(pDuplicate, Source->Buffer, Source->Length);
|
|
|
|
//
|
|
// Make sure the string is NULL terminated. We can safely do this
|
|
// because we allocated an extra WCHAR for the null terminator.
|
|
//
|
|
pDuplicate[Source->Length/sizeof(WCHAR)] = UNICODE_NULL;
|
|
}
|
|
|
|
return pDuplicate;
|
|
}
|