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.

704 lines
21 KiB

  1. #include <precomp.h>
  2. //
  3. // patchlzx.c
  4. //
  5. // Author: Tom McGuire (tommcg) 2/97 - 9/97
  6. //
  7. // Copyright (C) Microsoft, 1997-1998.
  8. //
  9. // MICROSOFT CONFIDENTIAL
  10. //
  11. #define LZX_BLOCKSIZE 0x8000 // 32K
  12. #define LZX_MINWINDOW 0x20000 // 128K
  13. typedef struct _LZX_OUTPUT_CONTEXT {
  14. PUCHAR PatchBufferPointer;
  15. ULONG PatchBufferSize;
  16. ULONG PatchSize;
  17. BOOL DiscardOutput;
  18. } LZX_OUTPUT_CONTEXT, *PLZX_OUTPUT_CONTEXT;
  19. ULONG
  20. __fastcall
  21. LzxWindowSize(
  22. IN ULONG OldDataSize,
  23. IN ULONG NewDataSize,
  24. IN DWORD OptionFlags
  25. )
  26. {
  27. ULONG WindowSize;
  28. ULONG DataSize;
  29. DataSize = ROUNDUP2( OldDataSize, LZX_BLOCKSIZE ) + NewDataSize;
  30. if ( OptionFlags & PATCH_OPTION_USE_LZX_LARGE ) {
  31. if ( DataSize > LZX_MAXWINDOW_32 ) {
  32. DataSize = LZX_MAXWINDOW_32;
  33. }
  34. }
  35. else {
  36. if ( DataSize > LZX_MAXWINDOW_8 ) {
  37. DataSize = LZX_MAXWINDOW_8;
  38. }
  39. }
  40. for ( WindowSize = LZX_MINWINDOW;
  41. WindowSize < DataSize;
  42. WindowSize <<= 1
  43. );
  44. return WindowSize;
  45. }
  46. ULONG
  47. __fastcall
  48. LzxInsertSize(
  49. IN ULONG OldDataSize,
  50. IN DWORD OptionFlags
  51. )
  52. {
  53. if ( OptionFlags & PATCH_OPTION_USE_LZX_LARGE ) {
  54. if ( OldDataSize > LZX_MAXWINDOW_32 ) {
  55. OldDataSize = LZX_MAXWINDOW_32;
  56. }
  57. }
  58. else {
  59. if ( OldDataSize > LZX_MAXWINDOW_8 ) {
  60. OldDataSize = LZX_MAXWINDOW_8;
  61. }
  62. }
  63. return OldDataSize;
  64. }
  65. //
  66. // Following group of functions and exported apis are exclusively for
  67. // creating patches. If we're only compiling the apply code, ignore
  68. // this group of functions.
  69. //
  70. #ifndef PATCH_APPLY_CODE_ONLY
  71. ULONG
  72. WINAPI
  73. EstimateLzxCompressionMemoryRequirement(
  74. IN ULONG OldDataSize,
  75. IN ULONG NewDataSize,
  76. IN ULONG OptionFlags
  77. )
  78. {
  79. ULONG WindowSize = LzxWindowSize( OldDataSize, NewDataSize, OptionFlags );
  80. //
  81. // Currently the LZX engine requires 9 times the size of the window
  82. // plus a fixed overhead of just under 0x1A0000 bytes (1.7MB).
  83. //
  84. return (( WindowSize * 9 ) + 0x1A0000 );
  85. }
  86. int
  87. __stdcall
  88. MyLzxOutputCallback(
  89. PVOID CallerContext,
  90. PUCHAR CompressedData,
  91. LONG CompressedSize,
  92. LONG UncompressedSize
  93. )
  94. {
  95. PLZX_OUTPUT_CONTEXT OutputContext = CallerContext;
  96. UNREFERENCED_PARAMETER( UncompressedSize );
  97. OutputContext->PatchSize += CompressedSize + sizeof( USHORT );
  98. if ( ! OutputContext->DiscardOutput ) {
  99. if ( OutputContext->PatchSize <= OutputContext->PatchBufferSize ) {
  100. *(UNALIGNED USHORT *)( OutputContext->PatchBufferPointer ) = (USHORT) CompressedSize;
  101. memcpy( OutputContext->PatchBufferPointer + sizeof( USHORT ), CompressedData, CompressedSize );
  102. OutputContext->PatchBufferPointer += CompressedSize + sizeof( USHORT );
  103. }
  104. }
  105. return TRUE;
  106. }
  107. ULONG
  108. WINAPI
  109. CreateRawLzxPatchDataFromBuffers(
  110. IN PVOID OldDataBuffer,
  111. IN ULONG OldDataSize,
  112. IN PVOID NewDataBuffer,
  113. IN ULONG NewDataSize,
  114. IN ULONG PatchBufferSize,
  115. OUT PVOID PatchBuffer,
  116. OUT ULONG *PatchSize,
  117. IN ULONG OptionFlags,
  118. IN PVOID OptionData,
  119. IN PFNALLOC pfnAlloc,
  120. IN HANDLE AllocHandle,
  121. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  122. IN PVOID CallbackContext,
  123. IN ULONG ProgressInitialValue,
  124. IN ULONG ProgressMaximumValue
  125. )
  126. {
  127. UP_IMAGE_NT_HEADERS32 NtHeader;
  128. LZX_OUTPUT_CONTEXT OutputContext;
  129. PVOID LzxContext;
  130. ULONG LzxWindow;
  131. ULONG LzxOptE8;
  132. LONG LzxStatus;
  133. PUCHAR BlockPointer;
  134. ULONG BytesRemaining;
  135. ULONG OddBytes;
  136. LONG Estimate;
  137. BOOL Success;
  138. ULONG ErrorCode;
  139. UNREFERENCED_PARAMETER( OptionData );
  140. ErrorCode = ERROR_INVALID_PARAMETER;
  141. if ( OptionFlags & ( PATCH_OPTION_USE_LZX_A | PATCH_OPTION_USE_LZX_B )) {
  142. ErrorCode = ERROR_OUTOFMEMORY;
  143. OutputContext.DiscardOutput = TRUE;
  144. LzxWindow = LzxWindowSize( OldDataSize, NewDataSize, OptionFlags );
  145. Success = LZX_EncodeInit(
  146. &LzxContext,
  147. LzxWindow,
  148. LZX_BLOCKSIZE,
  149. pfnAlloc,
  150. AllocHandle,
  151. MyLzxOutputCallback,
  152. &OutputContext
  153. );
  154. if ( Success ) {
  155. ULONG ProgressPosition = ProgressInitialValue;
  156. ErrorCode = ERROR_PATCH_ENCODE_FAILURE;
  157. BlockPointer = OldDataBuffer;
  158. BytesRemaining = LzxInsertSize( OldDataSize, OptionFlags );
  159. OddBytes = BytesRemaining % LZX_BLOCKSIZE;
  160. #ifdef TRACING
  161. EncTracingDefineOffsets(
  162. LzxWindow,
  163. OddBytes ? (LZX_BLOCKSIZE - OddBytes) : 0,
  164. OddBytes ? (BytesRemaining + LZX_BLOCKSIZE - OddBytes) : BytesRemaining
  165. );
  166. #endif
  167. if ( OddBytes ) {
  168. PUCHAR PadBuffer = pfnAlloc( AllocHandle, LZX_BLOCKSIZE );
  169. if ( PadBuffer == NULL ) {
  170. ErrorCode = ERROR_OUTOFMEMORY;
  171. Success = FALSE;
  172. }
  173. else {
  174. memcpy(
  175. PadBuffer + LZX_BLOCKSIZE - OddBytes,
  176. BlockPointer,
  177. OddBytes
  178. );
  179. Success = LZX_EncodeInsertDictionary(
  180. LzxContext,
  181. PadBuffer,
  182. LZX_BLOCKSIZE
  183. );
  184. if ( Success ) {
  185. ProgressPosition += OddBytes;
  186. Success = ProgressCallbackWrapper(
  187. ProgressCallback,
  188. CallbackContext,
  189. ProgressPosition,
  190. ProgressMaximumValue
  191. );
  192. if ( ! Success ) {
  193. ErrorCode = GetLastError();
  194. }
  195. }
  196. BlockPointer += OddBytes;
  197. BytesRemaining -= OddBytes;
  198. }
  199. }
  200. while (( BytesRemaining ) && ( Success )) {
  201. ASSERT(( BytesRemaining % LZX_BLOCKSIZE ) == 0 );
  202. Success = LZX_EncodeInsertDictionary(
  203. LzxContext,
  204. BlockPointer,
  205. LZX_BLOCKSIZE
  206. );
  207. if ( Success ) {
  208. ProgressPosition += LZX_BLOCKSIZE;
  209. Success = ProgressCallbackWrapper(
  210. ProgressCallback,
  211. CallbackContext,
  212. ProgressPosition,
  213. ProgressMaximumValue
  214. );
  215. if ( ! Success ) {
  216. ErrorCode = GetLastError();
  217. }
  218. }
  219. BlockPointer += LZX_BLOCKSIZE;
  220. BytesRemaining -= LZX_BLOCKSIZE;
  221. }
  222. if ( Success ) {
  223. LZX_EncodeResetState( LzxContext );
  224. LzxOptE8 = 0;
  225. NtHeader = GetNtHeader( NewDataBuffer, NewDataSize );
  226. //
  227. // If file has MZ signature AND it's NOT a PE image,
  228. // OR it's a PE image AND it's an i386 image, turn on
  229. // the i386-specific E8 call translation optimization.
  230. //
  231. if (( OptionFlags & PATCH_OPTION_USE_LZX_B ) &&
  232. ((( NtHeader ) && ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 )) ||
  233. (( ! NtHeader ) && ( *(UNALIGNED USHORT *)NewDataBuffer == 0x5A4D )))) {
  234. LzxOptE8 = NewDataSize;
  235. }
  236. OutputContext.PatchBufferSize = PatchBufferSize;
  237. OutputContext.PatchBufferPointer = PatchBuffer;
  238. OutputContext.PatchSize = 0;
  239. OutputContext.DiscardOutput = FALSE;
  240. BlockPointer = NewDataBuffer;
  241. BytesRemaining = NewDataSize;
  242. LzxStatus = ENCODER_SUCCESS;
  243. Success = TRUE;
  244. while (( BytesRemaining >= LZX_BLOCKSIZE ) && ( LzxStatus == ENCODER_SUCCESS ) && ( Success )) {
  245. LzxStatus = LZX_Encode(
  246. LzxContext,
  247. BlockPointer,
  248. LZX_BLOCKSIZE,
  249. &Estimate,
  250. LzxOptE8
  251. );
  252. if ( LzxStatus == ENCODER_SUCCESS ) {
  253. ProgressPosition += LZX_BLOCKSIZE;
  254. Success = ProgressCallbackWrapper(
  255. ProgressCallback,
  256. CallbackContext,
  257. ProgressPosition,
  258. ProgressMaximumValue
  259. );
  260. if ( ! Success ) {
  261. ErrorCode = GetLastError();
  262. }
  263. }
  264. BlockPointer += LZX_BLOCKSIZE;
  265. BytesRemaining -= LZX_BLOCKSIZE;
  266. }
  267. if (( BytesRemaining ) && ( LzxStatus == ENCODER_SUCCESS ) && ( Success )) {
  268. LzxStatus = LZX_Encode(
  269. LzxContext,
  270. BlockPointer,
  271. BytesRemaining,
  272. &Estimate,
  273. LzxOptE8
  274. );
  275. if ( LzxStatus == ENCODER_SUCCESS ) {
  276. ProgressPosition += BytesRemaining;
  277. Success = ProgressCallbackWrapper(
  278. ProgressCallback,
  279. CallbackContext,
  280. ProgressPosition,
  281. ProgressMaximumValue
  282. );
  283. if ( ! Success ) {
  284. ErrorCode = GetLastError();
  285. }
  286. }
  287. }
  288. if (( LzxStatus == ENCODER_SUCCESS ) && ( Success )) {
  289. Success = LZX_EncodeFlush( LzxContext );
  290. if ( Success ) {
  291. ErrorCode = ERROR_INSUFFICIENT_BUFFER;
  292. *PatchSize = OutputContext.PatchSize;
  293. if ( OutputContext.PatchSize <= OutputContext.PatchBufferSize ) {
  294. ErrorCode = NO_ERROR;
  295. }
  296. }
  297. }
  298. }
  299. }
  300. }
  301. return ErrorCode;
  302. }
  303. ULONG
  304. WINAPI
  305. RawLzxCompressBuffer(
  306. IN PVOID InDataBuffer,
  307. IN ULONG InDataSize,
  308. IN ULONG OutDataBufferSize,
  309. OUT PVOID OutDataBuffer OPTIONAL,
  310. OUT PULONG OutDataSize,
  311. IN PFNALLOC pfnAlloc,
  312. IN HANDLE AllocHandle,
  313. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  314. IN PVOID CallbackContext,
  315. IN ULONG ProgressInitialValue,
  316. IN ULONG ProgressMaximumValue
  317. )
  318. {
  319. UP_IMAGE_NT_HEADERS32 NtHeader;
  320. LZX_OUTPUT_CONTEXT OutputContext;
  321. ULONG ProgressPosition;
  322. PVOID LzxContext;
  323. ULONG LzxWindow;
  324. ULONG LzxOptE8;
  325. LONG LzxStatus;
  326. PUCHAR BlockPointer;
  327. ULONG BytesRemaining;
  328. LONG Estimate;
  329. BOOL Success;
  330. ULONG ErrorCode;
  331. if ( OutDataBufferSize == 0 ) {
  332. OutDataBuffer = NULL;
  333. }
  334. else if ( OutDataBuffer == NULL ) {
  335. OutDataBufferSize = 0;
  336. }
  337. ErrorCode = ERROR_OUTOFMEMORY;
  338. OutputContext.DiscardOutput = OutDataBuffer ? FALSE : TRUE;
  339. OutputContext.PatchBufferSize = OutDataBufferSize;
  340. OutputContext.PatchBufferPointer = OutDataBuffer;
  341. OutputContext.PatchSize = 0;
  342. LzxWindow = LzxWindowSize( 0, InDataSize, 0 );
  343. Success = LZX_EncodeInit(
  344. &LzxContext,
  345. LzxWindow,
  346. LZX_BLOCKSIZE,
  347. pfnAlloc,
  348. AllocHandle,
  349. MyLzxOutputCallback,
  350. &OutputContext
  351. );
  352. if ( Success ) {
  353. LzxOptE8 = 0;
  354. NtHeader = GetNtHeader( InDataBuffer, InDataSize );
  355. //
  356. // If file has MZ signature AND it's NOT a PE image,
  357. // OR it's a PE image AND it's an i386 image, turn on
  358. // the i386-specific E8 call translation optimization.
  359. //
  360. if ((( NtHeader ) && ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 )) ||
  361. (( ! NtHeader ) && ( *(UNALIGNED USHORT *)InDataBuffer == 0x5A4D ))) {
  362. LzxOptE8 = InDataSize;
  363. }
  364. ProgressPosition = ProgressInitialValue;
  365. ErrorCode = ERROR_PATCH_ENCODE_FAILURE;
  366. BlockPointer = InDataBuffer;
  367. BytesRemaining = InDataSize;
  368. LzxStatus = ENCODER_SUCCESS;
  369. Success = TRUE;
  370. while (( BytesRemaining >= LZX_BLOCKSIZE ) && ( LzxStatus == ENCODER_SUCCESS ) && ( Success )) {
  371. LzxStatus = LZX_Encode(
  372. LzxContext,
  373. BlockPointer,
  374. LZX_BLOCKSIZE,
  375. &Estimate,
  376. LzxOptE8
  377. );
  378. if ( LzxStatus == ENCODER_SUCCESS ) {
  379. ProgressPosition += LZX_BLOCKSIZE;
  380. Success = ProgressCallbackWrapper(
  381. ProgressCallback,
  382. CallbackContext,
  383. ProgressPosition,
  384. ProgressMaximumValue
  385. );
  386. if ( ! Success ) {
  387. ErrorCode = GetLastError();
  388. }
  389. }
  390. BlockPointer += LZX_BLOCKSIZE;
  391. BytesRemaining -= LZX_BLOCKSIZE;
  392. }
  393. if (( BytesRemaining ) && ( LzxStatus == ENCODER_SUCCESS ) && ( Success )) {
  394. LzxStatus = LZX_Encode(
  395. LzxContext,
  396. BlockPointer,
  397. BytesRemaining,
  398. &Estimate,
  399. LzxOptE8
  400. );
  401. if ( LzxStatus == ENCODER_SUCCESS ) {
  402. ProgressPosition += BytesRemaining;
  403. Success = ProgressCallbackWrapper(
  404. ProgressCallback,
  405. CallbackContext,
  406. ProgressPosition,
  407. ProgressMaximumValue
  408. );
  409. if ( ! Success ) {
  410. ErrorCode = GetLastError();
  411. }
  412. }
  413. }
  414. if (( LzxStatus == ENCODER_SUCCESS ) && ( Success )) {
  415. Success = LZX_EncodeFlush( LzxContext );
  416. if ( Success ) {
  417. if ( OutDataSize ) {
  418. *OutDataSize = OutputContext.PatchSize;
  419. }
  420. if (( OutDataBufferSize ) && ( OutputContext.PatchSize > OutDataBufferSize )) {
  421. ErrorCode = ERROR_INSUFFICIENT_BUFFER;
  422. }
  423. else {
  424. ErrorCode = NO_ERROR;
  425. }
  426. }
  427. }
  428. }
  429. return ErrorCode;
  430. }
  431. #endif // ! PATCH_APPLY_CODE_ONLY
  432. //
  433. // Following group of functions and exported apis are exclusively for
  434. // applying patches. If we're only compiling the create code, ignore
  435. // this group of functions.
  436. //
  437. #ifndef PATCH_CREATE_CODE_ONLY
  438. ULONG
  439. WINAPI
  440. EstimateLzxDecompressionMemoryRequirement(
  441. IN ULONG OldDataSize,
  442. IN ULONG NewDataSize,
  443. IN ULONG OptionFlags
  444. )
  445. {
  446. ULONG WindowSize = LzxWindowSize( OldDataSize, NewDataSize, OptionFlags );
  447. //
  448. // Currently the LZX decompression engine requires the size of the
  449. // window plus some slop and the size of the context. We'll add 64K
  450. // to cover the context size and slop.
  451. //
  452. return ( WindowSize + 0x10000 );
  453. }
  454. ULONG
  455. WINAPI
  456. ApplyRawLzxPatchToBuffer(
  457. IN PVOID OldDataBuffer,
  458. IN ULONG OldDataSize,
  459. IN PVOID PatchDataBuffer,
  460. IN ULONG PatchDataSize,
  461. OUT PVOID NewDataBuffer,
  462. IN ULONG NewDataSize,
  463. IN ULONG OptionFlags,
  464. IN PVOID OptionData,
  465. IN PFNALLOC pfnAlloc,
  466. IN HANDLE AllocHandle,
  467. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  468. IN PVOID CallbackContext,
  469. IN ULONG ProgressInitialValue,
  470. IN ULONG ProgressMaximumValue
  471. )
  472. {
  473. PVOID LzxContext;
  474. ULONG LzxWindow;
  475. BOOL Success;
  476. ULONG ErrorCode;
  477. UNREFERENCED_PARAMETER( OptionData );
  478. ErrorCode = ERROR_INVALID_PARAMETER;
  479. if ( OptionFlags & ( PATCH_OPTION_USE_LZX_A | PATCH_OPTION_USE_LZX_B )) {
  480. ErrorCode = ERROR_OUTOFMEMORY;
  481. LzxWindow = LzxWindowSize( OldDataSize, NewDataSize, OptionFlags );
  482. Success = LZX_DecodeInit(
  483. &LzxContext,
  484. LzxWindow,
  485. pfnAlloc,
  486. AllocHandle
  487. );
  488. if ( Success ) {
  489. ErrorCode = ERROR_PATCH_DECODE_FAILURE;
  490. Success = LZX_DecodeInsertDictionary(
  491. LzxContext,
  492. OldDataBuffer,
  493. LzxInsertSize( OldDataSize, OptionFlags )
  494. );
  495. if ( Success ) {
  496. PUCHAR CompressedInputPointer = PatchDataBuffer;
  497. PUCHAR CompressedInputExtent = CompressedInputPointer + PatchDataSize;
  498. PUCHAR UncompressedOutputPointer = NewDataBuffer;
  499. ULONG UncompressedBytesRemaining = NewDataSize;
  500. ULONG ProgressPosition = ProgressInitialValue;
  501. LONG LzxStatus = 0;
  502. LONG ActualSize;
  503. ULONG UncompressedBlockSize;
  504. ULONG CompressedBlockSize;
  505. while (( UncompressedBytesRemaining ) && ( LzxStatus == 0 )) {
  506. UncompressedBlockSize = ( UncompressedBytesRemaining > LZX_BLOCKSIZE ) ? LZX_BLOCKSIZE : UncompressedBytesRemaining;
  507. CompressedBlockSize = *(UNALIGNED USHORT *)( CompressedInputPointer );
  508. CompressedInputPointer += sizeof( USHORT );
  509. if (( CompressedInputPointer + CompressedBlockSize ) > CompressedInputExtent ) {
  510. LzxStatus = 1;
  511. break;
  512. }
  513. LzxStatus = LZX_Decode(
  514. LzxContext,
  515. UncompressedBlockSize,
  516. CompressedInputPointer,
  517. CompressedBlockSize,
  518. UncompressedOutputPointer,
  519. UncompressedBlockSize,
  520. &ActualSize
  521. );
  522. CompressedInputPointer += CompressedBlockSize;
  523. UncompressedOutputPointer += ActualSize;
  524. UncompressedBytesRemaining -= ActualSize;
  525. ProgressPosition += ActualSize;
  526. Success = ProgressCallbackWrapper(
  527. ProgressCallback,
  528. CallbackContext,
  529. ProgressPosition,
  530. ProgressMaximumValue
  531. );
  532. if ( ! Success ) {
  533. ErrorCode = GetLastError();
  534. LzxStatus = 1;
  535. }
  536. }
  537. if ( LzxStatus == 0 ) {
  538. ErrorCode = NO_ERROR;
  539. }
  540. }
  541. }
  542. }
  543. return ErrorCode;
  544. }
  545. #endif // ! PATCH_CREATE_CODE_ONLY