1835 lines
53 KiB
C
1835 lines
53 KiB
C
/**
|
|
* PROJECT: ExectOS
|
|
* COPYRIGHT: See COPYING.md in the top level directory
|
|
* FILE: xtoskrnl/rtl/widestr.c
|
|
* DESCRIPTION: Wide string support
|
|
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
|
*/
|
|
|
|
#include <xtos.h>
|
|
|
|
|
|
/**
|
|
* Compares at most specified number of characters of two C wide strings.
|
|
*
|
|
* @param String1
|
|
* Wide string to be compared.
|
|
*
|
|
* @param String2
|
|
* Wide string to be compared.
|
|
*
|
|
* @param Length
|
|
* Maximum number of characters to compare. If no limit set, it compares whole wide strings.
|
|
*
|
|
* @return Integral value indicating the relationship between the wide strings.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
SIZE_T
|
|
RtlCompareWideString(IN CONST PWCHAR String1,
|
|
IN CONST PWCHAR String2,
|
|
IN SIZE_T Length)
|
|
{
|
|
SIZE_T Index;
|
|
|
|
/* Iterate through the strings */
|
|
for(Index = 0; ; Index++) {
|
|
/* Check if length limit reached */
|
|
if(Index != 0 && Index == Length)
|
|
{
|
|
/* Skip checking next characters */
|
|
break;
|
|
}
|
|
|
|
/* Check if wide string characters are equal */
|
|
if(String1[Index] != String2[Index])
|
|
{
|
|
/* Different characters found */
|
|
return String1[Index] < String2[Index] ? -1 : 1;
|
|
}
|
|
|
|
/* Check if end of wide string reached */
|
|
if(!String1[Index] || !String2[Index])
|
|
{
|
|
/* Equal wide strings until the end of one of them */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Wide strings are equal */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Compares at most specified number of characters of two C wide strings, while ignoring differences in case.
|
|
*
|
|
* @param String1
|
|
* Wide string to be compared.
|
|
*
|
|
* @param String2
|
|
* Wide string to be compared.
|
|
*
|
|
* @param Length
|
|
* Maximum number of characters to compare. If no limit set, it compares whole wide strings.
|
|
*
|
|
* @return Integral value indicating the relationship between the wide strings.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
SIZE_T
|
|
RtlCompareWideStringInsensitive(IN CONST PWCHAR String1,
|
|
IN CONST PWCHAR String2,
|
|
IN SIZE_T Length)
|
|
{
|
|
WCHAR Character1;
|
|
WCHAR Character2;
|
|
ULONG Index = 0;
|
|
|
|
/* Iterate through the wide strings */
|
|
while(String1[Index] != L'\0' && String2[Index] != L'\0')
|
|
{
|
|
/* Check if length limit reached */
|
|
if(Index != 0 && Index == Length)
|
|
{
|
|
/* Skip checking next characters */
|
|
break;
|
|
}
|
|
|
|
/* Get the characters */
|
|
Character1 = String1[Index];
|
|
Character2 = String2[Index];
|
|
|
|
/* Lowercase wide string1 character if needed */
|
|
if(String1[Index] >= L'A' && String1[Index] <= L'Z')
|
|
{
|
|
Character1 = String1[Index] - L'A' + L'a';
|
|
}
|
|
|
|
/* Lowercase wide string2 character if needed */
|
|
if(String2[Index] >= L'A' && String2[Index] <= L'Z')
|
|
{
|
|
Character2 = String2[Index] - L'A' + L'a';
|
|
}
|
|
|
|
/* Compare the characters */
|
|
if(Character1 != Character2)
|
|
{
|
|
/* Wide strings are not equal */
|
|
return Character1 > Character2 ? 1 : -1;
|
|
}
|
|
|
|
/* Get next character */
|
|
Index++;
|
|
}
|
|
|
|
/* Wide strings are equal */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Appends a copy of the source wide string to the end of the destination wide string.
|
|
*
|
|
* @param Destination
|
|
* Supplies a pointer to the null-terminated wide string to append to.
|
|
*
|
|
* @param Source
|
|
* Supplies a pointer to the null-terminated wide string to copy from.
|
|
*
|
|
* @param Count
|
|
* Sets a maximum number of wide characters to copy. If no limit set, appends whole wide string.
|
|
*
|
|
* @return This routine returns a copy of a destination wide string.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
PWCHAR
|
|
RtlConcatenateWideString(OUT PWCHAR Destination,
|
|
IN PWCHAR Source,
|
|
IN SIZE_T Count)
|
|
{
|
|
PWCHAR DestString = Destination;
|
|
|
|
/* Go to the end of destination wide string */
|
|
while(*Destination)
|
|
{
|
|
Destination++;
|
|
}
|
|
|
|
/* Check if copy limit set */
|
|
if(Count > 0)
|
|
{
|
|
/* Copy character-by-character */
|
|
do
|
|
{
|
|
/* Check if NULL terminated character found */
|
|
if((*Destination = *Source++) == L'\0')
|
|
{
|
|
/* Break on '\0' character */
|
|
break;
|
|
}
|
|
Destination++;
|
|
}
|
|
while(--Count != 0);
|
|
|
|
/* Add NULL termination character to the end of destination wide string */
|
|
*Destination = L'\0';
|
|
}
|
|
else
|
|
{
|
|
/* No limit set, copy all wide characters */
|
|
while((*Destination++ = *Source++) != 0);
|
|
}
|
|
|
|
/* Return copy of the destination wide string */
|
|
return DestString;
|
|
}
|
|
|
|
/**
|
|
* Formats a wide string according to the given printf-alike format string.
|
|
*
|
|
* @param Context
|
|
* Supplies a pointer to the print context structure.
|
|
*
|
|
* @param Format
|
|
* Supplies a pointer to the printf-alike format string.
|
|
*
|
|
* @param ArgumentList
|
|
* Supplies a list of arguments to the format string.
|
|
*
|
|
* @return This routine returns a status code.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
RtlFormatWideString(IN PRTL_PRINT_CONTEXT Context,
|
|
IN PCWSTR Format,
|
|
IN VA_LIST ArgumentList)
|
|
{
|
|
VA_LIST LocalArgumentList;
|
|
XTSTATUS Status;
|
|
ULONG Index;
|
|
|
|
/* Make sure, that we have valid context and write routine */
|
|
if(Context == NULL || Context->WriteWideCharacter == NULL)
|
|
{
|
|
/* Invalid context or write routine not set */
|
|
return FALSE;
|
|
}
|
|
|
|
/* Check format string pointer */
|
|
if(Format == NULL)
|
|
{
|
|
/* Write null string */
|
|
Format = L"(null)";
|
|
}
|
|
|
|
/* Make a copy of the argument list */
|
|
VA_COPY(LocalArgumentList, ArgumentList);
|
|
|
|
/* Iterate through format string */
|
|
Index = 0;
|
|
while(Format[Index] != L'\0')
|
|
{
|
|
/* Look for format specifier */
|
|
if(Format[Index] == L'%')
|
|
{
|
|
/* Handle format along with arguments */
|
|
Status = RtlpFormatWideStringArgumentSpecifier(Context, Format, &LocalArgumentList, &Index);
|
|
}
|
|
else
|
|
{
|
|
/* Write wide character and increase string index */
|
|
Status = RtlpWriteWideCharacter(Context, Format[Index]);
|
|
Index++;
|
|
}
|
|
|
|
/* Make sure character written successfully */
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Return status code */
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* Clean up the argument list */
|
|
VA_END(LocalArgumentList);
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Reverses a characters order in a wide string. It modifies the original, input variable.
|
|
*
|
|
* @param String
|
|
* Supplies a pointer to the wide string to reverse.
|
|
*
|
|
* @param Length
|
|
* Supplies the length of the wide string to reverse.
|
|
*
|
|
* @return This routine does not return any value.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
VOID
|
|
RtlReverseWideString(IN OUT PWCHAR String,
|
|
IN ULONG Length)
|
|
{
|
|
WCHAR TempChar;
|
|
ULONG Index;
|
|
|
|
/* Iterate through the string */
|
|
for(Index = 0; Index < (Length / 2); Index++)
|
|
{
|
|
/* Swap characters */
|
|
TempChar = String[Index];
|
|
String[Index] = String[Length - Index - 1];
|
|
String[Length - Index - 1] = TempChar;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finds the next token in a null-terminated wide string.
|
|
*
|
|
* @param String
|
|
* Pointer to the null-terminated wide string to tokenize.
|
|
*
|
|
* @param Delimiter
|
|
* Pointer to the null-terminated wide string identifying delimiters.
|
|
*
|
|
* @param SavePtr
|
|
* Pointer to an object used to store routine internal state.
|
|
*
|
|
* @return Pointer to the beginning of the next token or NULL if there are no more tokens.
|
|
*
|
|
* @since: XT 1.0
|
|
*/
|
|
XTAPI
|
|
PWCHAR
|
|
RtlTokenizeWideString(IN PWCHAR String,
|
|
IN CONST PWCHAR Delimiter,
|
|
IN OUT PWCHAR *SavePtr)
|
|
{
|
|
PWCHAR Span, Token;
|
|
WCHAR Char, SpanChar;
|
|
|
|
/* Check if there is anything to tokenize */
|
|
if(String == NULL && (String = *SavePtr) == NULL)
|
|
{
|
|
/* Empty string given */
|
|
return NULL;
|
|
}
|
|
|
|
/* Check non-delimiter characters */
|
|
Char = *String++;
|
|
if(Char == L'\0')
|
|
{
|
|
*SavePtr = NULL;
|
|
return NULL;
|
|
}
|
|
Token = String - 1;
|
|
|
|
/* Scan token for delimiters */
|
|
for(;;)
|
|
{
|
|
Char = *String++;
|
|
Span = (PWCHAR)Delimiter;
|
|
do
|
|
{
|
|
if((SpanChar = *Span++) == Char)
|
|
{
|
|
if(Char == L'\0')
|
|
{
|
|
String = NULL;
|
|
}
|
|
else
|
|
{
|
|
String[-1] = L'\0';
|
|
}
|
|
|
|
/* Store pointer to the next token */
|
|
*SavePtr = String;
|
|
|
|
/* Return token */
|
|
return Token;
|
|
}
|
|
}
|
|
while(SpanChar != L'\0');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes certain characters from a beginning of the wide string.
|
|
*
|
|
* @param String
|
|
* Pointer to the null-terminated wide string to be trimmed.
|
|
*
|
|
* @return This routine returns a pointer to the left-trimmed wide string.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
PWCHAR
|
|
RtlTrimLeftWideString(IN CONST PWCHAR String)
|
|
{
|
|
PWCHAR Start;
|
|
|
|
/* Initialize pointer */
|
|
Start = String;
|
|
|
|
/* Skip all leading whitespaces */
|
|
while(*Start == L' ' || *Start == L'\n' || *Start == L'\t' || *Start == L'\r' || *Start == L'\v' || *Start == L'\f')
|
|
{
|
|
/* Advance to the next character */
|
|
Start++;
|
|
}
|
|
|
|
/* Return left-trimmed string */
|
|
return Start;
|
|
}
|
|
|
|
/**
|
|
* Removes certain characters from the end of the wide string.
|
|
*
|
|
* @param String
|
|
* Pointer to the null-terminated wide string to be trimmed.
|
|
*
|
|
* @return This routine returns a pointer to the right-trimmed wide string.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
PWCHAR
|
|
RtlTrimRightWideString(IN CONST PWCHAR String)
|
|
{
|
|
PWCHAR End;
|
|
|
|
/* Find end of the string */
|
|
End = String + RtlWideStringLength(String, 0);
|
|
|
|
/* Skip all trailing whitespaces */
|
|
while((End != String) && (*End == L' ' || *End == L'\n' || *End == L'\t' || *End == L'\r' || *End == L'\v' || *End == L'\f'))
|
|
{
|
|
/* Move to the previous character */
|
|
End--;
|
|
}
|
|
|
|
/* Terminate the string */
|
|
*End = 0;
|
|
|
|
/* Return right-trimmed string */
|
|
return String;
|
|
}
|
|
|
|
/**
|
|
* Removes certain characters from the beginning and the end of the wide string.
|
|
*
|
|
* @param String
|
|
* Pointer to the null-terminated wide string to be trimmed.
|
|
*
|
|
* @return This routine returns a pointer to the trimmed wide string.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
PWCHAR
|
|
RtlTrimWideString(IN CONST PWCHAR String)
|
|
{
|
|
return RtlTrimLeftWideString(RtlTrimRightWideString(String));
|
|
}
|
|
|
|
/**
|
|
* Calculates the length of a given wide string.
|
|
*
|
|
* @param String
|
|
* Pointer to the null-terminated wide string to be examined.
|
|
*
|
|
* @param MaxLength
|
|
* Maximum number of wide characters to examine. If no limit set, it examines whole string.
|
|
*
|
|
* @return The length of the null-terminated wide string.
|
|
*
|
|
* @since: XT 1.0
|
|
*/
|
|
XTAPI
|
|
SIZE_T
|
|
RtlWideStringLength(IN CONST PWCHAR String,
|
|
IN SIZE_T MaxLength)
|
|
{
|
|
SIZE_T Length;
|
|
|
|
/* Check if NULL pointer passed */
|
|
if(String == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Iterate through the wide string */
|
|
for(Length = 0; ; Length++)
|
|
{
|
|
|
|
/* Check if NULL found or max length limit reached */
|
|
if((Length != 0 && Length == MaxLength) || !String[Length])
|
|
{
|
|
/* Finish examination */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Return wide string length */
|
|
return Length;
|
|
}
|
|
|
|
/**
|
|
* Formats a wide string according to the given printf-alike format string and a list of arguments.
|
|
*
|
|
* @param Context
|
|
* Supplies a pointer to the print context structure.
|
|
*
|
|
* @param Format
|
|
* Supplies a pointer to the printf-alike format string.
|
|
*
|
|
* @param ArgumentList
|
|
* Supplies a list of arguments to the format string.
|
|
*
|
|
* @param Index
|
|
* Supplies a pointer to the position of the current format specifier, that will be advanced beyond the specifier.
|
|
*
|
|
* @return This routine returns a status code.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
RtlpFormatWideStringArgumentSpecifier(IN PRTL_PRINT_CONTEXT Context,
|
|
IN PCWSTR Format,
|
|
IN PVA_LIST ArgumentList,
|
|
IN OUT PULONG Index)
|
|
{
|
|
RTL_PRINT_FORMAT_PROPERTIES FormatProperties;
|
|
PUNICODE_STRING UnicodeStrArg;
|
|
WCHAR Specifier, WideCharArg;
|
|
PANSI_STRING AnsiStrArg;
|
|
LONGLONG SpecifierValue;
|
|
VA_LIST ArgumentsCopy;
|
|
LARGE_DOUBLE FloatArg;
|
|
PCWSTR FormatIndex;
|
|
ULONG ArgPosition;
|
|
PWCHAR WideStrArg;
|
|
ULONGLONG IntArg;
|
|
XTSTATUS Status;
|
|
PGUID GuidArg;
|
|
PCHAR StrArg;
|
|
CHAR CharArg;
|
|
|
|
/* Set current format specifier index and custom argument position */
|
|
FormatIndex = Format + *Index + 1;
|
|
ArgPosition = 0;
|
|
|
|
/* Initialize format properties */
|
|
RtlZeroMemory(&FormatProperties, sizeof(RTL_PRINT_FORMAT_PROPERTIES));
|
|
FormatProperties.IntegerSize = sizeof(INT);
|
|
FormatProperties.Precision = -1;
|
|
|
|
|
|
/* Make a copy of the argument list */
|
|
VA_COPY(ArgumentsCopy, *ArgumentList);
|
|
|
|
/* Lookup parameter field */
|
|
if((*FormatIndex >= L'1') && (*FormatIndex <= L'9'))
|
|
{
|
|
/* POSIX extension found, read its value */
|
|
SpecifierValue = RtlpGetWideStringSpecifierValue((PWSTR*)&FormatIndex);
|
|
|
|
/* Make sure parameter field ends with '$' character */
|
|
if(*FormatIndex == L'$')
|
|
{
|
|
/* Store number of parameter and increment index */
|
|
ArgPosition = (ULONG)SpecifierValue;
|
|
FormatIndex++;
|
|
}
|
|
else
|
|
{
|
|
/* Field not ended with '$' character, treat it as width field */
|
|
FormatProperties.FieldWidth = (ULONG)SpecifierValue;
|
|
}
|
|
}
|
|
|
|
/* Lookup flags field */
|
|
while(TRUE)
|
|
{
|
|
/* Look for a valid flag and set properties */
|
|
if(*FormatIndex == L'\'')
|
|
{
|
|
/* Thousands grouping separator applied */
|
|
FormatProperties.ThousandsGrouping = TRUE;
|
|
}
|
|
else if(*FormatIndex == L'-')
|
|
{
|
|
/* Left-align the output */
|
|
FormatProperties.LeftJustified = TRUE;
|
|
}
|
|
else if(*FormatIndex == L' ')
|
|
{
|
|
/* Prepend a space for positive signed-numeric types */
|
|
FormatProperties.SpaceForPlus = TRUE;
|
|
}
|
|
else if(*FormatIndex == L'+')
|
|
{
|
|
/* Prepend a plus for positive signed-numeric types */
|
|
FormatProperties.AlwaysPrintSign = TRUE;
|
|
}
|
|
else if(*FormatIndex == L'#')
|
|
{
|
|
/* Convert to an alternate form */
|
|
FormatProperties.PrintRadix = TRUE;
|
|
}
|
|
else if(*FormatIndex == L'0')
|
|
{
|
|
/* Prepend zeros for numeric types */
|
|
FormatProperties.PrintLeadingZeroes = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* No more flags to read */
|
|
break;
|
|
}
|
|
|
|
/* Move to the next character */
|
|
FormatIndex++;
|
|
}
|
|
|
|
/* Check if output is left-justified */
|
|
if(FormatProperties.LeftJustified)
|
|
{
|
|
/* Left justified output can't have leading zeros */
|
|
FormatProperties.PrintLeadingZeroes = FALSE;
|
|
}
|
|
|
|
/* Check if plus for positive signed-numeric types is enabled */
|
|
if(FormatProperties.AlwaysPrintSign)
|
|
{
|
|
/* Do not append a space when plus character is enabled */
|
|
FormatProperties.SpaceForPlus = FALSE;
|
|
}
|
|
|
|
/* Lookup width field */
|
|
if(*FormatIndex == L'*')
|
|
{
|
|
/* Skip dynamic width field indicator */
|
|
FormatIndex++;
|
|
|
|
/* Read dynamic width value from the argument list */
|
|
FormatProperties.FieldWidth = VA_ARG(*ArgumentList, INT);
|
|
}
|
|
else if((*FormatIndex >= L'1') && (*FormatIndex <= L'9'))
|
|
{
|
|
/* Read a numeric width value */
|
|
FormatProperties.FieldWidth = RtlpGetWideStringSpecifierValue((PWSTR*)&FormatIndex);
|
|
}
|
|
|
|
/* Check if field width is set to negative value */
|
|
if(FormatProperties.FieldWidth < 0)
|
|
{
|
|
/* Force left-aligned output and turn field width into positive value */
|
|
FormatProperties.LeftJustified = TRUE;
|
|
FormatProperties.FieldWidth *= -1;
|
|
}
|
|
|
|
/* Lookup precision field */
|
|
if(*FormatIndex == L'.')
|
|
{
|
|
/* Skip precision field indicator */
|
|
FormatIndex++;
|
|
|
|
/* Look for a dynamic precision value indicator */
|
|
if(*FormatIndex == L'*')
|
|
{
|
|
/* Read dynamic precision value from the argument list */
|
|
FormatIndex++;
|
|
FormatProperties.Precision = VA_ARG(*ArgumentList, INT);
|
|
}
|
|
else if((*FormatIndex >= L'0') && (*FormatIndex <= L'9'))
|
|
{
|
|
/* Read a numeric precision value */
|
|
FormatProperties.Precision = RtlpGetWideStringSpecifierValue((PWSTR*)&FormatIndex);
|
|
}
|
|
else
|
|
{
|
|
/* Set default precision */
|
|
FormatProperties.Precision = 0;
|
|
}
|
|
}
|
|
|
|
/* Check if precision is set to negative value */
|
|
if(FormatProperties.Precision < 0)
|
|
{
|
|
/* Disable precision */
|
|
FormatProperties.Precision = -1;
|
|
}
|
|
|
|
/* Lookup argument length modifier */
|
|
Specifier = *FormatIndex;
|
|
switch(Specifier)
|
|
{
|
|
case L'h':
|
|
/* SHORT-sized integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.IntegerSize = sizeof(SHORT);
|
|
if(*FormatIndex == L'h')
|
|
{
|
|
/* CHAR-sized integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.IntegerSize = sizeof(CHAR);
|
|
}
|
|
break;
|
|
case L'j':
|
|
/* INTMAX-sized integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.IntegerSize = sizeof(LONG_PTR);
|
|
break;
|
|
case L'l':
|
|
/* LONG-sized double/integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.LongDouble = TRUE;
|
|
FormatProperties.LongInteger = TRUE;
|
|
FormatProperties.IntegerSize = sizeof(LONG);
|
|
if(*FormatIndex == L'l')
|
|
{
|
|
/* LONGLONG-sized integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.LongDouble = FALSE;
|
|
FormatProperties.LongInteger = FALSE;
|
|
FormatProperties.IntegerSize = sizeof(LONGLONG);
|
|
}
|
|
break;
|
|
case L'q':
|
|
/* BSD extension: 64-bit (quad word) integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.IntegerSize = sizeof(LONGLONG);
|
|
break;
|
|
case L't':
|
|
/* PTRDIFF-sized integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.IntegerSize = sizeof(PVOID);
|
|
break;
|
|
case L'w':
|
|
/* MSVC extension: wide character or wide string argument */
|
|
FormatIndex++;
|
|
FormatProperties.LongInteger = TRUE;
|
|
break;
|
|
case L'z':
|
|
/* SIZE_T-sized integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.IntegerSize = sizeof(SIZE_T);
|
|
break;
|
|
case L'I':
|
|
/* MSVC extension: SIZE_T-sized integer argument */
|
|
FormatIndex++;
|
|
FormatProperties.IntegerSize = sizeof(SIZE_T);
|
|
if((*FormatIndex == L'3') && (*(FormatIndex + 1) == L'2'))
|
|
{
|
|
/* MSVC extension: 32-bit (double word) integer argument */
|
|
FormatIndex += 2;
|
|
FormatProperties.LongInteger = TRUE;
|
|
FormatProperties.IntegerSize = sizeof(LONG);
|
|
}
|
|
else if((*FormatIndex == L'6') && (*(FormatIndex + 1) == L'4'))
|
|
{
|
|
/* MSVC extension: 64-bit (quad word) integer argument */
|
|
FormatIndex += 2;
|
|
FormatProperties.IntegerSize = sizeof(LONGLONG);
|
|
}
|
|
break;
|
|
case L'L':
|
|
/* LONG-sized double argument */
|
|
FormatIndex++;
|
|
FormatProperties.LongDouble = TRUE;
|
|
FormatProperties.IntegerSize = sizeof(LDOUBLE);
|
|
break;
|
|
}
|
|
|
|
/* Lookup format specifier */
|
|
Specifier = *FormatIndex++;
|
|
|
|
/* Handle char and string modifiers */
|
|
if(FormatProperties.LongInteger)
|
|
{
|
|
if(Specifier == L'c')
|
|
{
|
|
/* Wide character argument */
|
|
Specifier = L'C';
|
|
}
|
|
else if(Specifier == L's')
|
|
{
|
|
/* Wide string argument */
|
|
Specifier = L'S';
|
|
}
|
|
}
|
|
|
|
/* Lookup format specifier */
|
|
FormatProperties.UnsignedValue = TRUE;
|
|
switch(Specifier)
|
|
{
|
|
case L'a':
|
|
/* Double argument as hexadecimal number (lowercase) */
|
|
FormatProperties.VariableType = Float;
|
|
FormatProperties.ScientificFormat = TRUE;
|
|
FormatProperties.Radix = 16;
|
|
break;
|
|
case L'A':
|
|
/* Double argument as hexadecimal number (uppercase) */
|
|
FormatProperties.VariableType = Float;
|
|
FormatProperties.ScientificFormat = TRUE;
|
|
FormatProperties.PrintUpperCase = TRUE;
|
|
FormatProperties.Radix = 16;
|
|
break;
|
|
case L'b':
|
|
/* XTOS extension: Boolean argument (lowercase) */
|
|
FormatProperties.VariableType = Boolean;
|
|
break;
|
|
case L'B':
|
|
/* XTOS extension: Boolean argument (uppercase) */
|
|
FormatProperties.VariableType = Boolean;
|
|
FormatProperties.PrintUpperCase = TRUE;
|
|
break;
|
|
case L'c':
|
|
/* Character argument */
|
|
FormatProperties.VariableType = Char;
|
|
break;
|
|
case L'C':
|
|
/* Wide character argument */
|
|
FormatProperties.VariableType = WideChar;
|
|
break;
|
|
case L'd':
|
|
case L'i':
|
|
/* Signed integer argument as decimal number */
|
|
FormatProperties.VariableType = Integer;
|
|
FormatProperties.Radix = 10;
|
|
FormatProperties.UnsignedValue = FALSE;
|
|
break;
|
|
case L'e':
|
|
/* Double argument in scientific notation (lowercase) */
|
|
FormatProperties.VariableType = Float;
|
|
FormatProperties.ScientificFormat = TRUE;
|
|
break;
|
|
case L'E':
|
|
/* Double argument in scientific notation (uppercase) */
|
|
FormatProperties.VariableType = Float;
|
|
FormatProperties.ScientificFormat = TRUE;
|
|
FormatProperties.PrintUpperCase = TRUE;
|
|
break;
|
|
case L'f':
|
|
/* Double argument as floating point number (lowercase) */
|
|
FormatProperties.VariableType = Float;
|
|
FormatProperties.FloatFormat = TRUE;
|
|
break;
|
|
case L'F':
|
|
/* Double argument as floating point number (uppercase) */
|
|
FormatProperties.VariableType = Float;
|
|
FormatProperties.FloatFormat = TRUE;
|
|
FormatProperties.PrintUpperCase = TRUE;
|
|
break;
|
|
case L'g':
|
|
/* Double argument as either floating point number or in scientific notation (lowercase) */
|
|
FormatProperties.VariableType = Float;
|
|
FormatProperties.SignificantDigitPrecision = TRUE;
|
|
break;
|
|
case L'G':
|
|
/* Double argument as either floating point number or in scientific notation (uppercase) */
|
|
FormatProperties.VariableType = Float;
|
|
FormatProperties.PrintUpperCase = TRUE;
|
|
FormatProperties.SignificantDigitPrecision = TRUE;
|
|
break;
|
|
case L'n':
|
|
/* Write number of characters written so far into an integer pointer parameter */
|
|
FormatProperties.VariableType = Integer;
|
|
FormatProperties.IntegerSize = sizeof(PVOID);
|
|
break;
|
|
case L'o':
|
|
/* Unsigned integer argument as octal number */
|
|
FormatProperties.VariableType = Integer;
|
|
FormatProperties.Radix = 8;
|
|
break;
|
|
case L'p':
|
|
/* Pointer argument as hexadecimal number (uppercase) */
|
|
FormatProperties.VariableType = Integer;
|
|
FormatProperties.IntegerSize = sizeof(UINT_PTR);
|
|
FormatProperties.Radix = 16;
|
|
FormatProperties.PrintUpperCase = TRUE;
|
|
FormatProperties.PrintRadix = TRUE;
|
|
break;
|
|
case L's':
|
|
/* String argument */
|
|
FormatProperties.VariableType = String;
|
|
break;
|
|
case L'S':
|
|
/* Wide string argument */
|
|
FormatProperties.VariableType = WideString;
|
|
break;
|
|
case L'u':
|
|
/* Unsigned integer argument as decimal number */
|
|
FormatProperties.VariableType = Integer;
|
|
FormatProperties.Radix = 10;
|
|
break;
|
|
case L'U':
|
|
/* XTOS extension: UUID/GUID argument */
|
|
FormatProperties.VariableType = Guid;
|
|
break;
|
|
case L'x':
|
|
/* Unsigned integer argument as hexadecimal number (lowercase) */
|
|
FormatProperties.VariableType = Integer;
|
|
FormatProperties.Radix = 16;
|
|
break;
|
|
case L'X':
|
|
/* Unsigned integer argument as hexadecimal number (uppercase) */
|
|
FormatProperties.VariableType = Integer;
|
|
FormatProperties.Radix = 16;
|
|
FormatProperties.PrintUpperCase = TRUE;
|
|
break;
|
|
case L'Z':
|
|
/* MSVC extension: ANSI/Unicode string argument */
|
|
FormatProperties.VariableType = FormatProperties.LongInteger ? UnicodeString : AnsiString;
|
|
break;
|
|
case L'%':
|
|
/* Print '%' character */
|
|
FormatProperties.VariableType = Unknown;
|
|
WideCharArg = L'%';
|
|
break;
|
|
default:
|
|
/* Unknown format specifier, print '?' character */
|
|
FormatProperties.VariableType = Unknown;
|
|
WideCharArg = L'?';
|
|
break;
|
|
}
|
|
|
|
/* Finally, write the formatted argument */
|
|
if(FormatProperties.VariableType == Unknown)
|
|
{
|
|
/* Write defined wide character */
|
|
Status = RtlpWriteWideStringValue(Context, &FormatProperties, &WideCharArg, 1);
|
|
}
|
|
if(FormatProperties.VariableType == Boolean)
|
|
{
|
|
/* Boolean type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
IntArg = RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, FormatProperties.IntegerSize);
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument */
|
|
IntArg = VA_ARG(*ArgumentList, ULONGLONG);
|
|
}
|
|
|
|
/* Check if using uppercase format */
|
|
if(FormatProperties.PrintUpperCase)
|
|
{
|
|
/* Set uppercase boolean string depending on argument value */
|
|
WideStrArg = IntArg ? L"TRUE" : L"FALSE";
|
|
}
|
|
else
|
|
{
|
|
/* Set lowercase boolean string depending on argument value */
|
|
WideStrArg = IntArg ? L"true" : L"false";
|
|
}
|
|
|
|
/* Write formatted boolean string */
|
|
Status = RtlpWriteWideStringValue(Context, &FormatProperties, WideStrArg, RtlWideStringLength(WideStrArg, 0));
|
|
}
|
|
else if(FormatProperties.VariableType == Guid)
|
|
{
|
|
/* GUID type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
IntArg = RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, sizeof(PGUID));
|
|
GuidArg = (PGUID)(UINT_PTR)IntArg;
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument */
|
|
GuidArg = VA_ARG(*ArgumentList, PGUID);
|
|
}
|
|
|
|
/* Make sure GUID is not NULL */
|
|
if(GuidArg != NULL)
|
|
{
|
|
/* Write formatted GUID string */
|
|
Status = RtlpWriteWideStringCustomValue(Context, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
GuidArg->Data1, GuidArg->Data2, GuidArg->Data3,
|
|
GuidArg->Data4[0], GuidArg->Data4[1], GuidArg->Data4[2],
|
|
GuidArg->Data4[3], GuidArg->Data4[4], GuidArg->Data4[5],
|
|
GuidArg->Data4[6], GuidArg->Data4[7]);
|
|
}
|
|
}
|
|
else if(FormatProperties.VariableType == Char)
|
|
{
|
|
/* Character type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
CharArg = (UCHAR)RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, sizeof(UCHAR));
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument */
|
|
CharArg = VA_ARG(*ArgumentList, INT);
|
|
}
|
|
|
|
/* Write formatted character */
|
|
Status = RtlpWriteWideStringStringValue(Context, &FormatProperties, &CharArg, 1);
|
|
}
|
|
else if(FormatProperties.VariableType == WideChar)
|
|
{
|
|
/* Wide character type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
WideCharArg = (WCHAR)RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument */
|
|
WideCharArg = VA_ARG(*ArgumentList, INT);
|
|
}
|
|
|
|
/* Write formatted wide character */
|
|
Status = RtlpWriteWideStringValue(Context, &FormatProperties, &WideCharArg, 1);
|
|
}
|
|
else if(FormatProperties.VariableType == Float)
|
|
{
|
|
/* Float/Double type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
FloatArg.QuadPart = RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, sizeof(ULONGLONG));
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument, depending on its size */
|
|
if(FormatProperties.LongDouble)
|
|
{
|
|
FloatArg.DoublePart = VA_ARG(*ArgumentList, LDOUBLE);
|
|
}
|
|
else
|
|
{
|
|
FloatArg.DoublePart = VA_ARG(*ArgumentList, DOUBLE);
|
|
}
|
|
}
|
|
|
|
/* Write formatted double value */
|
|
// Status = RtlpWriteWideStringDoubleValue(Context, &FormatProperties, FloatArg.DoublePart);
|
|
}
|
|
else if(FormatProperties.VariableType == Integer)
|
|
{
|
|
/* Integer type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
IntArg = RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, FormatProperties.IntegerSize);
|
|
|
|
/* Convert to required integer size */
|
|
switch(FormatProperties.IntegerSize)
|
|
{
|
|
case sizeof(CHAR):
|
|
IntArg = (UCHAR)IntArg;
|
|
break;
|
|
case sizeof(SHORT):
|
|
IntArg = (USHORT)IntArg;
|
|
break;
|
|
case sizeof(LONG):
|
|
IntArg = (ULONG)IntArg;
|
|
break;
|
|
case sizeof(LONGLONG):
|
|
IntArg = (ULONGLONG)IntArg;
|
|
break;
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument, depending on its size */
|
|
switch(FormatProperties.IntegerSize)
|
|
{
|
|
case sizeof(CHAR):
|
|
IntArg = (CHAR)VA_ARG(*ArgumentList, UINT);
|
|
break;
|
|
case sizeof(SHORT):
|
|
IntArg = (SHORT)VA_ARG(*ArgumentList, UINT);
|
|
break;
|
|
case sizeof(LONG):
|
|
IntArg = VA_ARG(*ArgumentList, ULONG);
|
|
break;
|
|
case sizeof(LONGLONG):
|
|
IntArg = VA_ARG(*ArgumentList, ULONGLONG);
|
|
break;
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
/* Check if using 'n' specifier */
|
|
if(Specifier == L'n')
|
|
{
|
|
/* Make sure, that integer pointer parameter is not NULL */
|
|
if(IntArg != (UINT_PTR)NULL)
|
|
{
|
|
/* Store number of characters written in integer pointer parameter */
|
|
*((PINT)(UINT_PTR)IntArg) = Context->CharactersWritten;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Write formatted integer value */
|
|
Status = RtlpWriteWideStringIntegerValue(Context, &FormatProperties, IntArg);
|
|
}
|
|
}
|
|
else if(FormatProperties.VariableType == String)
|
|
{
|
|
/* String type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
IntArg = RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, sizeof(PCHAR));
|
|
StrArg = (PCHAR)(UINT_PTR)IntArg;
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument */
|
|
StrArg = VA_ARG(*ArgumentList, PCHAR);
|
|
}
|
|
|
|
/* Write formatted string value */
|
|
Status = RtlpWriteWideStringStringValue(Context, &FormatProperties, StrArg, RtlStringLength(StrArg, 0));
|
|
}
|
|
else if(FormatProperties.VariableType == WideString)
|
|
{
|
|
/* Wide string type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
IntArg = RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, sizeof(PWCHAR));
|
|
WideStrArg = (PWCHAR)(UINT_PTR)IntArg;
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument */
|
|
WideStrArg = VA_ARG(*ArgumentList, PWCHAR);
|
|
}
|
|
|
|
/* Write formatted wide string value */
|
|
Status = RtlpWriteWideStringValue(Context, &FormatProperties, WideStrArg, RtlWideStringLength(WideStrArg, 0));
|
|
}
|
|
else if(FormatProperties.VariableType == AnsiString )
|
|
{
|
|
/* ANSI string type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
IntArg = RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, sizeof(PANSI_STRING));
|
|
AnsiStrArg = (PANSI_STRING)(UINT_PTR)IntArg;
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument */
|
|
AnsiStrArg = VA_ARG(*ArgumentList, PANSI_STRING);
|
|
}
|
|
|
|
/* Write formatted ANSI string value */
|
|
Status = RtlpWriteWideStringStringValue(Context, &FormatProperties, AnsiStrArg->Buffer, AnsiStrArg->Length);
|
|
}
|
|
else if(FormatProperties.VariableType == UnicodeString)
|
|
{
|
|
/* Unicode string type */
|
|
if(ArgPosition != 0)
|
|
{
|
|
/* Get argument value from specified argument position */
|
|
IntArg = RtlpGetWideStringArgument(&ArgumentsCopy, ArgPosition, sizeof(PUNICODE_STRING));
|
|
UnicodeStrArg = (PUNICODE_STRING)(UINT_PTR)IntArg;
|
|
}
|
|
else
|
|
{
|
|
/* Get argument value from the next argument */
|
|
UnicodeStrArg = VA_ARG(*ArgumentList, PUNICODE_STRING);
|
|
}
|
|
|
|
/* Write formatted UNICODE string value */
|
|
Status = RtlpWriteWideStringValue(Context, &FormatProperties, UnicodeStrArg->Buffer, UnicodeStrArg->Length);
|
|
}
|
|
|
|
/* Cleanup ArgumentsCopy object */
|
|
VA_END(ArgumentsCopy);
|
|
|
|
/* Increase index position according to number of characters consumed */
|
|
*Index += ((UINT_PTR)FormatIndex - (UINT_PTR)(Format + *Index)) / sizeof(WCHAR);
|
|
|
|
/* Return status code */
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
* Gets the positional argument by scanning the argument list.
|
|
*
|
|
* @param ArgumentList
|
|
* Supplies a pointer to the argument list.
|
|
*
|
|
* @param ArgumentNumber
|
|
* Supplies the argument number.
|
|
*
|
|
* @param ArgumentSize
|
|
* Supplies the expected size of the argument.
|
|
*/
|
|
XTAPI
|
|
ULONGLONG
|
|
RtlpGetWideStringArgument(IN PVA_LIST ArgumentList,
|
|
IN ULONG ArgumentNumber,
|
|
IN LONG ArgumentSize)
|
|
{
|
|
VA_LIST ArgumentsCopy;
|
|
ULONGLONG Value;
|
|
ULONG Index;
|
|
|
|
/* Make a copy of the argument list */
|
|
VA_COPY(ArgumentsCopy, *ArgumentList);
|
|
|
|
/* Skip all arguments before the specified one */
|
|
for(Index = 1; Index < ArgumentNumber; Index += 1)
|
|
{
|
|
/* Skip the argument */
|
|
Value = VA_ARG(ArgumentsCopy, LONGLONG);
|
|
}
|
|
|
|
/* Set default value */
|
|
Value = 0;
|
|
|
|
/* Get the argument value depending on its declared size */
|
|
switch(ArgumentSize)
|
|
{
|
|
case sizeof(CHAR):
|
|
Value = (UCHAR)VA_ARG(ArgumentsCopy, INT);
|
|
break;
|
|
case sizeof(SHORT):
|
|
Value = (USHORT)VA_ARG(ArgumentsCopy, INT);
|
|
break;
|
|
case sizeof(LONG):
|
|
Value = VA_ARG(ArgumentsCopy, LONG);
|
|
break;
|
|
case sizeof(LONGLONG):
|
|
Value = VA_ARG(ArgumentsCopy, LONGLONG);
|
|
break;
|
|
default:
|
|
Value = 0;
|
|
break;
|
|
}
|
|
|
|
/* Cleanup ArgumentsCopy object and return the argument value */
|
|
VA_END(ArgumentsCopy);
|
|
return Value;
|
|
}
|
|
|
|
/**
|
|
* Gets the specifier integer value from the wide string advancing the pointer.
|
|
*
|
|
* @param Format
|
|
* Supplies a pointer to the wide string format, at integer value position.
|
|
*
|
|
* @return This routine returns a specifier integer value read from wide string format, or zero if no valid value found.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
ULONGLONG
|
|
RtlpGetWideStringSpecifierValue(IN PWCHAR *Format)
|
|
{
|
|
ULONG Count;
|
|
PWCHAR Fmt;
|
|
|
|
/* Initialize variables */
|
|
Fmt = *Format;
|
|
Count = 0;
|
|
|
|
/* Read the specifier value */
|
|
for(;; Fmt++)
|
|
{
|
|
switch(*Fmt)
|
|
{
|
|
case L'0' ... L'9':
|
|
/* Read the number from wide string */
|
|
Count = Count * 10 + *Fmt - L'0';
|
|
break;
|
|
default:
|
|
/* No more numbers, return count */
|
|
*Format = Fmt;
|
|
return Count;
|
|
}
|
|
}
|
|
|
|
/* Return zero if no value specified */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Writes a wide character to the destination provided by the print context.
|
|
*
|
|
* @param Context
|
|
* Supplies a pointer to the print context structure.
|
|
*
|
|
* @param Character
|
|
* Supplies the wide character to write.
|
|
*
|
|
* @return This routine returns a status code.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
RtlpWriteWideCharacter(IN PRTL_PRINT_CONTEXT Context,
|
|
IN WCHAR Character)
|
|
{
|
|
XTSTATUS Status;
|
|
|
|
/* Write wide character and increment number of characters written so far */
|
|
Status = Context->WriteWideCharacter(Character);
|
|
Context->CharactersWritten++;
|
|
|
|
/* Return status code */
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
* Writes a wide string custom-formatted value to the destination provided by the print context.
|
|
*
|
|
* @param Context
|
|
* Supplies a pointer to the print context structure.
|
|
*
|
|
* @param Format
|
|
* Supplies a pointer to the printf-alike format string.
|
|
*
|
|
* @param ...
|
|
* Depending on the format string, this routine might expect a sequence of additional arguments.
|
|
*
|
|
* @return This routine returns a status code.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
RtlpWriteWideStringCustomValue(IN PRTL_PRINT_CONTEXT Context,
|
|
IN PCWSTR Format,
|
|
IN ...)
|
|
{
|
|
VA_LIST Arguments;
|
|
XTSTATUS Status;
|
|
|
|
/* Initialise the va_list */
|
|
VA_START(Arguments, Format);
|
|
|
|
/* Format and print the string to the desired output */
|
|
Status = RtlFormatWideString(Context, Format, Arguments);
|
|
|
|
/* Clean up the va_list */
|
|
VA_END(Arguments);
|
|
|
|
/* Return status code */
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
* Writes a wide string integer value to the destination provided by the print context.
|
|
*
|
|
* @param Context
|
|
* Supplies a pointer to the print context structure.
|
|
*
|
|
* @param FormatProperties
|
|
* Supplies a pointer to the print format properties structure, describing the style characteristics.
|
|
*
|
|
* @param Integer
|
|
* Supplies the integer value to write as a wide string.
|
|
*
|
|
* @return This routine returns a status code.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
RtlpWriteWideStringIntegerValue(IN PRTL_PRINT_CONTEXT Context,
|
|
IN PRTL_PRINT_FORMAT_PROPERTIES FormatProperties,
|
|
IN ULONGLONG Integer)
|
|
{
|
|
LONG BufferIndex, FieldLength, IntegerLength, PrecisionLength, PrefixIndex, PrefixLength;
|
|
WCHAR Buffer[MAX_INTEGER_STRING_SIZE];
|
|
ULONGLONG NextInteger, Remainder;
|
|
BOOLEAN Negative;
|
|
WCHAR Prefix[4];
|
|
WCHAR Character;
|
|
XTSTATUS Status;
|
|
|
|
/* Set default values */
|
|
IntegerLength = 0;
|
|
Negative = FALSE;
|
|
|
|
/* Check if this is signed integer */
|
|
if(!FormatProperties->UnsignedValue)
|
|
{
|
|
/* Check integer size and extend to signed value */
|
|
switch(FormatProperties->IntegerSize)
|
|
{
|
|
case sizeof(CHAR):
|
|
Integer = (CHAR)Integer;
|
|
break;
|
|
case sizeof(SHORT):
|
|
Integer = (SHORT)Integer;
|
|
break;
|
|
case sizeof(LONG):
|
|
Integer = (LONG)Integer;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Check if the integer value is zero */
|
|
if(Integer == 0)
|
|
{
|
|
/* Cannot print radix if integer is zero */
|
|
FormatProperties->PrintRadix = FALSE;
|
|
}
|
|
|
|
/* Check if any of the integer value or precision is non-zero */
|
|
if(Integer != 0 || FormatProperties->Precision != 0)
|
|
{
|
|
/* Check if the integer is negative */
|
|
if(!FormatProperties->UnsignedValue && (LONGLONG)Integer < 0)
|
|
{
|
|
/* Mark the integer as negative and turn it positive */
|
|
Negative = TRUE;
|
|
Integer *= -1;
|
|
}
|
|
|
|
/* Initialize the buffer */
|
|
RtlZeroMemory(Buffer, sizeof(Buffer));
|
|
|
|
/* Convert the integer into a reversed wide string */
|
|
do
|
|
{
|
|
/* Get the next digit */
|
|
NextInteger = RtlDivideUnsigned64(Integer, FormatProperties->Radix, &Remainder);
|
|
|
|
/* Convert the digit into a character */
|
|
Character = (WCHAR)Remainder;
|
|
if(Character > 9)
|
|
{
|
|
/* Check if the character should be upper case */
|
|
if(FormatProperties->PrintUpperCase)
|
|
{
|
|
/* Get the uppercase character */
|
|
Character = Character - 10 + L'A';
|
|
}
|
|
else
|
|
{
|
|
/* Get the lowercase character */
|
|
Character = Character - 10 + L'a';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Get the numeric character */
|
|
Character += L'0';
|
|
}
|
|
|
|
/* Store the character in the buffer */
|
|
Buffer[IntegerLength] = Character;
|
|
IntegerLength += 1;
|
|
|
|
/* Get next signed digit */
|
|
Integer = NextInteger;
|
|
}
|
|
while(Integer > 0);
|
|
|
|
/* Reverse the string representation of the integer */
|
|
RtlReverseWideString(Buffer, IntegerLength);
|
|
}
|
|
|
|
/* Handle the sign decoration */
|
|
PrefixLength = 0;
|
|
if(!FormatProperties->UnsignedValue && Negative)
|
|
{
|
|
/* Signed negative value, write '-' character */
|
|
Prefix[PrefixLength] = L'-';
|
|
PrefixLength += 1;
|
|
}
|
|
else if(FormatProperties->AlwaysPrintSign)
|
|
{
|
|
/* Write '+' character for positive value */
|
|
Prefix[PrefixLength] = L'+';
|
|
PrefixLength += 1;
|
|
}
|
|
else if(FormatProperties->SpaceForPlus)
|
|
{
|
|
/* Write ' ' character for positive value */
|
|
Prefix[PrefixLength] = L' ';
|
|
PrefixLength += 1;
|
|
}
|
|
|
|
/* Handle the radix decoration */
|
|
if(FormatProperties->PrintRadix)
|
|
{
|
|
if(FormatProperties->Radix == 8)
|
|
{
|
|
/* Check if leading zero is required */
|
|
if(Buffer[0] != L'0')
|
|
{
|
|
/* Write '0' character */
|
|
Prefix[PrefixLength] = L'0';
|
|
PrefixLength += 1;
|
|
}
|
|
}
|
|
else if(FormatProperties->Radix == 16)
|
|
{
|
|
/* Write '0x' characters */
|
|
Prefix[PrefixLength] = L'0';
|
|
PrefixLength += 1;
|
|
|
|
/* Check if uppercase is required */
|
|
if(FormatProperties->PrintUpperCase != 0)
|
|
{
|
|
/* Write uppercase 'X' character */
|
|
Prefix[PrefixLength] = L'X';
|
|
}
|
|
else
|
|
{
|
|
/* Write lowercase 'x' character */
|
|
Prefix[PrefixLength] = L'x';
|
|
}
|
|
|
|
PrefixLength += 1;
|
|
}
|
|
}
|
|
|
|
/* Calculate the precision */
|
|
PrecisionLength = 0;
|
|
if(IntegerLength < FormatProperties->Precision)
|
|
{
|
|
PrecisionLength = FormatProperties->Precision - IntegerLength;
|
|
}
|
|
|
|
/* Calculate the field length */
|
|
FieldLength = 0;
|
|
if(IntegerLength + PrefixLength + PrecisionLength < FormatProperties->FieldWidth)
|
|
{
|
|
FieldLength = FormatProperties->FieldWidth - (IntegerLength + PrefixLength + PrecisionLength);
|
|
}
|
|
|
|
/* Check if leading zero padding is required and if field is left aligned */
|
|
if(!FormatProperties->LeftJustified || FormatProperties->PrintLeadingZeroes)
|
|
{
|
|
Character = L' ';
|
|
if(FormatProperties->PrintLeadingZeroes)
|
|
{
|
|
/* Write leading zero padding characters */
|
|
Character = L'0';
|
|
for(PrefixIndex = 0; PrefixIndex < PrefixLength; PrefixIndex++)
|
|
{
|
|
Status = RtlpWriteWideCharacter(Context, Prefix[PrefixIndex]);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* Clear prefix */
|
|
PrefixLength = 0;
|
|
}
|
|
|
|
/* Write additional field width characters */
|
|
while(FieldLength > 0)
|
|
{
|
|
Status = RtlpWriteWideCharacter(Context, Character);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Decrement field length */
|
|
FieldLength--;
|
|
}
|
|
}
|
|
|
|
/* Write the prefix characters */
|
|
for(PrefixIndex = 0; PrefixIndex < PrefixLength; PrefixIndex++)
|
|
{
|
|
Status = RtlpWriteWideCharacter(Context, Prefix[PrefixIndex]);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* Fill the precision characters with '0' */
|
|
while(PrecisionLength > 0)
|
|
{
|
|
Status = RtlpWriteWideCharacter(Context, L'0');
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Decrement precision length */
|
|
PrecisionLength--;
|
|
}
|
|
|
|
/* Write the actual integer value */
|
|
for(BufferIndex = 0; BufferIndex < IntegerLength; BufferIndex++)
|
|
{
|
|
Status = RtlpWriteWideCharacter(Context, Buffer[BufferIndex]);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* Write additional field width with ' ' characters */
|
|
while(FieldLength > 0)
|
|
{
|
|
Status = RtlpWriteWideCharacter(Context, L' ');
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Decrement field length */
|
|
FieldLength--;
|
|
}
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Writes a string value to the destination provided by the print context.
|
|
*
|
|
* @param Context
|
|
* Supplies a pointer to the print context structure.
|
|
*
|
|
* @param FormatProperties
|
|
* Supplies a pointer to the print format properties structure, describing the style characteristics.
|
|
*
|
|
* @param String
|
|
* Supplies the string value to write as a wide string.
|
|
*
|
|
* @param Character
|
|
* Specifies whether the string value is expected to be a single character or not.
|
|
*
|
|
* @return This routine returns a status code.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
RtlpWriteWideStringStringValue(PRTL_PRINT_CONTEXT Context,
|
|
PRTL_PRINT_FORMAT_PROPERTIES FormatProperties,
|
|
PCHAR String,
|
|
SIZE_T StringLength)
|
|
{
|
|
WCHAR WideCharacter[2];
|
|
ULONG PaddingLength;
|
|
XTSTATUS Status;
|
|
|
|
/* Check for NULL string */
|
|
if(String == NULL)
|
|
{
|
|
/* Print '(null)' instead */
|
|
String = "(null)";
|
|
StringLength = 6;
|
|
}
|
|
|
|
/* Check if string length exceeds precision limit */
|
|
if((FormatProperties->Precision >= 0) && (StringLength > FormatProperties->Precision))
|
|
{
|
|
/* Limit string length to precision number */
|
|
StringLength = FormatProperties->Precision;
|
|
}
|
|
|
|
/* Calculate padding */
|
|
PaddingLength = 0;
|
|
if(FormatProperties->FieldWidth > StringLength)
|
|
{
|
|
PaddingLength = FormatProperties->FieldWidth - StringLength;
|
|
}
|
|
|
|
/* Check is left side padding is required */
|
|
if(!FormatProperties->LeftJustified)
|
|
{
|
|
/* Pad left */
|
|
while(PaddingLength > 0)
|
|
{
|
|
/* Write space */
|
|
Status = RtlpWriteWideCharacter(Context, L' ');
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Decrement padding length */
|
|
PaddingLength--;
|
|
}
|
|
}
|
|
|
|
/* Write string character by character */
|
|
while(StringLength)
|
|
{
|
|
/* Prepare wide character to write */
|
|
WideCharacter[0] = *String;
|
|
WideCharacter[1] = 0;
|
|
|
|
/* Write wide character */
|
|
Status = RtlpWriteWideCharacter(Context, *WideCharacter);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Get next character */
|
|
StringLength--;
|
|
String++;
|
|
}
|
|
|
|
/* Pad right, if required */
|
|
while(PaddingLength > 0)
|
|
{
|
|
/* Write space */
|
|
Status = RtlpWriteWideCharacter(Context, L' ');
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Decrement padding length */
|
|
PaddingLength--;
|
|
}
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Writes a wide string value to the destination provided by the print context.
|
|
*
|
|
* @param Context
|
|
* Supplies a pointer to the print context structure.
|
|
*
|
|
* @param FormatProperties
|
|
* Supplies a pointer to the print format properties structure, describing the style characteristics.
|
|
*
|
|
* @param String
|
|
* Supplies the wide string value to write.
|
|
*
|
|
* @param Character
|
|
* Specifies whether the string value is expected to be a single character or not.
|
|
*
|
|
* @return This routine returns a status code.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
RtlpWriteWideStringValue(PRTL_PRINT_CONTEXT Context,
|
|
PRTL_PRINT_FORMAT_PROPERTIES FormatProperties,
|
|
PWCHAR String,
|
|
SIZE_T StringLength)
|
|
{
|
|
ULONG PaddingLength;
|
|
XTSTATUS Status;
|
|
|
|
/* Check for NULL string */
|
|
if(String == NULL)
|
|
{
|
|
/* Print '(null)' instead */
|
|
String = L"(null)";
|
|
StringLength = 6;
|
|
}
|
|
|
|
/* Check if string length exceeds precision limit */
|
|
if((FormatProperties->Precision >= 0) && (StringLength > FormatProperties->Precision))
|
|
{
|
|
/* Limit string length to precision number */
|
|
StringLength = FormatProperties->Precision;
|
|
}
|
|
|
|
/* Calculate padding */
|
|
PaddingLength = 0;
|
|
if(FormatProperties->FieldWidth > StringLength)
|
|
{
|
|
PaddingLength = FormatProperties->FieldWidth - StringLength;
|
|
}
|
|
|
|
|
|
/* Check is left side padding is required */
|
|
if(!FormatProperties->LeftJustified)
|
|
{
|
|
/* Pad left */
|
|
while(PaddingLength > 0)
|
|
{
|
|
/* Write space */
|
|
Status = RtlpWriteWideCharacter(Context, L' ');
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Decrement padding length */
|
|
PaddingLength--;
|
|
}
|
|
}
|
|
|
|
/* Write string character by character */
|
|
while(StringLength != 0)
|
|
{
|
|
/* Write wide character */
|
|
Status = RtlpWriteWideCharacter(Context, *String);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Get next character */
|
|
StringLength--;
|
|
String++;
|
|
}
|
|
|
|
/* Pad right, if required */
|
|
while(PaddingLength > 0)
|
|
{
|
|
/* Write space */
|
|
Status = RtlpWriteWideCharacter(Context, L' ');
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Failed to write character, return status code */
|
|
return Status;
|
|
}
|
|
|
|
/* Decrement padding length */
|
|
PaddingLength--;
|
|
}
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|