xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Far/ProgressBox.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // ProgressBox.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/IntToString.h"
6 #include "../../../Common/StringConvert.h"
7 
8 #include "FarUtils.h"
9 #include "ProgressBox.h"
10 
ClearCurState()11 void CPercentPrinterState::ClearCurState()
12 {
13   Completed = 0;
14   Total = ((UInt64)(Int64)-1);
15   Files = 0;
16   FilesTotal = 0;
17   Command.Empty();
18   FileName.Empty();
19 }
20 
Init(const char * title)21 void CProgressBox::Init(const char *title)
22 {
23   _title = title;
24   _wasPrinted = false;
25   StartTick = GetTickCount();
26   _prevTick = StartTick;
27   _prevElapsedSec = 0;
28 }
29 
GetPower32(UInt32 val)30 static unsigned GetPower32(UInt32 val)
31 {
32   const unsigned kStart = 32;
33   UInt32 mask = ((UInt32)1 << (kStart - 1));
34   for (unsigned i = kStart;; i--)
35   {
36     if (i == 0 || (val & mask) != 0)
37       return i;
38     mask >>= 1;
39   }
40 }
41 
GetPower64(UInt64 val)42 static unsigned GetPower64(UInt64 val)
43 {
44   UInt32 high = (UInt32)(val >> 32);
45   if (high == 0)
46     return GetPower32((UInt32)val);
47   return GetPower32(high) + 32;
48 }
49 
MyMultAndDiv(UInt64 mult1,UInt64 mult2,UInt64 divider)50 static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider)
51 {
52   unsigned pow1 = GetPower64(mult1);
53   unsigned pow2 = GetPower64(mult2);
54   while (pow1 + pow2 > 64)
55   {
56     if (pow1 > pow2) { pow1--; mult1 >>= 1; }
57     else             { pow2--; mult2 >>= 1; }
58     divider >>= 1;
59   }
60   UInt64 res = mult1 * mult2;
61   if (divider != 0)
62     res /= divider;
63   return res;
64 }
65 
66 #define UINT_TO_STR_2(val) { s[0] = (char)('0' + (val) / 10); s[1] = (char)('0' + (val) % 10); s += 2; }
67 
GetTimeString(UInt64 timeValue,char * s)68 static void GetTimeString(UInt64 timeValue, char *s)
69 {
70   const UInt64 hours = timeValue / 3600;
71   UInt32 seconds = (UInt32)(timeValue - hours * 3600);
72   const UInt32 minutes = seconds / 60;
73   seconds %= 60;
74   if (hours > 99)
75   {
76     ConvertUInt64ToString(hours, s);
77     for (; *s != 0; s++);
78   }
79   else
80   {
81     const UInt32 hours32 = (UInt32)hours;
82     UINT_TO_STR_2(hours32)
83   }
84   *s++ = ':'; UINT_TO_STR_2(minutes)
85   *s++ = ':'; UINT_TO_STR_2(seconds)
86   *s = 0;
87 }
88 
ReduceString(const UString & src,AString & dest)89 void CProgressBox::ReduceString(const UString &src, AString &dest)
90 {
91   UnicodeStringToMultiByte2(dest, src, CP_OEMCP);
92 
93   if (dest.Len() <= MaxLen)
94     return;
95   unsigned len = FileName.Len();
96   for (; len != 0;)
97   {
98     unsigned delta = len / 8;
99     if (delta == 0)
100       delta = 1;
101     len -= delta;
102     _tempU = FileName;
103     _tempU.Delete(len / 2, FileName.Len() - len);
104     _tempU.Insert(len / 2, L" . ");
105     UnicodeStringToMultiByte2(dest, _tempU, CP_OEMCP);
106     if (dest.Len() <= MaxLen)
107       return;
108   }
109   dest.Empty();
110 }
111 
Print_UInt64_and_String(AString & s,UInt64 val,const char * name)112 static void Print_UInt64_and_String(AString &s, UInt64 val, const char *name)
113 {
114   char temp[32];
115   ConvertUInt64ToString(val, temp);
116   s += temp;
117   s.Add_Space();
118   s += name;
119 }
120 
121 
PrintSize_bytes_Smart(AString & s,UInt64 val)122 static void PrintSize_bytes_Smart(AString &s, UInt64 val)
123 {
124   // Print_UInt64_and_String(s, val, "bytes");
125   {
126     char temp[32];
127     ConvertUInt64ToString(val, temp);
128     s += temp;
129   }
130 
131   if (val == 0)
132     return;
133 
134   unsigned numBits = 10;
135   char c = 'K';
136   char temp[4] = { 'K', 'i', 'B', 0 };
137        if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; }
138   else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; }
139   temp[0] = c;
140   s += " (";
141   Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp);
142   s += ')';
143 }
144 
145 
146 static const unsigned kPercentsSize = 4;
147 
Print()148 void CProgressBox::Print()
149 {
150   DWORD tick = GetTickCount();
151   DWORD elapsedTicks = tick - StartTick;
152   DWORD elapsedSec = elapsedTicks / 1000;
153 
154   if (_wasPrinted)
155   {
156     if (elapsedSec == _prevElapsedSec)
157     {
158       if ((UInt32)(tick - _prevTick) < _tickStep)
159         return;
160       if (_printedState.IsEqualTo((const CPercentPrinterState &)*this))
161         return;
162     }
163   }
164 
165   UInt64 cur = Completed;
166   UInt64 total = Total;
167 
168   if (!UseBytesForPercents)
169   {
170     cur = Files;
171     total = FilesTotal;
172   }
173 
174   {
175     _timeStr.Empty();
176     _timeStr = "Elapsed time: ";
177     char s[40];
178     GetTimeString(elapsedSec, s);
179     _timeStr += s;
180 
181     if (cur != 0)
182     {
183       UInt64 remainingTime = 0;
184       if (cur < total)
185         remainingTime = MyMultAndDiv(elapsedTicks, total - cur, cur);
186       UInt64 remainingSec = remainingTime / 1000;
187       _timeStr += "    Remaining time: ";
188 
189       GetTimeString(remainingSec, s);
190       _timeStr += s;
191     }
192   }
193 
194 
195   {
196     _perc.Empty();
197     char s[32];
198     unsigned size;
199     {
200       UInt64 val = 0;
201       if (total != (UInt64)(Int64)-1 && total != 0)
202         val = cur * 100 / Total;
203 
204       ConvertUInt64ToString(val, s);
205       size = (unsigned)strlen(s);
206       s[size++] = '%';
207       s[size] = 0;
208     }
209 
210     unsigned len = size;
211     while (len < kPercentsSize)
212       len = kPercentsSize;
213     len++;
214 
215     if (len < MaxLen)
216     {
217       unsigned numChars = MaxLen - len;
218       unsigned filled = 0;
219       if (total != (UInt64)(Int64)-1 && total != 0)
220         filled = (unsigned)(cur * numChars / total);
221       if (filled > numChars)
222         filled = numChars;
223       unsigned i = 0;
224       for (i = 0; i < filled; i++)
225         _perc += (char)(Byte)0xDB; // '=';
226       for (; i < numChars; i++)
227         _perc += (char)(Byte)0xB0; // '.';
228     }
229 
230     _perc.Add_Space();
231     while (size < kPercentsSize)
232     {
233       _perc.Add_Space();
234       size++;
235     }
236     _perc += s;
237   }
238 
239   _files.Empty();
240   if (Files != 0 || FilesTotal != 0)
241   {
242     _files += "Files: ";
243     char s[32];
244     // if (Files != 0)
245     {
246       ConvertUInt64ToString(Files, s);
247       _files += s;
248     }
249     if (FilesTotal != 0)
250     {
251       _files += " / ";
252       ConvertUInt64ToString(FilesTotal, s);
253       _files += s;
254     }
255   }
256 
257   _sizesStr.Empty();
258   if (Total != 0)
259   {
260     _sizesStr += "Size: ";
261     PrintSize_bytes_Smart(_sizesStr, Completed);
262     if (Total != 0 && Total != (UInt64)(Int64)-1)
263     {
264       _sizesStr += " / ";
265       PrintSize_bytes_Smart(_sizesStr, Total);
266     }
267   }
268 
269   _name1.Empty();
270   _name2.Empty();
271 
272   if (!FileName.IsEmpty())
273   {
274     _name1U.Empty();
275     _name2U.Empty();
276 
277     /*
278     if (_isDir)
279       s1 = _filePath;
280     else
281     */
282     {
283       const int slashPos = FileName.ReverseFind_PathSepar();
284       if (slashPos >= 0)
285       {
286         _name1U.SetFrom(FileName, (unsigned)(slashPos + 1));
287         _name2U = FileName.Ptr(slashPos + 1);
288       }
289       else
290         _name2U = FileName;
291     }
292     ReduceString(_name1U, _name1);
293     ReduceString(_name2U, _name2);
294   }
295 
296   {
297     const char *strings[] = { _title, _timeStr, _files, _sizesStr, Command, _name1, _name2, _perc };
298     NFar::g_StartupInfo.ShowMessage(FMSG_LEFTALIGN, NULL, strings, Z7_ARRAY_SIZE(strings), 0);
299   }
300 
301   _wasPrinted = true;
302   _printedState = *this;
303   _prevTick = tick;
304   _prevElapsedSec = elapsedSec;
305 }
306