windows-nt/Source/XPSP1/NT/base/win32/lz32/winlza/expand.c
2020-09-26 16:20:57 +08:00

282 lines
7.2 KiB
C

/*
** expand.c - Main expansion routine for LZA file expansion program.
**
** Author: DavidDi
*/
// Headers
///////////
#ifndef LZA_DLL
#include <dos.h>
#include <errno.h>
#include <io.h>
#include <stdio.h>
#include <string.h>
#endif
#include "lz_common.h"
#include "lzcommon.h"
#include "lz_buffers.h"
#include "lz_header.h"
/*
** N.b., one reason DOS file handles are used for file references in this
** module is that using FILE *'s for file references poses a problem.
** fclose()'ing a file which was fopen()'ed in write "w" or append "a" mode
** stamps the file with the current date. This undoes the intended effect of
** CopyDateTimeStamp(). We could also get around this fclose() problem by
** first fclose()'ing the file, and then fopen()'ing it again in read "r"
** mode.
**
** Using file handles also allows us to bypass stream buffering, so reads and
** writes may be done with whatever buffer size we choose. Also, the
** lower-level DOS file handle functions are faster than their stream
** counterparts.
*/
/*
** int CopyFile(int doshSource, int doshDest);
**
** Copy file.
**
** Arguments: doshSource - source DOS file handle
** doshDest - destination DOS file handle
**
** Returns: int - TRUE if successful. One of the LZERROR_ codes if
** unsuccessful.
**
** Globals: none
*/
/* WIN32 MOD, CopyFile is a win32 API!*/
INT lz_CopyFile(INT doshSource, INT doshDest, PLZINFO pLZI)
{
DWORD ucbRead, ucbWritten;
// !!! Assumes pLZI parm is valid. No sanity check (should be done above in caller).
// Rewind input file again.
if (FSEEK(doshSource, 0L, SEEK_SET) != 0L) {
return(LZERROR_BADINHANDLE);
}
// Rewind output file.
if (doshDest != NO_DOSH &&
FSEEK(doshDest, 0L, SEEK_SET) != 0L) {
return( LZERROR_BADOUTHANDLE );
}
// Set up a fresh buffer state.
ResetBuffers();
while ((ucbRead = FREAD(doshSource, pLZI->rgbyteInBuf, pLZI->ucbInBufLen)) > 0U &&
#ifdef LZA_DLL
ucbRead != (DWORD)(-1))
#else
FERROR() == 0)
#endif
{
if ((ucbWritten = FWRITE(doshDest, pLZI->rgbyteInBuf, ucbRead)) != ucbRead)
#ifdef LZA_DLL
if (ucbWritten != (DWORD)(-1)) {
#else
if (FERROR() != 0) {
#endif
return(LZERROR_BADOUTHANDLE);
}
else {
return(LZERROR_WRITE);
}
pLZI->cblOutSize += ucbWritten;
if (ucbRead != pLZI->ucbInBufLen)
break;
}
#ifdef LZA_DLL
// here, ucbRead == 0, EOF (proper loop termination)
// == -1, bad DOS handle
if (ucbRead == (DWORD)(-1)) {
#else
// here, FERROR() == 0U, EOF (proper loop termination)
// != 0U, bad DOS handle
if (FERROR() != 0U) {
#endif
return(LZERROR_BADINHANDLE);
}
// Copy successful - return number of bytes copied.
return(TRUE);
}
/*
** int ExpandOrCopyFile(int doshDource, int doshDest);
**
** Expands one file to another.
**
** Arguments: doshSource - source DOS file handle
** doshDest - destination DOS file handle
**
** Returns: int - TRUE if expansion finished successfully. One of the
** LZERROR_ codes if not.
**
** Globals: none
*/
INT ExpandOrCopyFile(INT doshSource, INT doshDest, PLZINFO pLZI)
{
INT f;
FH FHInfo; // compressed header info struct
BOOL bExpandingFile;
// !!! Assumes pLZI parm is valid. No sanity check (should be done above in caller).
// Get compressed file header.
if (GetHdr(&FHInfo, doshSource, &pLZI->cblInSize) != TRUE
&& pLZI->cblInSize >= (LONG)HEADER_LEN)
// read error occurred
return(LZERROR_BADINHANDLE);
// Expand or copy input file to output file.
bExpandingFile = (IsCompressed(& FHInfo) == TRUE);
if (bExpandingFile)
{
switch (FHInfo.byteAlgorithm)
{
case ALG_FIRST:
f = LZDecode(doshSource, doshDest, (LONG)FHInfo.cbulUncompSize - 1L,
TRUE, TRUE, pLZI);
break;
#if 0
case ALG_LZ:
f = LZDecode(doshSource, doshDest, (LONG)FHInfo.cbulUncompSize - 1L,
TRUE, FALSE, pLZI);
break;
#endif
default:
f = LZERROR_UNKNOWNALG;
break;
}
}
else
f = lz_CopyFile(doshSource, doshDest, pLZI);
if (f != TRUE)
return(f);
// Flush output buffer to file.
if ((f = FlushOutputBuffer(doshDest, pLZI)) != TRUE)
return(f);
// Copy date and time stamp from source file to destination file.
if ((f = CopyDateTimeStamp(doshSource, doshDest)) != TRUE)
return(f);
// Did we expand the exact number of bytes we expected to from the
// compressed file header entry?
if (bExpandingFile &&
(DWORD)pLZI->cblOutSize != FHInfo.cbulUncompSize)
return(LZERROR_READ);
// Expansion / copying finished successfully.
return(TRUE);
}
/*
** int Expand(char ARG_PTR *pszSource, char ARG_PTR *pszDest, BOOL bDoRename);
**
** Expands one file to another.
**
** Arguments: pszSource - name of file to compress
** pszDest - name of compressed output file
** bDoRename - flag for output file renaming
**
** Returns: int - TRUE if expansion finished successfully. One of the
** LZERROR_ codes if not.
**
** Globals: none
*/
INT Expand(
NOTIFYPROC pfnNotify,
CHAR ARG_PTR *pszSource,
CHAR ARG_PTR *pszDest,
BOOL bDoRename,
PLZINFO pLZI)
{
INT doshSource, // input file handle
doshDest, // output file handle
f;
FH FHInfo; // compressed header info struct
CHAR szDestFileName[MAX_PATH];
// Sanity check
if (!pLZI) {
return(LZERROR_GLOBLOCK);
}
// Set up input file handle. Set cblInSize to length of input file.
if ((f = GetIOHandle(pszSource, READ_IT, & doshSource, &pLZI->cblInSize)) != TRUE)
return(f);
if (GetHdr(&FHInfo, doshSource, &pLZI->cblInSize) != TRUE &&
pLZI->cblInSize >= (LONG)HEADER_LEN)
{
// Read error occurred.
FCLOSE(doshSource);
return(LZERROR_BADINHANDLE);
}
// Create destination file name.
STRCPY(szDestFileName, pszDest);
#if 0
if (bDoRename == TRUE && FHInfo.byteAlgorithm != ALG_FIRST)
#else
if (bDoRename == TRUE)
#endif
{
// Rename output file using expanded file name extension character
// stored in compressed file header.
MakeExpandedName(szDestFileName, FHInfo.byteExtensionChar);
}
// Ask if we should compress this file.
if (! (*pfnNotify)(pszSource, szDestFileName, (WORD)
(IsCompressed(&FHInfo) ? NOTIFY_START_EXPAND : NOTIFY_START_COPY)))
{
// Don't expand / copy file. This error condition should be handled in
// pfnNotify, so indicate that it is not necessary for the caller to
// display an error message.
FCLOSE(doshSource);
return(BLANK_ERROR);
}
// Set up output file handle.
if ((f = GetIOHandle(szDestFileName, WRITE_IT, & doshDest, &pLZI->cblInSize)) != TRUE)
{
FCLOSE(doshSource);
return(f);
}
// Expand or copy input file into output file.
f = ExpandOrCopyFile(doshSource, doshDest, pLZI);
// Close files.
FCLOSE(doshSource);
FCLOSE(doshDest);
return(f);
}