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_LEAN_AND_MEAN 22 23 #include <stdio.h> 24 #include <string.h> 25 #include <windows.h> 26 #include <lzexpand.h> 27 #include <setupapi.h> 28 29 static int myprintf(const char* format, ...) 30 { 31 va_list va; 32 char tmp[8192]; 33 DWORD w = 0; 34 int len; 35 36 va_start(va, format); 37 len = vsnprintf(tmp, sizeof(tmp), format, va); 38 if (len > 0) 39 WriteFile(GetStdHandle(STD_ERROR_HANDLE), tmp, len, &w, NULL); 40 va_end(va); 41 return w; 42 } 43 44 static UINT CALLBACK set_outfile( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 ) 45 { 46 FILE_IN_CABINET_INFO_A *info = (FILE_IN_CABINET_INFO_A *)param1; 47 char buffer[MAX_PATH]; 48 char* basename; 49 50 switch (notification) 51 { 52 case SPFILENOTIFY_FILEINCABINET: 53 { 54 LPSTR outfile = context; 55 if (outfile[0] != 0) 56 { 57 SetLastError( ERROR_NOT_SUPPORTED ); 58 return FILEOP_ABORT; 59 } 60 GetFullPathNameA( info->NameInCabinet, sizeof(buffer), buffer, &basename ); 61 strcpy( outfile, basename ); 62 return FILEOP_SKIP; 63 } 64 default: return NO_ERROR; 65 } 66 } 67 68 static UINT CALLBACK extract_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 ) 69 { 70 FILE_IN_CABINET_INFO_A *info = (FILE_IN_CABINET_INFO_A *)param1; 71 72 switch (notification) 73 { 74 case SPFILENOTIFY_FILEINCABINET: 75 { 76 LPCSTR targetname = context; 77 78 strcpy( info->FullTargetName, targetname ); 79 return FILEOP_DOIT; 80 } 81 default: return NO_ERROR; 82 } 83 } 84 85 static BOOL option_equal(LPCSTR str1, LPCSTR str2) 86 { 87 if (str1[0] != '/' && str1[0] != '-') 88 return FALSE; 89 return !lstrcmpA( str1 + 1, str2 ); 90 } 91 92 int main(int argc, char *argv[]) 93 { 94 int ret = 0; 95 char infile[MAX_PATH], outfile[MAX_PATH], actual_name[MAX_PATH]; 96 char outfile_basename[MAX_PATH], *basename_index; 97 UINT comp; 98 99 if (argc < 3) 100 { 101 myprintf( "Usage:\n" ); 102 myprintf( "\t%s infile outfile\n", argv[0] ); 103 myprintf( "\t%s /r infile\n", argv[0] ); 104 return 1; 105 } 106 107 if (argc == 3 && (option_equal(argv[1], "R") || option_equal(argv[1], "r"))) 108 GetFullPathNameA( argv[2], sizeof(infile), infile, NULL ); 109 else 110 GetFullPathNameA( argv[1], sizeof(infile), infile, NULL ); 111 112 if (!SetupGetFileCompressionInfoExA( infile, actual_name, sizeof(actual_name), NULL, NULL, NULL, &comp )) 113 { 114 myprintf( "%s: can't open input file %s\n", argv[0], infile ); 115 return 1; 116 } 117 118 if (argc == 3 && (option_equal(argv[1], "R") || option_equal(argv[1], "r"))) 119 { 120 switch (comp) 121 { 122 case FILE_COMPRESSION_MSZIP: 123 outfile_basename[0] = 0; 124 if (!SetupIterateCabinetA( infile, 0, set_outfile, outfile_basename )) 125 { 126 myprintf( "%s: can't determine original name\n", argv[0] ); 127 return 1; 128 } 129 GetFullPathNameA( infile, sizeof(outfile), outfile, &basename_index ); 130 *basename_index = 0; 131 strcat( outfile, outfile_basename ); 132 break; 133 case FILE_COMPRESSION_WINLZA: 134 GetExpandedNameA( infile, outfile_basename ); 135 break; 136 default: 137 myprintf( "%s: can't determine original\n", argv[0] ); 138 return 1; 139 } 140 } 141 else 142 GetFullPathNameA( argv[2], sizeof(outfile), outfile, NULL ); 143 144 if (!lstrcmpiA( infile, outfile )) 145 { 146 myprintf( "%s: can't expand file to itself\n", argv[0] ); 147 return 1; 148 } 149 150 switch (comp) 151 { 152 case FILE_COMPRESSION_MSZIP: 153 if (!SetupIterateCabinetA( infile, 0, extract_callback, outfile )) 154 { 155 myprintf( "%s: cabinet extraction failed\n", argv[0] ); 156 return 1; 157 } 158 break; 159 case FILE_COMPRESSION_WINLZA: 160 { 161 INT hin, hout; 162 OFSTRUCT ofin, ofout; 163 LONG error; 164 165 if ((hin = LZOpenFileA( infile, &ofin, OF_READ )) < 0) 166 { 167 myprintf( "%s: can't open input file %s\n", argv[0], infile ); 168 return 1; 169 } 170 if ((hout = LZOpenFileA( outfile, &ofout, OF_CREATE | OF_WRITE )) < 0) 171 { 172 LZClose( hin ); 173 myprintf( "%s: can't open output file %s\n", argv[0], outfile ); 174 return 1; 175 } 176 error = LZCopy( hin, hout ); 177 178 LZClose( hin ); 179 LZClose( hout ); 180 181 if (error < 0) 182 { 183 myprintf( "%s: LZCopy failed, error is %d\n", argv[0], error ); 184 return 1; 185 } 186 break; 187 } 188 default: 189 if (!CopyFileA( infile, outfile, FALSE )) 190 { 191 myprintf( "%s: CopyFileA failed\n", argv[0] ); 192 return 1; 193 } 194 break; 195 } 196 return ret; 197 } 198