Leaked source code of windows server 2003
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.

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