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