Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

981 lines
30 KiB

  1. /*
  2. ** winlzexp.c - Windows LZExpand library routines for manipulating compressed
  3. ** files.
  4. **
  5. ** Author: DavidDi
  6. */
  7. /*
  8. ** Notes:
  9. ** -----
  10. **
  11. ** The LZInit() function returns either DOS handles or LZFile struct
  12. ** identifiers of some kind, depending upon how it is called. The LZ
  13. ** functions LZSeek(), LZRead(), and LZClose() needed some way to
  14. ** differentiate between DOS file handles and the LZFile struct identifiers.
  15. ** As the functions stand now, they use DOS file handles as themselves, and
  16. ** table offsets as LZFile identifiers. The table offsets are incremented by
  17. ** some base value, LZ_TABLE_BIAS, in order to push their values past all
  18. ** possible DOS file handle values. The table offsets (- LZ_TABLE_BIAS) are
  19. ** used as indices in rghLZFileTable[] to retrieve a global handle to an
  20. ** LZFile struct. The table of global handles is allocated statically from
  21. ** the DLL's data segment. The LZFile struct's are allocated from global
  22. ** heap space and are moveable. This scheme might also be implemented as a
  23. ** linked list of global handles.
  24. **
  25. ** Now the resulting benefit from this scheme is that DOS file handles and
  26. ** LZFile struct identifiers can be differentiated, since DOS file handles
  27. ** are always < LZ_TABLE_BIAS, and LZFile struct identifiers are always
  28. ** >= LZ_TABLE_BIAS. This dichotomy may be used in macros, like the sample
  29. ** ones provided in lzexpand.h, to select the appropriate function to call
  30. ** (e.g., LZSeek() or _llseek()) in order to avoid the overhead of an extra
  31. ** function call for uncompressed files. LZSeek(), LZRead(), and LZClose()
  32. ** are, however, "smart" enough to figure out whether they are dealing with
  33. ** DOS file handles or table offsets, and take action appropriately. As an
  34. ** extreme example, LZOpenFile(), LZSeek(), LZRead, and LZClose() can be used
  35. ** as replacements for OpenFile(), _llseek(), _lread(), and _lclose. In this
  36. ** case, the program using the DLL functions could call them without ever
  37. ** caring whether the files it was reading were LZ compressed or not.
  38. */
  39. /* WIN32 MODS
  40. ** Since the above is a DOS only hack, I have to change the logic for
  41. ** for the 0-255 file handle deal'o. The original code, tests greater than
  42. ** LZ_TABLE_BIAS for file structures. What I will do, is convert file handles
  43. ** returned from OpenFile, to a range 0-255. Once the test is complete, I'll
  44. ** use the file handle as an offset into a 255 element array, which will
  45. ** contain the WIN32 file handle. So there will be an additional array
  46. ** fhWin32File[255], which will be allocated sequencially starting at 0.
  47. ** Unfortunately, this means everywhere the file handle is used, must be converted
  48. */
  49. // Headers
  50. ///////////
  51. #include <basedll.h>
  52. #define LZA_DLL
  53. #include "lz_common.h"
  54. #include "lz_buffers.h"
  55. #include "lz_header.h"
  56. #include "lzcommon.h"
  57. #include "lzpriv.h"
  58. #include "wchar.h"
  59. #if DEBUG
  60. #include "stdio.h"
  61. #endif
  62. // Globals
  63. ///////////
  64. // Semaphore for File Table allocation
  65. RTL_CRITICAL_SECTION semTable;
  66. BOOL fCSInit = FALSE;
  67. // table of handles to LZFile structs
  68. HANDLE rghLZFileTable[MAX_LZFILES] = {0};
  69. // next free entry in rghLZFileTable[]
  70. static INT iNextLZFileEntry = 0;
  71. HFILE fhWin32File[MAX_LZFILES] = {0};
  72. /*
  73. ** int APIENTRY LZInit(int hWin32File);
  74. **
  75. ** Sets up LZFile struct for a file that has already been opened by
  76. ** OpenFile().
  77. **
  78. ** Arguments: hWin32File - source DOS file handle
  79. **
  80. ** Returns: int - LZFile struct table offset or DOS file handle if
  81. ** successful. One of the LZERROR_ codes if unsuccessful.
  82. **
  83. ** Globals: iNextLZFile entry advanced, or returned to beginning from end.
  84. */
  85. INT APIENTRY LZInit(INT hWin32File)
  86. {
  87. HANDLE hLZFile; // handle to new LZFile struct
  88. LZFile *lpLZ; // pointer to new LZFile struct
  89. FH FHComp; // header info structure from input file
  90. BOOL bHdr; // holds GetHdr() return value
  91. INT iTableIndex, // holds rghLZFileTable[] slot to be filled by
  92. // new LZFile struct handle
  93. iStartEntry; // original value of iNextLZFileEntry
  94. LONG cblInSize = 0;
  95. INT nRet;
  96. if (!fCSInit) {
  97. if (!NT_SUCCESS(RtlInitializeCriticalSection(&semTable))) {
  98. return LZERROR_GLOBALLOC;
  99. }
  100. fCSInit = TRUE;
  101. }
  102. // Did the read succeed?
  103. if ((bHdr = GetHdr((FH *)&FHComp, hWin32File, &cblInSize)) != TRUE
  104. && cblInSize >= (LONG)HEADER_LEN) {
  105. return(LZERROR_BADINHANDLE);
  106. }
  107. // Check for uncompressed input file.
  108. if (bHdr != TRUE || IsCompressed(& FHComp) != TRUE)
  109. {
  110. // This is an uncompressed file - rewind it.
  111. if (FSEEK(hWin32File, 0L, SEEK_SET) != 0L) {
  112. return(LZERROR_BADINHANDLE);
  113. }
  114. else {
  115. // And return DOS file handle.
  116. return(ConvertWin32FHToDos(hWin32File));
  117. }
  118. }
  119. // Check compression algorithm used.
  120. if (RecognizeCompAlg(FHComp.byteAlgorithm) != TRUE) {
  121. return(LZERROR_UNKNOWNALG);
  122. }
  123. // Find next free rghLZFileTable[] entry. N.b., we depend upon LZClose()
  124. // to free unused entries up.
  125. RtlEnterCriticalSection(&semTable);
  126. iStartEntry = iNextLZFileEntry;
  127. while (rghLZFileTable[iNextLZFileEntry] != NULL)
  128. {
  129. if (++iNextLZFileEntry >= MAX_LZFILES)
  130. // Return to beginning of table.
  131. iNextLZFileEntry = 0;
  132. if (iNextLZFileEntry == iStartEntry) {
  133. // We've gone full circle through rghLZFileTable[].
  134. // It's full, so bail out.
  135. nRet = LZERROR_GLOBALLOC;
  136. goto LZInitExit;
  137. }
  138. }
  139. // Keep track of the rghLZFileTable() slot to be filled by a handle to the
  140. // new LZFile struct.
  141. iTableIndex = iNextLZFileEntry;
  142. // Allocate global storage for the new LZFile struct, initializing all
  143. // fields to 0.
  144. hLZFile = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (DWORD)sizeof(LZFile));
  145. if (!hLZFile) {
  146. nRet = LZERROR_GLOBALLOC;
  147. goto LZInitExit;
  148. }
  149. // Lock that baby up.
  150. if ((lpLZ = (LZFile *)GlobalLock(hLZFile)) == NULL)
  151. {
  152. GlobalFree(hLZFile);
  153. nRet =LZERROR_GLOBLOCK;
  154. goto LZInitExit;
  155. }
  156. // Initialize the new LZFile struct's general information fields.
  157. lpLZ->dosh = hWin32File;
  158. lpLZ->byteAlgorithm = FHComp.byteAlgorithm;
  159. lpLZ->wFlags = 0;
  160. lpLZ->cbulUncompSize = FHComp.cbulUncompSize;
  161. lpLZ->cbulCompSize = FHComp.cbulCompSize;
  162. lpLZ->lCurSeekPos = 0L;
  163. // LZRead/LZSeeks expansion data is kept on a per file basis
  164. lpLZ->pLZI = NULL;
  165. // Enter new handle in table of handles.
  166. rghLZFileTable[iTableIndex] = hLZFile;
  167. /* WIN32 NOTE, dont need convert below, as forces a non file handle
  168. * to the API.
  169. */
  170. GlobalUnlock(hLZFile);
  171. // Advance to next free entry.
  172. if (++iNextLZFileEntry >= MAX_LZFILES)
  173. iNextLZFileEntry = 0;
  174. nRet = LZ_TABLE_BIAS + iTableIndex;
  175. LZInitExit:
  176. RtlLeaveCriticalSection(&semTable);
  177. // Return rghLZFileTable[] offset of the new LZFile struct's handle's
  178. // entry + the table bias.
  179. return(nRet);
  180. }
  181. /*
  182. ** int APIENTRY GetExpandedNameA(LPSTR lpszSource, LPSTR lpszBuffer);
  183. **
  184. ** Looks in the header of a compressed file to find its original expanded
  185. ** name.
  186. **
  187. ** Arguments: lpszSource - name of input file
  188. ** lpszBuffer - pointer to a buffer that will be filled in with
  189. ** the expanded name of the compressed source file
  190. **
  191. ** Returns: int - TRUE if successful. One of the LZERROR_ codes if
  192. ** unsuccessful.
  193. **
  194. ** Globals: none
  195. */
  196. INT APIENTRY GetExpandedNameA(LPSTR lpszSource, LPSTR lpszBuffer)
  197. {
  198. INT doshSource, // source DOS file handle
  199. bHdr; // holds GetHdr() return value
  200. FH FHComp; // header info structure from input file
  201. OFSTRUCT ofOpenBuf; // source struct for OpenFile() call
  202. LONG cblInSize = 0;
  203. // Try to open the source file.
  204. if ((doshSource = (HFILE)MOpenFile(lpszSource, (LPOFSTRUCT)(& ofOpenBuf), OF_READ))
  205. == -1)
  206. return(LZERROR_BADVALUE);
  207. // Get the compressed file header.
  208. if ((bHdr = GetHdr((FH *)&FHComp, doshSource, &cblInSize)) != TRUE
  209. && cblInSize >= (LONG)HEADER_LEN)
  210. {
  211. FCLOSE(doshSource);
  212. return(LZERROR_BADVALUE);
  213. }
  214. // Close source file.
  215. FCLOSE(doshSource);
  216. // Return expanded name same as source name for uncompressed files.
  217. STRCPY(lpszBuffer, lpszSource);
  218. // Check for compressed input file.
  219. if (bHdr == TRUE && IsCompressed(& FHComp) == TRUE)
  220. MakeExpandedName(lpszBuffer, FHComp.byteExtensionChar);
  221. return(TRUE);
  222. }
  223. /*
  224. ** int APIENTRY GetExpandedNameW(LPSTR lpszSource, LPSTR lpszBuffer);
  225. **
  226. ** Wide Character version of GetExpandedName. Converts the filename to
  227. ** the ANSI Character set and calls the ANSI version.
  228. **
  229. */
  230. INT APIENTRY GetExpandedNameW(LPWSTR lpszSource, LPWSTR lpszBuffer)
  231. {
  232. UNICODE_STRING TempW;
  233. ANSI_STRING TempA;
  234. NTSTATUS Status;
  235. NTSTATUS StatusR;
  236. CHAR szBuffer[MAX_PATH];
  237. TempW.Buffer = lpszSource;
  238. TempW.Length = wcslen(lpszSource)*sizeof(WCHAR);
  239. TempW.MaximumLength = TempW.Length + sizeof(WCHAR);
  240. TempA.Buffer = szBuffer;
  241. TempA.MaximumLength = MAX_PATH;
  242. StatusR = RtlUnicodeStringToAnsiString(&TempA, &TempW, FALSE);
  243. if (!NT_SUCCESS(StatusR))
  244. return LZERROR_GLOBALLOC;
  245. Status = GetExpandedNameA(szBuffer, (LPSTR)lpszBuffer);
  246. if (Status != -1) {
  247. strcpy(szBuffer, (LPSTR)lpszBuffer);
  248. TempA.Length = (USHORT) strlen(szBuffer);
  249. TempA.MaximumLength = TempA.Length+sizeof(CHAR);
  250. TempW.Buffer = lpszBuffer;
  251. TempW.MaximumLength = MAX_PATH;
  252. StatusR = RtlAnsiStringToUnicodeString(&TempW, &TempA, FALSE);
  253. if (!NT_SUCCESS(StatusR))
  254. return LZERROR_GLOBALLOC;
  255. }
  256. return Status;
  257. }
  258. //
  259. // INT LZCreateFileW(LPCWSTR lpFileName, DWORD fdwAccess)
  260. //
  261. // Opens a file (using CreateFile) and sets up an LZFile struct for
  262. // expanding it.
  263. //
  264. // Arguments: lpFileName - name of input file
  265. // fdwAccess - CreateFile access type - (e.g. GENERIC_READ)
  266. // fdwShareMode - Share mode - (e.g. FILE_SHARE_READ)
  267. // fdwCreate - Action to be taken - (e.g. OPEN_EXISTING)
  268. //
  269. // Returns: INT - LZFile struct table offset or WIN32 file HANDLE if
  270. // successful. One of the LZERROR_ codes if unsuccessful.
  271. //
  272. INT
  273. LZCreateFileW(
  274. LPWSTR lpFileName,
  275. DWORD fdwAccess,
  276. DWORD fdwShareMode,
  277. DWORD fdwCreate,
  278. LPWSTR lpCompressedName)
  279. {
  280. HANDLE hWin32; // WIN32 file HANDLE returned from CreateFileW()
  281. INT lzh; // LZ File struct ID returned from LZInit()
  282. static WCHAR pszCompName[MAX_PATH]; // buffer for compressed name
  283. lstrcpyW((LPWSTR)pszCompName, lpFileName);
  284. // Just for Vlad, only try to open the compressed version of the original
  285. // file name if we can't find the original file. All other errors get
  286. // returned immediately.
  287. hWin32 = CreateFileW(pszCompName, fdwAccess, fdwShareMode, NULL, fdwCreate,
  288. FILE_ATTRIBUTE_NORMAL, NULL);
  289. if (hWin32 == INVALID_HANDLE_VALUE) {
  290. DWORD dwErr = GetLastError();
  291. if (dwErr == ERROR_FILE_NOT_FOUND) {
  292. // Let's try to open the file of the corresponding compressed name.
  293. MakeCompressedNameW((LPWSTR)pszCompName);
  294. hWin32 = CreateFileW(pszCompName, fdwAccess, fdwShareMode,
  295. NULL, fdwCreate, FILE_ATTRIBUTE_NORMAL, NULL);
  296. }
  297. }
  298. // Error opening file?
  299. if (hWin32 == INVALID_HANDLE_VALUE) {
  300. return(LZERROR_BADINHANDLE);
  301. }
  302. // Don't call LZinit() on files opened in other read only mode
  303. if (fdwCreate != OPEN_EXISTING) {
  304. lzh = ConvertWin32FHToDos((HFILE)((DWORD_PTR)hWin32));
  305. if (lzh == LZERROR_GLOBALLOC) {
  306. CloseHandle(hWin32);
  307. }
  308. return(lzh);
  309. }
  310. // File has been opened with read-only action - call LZInit() to detect
  311. // whether or not it's an LZ file, and to create structures for expansion
  312. // if it is an LZ file.
  313. lzh = LZInit((INT)((DWORD_PTR)hWin32));
  314. // Close DOS file handle if LZInit() is unsuccessful.
  315. if (lzh < 0)
  316. CloseHandle(hWin32);
  317. // Pass real file name to caller
  318. //
  319. // we believe the caller have enough buffer.
  320. //
  321. if( lpCompressedName != NULL )
  322. lstrcpyW(lpCompressedName,pszCompName);
  323. // Return LZ struct ID or LZERROR_ code.
  324. return(lzh);
  325. }
  326. /*
  327. ** int APIENTRY LZOpenFileA(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuf,
  328. ** WORD wStyle);
  329. **
  330. ** Opens a file and sets up an LZFile struct for expanding it.
  331. **
  332. ** Arguments: lpFileName - name of input file
  333. ** lpReOpenBuf - pointer to LPOFSTRUCT to be used by OpenFile()
  334. ** wStyle - OpenFile() action to take
  335. **
  336. ** Returns: int - LZFile struct table offset or DOS file handle if
  337. ** successful. One of the LZERROR_ codes if unsuccessful.
  338. **
  339. ** Globals: none
  340. */
  341. INT APIENTRY LZOpenFileA(LPSTR lpFileName, LPOFSTRUCT lpReOpenBuf, WORD wStyle)
  342. {
  343. INT dosh, // DOS file handle returned from OpenFile()
  344. lzh; // LZ File struct ID returned from LZInit()
  345. CHAR pszCompName[MAX_PATH]; // buffer for compressed name
  346. STRCPY((LPSTR)pszCompName, lpFileName);
  347. // Just for Vlad, only try to open the compressed version of the original
  348. // file name if we can't find the original file. All other errors get
  349. // returned immediately.
  350. if ((dosh = OpenFile(pszCompName, lpReOpenBuf, wStyle)) == -1 &&
  351. lpReOpenBuf->nErrCode == DEE_FILENOTFOUND)
  352. {
  353. // Let's try to open the file of the corresponding compressed name.
  354. MakeCompressedName(pszCompName);
  355. dosh = (HFILE) MOpenFile((LPSTR)pszCompName, lpReOpenBuf, wStyle);
  356. }
  357. // Error opening file?
  358. if (dosh == -1)
  359. return(LZERROR_BADINHANDLE);
  360. // Don't call LZinit() on files opened in other than O_RDONLY mode.
  361. // Ignore the SHARE bits.
  362. if ((wStyle & STYLE_MASK) != OF_READ) {
  363. lzh = ConvertWin32FHToDos(dosh);
  364. if (lzh == LZERROR_GLOBALLOC) {
  365. FCLOSE(dosh);
  366. }
  367. return(lzh);
  368. }
  369. // File has been opened with OF_READ style - call LZInit() to detect
  370. // whether or not it's an LZ file, and to create structures for expansion
  371. // if it is an LZ file.
  372. lzh = LZInit(dosh);
  373. // Close DOS file handle if LZInit() is unsuccessful.
  374. if (lzh < 0)
  375. FCLOSE(dosh);
  376. // Return LZ struct ID or LZERROR_ code.
  377. return(lzh);
  378. }
  379. /*
  380. ** int APIENTRY LZOpenFileW(LPCWSTR lpFileName, LPOFSTRUCT lpReOpenBuf,
  381. ** WORD wStyle);
  382. **
  383. ** Wide Character version of LZOpenFile. Converts the filename to
  384. ** the ANSI Character set and calls the ANSI version.
  385. **
  386. */
  387. INT APIENTRY LZOpenFileW(LPWSTR lpFileName, LPOFSTRUCT lpReOpenBuf, WORD wStyle)
  388. {
  389. UNICODE_STRING FileName;
  390. ANSI_STRING AnsiString;
  391. NTSTATUS StatusR;
  392. CHAR szFileName[MAX_PATH];
  393. FileName.Buffer = lpFileName;
  394. FileName.Length = wcslen(lpFileName)*sizeof(WCHAR);
  395. FileName.MaximumLength = FileName.Length + sizeof(WCHAR);
  396. AnsiString.Buffer = szFileName;
  397. AnsiString.MaximumLength = MAX_PATH;
  398. StatusR = RtlUnicodeStringToAnsiString(&AnsiString, &FileName, FALSE);
  399. if (!NT_SUCCESS(StatusR))
  400. return LZERROR_GLOBALLOC;
  401. return(LZOpenFileA(szFileName, lpReOpenBuf, wStyle));
  402. }
  403. /*
  404. ** LONG APIENTRY LZSeek(int oLZFile, long lSeekTo, int nMode);
  405. **
  406. ** Works like _llseek(), but in the expanded image of a compressed file,
  407. ** without expanding the compressed file to disk.
  408. **
  409. ** Arguments: oLZFile - source LZFile struct identifier or DOS file handle
  410. ** lSeekTo - number of bytes past nMode target to seek
  411. ** nMode - seek mode as in _llseek()
  412. **
  413. ** Returns: LONG - Offset of the seek target if successful. One of the
  414. ** LZERROR_ codes if unsuccessful.
  415. **
  416. ** Globals: none
  417. */
  418. LONG APIENTRY
  419. LZSeek(
  420. INT oLZFile,
  421. LONG lSeekTo,
  422. INT nMode)
  423. {
  424. HANDLE hSourceStruct; // handle to LZFile struct
  425. LZFile *lpLZ; // pointer to LZFile struct
  426. LONG lExpSeekTarget; // target seek offset
  427. // Check input LZFile struct indentifier / DOS file handle.
  428. if (oLZFile < 0 || oLZFile >= LZ_TABLE_BIAS + MAX_LZFILES)
  429. return(LZERROR_BADINHANDLE);
  430. // We were passed a regular DOS file handle, so just do an _llseek() on it.
  431. if (oLZFile < LZ_TABLE_BIAS)
  432. return(FSEEK(ConvertDosFHToWin32(oLZFile), lSeekTo, nMode));
  433. // We're dealing with a compressed file. Get the associated LZFile struct.
  434. hSourceStruct = rghLZFileTable[oLZFile - LZ_TABLE_BIAS];
  435. if ((lpLZ = (LZFile *)GlobalLock(hSourceStruct)) == NULL)
  436. return(LZERROR_GLOBLOCK);
  437. // Figure out what our seek target is.
  438. if (nMode == SEEK_SET)
  439. lExpSeekTarget = 0L;
  440. else if (nMode == SEEK_CUR)
  441. lExpSeekTarget = lpLZ->lCurSeekPos;
  442. else if (nMode == SEEK_END)
  443. lExpSeekTarget = (LONG)lpLZ->cbulUncompSize;
  444. else
  445. {
  446. GlobalUnlock(hSourceStruct);
  447. return(LZERROR_BADVALUE);
  448. }
  449. // Add bias.
  450. lExpSeekTarget += lSeekTo;
  451. // Make sure the desired expanded file position is in the expanded file
  452. // bounds. It's only an error to seek before the beginning of the file;
  453. // it's not an error to seek after the end of the file, as in _llseek().
  454. if (lExpSeekTarget < 0L)
  455. {
  456. GlobalUnlock(hSourceStruct);
  457. return(LZERROR_BADVALUE);
  458. }
  459. // Seek target is ok. Set the file pointer for the expanded file image.
  460. lpLZ->lCurSeekPos = lExpSeekTarget;
  461. GlobalUnlock(hSourceStruct);
  462. // Return the offset of the seek target.
  463. return(lExpSeekTarget);
  464. }
  465. /*
  466. ** int APIENTRY LZRead(int oLZFile, LPSTR lpBuf, int nCount);
  467. **
  468. ** Works like _lread(), but in the expanded image of a compressed file,
  469. ** without expanding the compressed file to disk.
  470. **
  471. ** Arguments: oLZFile - source LZFile struct identifier or DOS file handle
  472. ** lpBuf - pointer to destination buffer for bytes read
  473. ** nCount - number of bytes to read
  474. **
  475. ** Returns: int - Number of bytes copied to destination buffer if
  476. ** successful. One of the LZERROR_ codes if unsuccessful.
  477. **
  478. ** Globals: none
  479. */
  480. INT APIENTRY LZRead(INT oLZFile, LPSTR lpBuf, INT nCount)
  481. {
  482. INT f;
  483. HANDLE hSourceStruct; // handle to LZFile struct
  484. LZFile *lpLZ; // pointer to LZFile struct
  485. INT cbWritten = 0, // total number of bytes copied to
  486. // destination buffer
  487. cbCopied, // number of bytes copied to destination
  488. // buffer during each read iteration
  489. iCurReadPos, // current read offset in expanded buffer
  490. nNumExpBufBytes; // number of bytes in expanded data buffer
  491. LONG lNextDecodeTarget, // expanded file image read target for decoding
  492. lStartCopyOffset, // expanded file buffer offset where we should
  493. // start copying to destination buffer (cast
  494. // to iCurReadPos when this start position
  495. // is actually in the buffer)
  496. lNextExpEndOffset; // expanded file offset of the start of the
  497. // next desired block of expanded data
  498. BOOL bRestartDecoding; // flag indicating whether or not decoding
  499. // needs to be restarted, set to TRUE when
  500. // the current seek position is smaller than
  501. // the offset of the beginning of the
  502. // expanded file buffer
  503. BYTE *lpbyteBuf; // byte pointer version of lpBuf
  504. LONG lExpBufStart;
  505. LONG lExpBufEnd;
  506. PLZINFO pLZI;
  507. // Check input LZFile struct indentifier / DOS file handle.
  508. if (oLZFile < 0 || oLZFile >= LZ_TABLE_BIAS + MAX_LZFILES)
  509. return(LZERROR_BADINHANDLE);
  510. // Can't read a negative number of bytes.
  511. if (nCount < 0)
  512. return(LZERROR_BADVALUE);
  513. // We were passed a regular DOS file handle, so just do an _lread() on it.
  514. if (oLZFile < LZ_TABLE_BIAS)
  515. return(FREAD(ConvertDosFHToWin32(oLZFile), lpBuf, nCount));
  516. // We're dealing with a compressed file. Get the associated LZFile struct.
  517. hSourceStruct = rghLZFileTable[oLZFile - LZ_TABLE_BIAS];
  518. if ((lpLZ = (LZFile *)GlobalLock(hSourceStruct)) == NULL)
  519. return(LZERROR_GLOBLOCK);
  520. if (!(pLZI = lpLZ->pLZI)) {
  521. // Initialize buffers
  522. lpLZ->pLZI = InitGlobalBuffers(EXP_BUF_LEN, MAX_RING_BUF_LEN, IN_BUF_LEN + 1);
  523. if (!(pLZI = lpLZ->pLZI)) {
  524. return(LZERROR_GLOBALLOC);
  525. }
  526. ResetBuffers();
  527. }
  528. lExpBufStart = pLZI->cblOutSize - (LONG)(pLZI->pbyteOutBuf - pLZI->rgbyteOutBuf);
  529. lExpBufEnd = (LONG)(pLZI->pbyteOutBufEnd - pLZI->rgbyteOutBuf);
  530. // Do we need to restart decoding?
  531. if (! (lpLZ->wFlags & LZF_INITIALIZED))
  532. {
  533. lpLZ->wFlags |= LZF_INITIALIZED;
  534. bRestartDecoding = TRUE;
  535. }
  536. else if (lpLZ->lCurSeekPos < lExpBufStart)
  537. bRestartDecoding = TRUE;
  538. else
  539. bRestartDecoding = FALSE;
  540. // Set up byte pointer version of lpBuf.
  541. lpbyteBuf = lpBuf;
  542. // Copy bytes until buffer is filled or EOF in expanded file image is
  543. // reached.
  544. while (nCount > 0 && lpLZ->lCurSeekPos < (LONG)lpLZ->cbulUncompSize)
  545. {
  546. /* How many expanded data bytes are in the expanded data buffer?
  547. * (pbyteOutBuf points AFTER the last valid byte in rgbyteOutBuf[].)
  548. */
  549. nNumExpBufBytes = (INT)(pLZI->pbyteOutBuf - pLZI->rgbyteOutBuf);
  550. /* Is the start of the desired expanded data currently in the bounds of
  551. * the expanded data buffer?
  552. */
  553. lStartCopyOffset = lpLZ->lCurSeekPos - lExpBufStart;
  554. if (lStartCopyOffset < lExpBufEnd)
  555. /* It's ok to set iCurReadPos to a negative value here, since we
  556. * will only use expanded data from the expanded data buffer if
  557. * iCurReadPos is non-negative.
  558. */
  559. iCurReadPos = (INT)lStartCopyOffset;
  560. else
  561. iCurReadPos = -1;
  562. /* Now, if iCurReadPos > 0, some of the expanded data in the expanded
  563. * data buffer should be copied to the caller's buffer. If not, we
  564. * need to continue expanding or restart expanding.
  565. */
  566. if (iCurReadPos >= 0)
  567. {
  568. /* Copy available expanded data from expanded data buffer. */
  569. for (cbCopied = 0;
  570. iCurReadPos < nNumExpBufBytes && nCount > 0;
  571. cbCopied++, nCount--)
  572. *lpbyteBuf++ = pLZI->rgbyteOutBuf[iCurReadPos++];
  573. // Update expanded file pointer.
  574. lpLZ->lCurSeekPos += (LONG)cbCopied;
  575. // Keep track of bytes written to buffer.
  576. cbWritten += cbCopied;
  577. }
  578. /* Expand more data, restarting the expansion process first if
  579. * necessary.
  580. */
  581. if (nCount > 0 && lpLZ->lCurSeekPos < (LONG)lpLZ->cbulUncompSize)
  582. {
  583. /* If we get here, we've copied all the available expanded data out
  584. * of rgbyteOutBuf[], through pbyteOutBuf, and we need to expand
  585. * more data.
  586. */
  587. /* Where is the end of the next desired expanded data block? */
  588. if (bRestartDecoding)
  589. {
  590. /* Seek back to start of target data, allowing for buffer
  591. * overflow.
  592. */
  593. lNextExpEndOffset = lpLZ->lCurSeekPos - MAX_OVERRUN;
  594. /* Don't try to read before offset 0! */
  595. if (lNextExpEndOffset < 0)
  596. lNextExpEndOffset = 0;
  597. }
  598. else
  599. /* Continue decoding. */
  600. lNextExpEndOffset = lExpBufStart
  601. + (LONG)nNumExpBufBytes
  602. + lExpBufEnd
  603. - MAX_OVERRUN;
  604. /* How much farther should we expand? The target decoding offset
  605. * should be the smallest expanded file offset of the following:
  606. *
  607. * 1) the last byte in the largest expanded data block that will
  608. * safely fit in the expanded data buffer, while guaranteeing
  609. * that the start of this block is also in the expanded data
  610. * buffer
  611. * 2) the last requested expanded data byte
  612. * 3) the last byte in the expanded file
  613. */
  614. lNextDecodeTarget = MIN(lNextExpEndOffset,
  615. MIN(lpLZ->lCurSeekPos + (LONG)nCount,
  616. (LONG)lpLZ->cbulUncompSize - 1L));
  617. // Reset expanded data buffer to empty state.
  618. pLZI->pbyteOutBuf = pLZI->rgbyteOutBuf;
  619. // Refill rgbyteOutBuf[] with expanded data.
  620. switch (lpLZ->byteAlgorithm)
  621. {
  622. case ALG_FIRST:
  623. f = LZDecode(lpLZ->dosh, NO_DOSH, lNextDecodeTarget,
  624. bRestartDecoding, TRUE, pLZI);
  625. break;
  626. default:
  627. f = LZERROR_UNKNOWNALG;
  628. break;
  629. }
  630. // Did the decoding go ok?
  631. if (f != TRUE)
  632. {
  633. // Uh oh. Something went wrong.
  634. GlobalUnlock(hSourceStruct);
  635. return(f);
  636. }
  637. /* Now how many expanded data bytes are in the expanded data buffer?
  638. * (pbyteOutBuf points AFTER the last valid byte in rgbyteOutBuf[].)
  639. */
  640. #if DEBUG
  641. printf("pbyteOutBuf: 0x%x, rgbyteOutBuf: 0x%x \n", pLZI->pbyteOutBuf, pLZI->rgbyteOutBuf);
  642. #endif
  643. nNumExpBufBytes = (INT)(pLZI->pbyteOutBuf - pLZI->rgbyteOutBuf);
  644. /* Check to make sure we actually read some bytes. */
  645. if (nNumExpBufBytes <= 0)
  646. {
  647. GlobalUnlock(hSourceStruct);
  648. return(LZERROR_READ);
  649. }
  650. /* What is the offset of the start of the expanded data buffer in
  651. * the expanded file image?
  652. */
  653. lExpBufStart = pLZI->cblOutSize - (LONG)nNumExpBufBytes;
  654. /* Did LZDecode() satisfy the read request, or did the compressed
  655. * file end prematurely?
  656. */
  657. if (pLZI->cblOutSize < lNextDecodeTarget)
  658. {
  659. /* Oh oh. lNextDecodeTarget cannot exceed the expanded file
  660. * bounds, so the compressed file must have ended prematurely.
  661. */
  662. GlobalUnlock(hSourceStruct);
  663. return(LZERROR_READ);
  664. }
  665. // Reset flag so we continue decoding where we left off.
  666. bRestartDecoding = FALSE;
  667. }
  668. }
  669. GlobalUnlock(hSourceStruct);
  670. // Return number of bytes copied to destination buffer.
  671. return(cbWritten);
  672. }
  673. //
  674. // VOID LZCloseFile(INT oLZFile);
  675. //
  676. // Close a file and free the associated LZFile struct.
  677. //
  678. // Arguments: oLZFile - source LZFile struct identifier or WIN32 file handle
  679. //
  680. // Returns: VOID
  681. //
  682. // Globals: rghLZFileTable[] entry cleared.
  683. //
  684. VOID
  685. LZCloseFile(
  686. INT oLZFile)
  687. {
  688. HANDLE hSourceStruct; // handle to LZFile struct
  689. LZFile *lpLZ; // pointer to LZFile struct
  690. // Check input LZFile struct indentifier / DOS file handle.
  691. if (oLZFile < 0 || oLZFile >= LZ_TABLE_BIAS + MAX_LZFILES)
  692. return;
  693. // We were passed a regular DOS file handle, so just close it.
  694. if (oLZFile < LZ_TABLE_BIAS) {
  695. CloseHandle((HANDLE)IntToPtr(ConvertDosFHToWin32(oLZFile)));
  696. // also need to clean out the file array entry
  697. fhWin32File[oLZFile] = 0;
  698. return;
  699. }
  700. // We're dealing with a compressed file. Get the associated LZFile struct.
  701. hSourceStruct = rghLZFileTable[oLZFile - LZ_TABLE_BIAS];
  702. // Clear rghLZFIleTable[] entry.
  703. rghLZFileTable[oLZFile - LZ_TABLE_BIAS] = NULL;
  704. // Close the file and free the associated LZFile struct.
  705. if ((lpLZ = (LZFile *)GlobalLock(hSourceStruct)) != NULL)
  706. {
  707. CloseHandle((HANDLE)IntToPtr(lpLZ->dosh));
  708. if (lpLZ->pLZI) {
  709. FreeGlobalBuffers(lpLZ->pLZI);
  710. }
  711. GlobalUnlock(hSourceStruct);
  712. GlobalFree(hSourceStruct);
  713. }
  714. return;
  715. }
  716. /*
  717. ** VOID APIENTRY LZClose(int oLZFile);
  718. **
  719. ** Close a file and free the associated LZFile struct.
  720. **
  721. ** Arguments: oLZFile - source LZFile struct identifier or DOS file handle
  722. **
  723. ** Returns: VOID
  724. **
  725. ** Globals: rghLZFileTable[] entry cleared.
  726. */
  727. VOID APIENTRY LZClose(INT oLZFile)
  728. {
  729. HANDLE hSourceStruct; // handle to LZFile struct
  730. LZFile *lpLZ; // pointer to LZFile struct
  731. // Check input LZFile struct indentifier / DOS file handle.
  732. if (oLZFile < 0 || oLZFile >= LZ_TABLE_BIAS + MAX_LZFILES)
  733. return;
  734. // We were passed a regular DOS file handle, so just close it.
  735. if (oLZFile < LZ_TABLE_BIAS)
  736. {
  737. FCLOSE(ConvertDosFHToWin32(oLZFile));
  738. /* also need to clean out the file array entry */
  739. fhWin32File[oLZFile] = 0;
  740. return;
  741. }
  742. // We're dealing with a compressed file. Get the associated LZFile struct.
  743. hSourceStruct = rghLZFileTable[oLZFile - LZ_TABLE_BIAS];
  744. // Clear rghLZFIleTable[] entry.
  745. rghLZFileTable[oLZFile - LZ_TABLE_BIAS] = NULL;
  746. // Close the file and free the associated LZFile struct.
  747. if ((lpLZ = (LZFile *)GlobalLock(hSourceStruct)) != NULL)
  748. {
  749. FCLOSE(lpLZ->dosh);
  750. if (lpLZ->pLZI) {
  751. FreeGlobalBuffers(lpLZ->pLZI);
  752. }
  753. GlobalUnlock(hSourceStruct);
  754. GlobalFree(hSourceStruct);
  755. }
  756. return;
  757. }
  758. /* WIN32 MODS */
  759. INT ConvertWin32FHToDos(HFILE DoshSource)
  760. {
  761. INT x;
  762. if (!fCSInit) {
  763. if (!NT_SUCCESS(RtlInitializeCriticalSection(&semTable))) {
  764. return LZERROR_GLOBALLOC;
  765. }
  766. fCSInit = TRUE;
  767. }
  768. /* here we are given an NT file handle, need save this into
  769. * fhWin32File[], test for overflow, also need see
  770. * if there is a free slot in the array */
  771. /* If error, return greater than MAX_LZFILES */
  772. RtlEnterCriticalSection(&semTable);
  773. /* walk array, looking for a free slot (free slot = 0) */
  774. for(x = 0; x < MAX_LZFILES; x++){
  775. if(fhWin32File[x] == 0)
  776. break;
  777. }
  778. if(x < MAX_LZFILES){
  779. /* no overflow, save into array*/
  780. fhWin32File[x] = DoshSource;
  781. }
  782. else{
  783. x = LZERROR_GLOBALLOC;
  784. }
  785. RtlLeaveCriticalSection(&semTable);
  786. return(x);
  787. }
  788. HFILE ConvertDosFHToWin32(INT DoshSource)
  789. {
  790. /* here, we are given the pseudo Dos File Handle, need convert to
  791. * real file handle, for use by API.
  792. */
  793. if (DoshSource >= MAX_LZFILES || DoshSource < 0 ||
  794. fhWin32File[DoshSource] == 0) {
  795. return (HFILE)DoshSource;
  796. }
  797. else{
  798. return(fhWin32File[DoshSource]);
  799. }
  800. }