1 /*
2 miniunz.c
3 Version 1.01e, February 12th, 2005
4
5 Copyright (C) 1998-2005 Gilles Vollant
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12 #include <errno.h>
13 #include <sys/stat.h>
14
15 #define unix
16
17 #ifdef unix
18 #include <unistd.h>
19 #include <utime.h>
20 #else
21 #include <dirent.h>
22 #include <io.h>
23 #endif
24
25 #include "unzip.h"
26 #include "miniunz.h"
27
28 #define CASESENSITIVITY (0)
29 #define WRITEBUFFERSIZE (8192)
30 #define MAXFILENAME (256)
31
32 /*
33 mini unzip, demo of unzip package
34
35 usage :
36 Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir]
37
38 list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT
39 if it exists
40 */
41
42 /* change_file_date : change the date/time of a file
43 filename : the filename of the file where date/time must be modified
44 tmu_date : the SAME new date at the tm_unz format */
change_file_date(const char * filename,tm_unz tmu_date)45 void change_file_date(const char* filename, tm_unz tmu_date)
46 {
47
48 #ifdef unix
49 struct utimbuf ut;
50 struct tm newdate;
51 newdate.tm_sec = tmu_date.tm_sec;
52 newdate.tm_min = tmu_date.tm_min;
53 newdate.tm_hour = tmu_date.tm_hour;
54 newdate.tm_mday = tmu_date.tm_mday;
55 newdate.tm_mon = tmu_date.tm_mon;
56 if (tmu_date.tm_year > 1900)
57 newdate.tm_year = tmu_date.tm_year - 1900;
58 else
59 newdate.tm_year = tmu_date.tm_year;
60 newdate.tm_isdst = -1;
61
62 ut.actime = ut.modtime = mktime(&newdate);
63 //utime(filename, &ut);
64 #endif
65 }
66
67 /* mymkdir and change_file_date are not 100 % portable
68 As I don't know well Unix, I wait feedback for the unix portion */
69
mymkdir(const char * dirname)70 int mymkdir(const char* dirname)
71 {
72 int ret = 0;
73 #ifdef unix
74 ret = mkdir(dirname, 0775);
75 #endif
76 return ret;
77 }
78
makedir(newdir)79 int makedir(newdir) char* newdir;
80 {
81 char* buffer;
82 char* p;
83 int len = (int)strlen(newdir);
84
85 if (len <= 0)
86 return 0;
87
88 buffer = (char*)malloc(len + 1);
89 strcpy(buffer, newdir);
90
91 if (buffer[len - 1] == '/') {
92 buffer[len - 1] = '\0';
93 }
94 if (mymkdir(buffer) == 0) {
95 free(buffer);
96 return 1;
97 }
98
99 p = buffer + 1;
100 while (1) {
101 char hold;
102
103 while (*p && *p != '\\' && *p != '/')
104 p++;
105 hold = *p;
106 *p = 0;
107 if ((mymkdir(buffer) == -1) && (errno == ENOENT)) {
108 printf("couldn't create directory %s\n", buffer);
109 free(buffer);
110 return 0;
111 }
112 if (hold == 0)
113 break;
114 *p++ = hold;
115 }
116 free(buffer);
117 return 1;
118 }
119
do_banner()120 void do_banner()
121 {
122 printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n");
123 printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n");
124 }
125
126 // static void do_help()
127 // {
128 // printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n"
129 // " -e Extract without pathname (junk paths)\n"
130 // " -x Extract with pathname\n"
131 // " -v list files\n"
132 // " -l list files\n"
133 // " -d directory to extract into\n"
134 // " -o overwrite files without prompting\n"
135 // " -p extract crypted file using password\n\n");
136 // }
137
do_list(unzFile uf)138 int do_list(unzFile uf)
139 {
140 uLong i;
141 unz_global_info gi;
142 int err;
143
144 err = unzGetGlobalInfo(uf, &gi);
145 if (err != UNZ_OK) {
146 printf("error %d with zipfile in unzGetGlobalInfo \n", err);
147 }
148
149 printf(" Length Method Size Ratio Date Time CRC-32 Name\n");
150 printf(" ------ ------ ---- ----- ---- ---- ------ ----\n");
151 for (i = 0; i < gi.number_entry; i++) {
152 char filename_inzip[256];
153 unz_file_info file_info;
154 uLong ratio = 0;
155 const char* string_method = NULL;
156 char charCrypt = ' ';
157 err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
158 if (err != UNZ_OK) {
159 printf("error %d with zipfile in unzGetCurrentFileInfo\n", err);
160 break;
161 }
162 if (file_info.uncompressed_size > 0)
163 ratio = (file_info.compressed_size * 100) / file_info.uncompressed_size;
164
165 /* display a '*' if the file is crypted */
166 if ((file_info.flag & 1) != 0)
167 charCrypt = '*';
168
169 if (file_info.compression_method == 0)
170 string_method = "Stored";
171 else if (file_info.compression_method == Z_DEFLATED) {
172 uInt iLevel = (uInt)((file_info.flag & 0x6) / 2);
173 if (iLevel == 0)
174 string_method = "Defl:N";
175 else if (iLevel == 1)
176 string_method = "Defl:X";
177 else if ((iLevel == 2) || (iLevel == 3))
178 string_method = "Defl:F"; /* 2:fast , 3 : extra fast*/
179 } else
180 string_method = "Unkn. ";
181
182 printf("%7lu %6s%c%7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n",
183 file_info.uncompressed_size, string_method,
184 charCrypt,
185 file_info.compressed_size,
186 ratio,
187 (uLong)file_info.tmu_date.tm_mon + 1,
188 (uLong)file_info.tmu_date.tm_mday,
189 (uLong)file_info.tmu_date.tm_year % 100,
190 (uLong)file_info.tmu_date.tm_hour, (uLong)file_info.tmu_date.tm_min,
191 (uLong)file_info.crc, filename_inzip);
192 if ((i + 1) < gi.number_entry) {
193 err = unzGoToNextFile(uf);
194 if (err != UNZ_OK) {
195 printf("error %d with zipfile in unzGoToNextFile\n", err);
196 break;
197 }
198 }
199 }
200
201 unzClose(uf);
202
203 return 0;
204 }
205
direct_is_exist(const char * path)206 int direct_is_exist(const char* path)
207 {
208 struct stat stat_buf;
209 if (stat(path, &stat_buf) == 0) {
210 return (stat_buf.st_mode & S_IFMT) == S_IFDIR;
211 }
212
213 return 0;
214 }
215
do_extract_currentfile(unzFile uf,const int * popt_extract_without_path,int * popt_overwrite,const char * password,const char * direct_name)216 int do_extract_currentfile(unzFile uf,
217 const int* popt_extract_without_path,
218 int* popt_overwrite,
219 const char* password,
220 const char* direct_name)
221 {
222 char filename_inzip[256];
223 int err = UNZ_OK;
224 FILE* fout = NULL;
225 void* buf;
226 uInt size_buf;
227
228 unz_file_info file_info;
229 err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip),
230 NULL, 0, NULL, 0);
231 if (err != UNZ_OK) {
232 printf("error %d with zipfile in unzGetCurrentFileInfo\n", err);
233 return err;
234 }
235
236 char path_name[256];
237 int path_length = 0;
238 char absolute_path_name[256];
239 char* p;
240 for (p = filename_inzip; *p != '\0'; p++) {
241 path_name[path_length] = *p;
242 if ((*p) == '/') {
243 path_name[path_length] = '\0';
244 strcpy(absolute_path_name, direct_name);
245 strcat(absolute_path_name, path_name);
246 if (!direct_is_exist(absolute_path_name)) {
247 mymkdir(absolute_path_name);
248 }
249 path_name[path_length] = '/';
250 }
251
252 path_length++;
253 }
254
255 size_buf = WRITEBUFFERSIZE;
256 buf = (void*)malloc(size_buf);
257 if (buf == NULL) {
258 printf("Error allocating memory\n");
259 return UNZ_INTERNALERROR;
260 }
261
262 char write_filename[256];
263 int skip = 0;
264
265 strcpy(write_filename, direct_name);
266 strcat(write_filename, filename_inzip);
267
268 err = unzOpenCurrentFilePassword(uf, password);
269 if (err != UNZ_OK) {
270 printf("error %d with zipfile in unzOpenCurrentFilePassword\n", err);
271 }
272
273 if (((*popt_overwrite) == 0) && (err == UNZ_OK)) {
274 char rep = 0;
275 FILE* ftestexist;
276 ftestexist = fopen(write_filename, "rb");
277 if (ftestexist != NULL) {
278 fclose(ftestexist);
279 do {
280 char answer[128];
281 int ret;
282
283 printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ", write_filename);
284 ret = scanf("%1s", answer);
285 if (ret != 1) {
286 exit(EXIT_FAILURE);
287 }
288 rep = answer[0];
289 if ((rep >= 'a') && (rep <= 'z'))
290 rep -= 0x20;
291 } while ((rep != 'Y') && (rep != 'N') && (rep != 'A'));
292 }
293
294 if (rep == 'N')
295 skip = 1;
296
297 if (rep == 'A')
298 *popt_overwrite = 1;
299 }
300
301 if ((skip == 0) && (err == UNZ_OK)) {
302 fout = fopen(write_filename, "wb");
303 if (fout == NULL) {
304 //printf("error opening %s\n", write_filename);
305 }
306 }
307
308 if (fout != NULL) {
309 //printf(" extracting: %s\n", write_filename);
310
311 do {
312 err = unzReadCurrentFile(uf, buf, size_buf);
313 if (err < 0) {
314 printf("error %d with zipfile in unzReadCurrentFile\n", err);
315 break;
316 }
317 if (err > 0)
318 if (fwrite(buf, err, 1, fout) != 1) {
319 printf("error in writing extracted file\n");
320 err = UNZ_ERRNO;
321 break;
322 }
323 } while (err > 0);
324 if (fout)
325 fclose(fout);
326
327 if (err == 0)
328 change_file_date(write_filename, file_info.tmu_date);
329 }
330
331 if (err == UNZ_OK) {
332 err = unzCloseCurrentFile(uf);
333 if (err != UNZ_OK) {
334 printf("error %d with zipfile in unzCloseCurrentFile\n", err);
335 }
336 } else
337 unzCloseCurrentFile(uf); /* don't lose the error */
338
339 free(buf);
340 return err;
341 }
342
do_extract(unzFile uf,int opt_extract_without_path,int opt_overwrite,const char * password,const char * direct_name)343 int do_extract(unzFile uf,
344 int opt_extract_without_path,
345 int opt_overwrite,
346 const char* password,
347 const char* direct_name)
348 {
349 uLong i;
350 unz_global_info gi;
351 int err;
352
353 err = unzGetGlobalInfo(uf, &gi);
354 if (err != UNZ_OK)
355 printf("error %d with zipfile in unzGetGlobalInfo \n", err);
356
357 for (i = 0; i < gi.number_entry; i++) {
358 if (do_extract_currentfile(uf, &opt_extract_without_path,
359 &opt_overwrite,
360 password,
361 direct_name) != UNZ_OK)
362 break;
363
364 if ((i + 1) < gi.number_entry) {
365 err = unzGoToNextFile(uf);
366 if (err != UNZ_OK) {
367 printf("error %d with zipfile in unzGoToNextFile\n", err);
368 break;
369 }
370 }
371 }
372
373 return 0;
374 }
375
do_extract_onefile(unzFile uf,const char * filename,int opt_extract_without_path,int opt_overwrite,const char * password,const char * direct_name)376 int do_extract_onefile(unzFile uf,
377 const char* filename,
378 int opt_extract_without_path,
379 int opt_overwrite,
380 const char* password,
381 const char* direct_name)
382 {
383 if (unzLocateFile(uf, filename, CASESENSITIVITY) != UNZ_OK) {
384 printf("file %s not found in the zipfile\n", filename);
385 return 2;
386 }
387
388 if (do_extract_currentfile(uf, &opt_extract_without_path,
389 &opt_overwrite,
390 password,
391 direct_name) == UNZ_OK)
392 return 0;
393 else
394 return 1;
395 }
396
miniUnzip(const char * filePath,const char * outPath)397 int miniUnzip(const char* filePath, const char* outPath)
398 {
399 const char* zipfilename = filePath;
400 const char* filename_to_extract = NULL;
401 const char* password = NULL;
402 char filename_try[MAXFILENAME + 16] = "";
403 int opt_do_list = 0;
404 int opt_do_extract = 1;
405 int opt_do_extract_withoutpath = 0;
406 int opt_overwrite = 1;
407 int opt_extractdir = 0;
408 const char* dirname = NULL;
409 unzFile uf = NULL;
410 int ret_value = 0;
411
412 if (zipfilename != NULL) {
413 #ifdef USEWIN32IOAPI
414 zlib_filefunc_def ffunc;
415 #endif
416
417 strncpy(filename_try, zipfilename, MAXFILENAME - 1);
418 /* strncpy doesnt append the trailing NULL, of the string is too long. */
419 filename_try[MAXFILENAME] = '\0';
420
421 #ifdef USEWIN32IOAPI
422 fill_win32_filefunc(&ffunc);
423 uf = unzOpen2(zipfilename, &ffunc);
424 #else
425 uf = unzOpen(zipfilename);
426 #endif
427 }
428
429 if (uf == NULL) {
430 printf("Cannot open %s\n", zipfilename);
431 return 1;
432 }
433 //printf("%s opened\n", filename_try);
434
435 if (opt_do_list == 1)
436 return do_list(uf);
437 else if (opt_do_extract == 1) {
438 if (opt_extractdir && chdir(dirname)) {
439 printf("Error changing into %s, aborting\n", dirname);
440 exit(-1);
441 }
442
443 if (filename_to_extract == NULL)
444 ret_value = do_extract(uf, opt_do_extract_withoutpath, opt_overwrite, password, outPath);
445 else
446 ret_value = do_extract_onefile(uf, filename_to_extract,
447 opt_do_extract_withoutpath, opt_overwrite, password, outPath);
448 }
449
450 unzClose(uf);
451
452 return ret_value;
453 }
454