home *** CD-ROM | disk | FTP | other *** search
- /*---------------------------------------------------------------------------
-
- file_io.c
-
- This file contains routines for doing direct input/output, file-related
- sorts of things.
-
- ---------------------------------------------------------------------------*/
-
-
- #include "unzip.h"
- #ifdef MSWIN
- #include <windows.h>
- #include "wizunzip.h"
- #include "replace.h"
- #endif
-
-
- /************************************/
- /* File_IO Local Prototypes, etc. */
- /************************************/
-
- static int WriteBuffer __((int fd, unsigned char *buf, int len));
- static int dos2unix __((unsigned char *buf, int len));
-
- int CR_flag = 0; /* when last char of buffer == CR (for dos2unix()) */
-
-
-
-
-
- /*******************************/
- /* Function open_input_file() */
- /*******************************/
-
- int open_input_file()
- { /* return non-0 if open failed */
- /*
- * open the zipfile for reading and in BINARY mode to prevent cr/lf
- * translation, which would corrupt the bitstreams
- */
-
- #ifndef UNIX
- zipfd = open(zipfn, O_RDONLY | O_BINARY);
- #else
- zipfd = open(zipfn, O_RDONLY);
- #endif
- if (zipfd < 1) {
- fprintf(stderr, "error: can't open zipfile [ %s ]\n", zipfn);
- return (1);
- }
- return 0;
- }
-
-
-
-
-
- /************************/
- /* Function readbuf() */
- /************************/
-
- int readbuf(buf, size)
- char *buf;
- register unsigned size;
- { /* return number of bytes read into buf */
- register int count;
- int n;
-
- n = size;
- while (size) {
- if (incnt == 0) {
- if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0)
- return (n-size);
- /* buffer ALWAYS starts on a block boundary: */
- cur_zipfile_bufstart += INBUFSIZ;
- inptr = inbuf;
- }
- count = min(size, incnt);
- memcpy(buf, inptr, count);
- buf += count;
- inptr += count;
- incnt -= count;
- size -= count;
- }
- return (n);
- }
-
-
-
-
-
- /**********************************/
- /* Function create_output_file() */
- /**********************************/
-
- int create_output_file()
- { /* return non-0 if creat failed */
- /*
- * Create the output file with default permissions.
- */
- extern int do_all;
- char answerbuf[10];
- UWORD holder;
- int already_exists;
-
-
-
- CR_flag = 0; /* Hack to get CR at end of buffer working. */
-
- #ifndef VMS /* creates higher version number instead of overwriting (will
- * have to modify for VMS-style names with specific version
- * numbers: check for failure on creat()??? */
- /*
- * check if the file exists, unless do_all
- */
- already_exists = open(filename, 0);
- if (already_exists >= 0)
- close(already_exists); /* before you forget */
- if (!do_all) {
- if (already_exists >= 0) { /* first close it, before you forget! */
-
- /* ask the user before blowing it away */
- #ifdef MSWIN
- {
- FARPROC lpProcReplace;
- int ReplaceDlgRetVal; /* replace dialog return value */
-
- ShowCursor(FALSE); /* turn off cursor */
- SetCursor(hSaveCursor); /* restore the cursor */
- lpProcReplace = MakeProcInstance(Replace, hInst);
- ReplaceDlgRetVal = DialogBoxParam(hInst, "Replace", hMainWnd,
- lpProcReplace, (DWORD)(LPSTR)filename);
- FreeProcInstance(lpProcReplace);
- switch (ReplaceDlgRetVal) {
- case IDM_REPLACE_YES:
- break;
- case IDM_REPLACE_ALL:
- do_all = 1;
- break;
- case IDM_REPLACE_NO:
- while (ReadByte(&holder));
- hSaveCursor = SetCursor(hHourGlass);
- ShowCursor(TRUE); /* show it */
- return 1; /* it's done! */
- }
- hSaveCursor = SetCursor(hHourGlass);
- ShowCursor(TRUE); /* show it */
- }
- #else
- fprintf(stderr, "replace %s, y-yes, n-no, a-all: ", filename);
- #ifdef AMIGA
- fflush(stderr);
- #endif
- fgets(answerbuf, 9, stdin);
-
- switch (answerbuf[0]) {
- case 'y':
- case 'Y':
- break;
- case 'a':
- case 'A':
- do_all = 1;
- break;
- case 'n':
- case 'N':
- default:
- while (ReadByte(&holder));
- return 1; /* it's done! */
- }
- #endif
- }
- }
-
- #if defined(UNIX) && !defined(AMIGA)
- {
- int mask;
- if (already_exists >= 0 && unlink(filename) < 0)
- fprintf(stderr, "Can't unlink %s\n", filename); /* So we own it */
- mask = umask(0);
- outfd = creat(filename, 0777 & f_attr); /* Unix */
- umask(mask);
- }
- #else /* !UNIX || AMIGA */
- /* Some Unix archives yield impossible f_attr's !!!
- Also, creating a file read-only makes absolutely no sense here
- because we immediately close it and then open it using open()
- and O_RDWR which could not work then. */
- outfd = creat(filename, (S_IWRITE | S_IREAD) /* & f_attr */); /* PCs */
- #endif /* ?(UNIX && !AMIGA) */
- #else /* VMS */
- outfd = creat(filename, 0, "rfm=stmlf", "rat=cr"); /* VMS */
- #endif /* ?VMS */
-
- if (outfd < 1) {
- fprintf(stderr, "Can't create output file: %s\n", filename);
- return 1;
- }
- /*
- * close the newly created file and reopen it in BINARY mode to
- * disable all CR/LF translations
- */
- #ifndef UNIX
- #ifdef THINK_C
- /*
- * THINKC's stdio routines have the horrible habit of
- * making any file you open look like generic files
- * this code tells the OS that it's a text file
- */
- if (aflag) {
- fileParam pb;
- OSErr err;
-
- CtoPstr(filename);
- pb.ioNamePtr = filename;
- pb.ioVRefNum = 0;
- pb.ioFVersNum = 0;
- pb.ioFDirIndex = 0;
- err = PBGetFInfo(&pb,0);
- if (err == noErr) {
- pb.ioFlFndrInfo.fdCreator = 0x3F3F3F3F;
- pb.ioFlFndrInfo.fdType = 'TEXT';
- err = PBSetFInfo(&pb, 0);
- }
- PtoCstr(filename);
- }
- #endif /* THINK_C */
- if (!aflag) {
- close(outfd);
- outfd = open(filename, O_RDWR | O_BINARY);
- }
- #endif /* !UNIX */
- if (outfd < 1) {
- fprintf(stderr, "Can't open output: %s\n", filename);
- return 1;
- }
- return 0;
- }
-
-
-
-
-
- /*****************************/
- /* Function FillBitBuffer() */
- /*****************************/
-
- int FillBitBuffer(bits)
- register int bits;
- {
- /*
- * Get the bits that are left and read the next UWORD. This
- * function is only used by the READBIT macro (which is used
- * by all of the uncompression routines).
- */
- register int result = bitbuf;
- UWORD temp;
- int sbits = bits_left;
-
-
- bits -= bits_left;
-
- /* read next UWORD of input */
- bits_left = ReadByte(&bitbuf);
- bits_left += ReadByte(&temp);
-
- bitbuf |= (temp << 8);
- if (bits_left == 0)
- zipeof = 1;
-
- /* get the remaining bits */
- result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
- bitbuf >>= bits;
- bits_left -= bits;
- return result;
- }
-
-
-
-
-
- /************************/
- /* Function ReadByte() */
- /************************/
-
- int ReadByte(x)
- UWORD *x;
- {
- /*
- * read a byte; return 8 if byte available, 0 if not
- */
-
-
- if (csize-- <= 0)
- return 0;
-
- if (incnt == 0) {
- if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0)
- return 0;
- /* buffer ALWAYS starts on a block boundary: */
- cur_zipfile_bufstart += INBUFSIZ;
- inptr = inbuf;
- }
- *x = *inptr++;
- --incnt;
- return 8;
- }
-
-
-
- #ifdef FLUSH_AND_WRITE
- /***************************/
- /* Function FlushOutput() */
- /***************************/
-
- int FlushOutput()
- { /* return PK-type error code */
- /* flush contents of output buffer */
- /*
- * This combined version doesn't work, and I sure can't see why not...
- * probably something stupid, but how much can you screw up in 6 lines???
- * [optimization problem??]
- */
- int len;
-
-
- if (outcnt) {
- UpdateCRC(outbuf, outcnt);
-
- if (!tflag) {
- if (aflag)
- len = dos2unix(outbuf, outcnt);
- #ifdef MSWIN
- if (_lwrite(outfd, outout, len) != len) {
- #else
- if (write(outfd, outout, len) != len) {
- #endif
- fprintf(stderr, "Fatal write error.\n");
- return (50); /* 50: disk full */
- }
- }
- outpos += outcnt;
- outcnt = 0;
- outptr = outbuf;
- }
- return (0); /* 0: no error */
- }
-
- #else /* separate flush and write routines */
- /***************************/
- /* Function FlushOutput() */
- /***************************/
-
- int FlushOutput()
- { /* return PK-type error code */
- /* flush contents of output buffer */
- if (outcnt) {
- UpdateCRC(outbuf, outcnt);
-
- if (!tflag && WriteBuffer(outfd, outbuf, outcnt))
- return (50); /* 50: disk full */
-
- outpos += outcnt;
- outcnt = 0;
- outptr = outbuf;
- }
- return (0); /* 0: no error */
- }
-
- /***************************/
- /* Function WriteBuffer() */
- /***************************/
-
- static int WriteBuffer(fd, buf, len) /* return 0 if successful, 1 if not */
- int fd;
- unsigned char *buf;
- int len;
- {
- if (aflag)
- len = dos2unix(buf, len);
- #ifdef MSWIN
- if (cflag) /* if writing to console vs. actual file, write to Msg Window */
- {
- WriteBufferToMsgWin(outout, len, FALSE);
- return 0;
- }
- if (_lwrite(fd, outout, len) != len) {
- #else
- if (write(fd, outout, len) != len) {
- #endif
- #ifdef DOS_OS2
- if (!cflag) { /* ^Z treated as EOF, removed with -c */
- #endif
- fprintf(stderr, "Fatal write error.\n");
- return (1); /* FAILED */
- #ifdef DOS_OS2
- }
- #endif
- }
- return (0);
- }
-
- #endif
-
-
-
-
- /************************/
- /* Function dos2unix() */
- /************************/
-
- static int dos2unix(buf, len)
- unsigned char *buf;
- int len;
- {
- int new_len;
- int i;
- #ifdef MSWIN
- unsigned char _far *walker;
- #else
- unsigned char *walker;
- #endif
-
- new_len = len;
- walker = outout;
- #ifdef MACOS
- /*
- * Mac wants to strip LFs instead CRs from CRLF pairs
- */
- if (CR_flag && *buf == LF) {
- buf++;
- new_len--;
- len--;
- CR_flag = buf[len] == CR;
- }
- else
- CR_flag = buf[len - 1] == CR;
- for (i = 0; i < len; i += 1) {
- *walker++ = ascii_to_native(*buf);
- if (*buf == LF) walker[-1] = CR;
- if (*buf++ == CR && *buf == LF) {
- new_len--;
- buf++;
- i++;
- }
- }
- #else
- if (CR_flag && *buf != LF)
- *walker++ = ascii_to_native(CR);
- CR_flag = buf[len - 1] == CR;
- for (i = 0; i < len; i += 1) {
- *walker++ = ascii_to_native(*buf);
- if (*buf++ == CR && *buf == LF) {
- new_len--;
- walker[-1] = ascii_to_native(*buf++);
- i++;
- }
- }
- /*
- * If the last character is a CR, then "ignore it" for now...
- */
- if (walker[-1] == ascii_to_native(CR))
- new_len--;
- #endif
- return new_len;
- }
-
-
-
-
-
- #ifdef DOS_OS2
-
- /***************************************/
- /* Function set_file_time_and_close() */
- /***************************************/
-
- void set_file_time_and_close()
- /*
- * MS-DOS AND OS/2 VERSION (Mac, Unix/VMS versions are below)
- *
- * Set the output file date/time stamp according to information from the
- * zipfile directory record for this member, then close the file. This
- * is optional and can be deleted if your compiler does not easily support
- * setftime().
- */
- {
- /*---------------------------------------------------------------------------
- Allocate local variables needed by OS/2 and Turbo C. [OK, OK, so it's
- a bogus comment...but this routine was getting way too cluttered and
- needed some visual separators. Bleah.]
- ---------------------------------------------------------------------------*/
-
- #ifdef OS2 /* (assuming only MSC or MSC-compatible compilers
- * for this part) */
-
- union {
- FDATE fd; /* system file date record */
- UWORD zdate; /* date word */
- } ud;
-
- union {
- FTIME ft; /* system file time record */
- UWORD ztime; /* time word */
- } ut;
-
- FILESTATUS fs;
-
- #else /* !OS2 */
- #ifdef __TURBOC__
-
- union {
- struct ftime ft; /* system file time record */
- struct {
- UWORD ztime; /* date and time words */
- UWORD zdate; /* .. same format as in .ZIP file */
- } zt;
- } td;
-
- #endif /* __TURBOC__ */
- #endif /* !OS2 */
-
- /*---------------------------------------------------------------------------
- Do not attempt to set the time stamp on standard output.
- ---------------------------------------------------------------------------*/
-
- if (cflag) {
- close(outfd);
- return;
- }
-
- /*---------------------------------------------------------------------------
- Copy and/or convert time and date variables, if necessary; then set the
- file time/date.
- ---------------------------------------------------------------------------*/
-
- #ifdef OS2
-
- DosQFileInfo(outfd, 1, &fs, sizeof(fs));
- ud.zdate = lrec.last_mod_file_date;
- fs.fdateLastWrite = ud.fd;
- ut.ztime = lrec.last_mod_file_time;
- fs.ftimeLastWrite = ut.ft;
- DosSetFileInfo(outfd, 1, (PBYTE) &fs, sizeof(fs));
-
- #else /* !OS2 */
- #ifdef __TURBOC__
-
- td.zt.ztime = lrec.last_mod_file_time;
- td.zt.zdate = lrec.last_mod_file_date;
- setftime(outfd, &td.ft);
-
- #else /* !__TURBOC__: MSC MS-DOS */
-
- _dos_setftime(outfd, lrec.last_mod_file_date, lrec.last_mod_file_time);
-
- #endif /* !__TURBOC__ */
- #endif /* !OS2 */
-
- /*---------------------------------------------------------------------------
- And finally we can close the file...at least everybody agrees on how to
- do *this*. I think...
- ---------------------------------------------------------------------------*/
-
- close(outfd);
- }
-
-
-
-
-
- #else /* !DOS_OS2 */
- #ifdef MACOS /* Mac first */
-
- /***************************************/
- /* Function set_file_time_and_close() */
- /***************************************/
-
- void set_file_time_and_close()
- /*
- * MAC VERSION
- *
- * First close the output file, then set its date/time stamp according
- * to information from the zipfile directory record for this file. [So
- * technically this should be called "close_file_and_set_time()", but
- * this way we can use the same prototype for either case, without extra
- * #ifdefs. So there.]
- */
- {
- long m_time;
- DateTimeRec dtr;
- ParamBlockRec pbr;
- OSErr err;
-
- if (outfd != 1)
- {
- close(outfd);
-
- /*
- * Macintosh bases all file modification times on the number of seconds
- * elapsed since Jan 1, 1904, 00:00:00. Therefore, to maintain
- * compatibility with MS-DOS archives, which date from Jan 1, 1980,
- * with NO relation to GMT, the following conversions must be made:
- * the Year (yr) must be incremented by 1980;
- * and converted to seconds using the Mac routine Date2Secs(),
- * almost similar in complexity to the Unix version :-)
- * J. Lee
- */
-
- dtr.year = (((lrec.last_mod_file_date >> 9) & 0x7f) + 1980); /* dissect date */
- dtr.month = ((lrec.last_mod_file_date >> 5) & 0x0f);
- dtr.day = (lrec.last_mod_file_date & 0x1f);
-
- dtr.hour = ((lrec.last_mod_file_time >> 11) & 0x1f); /* dissect time */
- dtr.minute = ((lrec.last_mod_file_time >> 5) & 0x3f);
- dtr.second = ((lrec.last_mod_file_time & 0x1f) * 2);
- Date2Secs(&dtr, &m_time);
- CtoPstr(filename);
- pbr.fileParam.ioNamePtr = filename;
- pbr.fileParam.ioVRefNum = pbr.fileParam.ioFVersNum = pbr.fileParam.ioFDirIndex = 0;
- err = PBGetFInfo(&pbr, 0L);
- pbr.fileParam.ioFlMdDat = pbr.fileParam.ioFlCrDat = m_time;
- if (err == noErr) {
- err = PBSetFInfo(&pbr, 0L);
- }
- if (err != noErr) {
- printf("Error, can't set the time for %s\n",filename);
- }
-
- /* set read-only perms if needed */
- if (err != noErr && f_attr != 0) {
- err = SetFLock(filename, 0);
- }
- PtoCstr(filename);
- }
- }
-
-
- /* #elif defined(AMIGA) */
- #else
- #ifdef AMIGA
- #include <libraries/dos.h>
- void set_file_time_and_close()
- {
- /* This routine is derived from the unix routine. In AmigaDos, the
- * counting begins 01-Jan-1978
- */
- long m_time;
- int yr, mo, dy, hh, mm, ss, leap, days = 0;
- struct DateStamp myadate;
- if (cflag) /* can't set time on stdout */
- return;
- close(outfd);
- yr = (((lrec.last_mod_file_date >> 9) & 0x7f) + 2); /* dissect date */
- mo = ((lrec.last_mod_file_date >> 5) & 0x0f);
- dy = ((lrec.last_mod_file_date & 0x1f) - 1);
- hh = ((lrec.last_mod_file_time >> 11) & 0x1f); /* dissect time */
- mm = ((lrec.last_mod_file_time >> 5) & 0x3f);
- ss = ((lrec.last_mod_file_time & 0x1f) * 2);
- /* leap = # of leap years from 1978 up to but not including
- the current year */
- leap = ((yr + 1977) / 4); /* Leap year base factor */
- /* How many days from 1978 to this year? */
- days = (yr * 365) + (leap - 492);
- switch (mo) { /* calculate expired days this year */
- case 12:
- days += 30;
- case 11:
- days += 31;
- case 10:
- days += 30;
- case 9:
- days += 31;
- case 8:
- days += 31;
- case 7:
- days += 30;
- case 6:
- days += 31;
- case 5:
- days += 30;
- case 4:
- days += 31;
- case 3:
- days += 28; /* account for leap years (2000 IS one) */
- if (((yr + 1978) % 4 == 0) && (yr + 1978) != 2100) /* OK thru 2199 */
- ++days;
- case 2:
- days += 31;
- }
- myadate.ds_Days = days+dy-2;
- myadate.ds_Minute = hh*60+mm;
- myadate.ds_Tick = ss*TICKS_PER_SECOND;
- if (!(SetFileDate(filename, &myadate)))
- fprintf(stderr, "Error, can't set the time for %s\n",filename);
- }
-
- #else /* !MACOS... */
- #ifndef MTS /* && !MTS (can't do): only one left is UNIX */
-
- /***************************************/
- /* Function set_file_time_and_close() */
- /***************************************/
-
- void set_file_time_and_close()
- /*
- * UNIX AND VMS VERSION (MS-DOS & OS/2, Mac versions are above)
- *
- * First close the output file, then set its date/time stamp according
- * to information from the zipfile directory record for this file. [So
- * technically this should be called "close_file_and_set_time()", but
- * this way we can use the same prototype for either case, without extra
- * #ifdefs. So there.]
- */
- {
- long m_time;
- int yr, mo, dy, hh, mm, ss, leap, days = 0;
- #ifdef VMS
- char timbuf[24];
- static char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
- "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
- struct VMStimbuf {
- char *actime; /* VMS revision date, ASCII format */
- char *modtime; /* VMS creation date, ASCII format */
- } ascii_times;
- #else /* !VMS */
- struct utimbuf {
- time_t atime; /* New access time */
- time_t mtime; /* New modification time */
- } tp;
- #ifdef BSD
- static struct timeb tbp;
- #else /* !BSD */
- #ifdef AMIGA
- extern char *_TZ;
- #else /* !AMIGA */
- extern long timezone;
- #endif /* ?AMIGA */
- #endif /* ?BSD */
- #endif /* ?VMS */
-
-
- close(outfd);
-
- if (cflag) /* can't set time on stdout */
- return;
-
- /*
- * These date conversions look a little weird, so I'll explain.
- * UNIX bases all file modification times on the number of seconds
- * elapsed since Jan 1, 1970, 00:00:00 GMT. Therefore, to maintain
- * compatibility with MS-DOS archives, which date from Jan 1, 1980,
- * with NO relation to GMT, the following conversions must be made:
- * the Year (yr) must be incremented by 10;
- * the Date (dy) must be decremented by 1;
- * and the whole mess must be adjusted by TWO factors:
- * relationship to GMT (ie.,Pacific Time adds 8 hrs.),
- * and whether or not it is Daylight Savings Time.
- * Also, the usual conversions must take place to account for leap years,
- * etc.
- * C. Seaman
- */
-
- yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + 10; /* dissect date */
- mo = (lrec.last_mod_file_date >> 5) & 0x0f;
- dy = (lrec.last_mod_file_date & 0x1f) - 1;
-
- hh = (lrec.last_mod_file_time >> 11) & 0x1f; /* dissect time */
- mm = (lrec.last_mod_file_time >> 5) & 0x3f;
- ss = (lrec.last_mod_file_time & 0x1f) * 2;
-
- #ifdef VMS
- sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", dy+1, month[mo-1],
- yr+1970, hh, mm, ss);
-
- ascii_times.actime = timbuf;
- ascii_times.modtime = timbuf;
-
- if ((mm = VMSmunch(filename, SET_TIMES, &ascii_times)) != RMS$_NMF)
- fprintf(stderr, "error %d: can't set the time for %s\n", mm, filename);
-
- #else /* !VMS */
- /* leap = # of leap years from 1970 up to but not including
- the current year */
-
- leap = ((yr + 1969) / 4); /* Leap year base factor */
-
- /* How many days from 1970 to this year? */
- days = (yr * 365) + (leap - 492);
-
- switch (mo) { /* calculate expired days this year */
- case 12:
- days += 30;
- case 11:
- days += 31;
- case 10:
- days += 30;
- case 9:
- days += 31;
- case 8:
- days += 31;
- case 7:
- days += 30;
- case 6:
- days += 31;
- case 5:
- days += 30;
- case 4:
- days += 31;
- case 3:
- days += 28; /* account for leap years (2000 IS one) */
- if (((yr + 1970) % 4 == 0) && (yr + 1970) != 2100) /* OK thru 2199 */
- ++days;
- case 2:
- days += 31;
- }
-
- /* convert date & time to seconds relative to 00:00:00, 01/01/1970 */
- m_time = ((days + dy) * 86400) + (hh * 3600) + (mm * 60) + ss;
-
- #ifdef BSD
- ftime(&tbp);
- m_time += tbp.timezone * 60L;
- #else /* !BSD */
- #ifdef AMIGA
- _TZ = getenv("TZ");
- #endif
- tzset(); /* Set `timezone'. */
- m_time += timezone; /* account for timezone differences */
- #endif /* ?BSD */
-
- if (localtime(&m_time)->tm_isdst)
- m_time -= 60L * 60L; /* Adjust for daylight savings time */
-
- /* set the time stamp on the file */
- tp.mtime = m_time; /* Set modification time */
- tp.atime = m_time; /* Set access time */
-
- if (utime(filename, &tp))
- fprintf(stderr, "error: can't set the time for %s\n",filename);
- #endif /* ?VMS */
- }
-
- #endif /* ?MTS */
- #endif /* ?MACOS */
- #endif /* ?AMIGA */
- #endif /* ?DOS_OS2 */
-