Mercurial > repos > SharpZipLib
comparison BZip2/BZip2InputStream.cs @ 1:94e25b786321
Re #311: can't read ZIP file packed by Linux app Archive Manager/File Roller
Initial commit of clean SharpZipLib 0860 source. Only change is build paths.
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sat, 30 Oct 2010 14:03:17 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:d16ef17fa7bb | 1:94e25b786321 |
---|---|
1 // BZip2InputStream.cs | |
2 // | |
3 // Copyright (C) 2001 Mike Krueger | |
4 // | |
5 // This program is free software; you can redistribute it and/or | |
6 // modify it under the terms of the GNU General Public License | |
7 // as published by the Free Software Foundation; either version 2 | |
8 // of the License, or (at your option) any later version. | |
9 // | |
10 // This program is distributed in the hope that it will be useful, | |
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 // GNU General Public License for more details. | |
14 // | |
15 // You should have received a copy of the GNU General Public License | |
16 // along with this program; if not, write to the Free Software | |
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 // | |
19 // Linking this library statically or dynamically with other modules is | |
20 // making a combined work based on this library. Thus, the terms and | |
21 // conditions of the GNU General Public License cover the whole | |
22 // combination. | |
23 // | |
24 // As a special exception, the copyright holders of this library give you | |
25 // permission to link this library with independent modules to produce an | |
26 // executable, regardless of the license terms of these independent | |
27 // modules, and to copy and distribute the resulting executable under | |
28 // terms of your choice, provided that you also meet, for each linked | |
29 // independent module, the terms and conditions of the license of that | |
30 // module. An independent module is a module which is not derived from | |
31 // or based on this library. If you modify this library, you may extend | |
32 // this exception to your version of the library, but you are not | |
33 // obligated to do so. If you do not wish to do so, delete this | |
34 // exception statement from your version. | |
35 | |
36 using System; | |
37 using System.IO; | |
38 | |
39 using ICSharpCode.SharpZipLib.Checksums; | |
40 | |
41 namespace ICSharpCode.SharpZipLib.BZip2 | |
42 { | |
43 | |
44 /// <summary> | |
45 /// An input stream that decompresses files in the BZip2 format | |
46 /// </summary> | |
47 public class BZip2InputStream : Stream | |
48 { | |
49 #region Constants | |
50 const int START_BLOCK_STATE = 1; | |
51 const int RAND_PART_A_STATE = 2; | |
52 const int RAND_PART_B_STATE = 3; | |
53 const int RAND_PART_C_STATE = 4; | |
54 const int NO_RAND_PART_A_STATE = 5; | |
55 const int NO_RAND_PART_B_STATE = 6; | |
56 const int NO_RAND_PART_C_STATE = 7; | |
57 #endregion | |
58 #region Constructors | |
59 /// <summary> | |
60 /// Construct instance for reading from stream | |
61 /// </summary> | |
62 /// <param name="stream">Data source</param> | |
63 public BZip2InputStream(Stream stream) | |
64 { | |
65 // init arrays | |
66 for (int i = 0; i < BZip2Constants.GroupCount; ++i) | |
67 { | |
68 limit[i] = new int[BZip2Constants.MaximumAlphaSize]; | |
69 baseArray[i] = new int[BZip2Constants.MaximumAlphaSize]; | |
70 perm[i] = new int[BZip2Constants.MaximumAlphaSize]; | |
71 } | |
72 | |
73 BsSetStream(stream); | |
74 Initialize(); | |
75 InitBlock(); | |
76 SetupBlock(); | |
77 } | |
78 | |
79 #endregion | |
80 | |
81 /// <summary> | |
82 /// Get/set flag indicating ownership of underlying stream. | |
83 /// When the flag is true <see cref="Close"></see> will close the underlying stream also. | |
84 /// </summary> | |
85 public bool IsStreamOwner | |
86 { | |
87 get { return isStreamOwner; } | |
88 set { isStreamOwner = value; } | |
89 } | |
90 | |
91 | |
92 #region Stream Overrides | |
93 /// <summary> | |
94 /// Gets a value indicating if the stream supports reading | |
95 /// </summary> | |
96 public override bool CanRead | |
97 { | |
98 get { | |
99 return baseStream.CanRead; | |
100 } | |
101 } | |
102 | |
103 /// <summary> | |
104 /// Gets a value indicating whether the current stream supports seeking. | |
105 /// </summary> | |
106 public override bool CanSeek { | |
107 get { | |
108 return baseStream.CanSeek; | |
109 } | |
110 } | |
111 | |
112 /// <summary> | |
113 /// Gets a value indicating whether the current stream supports writing. | |
114 /// This property always returns false | |
115 /// </summary> | |
116 public override bool CanWrite { | |
117 get { | |
118 return false; | |
119 } | |
120 } | |
121 | |
122 /// <summary> | |
123 /// Gets the length in bytes of the stream. | |
124 /// </summary> | |
125 public override long Length { | |
126 get { | |
127 return baseStream.Length; | |
128 } | |
129 } | |
130 | |
131 /// <summary> | |
132 /// Gets or sets the streams position. | |
133 /// Setting the position is not supported and will throw a NotSupportException | |
134 /// </summary> | |
135 /// <exception cref="NotSupportedException">Any attempt to set the position</exception> | |
136 public override long Position { | |
137 get { | |
138 return baseStream.Position; | |
139 } | |
140 set { | |
141 throw new NotSupportedException("BZip2InputStream position cannot be set"); | |
142 } | |
143 } | |
144 | |
145 /// <summary> | |
146 /// Flushes the stream. | |
147 /// </summary> | |
148 public override void Flush() | |
149 { | |
150 if (baseStream != null) { | |
151 baseStream.Flush(); | |
152 } | |
153 } | |
154 | |
155 /// <summary> | |
156 /// Set the streams position. This operation is not supported and will throw a NotSupportedException | |
157 /// </summary> | |
158 /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param> | |
159 /// <param name="origin">A value of type <see cref="SeekOrigin"/> indicating the reference point used to obtain the new position.</param> | |
160 /// <returns>The new position of the stream.</returns> | |
161 /// <exception cref="NotSupportedException">Any access</exception> | |
162 public override long Seek(long offset, SeekOrigin origin) | |
163 { | |
164 throw new NotSupportedException("BZip2InputStream Seek not supported"); | |
165 } | |
166 | |
167 /// <summary> | |
168 /// Sets the length of this stream to the given value. | |
169 /// This operation is not supported and will throw a NotSupportedExceptionortedException | |
170 /// </summary> | |
171 /// <param name="value">The new length for the stream.</param> | |
172 /// <exception cref="NotSupportedException">Any access</exception> | |
173 public override void SetLength(long value) | |
174 { | |
175 throw new NotSupportedException("BZip2InputStream SetLength not supported"); | |
176 } | |
177 | |
178 /// <summary> | |
179 /// Writes a block of bytes to this stream using data from a buffer. | |
180 /// This operation is not supported and will throw a NotSupportedException | |
181 /// </summary> | |
182 /// <param name="buffer">The buffer to source data from.</param> | |
183 /// <param name="offset">The offset to start obtaining data from.</param> | |
184 /// <param name="count">The number of bytes of data to write.</param> | |
185 /// <exception cref="NotSupportedException">Any access</exception> | |
186 public override void Write(byte[] buffer, int offset, int count) | |
187 { | |
188 throw new NotSupportedException("BZip2InputStream Write not supported"); | |
189 } | |
190 | |
191 /// <summary> | |
192 /// Writes a byte to the current position in the file stream. | |
193 /// This operation is not supported and will throw a NotSupportedException | |
194 /// </summary> | |
195 /// <param name="value">The value to write.</param> | |
196 /// <exception cref="NotSupportedException">Any access</exception> | |
197 public override void WriteByte(byte value) | |
198 { | |
199 throw new NotSupportedException("BZip2InputStream WriteByte not supported"); | |
200 } | |
201 | |
202 /// <summary> | |
203 /// Read a sequence of bytes and advances the read position by one byte. | |
204 /// </summary> | |
205 /// <param name="buffer">Array of bytes to store values in</param> | |
206 /// <param name="offset">Offset in array to begin storing data</param> | |
207 /// <param name="count">The maximum number of bytes to read</param> | |
208 /// <returns>The total number of bytes read into the buffer. This might be less | |
209 /// than the number of bytes requested if that number of bytes are not | |
210 /// currently available or zero if the end of the stream is reached. | |
211 /// </returns> | |
212 public override int Read(byte[] buffer, int offset, int count) | |
213 { | |
214 if ( buffer == null ) | |
215 { | |
216 throw new ArgumentNullException("buffer"); | |
217 } | |
218 | |
219 for (int i = 0; i < count; ++i) { | |
220 int rb = ReadByte(); | |
221 if (rb == -1) { | |
222 return i; | |
223 } | |
224 buffer[offset + i] = (byte)rb; | |
225 } | |
226 return count; | |
227 } | |
228 | |
229 /// <summary> | |
230 /// Closes the stream, releasing any associated resources. | |
231 /// </summary> | |
232 public override void Close() | |
233 { | |
234 if ( IsStreamOwner && (baseStream != null) ) { | |
235 baseStream.Close(); | |
236 } | |
237 } | |
238 /// <summary> | |
239 /// Read a byte from stream advancing position | |
240 /// </summary> | |
241 /// <returns>byte read or -1 on end of stream</returns> | |
242 public override int ReadByte() | |
243 { | |
244 if (streamEnd) | |
245 { | |
246 return -1; // ok | |
247 } | |
248 | |
249 int retChar = currentChar; | |
250 switch (currentState) | |
251 { | |
252 case RAND_PART_B_STATE: | |
253 SetupRandPartB(); | |
254 break; | |
255 case RAND_PART_C_STATE: | |
256 SetupRandPartC(); | |
257 break; | |
258 case NO_RAND_PART_B_STATE: | |
259 SetupNoRandPartB(); | |
260 break; | |
261 case NO_RAND_PART_C_STATE: | |
262 SetupNoRandPartC(); | |
263 break; | |
264 case START_BLOCK_STATE: | |
265 case NO_RAND_PART_A_STATE: | |
266 case RAND_PART_A_STATE: | |
267 break; | |
268 default: | |
269 break; | |
270 } | |
271 return retChar; | |
272 } | |
273 | |
274 #endregion | |
275 | |
276 void MakeMaps() | |
277 { | |
278 nInUse = 0; | |
279 for (int i = 0; i < 256; ++i) { | |
280 if (inUse[i]) { | |
281 seqToUnseq[nInUse] = (byte)i; | |
282 unseqToSeq[i] = (byte)nInUse; | |
283 nInUse++; | |
284 } | |
285 } | |
286 } | |
287 | |
288 void Initialize() | |
289 { | |
290 char magic1 = BsGetUChar(); | |
291 char magic2 = BsGetUChar(); | |
292 | |
293 char magic3 = BsGetUChar(); | |
294 char magic4 = BsGetUChar(); | |
295 | |
296 if (magic1 != 'B' || magic2 != 'Z' || magic3 != 'h' || magic4 < '1' || magic4 > '9') { | |
297 streamEnd = true; | |
298 return; | |
299 } | |
300 | |
301 SetDecompressStructureSizes(magic4 - '0'); | |
302 computedCombinedCRC = 0; | |
303 } | |
304 | |
305 void InitBlock() | |
306 { | |
307 char magic1 = BsGetUChar(); | |
308 char magic2 = BsGetUChar(); | |
309 char magic3 = BsGetUChar(); | |
310 char magic4 = BsGetUChar(); | |
311 char magic5 = BsGetUChar(); | |
312 char magic6 = BsGetUChar(); | |
313 | |
314 if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) { | |
315 Complete(); | |
316 return; | |
317 } | |
318 | |
319 if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) { | |
320 BadBlockHeader(); | |
321 streamEnd = true; | |
322 return; | |
323 } | |
324 | |
325 storedBlockCRC = BsGetInt32(); | |
326 | |
327 blockRandomised = (BsR(1) == 1); | |
328 | |
329 GetAndMoveToFrontDecode(); | |
330 | |
331 mCrc.Reset(); | |
332 currentState = START_BLOCK_STATE; | |
333 } | |
334 | |
335 void EndBlock() | |
336 { | |
337 computedBlockCRC = (int)mCrc.Value; | |
338 | |
339 // -- A bad CRC is considered a fatal error. -- | |
340 if (storedBlockCRC != computedBlockCRC) { | |
341 CrcError(); | |
342 } | |
343 | |
344 // 1528150659 | |
345 computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31); | |
346 computedCombinedCRC = computedCombinedCRC ^ (uint)computedBlockCRC; | |
347 } | |
348 | |
349 void Complete() | |
350 { | |
351 storedCombinedCRC = BsGetInt32(); | |
352 if (storedCombinedCRC != (int)computedCombinedCRC) { | |
353 CrcError(); | |
354 } | |
355 | |
356 streamEnd = true; | |
357 } | |
358 | |
359 void BsSetStream(Stream stream) | |
360 { | |
361 baseStream = stream; | |
362 bsLive = 0; | |
363 bsBuff = 0; | |
364 } | |
365 | |
366 void FillBuffer() | |
367 { | |
368 int thech = 0; | |
369 | |
370 try { | |
371 thech = baseStream.ReadByte(); | |
372 } catch (Exception) { | |
373 CompressedStreamEOF(); | |
374 } | |
375 | |
376 if (thech == -1) { | |
377 CompressedStreamEOF(); | |
378 } | |
379 | |
380 bsBuff = (bsBuff << 8) | (thech & 0xFF); | |
381 bsLive += 8; | |
382 } | |
383 | |
384 int BsR(int n) | |
385 { | |
386 while (bsLive < n) { | |
387 FillBuffer(); | |
388 } | |
389 | |
390 int v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); | |
391 bsLive -= n; | |
392 return v; | |
393 } | |
394 | |
395 char BsGetUChar() | |
396 { | |
397 return (char)BsR(8); | |
398 } | |
399 | |
400 int BsGetIntVS(int numBits) | |
401 { | |
402 return BsR(numBits); | |
403 } | |
404 | |
405 int BsGetInt32() | |
406 { | |
407 int result = BsR(8); | |
408 result = (result << 8) | BsR(8); | |
409 result = (result << 8) | BsR(8); | |
410 result = (result << 8) | BsR(8); | |
411 return result; | |
412 } | |
413 | |
414 void RecvDecodingTables() | |
415 { | |
416 char[][] len = new char[BZip2Constants.GroupCount][]; | |
417 for (int i = 0; i < BZip2Constants.GroupCount; ++i) { | |
418 len[i] = new char[BZip2Constants.MaximumAlphaSize]; | |
419 } | |
420 | |
421 bool[] inUse16 = new bool[16]; | |
422 | |
423 //--- Receive the mapping table --- | |
424 for (int i = 0; i < 16; i++) { | |
425 inUse16[i] = (BsR(1) == 1); | |
426 } | |
427 | |
428 for (int i = 0; i < 16; i++) { | |
429 if (inUse16[i]) { | |
430 for (int j = 0; j < 16; j++) { | |
431 inUse[i * 16 + j] = (BsR(1) == 1); | |
432 } | |
433 } else { | |
434 for (int j = 0; j < 16; j++) { | |
435 inUse[i * 16 + j] = false; | |
436 } | |
437 } | |
438 } | |
439 | |
440 MakeMaps(); | |
441 int alphaSize = nInUse + 2; | |
442 | |
443 //--- Now the selectors --- | |
444 int nGroups = BsR(3); | |
445 int nSelectors = BsR(15); | |
446 | |
447 for (int i = 0; i < nSelectors; i++) { | |
448 int j = 0; | |
449 while (BsR(1) == 1) { | |
450 j++; | |
451 } | |
452 selectorMtf[i] = (byte)j; | |
453 } | |
454 | |
455 //--- Undo the MTF values for the selectors. --- | |
456 byte[] pos = new byte[BZip2Constants.GroupCount]; | |
457 for (int v = 0; v < nGroups; v++) { | |
458 pos[v] = (byte)v; | |
459 } | |
460 | |
461 for (int i = 0; i < nSelectors; i++) { | |
462 int v = selectorMtf[i]; | |
463 byte tmp = pos[v]; | |
464 while (v > 0) { | |
465 pos[v] = pos[v - 1]; | |
466 v--; | |
467 } | |
468 pos[0] = tmp; | |
469 selector[i] = tmp; | |
470 } | |
471 | |
472 //--- Now the coding tables --- | |
473 for (int t = 0; t < nGroups; t++) { | |
474 int curr = BsR(5); | |
475 for (int i = 0; i < alphaSize; i++) { | |
476 while (BsR(1) == 1) { | |
477 if (BsR(1) == 0) { | |
478 curr++; | |
479 } else { | |
480 curr--; | |
481 } | |
482 } | |
483 len[t][i] = (char)curr; | |
484 } | |
485 } | |
486 | |
487 //--- Create the Huffman decoding tables --- | |
488 for (int t = 0; t < nGroups; t++) { | |
489 int minLen = 32; | |
490 int maxLen = 0; | |
491 for (int i = 0; i < alphaSize; i++) { | |
492 maxLen = Math.Max(maxLen, len[t][i]); | |
493 minLen = Math.Min(minLen, len[t][i]); | |
494 } | |
495 HbCreateDecodeTables(limit[t], baseArray[t], perm[t], len[t], minLen, maxLen, alphaSize); | |
496 minLens[t] = minLen; | |
497 } | |
498 } | |
499 | |
500 void GetAndMoveToFrontDecode() | |
501 { | |
502 byte[] yy = new byte[256]; | |
503 int nextSym; | |
504 | |
505 int limitLast = BZip2Constants.BaseBlockSize * blockSize100k; | |
506 origPtr = BsGetIntVS(24); | |
507 | |
508 RecvDecodingTables(); | |
509 int EOB = nInUse+1; | |
510 int groupNo = -1; | |
511 int groupPos = 0; | |
512 | |
513 /*-- | |
514 Setting up the unzftab entries here is not strictly | |
515 necessary, but it does save having to do it later | |
516 in a separate pass, and so saves a block's worth of | |
517 cache misses. | |
518 --*/ | |
519 for (int i = 0; i <= 255; i++) { | |
520 unzftab[i] = 0; | |
521 } | |
522 | |
523 for (int i = 0; i <= 255; i++) { | |
524 yy[i] = (byte)i; | |
525 } | |
526 | |
527 last = -1; | |
528 | |
529 if (groupPos == 0) { | |
530 groupNo++; | |
531 groupPos = BZip2Constants.GroupSize; | |
532 } | |
533 | |
534 groupPos--; | |
535 int zt = selector[groupNo]; | |
536 int zn = minLens[zt]; | |
537 int zvec = BsR(zn); | |
538 int zj; | |
539 | |
540 while (zvec > limit[zt][zn]) { | |
541 if (zn > 20) { // the longest code | |
542 throw new BZip2Exception("Bzip data error"); | |
543 } | |
544 zn++; | |
545 while (bsLive < 1) { | |
546 FillBuffer(); | |
547 } | |
548 zj = (bsBuff >> (bsLive-1)) & 1; | |
549 bsLive--; | |
550 zvec = (zvec << 1) | zj; | |
551 } | |
552 if (zvec - baseArray[zt][zn] < 0 || zvec - baseArray[zt][zn] >= BZip2Constants.MaximumAlphaSize) { | |
553 throw new BZip2Exception("Bzip data error"); | |
554 } | |
555 nextSym = perm[zt][zvec - baseArray[zt][zn]]; | |
556 | |
557 while (true) { | |
558 if (nextSym == EOB) { | |
559 break; | |
560 } | |
561 | |
562 if (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB) { | |
563 int s = -1; | |
564 int n = 1; | |
565 do { | |
566 if (nextSym == BZip2Constants.RunA) { | |
567 s += (0 + 1) * n; | |
568 } else if (nextSym == BZip2Constants.RunB) { | |
569 s += (1 + 1) * n; | |
570 } | |
571 | |
572 n <<= 1; | |
573 | |
574 if (groupPos == 0) { | |
575 groupNo++; | |
576 groupPos = BZip2Constants.GroupSize; | |
577 } | |
578 | |
579 groupPos--; | |
580 | |
581 zt = selector[groupNo]; | |
582 zn = minLens[zt]; | |
583 zvec = BsR(zn); | |
584 | |
585 while (zvec > limit[zt][zn]) { | |
586 zn++; | |
587 while (bsLive < 1) { | |
588 FillBuffer(); | |
589 } | |
590 zj = (bsBuff >> (bsLive - 1)) & 1; | |
591 bsLive--; | |
592 zvec = (zvec << 1) | zj; | |
593 } | |
594 nextSym = perm[zt][zvec - baseArray[zt][zn]]; | |
595 } while (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB); | |
596 | |
597 s++; | |
598 byte ch = seqToUnseq[yy[0]]; | |
599 unzftab[ch] += s; | |
600 | |
601 while (s > 0) { | |
602 last++; | |
603 ll8[last] = ch; | |
604 s--; | |
605 } | |
606 | |
607 if (last >= limitLast) { | |
608 BlockOverrun(); | |
609 } | |
610 continue; | |
611 } else { | |
612 last++; | |
613 if (last >= limitLast) { | |
614 BlockOverrun(); | |
615 } | |
616 | |
617 byte tmp = yy[nextSym - 1]; | |
618 unzftab[seqToUnseq[tmp]]++; | |
619 ll8[last] = seqToUnseq[tmp]; | |
620 | |
621 for (int j = nextSym-1; j > 0; --j) { | |
622 yy[j] = yy[j - 1]; | |
623 } | |
624 yy[0] = tmp; | |
625 | |
626 if (groupPos == 0) { | |
627 groupNo++; | |
628 groupPos = BZip2Constants.GroupSize; | |
629 } | |
630 | |
631 groupPos--; | |
632 zt = selector[groupNo]; | |
633 zn = minLens[zt]; | |
634 zvec = BsR(zn); | |
635 while (zvec > limit[zt][zn]) { | |
636 zn++; | |
637 while (bsLive < 1) { | |
638 FillBuffer(); | |
639 } | |
640 zj = (bsBuff >> (bsLive-1)) & 1; | |
641 bsLive--; | |
642 zvec = (zvec << 1) | zj; | |
643 } | |
644 nextSym = perm[zt][zvec - baseArray[zt][zn]]; | |
645 continue; | |
646 } | |
647 } | |
648 } | |
649 | |
650 void SetupBlock() | |
651 { | |
652 int[] cftab = new int[257]; | |
653 | |
654 cftab[0] = 0; | |
655 Array.Copy(unzftab, 0, cftab, 1, 256); | |
656 | |
657 for (int i = 1; i <= 256; i++) { | |
658 cftab[i] += cftab[i - 1]; | |
659 } | |
660 | |
661 for (int i = 0; i <= last; i++) { | |
662 byte ch = ll8[i]; | |
663 tt[cftab[ch]] = i; | |
664 cftab[ch]++; | |
665 } | |
666 | |
667 cftab = null; | |
668 | |
669 tPos = tt[origPtr]; | |
670 | |
671 count = 0; | |
672 i2 = 0; | |
673 ch2 = 256; /*-- not a char and not EOF --*/ | |
674 | |
675 if (blockRandomised) { | |
676 rNToGo = 0; | |
677 rTPos = 0; | |
678 SetupRandPartA(); | |
679 } else { | |
680 SetupNoRandPartA(); | |
681 } | |
682 } | |
683 | |
684 void SetupRandPartA() | |
685 { | |
686 if (i2 <= last) { | |
687 chPrev = ch2; | |
688 ch2 = ll8[tPos]; | |
689 tPos = tt[tPos]; | |
690 if (rNToGo == 0) { | |
691 rNToGo = BZip2Constants.RandomNumbers[rTPos]; | |
692 rTPos++; | |
693 if (rTPos == 512) { | |
694 rTPos = 0; | |
695 } | |
696 } | |
697 rNToGo--; | |
698 ch2 ^= (int)((rNToGo == 1) ? 1 : 0); | |
699 i2++; | |
700 | |
701 currentChar = ch2; | |
702 currentState = RAND_PART_B_STATE; | |
703 mCrc.Update(ch2); | |
704 } else { | |
705 EndBlock(); | |
706 InitBlock(); | |
707 SetupBlock(); | |
708 } | |
709 } | |
710 | |
711 void SetupNoRandPartA() | |
712 { | |
713 if (i2 <= last) { | |
714 chPrev = ch2; | |
715 ch2 = ll8[tPos]; | |
716 tPos = tt[tPos]; | |
717 i2++; | |
718 | |
719 currentChar = ch2; | |
720 currentState = NO_RAND_PART_B_STATE; | |
721 mCrc.Update(ch2); | |
722 } else { | |
723 EndBlock(); | |
724 InitBlock(); | |
725 SetupBlock(); | |
726 } | |
727 } | |
728 | |
729 void SetupRandPartB() | |
730 { | |
731 if (ch2 != chPrev) { | |
732 currentState = RAND_PART_A_STATE; | |
733 count = 1; | |
734 SetupRandPartA(); | |
735 } else { | |
736 count++; | |
737 if (count >= 4) { | |
738 z = ll8[tPos]; | |
739 tPos = tt[tPos]; | |
740 if (rNToGo == 0) { | |
741 rNToGo = BZip2Constants.RandomNumbers[rTPos]; | |
742 rTPos++; | |
743 if (rTPos == 512) { | |
744 rTPos = 0; | |
745 } | |
746 } | |
747 rNToGo--; | |
748 z ^= (byte)((rNToGo == 1) ? 1 : 0); | |
749 j2 = 0; | |
750 currentState = RAND_PART_C_STATE; | |
751 SetupRandPartC(); | |
752 } else { | |
753 currentState = RAND_PART_A_STATE; | |
754 SetupRandPartA(); | |
755 } | |
756 } | |
757 } | |
758 | |
759 void SetupRandPartC() | |
760 { | |
761 if (j2 < (int)z) { | |
762 currentChar = ch2; | |
763 mCrc.Update(ch2); | |
764 j2++; | |
765 } else { | |
766 currentState = RAND_PART_A_STATE; | |
767 i2++; | |
768 count = 0; | |
769 SetupRandPartA(); | |
770 } | |
771 } | |
772 | |
773 void SetupNoRandPartB() | |
774 { | |
775 if (ch2 != chPrev) { | |
776 currentState = NO_RAND_PART_A_STATE; | |
777 count = 1; | |
778 SetupNoRandPartA(); | |
779 } else { | |
780 count++; | |
781 if (count >= 4) { | |
782 z = ll8[tPos]; | |
783 tPos = tt[tPos]; | |
784 currentState = NO_RAND_PART_C_STATE; | |
785 j2 = 0; | |
786 SetupNoRandPartC(); | |
787 } else { | |
788 currentState = NO_RAND_PART_A_STATE; | |
789 SetupNoRandPartA(); | |
790 } | |
791 } | |
792 } | |
793 | |
794 void SetupNoRandPartC() | |
795 { | |
796 if (j2 < (int)z) { | |
797 currentChar = ch2; | |
798 mCrc.Update(ch2); | |
799 j2++; | |
800 } else { | |
801 currentState = NO_RAND_PART_A_STATE; | |
802 i2++; | |
803 count = 0; | |
804 SetupNoRandPartA(); | |
805 } | |
806 } | |
807 | |
808 void SetDecompressStructureSizes(int newSize100k) | |
809 { | |
810 if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9)) { | |
811 throw new BZip2Exception("Invalid block size"); | |
812 } | |
813 | |
814 blockSize100k = newSize100k; | |
815 | |
816 if (newSize100k == 0) { | |
817 return; | |
818 } | |
819 | |
820 int n = BZip2Constants.BaseBlockSize * newSize100k; | |
821 ll8 = new byte[n]; | |
822 tt = new int[n]; | |
823 } | |
824 | |
825 static void CompressedStreamEOF() | |
826 { | |
827 throw new EndOfStreamException("BZip2 input stream end of compressed stream"); | |
828 } | |
829 | |
830 static void BlockOverrun() | |
831 { | |
832 throw new BZip2Exception("BZip2 input stream block overrun"); | |
833 } | |
834 | |
835 static void BadBlockHeader() | |
836 { | |
837 throw new BZip2Exception("BZip2 input stream bad block header"); | |
838 } | |
839 | |
840 static void CrcError() | |
841 { | |
842 throw new BZip2Exception("BZip2 input stream crc error"); | |
843 } | |
844 | |
845 static void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, int alphaSize) | |
846 { | |
847 int pp = 0; | |
848 | |
849 for (int i = minLen; i <= maxLen; ++i) | |
850 { | |
851 for (int j = 0; j < alphaSize; ++j) | |
852 { | |
853 if (length[j] == i) | |
854 { | |
855 perm[pp] = j; | |
856 ++pp; | |
857 } | |
858 } | |
859 } | |
860 | |
861 for (int i = 0; i < BZip2Constants.MaximumCodeLength; i++) | |
862 { | |
863 baseArray[i] = 0; | |
864 } | |
865 | |
866 for (int i = 0; i < alphaSize; i++) | |
867 { | |
868 ++baseArray[length[i] + 1]; | |
869 } | |
870 | |
871 for (int i = 1; i < BZip2Constants.MaximumCodeLength; i++) | |
872 { | |
873 baseArray[i] += baseArray[i - 1]; | |
874 } | |
875 | |
876 for (int i = 0; i < BZip2Constants.MaximumCodeLength; i++) | |
877 { | |
878 limit[i] = 0; | |
879 } | |
880 | |
881 int vec = 0; | |
882 | |
883 for (int i = minLen; i <= maxLen; i++) | |
884 { | |
885 vec += (baseArray[i + 1] - baseArray[i]); | |
886 limit[i] = vec - 1; | |
887 vec <<= 1; | |
888 } | |
889 | |
890 for (int i = minLen + 1; i <= maxLen; i++) | |
891 { | |
892 baseArray[i] = ((limit[i - 1] + 1) << 1) - baseArray[i]; | |
893 } | |
894 } | |
895 | |
896 #region Instance Fields | |
897 /*-- | |
898 index of the last char in the block, so | |
899 the block size == last + 1. | |
900 --*/ | |
901 int last; | |
902 | |
903 /*-- | |
904 index in zptr[] of original string after sorting. | |
905 --*/ | |
906 int origPtr; | |
907 | |
908 /*-- | |
909 always: in the range 0 .. 9. | |
910 The current block size is 100000 * this number. | |
911 --*/ | |
912 int blockSize100k; | |
913 | |
914 bool blockRandomised; | |
915 | |
916 int bsBuff; | |
917 int bsLive; | |
918 IChecksum mCrc = new StrangeCRC(); | |
919 | |
920 bool[] inUse = new bool[256]; | |
921 int nInUse; | |
922 | |
923 byte[] seqToUnseq = new byte[256]; | |
924 byte[] unseqToSeq = new byte[256]; | |
925 | |
926 byte[] selector = new byte[BZip2Constants.MaximumSelectors]; | |
927 byte[] selectorMtf = new byte[BZip2Constants.MaximumSelectors]; | |
928 | |
929 int[] tt; | |
930 byte[] ll8; | |
931 | |
932 /*-- | |
933 freq table collected to save a pass over the data | |
934 during decompression. | |
935 --*/ | |
936 int[] unzftab = new int[256]; | |
937 | |
938 int[][] limit = new int[BZip2Constants.GroupCount][]; | |
939 int[][] baseArray = new int[BZip2Constants.GroupCount][]; | |
940 int[][] perm = new int[BZip2Constants.GroupCount][]; | |
941 int[] minLens = new int[BZip2Constants.GroupCount]; | |
942 | |
943 Stream baseStream; | |
944 bool streamEnd; | |
945 | |
946 int currentChar = -1; | |
947 | |
948 int currentState = START_BLOCK_STATE; | |
949 | |
950 int storedBlockCRC, storedCombinedCRC; | |
951 int computedBlockCRC; | |
952 uint computedCombinedCRC; | |
953 | |
954 int count, chPrev, ch2; | |
955 int tPos; | |
956 int rNToGo; | |
957 int rTPos; | |
958 int i2, j2; | |
959 byte z; | |
960 bool isStreamOwner = true; | |
961 #endregion | |
962 } | |
963 } | |
964 /* This file was derived from a file containing this license: | |
965 * | |
966 * This file is a part of bzip2 and/or libbzip2, a program and | |
967 * library for lossless, block-sorting data compression. | |
968 * | |
969 * Copyright (C) 1996-1998 Julian R Seward. All rights reserved. | |
970 * | |
971 * Redistribution and use in source and binary forms, with or without | |
972 * modification, are permitted provided that the following conditions | |
973 * are met: | |
974 * | |
975 * 1. Redistributions of source code must retain the above copyright | |
976 * notice, this list of conditions and the following disclaimer. | |
977 * | |
978 * 2. The origin of this software must not be misrepresented; you must | |
979 * not claim that you wrote the original software. If you use this | |
980 * software in a product, an acknowledgment in the product | |
981 * documentation would be appreciated but is not required. | |
982 * | |
983 * 3. Altered source versions must be plainly marked as such, and must | |
984 * not be misrepresented as being the original software. | |
985 * | |
986 * 4. The name of the author may not be used to endorse or promote | |
987 * products derived from this software without specific prior written | |
988 * permission. | |
989 * | |
990 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS | |
991 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
992 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
993 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
994 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
995 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | |
996 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
997 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
998 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
999 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
1000 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
1001 * | |
1002 * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001 | |
1003 */ |