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.

215 lines
4.8 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: filesize.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include "filesize.h"
  13. #include "util.h"
  14. #include <resource.h>
  15. //-----------------------------------------------------------------------------
  16. // class FileSize
  17. //-----------------------------------------------------------------------------
  18. //
  19. // Static array of file size "order" string IDs.
  20. // These IDs identify the "%1 KB", "%1 MB", "%1 GB" resource strings.
  21. //
  22. int FileSize::m_rgiOrders[IDS_ORDER_EB - IDS_ORDER_BYTES + 1];
  23. FileSize::FileSize(
  24. ULONGLONG ullSize
  25. ) : m_ullSize(ullSize)
  26. {
  27. TraceAssert(IDS_ORDER_BYTES != 0);
  28. if (0 == m_rgiOrders[0])
  29. {
  30. //
  31. // Initialize the static array of file size "order" string IDs.
  32. //
  33. for (int i = IDS_ORDER_BYTES; i <= IDS_ORDER_EB; i++)
  34. {
  35. m_rgiOrders[i - IDS_ORDER_BYTES] = i;
  36. }
  37. }
  38. }
  39. //
  40. // FileSize assignment.
  41. //
  42. FileSize&
  43. FileSize::operator = (
  44. const FileSize& rhs
  45. )
  46. {
  47. if (this != &rhs)
  48. {
  49. m_ullSize = rhs.m_ullSize;
  50. }
  51. return *this;
  52. }
  53. //
  54. // The following code for converting a file size value to a text
  55. // string (i.e. "10.5 MB") was taken from shell32.dll so that file size
  56. // values would match those displayed in shell views. The code isn't
  57. // my normal style but I left it "as is" so I wouldn't break it. [brianau]
  58. //
  59. const int MAX_INT64_SIZE = 30;
  60. const int MAX_COMMA_NUMBER_SIZE = MAX_INT64_SIZE + 10;
  61. //
  62. // Convert a ULONGLONG file size value to a text string.
  63. //
  64. void
  65. FileSize::CvtSizeToText(
  66. ULONGLONG n,
  67. LPTSTR pszBuffer
  68. ) const
  69. {
  70. TCHAR szTemp[MAX_INT64_SIZE];
  71. ULONGLONG iChr;
  72. iChr = 0;
  73. do {
  74. szTemp[iChr++] = (TCHAR)(TEXT('0') + (TCHAR)(n % 10));
  75. n = n / 10;
  76. } while (n != 0);
  77. do {
  78. iChr--;
  79. *pszBuffer++ = szTemp[iChr];
  80. } while (iChr != 0);
  81. *pszBuffer++ = '\0';
  82. }
  83. //
  84. // Convert a string to an integer (taken from shlwapi.dll).
  85. //
  86. int
  87. FileSize::StrToInt(
  88. LPCTSTR lpSrc
  89. ) const
  90. {
  91. int n = 0;
  92. BOOL bNeg = FALSE;
  93. if (*lpSrc == TEXT('-')) {
  94. bNeg = TRUE;
  95. lpSrc++;
  96. }
  97. while (IsDigit(*lpSrc)) {
  98. n *= 10;
  99. n += *lpSrc - TEXT('0');
  100. lpSrc++;
  101. }
  102. return bNeg ? -n : n;
  103. }
  104. //
  105. // Add commas where necessary to a number with more than 3 digits.
  106. //
  107. LPTSTR
  108. FileSize::AddCommas(
  109. ULONGLONG n,
  110. LPTSTR pszResult,
  111. int cchResult
  112. ) const
  113. {
  114. TCHAR szTemp[MAX_COMMA_NUMBER_SIZE];
  115. TCHAR szSep[5];
  116. NUMBERFMT nfmt;
  117. nfmt.NumDigits=0;
  118. nfmt.LeadingZero=0;
  119. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
  120. nfmt.Grouping = StrToInt(szSep);
  121. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
  122. nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
  123. nfmt.NegativeOrder= 0;
  124. CvtSizeToText(n, szTemp);
  125. if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, cchResult) == 0)
  126. lstrcpy(pszResult, szTemp);
  127. return pszResult;
  128. }
  129. //
  130. // Format a file size value as a text string suitable for viewing.
  131. //
  132. void
  133. FileSize::Format(
  134. ULONGLONG ullSize,
  135. LPTSTR pszFS,
  136. UINT cchFS
  137. ) const
  138. {
  139. TraceAssert(NULL != pszFS);
  140. TraceAssert(0 < cchFS);
  141. int i;
  142. ULONGLONG wInt;
  143. ULONGLONG dw64 = ullSize;
  144. UINT wLen, wDec;
  145. TCHAR szTemp[MAX_COMMA_NUMBER_SIZE], szFormat[5];
  146. if (dw64 < 1000)
  147. {
  148. wsprintf(szTemp, TEXT("%d"), (DWORD)(dw64));
  149. i = 0;
  150. }
  151. else
  152. {
  153. int cOrders = ARRAYSIZE(m_rgiOrders);
  154. for (i = 1; i < cOrders - 1 && dw64 >= 1000L * 1024L; dw64 >>= 10, i++);
  155. /* do nothing */
  156. wInt = dw64 >> 10;
  157. AddCommas(wInt, szTemp, ARRAYSIZE(szTemp));
  158. wLen = lstrlen(szTemp);
  159. if (wLen < 3)
  160. {
  161. wDec = ((DWORD)(dw64 - wInt * 1024L)) * 1000 / 1024;
  162. // At this point, wDec should be between 0 and 1000
  163. // we want get the top one (or two) digits.
  164. wDec /= 10;
  165. if (wLen == 2)
  166. wDec /= 10;
  167. // Note that we need to set the format before getting the
  168. // intl char.
  169. lstrcpy(szFormat, TEXT("%02d"));
  170. szFormat[2] = (TCHAR)(TEXT('0') + 3 - wLen);
  171. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
  172. szTemp+wLen, ARRAYSIZE(szTemp)-wLen);
  173. wLen = lstrlen(szTemp);
  174. wLen += wsprintf(szTemp+wLen, szFormat, wDec);
  175. }
  176. }
  177. *pszFS = TEXT('\0');
  178. LPTSTR pszText;
  179. if (0 < FormatStringID(&pszText, g_hInstance, m_rgiOrders[i], szTemp))
  180. {
  181. lstrcpyn(pszFS, pszText, cchFS);
  182. LocalFree(pszText);
  183. }
  184. }