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