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
FxCalculateTotalStringSize(__in FxCollectionInternal * StringCollection,__in BOOLEAN Verify,__out_opt PBOOLEAN ContainsOnlyStrings)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
FxCalculateTotalMultiSzStringSize(__in __nullnullterminated PCWSTR MultiSz)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
FxCopyMultiSz(__out LPWSTR Buffer,__in FxCollectionInternal * StringCollection)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
FxDuplicateUnicodeString(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in const UNICODE_STRING * Source,__out PUNICODE_STRING Destination)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
FxDuplicateUnicodeStringToString(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in const UNICODE_STRING * Source)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