1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 StringUtil.cpp 8 9 Abstract: 10 11 This module implements string utlities in the framework 12 13 Author: 14 15 16 17 Environment: 18 19 Both kernel and user mode 20 21 Revision History: 22 23 --*/ 24 25 #include "fxsupportpch.hpp" 26 27 extern "C" { 28 // #include "StringUtil.tmh" 29 } 30 31 size_t 32 FxCalculateTotalStringSize( 33 __in FxCollectionInternal *StringCollection, 34 __in BOOLEAN Verify, 35 __out_opt PBOOLEAN ContainsOnlyStrings 36 ) 37 { 38 size_t cbLength; 39 FxString *pString; 40 FxCollectionEntry* cur, *end; 41 42 cbLength = 0; 43 44 end = StringCollection->End(); 45 for (cur = StringCollection->Start(); 46 cur != end; 47 cur = cur->Next()) { 48 pString = (FxString *) cur->m_Object; 49 50 if (Verify && pString->GetType() != FX_TYPE_STRING) { 51 *ContainsOnlyStrings = FALSE; 52 return 0; 53 } 54 55 cbLength += pString->ByteLength(TRUE); 56 } 57 58 if (ContainsOnlyStrings != NULL) { 59 *ContainsOnlyStrings = TRUE; 60 } 61 62 if (StringCollection->Count() == 0) { 63 // 64 // If there are not entries, we still need 2 NULLs 65 // 66 cbLength = sizeof(UNICODE_NULL) * 2; 67 } 68 else { 69 // 70 // Extra NULL 71 // 72 cbLength += sizeof(UNICODE_NULL); 73 } 74 75 // 76 // ASSERT that we are reporting an integral number of WCHARs in bytes 77 // 78 ASSERT((cbLength % sizeof(WCHAR)) == 0); 79 80 return cbLength; 81 } 82 83 size_t 84 FxCalculateTotalMultiSzStringSize( 85 __in __nullnullterminated PCWSTR MultiSz 86 ) 87 { 88 PCWSTR pCur; 89 size_t cbSize, cbLength; 90 91 cbSize = 0; 92 93 pCur = MultiSz; 94 95 while (*pCur != NULL) { 96 // 97 // Compute length of string including terminating NULL 98 // 99 cbLength = (wcslen(pCur) + 1) * sizeof(WCHAR); 100 101 cbSize += cbLength; 102 pCur = (PWSTR) WDF_PTR_ADD_OFFSET(pCur, cbLength); 103 } 104 105 if (cbSize == 0) { 106 // 107 // If there are no strings, we still need 2 NULLs 108 // 109 cbSize = sizeof(UNICODE_NULL); 110 } 111 112 // 113 // Final NULL which makes this a multi sz 114 // 115 cbSize += sizeof(UNICODE_NULL); 116 117 // 118 // ASSERT that we are reporting an integral number of WCHARs in bytes 119 // 120 ASSERT((cbSize % sizeof(WCHAR)) == 0); 121 122 return cbSize; 123 } 124 125 #pragma prefast(push) 126 // Caller is responsible for allocating the correct amount of memory. 127 #pragma prefast(disable:__WARNING_INCORRECT_ANNOTATION_STRING ) 128 PWSTR 129 FxCopyMultiSz( 130 __out LPWSTR Buffer, 131 __in FxCollectionInternal* StringCollection 132 ) 133 { 134 LPWSTR pCur; 135 ULONG length; 136 FxCollectionEntry* cur, *end; 137 138 pCur = Buffer; 139 end = StringCollection->End(); 140 141 for (cur = StringCollection->Start(); cur != end; cur = cur->Next()) { 142 FxString* pSourceString; 143 144 pSourceString = (FxString *) cur->m_Object; 145 146 length = pSourceString->ByteLength(TRUE); 147 RtlCopyMemory(pCur, pSourceString->Buffer(), length); 148 149 // 150 // Length is expressed in number of bytes, not number of 151 // characters. 152 // 153 // length includes the NULL. 154 // 155 pCur = WDF_PTR_ADD_OFFSET_TYPE(pCur, length, LPWSTR); 156 } 157 158 // 159 // If there are no entries, we still need 2 NULLs. 160 // 161 if (StringCollection->Count() == 0) { 162 *pCur = UNICODE_NULL; 163 pCur++; 164 } 165 166 // 167 // double NULL terminate the string 168 // 169 *pCur = UNICODE_NULL; 170 171 // 172 // Return the start of the next location in the buffer 173 // 174 return pCur + 1; 175 } 176 #pragma prefast(pop) 177 178 _Must_inspect_result_ 179 NTSTATUS 180 FxDuplicateUnicodeString( 181 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 182 __in const UNICODE_STRING* Source, 183 __out PUNICODE_STRING Destination 184 ) 185 /*++ 186 187 Routine Description: 188 Makes a deep copy from Source to Destination. 189 190 Destination is assumed to have been initialized by the caller, be owned by 191 an internal Fx object. Destination could already contain a previously 192 allocated buffer. If one exists and is large enough, it will be reused 193 for the copy. 194 195 This function guarantees that the Buffer will be NULL terminated. While 196 this is not necessary because Length describes the length of the buffer, the 197 resulting buffer can be copied back to the client driver and we cannot trust 198 the client driver to treat the string as an unterminated buffer, typically 199 the client driver will just extract the buffer and treat it as NULL 200 terminated. To be defensive with this type of (mis)use, we always NULL 201 terminate the resuling Buffer. 202 203 Arguments: 204 Source - source struct to copy from. This string can originate from the 205 client driver. 206 207 Destination - destination struct to copy to. This struct is assumed to be 208 internal and is not given to the outside caller 209 210 Return Value: 211 NTSTATUS 212 213 --*/ 214 { 215 NTSTATUS status; 216 USHORT srcCbLength, srcCbLengthAndNull, dstMaxCbLength; 217 218 // 219 // NOTE: We assume the sources string will be smaller than 64k. 220 // 221 srcCbLength = Source->Length; 222 dstMaxCbLength = Destination->MaximumLength; 223 224 status = RtlUShortAdd(srcCbLength, 225 sizeof(UNICODE_NULL), 226 &srcCbLengthAndNull); 227 if (!NT_SUCCESS(status)) { 228 DoTraceLevelMessage( 229 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 230 "Interger overflow occured when duplicating string %!STATUS!", 231 status); 232 return status; 233 } 234 235 // 236 // First see if we already have enough memory to hold the string + a NULL 237 // 238 if (dstMaxCbLength < srcCbLengthAndNull) { 239 // 240 // Allocate enough memory for the source string and a NULL character 241 // 242 dstMaxCbLength = srcCbLengthAndNull; 243 244 // 245 // We need to allocate memory. Free any old memory first. 246 // 247 if (Destination->Buffer != NULL) { 248 FxPoolFree(Destination->Buffer); 249 250 RtlZeroMemory(Destination, sizeof(UNICODE_STRING)); 251 } 252 253 Destination->Buffer = (PWSTR) FxPoolAllocate( 254 FxDriverGlobals, PagedPool, dstMaxCbLength); 255 256 if (Destination->Buffer == NULL) { 257 status = STATUS_INSUFFICIENT_RESOURCES; 258 DoTraceLevelMessage( 259 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 260 "Failed to allocate memory when duplicating string %!STATUS!", 261 status); 262 return status; 263 } 264 265 Destination->MaximumLength = dstMaxCbLength; 266 } 267 268 // 269 // If we get here and we have a buffer, then we can just copy the 270 // string into the buffer. 271 // 272 RtlCopyMemory(Destination->Buffer, Source->Buffer, srcCbLength); 273 Destination->Length = srcCbLength; 274 275 // 276 // Make sure the string is NULL terminated and there is room for the NULL 277 // 278 ASSERT(Destination->Length + sizeof(UNICODE_NULL) <= 279 Destination->MaximumLength); 280 Destination->Buffer[Destination->Length/sizeof(WCHAR)] = UNICODE_NULL; 281 282 return STATUS_SUCCESS; 283 } 284 285 _Must_inspect_result_ 286 PWCHAR 287 FxDuplicateUnicodeStringToString( 288 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 289 __in const UNICODE_STRING* Source 290 ) 291 { 292 PWSTR pDuplicate; 293 294 pDuplicate = (PWSTR) FxPoolAllocate( 295 FxDriverGlobals, PagedPool, Source->Length + sizeof(UNICODE_NULL)); 296 297 if (pDuplicate != NULL) { 298 RtlCopyMemory(pDuplicate, Source->Buffer, Source->Length); 299 300 // 301 // Make sure the string is NULL terminated. We can safely do this 302 // because we allocated an extra WCHAR for the null terminator. 303 // 304 pDuplicate[Source->Length/sizeof(WCHAR)] = UNICODE_NULL; 305 } 306 307 return pDuplicate; 308 } 309