Leaked source code of windows server 2003
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.

312 lines
11 KiB

  1. #include "priv.h"
  2. #include "ids.h"
  3. #include <mluisupp.h>
  4. #ifndef DATE_LTRREADING
  5. #define DATE_LTRREADING 0x00000010 //FEATURE: figure out why we have to do this, and fix it.
  6. #define DATE_RTLREADING 0x00000020
  7. #endif
  8. /*-------------------------------------------------------------------------
  9. Purpose: Calls GetDateFormat and tries to replace the day with
  10. a relative reference like "Today" or "Yesterday".
  11. Returns the count of characters written to pszBuf.
  12. */
  13. int GetRelativeDateFormat(
  14. DWORD dwDateFlags,
  15. DWORD * pdwFlags,
  16. SYSTEMTIME * pstDate,
  17. LPWSTR pszBuf,
  18. int cchBuf)
  19. {
  20. int cch;
  21. ASSERT(pdwFlags);
  22. ASSERT(pstDate);
  23. ASSERT(pszBuf);
  24. // Assume that no relative date is applied, so clear the bit
  25. // for now.
  26. *pdwFlags &= ~FDTF_RELATIVE;
  27. // Get the Win32 date format. (GetDateFormat's return value includes
  28. // the null terminator.)
  29. cch = GetDateFormat(LOCALE_USER_DEFAULT, dwDateFlags, pstDate, NULL, pszBuf, cchBuf);
  30. if (0 < cch)
  31. {
  32. SYSTEMTIME stCurrentTime;
  33. int iDay = 0; // 1 = today, -1 = yesterday, 0 = neither today nor yesterday.
  34. // Now see if the date merits a replacement to "Yesterday" or "Today".
  35. GetLocalTime(&stCurrentTime); // get the current date
  36. // Does it match the current day?
  37. if (pstDate->wYear == stCurrentTime.wYear &&
  38. pstDate->wMonth == stCurrentTime.wMonth &&
  39. pstDate->wDay == stCurrentTime.wDay)
  40. {
  41. // Yes
  42. iDay = 1;
  43. }
  44. else
  45. {
  46. // No; maybe it matches yesterday
  47. FILETIME ftYesterday;
  48. SYSTEMTIME stYesterday;
  49. // Compute yesterday's date by converting to FILETIME,
  50. // subtracting one day, then converting back.
  51. SystemTimeToFileTime(&stCurrentTime, &ftYesterday);
  52. DecrementFILETIME(&ftYesterday, FT_ONEDAY);
  53. FileTimeToSystemTime(&ftYesterday, &stYesterday);
  54. // Does it match yesterday?
  55. if (pstDate->wYear == stYesterday.wYear &&
  56. pstDate->wMonth == stYesterday.wMonth &&
  57. pstDate->wDay == stYesterday.wDay)
  58. {
  59. // Yes
  60. iDay = -1;
  61. }
  62. }
  63. // Should we try replacing the day?
  64. if (0 != iDay)
  65. {
  66. // Yes
  67. TCHAR szDayOfWeek[32];
  68. LPTSTR pszModifier;
  69. int cchDayOfWeek;
  70. cchDayOfWeek = MLLoadString((IDS_DAYSOFTHEWEEK + pstDate->wDayOfWeek),
  71. szDayOfWeek, SIZECHARS(szDayOfWeek));
  72. // Search for the day of week text in the string we got back.
  73. // Depending on the user's regional settings, there might not
  74. // be a day in the long-date format...
  75. pszModifier = StrStr(pszBuf, szDayOfWeek);
  76. if (pszModifier)
  77. {
  78. // We found the day in the string, so replace it with
  79. // "Today" or "Yesterday"
  80. TCHAR szTemp[64];
  81. TCHAR szRelativeDay[32];
  82. int cchRelativeDay;
  83. int cchModifier;
  84. cchModifier = cchBuf - ((int)(pszModifier - pszBuf));
  85. // Save the tail end (the part after the "Monday" string)
  86. StringCchCopy(szTemp, SIZECHARS(szTemp), &pszModifier[cchDayOfWeek]);
  87. // Load the appropriate string ("Yesterday" or "Today").
  88. // If the string is empty (localizers might need to do this
  89. // if this logic isn't locale-friendly), don't bother doing
  90. // anything.
  91. cchRelativeDay = MLLoadString((1 == iDay) ? IDS_TODAY : IDS_YESTERDAY,
  92. szRelativeDay, SIZECHARS(szRelativeDay));
  93. if (0 < cchRelativeDay)
  94. {
  95. // Make sure that we have enough room for the replacement
  96. // (cch already accounts for the null terminator)
  97. if (cch - cchDayOfWeek + cchRelativeDay <= cchBuf)
  98. {
  99. // copy the friendly name over the day of the week
  100. StringCchCopy(pszModifier, cchModifier , szRelativeDay);
  101. // put back the tail end
  102. StringCchCat(pszModifier, cchModifier, szTemp);
  103. cch = cch - cchDayOfWeek + cchRelativeDay;
  104. *pdwFlags |= FDTF_RELATIVE;
  105. }
  106. }
  107. }
  108. }
  109. }
  110. return cch;
  111. }
  112. #define LRM 0x200E // UNICODE Left-to-right mark control character
  113. #define RLM 0x200F // UNICODE Left-to-right mark control character
  114. /*-------------------------------------------------------------------------
  115. Purpose: Constructs a displayname form of the file time.
  116. *pdwFlags may be NULL, in which case FDTF_DEFAULT is assumed. Other
  117. valid flags are:
  118. FDTF_DEFAULT "3/29/98 7:48 PM"
  119. FDTF_SHORTTIME "7:48 PM"
  120. FDTF_SHORTDATE "3/29/98"
  121. FDTF_LONGDATE "Monday, March 29, 1998"
  122. FDTF_LONGTIME "7:48:33 PM"
  123. FDTF_RELATIVE only works with FDTF_LONGDATE. If possible,
  124. replace the day with "Yesterday" or "Today":
  125. "Yesterday, March 29, 1998"
  126. This function updates *pdwFlags to indicate which sections of the
  127. string were actually set. For example, if FDTF_RELATIVE is passed
  128. in, but no relative date conversion was performed, then FDTF_RELATIVE
  129. is cleared before returning.
  130. If the date is the magic "Sorry, I don't know what date it is" value
  131. that FAT uses, then we return an empty string.
  132. */
  133. STDAPI_(int) SHFormatDateTimeW(const FILETIME UNALIGNED *puft, DWORD *pdwFlags, LPWSTR pszBuf, UINT ucchBuf)
  134. {
  135. int cchBuf = ucchBuf;
  136. int cchBufSav = cchBuf;
  137. FILETIME ftLocal, ftInput = *puft; // allign the data
  138. ASSERT(IS_VALID_READ_PTR(puft, FILETIME));
  139. ASSERT(IS_VALID_WRITE_BUFFER(pszBuf, WCHAR, cchBuf));
  140. ASSERT(NULL == pdwFlags || IS_VALID_WRITE_PTR(pdwFlags, DWORD));
  141. DWORD dwFlags = 0;
  142. FileTimeToLocalFileTime(&ftInput, &ftLocal);
  143. if (FILETIMEtoInt64(ftInput) == FT_NTFS_UNKNOWNGMT ||
  144. FILETIMEtoInt64(ftLocal) == FT_FAT_UNKNOWNLOCAL)
  145. {
  146. // This date is uninitialized. Don't show a bogus "10/10/72" string.
  147. if (0 < cchBuf)
  148. *pszBuf = 0;
  149. }
  150. else if (0 < cchBuf)
  151. {
  152. int cch;
  153. SYSTEMTIME st;
  154. DWORD dwDateFlags = DATE_SHORTDATE; // default
  155. DWORD dwTimeFlags = TIME_NOSECONDS; // default
  156. dwFlags = pdwFlags ? *pdwFlags : FDTF_DEFAULT;
  157. // Initialize the flags we're going to use
  158. if (dwFlags & FDTF_LONGDATE)
  159. dwDateFlags = DATE_LONGDATE;
  160. else
  161. dwFlags &= ~FDTF_RELATIVE; // can't show relative dates w/o long dates
  162. if (dwFlags & FDTF_LTRDATE)
  163. dwDateFlags |= DATE_LTRREADING;
  164. else if(dwFlags & FDTF_RTLDATE)
  165. dwDateFlags |= DATE_RTLREADING;
  166. if (dwFlags & FDTF_LONGTIME)
  167. dwTimeFlags &= ~TIME_NOSECONDS;
  168. FileTimeToSystemTime(&ftLocal, &st);
  169. cchBuf--; // Account for null terminator first
  170. if (dwFlags & (FDTF_LONGDATE | FDTF_SHORTDATE))
  171. {
  172. // Get the date
  173. if (dwFlags & FDTF_RELATIVE)
  174. cch = GetRelativeDateFormat(dwDateFlags, &dwFlags, &st, pszBuf, cchBuf);
  175. else
  176. cch = GetDateFormat(LOCALE_USER_DEFAULT, dwDateFlags, &st, NULL, pszBuf, cchBuf);
  177. ASSERT(0 <= cch && cch <= cchBuf);
  178. if (0 < cch)
  179. {
  180. cch--; // (null terminator was counted above, so don't count it again)
  181. ASSERT('\0'==pszBuf[cch]);
  182. }
  183. else
  184. dwFlags &= ~(FDTF_LONGDATE | FDTF_SHORTDATE); // no date, so clear these bits
  185. cchBuf -= cch;
  186. pszBuf += cch;
  187. // Are we tacking on the time too?
  188. if (dwFlags & (FDTF_SHORTTIME | FDTF_LONGTIME))
  189. {
  190. // Yes; for long dates, separate with a comma, otherwise
  191. // separate with a space.
  192. if (dwFlags & FDTF_LONGDATE)
  193. {
  194. WCHAR szT[8];
  195. cch = MLLoadString(IDS_LONGDATE_SEP, szT, SIZECHARS(szT));
  196. StrCpyNW(pszBuf, szT, cchBuf);
  197. int cchCopied = min(cchBuf, cch);
  198. cchBuf -= cchCopied;
  199. pszBuf += cchCopied;
  200. }
  201. else
  202. {
  203. if (cchBuf>0)
  204. {
  205. *pszBuf++ = TEXT(' ');
  206. *pszBuf = 0; // (in case GetTimeFormat doesn't add anything)
  207. cchBuf--;
  208. }
  209. }
  210. // [msadek]; need to insert strong a Unicode control character to simulate
  211. // a strong run in the opposite base direction to enforce
  212. // correct display of concatinated string in all cases
  213. if (dwFlags & FDTF_RTLDATE)
  214. {
  215. if (cchBuf>=2)
  216. {
  217. *pszBuf++ = LRM; // simulate an opposite run
  218. *pszBuf++ = RLM; // force RTL display of the time part.
  219. *pszBuf = 0;
  220. cchBuf -= 2;
  221. }
  222. }
  223. else if (dwFlags & FDTF_LTRDATE)
  224. {
  225. if (cchBuf>=2)
  226. {
  227. *pszBuf++ = RLM; // simulate an opposite run
  228. *pszBuf++ = LRM; // force LTR display of the time part.
  229. *pszBuf = 0;
  230. cchBuf -= 2;
  231. }
  232. }
  233. }
  234. }
  235. if (dwFlags & (FDTF_SHORTTIME | FDTF_LONGTIME))
  236. {
  237. // Get the time
  238. cch = GetTimeFormat(LOCALE_USER_DEFAULT, dwTimeFlags, &st, NULL, pszBuf, cchBuf);
  239. if (0 < cch)
  240. cch--; // (null terminator was counted above, so don't count it again)
  241. else
  242. dwFlags &= ~(FDTF_LONGTIME | FDTF_SHORTTIME); // no time, so clear these bits
  243. cchBuf -= cch;
  244. }
  245. }
  246. if (pdwFlags)
  247. *pdwFlags = dwFlags;
  248. return cchBufSav - cchBuf;
  249. }
  250. STDAPI_(int) SHFormatDateTimeA(const FILETIME UNALIGNED *pft, DWORD *pdwFlags, LPSTR pszBuf, UINT cchBuf)
  251. {
  252. WCHAR wsz[256];
  253. int cchRet = SHFormatDateTimeW(pft, pdwFlags, wsz, SIZECHARS(wsz));
  254. if (0 < cchRet)
  255. {
  256. cchRet = SHUnicodeToAnsi(wsz, pszBuf, cchBuf);
  257. }
  258. else if (0 < cchBuf)
  259. {
  260. *pszBuf = 0;
  261. }
  262. return cchRet;
  263. }