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

  1. /*****************************************************************************************************************
  2. FILENAME: TextBlock.cpp
  3. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  4. */
  5. #include "stdafx.h"
  6. #include <windows.h>
  7. #include <assert.h>
  8. #include <stdio.h>
  9. #include <stdarg.h>
  10. #include <locale.h>
  11. #include <tchar.h>
  12. #include "ErrMacro.h"
  13. #include "DfrgRes.h"
  14. #include "TextBlock.h"
  15. #include "secattr.h"
  16. #include <stdlib.h>
  17. PTCHAR
  18. CommafyNumberFloat(
  19. double number,
  20. BOOL bDecimal,
  21. PTCHAR stringBuffer,
  22. UINT stringBufferLength
  23. );
  24. /*****************************************************************************************************************
  25. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  26. ROUTINE DESCRIPTION:
  27. Constructor for CTextBlock
  28. GLOBAL VARIABLES:
  29. None
  30. INPUT:
  31. None
  32. RETURN:
  33. None
  34. */
  35. CTextBlock::CTextBlock(void)
  36. {
  37. // initialize
  38. m_isFixedWidth = m_isUseTabs = m_isUseCRLF = FALSE;
  39. m_colCount = m_currentCol = 0;
  40. m_hResource = NULL;
  41. m_pEndOfBuffer = m_pText = NULL;
  42. // Allocate 64K
  43. EV((m_hMemory = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, 0x10000)) != NULL);
  44. // Lock the memory and get the pointer
  45. m_pText = (PTCHAR) GlobalLock(m_hMemory);
  46. EV(m_pText);
  47. m_pEndOfBuffer = m_pText;
  48. }
  49. /*****************************************************************************************************************
  50. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  51. ROUTINE DESCRIPTION:
  52. GLOBAL VARIABLES:
  53. None
  54. INPUT:
  55. None
  56. RETURN:
  57. None
  58. */
  59. CTextBlock::~CTextBlock(void)
  60. {
  61. if (m_hMemory){
  62. EH_ASSERT(GlobalUnlock(m_hMemory) == FALSE);
  63. EH_ASSERT(GlobalFree(m_hMemory) == NULL);
  64. }
  65. }
  66. /*****************************************************************************************************************
  67. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  68. ROUTINE DESCRIPTION:
  69. GLOBAL VARIABLES:
  70. None
  71. INPUT:
  72. None
  73. RETURN:
  74. None
  75. */
  76. void
  77. __cdecl CTextBlock::WriteToBuffer(
  78. PTCHAR cFormat,
  79. ...
  80. )
  81. {
  82. // cannot have fixed width with no columns defined
  83. assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0));
  84. va_list argptr;
  85. va_start(argptr, cFormat); // init the argument list
  86. if (m_isFixedWidth){
  87. TCHAR buffer[4 * MAX_PATH];
  88. int num;
  89. // print the data into a temp buffer
  90. num = vswprintf(buffer, cFormat, argptr);
  91. assert(num < 4 * MAX_PATH);
  92. // concat and pad onto text buffer
  93. //m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), m_colWidth[m_currentCol], buffer);
  94. WriteToBufferAndPad(buffer, m_colWidth[m_currentCol]);
  95. }
  96. else{
  97. m_pEndOfBuffer += vswprintf(m_pEndOfBuffer, cFormat, argptr);
  98. }
  99. va_end(argptr);
  100. // increment the column counter
  101. m_currentCol++;
  102. }
  103. /*****************************************************************************************************************
  104. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  105. ROUTINE DESCRIPTION:
  106. GLOBAL VARIABLES:
  107. None
  108. INPUT:
  109. None
  110. RETURN:
  111. None
  112. */
  113. void
  114. CTextBlock::WriteToBufferLL(
  115. LONGLONG number
  116. )
  117. {
  118. // cannot have fixed width with no columns defined
  119. assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0));
  120. // convert to a string, putting commas in if needed
  121. TCHAR tmpBuffer[256];
  122. CommafyNumber(number, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR));
  123. if (m_isFixedWidth){
  124. // concat and pad onto text buffer
  125. WriteToBufferAndPad(tmpBuffer, m_colWidth[m_currentCol]);
  126. //m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), m_colWidth[m_currentCol], tmpBuffer);
  127. }
  128. else{
  129. m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, tmpBuffer);
  130. }
  131. // increment the column counter
  132. m_currentCol++;
  133. }
  134. /*****************************************************************************************************************
  135. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  136. ROUTINE DESCRIPTION:
  137. GLOBAL VARIABLES:
  138. None
  139. INPUT:
  140. None
  141. RETURN:
  142. None
  143. */
  144. void
  145. CTextBlock::WriteToBuffer(
  146. UINT resourceID
  147. )
  148. {
  149. // cannot have fixed width with no columns defined
  150. assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0));
  151. // must have assigned a handle to the resource
  152. assert(m_hResource);
  153. TCHAR buffer[256];
  154. EH_ASSERT(LoadString(m_hResource, resourceID, buffer, sizeof(buffer)/sizeof(TCHAR)));
  155. if (m_isFixedWidth){
  156. WriteToBufferAndPad(buffer, m_colWidth[m_currentCol]);
  157. }
  158. else{
  159. m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%s"), buffer);
  160. }
  161. // increment the column counter
  162. m_currentCol++;
  163. }
  164. /*****************************************************************************************************************
  165. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  166. ROUTINE DESCRIPTION:
  167. GLOBAL VARIABLES:
  168. None
  169. INPUT:
  170. None
  171. RETURN:
  172. None
  173. */
  174. void
  175. CTextBlock::SetColumnWidth(
  176. UINT col,
  177. UINT colWidth
  178. )
  179. {
  180. // cannot have fixed width with no columns defined
  181. assert(m_isFixedWidth);
  182. assert(m_colCount > 0);
  183. // the column number must be less than the column count
  184. assert(col < m_colCount);
  185. m_colWidth[col] = colWidth;
  186. }
  187. /*****************************************************************************************************************
  188. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  189. ROUTINE DESCRIPTION:
  190. GLOBAL VARIABLES:
  191. None
  192. INPUT:
  193. None
  194. RETURN:
  195. None
  196. */
  197. void
  198. CTextBlock::WriteTab(
  199. void
  200. )
  201. {
  202. // only write the tab if the tab feature has been turned on
  203. if (m_isUseTabs)
  204. m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\t"));
  205. }
  206. /*****************************************************************************************************************
  207. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  208. ROUTINE DESCRIPTION:
  209. GLOBAL VARIABLES:
  210. None
  211. INPUT:
  212. None
  213. RETURN:
  214. None
  215. */
  216. void
  217. CTextBlock::WriteNULL(
  218. void
  219. )
  220. {
  221. m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\0"));
  222. }
  223. /*****************************************************************************************************************
  224. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  225. ROUTINE DESCRIPTION:
  226. GLOBAL VARIABLES:
  227. None
  228. INPUT:
  229. None
  230. RETURN:
  231. None
  232. */
  233. void
  234. CTextBlock::EndOfLine(
  235. void
  236. )
  237. {
  238. // the first few lines here are to strip off trailing spaces
  239. PTCHAR pEOL = m_pEndOfBuffer-1;
  240. while (*pEOL == TEXT(' ') && pEOL != m_pText){
  241. pEOL--;
  242. }
  243. m_pEndOfBuffer = pEOL + 1;
  244. *m_pEndOfBuffer = NULL;
  245. // only write the tab if the tab feature has been turned on
  246. if (m_isUseCRLF)
  247. m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\r\n"));
  248. // reset the col counter to col 0 (start of next line)
  249. m_currentCol = 0;
  250. }
  251. /*****************************************************************************************************************
  252. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  253. ROUTINE DESCRIPTION:
  254. GLOBAL VARIABLES:
  255. None
  256. INPUT:
  257. None
  258. RETURN:
  259. None
  260. */
  261. void
  262. CTextBlock::WriteByteCount(
  263. LONGLONG number
  264. )
  265. {
  266. TCHAR buffer[256];
  267. // formats the number and appends the units
  268. FormatNumber(m_hResource, number, buffer);
  269. // write the number and units to the text block
  270. WriteToBuffer(buffer);
  271. }
  272. void
  273. CTextBlock::FormatNum(
  274. HINSTANCE hResource,
  275. LONGLONG number,
  276. PTCHAR buffer
  277. )
  278. {
  279. FormatNumber(hResource, number, buffer);
  280. }
  281. /***************************************************************************************************************
  282. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  283. DESCRIPTION:
  284. DATA STRUCTURES:
  285. None.
  286. GLOBALS:
  287. None.
  288. INPUT:
  289. RETURN:
  290. The number of characters written.
  291. 0 on error.
  292. */
  293. DWORD
  294. FormatNumber(
  295. HINSTANCE hResource,
  296. LONGLONG number,
  297. PTCHAR buffer
  298. )
  299. {
  300. UINT resourceID = IDS_UNITS_GB;
  301. double numberFloat = 0;
  302. BOOL bDecimal = FALSE;
  303. numberFloat = (double) number;
  304. __try{
  305. //Byte range.
  306. if (number < 1024){
  307. resourceID = IDS_UNITS_BYTES;
  308. __leave;
  309. }
  310. // KB range
  311. numberFloat = (double) number / 1024;
  312. if (numberFloat < 1024){
  313. resourceID = IDS_UNITS_KB;
  314. __leave;
  315. }
  316. // MB range
  317. numberFloat /= 1024;
  318. if (numberFloat < 1024){
  319. resourceID = IDS_UNITS_MB;
  320. __leave;
  321. }
  322. // GB range
  323. //This is the default range that we will display, so we dont need to test number
  324. numberFloat /= 1024;
  325. resourceID = IDS_UNITS_GB;
  326. if (numberFloat < 100) {
  327. bDecimal = TRUE;
  328. }
  329. __leave;
  330. }
  331. __finally {
  332. // load the "units" string from resources
  333. TCHAR units[30];
  334. EH_ASSERT(LoadString(hResource, resourceID, units, sizeof(units)/sizeof(TCHAR)));
  335. // convert to a string, putting commas in if needed
  336. TCHAR tmpBuffer[256];
  337. CommafyNumberFloat(numberFloat, bDecimal, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR));
  338. // concat a spacer
  339. _tcscat(tmpBuffer, TEXT(" "));
  340. // concat the units
  341. _tcscat(tmpBuffer, units);
  342. // write the number and units to the text block
  343. _tcscpy(buffer, tmpBuffer);
  344. }
  345. return _tcslen(buffer);
  346. }
  347. DWORD
  348. FormatNumberMB(
  349. HINSTANCE hResource,
  350. LONGLONG number,
  351. PTCHAR buffer
  352. )
  353. {
  354. // MB range
  355. double numberMB = (double) (number / 0x100000); // 1 MB
  356. UINT resourceID = IDS_UNITS_MB;
  357. BOOL decimal = FALSE;
  358. // if it turned out to be 0, switch over to KB
  359. if (numberMB < 1){
  360. numberMB = (double) number / 1024; // 1 KB
  361. resourceID = IDS_UNITS_KB;
  362. }
  363. else if (numberMB > 1024){ // if it is greater than 1024 MB, switch to GB
  364. numberMB /= 1024;
  365. resourceID = IDS_UNITS_GB;
  366. if (numberMB < 100) {
  367. decimal = TRUE;
  368. }
  369. }
  370. // load the "units" string from resources
  371. TCHAR units[30];
  372. EH_ASSERT(LoadString(hResource, resourceID, units, sizeof(units)/sizeof(TCHAR)));
  373. // convert to a string, putting commas in if needed
  374. TCHAR tmpBuffer[256];
  375. CommafyNumberFloat(numberMB, decimal, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR));
  376. // concat a spacer
  377. _tcscat(tmpBuffer, TEXT(" "));
  378. // concat the units
  379. _tcscat(tmpBuffer, units);
  380. // write the number and units to the text block
  381. _tcscpy(buffer, tmpBuffer);
  382. return _tcslen(buffer);
  383. }
  384. /***************************************************************************************************************
  385. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  386. DESCRIPTION:
  387. This takes the source string and works from right to left,
  388. copying chars from the source to the target, adding commas
  389. every third character
  390. DATA STRUCTURES:
  391. None.
  392. GLOBALS:
  393. None.
  394. INPUT:
  395. RETURN:
  396. Pointer to buffer with commafied number or NULL if error
  397. */
  398. PTCHAR
  399. CommafyNumber(
  400. LONGLONG number,
  401. PTCHAR stringBuffer,
  402. UINT stringBufferLength
  403. )
  404. {
  405. EN_ASSERT(stringBuffer);
  406. EN_ASSERT(stringBufferLength);
  407. TCHAR sourceString[256];
  408. TCHAR targetString[256];
  409. TCHAR tcThousandsSep[2] = {TEXT(','), 0};
  410. struct lconv *locals = localeconv();
  411. if (locals && (locals->thousands_sep) && (*(locals->thousands_sep) != 0)) {
  412. _stprintf(tcThousandsSep, TEXT("%C"), *(locals->thousands_sep));
  413. }
  414. UINT uGrouping = 0;
  415. if (locals && (locals->grouping)) {
  416. uGrouping = atoi(locals->grouping);
  417. }
  418. if(uGrouping == 0)
  419. {
  420. uGrouping = 3; //default value if its not supported
  421. }
  422. // convert LONGLONG number to a Unicode string
  423. _stprintf(sourceString, TEXT("%I64d"), number);
  424. // point the source pointer at the null terminator
  425. PTCHAR pSource = sourceString + _tcslen(sourceString);
  426. // put the target pointer at the end of the target buffer
  427. PTCHAR pTarget = targetString + sizeof(targetString) / sizeof(TCHAR) - 1;
  428. // write the null terminator
  429. *pTarget = NULL;
  430. for (UINT i=0; i<_tcslen(sourceString); i++) {
  431. if (i>0 && i%uGrouping == 0) {
  432. pTarget--;
  433. *pTarget = tcThousandsSep[0];
  434. }
  435. pTarget--;
  436. pSource--;
  437. *pTarget = *pSource;
  438. }
  439. if (stringBufferLength > _tcslen(pTarget)){
  440. _tcscpy(stringBuffer, pTarget);
  441. }
  442. else{
  443. _tcscpy(stringBuffer, TEXT(""));
  444. }
  445. return stringBuffer;
  446. }
  447. /***************************************************************************************************************
  448. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  449. DESCRIPTION:
  450. This takes the source string and works from right to left,
  451. copying chars from the source to the target, adding commas
  452. every third character
  453. DATA STRUCTURES:
  454. None.
  455. GLOBALS:
  456. None.
  457. INPUT:
  458. RETURN:
  459. Pointer to buffer with commafied number or NULL if error
  460. */
  461. PTCHAR
  462. CommafyNumberFloat(
  463. double number,
  464. BOOL bDecimal,
  465. PTCHAR stringBuffer,
  466. UINT stringBufferLength
  467. )
  468. {
  469. EN_ASSERT(stringBuffer);
  470. EN_ASSERT(stringBufferLength);
  471. TCHAR sourceString[256];
  472. TCHAR targetString[256];
  473. TCHAR tcThousandsSep[2] = {TEXT(','), 0};
  474. struct lconv *locals = localeconv();
  475. if (locals && (locals->thousands_sep) && (*(locals->thousands_sep) != 0)) {
  476. _stprintf(tcThousandsSep, TEXT("%C"), *(locals->thousands_sep));
  477. }
  478. UINT uGrouping = 0;
  479. if (locals && (locals->grouping)) {
  480. uGrouping = atoi(locals->grouping);
  481. }
  482. if(uGrouping == 0)
  483. {
  484. uGrouping = 3; //default value if its not supported
  485. }
  486. if (bDecimal) {
  487. // convert double number to a Unicode string
  488. _stprintf(sourceString, TEXT("%0.02f"), number);
  489. }
  490. else {
  491. // convert double number to a Unicode string
  492. _stprintf(sourceString, TEXT("%0.0f"), number);
  493. }
  494. // point the source pointer at the null terminator
  495. PTCHAR pSource = sourceString + _tcslen(sourceString);
  496. // put the target pointer at the end of the target buffer
  497. PTCHAR pTarget = targetString + sizeof(targetString) / sizeof(TCHAR) - 1;
  498. // write the null terminator
  499. *pTarget = NULL;
  500. if (bDecimal) {
  501. for (UINT j = 0; j < 3; j++) {
  502. pTarget--;
  503. pSource--;
  504. *pTarget = *pSource;
  505. }
  506. }
  507. for (UINT i=0; i<_tcslen(sourceString)-(bDecimal ? 3 : 0); i++) {
  508. if (i>0 && i%uGrouping == 0) {
  509. pTarget--;
  510. *pTarget = tcThousandsSep[0];
  511. }
  512. pTarget--;
  513. pSource--;
  514. *pTarget = *pSource;
  515. }
  516. if (stringBufferLength > _tcslen(pTarget)){
  517. _tcscpy(stringBuffer, pTarget);
  518. }
  519. else{
  520. _tcscpy(stringBuffer, TEXT(""));
  521. }
  522. return stringBuffer;
  523. }
  524. /***************************************************************************************************************
  525. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  526. DESCRIPTION:
  527. DATA STRUCTURES:
  528. None.
  529. GLOBALS:
  530. None.
  531. INPUT:
  532. RETURN:
  533. */
  534. BOOL CTextBlock::StoreFile(
  535. IN TCHAR* cStoreFileName,
  536. IN DWORD dwCreate
  537. )
  538. {
  539. HANDLE hFileHandle = NULL;
  540. SECURITY_ATTRIBUTES saSecurityAttributes;
  541. SECURITY_DESCRIPTOR sdSecurityDescriptor;
  542. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  543. saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
  544. saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
  545. saSecurityAttributes.bInheritHandle = FALSE;
  546. if (!ConstructSecurityAttributes(&saSecurityAttributes, esatFile, FALSE)) {
  547. return FALSE;
  548. }
  549. // Create a new file for this text
  550. hFileHandle = CreateFile(
  551. cStoreFileName,
  552. GENERIC_WRITE,
  553. 0, // no sharing
  554. &saSecurityAttributes,
  555. dwCreate,
  556. FILE_ATTRIBUTE_NORMAL,
  557. NULL);
  558. CleanupSecurityAttributes(&saSecurityAttributes);
  559. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  560. // No error handling here! The calling function may wish
  561. // to handle different situations in different ways. Save the error.
  562. if(hFileHandle == INVALID_HANDLE_VALUE) {
  563. return FALSE;
  564. }
  565. DWORD dwWriteCount; // Total bytes written during WriteFile
  566. DWORD dwByteCount = _tcslen(m_pText) * sizeof(TCHAR);
  567. // The hex pattern FFFE must be the first 2 characters of a Unicode text file
  568. char unicodeMarker[3];
  569. unicodeMarker[0] = '\xFF';
  570. unicodeMarker[1] = '\xFE';
  571. unicodeMarker[2] = NULL;
  572. // write the Unicode marker
  573. EF(WriteFile(hFileHandle, unicodeMarker, 2, &dwWriteCount, NULL));
  574. // write the rest of the text block
  575. EF(WriteFile(hFileHandle, m_pText, dwByteCount, &dwWriteCount, NULL));
  576. CloseHandle(hFileHandle);
  577. // Make sure we wrote the correct amount.
  578. if (dwByteCount == dwWriteCount)
  579. return TRUE;
  580. return FALSE;
  581. }
  582. /*****************************************************************************************************************
  583. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  584. ROUTINE DESCRIPTION:
  585. GLOBAL VARIABLES:
  586. None
  587. INPUT:
  588. None
  589. RETURN:
  590. None
  591. */
  592. void
  593. CTextBlock::WriteToBufferAndPad(
  594. PTCHAR buffer,
  595. UINT length
  596. )
  597. {
  598. // concat and pad onto text buffer
  599. m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%s"), buffer);
  600. char outputBuffer[300];
  601. int ret = WideCharToMultiByte(
  602. GetACP(),
  603. //CP_ACP,
  604. 0,
  605. buffer,
  606. -1,
  607. outputBuffer,
  608. sizeof(outputBuffer),
  609. NULL,
  610. NULL);
  611. if (((int)length - (int)strlen(outputBuffer)) > 0) {
  612. m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), length - strlen(outputBuffer), TEXT(""));
  613. }
  614. }