home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip512.zip / file_io.c < prev    next >
C/C++ Source or Header  |  1994-08-23  |  35KB  |  1,170 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   file_io.c
  4.  
  5.   This file contains routines for doing direct but relatively generic input/
  6.   output, file-related sorts of things, plus some miscellaneous stuff.  Most
  7.   of the stuff has to do with opening, closing, reading and/or writing files.
  8.  
  9.   Contains:  open_input_file()
  10.              open_outfile()           (non-VMS)
  11.              readbuf()
  12.              readbyte()
  13.              flush()                  (non-VMS)
  14.              disk_error()             (non-VMS)
  15.              handler()
  16.              dos_to_unix_time()       (non-VMS, non-OS/2)
  17.              check_for_newer()        (non-VMS, non-OS/2)
  18.              find_ecrec()
  19.              get_cdir_ent()
  20.              do_string()
  21.              makeword()
  22.              makelong()
  23.              memset()                 (ZMEM only)
  24.              memcpy()                 (ZMEM only)
  25.              zstrnicmp()
  26.              zstat()                  (REGULUS only)
  27.              LoadFarString()          (SMALL_MEM only)
  28.              LoadFarStringSmall()     (SMALL_MEM only)
  29.              LoadFarStringSmall2()    (SMALL_MEM only)
  30.  
  31.   ---------------------------------------------------------------------------*/
  32.  
  33.  
  34. #define FILE_IO_C
  35. #include "unzip.h"
  36. #include "crypt.h"
  37. #include "tables.h"   /* definition/initialization of ebcdic[] */
  38.  
  39. #ifdef USE_FWRITE
  40. #  define WriteError(buf,len,strm) \
  41.      ((extent)fwrite((char *)(buf),1,(extent)(len),strm) != (extent)(len))
  42. #else
  43. #  define WriteError(buf,len,strm) \
  44.      ((extent)write(fileno(strm),(char *)(buf),(extent)(len)) != (extent)(len))
  45. #endif
  46.  
  47. static int disk_error OF((void));
  48.  
  49.  
  50.  
  51. /*****************************/
  52. /* Strings used in file_io.c */
  53. /*****************************/
  54.  
  55. #ifdef UNIX
  56.    static char Far CannotDeleteOldFile[] = "\nerror:  cannot delete old %s\n";
  57. #endif
  58.  
  59. static char Far CantOpenZipfile[] = "error:  can't open zipfile [ %s ]\n";
  60. static char Far CannotCreateFile[] = "\nerror:  cannot create %s\n";
  61. static char Far ReadError[] = "error:  zipfile read error\n";
  62. static char Far DiskFull[] =
  63.   "\n%s:  write error (disk full?).  Continue? (y/n/^C) ";
  64. static char Far ZipfileCorrupt[] = "error:  zipfile probably corrupt (%s)\n";
  65. static char Far CentDirEndSigNotFound[] = "\
  66.   End-of-central-directory signature not found.  Either this file is not\n\
  67.   a zipfile, or it constitutes one disk of a multi-part archive.  In the\n\
  68.   latter case the central directory and zipfile comment will be found on\n\
  69.   the last disk(s) of this archive.\n";
  70. static char Far FilenameTooLongTrunc[] =
  71.   "warning:  filename too long--truncating.\n";
  72. static char Far ExtraFieldTooLong[] =
  73.   "warning:  extra field too long (%d).  Ignoring...\n";
  74.  
  75.  
  76.  
  77.  
  78.  
  79. /******************************/
  80. /* Function open_input_file() */
  81. /******************************/
  82.  
  83. int open_input_file()    /* return 1 if open failed */
  84. {
  85.     /*
  86.      *  open the zipfile for reading and in BINARY mode to prevent cr/lf
  87.      *  translation, which would corrupt the bitstreams
  88.      */
  89.  
  90. #if defined(UNIX) || defined(TOPS20) || defined(ATARI_ST)
  91.     zipfd = open(zipfn, O_RDONLY);
  92. #else /* !(UNIX || TOPS20) */
  93. #ifdef VMS
  94.     zipfd = open(zipfn, O_RDONLY, 0, "ctx=stm");
  95. #else /* !VMS */
  96. #ifdef MACOS
  97.     zipfd = open(zipfn, 0);
  98. #else /* !MACOS */
  99.     zipfd = open(zipfn, O_RDONLY | O_BINARY);
  100. #endif /* ?MACOS */
  101. #endif /* ?VMS */
  102. #endif /* ?(UNIX || TOPS20) */
  103.     if (zipfd < 0) {
  104.         FPRINTF(stderr, LoadFarString(CantOpenZipfile), zipfn);
  105.         return 1;
  106.     }
  107.     return 0;
  108.  
  109. } /* end function open_input_file() */
  110.  
  111.  
  112.  
  113.  
  114. #ifndef VMS                      /* for VMS use code in vms.c */
  115.  
  116. /***************************/
  117. /* Function open_outfile() */
  118. /***************************/
  119.  
  120. int open_outfile()         /* return 1 if fail */
  121. {
  122. #ifdef DOS_NT_OS2
  123.     if (stat(filename, &statbuf) == 0 && !(statbuf.st_mode & S_IWRITE))
  124.         chmod(filename, S_IREAD | S_IWRITE);
  125. #endif
  126. #ifdef UNIX
  127.     if (stat(filename, &statbuf) == 0 && unlink(filename) < 0) {
  128.         FPRINTF(stderr, LoadFarString(CannotDeleteOldFile), filename);
  129.         return 1;
  130.     }
  131. #endif
  132. #ifdef TOPS20
  133.     char *tfilnam;
  134.  
  135.     if ((tfilnam = (char *)malloc(2*strlen(filename)+1)) == (char *)NULL)
  136.         return 1;
  137.     strcpy(tfilnam, filename);
  138.     upper(tfilnam);
  139.     enquote(tfilnam);
  140.     if ((outfile = fopen(tfilnam, FOPW)) == (FILE *)NULL) {
  141.         FPRINTF(stderr, LoadFarString(CannotCreateFile), tfilnam);
  142.         free(tfilnam);
  143.         return 1;
  144.     }
  145.     free(tfilnam);
  146. #else
  147. #ifdef MTS
  148.     if (aflag)
  149.         outfile = fopen(filename, FOPWT);
  150.     else
  151.         outfile = fopen(filename, FOPW);
  152.     if (outfile == (FILE *)NULL) {
  153.         FPRINTF(stderr, LoadFarString(CannotCreateFile), filename);
  154.         return 1;
  155.     }
  156. #else
  157.     if ((outfile = fopen(filename, FOPW)) == (FILE *)NULL) {
  158.         FPRINTF(stderr, LoadFarString(CannotCreateFile), filename);
  159.         return 1;
  160.     }
  161. #endif
  162. #endif
  163.  
  164. #if 0      /* this SUCKS!  on Ultrix, it must be writing a byte at a time... */
  165.     setbuf(outfile, (char *)NULL);   /* make output unbuffered */
  166. #endif
  167.  
  168. #ifdef USE_FWRITE
  169. #ifdef DOS_NT_OS2
  170.     /* 16-bit MSC: buffer size must be strictly LESS than 32K (WSIZE):  bogus */
  171.     setbuf(outfile, (char *)NULL);   /* make output unbuffered */
  172. #else /* !DOS_NT_OS2 */
  173. #ifdef _IOFBF  /* make output fully buffered (works just about like write()) */
  174.     setvbuf(outfile, (char *)slide, _IOFBF, WSIZE);
  175. #else
  176.     setbuf(outfile, (char *)slide);
  177. #endif
  178. #endif /* ?DOS_NT_OS2 */
  179. #endif /* USE_FWRITE */
  180.     return 0;
  181.  
  182. } /* end function open_outfile() */
  183.  
  184. #endif /* !VMS */
  185.  
  186.  
  187.  
  188.  
  189.  
  190. /**********************/
  191. /* Function readbuf() */
  192. /**********************/
  193.  
  194. unsigned readbuf(buf, size)   /* return number of bytes read into buf */
  195.     char *buf;
  196.     register unsigned size;
  197. {
  198.     register unsigned count;
  199.     unsigned n;
  200.  
  201.     n = size;
  202.     while (size) {
  203.         if (incnt == 0) {
  204. #ifdef OLD_READBUF
  205.             if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) <= 0)
  206.                 return (n-size);
  207. #else
  208.             if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) == 0)
  209.                 return (n-size);
  210.             else if (incnt < 0) {
  211.                 FPRINTF(stderr, LoadFarString(ReadError));
  212.                 return 0;  /* discarding some data; better than lock-up */
  213.             }
  214. #endif
  215.             /* buffer ALWAYS starts on a block boundary:  */
  216.             cur_zipfile_bufstart += INBUFSIZ;
  217.             inptr = inbuf;
  218.         }
  219.         count = MIN(size, (unsigned)incnt);
  220.         memcpy(buf, inptr, count);
  221.         buf += count;
  222.         inptr += count;
  223.         incnt -= count;
  224.         size -= count;
  225.     }
  226.     return n;
  227.  
  228. } /* end function readbuf() */
  229.  
  230.  
  231.  
  232.  
  233.  
  234. /***********************/
  235. /* Function readbyte() */
  236. /***********************/
  237.  
  238. int readbyte()   /* refill inbuf and return a byte if available, else EOF */
  239. {
  240.     if (mem_mode || (incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) <= 0)
  241.         return EOF;
  242.     cur_zipfile_bufstart += INBUFSIZ;   /* always starts on a block boundary */
  243.     inptr = inbuf;
  244.  
  245. #ifdef CRYPT
  246.     if (pInfo->encrypted) {
  247.         uch *p;
  248.         int n;
  249.  
  250.         for (n = (long)incnt > csize + 1 ? (int)csize + 1 : incnt,
  251.              p = inptr;  n--;  p++)
  252.             zdecode(*p);
  253.     }
  254. #endif /* CRYPT */
  255.  
  256.     --incnt;
  257.     return *inptr++;
  258.  
  259. } /* end function readbyte() */
  260.  
  261.  
  262.  
  263.  
  264.  
  265. #ifndef VMS                 /* for VMS use code in vms.c */
  266.  
  267. /********************/
  268. /* Function flush() */
  269. /********************/
  270.  
  271. int flush(rawbuf, size, unshrink)   /* cflag => always 0; 50 if write error */
  272.     uch *rawbuf;
  273.     ulg size;
  274.     int unshrink;
  275. {
  276. #ifdef ASM_CRC
  277.     ulg CalcCRC(ulg *crc_table, ulg crcval, uch *rawbuf, ulg rawbufsize);
  278. #else
  279.     register ulg crcval = crc32val;
  280.     register ulg n = size;
  281. #endif
  282.     register uch *p, *q;
  283.     uch *transbuf;
  284.     ulg transbufsiz;
  285.     static int didCRlast = FALSE;
  286.  
  287.  
  288. /*---------------------------------------------------------------------------
  289.     Compute the CRC first; if testing or if disk is full, that's it.
  290.   ---------------------------------------------------------------------------*/
  291.  
  292. #ifdef ASM_CRC
  293.     crc32val = CalcCRC(crc_32_tab, crc32val, rawbuf, size);
  294. #else
  295.     p = rawbuf;
  296.     while (n--)
  297.         crcval = crc_32_tab[((uch)crcval ^ (*p++)) & 0xff] ^ (crcval >> 8);
  298.     crc32val = crcval;
  299. #endif /* ?ASM_CRC */
  300.  
  301.     if (tflag || size == 0L)   /* testing or nothing to write:  all done */
  302.         return 0;
  303.  
  304.     if (disk_full)
  305.         return 50;            /* disk already full:  ignore rest of file */
  306.  
  307. /*---------------------------------------------------------------------------
  308.     Write the bytes rawbuf[0..size-1] to the output device, first converting
  309.     end-of-lines and ASCII/EBCDIC as needed.  If SMALL_MEM or MED_MEM are NOT
  310.     defined, outbuf is assumed to be at least as large as rawbuf and is not
  311.     necessarily checked for overflow.
  312.   ---------------------------------------------------------------------------*/
  313.  
  314.     if (!pInfo->textmode) {
  315.         /* GRR:  note that for standard MS-DOS compilers, size argument to
  316.          * fwrite() can never be more than 65534, so WriteError macro will
  317.          * have to be rewritten if size can ever be that large.  For now,
  318.          * never more than 32K.  Also note that write() returns an int, which
  319.          * doesn't necessarily limit size to 32767 bytes if write() is used
  320.          * on 16-bit systems but does make it more of a pain; however, because
  321.          * at least MSC 5.1 has a lousy implementation of fwrite() (as does
  322.          * DEC Ultrix cc), write() is used anyway.
  323.          */
  324.         if (WriteError(rawbuf, size, outfile))  /* write raw binary data */
  325.             return cflag? 0 : disk_error();
  326.     } else {
  327.         if (unshrink) {
  328.             /* rawbuf = outbuf */
  329.             transbuf = outbuf2;
  330.             transbufsiz = TRANSBUFSIZ;
  331.         } else {
  332.             /* rawbuf = slide */
  333.             transbuf = outbuf;
  334.             transbufsiz = OUTBUFSIZ;
  335.             Trace((stderr, "\ntransbufsiz = OUTBUFSIZ = %u\n", OUTBUFSIZ));
  336.         }
  337.         if (newfile) {
  338.             didCRlast = FALSE;   /* no previous buffers written */
  339.             newfile = FALSE;
  340.         }
  341.         p = rawbuf;
  342.         if (*p == LF && didCRlast)
  343.             ++p;
  344.  
  345.     /*-----------------------------------------------------------------------
  346.         Algorithm:  CR/LF => native; lone CR => native; lone LF => native.
  347.         This routine is only for non-raw-VMS, non-raw-VM/CMS files (i.e.,
  348.         stream-oriented files, not record-oriented).
  349.       -----------------------------------------------------------------------*/
  350.  
  351.         for (didCRlast = FALSE, q = transbuf;  p < rawbuf+size;  ++p) {
  352.             if (*p == CR) {              /* lone CR or CR/LF: EOL either way */
  353.                 PutNativeEOL
  354.                 if (p == rawbuf+size-1)  /* last char in buffer */
  355.                     didCRlast = TRUE;
  356.                 else if (p[1] == LF)     /* get rid of accompanying LF */
  357.                     ++p;
  358.             } else if (*p == LF)         /* lone LF */
  359.                 PutNativeEOL
  360.             else
  361. #ifndef DOS_NT_OS2
  362.             if (*p != CTRLZ)             /* lose all ^Z's */
  363. #endif
  364.                 *q++ = native(*p);
  365.  
  366. #if (defined(SMALL_MEM) || defined(MED_MEM))
  367. # if (lenEOL == 1)   /* don't check unshrink:  both buffers small but equal */
  368.             if (!unshrink)
  369. # endif
  370.                 /* check for danger of buffer overflow and flush */
  371.                 if (q > transbuf+transbufsiz-lenEOL) {
  372.                     Trace((stderr,
  373.                       "p - rawbuf = %u   q-transbuf = %u   size = %lu\n",
  374.                       (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
  375.                     if (WriteError(transbuf, (unsigned)(q-transbuf), outfile))
  376.                         return cflag? 0 : disk_error();
  377.                     q = transbuf;
  378.                     continue;
  379.                 }
  380. #endif /* SMALL_MEM || MED_MEM */
  381.         }
  382.  
  383.     /*-----------------------------------------------------------------------
  384.         Done translating:  write whatever we've got to file.
  385.       -----------------------------------------------------------------------*/
  386.  
  387.         Trace((stderr, "p - rawbuf = %u   q-transbuf = %u   size = %lu\n",
  388.           (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
  389.         if (q > transbuf &&
  390.             WriteError(transbuf, (unsigned)(q-transbuf), outfile))
  391.             return cflag? 0 : disk_error();
  392.     }
  393.  
  394.     return 0;
  395.  
  396. } /* end function flush() */
  397.  
  398.  
  399.  
  400.  
  401.  
  402. /*************************/
  403. /* Function disk_error() */
  404. /*************************/
  405.  
  406. static int disk_error()
  407. {
  408.     FPRINTF(stderr, LoadFarString(DiskFull), filename);
  409.     FFLUSH(stderr);
  410.  
  411. #ifndef MSWIN
  412.     fgets(answerbuf, 9, stdin);
  413.     if (*answerbuf == 'y')   /* stop writing to this file */
  414.         disk_full = 1;       /*  (outfile bad?), but new OK */
  415.     else
  416. #endif
  417.         disk_full = 2;       /* no:  exit program */
  418.  
  419.     return 50;               /* 50:  disk full */
  420.  
  421. } /* end function disk_error() */
  422.  
  423. #endif /* !VMS */
  424.  
  425.  
  426.  
  427.  
  428.  
  429. /**********************/
  430. /* Function handler() */
  431. /**********************/
  432.  
  433. void handler(signal)   /* upon interrupt, turn on echo and exit cleanly */
  434.     int signal;
  435. {
  436. #if defined(SIGBUS) || defined(SIGSEGV)
  437. #  ifdef SMALL_MEM
  438.     static char *corrupt;
  439.     corrupt = LoadFarString(ZipfileCorrupt);
  440. #  else
  441.     static char *corrupt = LoadFarString(ZipfileCorrupt);
  442. #  endif
  443. #endif
  444.  
  445. #if !defined(DOS_NT_OS2) && !defined(MACOS)
  446.     echon();
  447.     PUTC('\n', stderr);
  448. #endif /* !DOS_NT_OS2 && !MACOS */
  449. #ifdef SIGBUS
  450.     if (signal == SIGBUS) {
  451.         FPRINTF(stderr, corrupt, "bus error");
  452.         exit(3);
  453.     }
  454. #endif /* SIGBUS */
  455. #ifdef SIGSEGV
  456.     if (signal == SIGSEGV) {
  457.         FPRINTF(stderr, corrupt, "segmentation violation");
  458.         exit(3);
  459.     }
  460. #endif /* SIGSEGV */
  461.     exit(0);
  462. }
  463.  
  464.  
  465.  
  466.  
  467.  
  468. #ifdef DEBUG_TIME
  469. #  define TTrace(x)  FPRINTF x
  470. #else
  471. #  define TTrace(x)
  472. #endif
  473.  
  474. #if !defined(VMS) && !defined(OS2)
  475.  
  476. /*******************************/
  477. /* Function dos_to_unix_time() */   /* only used for freshening/updating */
  478. /*******************************/
  479.  
  480. time_t dos_to_unix_time(ddate, dtime)
  481.     unsigned ddate, dtime;
  482. {
  483.     int yr, mo, dy, hh, mm, ss;
  484. #ifdef TOPS20
  485. #   define YRBASE  1900
  486.     struct tmx *tmx;
  487.     char temp[20];
  488.     time_t retval;
  489. #else /* !TOPS20 */
  490. #   define YRBASE  1970
  491.     static short yday[]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  492.     int leap;
  493.     long m_time, days=0;
  494. #if (!defined(MACOS) && !defined(MSC))
  495. #if (defined(BSD) || defined(MTS) || defined(__GO32__))
  496. #ifndef BSD4_4
  497.     static struct timeb tbp;
  498. #endif /* !BSD4_4 */
  499. #else /* !(BSD || MTS || __GO32__) */
  500. #ifdef ATARI_ST
  501.     extern long _timezone;
  502. #   define timezone _timezone;  /* a whoops in our library... */
  503. #else /* !ATARI_ST */
  504.     extern long timezone;       /* declared in <time.h> for MSC (& Borland?) */
  505. #endif /* ?ATARI_ST */
  506. #endif /* ?(BSD || MTS || __GO32__) */
  507. #endif /* !MACOS && !MSC */
  508. #endif /* ?TOPS20 */
  509.  
  510.  
  511.     /* dissect date */
  512.     yr = ((ddate >> 9) & 0x7f) + (1980 - YRBASE);
  513.     mo = ((ddate >> 5) & 0x0f) - 1;
  514.     dy = (ddate & 0x1f) - 1;
  515.  
  516.     /* dissect time */
  517.     hh = (dtime >> 11) & 0x1f;
  518.     mm = (dtime >> 5) & 0x3f;
  519.     ss = (dtime & 0x1f) * 2;
  520.  
  521. #ifdef TOPS20
  522.     tmx = (struct tmx *)malloc(sizeof(struct tmx));
  523.     sprintf (temp, "%02d/%02d/%02d %02d:%02d:%02d", mo+1, dy+1, yr, hh, mm, ss);
  524.     time_parse(temp, tmx, (char *)0);
  525.     retval = time_make(tmx);
  526.     free(tmx);
  527.     return retval;
  528.  
  529. #else /* !TOPS20 */
  530.     /* leap = # of leap years from BASE up to but not including current year */
  531.     leap = ((yr + YRBASE - 1) / 4);   /* leap year base factor */
  532.  
  533.     /* calculate days from BASE to this year and add expired days this year */
  534.     days = (yr * 365) + (leap - 492) + yday[mo];
  535.  
  536.     /* if year is a leap year and month is after February, add another day */
  537.     if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100))
  538.         ++days;                 /* OK through 2199 */
  539.  
  540.     /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */
  541.     m_time = ((long)(days + dy) * 86400L) + ((long)hh * 3600) + (mm * 60) + ss;
  542.       /* - 1;   MS-DOS times always rounded up to nearest even second */
  543.     TTrace((stderr, "dos_to_unix_time:\n"));
  544.     TTrace((stderr, "  m_time before timezone = %ld\n", m_time));
  545.  
  546. #ifndef MACOS
  547. #if (defined(BSD) || defined(MTS) || defined(__GO32__))
  548. #ifndef BSD4_4
  549.     ftime(&tbp);
  550.     m_time += tbp.timezone * 60L;
  551. #endif
  552. #else /* !(BSD || MTS || __GO32__) */
  553. #ifdef WIN32
  554.     {
  555.         TIME_ZONE_INFORMATION tzinfo;
  556.         DWORD res;
  557.  
  558.         /* account for timezone differences */
  559.         res = GetTimeZoneInformation(&tzinfo);
  560.         if (res == TIME_ZONE_ID_STANDARD)
  561.             m_time += 60*(tzinfo.Bias + tzinfo.StandardBias);
  562.         else if (res == TIME_ZONE_ID_DAYLIGHT)
  563.             m_time += 60*(tzinfo.Bias + tzinfo.DaylightBias);
  564.         /* GRR:  are other return-values possible? */
  565.     }
  566. #else /* !WIN32 */
  567.     tzset();                    /* set `timezone' variable */
  568.     m_time += timezone;
  569. #endif /* ?WIN32 */
  570. #endif /* ?(BSD || MTS || __GO32__) */
  571. #endif /* !MACOS */
  572.     TTrace((stderr, "  m_time after timezone =  %ld\n", m_time));
  573.  
  574. #ifdef BSD4_4               /* see comments in unix.c */
  575.     m_time -= localtime((time_t *) &m_time)->tm_gmtoff;
  576. #else /* !BSD4_4 */
  577. #ifndef WIN32
  578.     if (localtime((time_t *)&m_time)->tm_isdst)
  579.         m_time -= 60L * 60L;    /* adjust for daylight savings time */
  580. #endif /* !WIN32 */
  581. #endif /* ?BSD4_4 */
  582.     TTrace((stderr, "  m_time after DST =       %ld\n", m_time));
  583.  
  584.     return m_time;
  585. #endif /* ?TOPS20 */
  586.  
  587. } /* end function dos_to_unix_time() */
  588.  
  589.  
  590.  
  591.  
  592.  
  593. /******************************/
  594. /* Function check_for_newer() */   /* only used for freshening/updating */
  595. /******************************/
  596.  
  597. int check_for_newer(filename)   /* return 1 if existing file newer or equal; */
  598.     char *filename;             /*  0 if older; -1 if doesn't exist yet */
  599. {
  600.     time_t existing, archive;
  601.  
  602.     if (stat(filename, &statbuf))
  603.         return DOES_NOT_EXIST;
  604.  
  605.     /* round up existing filetime to nearest 2 seconds for comparison */
  606.     existing = (statbuf.st_mtime & 1) ? statbuf.st_mtime+1 : statbuf.st_mtime;
  607.     archive  = dos_to_unix_time(lrec.last_mod_file_date,
  608.                                 lrec.last_mod_file_time);
  609.  
  610.     TTrace((stderr, "check_for_newer:  existing %ld, archive %ld, e-a %ld\n",
  611.       existing, archive, existing-archive));
  612.  
  613.     return (existing >= archive);
  614.  
  615. } /* end function check_for_newer() */
  616.  
  617. #endif /* !VMS && !OS2 */
  618.  
  619.  
  620.  
  621.  
  622.  
  623. /*************************/
  624. /* Function find_ecrec() */
  625. /*************************/
  626.  
  627. int find_ecrec(searchlen)   /* return PK-class error */
  628.     long searchlen;
  629. {
  630.     int i, numblks, found=FALSE;
  631.     LONGINT tail_len;
  632.     ec_byte_rec byterec;
  633.  
  634.  
  635. /*---------------------------------------------------------------------------
  636.     Treat case of short zipfile separately.
  637.   ---------------------------------------------------------------------------*/
  638.  
  639.     if (ziplen <= INBUFSIZ) {
  640.         lseek(zipfd, 0L, SEEK_SET);
  641.         if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)ziplen)) ==
  642.              (int)ziplen)
  643.  
  644.             /* 'P' must be at least 22 bytes from end of zipfile */
  645.             for (inptr = inbuf+(int)ziplen-22;  inptr >= inbuf;  --inptr)
  646.                 if ((native(*inptr) == 'P')  &&
  647.                      !strncmp((char *)inptr, end_central_sig, 4)) {
  648.                     incnt -= inptr - inbuf;
  649.                     found = TRUE;
  650.                     break;
  651.                 }
  652.  
  653. /*---------------------------------------------------------------------------
  654.     Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
  655.     block at end of zipfile (if not TOO short).
  656.   ---------------------------------------------------------------------------*/
  657.  
  658.     } else {
  659.         if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
  660.             cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
  661.             if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)tail_len)) !=
  662.                  (int)tail_len)
  663.                 goto fail;      /* shut up; it's expedient */
  664.  
  665.             /* 'P' must be at least 22 bytes from end of zipfile */
  666.             for (inptr = inbuf+(int)tail_len-22;  inptr >= inbuf;  --inptr)
  667.                 if ((native(*inptr) == 'P')  &&
  668.                      !strncmp((char *)inptr, end_central_sig, 4)) {
  669.                     incnt -= inptr - inbuf;
  670.                     found = TRUE;
  671.                     break;
  672.                 }
  673.             /* sig may span block boundary: */
  674.             strncpy((char *)hold, (char *)inbuf, 3);
  675.         } else
  676.             cur_zipfile_bufstart = ziplen - tail_len;
  677.  
  678.     /*-----------------------------------------------------------------------
  679.         Loop through blocks of zipfile data, starting at the end and going
  680.         toward the beginning.  In general, need not check whole zipfile for
  681.         signature, but may want to do so if testing.
  682.       -----------------------------------------------------------------------*/
  683.  
  684.         numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
  685.         /*               ==amount=   ==done==   ==rounding==    =blksiz=  */
  686.  
  687.         for (i = 1;  !found && (i <= numblks);  ++i) {
  688.             cur_zipfile_bufstart -= INBUFSIZ;
  689.             lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
  690.             if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) != INBUFSIZ)
  691.                 break;          /* fall through and fail */
  692.  
  693.             for (inptr = inbuf+INBUFSIZ-1;  inptr >= inbuf;  --inptr)
  694.                 if ((native(*inptr) == 'P')  &&
  695.                      !strncmp((char *)inptr, end_central_sig, 4)) {
  696.                     incnt -= inptr - inbuf;
  697.                     found = TRUE;
  698.                     break;
  699.                 }
  700.             /* sig may span block boundary: */
  701.             strncpy((char *)hold, (char *)inbuf, 3);
  702.         }
  703.     } /* end if (ziplen > INBUFSIZ) */
  704.  
  705. /*---------------------------------------------------------------------------
  706.     Searched through whole region where signature should be without finding
  707.     it.  Print informational message and die a horrible death.
  708.   ---------------------------------------------------------------------------*/
  709.  
  710. fail:
  711.     if (!found) {
  712. #ifdef MSWIN
  713.         MessageBeep(1);
  714. #endif
  715.         if (qflag || (zipinfo_mode && !hflag))
  716.             FPRINTF(stderr, "[%s]\n", zipfn);
  717.         FPRINTF(stderr, LoadFarString(CentDirEndSigNotFound));
  718.         return PK_ERR;   /* failed */
  719.     }
  720.  
  721. /*---------------------------------------------------------------------------
  722.     Found the signature, so get the end-central data before returning.  Do
  723.     any necessary machine-type conversions (byte ordering, structure padding
  724.     compensation) by reading data into character array and copying to struct.
  725.   ---------------------------------------------------------------------------*/
  726.  
  727.     real_ecrec_offset = cur_zipfile_bufstart + (inptr-inbuf);
  728. #ifdef TEST
  729.     printf("\n  found end-of-central-dir signature at offset %ld (%.8lXh)\n",
  730.       real_ecrec_offset, real_ecrec_offset);
  731.     printf("    from beginning of file; offset %d (%.4Xh) within block\n",
  732.       inptr-inbuf, inptr-inbuf);
  733. #endif
  734.  
  735.     if (readbuf((char *)byterec, ECREC_SIZE+4) == 0)
  736.         return PK_EOF;
  737.  
  738.     ecrec.number_this_disk =
  739.         makeword(&byterec[NUMBER_THIS_DISK]);
  740.     ecrec.num_disk_with_start_central_dir =
  741.         makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
  742.     ecrec.num_entries_centrl_dir_ths_disk =
  743.         makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
  744.     ecrec.total_entries_central_dir =
  745.         makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
  746.     ecrec.size_central_directory =
  747.         makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
  748.     ecrec.offset_start_central_directory =
  749.         makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
  750.     ecrec.zipfile_comment_length =
  751.         makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
  752.  
  753.     expect_ecrec_offset = ecrec.offset_start_central_directory +
  754.                           ecrec.size_central_directory;
  755.     return PK_COOL;
  756.  
  757. } /* end function find_ecrec() */
  758.  
  759.  
  760.  
  761.  
  762.  
  763. /***************************/
  764. /* Function get_cdir_ent() */
  765. /***************************/
  766.  
  767. int get_cdir_ent()   /* return PK-type error code */
  768. {
  769.     cdir_byte_hdr byterec;
  770.  
  771.  
  772. /*---------------------------------------------------------------------------
  773.     Read the next central directory entry and do any necessary machine-type
  774.     conversions (byte ordering, structure padding compensation--do so by
  775.     copying the data from the array into which it was read (byterec) to the
  776.     usable struct (crec)).
  777.   ---------------------------------------------------------------------------*/
  778.  
  779.     if (readbuf((char *)byterec, CREC_SIZE) == 0)
  780.         return PK_EOF;
  781.  
  782.     crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
  783.     crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
  784.     crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
  785.     crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
  786.  
  787.     crec.general_purpose_bit_flag =
  788.         makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
  789.     crec.compression_method =
  790.         makeword(&byterec[C_COMPRESSION_METHOD]);
  791.     crec.last_mod_file_time =
  792.         makeword(&byterec[C_LAST_MOD_FILE_TIME]);
  793.     crec.last_mod_file_date =
  794.         makeword(&byterec[C_LAST_MOD_FILE_DATE]);
  795.     crec.crc32 =
  796.         makelong(&byterec[C_CRC32]);
  797.     crec.csize =
  798.         makelong(&byterec[C_COMPRESSED_SIZE]);
  799.     crec.ucsize =
  800.         makelong(&byterec[C_UNCOMPRESSED_SIZE]);
  801.     crec.filename_length =
  802.         makeword(&byterec[C_FILENAME_LENGTH]);
  803.     crec.extra_field_length =
  804.         makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
  805.     crec.file_comment_length =
  806.         makeword(&byterec[C_FILE_COMMENT_LENGTH]);
  807.     crec.disk_number_start =
  808.         makeword(&byterec[C_DISK_NUMBER_START]);
  809.     crec.internal_file_attributes =
  810.         makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
  811.     crec.external_file_attributes =
  812.         makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]);  /* LONG, not word! */
  813.     crec.relative_offset_local_header =
  814.         makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
  815.  
  816.     return PK_COOL;
  817.  
  818. } /* end function get_cdir_ent() */
  819.  
  820.  
  821.  
  822.  
  823.  
  824. /************************/
  825. /* Function do_string() */
  826. /************************/
  827.  
  828. int do_string(len, option)      /* return PK-type error code */
  829.     unsigned int len;           /* without prototype, ush converted to this */
  830.     int option;
  831. {
  832.     long comment_bytes_left, block_length;
  833.     int error=PK_OK;
  834.     ush extra_len;
  835.  
  836.  
  837. /*---------------------------------------------------------------------------
  838.     This function processes arbitrary-length (well, usually) strings.  Three
  839.     options are allowed:  SKIP, wherein the string is skipped (pretty logical,
  840.     eh?); DISPLAY, wherein the string is printed to standard output after un-
  841.     dergoing any necessary or unnecessary character conversions; and FILENAME,
  842.     wherein the string is put into the filename[] array after undergoing ap-
  843.     propriate conversions (including case-conversion, if that is indicated:
  844.     see the global variable pInfo->lcflag).  The latter option should be OK,
  845.     since filename is now dimensioned at 1025, but we check anyway.
  846.  
  847.     The string, by the way, is assumed to start at the current file-pointer
  848.     position; its length is given by len.  So start off by checking length
  849.     of string:  if zero, we're already done.
  850.   ---------------------------------------------------------------------------*/
  851.  
  852.     if (!len)
  853.         return PK_COOL;
  854.  
  855.     switch (option) {
  856.  
  857.     /*
  858.      * First case:  print string on standard output.  First set loop vari-
  859.      * ables, then loop through the comment in chunks of OUTBUFSIZ bytes,
  860.      * converting formats and printing as we go.  The second half of the
  861.      * loop conditional was added because the file might be truncated, in
  862.      * which case comment_bytes_left will remain at some non-zero value for
  863.      * all time.  outbuf and slide are used as scratch buffers because they
  864.      * are available (we should be either before or in between any file pro-
  865.      * cessing).
  866.      */
  867.  
  868.     case DISPLAY:
  869.         comment_bytes_left = len;
  870.         block_length = OUTBUFSIZ;    /* for the while statement, first time */
  871.         while (comment_bytes_left > 0 && block_length > 0) {
  872. #ifndef MSWIN
  873.             register uch *p = outbuf;
  874.             register uch *q = outbuf;
  875. #endif
  876.             if ((block_length = readbuf((char *)outbuf,
  877.                    (unsigned) MIN((long)OUTBUFSIZ, comment_bytes_left))) == 0)
  878.                 return PK_EOF;
  879.             comment_bytes_left -= block_length;
  880.  
  881.             /* this is why we allocated an extra byte for outbuf: */
  882.             outbuf[block_length] = '\0';   /* terminate w/zero:  ASCIIZ */
  883.  
  884.             /* remove all ASCII carriage returns comment before printing
  885.              * (since used before A_TO_N(), check for CR instead of '\r')
  886.              */
  887.             while (*p) {
  888.                 while (*p == CR)
  889.                     ++p;
  890.                 *q++ = *p++;
  891.             }
  892.             /* could check whether (p - outbuf) == block_length here */
  893.             *q = '\0';
  894.  
  895.             A_TO_N(outbuf);   /* translate string to native */
  896.  
  897. #ifdef MSWIN
  898.             /* ran out of local mem -- had to cheat */
  899.             WriteStringToMsgWin(outbuf, bRealTimeMsgUpdate);
  900. #else /* !MSWIN */
  901. #ifdef NATIVE
  902.             PRINTF("%s", outbuf);   /* GRR:  can ANSI be used with EBCDIC? */
  903. #else /* ASCII */
  904.             p = outbuf - 1;
  905.             q = slide;
  906.             while (*++p) {
  907.                 if (*p == 0x1B) {   /* ASCII escape char */
  908.                     *q++ = '^';
  909.                     *q++ = '[';
  910.                 } else
  911.                     *q++ = *p;
  912.                 if ((unsigned)(q-slide) > WSIZE-3) {   /* time to flush */
  913.                     *q = '\0';
  914.                     PRINTF("%s", slide);
  915.                     q = slide;
  916.                 }
  917.             }
  918.             *q = '\0';
  919.             PRINTF("%s", slide);
  920. #endif /* ?NATIVE */
  921. #endif /* ?MSWIN */
  922.         }
  923.         PRINTF("\n");   /* assume no newline at end */
  924.         break;
  925.  
  926.     /*
  927.      * Second case:  read string into filename[] array.  The filename should
  928.      * never ever be longer than FILNAMSIZ-1 (1024), but for now we'll check,
  929.      * just to be sure.
  930.      */
  931.  
  932.     case FILENAME:
  933.         extra_len = 0;
  934.         if (len >= FILNAMSIZ) {
  935.             FPRINTF(stderr, LoadFarString(FilenameTooLongTrunc));
  936.             error = PK_WARN;
  937.             extra_len = len - FILNAMSIZ + 1;
  938.             len = FILNAMSIZ - 1;
  939.         }
  940.         if (readbuf(filename, len) == 0)
  941.             return PK_EOF;
  942.         filename[len] = '\0';   /* terminate w/zero:  ASCIIZ */
  943.  
  944.         A_TO_N(filename);       /* translate string to native */
  945.  
  946.         if (pInfo->lcflag)      /* replace with lowercase filename */
  947.             TOLOWER(filename, filename);
  948.  
  949.         if (pInfo->vollabel && len > 8 && filename[8] == '.') {
  950.             char *p = filename+8;
  951.             while (*p++)
  952.                 p[-1] = *p;  /* disk label, and 8th char is dot:  remove dot */
  953.         }
  954.  
  955.         if (!extra_len)         /* we're done here */
  956.             break;
  957.  
  958.         /*
  959.          * We truncated the filename, so print what's left and then fall
  960.          * through to the SKIP routine.
  961.          */
  962.         FPRINTF(stderr, "[ %s ]\n", filename);
  963.         len = extra_len;
  964.         /*  FALL THROUGH...  */
  965.  
  966.     /*
  967.      * Third case:  skip string, adjusting readbuf's internal variables
  968.      * as necessary (and possibly skipping to and reading a new block of
  969.      * data).
  970.      */
  971.  
  972.     case SKIP:
  973.         LSEEK(cur_zipfile_bufstart + (inptr-inbuf) + len)
  974.         break;
  975.  
  976.     /*
  977.      * Fourth case:  assume we're at the start of an "extra field"; malloc
  978.      * storage for it and read data into the allocated space.
  979.      */
  980.  
  981.     case EXTRA_FIELD:
  982.         if (extra_field != (uch *)NULL)
  983.             free(extra_field);
  984.         if ((extra_field = (uch *)malloc(len)) == (uch *)NULL) {
  985.             FPRINTF(stderr, LoadFarString(ExtraFieldTooLong), len);
  986.             LSEEK(cur_zipfile_bufstart + (inptr-inbuf) + len)
  987.         } else
  988.             if (readbuf((char *)extra_field, len) == 0)
  989.                 return PK_EOF;
  990.         break;
  991.  
  992.     } /* end switch (option) */
  993.     return error;
  994.  
  995. } /* end function do_string() */
  996.  
  997.  
  998.  
  999.  
  1000.  
  1001. /***********************/
  1002. /* Function makeword() */
  1003. /***********************/
  1004.  
  1005. ush makeword(b)
  1006.     uch *b;
  1007. {
  1008.     /*
  1009.      * Convert Intel style 'short' integer to non-Intel non-16-bit
  1010.      * host format.  This routine also takes care of byte-ordering.
  1011.      */
  1012.     return (ush)((b[1] << 8) | b[0]);
  1013. }
  1014.  
  1015.  
  1016.  
  1017.  
  1018.  
  1019. /***********************/
  1020. /* Function makelong() */
  1021. /***********************/
  1022.  
  1023. ulg makelong(sig)
  1024.     uch *sig;
  1025. {
  1026.     /*
  1027.      * Convert intel style 'long' variable to non-Intel non-16-bit
  1028.      * host format.  This routine also takes care of byte-ordering.
  1029.      */
  1030.     return (((ulg)sig[3]) << 24)
  1031.         + (((ulg)sig[2]) << 16)
  1032.         + (((ulg)sig[1]) << 8)
  1033.         + ((ulg)sig[0]);
  1034. }
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040. #ifdef ZMEM   /* memset, memcpy for systems without them */
  1041.  
  1042. /*********************/
  1043. /* Function memset() */
  1044. /*********************/
  1045.  
  1046. char *memset(buf, init, len)
  1047.     register char *buf, init;   /* buffer loc and initializer */
  1048.     register unsigned int len;  /* length of the buffer */
  1049. {
  1050.     char *start;
  1051.  
  1052.     start = buf;
  1053.     while (len--)
  1054.         *(buf++) = init;
  1055.     return start;
  1056. }
  1057.  
  1058.  
  1059.  
  1060.  
  1061.  
  1062. /*********************/
  1063. /* Function memcpy() */
  1064. /*********************/
  1065.  
  1066. char *memcpy(dst, src, len)
  1067.     register char *dst, *src;
  1068.     register unsigned int len;
  1069. {
  1070.     char *start;
  1071.  
  1072.     start = dst;
  1073.     while (len-- > 0)
  1074.         *dst++ = *src++;
  1075.     return start;
  1076. }
  1077.  
  1078. #endif /* ZMEM */
  1079.  
  1080.  
  1081.  
  1082.  
  1083.  
  1084. /************************/
  1085. /* Function zstrnicmp() */
  1086. /************************/
  1087.  
  1088. int zstrnicmp(s1, s2, n)
  1089.     register char *s1, *s2;
  1090.     register int n;
  1091. {
  1092.     for (; n > 0;  --n, ++s1, ++s2) {
  1093.  
  1094.         if (ToLower(*s1) != ToLower(*s2))
  1095.             /* test includes early termination of one string */
  1096.             return (ToLower(*s1) < ToLower(*s2))? -1 : 1;
  1097.  
  1098.         if (*s1 == '\0')   /* both strings terminate early */
  1099.             return 0;
  1100.     }
  1101.     return 0;
  1102. }
  1103.  
  1104.  
  1105.  
  1106.  
  1107.  
  1108. #ifdef REGULUS  /* returns the inode number on success(!)...argh argh argh */
  1109. #  undef stat
  1110.  
  1111. /********************/
  1112. /* Function zstat() */
  1113. /********************/
  1114.  
  1115. int zstat(p, s)
  1116.     char *p;
  1117.     struct stat *s;
  1118. {
  1119.     return (stat(p,s) >= 0? 0 : (-1));
  1120. }
  1121.  
  1122. #endif /* REGULUS */
  1123.  
  1124.  
  1125.  
  1126.  
  1127.  
  1128. #ifdef SMALL_MEM
  1129.  
  1130. char rgchBigBuffer[512];
  1131. char rgchSmallBuffer[96];
  1132. char rgchSmallBuffer2[96];
  1133.  
  1134. /******************************/
  1135. /*  Function LoadFarString()  */   /* (and friends...) */
  1136. /******************************/
  1137.  
  1138. char *LoadFarString(char Far *sz)
  1139. {
  1140.     (void)zfstrcpy(rgchBigBuffer, sz);
  1141.     return rgchBigBuffer;
  1142. }
  1143.  
  1144. char *LoadFarStringSmall(char Far *sz)
  1145. {
  1146.     (void)zfstrcpy(rgchSmallBuffer, sz);
  1147.     return rgchSmallBuffer;
  1148. }
  1149.  
  1150. char *LoadFarStringSmall2(char Far *sz)
  1151. {
  1152.     (void)zfstrcpy(rgchSmallBuffer2, sz);
  1153.     return rgchSmallBuffer2;
  1154. }
  1155.  
  1156.  
  1157. /*************************/
  1158. /*  Function zfstrcpy()  */   /* portable clone of _fstrcpy() */
  1159. /*************************/
  1160.  
  1161. char Far * Far zfstrcpy(char Far *s1, const char Far *s2)
  1162. {
  1163.     char Far *p = s1;
  1164.  
  1165.     while ((*s1++ = *s2++) != '\0');
  1166.     return p;
  1167. }
  1168.  
  1169. #endif /* SMALL_MEM */
  1170.