#include "rar.hpp" const char *NullToEmpty(const char *Str) { return Str==NULL ? "":Str; } const wchar *NullToEmpty(const wchar *Str) { return Str==NULL ? L"":Str; } void IntToExt(const char *Src,char *Dest,size_t DestSize) { #ifdef _WIN_ALL // OemToCharBuff does not stop at 0, so let's check source length. size_t SrcLength=strlen(Src)+1; if (DestSize>SrcLength) DestSize=SrcLength; OemToCharBuffA(Src,Dest,(DWORD)DestSize); Dest[DestSize-1]=0; #else if (Dest!=Src) strncpyz(Dest,Src,DestSize); #endif } // Convert archived names and comments to Unicode. // Allows user to select a code page in GUI. void ArcCharToWide(const char *Src,wchar *Dest,size_t DestSize,ACTW_ENCODING Encoding) { #if defined(_WIN_ALL) // Console Windows RAR. if (Encoding==ACTW_UTF8) UtfToWide(Src,Dest,DestSize); else { Array NameA; if (Encoding==ACTW_OEM) { NameA.Alloc(DestSize+1); IntToExt(Src,&NameA[0],NameA.Size()); Src=&NameA[0]; } CharToWide(Src,Dest,DestSize); } #else // RAR for Unix. if (Encoding==ACTW_UTF8) UtfToWide(Src,Dest,DestSize); else CharToWide(Src,Dest,DestSize); #endif // Ensure that we return a zero terminate string for security reason. // While [Jni]CharToWide might already do it, be protected in case of future // changes in these functions. if (DestSize>0) Dest[DestSize-1]=0; } int stricomp(const char *s1,const char *s2) { #ifdef _WIN_ALL return CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,-1,s2,-1)-2; #else while (toupper(*s1)==toupper(*s2)) { if (*s1==0) return 0; s1++; s2++; } return s1 < s2 ? -1 : 1; #endif } int strnicomp(const char *s1,const char *s2,size_t n) { #ifdef _WIN_ALL // If we specify 'n' exceeding the actual string length, CompareString goes // beyond the trailing zero and compares garbage. So we need to limit 'n' // to real string length. // It is important to use strnlen (or memchr(...,0)) instead of strlen, // because data can be not zero terminated. size_t l1=Min(strnlen(s1,n),n); size_t l2=Min(strnlen(s2,n),n); return CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,(int)l1,s2,(int)l2)-2; #else if (n==0) return 0; while (toupper(*s1)==toupper(*s2)) { if (*s1==0 || --n==0) return 0; s1++; s2++; } return s1 < s2 ? -1 : 1; #endif } wchar* RemoveEOL(wchar *Str) { for (int I=(int)wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n' || Str[I]==' ' || Str[I]=='\t');I--) Str[I]=0; return Str; } wchar* RemoveLF(wchar *Str) { for (int I=(int)wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--) Str[I]=0; return Str; } unsigned char loctolower(unsigned char ch) { #if defined(_WIN_ALL) // Convert to LPARAM first to avoid a warning in 64 bit mode. // Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast] return (int)(LPARAM)CharLowerA((LPSTR)(uintptr_t)ch); #else return tolower(ch); #endif } unsigned char loctoupper(unsigned char ch) { #if defined(_WIN_ALL) // Convert to LPARAM first to avoid a warning in 64 bit mode. // Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast] return (int)(LPARAM)CharUpperA((LPSTR)(uintptr_t)ch); #else return toupper(ch); #endif } // toupper with English only results if English input is provided. // It avoids Turkish (small i) -> (big I with dot) conversion problem. // We do not define 'ch' as 'int' to avoid necessity to cast all // signed chars passed to this function to unsigned char. unsigned char etoupper(unsigned char ch) { if (ch=='i') return 'I'; return toupper(ch); } // Unicode version of etoupper. wchar etoupperw(wchar ch) { if (ch=='i') return 'I'; return toupperw(ch); } // We do not want to cast every signed char to unsigned when passing to // isdigit, so we implement the replacement. Shall work for Unicode too. // If chars are signed, conversion from char to int could generate negative // values, resulting in undefined behavior in standard isdigit. bool IsDigit(int ch) { return ch>='0' && ch<='9'; } // We do not want to cast every signed char to unsigned when passing to // isspace, so we implement the replacement. Shall work for Unicode too. // If chars are signed, conversion from char to int could generate negative // values, resulting in undefined behavior in standard isspace. bool IsSpace(int ch) { return ch==' ' || ch=='\t'; } // We do not want to cast every signed char to unsigned when passing to // isalpha, so we implement the replacement. Shall work for Unicode too. // If chars are signed, conversion from char to int could generate negative // values, resulting in undefined behavior in standard function. bool IsAlpha(int ch) { return ch>='A' && ch<='Z' || ch>='a' && ch<='z'; } void BinToHex(const byte *Bin,size_t BinSize,char *HexA,wchar *HexW,size_t HexSize) { uint A=0,W=0; // ASCII and Unicode hex output positions. for (uint I=0;I> 4; uint Low=Bin[I] & 0xf; uint HighHex=High>9 ? 'a'+High-10:'0'+High; uint LowHex=Low>9 ? 'a'+Low-10:'0'+Low; if (HexA!=NULL && A0) HexA[A]=0; if (HexW!=NULL && HexSize>0) HexW[W]=0; } #ifndef SFX_MODULE uint GetDigits(uint Number) { uint Digits=1; while (Number>=10) { Number/=10; Digits++; } return Digits; } #endif bool LowAscii(const char *Str) { for (int I=0;Str[I]!=0;I++) if ((byte)Str[I]<32 || (byte)Str[I]>127) return false; return true; } bool LowAscii(const wchar *Str) { for (int I=0;Str[I]!=0;I++) { // We convert wchar_t to uint just in case if some compiler // uses signed wchar_t. if ((uint)Str[I]<32 || (uint)Str[I]>127) return false; } return true; } int wcsicompc(const wchar *s1,const wchar *s2) // For path comparison. { #if defined(_UNIX) return wcscmp(s1,s2); #else return wcsicomp(s1,s2); #endif } int wcsnicompc(const wchar *s1,const wchar *s2,size_t n) { #if defined(_UNIX) return wcsncmp(s1,s2,n); #else return wcsnicomp(s1,s2,n); #endif } // Safe strncpy: copies maxlen-1 max and always returns zero terminated dest. char* strncpyz(char *dest, const char *src, size_t maxlen) { if (maxlen>0) { strncpy(dest,src,maxlen-1); dest[maxlen-1]=0; } return dest; } // Safe wcsncpy: copies maxlen-1 max and always returns zero terminated dest. wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen) { if (maxlen>0) { wcsncpy(dest,src,maxlen-1); dest[maxlen-1]=0; } return dest; } // Safe strncat: resulting dest length cannot exceed maxlen and dest // is always zero terminated. Note that 'maxlen' parameter defines the entire // dest buffer size and is not compatible with standard strncat. char* strncatz(char* dest, const char* src, size_t maxlen) { size_t Length = strlen(dest); int avail=int(maxlen - Length - 1); if (avail > 0) strncat(dest, src, avail); return dest; } // Safe wcsncat: resulting dest length cannot exceed maxlen and dest // is always zero terminated. Note that 'maxlen' parameter defines the entire // dest buffer size and is not compatible with standard wcsncat. wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen) { size_t Length = wcslen(dest); int avail=int(maxlen - Length - 1); if (avail > 0) wcsncat(dest, src, avail); return dest; } void itoa(int64 n,char *Str,size_t MaxSize) { char NumStr[50]; size_t Pos=0; int Neg=n < 0 ? 1 : 0; if (Neg) n=-n; do { if (Pos+1>=MaxSize-Neg) break; NumStr[Pos++]=char(n%10)+'0'; n=n/10; } while (n!=0); if (Neg) NumStr[Pos++]='-'; for (size_t I=0;I=MaxSize-Neg) break; NumStr[Pos++]=wchar(n%10)+'0'; n=n/10; } while (n!=0); if (Neg) NumStr[Pos++]='-'; for (size_t I=0;I= ASIZE(StrTable)) StrNum=0; wchar *Str=StrTable[StrNum]; CharToWide(Src,Str,MaxLength); Str[MaxLength-1]=0; return Str; } // Parse string containing parameters separated with spaces. // Support quote marks. Param can be NULL to return the pointer to next // parameter, which can be used to estimate the buffer size for Param. const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize) { while (IsSpace(*CmdLine)) CmdLine++; if (*CmdLine==0) return NULL; size_t ParamSize=0; bool Quote=false; while (*CmdLine!=0 && (Quote || !IsSpace(*CmdLine))) { if (*CmdLine=='\"') { if (CmdLine[1]=='\"') { // Insert the quote character instead of two adjoining quote characters. if (Param!=NULL && ParamSize