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.

1484 lines
45 KiB

  1. // TXINST.cpp -- Implementation for the CTransformInstance class
  2. #include "stdafx.h"
  3. // The following buffer is shared among all instances of active ITS files. All access to it
  4. // must be via a CBufferRef object.
  5. CBuffer *pBufferForCompressedData = NULL; // Used to read compressed data from next transform
  6. // The following counters are used to gather statistics about the behavior of
  7. // the decompression code. They are reported at the end of a debugging run.
  8. // BugBug: Maybe we should probably add an interface to retrieve these stats
  9. // at any time.
  10. ULONG cLZXResetDecompressor = 0;
  11. ULONG cLZXReadFromBuffer = 0;
  12. ULONG cLZXReadFromCurrentSpan = 0;
  13. ULONG cLZXReadFromOtherSpan = 0;
  14. #ifdef _DEBUG
  15. void DumpLZXCounts()
  16. {
  17. char acDebugBuff[256];
  18. wsprintf(acDebugBuff, "Count of decompressor resets: %u\n", cLZXResetDecompressor);
  19. OutputDebugString(acDebugBuff);
  20. wsprintf(acDebugBuff, "Count of reads from buffer: %u\n", cLZXReadFromBuffer);
  21. OutputDebugString(acDebugBuff);
  22. wsprintf(acDebugBuff, "Count of reads from current span: %u\n", cLZXReadFromCurrentSpan);
  23. OutputDebugString(acDebugBuff);
  24. wsprintf(acDebugBuff, "Count of abandoned spans: %u\n", cLZXReadFromOtherSpan);
  25. OutputDebugString(acDebugBuff);
  26. }
  27. #endif _DEBUG
  28. /* --- MyAlloc() ---------------------------------------------------------- */
  29. // This routine does memory allocation for the LZX libraries.
  30. MI_MEMORY __cdecl CTransformInstance::CImpITransformInstance::MyAlloc(ULONG amount)
  31. {
  32. void * pv = (void *) (New BYTE[amount]);
  33. RonM_ASSERT(pv != NULL);
  34. return(pv);
  35. }
  36. /* --- MyFree() ----------------------------------------------------------- */
  37. // This routine does memory deallocations for the LZX libraries.
  38. void __cdecl CTransformInstance::CImpITransformInstance::MyFree(MI_MEMORY pointer)
  39. {
  40. delete [] (BYTE *) pointer;
  41. }
  42. /* ---- lzx_output_callback) ------------------------------------------------*/
  43. // This routine is called by the LZX compression routines to process the
  44. // compressed data output.
  45. int __cdecl CTransformInstance::CImpITransformInstance::lzx_output_callback(
  46. void *pfol,
  47. unsigned char *compressed_data,
  48. long compressed_size,
  49. long uncompressed_size
  50. )
  51. {
  52. CImpITransformInstance* pTxInst = (CImpITransformInstance *) pfol;
  53. ULONG cbBytesWritten;
  54. ULONG cbDestBufSize = compressed_size;
  55. RonM_ASSERT(SUCCEEDED(pTxInst->m_context.hr));
  56. //We got this fixed in LZX libraries
  57. //if (uncompressed_size == 0)
  58. // return 0;
  59. RonM_ASSERT(uncompressed_size == (32*1024));
  60. ImageSpan is = pTxInst->m_ImageSpanX;
  61. //Tell next transform where to start and how much to write
  62. ULARGE_INTEGER ulWriteOffset = is.uliSize;
  63. if ( cbDestBufSize
  64. && SUCCEEDED(pTxInst->m_context.hr = pTxInst->m_pITxNextInst->WriteAt
  65. (ulWriteOffset,
  66. (LPBYTE)compressed_data,
  67. cbDestBufSize,
  68. &cbBytesWritten,
  69. &is
  70. )
  71. )
  72. )
  73. {
  74. RonM_ASSERT(cbBytesWritten == cbDestBufSize);
  75. RonM_ASSERT(cbDestBufSize
  76. == (CULINT(is.uliSize) - CULINT(pTxInst->m_ImageSpanX.uliSize)).Uli().LowPart
  77. );
  78. #if 0 //test code
  79. LPSTR szSection = "Start Section";
  80. cbBytesWritten= fwrite((LPBYTE)szSection, 1, lstrlenA(szSection), pTxInst->m_context.m_file);
  81. cbBytesWritten= fwrite((LPBYTE)compressed_data, 1, cbDestBufSize, pTxInst->m_context.m_file);
  82. RonM_ASSERT(cbBytesWritten == cbDestBufSize);
  83. #endif
  84. #ifdef TXDEBUG
  85. #ifdef _DEBUG
  86. BYTE XBuf[6];
  87. memCpy(XBuf, compressed_data, 6);
  88. int cNum = pTxInst->m_pResetData->GetRecordNum();
  89. int adr = (int)CULINT(pTxInst->m_ImageSpanX.uliSize).Ull();
  90. printf("At adr = %d Added Entry %d size = %d Blk=%x %x %x %x %x %x\n",
  91. adr,
  92. cNum, (int)compressed_size,
  93. XBuf[0], XBuf[1],XBuf[2],XBuf[3],XBuf[4], XBuf[5]);
  94. #endif
  95. #endif
  96. //add new ssync point
  97. if (SUCCEEDED(pTxInst->m_context.hr = pTxInst->m_pResetData->AddRecord
  98. (pTxInst->m_ImageSpan.uliSize,
  99. pTxInst->m_ImageSpanX.uliSize
  100. )
  101. )
  102. )
  103. {
  104. pTxInst->m_ImageSpanX.uliSize = is.uliSize;
  105. pTxInst->m_ImageSpan .uliSize = (CULINT(pTxInst->m_ImageSpan.uliSize)
  106. + uncompressed_size
  107. ).Uli();
  108. pTxInst->m_cbUnFlushedBuf -= uncompressed_size;
  109. }
  110. else pTxInst->m_context.hr = STG_E_INSUFFICIENTMEMORY;
  111. }
  112. return 0;
  113. }
  114. HRESULT CTransformInstance::Create(
  115. ITransformInstance *pITxInst,
  116. ULARGE_INTEGER cbUntransformedSize, // Untransformed size of data
  117. PXformControlData pXFCD, // Control data for this instance
  118. const CLSID *rclsidXForm, // Transform Class ID
  119. const WCHAR *pwszDataSpaceName, // Data space name for this instance
  120. ITransformServices *pXformServices, // Utility routines
  121. IKeyInstance *pKeyManager, // Interface to get enciphering keys
  122. ITransformInstance **ppTransformInstance
  123. )
  124. {
  125. CTransformInstance *pTxInst = New CTransformInstance(NULL);
  126. if (!pTxInst)
  127. return E_OUTOFMEMORY;
  128. HRESULT hr = pTxInst->m_ImpITxInst.InitTransformInstance
  129. (pITxInst, cbUntransformedSize, pXFCD,
  130. rclsidXForm, pwszDataSpaceName,
  131. pXformServices, pKeyManager
  132. );
  133. if (hr == S_OK)
  134. hr = pTxInst->QueryInterface(IID_ITransformInstance, (void **) ppTransformInstance);
  135. if (hr != S_OK)
  136. delete pTxInst;
  137. else ((IITTransformInstance *) *ppTransformInstance)->Container()->MarkSecondary();
  138. return hr;
  139. }
  140. ////////////////// non static methods ///////////////////////////
  141. CTransformInstance::CImpITransformInstance::CImpITransformInstance
  142. (CTransformInstance *pBackObj, IUnknown *punkOuter)
  143. : IITTransformInstance(pBackObj, punkOuter)
  144. {
  145. m_pITxNextInst = NULL;
  146. m_fDirty = NULL;
  147. m_pResetData = NULL;
  148. m_cbUnFlushedBuf = 0;
  149. m_cbResetSpan = 0;
  150. m_ImageSpan.uliHandle = CULINT(0).Uli();
  151. m_ImageSpan.uliSize = CULINT(0).Uli();
  152. m_ImageSpanX.uliHandle = CULINT(0).Uli();
  153. m_ImageSpanX.uliSize = CULINT(0).Uli();
  154. m_pKeyManager = NULL;
  155. m_pXformServices = NULL;
  156. m_fCompressionInitialed = FALSE;
  157. m_fInitialed = FALSE;
  158. m_fCompressionActive = FALSE;
  159. m_fDecompressionActive = FALSE;
  160. m_pStrmReconstruction = NULL;
  161. ZeroMemory((LPVOID)&m_context, sizeof(m_context));
  162. }
  163. CTransformInstance::CImpITransformInstance::~CImpITransformInstance(void)
  164. {
  165. if (m_fInitialed)
  166. DeInitTransform();
  167. if (m_pStrmReconstruction)
  168. m_pStrmReconstruction->Release();
  169. if (m_pKeyManager)
  170. m_pKeyManager->Release();
  171. if (m_pXformServices)
  172. m_pXformServices->Release();
  173. //release next transform
  174. if (m_pITxNextInst)
  175. m_pITxNextInst->Release();
  176. }
  177. HRESULT STDMETHODCALLTYPE CTransformInstance::CImpITransformInstance::SpaceSize
  178. (ULARGE_INTEGER *puliSize)
  179. {
  180. *puliSize = (CULINT(m_ImageSpan.uliSize)
  181. + CULINT(m_cbUnFlushedBuf)).Uli();
  182. return NO_ERROR;
  183. }
  184. HRESULT CTransformInstance::CImpITransformInstance::DeInitTransform()
  185. {
  186. //Save everything to disk
  187. HRESULT hr = Flush();
  188. #if 0 //test code
  189. fclose(m_context.m_file);
  190. #endif
  191. //destroy compressor and decompressor
  192. if (m_fCompressionActive && m_context.cHandle)
  193. LCIDestroyCompression(m_context.cHandle);
  194. if (m_fDecompressionActive && m_context.dHandle)
  195. LDIDestroyDecompression(m_context.dHandle);
  196. //destroy reset table
  197. if (m_pResetData)
  198. delete m_pResetData;
  199. return hr;
  200. }
  201. HRESULT CTransformInstance::CImpITransformInstance::InitTransformInstance(
  202. ITransformInstance *pITxInst,
  203. ULARGE_INTEGER cbUntransformedSize, // Untransformed size of data
  204. PXformControlData pXFCD, // Control data for this instance
  205. const CLSID *rclsidXForm, // Transform Class ID
  206. const WCHAR *pwszDataSpaceName, // Data space name for this instance
  207. ITransformServices *pXformServices, // Utility routines
  208. IKeyInstance *pKeyManager // Interface to get encipheri
  209. )
  210. {
  211. m_ControlData = *(LZX_Control_Data *) pXFCD;
  212. if ( (m_ControlData.dwVersion == LZX_Current_Version)
  213. && (pXFCD->cdwControlData != ((sizeof(LZX_Control_Data) - sizeof(UINT)))
  214. / sizeof(DWORD)
  215. )
  216. ) return STG_E_INVALIDPARAMETER;
  217. if (m_ControlData.dwLZXMagic != LZX_MAGIC || m_ControlData.dwVersion > LZX_Current_Version)
  218. return STG_E_INVALIDPARAMETER;
  219. m_rclsidXForm = rclsidXForm;
  220. m_pwszDataSpaceName = pwszDataSpaceName;
  221. m_pXformServices = pXformServices;
  222. m_pKeyManager = pKeyManager;
  223. m_pITxNextInst = pITxInst;
  224. m_pResetData = New CXResetData;
  225. if (!m_pResetData)
  226. {
  227. return STG_E_INSUFFICIENTMEMORY;
  228. }
  229. ZeroMemory(&(m_context.lcfg), sizeof(m_context.lcfg));
  230. if (m_ControlData.dwMulSecondPartition < 1)
  231. m_ControlData.dwMulSecondPartition = 1;
  232. m_context.cbMaxUncomBufSize = SOURCE_CHUNK; // m_ControlData.cbSourceSize;
  233. m_context.cbMaxComBufSize = SOURCE_CHUNK; // as an initial guess...
  234. if (m_ControlData.dwVersion == LZX_Current_Version)
  235. {
  236. m_context.lcfg.WindowSize = SOURCE_CHUNK * m_ControlData.dwMulWindowSize;
  237. m_context.lcfg.SecondPartitionSize = SOURCE_CHUNK * m_ControlData.dwMulSecondPartition;
  238. m_context.cbResetBlkSize = SOURCE_CHUNK * m_ControlData.dwMulResetBlock;
  239. }
  240. else if (m_ControlData.dwVersion == 1)
  241. {
  242. //In older version we used actual size rather than muliplier of 32K.
  243. m_context.lcfg.WindowSize = m_ControlData.dwMulWindowSize;
  244. m_context.lcfg.SecondPartitionSize = m_ControlData.dwMulSecondPartition;
  245. m_context.cbResetBlkSize = m_ControlData.dwMulResetBlock;
  246. RonM_ASSERT(m_context.lcfg.WindowSize >= (32*1024));
  247. RonM_ASSERT(m_context.lcfg.SecondPartitionSize >= (32*1024));
  248. RonM_ASSERT(m_context.cbResetBlkSize >= (32*1024));
  249. }
  250. m_ullReadCursor = -CULINT(1);
  251. m_ullResetBase = -CULINT(1);
  252. m_ullResetLimit = -CULINT(1);
  253. m_ullBuffBase = -CULINT(1);
  254. m_ullWindowBase = -CULINT(1);
  255. m_cbHistoryWindow = 0;
  256. m_pbHistoryWindow = NULL;
  257. HRESULT hr = NO_ERROR;
  258. IStorage *pstg = NULL;
  259. if (SUCCEEDED(hr = m_pXformServices->PerTransformInstanceStorage
  260. (*m_rclsidXForm, m_pwszDataSpaceName, &pstg)
  261. )
  262. )
  263. {
  264. hr = m_pResetData->InitResetTable(pstg,
  265. &m_ImageSpan.uliSize,
  266. &m_ImageSpanX.uliSize,
  267. m_context.cbMaxUncomBufSize
  268. );
  269. pstg->Release();
  270. }
  271. if (!SUCCEEDED(hr))
  272. return hr;
  273. #if 0
  274. //test code
  275. char szLogFile[100];
  276. #ifdef _DEBUG
  277. lstrcpyA(szLogFile, "c:\\dbgData");
  278. #else
  279. lstrcpyA(szLogFile, "c:\\relData");
  280. #endif
  281. m_context.m_file = fopen(szLogFile, "a" );
  282. //end test code
  283. #endif
  284. m_fInitialed = TRUE;
  285. return hr;
  286. }
  287. HRESULT CTransformInstance::CImpITransformInstance::ReconstructCompressionState
  288. (PBYTE pbWriteQueueBuffer)
  289. {
  290. // This routine reconstructs the compression state when we've opened an
  291. // ITS which already contains compressed data. When it's finished the
  292. // compression state will match the situation just after the most recent
  293. // write to the ITS file.
  294. //
  295. // There are two aspects to this reconstruction work. The first is simply
  296. // to pass data through the LZX compressor to build up the correct state
  297. // there. The other issue is reconstructing the last partial block of
  298. // write data. The pbWriteQueueBuffer points to the buffer we use for queuing
  299. // write data until we have a full block.
  300. RonM_ASSERT(m_pResetData);
  301. RonM_ASSERT(!m_fCompressionInitialed);
  302. ULONG cNumRecs = m_pResetData->GetRecordNum();
  303. // Have we got any compressed data at all?
  304. if (cNumRecs == 0)
  305. {
  306. m_fCompressionInitialed = TRUE;
  307. return S_OK;
  308. }
  309. ULARGE_INTEGER uliVOffset, uliXOffset;
  310. BOOL fLastRec;
  311. #ifdef _DEBUG
  312. BOOL fGotaRecord =
  313. #endif // _DEBUG
  314. m_pResetData->FGetRecord(cNumRecs - 1, &uliVOffset, &uliXOffset, &fLastRec);
  315. RonM_ASSERT(fGotaRecord);
  316. RonM_ASSERT(fLastRec);
  317. ULONG ulLastRec = cNumRecs - 1;
  318. ULONG cBytesToReadunX = (CULINT(m_ImageSpan .uliSize) - CULINT(uliVOffset)).Uli().LowPart;
  319. ULONG cBytesToReadX = (CULINT(m_ImageSpanX.uliSize) - CULINT(uliXOffset)).Uli().LowPart;
  320. BOOL fLastBlockIsFull = cBytesToReadunX == m_context.cbMaxUncomBufSize;
  321. // Now we need to back up to the nearest previous reset point.
  322. int N = GetMulFactor(); // Number of blocks in a reset span.
  323. int mod = ulLastRec % N;
  324. if (mod == N-1 && fLastBlockIsFull)
  325. {
  326. // The next write will start at exactly on a reset boundary.
  327. m_cbUnFlushedBuf = 0;
  328. m_cbResetSpan = 0;
  329. return NO_ERROR;
  330. }
  331. UINT cBlocksLastSpan = mod + 1;
  332. if (mod != 0)
  333. {
  334. // Reconstruction always starts at the first block in a reset span.
  335. ulLastRec -= mod;
  336. cBytesToReadunX += mod * m_context.cbMaxUncomBufSize;
  337. uliVOffset = (CULINT(uliVOffset) - CULINT(mod * m_context.cbMaxUncomBufSize)
  338. ).Uli();
  339. }
  340. RonM_ASSERT(cBytesToReadunX < m_context.cbResetBlkSize);
  341. m_cbResetSpan = cBytesToReadunX;
  342. LONG lCurRec = ulLastRec;
  343. ULONG cbBytesReadTotal = 0;
  344. HRESULT hr = NO_ERROR;
  345. ULONG cbBytesRead = 0;
  346. ULONG cbBytesToRead = 0;
  347. // The code below recreates the compression state for appending data
  348. // to this ITS file. It does this by running the last partial reset
  349. // span through the compressor. We first copy the partial span to a
  350. // temporary file. Then we remove the entries for that data from m_pResetData.
  351. // Finally we copy the span from the temp file back through the compressor.
  352. // Note that we don't write the last partial block because it will become
  353. // the content of the queued-write buffer.
  354. ILockBytes *pLKB = NULL;
  355. hr = CFSLockBytes::CreateTemp(NULL, &pLKB);
  356. if (!SUCCEEDED(hr)) return hr;
  357. hr = CStream::OpenStream(NULL, pLKB, STGM_READWRITE, &m_pStrmReconstruction);
  358. if (!SUCCEEDED(hr))
  359. {
  360. pLKB->Release(); pLKB = NULL;
  361. return hr;
  362. }
  363. // Here we're reading the last partial span into the temporary file.
  364. while (cbBytesReadTotal < cBytesToReadunX)
  365. {
  366. #ifdef _DEBUG
  367. BOOL fGotaRecord =
  368. #endif // _DEBUG
  369. m_pResetData->FGetRecord(lCurRec++, &uliVOffset, &uliXOffset, &fLastRec);
  370. RonM_ASSERT(fGotaRecord);
  371. cbBytesToRead = cBytesToReadunX - cbBytesReadTotal;
  372. if (cbBytesToRead > m_context.cbMaxUncomBufSize)
  373. cbBytesToRead = m_context.cbMaxUncomBufSize;
  374. hr = ReadAt(uliVOffset, pbWriteQueueBuffer, cbBytesToRead, &cbBytesRead, &m_ImageSpan);
  375. if (!SUCCEEDED(hr)) return hr;
  376. if (cbBytesRead != cbBytesToRead) return STG_E_READFAULT;
  377. ULONG cbWritten;
  378. hr = m_pStrmReconstruction->Write(pbWriteQueueBuffer, cbBytesToRead, &cbWritten);
  379. if (!SUCCEEDED(hr)) return hr;
  380. if (cbWritten != cbBytesToRead) return STG_E_WRITEFAULT;
  381. cbBytesReadTotal += cbBytesRead;
  382. }
  383. RonM_ASSERT(cbBytesReadTotal == cBytesToReadunX);
  384. // The next several lines invalidate any cached data. We have to do this because
  385. // the last block in the ITS file is usually a partial block padded out to 32K
  386. // with zeroes. If we don't invalidate the cache, this can cause problems if we
  387. // write out a new stream, close it, and then try to read it. The problem is that
  388. // the cacheing mechanism thinks it has valid data in multiples of 32K. So it
  389. // copies result data from the cache instead of falling through to the code that
  390. // would pick it out of the queued-write buffer.
  391. m_ullBuffBase = -CULINT(1);
  392. m_ullWindowBase = m_ullBuffBase;
  393. m_ullReadCursor = m_ullBuffBase;
  394. m_ullResetBase = m_ullBuffBase;
  395. m_ullResetLimit = m_ullBuffBase;
  396. // This code deletes all the reset data records for the last reset span.
  397. // This is necessary because compression coordinates information and
  398. // assumptions across multiple blocks. Thus later uncompressed data can
  399. // influence the content of early compressed blocks. So we always have
  400. // to start writing at a reset block boundary.
  401. for (ulLastRec = cNumRecs - 1; cBlocksLastSpan--; ulLastRec--)
  402. {
  403. #ifdef _DEBUG
  404. BOOL fResult =
  405. #endif // _DEBUG
  406. m_pResetData->FGetRecord(ulLastRec, &uliVOffset, &uliXOffset, &fLastRec);
  407. RonM_ASSERT(fResult);
  408. m_pResetData->DeleteRecord(ulLastRec);
  409. RonM_ASSERT(ulLastRec == m_pResetData->GetRecordNum());
  410. }
  411. m_cbUnFlushedBuf = (CULINT(m_ImageSpan.uliSize) - CULINT(uliVOffset)).Uli().LowPart;
  412. RonM_ASSERT(m_cbUnFlushedBuf == cbBytesReadTotal);
  413. m_ImageSpan .uliSize = uliVOffset;
  414. m_ImageSpanX.uliSize = uliXOffset;
  415. hr= m_pStrmReconstruction->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
  416. if (!SUCCEEDED(hr)) return hr;
  417. // Now we have to copy the temp file data through the compressor.
  418. for (;cbBytesReadTotal; cbBytesReadTotal-= cbBytesToRead)
  419. {
  420. cbBytesToRead = cbBytesReadTotal;
  421. if (cbBytesToRead > m_context.cbMaxUncomBufSize)
  422. cbBytesToRead = m_context.cbMaxUncomBufSize;
  423. hr = m_pStrmReconstruction->Read(pbWriteQueueBuffer, cbBytesToRead, &cbBytesRead);
  424. if (!SUCCEEDED(hr)) return hr;
  425. if (cbBytesToRead != cbBytesRead) return STG_E_READFAULT;
  426. if (cbBytesRead == m_context.cbMaxUncomBufSize)
  427. hr = Write(pbWriteQueueBuffer, cbBytesRead);
  428. if (!SUCCEEDED(hr)) return hr;
  429. }
  430. m_pStrmReconstruction->Release(); m_pStrmReconstruction = NULL;
  431. m_fCompressionInitialed = TRUE;
  432. return S_OK;
  433. }
  434. void CTransformInstance::CImpITransformInstance::CopyFromWindow
  435. (PBYTE pbDest, ULONG offStart, ULONG cb)
  436. {
  437. // This method copies a span of data from the history window.
  438. // The history window is a circular buffer. So the copy span
  439. // may wrap around from the end of the buffer through the
  440. // leading portion of the buffer.
  441. RonM_ASSERT(m_pbHistoryWindow);
  442. RonM_ASSERT(cb);
  443. RonM_ASSERT(cb <= m_cbHistoryWindow);
  444. RonM_ASSERT(offStart <= m_cbHistoryWindow);
  445. // Note that offStart can be == m_cbHistoryWindow and will be mapped
  446. // into a zero offset.
  447. ULONG cbTrailing = m_cbHistoryWindow - offStart;
  448. if (cbTrailing > cb) cbTrailing = cb;
  449. if (cbTrailing)
  450. {
  451. CopyMemory(pbDest, m_pbHistoryWindow + offStart, cbTrailing);
  452. pbDest += cbTrailing;
  453. cb -= cbTrailing;
  454. }
  455. if (cb) CopyMemory(pbDest, m_pbHistoryWindow, cb);
  456. }
  457. HRESULT CTransformInstance::CImpITransformInstance::HandleReadResidue
  458. (PBYTE pb, ULONG *pcbRead, BOOL fEOS, ImageSpan *pSpan,
  459. CULINT ullBase, CULINT ullLimit,
  460. CULINT ullXferBase, CULINT ullXferLimit
  461. )
  462. {
  463. HRESULT hr = S_OK;
  464. ULONG cbRead = (ullXferLimit - ullXferBase).Uli().LowPart;
  465. if (pcbRead) *pcbRead = cbRead;
  466. // Then we recursively handle the remainder of the read span (if any).
  467. // First we look to see if the span extends beyond the current
  468. // window. If so we can simply continue decompressing forward.
  469. if (ullXferLimit < ullLimit)
  470. {
  471. hr = ReadAt((ullXferLimit - pSpan->uliHandle).Uli(),
  472. pb + (ullXferLimit - ullBase).Uli().LowPart,
  473. (ullLimit - ullXferLimit).Uli().LowPart,
  474. &cbRead, pSpan
  475. );
  476. if (SUCCEEDED(hr) && pcbRead) *pcbRead += cbRead;
  477. }
  478. if (SUCCEEDED(hr))
  479. {
  480. // Then we look to see if part of the read span precedes
  481. // our history span. This is a harsh condition which requires
  482. // that we discard the current history and restart at the next
  483. // lower resync point.
  484. if (ullXferBase > ullBase)
  485. {
  486. hr = ReadAt((ullBase - pSpan->uliHandle).Uli(), pb,
  487. (ullXferBase - ullBase).Uli().LowPart,
  488. &cbRead, pSpan
  489. );
  490. if (pcbRead && SUCCEEDED(hr)) *pcbRead += cbRead;
  491. }
  492. }
  493. if (!SUCCEEDED(hr) && pcbRead) *pcbRead = 0;
  494. if (fEOS && hr == NO_ERROR && !*pcbRead)
  495. hr = S_FALSE;
  496. return hr;
  497. }
  498. HRESULT STDMETHODCALLTYPE CTransformInstance::CImpITransformInstance::ReadAt(
  499. /* [in] */ ULARGE_INTEGER ulOffset,
  500. /* [length_is][size_is][out] */ void __RPC_FAR *pv,
  501. /* [in] */ ULONG cb,
  502. /* [out] */ ULONG __RPC_FAR *pcbRead,
  503. /* [in] */ ImageSpan *pSpan)
  504. {
  505. /*
  506. This routine reads data from the MSCompressed data space. It hides all the details
  507. of how data is actually stored and how it is cached to optimized performance.
  508. The *pSpan parameter identifies a logical segment of data which corresponds
  509. to a stream in our caller's environment. This span value consists of a handle
  510. value which we assign, and a size value. By convention the handle value is
  511. a simple offset into the uncompressed linear data space which we simulate.
  512. The ulOffset parameter identifies where the read operation is to begin. It is
  513. given relative to the segment identified by *pSpan.
  514. The pv parameter defines where the read data is to be stored.
  515. The cb parameter defines how many bytes of data are requested.
  516. The *pcbRead value will indicate how many bytes were actually read.
  517. */
  518. if (cb == 0) // Empty reads always succeed.
  519. {
  520. *pcbRead = cb;
  521. return NO_ERROR;
  522. }
  523. ULONG cbDestBufSize = 0,
  524. ulEntry = 0,
  525. ulEntryNext = 0,
  526. ulEntryLast = 0;
  527. HRESULT hr = NO_ERROR;
  528. if (!m_fDecompressionActive)
  529. {
  530. // We don't fire up the decompression code until we
  531. // know we need it. We follow a similar strategy with
  532. // the compression code.
  533. int err;
  534. //create decompressor
  535. UINT destSize2 = (UINT)m_context.cbMaxComBufSize;
  536. err= LDICreateDecompression(&m_context.cbMaxUncomBufSize,
  537. &m_context.lcfg,
  538. MyAlloc,
  539. MyFree,
  540. &destSize2,
  541. &(m_context.dHandle),
  542. NULL,NULL,NULL,NULL,NULL
  543. );
  544. if (err == 0) m_fDecompressionActive= TRUE;
  545. else return E_FAIL;
  546. if (m_context.cbMaxComBufSize < destSize2)
  547. m_context.cbMaxComBufSize = destSize2;
  548. }
  549. // Now we need a synchronous reference to the buffer we used
  550. // to read compressed data. This prevents other threads from
  551. // altering the read state, and it gives us access to the buffer
  552. // for read operations.
  553. CBufferRef refReadBuffer(*pBufferForCompressedData, m_context.cbMaxComBufSize);
  554. // Here we're converting the read parameters from stream-relative to
  555. // space-relative. Initially ulOffset and cb describe the read operation
  556. // relative to the corresponding ILockBytes object denoted by *pSpan.
  557. // In the following code ullBase and ullLimit will denote the same data
  558. // relative to the entire uncompressed data sequence.
  559. // pSpan->uliHandle gives the starting offset for the ILockBytes object.
  560. CULINT ullBase = CULINT(pSpan->uliHandle) + CULINT(ulOffset);
  561. CULINT ullLimit = ullBase + cb;
  562. // ullLimitLockBytes marks the end point of the lockbyte object.
  563. CULINT ullLimitLockBytes = CULINT(pSpan->uliHandle) + CULINT(pSpan->uliSize);
  564. // Now we'll see whether the requested span lies within the ILockBytes segment.
  565. // This is where we detect end-of-stream conditions.
  566. if (ullBase > ullLimitLockBytes) // Starting beyond the end of the segment?
  567. {
  568. *pcbRead = 0;
  569. return S_FALSE;
  570. }
  571. BOOL fEOS = FALSE;
  572. if ( ullLimit < ullBase // Wrapped at 2**64 bytes?
  573. || ullLimit > ullLimitLockBytes // Trying to read past end of segment?
  574. )
  575. {
  576. fEOS = TRUE;
  577. ullLimit = ullLimitLockBytes;
  578. }
  579. ulOffset = ullBase.Uli();
  580. cb = (ullLimit - ullBase).Uli().LowPart;
  581. // Here we're getting a synchronous reference to the write-queue buffer.
  582. // This prevents any other thread from writing while we're trying to read.
  583. CBufferRef refBuffWriteQueue(m_buffWriteQueue, 0);
  584. int N = GetMulFactor();
  585. // Here we look aside to see if we need to flush out any queued write data.
  586. // Note that we don't force all queued data. We leave the last partial block
  587. // alone and handle reads from the partial block in the code below.
  588. if (m_cbUnFlushedBuf / m_context.cbMaxUncomBufSize)
  589. {
  590. m_context.hr = NO_ERROR;
  591. ImageSpan span;
  592. span.uliHandle = CULINT(0).Uli();
  593. span.uliSize = CULINT(0).Uli();
  594. RonM_ASSERT(m_fCompressionActive);
  595. int err = LCIFlushCompressorOutput(m_context.cHandle);
  596. hr = (err != 0)? E_FAIL : m_context.hr;
  597. RonM_ASSERT(SUCCEEDED(hr));
  598. if (!SUCCEEDED(hr)) return hr;
  599. m_cbUnFlushedBuf = m_cbUnFlushedBuf % m_context.cbMaxUncomBufSize;
  600. }
  601. RonM_ASSERT(m_cbUnFlushedBuf < m_context.cbMaxUncomBufSize);
  602. if (CULINT(ulOffset) < (CULINT(m_ImageSpan.uliSize))) // Has the data been written out?
  603. {
  604. // If so, we may be able to get it out of the history window
  605. // or the read cache buffer.
  606. // Are we not doing X86 machine code decompression?
  607. if (!(m_ControlData.dwOptions & OPT_FLAG_EXE))
  608. {
  609. // The code in this block determines whether some or all of the data
  610. // we need to return exists within the LZX history window.
  611. // We can do this only when we aren't doing X86 machine code decompression.
  612. // The LZX code does that work in an external buffer which we supply.
  613. long cbOffsetUncompressed = 0;
  614. long cbOffsetWindow = 0;
  615. int errCode = 0;
  616. errCode = LDIGetWindow(m_context.dHandle, &m_pbHistoryWindow,
  617. &cbOffsetUncompressed,
  618. &cbOffsetWindow,
  619. &m_cbHistoryWindow
  620. );
  621. if (errCode != 0)
  622. {
  623. hr = E_FAIL;
  624. RonM_ASSERT(FALSE);
  625. }
  626. if (m_cbHistoryWindow) // Do we have any history data?
  627. {
  628. // If so, we first must calculate the intersection between
  629. // the history span and the requested read span.
  630. CULINT ullWindowBase = m_ullWindowBase + cbOffsetUncompressed;
  631. CULINT ullXferBase = ullWindowBase;
  632. CULINT ullXferLimit = ullWindowBase + CULINT(m_cbHistoryWindow);
  633. if (ullXferBase < ullBase)
  634. ullXferBase = ullBase;
  635. if (ullXferLimit > ullLimit)
  636. ullXferLimit = ullLimit;
  637. if (ullXferBase < ullXferLimit) // Is the intersection non-empty?
  638. {
  639. // If so, we need to copy the corresponding history data
  640. // span into the result area.
  641. ++cLZXReadFromBuffer;
  642. cbOffsetWindow = (cbOffsetWindow
  643. + (ullXferBase - ullWindowBase).Uli().LowPart
  644. ) % m_context.lcfg.WindowSize;
  645. CopyFromWindow(PBYTE(pv) + (ullXferBase - ullBase).Uli().LowPart,
  646. cbOffsetWindow,
  647. (ullXferLimit - ullXferBase).Uli().LowPart
  648. );
  649. return HandleReadResidue(PBYTE(pv), pcbRead, fEOS, pSpan,
  650. ullBase, ullLimit,
  651. ullXferBase, ullXferLimit
  652. );
  653. }
  654. }
  655. }
  656. else
  657. {
  658. // The X86 code option is active. This means that we've
  659. // got a dedicated buffer of decompressed data. So let's
  660. // see if it contains the data span we need.
  661. // Get a synchronous reference to the buffer
  662. CBufferRef refbuffRead(m_buffReadCache, m_context.cbMaxUncomBufSize);
  663. PBYTE pbBuff = refbuffRead.StartAddress();
  664. CULINT ullXferBase = m_ullBuffBase;
  665. CULINT ullXferLimit = ullXferBase + m_context.cbMaxUncomBufSize;
  666. if (ullXferBase < ullBase ) ullXferBase = ullBase;
  667. if (ullXferLimit > ullLimit) ullXferLimit = ullLimit;
  668. if (ullXferBase < ullXferLimit)
  669. {
  670. ++cLZXReadFromBuffer;
  671. CopyMemory(PBYTE(pv) + (ullXferBase - ullBase ).Uli().LowPart,
  672. pbBuff + (ullXferBase - m_ullBuffBase).Uli().LowPart,
  673. (ullXferLimit - ullXferBase).Uli().LowPart
  674. );
  675. return HandleReadResidue(PBYTE(pv), pcbRead, fEOS, pSpan,
  676. ullBase, ullLimit,
  677. ullXferBase, ullXferLimit
  678. );
  679. }
  680. }
  681. }
  682. // At this point we know that the data does not exist in RAM. So we will
  683. // need to read and decompress data. The key question now is whether we
  684. // must reset the state of the decompression engine.
  685. ULARGE_INTEGER uliVOffset, uliXOffset,
  686. uliVNextOffset, uliXNextOffset,
  687. uliEndOffset, uliXEndOffset;
  688. BOOL fLastRec;
  689. if (CULINT(ulOffset) < (CULINT(m_ImageSpan.uliSize))) // Has the data been written out?
  690. {
  691. ulEntryNext = m_pResetData->FindRecord(ulOffset, &uliXOffset, &fLastRec);
  692. uliEndOffset = (CULINT(ulOffset) + cb - 1).Uli();
  693. if (CULINT(uliEndOffset) > CULINT(m_ImageSpan.uliSize))
  694. ulEntryLast = m_pResetData->GetRecordNum() - 1;
  695. else ulEntryLast = m_pResetData->FindRecord(uliEndOffset, &uliXEndOffset, &fLastRec);
  696. // Now we must decide where we have to start decompressing.
  697. // The best situation would be to continue decompressing from
  698. // the current read cursor position. However we can only do
  699. // that when the read starts after the cursor position within
  700. // the current reset span.
  701. if ( m_ullReadCursor < m_ImageSpan.uliSize // Do we have a read state?
  702. && ullBase >= m_ullReadCursor // Beyond current read cursor?
  703. && ullBase >= m_ullResetBase // Within current reset span?
  704. && ullBase < m_ullResetLimit
  705. )
  706. {
  707. ++cLZXReadFromCurrentSpan;
  708. ulEntryNext = m_pResetData->FindRecord(m_ullReadCursor.Uli(), &uliXOffset, &fLastRec);
  709. }
  710. else
  711. {
  712. ++cLZXReadFromOtherSpan;
  713. ulEntryNext -= ulEntryNext % N;
  714. }
  715. }
  716. else
  717. {
  718. // The compressed data hasn't been written out yet. Instead it's in
  719. // m_buffWriteQueue. So we set the block index boundaries to avoid
  720. // the read-and-decompress loop entirely.
  721. ulEntryNext = 1;
  722. ulEntryLast = 0;
  723. }
  724. ULONG ulEntrySkipChk = ulEntryNext;
  725. ULONG TotalBytesRead = 0;
  726. ULONG TotalBytesToRead = cb;
  727. for (; ulEntryNext <= ulEntryLast && SUCCEEDED(hr); ulEntryNext++)
  728. {
  729. #ifdef _DEBUG
  730. BOOL fResult =
  731. #endif // _DEBUG
  732. m_pResetData->FGetRecord(ulEntryNext, &uliVOffset, &uliXOffset, &fLastRec);
  733. RonM_ASSERT(fResult);
  734. if (fLastRec)
  735. {
  736. uliXNextOffset = CULINT(m_ImageSpanX.uliSize).Uli();
  737. uliVNextOffset = CULINT(m_ImageSpan .uliSize).Uli();
  738. }
  739. else
  740. {
  741. #ifdef _DEBUG
  742. BOOL fResult =
  743. #endif // _DEBUG
  744. m_pResetData->FGetRecord(ulEntryNext + 1, &uliVNextOffset, &uliXNextOffset,
  745. &fLastRec
  746. );
  747. RonM_ASSERT(fResult);
  748. }
  749. ULONG cBytesToReadX = (CULINT(uliXNextOffset) - CULINT(uliXOffset)).Uli().LowPart;
  750. ULONG cBytesToReadUnX = (CULINT(uliVNextOffset) - CULINT(uliVOffset)).Uli().LowPart;
  751. ULONG cbBytesRead;
  752. CBufferRef *prefOutput
  753. = (m_ControlData.dwOptions & OPT_FLAG_EXE)
  754. ? New CBufferRef(m_buffReadCache, m_context.cbMaxUncomBufSize)
  755. : NULL;
  756. if (cBytesToReadX)
  757. {
  758. hr = m_pITxNextInst->ReadAt(uliXOffset, refReadBuffer.StartAddress(),
  759. cBytesToReadX, &cbBytesRead, &m_ImageSpanX
  760. );
  761. if (SUCCEEDED(hr))
  762. {
  763. RonM_ASSERT(cbBytesRead == cBytesToReadX);
  764. //We might have been appending zeros for last most block which could be
  765. //less than m_context.cbMaxUncomBufSize.
  766. cbDestBufSize = cBytesToReadUnX;
  767. RonM_ASSERT(cbDestBufSize <= SOURCE_CHUNK);
  768. if (m_ControlData.dwVersion == LZX_Current_Version)
  769. cbDestBufSize = m_context.cbMaxUncomBufSize;
  770. RonM_ASSERT(m_fDecompressionActive);
  771. if (ulEntryNext % N == 0)
  772. {
  773. ++cLZXResetDecompressor;
  774. LDIResetDecompression(m_context.dHandle);
  775. m_ullWindowBase = CULINT(ulEntryNext)
  776. * CULINT(m_context.cbMaxUncomBufSize);
  777. m_ullResetBase = m_ullWindowBase;
  778. m_ullResetLimit = m_ullResetBase + m_context.cbResetBlkSize;
  779. }
  780. int err = LDIDecompress(m_context.dHandle, refReadBuffer.StartAddress(),
  781. cbBytesRead, prefOutput? prefOutput->StartAddress()
  782. : NULL,
  783. (UINT *) &cbDestBufSize
  784. );
  785. if (err != 0)
  786. {
  787. m_ullBuffBase = -CULINT(1);
  788. m_ullReadCursor = -CULINT(1);
  789. hr = E_FAIL;
  790. RonM_ASSERT(FALSE);
  791. }
  792. else
  793. {
  794. m_ullBuffBase = uliVOffset;
  795. m_ullReadCursor = m_ullBuffBase + cBytesToReadUnX;
  796. }
  797. PBYTE pbUncompressed = NULL;
  798. if (prefOutput)
  799. pbUncompressed = prefOutput->StartAddress();
  800. else
  801. {
  802. long cbOffsetUncompressed = 0;
  803. long cbOffsetWindow = 0;
  804. int errCode = 0;
  805. errCode = LDIGetWindow(m_context.dHandle, &m_pbHistoryWindow,
  806. &cbOffsetUncompressed,
  807. &cbOffsetWindow,
  808. &m_cbHistoryWindow
  809. );
  810. if (errCode != 0)
  811. {
  812. hr = E_FAIL;
  813. RonM_ASSERT(FALSE);
  814. }
  815. // Since the history window is a ring buffer, we need
  816. // to do some modulo arithmetic to find the last block
  817. // image.
  818. cbOffsetWindow = (cbOffsetWindow
  819. + m_cbHistoryWindow
  820. - cbDestBufSize
  821. ) % m_context.lcfg.WindowSize;
  822. pbUncompressed = m_pbHistoryWindow + cbOffsetWindow;
  823. }
  824. RonM_ASSERT(cBytesToReadUnX <= m_context.cbMaxUncomBufSize);
  825. RonM_ASSERT(cbDestBufSize <= m_context.cbMaxUncomBufSize);
  826. // if (cBytesToReadUnX < m_context.cbMaxUncomBufSize)
  827. // cbDestBufSize = cBytesToReadUnX;
  828. RonM_ASSERT(cbDestBufSize >= (CULINT(uliVNextOffset) - CULINT(uliVOffset)));
  829. if (ullBase < m_ullReadCursor) // Is our starting point in this buffer?
  830. {
  831. RonM_ASSERT(ullBase >= m_ullBuffBase);
  832. ULONG BytesToSkip = (ullBase - m_ullBuffBase).Uli().LowPart;
  833. pbUncompressed += BytesToSkip;
  834. cbDestBufSize -= BytesToSkip;
  835. ULONG cBytesToCopy = cbDestBufSize;
  836. if (cBytesToCopy > (TotalBytesToRead-TotalBytesRead))
  837. cBytesToCopy = (TotalBytesToRead-TotalBytesRead);
  838. memCpy((LPBYTE)pv + TotalBytesRead, pbUncompressed, cBytesToCopy);
  839. TotalBytesRead += cBytesToCopy;
  840. ullBase = m_ullReadCursor;
  841. }
  842. }//ReadAt
  843. }
  844. if (prefOutput) delete prefOutput;
  845. } //End for
  846. if (!SUCCEEDED(hr))
  847. {
  848. *pcbRead = 0;
  849. return hr;
  850. }
  851. if (ullBase < ullLimit) // Still have data to read?
  852. {
  853. // Then it must be in the write queue.
  854. RonM_ASSERT(m_cbUnFlushedBuf > 0);
  855. RonM_ASSERT(m_cbUnFlushedBuf < SOURCE_CHUNK);
  856. RonM_ASSERT(m_cbUnFlushedBuf >= (ullLimit - ullBase).Uli().LowPart);
  857. RonM_ASSERT(ullBase >= m_ImageSpan.uliSize);
  858. // We actually need to put some of these assertion tests into the
  859. // retail code to catch cases of ITS file corruption or errors in
  860. // the Win32 file system.
  861. if ( m_cbUnFlushedBuf == 0
  862. || ullBase < m_ImageSpan.uliSize
  863. || m_cbUnFlushedBuf < (ullLimit - ullBase).Uli().LowPart
  864. )
  865. {
  866. *pcbRead = 0;
  867. return STG_E_READFAULT;
  868. }
  869. PBYTE pbWriteQueue = refBuffWriteQueue.StartAddress();
  870. DWORD cb = (ullLimit - ullBase).Uli().LowPart;
  871. CopyMemory(pv, pbWriteQueue + (ullBase - m_ImageSpan.uliSize).Uli().LowPart, cb);
  872. TotalBytesRead += cb;
  873. }
  874. RonM_ASSERT(!SUCCEEDED(hr) || TotalBytesToRead == TotalBytesRead);
  875. *pcbRead = TotalBytesRead;
  876. if (fEOS && hr == NO_ERROR && !*pcbRead)
  877. hr = S_FALSE;
  878. return hr;
  879. }
  880. HRESULT STDMETHODCALLTYPE CTransformInstance::CImpITransformInstance::WriteAt(
  881. /* [in] */ ULARGE_INTEGER ulOffset,
  882. /* [size_is][in] */ const void __RPC_FAR *pv,
  883. /* [in] */ ULONG cb,
  884. /* [out] */ ULONG __RPC_FAR *pcbWritten,
  885. /* [out] */ImageSpan *pSpan)
  886. {
  887. /*
  888. This routine writes data into the MSCompressed data space. It hides all the details
  889. of how data is actually stored and how it is cached and queued to optimized
  890. performance.
  891. The *pSpan parameter identifies a logical segment of data which corresponds
  892. to a stream in our caller's environment. This span value consists of a handle
  893. value which we assign, and a size value. By convention the handle value is
  894. a simple offset into the uncompressed linear data space which we simulate. If
  895. we get a WriteAt transaction where pSpan->uliSize is zero and cb is not, that's
  896. our signal to assign a handle value.
  897. The ulOffset parameter identifies where the write operation is to begin. It is
  898. given relative to the segment identified by *pSpan.
  899. The pv parameter defines where the write data is.
  900. The cb parameter defines how many bytes of data are to be written.
  901. The *pcbWritten value will indicate how many bytes were actually written.
  902. */
  903. if (!cb)
  904. {
  905. *pcbWritten = 0;
  906. return NO_ERROR;
  907. }
  908. if (!m_fCompressionActive)
  909. {
  910. UINT destSize2 = (UINT)m_context.cbMaxComBufSize;
  911. int err= LCICreateCompression(&(m_context.cbMaxUncomBufSize),
  912. &(m_context.lcfg),
  913. MyAlloc,
  914. MyFree,
  915. &destSize2,
  916. &(m_context.cHandle),
  917. lzx_output_callback, (LPVOID)this
  918. );
  919. if (err == 0)
  920. {
  921. if (m_context.cbMaxComBufSize < destSize2)
  922. m_context.cbMaxComBufSize = destSize2;
  923. m_fCompressionActive = TRUE;
  924. //Making 10% faster decoding for nonexe data
  925. if (!(m_ControlData.dwOptions & OPT_FLAG_EXE))
  926. LCISetTranslationSize(m_context.cHandle, 0);
  927. }
  928. else return E_FAIL;
  929. }
  930. CBufferRef refLastBlock(m_buffWriteQueue, m_context.cbMaxUncomBufSize);
  931. PBYTE pbWriteQueueBuffer = refLastBlock.StartAddress();
  932. if (!CULINT(pSpan->uliSize).NonZero())
  933. pSpan->uliHandle = (CULINT(m_ImageSpan.uliSize) + m_cbUnFlushedBuf).Uli();
  934. CULINT ullBase, ullLimit;
  935. ullBase = CULINT(pSpan->uliHandle) + CULINT(ulOffset);
  936. ullLimit = ullBase + cb;
  937. CULINT ullLimitSegment = CULINT(pSpan->uliHandle) + CULINT(pSpan->uliSize);
  938. // The assert below verifies that the segment doesn't wrap around
  939. // through the beginning of the 64-bit address space.
  940. RonM_ASSERT(CULINT(pSpan->uliHandle) <= ullLimitSegment
  941. || !(ullLimitSegment.NonZero())
  942. );
  943. if ( ullBase < CULINT(pSpan->uliHandle)
  944. || (ullBase > ullLimit && ullLimit.NonZero())
  945. )
  946. {
  947. // The write would wrap around.
  948. // This is very unlikely -- at least for the next few years.
  949. *pcbWritten = 0;
  950. return STG_E_WRITEFAULT;
  951. }
  952. ulOffset = ullBase.Uli();
  953. //initialize out params
  954. *pcbWritten = 0;
  955. HRESULT hr = NO_ERROR;
  956. //writing in the middle not supported for now
  957. if (ullBase < (CULINT(m_ImageSpan.uliSize) + m_cbUnFlushedBuf))
  958. {
  959. RonM_ASSERT(FALSE);
  960. return E_FAIL;
  961. }
  962. if (!m_fCompressionInitialed)
  963. {
  964. // The first time we write to an ITS file, we must set up
  965. // the initial state of the LZX compressor.
  966. hr = ReconstructCompressionState(pbWriteQueueBuffer);
  967. RonM_ASSERT(SUCCEEDED(hr));
  968. if (!SUCCEEDED(hr)) return E_FAIL;
  969. }
  970. ULONG cbWritten = 0;
  971. for (; cb;)
  972. {
  973. ULONG offNextWrite = m_cbUnFlushedBuf % SOURCE_CHUNK;
  974. ULONG cbToCopy = cb;
  975. ULONG cbAvail = SOURCE_CHUNK - offNextWrite;
  976. RonM_ASSERT(cbAvail != 0);
  977. if (cbToCopy > cbAvail)
  978. cbToCopy = cbAvail;
  979. CopyMemory(pbWriteQueueBuffer + offNextWrite, pv, cbToCopy);
  980. cb -= cbToCopy;
  981. cbAvail -= cbToCopy;
  982. m_cbUnFlushedBuf += cbToCopy;
  983. m_cbResetSpan += cbToCopy;
  984. cbWritten += cbToCopy;
  985. pv = PBYTE(pv) + cbToCopy;
  986. if (cbAvail == 0)
  987. {
  988. hr = Write(pbWriteQueueBuffer, SOURCE_CHUNK);
  989. if (m_cbResetSpan == m_context.cbResetBlkSize)
  990. FlushQueuedOutput();
  991. if (!SUCCEEDED(hr)) break;
  992. }
  993. }
  994. RonM_ASSERT(m_cbUnFlushedBuf < m_context.cbResetBlkSize);
  995. RonM_ASSERT(m_cbResetSpan < m_context.cbResetBlkSize);
  996. *pcbWritten = cbWritten;
  997. pSpan->uliSize = (CULINT(pSpan->uliSize) + cbWritten).Uli();
  998. m_fDirty = TRUE;
  999. return hr;
  1000. }
  1001. HRESULT STDMETHODCALLTYPE CTransformInstance::CImpITransformInstance::Flush(void)
  1002. {
  1003. // This routine gets all queued ITS data written out to the containing ILockBytes object.
  1004. if (!m_fDirty) return NO_ERROR;
  1005. HRESULT hr = Commit();
  1006. if (SUCCEEDED(hr))
  1007. {
  1008. //Save reset table to disk
  1009. hr = m_pResetData->CommitResetTable(m_ImageSpan.uliSize, m_ImageSpanX.uliSize);
  1010. if (SUCCEEDED(hr))
  1011. {
  1012. m_fDirty = FALSE;
  1013. hr = m_pITxNextInst->Flush();
  1014. }
  1015. }
  1016. return hr;
  1017. }
  1018. HRESULT CTransformInstance::CImpITransformInstance::Commit(void)
  1019. {
  1020. // This routine forces all the queued write data to be written out.
  1021. HRESULT hr = NO_ERROR;
  1022. ULONG cbBytesToX = m_cbUnFlushedBuf % m_context.cbMaxUncomBufSize;
  1023. if (cbBytesToX)
  1024. {
  1025. CBufferRef refQueuedData(m_buffWriteQueue, m_context.cbMaxUncomBufSize);
  1026. PBYTE pbQueueData = refQueuedData.StartAddress();
  1027. RonM_ASSERT(cbBytesToX < m_context.cbMaxUncomBufSize);
  1028. ULONG cbPadding = m_context.cbMaxUncomBufSize - cbBytesToX;
  1029. ZeroMemory(pbQueueData + cbBytesToX, cbPadding);
  1030. m_cbUnFlushedBuf += cbPadding;
  1031. hr = Write(pbQueueData, m_context.cbMaxUncomBufSize);
  1032. if (SUCCEEDED(hr))
  1033. hr = FlushQueuedOutput();
  1034. if (SUCCEEDED(hr))
  1035. {
  1036. // Pretend we didn't write those trailing zeroes.
  1037. m_ImageSpan.uliSize = (CULINT(m_ImageSpan.uliSize) - CULINT(cbPadding)).Uli();
  1038. }//write compressed bytes to disk
  1039. }//something remains to be transformed
  1040. if (SUCCEEDED(hr))
  1041. hr = FlushQueuedOutput();
  1042. return hr;
  1043. }
  1044. //This write takes care of the write request <= reset block size
  1045. HRESULT CTransformInstance::CImpITransformInstance::Write(LPBYTE pbData, ULONG cbData)
  1046. {
  1047. int err = 0;
  1048. ULONG cbDestBufSize = 0;
  1049. HRESULT hr = NO_ERROR;
  1050. // BugBug: If we we're really always writing out a full block
  1051. // we should change the name of this routine and get
  1052. // rid of the cbData parameter.
  1053. RonM_ASSERT(cbData == m_context.cbMaxUncomBufSize);
  1054. m_context.hr = NO_ERROR;
  1055. #ifdef TXDEBUG
  1056. #ifdef _DEBUG
  1057. BYTE XBuf[6];
  1058. memCpy(XBuf, pbData + cbTotalBytesX, 6);
  1059. printf("size = %d Blk=%x %x %x %x %x %x\n",
  1060. cbBytesToBeX,
  1061. XBuf[0], XBuf[1],XBuf[2],XBuf[3],XBuf[4], XBuf[5]);
  1062. #endif
  1063. #endif
  1064. RonM_ASSERT(m_fCompressionActive);
  1065. err = LCICompress(m_context.cHandle, pbData, cbData,
  1066. NULL, m_context.cbMaxComBufSize, &cbDestBufSize
  1067. );
  1068. if (err == 0)
  1069. {
  1070. hr = m_context.hr;
  1071. }
  1072. else hr = E_FAIL;
  1073. return hr;
  1074. }
  1075. HRESULT CTransformInstance::CImpITransformInstance::FlushQueuedOutput()
  1076. {
  1077. // This routine flushes output which is queued within the compressor.
  1078. RonM_ASSERT(m_fCompressionActive);
  1079. int err = LCIFlushCompressorOutput(m_context.cHandle);
  1080. HRESULT hr = (err != 0)? E_FAIL : m_context.hr;
  1081. RonM_ASSERT(SUCCEEDED(hr));
  1082. if (!SUCCEEDED(hr)) return hr;
  1083. int mod = m_pResetData->GetRecordNum() % GetMulFactor();
  1084. if (mod == 0)
  1085. {
  1086. #ifdef TXDEBUG
  1087. #ifdef _DEBUG
  1088. printf("resetting before %d\n", m_pResetData->GetRecordNum());
  1089. #endif
  1090. #endif
  1091. RonM_ASSERT(m_fCompressionActive);
  1092. err = LCIResetCompression(m_context.cHandle);
  1093. if (err != 0) return E_FAIL;
  1094. m_cbResetSpan -= m_context.cbResetBlkSize;
  1095. }
  1096. return hr;
  1097. }