"Fossies" - the Fresh Open Source Software Archive

Member "unrar/consio.cpp" (4 May 2022, 11213 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "consio.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 6.1.4_vs_6.1.5.

    1 #include "rar.hpp"
    2 #include "log.cpp"
    3 
    4 static MESSAGE_TYPE MsgStream=MSG_STDOUT;
    5 static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
    6 static bool ProhibitInput=false;
    7 
    8 const int MaxMsgSize=2*NM+2048;
    9 
   10 static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
   11 
   12 #ifdef _WIN_ALL
   13 static bool IsRedirected(DWORD nStdHandle)
   14 {
   15   HANDLE hStd=GetStdHandle(nStdHandle);
   16   DWORD Mode;
   17   return GetFileType(hStd)!=FILE_TYPE_CHAR || GetConsoleMode(hStd,&Mode)==0;
   18 }
   19 #endif
   20 
   21 
   22 void InitConsole()
   23 {
   24 #ifdef _WIN_ALL
   25   // We want messages like file names or progress percent to be printed
   26   // immediately. Use only in Windows, in Unix they can cause wprintf %ls
   27   // to fail with non-English strings.
   28   setbuf(stdout,NULL);
   29   setbuf(stderr,NULL);
   30 
   31   // Detect if output is redirected and set output mode properly.
   32   // We do not want to send Unicode output to files and especially to pipes
   33   // like '|more', which cannot handle them correctly in Windows.
   34   // In Unix console output is UTF-8 and it is handled correctly
   35   // when redirecting, so no need to perform any adjustments.
   36   StdoutRedirected=IsRedirected(STD_OUTPUT_HANDLE);
   37   StderrRedirected=IsRedirected(STD_ERROR_HANDLE);
   38   StdinRedirected=IsRedirected(STD_INPUT_HANDLE);
   39 #ifdef _MSC_VER
   40   if (!StdoutRedirected)
   41     _setmode(_fileno(stdout), _O_U16TEXT);
   42   if (!StderrRedirected)
   43     _setmode(_fileno(stderr), _O_U16TEXT);
   44 #endif
   45 #elif defined(_UNIX)
   46   StdoutRedirected=!isatty(fileno(stdout));
   47   StderrRedirected=!isatty(fileno(stderr));
   48   StdinRedirected=!isatty(fileno(stdin));
   49 #endif
   50 }
   51 
   52 
   53 void SetConsoleMsgStream(MESSAGE_TYPE MsgStream)
   54 {
   55   ::MsgStream=MsgStream;
   56 }
   57 
   58 
   59 void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
   60 {
   61   ::RedirectCharset=RedirectCharset;
   62 }
   63 
   64 
   65 void ProhibitConsoleInput()
   66 {
   67   ProhibitInput=true;
   68 }
   69 
   70 
   71 #ifndef SILENT
   72 static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
   73 {
   74   // This buffer is for format string only, not for entire output,
   75   // so it can be short enough.
   76   wchar fmtw[1024];
   77   PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
   78 #ifdef _WIN_ALL
   79   safebuf wchar Msg[MaxMsgSize];
   80   if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected)
   81   {
   82     HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE);
   83     vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
   84     DWORD Written;
   85     if (RedirectCharset==RCH_UNICODE)
   86       WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL);
   87     else
   88     {
   89       // Avoid Unicode for redirect in Windows, it does not work with pipes.
   90       safebuf char MsgA[MaxMsgSize];
   91       if (RedirectCharset==RCH_UTF8)
   92         WideToUtf(Msg,MsgA,ASIZE(MsgA));
   93       else
   94         WideToChar(Msg,MsgA,ASIZE(MsgA));
   95       if (RedirectCharset==RCH_DEFAULT || RedirectCharset==RCH_OEM)
   96         CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding.
   97 
   98       // We already converted \n to \r\n above, so we use WriteFile instead
   99       // of C library to avoid unnecessary additional conversion.
  100       WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL);
  101     }
  102     return;
  103   }
  104   // MSVC2008 vfwprintf writes every character to console separately
  105   // and it is too slow. We use direct WriteConsole call instead.
  106   vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
  107   HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE);
  108   DWORD Written;
  109   WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL);
  110 #else
  111   vfwprintf(dest,fmtw,arglist);
  112   // We do not use setbuf(NULL) in Unix (see comments in InitConsole).
  113   fflush(dest);
  114 #endif
  115 }
  116 
  117 
  118 void mprintf(const wchar *fmt,...)
  119 {
  120   if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY)
  121     return;
  122 
  123   fflush(stderr); // Ensure proper message order.
  124 
  125   va_list arglist;
  126   va_start(arglist,fmt);
  127   FILE *dest=MsgStream==MSG_STDERR ? stderr:stdout;
  128   cvt_wprintf(dest,fmt,arglist);
  129   va_end(arglist);
  130 }
  131 #endif
  132 
  133 
  134 #ifndef SILENT
  135 void eprintf(const wchar *fmt,...)
  136 {
  137   if (MsgStream==MSG_NULL)
  138     return;
  139 
  140   fflush(stdout); // Ensure proper message order.
  141 
  142   va_list arglist;
  143   va_start(arglist,fmt);
  144   cvt_wprintf(stderr,fmt,arglist);
  145   va_end(arglist);
  146 }
  147 #endif
  148 
  149 
  150 #ifndef SILENT
  151 static void QuitIfInputProhibited()
  152 {
  153   // We cannot handle user prompts if -si is used to read file or archive data
  154   // from stdin.
  155   if (ProhibitInput)
  156   {
  157     mprintf(St(MStdinNoInput));
  158     ErrHandler.Exit(RARX_FATAL);
  159   }
  160 }
  161 
  162 
  163 static void GetPasswordText(wchar *Str,uint MaxLength)
  164 {
  165   if (MaxLength==0)
  166     return;
  167   QuitIfInputProhibited();
  168   if (StdinRedirected)
  169     getwstr(Str,MaxLength); // Read from pipe or redirected file.
  170   else
  171   {
  172 #ifdef _WIN_ALL
  173     HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE);
  174     DWORD ConInMode;
  175     GetConsoleMode(hConIn,&ConInMode);
  176     SetConsoleMode(hConIn,ENABLE_LINE_INPUT); // Remove ENABLE_ECHO_INPUT.
  177 
  178     // We prefer ReadConsole to ReadFile, so we can read Unicode input.
  179     DWORD Read=0;
  180     ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
  181     Str[Read]=0;
  182     SetConsoleMode(hConIn,ConInMode);
  183 
  184     // If entered password is longer than MAXPASSWORD and truncated,
  185     // read its unread part anyway, so it isn't read later as the second
  186     // password for -p switch. Low level FlushConsoleInputBuffer doesn't help
  187     // for high level ReadConsole, which in line input mode seems to store
  188     // the rest of string in its own internal buffer.
  189     if (wcschr(Str,'\r')==NULL) // If '\r' is missing, the password was truncated.
  190       while (true)
  191       {
  192         wchar Trail[64];
  193         DWORD TrailRead=0;
  194         // Use ASIZE(Trail)-1 to reserve the space for trailing 0.
  195         ReadConsole(hConIn,Trail,ASIZE(Trail)-1,&TrailRead,NULL);
  196         Trail[TrailRead]=0;
  197         if (TrailRead==0 || wcschr(Trail,'\r')!=NULL)
  198           break;
  199       }
  200 
  201 #else
  202     char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters.
  203 #if defined(_EMX) || defined (__VMS)
  204     fgets(StrA,ASIZE(StrA)-1,stdin);
  205 #elif defined(__sun)
  206     strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
  207 #else
  208     strncpyz(StrA,getpass(""),ASIZE(StrA));
  209 #endif
  210     CharToWide(StrA,Str,MaxLength);
  211     cleandata(StrA,sizeof(StrA));
  212 #endif
  213   }
  214   Str[MaxLength-1]=0;
  215   RemoveLF(Str);
  216 }
  217 #endif
  218 
  219 
  220 #ifndef SILENT
  221 bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
  222 {
  223   if (!StdinRedirected)
  224     uiAlarm(UIALARM_QUESTION);
  225   
  226   while (true)
  227   {
  228 //    if (!StdinRedirected)
  229       if (Type==UIPASSWORD_GLOBAL)
  230         eprintf(L"\n%s: ",St(MAskPsw));
  231       else
  232         eprintf(St(MAskPswFor),FileName);
  233 
  234     wchar PlainPsw[MAXPASSWORD+1];
  235     GetPasswordText(PlainPsw,ASIZE(PlainPsw));
  236     if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
  237       return false;
  238     if (wcslen(PlainPsw)>=MAXPASSWORD)
  239     {
  240       PlainPsw[MAXPASSWORD-1]=0;
  241       uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
  242     }
  243     if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
  244     {
  245       eprintf(St(MReAskPsw));
  246       wchar CmpStr[MAXPASSWORD];
  247       GetPasswordText(CmpStr,ASIZE(CmpStr));
  248       if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0)
  249       {
  250         eprintf(St(MNotMatchPsw));
  251         cleandata(PlainPsw,sizeof(PlainPsw));
  252         cleandata(CmpStr,sizeof(CmpStr));
  253         continue;
  254       }
  255       cleandata(CmpStr,sizeof(CmpStr));
  256     }
  257     Password->Set(PlainPsw);
  258     cleandata(PlainPsw,sizeof(PlainPsw));
  259     break;
  260   }
  261   return true;
  262 }
  263 #endif
  264 
  265 
  266 #ifndef SILENT
  267 bool getwstr(wchar *str,size_t n)
  268 {
  269   // Print buffered prompt title function before waiting for input.
  270   fflush(stderr);
  271 
  272   QuitIfInputProhibited();
  273 
  274   *str=0;
  275 #if defined(_WIN_ALL)
  276   // fgetws does not work well with non-English text in Windows,
  277   // so we do not use it.
  278   if (StdinRedirected) // ReadConsole does not work if redirected.
  279   {
  280     // fgets does not work well with pipes in Windows in our test.
  281     // Let's use files.
  282     Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
  283     File SrcFile;
  284     SrcFile.SetHandleType(FILE_HANDLESTD);
  285     SrcFile.SetLineInputMode(true);
  286     int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
  287     if (ReadSize<=0)
  288     {
  289       // Looks like stdin is a null device. We can enter to infinite loop
  290       // calling Ask(), so let's better exit.
  291       ErrHandler.Exit(RARX_USERBREAK);
  292     }
  293     StrA[ReadSize]=0;
  294 
  295     // We expect ANSI encoding here, but "echo text|rar ..." to pipe to RAR,
  296     // such as send passwords, we get OEM encoding by default, unless we
  297     // use "chcp" in console. But we avoid OEM to ANSI conversion,
  298     // because we also want to handle ANSI files redirection correctly,
  299     // like "rar ... < ansifile.txt".
  300     CharToWide(&StrA[0],str,n);
  301     cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords.
  302   }
  303   else
  304   {
  305     DWORD ReadSize=0;
  306     if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
  307       return false;
  308     str[ReadSize]=0;
  309   }
  310 #else
  311   if (fgetws(str,n,stdin)==NULL)
  312     ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
  313 #endif
  314   RemoveLF(str);
  315   return true;
  316 }
  317 #endif
  318 
  319 
  320 #ifndef SILENT
  321 // We allow this function to return 0 in case of invalid input,
  322 // because it might be convenient to press Enter to some not dangerous
  323 // prompts like "insert disk with next volume". We should call this function
  324 // again in case of 0 in dangerous prompt such as overwriting file.
  325 int Ask(const wchar *AskStr)
  326 {
  327   uiAlarm(UIALARM_QUESTION);
  328 
  329   const int MaxItems=10;
  330   wchar Item[MaxItems][40];
  331   int ItemKeyPos[MaxItems],NumItems=0;
  332 
  333   for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
  334   {
  335     wchar *CurItem=Item[NumItems];
  336     wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
  337     wchar *EndItem=wcschr(CurItem,'_');
  338     if (EndItem!=NULL)
  339       *EndItem=0;
  340     int KeyPos=0,CurKey;
  341     while ((CurKey=CurItem[KeyPos])!=0)
  342     {
  343       bool Found=false;
  344       for (int I=0;I<NumItems && !Found;I++)
  345         if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey))
  346           Found=true;
  347       if (!Found && CurKey!=' ')
  348         break;
  349       KeyPos++;
  350     }
  351     ItemKeyPos[NumItems]=KeyPos;
  352     NumItems++;
  353   }
  354 
  355   for (int I=0;I<NumItems;I++)
  356   {
  357     eprintf(I==0 ? (NumItems>3 ? L"\n":L" "):L", ");
  358     int KeyPos=ItemKeyPos[I];
  359     for (int J=0;J<KeyPos;J++)
  360       eprintf(L"%c",Item[I][J]);
  361     eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
  362   }
  363   eprintf(L" ");
  364   wchar Str[50];
  365   getwstr(Str,ASIZE(Str));
  366   wchar Ch=toupperw(Str[0]);
  367   for (int I=0;I<NumItems;I++)
  368     if (Ch==Item[I][ItemKeyPos[I]])
  369       return I+1;
  370   return 0;
  371 }
  372 #endif
  373 
  374 
  375 static bool IsCommentUnsafe(const wchar *Data,size_t Size)
  376 {
  377   for (size_t I=0;I<Size;I++)
  378     if (Data[I]==27 && Data[I+1]=='[')
  379       for (size_t J=I+2;J<Size;J++)
  380       {
  381         // Return true for <ESC>[{key};"{string}"p used to redefine
  382         // a keyboard key on some terminals.
  383         if (Data[J]=='\"')
  384           return true;
  385         if (!IsDigit(Data[J]) && Data[J]!=';')
  386           break;
  387       }
  388   return false;
  389 }
  390 
  391 
  392 void OutComment(const wchar *Comment,size_t Size)
  393 {
  394   if (IsCommentUnsafe(Comment,Size))
  395     return;
  396   const size_t MaxOutSize=0x400;
  397   for (size_t I=0;I<Size;I+=MaxOutSize)
  398   {
  399     wchar Msg[MaxOutSize+1];
  400     size_t CopySize=Min(MaxOutSize,Size-I);
  401     wcsncpy(Msg,Comment+I,CopySize);
  402     Msg[CopySize]=0;
  403     mprintf(L"%s",Msg);
  404   }
  405   mprintf(L"\n");
  406 }