Home | History | Annotate | Download | only in ddk
      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 (at) 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 ULONG DWORD;
     33 
     34 /* PRIVATE FUNCTIONS *********************************************************/
     35 
     36 static __inline
     37 NTSTATUS
     38 NTAPI
     39 RtlStringLengthWorkerA(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 
     69 static __inline
     70 NTSTATUS
     71 NTAPI
     72 RtlStringValidateDestA(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 
     98 static __inline
     99 NTSTATUS
    100 NTAPI
    101 RtlStringExValidateDestA(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 
    114 static __inline
    115 NTSTATUS
    116 NTAPI
    117 RtlStringExValidateSrcA(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 
    133 static __inline
    134 NTSTATUS
    135 NTAPI
    136 RtlStringVPrintfWorkerA(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 
    174 static __inline
    175 NTSTATUS
    176 NTAPI
    177 RtlStringCopyWorkerA(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 
    211 static __inline
    212 NTSTATUS
    213 NTAPI
    214 RtlStringCchCopyA(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 
    222 static __inline
    223 NTSTATUS
    224 RtlStringCbPrintfA(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 
    251 static __inline
    252 NTSTATUS
    253 RtlStringCbPrintfExA(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 
    331 static __inline
    332 NTSTATUS
    333 NTAPI
    334 RtlStringCbCopyExA(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 
    408 static __inline
    409 NTSTATUS
    410 RtlStringCbPrintfW(
    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 
    420 static __inline
    421 NTSTATUS
    422 NTAPI
    423 RtlStringCbCatExA(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 
    494 static __inline
    495 NTSTATUS
    496 NTAPI
    497 RtlStringCbCopyA(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