055d3b312d20445c7623d218db498806a08c0674
[reactos.git] / reactos / include / ddk / ntstrsafe.h
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: This file is in the public domain.
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 #include <windef.h> /* we need DWORD */
21
22 //
23 // Maximum limits: allow overriding the maximum
24 //
25 #ifndef NTSTRSAFE_MAX_CCH
26 #define NTSTRSAFE_MAX_CCH 2147483647
27 #endif
28 #define NTSTRSAFE_MAX_LENGTH (NTSTRSAFE_MAX_CCH - 1)
29
30 /* PRIVATE FUNCTIONS *********************************************************/
31
32 static __inline
33 NTSTATUS
34 NTAPI
35 RtlStringLengthWorkerA(IN LPCSTR String,
36 IN SIZE_T MaxLength,
37 OUT PSIZE_T ReturnLength OPTIONAL)
38 {
39 NTSTATUS Status = STATUS_SUCCESS;
40 SIZE_T LocalMax = MaxLength;
41
42 while (MaxLength && (*String != ANSI_NULL))
43 {
44 String++;
45 MaxLength--;
46 }
47
48 if (!MaxLength) Status = STATUS_INVALID_PARAMETER;
49
50 if (ReturnLength)
51 {
52 if (NT_SUCCESS(Status))
53 {
54 *ReturnLength = LocalMax - MaxLength;
55 }
56 else
57 {
58 *ReturnLength = 0;
59 }
60 }
61
62 return Status;
63 }
64
65 static __inline
66 NTSTATUS
67 NTAPI
68 RtlStringLengthWorkerW(IN LPCWSTR String,
69 IN SIZE_T MaxLength,
70 OUT PSIZE_T ReturnLength OPTIONAL)
71 {
72 NTSTATUS Status = STATUS_SUCCESS;
73 SIZE_T LocalMax = MaxLength;
74
75 while (MaxLength && (*String != UNICODE_NULL))
76 {
77 String++;
78 MaxLength--;
79 }
80
81 if (!MaxLength) Status = STATUS_INVALID_PARAMETER;
82
83 if (ReturnLength)
84 {
85 if (NT_SUCCESS(Status))
86 {
87 *ReturnLength = LocalMax - MaxLength;
88 }
89 else
90 {
91 *ReturnLength = 0;
92 }
93 }
94
95 return Status;
96 }
97
98 static __inline
99 NTSTATUS
100 NTAPI
101 RtlStringValidateDestA(IN LPSTR Destination,
102 IN SIZE_T Length,
103 OUT PSIZE_T ReturnLength OPTIONAL,
104 IN SIZE_T MaxLength)
105 {
106 NTSTATUS Status = STATUS_SUCCESS;
107
108 if (!(Length) || (Length > MaxLength)) Status = STATUS_INVALID_PARAMETER;
109
110 if (ReturnLength)
111 {
112 if (NT_SUCCESS(Status))
113 {
114 Status = RtlStringLengthWorkerA(Destination,
115 Length,
116 ReturnLength);
117 }
118 else
119 {
120 *ReturnLength = 0;
121 }
122 }
123
124 return Status;
125 }
126
127 static __inline
128 NTSTATUS
129 NTAPI
130 RtlStringValidateDestW(IN LPWSTR Destination,
131 IN SIZE_T Length,
132 OUT PSIZE_T ReturnLength OPTIONAL,
133 IN SIZE_T MaxLength)
134 {
135 NTSTATUS Status = STATUS_SUCCESS;
136
137 if (!(Length) || (Length > MaxLength)) Status = STATUS_INVALID_PARAMETER;
138
139 if (ReturnLength)
140 {
141 if (NT_SUCCESS(Status))
142 {
143 Status = RtlStringLengthWorkerW(Destination,
144 Length,
145 ReturnLength);
146 }
147 else
148 {
149 *ReturnLength = 0;
150 }
151 }
152
153 return Status;
154 }
155
156 static __inline
157 NTSTATUS
158 NTAPI
159 RtlStringExValidateDestA(IN OUT LPSTR *Destination,
160 IN OUT PSIZE_T DestinationLength,
161 OUT PSIZE_T ReturnLength OPTIONAL,
162 IN SIZE_T MaxLength,
163 IN DWORD Flags)
164 {
165 ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
166 return RtlStringValidateDestA(*Destination,
167 *DestinationLength,
168 ReturnLength,
169 MaxLength);
170 }
171
172 static __inline
173 NTSTATUS
174 NTAPI
175 RtlStringExValidateDestW(IN OUT LPWSTR *Destination,
176 IN OUT PSIZE_T DestinationLength,
177 OUT PSIZE_T ReturnLength OPTIONAL,
178 IN SIZE_T MaxLength,
179 IN DWORD Flags)
180 {
181 ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
182 return RtlStringValidateDestW(*Destination,
183 *DestinationLength,
184 ReturnLength,
185 MaxLength);
186 }
187
188 static __inline
189 NTSTATUS
190 NTAPI
191 RtlStringExValidateSrcA(IN OUT LPCSTR *Source OPTIONAL,
192 IN OUT PSIZE_T ReturnLength OPTIONAL,
193 IN SIZE_T MaxLength,
194 IN DWORD Flags)
195 {
196 NTSTATUS Status = STATUS_SUCCESS;
197 ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
198
199 if ((ReturnLength) && (*ReturnLength >= MaxLength))
200 {
201 Status = STATUS_INVALID_PARAMETER;
202 }
203
204 return Status;
205 }
206
207 static __inline
208 NTSTATUS
209 NTAPI
210 RtlStringExValidateSrcW(IN OUT LPCWSTR *Source OPTIONAL,
211 IN OUT PSIZE_T ReturnLength OPTIONAL,
212 IN SIZE_T MaxLength,
213 IN DWORD Flags)
214 {
215 NTSTATUS Status = STATUS_SUCCESS;
216 ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
217
218 if ((ReturnLength) && (*ReturnLength >= MaxLength))
219 {
220 Status = STATUS_INVALID_PARAMETER;
221 }
222
223 return Status;
224 }
225
226 static __inline
227 NTSTATUS
228 NTAPI
229 RtlStringVPrintfWorkerA(OUT LPSTR Destination,
230 IN SIZE_T Length,
231 OUT PSIZE_T NewLength OPTIONAL,
232 IN LPCSTR Format,
233 IN va_list argList)
234 {
235 NTSTATUS Status = STATUS_SUCCESS;
236 LONG Return;
237 SIZE_T MaxLength, LocalNewLength = 0;
238
239 MaxLength = Length - 1;
240
241 Return = _vsnprintf(Destination, MaxLength, Format, argList);
242 if ((Return < 0) || ((SIZE_T)Return > MaxLength))
243 {
244 Destination += MaxLength;
245 *Destination = ANSI_NULL;
246
247 LocalNewLength = MaxLength;
248
249 Status = STATUS_BUFFER_OVERFLOW;
250 }
251 else if ((SIZE_T)Return == MaxLength)
252 {
253 Destination += MaxLength;
254 *Destination = ANSI_NULL;
255
256 LocalNewLength = MaxLength;
257 }
258 else
259 {
260 LocalNewLength = Return;
261 }
262
263 if (NewLength) *NewLength = LocalNewLength;
264 return Status;
265 }
266
267 static __inline
268 NTSTATUS
269 NTAPI
270 RtlStringCopyWorkerA(OUT LPSTR Destination,
271 IN SIZE_T Length,
272 OUT PSIZE_T NewLength OPTIONAL,
273 IN LPCSTR Source,
274 IN SIZE_T CopyLength)
275 {
276 NTSTATUS Status = STATUS_SUCCESS;
277 SIZE_T LocalNewLength = 0;
278
279 while ((Length) && (CopyLength) && (*Source != ANSI_NULL))
280 {
281 *Destination++ = *Source++;
282 Length--;
283 CopyLength--;
284
285 LocalNewLength++;
286 }
287
288 if (!Length)
289 {
290 Destination--;
291 LocalNewLength--;
292
293 Status = STATUS_BUFFER_OVERFLOW;
294 }
295
296 *Destination = ANSI_NULL;
297
298 if (NewLength) *NewLength = LocalNewLength;
299 return Status;
300 }
301
302 static __inline
303 NTSTATUS
304 NTAPI
305 RtlStringCopyWorkerW(OUT LPWSTR Destination,
306 IN SIZE_T Length,
307 OUT PSIZE_T NewLength OPTIONAL,
308 IN LPCWSTR Source,
309 IN SIZE_T CopyLength)
310 {
311 NTSTATUS Status = STATUS_SUCCESS;
312 SIZE_T LocalNewLength = 0;
313
314 while ((Length) && (CopyLength) && (*Source != UNICODE_NULL))
315 {
316 *Destination++ = *Source++;
317 Length--;
318 CopyLength--;
319
320 LocalNewLength++;
321 }
322
323 if (!Length)
324 {
325 Destination--;
326 LocalNewLength--;
327
328 Status = STATUS_BUFFER_OVERFLOW;
329 }
330
331 *Destination = UNICODE_NULL;
332
333 if (NewLength) *NewLength = LocalNewLength;
334 return Status;
335 }
336
337 /* PUBLIC FUNCTIONS **********************************************************/
338
339 static __inline
340 NTSTATUS
341 NTAPI
342 RtlStringCchCopyA(IN LPSTR Destination,
343 IN SIZE_T cchDest,
344 IN LPCSTR pszSrc)
345 {
346 ASSERTMSG("RtlStringCchCopyA is UNIMPLEMENTED!\n", FALSE);
347 return STATUS_NOT_IMPLEMENTED;
348 }
349
350 static __inline
351 NTSTATUS
352 NTAPI
353 RtlStringCchCopyW(IN LPWSTR Destination,
354 IN SIZE_T cchDest,
355 IN LPCWSTR pszSrc)
356 {
357 ASSERTMSG("RtlStringCchCopyA is UNIMPLEMENTED!\n", FALSE);
358 return STATUS_NOT_IMPLEMENTED;
359 }
360
361 static __inline
362 NTSTATUS
363 RtlStringCbPrintfA(OUT LPSTR Destination,
364 IN SIZE_T Length,
365 IN LPCSTR Format,
366 ...)
367 {
368 NTSTATUS Status;
369 SIZE_T CharLength = Length / sizeof(CHAR);
370 va_list argList;
371
372 Status = RtlStringValidateDestA(Destination,
373 CharLength,
374 NULL,
375 NTSTRSAFE_MAX_CCH);
376 if (NT_SUCCESS(Status))
377 {
378 va_start(argList, Format);
379 Status = RtlStringVPrintfWorkerA(Destination,
380 CharLength,
381 NULL,
382 Format,
383 argList);
384 va_end(argList);
385 }
386
387 return Status;
388 }
389
390 static __inline
391 NTSTATUS
392 RtlStringCbPrintfExA(OUT LPSTR Destination,
393 IN SIZE_T Length,
394 OUT LPSTR *DestinationEnd OPTIONAL,
395 OUT PSIZE_T RemainingSize OPTIONAL,
396 IN DWORD Flags,
397 IN LPCSTR Format,
398 ...)
399 {
400 NTSTATUS Status;
401 SIZE_T CharLength = Length / sizeof(CHAR), Remaining, LocalNewLength = 0;
402 PCHAR LocalDestinationEnd;
403 va_list argList;
404 ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
405
406 Status = RtlStringExValidateDestA(&Destination,
407 &CharLength,
408 NULL,
409 NTSTRSAFE_MAX_CCH,
410 Flags);
411 if (NT_SUCCESS(Status))
412 {
413 LocalDestinationEnd = Destination;
414 Remaining = CharLength;
415
416 Status = RtlStringExValidateSrcA(&Format,
417 NULL,
418 NTSTRSAFE_MAX_CCH,
419 Flags);
420 if (NT_SUCCESS(Status))
421 {
422 if (!Length)
423 {
424 if (*Format != ANSI_NULL)
425 {
426 if (!Destination)
427 {
428 Status = STATUS_INVALID_PARAMETER;
429 }
430 else
431 {
432 Status = STATUS_BUFFER_OVERFLOW;
433 }
434 }
435 }
436 else
437 {
438 va_start(argList, Format);
439 Status = RtlStringVPrintfWorkerA(Destination,
440 CharLength,
441 &LocalNewLength,
442 Format,
443 argList);
444 va_end(argList);
445
446 LocalDestinationEnd = Destination + LocalNewLength;
447 Remaining = CharLength - LocalNewLength;
448 }
449 }
450 else
451 {
452 if (Length) *Destination = ANSI_NULL;
453 }
454
455 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
456 {
457 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
458
459 if (RemainingSize)
460 {
461 *RemainingSize = (Remaining * sizeof(CHAR)) +
462 (Length % sizeof(CHAR));
463 }
464 }
465 }
466
467 return Status;
468 }
469
470 static __inline
471 NTSTATUS
472 NTAPI
473 RtlStringCbCopyExA(OUT LPSTR Destination,
474 IN SIZE_T Length,
475 IN LPCSTR Source,
476 OUT LPSTR *DestinationEnd OPTIONAL,
477 OUT PSIZE_T RemainingSize OPTIONAL,
478 IN DWORD Flags)
479 {
480 NTSTATUS Status;
481 SIZE_T CharLength = Length / sizeof(CHAR), Copied = 0, Remaining;
482 PCHAR LocalDestinationEnd;
483 ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
484
485 Status = RtlStringExValidateDestA(&Destination,
486 &Length,
487 NULL,
488 NTSTRSAFE_MAX_CCH,
489 Flags);
490 if (NT_SUCCESS(Status))
491 {
492 LocalDestinationEnd = Destination;
493 Remaining = CharLength;
494
495 Status = RtlStringExValidateSrcA(&Source,
496 NULL,
497 NTSTRSAFE_MAX_CCH,
498 Flags);
499 if (NT_SUCCESS(Status))
500 {
501 if (!CharLength)
502 {
503 if (*Source != ANSI_NULL)
504 {
505 if (!Destination)
506 {
507 Status = STATUS_INVALID_PARAMETER;
508 }
509 else
510 {
511 Status = STATUS_BUFFER_OVERFLOW;
512 }
513 }
514 }
515 else
516 {
517 Status = RtlStringCopyWorkerA(Destination,
518 CharLength,
519 &Copied,
520 Source,
521 NTSTRSAFE_MAX_LENGTH);
522
523 LocalDestinationEnd = Destination + Copied;
524 Remaining = CharLength - Copied;
525 }
526 }
527 else
528 {
529 if (CharLength) *Destination = ANSI_NULL;
530 }
531
532 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
533 {
534 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
535
536 if (RemainingSize)
537 {
538 *RemainingSize = (Remaining * sizeof(CHAR)) +
539 (Length % sizeof(CHAR));
540 }
541 }
542 }
543
544 return Status;
545 }
546
547 static __inline
548 NTSTATUS
549 RtlStringCbPrintfW(
550 LPWSTR pszDest,
551 IN size_t cbDest,
552 IN LPCWSTR pszFormat,
553 ...)
554 {
555 ASSERTMSG("RtlStringCbPrintfW is UNIMPLEMENTED!\n", FALSE);
556 return STATUS_NOT_IMPLEMENTED;
557 }
558
559 static __inline
560 NTSTATUS
561 NTAPI
562 RtlStringCbCatExA(IN OUT LPSTR Destination,
563 IN SIZE_T Length,
564 IN LPCSTR Source,
565 OUT LPSTR *DestinationEnd OPTIONAL,
566 OUT PSIZE_T RemainingSize OPTIONAL,
567 IN DWORD Flags)
568 {
569 NTSTATUS Status;
570 SIZE_T CharLength = Length / sizeof(CHAR);
571 SIZE_T DestinationLength, Remaining, Copied = 0;
572 PCHAR LocalDestinationEnd;
573 ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
574
575 Status = RtlStringExValidateDestA(&Destination,
576 &CharLength,
577 &DestinationLength,
578 NTSTRSAFE_MAX_CCH,
579 Flags);
580 if (NT_SUCCESS(Status))
581 {
582 LocalDestinationEnd = Destination + DestinationLength;
583 Remaining = CharLength - DestinationLength;
584
585 Status = RtlStringExValidateSrcA(&Source,
586 NULL,
587 NTSTRSAFE_MAX_CCH,
588 Flags);
589 if (NT_SUCCESS(Status))
590 {
591 if (Remaining <= 1)
592 {
593 if (*Source != ANSI_NULL)
594 {
595 if (!Destination)
596 {
597 Status = STATUS_INVALID_PARAMETER;
598 }
599 else
600 {
601 Status = STATUS_BUFFER_OVERFLOW;
602 }
603 }
604 }
605 else
606 {
607 Status = RtlStringCopyWorkerA(LocalDestinationEnd,
608 Remaining,
609 &Copied,
610 Source,
611 NTSTRSAFE_MAX_LENGTH);
612
613 LocalDestinationEnd = LocalDestinationEnd + Copied;
614 Remaining = Remaining - Copied;
615 }
616 }
617
618 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
619 {
620 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
621
622 if (RemainingSize)
623 {
624 *RemainingSize = (Remaining * sizeof(CHAR)) +
625 (Length % sizeof(CHAR));
626 }
627 }
628 }
629
630 return Status;
631 }
632
633 static __inline
634 NTSTATUS
635 NTAPI
636 RtlStringCbCatExW(IN OUT LPWSTR Destination,
637 IN SIZE_T Length,
638 IN LPCWSTR Source,
639 OUT LPWSTR *DestinationEnd OPTIONAL,
640 OUT PSIZE_T RemainingSize OPTIONAL,
641 IN DWORD Flags)
642 {
643 NTSTATUS Status;
644 SIZE_T CharLength = Length / sizeof(WCHAR);
645 SIZE_T DestinationLength, Remaining, Copied = 0;
646 PWCHAR LocalDestinationEnd;
647 ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
648
649 Status = RtlStringExValidateDestW(&Destination,
650 &CharLength,
651 &DestinationLength,
652 NTSTRSAFE_MAX_CCH,
653 Flags);
654 if (NT_SUCCESS(Status))
655 {
656 LocalDestinationEnd = Destination + DestinationLength;
657 Remaining = CharLength - DestinationLength;
658
659 Status = RtlStringExValidateSrcW(&Source,
660 NULL,
661 NTSTRSAFE_MAX_CCH,
662 Flags);
663 if (NT_SUCCESS(Status))
664 {
665 if (Remaining <= 1)
666 {
667 if (*Source != UNICODE_NULL)
668 {
669 if (!Destination)
670 {
671 Status = STATUS_INVALID_PARAMETER;
672 }
673 else
674 {
675 Status = STATUS_BUFFER_OVERFLOW;
676 }
677 }
678 }
679 else
680 {
681 Status = RtlStringCopyWorkerW(LocalDestinationEnd,
682 Remaining,
683 &Copied,
684 Source,
685 NTSTRSAFE_MAX_LENGTH);
686
687 LocalDestinationEnd = LocalDestinationEnd + Copied;
688 Remaining = Remaining - Copied;
689 }
690 }
691
692 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
693 {
694 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
695
696 if (RemainingSize)
697 {
698 *RemainingSize = (Remaining * sizeof(WCHAR)) +
699 (Length % sizeof(WCHAR));
700 }
701 }
702 }
703
704 return Status;
705 }
706
707 static __inline
708 NTSTATUS
709 NTAPI
710 RtlStringCbCopyA(OUT LPSTR Destination,
711 IN SIZE_T Length,
712 IN LPCSTR Source)
713 {
714 NTSTATUS Status;
715 SIZE_T CharLength = Length / sizeof(CHAR);
716
717 Status = RtlStringValidateDestA(Destination,
718 CharLength,
719 NULL,
720 NTSTRSAFE_MAX_CCH);
721 if (NT_SUCCESS(Status))
722 {
723 Status = RtlStringCopyWorkerA(Destination,
724 CharLength,
725 NULL,
726 Source,
727 NTSTRSAFE_MAX_LENGTH);
728 }
729
730 return Status;
731 }
732
733 static __inline
734 NTSTATUS
735 NTAPI
736 RtlStringCbCopyW(OUT LPWSTR Destination,
737 IN SIZE_T Length,
738 IN LPCWSTR Source)
739 {
740 NTSTATUS Status;
741 SIZE_T CharLength = Length / sizeof(WCHAR);
742
743 Status = RtlStringValidateDestW(Destination,
744 CharLength,
745 NULL,
746 NTSTRSAFE_MAX_CCH);
747 if (NT_SUCCESS(Status))
748 {
749 Status = RtlStringCopyWorkerW(Destination,
750 CharLength,
751 NULL,
752 Source,
753 NTSTRSAFE_MAX_LENGTH);
754 }
755
756 return Status;
757 }
758
759 #endif /* _NTSTRSAFE_H_INCLUDED_ */