PageRenderTime 62ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/FileGuard/UpdatesUnit.pas

http://github.com/rofl0r/KOL
Pascal | 703 lines | 565 code | 38 blank | 100 comment | 76 complexity | 09b62425b025b1fa35a21673363acc62 MD5 | raw file
  1. {
  2. MakeUpdates
  3. ApplyUpdates
  4. (C) by Vladimir Kladov, 2002-2004
  5. These functions allows to create (MakeUpdates) a command stream
  6. on base of two data streams: Stream1 and Stream2,
  7. which later can be used to restore (ApplyUpdates) Stream2 on base of
  8. the same source Stream1 and created by MakeUpdates command stream.
  9. This technique used in my UpdateMaker and Updater applications
  10. to provide patches to a set of (big) files which otherwise could
  11. require a lot of files to download to get new version. This is great
  12. for developers providing sources rather then compiled stuff.
  13. History:
  14. 5-sep-2004
  15. first release of this unit: functions MakeUpdates and ApplyUpdates
  16. extracted from UpdateMaker / Updater sources, with some sumplifications
  17. in order to make possible to use streams rather then files, and to use
  18. these two functions separately from UpdateMaker and Updater utilities.
  19. 7-Sep-2004
  20. version 2 of this unit, algorithm improved in comparison to current
  21. version of UpdateMaker program and errors fixed (though new verion of
  22. MakeUpdates creates command file still compatible with old version
  23. of ApplyUpdates been corrected). Now plan to re-use these functions in
  24. newer versions of Updater / UpdateMaker.
  25. 8-Sep-2004
  26. version 3 of this unit. Some errors fixed. Parameter added: OnProgress.
  27. }
  28. unit UpdatesUnit;
  29. interface
  30. uses Windows, KOL;
  31. //{$DEFINE WRITE_LEN_CC}
  32. type
  33. TOnUpdatesProgress = procedure( Percents, TotalSize, CurrentPosition: Integer;
  34. var Cancel: Boolean ) of object;
  35. function ApplyUpdates( OutStrm, SourceStream, CmdStrm: PStream;
  36. OnProgress: TOnUpdatesProgress ): Boolean;
  37. function MakeUpdates( DestCommandStream, LastVersion, PrevVersion: PStream;
  38. OnProgress: TOnUpdatesProgress ): Boolean;
  39. implementation
  40. type
  41. TCommand = (cmdFWDandCOPY, cmdBCKandCOPY, cmdINSERT, cmdNone);
  42. TDwordArray = array[ 0..1000000 ] of DWORD;
  43. PDwordArray = ^TDwordArray;
  44. function Compare4Bytes( A: PDwordArray; e1, e2: DWORD ): Integer;
  45. {$IFDEF PAS_CODE}
  46. var X, Y: DWORD;
  47. begin
  48. X := A[ e1 ];
  49. Y := A[ e2 ];
  50. asm
  51. MOV EAX, [X]
  52. MOV EDX, [Y]
  53. MOV EAX, [EAX]
  54. MOV EDX, [EDX]
  55. BSWAP EAX
  56. BSWAP EDX
  57. SUB EAX, EDX
  58. MOV Result, EAX
  59. end;
  60. end;
  61. {$ELSE}
  62. asm
  63. MOV ECX, [EAX+ECX*4]
  64. MOV EAX, [EAX+EDX*4]
  65. MOV ECX, [ECX]
  66. MOV EAX, [EAX]
  67. BSWAP ECX
  68. BSWAP EAX
  69. SUB EAX, ECX
  70. end;
  71. {$ENDIF}
  72. procedure SwapIndxes( A: PDwordArray; e1, e2: DWORD );
  73. {$IFDEF PAS_CODE}
  74. var X, Y: Integer;
  75. begin
  76. X := A[ e1 ];
  77. Y := A[ e2 ];
  78. A[ e1 ] := Y;
  79. A[ e2 ] := X;
  80. end;
  81. {$ELSE}
  82. asm
  83. PUSH EBX
  84. MOV EBX, [EAX+ECX*4]
  85. XCHG EBX, [EAX+EDX*4]
  86. MOV [EAX+ECX*4], EBX
  87. POP EBX
  88. end;
  89. {$ENDIF}
  90. function MakePattern2(Data: PStream; Old, New: PChar; OldLen, NewLen: Integer;
  91. MaxSize: Integer; var Equal: Boolean; OnProgress: TOnUpdatesProgress): Boolean;
  92. var HashTable1: PChar;
  93. SortTable1, AccTable1: PDwordArray;
  94. function BytesEqual( OldPos, NewPos: Integer ): Integer;
  95. var I: Integer;
  96. begin
  97. Result := Min( OldLen - OldPos, NewLen - NewPos );
  98. for I := 1 to Result do
  99. begin
  100. if Old[ OldPos ] <> New[ NewPos ] then
  101. begin
  102. Result := I - 1;
  103. Exit;
  104. end;
  105. Inc( OldPos );
  106. Inc( NewPos );
  107. end;
  108. end;
  109. // запись одного байта в выходной поток
  110. procedure WriteByte( B: Byte );
  111. begin
  112. Data.Write( B, 1 );
  113. end;
  114. // возвратит Flag, если выполнено условие Cond, иначе 0.
  115. function MakeFlag( Flag: Byte; Cond: Boolean ): Byte;
  116. begin
  117. if Cond then Result := Flag
  118. else Result := 0;
  119. end;
  120. // запись числа в формате с переменной длиной. Старший бит байта определяет
  121. // для читателя числа, читать ли следующий байт. 7 разрядов хранят очередные
  122. // 7 бит числа. Для хранения числа от 0 до 127 достаточно 1 байта, от 128 до
  123. // 16383 (14 бит единиц) - двух байт, и т.д.
  124. procedure WriteNum( N: DWORD );
  125. begin
  126. REPEAT
  127. WriteByte( N and $7F or MakeFlag( $80, N > 127 ) );
  128. N := N shr 7;
  129. UNTIL N = 0;
  130. end;
  131. // Предварительный подсчет числа в байтах
  132. function CalcNumLen( N: DWORD ): Integer;
  133. begin
  134. Result := 1;
  135. while N <> 0 do
  136. begin
  137. N := N shr 7;
  138. Inc( Result );
  139. end;
  140. end;
  141. var PrevCmd: TCommand;
  142. // формирует команду с параметром "длина" переменной разрядности. См. описание
  143. // выше. Формат команды зависит от PrevCmd.
  144. procedure WriteCommand( Cmd: TCommand; Len: Integer );
  145. begin
  146. Dec( Len );
  147. CASE PrevCmd OF
  148. cmdNONE:
  149. CASE Cmd OF
  150. cmdFWDandCOPY:
  151. begin
  152. WriteByte( Len and $3F or $00 or MakeFlag( $40, Len > 63 ) );
  153. if Len > 63 then WriteNum( Len shr 6 );
  154. end;
  155. cmdINSERT:
  156. begin
  157. WriteByte( Len and $3F or $80 or MakeFlag( $40, Len > 63 ) );
  158. if Len > 63 then WriteNum( Len shr 6 );
  159. end;
  160. else
  161. begin
  162. ShowMessage( 'Error! BCKandCOPY at the beginning' );
  163. Halt;
  164. end;
  165. END;
  166. cmdINSERT:
  167. begin
  168. CASE Cmd OF
  169. cmdFWDandCOPY:
  170. begin
  171. WriteByte( Len and $3F or $00 or MakeFlag( $40, Len > 63 ) );
  172. if Len > 63 then WriteNum( Len shr 6 );
  173. end;
  174. cmdBCKandCOPY:
  175. begin
  176. WriteByte( Len and $3F or $80 or MakeFlag( $40, Len > 63 ) );
  177. if Len > 63 then WriteNum( Len shr 6 );
  178. end;
  179. else
  180. begin
  181. ShowMessage( 'Error! INSERT after INSERT' );
  182. Halt;
  183. end;
  184. END;
  185. end;
  186. cmdBCKandCOPY, cmdFWDandCOPY:
  187. begin
  188. CASE Cmd OF
  189. cmdINSERT:
  190. begin
  191. WriteByte( Len and $3F or $80 or MakeFlag( $40, Len > 63 ) );
  192. if Len > 63 then WriteNum( Len shr 6 );
  193. end;
  194. cmdFWDandCOPY:
  195. begin
  196. WriteByte( Len and $1F or $00 or MakeFlag( $20, Len > 31 ) );
  197. if Len > 31 then WriteNum( Len shr 5 );
  198. end;
  199. cmdBCKandCOPY:
  200. begin
  201. WriteByte( Len and $1F or $40 or MakeFlag( $20, Len > 31 ) );
  202. if Len > 31 then WriteNum( Len shr 5 );
  203. end;
  204. END;
  205. end;
  206. END;
  207. PrevCmd := Cmd;
  208. end;
  209. var OldPos, NewPos: Integer;
  210. // Вычисляет предположительный размер команды BCKandCOPY или FWDandCOPY.
  211. function CalcCmdLen( OldIdx: Integer; LCopy: Integer ): Integer;
  212. var //Cmd: TCommand;
  213. Off: Integer;
  214. begin
  215. if OldIdx < OldPos then
  216. begin
  217. //Cmd := cmdBCKandCOPY;
  218. Off := OldPos-OldIdx-1-LCopy;
  219. end
  220. else
  221. begin
  222. //Cmd := cmdFWDandCOPY;
  223. Off := OldIdx - OldPos;
  224. end;
  225. Dec( LCopy );
  226. Result := 1 + CalcNumLen( Off );
  227. CASE PrevCmd OF
  228. cmdNONE, cmdINSERT:
  229. if LCopy > 63 then Inc( Result, CalcNumLen( LCopy shr 6 ) );
  230. cmdBCKandCOPY, cmdFWDandCOPY:
  231. if LCopy > 31 then Inc( Result, CalcNumLen( LCopy shr 5 ) );
  232. END;
  233. end;
  234. // Вычисляет предположительный размер команды BCKandCOPY или FWDandCOPY.
  235. function CalcCmdLen2( NewIdx: Integer; LCopy: Integer ): Integer;
  236. var //Cmd: TCommand;
  237. Off: Integer;
  238. begin
  239. if NewIdx < NewPos then
  240. begin
  241. //Cmd := cmdBCKandCOPY;
  242. Off := NewPos-NewIdx-1-LCopy;
  243. end
  244. else
  245. begin
  246. //Cmd := cmdFWDandCOPY;
  247. Off := NewIdx - NewPos;
  248. end;
  249. Dec( LCopy );
  250. Result := 1 + CalcNumLen( Off );
  251. CASE PrevCmd OF
  252. cmdNONE, cmdINSERT:
  253. if LCopy > 63 then Inc( Result, CalcNumLen( LCopy shr 6 ) );
  254. cmdBCKandCOPY, cmdFWDandCOPY:
  255. if LCopy > 31 then Inc( Result, CalcNumLen( LCopy shr 5 ) );
  256. END;
  257. end;
  258. // изображение прогресса просмотра новой версии файла.
  259. function ShowProgress_Cancel: Boolean;
  260. var Pr: Integer;
  261. begin
  262. Pr := NewPos * 100 div NewLen;
  263. Result := FALSE;
  264. if Assigned( OnProgress ) then
  265. OnProgress( Pr, NewPos, NewLen, Result );
  266. end;
  267. // поиск в старом файле последовательности байтов, по возможности большей длины,
  268. // совпадающей с байтами в новой версии файла в позиции NewIdx.
  269. // Если удается найти такую, возвращается позиция в старой версии файла
  270. // и LenFound = длина найденной посл-сти.
  271. function SearchSimilar( NewIdx: Integer; var LenFound: Integer ): Integer;
  272. function LexicographicCompare( X, Y: DWORD ): Integer;
  273. asm
  274. BSWAP EAX
  275. BSWAP EDX
  276. SUB EAX, EDX
  277. end;
  278. var I, L: Integer;
  279. Hash: DWORD;
  280. Ptr: PDWORD;
  281. Pos, CmdLenFound, CmdLen: Integer;
  282. begin
  283. Result := -1;
  284. LenFound := 0;
  285. CmdLenFound := 0;
  286. Hash := PDWORD( @ New[ NewIdx ] )^ and $FFFFFF;
  287. I := AccTable1[ Hash and $FFFF ]; // индекс первого элемента в SortTable1,
  288. // указывающего на последовательность в Old[],
  289. // начинающуюся с байтов New[ NewIdx ], New[ NewIdx + 1 ]
  290. if I = 0 then
  291. Exit; // нет таких последовательностей из 2х байт в Old[]
  292. for I := I to OldLen-4 do
  293. begin
  294. Ptr := Pointer( SortTable1[ I ] );
  295. if (Ptr^ and $FFFFFF) <> Hash then
  296. begin
  297. if LexicographicCompare( Ptr^ and $FFFFFF, Hash ) > 0 then
  298. begin
  299. Exit; // всё, все такие последовательности из по крайней мере трех байт кончились
  300. end;
  301. end
  302. else
  303. begin
  304. Pos := Integer( Ptr ) - Integer( @ Old[ 0 ] );
  305. L := BytesEqual( Pos, NewIdx );
  306. if L < 3 then Exit;
  307. //Assert( L >= 3, 'что-то не то' );
  308. if L >= 3 then
  309. begin
  310. // предотвратим появление отрицательного смещения:
  311. if (Pos < OldPos) and (Pos + L >= OldPos - 1) then
  312. L := OldPos - 1 - Pos;
  313. if L >= 2 then
  314. begin
  315. CmdLen := CalcCmdLen( Pos, L );
  316. if L + CmdLen > LenFound + CmdLenFound then
  317. begin
  318. CmdLenFound := CmdLen;
  319. LenFound := L;
  320. Result := Pos;
  321. end;
  322. end;
  323. end;
  324. end;
  325. end;
  326. end;
  327. var I, J, L: Integer;
  328. Found: Boolean;
  329. {$IFDEF WRITE_LEN_CC}
  330. CC: DWORD;
  331. {$ENDIF}
  332. begin
  333. Result := FALSE;
  334. Equal := FALSE;
  335. if (OldLen = NewLen) and (OldLen <> 0) and (CompareMem( Old, New, OldLen )) then
  336. begin
  337. Equal := TRUE;
  338. Exit;
  339. end;
  340. HashTable1 := AllocMem( 1 shl 21 );
  341. GetMem( SortTable1, (OldLen-3) * Sizeof( DWORD ) );
  342. AccTable1 := AllocMem( 65536 * Sizeof( DWORD ) );
  343. TRY
  344. if (HashTable1 = nil) or
  345. (SortTable1 = nil) or (AccTable1 = nil) then
  346. begin
  347. //ShowMessage( 'No memory to process (' + OldFile + '->' + NewFile + ').' );
  348. Exit;
  349. end;
  350. // Инициализируем хэш-таблицы:
  351. for I := 0 to OldLen-3 do
  352. begin
  353. J := PDWORD( @ Old[ I ] )^ and $FFFFFF;
  354. Byte( HashTable1[ J shr 3 ] ) := Byte( HashTable1[ J shr 3 ] ) or (1 shl (J and 7));
  355. end;
  356. // Строим таблицу быстрого поиска последовательностей:
  357. for I := 0 to OldLen-4 do
  358. SortTable1[ I ] := DWORD( @ Old[ I ] );
  359. SortData( SortTable1, OldLen-3, @ Compare4Bytes, @ SwapIndxes );
  360. for I := 0 to OldLen-4 do
  361. begin
  362. J := SortTable1[ I ];
  363. J := PDWORD( J )^ and $FFFF;
  364. if (AccTable1[ J ] = 0) or (AccTable1[ J ] > DWORD( I )) then
  365. AccTable1[ J ] := I; // AccTable1[ I ] = индексу первого вхождения последовательности
  366. // начинающейся с 2х байтов (J and $FF), (J shr 8)and $FF
  367. end;
  368. // Строим файл различий:
  369. OldPos := 0;
  370. NewPos := 0;
  371. {$IFDEF WRITE_LEN_CC}
  372. WriteNum( OldLen );
  373. // Посчитаем контрольную сумму:
  374. I := 0;
  375. CC := 0;
  376. while I < OldLen do
  377. begin
  378. CC := ((CC shl 1) or (CC shr 31)) xor PDWORD(@Old[ I ])^;
  379. Inc( I, 4 );
  380. end;
  381. Data.Write( CC, 4 );
  382. {$ENDIF}
  383. PrevCmd := cmdNone;
  384. while (NewPos < NewLen) do
  385. begin
  386. if ShowProgress_Cancel then Exit;
  387. L := BytesEqual( OldPos, NewPos );
  388. if L >= 2 then
  389. begin
  390. // совпадает участок достаточно хорошей длины, копируем его:
  391. WriteCommand( cmdFWDandCOPY, L );
  392. WriteByte( 0 ); // смещение = 0
  393. Inc( OldPos, L );
  394. Inc( NewPos, L );
  395. end
  396. else
  397. begin
  398. // иначе ищем следующий участок, который можно скопировать:
  399. Found := FALSE;
  400. for I := NewPos to NewLen-6 do
  401. begin
  402. //if (I and $1F) = 0 then
  403. begin
  404. if ShowProgress_Cancel then Exit;
  405. end;
  406. J := PDWORD( @ New[ I ] )^ and $FFFFFF;
  407. if ( Byte( HashTable1[ J shr 3 ] ) and (1 shl (J and 7))) = 0 then continue;
  408. J := SearchSimilar( I, L );
  409. if L > 0 then
  410. begin
  411. Found := TRUE;
  412. if I > NewPos then
  413. begin
  414. WriteCommand( cmdINSERT, I-NewPos );
  415. Data.Write( New[ NewPos ], I-NewPos );
  416. end;
  417. if J < OldPos then begin
  418. WriteCommand( cmdBCKandCOPY, L );
  419. WriteNum( OldPos-J-1-L );
  420. end else begin
  421. WriteCommand( cmdFWDandCOPY, L );
  422. WriteNum( J-OldPos );
  423. end;
  424. NewPos := I + L;
  425. OldPos := J + L;
  426. break;
  427. end;
  428. end;
  429. if not Found then
  430. begin
  431. for I := NewPos to NewLen-6 do
  432. begin
  433. //if (I and $1F) = 0 then
  434. begin
  435. if ShowProgress_Cancel then Exit;
  436. end;
  437. J := PDWORD( @ New[ I ] )^ and $FFFFFF;
  438. if ( Byte( HashTable1[ J shr 3 ] ) and (1 shl (J and 7))) = 0 then continue;
  439. J := SearchSimilar( I, L );
  440. if L > 0 then
  441. begin
  442. Found := TRUE;
  443. WriteCommand( cmdINSERT, I-NewPos );
  444. Data.Write( New[ NewPos ], I-NewPos );
  445. if J < OldPos then begin
  446. WriteCommand( cmdBCKandCOPY, L );
  447. WriteNum( OldPos-J-1-L );
  448. end else begin
  449. WriteCommand( cmdFWDandCOPY, L );
  450. WriteNum( J-OldPos );
  451. end;
  452. NewPos := I + L;
  453. OldPos := J + L;
  454. break;
  455. end;
  456. end;
  457. if not Found then
  458. begin
  459. // Вообще нет больше совпадений, остаток копируем вставкой.
  460. WriteCommand( cmdINSERT, NewLen-NewPos );
  461. Data.Write( New[ NewPos ], NewLen-NewPos );
  462. NewPos := NewLen;
  463. end;
  464. end;
  465. end;
  466. end;
  467. Result := TRUE;
  468. FINALLY
  469. FreeMem( HashTable1 );
  470. //FreeMem( HashTable2 );
  471. FreeMem( SortTable1 );
  472. FreeMem( AccTable1 );
  473. //FreeMem( SortTable2 );
  474. //FreeMem( AccTable2 );
  475. END;
  476. end;
  477. function ApplyUpdates( OutStrm, SourceStream, CmdStrm: PStream;
  478. OnProgress: TOnUpdatesProgress ): Boolean;
  479. var DataLen: DWORD;
  480. L: Integer;
  481. Pos0: DWORD;
  482. SrcPos: Integer;
  483. Src: PChar;
  484. function ShowProgress_Cancel: Boolean;
  485. var Pr: Integer;
  486. begin
  487. Pr := CmdStrm.Position * 100 div CmdStrm.Size;
  488. Result := FALSE;
  489. if Assigned( OnProgress ) then
  490. OnProgress( Pr, CmdStrm.Position, CmdStrm.Size, Result );
  491. end;
  492. function ReadNum( Shft: Integer = 0 ): Integer;
  493. var B: Byte;
  494. begin
  495. Result := 0;
  496. while CmdStrm.Position < CmdStrm.Size do
  497. begin
  498. CmdStrm.Read( B, 1 );
  499. Result := Result or ((B and $7F) shl Shft);
  500. Shft := Shft + 7;
  501. if (B and $80) = 0 then break;
  502. end;
  503. end;
  504. var I: Integer;
  505. B: Byte;
  506. Cmd: TCommand;
  507. PrevCmd: TCommand;
  508. begin
  509. Result := FALSE;
  510. // начинаем построение выходного файла
  511. SrcPos := 0;
  512. GetMem( Src, SourceStream.Size );
  513. TRY
  514. SourceStream.Position := 0;
  515. DataLen := CmdStrm.Size;
  516. SourceStream.Read( Src^, SourceStream.Size );
  517. PrevCmd := cmdNONE;
  518. Pos0 := CmdStrm.Position;
  519. while CmdStrm.Position < DWORD( Pos0 + DataLen ) do
  520. begin
  521. if ShowProgress_Cancel then Exit;
  522. // читаем команду:
  523. CmdStrm.Read( B, 1 );
  524. CASE PrevCmd OF
  525. cmdNONE:
  526. begin
  527. if (B and $80) = 0 then
  528. Cmd := cmdFWDandCOPY
  529. else
  530. Cmd := cmdINSERT;
  531. L := B and $3F;
  532. if (B and $40) <> 0 then
  533. L := L or ReadNum( 6 );
  534. end;
  535. cmdINSERT:
  536. begin
  537. if (B and $80) = 0 then
  538. Cmd := cmdFWDandCOPY
  539. else
  540. Cmd := cmdBCKandCOPY;
  541. L := B and $3F;
  542. if (B and $40) <> 0 then
  543. L := L or ReadNum( 6 );
  544. end;
  545. //cmdFWDandCOPY, cmdBCKandCOPY:
  546. else
  547. begin
  548. if (B and $80) = 0 then
  549. begin
  550. if (B and $40) = 0 then
  551. Cmd := cmdFWDandCOPY
  552. else
  553. Cmd := cmdBCKandCOPY;
  554. L := B and $1F;
  555. if (B and $20) <> 0 then
  556. L := L or ReadNum( 5 );
  557. end
  558. else
  559. begin
  560. Cmd := cmdINSERT;
  561. L := B and $3F;
  562. if (B and $40) <> 0 then
  563. L := L or ReadNum( 6 );
  564. end;
  565. end;
  566. END;
  567. {$IFDEF DEBUG}
  568. CASE PrevCmd OF
  569. cmdNONE: Exit;//Assert( Cmd in [cmdFWDandCOPY, cmdINSERT], '!' );
  570. cmdINSERT: Exit; //Assert( Cmd in [cmdFWDandCOPY, cmdBCKandCOPY], '!' );
  571. else ;
  572. END;
  573. {$ENDIF}
  574. PrevCmd := Cmd;
  575. Inc( L );
  576. {$IFDEF DEBUG}
  577. CASE Cmd OF
  578. cmdBCKandCOPY: Protocol.Add( 'BCKandCOPY ' + Int2Str( L ) );
  579. cmdFWDandCOPY: Protocol.Add( 'FWDandCOPY ' + Int2Str( L ) );
  580. cmdINSERT: Protocol.Add( 'INSERT ' + Int2Str( L ) );
  581. END;
  582. {$ENDIF}
  583. // выполняем команду:
  584. CASE Cmd OF
  585. cmdBCKandCOPY, // сместиться на N + L + 1 байт назад
  586. cmdFWDandCOPY: // или вперед и скопировать L байт из исходного файла:
  587. begin
  588. I := ReadNum( 0 );
  589. {$IFDEF DEBUG}
  590. Protocol.Add( 'OFFSET ' + Int2Str( I ) );
  591. {$ENDIF}
  592. if Cmd = cmdBCKandCOPY then SrcPos := SrcPos - 1 - I - L
  593. else SrcPos := SrcPos + I;
  594. {$IFDEF DEBUG}
  595. Protocol.Add( 'SRCPOS ' + Int2Str( SrcPos ) );
  596. if (SrcPos < 0) or (SrcPos >= InLen) then
  597. begin
  598. //MsgBox( 'out of bounds', MB_OK );
  599. Result := FALSE;
  600. Exit;
  601. end;
  602. {$ENDIF}
  603. OutStrm.Write( Src[ SrcPos ], L );
  604. {$IFDEF DEBUG}
  605. I := Min( 512, L );
  606. SetLength( S, I );
  607. Move( Src[ SrcPos + L - I ], S[ 1 ], I );
  608. Protocol.Add( 'LAST WRITTEN ARE: <' + S + '>' );
  609. {$ENDIF}
  610. Inc( SrcPos, L );
  611. end;
  612. cmdINSERT: // вставить L байтов прямо из командного файла:
  613. begin
  614. Stream2Stream( OutStrm, CmdStrm, L );
  615. {$IFDEF DEBUG}
  616. CmdStrm.Position := CmdStrm.Position - DWORD( L );
  617. SetLength( S, L );
  618. CmdStrm.Read( S[ 1 ], L );
  619. Protocol.Add( 'DATA: ' + Copy( S, 1, 100 ) );
  620. {$ENDIF}
  621. end;
  622. END;
  623. end;
  624. FINALLY
  625. FreeMem( Src );
  626. END;
  627. Result := TRUE;
  628. end;
  629. function MakeUpdates( DestCommandStream, LastVersion, PrevVersion: PStream;
  630. OnProgress: TOnUpdatesProgress ): Boolean;
  631. var Old, New: PChar;
  632. Eq: Boolean;
  633. begin
  634. Result := FALSE;
  635. GetMem( Old, PrevVersion.Size );
  636. GetMem( New, LastVersion.Size );
  637. TRY
  638. if LastVersion.Size > 0 then
  639. begin
  640. LastVersion.Position := 0;
  641. LastVersion.Read( New^, LastVersion.Size );
  642. end;
  643. if PrevVersion.Size > 0 then
  644. begin
  645. PrevVersion.Position := 0;
  646. PrevVersion.Read( Old^, PrevVersion.Size );
  647. end;
  648. if not MakePattern2( DestCommandStream, Old, New, PrevVersion.Size,
  649. LastVersion.Size, max( PrevVersion.Size, LastVersion.Size ), Eq,
  650. OnProgress ) then Exit;
  651. if Eq then Exit;
  652. Result := TRUE;
  653. FINALLY
  654. if Old <> nil then FreeMem( Old );
  655. if New <> nil then FreeMem( New );
  656. END;
  657. end;
  658. end.