1 #include "rar.hpp"
2 
GetLocal(RarLocalTime * lt)3 void RarTime::GetLocal(RarLocalTime *lt)
4 {
5 #ifdef _WIN_ALL
6   FILETIME ft;
7   GetWinFT(&ft);
8   FILETIME lft;
9 
10   if (WinNT() < WNT_VISTA)
11   {
12     // SystemTimeToTzSpecificLocalTime based code produces 1 hour error on XP.
13     FileTimeToLocalFileTime(&ft,&lft);
14   }
15   else
16   {
17     // We use these functions instead of FileTimeToLocalFileTime according to
18     // MSDN recommendation: "To account for daylight saving time
19     // when converting a file time to a local time ..."
20     SYSTEMTIME st1,st2;
21     FileTimeToSystemTime(&ft,&st1);
22     SystemTimeToTzSpecificLocalTime(NULL,&st1,&st2);
23     SystemTimeToFileTime(&st2,&lft);
24 
25     // Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime.
26     FILETIME rft;
27     SystemTimeToFileTime(&st1,&rft);
28     uint64 Corrected=INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime)-
29                      INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+
30                      INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime);
31     lft.dwLowDateTime=(DWORD)Corrected;
32     lft.dwHighDateTime=(DWORD)(Corrected>>32);
33   }
34 
35   SYSTEMTIME st;
36   FileTimeToSystemTime(&lft,&st);
37   lt->Year=st.wYear;
38   lt->Month=st.wMonth;
39   lt->Day=st.wDay;
40   lt->Hour=st.wHour;
41   lt->Minute=st.wMinute;
42   lt->Second=st.wSecond;
43   lt->wDay=st.wDayOfWeek;
44   lt->yDay=lt->Day-1;
45 
46   static int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
47   for (uint I=1;I<lt->Month && I<=ASIZE(mdays);I++)
48     lt->yDay+=mdays[I-1];
49 
50   if (lt->Month>2 && IsLeapYear(lt->Year))
51     lt->yDay++;
52 #else
53   time_t ut=GetUnix();
54   struct tm *t;
55   t=localtime(&ut);
56 
57   lt->Year=t->tm_year+1900;
58   lt->Month=t->tm_mon+1;
59   lt->Day=t->tm_mday;
60   lt->Hour=t->tm_hour;
61   lt->Minute=t->tm_min;
62   lt->Second=t->tm_sec;
63   lt->wDay=t->tm_wday;
64   lt->yDay=t->tm_yday;
65 #endif
66   lt->Reminder=(itime % TICKS_PER_SECOND);
67 }
68 
69 
SetLocal(RarLocalTime * lt)70 void RarTime::SetLocal(RarLocalTime *lt)
71 {
72 #ifdef _WIN_ALL
73   SYSTEMTIME st;
74   st.wYear=lt->Year;
75   st.wMonth=lt->Month;
76   st.wDay=lt->Day;
77   st.wHour=lt->Hour;
78   st.wMinute=lt->Minute;
79   st.wSecond=lt->Second;
80   st.wMilliseconds=0;
81   st.wDayOfWeek=0;
82   FILETIME lft;
83   if (SystemTimeToFileTime(&st,&lft))
84   {
85     FILETIME ft;
86 
87     if (WinNT() < WNT_VISTA)
88     {
89       // TzSpecificLocalTimeToSystemTime based code produces 1 hour error on XP.
90       LocalFileTimeToFileTime(&lft,&ft);
91     }
92     else
93     {
94       // Reverse procedure which we do in GetLocal.
95       SYSTEMTIME st1,st2;
96       FileTimeToSystemTime(&lft,&st2); // st2 might be unequal to st, because we added lt->Reminder to lft.
97       TzSpecificLocalTimeToSystemTime(NULL,&st2,&st1);
98       SystemTimeToFileTime(&st1,&ft);
99 
100       // Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime.
101       FILETIME rft;
102       SystemTimeToFileTime(&st2,&rft);
103       uint64 Corrected=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)-
104                        INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+
105                        INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime);
106       ft.dwLowDateTime=(DWORD)Corrected;
107       ft.dwHighDateTime=(DWORD)(Corrected>>32);
108     }
109 
110     SetWinFT(&ft);
111   }
112   else
113     Reset();
114 #else
115   struct tm t;
116 
117   t.tm_sec=lt->Second;
118   t.tm_min=lt->Minute;
119   t.tm_hour=lt->Hour;
120   t.tm_mday=lt->Day;
121   t.tm_mon=lt->Month-1;
122   t.tm_year=lt->Year-1900;
123   t.tm_isdst=-1;
124   SetUnix(mktime(&t));
125 #endif
126   itime+=lt->Reminder;
127 }
128 
129 
130 
131 
132 #ifdef _WIN_ALL
GetWinFT(FILETIME * ft)133 void RarTime::GetWinFT(FILETIME *ft)
134 {
135   _ULARGE_INTEGER ul;
136   ul.QuadPart=GetWin();
137   ft->dwLowDateTime=ul.LowPart;
138   ft->dwHighDateTime=ul.HighPart;
139 }
140 
141 
SetWinFT(FILETIME * ft)142 void RarTime::SetWinFT(FILETIME *ft)
143 {
144   _ULARGE_INTEGER ul = {ft->dwLowDateTime, ft->dwHighDateTime};
145   SetWin(ul.QuadPart);
146 }
147 #endif
148 
149 
150 // Get 64-bit representation of Windows FILETIME (100ns since 01.01.1601).
GetWin()151 uint64 RarTime::GetWin()
152 {
153   return itime/(TICKS_PER_SECOND/10000000);
154 }
155 
156 
157 // Set 64-bit representation of Windows FILETIME (100ns since 01.01.1601).
SetWin(uint64 WinTime)158 void RarTime::SetWin(uint64 WinTime)
159 {
160   itime=WinTime*(TICKS_PER_SECOND/10000000);
161 }
162 
163 
GetUnix()164 time_t RarTime::GetUnix()
165 {
166   return time_t(GetUnixNS()/1000000000);
167 }
168 
169 
SetUnix(time_t ut)170 void RarTime::SetUnix(time_t ut)
171 {
172   if (sizeof(ut)>4)
173     SetUnixNS(uint64(ut)*1000000000);
174   else
175   {
176     // Convert 32-bit and possibly signed time_t to uint32 first,
177     // uint64 cast is not enough. Otherwise sign can expand to 64 bits.
178     SetUnixNS(uint64(uint32(ut))*1000000000);
179   }
180 }
181 
182 
183 // Get the high precision Unix time in nanoseconds since 01-01-1970.
GetUnixNS()184 uint64 RarTime::GetUnixNS()
185 {
186   // 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970.
187   uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
188   return itime*(1000000000/TICKS_PER_SECOND)-ushift;
189 }
190 
191 
192 // Set the high precision Unix time in nanoseconds since 01-01-1970.
SetUnixNS(uint64 ns)193 void RarTime::SetUnixNS(uint64 ns)
194 {
195   // 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970.
196   uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
197   itime=(ns+ushift)/(1000000000/TICKS_PER_SECOND);
198 }
199 
200 
GetDos()201 uint RarTime::GetDos()
202 {
203   RarLocalTime lt;
204   GetLocal(&lt);
205   uint DosTime=(lt.Second/2)|(lt.Minute<<5)|(lt.Hour<<11)|
206                (lt.Day<<16)|(lt.Month<<21)|((lt.Year-1980)<<25);
207   return DosTime;
208 }
209 
210 
SetDos(uint DosTime)211 void RarTime::SetDos(uint DosTime)
212 {
213   RarLocalTime lt;
214   lt.Second=(DosTime & 0x1f)*2;
215   lt.Minute=(DosTime>>5) & 0x3f;
216   lt.Hour=(DosTime>>11) & 0x1f;
217   lt.Day=(DosTime>>16) & 0x1f;
218   lt.Month=(DosTime>>21) & 0x0f;
219   lt.Year=(DosTime>>25)+1980;
220   lt.Reminder=0;
221   SetLocal(&lt);
222 }
223 
224 
GetText(wchar * DateStr,size_t MaxSize,bool FullMS)225 void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS)
226 {
227   if (IsSet())
228   {
229     RarLocalTime lt;
230     GetLocal(&lt);
231     if (FullMS)
232       swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u:%02u,%09u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute,lt.Second,lt.Reminder*(1000000000/TICKS_PER_SECOND));
233     else
234       swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute);
235   }
236   else
237   {
238     // We use escape before '?' to avoid weird C trigraph characters.
239     wcsncpyz(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?",MaxSize);
240   }
241 }
242 
243 
244 #ifndef SFX_MODULE
SetIsoText(const wchar * TimeText)245 void RarTime::SetIsoText(const wchar *TimeText)
246 {
247   int Field[6];
248   memset(Field,0,sizeof(Field));
249   for (uint DigitCount=0;*TimeText!=0;TimeText++)
250     if (IsDigit(*TimeText))
251     {
252       int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1;
253       if (FieldPos<ASIZE(Field))
254         Field[FieldPos]=Field[FieldPos]*10+*TimeText-'0';
255       DigitCount++;
256     }
257   RarLocalTime lt;
258   lt.Second=Field[5];
259   lt.Minute=Field[4];
260   lt.Hour=Field[3];
261   lt.Day=Field[2]==0 ? 1:Field[2];
262   lt.Month=Field[1]==0 ? 1:Field[1];
263   lt.Year=Field[0];
264   lt.Reminder=0;
265   SetLocal(&lt);
266 }
267 #endif
268 
269 
270 #ifndef SFX_MODULE
SetAgeText(const wchar * TimeText)271 void RarTime::SetAgeText(const wchar *TimeText)
272 {
273   uint Seconds=0,Value=0;
274   for (uint I=0;TimeText[I]!=0;I++)
275   {
276     int Ch=TimeText[I];
277     if (IsDigit(Ch))
278       Value=Value*10+Ch-'0';
279     else
280     {
281       switch(etoupper(Ch))
282       {
283         case 'D':
284           Seconds+=Value*24*3600;
285           break;
286         case 'H':
287           Seconds+=Value*3600;
288           break;
289         case 'M':
290           Seconds+=Value*60;
291           break;
292         case 'S':
293           Seconds+=Value;
294           break;
295       }
296       Value=0;
297     }
298   }
299   SetCurrentTime();
300   itime-=uint64(Seconds)*TICKS_PER_SECOND;
301 }
302 #endif
303 
304 
SetCurrentTime()305 void RarTime::SetCurrentTime()
306 {
307 #ifdef _WIN_ALL
308   FILETIME ft;
309   SYSTEMTIME st;
310   GetSystemTime(&st);
311   SystemTimeToFileTime(&st,&ft);
312   SetWinFT(&ft);
313 #else
314   time_t st;
315   time(&st);
316   SetUnix(st);
317 #endif
318 }
319 
320 
321 // Add the specified signed number of nanoseconds.
Adjust(int64 ns)322 void RarTime::Adjust(int64 ns)
323 {
324   ns/=1000000000/TICKS_PER_SECOND; // Convert ns to internal ticks.
325   itime+=(uint64)ns;
326 }
327 
328 
329 #ifndef SFX_MODULE
GetMonthName(int Month)330 const wchar *GetMonthName(int Month)
331 {
332   return uiGetMonthName(Month);
333 }
334 #endif
335 
336 
IsLeapYear(int Year)337 bool IsLeapYear(int Year)
338 {
339   return (Year&3)==0 && (Year%100!=0 || Year%400==0);
340 }
341