xref: /reactos/base/system/expand/expand.c (revision 84ccccab)
1 /*
2  * Copyright 1997 Victor Schneider
3  * Copyright 2002 Alexandre Julliard
4  * Copyright 2007 Hans Leidekker
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #define WIN32_NO_STATUS
22 #include <stdarg.h>
23 #include <windef.h>
24 #include <winbase.h>
25 #include <winreg.h>
26 #include <winuser.h>
27 #include <stdio.h>
28 #include <lzexpand.h>
29 #include <setupapi.h>
30 
31 static int myprintf(const char* format, ...)
32 {
33     va_list     va;
34     char        tmp[8192];
35     DWORD       w = 0;
36     int         len;
37 
38     va_start(va, format);
39     len = vsnprintf(tmp, sizeof(tmp), format, va);
40     if (len > 0)
41         WriteFile(GetStdHandle(STD_ERROR_HANDLE), tmp, len, &w, NULL);
42     va_end(va);
43     return w;
44 }
45 
46 static UINT CALLBACK set_outfile( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
47 {
48     FILE_IN_CABINET_INFO_A *info = (FILE_IN_CABINET_INFO_A *)param1;
49     char buffer[MAX_PATH];
50     char* basename;
51 
52     switch (notification)
53     {
54     case SPFILENOTIFY_FILEINCABINET:
55     {
56         LPSTR outfile = context;
57         if (outfile[0] != 0)
58         {
59             SetLastError( ERROR_NOT_SUPPORTED );
60             return FILEOP_ABORT;
61         }
62         GetFullPathNameA( info->NameInCabinet, sizeof(buffer), buffer, &basename );
63         strcpy( outfile, basename );
64         return FILEOP_SKIP;
65     }
66     default: return NO_ERROR;
67     }
68 }
69 
70 static UINT CALLBACK extract_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
71 {
72     FILE_IN_CABINET_INFO_A *info = (FILE_IN_CABINET_INFO_A *)param1;
73 
74     switch (notification)
75     {
76     case SPFILENOTIFY_FILEINCABINET:
77     {
78         LPCSTR targetname = context;
79 
80         strcpy( info->FullTargetName, targetname );
81         return FILEOP_DOIT;
82     }
83     default: return NO_ERROR;
84     }
85 }
86 
87 static BOOL option_equal(LPCSTR str1, LPCSTR str2)
88 {
89     if (str1[0] != '/' && str1[0] != '-')
90         return FALSE;
91     return !lstrcmpA( str1 + 1, str2 );
92 }
93 
94 int main(int argc, char *argv[])
95 {
96     int ret = 0;
97     char infile[MAX_PATH], outfile[MAX_PATH], actual_name[MAX_PATH];
98     char outfile_basename[MAX_PATH], *basename_index;
99     UINT comp;
100 
101     if (argc < 3)
102     {
103         myprintf( "Usage:\n" );
104         myprintf( "\t%s infile outfile\n", argv[0] );
105         myprintf( "\t%s /r infile\n", argv[0] );
106         return 1;
107     }
108 
109     if (argc == 3 && (option_equal(argv[1], "R") || option_equal(argv[1], "r")))
110         GetFullPathNameA( argv[2], sizeof(infile), infile, NULL );
111     else
112         GetFullPathNameA( argv[1], sizeof(infile), infile, NULL );
113 
114     if (!SetupGetFileCompressionInfoExA( infile, actual_name, sizeof(actual_name), NULL, NULL, NULL, &comp ))
115     {
116         myprintf( "%s: can't open input file %s\n", argv[0], infile );
117         return 1;
118     }
119 
120     if (argc == 3 && (option_equal(argv[1], "R") || option_equal(argv[1], "r")))
121     {
122         switch (comp)
123         {
124         case FILE_COMPRESSION_MSZIP:
125             outfile_basename[0] = 0;
126             if (!SetupIterateCabinetA( infile, 0, set_outfile, outfile_basename ))
127             {
128                 myprintf( "%s: can't determine original name\n", argv[0] );
129                 return 1;
130             }
131             GetFullPathNameA( infile, sizeof(outfile), outfile, &basename_index );
132             *basename_index = 0;
133             strcat( outfile, outfile_basename );
134             break;
135         case FILE_COMPRESSION_WINLZA:
136             GetExpandedNameA( infile, outfile_basename );
137             break;
138         default:
139             myprintf( "%s: can't determine original\n", argv[0] );
140             return 1;
141         }
142     }
143     else
144         GetFullPathNameA( argv[2], sizeof(outfile), outfile, NULL );
145 
146     if (!lstrcmpiA( infile, outfile ))
147     {
148         myprintf( "%s: can't expand file to itself\n", argv[0] );
149         return 1;
150     }
151 
152     switch (comp)
153     {
154     case FILE_COMPRESSION_MSZIP:
155         if (!SetupIterateCabinetA( infile, 0, extract_callback, outfile ))
156         {
157             myprintf( "%s: cabinet extraction failed\n", argv[0] );
158             return 1;
159         }
160         break;
161     case FILE_COMPRESSION_WINLZA:
162     {
163         INT hin, hout;
164         OFSTRUCT ofin, ofout;
165         LONG error;
166 
167         if ((hin = LZOpenFileA( infile, &ofin, OF_READ )) < 0)
168         {
169             myprintf( "%s: can't open input file %s\n", argv[0], infile );
170             return 1;
171         }
172         if ((hout = LZOpenFileA( outfile, &ofout, OF_CREATE | OF_WRITE )) < 0)
173         {
174             LZClose( hin );
175             myprintf( "%s: can't open output file %s\n", argv[0], outfile );
176             return 1;
177         }
178         error = LZCopy( hin, hout );
179 
180         LZClose( hin );
181         LZClose( hout );
182 
183         if (error < 0)
184         {
185             myprintf( "%s: LZCopy failed, error is %d\n", argv[0], error );
186             return 1;
187         }
188         break;
189     }
190     default:
191         if (!CopyFileA( infile, outfile, FALSE ))
192         {
193             myprintf( "%s: CopyFileA failed\n", argv[0] );
194             return 1;
195         }
196         break;
197     }
198     return ret;
199 }
200