469 lines
15 KiB
C
469 lines
15 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1991 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
message.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Message table resource accessing functions
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Steve Wood (stevewo) 10-Sep-1991
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "ntrtlp.h"
|
||
|
#include "string.h"
|
||
|
#include "stdio.h"
|
||
|
|
||
|
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
|
||
|
#pragma alloc_text(PAGE,RtlFindMessage)
|
||
|
#endif
|
||
|
|
||
|
NTSTATUS
|
||
|
RtlFindMessage(
|
||
|
IN PVOID DllHandle,
|
||
|
IN ULONG MessageTableId,
|
||
|
IN ULONG MessageLanguageId,
|
||
|
IN ULONG MessageId,
|
||
|
OUT PMESSAGE_RESOURCE_ENTRY *MessageEntry
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ULONG NumberOfBlocks;
|
||
|
ULONG EntryIndex;
|
||
|
PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
|
||
|
PMESSAGE_RESOURCE_DATA MessageData;
|
||
|
PMESSAGE_RESOURCE_BLOCK MessageBlock;
|
||
|
PCHAR s;
|
||
|
ULONG_PTR ResourceIdPath[ 3 ];
|
||
|
|
||
|
RTL_PAGED_CODE();
|
||
|
|
||
|
ResourceIdPath[ 0 ] = MessageTableId;
|
||
|
ResourceIdPath[ 1 ] = 1;
|
||
|
ResourceIdPath[ 2 ] = MessageLanguageId;
|
||
|
|
||
|
Status = LdrpSearchResourceSection_U( DllHandle,
|
||
|
ResourceIdPath,
|
||
|
3,
|
||
|
0,
|
||
|
(PVOID *)&ResourceDataEntry
|
||
|
);
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
Status = LdrpAccessResourceData( DllHandle,
|
||
|
ResourceDataEntry,
|
||
|
(PVOID *)&MessageData,
|
||
|
NULL
|
||
|
);
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
NumberOfBlocks = MessageData->NumberOfBlocks;
|
||
|
MessageBlock = &MessageData->Blocks[ 0 ];
|
||
|
while (NumberOfBlocks--) {
|
||
|
if (MessageId >= MessageBlock->LowId &&
|
||
|
MessageId <= MessageBlock->HighId
|
||
|
) {
|
||
|
s = (PCHAR)MessageData + MessageBlock->OffsetToEntries;
|
||
|
EntryIndex = MessageId - MessageBlock->LowId;
|
||
|
while (EntryIndex--) {
|
||
|
s += ((PMESSAGE_RESOURCE_ENTRY)s)->Length;
|
||
|
}
|
||
|
|
||
|
*MessageEntry = (PMESSAGE_RESOURCE_ENTRY)s;
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
|
||
|
MessageBlock++;
|
||
|
}
|
||
|
|
||
|
return( STATUS_MESSAGE_NOT_FOUND );
|
||
|
}
|
||
|
|
||
|
#ifndef NTOS_KERNEL_RUNTIME
|
||
|
|
||
|
#define MAX_INSERTS 200
|
||
|
|
||
|
NTSTATUS
|
||
|
RtlFormatMessage(
|
||
|
IN PWSTR MessageFormat,
|
||
|
IN ULONG MaximumWidth OPTIONAL,
|
||
|
IN BOOLEAN IgnoreInserts,
|
||
|
IN BOOLEAN ArgumentsAreAnsi,
|
||
|
IN BOOLEAN ArgumentsAreAnArray,
|
||
|
IN va_list *Arguments,
|
||
|
OUT PWSTR Buffer,
|
||
|
IN ULONG Length,
|
||
|
OUT PULONG ReturnLength OPTIONAL
|
||
|
)
|
||
|
{
|
||
|
ULONG Column;
|
||
|
int cchRemaining, cchWritten;
|
||
|
PULONG_PTR ArgumentsArray = (PULONG_PTR)Arguments;
|
||
|
ULONG_PTR rgInserts[ MAX_INSERTS ];
|
||
|
ULONG cSpaces;
|
||
|
ULONG MaxInsert, CurInsert;
|
||
|
ULONG PrintParameterCount;
|
||
|
ULONG_PTR PrintParameter1;
|
||
|
ULONG_PTR PrintParameter2;
|
||
|
WCHAR PrintFormatString[ 32 ];
|
||
|
BOOLEAN DefaultedFormatString;
|
||
|
WCHAR c;
|
||
|
PWSTR s, s1, s2, s3;
|
||
|
PWSTR lpDst, lpDstBeg, lpDstLastSpace;
|
||
|
BOOLEAN WideArg = FALSE;
|
||
|
|
||
|
cchRemaining = Length / sizeof( WCHAR );
|
||
|
lpDst = Buffer;
|
||
|
MaxInsert = 0;
|
||
|
lpDstLastSpace = NULL;
|
||
|
Column = 0;
|
||
|
s = MessageFormat;
|
||
|
while (*s != UNICODE_NULL) {
|
||
|
if (*s == L'%') {
|
||
|
s++;
|
||
|
lpDstBeg = lpDst;
|
||
|
if (*s >= L'1' && *s <= L'9') {
|
||
|
CurInsert = *s++ - L'0';
|
||
|
if (*s >= L'0' && *s <= L'9') {
|
||
|
CurInsert = (CurInsert * 10) + (*s++ - L'0');
|
||
|
if (*s >= L'0' && *s <= L'9') {
|
||
|
CurInsert = (CurInsert * 10) + (*s++ - L'0');
|
||
|
if (*s >= L'0' && *s <= L'9') {
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
CurInsert -= 1;
|
||
|
|
||
|
PrintParameterCount = 0;
|
||
|
if (*s == L'!') {
|
||
|
DefaultedFormatString = FALSE;
|
||
|
s1 = PrintFormatString;
|
||
|
*s1++ = L'%';
|
||
|
s2 = s1;
|
||
|
s++;
|
||
|
while (*s != L'!') {
|
||
|
if (*s != UNICODE_NULL) {
|
||
|
if (s1 >= &PrintFormatString[ 31 ]) {
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
}
|
||
|
|
||
|
if (*s == L'*') {
|
||
|
if (PrintParameterCount++ > 1) {
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*s1++ = *s++;
|
||
|
} else {
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s++;
|
||
|
*s1 = UNICODE_NULL;
|
||
|
WideArg = FALSE;
|
||
|
#if !defined(_IA64_)
|
||
|
// look for I64 format string
|
||
|
s3 = s2;
|
||
|
while (*s3 && !WideArg) {
|
||
|
if (s3[0] == L'I' && s3[1] == L'6' && s3[2] == L'4') {
|
||
|
WideArg = TRUE;
|
||
|
}
|
||
|
s3 += 1;
|
||
|
}
|
||
|
#endif
|
||
|
} else {
|
||
|
DefaultedFormatString = TRUE;
|
||
|
wcscpy( PrintFormatString, L"%s" );
|
||
|
s1 = PrintFormatString + wcslen( PrintFormatString );
|
||
|
WideArg = FALSE;
|
||
|
}
|
||
|
|
||
|
if (IgnoreInserts) {
|
||
|
if (!wcscmp( PrintFormatString, L"%s" )) {
|
||
|
cchWritten = _snwprintf( lpDst,
|
||
|
cchRemaining,
|
||
|
L"%%%u",
|
||
|
CurInsert+1
|
||
|
);
|
||
|
} else {
|
||
|
cchWritten = _snwprintf( lpDst,
|
||
|
cchRemaining,
|
||
|
L"%%%u!%s!",
|
||
|
CurInsert+1,
|
||
|
&PrintFormatString[ 1 ]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (cchWritten == -1) {
|
||
|
return(STATUS_BUFFER_OVERFLOW);
|
||
|
}
|
||
|
} else if (ARGUMENT_PRESENT( Arguments )) {
|
||
|
if ((CurInsert+PrintParameterCount) >= MAX_INSERTS) {
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
}
|
||
|
|
||
|
if (ArgumentsAreAnsi) {
|
||
|
if (s1[ -1 ] == L'c' && s1[ -2 ] != L'h'
|
||
|
&& s1[ -2 ] != L'w' && s1[ -2 ] != L'l') {
|
||
|
wcscpy( &s1[ -1 ], L"hc" );
|
||
|
} else if (s1[ -1 ] == L's' && s1[ -2 ] != L'h'
|
||
|
&& s1[ -2 ] != L'w' && s1[ -2 ] != L'l') {
|
||
|
wcscpy( &s1[ -1 ], L"hs" );
|
||
|
} else if (s1[ -1 ] == L'S') {
|
||
|
s1[ -1 ] = L's';
|
||
|
} else if (s1[ -1 ] == L'C') {
|
||
|
s1[ -1 ] = L'c';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (CurInsert >= MaxInsert) {
|
||
|
if (ArgumentsAreAnArray) {
|
||
|
rgInserts[ MaxInsert++ ] = *((PULONG_PTR)Arguments)++;
|
||
|
} else {
|
||
|
if (WideArg) {
|
||
|
rgInserts[ MaxInsert++ ] = va_arg( *Arguments, ULONG_PTR );
|
||
|
rgInserts[ MaxInsert++ ] = va_arg( *Arguments, ULONG_PTR );
|
||
|
} else {
|
||
|
rgInserts[ MaxInsert++ ] = va_arg( *Arguments, ULONG_PTR );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s1 = (PWSTR)rgInserts[ CurInsert ];
|
||
|
PrintParameter1 = 0;
|
||
|
PrintParameter2 = 0;
|
||
|
if (PrintParameterCount > 0) {
|
||
|
if (ArgumentsAreAnArray) {
|
||
|
PrintParameter1 = rgInserts[ MaxInsert++ ] = *((PULONG_PTR)Arguments)++;
|
||
|
} else {
|
||
|
PrintParameter1 = va_arg( *Arguments, ULONG_PTR );
|
||
|
}
|
||
|
|
||
|
if (PrintParameterCount > 1) {
|
||
|
if (ArgumentsAreAnArray) {
|
||
|
PrintParameter2 = rgInserts[ MaxInsert++ ] = *((PULONG_PTR)Arguments)++;
|
||
|
} else {
|
||
|
PrintParameter2 = rgInserts[ MaxInsert++ ] = va_arg( *Arguments, ULONG_PTR );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (WideArg) {
|
||
|
cchWritten = _snwprintf(
|
||
|
lpDst,
|
||
|
cchRemaining,
|
||
|
PrintFormatString,
|
||
|
*(PULONGLONG)&rgInserts[CurInsert],
|
||
|
PrintParameter1,
|
||
|
PrintParameter2
|
||
|
);
|
||
|
} else {
|
||
|
cchWritten = _snwprintf(
|
||
|
lpDst,
|
||
|
cchRemaining,
|
||
|
PrintFormatString,
|
||
|
s1,
|
||
|
PrintParameter1,
|
||
|
PrintParameter2
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (cchWritten == -1) {
|
||
|
return(STATUS_BUFFER_OVERFLOW);
|
||
|
}
|
||
|
} else {
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
}
|
||
|
|
||
|
if ((cchRemaining -= cchWritten) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
lpDst += cchWritten;
|
||
|
} else if (*s == L'0') {
|
||
|
break;
|
||
|
} else if (!*s) {
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
} else if (*s == L'r') {
|
||
|
if ((cchRemaining -= 1) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
*lpDst++ = L'\r';
|
||
|
s++;
|
||
|
lpDstBeg = NULL;
|
||
|
} else if (*s == L'n') {
|
||
|
if ((cchRemaining -= 2) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
*lpDst++ = L'\r';
|
||
|
*lpDst++ = L'\n';
|
||
|
s++;
|
||
|
lpDstBeg = NULL;
|
||
|
} else if (*s == L't') {
|
||
|
if ((cchRemaining -= 1) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
if (Column % 8) {
|
||
|
Column = (Column + 7) & ~7;
|
||
|
} else {
|
||
|
Column += 8;
|
||
|
}
|
||
|
|
||
|
lpDstLastSpace = lpDst;
|
||
|
*lpDst++ = L'\t';
|
||
|
s++;
|
||
|
} else if (*s == L'b') {
|
||
|
if ((cchRemaining -= 1) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
lpDstLastSpace = lpDst;
|
||
|
*lpDst++ = L' ';
|
||
|
s++;
|
||
|
} else if (IgnoreInserts) {
|
||
|
if ((cchRemaining -= 2) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
*lpDst++ = L'%';
|
||
|
*lpDst++ = *s++;
|
||
|
} else {
|
||
|
if ((cchRemaining -= 1) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
*lpDst++ = *s++;
|
||
|
}
|
||
|
|
||
|
if (lpDstBeg == NULL) {
|
||
|
lpDstLastSpace = NULL;
|
||
|
Column = 0;
|
||
|
} else {
|
||
|
Column += (ULONG)(lpDst - lpDstBeg);
|
||
|
}
|
||
|
} else {
|
||
|
c = *s++;
|
||
|
if (c == L'\r' || c == L'\n') {
|
||
|
if ((c == L'\n' && *s == L'\r') ||
|
||
|
(c == L'\r' && *s == L'\n')
|
||
|
)
|
||
|
{
|
||
|
s++;
|
||
|
}
|
||
|
|
||
|
if (MaximumWidth != 0) {
|
||
|
lpDstLastSpace = lpDst;
|
||
|
c = L' ';
|
||
|
} else {
|
||
|
c = L'\n';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (c == L'\n') {
|
||
|
if ((cchRemaining -= 2) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
*lpDst++ = L'\r';
|
||
|
*lpDst++ = L'\n';
|
||
|
lpDstLastSpace = NULL;
|
||
|
Column = 0;
|
||
|
} else {
|
||
|
if ((cchRemaining -= 1) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
if (c == L' ') {
|
||
|
lpDstLastSpace = lpDst;
|
||
|
}
|
||
|
|
||
|
*lpDst++ = c;
|
||
|
Column += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (MaximumWidth != 0 &&
|
||
|
MaximumWidth != 0xFFFFFFFF &&
|
||
|
Column >= MaximumWidth
|
||
|
) {
|
||
|
if (lpDstLastSpace != NULL) {
|
||
|
lpDstBeg = lpDstLastSpace;
|
||
|
while (*lpDstBeg == L' ' || *lpDstBeg == L'\t') {
|
||
|
lpDstBeg += 1;
|
||
|
if (lpDstBeg == lpDst) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
while (lpDstLastSpace > Buffer) {
|
||
|
if (lpDstLastSpace[ -1 ] == L' ' || lpDstLastSpace[ -1 ] == L'\t') {
|
||
|
lpDstLastSpace -= 1;
|
||
|
}
|
||
|
else {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cSpaces = (ULONG)(lpDstBeg - lpDstLastSpace);
|
||
|
if (cSpaces == 1) {
|
||
|
if ((cchRemaining -= 1) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (cSpaces > 2) {
|
||
|
cchRemaining += (cSpaces - 2);
|
||
|
}
|
||
|
|
||
|
memmove( lpDstLastSpace + 2,
|
||
|
lpDstBeg,
|
||
|
(ULONG) ((lpDst - lpDstBeg) * sizeof( WCHAR ))
|
||
|
);
|
||
|
*lpDstLastSpace++ = L'\r';
|
||
|
*lpDstLastSpace++ = L'\n';
|
||
|
Column = (ULONG)(lpDst - lpDstBeg);
|
||
|
lpDst = lpDstLastSpace + Column;
|
||
|
lpDstLastSpace = NULL;
|
||
|
}
|
||
|
else {
|
||
|
if ((cchRemaining -= 2) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
*lpDst++ = L'\r';
|
||
|
*lpDst++ = L'\n';
|
||
|
lpDstLastSpace = NULL;
|
||
|
Column = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((cchRemaining -= 1) <= 0) {
|
||
|
return STATUS_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
|
||
|
*lpDst++ = '\0';
|
||
|
if ( ARGUMENT_PRESENT(ReturnLength) ) {
|
||
|
*ReturnLength = (ULONG)(lpDst - Buffer) * sizeof( WCHAR );
|
||
|
}
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
#endif
|
||
|
|