|
|
#include <setupp.h>
DEFINE_GUID( SAC_CHANNEL_GUI_MODE_DEBUG_GUID, 0x5ed3bac7, 0xa2f9, 0x4e45, 0x98, 0x75, 0xb2, 0x59, 0xea, 0x3f, 0x29, 0x1f );
DEFINE_GUID( SAC_CHANNEL_GUI_MODE_ERROR_LOG_GUID, 0x773d2759, 0x19b8, 0x4d6e, 0x80, 0x45, 0x26, 0xbf, 0x38, 0x40, 0x22, 0x52 );
DEFINE_GUID( SAC_CHANNEL_GUI_MODE_ACTION_LOG_GUID, 0xd37c67ba, 0x89e7, 0x44ba, 0xae, 0x5a, 0x11, 0x2c, 0x68, 0x06, 0xb0, 0xdd );
//
// The GUI-mode channels
//
SAC_CHANNEL_HANDLE SacChannelGuiModeDebugHandle; BOOL SacChannelGuiModeDebugEnabled = FALSE; SAC_CHANNEL_HANDLE SacChannelActionLogHandle; BOOL SacChannelActionLogEnabled = FALSE; SAC_CHANNEL_HANDLE SacChannelErrorLogHandle; BOOL SacChannelErrorLogEnabled = FALSE;
PUCHAR Utf8ConversionBuffer = NULL; ULONG Utf8ConversionBufferSize = 0;
//
// Define the max # of Unicode chars that can be translated with the
// given size of the utf8 translation buffer
//
#define MAX_UTF8_ENCODE_BLOCK_LENGTH ((Utf8ConversionBufferSize / 3) - 1)
VOID SacChannelInitialize( VOID ) /*++
Routine Description:
This routine creates and initializes all the GUI-mode channels
Arguments:
None
Return Value:
None
--*/ { BOOL bSuccess; SAC_CHANNEL_OPEN_ATTRIBUTES Attributes;
//
//
//
Utf8ConversionBufferSize = 512*3+3; Utf8ConversionBuffer = malloc(Utf8ConversionBufferSize); if (Utf8ConversionBuffer == NULL) { return; }
//
// Configure the new channel
//
RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
Attributes.Type = ChannelTypeRaw; if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_DEBUG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) { Attributes.Name[0] = L'\0'; } if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_DEBUG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) { Attributes.Description[0] = L'\0'; } Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_DEBUG_GUID;
//
// Create a channel for the GUI Mode Debug spew
//
bSuccess = SacChannelOpen( &SacChannelGuiModeDebugHandle, &Attributes );
if (bSuccess) { //
// We can now use this channel
//
SacChannelGuiModeDebugEnabled = TRUE; SetupDebugPrint(L"Successfully opened GuiModeDebug channel\n"); } else { SetupDebugPrint(L"Failed to open GuiModeDebug channel\n"); }
//
// Configure the new channel
//
RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
Attributes.Type = ChannelTypeRaw; if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ACTION_LOG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) { Attributes.Name[0] = L'\0'; } if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ACTION_LOG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) { Attributes.Description[0] = L'\0'; } Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_ACTION_LOG_GUID; //
// Create a channel for the Action Log spew
//
bSuccess = SacChannelOpen( &SacChannelActionLogHandle, &Attributes );
if (bSuccess) { //
// We can now use this channel
//
SacChannelActionLogEnabled = TRUE;
SetupDebugPrint(L"Successfully opened ActionLog channel\n"); } else { SetupDebugPrint(L"Failed to open ActionLog channel\n"); }
//
// Configure the new channel
//
RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
Attributes.Type = ChannelTypeRaw; if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ERROR_LOG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) { Attributes.Name[0] = L'\0'; } if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ERROR_LOG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) { Attributes.Description[0] = L'\0'; } Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_ERROR_LOG_GUID;
//
// Create a channel for the Error Log spew
//
bSuccess = SacChannelOpen( &SacChannelErrorLogHandle, &Attributes );
if (bSuccess) { //
// We can now use this channel
//
SacChannelErrorLogEnabled = TRUE; SetupDebugPrint(L"Successfully opened ErrorLog channel\n"); } else { SetupDebugPrint(L"Failed to open ErrorLog channel\n"); }
}
VOID SacChannelTerminate( VOID ) /*++
Routine Description:
This routine closes all the GUI-mode setup channels
Arguments:
None
Return Value:
None
--*/ {
//
// If the channel is enabled,
// then attempt to close it
//
if (SacChannelActionLogEnabled) { //
// This channel is no longer available
//
SacChannelActionLogEnabled = FALSE;
//
// Attempt to close the channel
//
if (SacChannelClose(&SacChannelActionLogHandle)) { SetupDebugPrint(L"Successfully closed ActionLog channel\n"); } else { SetupDebugPrint(L"Failed to close ActionLog channel\n"); } } //
// If the channel is enabled,
// then attempt to close it
//
if (SacChannelErrorLogEnabled) { //
// This channel is no longer available
//
SacChannelErrorLogEnabled = FALSE; //
// Attempt to close the channel
//
if (SacChannelClose(&SacChannelErrorLogHandle)) { SetupDebugPrint(L"Successfully closed ErrorLog channel\n"); } else { SetupDebugPrint(L"Failed to close ErrorLog channel\n"); }
}
//
// If the channel is enabled,
// then attempt to close it
//
if (SacChannelGuiModeDebugEnabled) {
//
// This channel is no longer available
//
SacChannelGuiModeDebugEnabled = FALSE;
//
// Attempt to close the channel
//
if (SacChannelClose(&SacChannelGuiModeDebugHandle)) { SetupDebugPrint(L"Successfully closed GuiModeDebug channel\n"); } else { SetupDebugPrint(L"Failed to close GuiModeDebug channel\n"); } }
//
// free the conversion buffer if necessary
//
if (Utf8ConversionBuffer != NULL) { free(Utf8ConversionBuffer); Utf8ConversionBuffer = NULL; Utf8ConversionBufferSize = 0; }
}
#if 0
BOOL CopyAndInsertStringAtInterval( IN PSTR SourceStr, IN ULONG Interval, IN PSTR InsertStr, OUT PSTR *pDestStr ) /*++
Routine Description:
This routine takes a source string and inserts an "interval string" at interval characters in the new destination string. Note: caller is responsible for releasing DestStr if successful ex: src "aaabbbccc" interval string = "XYZ" interval = 3 ==> dest string == "aaaXYZbbbXYZccc"
Arguments: SourceStr - the source string Interval - spanning interval InsertStr - the insert string DestStr - the destination string
Return Value:
Status
--*/ { ULONG SrcLength; ULONG DestLength; ULONG DestSize; ULONG InsertLength; ULONG k; ULONG l; ULONG i; PSTR DestStr; ULONG IntervalCnt;
ASSERT(SourceStr); ASSERT(Interval > 0); ASSERT(InsertStr); ASSERT(pDestStr > 0);
//
// the length of the insert string
//
InsertLength = strlen(InsertStr); //
// Compute how large the destination string needs to be,
// including the source string and the interval strings.
//
// Note: if the srclength is an integer multiple of Interval
// then we need to subtract 1 from the # of partitions
//
SrcLength = strlen(SourceStr); IntervalCnt = SrcLength / Interval; if (SrcLength % Interval == 0) { IntervalCnt = IntervalCnt > 0 ? IntervalCnt - 1 : IntervalCnt; } DestLength = SrcLength + (IntervalCnt * strlen(InsertStr)); DestSize = (DestLength + 1) * sizeof(UCHAR);
//
// Allocate the new destination string
//
DestStr = LocalAlloc(LPTR, DestSize); if (!DestStr) { return FALSE; } RtlZeroMemory(DestStr, DestSize);
//
// Initialize the pointers into the source and destination strings
//
l = 0; i = 0;
do {
//
// k = # of characters to copy
//
// if Interval > # of characters left to copy,
// then k = # of characters left to copy
// else k = interval
//
k = Interval > (SrcLength - i) ? (SrcLength - i) : Interval; //
// Copy k charactars to the destination buffer
//
strncpy( &DestStr[l], &SourceStr[i], k );
//
// Account for how many characters we just copied
//
l += k; i += k;
//
// If there are any characters left to copy,
// then we need to insert the InsertString
// That is, we are at an interval.
//
if (i < SrcLength) { //
// Insert the specified string at the interval
//
strcpy( &DestStr[l], InsertStr );
//
// Account for how many characters we just copied
//
l += InsertLength; }
} while ( i < SrcLength);
//
//
//
ASSERT(i == SrcLength); ASSERT(l == DestLength); ASSERT((l + 1) * sizeof(UCHAR) == DestSize);
//
// Send back the destination string
//
*pDestStr = DestStr;
return TRUE; }
BOOL SacChannelWrappedWrite( IN SAC_CHANNEL_HANDLE SacChannelHandle, IN PCBYTE Buffer, IN ULONG BufferSize ) /*++
Routine Description:
This routine takes a string and makes it wrap at 80 cols and then sends the new string to the specified channel. Arguments:
SacChannelHandle - the channel reference to received the data Buffer - the string BufferSize - the string size Return Value:
--*/ { BOOL bSuccess; PSTR OutStr;
UNREFERENCED_PARAMETER(BufferSize);
bSuccess = CopyAndInsertStringAtInterval( Buffer, 80, "\r\n", &OutStr );
if (bSuccess) {
bSuccess = SacChannelRawWrite( SacChannelHandle, OutStr, strlen(OutStr)*sizeof(UCHAR) );
LocalFree(OutStr);
}
return bSuccess; } #endif
BOOLEAN SacTranslateUnicodeToUtf8( IN PCWSTR SourceBuffer, IN ULONG SourceBufferLength, IN PUCHAR DestinationBuffer, IN ULONG DestinationBufferSize, OUT PULONG UTF8Count, OUT PULONG ProcessedCount ) /*++
Routine Description:
This routine translates a Unicode string into a UFT8 encoded string.
Note: if the destination buffer is not large enough to hold the entire encoded UFT8 string, then it will contain as much as can fit. TODO: this routine should return some notification if the entire Unicode string was not encoded. Arguments:
SourceBuffer - the source Unicode string SourceBufferLength - the # of characters the caller wants to translate note: a NULL termination overrides this DestinationBuffer - the destination for the UTF8 string DestinationBufferSize - the size of the destination buffer UTF8Count - on exit, contains the # of resulting UTF8 characters ProcessedCount - on exit, contains the # of processed Unicode characters Return Value:
Status
--*/ { //
// Init
//
*UTF8Count = 0; *ProcessedCount = 0;
//
// convert into UTF8 for actual transmission
//
// UTF-8 encodes 2-byte Unicode characters as follows:
// If the first nine bits are zero (00000000 0xxxxxxx), encode it as one byte 0xxxxxxx
// If the first five bits are zero (00000yyy yyxxxxxx), encode it as two bytes 110yyyyy 10xxxxxx
// Otherwise (zzzzyyyy yyxxxxxx), encode it as three bytes 1110zzzz 10yyyyyy 10xxxxxx
//
//
// Process until one of the specified conditions is met
//
while (*SourceBuffer && (*UTF8Count < DestinationBufferSize) && (*ProcessedCount < SourceBufferLength) ) {
if( (*SourceBuffer & 0xFF80) == 0 ) { //
// if the top 9 bits are zero, then just
// encode as 1 byte. (ASCII passes through unchanged).
//
DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0x7F); } else if( (*SourceBuffer & 0xF800) == 0 ) { //
// see if we pass the end of the buffer
//
if ((*UTF8Count + 2) >= DestinationBufferSize) { break; } //
// if the top 5 bits are zero, then encode as 2 bytes
//
DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 6) & 0x1F) | 0xC0; DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0xBF) | 0x80; } else { //
// see if we pass the end of the buffer
//
if ((*UTF8Count + 3) >= DestinationBufferSize) { break; } //
// encode as 3 bytes
//
DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 12) & 0xF) | 0xE0; DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 6) & 0x3F) | 0x80; DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0xBF) | 0x80;
} //
// Advance the # of characters processed
//
(*ProcessedCount)++; //
// Advanced to the next character to process
//
SourceBuffer += 1; }
//
// Sanity checks
//
ASSERT(*ProcessedCount <= SourceBufferLength); ASSERT(*UTF8Count <= DestinationBufferSize);
return(TRUE);
}
BOOL SacChannelUnicodeWrite( IN SAC_CHANNEL_HANDLE SacChannelHandle, IN PCWSTR String ) /*++
Routine Description:
This is a wrapper routine for sending data to a channel. That is, we can use this routine to modify the string before we send it off without having to modify the callers. This is a convenience routine to simplify UFT8 encoding and sending a Unicode string. Arguments:
Channel - Previously created channel. String - Output string. Return Value:
STATUS_SUCCESS if successful, otherwise status
--*/ { BOOL bStatus; ULONG Length; ULONG i; ULONG k; ULONG j; ULONG TranslatedCount; ULONG UTF8TranslationSize; PCWSTR pwch;
ASSERT(String); //
// Determine the total # of WCHARs to process
//
Length = wcslen(String);
//
// Do nothing if there is nothing to do
//
if (Length == 0) { return TRUE; }
//
// Point to the beginning of the string
//
pwch = (PCWSTR)String;
//
// default:
//
bStatus = TRUE;
//
// Divide the incoming buffer into blocks of length
// MAX_UTF8_ENCODE_BLOCK_LENGTH.
//
do {
//
// Determine the remainder
//
k = Length % MAX_UTF8_ENCODE_BLOCK_LENGTH;
if (k > 0) { //
// Translate the first k characters
//
bStatus = SacTranslateUnicodeToUtf8( pwch, k, Utf8ConversionBuffer, Utf8ConversionBufferSize, &UTF8TranslationSize, &TranslatedCount );
//
// If this assert hits, it is probably caused by
// a premature NULL termination in the incoming string
//
ASSERT(k == TranslatedCount);
if (!bStatus) { break; }
//
// Send the UTF8 encoded characters
//
bStatus = SacChannelRawWrite( SacChannelHandle, Utf8ConversionBuffer, UTF8TranslationSize );
if (! bStatus) { break; } //
// Adjust the pwch to account for the sent length
//
pwch += k;
} //
// Determine the # of blocks we can process
//
j = Length / MAX_UTF8_ENCODE_BLOCK_LENGTH;
//
// Translate each WCHAR to UTF8 individually. This way,
// no matter how big the String is, we don't run into
// buffer size problems (it just might take a while).
//
for (i = 0; i < j; i++) {
//
// Encode the next block
//
bStatus = SacTranslateUnicodeToUtf8( pwch, MAX_UTF8_ENCODE_BLOCK_LENGTH, Utf8ConversionBuffer, Utf8ConversionBufferSize, &UTF8TranslationSize, &TranslatedCount );
//
// If this assert hits, it is probably caused by
// a premature NULL termination in the incoming string
//
ASSERT(MAX_UTF8_ENCODE_BLOCK_LENGTH == TranslatedCount);
if (! bStatus) { break; }
//
// Adjust the pwch to account for the sent length
//
pwch += MAX_UTF8_ENCODE_BLOCK_LENGTH;
//
// Send the UTF8 encoded characters
//
bStatus = SacChannelRawWrite( SacChannelHandle, Utf8ConversionBuffer, UTF8TranslationSize );
if (! bStatus) { break; }
}
} while ( FALSE ); //
// Validate that the pwch pointer stopped at the end of the buffer
//
ASSERT(pwch == (String + Length)); return bStatus; }
|