| #include "rar.hpp" |
| |
| namespace third_party_unrar { |
| |
| 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<char> 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<BinSize;I++) |
| { |
| uint High=Bin[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 && A<HexSize-2) // Need space for 2 chars and final zero. |
| { |
| HexA[A++]=(char)HighHex; |
| HexA[A++]=(char)LowHex; |
| } |
| if (HexW!=NULL && W<HexSize-2) // Need space for 2 chars and final zero. |
| { |
| HexW[W++]=HighHex; |
| HexW[W++]=LowHex; |
| } |
| } |
| if (HexA!=NULL && HexSize>0) |
| 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<Pos;I++) |
| Str[I]=NumStr[Pos-I-1]; |
| Str[Pos]=0; |
| } |
| |
| |
| void itoa(int64 n,wchar *Str,size_t MaxSize) |
| { |
| wchar 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++]=wchar(n%10)+'0'; |
| n=n/10; |
| } while (n!=0); |
| |
| if (Neg) |
| NumStr[Pos++]='-'; |
| |
| for (size_t I=0;I<Pos;I++) |
| Str[I]=NumStr[Pos-I-1]; |
| Str[Pos]=0; |
| } |
| |
| |
| const wchar* GetWide(const char *Src) |
| { |
| const size_t MaxLength=NM; |
| static wchar StrTable[4][MaxLength]; |
| static uint StrNum=0; |
| if (++StrNum >= 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<MaxSize-1) |
| Param[ParamSize++]='\"'; |
| CmdLine++; |
| } |
| else |
| Quote=!Quote; |
| } |
| else |
| if (Param!=NULL && ParamSize<MaxSize-1) |
| Param[ParamSize++]=*CmdLine; |
| CmdLine++; |
| } |
| if (Param!=NULL) |
| Param[ParamSize]=0; |
| return CmdLine; |
| } |
| |
| |
| #ifndef RARDLL |
| // For compatibility with existing translations we use %s to print Unicode |
| // strings in format strings and convert them to %ls here. %s could work |
| // without such conversion in Windows, but not in Unix wprintf. |
| void PrintfPrepareFmt(const wchar *Org,wchar *Cvt,size_t MaxSize) |
| { |
| uint Src=0,Dest=0; |
| while (Org[Src]!=0 && Dest<MaxSize-1) |
| { |
| if (Org[Src]=='%' && (Src==0 || Org[Src-1]!='%')) |
| { |
| uint SPos=Src+1; |
| // Skipping a possible width specifier like %-50s. |
| while (IsDigit(Org[SPos]) || Org[SPos]=='-') |
| SPos++; |
| if (Org[SPos]=='s' && Dest<MaxSize-(SPos-Src+1)) |
| { |
| while (Src<SPos) |
| Cvt[Dest++]=Org[Src++]; |
| Cvt[Dest++]='l'; |
| } |
| } |
| #ifdef _WIN_ALL |
| // Convert \n to \r\n in Windows. Important when writing to log, |
| // so other tools like Notebook can view resulting log properly. |
| if (Org[Src]=='\n' && (Src==0 || Org[Src-1]!='\r')) |
| Cvt[Dest++]='\r'; |
| #endif |
| |
| Cvt[Dest++]=Org[Src++]; |
| } |
| Cvt[Dest]=0; |
| } |
| #endif |
| |
| } |