wow64: In wow64_NtSetInformationToken forward TokenIntegrityLevel.
[wine.git] / programs / extrac32 / extrac32.c
blob6d6dd2eb2ef3c0fee79fde38ea367a87d109122a
1 /*
2 * Extract - Wine-compatible program for extract *.cab files.
4 * Copyright 2007 Etersoft (Lyutin Anatoly)
5 * Copyright 2009 Ilya Shpigor
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.
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.
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
22 #include <stdio.h>
23 #include <windows.h>
24 #include <commctrl.h>
25 #include <shellapi.h>
26 #include <setupapi.h>
27 #include <shlwapi.h>
28 #include <shlobj.h>
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(extrac32);
34 static BOOL force_mode;
35 static BOOL show_content;
37 static void create_target_directory(LPWSTR Target)
39 WCHAR dir[MAX_PATH];
40 int res;
42 lstrcpyW(dir, Target);
43 *PathFindFileNameW(dir) = 0; /* Truncate file name */
44 if(!PathIsDirectoryW(dir))
46 res = SHCreateDirectoryExW(NULL, dir, NULL);
47 if(res != ERROR_SUCCESS && res != ERROR_ALREADY_EXISTS)
48 WINE_ERR("Can't create directory: %s\n", wine_dbgstr_w(dir));
52 static UINT WINAPI ExtCabCallback(PVOID Context, UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
54 FILE_IN_CABINET_INFO_W *pInfo;
55 FILEPATHS_W *pFilePaths;
57 switch(Notification)
59 case SPFILENOTIFY_FILEINCABINET:
60 pInfo = (FILE_IN_CABINET_INFO_W*)Param1;
61 if(show_content)
63 FILETIME ft;
64 SYSTEMTIME st;
65 CHAR date[12], time[12], buf[2 * MAX_PATH];
66 int count;
67 DWORD dummy;
69 /* DosDate and DosTime already represented at local time */
70 DosDateTimeToFileTime(pInfo->DosDate, pInfo->DosTime, &ft);
71 FileTimeToSystemTime(&ft, &st);
72 GetDateFormatA(0, 0, &st, "MM'-'dd'-'yyyy", date, sizeof date);
73 GetTimeFormatA(0, 0, &st, "HH':'mm':'ss", time, sizeof time);
74 count = wsprintfA(buf, "%s %s %c%c%c%c %15u %S\n", date, time,
75 pInfo->DosAttribs & FILE_ATTRIBUTE_ARCHIVE ? 'A' : '-',
76 pInfo->DosAttribs & FILE_ATTRIBUTE_HIDDEN ? 'H' : '-',
77 pInfo->DosAttribs & FILE_ATTRIBUTE_READONLY ? 'R' : '-',
78 pInfo->DosAttribs & FILE_ATTRIBUTE_SYSTEM ? 'S' : '-',
79 pInfo->FileSize, pInfo->NameInCabinet);
80 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, count, &dummy, NULL);
81 return FILEOP_SKIP;
83 else
85 lstrcpyW(pInfo->FullTargetName, (LPCWSTR)Context);
86 lstrcatW(pInfo->FullTargetName, pInfo->NameInCabinet);
87 /* SetupIterateCabinet() doesn't create full path to target by itself,
88 so we should do it manually */
89 create_target_directory(pInfo->FullTargetName);
90 return FILEOP_DOIT;
92 case SPFILENOTIFY_FILEEXTRACTED:
93 pFilePaths = (FILEPATHS_W*)Param1;
94 WINE_TRACE("Extracted %s\n", wine_dbgstr_w(pFilePaths->Target));
95 return NO_ERROR;
97 return NO_ERROR;
100 static void extract(LPCWSTR cabfile, LPWSTR destdir)
102 if (!SetupIterateCabinetW(cabfile, 0, ExtCabCallback, destdir))
103 WINE_ERR("Could not extract cab file %s\n", wine_dbgstr_w(cabfile));
106 static void copy_file(LPCWSTR source, LPCWSTR destination)
108 WCHAR destfile[MAX_PATH];
110 /* append source filename if destination is a directory */
111 if (PathIsDirectoryW(destination))
113 PathCombineW(destfile, destination, PathFindFileNameW(source));
114 destination = destfile;
117 if (PathFileExistsW(destination) && !force_mode)
119 WCHAR msg[MAX_PATH+100];
120 swprintf(msg, ARRAY_SIZE(msg), L"Overwrite \"%s\"?", destination);
121 if (MessageBoxW(NULL, msg, L"Extract", MB_YESNO | MB_ICONWARNING) != IDYES)
122 return;
125 WINE_TRACE("copying %s to %s\n", wine_dbgstr_w(source), wine_dbgstr_w(destination));
126 CopyFileW(source, destination, FALSE);
129 static LPWSTR *get_extrac_args(LPWSTR cmdline, int *pargc)
131 enum {OUTSIDE_ARG, INSIDE_ARG, INSIDE_QUOTED_ARG} state;
132 LPWSTR str;
133 int argc;
134 LPWSTR *argv;
135 int max_argc = 16;
136 BOOL new_arg;
138 WINE_TRACE("cmdline: %s\n", wine_dbgstr_w(cmdline));
139 str = wcsdup(cmdline);
140 if(!str) return NULL;
141 argv = malloc((max_argc + 1) * sizeof(WCHAR*));
142 if(!argv)
144 free(str);
145 return NULL;
148 /* Split command line to separate arg-strings and fill argv */
149 state = OUTSIDE_ARG;
150 argc = 0;
151 while(*str)
153 new_arg = FALSE;
154 /* Check character */
155 if(iswspace(*str)) /* white space */
157 if(state == INSIDE_ARG)
159 state = OUTSIDE_ARG;
160 *str = 0;
163 else if(*str == '"') /* double quote */
164 switch(state)
166 case INSIDE_QUOTED_ARG:
167 state = OUTSIDE_ARG;
168 *str = 0;
169 break;
170 case INSIDE_ARG:
171 *str = 0;
172 /* Fall through */
173 case OUTSIDE_ARG:
174 if(!*++str) continue;
175 state = INSIDE_QUOTED_ARG;
176 new_arg = TRUE;
177 break;
179 else /* regular character */
180 if(state == OUTSIDE_ARG)
182 state = INSIDE_ARG;
183 new_arg = TRUE;
186 /* Add new argv entry, if need */
187 if(new_arg)
189 if(argc >= max_argc - 1)
191 /* Realloc argv here because there always should be
192 at least one reserved cell for terminating NULL */
193 max_argc *= 2;
194 argv = realloc(argv, (max_argc + 1) * sizeof(WCHAR*));
195 if(!argv)
197 free(str);
198 return NULL;
201 argv[argc++] = str;
204 str++;
207 argv[argc] = NULL;
208 *pargc = argc;
210 if(TRACE_ON(extrac32))
212 int i;
213 for(i = 0; i < argc; i++)
214 WINE_TRACE("arg %d: %s\n", i, wine_dbgstr_w(argv[i]));
216 return argv;
219 int PASCAL wWinMain(HINSTANCE hInstance, HINSTANCE prev, LPWSTR cmdline, int show)
221 LPWSTR *argv;
222 int argc;
223 int i;
224 WCHAR check, cmd = 0;
225 WCHAR path[MAX_PATH];
226 LPCWSTR cabfile = NULL;
228 InitCommonControls();
230 path[0] = 0;
232 /* Do not use CommandLineToArgvW() or __wgetmainargs() to parse
233 * command line for this program. It should treat each quote as argument
234 * delimiter. This doesn't match with behavior of mentioned functions.
235 * Do not use args provided by wmain() for the same reason.
237 argv = get_extrac_args(cmdline, &argc);
239 if(!argv)
241 WINE_ERR("Command line parsing failed\n");
242 return 0;
245 /* Parse arguments */
246 for(i = 0; i < argc; i++)
248 /* Get cabfile */
249 if (argv[i][0] != '/' && argv[i][0] != '-')
251 if (!cabfile)
253 cabfile = argv[i];
254 continue;
255 } else
256 break;
258 /* Get parameters for commands */
259 check = towupper( argv[i][1] );
260 switch(check)
262 case 'A':
263 WINE_FIXME("/A not implemented\n");
264 break;
265 case 'Y':
266 force_mode = TRUE;
267 break;
268 case 'L':
269 if ((i + 1) >= argc) return 0;
270 if (!GetFullPathNameW(argv[++i], MAX_PATH, path, NULL))
271 return 0;
272 break;
273 case 'C':
274 case 'E':
275 case 'D':
276 if (cmd) return 0;
277 cmd = check;
278 break;
279 default:
280 return 0;
284 if (!cabfile)
285 return 0;
287 if (cmd == 'C')
289 if ((i + 1) != argc) return 0;
290 if (!GetFullPathNameW(argv[i], MAX_PATH, path, NULL))
291 return 0;
293 else if (!cmd)
294 /* Use extraction by default if names of required files presents */
295 cmd = i < argc ? 'E' : 'D';
297 if (cmd == 'E' && !path[0])
298 GetCurrentDirectoryW(MAX_PATH, path);
300 PathAddBackslashW(path);
302 /* Execute the specified command */
303 switch(cmd)
305 case 'C':
306 /* Copy file */
307 copy_file(cabfile, path);
308 break;
309 case 'D':
310 /* Display CAB archive */
311 show_content = TRUE;
312 /* Fall through */
313 case 'E':
314 /* Extract CAB archive */
315 extract(cabfile, path);
316 break;
318 return 0;