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

982 lines
30 KiB
C

/*
** winlzexp.c - Windows LZExpand library routines for manipulating compressed
** files.
**
** Author: DavidDi
*/
/*
** Notes:
** -----
**
** The LZInit() function returns either DOS handles or LZFile struct
** identifiers of some kind, depending upon how it is called. The LZ
** functions LZSeek(), LZRead(), and LZClose() needed some way to
** differentiate between DOS file handles and the LZFile struct identifiers.
** As the functions stand now, they use DOS file handles as themselves, and
** table offsets as LZFile identifiers. The table offsets are incremented by
** some base value, LZ_TABLE_BIAS, in order to push their values past all
** possible DOS file handle values. The table offsets (- LZ_TABLE_BIAS) are
** used as indices in rghLZFileTable[] to retrieve a global handle to an
** LZFile struct. The table of global handles is allocated statically from
** the DLL's data segment. The LZFile struct's are allocated from global
** heap space and are moveable. This scheme might also be implemented as a
** linked list of global handles.
**
** Now the resulting benefit from this scheme is that DOS file handles and
** LZFile struct identifiers can be differentiated, since DOS file handles
** are always < LZ_TABLE_BIAS, and LZFile struct identifiers are always
** >= LZ_TABLE_BIAS. This dichotomy may be used in macros, like the sample
** ones provided in lzexpand.h, to select the appropriate function to call
** (e.g., LZSeek() or _llseek()) in order to avoid the overhead of an extra
** function call for uncompressed files. LZSeek(), LZRead(), and LZClose()
** are, however, "smart" enough to figure out whether they are dealing with
** DOS file handles or table offsets, and take action appropriately. As an
** extreme example, LZOpenFile(), LZSeek(), LZRead, and LZClose() can be used
** as replacements for OpenFile(), _llseek(), _lread(), and _lclose. In this
** case, the program using the DLL functions could call them without ever
** caring whether the files it was reading were LZ compressed or not.
*/
/* WIN32 MODS
** Since the above is a DOS only hack, I have to change the logic for
** for the 0-255 file handle deal'o. The original code, tests greater than
** LZ_TABLE_BIAS for file structures. What I will do, is convert file handles
** returned from OpenFile, to a range 0-255. Once the test is complete, I'll
** use the file handle as an offset into a 255 element array, which will
** contain the WIN32 file handle. So there will be an additional array
** fhWin32File[255], which will be allocated sequencially starting at 0.
** Unfortunately, this means everywhere the file handle is used, must be converted
*/
// Headers
///////////
#include <basedll.h>
#define LZA_DLL
#include "lz_common.h"
#include "lz_buffers.h"
#include "lz_header.h"
#include "lzcommon.h"
#include "lzpriv.h"
#include "wchar.h"
#if DEBUG
#include "stdio.h"
#endif
// Globals
///////////
// Semaphore for File Table allocation
RTL_CRITICAL_SECTION semTable;
BOOL fCSInit = FALSE;
// table of handles to LZFile structs
HANDLE rghLZFileTable[MAX_LZFILES] = {0};
// next free entry in rghLZFileTable[]
static INT iNextLZFileEntry = 0;
HFILE fhWin32File[MAX_LZFILES] = {0};
/*
** int APIENTRY LZInit(int hWin32File);
**
** Sets up LZFile struct for a file that has already been opened by
** OpenFile().
**
** Arguments: hWin32File - source DOS file handle
**
** Returns: int - LZFile struct table offset or DOS file handle if
** successful. One of the LZERROR_ codes if unsuccessful.
**
** Globals: iNextLZFile entry advanced, or returned to beginning from end.
*/
INT APIENTRY LZInit(INT hWin32File)
{
HANDLE hLZFile; // handle to new LZFile struct
LZFile *lpLZ; // pointer to new LZFile struct
FH FHComp; // header info structure from input file
BOOL bHdr; // holds GetHdr() return value
INT iTableIndex, // holds rghLZFileTable[] slot to be filled by
// new LZFile struct handle
iStartEntry; // original value of iNextLZFileEntry
LONG cblInSize = 0;
INT nRet;
if (!fCSInit) {
if (!NT_SUCCESS(RtlInitializeCriticalSection(&semTable))) {
return LZERROR_GLOBALLOC;
}
fCSInit = TRUE;
}
// Did the read succeed?
if ((bHdr = GetHdr((FH *)&FHComp, hWin32File, &cblInSize)) != TRUE
&& cblInSize >= (LONG)HEADER_LEN) {
return(LZERROR_BADINHANDLE);
}
// Check for uncompressed input file.
if (bHdr != TRUE || IsCompressed(& FHComp) != TRUE)
{
// This is an uncompressed file - rewind it.
if (FSEEK(hWin32File, 0L, SEEK_SET) != 0L) {
return(LZERROR_BADINHANDLE);
}
else {
// And return DOS file handle.
return(ConvertWin32FHToDos(hWin32File));
}
}
// Check compression algorithm used.
if (RecognizeCompAlg(FHComp.byteAlgorithm) != TRUE) {
return(LZERROR_UNKNOWNALG);
}
// Find next free rghLZFileTable[] entry. N.b., we depend upon LZClose()
// to free unused entries up.
RtlEnterCriticalSection(&semTable);
iStartEntry = iNextLZFileEntry;
while (rghLZFileTable[iNextLZFileEntry] != NULL)
{
if (++iNextLZFileEntry >= MAX_LZFILES)
// Return to beginning of table.
iNextLZFileEntry = 0;
if (iNextLZFileEntry == iStartEntry) {
// We've gone full circle through rghLZFileTable[].
// It's full, so bail out.
nRet = LZERROR_GLOBALLOC;
goto LZInitExit;
}
}
// Keep track of the rghLZFileTable() slot to be filled by a handle to the
// new LZFile struct.
iTableIndex = iNextLZFileEntry;
// Allocate global storage for the new LZFile struct, initializing all
// fields to 0.
hLZFile = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (DWORD)sizeof(LZFile));
if (!hLZFile) {
nRet = LZERROR_GLOBALLOC;
goto LZInitExit;
}
// Lock that baby up.
if ((lpLZ = (LZFile *)GlobalLock(hLZFile)) == NULL)
{
GlobalFree(hLZFile);
nRet =LZERROR_GLOBLOCK;
goto LZInitExit;
}
// Initialize the new LZFile struct's general information fields.
lpLZ->dosh = hWin32File;
lpLZ->byteAlgorithm = FHComp.byteAlgorithm;
lpLZ->wFlags = 0;
lpLZ->cbulUncompSize = FHComp.cbulUncompSize;
lpLZ->cbulCompSize = FHComp.cbulCompSize;
lpLZ->lCurSeekPos = 0L;
// LZRead/LZSeeks expansion data is kept on a per file basis
lpLZ->pLZI = NULL;
// Enter new handle in table of handles.
rghLZFileTable[iTableIndex] = hLZFile;
/* WIN32 NOTE, dont need convert below, as forces a non file handle
* to the API.
*/
GlobalUnlock(hLZFile);
// Advance to next free entry.
if (++iNextLZFileEntry >= MAX_LZFILES)
iNextLZFileEntry = 0;
nRet = LZ_TABLE_BIAS + iTableIndex;
LZInitExit:
RtlLeaveCriticalSection(&semTable);
// Return rghLZFileTable[] offset of the new LZFile struct's handle's
// entry + the table bias.
return(nRet);
}
/*
** int APIENTRY GetExpandedNameA(LPSTR lpszSource, LPSTR lpszBuffer);
**
** Looks in the header of a compressed file to find its original expanded
** name.
**
** Arguments: lpszSource - name of input file
** lpszBuffer - pointer to a buffer that will be filled in with
** the expanded name of the compressed source file
**
** Returns: int - TRUE if successful. One of the LZERROR_ codes if
** unsuccessful.
**
** Globals: none
*/
INT APIENTRY GetExpandedNameA(LPSTR lpszSource, LPSTR lpszBuffer)
{
INT doshSource, // source DOS file handle
bHdr; // holds GetHdr() return value
FH FHComp; // header info structure from input file
OFSTRUCT ofOpenBuf; // source struct for OpenFile() call
LONG cblInSize = 0;
// Try to open the source file.
if ((doshSource = (HFILE)MOpenFile(lpszSource, (LPOFSTRUCT)(& ofOpenBuf), OF_READ))
== -1)
return(LZERROR_BADVALUE);
// Get the compressed file header.
if ((bHdr = GetHdr((FH *)&FHComp, doshSource, &cblInSize)) != TRUE
&& cblInSize >= (LONG)HEADER_LEN)
{
FCLOSE(doshSource);
return(LZERROR_BADVALUE);
}
// Close source file.
FCLOSE(doshSource);
// Return expanded name same as source name for uncompressed files.
STRCPY(lpszBuffer, lpszSource);
// Check for compressed input file.
if (bHdr == TRUE && IsCompressed(& FHComp) == TRUE)
MakeExpandedName(lpszBuffer, FHComp.byteExtensionChar);
return(TRUE);
}
/*
** int APIENTRY GetExpandedNameW(LPSTR lpszSource, LPSTR lpszBuffer);
**
** Wide Character version of GetExpandedName. Converts the filename to
** the ANSI Character set and calls the ANSI version.
**
*/
INT APIENTRY GetExpandedNameW(LPWSTR lpszSource, LPWSTR lpszBuffer)
{
UNICODE_STRING TempW;
ANSI_STRING TempA;
NTSTATUS Status;
NTSTATUS StatusR;
CHAR szBuffer[MAX_PATH];
TempW.Buffer = lpszSource;
TempW.Length = wcslen(lpszSource)*sizeof(WCHAR);
TempW.MaximumLength = TempW.Length + sizeof(WCHAR);
TempA.Buffer = szBuffer;
TempA.MaximumLength = MAX_PATH;
StatusR = RtlUnicodeStringToAnsiString(&TempA, &TempW, FALSE);
if (!NT_SUCCESS(StatusR))
return LZERROR_GLOBALLOC;
Status = GetExpandedNameA(szBuffer, (LPSTR)lpszBuffer);
if (Status != -1) {
strcpy(szBuffer, (LPSTR)lpszBuffer);
TempA.Length = (USHORT) strlen(szBuffer);
TempA.MaximumLength = TempA.Length+sizeof(CHAR);
TempW.Buffer = lpszBuffer;
TempW.MaximumLength = MAX_PATH;
StatusR = RtlAnsiStringToUnicodeString(&TempW, &TempA, FALSE);
if (!NT_SUCCESS(StatusR))
return LZERROR_GLOBALLOC;
}
return Status;
}
//
// INT LZCreateFileW(LPCWSTR lpFileName, DWORD fdwAccess)
//
// Opens a file (using CreateFile) and sets up an LZFile struct for
// expanding it.
//
// Arguments: lpFileName - name of input file
// fdwAccess - CreateFile access type - (e.g. GENERIC_READ)
// fdwShareMode - Share mode - (e.g. FILE_SHARE_READ)
// fdwCreate - Action to be taken - (e.g. OPEN_EXISTING)
//
// Returns: INT - LZFile struct table offset or WIN32 file HANDLE if
// successful. One of the LZERROR_ codes if unsuccessful.
//
INT
LZCreateFileW(
LPWSTR lpFileName,
DWORD fdwAccess,
DWORD fdwShareMode,
DWORD fdwCreate,
LPWSTR lpCompressedName)
{
HANDLE hWin32; // WIN32 file HANDLE returned from CreateFileW()
INT lzh; // LZ File struct ID returned from LZInit()
static WCHAR pszCompName[MAX_PATH]; // buffer for compressed name
lstrcpyW((LPWSTR)pszCompName, lpFileName);
// Just for Vlad, only try to open the compressed version of the original
// file name if we can't find the original file. All other errors get
// returned immediately.
hWin32 = CreateFileW(pszCompName, fdwAccess, fdwShareMode, NULL, fdwCreate,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hWin32 == INVALID_HANDLE_VALUE) {
DWORD dwErr = GetLastError();
if (dwErr == ERROR_FILE_NOT_FOUND) {
// Let's try to open the file of the corresponding compressed name.
MakeCompressedNameW((LPWSTR)pszCompName);
hWin32 = CreateFileW(pszCompName, fdwAccess, fdwShareMode,
NULL, fdwCreate, FILE_ATTRIBUTE_NORMAL, NULL);
}
}
// Error opening file?
if (hWin32 == INVALID_HANDLE_VALUE) {
return(LZERROR_BADINHANDLE);
}
// Don't call LZinit() on files opened in other read only mode
if (fdwCreate != OPEN_EXISTING) {
lzh = ConvertWin32FHToDos((HFILE)((DWORD_PTR)hWin32));
if (lzh == LZERROR_GLOBALLOC) {
CloseHandle(hWin32);
}
return(lzh);
}
// File has been opened with read-only action - call LZInit() to detect
// whether or not it's an LZ file, and to create structures for expansion
// if it is an LZ file.
lzh = LZInit((INT)((DWORD_PTR)hWin32));
// Close DOS file handle if LZInit() is unsuccessful.
if (lzh < 0)
CloseHandle(hWin32);
// Pass real file name to caller
//
// we believe the caller have enough buffer.
//
if( lpCompressedName != NULL )
lstrcpyW(lpCompressedName,pszCompName);
// Return LZ struct ID or LZERROR_ code.
return(lzh);
}
/*
** int APIENTRY LZOpenFileA(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuf,
** WORD wStyle);
**
** Opens a file and sets up an LZFile struct for expanding it.
**
** Arguments: lpFileName - name of input file
** lpReOpenBuf - pointer to LPOFSTRUCT to be used by OpenFile()
** wStyle - OpenFile() action to take
**
** Returns: int - LZFile struct table offset or DOS file handle if
** successful. One of the LZERROR_ codes if unsuccessful.
**
** Globals: none
*/
INT APIENTRY LZOpenFileA(LPSTR lpFileName, LPOFSTRUCT lpReOpenBuf, WORD wStyle)
{
INT dosh, // DOS file handle returned from OpenFile()
lzh; // LZ File struct ID returned from LZInit()
CHAR pszCompName[MAX_PATH]; // buffer for compressed name
STRCPY((LPSTR)pszCompName, lpFileName);
// Just for Vlad, only try to open the compressed version of the original
// file name if we can't find the original file. All other errors get
// returned immediately.
if ((dosh = OpenFile(pszCompName, lpReOpenBuf, wStyle)) == -1 &&
lpReOpenBuf->nErrCode == DEE_FILENOTFOUND)
{
// Let's try to open the file of the corresponding compressed name.
MakeCompressedName(pszCompName);
dosh = (HFILE) MOpenFile((LPSTR)pszCompName, lpReOpenBuf, wStyle);
}
// Error opening file?
if (dosh == -1)
return(LZERROR_BADINHANDLE);
// Don't call LZinit() on files opened in other than O_RDONLY mode.
// Ignore the SHARE bits.
if ((wStyle & STYLE_MASK) != OF_READ) {
lzh = ConvertWin32FHToDos(dosh);
if (lzh == LZERROR_GLOBALLOC) {
FCLOSE(dosh);
}
return(lzh);
}
// File has been opened with OF_READ style - call LZInit() to detect
// whether or not it's an LZ file, and to create structures for expansion
// if it is an LZ file.
lzh = LZInit(dosh);
// Close DOS file handle if LZInit() is unsuccessful.
if (lzh < 0)
FCLOSE(dosh);
// Return LZ struct ID or LZERROR_ code.
return(lzh);
}
/*
** int APIENTRY LZOpenFileW(LPCWSTR lpFileName, LPOFSTRUCT lpReOpenBuf,
** WORD wStyle);
**
** Wide Character version of LZOpenFile. Converts the filename to
** the ANSI Character set and calls the ANSI version.
**
*/
INT APIENTRY LZOpenFileW(LPWSTR lpFileName, LPOFSTRUCT lpReOpenBuf, WORD wStyle)
{
UNICODE_STRING FileName;
ANSI_STRING AnsiString;
NTSTATUS StatusR;
CHAR szFileName[MAX_PATH];
FileName.Buffer = lpFileName;
FileName.Length = wcslen(lpFileName)*sizeof(WCHAR);
FileName.MaximumLength = FileName.Length + sizeof(WCHAR);
AnsiString.Buffer = szFileName;
AnsiString.MaximumLength = MAX_PATH;
StatusR = RtlUnicodeStringToAnsiString(&AnsiString, &FileName, FALSE);
if (!NT_SUCCESS(StatusR))
return LZERROR_GLOBALLOC;
return(LZOpenFileA(szFileName, lpReOpenBuf, wStyle));
}
/*
** LONG APIENTRY LZSeek(int oLZFile, long lSeekTo, int nMode);
**
** Works like _llseek(), but in the expanded image of a compressed file,
** without expanding the compressed file to disk.
**
** Arguments: oLZFile - source LZFile struct identifier or DOS file handle
** lSeekTo - number of bytes past nMode target to seek
** nMode - seek mode as in _llseek()
**
** Returns: LONG - Offset of the seek target if successful. One of the
** LZERROR_ codes if unsuccessful.
**
** Globals: none
*/
LONG APIENTRY
LZSeek(
INT oLZFile,
LONG lSeekTo,
INT nMode)
{
HANDLE hSourceStruct; // handle to LZFile struct
LZFile *lpLZ; // pointer to LZFile struct
LONG lExpSeekTarget; // target seek offset
// Check input LZFile struct indentifier / DOS file handle.
if (oLZFile < 0 || oLZFile >= LZ_TABLE_BIAS + MAX_LZFILES)
return(LZERROR_BADINHANDLE);
// We were passed a regular DOS file handle, so just do an _llseek() on it.
if (oLZFile < LZ_TABLE_BIAS)
return(FSEEK(ConvertDosFHToWin32(oLZFile), lSeekTo, nMode));
// We're dealing with a compressed file. Get the associated LZFile struct.
hSourceStruct = rghLZFileTable[oLZFile - LZ_TABLE_BIAS];
if ((lpLZ = (LZFile *)GlobalLock(hSourceStruct)) == NULL)
return(LZERROR_GLOBLOCK);
// Figure out what our seek target is.
if (nMode == SEEK_SET)
lExpSeekTarget = 0L;
else if (nMode == SEEK_CUR)
lExpSeekTarget = lpLZ->lCurSeekPos;
else if (nMode == SEEK_END)
lExpSeekTarget = (LONG)lpLZ->cbulUncompSize;
else
{
GlobalUnlock(hSourceStruct);
return(LZERROR_BADVALUE);
}
// Add bias.
lExpSeekTarget += lSeekTo;
// Make sure the desired expanded file position is in the expanded file
// bounds. It's only an error to seek before the beginning of the file;
// it's not an error to seek after the end of the file, as in _llseek().
if (lExpSeekTarget < 0L)
{
GlobalUnlock(hSourceStruct);
return(LZERROR_BADVALUE);
}
// Seek target is ok. Set the file pointer for the expanded file image.
lpLZ->lCurSeekPos = lExpSeekTarget;
GlobalUnlock(hSourceStruct);
// Return the offset of the seek target.
return(lExpSeekTarget);
}
/*
** int APIENTRY LZRead(int oLZFile, LPSTR lpBuf, int nCount);
**
** Works like _lread(), but in the expanded image of a compressed file,
** without expanding the compressed file to disk.
**
** Arguments: oLZFile - source LZFile struct identifier or DOS file handle
** lpBuf - pointer to destination buffer for bytes read
** nCount - number of bytes to read
**
** Returns: int - Number of bytes copied to destination buffer if
** successful. One of the LZERROR_ codes if unsuccessful.
**
** Globals: none
*/
INT APIENTRY LZRead(INT oLZFile, LPSTR lpBuf, INT nCount)
{
INT f;
HANDLE hSourceStruct; // handle to LZFile struct
LZFile *lpLZ; // pointer to LZFile struct
INT cbWritten = 0, // total number of bytes copied to
// destination buffer
cbCopied, // number of bytes copied to destination
// buffer during each read iteration
iCurReadPos, // current read offset in expanded buffer
nNumExpBufBytes; // number of bytes in expanded data buffer
LONG lNextDecodeTarget, // expanded file image read target for decoding
lStartCopyOffset, // expanded file buffer offset where we should
// start copying to destination buffer (cast
// to iCurReadPos when this start position
// is actually in the buffer)
lNextExpEndOffset; // expanded file offset of the start of the
// next desired block of expanded data
BOOL bRestartDecoding; // flag indicating whether or not decoding
// needs to be restarted, set to TRUE when
// the current seek position is smaller than
// the offset of the beginning of the
// expanded file buffer
BYTE *lpbyteBuf; // byte pointer version of lpBuf
LONG lExpBufStart;
LONG lExpBufEnd;
PLZINFO pLZI;
// Check input LZFile struct indentifier / DOS file handle.
if (oLZFile < 0 || oLZFile >= LZ_TABLE_BIAS + MAX_LZFILES)
return(LZERROR_BADINHANDLE);
// Can't read a negative number of bytes.
if (nCount < 0)
return(LZERROR_BADVALUE);
// We were passed a regular DOS file handle, so just do an _lread() on it.
if (oLZFile < LZ_TABLE_BIAS)
return(FREAD(ConvertDosFHToWin32(oLZFile), lpBuf, nCount));
// We're dealing with a compressed file. Get the associated LZFile struct.
hSourceStruct = rghLZFileTable[oLZFile - LZ_TABLE_BIAS];
if ((lpLZ = (LZFile *)GlobalLock(hSourceStruct)) == NULL)
return(LZERROR_GLOBLOCK);
if (!(pLZI = lpLZ->pLZI)) {
// Initialize buffers
lpLZ->pLZI = InitGlobalBuffers(EXP_BUF_LEN, MAX_RING_BUF_LEN, IN_BUF_LEN + 1);
if (!(pLZI = lpLZ->pLZI)) {
return(LZERROR_GLOBALLOC);
}
ResetBuffers();
}
lExpBufStart = pLZI->cblOutSize - (LONG)(pLZI->pbyteOutBuf - pLZI->rgbyteOutBuf);
lExpBufEnd = (LONG)(pLZI->pbyteOutBufEnd - pLZI->rgbyteOutBuf);
// Do we need to restart decoding?
if (! (lpLZ->wFlags & LZF_INITIALIZED))
{
lpLZ->wFlags |= LZF_INITIALIZED;
bRestartDecoding = TRUE;
}
else if (lpLZ->lCurSeekPos < lExpBufStart)
bRestartDecoding = TRUE;
else
bRestartDecoding = FALSE;
// Set up byte pointer version of lpBuf.
lpbyteBuf = lpBuf;
// Copy bytes until buffer is filled or EOF in expanded file image is
// reached.
while (nCount > 0 && lpLZ->lCurSeekPos < (LONG)lpLZ->cbulUncompSize)
{
/* How many expanded data bytes are in the expanded data buffer?
* (pbyteOutBuf points AFTER the last valid byte in rgbyteOutBuf[].)
*/
nNumExpBufBytes = (INT)(pLZI->pbyteOutBuf - pLZI->rgbyteOutBuf);
/* Is the start of the desired expanded data currently in the bounds of
* the expanded data buffer?
*/
lStartCopyOffset = lpLZ->lCurSeekPos - lExpBufStart;
if (lStartCopyOffset < lExpBufEnd)
/* It's ok to set iCurReadPos to a negative value here, since we
* will only use expanded data from the expanded data buffer if
* iCurReadPos is non-negative.
*/
iCurReadPos = (INT)lStartCopyOffset;
else
iCurReadPos = -1;
/* Now, if iCurReadPos > 0, some of the expanded data in the expanded
* data buffer should be copied to the caller's buffer. If not, we
* need to continue expanding or restart expanding.
*/
if (iCurReadPos >= 0)
{
/* Copy available expanded data from expanded data buffer. */
for (cbCopied = 0;
iCurReadPos < nNumExpBufBytes && nCount > 0;
cbCopied++, nCount--)
*lpbyteBuf++ = pLZI->rgbyteOutBuf[iCurReadPos++];
// Update expanded file pointer.
lpLZ->lCurSeekPos += (LONG)cbCopied;
// Keep track of bytes written to buffer.
cbWritten += cbCopied;
}
/* Expand more data, restarting the expansion process first if
* necessary.
*/
if (nCount > 0 && lpLZ->lCurSeekPos < (LONG)lpLZ->cbulUncompSize)
{
/* If we get here, we've copied all the available expanded data out
* of rgbyteOutBuf[], through pbyteOutBuf, and we need to expand
* more data.
*/
/* Where is the end of the next desired expanded data block? */
if (bRestartDecoding)
{
/* Seek back to start of target data, allowing for buffer
* overflow.
*/
lNextExpEndOffset = lpLZ->lCurSeekPos - MAX_OVERRUN;
/* Don't try to read before offset 0! */
if (lNextExpEndOffset < 0)
lNextExpEndOffset = 0;
}
else
/* Continue decoding. */
lNextExpEndOffset = lExpBufStart
+ (LONG)nNumExpBufBytes
+ lExpBufEnd
- MAX_OVERRUN;
/* How much farther should we expand? The target decoding offset
* should be the smallest expanded file offset of the following:
*
* 1) the last byte in the largest expanded data block that will
* safely fit in the expanded data buffer, while guaranteeing
* that the start of this block is also in the expanded data
* buffer
* 2) the last requested expanded data byte
* 3) the last byte in the expanded file
*/
lNextDecodeTarget = MIN(lNextExpEndOffset,
MIN(lpLZ->lCurSeekPos + (LONG)nCount,
(LONG)lpLZ->cbulUncompSize - 1L));
// Reset expanded data buffer to empty state.
pLZI->pbyteOutBuf = pLZI->rgbyteOutBuf;
// Refill rgbyteOutBuf[] with expanded data.
switch (lpLZ->byteAlgorithm)
{
case ALG_FIRST:
f = LZDecode(lpLZ->dosh, NO_DOSH, lNextDecodeTarget,
bRestartDecoding, TRUE, pLZI);
break;
default:
f = LZERROR_UNKNOWNALG;
break;
}
// Did the decoding go ok?
if (f != TRUE)
{
// Uh oh. Something went wrong.
GlobalUnlock(hSourceStruct);
return(f);
}
/* Now how many expanded data bytes are in the expanded data buffer?
* (pbyteOutBuf points AFTER the last valid byte in rgbyteOutBuf[].)
*/
#if DEBUG
printf("pbyteOutBuf: 0x%x, rgbyteOutBuf: 0x%x \n", pLZI->pbyteOutBuf, pLZI->rgbyteOutBuf);
#endif
nNumExpBufBytes = (INT)(pLZI->pbyteOutBuf - pLZI->rgbyteOutBuf);
/* Check to make sure we actually read some bytes. */
if (nNumExpBufBytes <= 0)
{
GlobalUnlock(hSourceStruct);
return(LZERROR_READ);
}
/* What is the offset of the start of the expanded data buffer in
* the expanded file image?
*/
lExpBufStart = pLZI->cblOutSize - (LONG)nNumExpBufBytes;
/* Did LZDecode() satisfy the read request, or did the compressed
* file end prematurely?
*/
if (pLZI->cblOutSize < lNextDecodeTarget)
{
/* Oh oh. lNextDecodeTarget cannot exceed the expanded file
* bounds, so the compressed file must have ended prematurely.
*/
GlobalUnlock(hSourceStruct);
return(LZERROR_READ);
}
// Reset flag so we continue decoding where we left off.
bRestartDecoding = FALSE;
}
}
GlobalUnlock(hSourceStruct);
// Return number of bytes copied to destination buffer.
return(cbWritten);
}
//
// VOID LZCloseFile(INT oLZFile);
//
// Close a file and free the associated LZFile struct.
//
// Arguments: oLZFile - source LZFile struct identifier or WIN32 file handle
//
// Returns: VOID
//
// Globals: rghLZFileTable[] entry cleared.
//
VOID
LZCloseFile(
INT oLZFile)
{
HANDLE hSourceStruct; // handle to LZFile struct
LZFile *lpLZ; // pointer to LZFile struct
// Check input LZFile struct indentifier / DOS file handle.
if (oLZFile < 0 || oLZFile >= LZ_TABLE_BIAS + MAX_LZFILES)
return;
// We were passed a regular DOS file handle, so just close it.
if (oLZFile < LZ_TABLE_BIAS) {
CloseHandle((HANDLE)IntToPtr(ConvertDosFHToWin32(oLZFile)));
// also need to clean out the file array entry
fhWin32File[oLZFile] = 0;
return;
}
// We're dealing with a compressed file. Get the associated LZFile struct.
hSourceStruct = rghLZFileTable[oLZFile - LZ_TABLE_BIAS];
// Clear rghLZFIleTable[] entry.
rghLZFileTable[oLZFile - LZ_TABLE_BIAS] = NULL;
// Close the file and free the associated LZFile struct.
if ((lpLZ = (LZFile *)GlobalLock(hSourceStruct)) != NULL)
{
CloseHandle((HANDLE)IntToPtr(lpLZ->dosh));
if (lpLZ->pLZI) {
FreeGlobalBuffers(lpLZ->pLZI);
}
GlobalUnlock(hSourceStruct);
GlobalFree(hSourceStruct);
}
return;
}
/*
** VOID APIENTRY LZClose(int oLZFile);
**
** Close a file and free the associated LZFile struct.
**
** Arguments: oLZFile - source LZFile struct identifier or DOS file handle
**
** Returns: VOID
**
** Globals: rghLZFileTable[] entry cleared.
*/
VOID APIENTRY LZClose(INT oLZFile)
{
HANDLE hSourceStruct; // handle to LZFile struct
LZFile *lpLZ; // pointer to LZFile struct
// Check input LZFile struct indentifier / DOS file handle.
if (oLZFile < 0 || oLZFile >= LZ_TABLE_BIAS + MAX_LZFILES)
return;
// We were passed a regular DOS file handle, so just close it.
if (oLZFile < LZ_TABLE_BIAS)
{
FCLOSE(ConvertDosFHToWin32(oLZFile));
/* also need to clean out the file array entry */
fhWin32File[oLZFile] = 0;
return;
}
// We're dealing with a compressed file. Get the associated LZFile struct.
hSourceStruct = rghLZFileTable[oLZFile - LZ_TABLE_BIAS];
// Clear rghLZFIleTable[] entry.
rghLZFileTable[oLZFile - LZ_TABLE_BIAS] = NULL;
// Close the file and free the associated LZFile struct.
if ((lpLZ = (LZFile *)GlobalLock(hSourceStruct)) != NULL)
{
FCLOSE(lpLZ->dosh);
if (lpLZ->pLZI) {
FreeGlobalBuffers(lpLZ->pLZI);
}
GlobalUnlock(hSourceStruct);
GlobalFree(hSourceStruct);
}
return;
}
/* WIN32 MODS */
INT ConvertWin32FHToDos(HFILE DoshSource)
{
INT x;
if (!fCSInit) {
if (!NT_SUCCESS(RtlInitializeCriticalSection(&semTable))) {
return LZERROR_GLOBALLOC;
}
fCSInit = TRUE;
}
/* here we are given an NT file handle, need save this into
* fhWin32File[], test for overflow, also need see
* if there is a free slot in the array */
/* If error, return greater than MAX_LZFILES */
RtlEnterCriticalSection(&semTable);
/* walk array, looking for a free slot (free slot = 0) */
for(x = 0; x < MAX_LZFILES; x++){
if(fhWin32File[x] == 0)
break;
}
if(x < MAX_LZFILES){
/* no overflow, save into array*/
fhWin32File[x] = DoshSource;
}
else{
x = LZERROR_GLOBALLOC;
}
RtlLeaveCriticalSection(&semTable);
return(x);
}
HFILE ConvertDosFHToWin32(INT DoshSource)
{
/* here, we are given the pseudo Dos File Handle, need convert to
* real file handle, for use by API.
*/
if (DoshSource >= MAX_LZFILES || DoshSource < 0 ||
fhWin32File[DoshSource] == 0) {
return (HFILE)DoshSource;
}
else{
return(fhWin32File[DoshSource]);
}
}