ReactOS  0.4.12-dev-102-g4b7f1e0
extrac32.c
Go to the documentation of this file.
1 /*
2  * Extract - Wine-compatible program for extract *.cab files.
3  *
4  * Copyright 2007 Etersoft (Lyutin Anatoly)
5  * Copyright 2009 Ilya Shpigor
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <windows.h>
23 #include <shellapi.h>
24 #include <setupapi.h>
25 #include <shlwapi.h>
26 #include <shlobj.h>
27 
28 #include "wine/unicode.h"
29 #include "wine/debug.h"
30 
32 
35 
37 {
39  int res;
40 
41  strcpyW(dir, Target);
42  *PathFindFileNameW(dir) = 0; /* Truncate file name */
43  if(!PathIsDirectoryW(dir))
44  {
45  res = SHCreateDirectoryExW(NULL, dir, NULL);
46  if(res != ERROR_SUCCESS && res != ERROR_ALREADY_EXISTS)
47  WINE_ERR("Can't create directory: %s\n", wine_dbgstr_w(dir));
48  }
49 }
50 
51 static UINT WINAPI ExtCabCallback(PVOID Context, UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
52 {
54  FILEPATHS_W *pFilePaths;
55 
56  switch(Notification)
57  {
59  pInfo = (FILE_IN_CABINET_INFO_W*)Param1;
60  if(show_content)
61  {
62  FILETIME ft;
63  SYSTEMTIME st;
64  CHAR date[12], time[12], buf[2 * MAX_PATH];
65  int count;
66  DWORD dummy;
67 
68  /* DosDate and DosTime already represented at local time */
69  DosDateTimeToFileTime(pInfo->DosDate, pInfo->DosTime, &ft);
70  FileTimeToSystemTime(&ft, &st);
71  GetDateFormatA(0, 0, &st, "MM'-'dd'-'yyyy", date, sizeof date);
72  GetTimeFormatA(0, 0, &st, "HH':'mm':'ss", time, sizeof time);
73  count = wsprintfA(buf, "%s %s %c%c%c%c %15u %S\n", date, time,
74  pInfo->DosAttribs & FILE_ATTRIBUTE_ARCHIVE ? 'A' : '-',
75  pInfo->DosAttribs & FILE_ATTRIBUTE_HIDDEN ? 'H' : '-',
76  pInfo->DosAttribs & FILE_ATTRIBUTE_READONLY ? 'R' : '-',
77  pInfo->DosAttribs & FILE_ATTRIBUTE_SYSTEM ? 'S' : '-',
78  pInfo->FileSize, pInfo->NameInCabinet);
79  WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, count, &dummy, NULL);
80  return FILEOP_SKIP;
81  }
82  else
83  {
84  lstrcpyW(pInfo->FullTargetName, (LPCWSTR)Context);
85  lstrcatW(pInfo->FullTargetName, pInfo->NameInCabinet);
86  /* SetupIterateCabinet() doesn't create full path to target by itself,
87  so we should do it manually */
89  return FILEOP_DOIT;
90  }
92  pFilePaths = (FILEPATHS_W*)Param1;
93  WINE_TRACE("Extracted %s\n", wine_dbgstr_w(pFilePaths->Target));
94  return NO_ERROR;
95  }
96  return NO_ERROR;
97 }
98 
99 static void extract(LPCWSTR cabfile, LPWSTR destdir)
100 {
101  if (!SetupIterateCabinetW(cabfile, 0, ExtCabCallback, destdir))
102  WINE_ERR("Could not extract cab file %s\n", wine_dbgstr_w(cabfile));
103 }
104 
105 static void copy_file(LPCWSTR source, LPCWSTR destination)
106 {
107  WCHAR destfile[MAX_PATH];
108 
109  /* append source filename if destination is a directory */
110  if (PathIsDirectoryW(destination))
111  {
112  PathCombineW(destfile, destination, PathFindFileNameW(source));
113  destination = destfile;
114  }
115 
116  if (PathFileExistsW(destination) && !force_mode)
117  {
118  static const WCHAR overwriteMsg[] = {'O','v','e','r','w','r','i','t','e',' ','"','%','s','"','?',0};
119  static const WCHAR titleMsg[] = {'E','x','t','r','a','c','t',0};
120  WCHAR msg[MAX_PATH+100];
121  snprintfW(msg, sizeof(msg)/sizeof(msg[0]), overwriteMsg, destination);
122  if (MessageBoxW(NULL, msg, titleMsg, MB_YESNO | MB_ICONWARNING) != IDYES)
123  return;
124  }
125 
126  WINE_TRACE("copying %s to %s\n", wine_dbgstr_w(source), wine_dbgstr_w(destination));
127  CopyFileW(source, destination, FALSE);
128 }
129 
130 static LPWSTR *get_extrac_args(LPWSTR cmdline, int *pargc)
131 {
132  enum {OUTSIDE_ARG, INSIDE_ARG, INSIDE_QUOTED_ARG} state;
133  LPWSTR str;
134  int argc;
135  LPWSTR *argv;
136  int max_argc = 16;
137  BOOL new_arg;
138 
139  WINE_TRACE("cmdline: %s\n", wine_dbgstr_w(cmdline));
140  str = HeapAlloc(GetProcessHeap(), 0, (strlenW(cmdline) + 1) * sizeof(WCHAR));
141  if(!str) return NULL;
142  strcpyW(str, cmdline);
143  argv = HeapAlloc(GetProcessHeap(), 0, (max_argc + 1) * sizeof(LPWSTR));
144  if(!argv)
145  {
146  HeapFree(GetProcessHeap(), 0, str);
147  return NULL;
148  }
149 
150  /* Split command line to separate arg-strings and fill argv */
151  state = OUTSIDE_ARG;
152  argc = 0;
153  while(*str)
154  {
155  new_arg = FALSE;
156  /* Check character */
157  if(isspaceW(*str)) /* white space */
158  {
159  if(state == INSIDE_ARG)
160  {
161  state = OUTSIDE_ARG;
162  *str = 0;
163  }
164  }
165  else if(*str == '"') /* double quote */
166  switch(state)
167  {
168  case INSIDE_QUOTED_ARG:
169  state = OUTSIDE_ARG;
170  *str = 0;
171  break;
172  case INSIDE_ARG:
173  *str = 0;
174  /* Fall through */
175  case OUTSIDE_ARG:
176  if(!*++str) continue;
177  state = INSIDE_QUOTED_ARG;
178  new_arg = TRUE;
179  break;
180  }
181  else /* regular character */
182  if(state == OUTSIDE_ARG)
183  {
184  state = INSIDE_ARG;
185  new_arg = TRUE;
186  }
187 
188  /* Add new argv entry, if need */
189  if(new_arg)
190  {
191  if(argc >= max_argc - 1)
192  {
193  /* Realloc argv here because there always should be
194  at least one reserved cell for terminating NULL */
195  max_argc *= 2;
196  argv = HeapReAlloc(GetProcessHeap(), 0, argv,
197  (max_argc + 1) * sizeof(LPWSTR));
198  if(!argv)
199  {
200  HeapFree(GetProcessHeap(), 0, str);
201  return NULL;
202  }
203  }
204  argv[argc++] = str;
205  }
206 
207  str++;
208  }
209 
210  argv[argc] = NULL;
211  *pargc = argc;
212 
213  if(TRACE_ON(extrac32))
214  {
215  int i;
216  for(i = 0; i < argc; i++)
217  WINE_TRACE("arg %d: %s\n", i, wine_dbgstr_w(argv[i]));
218  }
219  return argv;
220 }
221 
223 {
224  LPWSTR *argv;
225  int argc;
226  int i;
227  WCHAR check, cmd = 0;
229  LPCWSTR cabfile = NULL;
230 
231  path[0] = 0;
232 
233  /* Do not use CommandLineToArgvW() or __wgetmainargs() to parse
234  * command line for this program. It should treat each quote as argument
235  * delimiter. This doesn't match with behavior of mentioned functions.
236  * Do not use args provided by wmain() for the same reason.
237  */
238  argv = get_extrac_args(cmdline, &argc);
239 
240  if(!argv)
241  {
242  WINE_ERR("Command line parsing failed\n");
243  return 0;
244  }
245 
246  /* Parse arguments */
247  for(i = 0; i < argc; i++)
248  {
249  /* Get cabfile */
250  if (argv[i][0] != '/' && argv[i][0] != '-')
251  {
252  if (!cabfile)
253  {
254  cabfile = argv[i];
255  continue;
256  } else
257  break;
258  }
259  /* Get parameters for commands */
260  check = toupperW( argv[i][1] );
261  switch(check)
262  {
263  case 'A':
264  WINE_FIXME("/A not implemented\n");
265  break;
266  case 'Y':
267  force_mode = TRUE;
268  break;
269  case 'L':
270  if ((i + 1) >= argc) return 0;
271  if (!GetFullPathNameW(argv[++i], MAX_PATH, path, NULL))
272  return 0;
273  break;
274  case 'C':
275  case 'E':
276  case 'D':
277  if (cmd) return 0;
278  cmd = check;
279  break;
280  default:
281  return 0;
282  }
283  }
284 
285  if (!cabfile)
286  return 0;
287 
288  if (cmd == 'C')
289  {
290  if ((i + 1) != argc) return 0;
291  if (!GetFullPathNameW(argv[i], MAX_PATH, path, NULL))
292  return 0;
293  }
294  else if (!cmd)
295  /* Use extraction by default if names of required files presents */
296  cmd = i < argc ? 'E' : 'D';
297 
298  if (cmd == 'E' && !path[0])
300 
301  PathAddBackslashW(path);
302 
303  /* Execute the specified command */
304  switch(cmd)
305  {
306  case 'C':
307  /* Copy file */
308  copy_file(cabfile, path);
309  break;
310  case 'D':
311  /* Display CAB archive */
312  show_content = TRUE;
313  /* Fall through */
314  case 'E':
315  /* Extract CAB archive */
316  extract(cabfile, path);
317  break;
318  }
319  return 0;
320 }
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1702
static int argc
Definition: ServiceArgs.c:12
#define TRUE
Definition: types.h:120
#define snprintfW
Definition: unicode.h:60
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
#define ERROR_SUCCESS
Definition: deptool.c:10
#define IDYES
Definition: winuser.h:829
static UINT WINAPI ExtCabCallback(PVOID Context, UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
Definition: extrac32.c:51
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
Definition: ftp_var.h:139
#define SPFILENOTIFY_FILEEXTRACTED
Definition: setupapi.h:559
INT WINAPI GetDateFormatA(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCSTR lpFormat, LPSTR lpDateStr, INT cchOut)
Definition: lcformat.c:859
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
WINE_UNICODE_INLINE int isspaceW(WCHAR wc)
Definition: unicode.h:165
GLuint GLuint GLsizei count
Definition: gl.h:1545
char CHAR
Definition: xmlstorage.h:175
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:413
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define WINE_TRACE
Definition: debug.h:353
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:152
static LPWSTR * get_extrac_args(LPWSTR cmdline, int *pargc)
Definition: extrac32.c:130
TCHAR * cmdline
Definition: stretchblt.cpp:32
__u16 time
Definition: mkdosfs.c:366
BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved, PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
Definition: setupcab.c:575
#define NO_ERROR
Definition: dderror.h:5
static BOOL show_content
Definition: extrac32.c:34
static char ** argv
Definition: ServiceArgs.c:11
static void extract(LPCWSTR cabfile, LPWSTR destdir)
Definition: extrac32.c:99
#define MB_ICONWARNING
Definition: winuser.h:780
INT WINAPI GetTimeFormatA(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCSTR lpFormat, LPSTR lpTimeStr, INT cchOut)
Definition: lcformat.c:967
GLenum GLclampf GLint i
Definition: glfuncs.h:14
HINSTANCE hInstance
Definition: charmap.c:20
#define MB_YESNO
Definition: winuser.h:811
WINE_DEFAULT_DEBUG_CHANNEL(extrac32)
LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
Definition: path.c:289
char * wine_dbgstr_w(const wchar_t *wstr)
Definition: CString.cpp:62
const WCHAR * str
WCHAR FullTargetName[MAX_PATH]
Definition: setupapi.h:799
#define WINE_ERR
Definition: debug.h:370
UINT msg
Definition: msvc.h:92
smooth NULL
Definition: ftsmooth.c:416
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:389
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1756
unsigned int dir
Definition: maze.c:112
WINE_UNICODE_INLINE WCHAR toupperW(WCHAR ch)
Definition: unicode.h:141
static void copy_file(LPCWSTR source, LPCWSTR destination)
Definition: extrac32.c:105
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
#define FILEOP_DOIT
Definition: fileqsup.h:48
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:178
unsigned int BOOL
Definition: ntddk_ex.h:94
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
int WINAPI MessageBoxW(_In_opt_ HWND, _In_opt_ LPCWSTR, _In_opt_ LPCWSTR, _In_ UINT)
BOOL WINAPI DosDateTimeToFileTime(IN WORD wFatDate, IN WORD wFatTime, OUT LPFILETIME lpFileTime)
Definition: time.c:75
BOOL WINAPI CopyFileW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN BOOL bFailIfExists)
Definition: copy.c:439
#define MAX_PATH
Definition: compat.h:26
unsigned int UINT
Definition: ndis.h:50
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
void check(CONTEXT *pContext)
Definition: NtContinue.c:61
_Must_inspect_result_ typedef _In_ ULONG _In_ BOOLEAN Target
Definition: iotypes.h:1067
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
int PASCAL wWinMain(HINSTANCE hInstance, HINSTANCE prev, LPWSTR cmdline, int show)
Definition: extrac32.c:222
static int state
Definition: maze.c:121
#define PASCAL
Definition: windef.h:133
#define STD_OUTPUT_HANDLE
Definition: winbase.h:265
#define SPFILENOTIFY_FILEINCABINET
Definition: setupapi.h:557
#define WINAPI
Definition: msvc.h:20
WINE_UNICODE_INLINE WCHAR * strcpyW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:219
int WINAPIV wsprintfA(_Out_ LPSTR, _In_ _Printf_format_string_ LPCSTR,...)
static void create_target_directory(LPWSTR Target)
Definition: extrac32.c:36
#define lstrcpyW
Definition: compat.h:406
unsigned char dummy
Definition: maze.c:118
int WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
Definition: shlfileop.cpp:845
__u16 date
Definition: mkdosfs.c:366
#define FILEOP_SKIP
Definition: fileqsup.h:49
#define HeapReAlloc
Definition: compat.h:393
Definition: services.c:325
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
PCWSTR Target
Definition: fileqsup.h:60
GLuint res
Definition: glext.h:9613
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
WCHAR * LPWSTR
Definition: xmlstorage.h:184
LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
Definition: path.c:189
#define TRACE_ON(x)
Definition: compat.h:65
#define HeapFree(x, y, z)
Definition: compat.h:394
static BOOL force_mode
Definition: extrac32.c:33
#define WINE_FIXME
Definition: debug.h:365