blob: 3697d09930f69babcb9d5fec661acfa6e3c181d7 [file] [log] [blame]
#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
}