Merge from amd64-branch:
[reactos.git] / reactos / include / ddk / ntstrsafe.h
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: include/ddk/ntstrsafe.h
5 * PURPOSE: Safe String Library for NT Code (Native/Kernel)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #ifndef _NTSTRSAFE_H_INCLUDED_
12 #define _NTSTRSAFE_H_INCLUDED_
13
14 //
15 // Dependencies
16 //
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdarg.h>
20
21 //
22 // Maximum limits: allow overriding the maximum
23 //
24 #ifndef NTSTRSAFE_MAX_CCH
25 #define NTSTRSAFE_MAX_CCH 2147483647
26 #endif
27 #define NTSTRSAFE_MAX_LENGTH (NTSTRSAFE_MAX_CCH - 1)
28
29 //
30 // Typedefs
31 //
32 typedef unsigned long DWORD;
33
34 /* PRIVATE FUNCTIONS *********************************************************/
35
36 FORCEINLINE
37 NTSTATUS
38 NTAPI
39 RtlStringLengthWorkerA(IN PCHAR String,
40 IN SIZE_T MaxLength,
41 OUT PSIZE_T ReturnLength OPTIONAL)
42 {
43 NTSTATUS Status = STATUS_SUCCESS;
44 SIZE_T LocalMax = MaxLength;
45
46 while (MaxLength && (*String != ANSI_NULL))
47 {
48 String++;
49 MaxLength--;
50 }
51
52 if (!MaxLength) Status = STATUS_INVALID_PARAMETER;
53
54 if (ReturnLength)
55 {
56 if (NT_SUCCESS(Status))
57 {
58 *ReturnLength = LocalMax - MaxLength;
59 }
60 else
61 {
62 *ReturnLength = 0;
63 }
64 }
65
66 return Status;
67 }
68
69 FORCEINLINE
70 NTSTATUS
71 NTAPI
72 RtlStringValidateDestA(IN PCHAR Destination,
73 IN SIZE_T Length,
74 OUT PSIZE_T ReturnLength OPTIONAL,
75 IN SIZE_T MaxLength)
76 {
77 NTSTATUS Status = STATUS_SUCCESS;
78
79 if (!(Length) || (Length > MaxLength)) Status = STATUS_INVALID_PARAMETER;
80
81 if (ReturnLength)
82 {
83 if (NT_SUCCESS(Status))
84 {
85 Status = RtlStringLengthWorkerA(Destination,
86 Length,
87 ReturnLength);
88 }
89 else
90 {
91 *ReturnLength = 0;
92 }
93 }
94
95 return Status;
96 }
97
98 FORCEINLINE
99 NTSTATUS
100 NTAPI
101 RtlStringExValidateDestA(IN OUT PCHAR *Destination,
102 IN OUT PSIZE_T DestinationLength,
103 OUT PSIZE_T ReturnLength OPTIONAL,
104 IN SIZE_T MaxLength,
105 IN DWORD Flags)
106 {
107 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
108 return RtlStringValidateDestA(*Destination,
109 *DestinationLength,
110 ReturnLength,
111 MaxLength);
112 }
113
114 FORCEINLINE
115 NTSTATUS
116 NTAPI
117 RtlStringExValidateSrcA(IN OUT PCCHAR *Source OPTIONAL,
118 IN OUT PSIZE_T ReturnLength OPTIONAL,
119 IN SIZE_T MaxLength,
120 IN DWORD Flags)
121 {
122 NTSTATUS Status = STATUS_SUCCESS;
123 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
124
125 if ((ReturnLength) && (*ReturnLength >= MaxLength))
126 {
127 Status = STATUS_INVALID_PARAMETER;
128 }
129
130 return Status;
131 }
132
133 FORCEINLINE
134 NTSTATUS
135 NTAPI
136 RtlStringVPrintfWorkerA(OUT PCHAR Destination,
137 IN SIZE_T Length,
138 OUT PSIZE_T NewLength OPTIONAL,
139 IN PCCHAR Format,
140 IN va_list argList)
141 {
142 NTSTATUS Status = STATUS_SUCCESS;
143 LONG Return;
144 SIZE_T MaxLength, LocalNewLength = 0;
145
146 MaxLength = Length - 1;
147
148 Return = _vsnprintf(Destination, MaxLength, Format, argList);
149 if ((Return < 0) || ((SIZE_T)Return > MaxLength))
150 {
151 Destination += MaxLength;
152 *Destination = ANSI_NULL;
153
154 LocalNewLength = MaxLength;
155
156 Status = STATUS_BUFFER_OVERFLOW;
157 }
158 else if ((SIZE_T)Return == MaxLength)
159 {
160 Destination += MaxLength;
161 *Destination = ANSI_NULL;
162
163 LocalNewLength = MaxLength;
164 }
165 else
166 {
167 LocalNewLength = Return;
168 }
169
170 if (NewLength) *NewLength = LocalNewLength;
171 return Status;
172 }
173
174 FORCEINLINE
175 NTSTATUS
176 NTAPI
177 RtlStringCopyWorkerA(OUT PCHAR Destination,
178 IN SIZE_T Length,
179 OUT PSIZE_T NewLength OPTIONAL,
180 IN PCCHAR Source,
181 IN SIZE_T CopyLength)
182 {
183 NTSTATUS Status = STATUS_SUCCESS;
184 SIZE_T LocalNewLength = 0;
185
186 while ((Length) && (CopyLength) && (*Source != ANSI_NULL))
187 {
188 *Destination++ = *Source++;
189 Length--;
190 CopyLength--;
191
192 LocalNewLength++;
193 }
194
195 if (!Length)
196 {
197 Destination--;
198 LocalNewLength--;
199
200 Status = STATUS_BUFFER_OVERFLOW;
201 }
202
203 *Destination = ANSI_NULL;
204
205 if (NewLength) *NewLength = LocalNewLength;
206 return Status;
207 }
208
209 /* PUBLIC FUNCTIONS **********************************************************/
210
211 NTSTATUS
212 NTAPI
213 RtlStringCbPrintfA(OUT PCHAR Destination,
214 IN SIZE_T Length,
215 IN PCHAR Format,
216 ...)
217 {
218 NTSTATUS Status;
219 SIZE_T CharLength = Length / sizeof(CHAR);
220 va_list argList;
221
222 Status = RtlStringValidateDestA(Destination,
223 CharLength,
224 NULL,
225 NTSTRSAFE_MAX_CCH);
226 if (NT_SUCCESS(Status))
227 {
228 va_start(argList, Format);
229 Status = RtlStringVPrintfWorkerA(Destination,
230 CharLength,
231 NULL,
232 Format,
233 argList);
234 va_end(argList);
235 }
236
237 return Status;
238 }
239
240 NTSTATUS
241 NTAPI
242 RtlStringCbPrintfExA(OUT PCHAR Destination,
243 IN SIZE_T Length,
244 OUT PCHAR *DestinationEnd OPTIONAL,
245 OUT PSIZE_T RemainingSize OPTIONAL,
246 IN DWORD Flags,
247 IN PCCHAR Format,
248 ...)
249 {
250 NTSTATUS Status;
251 SIZE_T CharLength = Length / sizeof(CHAR), Remaining, LocalNewLength = 0;
252 PCHAR LocalDestinationEnd;
253 va_list argList;
254 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
255
256 Status = RtlStringExValidateDestA(&Destination,
257 &CharLength,
258 NULL,
259 NTSTRSAFE_MAX_CCH,
260 Flags);
261 if (NT_SUCCESS(Status))
262 {
263 LocalDestinationEnd = Destination;
264 Remaining = CharLength;
265
266 Status = RtlStringExValidateSrcA(&Format,
267 NULL,
268 NTSTRSAFE_MAX_CCH,
269 Flags);
270 if (NT_SUCCESS(Status))
271 {
272 if (!Length)
273 {
274 if (*Format != ANSI_NULL)
275 {
276 if (!Destination)
277 {
278 Status = STATUS_INVALID_PARAMETER;
279 }
280 else
281 {
282 Status = STATUS_BUFFER_OVERFLOW;
283 }
284 }
285 }
286 else
287 {
288 va_start(argList, Format);
289 Status = RtlStringVPrintfWorkerA(Destination,
290 CharLength,
291 &LocalNewLength,
292 Format,
293 argList);
294 va_end(argList);
295
296 LocalDestinationEnd = Destination + LocalNewLength;
297 Remaining = CharLength - LocalNewLength;
298 }
299 }
300 else
301 {
302 if (Length) *Destination = ANSI_NULL;
303 }
304
305 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
306 {
307 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
308
309 if (RemainingSize)
310 {
311 *RemainingSize = (Remaining * sizeof(CHAR)) +
312 (Length % sizeof(CHAR));
313 }
314 }
315 }
316
317 return Status;
318 }
319
320 FORCEINLINE
321 NTSTATUS
322 NTAPI
323 RtlStringCbCopyExA(OUT PCHAR Destination,
324 IN SIZE_T Length,
325 IN PCCHAR Source,
326 OUT PCHAR *DestinationEnd OPTIONAL,
327 OUT PSIZE_T RemainingSize OPTIONAL,
328 IN DWORD Flags)
329 {
330 NTSTATUS Status;
331 SIZE_T CharLength = Length / sizeof(CHAR), Copied = 0, Remaining;
332 PCHAR LocalDestinationEnd;
333 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
334
335 Status = RtlStringExValidateDestA(&Destination,
336 &Length,
337 NULL,
338 NTSTRSAFE_MAX_CCH,
339 Flags);
340 if (NT_SUCCESS(Status))
341 {
342 LocalDestinationEnd = Destination;
343 Remaining = CharLength;
344
345 Status = RtlStringExValidateSrcA(&Source,
346 NULL,
347 NTSTRSAFE_MAX_CCH,
348 Flags);
349 if (NT_SUCCESS(Status))
350 {
351 if (!CharLength)
352 {
353 if (*Source != ANSI_NULL)
354 {
355 if (!Destination)
356 {
357 Status = STATUS_INVALID_PARAMETER;
358 }
359 else
360 {
361 Status = STATUS_BUFFER_OVERFLOW;
362 }
363 }
364 }
365 else
366 {
367 Status = RtlStringCopyWorkerA(Destination,
368 CharLength,
369 &Copied,
370 Source,
371 NTSTRSAFE_MAX_LENGTH);
372
373 LocalDestinationEnd = Destination + Copied;
374 Remaining = CharLength - Copied;
375 }
376 }
377 else
378 {
379 if (CharLength) *Destination = ANSI_NULL;
380 }
381
382 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
383 {
384 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
385
386 if (RemainingSize)
387 {
388 *RemainingSize = (Remaining * sizeof(CHAR)) +
389 (Length % sizeof(CHAR));
390 }
391 }
392 }
393
394 return Status;
395 }
396
397
398 NTSTATUS
399 NTAPI
400 RtlStringCbPrintfW(
401 LPWSTR pszDest,
402 IN size_t cbDest,
403 IN LPCWSTR pszFormat,
404 ...)
405 {
406 UNIMPLEMENTED
407 return STATUS_NOT_IMPLEMENTED;
408 }
409
410 FORCEINLINE
411 NTSTATUS
412 NTAPI
413 RtlStringCbCatExA(IN OUT PCHAR Destination,
414 IN SIZE_T Length,
415 IN PCCHAR Source,
416 OUT PCHAR *DestinationEnd OPTIONAL,
417 OUT PSIZE_T RemainingSize OPTIONAL,
418 IN DWORD Flags)
419 {
420 NTSTATUS Status;
421 SIZE_T CharLength = Length / sizeof(CHAR);
422 SIZE_T DestinationLength, Remaining, Copied = 0;
423 PCHAR LocalDestinationEnd;
424 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
425
426 Status = RtlStringExValidateDestA(&Destination,
427 &CharLength,
428 &DestinationLength,
429 NTSTRSAFE_MAX_CCH,
430 Flags);
431 if (NT_SUCCESS(Status))
432 {
433 LocalDestinationEnd = Destination + DestinationLength;
434 Remaining = CharLength - DestinationLength;
435
436 Status = RtlStringExValidateSrcA(&Source,
437 NULL,
438 NTSTRSAFE_MAX_CCH,
439 Flags);
440 if (NT_SUCCESS(Status))
441 {
442 if (Remaining <= 1)
443 {
444 if (*Source != ANSI_NULL)
445 {
446 if (!Destination)
447 {
448 Status = STATUS_INVALID_PARAMETER;
449 }
450 else
451 {
452 Status = STATUS_BUFFER_OVERFLOW;
453 }
454 }
455 }
456 else
457 {
458 Status = RtlStringCopyWorkerA(LocalDestinationEnd,
459 Remaining,
460 &Copied,
461 Source,
462 NTSTRSAFE_MAX_LENGTH);
463
464 LocalDestinationEnd = LocalDestinationEnd + Copied;
465 Remaining = Remaining - Copied;
466 }
467 }
468
469 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
470 {
471 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
472
473 if (RemainingSize)
474 {
475 *RemainingSize = (Remaining * sizeof(CHAR)) +
476 (Length % sizeof(CHAR));
477 }
478 }
479 }
480
481 return Status;
482 }
483
484 FORCEINLINE
485 NTSTATUS
486 NTAPI
487 RtlStringCbCopyA(OUT PCHAR Destination,
488 IN SIZE_T Length,
489 IN PCCHAR Source)
490 {
491 NTSTATUS Status;
492 SIZE_T CharLength = Length / sizeof(CHAR);
493
494 Status = RtlStringValidateDestA(Destination,
495 CharLength,
496 NULL,
497 NTSTRSAFE_MAX_CCH);
498 if (NT_SUCCESS(Status))
499 {
500 Status = RtlStringCopyWorkerA(Destination,
501 CharLength,
502 NULL,
503 Source,
504 NTSTRSAFE_MAX_LENGTH);
505 }
506
507 return Status;
508 }
509
510 #endif