windows-nt/Source/XPSP1/NT/base/ntos/rtl/message.c
2020-09-26 16:20:57 +08:00

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