Coverage Report

Created: 2024-04-23 06:19

/src/unrar/timefn.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "rar.hpp"
2
3
void RarTime::GetLocal(RarLocalTime *lt)
4
83
{
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
83
  time_t ut=GetUnix();
54
83
  struct tm *t;
55
83
  t=localtime(&ut);
56
57
83
  lt->Year=t->tm_year+1900;
58
83
  lt->Month=t->tm_mon+1;
59
83
  lt->Day=t->tm_mday;
60
83
  lt->Hour=t->tm_hour;
61
83
  lt->Minute=t->tm_min;
62
83
  lt->Second=t->tm_sec;
63
83
  lt->wDay=t->tm_wday;
64
83
  lt->yDay=t->tm_yday;
65
83
#endif
66
83
  lt->Reminder=(itime % TICKS_PER_SECOND);
67
83
}
68
69
70
void RarTime::SetLocal(RarLocalTime *lt)
71
3.78k
{
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
3.78k
  struct tm t;
116
117
3.78k
  t.tm_sec=lt->Second;
118
3.78k
  t.tm_min=lt->Minute;
119
3.78k
  t.tm_hour=lt->Hour;
120
3.78k
  t.tm_mday=lt->Day;
121
3.78k
  t.tm_mon=lt->Month-1;
122
3.78k
  t.tm_year=lt->Year-1900;
123
3.78k
  t.tm_isdst=-1;
124
3.78k
  SetUnix(mktime(&t));
125
3.78k
#endif
126
3.78k
  itime+=lt->Reminder;
127
3.78k
}
128
129
130
131
132
#ifdef _WIN_ALL
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
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).
151
uint64 RarTime::GetWin()
152
0
{
153
0
  return itime/(TICKS_PER_SECOND/10000000);
154
0
}
155
156
157
// Set 64-bit representation of Windows FILETIME (100ns since 01.01.1601).
158
void RarTime::SetWin(uint64 WinTime)
159
0
{
160
0
  itime=WinTime*(TICKS_PER_SECOND/10000000);
161
0
}
162
163
164
time_t RarTime::GetUnix()
165
834
{
166
834
  return time_t(GetUnixNS()/1000000000);
167
834
}
168
169
170
void RarTime::SetUnix(time_t ut)
171
8.84k
{
172
8.84k
  if (sizeof(ut)>4)
173
8.84k
    SetUnixNS(uint64(ut)*1000000000);
174
0
  else
175
0
  {
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
0
    SetUnixNS(uint64(uint32(ut))*1000000000);
179
0
  }
180
8.84k
}
181
182
183
// Get the high precision Unix time in nanoseconds since 01-01-1970.
184
uint64 RarTime::GetUnixNS()
185
1.58k
{
186
  // 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970.
187
1.58k
  uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
188
1.58k
  return itime*(1000000000/TICKS_PER_SECOND)-ushift;
189
1.58k
}
190
191
192
// Set the high precision Unix time in nanoseconds since 01-01-1970.
193
void RarTime::SetUnixNS(uint64 ns)
194
21.1k
{
195
  // 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970.
196
21.1k
  uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
197
21.1k
  itime=(ns+ushift)/(1000000000/TICKS_PER_SECOND);
198
21.1k
}
199
200
201
uint RarTime::GetDos()
202
0
{
203
0
  RarLocalTime lt;
204
0
  GetLocal(&lt);
205
0
  uint DosTime=(lt.Second/2)|(lt.Minute<<5)|(lt.Hour<<11)|
206
0
               (lt.Day<<16)|(lt.Month<<21)|((lt.Year-1980)<<25);
207
0
  return DosTime;
208
0
}
209
210
211
void RarTime::SetDos(uint DosTime)
212
3.70k
{
213
3.70k
  RarLocalTime lt;
214
3.70k
  lt.Second=(DosTime & 0x1f)*2;
215
3.70k
  lt.Minute=(DosTime>>5) & 0x3f;
216
3.70k
  lt.Hour=(DosTime>>11) & 0x1f;
217
3.70k
  lt.Day=(DosTime>>16) & 0x1f;
218
3.70k
  lt.Month=(DosTime>>21) & 0x0f;
219
3.70k
  lt.Year=(DosTime>>25)+1980;
220
3.70k
  lt.Reminder=0;
221
3.70k
  SetLocal(&lt);
222
3.70k
}
223
224
225
void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS)
226
0
{
227
0
  if (IsSet())
228
0
  {
229
0
    RarLocalTime lt;
230
0
    GetLocal(&lt);
231
0
    if (FullMS)
232
0
      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
0
    else
234
0
      swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute);
235
0
  }
236
0
  else
237
0
  {
238
    // We use escape before '?' to avoid weird C trigraph characters.
239
0
    wcsncpyz(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?",MaxSize);
240
0
  }
241
0
}
242
243
244
#ifndef SFX_MODULE
245
void RarTime::SetIsoText(const wchar *TimeText)
246
0
{
247
0
  int Field[6];
248
0
  memset(Field,0,sizeof(Field));
249
0
  for (uint DigitCount=0;*TimeText!=0;TimeText++)
250
0
    if (IsDigit(*TimeText))
251
0
    {
252
0
      int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1;
253
0
      if (FieldPos<ASIZE(Field))
254
0
        Field[FieldPos]=Field[FieldPos]*10+*TimeText-'0';
255
0
      DigitCount++;
256
0
    }
257
0
  RarLocalTime lt;
258
0
  lt.Second=Field[5];
259
0
  lt.Minute=Field[4];
260
0
  lt.Hour=Field[3];
261
0
  lt.Day=Field[2]==0 ? 1:Field[2];
262
0
  lt.Month=Field[1]==0 ? 1:Field[1];
263
0
  lt.Year=Field[0];
264
0
  lt.Reminder=0;
265
0
  SetLocal(&lt);
266
0
}
267
#endif
268
269
270
#ifndef SFX_MODULE
271
void RarTime::SetAgeText(const wchar *TimeText)
272
0
{
273
0
  uint Seconds=0,Value=0;
274
0
  for (uint I=0;TimeText[I]!=0;I++)
275
0
  {
276
0
    wchar Ch=TimeText[I];
277
0
    if (IsDigit(Ch))
278
0
      Value=Value*10+Ch-'0';
279
0
    else
280
0
    {
281
0
      switch(etoupperw(Ch))
282
0
      {
283
0
        case 'D':
284
0
          Seconds+=Value*24*3600;
285
0
          break;
286
0
        case 'H':
287
0
          Seconds+=Value*3600;
288
0
          break;
289
0
        case 'M':
290
0
          Seconds+=Value*60;
291
0
          break;
292
0
        case 'S':
293
0
          Seconds+=Value;
294
0
          break;
295
0
      }
296
0
      Value=0;
297
0
    }
298
0
  }
299
0
  SetCurrentTime();
300
0
  itime-=uint64(Seconds)*TICKS_PER_SECOND;
301
0
}
302
#endif
303
304
305
void RarTime::SetCurrentTime()
306
4.04k
{
307
#ifdef _WIN_ALL
308
  FILETIME ft;
309
  SYSTEMTIME st;
310
  GetSystemTime(&st);
311
  SystemTimeToFileTime(&st,&ft);
312
  SetWinFT(&ft);
313
#else
314
4.04k
  time_t st;
315
4.04k
  time(&st);
316
4.04k
  SetUnix(st);
317
4.04k
#endif
318
4.04k
}
319
320
321
// Add the specified signed number of nanoseconds.
322
void RarTime::Adjust(int64 ns)
323
3
{
324
3
  ns/=1000000000/TICKS_PER_SECOND; // Convert ns to internal ticks.
325
3
  itime+=(uint64)ns;
326
3
}
327
328
329
#ifndef SFX_MODULE
330
const wchar *GetMonthName(int Month)
331
0
{
332
0
  return uiGetMonthName(Month);
333
0
}
334
#endif
335
336
337
bool IsLeapYear(int Year)
338
0
{
339
0
  return (Year&3)==0 && (Year%100!=0 || Year%400==0);
340
0
}