libclamunrar/strfn.cpp
d39cb658
 #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<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