/*
* 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 ULONG 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_ */