]> git.lyx.org Git - lyx.git/blob - src/support/minizip/zipunzip.cpp
Revert qprocess code. Revisions reverted: 22026, 22030, 22044, 22048,
[lyx.git] / src / support / minizip / zipunzip.cpp
1 /* zipunzip.cpp -- IO for compress .zip files using zlib
2    Version 1.01e, February 12th, 2005
3
4    Copyright (C) 1998-2005 Gilles Vollant
5
6    This unzip package allow creates .ZIP file, compatible with PKZip 2.04g
7      WinZip, InfoZip tools and compatible.
8    Multi volume ZipFile (span) are not supported.
9    Encryption compatible with pkzip 2.04g only supported
10    Old compressions used by old PKZip 1.x are not supported
11
12   For uncompress .zip file, look at unzip.h
13
14
15    I WAIT FEEDBACK at mail info@winimage.com
16    Visit also http://www.winimage.com/zLibDll/unzip.html for evolution
17
18    Condition of use and distribution are the same than zlib :
19
20   This software is provided 'as-is', without any express or implied
21   warranty.  In no event will the authors be held liable for any damages
22   arising from the use of this software.
23
24   Permission is granted to anyone to use this software for any purpose,
25   including commercial applications, and to alter it and redistribute it
26   freely, subject to the following restrictions:
27
28   1. The origin of this software must not be misrepresented; you must not
29      claim that you wrote the original software. If you use this software
30      in a product, an acknowledgment in the product documentation would be
31      appreciated but is not required.
32   2. Altered source versions must be plainly marked as such, and must not be
33      misrepresented as being the original software.
34   3. This notice may not be removed or altered from any source distribution.
35
36
37 */
38
39 /* for more info about .ZIP format, see
40       http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
41       http://www.info-zip.org/pub/infozip/doc/
42    PkWare has also a specification at :
43       ftp://ftp.pkware.com/probdesc.zip
44 */
45
46
47 // The original minizip.c and miniunz.c distributed with minizip provide
48 // two command line tools minizip and miniunz. This file combines these two 
49 // files and modifies the interface to provide two functions zipFiles and 
50 // unzipToDir. This file is covered by the original minizip license.
51 // 
52
53 #include <config.h>
54
55 #include <string>
56 #include <vector>
57 #include <utility>
58
59 #ifdef HAVE_UNISTD_H
60 # include <unistd.h>
61 #endif
62 #ifdef HAVE_DIRECT_H
63 # include <direct.h>
64 #endif
65 #ifdef HAVE_SYS_TYPES_H
66 # include <sys/types.h>
67 #endif
68 #ifdef HAVE_SYS_STAT_H
69 # include <sys/stat.h>
70 #endif
71 #ifdef HAVE_IO_H
72 # include <io.h>
73 #endif
74 #ifdef HAVE_SYS_UTIME_H
75 # include <sys/utime.h>
76 #endif
77 #ifdef HAVE_UTIME_H
78 # include <utime.h>
79 #endif
80 #include <fcntl.h>
81
82 #include "zip.h"
83 #include "unzip.h"
84
85 #ifdef WIN32
86 #define USEWIN32IOAPI
87 #include "iowin32.h"
88 #endif
89
90 #define WRITEBUFFERSIZE (16384)
91 #define MAXFILENAME (256)
92
93 using namespace std;\r
94
95
96 #ifdef WIN32
97 uLong filetime(const char * f, tm_zip * tmzip, uLong * dt)
98 {
99         int ret = 0;
100         {
101                 FILETIME ftLocal;
102                 HANDLE hFind;
103                 WIN32_FIND_DATA  ff32;
104
105                 hFind = FindFirstFile(f,&ff32);
106                 if (hFind != INVALID_HANDLE_VALUE)
107                 {
108                         FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
109                         FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
110                         FindClose(hFind);
111                         ret = 1;
112                 }
113         }
114         return ret;
115 }
116
117 #else
118 #ifdef unix
119 uLong filetime(const char * f, tm_zip * tmzip, uLong * /*dt*/)
120 {
121         int ret=0;
122         struct stat s;                                                            /* results of stat() */
123         struct tm* filedate;
124         time_t tm_t=0;
125
126         if (strcmp(f,"-")!=0) {
127                 char name[MAXFILENAME+1];
128                 int len = strlen(f);
129                 if (len > MAXFILENAME)
130                         len = MAXFILENAME;
131
132                 strncpy(name, f,MAXFILENAME-1);
133                 /* strncpy doesnt append the trailing NULL, of the string is too long. */
134                 name[ MAXFILENAME ] = '\0';
135
136                 if (name[len - 1] == '/')
137                         name[len - 1] = '\0';
138                 /* not all systems allow stat'ing a file with / appended */
139                 if (stat(name,&s)==0) {
140                         tm_t = s.st_mtime;
141                         ret = 1;
142                 }
143         }
144         filedate = localtime(&tm_t);
145
146         tmzip->tm_sec  = filedate->tm_sec;
147         tmzip->tm_min  = filedate->tm_min;
148         tmzip->tm_hour = filedate->tm_hour;
149         tmzip->tm_mday = filedate->tm_mday;
150         tmzip->tm_mon  = filedate->tm_mon ;
151         tmzip->tm_year = filedate->tm_year;
152
153         return ret;
154 }
155
156 #else
157
158 uLong filetime(const char * f, tm_zip * tmzip, uLong * dt)
159 {
160         return 0;
161 }
162 #endif
163 #endif
164
165 bool zipFiles(string const & zipfile, vector<pair<string, string> > const & files)
166 {
167         int err = 0;
168         zipFile zf;
169         int errclose;
170         void * buf = NULL;
171
172         int size_buf = WRITEBUFFERSIZE;
173         buf = (void*)malloc(size_buf);
174         if (buf==NULL) {
175                 printf("Error allocating memory\n");
176                 return false;
177         }
178         const char * fname = zipfile.c_str();
179
180 #ifdef USEWIN32IOAPI
181         zlib_filefunc_def ffunc;
182         fill_win32_filefunc(&ffunc);
183         // false: not append
184         zf = zipOpen2(fname, false, NULL, &ffunc);
185 #else
186         zf = zipOpen(fname, false);
187 #endif
188
189         if (zf == NULL) {
190                 return false;
191         }
192
193         for (vector<pair<string, string> >::const_iterator it = files.begin(); it != files.end(); ++it) {
194                 FILE * fin;
195                 int size_read;
196                 zip_fileinfo zi;
197                 const char * diskfilename = it->first.c_str();
198                 const char * filenameinzip = it->second.c_str();
199                 unsigned long crcFile=0;
200
201                 zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
202                         zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
203                 zi.dosDate = 0;
204                 zi.internal_fa = 0;
205                 zi.external_fa = 0;
206                 filetime(filenameinzip, &zi.tmz_date, &zi.dosDate);
207
208                 err = zipOpenNewFileInZip3(zf, filenameinzip, &zi,
209                         NULL,0,NULL,0,NULL /* comment*/,
210                         Z_DEFLATED,
211                         Z_DEFAULT_COMPRESSION,            // compression level
212                         0,
213                 /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
214                         -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
215                         NULL,                                             // password,
216                         crcFile);
217
218                 if (err != ZIP_OK) {
219                         printf("error in opening %s in zipfile\n",filenameinzip);
220                         return false;
221                 }
222                 fin = fopen(diskfilename, "rb");
223                 if (fin==NULL) {
224                         return false;
225                 }
226
227                 do {
228                         err = ZIP_OK;
229                         size_read = (int)fread(buf, 1, size_buf, fin);
230                         if (size_read < size_buf)
231                                 if (feof(fin)==0) {
232                                         printf("error in reading %s\n",filenameinzip);
233                                         return false;
234                                 }
235
236                         if (size_read>0) {
237                                 err = zipWriteInFileInZip (zf, buf, size_read);
238                                 if (err<0) {
239                                         printf("error in writing %s in the zipfile\n",
240                                                  filenameinzip);
241                                         return false;
242                                 }
243                         }
244                 } while ((err == ZIP_OK) && (size_read>0));
245
246                 if (fin)
247                         fclose(fin);
248
249                 err = zipCloseFileInZip(zf);
250                 if (err != ZIP_OK) {
251                         printf("error in closing %s in the zipfile\n",
252                                     filenameinzip);
253                         return false;
254                 }
255         }
256         errclose = zipClose(zf, NULL);
257         if (errclose != ZIP_OK) {
258                 printf("error in closing zip file\n");
259                 return false;
260         }
261         free(buf);
262         return true;
263 }
264
265 // adapted from miniunz.c
266
267
268 int mymkdir(char const * pathname, unsigned long int mode)
269 {
270 #if HAVE_MKDIR
271 # if MKDIR_TAKES_ONE_ARG
272         // MinGW32
273         return ::mkdir(pathname);
274 # else
275         // POSIX
276         return ::mkdir(pathname, mode_t(mode));
277 # endif
278 #elif defined(_WIN32)
279         // plain Windows 32
280         return CreateDirectory(pathname, 0) != 0 ? 0 : -1;
281 #elif HAVE__MKDIR
282         return ::_mkdir(pathname);
283 #else
284 #   error "Don't know how to create a directory on this system."
285 #endif
286 }
287
288
289 int makedir(char * newdir)
290 {
291         char *buffer;
292         char *p;
293         int     len = (int)strlen(newdir);
294         int mode = 0775;
295
296         if (len <= 0)
297                 return 1;
298
299         buffer = (char*)malloc(len+1);
300         strcpy(buffer,newdir);
301
302         if (buffer[len-1] == '/')
303                 buffer[len-1] = '\0';
304         if (mymkdir(buffer, mode) == 0) {
305                 free(buffer);
306                 return 0;
307         }
308
309         p = buffer + 1;
310         while (1) {
311                 char hold;
312
313                 while(*p && *p != '\\' && *p != '/')
314                         p++;
315                 hold = *p;
316                 *p = 0;
317                 if (mymkdir(buffer, mode) != 0) {
318                         printf("couldn't create directory %s\n",buffer);
319                         free(buffer);
320                         return 1;
321                 }
322                 if (hold == 0)
323                         break;
324                 *p++ = hold;
325         }
326         free(buffer);
327         return 0;
328 }
329
330
331 /* change_file_date : change the date/time of a file
332         filename : the filename of the file where date/time must be modified
333         dosdate : the new date at the MSDos format (4 bytes)
334         tmu_date : the SAME new date at the tm_unz format */
335 void change_file_date(const char * filename, uLong dosdate, tm_unz tmu_date)
336 {
337 #ifdef WIN32
338         HANDLE hFile;
339         FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
340
341         hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE,
342                 0,NULL,OPEN_EXISTING,0,NULL);
343         GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
344         DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
345         LocalFileTimeToFileTime(&ftLocal,&ftm);
346         SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
347         CloseHandle(hFile);
348 #else
349 #ifdef unix
350         utimbuf ut;
351         tm newdate;
352
353         newdate.tm_sec = tmu_date.tm_sec;
354         newdate.tm_min=tmu_date.tm_min;
355         newdate.tm_hour=tmu_date.tm_hour;
356         newdate.tm_mday=tmu_date.tm_mday;
357         newdate.tm_mon=tmu_date.tm_mon;
358         if (tmu_date.tm_year > 1900)
359                 newdate.tm_year=tmu_date.tm_year - 1900;
360         else
361                 newdate.tm_year=tmu_date.tm_year ;
362         newdate.tm_isdst=-1;
363
364         ut.actime=ut.modtime=mktime(&newdate);
365         utime(filename,&ut);
366 #endif
367 #endif
368 }
369
370
371 int do_extract_currentfile(unzFile uf,
372         const int * popt_extract_without_path,
373         int * popt_overwrite,
374         const char * password,
375         const char * dirname)
376 {
377         char filename_inzip[256];
378         char* filename_withoutpath;
379         char* p;
380         int err=UNZ_OK;
381         FILE *fout=NULL;
382         void* buf;
383         uInt size_buf;
384
385         unz_file_info file_info;
386         //uLong ratio=0;
387         err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
388
389         if (err!=UNZ_OK) {
390                 printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
391                 return err;
392         }
393
394         size_buf = WRITEBUFFERSIZE;
395         buf = (void*)malloc(size_buf);
396         if (buf==NULL) {
397                 printf("Error allocating memory\n");
398                 return UNZ_INTERNALERROR;
399         }
400
401         p = filename_withoutpath = filename_inzip;
402         while ((*p) != '\0') {
403                 if (((*p)=='/') || ((*p)=='\\'))
404                         filename_withoutpath = p+1;
405                 p++;
406         }
407         // this is a directory
408         if ((*filename_withoutpath)=='\0') {
409                 if ((*popt_extract_without_path)==0)
410                         makedir(filename_inzip);
411         }
412         // this is a filename
413         else {
414                 char write_filename[1024];
415
416                 strcpy(write_filename, dirname);
417                 int len = strlen(write_filename);
418                 if (write_filename[len-1] != '\\' &&
419                         write_filename[len-1] != '/')
420                         strcat(write_filename, "/");
421
422                 if ((*popt_extract_without_path)==0)
423                         strcat(write_filename, filename_inzip);
424                 else
425                         strcat(write_filename, filename_withoutpath);
426
427                 err = unzOpenCurrentFilePassword(uf,password);
428                 if (err!=UNZ_OK) {
429                         printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err);
430                 } else {
431                         fout=fopen(write_filename, "wb");
432
433                         /* some zipfile don't contain directory alone before file */
434                         if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
435                                 (filename_withoutpath!=(char*)filename_inzip)) {
436                                 char c=*(filename_withoutpath-1);
437                                 *(filename_withoutpath-1)='\0';
438                                 makedir(write_filename);
439                                 *(filename_withoutpath-1)=c;
440                                 fout=fopen(write_filename,"wb");
441                         }
442
443                         if (fout==NULL) {
444                                 printf("error opening %s\n",write_filename);
445                         }
446                 }
447
448                 if (fout!=NULL) {
449
450                         do {
451                                 err = unzReadCurrentFile(uf,buf,size_buf);
452                                 if (err<0) {
453                                         printf("error %d with zipfile in unzReadCurrentFile\n",err);
454                                         break;
455                                 }
456                                 if (err>0)
457                                         if (fwrite(buf,err,1,fout)!=1) {
458                                                 printf("error in writing extracted file\n");
459                                                 err=UNZ_ERRNO;
460                                                 break;
461                                         }
462                         } while (err>0);
463                         if (fout)
464                                 fclose(fout);
465
466                         if (err==0)
467                                 change_file_date(write_filename,file_info.dosDate,
468                                         file_info.tmu_date);
469                 }
470
471                 if (err==UNZ_OK) {
472                         err = unzCloseCurrentFile (uf);
473                         if (err!=UNZ_OK) {
474                                 printf("error %d with zipfile in unzCloseCurrentFile\n",err);
475                         }
476                 }
477                 else
478                         unzCloseCurrentFile(uf);          /* don't lose the error */
479         }
480
481         free(buf);
482         return err;
483 }
484
485
486 bool unzipToDir(string const & zipfile, string const & dirname)
487 {
488         unzFile uf=NULL;
489 #ifdef USEWIN32IOAPI
490         zlib_filefunc_def ffunc;
491 #endif
492
493         const char * zipfilename = zipfile.c_str();
494
495 #ifdef USEWIN32IOAPI
496         fill_win32_filefunc(&ffunc);
497         uf = unzOpen2(zipfilename, &ffunc);
498 #else
499         uf = unzOpen(zipfilename);
500 #endif
501
502         if (uf==NULL) {
503                 return false;
504         }
505
506         uLong i;
507         unz_global_info gi;
508         int err;
509         //FILE* fout=NULL;
510         int opt_extract_without_path = 0;
511         int opt_overwrite = 1;
512         char * password = NULL;
513
514         err = unzGetGlobalInfo (uf, &gi);
515         if (err != UNZ_OK) {
516                 printf("error %d with zipfile in unzGetGlobalInfo \n",err);
517                 return false;
518         }
519
520         for (i=0; i < gi.number_entry; i++) {
521                 if (do_extract_currentfile(uf, &opt_extract_without_path,
522                         &opt_overwrite,
523                         password, dirname.c_str()) != UNZ_OK)
524                         break;
525
526                 if ((i+1)<gi.number_entry) {
527                         err = unzGoToNextFile(uf);
528                         if (err != UNZ_OK) {
529                                 printf("error %d with zipfile in unzGoToNextFile\n",err);
530                                 break;
531                         }
532                 }
533         }
534
535         unzCloseCurrentFile(uf);
536     return true;
537 }
538