From 4e90ccc7d91d9b493552fd3cbdaf1f388052c19f Mon Sep 17 00:00:00 2001 From: wj32 Date: Sun, 3 Oct 2010 03:58:03 +0000 Subject: [PATCH] added alignment support to PhFormat git-svn-id: svn://svn.code.sf.net/p/processhacker/code@3719 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- 2.x/trunk/phlib/format.c | 41 +++++--- 2.x/trunk/phlib/format_i.h | 167 +++++++++++++++++++++++++++---- 2.x/trunk/phlib/include/phbase.h | 38 +++++-- 2.x/trunk/phlib/support.c | 13 ++- 4 files changed, 215 insertions(+), 44 deletions(-) diff --git a/2.x/trunk/phlib/format.c b/2.x/trunk/phlib/format.c index 613c006c2..8372298a0 100644 --- a/2.x/trunk/phlib/format.c +++ b/2.x/trunk/phlib/format.c @@ -34,7 +34,9 @@ extern ULONG PhMaxSizeUnit; #define SMALL_BUFFER_LENGTH (PHOBJ_SMALL_OBJECT_SIZE - FIELD_OFFSET(PH_STRING, Buffer) - sizeof(WCHAR)) #define BUFFER_SIZE 512 -#define PHP_FORMAT_NEGATIVE 0x1000 +#define PHP_FORMAT_NEGATIVE 0x1 +#define PHP_FORMAT_POSITIVE 0x2 +#define PHP_FORMAT_PAD 0x4 // Internal CRT routines needed for floating-point conversion @@ -61,6 +63,31 @@ static WCHAR PhpFormatDecimalSeparator = '.'; static WCHAR PhpFormatThousandSeparator = ','; static _locale_t PhpFormatUserLocale = NULL; +PPH_STRING PhpResizeFormatBuffer( + __in PPH_STRING String, + __inout PSIZE_T AllocatedLength, + __in SIZE_T UsedLength, + __in SIZE_T NeededLength + ) +{ + PPH_STRING newString; + SIZE_T allocatedLength; + + allocatedLength = *AllocatedLength; + allocatedLength *= 2; + + if (allocatedLength < UsedLength + NeededLength) + allocatedLength = UsedLength + NeededLength; + + newString = PhCreateStringEx(NULL, allocatedLength); + memcpy(newString->Buffer, String->Buffer, UsedLength); + PhDereferenceObject(String); + + *AllocatedLength = allocatedLength; + + return newString; +} + PPH_STRING PhFormat( __in PPH_FORMAT Format, __in ULONG Count, @@ -90,17 +117,7 @@ PPH_STRING PhFormat( do { \ if (allocatedLength < usedLength + (NeededLength)) \ { \ - PPH_STRING newString; \ - \ - allocatedLength *= 2; \ - \ - if (allocatedLength < usedLength + (NeededLength)) \ - allocatedLength = usedLength + (NeededLength); \ - \ - newString = PhCreateStringEx(NULL, allocatedLength); \ - memcpy(newString->Buffer, string->Buffer, usedLength); \ - PhDereferenceObject(string); \ - string = newString; \ + string = PhpResizeFormatBuffer(string, &allocatedLength, usedLength, (NeededLength)); \ buffer = string->Buffer + usedLength / sizeof(WCHAR); \ } \ } while (0) diff --git a/2.x/trunk/phlib/format_i.h b/2.x/trunk/phlib/format_i.h index 3b3003a72..d0b8cfa8f 100644 --- a/2.x/trunk/phlib/format_i.h +++ b/2.x/trunk/phlib/format_i.h @@ -127,6 +127,8 @@ PWSTR temp; \ ULONG tempCount; \ ULONG r; \ + ULONG preCount; \ + ULONG padCount; \ \ radix = 10; \ if (((Format)->Type & FormatUseRadix) && (Format)->Radix >= 2 && (Format)->Radix <= 69) \ @@ -169,22 +171,42 @@ tempCount++; \ } \ \ + preCount = 0; \ + \ if (flags & PHP_FORMAT_NEGATIVE) \ - { \ - *temp-- = '-'; \ - tempCount++; \ - } \ + preCount++; \ else if ((Format)->Type & FormatPrefixSign) \ + preCount++; \ + \ + if (((Format)->Type & FormatPadZeros) && !((Format)->Type & FormatGroupDigits)) \ { \ - *temp-- = '+'; \ - tempCount++; \ + if (preCount + tempCount < (Format)->Width) \ + { \ + flags |= PHP_FORMAT_PAD; \ + padCount = (Format)->Width - (preCount + tempCount); \ + preCount += padCount; \ + } \ } \ \ temp++; \ - ENSURE_BUFFER(tempCount * sizeof(WCHAR)); \ + ENSURE_BUFFER((preCount + tempCount) * sizeof(WCHAR)); \ if (OK_BUFFER) \ + { \ + if (flags & PHP_FORMAT_NEGATIVE) \ + *buffer++ = '-'; \ + else if ((Format)->Type & FormatPrefixSign) \ + *buffer++ = '+'; \ + \ + if (flags & PHP_FORMAT_PAD) \ + { \ + wmemset(buffer, '0', padCount); \ + buffer += padCount; \ + } \ + \ memcpy(buffer, temp, tempCount * sizeof(WCHAR)); \ - ADVANCE_BUFFER(tempCount * sizeof(WCHAR)); \ + buffer += tempCount; \ + } \ + usedLength += (preCount + tempCount) * sizeof(WCHAR); \ } while (0) #ifdef _M_IX86 @@ -241,14 +263,15 @@ CommonInt64Format: ULONG precision; \ DOUBLE value; \ CHAR c; \ + PSTR temp; \ ULONG length; \ \ if ((Format)->Type & FormatUsePrecision) \ { \ precision = (Format)->Precision; \ \ - if (precision > BUFFER_SIZE - _CVTBUFSIZE) \ - precision = BUFFER_SIZE - _CVTBUFSIZE; \ + if (precision > BUFFER_SIZE - 1 - _CVTBUFSIZE) \ + precision = BUFFER_SIZE - 1 - _CVTBUFSIZE; \ } \ else \ { \ @@ -268,10 +291,11 @@ CommonInt64Format: /* Use MS CRT routines to do the work. */ \ \ value = (Format)->u.Double; \ + temp = (PSTR)tempBuffer + 1; /* leave one character so we can insert a prefix if needed */ \ _cfltcvt_l( \ &value, \ - (PSTR)tempBuffer, \ - sizeof(tempBuffer), \ + temp, \ + sizeof(tempBuffer) - 1, \ c, \ precision, \ !!((Format)->Type & FormatUpperCase), \ @@ -281,9 +305,20 @@ CommonInt64Format: /* if (((Format)->Type & FormatForceDecimalPoint) && precision == 0) */ \ /* _forcdecpt_l(tempBufferAnsi, PhpFormatUserLocale); */ \ if ((Format)->Type & FormatCropZeros) \ - _cropzeros_l((PSTR)tempBuffer, PhpFormatUserLocale); \ + _cropzeros_l(temp, PhpFormatUserLocale); \ \ - length = (ULONG)strlen((PSTR)tempBuffer); \ + length = (ULONG)strlen(temp); \ + \ + if (temp[0] == '-') \ + { \ + flags |= PHP_FORMAT_NEGATIVE; \ + temp++; \ + length--; \ + } \ + else if ((Format)->Type & FormatPrefixSign) \ + { \ + flags |= PHP_FORMAT_POSITIVE; \ + } \ \ if (((Format)->Type & FormatGroupDigits) && !((Format)->Type & (FormatStandardForm | FormatHexadecimalForm))) \ { \ @@ -291,14 +326,15 @@ CommonInt64Format: PSTR decimalPoint; \ ULONG wholeCount; \ ULONG sepsCount; \ + ULONG ensureLength; \ ULONG copyCount; \ ULONG needsSep; \ \ /* Find the first non-digit character and assume that is the */ \ /* decimal point (or the end of the string). */ \ \ - whole = (PSTR)tempBuffer; \ - decimalPoint = (PSTR)tempBuffer; \ + whole = temp; \ + decimalPoint = temp; \ \ while ((UCHAR)(*decimalPoint - '0') < 10) \ decimalPoint++; \ @@ -306,20 +342,28 @@ CommonInt64Format: /* Copy the characters to the output buffer, and at the same time */ \ /* insert the separators. */ \ \ - wholeCount = (ULONG)(decimalPoint - (PSTR)tempBuffer); \ + wholeCount = (ULONG)(decimalPoint - temp); \ \ if (wholeCount != 0) \ sepsCount = (wholeCount + 2) / 3 - 1; \ else \ sepsCount = 0; \ \ - ENSURE_BUFFER((length + sepsCount) * sizeof(WCHAR)); \ + ensureLength = (length + sepsCount) * sizeof(WCHAR); \ + if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ + ensureLength += sizeof(WCHAR); \ + ENSURE_BUFFER(ensureLength); \ \ copyCount = wholeCount; \ needsSep = (wholeCount + 2) % 3; \ \ if (OK_BUFFER) \ { \ + if (flags & PHP_FORMAT_NEGATIVE) \ + *buffer++ = '-'; \ + else if (flags & PHP_FORMAT_POSITIVE) \ + *buffer++ = '+'; \ + \ while (copyCount--) \ { \ *buffer++ = *whole++; \ @@ -332,6 +376,8 @@ CommonInt64Format: } \ } \ \ + if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ + usedLength += sizeof(WCHAR); \ usedLength += (wholeCount + sepsCount) * sizeof(WCHAR); \ \ /* Copy the rest. */ \ @@ -351,16 +397,50 @@ CommonInt64Format: } \ else \ { \ + SIZE_T preLength; \ + SIZE_T padLength; \ + \ + /* Take care of the sign and zero padding. */ \ + preLength = 0; \ + \ + if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ + preLength++; \ + \ + if ((Format)->Type & FormatPadZeros) \ + { \ + if (preLength + length < (Format)->Width) \ + { \ + flags |= PHP_FORMAT_PAD; \ + padLength = (Format)->Width - (preLength + length); \ + preLength += padLength; \ + } \ + } \ /* We don't need to group digits, so directly copy the characters */ \ /* to the output buffer. */ \ \ - ENSURE_BUFFER(length * sizeof(WCHAR)); \ + ENSURE_BUFFER((preLength + length) * sizeof(WCHAR)); \ + \ + if (OK_BUFFER) \ + { \ + if (flags & PHP_FORMAT_NEGATIVE) \ + *buffer++ = '-'; \ + else if (flags & PHP_FORMAT_POSITIVE) \ + *buffer++ = '+'; \ + \ + if (flags & PHP_FORMAT_PAD) \ + { \ + wmemset(buffer, '0', padLength); \ + buffer += padLength; \ + } \ + } \ + \ + usedLength += preLength * sizeof(WCHAR); \ \ if (!OK_BUFFER || NT_SUCCESS(RtlMultiByteToUnicodeN( \ buffer, \ length * sizeof(WCHAR), \ NULL, \ - (PSTR)tempBuffer, \ + (PSTR)temp, \ length \ ))) \ { \ @@ -370,6 +450,7 @@ CommonInt64Format: } while (0) case DoubleFormatType: + flags = 0; COMMON_DOUBLE_FORMAT(format); break; @@ -412,7 +493,9 @@ CommonInt64Format: doubleFormat.Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros | FormatGroupDigits; doubleFormat.Precision = 2; + doubleFormat.Width = 0; // stupid compiler doubleFormat.u.Double = s; + flags = 0; COMMON_DOUBLE_FORMAT(&doubleFormat); ENSURE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length); @@ -428,5 +511,49 @@ CommonInt64Format: ContinueLoop: partLength = usedLength - partLength; + + if (format->Type & (FormatLeftAlign | FormatRightAlign)) + { + SIZE_T newLength; + SIZE_T addLength; + + newLength = format->Width * sizeof(WCHAR); + + // We only pad and never truncate. + if (partLength < newLength) + { + addLength = newLength - partLength; + ENSURE_BUFFER(addLength); + + if (OK_BUFFER) + { + WCHAR pad; + + if (format->Type & FormatUsePad) + pad = format->Pad; + else + pad = ' '; + + if (format->Type & FormatLeftAlign) + { + // Left alignment is easy; we just fill the remaining space + // with the pad character. + wmemset(buffer, pad, addLength / sizeof(WCHAR)); + } + else + { + PWSTR start; + + // Right alignment is much slower and involves moving the + // text forward, then filling in the space before it. + start = buffer - partLength / sizeof(WCHAR); + memmove(start + addLength / sizeof(WCHAR), start, partLength); + wmemset(start, pad, addLength / sizeof(WCHAR)); + } + } + + ADVANCE_BUFFER(addLength); + } + } } } diff --git a/2.x/trunk/phlib/include/phbase.h b/2.x/trunk/phlib/include/phbase.h index 06cd54ede..0e960eea2 100644 --- a/2.x/trunk/phlib/include/phbase.h +++ b/2.x/trunk/phlib/include/phbase.h @@ -2999,26 +2999,44 @@ typedef enum _PH_FORMAT_TYPE UIntPtrFormatType, DoubleFormatType, SizeFormatType, - FormatTypeMask = 0xff, + FormatTypeMask = 0x3f, - FormatUsePrecision = 0x100, - FormatUseWidth = 0x200, - FormatUseRadix = 0x400, + /** If not specified, for floating-point 6 is assumed **/ + FormatUsePrecision = 0x40, + /** If not specified, ' ' is assumed */ + FormatUsePad = 0x80, + /** If not specified, 10 is assumed */ + FormatUseRadix = 0x100, + /** Reserved */ + FormatUseReserved = 0x200, // Floating-point flags - FormatStandardForm = 0x1000, // Use standard form instead of normal form - FormatHexadecimalForm = 0x2000, // Use hexadecimal form instead of normal form - FormatForceDecimalPoint = 0x4000, // Reserved + /** Use standard form instead of normal form */ + FormatStandardForm = 0x1000, + /** Use hexadecimal form instead of normal form */ + FormatHexadecimalForm = 0x2000, + /** Reserved */ + FormatForceDecimalPoint = 0x4000, + /** Trailing zeros and possibly the decimal point are trimmed */ FormatCropZeros = 0x8000, // Floating-point and integer flags - FormatGroupDigits = 0x10000, // Group digits (with floating-point, only works when in normal form) - FormatPrefixSign = 0x20000, // Always insert a prefix, '+' for positive and '-' for negative + /** Group digits (with floating-point, only works when in normal form) */ + FormatGroupDigits = 0x10000, + /** Always insert a prefix, '+' for positive and '-' for negative */ + FormatPrefixSign = 0x20000, + /** Pad left with zeros, taking into consideration the sign. Width must be specified. + * Format*Align cannot be used in conjunction with this flag. If FormatGroupDigits is specified, + * this flag is ignored. */ + FormatPadZeros = 0x40000, // General flags + /** Applies left alignment. Width must be specified. */ FormatLeftAlign = 0x80000000, + /** Applies right alignment. Width must be specified. */ FormatRightAlign = 0x40000000, - FormatUpperCase = 0x20000000 // Make characters uppercase (only available for some types) + /** Make characters uppercase (only available for some types) */ + FormatUpperCase = 0x20000000 } PH_FORMAT_TYPE; typedef struct _PH_FORMAT diff --git a/2.x/trunk/phlib/support.c b/2.x/trunk/phlib/support.c index 88ba8ccfb..97919b6ef 100644 --- a/2.x/trunk/phlib/support.c +++ b/2.x/trunk/phlib/support.c @@ -1426,10 +1426,19 @@ PPH_STRING PhGetFileVersionInfoString2( ) { WCHAR subBlock[65]; + PH_FORMAT format[4]; - _snwprintf(subBlock, 64, L"\\StringFileInfo\\%08X\\%s", LangCodePage, StringName); + PhInitFormatS(&format[0], L"\\StringFileInfo\\"); + PhInitFormatX(&format[1], LangCodePage); + format[1].Type |= FormatPadZeros | FormatUpperCase; + format[1].Width = 8; + PhInitFormatC(&format[2], '\\'); + PhInitFormatS(&format[3], StringName); - return PhGetFileVersionInfoString(VersionInfo, subBlock); + if (PhFormatToBuffer(format, 4, subBlock, sizeof(subBlock), NULL)) + return PhGetFileVersionInfoString(VersionInfo, subBlock); + else + return NULL; } BOOLEAN PhInitializeImageVersionInfo(