home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windoware
/
WINDOWARE_1_6.iso
/
source
/
wzun11sr
/
file_io.c
< prev
next >
Wrap
Text File
|
1992-04-18
|
25KB
|
849 lines
/*---------------------------------------------------------------------------
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 */