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