434 lines
14 KiB
C
434 lines
14 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1997-2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
traceprt.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Trace formatting library. Converts binary trace file to CSV format,
|
||
|
and other formattted string formats.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Ian Service (IanServ) 3rd May 2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Source taken from RtlFormatMessage and adapted for the needs of TraceFmt processing.
|
||
|
|
||
|
Due to the way we pre format strings and get information about 64 and 32 bit strings, the odditties
|
||
|
like %p do not work correctly when handled on a machine of the other type.
|
||
|
This module contains a special version of RtlFormatMessage that does fixups in conjunction
|
||
|
with TracePrt's processing of ItemPtr.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C"{
|
||
|
#endif
|
||
|
|
||
|
#define UNICODE
|
||
|
#define _UNICODE
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
#include <windows.h>
|
||
|
#include <shellapi.h>
|
||
|
#include <tchar.h>\
|
||
|
|
||
|
#define MAX_INSERTS 200
|
||
|
|
||
|
NTSTATUS
|
||
|
TraceFormatMessage(
|
||
|
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;
|
||
|
PWSTR lpDst, lpDstBeg, lpDstLastSpace;
|
||
|
|
||
|
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'%';
|
||
|
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;
|
||
|
}
|
||
|
else {
|
||
|
DefaultedFormatString = TRUE;
|
||
|
wcscpy( PrintFormatString, L"%s" );
|
||
|
s1 = PrintFormatString + wcslen( PrintFormatString );
|
||
|
}
|
||
|
|
||
|
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 {
|
||
|
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 = rgInserts[ MaxInsert++ ] = 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 );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Here is where we diverage and fro Trace Formatting we fixup parameters
|
||
|
// %p becomes %s because thats the way we guarantee that its 64/32 compatible
|
||
|
{
|
||
|
SIZE_T len = _tcslen(PrintFormatString);
|
||
|
if (_tcschr(PrintFormatString,L'p') != NULL ||
|
||
|
(len >= 2) && (PrintFormatString[len-2] == 'I') ||
|
||
|
(len >= 4) && (PrintFormatString[len-4] == 'I') &&
|
||
|
(PrintFormatString[len-3] == '6') &&
|
||
|
(PrintFormatString[len-2] == '4') )
|
||
|
{
|
||
|
_stprintf(PrintFormatString,_T("%%s"));
|
||
|
}
|
||
|
}
|
||
|
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 );
|
||
|
}
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|