Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

805 lines
18 KiB

/*****************************************************************************************************************
FILENAME: TextBlock.cpp
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
*/
#include "stdafx.h"
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <locale.h>
#include <tchar.h>
#include "ErrMacro.h"
#include "DfrgRes.h"
#include "TextBlock.h"
#include "secattr.h"
#include <stdlib.h>
PTCHAR
CommafyNumberFloat(
double number,
BOOL bDecimal,
PTCHAR stringBuffer,
UINT stringBufferLength
);
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
Constructor for CTextBlock
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
CTextBlock::CTextBlock(void)
{
// initialize
m_isFixedWidth = m_isUseTabs = m_isUseCRLF = FALSE;
m_colCount = m_currentCol = 0;
m_hResource = NULL;
m_pEndOfBuffer = m_pText = NULL;
// Allocate 64K
EV((m_hMemory = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, 0x10000)) != NULL);
// Lock the memory and get the pointer
m_pText = (PTCHAR) GlobalLock(m_hMemory);
EV(m_pText);
m_pEndOfBuffer = m_pText;
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
CTextBlock::~CTextBlock(void)
{
if (m_hMemory){
EH_ASSERT(GlobalUnlock(m_hMemory) == FALSE);
EH_ASSERT(GlobalFree(m_hMemory) == NULL);
}
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
__cdecl CTextBlock::WriteToBuffer(
PTCHAR cFormat,
...
)
{
// cannot have fixed width with no columns defined
assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0));
va_list argptr;
va_start(argptr, cFormat); // init the argument list
if (m_isFixedWidth){
TCHAR buffer[4 * MAX_PATH];
int num;
// print the data into a temp buffer
num = vswprintf(buffer, cFormat, argptr);
assert(num < 4 * MAX_PATH);
// concat and pad onto text buffer
//m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), m_colWidth[m_currentCol], buffer);
WriteToBufferAndPad(buffer, m_colWidth[m_currentCol]);
}
else{
m_pEndOfBuffer += vswprintf(m_pEndOfBuffer, cFormat, argptr);
}
va_end(argptr);
// increment the column counter
m_currentCol++;
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
CTextBlock::WriteToBufferLL(
LONGLONG number
)
{
// cannot have fixed width with no columns defined
assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0));
// convert to a string, putting commas in if needed
TCHAR tmpBuffer[256];
CommafyNumber(number, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR));
if (m_isFixedWidth){
// concat and pad onto text buffer
WriteToBufferAndPad(tmpBuffer, m_colWidth[m_currentCol]);
//m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), m_colWidth[m_currentCol], tmpBuffer);
}
else{
m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, tmpBuffer);
}
// increment the column counter
m_currentCol++;
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
CTextBlock::WriteToBuffer(
UINT resourceID
)
{
// cannot have fixed width with no columns defined
assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0));
// must have assigned a handle to the resource
assert(m_hResource);
TCHAR buffer[256];
EH_ASSERT(LoadString(m_hResource, resourceID, buffer, sizeof(buffer)/sizeof(TCHAR)));
if (m_isFixedWidth){
WriteToBufferAndPad(buffer, m_colWidth[m_currentCol]);
}
else{
m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%s"), buffer);
}
// increment the column counter
m_currentCol++;
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
CTextBlock::SetColumnWidth(
UINT col,
UINT colWidth
)
{
// cannot have fixed width with no columns defined
assert(m_isFixedWidth);
assert(m_colCount > 0);
// the column number must be less than the column count
assert(col < m_colCount);
m_colWidth[col] = colWidth;
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
CTextBlock::WriteTab(
void
)
{
// only write the tab if the tab feature has been turned on
if (m_isUseTabs)
m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\t"));
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
CTextBlock::WriteNULL(
void
)
{
m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\0"));
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
CTextBlock::EndOfLine(
void
)
{
// the first few lines here are to strip off trailing spaces
PTCHAR pEOL = m_pEndOfBuffer-1;
while (*pEOL == TEXT(' ') && pEOL != m_pText){
pEOL--;
}
m_pEndOfBuffer = pEOL + 1;
*m_pEndOfBuffer = NULL;
// only write the tab if the tab feature has been turned on
if (m_isUseCRLF)
m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\r\n"));
// reset the col counter to col 0 (start of next line)
m_currentCol = 0;
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
CTextBlock::WriteByteCount(
LONGLONG number
)
{
TCHAR buffer[256];
// formats the number and appends the units
FormatNumber(m_hResource, number, buffer);
// write the number and units to the text block
WriteToBuffer(buffer);
}
void
CTextBlock::FormatNum(
HINSTANCE hResource,
LONGLONG number,
PTCHAR buffer
)
{
FormatNumber(hResource, number, buffer);
}
/***************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
DESCRIPTION:
DATA STRUCTURES:
None.
GLOBALS:
None.
INPUT:
RETURN:
The number of characters written.
0 on error.
*/
DWORD
FormatNumber(
HINSTANCE hResource,
LONGLONG number,
PTCHAR buffer
)
{
UINT resourceID = IDS_UNITS_GB;
double numberFloat = 0;
BOOL bDecimal = FALSE;
numberFloat = (double) number;
__try{
//Byte range.
if (number < 1024){
resourceID = IDS_UNITS_BYTES;
__leave;
}
// KB range
numberFloat = (double) number / 1024;
if (numberFloat < 1024){
resourceID = IDS_UNITS_KB;
__leave;
}
// MB range
numberFloat /= 1024;
if (numberFloat < 1024){
resourceID = IDS_UNITS_MB;
__leave;
}
// GB range
//This is the default range that we will display, so we dont need to test number
numberFloat /= 1024;
resourceID = IDS_UNITS_GB;
if (numberFloat < 100) {
bDecimal = TRUE;
}
__leave;
}
__finally {
// load the "units" string from resources
TCHAR units[30];
EH_ASSERT(LoadString(hResource, resourceID, units, sizeof(units)/sizeof(TCHAR)));
// convert to a string, putting commas in if needed
TCHAR tmpBuffer[256];
CommafyNumberFloat(numberFloat, bDecimal, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR));
// concat a spacer
_tcscat(tmpBuffer, TEXT(" "));
// concat the units
_tcscat(tmpBuffer, units);
// write the number and units to the text block
_tcscpy(buffer, tmpBuffer);
}
return _tcslen(buffer);
}
DWORD
FormatNumberMB(
HINSTANCE hResource,
LONGLONG number,
PTCHAR buffer
)
{
// MB range
double numberMB = (double) (number / 0x100000); // 1 MB
UINT resourceID = IDS_UNITS_MB;
BOOL decimal = FALSE;
// if it turned out to be 0, switch over to KB
if (numberMB < 1){
numberMB = (double) number / 1024; // 1 KB
resourceID = IDS_UNITS_KB;
}
else if (numberMB > 1024){ // if it is greater than 1024 MB, switch to GB
numberMB /= 1024;
resourceID = IDS_UNITS_GB;
if (numberMB < 100) {
decimal = TRUE;
}
}
// load the "units" string from resources
TCHAR units[30];
EH_ASSERT(LoadString(hResource, resourceID, units, sizeof(units)/sizeof(TCHAR)));
// convert to a string, putting commas in if needed
TCHAR tmpBuffer[256];
CommafyNumberFloat(numberMB, decimal, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR));
// concat a spacer
_tcscat(tmpBuffer, TEXT(" "));
// concat the units
_tcscat(tmpBuffer, units);
// write the number and units to the text block
_tcscpy(buffer, tmpBuffer);
return _tcslen(buffer);
}
/***************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
DESCRIPTION:
This takes the source string and works from right to left,
copying chars from the source to the target, adding commas
every third character
DATA STRUCTURES:
None.
GLOBALS:
None.
INPUT:
RETURN:
Pointer to buffer with commafied number or NULL if error
*/
PTCHAR
CommafyNumber(
LONGLONG number,
PTCHAR stringBuffer,
UINT stringBufferLength
)
{
EN_ASSERT(stringBuffer);
EN_ASSERT(stringBufferLength);
TCHAR sourceString[256];
TCHAR targetString[256];
TCHAR tcThousandsSep[2] = {TEXT(','), 0};
struct lconv *locals = localeconv();
if (locals && (locals->thousands_sep) && (*(locals->thousands_sep) != 0)) {
_stprintf(tcThousandsSep, TEXT("%C"), *(locals->thousands_sep));
}
UINT uGrouping = 0;
if (locals && (locals->grouping)) {
uGrouping = atoi(locals->grouping);
}
if(uGrouping == 0)
{
uGrouping = 3; //default value if its not supported
}
// convert LONGLONG number to a Unicode string
_stprintf(sourceString, TEXT("%I64d"), number);
// point the source pointer at the null terminator
PTCHAR pSource = sourceString + _tcslen(sourceString);
// put the target pointer at the end of the target buffer
PTCHAR pTarget = targetString + sizeof(targetString) / sizeof(TCHAR) - 1;
// write the null terminator
*pTarget = NULL;
for (UINT i=0; i<_tcslen(sourceString); i++) {
if (i>0 && i%uGrouping == 0) {
pTarget--;
*pTarget = tcThousandsSep[0];
}
pTarget--;
pSource--;
*pTarget = *pSource;
}
if (stringBufferLength > _tcslen(pTarget)){
_tcscpy(stringBuffer, pTarget);
}
else{
_tcscpy(stringBuffer, TEXT(""));
}
return stringBuffer;
}
/***************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
DESCRIPTION:
This takes the source string and works from right to left,
copying chars from the source to the target, adding commas
every third character
DATA STRUCTURES:
None.
GLOBALS:
None.
INPUT:
RETURN:
Pointer to buffer with commafied number or NULL if error
*/
PTCHAR
CommafyNumberFloat(
double number,
BOOL bDecimal,
PTCHAR stringBuffer,
UINT stringBufferLength
)
{
EN_ASSERT(stringBuffer);
EN_ASSERT(stringBufferLength);
TCHAR sourceString[256];
TCHAR targetString[256];
TCHAR tcThousandsSep[2] = {TEXT(','), 0};
struct lconv *locals = localeconv();
if (locals && (locals->thousands_sep) && (*(locals->thousands_sep) != 0)) {
_stprintf(tcThousandsSep, TEXT("%C"), *(locals->thousands_sep));
}
UINT uGrouping = 0;
if (locals && (locals->grouping)) {
uGrouping = atoi(locals->grouping);
}
if(uGrouping == 0)
{
uGrouping = 3; //default value if its not supported
}
if (bDecimal) {
// convert double number to a Unicode string
_stprintf(sourceString, TEXT("%0.02f"), number);
}
else {
// convert double number to a Unicode string
_stprintf(sourceString, TEXT("%0.0f"), number);
}
// point the source pointer at the null terminator
PTCHAR pSource = sourceString + _tcslen(sourceString);
// put the target pointer at the end of the target buffer
PTCHAR pTarget = targetString + sizeof(targetString) / sizeof(TCHAR) - 1;
// write the null terminator
*pTarget = NULL;
if (bDecimal) {
for (UINT j = 0; j < 3; j++) {
pTarget--;
pSource--;
*pTarget = *pSource;
}
}
for (UINT i=0; i<_tcslen(sourceString)-(bDecimal ? 3 : 0); i++) {
if (i>0 && i%uGrouping == 0) {
pTarget--;
*pTarget = tcThousandsSep[0];
}
pTarget--;
pSource--;
*pTarget = *pSource;
}
if (stringBufferLength > _tcslen(pTarget)){
_tcscpy(stringBuffer, pTarget);
}
else{
_tcscpy(stringBuffer, TEXT(""));
}
return stringBuffer;
}
/***************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
DESCRIPTION:
DATA STRUCTURES:
None.
GLOBALS:
None.
INPUT:
RETURN:
*/
BOOL CTextBlock::StoreFile(
IN TCHAR* cStoreFileName,
IN DWORD dwCreate
)
{
HANDLE hFileHandle = NULL;
SECURITY_ATTRIBUTES saSecurityAttributes;
SECURITY_DESCRIPTOR sdSecurityDescriptor;
ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
saSecurityAttributes.bInheritHandle = FALSE;
if (!ConstructSecurityAttributes(&saSecurityAttributes, esatFile, FALSE)) {
return FALSE;
}
// Create a new file for this text
hFileHandle = CreateFile(
cStoreFileName,
GENERIC_WRITE,
0, // no sharing
&saSecurityAttributes,
dwCreate,
FILE_ATTRIBUTE_NORMAL,
NULL);
CleanupSecurityAttributes(&saSecurityAttributes);
ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
// No error handling here! The calling function may wish
// to handle different situations in different ways. Save the error.
if(hFileHandle == INVALID_HANDLE_VALUE) {
return FALSE;
}
DWORD dwWriteCount; // Total bytes written during WriteFile
DWORD dwByteCount = _tcslen(m_pText) * sizeof(TCHAR);
// The hex pattern FFFE must be the first 2 characters of a Unicode text file
char unicodeMarker[3];
unicodeMarker[0] = '\xFF';
unicodeMarker[1] = '\xFE';
unicodeMarker[2] = NULL;
// write the Unicode marker
EF(WriteFile(hFileHandle, unicodeMarker, 2, &dwWriteCount, NULL));
// write the rest of the text block
EF(WriteFile(hFileHandle, m_pText, dwByteCount, &dwWriteCount, NULL));
CloseHandle(hFileHandle);
// Make sure we wrote the correct amount.
if (dwByteCount == dwWriteCount)
return TRUE;
return FALSE;
}
/*****************************************************************************************************************
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
ROUTINE DESCRIPTION:
GLOBAL VARIABLES:
None
INPUT:
None
RETURN:
None
*/
void
CTextBlock::WriteToBufferAndPad(
PTCHAR buffer,
UINT length
)
{
// concat and pad onto text buffer
m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%s"), buffer);
char outputBuffer[300];
int ret = WideCharToMultiByte(
GetACP(),
//CP_ACP,
0,
buffer,
-1,
outputBuffer,
sizeof(outputBuffer),
NULL,
NULL);
if (((int)length - (int)strlen(outputBuffer)) > 0) {
m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), length - strlen(outputBuffer), TEXT(""));
}
}