1 /* zipunzip.cpp -- IO for compress .zip files using zlib
2 Version 1.01e, February 12th, 2005
4 Copyright (C) 1998-2005 Gilles Vollant
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
12 For uncompress .zip file, look at unzip.h
15 I WAIT FEEDBACK at mail info@winimage.com
16 Visit also http://www.winimage.com/zLibDll/unzip.html for evolution
18 Condition of use and distribution are the same than zlib :
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.
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:
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.
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
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.
65 #ifdef HAVE_SYS_TYPES_H
66 # include <sys/types.h>
68 #ifdef HAVE_SYS_STAT_H
69 # include <sys/stat.h>
74 #ifdef HAVE_SYS_UTIME_H
75 # include <sys/utime.h>
90 #define WRITEBUFFERSIZE (16384)
91 #define MAXFILENAME (256)
93 using namespace std;
\r
97 uLong filetime(const char * f, tm_zip * tmzip, uLong * dt)
103 WIN32_FIND_DATA ff32;
105 hFind = FindFirstFile(f,&ff32);
106 if (hFind != INVALID_HANDLE_VALUE)
108 FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
109 FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
119 uLong filetime(const char * f, tm_zip * tmzip, uLong * /*dt*/)
122 struct stat s; /* results of stat() */
126 if (strcmp(f,"-")!=0) {
127 char name[MAXFILENAME+1];
129 if (len > MAXFILENAME)
132 strncpy(name, f,MAXFILENAME-1);
133 /* strncpy doesnt append the trailing NULL, of the string is too long. */
134 name[ MAXFILENAME ] = '\0';
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) {
144 filedate = localtime(&tm_t);
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;
158 uLong filetime(const char * f, tm_zip * tmzip, uLong * dt)
165 bool zipFiles(string const & zipfile, vector<pair<string, string> > const & files)
172 int size_buf = WRITEBUFFERSIZE;
173 buf = (void*)malloc(size_buf);
175 printf("Error allocating memory\n");
178 const char * fname = zipfile.c_str();
181 zlib_filefunc_def ffunc;
182 fill_win32_filefunc(&ffunc);
184 zf = zipOpen2(fname, false, NULL, &ffunc);
186 zf = zipOpen(fname, false);
193 for (vector<pair<string, string> >::const_iterator it = files.begin(); it != files.end(); ++it) {
197 const char * diskfilename = it->first.c_str();
198 const char * filenameinzip = it->second.c_str();
199 unsigned long crcFile=0;
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;
206 filetime(filenameinzip, &zi.tmz_date, &zi.dosDate);
208 err = zipOpenNewFileInZip3(zf, filenameinzip, &zi,
209 NULL,0,NULL,0,NULL /* comment*/,
211 Z_DEFAULT_COMPRESSION, // compression level
213 /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
214 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
219 printf("error in opening %s in zipfile\n",filenameinzip);
222 fin = fopen(diskfilename, "rb");
229 size_read = (int)fread(buf, 1, size_buf, fin);
230 if (size_read < size_buf)
232 printf("error in reading %s\n",filenameinzip);
237 err = zipWriteInFileInZip (zf, buf, size_read);
239 printf("error in writing %s in the zipfile\n",
244 } while ((err == ZIP_OK) && (size_read>0));
249 err = zipCloseFileInZip(zf);
251 printf("error in closing %s in the zipfile\n",
256 errclose = zipClose(zf, NULL);
257 if (errclose != ZIP_OK) {
258 printf("error in closing zip file\n");
265 // adapted from miniunz.c
268 int mymkdir(char const * pathname, unsigned long int mode)
271 # if MKDIR_TAKES_ONE_ARG
273 return ::mkdir(pathname);
276 return ::mkdir(pathname, mode_t(mode));
278 #elif defined(_WIN32)
280 return CreateDirectory(pathname, 0) != 0 ? 0 : -1;
282 return ::_mkdir(pathname);
284 # error "Don't know how to create a directory on this system."
289 int makedir(char * newdir)
293 int len = (int)strlen(newdir);
299 buffer = (char*)malloc(len+1);
300 strcpy(buffer,newdir);
302 if (buffer[len-1] == '/')
303 buffer[len-1] = '\0';
304 if (mymkdir(buffer, mode) == 0) {
313 while(*p && *p != '\\' && *p != '/')
317 if (mymkdir(buffer, mode) != 0) {
318 printf("couldn't create directory %s\n",buffer);
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)
339 FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
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);
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;
361 newdate.tm_year=tmu_date.tm_year ;
364 ut.actime=ut.modtime=mktime(&newdate);
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)
377 char filename_inzip[256];
378 char* filename_withoutpath;
385 unz_file_info file_info;
387 err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
390 printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
394 size_buf = WRITEBUFFERSIZE;
395 buf = (void*)malloc(size_buf);
397 printf("Error allocating memory\n");
398 return UNZ_INTERNALERROR;
401 p = filename_withoutpath = filename_inzip;
402 while ((*p) != '\0') {
403 if (((*p)=='/') || ((*p)=='\\'))
404 filename_withoutpath = p+1;
407 // this is a directory
408 if ((*filename_withoutpath)=='\0') {
409 if ((*popt_extract_without_path)==0)
410 makedir(filename_inzip);
412 // this is a filename
414 char write_filename[1024];
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, "/");
422 if ((*popt_extract_without_path)==0)
423 strcat(write_filename, filename_inzip);
425 strcat(write_filename, filename_withoutpath);
427 err = unzOpenCurrentFilePassword(uf,password);
429 printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err);
431 fout=fopen(write_filename, "wb");
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");
444 printf("error opening %s\n",write_filename);
451 err = unzReadCurrentFile(uf,buf,size_buf);
453 printf("error %d with zipfile in unzReadCurrentFile\n",err);
457 if (fwrite(buf,err,1,fout)!=1) {
458 printf("error in writing extracted file\n");
467 change_file_date(write_filename,file_info.dosDate,
472 err = unzCloseCurrentFile (uf);
474 printf("error %d with zipfile in unzCloseCurrentFile\n",err);
478 unzCloseCurrentFile(uf); /* don't lose the error */
486 bool unzipToDir(string const & zipfile, string const & dirname)
490 zlib_filefunc_def ffunc;
493 const char * zipfilename = zipfile.c_str();
496 fill_win32_filefunc(&ffunc);
497 uf = unzOpen2(zipfilename, &ffunc);
499 uf = unzOpen(zipfilename);
510 int opt_extract_without_path = 0;
511 int opt_overwrite = 1;
512 char * password = NULL;
514 err = unzGetGlobalInfo (uf, &gi);
516 printf("error %d with zipfile in unzGetGlobalInfo \n",err);
520 for (i=0; i < gi.number_entry; i++) {
521 if (do_extract_currentfile(uf, &opt_extract_without_path,
523 password, dirname.c_str()) != UNZ_OK)
526 if ((i+1)<gi.number_entry) {
527 err = unzGoToNextFile(uf);
529 printf("error %d with zipfile in unzGoToNextFile\n",err);
535 unzCloseCurrentFile(uf);