unrarsrc  6.1.7
About: unrar extracts, views and tests the contents of archives created with the RAR archiver.
  Fossies Dox: unrarsrc-6.1.7.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

consio.cpp
Go to the documentation of this file.
1#include "rar.hpp"
2#include "log.cpp"
3
6static bool ProhibitInput=false;
7
8const int MaxMsgSize=2*NM+2048;
9
11
12#ifdef _WIN_ALL
13static 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
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
41 _setmode(_fileno(stdout), _O_U16TEXT);
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
54{
56}
57
58
60{
62}
63
64
66{
67 ProhibitInput=true;
68}
69
70
71#ifndef SILENT
72static 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
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;
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];
92 WideToUtf(Msg,MsgA,ASIZE(MsgA));
93 else
94 WideToChar(Msg,MsgA,ASIZE(MsgA));
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
118void mprintf(const wchar *fmt,...)
119{
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
135void 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
152{
153 // We cannot handle user prompts if -si is used to read file or archive data
154 // from stdin.
155 if (ProhibitInput)
156 {
159 }
160}
161
162
163static void GetPasswordText(wchar *Str,uint MaxLength)
164{
165 if (MaxLength==0)
166 return;
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
221bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
222{
223 if (!StdinRedirected)
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;
242 }
244 {
246 wchar CmpStr[MAXPASSWORD];
247 GetPasswordText(CmpStr,ASIZE(CmpStr));
248 if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0)
249 {
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
267bool getwstr(wchar *str,size_t n)
268{
269 // Print buffered prompt title function before waiting for input.
270 fflush(stderr);
271
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;
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.
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.
325int Ask(const wchar *AskStr)
326{
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
375static 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
392void 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}
ErrorHandler ErrHandler
Definition: array.hpp:7
size_t Size()
Definition: array.hpp:94
void Exit(RAR_EXIT ExitCode)
Definition: errhnd.cpp:236
Definition: file.hpp:57
void SetHandleType(FILE_HANDLETYPE Type)
Definition: file.hpp:124
virtual int Read(void *Data, size_t Size)
Definition: file.cpp:374
void SetLineInputMode(bool Mode)
Definition: file.hpp:125
void Set(const wchar *Psw)
void OutComment(const wchar *Comment, size_t Size)
Definition: consio.cpp:392
void eprintf(const wchar *fmt,...)
Definition: consio.cpp:135
static RAR_CHARSET RedirectCharset
Definition: consio.cpp:5
static void QuitIfInputProhibited()
Definition: consio.cpp:151
static bool StderrRedirected
Definition: consio.cpp:10
static bool StdoutRedirected
Definition: consio.cpp:10
static MESSAGE_TYPE MsgStream
Definition: consio.cpp:4
static bool IsCommentUnsafe(const wchar *Data, size_t Size)
Definition: consio.cpp:375
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
Definition: consio.cpp:59
static bool ProhibitInput
Definition: consio.cpp:6
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream)
Definition: consio.cpp:53
void InitConsole()
Definition: consio.cpp:22
static void cvt_wprintf(FILE *dest, const wchar *fmt, va_list arglist)
Definition: consio.cpp:72
static bool StdinRedirected
Definition: consio.cpp:10
bool GetConsolePassword(UIPASSWORD_TYPE Type, const wchar *FileName, SecPassword *Password)
Definition: consio.cpp:221
void ProhibitConsoleInput()
Definition: consio.cpp:65
int Ask(const wchar *AskStr)
Definition: consio.cpp:325
bool getwstr(wchar *str, size_t n)
Definition: consio.cpp:267
const int MaxMsgSize
Definition: consio.cpp:8
static void GetPasswordText(wchar *Str, uint MaxLength)
Definition: consio.cpp:163
void mprintf(const wchar *fmt,...)
Definition: consio.cpp:118
@ RARX_USERBREAK
Definition: errhnd.hpp:19
@ RARX_FATAL
Definition: errhnd.hpp:8
@ FILE_HANDLESTD
Definition: file.hpp:19
#define MStdinNoInput
Definition: loclang.hpp:392
#define MAskPswFor
Definition: loclang.hpp:153
#define MNotMatchPsw
Definition: loclang.hpp:155
#define MReAskPsw
Definition: loclang.hpp:154
#define MAskPsw
Definition: loclang.hpp:152
RAR_CHARSET
Definition: options.hpp:51
@ RCH_UTF8
Definition: options.hpp:51
@ RCH_OEM
Definition: options.hpp:51
@ RCH_DEFAULT
Definition: options.hpp:51
@ RCH_UNICODE
Definition: options.hpp:51
MESSAGE_TYPE
Definition: options.hpp:29
@ MSG_NULL
Definition: options.hpp:29
@ MSG_STDERR
Definition: options.hpp:29
@ MSG_ERRONLY
Definition: options.hpp:29
@ MSG_STDOUT
Definition: options.hpp:29
#define safebuf
Definition: os.hpp:235
#define Min(x, y)
Definition: rardefs.hpp:4
#define MAXPASSWORD
Definition: rardefs.hpp:14
#define ASIZE(x)
Definition: rardefs.hpp:10
wchar_t wchar
Definition: rartypes.hpp:13
unsigned int uint
Definition: rartypes.hpp:8
const wchar * St(MSGID StringId)
Definition: resource.cpp:8
void cleandata(void *data, size_t size)
Definition: secpassword.cpp:80
#define Ch(x, y, z)
Definition: sha256.cpp:26
void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen)
Definition: strfn.cpp:275
void strncpyz(char *dest, const char *src, size_t maxlen)
Definition: strfn.cpp:263
void PrintfPrepareFmt(const wchar *Org, wchar *Cvt, size_t MaxSize)
Definition: strfn.cpp:415
wchar * RemoveLF(wchar *Str)
Definition: strfn.cpp:116
bool IsDigit(int ch)
Definition: strfn.cpp:151
UIPASSWORD_TYPE
Definition: ui.hpp:90
@ UIPASSWORD_GLOBAL
Definition: ui.hpp:90
void uiAlarm(UIALARM_TYPE Type)
Definition: uiconsole.cpp:413
void uiMsg(UIMESSAGE_CODE Code)
Definition: ui.hpp:148
@ UIALARM_QUESTION
Definition: ui.hpp:94
@ UIERROR_TRUNCPSW
Definition: ui.hpp:42
bool WideToChar(const wchar *Src, char *Dest, size_t DestSize)
Definition: unicode.cpp:20
bool CharToWide(const char *Src, wchar *Dest, size_t DestSize)
Definition: unicode.cpp:85
void WideToUtf(const wchar *Src, char *Dest, size_t DestSize)
Definition: unicode.cpp:255
int toupperw(int ch)
Definition: unicode.cpp:523