home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume19 / unzip / part01 next >
Text File  |  1991-05-19  |  54KB  |  1,460 lines

  1. Newsgroups: comp.sources.misc
  2. From: David Kirschbaum <kirsch@usasoc.soc.mil>
  3. Subject:  v19i096:  unzip - Portable unzip v4.1, Part01/06
  4. Message-ID: <1991May20.012040.29123@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 8f2def4e88a30816021b5578e62b8e5b
  6. Date: Mon, 20 May 1991 01:20:40 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: David Kirschbaum <kirsch@usasoc.soc.mil>
  10. Posting-number: Volume 19, Issue 96
  11. Archive-name: unzip/part01
  12. Supersedes: unzip-3.1: Volume 14, Issue 102-106
  13.  
  14. This is unzip v4.1, a public distribution version of the Info-ZIP project's
  15. portable generic Unix unzip utility.  This version of unzip has been ported 
  16. to a wide array of Unix and other mainframes, minis, and micros (to include 
  17. MSDOS, Atari ST (kinda), and Macintosh).  Although highly compatible with 
  18. Phil Katz's PKZIP and PKUNZIP utilities of MSDOS fame, our objective has been 
  19. one of portability and other-than-MSDOS functionality.
  20.  
  21. See the Makefile (or the system-specific archives) for details on
  22. how to compile for your system.  See unzip.1 or unzip.man for usage.  
  23. (No, there isn't a manual per se.  There's plenty of space on the 
  24. Info-ZIP staff for a volunteer!)
  25.  
  26. If any changes are made to source, we'd appreciate them (context diff
  27. files only, please) with explanation as appropriate.
  28.  
  29. All E-Mail should go to Info-ZIP@WSMR-SIMTEL20.Army.Mil directly
  30. (and not to me:  I'm only the Coordinator).  However, if you're
  31. requesting something special (e.g., a copy of the "No Feelthy ..."
  32. rules for source and change submission), E-Mail me personally.
  33.  
  34. If you'd like to keep up to date with our unzip (and companion zip
  35. utility) development, join the ranks of BETA testers, add your own
  36. thoughts and contributions, etc., send your request to
  37.  
  38.  Info-ZIP-Request@WSMR-SIMTEL20.Army.Mil
  39.  
  40. and Keith Petersen'll add you to the Info-ZIP newsletter mailing list.
  41. Read unzip41.descr for some more details.
  42.  
  43. David Kirschbaum
  44. Toad Hall
  45. Info-ZIP Coordinator
  46. -----
  47. #! /bin/sh
  48. # This is a shell archive.  Remove anything before this line, then feed it
  49. # into a shell via "sh file" or similar.  To overwrite existing files,
  50. # type "sh file -c".
  51. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  52. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  53. # Contents:  MANIFEST . ./v41 ./v41/ATARI_ST ./v41/ATARI_ST/MAKEFILE.ST
  54. #   ./v41/MAC ./v41/MAC/macstat.c ./v41/MSDOS ./v41/OS2 ./v41/VMS
  55. #   ./v41/unzip.c.1
  56. # Wrapped by kent@sparky on Sun May 19 19:40:38 1991
  57. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  58. echo If this archive is complete, you will see the following message:
  59. echo '          "shar: End of archive 1 (of 6)."'
  60. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  61.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  62. else
  63.   echo shar: Extracting \"'MANIFEST'\" \(1735 characters\)
  64.   sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  65. X   File Name        Archive #    Description
  66. X----------------------------------------------------------
  67. XMANIFEST                   1    This shipping list
  68. X.                          1    
  69. X./v41                      1    
  70. X./v41/ATARI_ST             1    Atari ST-peculiar files 
  71. X./v41/ATARI_ST/MAKEFILE.ST  1    
  72. X./v41/ATARI_ST/MAKEIT      6    (for Turbo C)
  73. X./v41/ATARI_ST/README.ST   5    
  74. X./v41/ATARI_ST/TCM         6    
  75. X./v41/ATARI_ST/TLINK.OPT   5    
  76. X./v41/ATARI_ST/UNZIP.PRJ   6    
  77. X./v41/ATARI_ST/tc_cfg.uue  5    Uuencoded binary file
  78. X./v41/History.41           4    Development history
  79. X./v41/MAC                  1    Macintosh-peculiar files
  80. X./v41/MAC/macfile.c        5    
  81. X./v41/MAC/macstat.c        1    
  82. X./v41/MAC/macstat.h        6    
  83. X./v41/MSDOS                1    MSDOS-peculiar files
  84. X./v41/MSDOS/MAKEFILE.DOS   5    
  85. X./v41/MSDOS/UNZIP.PRJ      6    
  86. X./v41/MSDOS/tcconfig.uue   6    Uuencoded binary file
  87. X./v41/Makefile             4    
  88. X./v41/OS2                  1    OS2-peculiar files
  89. X./v41/OS2/Readme.os2       6    
  90. X./v41/OS2/unzip.def        6    
  91. X./v41/VMS                  1    VMS-peculiar files
  92. X./v41/VMS/DESCRIP.MMS      6    
  93. X./v41/VMS/VMS_MAKE.COM     6    
  94. X./v41/VMS/VMSnotes         5    
  95. X./v41/VMS/fatdef.h         6    
  96. X./v41/VMS/fchdef.h         6    
  97. X./v41/VMS/fjndef.h         2    
  98. X./v41/VMS/vms_attr.c       5    
  99. X./v41/file_io.c            3    
  100. X./v41/mapname.c            4    
  101. X./v41/match.c              4    
  102. X./v41/misc.c               3    
  103. X./v41/unimplod.c           3    
  104. X./v41/unreduce.c           5    
  105. X./v41/unshrink.c           5    
  106. X./v41/unzip.1              5    
  107. X./v41/unzip.c.1            1    unzip.c, part 1
  108. X./v41/unzip.c.2            2    unzip.c, part 2
  109. X./v41/unzip.h              2    
  110. X./v41/unzip.man            5    
  111. X./v41/unzip41.descr        6    Description
  112. X./v41/ziprules.txt         5    Rules for contributors
  113. END_OF_FILE
  114.   if test 1735 -ne `wc -c <'MANIFEST'`; then
  115.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  116.   fi
  117.   # end of 'MANIFEST'
  118. fi
  119. if test ! -d './v41' ; then
  120.     echo shar: Creating directory \"'./v41'\"
  121.     mkdir './v41'
  122. fi
  123. if test ! -d './v41/ATARI_ST' ; then
  124.     echo shar: Creating directory \"'./v41/ATARI_ST'\"
  125.     mkdir './v41/ATARI_ST'
  126. fi
  127. if test -f './v41/ATARI_ST/MAKEFILE.ST' -a "${1}" != "-c" ; then 
  128.   echo shar: Will not clobber existing file \"'./v41/ATARI_ST/MAKEFILE.ST'\"
  129. else
  130.   echo shar: Extracting \"'./v41/ATARI_ST/MAKEFILE.ST'\" \(1093 characters\)
  131.   sed "s/^X//" >'./v41/ATARI_ST/MAKEFILE.ST' <<'END_OF_FILE'
  132. X#  Makefile.st    Makefile for UnZip 4.0,
  133. X#  using Turbo C 2.0 for the Atari ST and
  134. X#  make from the Mark Williams C 3.9 (sorry for that mixture)
  135. X#
  136. X
  137. X# UPPERCASE file names facilitate TD's understanding of modules.
  138. X.SUFFIXES: .o .O .c .C .s
  139. X
  140. XDISK    = E:
  141. X#####################
  142. X# MACRO DEFINITIONS #
  143. X#####################
  144. X
  145. XCC    = tcc
  146. X#CFLAGS    = -DATARI_ST=1 -Y -I=$(DISK)\tc\include
  147. XCFLAGS    = -DATARI_ST=1 -I=$(DISK)\tc\include
  148. X#LFLAGS    = -L -Y
  149. XLFLAGS    =
  150. XLIB    = $(DISK)\tc\lib
  151. XLD    = tlink
  152. X
  153. XOBJS = unzip.o file_io.o mapname.o match.o misc.o\
  154. X       unimplod.o unreduce.o unshrink.o
  155. X
  156. X
  157. X###############################################
  158. X# BASIC COMPILE INSTRUCTIONS AND DEPENDENCIES #
  159. X###############################################
  160. X
  161. XALL    : unzip.prg
  162. X    echo done
  163. X
  164. Xunzip.o:      unzip.c unzip.h
  165. X
  166. Xfile_io.o:    file_io.c unzip.h
  167. X
  168. Xmapname.o:    mapname.c unzip.h
  169. X
  170. Xmatch.o:      match.c unzip.h
  171. X
  172. Xmisc.o:       misc.c unzip.h
  173. X
  174. Xunimplod.o:   unimplod.c unzip.h
  175. X
  176. Xunreduce.o:   unreduce.c unzip.h
  177. X
  178. Xunshrink.o:   unshrink.c unzip.h
  179. X
  180. Xunzip.prg:     $(OBJS)
  181. X    tlink -O=$@ $(LFLAGS) -S=4096 -C=tlink.opt
  182. X
  183. X.c.o:
  184. X    tcc $(CFLAGS) $<
  185. X
  186. END_OF_FILE
  187.   if test 1093 -ne `wc -c <'./v41/ATARI_ST/MAKEFILE.ST'`; then
  188.     echo shar: \"'./v41/ATARI_ST/MAKEFILE.ST'\" unpacked with wrong size!
  189.   fi
  190.   # end of './v41/ATARI_ST/MAKEFILE.ST'
  191. fi
  192. if test ! -d './v41/MAC' ; then
  193.     echo shar: Creating directory \"'./v41/MAC'\"
  194.     mkdir './v41/MAC'
  195. fi
  196. if test -f './v41/MAC/macstat.c' -a "${1}" != "-c" ; then 
  197.   echo shar: Will not clobber existing file \"'./v41/MAC/macstat.c'\"
  198. else
  199.   echo shar: Extracting \"'./v41/MAC/macstat.c'\" \(5947 characters\)
  200.   sed "s/^X//" >'./v41/MAC/macstat.c' <<'END_OF_FILE'
  201. X#ifdef THINK_C
  202. X#define MACOS
  203. X#include    <FileMgr.h>
  204. X#include    <HFS.h>
  205. X#include    <pascal.h>
  206. X#endif
  207. X#ifdef MPW
  208. X#define MACOS
  209. X#include    <Files.h>
  210. X#include    <Errors.h>
  211. X#define FSFCBLen    (*(short *)0x3F6)
  212. X#define hFileInfo   hfileInfo
  213. X#define CtoPstr c2pstr
  214. X#define PtoCstr p2cstr
  215. X#endif
  216. X
  217. X#ifdef MACOS
  218. X#include    <string.h>
  219. X#include    "macstat.h"
  220. Xint stat(char *path, struct stat *buf);
  221. X
  222. X/* assume that the path will contain a Mac-type pathname, i.e. ':'s, etc. */
  223. Xint stat(path, buf)
  224. Xchar *path;
  225. Xstruct stat *buf;
  226. X{
  227. X    char    temp[256];
  228. X    short   curVolume;
  229. X    long    curDir;
  230. X    short   fIsHFS = false;
  231. X    OSErr   err;
  232. X
  233. X    if (buf == (struct stat *)0L || path == (char *)0L) {
  234. X        SysBeep(1);
  235. X        return -1;
  236. X    }
  237. X    
  238. X    if (path[0] == '\0' || strlen(path)>255) {
  239. X        return -1;
  240. X    }
  241. X
  242. X    if (GetVol((StringPtr)&temp[0], &curVolume) != noErr) {
  243. X        SysBeep(1);
  244. X        return -1;
  245. X    }
  246. X    
  247. X    /* get info about the specified volume */
  248. X    if (FSFCBLen > 0)   /* HFS Disk? */
  249. X    {
  250. X        WDPBRec wdpb;
  251. X        HParamBlockRec    hpbr;
  252. X        Str255 st;
  253. X
  254. X        wdpb.ioCompletion = 0;
  255. X        wdpb.ioNamePtr = temp;
  256. X        err = PBHGetVol(&wdpb, 0);
  257. X        if (err == noErr)
  258. X        {
  259. X            hpbr.volumeParam.ioCompletion = 0;
  260. X            hpbr.volumeParam.ioNamePtr = st;
  261. X            hpbr.volumeParam.ioVRefNum = wdpb.ioVRefNum;
  262. X            hpbr.volumeParam.ioVolIndex = 0;
  263. X            err = PBHGetVInfo(&hpbr, 0);
  264. X
  265. X            if (err == noErr && hpbr.volumeParam.ioVFSID == 0
  266. X                && hpbr.volumeParam.ioVSigWord == 0x4244) {
  267. X                    fIsHFS = true;
  268. X            }
  269. X        }
  270. X    }
  271. X
  272. X
  273. X    /* number of links, at least in System 6.0x, 0 */
  274. X    buf->st_nlink = 0;
  275. X    /* user id */
  276. X    buf->st_uid = 0;
  277. X    /* group id */
  278. X    buf->st_gid = 0;
  279. X
  280. X    if (fIsHFS == true)   /* HFS? */
  281. X    {
  282. X        CInfoPBRec  cPB;
  283. X        HParamBlockRec  wPB;
  284. X        
  285. X        wPB.wdParam.ioCompletion = (ProcPtr)0L;
  286. X        wPB.wdParam.ioNamePtr = (StringPtr)temp;
  287. X        err = PBHGetVol((WDPBPtr)&wPB, false);
  288. X        if (err != noErr) {
  289. X            SysBeep(1);
  290. X            return -1;
  291. X        }
  292. X
  293. X        curVolume = wPB.wdParam.ioWDVRefNum;
  294. X        buf->st_dev = curDir = wPB.wdParam.ioWDDirID;
  295. X        
  296. X        /* get information about file */
  297. X        cPB.hFileInfo.ioCompletion = (ProcPtr)0L;
  298. X        CtoPstr(path);
  299. X        strncpy(temp,path, path[0]+1);
  300. X        PtoCstr(path);
  301. X        cPB.hFileInfo.ioNamePtr = (StringPtr)temp;
  302. X        cPB.hFileInfo.ioVRefNum = 0;
  303. X        cPB.hFileInfo.ioDirID = 0;
  304. X        cPB.hFileInfo.ioFDirIndex = 0;
  305. X        
  306. X        err = PBGetCatInfo(&cPB, false); 
  307. X        
  308. X        if (err != noErr) {
  309. X            if (err != fnfErr) {
  310. X                SysBeep(1);
  311. X            }
  312. X            return -1;
  313. X        }
  314. X        
  315. X        /* Type of file: directory or regular file */
  316. X        buf->st_mode = (cPB.hFileInfo.ioFlAttrib & ioDirMask) ? S_IFDIR : S_IFREG;
  317. X        
  318. X        /* last access time, modification time and creation time(?) */
  319. X        buf->st_atime = buf->st_mtime = cPB.hFileInfo.ioFlMdDat;
  320. X        buf->st_ctime = cPB.hFileInfo.ioFlCrDat;
  321. X        /* inode number */
  322. X        buf->st_ino = cPB.hFileInfo.ioDirID + ((long)curVolume)<<16;
  323. X        /* size of file - use only the data fork */
  324. X        buf->st_size = cPB.hFileInfo.ioFlLgLen;
  325. X        /* size of disk block */
  326. X        if (cPB.hFileInfo.ioFlClpSiz == 0) {
  327. X            HParamBlockRec hPB;
  328. X            
  329. X            hPB.volumeParam.ioCompletion = (ProcPtr)0L;
  330. X            hPB.volumeParam.ioNamePtr = (StringPtr)temp;
  331. X            hPB.volumeParam.ioVRefNum = 0;
  332. X            hPB.volumeParam.ioVolIndex = 0;
  333. X            
  334. X            err = PBHGetVInfo(&hPB, false);
  335. X            
  336. X            if (err != noErr) {
  337. X                SysBeep(1);
  338. X                return -1;
  339. X            }
  340. X            
  341. X            buf->st_blksize = hPB.volumeParam.ioVClpSiz;
  342. X        }
  343. X        else
  344. X            buf->st_blksize = cPB.hFileInfo.ioFlClpSiz;
  345. X    
  346. X        buf->st_blocks = cPB.hFileInfo.ioFlPyLen/ buf->st_blksize;
  347. X    }
  348. X    else    /* MFS? */
  349. X    {
  350. X        ParamBlockRec   pPB;
  351. X        
  352. X        buf->st_dev = 0;
  353. X        
  354. X        CtoPstr(path);
  355. X        strncpy(temp, path, path[0]+1);
  356. X        PtoCstr(path);
  357. X        pPB.fileParam.ioCompletion = (ProcPtr)0;
  358. X        pPB.fileParam.ioNamePtr = (StringPtr)temp;
  359. X        pPB.fileParam.ioVRefNum = curVolume;
  360. X        pPB.fileParam.ioFVersNum = 0;
  361. X        pPB.fileParam.ioFDirIndex = 0;
  362. X        
  363. X        err = PBGetFInfo(&pPB, false);   
  364. X        
  365. X        if (err != noErr) {
  366. X            SysBeep(1);
  367. X            return -1;
  368. X        }
  369. X        
  370. X        /* Type of file: either directory or regular file */
  371. X        buf->st_mode = (pPB.fileParam.ioFlAttrib & ioDirMask) ? S_IFDIR : S_IFREG;
  372. X        
  373. X        /* last access time, modification time and creation time(?) */
  374. X        buf->st_atime = buf->st_mtime = pPB.fileParam.ioFlMdDat;
  375. X        buf->st_ctime = pPB.fileParam.ioFlCrDat;
  376. X        /* inode number */
  377. X        buf->st_ino = pPB.fileParam.ioFlNum + ((long)curVolume)<<16;
  378. X        /* size of file - use only the data fork */
  379. X        buf->st_size = pPB.fileParam.ioFlLgLen;
  380. X        /* size of disk block */
  381. X        {
  382. X            ParamBlockRec hPB;
  383. X            
  384. X            hPB.volumeParam.ioCompletion = (ProcPtr)0;
  385. X            hPB.volumeParam.ioNamePtr = (StringPtr)temp;
  386. X            hPB.volumeParam.ioVRefNum = curVolume;
  387. X            hPB.volumeParam.ioVolIndex = 0;
  388. X            
  389. X            err = PBGetVInfo(&hPB, false);
  390. X            
  391. X            if (err != noErr) {
  392. X                SysBeep(1);
  393. X                return -1;
  394. X            }
  395. X            
  396. X            buf->st_blksize = hPB.volumeParam.ioVClpSiz;
  397. X        }
  398. X    
  399. X        /* number of disk blocks used by file - includes resource fork */
  400. X        buf->st_blocks = pPB.fileParam.ioFlPyLen/ buf->st_blksize +
  401. X                            pPB.fileParam.ioFlRPyLen/buf->st_blksize;
  402. X    }
  403. X
  404. X    return 0;
  405. X}
  406. X#else
  407. X#error 1
  408. X#endif
  409. END_OF_FILE
  410.   if test 5947 -ne `wc -c <'./v41/MAC/macstat.c'`; then
  411.     echo shar: \"'./v41/MAC/macstat.c'\" unpacked with wrong size!
  412.   fi
  413.   # end of './v41/MAC/macstat.c'
  414. fi
  415. if test ! -d './v41/MSDOS' ; then
  416.     echo shar: Creating directory \"'./v41/MSDOS'\"
  417.     mkdir './v41/MSDOS'
  418. fi
  419. if test ! -d './v41/OS2' ; then
  420.     echo shar: Creating directory \"'./v41/OS2'\"
  421.     mkdir './v41/OS2'
  422. fi
  423. if test ! -d './v41/VMS' ; then
  424.     echo shar: Creating directory \"'./v41/VMS'\"
  425.     mkdir './v41/VMS'
  426. fi
  427. if test -f './v41/unzip.c.1' -a "${1}" != "-c" ; then 
  428.   echo shar: Will not clobber existing file \"'./v41/unzip.c.1'\"
  429. else
  430.   echo shar: Extracting \"'./v41/unzip.c.1'\" \(38155 characters\)
  431.   sed "s/^X//" >'./v41/unzip.c.1' <<'END_OF_FILE'
  432. X/*---------------------------------------------------------------------------
  433. X
  434. X  unzip.c
  435. X
  436. X  This is nearly a complete rewrite of unzip.c, mainly to allow access to
  437. X  zipfiles via the central directory (and hence to the OS bytes, so we can
  438. X  make intelligent decisions about what to do with the extracted files).
  439. X  Based on unzip.c 3.15+ and zipinfo.c 0.90.
  440. X
  441. X  ---------------------------------------------------------------------------
  442. X
  443. X  To compile (partial instructions):
  444. X
  445. X     under Unix (cc):  make <system name>
  446. X       (type "make" for list of valid names, or read Makefile for details)
  447. X
  448. X     under MS-DOS (TurboC):  make -fMAKEFILE.DOS  for command line compiles
  449. X       (or use the integrated environment and the included files TCCONFIG.TC
  450. X        and UNZIP.PRJ.  Tweak for your environment.)
  451. X
  452. X     under MS-DOS (MSC):  make MAKEFILE.DOS
  453. X       (or use Makefile if you have MSC 6.0:  "nmake msc_dos")
  454. X
  455. X     under OS/2 (MSC):  make MAKEFILE.DOS   (edit appropriately)
  456. X       (or use Makefile if you have MSC 6.0:  "nmake msc_os2")
  457. X
  458. X     under Atari OS:  Any Day Now.
  459. X
  460. X     under VMS:  DEFINE LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB   (see VMSNOTES)
  461. X                 CC UNZIP,FILE_IO,MAPNAME,MATCH,...,UNSHRINK
  462. X                 LINK UNZIP,FILE_IO,MAPNAME,MATCH,...,UNSHRINK
  463. X                 UNZIP :== $DISKNAME:[DIRECTORY]UNZIP.EXE
  464. X
  465. X     under Macintosh OS:   Double click on unzip.mac.  Press <Command>-M
  466. X
  467. X  ---------------------------------------------------------------------------
  468. X
  469. X  Version:  unzip41.arc/unzip41.tar.Z for Unix, VMS, OS/2, MS-DOS & Mac
  470. X  Source:   wsmr-simtel20.army.mil (192.88.110.20) in pd1:[misc.unix]
  471. X            wuarchive.wustl.edu (128.252.135.4) in /mirrors/misc/unix
  472. X  Source:   wsmr-simtel20.army.mil (26.2.0.74) in pd1:[misc.unix]
  473. X
  474. X  ---------------------------------------------------------------------------
  475. X
  476. X  Copyright, originally from version 1.2 (?):
  477. X
  478. X     * Copyright 1989 Samuel H. Smith;  All rights reserved
  479. X     *
  480. X     * Do not distribute modified versions without my permission.
  481. X     * Do not remove or alter this notice or any other copyright notice.
  482. X     * If you use this in your own program you must distribute source code.
  483. X     * Do not use any of this in a commercial product.
  484. X
  485. X  ---------------------------------------------------------------------------
  486. X
  487. X  Comments from unzip.c, version 3.11:
  488. X
  489. X     * UnZip - A simple zipfile extract utility
  490. X     *
  491. X     * Compile-time definitions:
  492. X     * See the Makefile for details, explanations, and all the current
  493. X     * system makerules.
  494. X     *
  495. X     * If you have to add a new one for YOUR system, please forward the new
  496. X     * Makefile context diff to kirsch%maxemail@uunet.uu.net for distribution.
  497. X     * Be SURE to give FULL details on your system (hardware, OS, versions,
  498. X     * processor, whatever) that made it unique.
  499. X     *
  500. X     * REVISION HISTORY : See History.41 (or whatever current version is)
  501. X
  502. X  To join Info-ZIP, send a message to Info-ZIP-Request@WSMR-Simtel20.Army.Mil
  503. X
  504. X  ---------------------------------------------------------------------------*/
  505. X
  506. X
  507. X
  508. X
  509. X
  510. X#include "unzip.h"              /* includes, defines, and macros */
  511. X
  512. X#define VERSION  "v4.1 of 5-13-91"
  513. X#define PAKFIX   /* temporary solution to PAK-created zipfiles */
  514. X
  515. X
  516. X
  517. X
  518. X
  519. X/**********************/
  520. X/*  Global Variables */
  521. X/**********************/
  522. X
  523. Xint tflag;              /* -t: test */
  524. Xint vflag;              /* -v: view directory (only used in unzip.c) */
  525. Xint cflag;              /* -c: output to stdout */
  526. Xint aflag;              /* -a: do ascii to ebcdic translation OR CR-LF */
  527. X                        /*     to CR or LF conversion of extracted files */
  528. Xint dflag;              /* -d: create containing directories */
  529. Xint Uflag;              /* -U: leave filenames in upper or mixed case */
  530. Xint V_flag;             /* -V: don't strip VMS version numbers */
  531. Xint quietflg;           /* -q: produce a lot less output */
  532. Xint do_all;             /* -o: OK to overwrite files without prompting */
  533. Xint zflag;              /* -z: Display only the archive comment */
  534. X
  535. Xint lcflag;             /* convert filename to lowercase */
  536. Xunsigned f_attr;        /* file attributes (permissions) */
  537. Xlongint csize;          /* used by list_files(), ReadByte(): must be signed */
  538. Xlongint ucsize;         /* used by list_files(), unReduce(), unImplode() */
  539. X
  540. X/*---------------------------------------------------------------------------
  541. X    unShrink/unReduce/unImplode working storage:
  542. X  ---------------------------------------------------------------------------*/
  543. X
  544. X/* prefix_of (for unShrink) is biggest storage area, esp. on Crays...space */
  545. X/*  is shared by lit_nodes (unImplode) and followers (unReduce) */
  546. X
  547. Xshort prefix_of[HSIZE + 1];     /* (8193 * sizeof(short)) */
  548. X#ifdef MACOS
  549. Xbyte *suffix_of;
  550. Xbyte *stack;
  551. X#else
  552. Xbyte suffix_of[HSIZE + 1];      /* also s-f length_nodes (smaller) */
  553. Xbyte stack[HSIZE + 1];          /* also s-f distance_nodes (smaller) */
  554. X#endif
  555. X
  556. XULONG crc32val;
  557. X
  558. XUWORD mask_bits[] =
  559. X{0, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
  560. X    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff};
  561. X
  562. X/*---------------------------------------------------------------------------
  563. X    Input file variables:
  564. X  ---------------------------------------------------------------------------*/
  565. X
  566. Xbyte *inbuf, *inptr;    /* input buffer (any size is legal) and pointer */
  567. Xint incnt;
  568. X
  569. XUWORD bitbuf;
  570. Xint bits_left;
  571. Xboolean zipeof;
  572. X
  573. Xint zipfd;                      /* zipfile file handle */
  574. Xchar zipfn[FILNAMSIZ];
  575. X
  576. Xlocal_file_header lrec;
  577. Xstruct stat statbuf;            /* used by main(), mapped_name() */
  578. X
  579. Xlongint cur_zipfile_bufstart;   /* extract_or_test_files, readbuf, ReadByte */
  580. X
  581. X/*---------------------------------------------------------------------------
  582. X    Output stream variables:
  583. X  ---------------------------------------------------------------------------*/
  584. X
  585. Xbyte *outbuf;                   /* buffer for rle look-back */
  586. Xbyte *outptr;
  587. Xbyte *outout;                   /* scratch pad for ASCII-native trans */
  588. Xlongint outpos;                 /* absolute position in outfile */
  589. Xint outcnt;                     /* current position in outbuf */
  590. X
  591. Xint outfd;
  592. Xchar filename[FILNAMSIZ];
  593. X
  594. X/*---------------------------------------------------------------------------
  595. X    unzip.c static global variables (visible only within this file):
  596. X  ---------------------------------------------------------------------------*/
  597. X
  598. Xstatic char *fnames[2] =
  599. X{"*", NULL};                    /* default filenames vector */
  600. Xstatic char **fnv = &fnames[0];
  601. Xstatic char sig[5];
  602. Xstatic byte *hold;
  603. Xstatic int process_all_files;
  604. Xstatic longint ziplen;
  605. Xstatic UWORD hostnum;
  606. Xstatic UWORD methnum;
  607. X/* static UWORD extnum; */
  608. Xstatic central_directory_file_header crec;
  609. Xstatic end_central_dir_record ecrec;
  610. X
  611. X/*---------------------------------------------------------------------------
  612. X    unzip.c repeated error messages (we use all of these at least twice ==>
  613. X    worth it to centralize to keep executable small):
  614. X  ---------------------------------------------------------------------------*/
  615. X
  616. Xstatic char *CryptMsg =
  617. X  "%s:  encrypted (can't do yet)--skipping.\n";
  618. Xstatic char *FilNamMsg =
  619. X  "\n%s:  bad filename length (%s)\n";
  620. Xstatic char *ExtFieldMsg =
  621. X  "\n%s:  bad extra field length (%s)\n";
  622. Xstatic char *OffsetMsg =
  623. X  "\n%s:  bad zipfile offset (%s)\n";
  624. Xstatic char *EndSigMsg =
  625. X  "\nwarning:  didn't find end-of-central-dir signature at end of central dir.\n";
  626. Xstatic char *CentSigMsg =
  627. X  "\nerror:  expected central file header signature not found (file #%u).\n";
  628. Xstatic char *ReportMsg =
  629. X  "        (please report to info-zip@wsmr-simtel20.army.mil)\n";
  630. X
  631. X/* (original) Bill Davidsen version */
  632. X#define QCOND    (!quietflg)    /* -xq[q] kill "extracting: ..." msgs */
  633. X#define QCOND2   (which_hdr)    /* file comments with -v, -vq, -vqq */
  634. X
  635. X
  636. X
  637. X
  638. X/*****************/
  639. X/*  Main program */
  640. X/*****************/
  641. X
  642. Xmain(argc, argv)        /* return PK-type error code (except under VMS) */
  643. Xint argc;
  644. Xchar *argv[];
  645. X{
  646. X    char *s;
  647. X    int c, print_usage=TRUE;
  648. X
  649. X
  650. X
  651. X#ifdef MACOS
  652. X#ifdef THINK_C
  653. X    #include <console.h>
  654. X    #include <StdFilePkg.h>
  655. X    typedef struct sf_node {        /* node in a true shannon-fano tree */
  656. X        UWORD left;                 /* 0 means leaf node */
  657. X        UWORD right;                /*   or value if leaf node */
  658. X    } sf_node;
  659. X    static char *argstr[30], args[30*64];
  660. X    extern sf_node *lit_nodes, *length_nodes, *distance_nodes;
  661. X    Point   p;
  662. X    SFTypeList  sfT;
  663. X    int a;
  664. X    EventRecord theEvent;
  665. X    short   eMask;
  666. X    SFReply  fileRep;
  667. X
  668. X    suffix_of = (byte *)calloc(HSIZE+1, sizeof(byte));
  669. X    stack = (byte *)calloc(HSIZE+1, sizeof(byte));
  670. X    length_nodes = (sf_node *) suffix_of;  /* 2*LENVALS nodes */
  671. X    distance_nodes = (sf_node *) stack;    /* 2*DISTVALS nodes */
  672. X   
  673. X    for (a=0; a<30; a+=1)
  674. X    {
  675. X        argstr[a] = &args[a*64];
  676. X    }
  677. Xstart:
  678. X    tflag = vflag=cflag=aflag=dflag=Uflag=quietflg=lcflag=zflag = 0;
  679. X    argc = ccommand(&argv);
  680. X    SetPt(&p, 40,40);
  681. X
  682. X    SFGetFile(p, "\pSpecify ZIP file:", 0L, -1, sfT, 0L, &fileRep);
  683. X    if (!fileRep.good)
  684. X        exit(1);
  685. X    macfstest(fileRep.vRefNum, true);
  686. X    SetMacVol(NULL, fileRep.vRefNum);
  687. X    for (a=1; a<argc; a+=1)
  688. X    {
  689. X        if (argv[a][0] == '-')
  690. X        {
  691. X            BlockMove(argv[a], argstr[a], (strlen(argv[a])>63) ? 64 : strlen(argv[a])+1);
  692. X        }
  693. X        else
  694. X            break;
  695. X    }
  696. X    PtoCstr((char *)fileRep.fName);
  697. X    strcpy(argstr[a], fileRep.fName);
  698. X    for (;a<argc; a+=1)
  699. X    {
  700. X        BlockMove(argv[a], argstr[a+1], (strlen(argv[a])>63) ? 64 : strlen(argv[a])+1);
  701. X    }
  702. X    argc+=1;
  703. X    argv = argstr;
  704. X
  705. X#endif /* THINK_C */
  706. X#endif /* MACOS */
  707. X
  708. X/*---------------------------------------------------------------------------
  709. X    Debugging info for checking on structure padding:
  710. X  ---------------------------------------------------------------------------*/
  711. X
  712. X#ifdef DEBUG_STRUC
  713. X    printf("local_file_header size: %X\n",
  714. X           sizeof(struct local_file_header));
  715. X    printf("local_byte_header size: %X\n",
  716. X           sizeof(struct local_byte_header));
  717. X    printf("actual size of local headers: %X\n", LREC_SIZE);
  718. X
  719. X    printf("central directory header size: %X\n",
  720. X           sizeof(struct central_directory_file_header));
  721. X    printf("central directory byte header size: %X\n",
  722. X           sizeof(struct central_directory_byte_header));
  723. X    printf("actual size of central dir headers: %X\n", CREC_SIZE);
  724. X
  725. X    printf("end central dir record size: %X\n",
  726. X           sizeof(struct end_central_dir_record));
  727. X    printf("end central dir byte record size: %X\n",
  728. X           sizeof(struct end_central_byte_record));
  729. X    printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
  730. X#endif
  731. X
  732. X#ifndef KNOW_IT_WORKS  /* define this to save space, if things already work */
  733. X#ifndef DOS_OS2        /* already works (no RISCy OS/2's yet...) */
  734. X#ifndef NOTINT16       /* whole point is to see if this NEEDS defining */
  735. X    {
  736. X        int error=0;
  737. X        long testsig;
  738. X        static char *mach_type[3] = {"big-endian",
  739. X          "structure-padding", "big-endian and structure-padding"};
  740. X        strcpy((char *)&testsig,"012");
  741. X        if (testsig != 0x00323130)
  742. X            error = 1;
  743. X        if (sizeof(central_directory_file_header) != CREC_SIZE)
  744. X            error += 2;
  745. X        if (error--)
  746. X            fprintf(stderr, "It appears that your machine is %s.  If errors\n\
  747. Xoccur, please try recompiling with \"NOTINT16\" defined (read the\n\
  748. XMakefile, or try \"make hp\").\n\n", mach_type[error]);
  749. X    }
  750. X#endif /* !NOTINT16 */
  751. X#endif /* !DOS_OS2 */
  752. X#endif /* !KNOW_IT_WORKS */
  753. X
  754. X/*---------------------------------------------------------------------------
  755. X    Rip through any command-line options lurking about...
  756. X  ---------------------------------------------------------------------------*/
  757. X
  758. X    while (--argc > 0 && (*++argv)[0] == '-') {
  759. X        s = argv[0] + 1;
  760. X        while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
  761. X            switch (c) {
  762. X            case ('x'): /* just ignore -x, -e options (extract) */
  763. X            case ('e'):
  764. X                break;
  765. X            case ('q'):
  766. X                ++quietflg;
  767. X                break;
  768. X            case ('t'):
  769. X                ++tflag;
  770. X                break;
  771. X            case ('v'):
  772. X                ++vflag;
  773. X                /* fall thru */
  774. X            case ('l'):
  775. X                ++vflag;
  776. X                break;
  777. X            case ('p'):
  778. X                ++cflag;
  779. X#ifdef NATIVE
  780. X                ++aflag;
  781. X#endif
  782. X                quietflg += 2;
  783. X                break;
  784. X            case ('c'):
  785. X                ++cflag;
  786. X#ifdef NATIVE
  787. X                ++aflag;        /* this is so you can read it on the screen */
  788. X#endif
  789. X                break;
  790. X            case ('a'):
  791. X                ++aflag;
  792. X                break;
  793. X#ifdef VMS
  794. X            case ('u'): /* switches converted to l.c. unless quoted */
  795. X#endif
  796. X            case ('U'): /* "uppercase flag" (i.e., don't convert) */
  797. X                ++Uflag;
  798. X                break;
  799. X            case ('V'): /* Version flag:  retain VMS/DEC-20 file versions */
  800. X                ++V_flag;
  801. X                break;
  802. X            case ('d'): /* create parent dirs flag */
  803. X#ifdef MACOS
  804. X                if (hfsflag == true)
  805. X#endif
  806. X                ++dflag;
  807. X                break;
  808. X            case ('o'): /* OK to overwrite files without prompting */
  809. X                ++do_all;
  810. X                break;
  811. X            case ('z'): /* Display only the archive commentp */
  812. X                ++zflag;
  813. X                break;
  814. X            default:
  815. X                if (print_usage) {
  816. X                    usage();
  817. X                    print_usage = FALSE;
  818. X                }
  819. X                break;
  820. X            }
  821. X        }
  822. X    }
  823. X
  824. X/*---------------------------------------------------------------------------
  825. X    Make sure we aren't trying to do too many things here.  [This seems like
  826. X    kind of a brute-force way to do things; but aside from that, isn't the
  827. X    -a option useful when listing the directory (i.e., for reading zipfile
  828. X    comments)?  It's a modifier, not an action in and of itself, so perhaps
  829. X    it should not be included in the test--certainly, in the case of zipfile
  830. X    testing, it can just be ignored.]
  831. X  ---------------------------------------------------------------------------*/
  832. X
  833. X    if ((tflag && vflag) || (tflag && cflag) || (vflag && cflag) ||
  834. X        (tflag && aflag) || (aflag && vflag)) {
  835. X        fprintf(stderr, "only one of -t, -c, -a, or -v\n");
  836. X        RETURN(10);             /* 10:  bad or illegal parameters specified */
  837. X    }
  838. X    if (quietflg && zflag)
  839. X        quietflg = 0;
  840. X    if (argc-- == 0) {
  841. X        if (print_usage)
  842. X            usage();
  843. X        RETURN(10);             /* 10:  bad or illegal parameters specified */
  844. X    }
  845. X/*---------------------------------------------------------------------------
  846. X    Now get the zipfile name from the command line and see if it exists as a
  847. X    regular (non-directory) file.  If not, append the ".zip" suffix.  We don't
  848. X    immediately check to see if this results in a good name, but we will do so
  849. X    later.  In the meantime, see if there are any member filespecs on the com-
  850. X    mand line, and if so, set the filename pointer to point at them.
  851. X  ---------------------------------------------------------------------------*/
  852. X
  853. X    strcpy(zipfn, *argv++);
  854. X    if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
  855. X        strcat(zipfn, ZSUFX);
  856. X
  857. X    if (stat(zipfn, &statbuf)) {/* try again */
  858. X        fprintf(stderr, "error:  can't find zipfile [ %s ]\n", zipfn);
  859. X        RETURN(9);              /* 9:  file not found */
  860. X    } else
  861. X        ziplen = statbuf.st_size;
  862. X
  863. X    if (argc != 0) {
  864. X        fnv = argv;
  865. X        process_all_files = FALSE;
  866. X    } else
  867. X        process_all_files = TRUE;       /* for speed */
  868. X
  869. X/*---------------------------------------------------------------------------
  870. X    Okey dokey, we have everything we need to get started.  Let's roll.
  871. X  ---------------------------------------------------------------------------*/
  872. X
  873. X    inbuf = (byte *) (malloc(INBUFSIZ + 4));    /* 4 extra for hold[] (below) */
  874. X    outbuf = (byte *) (malloc(OUTBUFSIZ + 1));  /* 1 extra for string termin. */
  875. X    if (aflag)                  /* if need an ascebc scratch, */
  876. X        outout = (byte *) (malloc(OUTBUFSIZ));
  877. X    else                        /*  allocate it... */
  878. X        outout = outbuf;        /*  else just point to outbuf */
  879. X
  880. X    if ((inbuf == NULL) || (outbuf == NULL) || (outout == NULL)) {
  881. X        fprintf(stderr, "error:  can't allocate unzip buffers\n");
  882. X        RETURN(4);              /* 4-8:  insufficient memory */
  883. X    }
  884. X    hold = &inbuf[INBUFSIZ];    /* to check for boundary-spanning signatures */
  885. X
  886. X#ifdef THINK_C
  887. X    if (!process_zipfile())
  888. X        goto start;
  889. X#else
  890. X    RETURN(process_zipfile());  /* keep passing errors back... */
  891. X#endif
  892. X
  893. X}       /* end main() */
  894. X
  895. X
  896. X
  897. X
  898. X
  899. X/*********************/
  900. X/*  Function usage() */
  901. X/*********************/
  902. X
  903. Xvoid usage()
  904. X{
  905. X#ifdef NATIVE
  906. X    char *astring = "-a     convert ASCII to native character set";
  907. X#else
  908. X#ifdef MACOS
  909. X    char *astring = "-a     convert to Mac textfile format (CR LF => CR)";
  910. X#else
  911. X#ifdef DOS_OS2
  912. X    char *astring = "-a     convert to DOS & OS/2 textfile format (LF => CR LF)";
  913. X#else
  914. X    char *astring = "-a     convert to Unix/VMS textfile format (CR LF => LF)";
  915. X#endif /* ?DOS_OS2 */
  916. X#endif /* ?MACOS */
  917. X#endif /* ?NATIVE */
  918. X
  919. X
  920. X    fprintf(stderr, "UnZip:  Zipfile Extract %s;  (C) 1989 Samuel H. Smith\n",
  921. X                 VERSION);
  922. X    fprintf(stderr, "Courtesy of:  S.H.Smith  and  The Tool Shop BBS,  \
  923. X(602) 279-2673.\n\n");
  924. X    fprintf(stderr, "Versions 3.0 and later brought to you by the fine folks \
  925. Xat Info-ZIP\n");
  926. X    fprintf(stderr, "(Info-ZIP@WSMR-Simtel20.Army.Mil)\n\n");
  927. X    fprintf(stderr, "Usage:  unzip [ -xecptlvz[qadoUV] ] file[.zip] [filespec...]\n\
  928. X  -x,-e  extract files in archive (default--i.e., this flag is optional)\n\
  929. X  -c     extract files to stdout (\"CRT\")\n\
  930. X  -p     extract files to stdout and no informational messages (for pipes)\n\
  931. X  -t     test files\n\
  932. X  -l     list files (short format)\n\
  933. X  -v     verbose listing of files\n");
  934. X    fprintf(stderr, "\
  935. X  -z     display only the archive comment\n\
  936. X  -q     perform operations quietly (up to two q's allowed)\n\
  937. X  %s\n\
  938. X  -d     include directory structure when extracting/listing\n\
  939. X  -o     OK to overwrite files without prompting\n\
  940. X  -U     don't map filenames to lowercase for selected (uppercase) OS's\n\
  941. X  -V     retain file version numbers\n", astring);
  942. X
  943. X#ifdef VMS
  944. X    fprintf(stderr, "Remember that non-lowercase filespecs must be quoted in \
  945. XVMS (e.g., \"Makefile\").\n");
  946. X#endif
  947. X
  948. X}       /* end function usage() */
  949. X
  950. X
  951. X
  952. X
  953. X
  954. X/*******************************/
  955. X/*  Function process_zipfile() */
  956. X/*******************************/
  957. X
  958. Xint process_zipfile()
  959. X/* return PK-type error code */
  960. X{
  961. X    int error=0, error_in_archive;
  962. X
  963. X
  964. X
  965. X/*---------------------------------------------------------------------------
  966. X    Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
  967. X    lation, which would corrupt the bitstreams.  Then find and process the
  968. X    central directory; list, extract or test member files as instructed; and
  969. X    close the zipfile.
  970. X  ---------------------------------------------------------------------------*/
  971. X
  972. X#ifdef VMS
  973. X    change_zipfile_attributes(0);
  974. X#endif
  975. X    if (open_input_file())      /* this should never happen, given the */
  976. X        return (9);             /*   stat() test in main(), but... */
  977. X
  978. X    if (find_end_central_dir()) /* not found; nothing to do */
  979. X        return (2);             /* 2:  error in zipfile */
  980. X
  981. X#ifdef TEST
  982. X    printf("\n  found end-of-central-dir signature at offset %ld (%.8lXh)\n",
  983. X      cur_zipfile_bufstart+(inptr-inbuf), cur_zipfile_bufstart+(inptr-inbuf) );
  984. X    printf("    from beginning of file; offset %d (%.4Xh) within block\n",
  985. X      inptr-inbuf, inptr-inbuf);
  986. X#endif
  987. X
  988. X    if ((error_in_archive = process_end_central_dir()) > 1)
  989. X        return (error_in_archive);
  990. X
  991. X    if (zflag)
  992. X        return (0);
  993. X
  994. X#ifndef PAKFIX
  995. X    if (ecrec.number_this_disk == 0) {
  996. X#else /* PAKFIX */
  997. X    if (ecrec.number_this_disk == 0  ||  (error = (ecrec.number_this_disk == 1
  998. X        && ecrec.num_disk_with_start_central_dir == 1))) {
  999. X
  1000. X        if (error) {
  1001. X            fprintf(stderr,
  1002. X     "\n     Warning:  zipfile claims to be disk 2 of a two-part archive;\n\
  1003. X     attempting to process anyway.  If no further errors occur, this\n\
  1004. X     archive was probably created by PAK v2.5 or earlier.  This bug\n\
  1005. X     has been reported to NoGate and should be fixed by mid-April 1991.\n\n");
  1006. X            error_in_archive = 1;  /* 1:  warning */
  1007. X        }
  1008. X#endif /* ?PAKFIX */
  1009. X        if (vflag)
  1010. X            error = list_files();       /* LIST 'EM */
  1011. X        else
  1012. X            error = extract_or_test_files();    /* EXTRACT OR TEST 'EM */
  1013. X        if (error > error_in_archive)   /* don't overwrite stronger error */
  1014. X            error_in_archive = error;   /*  with (for example) a warning */
  1015. X    } else {
  1016. X        fprintf(stderr, "\nerror:  zipfile is part of multi-disk archive \
  1017. X(sorry, no can do).\n");
  1018. X        fprintf(stderr, ReportMsg);   /* report to info-zip */
  1019. X        error_in_archive = 11;  /* 11:  no files found */
  1020. X    }
  1021. X
  1022. X    close(zipfd);
  1023. X#ifdef VMS
  1024. X    change_zipfile_attributes(1);
  1025. X#endif
  1026. X    return (error_in_archive);
  1027. X
  1028. X}       /* end function process_zipfile() */
  1029. X
  1030. X
  1031. X
  1032. X
  1033. X
  1034. X/************************************/
  1035. X/*  Function find_end_central_dir() */
  1036. X/************************************/
  1037. X
  1038. Xint find_end_central_dir()
  1039. X/* return 0 if found, 1 otherwise */
  1040. X{
  1041. X    int i, numblks;
  1042. X    longint tail_len;
  1043. X
  1044. X
  1045. X
  1046. X/*---------------------------------------------------------------------------
  1047. X    Treat case of short zipfile separately.
  1048. X  ---------------------------------------------------------------------------*/
  1049. X
  1050. X    if (ziplen <= INBUFSIZ) {
  1051. X        lseek(zipfd, 0L, SEEK_SET);
  1052. X        if ((incnt = read(zipfd,inbuf,(unsigned int)ziplen)) == ziplen)
  1053. X
  1054. X            /* 'P' must be at least 22 bytes from end of zipfile */
  1055. X            for ( inptr = inbuf+ziplen-22  ;  inptr >= inbuf  ;  --inptr )
  1056. X                if ( (ascii_to_native(*inptr) == 'P')  &&
  1057. X                      !strncmp((char *)inptr, END_CENTRAL_SIG, 4) ) {
  1058. X                    incnt -= inptr - inbuf;
  1059. X                    return(0);  /* found it! */
  1060. X                }               /* ...otherwise fall through & fail */
  1061. X
  1062. X/*---------------------------------------------------------------------------
  1063. X    Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
  1064. X    block at end of zipfile (if not TOO short).
  1065. X  ---------------------------------------------------------------------------*/
  1066. X
  1067. X    } else {
  1068. X        if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
  1069. X            cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
  1070. X            if ((incnt = read(zipfd,inbuf,(unsigned int)tail_len)) != tail_len)
  1071. X                goto fail;      /* shut up, it's expedient. */
  1072. X
  1073. X            /* 'P' must be at least 22 bytes from end of zipfile */
  1074. X            for ( inptr = inbuf+tail_len-22  ;  inptr >= inbuf  ;  --inptr )
  1075. X                if ( (ascii_to_native(*inptr) == 'P')  &&
  1076. X                      !strncmp((char *)inptr, END_CENTRAL_SIG, 4) ) {
  1077. X                    incnt -= inptr - inbuf;
  1078. X                    return(0);  /* found it! */
  1079. X                }               /* ...otherwise search next block */
  1080. X            strncpy((char *)hold, (char *)inbuf, 3);    /* sig may span block
  1081. X                                                           boundary */
  1082. X
  1083. X        } else {
  1084. X            cur_zipfile_bufstart = ziplen - tail_len;
  1085. X        }
  1086. X
  1087. X        /*
  1088. X         * Loop through blocks of zipfile data, starting at the end and going
  1089. X         * toward the beginning.  Need only check last 65557 bytes of zipfile:
  1090. X         * comment may be up to 65535 bytes long, end-of-central-directory rec-
  1091. X         * ord is 18 bytes (shouldn't hardcode this number, but what the hell:
  1092. X         * already did so above (22=18+4)), and sig itself is 4 bytes.
  1093. X         */
  1094. X
  1095. X        /*          ==amt to search==   ==done==   ==rounding==     =blksiz= */
  1096. X        numblks = ( min(ziplen,65557) - tail_len + (INBUFSIZ-1) ) / INBUFSIZ;
  1097. X
  1098. X        for ( i = 1  ;  i <= numblks  ;  ++i ) {
  1099. X            cur_zipfile_bufstart -= INBUFSIZ;
  1100. X            lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
  1101. X            if ((incnt = read(zipfd,inbuf,INBUFSIZ)) != INBUFSIZ)
  1102. X                break;          /* fall through and fail */
  1103. X
  1104. X            for ( inptr = inbuf+INBUFSIZ-1  ;  inptr >= inbuf  ;  --inptr )
  1105. X                if ( (ascii_to_native(*inptr) == 'P')  &&
  1106. X                      !strncmp((char *)inptr, END_CENTRAL_SIG, 4) ) {
  1107. X                    incnt -= inptr - inbuf;
  1108. X                    return(0);  /* found it! */
  1109. X                }
  1110. X            strncpy((char *)hold, (char *)inbuf, 3);    /* sig may span block
  1111. X                                                           boundary */
  1112. X        }
  1113. X
  1114. X    } /* end if (ziplen > INBUFSIZ) */
  1115. X
  1116. X/*---------------------------------------------------------------------------
  1117. X    Searched through whole region where signature should be without finding
  1118. X    it.  Print informational message and die a horrible death.
  1119. X  ---------------------------------------------------------------------------*/
  1120. X
  1121. Xfail:
  1122. X
  1123. X    fprintf(stderr, "\nFile:  %s\n\n\
  1124. X     End-of-central-directory signature not found.  Either this file is not\n\
  1125. X     a zipfile, or it constitutes one disk of a multi-part archive.  In the\n\
  1126. X     latter case the central directory and zipfile comment will be found on\n\
  1127. X     the last disk(s) of this archive.\n", zipfn);
  1128. X    return(1);
  1129. X
  1130. X}       /* end function find_end_central_dir() */
  1131. X
  1132. X
  1133. X
  1134. X
  1135. X
  1136. X/***************************************/
  1137. X/*  Function process_end_central_dir() */
  1138. X/***************************************/
  1139. X
  1140. Xint process_end_central_dir()
  1141. X/* return PK-type error code */
  1142. X{
  1143. X#ifdef NOTINT16
  1144. X    end_central_byte_record byterec;
  1145. X#endif
  1146. X    int error=0;
  1147. X
  1148. X
  1149. X
  1150. X/*---------------------------------------------------------------------------
  1151. X    Read the end-of-central-directory record and do any necessary machine-
  1152. X    type conversions (byte ordering, structure padding compensation).
  1153. X  ---------------------------------------------------------------------------*/
  1154. X
  1155. X#ifndef NOTINT16
  1156. X    if (readbuf((char *) &ecrec, ECREC_SIZE+4) <= 0)
  1157. X        return (51);            /* 51:  unexpected EOF */
  1158. X
  1159. X#else  /* NOTINT16:  read data into character array, then copy to struct */
  1160. X    if (readbuf((char *) byterec, ECREC_SIZE+4) <= 0)
  1161. X        return (51);
  1162. X
  1163. X    ecrec.number_this_disk =
  1164. X        makeword(&byterec[NUMBER_THIS_DISK]);
  1165. X    ecrec.num_disk_with_start_central_dir =
  1166. X        makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
  1167. X    ecrec.num_entries_centrl_dir_ths_disk =
  1168. X        makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
  1169. X    ecrec.total_entries_central_dir =
  1170. X        makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
  1171. X    ecrec.size_central_directory =
  1172. X        makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
  1173. X    ecrec.offset_start_central_directory =
  1174. X        makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
  1175. X    ecrec.zipfile_comment_length =
  1176. X        makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
  1177. X#endif  /* NOTINT16 */
  1178. X
  1179. X/*---------------------------------------------------------------------------
  1180. X    Get the zipfile comment, if any, and print it out.  (Comment may be up
  1181. X    to 64KB long.  May the fleas of a thousand camels infest the armpits of
  1182. X    anyone who actually takes advantage of this fact.)  Then position the
  1183. X    file pointer to the beginning of the central directory and fill buffer.
  1184. X  ---------------------------------------------------------------------------*/
  1185. X
  1186. X    if (ecrec.zipfile_comment_length && !quietflg) {
  1187. X        if (!zflag)
  1188. X          printf("[%s] comment:  ", zipfn);
  1189. X        if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
  1190. X            fprintf(stderr, "\nwarning:  zipfile comment truncated\n");
  1191. X            error = 1;          /* 1:  warning error */
  1192. X        }
  1193. X        if (!zflag)
  1194. X          printf("\n\n");
  1195. X    }
  1196. X    LSEEK( ULONG_(ecrec.offset_start_central_directory) )
  1197. X
  1198. X    return (error);
  1199. X
  1200. X}       /* end function process_end_central_dir() */
  1201. X
  1202. X
  1203. X
  1204. X
  1205. X
  1206. X/**************************/
  1207. X/*  Function list_files() */
  1208. X/**************************/
  1209. X
  1210. Xint list_files()
  1211. X/* return PK-type error code */
  1212. X{
  1213. X    char **fnamev;
  1214. X    int do_this_file = FALSE, ratio, error, error_in_archive = 0;
  1215. X    int which_hdr = (vflag > 1);
  1216. X    UWORD j, yr, mo, dy, hh, mm, members = 0;
  1217. X    ULONG tot_csize = 0L, tot_ucsize = 0L;
  1218. X    static char *method[NUM_METHODS + 1] =
  1219. X    {"Stored", "Shrunk", "Reduce1", "Reduce2",
  1220. X     "Reduce3", "Reduce4", "Implode", "Unknown"};
  1221. X    static char *Headers[][2] =
  1222. X    {
  1223. X        {" Length    Date    Time    Name",
  1224. X         " ------    ----    ----    ----"},
  1225. X        {" Length  Method   Size  Ratio   Date    Time   CRC-32     Name",
  1226. X         " ------  ------   ----  -----   ----    ----   ------     ----"}};
  1227. X
  1228. X
  1229. X
  1230. X/*---------------------------------------------------------------------------
  1231. X    Unlike extract_or_test_files(), this routine confines itself to the cen-
  1232. X    tral directory.  Thus its structure is somewhat simpler, since we can do
  1233. X    just a single loop through the entire directory, listing files as we go.
  1234. X
  1235. X    So to start off, print the heading line and then begin main loop through
  1236. X    the central directory.  The results will look vaguely like the following:
  1237. X
  1238. X  Length  Method   Size  Ratio   Date    Time   CRC-32     Name ("^" ==> case
  1239. X  ------  ------   ----  -----   ----    ----   ------     ----   conversion)
  1240. X   44004  Implode  13041  71%  11-02-89  19:34  8b4207f7   Makefile.UNIX
  1241. X    3438  Shrunk    2209  36%  09-15-90  14:07  a2394fd8  ^dos-file.ext
  1242. X  ---------------------------------------------------------------------------*/
  1243. X
  1244. X    if (quietflg < 2)
  1245. X        if (Uflag)
  1246. X            printf("%s\n%s\n", Headers[which_hdr][0], Headers[which_hdr][1]);
  1247. X        else
  1248. X            printf("%s (\"^\" ==> case\n%s   conversion)\n", 
  1249. X              Headers[which_hdr][0], Headers[which_hdr][1]);
  1250. X
  1251. X    for (j = 0; j < ecrec.total_entries_central_dir; ++j) {
  1252. X
  1253. X        if (readbuf(sig, 4) <= 0)
  1254. X            return (51);        /* 51:  unexpected EOF */
  1255. X        if (strncmp(sig, CENTRAL_HDR_SIG, 4)) {  /* just to make sure */
  1256. X            fprintf(stderr, CentSigMsg, j);  /* sig not found */
  1257. X            fprintf(stderr, ReportMsg);   /* report to info-zip */
  1258. X            return (3);         /* 3:  error in zipfile */
  1259. X        }
  1260. X        if ((error = process_central_file_header()) != 0)  /* (sets lcflag) */
  1261. X            return (error);     /* only 51 (EOF) defined */
  1262. X
  1263. X        /*
  1264. X         * We could DISPLAY the filename instead of storing (and possibly trun-
  1265. X         * cating, in the case of a very long name) and printing it, but that
  1266. X         * has the disadvantage of not allowing case conversion--and it's nice
  1267. X         * to be able to see in the listing precisely how you have to type each
  1268. X         * filename in order for unzip to consider it a match.  Speaking of
  1269. X         * which, if member names were specified on the command line, check in
  1270. X         * with match() to see if the current file is one of them, and make a
  1271. X         * note of it if it is.
  1272. X         */
  1273. X
  1274. X        if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
  1275. X            error_in_archive = error;  /* (uses lcflag)---^   */
  1276. X            if (error > 1)      /* fatal:  can't continue */
  1277. X                return (error);
  1278. X        }
  1279. X        if ((error = do_string(crec.extra_field_length, SKIP)) != 0) {
  1280. X            error_in_archive = error;   /* might be just warning */
  1281. X            if (error > 1)      /* fatal */
  1282. X                return (error);
  1283. X        }
  1284. X        if (!process_all_files) {   /* check if specified on command line */
  1285. X            do_this_file = FALSE;
  1286. X            fnamev = fnv;       /* don't destroy permanent filename ptr */
  1287. X            for (--fnamev; *++fnamev;)
  1288. X                if (match(filename, *fnamev)) {
  1289. X                    do_this_file = TRUE;
  1290. X                    break;      /* found match, so stop looping */
  1291. X                }
  1292. X        }
  1293. X        /*
  1294. X         * If current file was specified on command line, or if no names were
  1295. X         * specified, do the listing for this file.  Otherwise, get rid of the
  1296. X         * file comment and go back for the next file.
  1297. X         */
  1298. X
  1299. X        if (process_all_files || do_this_file) {
  1300. X
  1301. X            yr = (((crec.last_mod_file_date >> 9) & 0x7f) + 80) % 100;
  1302. X            mo = (crec.last_mod_file_date >> 5) & 0x0f;
  1303. X            dy = crec.last_mod_file_date & 0x1f;
  1304. X            hh = (crec.last_mod_file_time >> 11) & 0x1f;
  1305. X            mm = (crec.last_mod_file_time >> 5) & 0x3f;
  1306. X
  1307. X            csize = (longint) ULONG_(crec.compressed_size);
  1308. X            ucsize = (longint) ULONG_(crec.uncompressed_size);
  1309. X            if (crec.general_purpose_bit_flag & 1)
  1310. X                csize -= 12;    /* if encrypted, don't count encrypt hdr */
  1311. X
  1312. X            ratio = (ucsize == 0) ? 0 :   /* .zip can have 0-length members */
  1313. X                ((ucsize > 2000000) ?     /* risk signed overflow if mult. */
  1314. X                (int) ((ucsize-csize) / (ucsize/1000L)) + 5 :   /* big */
  1315. X                (int) ((1000L*(ucsize-csize)) / ucsize) + 5);   /* small */
  1316. X
  1317. X            switch (which_hdr) {
  1318. X            case 0:             /* short form */
  1319. X                printf("%7ld  %02u-%02u-%02u  %02u:%02u  %c%s\n",
  1320. X                       ucsize, mo, dy, yr, hh, mm, (lcflag?'^':' '), filename);
  1321. X                break;
  1322. X            case 1:             /* verbose */
  1323. X                printf(
  1324. X                  "%7ld  %-7s%7ld %3d%%  %02u-%02u-%02u  %02u:%02u  %08lx  %c%s\n",
  1325. X                  ucsize, method[methnum], csize, ratio/10, mo, dy, yr, hh, mm,
  1326. X                  ULONG_(crec.crc32), (lcflag?'^':' '), filename);
  1327. X            }
  1328. X
  1329. X            error = do_string(crec.file_comment_length, (QCOND2 ? DISPLAY : SKIP));
  1330. X            if (error) {
  1331. X                error_in_archive = error;  /* might be just warning */
  1332. X                if (error > 1)  /* fatal */
  1333. X                    return (error);
  1334. X            }
  1335. X            tot_ucsize += (ULONG) ucsize;
  1336. X            tot_csize += (ULONG) csize;
  1337. X            ++members;
  1338. X
  1339. X        } else {        /* not listing this file */
  1340. X            if ((error = do_string(crec.file_comment_length, SKIP)) != 0) {
  1341. X              error_in_archive = error;   /* might be warning */
  1342. X              if (error > 1)      /* fatal */
  1343. X                  return (error);
  1344. X            }
  1345. X        }
  1346. X    }                   /* end for-loop (j: files in central directory) */
  1347. X
  1348. X/*---------------------------------------------------------------------------
  1349. X    Print footer line and totals (compressed size, uncompressed size, number
  1350. X    of members in zipfile).
  1351. X  ---------------------------------------------------------------------------*/
  1352. X
  1353. X    ratio = (tot_ucsize == 0) ? 
  1354. X        0 : ((tot_ucsize > 4000000) ?    /* risk unsigned overflow if mult. */
  1355. X        (int) ((tot_ucsize - tot_csize) / (tot_ucsize/1000L)) + 5 :
  1356. X        (int) ((tot_ucsize - tot_csize) * 1000L / tot_ucsize) + 5);
  1357. X
  1358. X    if (quietflg < 2) {
  1359. X        switch (which_hdr) {
  1360. X        case 0:         /* short */
  1361. X            printf("%s\n%7lu                    %-7u\n",
  1362. X                   " ------                    -------",
  1363. X                   tot_ucsize, members);
  1364. X            break;
  1365. X        case 1:         /* verbose */
  1366. X            printf(
  1367. X              "%s\n%7lu         %7lu %3d%%                              %-7u\n",
  1368. X              " ------          ------  ---                              -------",
  1369. X              tot_ucsize, tot_csize, ratio / 10, members);
  1370. X        }
  1371. X    }
  1372. X/*---------------------------------------------------------------------------
  1373. X    Double check that we're back at the end-of-central-directory record.
  1374. X  ---------------------------------------------------------------------------*/
  1375. X
  1376. X    readbuf(sig, 4);
  1377. X    if (strncmp(sig, END_CENTRAL_SIG, 4)) {     /* just to make sure again */
  1378. X        fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig */
  1379. X        fprintf(stderr, ReportMsg);  /* report to info-zip */
  1380. X        error_in_archive = 1;        /* 1:  warning error */
  1381. X    }
  1382. X    return (error_in_archive);
  1383. X
  1384. X}       /* end function list_files() */
  1385. X
  1386. X
  1387. X
  1388. X
  1389. X
  1390. X/*************************************/
  1391. X/*  Function extract_or_test_files() */
  1392. X/*************************************/
  1393. X
  1394. Xint extract_or_test_files()
  1395. X/* return PK-type error code */
  1396. X{
  1397. X    char **fnamev;
  1398. X    byte *cd_inptr;
  1399. X    int cd_incnt, error, error_in_archive = 0;
  1400. X    UWORD i, j, members_remaining;
  1401. X    longint cd_bufstart, bufstart, inbuf_offset;
  1402. X    struct min_info {
  1403. X        unsigned f_attr;
  1404. X        longint offset;
  1405. X        int lcflag;
  1406. X    } info[DIR_BLKSIZ];
  1407. X
  1408. X
  1409. X
  1410. X/*---------------------------------------------------------------------------
  1411. X    The basic idea of this function is as follows.  Since the central di-
  1412. X    rectory lies at the end of the zipfile and the member files lie at the
  1413. X    beginning or middle or wherever, it is not very desirable to simply
  1414. X    read a central directory entry, jump to the member and extract it, and
  1415. X    then jump back to the central directory.  In the case of a large zipfile
  1416. X    this would lead to a whole lot of disk-grinding, especially if each mem-
  1417. X    ber file is small.  Instead, we read from the central directory the per-
  1418. X    tinent information for a block of files, then go extract/test the whole
  1419. X    block.  Thus this routine contains two small(er) loops within a very
  1420. X    large outer loop:  the first of the small ones reads a block of files
  1421. X    from the central directory; the second extracts or tests each file; and
  1422. X    the outer one loops over blocks.  There's some file-pointer positioning
  1423. X    stuff in between, but that's about it.  Btw, it's because of this jump-
  1424. X    ing around that we can afford to be lenient if an error occurs in one of
  1425. X    the member files:  we should still be able to go find the other members,
  1426. X    since we know the offset of each from the beginning of the zipfile.
  1427. X
  1428. X    Begin main loop over blocks of member files.  We know the entire central
  1429. X    directory is on this disk:  we would not have any of this information un-
  1430. END_OF_FILE
  1431.   if test 38155 -ne `wc -c <'./v41/unzip.c.1'`; then
  1432.     echo shar: \"'./v41/unzip.c.1'\" unpacked with wrong size!
  1433.   fi
  1434.   # end of './v41/unzip.c.1'
  1435. fi
  1436. echo shar: End of archive 1 \(of 6\).
  1437. cp /dev/null ark1isdone
  1438. MISSING=""
  1439. for I in 1 2 3 4 5 6 ; do
  1440.     if test ! -f ark${I}isdone ; then
  1441.     MISSING="${MISSING} ${I}"
  1442.     fi
  1443. done
  1444. if test "${MISSING}" = "" ; then
  1445.     echo You have unpacked all 6 archives.
  1446.     rm -f ark[1-9]isdone
  1447. else
  1448.     echo You still must unpack the following archives:
  1449.     echo "        " ${MISSING}
  1450. fi
  1451. exit 0
  1452. exit 0 # Just in case...
  1453. -- 
  1454. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1455. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1456. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1457. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1458.