From 7f642e51670bc38a4ef782a363936850bc2b0ba9 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 22 Apr 2021 06:38:23 -0700 Subject: Move dutil into libs/dutil --- src/libs/dutil/WixToolset.DUtil/timeutil.cpp | 385 +++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 src/libs/dutil/WixToolset.DUtil/timeutil.cpp (limited to 'src/libs/dutil/WixToolset.DUtil/timeutil.cpp') diff --git a/src/libs/dutil/WixToolset.DUtil/timeutil.cpp b/src/libs/dutil/WixToolset.DUtil/timeutil.cpp new file mode 100644 index 00000000..b7953c94 --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/timeutil.cpp @@ -0,0 +1,385 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// Exit macros +#define TimeExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_TIMEUTIL, x, s, __VA_ARGS__) +#define TimeExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_TIMEUTIL, x, s, __VA_ARGS__) +#define TimeExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_TIMEUTIL, x, s, __VA_ARGS__) +#define TimeExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_TIMEUTIL, x, s, __VA_ARGS__) +#define TimeExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_TIMEUTIL, x, s, __VA_ARGS__) +#define TimeExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_TIMEUTIL, x, s, __VA_ARGS__) +#define TimeExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_TIMEUTIL, p, x, e, s, __VA_ARGS__) +#define TimeExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_TIMEUTIL, p, x, s, __VA_ARGS__) +#define TimeExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_TIMEUTIL, p, x, e, s, __VA_ARGS__) +#define TimeExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_TIMEUTIL, p, x, s, __VA_ARGS__) +#define TimeExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_TIMEUTIL, e, x, s, __VA_ARGS__) +#define TimeExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_TIMEUTIL, g, x, s, __VA_ARGS__) + +const LPCWSTR DAY_OF_WEEK[] = { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" }; +const LPCWSTR MONTH_OF_YEAR[] = { L"None", L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" }; +enum TIME_PARSER { DayOfWeek, DayOfMonth, MonthOfYear, Year, Hours, Minutes, Seconds, TimeZone }; +enum TIME_PARSERRFC3339 { RFC3339_Year, RFC3339_Month, RFC3339_Day, RFC3339_Hours, RFC3339_Minutes, RFC3339_Seconds, RFC3339_TimeZone }; + +// prototypes +static HRESULT DayFromString( + __in_z LPCWSTR wzDay, + __out WORD* pwDayOfWeek + ); +static HRESULT MonthFromString( + __in_z LPCWSTR wzMonth, + __out WORD* pwMonthOfYear + ); + + +/******************************************************************** + TimeFromString - converts string to FILETIME + +*******************************************************************/ +extern "C" HRESULT DAPI TimeFromString( + __in_z LPCWSTR wzTime, + __out FILETIME* pFileTime + ) +{ + Assert(wzTime && pFileTime); + + HRESULT hr = S_OK; + LPWSTR pwzTime = NULL; + + SYSTEMTIME sysTime = { }; + TIME_PARSER timeParser = DayOfWeek; + + LPCWSTR pwzStart = NULL; + LPWSTR pwzEnd = NULL; + + hr = StrAllocString(&pwzTime, wzTime, 0); + TimeExitOnFailure(hr, "Failed to copy time."); + + pwzStart = pwzEnd = pwzTime; + while (pwzEnd && *pwzEnd) + { + if (L',' == *pwzEnd || L' ' == *pwzEnd || L':' == *pwzEnd) + { + *pwzEnd = L'\0'; // null terminate + ++pwzEnd; + + while (L' ' == *pwzEnd) + { + ++pwzEnd; // and skip past the blank space + } + + switch (timeParser) + { + case DayOfWeek: + hr = DayFromString(pwzStart, &sysTime.wDayOfWeek); + TimeExitOnFailure(hr, "Failed to convert string to day: %ls", pwzStart); + break; + + case DayOfMonth: + sysTime.wDay = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case MonthOfYear: + hr = MonthFromString(pwzStart, &sysTime.wMonth); + TimeExitOnFailure(hr, "Failed to convert to month: %ls", pwzStart); + break; + + case Year: + sysTime.wYear = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case Hours: + sysTime.wHour = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case Minutes: + sysTime.wMinute = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case Seconds: + sysTime.wSecond = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case TimeZone: + // TODO: do something with this in the future, but this should only hit outside of the while loop. + break; + + default: + break; + } + + pwzStart = pwzEnd; + timeParser = (TIME_PARSER)((int)timeParser + 1); + } + + ++pwzEnd; + } + + + if (!::SystemTimeToFileTime(&sysTime, pFileTime)) + { + TimeExitWithLastError(hr, "Failed to convert system time to file time."); + } + +LExit: + ReleaseStr(pwzTime); + + return hr; +} + +/******************************************************************** + TimeFromString3339 - converts string formated in accorance with RFC3339 to FILETIME + http://tools.ietf.org/html/rfc3339 +*******************************************************************/ +extern "C" HRESULT DAPI TimeFromString3339( + __in_z LPCWSTR wzTime, + __out FILETIME* pFileTime + ) +{ + Assert(wzTime && pFileTime); + + HRESULT hr = S_OK; + LPWSTR pwzTime = NULL; + + SYSTEMTIME sysTime = { }; + TIME_PARSERRFC3339 timeParser = RFC3339_Year; + + LPCWSTR pwzStart = NULL; + LPWSTR pwzEnd = NULL; + + hr = StrAllocString(&pwzTime, wzTime, 0); + TimeExitOnFailure(hr, "Failed to copy time."); + + pwzStart = pwzEnd = pwzTime; + while (pwzEnd && *pwzEnd) + { + if (L'T' == *pwzEnd || L':' == *pwzEnd || L'-' == *pwzEnd) + { + *pwzEnd = L'\0'; // null terminate + ++pwzEnd; + + switch (timeParser) + { + case RFC3339_Year: + sysTime.wYear = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case RFC3339_Month: + sysTime.wMonth = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case RFC3339_Day: + sysTime.wDay = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case RFC3339_Hours: + sysTime.wHour = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case RFC3339_Minutes: + sysTime.wMinute = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case RFC3339_Seconds: + sysTime.wSecond = (WORD)wcstoul(pwzStart, NULL, 10); + break; + + case RFC3339_TimeZone: + // TODO: do something with this in the future, but this should only hit outside of the while loop. + break; + + default: + break; + } + + pwzStart = pwzEnd; + timeParser = (TIME_PARSERRFC3339)((int)timeParser + 1); + } + + ++pwzEnd; + } + + + if (!::SystemTimeToFileTime(&sysTime, pFileTime)) + { + TimeExitWithLastError(hr, "Failed to convert system time to file time."); + } + +LExit: + ReleaseStr(pwzTime); + + return hr; +} +/**************************************************************************** +TimeCurrentTime - gets the current time in string format + +****************************************************************************/ +extern "C" HRESULT DAPI TimeCurrentTime( + __deref_out_z LPWSTR* ppwz, + __in BOOL fGMT + ) +{ + SYSTEMTIME st; + + if (fGMT) + { + ::GetSystemTime(&st); + } + else + { + SYSTEMTIME stGMT; + TIME_ZONE_INFORMATION tzi; + + ::GetTimeZoneInformation(&tzi); + ::GetSystemTime(&stGMT); + ::SystemTimeToTzSpecificLocalTime(&tzi, &stGMT, &st); + } + + return StrAllocFormatted(ppwz, L"%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); +} + + +/**************************************************************************** +TimeCurrentDateTime - gets the current date and time in string format, + per format described in RFC 3339 +****************************************************************************/ +extern "C" HRESULT DAPI TimeCurrentDateTime( + __deref_out_z LPWSTR* ppwz, + __in BOOL fGMT + ) +{ + SYSTEMTIME st; + + ::GetSystemTime(&st); + + return TimeSystemDateTime(ppwz, &st, fGMT); +} + + +/**************************************************************************** +TimeSystemDateTime - converts the provided system time struct to string format, + per format described in RFC 3339 +****************************************************************************/ +extern "C" HRESULT DAPI TimeSystemDateTime( + __deref_out_z LPWSTR* ppwz, + __in const SYSTEMTIME *pst, + __in BOOL fGMT + ) +{ + DWORD dwAbsBias = 0; + + if (fGMT) + { + return StrAllocFormatted(ppwz, L"%04hu-%02hu-%02huT%02hu:%02hu:%02huZ", pst->wYear, pst->wMonth, pst->wDay, pst->wHour, pst->wMinute, pst->wSecond); + } + else + { + SYSTEMTIME st; + TIME_ZONE_INFORMATION tzi; + + ::GetTimeZoneInformation(&tzi); + ::SystemTimeToTzSpecificLocalTime(&tzi, pst, &st); + dwAbsBias = abs(tzi.Bias); + + return StrAllocFormatted(ppwz, L"%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02u:%02u", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, 0 >= tzi.Bias ? L'+' : L'-', dwAbsBias / 60, dwAbsBias % 60); + } +} + + +/**************************************************************************** +TimeSystemToDateTimeString - converts the provided system time struct to + string format representing date and time for the specified locale +****************************************************************************/ +HRESULT DAPI TimeSystemToDateTimeString( + __deref_out_z LPWSTR* ppwz, + __in const SYSTEMTIME* pst, + __in LCID locale + ) +{ + HRESULT hr = S_OK; + const WCHAR * DATE_FORMAT = L"MMM dd',' yyyy',' "; + const WCHAR * TIME_FORMAT = L"hh':'mm':'ss tt"; + int iLenDate = 0; + int iLenTime = 0; + + iLenDate = ::GetDateFormatW(locale, 0, pst, DATE_FORMAT, NULL, 0); + if (0 >= iLenDate) + { + TimeExitWithLastError(hr, "Failed to get date format with NULL"); + } + + iLenTime = ::GetTimeFormatW(locale, 0, pst, TIME_FORMAT, NULL, 0); + if (0 >= iLenTime) + { + TimeExitWithLastError(hr, "Failed to get time format with NULL"); + } + + // Between both lengths we account for 2 null terminators, and only need one, so we subtract one + hr = StrAlloc(ppwz, iLenDate + iLenTime - 1); + TimeExitOnFailure(hr, "Failed to allocate string"); + + if (!::GetDateFormatW(locale, 0, pst, DATE_FORMAT, *ppwz, iLenDate)) + { + TimeExitWithLastError(hr, "Failed to get date format with buffer"); + } + // Space to separate them + (*ppwz)[iLenDate - 1] = ' '; + + if (!::GetTimeFormatW(locale, 0, pst, TIME_FORMAT, (*ppwz) + iLenDate - 1, iLenTime)) + { + TimeExitWithLastError(hr, "Failed to get time format with buffer"); + } + +LExit: + return hr; +} + +/******************************************************************** + DayFromString - converts string to day + +*******************************************************************/ +static HRESULT DayFromString( + __in_z LPCWSTR wzDay, + __out WORD* pwDayOfWeek + ) +{ + HRESULT hr = E_INVALIDARG; // assume we won't find a matching name + + for (WORD i = 0; i < countof(DAY_OF_WEEK); ++i) + { + if (0 == lstrcmpW(wzDay, DAY_OF_WEEK[i])) + { + *pwDayOfWeek = i; + hr = S_OK; + break; + } + } + + return hr; +} + + +/******************************************************************** + MonthFromString - converts string to month + +*******************************************************************/ +static HRESULT MonthFromString( + __in_z LPCWSTR wzMonth, + __out WORD* pwMonthOfYear + ) +{ + HRESULT hr = E_INVALIDARG; // assume we won't find a matching name + + for (WORD i = 0; i < countof(MONTH_OF_YEAR); ++i) + { + if (0 == lstrcmpW(wzMonth, MONTH_OF_YEAR[i])) + { + *pwMonthOfYear = i; + hr = S_OK; + break; + } + } + + return hr; +} -- cgit v1.2.3-55-g6feb