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
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//
32typedef ULONG DWORD;
33
34/* PRIVATE FUNCTIONS *********************************************************/
35
36static __inline
37NTSTATUS
38NTAPI
39RtlStringLengthWorkerA(IN LPCSTR 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
69static __inline
70NTSTATUS
71NTAPI
72RtlStringValidateDestA(IN LPSTR 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
98static __inline
99NTSTATUS
100NTAPI
101RtlStringExValidateDestA(IN OUT LPSTR *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
114static __inline
115NTSTATUS
116NTAPI
117RtlStringExValidateSrcA(IN OUT LPCSTR *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
133static __inline
134NTSTATUS
135NTAPI
136RtlStringVPrintfWorkerA(OUT LPSTR Destination,
137                        IN SIZE_T Length,
138                        OUT PSIZE_T NewLength OPTIONAL,
139                        IN LPCSTR 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
174static __inline
175NTSTATUS
176NTAPI
177RtlStringCopyWorkerA(OUT LPSTR Destination,
178                     IN SIZE_T Length,
179                     OUT PSIZE_T NewLength OPTIONAL,
180                     IN LPCSTR 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
211static __inline
212NTSTATUS
213NTAPI
214RtlStringCchCopyA(IN LPSTR Destination,
215                  IN SIZE_T cchDest,
216                  IN LPCSTR pszSrc)
217{
218    ASSERTMSG("RtlStringCchCopyA is UNIMPLEMENTED!\n", FALSE);
219    return STATUS_NOT_IMPLEMENTED;
220}
221
222static __inline
223NTSTATUS
224RtlStringCbPrintfA(OUT LPSTR Destination,
225                   IN SIZE_T Length,
226                   IN LPCSTR Format,
227                   ...)
228{
229    NTSTATUS Status;
230    SIZE_T CharLength = Length / sizeof(CHAR);
231    va_list argList;
232
233    Status = RtlStringValidateDestA(Destination,
234                                    CharLength,
235                                    NULL,
236                                    NTSTRSAFE_MAX_CCH);
237    if (NT_SUCCESS(Status))
238    {
239        va_start(argList, Format);
240        Status = RtlStringVPrintfWorkerA(Destination,
241                                         CharLength,
242                                         NULL,
243                                         Format,
244                                         argList);
245        va_end(argList);
246    }
247
248    return Status;
249}
250
251static __inline
252NTSTATUS
253RtlStringCbPrintfExA(OUT LPSTR Destination,
254                     IN SIZE_T Length,
255                     OUT LPSTR *DestinationEnd OPTIONAL,
256                     OUT PSIZE_T RemainingSize OPTIONAL,
257                     IN DWORD Flags,
258                     IN LPCSTR Format,
259                     ...)
260{
261    NTSTATUS Status;
262    SIZE_T CharLength = Length / sizeof(CHAR), Remaining, LocalNewLength = 0;
263    PCHAR LocalDestinationEnd;
264    va_list argList;
265    ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
266
267    Status = RtlStringExValidateDestA(&Destination,
268                                      &CharLength,
269                                      NULL,
270                                      NTSTRSAFE_MAX_CCH,
271                                      Flags);
272    if (NT_SUCCESS(Status))
273    {
274        LocalDestinationEnd = Destination;
275        Remaining = CharLength;
276
277        Status = RtlStringExValidateSrcA(&Format,
278                                         NULL,
279                                         NTSTRSAFE_MAX_CCH,
280                                         Flags);
281        if (NT_SUCCESS(Status))
282        {
283            if (!Length)
284            {
285                if (*Format != ANSI_NULL)
286                {
287                    if (!Destination)
288                    {
289                        Status = STATUS_INVALID_PARAMETER;
290                    }
291                    else
292                    {
293                        Status = STATUS_BUFFER_OVERFLOW;
294                    }
295                }
296            }
297            else
298            {
299                va_start(argList, Format);
300                Status = RtlStringVPrintfWorkerA(Destination,
301                                                 CharLength,
302                                                 &LocalNewLength,
303                                                 Format,
304                                                 argList);
305                va_end(argList);
306
307                LocalDestinationEnd = Destination + LocalNewLength;
308                Remaining = CharLength - LocalNewLength;
309            }
310        }
311        else
312        {
313            if (Length) *Destination = ANSI_NULL;
314        }
315
316        if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
317        {
318            if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
319
320            if (RemainingSize)
321            {
322                *RemainingSize = (Remaining * sizeof(CHAR)) +
323                                 (Length % sizeof(CHAR));
324            }
325        }
326    }
327
328    return Status;
329}
330
331static __inline
332NTSTATUS
333NTAPI
334RtlStringCbCopyExA(OUT LPSTR Destination,
335                   IN SIZE_T Length,
336                   IN LPCSTR Source,
337                   OUT LPSTR *DestinationEnd OPTIONAL,
338                   OUT PSIZE_T RemainingSize OPTIONAL,
339                   IN DWORD Flags)
340{
341    NTSTATUS Status;
342    SIZE_T CharLength = Length / sizeof(CHAR), Copied = 0, Remaining;
343    PCHAR LocalDestinationEnd;
344    ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
345
346    Status = RtlStringExValidateDestA(&Destination,
347                                      &Length,
348                                      NULL,
349                                      NTSTRSAFE_MAX_CCH,
350                                      Flags);
351    if (NT_SUCCESS(Status))
352    {
353        LocalDestinationEnd = Destination;
354        Remaining = CharLength;
355
356        Status = RtlStringExValidateSrcA(&Source,
357                                         NULL,
358                                         NTSTRSAFE_MAX_CCH,
359                                         Flags);
360        if (NT_SUCCESS(Status))
361        {
362            if (!CharLength)
363            {
364                if (*Source != ANSI_NULL)
365                {
366                    if (!Destination)
367                    {
368                        Status = STATUS_INVALID_PARAMETER;
369                    }
370                    else
371                    {
372                        Status = STATUS_BUFFER_OVERFLOW;
373                    }
374                }
375            }
376            else
377            {
378                Status = RtlStringCopyWorkerA(Destination,
379                                              CharLength,
380                                              &Copied,
381                                              Source,
382                                              NTSTRSAFE_MAX_LENGTH);
383
384                LocalDestinationEnd = Destination + Copied;
385                Remaining = CharLength - Copied;
386            }
387        }
388        else
389        {
390            if (CharLength) *Destination = ANSI_NULL;
391        }
392
393        if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
394        {
395            if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
396
397            if (RemainingSize)
398            {
399                *RemainingSize = (Remaining * sizeof(CHAR)) +
400                                 (Length % sizeof(CHAR));
401            }
402        }
403    }
404
405    return Status;
406}
407
408static __inline
409NTSTATUS
410RtlStringCbPrintfW(
411    LPWSTR pszDest,
412    IN size_t cbDest,
413    IN LPCWSTR pszFormat,
414    ...)
415{
416    ASSERTMSG("RtlStringCbPrintfW is UNIMPLEMENTED!\n", FALSE);
417    return STATUS_NOT_IMPLEMENTED;
418}
419
420static __inline
421NTSTATUS
422NTAPI
423RtlStringCbCatExA(IN OUT LPSTR Destination,
424                  IN SIZE_T Length,
425                  IN LPCSTR Source,
426                  OUT LPSTR *DestinationEnd OPTIONAL,
427                  OUT PSIZE_T RemainingSize OPTIONAL,
428                  IN DWORD Flags)
429{
430    NTSTATUS Status;
431    SIZE_T CharLength = Length / sizeof(CHAR);
432    SIZE_T DestinationLength, Remaining, Copied = 0;
433    PCHAR LocalDestinationEnd;
434    ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
435
436    Status = RtlStringExValidateDestA(&Destination,
437                                      &CharLength,
438                                      &DestinationLength,
439                                      NTSTRSAFE_MAX_CCH,
440                                      Flags);
441    if (NT_SUCCESS(Status))
442    {
443        LocalDestinationEnd = Destination + DestinationLength;
444        Remaining = CharLength - DestinationLength;
445
446        Status = RtlStringExValidateSrcA(&Source,
447                                         NULL,
448                                         NTSTRSAFE_MAX_CCH,
449                                         Flags);
450        if (NT_SUCCESS(Status))
451        {
452            if (Remaining <= 1)
453            {
454                if (*Source != ANSI_NULL)
455                {
456                    if (!Destination)
457                    {
458                        Status = STATUS_INVALID_PARAMETER;
459                    }
460                    else
461                    {
462                        Status = STATUS_BUFFER_OVERFLOW;
463                    }
464                }
465            }
466            else
467            {
468                Status = RtlStringCopyWorkerA(LocalDestinationEnd,
469                                              Remaining,
470                                              &Copied,
471                                              Source,
472                                              NTSTRSAFE_MAX_LENGTH);
473
474                LocalDestinationEnd = LocalDestinationEnd + Copied;
475                Remaining = Remaining - Copied;
476            }
477        }
478
479        if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
480        {
481            if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
482
483            if (RemainingSize)
484            {
485                *RemainingSize = (Remaining * sizeof(CHAR)) +
486                                 (Length % sizeof(CHAR));
487            }
488        }
489    }
490
491    return Status;
492}
493
494static __inline
495NTSTATUS
496NTAPI
497RtlStringCbCopyA(OUT LPSTR Destination,
498                 IN SIZE_T Length,
499                 IN LPCSTR Source)
500{
501    NTSTATUS Status;
502    SIZE_T CharLength = Length / sizeof(CHAR);
503
504    Status = RtlStringValidateDestA(Destination,
505                                    CharLength,
506                                    NULL,
507                                    NTSTRSAFE_MAX_CCH);
508    if (NT_SUCCESS(Status))
509    {
510        Status = RtlStringCopyWorkerA(Destination,
511                                      CharLength,
512                                      NULL,
513                                      Source,
514                                      NTSTRSAFE_MAX_LENGTH);
515    }
516
517    return Status;
518}
519
520#endif /* _NTSTRSAFE_H_INCLUDED_ */
521
522