Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | {*******************************************************} |
2 | { } |
||
3 | { BZIP2 Data Compression Interface Unit } |
||
4 | { } |
||
5 | { Similar to ZLIB Data Compression Interface Unit } |
||
6 | { } |
||
7 | {*******************************************************} |
||
8 | |||
9 | unit BZip2; |
||
10 | |||
11 | interface |
||
12 | |||
13 | uses Sysutils, Classes; |
||
14 | |||
15 | type |
||
16 | TAlloc = function(opaque: Pointer; Items, Size: Integer): Pointer; cdecl; |
||
17 | TFree = procedure(opaque, Block: Pointer); cdecl; |
||
18 | |||
19 | // Internal structure. Ignore. |
||
20 | TBZStreamRec = packed record |
||
21 | next_in: PChar; // next input byte |
||
22 | avail_in: Integer; // number of bytes available at next_in |
||
23 | total_in_lo32: Integer; // total nb of input bytes read so far |
||
24 | total_in_hi32: Integer; |
||
25 | |||
26 | next_out: PChar; // next output byte should be put here |
||
27 | avail_out: Integer; // remaining free space at next_out |
||
28 | total_out_lo32: Integer; // total nb of bytes output so far |
||
29 | total_out_hi32: Integer; |
||
30 | |||
31 | state: Pointer; |
||
32 | |||
33 | bzalloc: TAlloc; // used to allocate the internal state |
||
34 | bzfree: TFree; // used to free the internal state |
||
35 | opaque: Pointer; |
||
36 | end; |
||
37 | |||
38 | // Abstract ancestor class |
||
39 | TCustomBZip2Stream = class(TStream) |
||
40 | private |
||
41 | FStrm: TStream; |
||
42 | FStrmPos: Integer; |
||
43 | FOnProgress: TNotifyEvent; |
||
44 | FBZRec: TBZStreamRec; |
||
45 | FBuffer: array[Word] of Char; |
||
46 | protected |
||
47 | procedure Progress(Sender: TObject); dynamic; |
||
48 | property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; |
||
49 | constructor Create(Strm: TStream); |
||
50 | end; |
||
51 | |||
52 | { TBZCompressionStream compresses data on the fly as data is written to it, and |
||
53 | stores the compressed data to another stream. |
||
54 | |||
55 | TBZCompressionStream is write-only and strictly sequential. Reading from the |
||
56 | stream will raise an exception. Using Seek to move the stream pointer |
||
57 | will raise an exception. |
||
58 | |||
59 | Output data is cached internally, written to the output stream only when |
||
60 | the internal output buffer is full. All pending output data is flushed |
||
61 | when the stream is destroyed. |
||
62 | |||
63 | The Position property returns the number of uncompressed bytes of |
||
64 | data that have been written to the stream so far. |
||
65 | |||
66 | CompressionRate returns the on-the-fly percentage by which the original |
||
67 | data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 |
||
68 | If raw data size = 100 and compressed data size = 25, the CompressionRate |
||
69 | is 75% |
||
70 | |||
71 | The OnProgress event is called each time the output buffer is filled and |
||
72 | written to the output stream. This is useful for updating a progress |
||
73 | indicator when you are writing a large chunk of data to the compression |
||
74 | stream in a single call.} |
||
75 | |||
76 | |||
77 | TBlockSize100k = (bs1, bs2, bs3, bs4, bs5, bs6, bs7, bs8, bs9); |
||
78 | |||
79 | TBZCompressionStream = class(TCustomBZip2Stream) |
||
80 | private |
||
81 | function GetCompressionRate: Single; |
||
82 | public |
||
83 | constructor Create(BlockSize100k: TBlockSize100k; Dest: TStream); |
||
84 | destructor Destroy; override; |
||
85 | function Read(var Buffer; Count: Longint): Longint; override; |
||
86 | function Write(const Buffer; Count: Longint): Longint; override; |
||
87 | function Seek(Offset: Longint; Origin: Word): Longint; override; |
||
88 | property CompressionRate: Single read GetCompressionRate; |
||
89 | property OnProgress; |
||
90 | end; |
||
91 | |||
92 | { TDecompressionStream decompresses data on the fly as data is read from it. |
||
93 | |||
94 | Compressed data comes from a separate source stream. TDecompressionStream |
||
95 | is read-only and unidirectional; you can seek forward in the stream, but not |
||
96 | backwards. The special case of setting the stream position to zero is |
||
97 | allowed. Seeking forward decompresses data until the requested position in |
||
98 | the uncompressed data has been reached. Seeking backwards, seeking relative |
||
99 | to the end of the stream, requesting the size of the stream, and writing to |
||
100 | the stream will raise an exception. |
||
101 | |||
102 | The Position property returns the number of bytes of uncompressed data that |
||
103 | have been read from the stream so far. |
||
104 | |||
105 | The OnProgress event is called each time the internal input buffer of |
||
106 | compressed data is exhausted and the next block is read from the input stream. |
||
107 | This is useful for updating a progress indicator when you are reading a |
||
108 | large chunk of data from the decompression stream in a single call.} |
||
109 | |||
110 | TBZDecompressionStream = class(TCustomBZip2Stream) |
||
111 | public |
||
112 | constructor Create(Source: TStream); |
||
113 | destructor Destroy; override; |
||
114 | function Read(var Buffer; Count: Longint): Longint; override; |
||
115 | function Write(const Buffer; Count: Longint): Longint; override; |
||
116 | function Seek(Offset: Longint; Origin: Word): Longint; override; |
||
117 | property OnProgress; |
||
118 | end; |
||
119 | |||
120 | { CompressBuf compresses data, buffer to buffer, in one call. |
||
121 | In: InBuf = ptr to compressed data |
||
122 | InBytes = number of bytes in InBuf |
||
123 | Out: OutBuf = ptr to newly allocated buffer containing decompressed data |
||
124 | OutBytes = number of bytes in OutBuf } |
||
125 | procedure BZCompressBuf(const InBuf: Pointer; InBytes: Integer; |
||
126 | out OutBuf: Pointer; out OutBytes: Integer); |
||
127 | |||
128 | |||
129 | { DecompressBuf decompresses data, buffer to buffer, in one call. |
||
130 | In: InBuf = ptr to compressed data |
||
131 | InBytes = number of bytes in InBuf |
||
132 | OutEstimate = zero, or est. size of the decompressed data |
||
133 | Out: OutBuf = ptr to newly allocated buffer containing decompressed data |
||
134 | OutBytes = number of bytes in OutBuf } |
||
135 | procedure BZDecompressBuf(const InBuf: Pointer; InBytes: Integer; |
||
136 | OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); |
||
137 | |||
138 | type |
||
139 | EBZip2Error = class(Exception); |
||
140 | EBZCompressionError = class(EBZip2Error); |
||
141 | EBZDecompressionError = class(EBZip2Error); |
||
142 | |||
143 | implementation |
||
144 | |||
145 | {$L blocks~1.obj} //blocksort |
||
146 | {$L huffman.obj} |
||
147 | {$L compress.obj} |
||
148 | {$L decomp~1.obj} //decompress |
||
149 | {$L bzlib.obj} |
||
150 | { $L crctable.obj} |
||
151 | { $L randtable.obj} |
||
152 | |||
153 | procedure _BZ2_hbMakeCodeLengths; external; |
||
154 | procedure _BZ2_blockSort; external; |
||
155 | procedure _BZ2_hbCreateDecodeTables; external; |
||
156 | procedure _BZ2_hbAssignCodes; external; |
||
157 | procedure _BZ2_compressBlock; external; |
||
158 | procedure _BZ2_decompress; external; |
||
159 | |||
160 | const |
||
161 | BZ_RUN = 0; |
||
162 | BZ_FLUSH = 1; |
||
163 | BZ_FINISH = 2; |
||
164 | BZ_OK = 0; |
||
165 | BZ_RUN_OK = 1; |
||
166 | BZ_FLUSH_OK = 2; |
||
167 | BZ_FINISH_OK = 3; |
||
168 | BZ_STREAM_END = 4; |
||
169 | BZ_SEQUENCE_ERROR = (-1); |
||
170 | BZ_PARAM_ERROR = (-2); |
||
171 | BZ_MEM_ERROR = (-3); |
||
172 | BZ_DATA_ERROR = (-4); |
||
173 | BZ_DATA_ERROR_MAGIC = (-5); |
||
174 | BZ_IO_ERROR = (-6); |
||
175 | BZ_UNEXPECTED_EOF = (-7); |
||
176 | BZ_OUTBUFF_FULL = (-8); |
||
177 | |||
178 | BZ_BLOCK_SIZE_100K = 9; |
||
179 | |||
180 | _BZ2_rNums: array[0..511] of Longint = ( |
||
181 | 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, |
||
182 | 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, |
||
183 | 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, |
||
184 | 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, |
||
185 | 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, |
||
186 | 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, |
||
187 | 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, |
||
188 | 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, |
||
189 | 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, |
||
190 | 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, |
||
191 | 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, |
||
192 | 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, |
||
193 | 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, |
||
194 | 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, |
||
195 | 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, |
||
196 | 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, |
||
197 | 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, |
||
198 | 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, |
||
199 | 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, |
||
200 | 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, |
||
201 | 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, |
||
202 | 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, |
||
203 | 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, |
||
204 | 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, |
||
205 | 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, |
||
206 | 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, |
||
207 | 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, |
||
208 | 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, |
||
209 | 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, |
||
210 | 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, |
||
211 | 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, |
||
212 | 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, |
||
213 | 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, |
||
214 | 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, |
||
215 | 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, |
||
216 | 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, |
||
217 | 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, |
||
218 | 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, |
||
219 | 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, |
||
220 | 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, |
||
221 | 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, |
||
222 | 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, |
||
223 | 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, |
||
224 | 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, |
||
225 | 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, |
||
226 | 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, |
||
227 | 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, |
||
228 | 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, |
||
229 | 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, |
||
230 | 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, |
||
231 | 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, |
||
232 | 936, 638 |
||
233 | ); |
||
234 | |||
235 | _BZ2_crc32Table: array[0..255] of Longint = ( |
||
236 | $00000000, $04C11DB7, $09823B6E, $0D4326D9, |
||
237 | $130476DC, $17C56B6B, $1A864DB2, $1E475005, |
||
238 | $2608EDB8, $22C9F00F, $2F8AD6D6, $2B4BCB61, |
||
239 | $350C9B64, $31CD86D3, $3C8EA00A, $384FBDBD, |
||
240 | $4C11DB70, $48D0C6C7, $4593E01E, $4152FDA9, |
||
241 | $5F15ADAC, $5BD4B01B, $569796C2, $52568B75, |
||
242 | $6A1936C8, $6ED82B7F, $639B0DA6, $675A1011, |
||
243 | $791D4014, $7DDC5DA3, $709F7B7A, $745E66CD, |
||
244 | -$67DC4920, -$631D54A9, -$6E5E7272, -$6A9F6FC7, |
||
245 | -$74D83FC4, -$70192275, -$7D5A04AE, -$799B191B, |
||
246 | -$41D4A4A8, -$4515B911, -$48569FCA, -$4C97827F, |
||
247 | -$52D0D27C, -$5611CFCD, -$5B52E916, -$5F93F4A3, |
||
248 | -$2BCD9270, -$2F0C8FD9, -$224FA902, -$268EB4B7, |
||
249 | -$38C9E4B4, -$3C08F905, -$314BDFDE, -$358AC26B, |
||
250 | -$0DC57FD8, -$09046261, -$044744BA, -$0086590F, |
||
251 | -$1EC1090C, -$1A0014BD, -$17433266, -$13822FD3, |
||
252 | $34867077, $30476DC0, $3D044B19, $39C556AE, |
||
253 | $278206AB, $23431B1C, $2E003DC5, $2AC12072, |
||
254 | $128E9DCF, $164F8078, $1B0CA6A1, $1FCDBB16, |
||
255 | $018AEB13, $054BF6A4, $0808D07D, $0CC9CDCA, |
||
256 | $7897AB07, $7C56B6B0, $71159069, $75D48DDE, |
||
257 | $6B93DDDB, $6F52C06C, $6211E6B5, $66D0FB02, |
||
258 | $5E9F46BF, $5A5E5B08, $571D7DD1, $53DC6066, |
||
259 | $4D9B3063, $495A2DD4, $44190B0D, $40D816BA, |
||
260 | -$535A3969, -$579B24E0, -$5AD80207, -$5E191FB2, |
||
261 | -$405E4FB5, -$449F5204, -$49DC74DB, -$4D1D696E, |
||
262 | -$7552D4D1, -$7193C968, -$7CD0EFBF, -$7811F20A, |
||
263 | -$6656A20D, -$6297BFBC, -$6FD49963, -$6B1584D6, |
||
264 | -$1F4BE219, -$1B8AFFB0, -$16C9D977, -$1208C4C2, |
||
265 | -$0C4F94C5, -$088E8974, -$05CDAFAB, -$010CB21E, |
||
266 | -$39430FA1, -$3D821218, -$30C134CF, -$3400297A, |
||
267 | -$2A47797D, -$2E8664CC, -$23C54213, -$27045FA6, |
||
268 | $690CE0EE, $6DCDFD59, $608EDB80, $644FC637, |
||
269 | $7A089632, $7EC98B85, $738AAD5C, $774BB0EB, |
||
270 | $4F040D56, $4BC510E1, $46863638, $42472B8F, |
||
271 | $5C007B8A, $58C1663D, $558240E4, $51435D53, |
||
272 | $251D3B9E, $21DC2629, $2C9F00F0, $285E1D47, |
||
273 | $36194D42, $32D850F5, $3F9B762C, $3B5A6B9B, |
||
274 | $0315D626, $07D4CB91, $0A97ED48, $0E56F0FF, |
||
275 | $1011A0FA, $14D0BD4D, $19939B94, $1D528623, |
||
276 | -$0ED0A9F2, -$0A11B447, -$075292A0, -$03938F29, |
||
277 | -$1DD4DF2E, -$1915C29B, -$1456E444, -$1097F9F5, |
||
278 | -$28D8444A, -$2C1959FF, -$215A7F28, -$259B6291, |
||
279 | -$3BDC3296, -$3F1D2F23, -$325E09FC, -$369F144D, |
||
280 | -$42C17282, -$46006F37, -$4B4349F0, -$4F825459, |
||
281 | -$51C5045E, -$550419EB, -$58473F34, -$5C862285, |
||
282 | -$64C99F3A, -$6008828F, -$6D4BA458, -$698AB9E1, |
||
283 | -$77CDE9E6, -$730CF453, -$7E4FD28C, -$7A8ECF3D, |
||
284 | $5D8A9099, $594B8D2E, $5408ABF7, $50C9B640, |
||
285 | $4E8EE645, $4A4FFBF2, $470CDD2B, $43CDC09C, |
||
286 | $7B827D21, $7F436096, $7200464F, $76C15BF8, |
||
287 | $68860BFD, $6C47164A, $61043093, $65C52D24, |
||
288 | $119B4BE9, $155A565E, $18197087, $1CD86D30, |
||
289 | $029F3D35, $065E2082, $0B1D065B, $0FDC1BEC, |
||
290 | $3793A651, $3352BBE6, $3E119D3F, $3AD08088, |
||
291 | $2497D08D, $2056CD3A, $2D15EBE3, $29D4F654, |
||
292 | -$3A56D987, -$3E97C432, -$33D4E2E9, -$3715FF60, |
||
293 | -$2952AF5B, -$2D93B2EE, -$20D09435, -$24118984, |
||
294 | -$1C5E343F, -$189F298A, -$15DC0F51, -$111D12E8, |
||
295 | -$0F5A42E3, -$0B9B5F56, -$06D8798D, -$0219643C, |
||
296 | -$764702F7, -$72861F42, -$7FC53999, -$7B042430, |
||
297 | -$6543742B, -$6182699E, -$6CC14F45, -$680052F4, |
||
298 | -$504FEF4F, -$548EF2FA, -$59CDD421, -$5D0CC998, |
||
299 | -$434B9993, -$478A8426, -$4AC9A2FD, -$4E08BF4C |
||
300 | ); |
||
301 | |||
302 | procedure _bz_internal_error(errcode: Integer); cdecl; |
||
303 | begin |
||
304 | raise EBZip2Error.CreateFmt('Compression Error %d', [errcode]); |
||
305 | end; |
||
306 | |||
307 | function _malloc(size: Integer): Pointer; cdecl; |
||
308 | begin |
||
309 | GetMem(Result, Size); |
||
310 | end; |
||
311 | |||
312 | procedure _free(block: Pointer); cdecl; |
||
313 | begin |
||
314 | FreeMem(block); |
||
315 | end; |
||
316 | |||
317 | // deflate compresses data |
||
318 | |||
319 | function BZ2_bzCompressInit(var strm: TBZStreamRec; blockSize100k: Integer; |
||
320 | verbosity: Integer; workFactor: Integer): Integer; stdcall; external; |
||
321 | |||
322 | function BZ2_bzCompress(var strm: TBZStreamRec; action: Integer): Integer; stdcall; external; |
||
323 | |||
324 | function BZ2_bzCompressEnd(var strm: TBZStreamRec): Integer; stdcall; external; |
||
325 | |||
326 | function BZ2_bzBuffToBuffCompress(dest: Pointer; var destLen: Integer; source: Pointer; |
||
327 | sourceLen, blockSize100k, verbosity, workFactor: Integer): Integer; stdcall; external; |
||
328 | |||
329 | // inflate decompresses data |
||
330 | |||
331 | function BZ2_bzDecompressInit(var strm: TBZStreamRec; verbosity: Integer; |
||
332 | small: Integer): Integer; stdcall; external; |
||
333 | |||
334 | function BZ2_bzDecompress(var strm: TBZStreamRec): Integer; stdcall; external; |
||
335 | |||
336 | function BZ2_bzDecompressEnd(var strm: TBZStreamRec): Integer; stdcall; external; |
||
337 | |||
338 | function BZ2_bzBuffToBuffDecompress(dest: Pointer; var destLen: Integer; source: Pointer; |
||
339 | sourceLen, small, verbosity: Integer): Integer; stdcall; external; |
||
340 | |||
341 | |||
342 | function bzip2AllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl; |
||
343 | begin |
||
344 | GetMem(Result, Items * Size); |
||
345 | end; |
||
346 | |||
347 | procedure bzip2FreeMem(AppData, Block: Pointer); cdecl; |
||
348 | begin |
||
349 | FreeMem(Block); |
||
350 | end; |
||
351 | |||
352 | { |
||
353 | function zlibCheck(code: Integer): Integer; |
||
354 | begin |
||
355 | Result := code; |
||
356 | if code < 0 then |
||
357 | raise EZlibError.Create('error'); //!! |
||
358 | end; |
||
359 | } |
||
360 | |||
361 | function CCheck(code: Integer): Integer; |
||
362 | begin |
||
363 | Result := code; |
||
364 | if code < 0 then |
||
365 | raise EBZCompressionError.CreateFmt('error %d', [code]); //!! |
||
366 | end; |
||
367 | |||
368 | function DCheck(code: Integer): Integer; |
||
369 | begin |
||
370 | Result := code; |
||
371 | if code < 0 then |
||
372 | raise EBZDecompressionError.CreateFmt('error %d', [code]); //!! |
||
373 | end; |
||
374 | |||
375 | |||
376 | procedure BZCompressBuf(const InBuf: Pointer; InBytes: Integer; |
||
377 | out OutBuf: Pointer; out OutBytes: Integer); |
||
378 | var |
||
379 | strm: TBZStreamRec; |
||
380 | P: Pointer; |
||
381 | begin |
||
382 | FillChar(strm, sizeof(strm), 0); |
||
383 | strm.bzalloc := bzip2AllocMem; |
||
384 | strm.bzfree := bzip2FreeMem; |
||
385 | OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; |
||
386 | GetMem(OutBuf, OutBytes); |
||
387 | try |
||
388 | strm.next_in := InBuf; |
||
389 | strm.avail_in := InBytes; |
||
390 | strm.next_out := OutBuf; |
||
391 | strm.avail_out := OutBytes; |
||
392 | CCheck(BZ2_bzCompressInit(strm, 9, 0, 0)); |
||
393 | try |
||
394 | while CCheck(BZ2_bzCompress(strm, BZ_FINISH)) <> BZ_STREAM_END do |
||
395 | begin |
||
396 | P := OutBuf; |
||
397 | Inc(OutBytes, 256); |
||
398 | ReallocMem(OutBuf, OutBytes); |
||
399 | strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); |
||
400 | strm.avail_out := 256; |
||
401 | end; |
||
402 | finally |
||
403 | CCheck(BZ2_bzCompressEnd(strm)); |
||
404 | end; |
||
405 | ReallocMem(OutBuf, strm.total_out_lo32); |
||
406 | OutBytes := strm.total_out_lo32; |
||
407 | except |
||
408 | FreeMem(OutBuf); |
||
409 | raise |
||
410 | end; |
||
411 | end; |
||
412 | |||
413 | |||
414 | procedure BZDecompressBuf(const InBuf: Pointer; InBytes: Integer; |
||
415 | OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); |
||
416 | var |
||
417 | strm: TBZStreamRec; |
||
418 | P: Pointer; |
||
419 | BufInc: Integer; |
||
420 | begin |
||
421 | FillChar(strm, sizeof(strm), 0); |
||
422 | strm.bzalloc := bzip2AllocMem; |
||
423 | strm.bzfree := bzip2FreeMem; |
||
424 | BufInc := (InBytes + 255) and not 255; |
||
425 | if OutEstimate = 0 then |
||
426 | OutBytes := BufInc |
||
427 | else |
||
428 | OutBytes := OutEstimate; |
||
429 | GetMem(OutBuf, OutBytes); |
||
430 | try |
||
431 | strm.next_in := InBuf; |
||
432 | strm.avail_in := InBytes; |
||
433 | strm.next_out := OutBuf; |
||
434 | strm.avail_out := OutBytes; |
||
435 | DCheck(BZ2_bzDecompressInit(strm, 0, 0)); |
||
436 | try |
||
437 | while DCheck(BZ2_bzDecompress(strm)) <> BZ_STREAM_END do |
||
438 | begin |
||
439 | P := OutBuf; |
||
440 | Inc(OutBytes, BufInc); |
||
441 | ReallocMem(OutBuf, OutBytes); |
||
442 | strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); |
||
443 | strm.avail_out := BufInc; |
||
444 | end; |
||
445 | finally |
||
446 | DCheck(BZ2_bzDecompressEnd(strm)); |
||
447 | end; |
||
448 | ReallocMem(OutBuf, strm.total_out_lo32); |
||
449 | OutBytes := strm.total_out_lo32; |
||
450 | except |
||
451 | FreeMem(OutBuf); |
||
452 | raise |
||
453 | end; |
||
454 | end; |
||
455 | |||
456 | // TCustomBZip2Stream |
||
457 | |||
458 | constructor TCustomBZip2Stream.Create(Strm: TStream); |
||
459 | begin |
||
460 | inherited Create; |
||
461 | FStrm := Strm; |
||
462 | FStrmPos := Strm.Position; |
||
463 | FBZRec.bzalloc := bzip2AllocMem; |
||
464 | FBZRec.bzfree := bzip2FreeMem; |
||
465 | end; |
||
466 | |||
467 | procedure TCustomBZip2Stream.Progress(Sender: TObject); |
||
468 | begin |
||
469 | if Assigned(FOnProgress) then FOnProgress(Sender); |
||
470 | end; |
||
471 | |||
472 | |||
473 | // TBZCompressionStream |
||
474 | |||
475 | constructor TBZCompressionStream.Create(BlockSize100k: TBlockSize100k; Dest: TStream); |
||
476 | const |
||
477 | BlockSizes: array[TBlockSize100k] of ShortInt = (1, 2, 3, 4, 5, 6, 7, 8, 9); |
||
478 | begin |
||
479 | inherited Create(Dest); |
||
480 | FBZRec.next_out := FBuffer; |
||
481 | FBZRec.avail_out := sizeof(FBuffer); |
||
482 | CCheck(BZ2_bzCompressInit(FBZRec, BlockSizes[BlockSize100k], 0, 0)); |
||
483 | end; |
||
484 | |||
485 | destructor TBZCompressionStream.Destroy; |
||
486 | begin |
||
487 | FBZRec.next_in := nil; |
||
488 | FBZRec.avail_in := 0; |
||
489 | try |
||
490 | if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; |
||
491 | while (CCheck(BZ2_bzCompress(FBZRec, BZ_FINISH)) <> BZ_STREAM_END) |
||
492 | and (FBZRec.avail_out = 0) do |
||
493 | begin |
||
494 | FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); |
||
495 | FBZRec.next_out := FBuffer; |
||
496 | FBZRec.avail_out := sizeof(FBuffer); |
||
497 | end; |
||
498 | if FBZRec.avail_out < sizeof(FBuffer) then |
||
499 | FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FBZRec.avail_out); |
||
500 | finally |
||
501 | BZ2_bzCompressEnd(FBZRec); |
||
502 | end; |
||
503 | inherited Destroy; |
||
504 | end; |
||
505 | |||
506 | function TBZCompressionStream.Read(var Buffer; Count: Longint): Longint; |
||
507 | begin |
||
508 | raise EBZCompressionError.Create('Invalid stream operation'); |
||
509 | end; |
||
510 | |||
511 | function TBZCompressionStream.Write(const Buffer; Count: Longint): Longint; |
||
512 | begin |
||
513 | FBZRec.next_in := @Buffer; |
||
514 | FBZRec.avail_in := Count; |
||
515 | if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; |
||
516 | while (FBZRec.avail_in > 0) do |
||
517 | begin |
||
518 | CCheck(BZ2_bzCompress(FBZRec, BZ_RUN)); |
||
519 | if FBZRec.avail_out = 0 then |
||
520 | begin |
||
521 | FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); |
||
522 | FBZRec.next_out := FBuffer; |
||
523 | FBZRec.avail_out := sizeof(FBuffer); |
||
524 | FStrmPos := FStrm.Position; |
||
525 | end; |
||
526 | Progress(Self); |
||
527 | end; |
||
528 | Result := Count; |
||
529 | end; |
||
530 | |||
531 | function TBZCompressionStream.Seek(Offset: Longint; Origin: Word): Longint; |
||
532 | begin |
||
533 | if (Offset = 0) and (Origin = soFromCurrent) then |
||
534 | Result := FBZRec.total_in_lo32 |
||
535 | else |
||
536 | raise EBZCompressionError.Create('Invalid stream operation'); |
||
537 | end; |
||
538 | |||
539 | function TBZCompressionStream.GetCompressionRate: Single; |
||
540 | begin |
||
541 | if FBZRec.total_in_lo32 = 0 then |
||
542 | Result := 0 |
||
543 | else |
||
544 | Result := (1.0 - (FBZRec.total_out_lo32 / FBZRec.total_in_lo32)) * 100.0; |
||
545 | end; |
||
546 | |||
547 | |||
548 | // TDecompressionStream |
||
549 | |||
550 | constructor TBZDecompressionStream.Create(Source: TStream); |
||
551 | begin |
||
552 | inherited Create(Source); |
||
553 | FBZRec.next_in := FBuffer; |
||
554 | FBZRec.avail_in := 0; |
||
555 | DCheck(BZ2_bzDecompressInit(FBZRec, 0, 0)); |
||
556 | end; |
||
557 | |||
558 | destructor TBZDecompressionStream.Destroy; |
||
559 | begin |
||
560 | BZ2_bzDecompressEnd(FBZRec); |
||
561 | inherited Destroy; |
||
562 | end; |
||
563 | |||
564 | function TBZDecompressionStream.Read(var Buffer; Count: Longint): Longint; |
||
565 | begin |
||
566 | FBZRec.next_out := @Buffer; |
||
567 | FBZRec.avail_out := Count; |
||
568 | if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; |
||
569 | while (FBZRec.avail_out > 0) do |
||
570 | begin |
||
571 | if FBZRec.avail_in = 0 then |
||
572 | begin |
||
573 | FBZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); |
||
574 | if FBZRec.avail_in = 0 then |
||
575 | begin |
||
576 | Result := Count - FBZRec.avail_out; |
||
577 | Exit; |
||
578 | end; |
||
579 | FBZRec.next_in := FBuffer; |
||
580 | FStrmPos := FStrm.Position; |
||
581 | end; |
||
582 | CCheck(BZ2_bzDecompress(FBZRec)); |
||
583 | Progress(Self); |
||
584 | end; |
||
585 | Result := Count; |
||
586 | end; |
||
587 | |||
588 | function TBZDecompressionStream.Write(const Buffer; Count: Longint): Longint; |
||
589 | begin |
||
590 | raise EBZDecompressionError.Create('Invalid stream operation'); |
||
591 | end; |
||
592 | |||
593 | function TBZDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint; |
||
594 | var |
||
595 | I: Integer; |
||
596 | Buf: array[0..4095] of Char; |
||
597 | begin |
||
598 | if (Offset = 0) and (Origin = soFromBeginning) then |
||
599 | begin |
||
600 | DCheck(BZ2_bzDecompressEnd(FBZRec)); |
||
601 | DCheck(BZ2_bzDecompressInit(FBZRec, 0, 0)); |
||
602 | FBZRec.next_in := FBuffer; |
||
603 | FBZRec.avail_in := 0; |
||
604 | FStrm.Position := 0; |
||
605 | FStrmPos := 0; |
||
606 | end |
||
607 | else if ((Offset >= 0) and (Origin = soFromCurrent)) or |
||
608 | (((Offset - FBZRec.total_out_lo32) > 0) and (Origin = soFromBeginning)) then |
||
609 | begin |
||
610 | if Origin = soFromBeginning then Dec(Offset, FBZRec.total_out_lo32); |
||
611 | if Offset > 0 then |
||
612 | begin |
||
613 | for I := 1 to Offset div sizeof(Buf) do |
||
614 | ReadBuffer(Buf, sizeof(Buf)); |
||
615 | ReadBuffer(Buf, Offset mod sizeof(Buf)); |
||
616 | end; |
||
617 | end |
||
618 | else |
||
619 | raise EBZDecompressionError.Create('Invalid stream operation'); |
||
620 | Result := FBZRec.total_out_lo32; |
||
621 | end; |
||
622 | |||
623 | end. |
||
624 | |||
625 |