| /* |
| * PROJECT: ReactOS Kernel |
| * LICENSE: This file is in the public domain. |
| * FILE: include/ddk/ntstrsafe.h |
| * PURPOSE: Safe String Library for NT Code (Native/Kernel) |
| * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) |
| */ |
| |
| /* INCLUDES ******************************************************************/ |
| |
| #ifndef _NTSTRSAFE_H_INCLUDED_ |
| #define _NTSTRSAFE_H_INCLUDED_ |
| |
| // |
| // Dependencies |
| // |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdarg.h> |
| |
| // |
| // Maximum limits: allow overriding the maximum |
| // |
| #ifndef NTSTRSAFE_MAX_CCH |
| #define NTSTRSAFE_MAX_CCH 2147483647 |
| #endif |
| #define NTSTRSAFE_MAX_LENGTH (NTSTRSAFE_MAX_CCH - 1) |
| |
| // |
| // Typedefs |
| // |
| typedef unsigned long DWORD; |
| |
| /* PRIVATE FUNCTIONS *********************************************************/ |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringLengthWorkerA(IN LPCSTR String, |
| IN SIZE_T MaxLength, |
| OUT PSIZE_T ReturnLength OPTIONAL) |
| { |
| NTSTATUS Status = STATUS_SUCCESS; |
| SIZE_T LocalMax = MaxLength; |
| |
| while (MaxLength && (*String != ANSI_NULL)) |
| { |
| String++; |
| MaxLength--; |
| } |
| |
| if (!MaxLength) Status = STATUS_INVALID_PARAMETER; |
| |
| if (ReturnLength) |
| { |
| if (NT_SUCCESS(Status)) |
| { |
| *ReturnLength = LocalMax - MaxLength; |
| } |
| else |
| { |
| *ReturnLength = 0; |
| } |
| } |
| |
| return Status; |
| } |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringValidateDestA(IN LPSTR Destination, |
| IN SIZE_T Length, |
| OUT PSIZE_T ReturnLength OPTIONAL, |
| IN SIZE_T MaxLength) |
| { |
| NTSTATUS Status = STATUS_SUCCESS; |
| |
| if (!(Length) || (Length > MaxLength)) Status = STATUS_INVALID_PARAMETER; |
| |
| if (ReturnLength) |
| { |
| if (NT_SUCCESS(Status)) |
| { |
| Status = RtlStringLengthWorkerA(Destination, |
| Length, |
| ReturnLength); |
| } |
| else |
| { |
| *ReturnLength = 0; |
| } |
| } |
| |
| return Status; |
| } |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringExValidateDestA(IN OUT LPSTR *Destination, |
| IN OUT PSIZE_T DestinationLength, |
| OUT PSIZE_T ReturnLength OPTIONAL, |
| IN SIZE_T MaxLength, |
| IN DWORD Flags) |
| { |
| ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0); |
| return RtlStringValidateDestA(*Destination, |
| *DestinationLength, |
| ReturnLength, |
| MaxLength); |
| } |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringExValidateSrcA(IN OUT LPCSTR *Source OPTIONAL, |
| IN OUT PSIZE_T ReturnLength OPTIONAL, |
| IN SIZE_T MaxLength, |
| IN DWORD Flags) |
| { |
| NTSTATUS Status = STATUS_SUCCESS; |
| ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0); |
| |
| if ((ReturnLength) && (*ReturnLength >= MaxLength)) |
| { |
| Status = STATUS_INVALID_PARAMETER; |
| } |
| |
| return Status; |
| } |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringVPrintfWorkerA(OUT LPSTR Destination, |
| IN SIZE_T Length, |
| OUT PSIZE_T NewLength OPTIONAL, |
| IN LPCSTR Format, |
| IN va_list argList) |
| { |
| NTSTATUS Status = STATUS_SUCCESS; |
| LONG Return; |
| SIZE_T MaxLength, LocalNewLength = 0; |
| |
| MaxLength = Length - 1; |
| |
| Return = _vsnprintf(Destination, MaxLength, Format, argList); |
| if ((Return < 0) || ((SIZE_T)Return > MaxLength)) |
| { |
| Destination += MaxLength; |
| *Destination = ANSI_NULL; |
| |
| LocalNewLength = MaxLength; |
| |
| Status = STATUS_BUFFER_OVERFLOW; |
| } |
| else if ((SIZE_T)Return == MaxLength) |
| { |
| Destination += MaxLength; |
| *Destination = ANSI_NULL; |
| |
| LocalNewLength = MaxLength; |
| } |
| else |
| { |
| LocalNewLength = Return; |
| } |
| |
| if (NewLength) *NewLength = LocalNewLength; |
| return Status; |
| } |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringCopyWorkerA(OUT LPSTR Destination, |
| IN SIZE_T Length, |
| OUT PSIZE_T NewLength OPTIONAL, |
| IN LPCSTR Source, |
| IN SIZE_T CopyLength) |
| { |
| NTSTATUS Status = STATUS_SUCCESS; |
| SIZE_T LocalNewLength = 0; |
| |
| while ((Length) && (CopyLength) && (*Source != ANSI_NULL)) |
| { |
| *Destination++ = *Source++; |
| Length--; |
| CopyLength--; |
| |
| LocalNewLength++; |
| } |
| |
| if (!Length) |
| { |
| Destination--; |
| LocalNewLength--; |
| |
| Status = STATUS_BUFFER_OVERFLOW; |
| } |
| |
| *Destination = ANSI_NULL; |
| |
| if (NewLength) *NewLength = LocalNewLength; |
| return Status; |
| } |
| |
| /* PUBLIC FUNCTIONS **********************************************************/ |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringCchCopyA(IN LPSTR Destination, |
| IN SIZE_T cchDest, |
| IN LPCSTR pszSrc) |
| { |
| ASSERTMSG("RtlStringCchCopyA is UNIMPLEMENTED!\n", FALSE); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| static __inline |
| NTSTATUS |
| RtlStringCbPrintfA(OUT LPSTR Destination, |
| IN SIZE_T Length, |
| IN LPCSTR Format, |
| ...) |
| { |
| NTSTATUS Status; |
| SIZE_T CharLength = Length / sizeof(CHAR); |
| va_list argList; |
| |
| Status = RtlStringValidateDestA(Destination, |
| CharLength, |
| NULL, |
| NTSTRSAFE_MAX_CCH); |
| if (NT_SUCCESS(Status)) |
| { |
| va_start(argList, Format); |
| Status = RtlStringVPrintfWorkerA(Destination, |
| CharLength, |
| NULL, |
| Format, |
| argList); |
| va_end(argList); |
| } |
| |
| return Status; |
| } |
| |
| static __inline |
| NTSTATUS |
| RtlStringCbPrintfExA(OUT LPSTR Destination, |
| IN SIZE_T Length, |
| OUT LPSTR *DestinationEnd OPTIONAL, |
| OUT PSIZE_T RemainingSize OPTIONAL, |
| IN DWORD Flags, |
| IN LPCSTR Format, |
| ...) |
| { |
| NTSTATUS Status; |
| SIZE_T CharLength = Length / sizeof(CHAR), Remaining, LocalNewLength = 0; |
| PCHAR LocalDestinationEnd; |
| va_list argList; |
| ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0); |
| |
| Status = RtlStringExValidateDestA(&Destination, |
| &CharLength, |
| NULL, |
| NTSTRSAFE_MAX_CCH, |
| Flags); |
| if (NT_SUCCESS(Status)) |
| { |
| LocalDestinationEnd = Destination; |
| Remaining = CharLength; |
| |
| Status = RtlStringExValidateSrcA(&Format, |
| NULL, |
| NTSTRSAFE_MAX_CCH, |
| Flags); |
| if (NT_SUCCESS(Status)) |
| { |
| if (!Length) |
| { |
| if (*Format != ANSI_NULL) |
| { |
| if (!Destination) |
| { |
| Status = STATUS_INVALID_PARAMETER; |
| } |
| else |
| { |
| Status = STATUS_BUFFER_OVERFLOW; |
| } |
| } |
| } |
| else |
| { |
| va_start(argList, Format); |
| Status = RtlStringVPrintfWorkerA(Destination, |
| CharLength, |
| &LocalNewLength, |
| Format, |
| argList); |
| va_end(argList); |
| |
| LocalDestinationEnd = Destination + LocalNewLength; |
| Remaining = CharLength - LocalNewLength; |
| } |
| } |
| else |
| { |
| if (Length) *Destination = ANSI_NULL; |
| } |
| |
| if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW)) |
| { |
| if (DestinationEnd) *DestinationEnd = LocalDestinationEnd; |
| |
| if (RemainingSize) |
| { |
| *RemainingSize = (Remaining * sizeof(CHAR)) + |
| (Length % sizeof(CHAR)); |
| } |
| } |
| } |
| |
| return Status; |
| } |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringCbCopyExA(OUT LPSTR Destination, |
| IN SIZE_T Length, |
| IN LPCSTR Source, |
| OUT LPSTR *DestinationEnd OPTIONAL, |
| OUT PSIZE_T RemainingSize OPTIONAL, |
| IN DWORD Flags) |
| { |
| NTSTATUS Status; |
| SIZE_T CharLength = Length / sizeof(CHAR), Copied = 0, Remaining; |
| PCHAR LocalDestinationEnd; |
| ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0); |
| |
| Status = RtlStringExValidateDestA(&Destination, |
| &Length, |
| NULL, |
| NTSTRSAFE_MAX_CCH, |
| Flags); |
| if (NT_SUCCESS(Status)) |
| { |
| LocalDestinationEnd = Destination; |
| Remaining = CharLength; |
| |
| Status = RtlStringExValidateSrcA(&Source, |
| NULL, |
| NTSTRSAFE_MAX_CCH, |
| Flags); |
| if (NT_SUCCESS(Status)) |
| { |
| if (!CharLength) |
| { |
| if (*Source != ANSI_NULL) |
| { |
| if (!Destination) |
| { |
| Status = STATUS_INVALID_PARAMETER; |
| } |
| else |
| { |
| Status = STATUS_BUFFER_OVERFLOW; |
| } |
| } |
| } |
| else |
| { |
| Status = RtlStringCopyWorkerA(Destination, |
| CharLength, |
| &Copied, |
| Source, |
| NTSTRSAFE_MAX_LENGTH); |
| |
| LocalDestinationEnd = Destination + Copied; |
| Remaining = CharLength - Copied; |
| } |
| } |
| else |
| { |
| if (CharLength) *Destination = ANSI_NULL; |
| } |
| |
| if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW)) |
| { |
| if (DestinationEnd) *DestinationEnd = LocalDestinationEnd; |
| |
| if (RemainingSize) |
| { |
| *RemainingSize = (Remaining * sizeof(CHAR)) + |
| (Length % sizeof(CHAR)); |
| } |
| } |
| } |
| |
| return Status; |
| } |
| |
| static __inline |
| NTSTATUS |
| RtlStringCbPrintfW( |
| LPWSTR pszDest, |
| IN size_t cbDest, |
| IN LPCWSTR pszFormat, |
| ...) |
| { |
| ASSERTMSG("RtlStringCbPrintfW is UNIMPLEMENTED!\n", FALSE); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringCbCatExA(IN OUT LPSTR Destination, |
| IN SIZE_T Length, |
| IN LPCSTR Source, |
| OUT LPSTR *DestinationEnd OPTIONAL, |
| OUT PSIZE_T RemainingSize OPTIONAL, |
| IN DWORD Flags) |
| { |
| NTSTATUS Status; |
| SIZE_T CharLength = Length / sizeof(CHAR); |
| SIZE_T DestinationLength, Remaining, Copied = 0; |
| PCHAR LocalDestinationEnd; |
| ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0); |
| |
| Status = RtlStringExValidateDestA(&Destination, |
| &CharLength, |
| &DestinationLength, |
| NTSTRSAFE_MAX_CCH, |
| Flags); |
| if (NT_SUCCESS(Status)) |
| { |
| LocalDestinationEnd = Destination + DestinationLength; |
| Remaining = CharLength - DestinationLength; |
| |
| Status = RtlStringExValidateSrcA(&Source, |
| NULL, |
| NTSTRSAFE_MAX_CCH, |
| Flags); |
| if (NT_SUCCESS(Status)) |
| { |
| if (Remaining <= 1) |
| { |
| if (*Source != ANSI_NULL) |
| { |
| if (!Destination) |
| { |
| Status = STATUS_INVALID_PARAMETER; |
| } |
| else |
| { |
| Status = STATUS_BUFFER_OVERFLOW; |
| } |
| } |
| } |
| else |
| { |
| Status = RtlStringCopyWorkerA(LocalDestinationEnd, |
| Remaining, |
| &Copied, |
| Source, |
| NTSTRSAFE_MAX_LENGTH); |
| |
| LocalDestinationEnd = LocalDestinationEnd + Copied; |
| Remaining = Remaining - Copied; |
| } |
| } |
| |
| if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW)) |
| { |
| if (DestinationEnd) *DestinationEnd = LocalDestinationEnd; |
| |
| if (RemainingSize) |
| { |
| *RemainingSize = (Remaining * sizeof(CHAR)) + |
| (Length % sizeof(CHAR)); |
| } |
| } |
| } |
| |
| return Status; |
| } |
| |
| static __inline |
| NTSTATUS |
| NTAPI |
| RtlStringCbCopyA(OUT LPSTR Destination, |
| IN SIZE_T Length, |
| IN LPCSTR Source) |
| { |
| NTSTATUS Status; |
| SIZE_T CharLength = Length / sizeof(CHAR); |
| |
| Status = RtlStringValidateDestA(Destination, |
| CharLength, |
| NULL, |
| NTSTRSAFE_MAX_CCH); |
| if (NT_SUCCESS(Status)) |
| { |
| Status = RtlStringCopyWorkerA(Destination, |
| CharLength, |
| NULL, |
| Source, |
| NTSTRSAFE_MAX_LENGTH); |
| } |
| |
| return Status; |
| } |
| |
| #endif /* _NTSTRSAFE_H_INCLUDED_ */ |
| |