Line | Count | Source (jump to first uncovered line) |
1 | | #include "rar.hpp" |
2 | | |
3 | | const char *NullToEmpty(const char *Str) |
4 | 0 | { |
5 | 0 | return Str==nullptr ? "":Str; |
6 | 0 | } |
7 | | |
8 | | |
9 | | const wchar *NullToEmpty(const wchar *Str) |
10 | 0 | { |
11 | 0 | return Str==nullptr ? L"":Str; |
12 | 0 | } |
13 | | |
14 | | |
15 | | // Convert from OEM encoding. |
16 | | void OemToExt(const std::string &Src,std::string &Dest) |
17 | 1.67k | { |
18 | | #ifdef _WIN_ALL |
19 | | if (std::addressof(Src)!=std::addressof(Dest)) |
20 | | Dest=Src; |
21 | | // OemToCharA use seems to be discouraged. So we use OemToCharBuffA, |
22 | | // which doesn't stop at 0 and converts the entire passed length. |
23 | | OemToCharBuffA(&Dest[0],&Dest[0],(DWORD)Dest.size()); |
24 | | |
25 | | std::string::size_type Pos=Dest.find('\0'); // Avoid zeroes inside of Dest. |
26 | | if (Pos!=std::string::npos) |
27 | | Dest.erase(Pos); |
28 | | |
29 | | #else |
30 | 1.67k | if (std::addressof(Src)!=std::addressof(Dest)) |
31 | 1.67k | Dest=Src; |
32 | 1.67k | #endif |
33 | 1.67k | } |
34 | | |
35 | | |
36 | | // Convert archived names and comments to Unicode. |
37 | | // Allows user to select a code page in GUI. |
38 | | void ArcCharToWide(const char *Src,std::wstring &Dest,ACTW_ENCODING Encoding) |
39 | 3.29k | { |
40 | | #if defined(_WIN_ALL) // Console Windows RAR. |
41 | | if (Encoding==ACTW_UTF8) |
42 | | UtfToWide(Src,Dest); |
43 | | else |
44 | | { |
45 | | std::string NameA; |
46 | | if (Encoding==ACTW_OEM) |
47 | | { |
48 | | OemToExt(Src,NameA); |
49 | | Src=NameA.data(); |
50 | | } |
51 | | CharToWide(Src,Dest); |
52 | | } |
53 | | #else // RAR for Unix. |
54 | 3.29k | if (Encoding==ACTW_UTF8) |
55 | 0 | UtfToWide(Src,Dest); |
56 | 3.29k | else |
57 | 3.29k | CharToWide(Src,Dest); |
58 | 3.29k | #endif |
59 | 3.29k | TruncateAtZero(Dest); // Ensure there are no zeroes inside of string. |
60 | 3.29k | } |
61 | | |
62 | | |
63 | | |
64 | | |
65 | | |
66 | | |
67 | | int stricomp(const char *s1,const char *s2) |
68 | 0 | { |
69 | | #ifdef _WIN_ALL |
70 | | return CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,-1,s2,-1)-2; |
71 | | #else |
72 | 0 | while (toupper(*s1)==toupper(*s2)) |
73 | 0 | { |
74 | 0 | if (*s1==0) |
75 | 0 | return 0; |
76 | 0 | s1++; |
77 | 0 | s2++; |
78 | 0 | } |
79 | 0 | return s1 < s2 ? -1 : 1; |
80 | 0 | #endif |
81 | 0 | } |
82 | | |
83 | | |
84 | | int strnicomp(const char *s1,const char *s2,size_t n) |
85 | 0 | { |
86 | | #ifdef _WIN_ALL |
87 | | // If we specify 'n' exceeding the actual string length, CompareString goes |
88 | | // beyond the trailing zero and compares garbage. So we need to limit 'n' |
89 | | // to real string length. |
90 | | // It is important to use strnlen (or memchr(...,0)) instead of strlen, |
91 | | // because data can be not zero terminated. |
92 | | size_t l1=Min(strnlen(s1,n),n); |
93 | | size_t l2=Min(strnlen(s2,n),n); |
94 | | return CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,(int)l1,s2,(int)l2)-2; |
95 | | #else |
96 | 0 | if (n==0) |
97 | 0 | return 0; |
98 | 0 | while (toupper(*s1)==toupper(*s2)) |
99 | 0 | { |
100 | 0 | if (*s1==0 || --n==0) |
101 | 0 | return 0; |
102 | 0 | s1++; |
103 | 0 | s2++; |
104 | 0 | } |
105 | 0 | return s1 < s2 ? -1 : 1; |
106 | 0 | #endif |
107 | 0 | } |
108 | | |
109 | | |
110 | | wchar* RemoveEOL(wchar *Str) |
111 | 0 | { |
112 | 0 | for (int I=(int)wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n' || Str[I]==' ' || Str[I]=='\t');I--) |
113 | 0 | Str[I]=0; |
114 | 0 | return Str; |
115 | 0 | } |
116 | | |
117 | | |
118 | | void RemoveEOL(std::wstring &Str) |
119 | 0 | { |
120 | 0 | while (!Str.empty()) |
121 | 0 | { |
122 | 0 | wchar c=Str.back(); |
123 | 0 | if (c=='\r' || c=='\n' || c==' ' || c=='\t') |
124 | 0 | Str.pop_back(); |
125 | 0 | else |
126 | 0 | break; |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | | |
131 | | wchar* RemoveLF(wchar *Str) |
132 | 0 | { |
133 | 0 | for (int I=(int)wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--) |
134 | 0 | Str[I]=0; |
135 | 0 | return Str; |
136 | 0 | } |
137 | | |
138 | | |
139 | | void RemoveLF(std::wstring &Str) |
140 | 0 | { |
141 | 0 | for (int I=(int)Str.size()-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--) |
142 | 0 | Str.erase(I); |
143 | 0 | } |
144 | | |
145 | | |
146 | | #if defined(SFX_MODULE) |
147 | | // char version of etoupperw. Used in console SFX module only. |
148 | | // Fast toupper for English only input and output. Additionally to speed, |
149 | | // it also avoids Turkish small i to big I with dot conversion problem. |
150 | | // We do not define 'c' as 'int' to avoid necessity to cast all |
151 | | // signed chars passed to this function to unsigned char. |
152 | | unsigned char etoupper(unsigned char c) |
153 | | { |
154 | | return c>='a' && c<='z' ? c-'a'+'A' : c; |
155 | | } |
156 | | #endif |
157 | | |
158 | | |
159 | | // Fast toupper for English only input and output. Additionally to speed, |
160 | | // it also avoids Turkish small i to big I with dot conversion problem. |
161 | | // We do not define 'c' as 'int' to avoid necessity to cast all |
162 | | // signed wchars passed to this function to unsigned char. |
163 | | wchar etoupperw(wchar c) |
164 | 3.15k | { |
165 | 3.15k | return c>='a' && c<='z' ? c-'a'+'A' : c; |
166 | 3.15k | } |
167 | | |
168 | | |
169 | | // We do not want to cast every signed char to unsigned when passing to |
170 | | // isdigit, so we implement the replacement. Shall work for Unicode too. |
171 | | // If chars are signed, conversion from char to int could generate negative |
172 | | // values, resulting in undefined behavior in standard isdigit. |
173 | | bool IsDigit(int ch) |
174 | 6.90k | { |
175 | 6.90k | return ch>='0' && ch<='9'; |
176 | 6.90k | } |
177 | | |
178 | | |
179 | | // We do not want to cast every signed char to unsigned when passing to |
180 | | // isspace, so we implement the replacement. Shall work for Unicode too. |
181 | | // If chars are signed, conversion from char to int could generate negative |
182 | | // values, resulting in undefined behavior in standard isspace. |
183 | | bool IsSpace(int ch) |
184 | 0 | { |
185 | 0 | return ch==' ' || ch=='\t'; |
186 | 0 | } |
187 | | |
188 | | |
189 | | // We do not want to cast every signed char to unsigned when passing to |
190 | | // isalpha, so we implement the replacement. Shall work for Unicode too. |
191 | | // If chars are signed, conversion from char to int could generate negative |
192 | | // values, resulting in undefined behavior in standard function. |
193 | | bool IsAlpha(int ch) |
194 | 0 | { |
195 | 0 | return ch>='A' && ch<='Z' || ch>='a' && ch<='z'; |
196 | 0 | } |
197 | | |
198 | | |
199 | | |
200 | | |
201 | | void BinToHex(const byte *Bin,size_t BinSize,std::wstring &Hex) |
202 | 0 | { |
203 | 0 | Hex.clear(); |
204 | 0 | for (uint I=0;I<BinSize;I++) |
205 | 0 | { |
206 | 0 | uint High=Bin[I] >> 4; |
207 | 0 | uint Low=Bin[I] & 0xf; |
208 | 0 | uint HighHex=High>9 ? 'a'+High-10 : '0'+High; |
209 | 0 | uint LowHex=Low>9 ? 'a'+Low-10 : '0'+Low; |
210 | 0 | Hex+=HighHex; |
211 | 0 | Hex+=LowHex; |
212 | 0 | } |
213 | 0 | } |
214 | | |
215 | | |
216 | | #ifndef SFX_MODULE |
217 | | uint GetDigits(uint Number) |
218 | 0 | { |
219 | 0 | uint Digits=1; |
220 | 0 | while (Number>=10) |
221 | 0 | { |
222 | 0 | Number/=10; |
223 | 0 | Digits++; |
224 | 0 | } |
225 | 0 | return Digits; |
226 | 0 | } |
227 | | #endif |
228 | | |
229 | | |
230 | | bool LowAscii(const std::string &Str) |
231 | 0 | { |
232 | 0 | for (char Ch : Str) |
233 | 0 | { |
234 | | // We convert char to byte in case char is signed. |
235 | 0 | if (/*(uint)Ch<32 || */(byte)Ch>127) |
236 | 0 | return false; |
237 | 0 | } |
238 | 0 | return true; |
239 | 0 | } |
240 | | |
241 | | |
242 | | bool LowAscii(const std::wstring &Str) |
243 | 0 | { |
244 | 0 | for (wchar Ch : Str) |
245 | 0 | { |
246 | | // We convert wchar_t to uint just in case if some compiler |
247 | | // uses signed wchar_t. |
248 | 0 | if (/*(uint)Ch<32 || */(uint)Ch>127) |
249 | 0 | return false; |
250 | 0 | } |
251 | 0 | return true; |
252 | 0 | } |
253 | | |
254 | | |
255 | | int wcsicompc(const wchar *s1,const wchar *s2) // For path comparison. |
256 | 76.2k | { |
257 | 76.2k | #if defined(_UNIX) |
258 | 76.2k | return wcscmp(s1,s2); |
259 | | #else |
260 | | return wcsicomp(s1,s2); |
261 | | #endif |
262 | 76.2k | } |
263 | | |
264 | | |
265 | | int wcsicompc(const std::wstring &s1,const std::wstring &s2) |
266 | 76.2k | { |
267 | 76.2k | return wcsicompc(s1.c_str(),s2.c_str()); |
268 | 76.2k | } |
269 | | |
270 | | |
271 | | int wcsnicompc(const wchar *s1,const wchar *s2,size_t n) |
272 | 0 | { |
273 | 0 | #if defined(_UNIX) |
274 | 0 | return wcsncmp(s1,s2,n); |
275 | | #else |
276 | | return wcsnicomp(s1,s2,n); |
277 | | #endif |
278 | 0 | } |
279 | | |
280 | | |
281 | | int wcsnicompc(const std::wstring &s1,const std::wstring &s2,size_t n) |
282 | 0 | { |
283 | 0 | return wcsnicompc(s1.c_str(),s2.c_str(),n); |
284 | 0 | } |
285 | | |
286 | | |
287 | | // Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest. |
288 | | void strncpyz(char *dest, const char *src, size_t maxlen) |
289 | 0 | { |
290 | 0 | if (maxlen>0) |
291 | 0 | { |
292 | 0 | while (--maxlen>0 && *src!=0) |
293 | 0 | *dest++=*src++; |
294 | 0 | *dest=0; |
295 | 0 | } |
296 | 0 | } |
297 | | |
298 | | |
299 | | // Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest. |
300 | | void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen) |
301 | 0 | { |
302 | 0 | if (maxlen>0) |
303 | 0 | { |
304 | 0 | while (--maxlen>0 && *src!=0) |
305 | 0 | *dest++=*src++; |
306 | 0 | *dest=0; |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | | |
311 | | // Safe append: resulting dest length cannot exceed maxlen and dest |
312 | | // is always zero terminated. 'maxlen' parameter defines the entire |
313 | | // dest buffer size and is not compatible with wcsncat. |
314 | | void strncatz(char* dest, const char* src, size_t maxlen) |
315 | 0 | { |
316 | 0 | size_t length = strlen(dest); |
317 | 0 | if (maxlen > length) |
318 | 0 | strncpyz(dest + length, src, maxlen - length); |
319 | 0 | } |
320 | | |
321 | | |
322 | | // Safe append: resulting dest length cannot exceed maxlen and dest |
323 | | // is always zero terminated. 'maxlen' parameter defines the entire |
324 | | // dest buffer size and is not compatible with wcsncat. |
325 | | void wcsncatz(wchar* dest, const wchar* src, size_t maxlen) |
326 | 0 | { |
327 | 0 | size_t length = wcslen(dest); |
328 | 0 | if (maxlen > length) |
329 | 0 | wcsncpyz(dest + length, src, maxlen - length); |
330 | 0 | } |
331 | | |
332 | | |
333 | | void itoa(int64 n,char *Str,size_t MaxSize) |
334 | 0 | { |
335 | 0 | char NumStr[50]; |
336 | 0 | size_t Pos=0; |
337 | |
|
338 | 0 | int Neg=n < 0 ? 1 : 0; |
339 | 0 | if (Neg) |
340 | 0 | n=-n; |
341 | |
|
342 | 0 | do |
343 | 0 | { |
344 | 0 | if (Pos+1>=MaxSize-Neg) |
345 | 0 | break; |
346 | 0 | NumStr[Pos++]=char(n%10)+'0'; |
347 | 0 | n=n/10; |
348 | 0 | } while (n!=0); |
349 | | |
350 | 0 | if (Neg) |
351 | 0 | NumStr[Pos++]='-'; |
352 | |
|
353 | 0 | for (size_t I=0;I<Pos;I++) |
354 | 0 | Str[I]=NumStr[Pos-I-1]; |
355 | 0 | Str[Pos]=0; |
356 | 0 | } |
357 | | |
358 | | |
359 | | void itoa(int64 n,wchar *Str,size_t MaxSize) |
360 | 0 | { |
361 | 0 | wchar NumStr[50]; |
362 | 0 | size_t Pos=0; |
363 | |
|
364 | 0 | int Neg=n < 0 ? 1 : 0; |
365 | 0 | if (Neg) |
366 | 0 | n=-n; |
367 | |
|
368 | 0 | do |
369 | 0 | { |
370 | 0 | if (Pos+1>=MaxSize-Neg) |
371 | 0 | break; |
372 | 0 | NumStr[Pos++]=wchar(n%10)+'0'; |
373 | 0 | n=n/10; |
374 | 0 | } while (n!=0); |
375 | | |
376 | 0 | if (Neg) |
377 | 0 | NumStr[Pos++]='-'; |
378 | |
|
379 | 0 | for (size_t I=0;I<Pos;I++) |
380 | 0 | Str[I]=NumStr[Pos-I-1]; |
381 | 0 | Str[Pos]=0; |
382 | 0 | } |
383 | | |
384 | | |
385 | | // Convert the number to string using thousand separators. |
386 | | void fmtitoa(int64 n,wchar *Str,size_t MaxSize) |
387 | 0 | { |
388 | 0 | static wchar ThSep=0; // Thousands separator. |
389 | | #ifdef _WIN_ALL |
390 | | wchar Info[10]; |
391 | | if (!ThSep!=0 && GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STHOUSAND,Info,ASIZE(Info))>0) |
392 | | ThSep=*Info; |
393 | | #elif defined(_UNIX) |
394 | | ThSep=*localeconv()->thousands_sep; |
395 | 0 | #endif |
396 | 0 | if (ThSep==0) // If failed to detect the actual separator value. |
397 | 0 | ThSep=' '; |
398 | 0 | wchar RawText[30]; // 20 characters are enough for largest unsigned 64 bit int. |
399 | 0 | itoa(n,RawText,ASIZE(RawText)); |
400 | 0 | uint S=0,D=0,L=wcslen(RawText)%3; |
401 | 0 | while (RawText[S]!=0 && D+1<MaxSize) |
402 | 0 | { |
403 | 0 | if (S!=0 && (S+3-L)%3==0) |
404 | 0 | Str[D++]=ThSep; |
405 | 0 | Str[D++]=RawText[S++]; |
406 | 0 | } |
407 | 0 | Str[D]=0; |
408 | 0 | } |
409 | | |
410 | | |
411 | | std::wstring GetWide(const char *Src) |
412 | 0 | { |
413 | 0 | std::wstring Str; |
414 | 0 | CharToWide(Src,Str); |
415 | 0 | return Str; |
416 | 0 | } |
417 | | |
418 | | |
419 | | // Parse string containing parameters separated with spaces. |
420 | | // Support quote marks. Accepts and updates the current position in the string. |
421 | | // Returns false if there is nothing to parse. |
422 | | bool GetCmdParam(const std::wstring &CmdLine,std::wstring::size_type &Pos,std::wstring &Param) |
423 | 0 | { |
424 | 0 | Param.clear(); |
425 | |
|
426 | 0 | while (IsSpace(CmdLine[Pos])) |
427 | 0 | Pos++; |
428 | 0 | if (Pos==CmdLine.size()) |
429 | 0 | return false; |
430 | | |
431 | 0 | bool Quote=false; |
432 | 0 | while (Pos<CmdLine.size() && (Quote || !IsSpace(CmdLine[Pos]))) |
433 | 0 | { |
434 | 0 | if (CmdLine[Pos]=='\"') |
435 | 0 | { |
436 | 0 | if (CmdLine[Pos+1]=='\"') |
437 | 0 | { |
438 | | // Insert the quote character instead of two adjoining quote characters. |
439 | 0 | Param+='\"'; |
440 | 0 | Pos++; |
441 | 0 | } |
442 | 0 | else |
443 | 0 | Quote=!Quote; |
444 | 0 | } |
445 | 0 | else |
446 | 0 | Param+=CmdLine[Pos]; |
447 | 0 | Pos++; |
448 | 0 | } |
449 | 0 | return true; |
450 | 0 | } |
451 | | |
452 | | |
453 | | |
454 | | |
455 | | #ifndef RARDLL |
456 | | // For compatibility with existing translations we use %s to print Unicode |
457 | | // strings in format strings and convert them to %ls here. %s could work |
458 | | // without such conversion in Windows, but not in Unix wprintf. |
459 | | void PrintfPrepareFmt(const wchar *Org,std::wstring &Cvt) |
460 | | { |
461 | | size_t Src=0; |
462 | | while (Org[Src]!=0) |
463 | | { |
464 | | if (Org[Src]=='%' && (Src==0 || Org[Src-1]!='%')) |
465 | | { |
466 | | size_t SPos=Src+1; |
467 | | // Skipping a possible width specifier like %-50s. |
468 | | while (IsDigit(Org[SPos]) || Org[SPos]=='-') |
469 | | SPos++; |
470 | | if (Org[SPos]=='s') |
471 | | { |
472 | | while (Src<SPos) |
473 | | Cvt.push_back(Org[Src++]); |
474 | | Cvt.push_back('l'); |
475 | | } |
476 | | } |
477 | | #ifdef _WIN_ALL |
478 | | // Convert \n to \r\n in Windows. Important when writing to log, |
479 | | // so other tools like Notebook can view resulting log properly. |
480 | | if (Org[Src]=='\n' && (Src==0 || Org[Src-1]!='\r')) |
481 | | Cvt.push_back('\r'); |
482 | | #endif |
483 | | |
484 | | Cvt.push_back(Org[Src++]); |
485 | | } |
486 | | } |
487 | | |
488 | | |
489 | | // Print output to std::wstring. |
490 | | std::wstring wstrprintf(const wchar *fmt,...) |
491 | | { |
492 | | va_list arglist; |
493 | | va_start(arglist,fmt); |
494 | | std::wstring s=vwstrprintf(fmt,arglist); |
495 | | va_end(arglist); |
496 | | return s; |
497 | | } |
498 | | |
499 | | |
500 | | std::wstring vwstrprintf(const wchar *fmt,va_list arglist) |
501 | | { |
502 | | std::wstring fmtw; |
503 | | PrintfPrepareFmt(fmt,fmtw); |
504 | | |
505 | | // We also tried to use _vscwprintf in MSVC to calculate the required buffer |
506 | | // size and allocate the exactly such size, but it seemed to be a little |
507 | | // slower than approach below. |
508 | | |
509 | | const size_t MaxAllocSize=0x10000; // Prevent the excessive allocation. |
510 | | |
511 | | // vswprintf returns only the error status without required buffer size, |
512 | | // so we try different buffer sizes. Start from reasonably small size |
513 | | // to reduce the zero initialization cost, but still large enough to fit |
514 | | // most of strings and avoid additional loop iterations. |
515 | | std::wstring Msg(256,L'\0'); |
516 | | while (true) |
517 | | { |
518 | | va_list argscopy; |
519 | | va_copy(argscopy, arglist); |
520 | | int r=vswprintf(&Msg[0],Msg.size(),fmtw.c_str(),argscopy); |
521 | | va_end(argscopy); |
522 | | if (r>=0 || Msg.size()>MaxAllocSize) |
523 | | break; |
524 | | Msg.resize(Msg.size()*4); |
525 | | } |
526 | | std::wstring::size_type ZeroPos=Msg.find(L'\0'); |
527 | | if (ZeroPos!=std::wstring::npos) |
528 | | Msg.resize(ZeroPos); // Remove excessive zeroes at the end. |
529 | | |
530 | | return Msg; |
531 | | } |
532 | | #endif |
533 | | |
534 | | |
535 | | #ifdef _WIN_ALL |
536 | | bool ExpandEnvironmentStr(std::wstring &Str) |
537 | | { |
538 | | DWORD ExpCode=ExpandEnvironmentStrings(Str.c_str(),nullptr,0); |
539 | | if (ExpCode==0) |
540 | | return false; |
541 | | std::vector<wchar> Buf(ExpCode); |
542 | | ExpCode=ExpandEnvironmentStrings(Str.c_str(),Buf.data(),(DWORD)Buf.size()); |
543 | | if (ExpCode==0 || ExpCode>Buf.size()) |
544 | | return false; |
545 | | Str=Buf.data(); |
546 | | return true; |
547 | | } |
548 | | #endif |
549 | | |
550 | | |
551 | | void TruncateAtZero(std::wstring &Str) |
552 | 84.2k | { |
553 | 84.2k | std::wstring::size_type Pos=Str.find(L'\0'); |
554 | 84.2k | if (Pos!=std::wstring::npos) |
555 | 1.61k | Str.erase(Pos); |
556 | 84.2k | } |
557 | | |
558 | | |
559 | | void ReplaceEsc(std::wstring &Str) |
560 | 0 | { |
561 | 0 | std::wstring::size_type Pos=0; |
562 | 0 | while (true) |
563 | 0 | { |
564 | 0 | Pos=Str.find(L'\033',Pos); |
565 | 0 | if (Pos==std::wstring::npos) |
566 | 0 | break; |
567 | 0 | Str[Pos]=L'\''; |
568 | 0 | Str.insert(Pos+1,L"\\033'"); |
569 | 0 | Pos+=6; |
570 | 0 | } |
571 | 0 | } |