/* ** 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 #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]); } }