Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package org.apache.tools.bzip2

File CBZip2InputStream.java

 

Coverage histogram

../../../../img/srcFileCovDistChart0.png
56% of files have more coverage

Code metrics

206
476
30
2
1,063
731
157
0.33
15.87
15
5.23

Classes

Class Line # Actions
CBZip2InputStream 46 470 153 702
0.00%
CBZip2InputStream.Data 988 6 4 10
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10    *
11    * Unless required by applicable law or agreed to in writing, software
12    * distributed under the License is distributed on an "AS IS" BASIS,
13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    * See the License for the specific language governing permissions and
15    * limitations under the License.
16    *
17    */
18   
19    /*
20    * This package is based on the work done by Keiron Liddle, Aftex Software
21    * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
22    * great code.
23    */
24    package org.apache.tools.bzip2;
25   
26    import java.io.IOException;
27    import java.io.InputStream;
28   
29    /**
30    * An input stream that decompresses from the BZip2 format (without the file
31    * header chars) to be read as any other stream.
32    *
33    * <p>The decompression requires large amounts of memory. Thus you
34    * should call the {@link #close() close()} method as soon as
35    * possible, to force <tt>CBZip2InputStream</tt> to release the
36    * allocated memory. See {@link CBZip2OutputStream
37    * CBZip2OutputStream} for information about memory usage.</p>
38    *
39    * <p><tt>CBZip2InputStream</tt> reads bytes from the compressed
40    * source stream via the single byte {@link java.io.InputStream#read()
41    * read()} method exclusively. Thus you should consider to use a
42    * buffered source stream.</p>
43    *
44    * <p>Instances of this class are not threadsafe.</p>
45    */
 
46    public class CBZip2InputStream extends InputStream implements BZip2Constants {
47   
48    /**
49    * Index of the last char in the block, so the block size == last + 1.
50    */
51    private int last;
52   
53    /**
54    * Index in zptr[] of original string after sorting.
55    */
56    private int origPtr;
57   
58    /**
59    * always: in the range 0 .. 9.
60    * The current block size is 100000 * this number.
61    */
62    private int blockSize100k;
63   
64    private boolean blockRandomised;
65   
66    private int bsBuff;
67    private int bsLive;
68    private final CRC crc = new CRC();
69   
70    private int nInUse;
71   
72    private InputStream in;
73    private final boolean decompressConcatenated;
74   
75    private int currentChar = -1;
76   
77    private static final int EOF = 0;
78    private static final int START_BLOCK_STATE = 1;
79    private static final int RAND_PART_A_STATE = 2;
80    private static final int RAND_PART_B_STATE = 3;
81    private static final int RAND_PART_C_STATE = 4;
82    private static final int NO_RAND_PART_A_STATE = 5;
83    private static final int NO_RAND_PART_B_STATE = 6;
84    private static final int NO_RAND_PART_C_STATE = 7;
85   
86    private int currentState = START_BLOCK_STATE;
87   
88    private int storedBlockCRC, storedCombinedCRC;
89    private int computedBlockCRC, computedCombinedCRC;
90   
91    // Variables used by setup* methods exclusively
92   
93    private int su_count;
94    private int su_ch2;
95    private int su_chPrev;
96    private int su_i2;
97    private int su_j2;
98    private int su_rNToGo;
99    private int su_rTPos;
100    private int su_tPos;
101    private char su_z;
102   
103    /**
104    * All memory intensive stuff.
105    * This field is initialized by initBlock().
106    */
107    private CBZip2InputStream.Data data;
108   
109    /**
110    * Constructs a new CBZip2InputStream which decompresses bytes read from
111    * the specified stream. This doesn't suppprt decompressing
112    * concatenated .bz2 files.
113    *
114    * <p>Although BZip2 headers are marked with the magic
115    * <tt>"Bz"</tt> this constructor expects the next byte in the
116    * stream to be the first one after the magic. Thus callers have
117    * to skip the first two bytes. Otherwise this constructor will
118    * throw an exception. </p>
119    * @param in
120    *
121    * @throws IOException
122    * if the stream content is malformed or an I/O error occurs.
123    * @throws NullPointerException
124    * if <tt>in == null</tt>
125    */
 
126  0 toggle public CBZip2InputStream(final InputStream in) throws IOException {
127  0 this(in, false);
128    }
129   
130    /**
131    * Constructs a new CBZip2InputStream which decompresses bytes
132    * read from the specified stream.
133    *
134    * <p>Although BZip2 headers are marked with the magic
135    * <tt>"Bz"</tt> this constructor expects the next byte in the
136    * stream to be the first one after the magic. Thus callers have
137    * to skip the first two bytes. Otherwise this constructor will
138    * throw an exception. </p>
139    *
140    * @param in the InputStream from which this object should be created
141    * @param decompressConcatenated
142    * if true, decompress until the end of the input;
143    * if false, stop after the first .bz2 stream and
144    * leave the input position to point to the next
145    * byte after the .bz2 stream
146    *
147    * @throws IOException
148    * if the stream content is malformed or an I/O error occurs.
149    * @throws NullPointerException
150    * if <tt>in == null</tt>
151    */
 
152  0 toggle public CBZip2InputStream(final InputStream in,
153    final boolean decompressConcatenated)
154    throws IOException {
155  0 super();
156   
157  0 this.in = in;
158  0 this.decompressConcatenated = decompressConcatenated;
159   
160  0 init(true);
161  0 initBlock();
162  0 setupBlock();
163    }
164   
165    /** {@inheritDoc} */
 
166  0 toggle @Override
167    public int read() throws IOException {
168  0 if (this.in == null)
169  0 throw new IOException("stream closed");
170  0 return read0();
171    }
172   
173    /*
174    * (non-Javadoc)
175    *
176    * @see java.io.InputStream#read(byte[], int, int)
177    */
 
178  0 toggle @Override
179    public int read(final byte[] dest, final int offs, final int len)
180    throws IOException {
181  0 if (offs < 0) {
182  0 throw new IndexOutOfBoundsException("offs(" + offs + ") < 0.");
183    }
184  0 if (len < 0) {
185  0 throw new IndexOutOfBoundsException("len(" + len + ") < 0.");
186    }
187  0 if (offs + len > dest.length) {
188  0 throw new IndexOutOfBoundsException("offs(" + offs + ") + len("
189    + len + ") > dest.length("
190    + dest.length + ").");
191    }
192  0 if (this.in == null) {
193  0 throw new IOException("stream closed");
194    }
195   
196  0 final int hi = offs + len;
197  0 int destOffs = offs;
198  0 for (int b; (destOffs < hi) && ((b = read0()) >= 0);) {
199  0 dest[destOffs++] = (byte) b;
200    }
201   
202  0 return (destOffs == offs) ? -1 : (destOffs - offs);
203    }
204   
 
205  0 toggle private void makeMaps() {
206  0 final boolean[] inUse = this.data.inUse;
207  0 final byte[] seqToUnseq = this.data.seqToUnseq;
208   
209  0 int nInUseShadow = 0;
210   
211  0 for (int i = 0; i < 256; i++) {
212  0 if (inUse[i]) {
213  0 seqToUnseq[nInUseShadow++] = (byte) i;
214    }
215    }
216   
217  0 this.nInUse = nInUseShadow;
218    }
219   
 
220  0 toggle private int read0() throws IOException {
221  0 final int retChar = this.currentChar;
222   
223  0 switch (this.currentState) {
224  0 case EOF:
225  0 return -1;
226   
227  0 case START_BLOCK_STATE:
228  0 throw new IllegalStateException();
229   
230  0 case RAND_PART_A_STATE:
231  0 throw new IllegalStateException();
232   
233  0 case RAND_PART_B_STATE:
234  0 setupRandPartB();
235  0 break;
236   
237  0 case RAND_PART_C_STATE:
238  0 setupRandPartC();
239  0 break;
240   
241  0 case NO_RAND_PART_A_STATE:
242  0 throw new IllegalStateException();
243   
244  0 case NO_RAND_PART_B_STATE:
245  0 setupNoRandPartB();
246  0 break;
247   
248  0 case NO_RAND_PART_C_STATE:
249  0 setupNoRandPartC();
250  0 break;
251   
252  0 default:
253  0 throw new IllegalStateException();
254    }
255   
256  0 return retChar;
257    }
258   
 
259  0 toggle private boolean init(boolean isFirstStream) throws IOException {
260  0 if (null == in) {
261  0 throw new IOException("No InputStream");
262    }
263   
264  0 if (isFirstStream) {
265  0 if (in.available() == 0) {
266  0 throw new IOException("Empty InputStream");
267    }
268    } else {
269  0 int magic0 = read();
270  0 if (magic0 == -1) {
271  0 return false;
272    }
273  0 int magic1 = read();
274  0 if (magic0 != 'B' || magic1 != 'Z') {
275  0 throw new IOException("Garbage after a valid BZip2 stream");
276    }
277    }
278   
279  0 int magic2 = read();
280  0 if (magic2 != 'h') {
281  0 throw new IOException(isFirstStream
282    ? "Stream is not in the BZip2 format"
283    : "Garbage after a valid BZip2 stream");
284    }
285   
286  0 int blockSize = read();
287  0 if ((blockSize < '1') || (blockSize > '9')) {
288  0 throw new IOException("Stream is not BZip2 formatted: illegal "
289    + "blocksize " + (char) blockSize);
290    }
291   
292  0 this.blockSize100k = blockSize - '0';
293   
294  0 this.bsLive = 0;
295  0 this.computedCombinedCRC = 0;
296   
297  0 return true;
298    }
299   
 
300  0 toggle private void initBlock() throws IOException {
301  0 char magic0;
302  0 char magic1;
303  0 char magic2;
304  0 char magic3;
305  0 char magic4;
306  0 char magic5;
307   
308  0 while (true) {
309    // Get the block magic bytes.
310  0 magic0 = bsGetUByte();
311  0 magic1 = bsGetUByte();
312  0 magic2 = bsGetUByte();
313  0 magic3 = bsGetUByte();
314  0 magic4 = bsGetUByte();
315  0 magic5 = bsGetUByte();
316   
317    // If isn't end of stream magic, break out of the loop.
318  0 if (magic0 != 0x17 || magic1 != 0x72 || magic2 != 0x45 || magic3 != 0x38
319    || magic4 != 0x50 || magic5 != 0x90) {
320  0 break;
321    }
322   
323    // End of stream was reached. Check the combined CRC and
324    // advance to the next .bz2 stream if decoding concatenated
325    // streams.
326  0 if (complete()) {
327  0 return;
328    }
329    }
330   
331  0 if (magic0 != 0x31 || // '1'
332    magic1 != 0x41 || // ')'
333    magic2 != 0x59 || // 'Y'
334    magic3 != 0x26 || // '&'
335    magic4 != 0x53 || // 'S'
336    magic5 != 0x59 // 'Y'
337    ) {
338  0 this.currentState = EOF;
339  0 throw new IOException("bad block header");
340    }
341  0 this.storedBlockCRC = bsGetInt();
342  0 this.blockRandomised = bsR(1) == 1;
343   
344    /**
345    * Allocate data here instead in constructor, so we do not allocate it if
346    * the input file is empty.
347    */
348  0 if (this.data == null) {
349  0 this.data = new Data(this.blockSize100k);
350    }
351   
352    // currBlockNo++;
353  0 getAndMoveToFrontDecode();
354   
355  0 this.crc.initialiseCRC();
356  0 this.currentState = START_BLOCK_STATE;
357    }
358   
 
359  0 toggle private void endBlock() throws IOException {
360  0 this.computedBlockCRC = this.crc.getFinalCRC();
361   
362    // A bad CRC is considered a fatal error.
363  0 if (this.storedBlockCRC != this.computedBlockCRC) {
364    // make next blocks readable without error
365    // (repair feature, not yet documented, not tested)
366  0 this.computedCombinedCRC
367    = (this.storedCombinedCRC << 1)
368    | (this.storedCombinedCRC >>> 31);
369  0 this.computedCombinedCRC ^= this.storedBlockCRC;
370   
371  0 reportCRCError();
372    }
373   
374  0 this.computedCombinedCRC
375    = (this.computedCombinedCRC << 1)
376    | (this.computedCombinedCRC >>> 31);
377  0 this.computedCombinedCRC ^= this.computedBlockCRC;
378    }
379   
 
380  0 toggle private boolean complete() throws IOException {
381  0 this.storedCombinedCRC = bsGetInt();
382  0 this.currentState = EOF;
383  0 this.data = null;
384   
385  0 if (this.storedCombinedCRC != this.computedCombinedCRC) {
386  0 reportCRCError();
387    }
388   
389    // Look for the next .bz2 stream if decompressing
390    // concatenated files.
391  0 return !decompressConcatenated || !init(false);
392    }
393   
 
394  0 toggle @Override
395    public void close() throws IOException {
396  0 InputStream inShadow = this.in;
397  0 if (inShadow != null) {
398  0 try {
399  0 if (inShadow != System.in) {
400  0 inShadow.close();
401    }
402    } finally {
403  0 this.data = null;
404  0 this.in = null;
405    }
406    }
407    }
408   
 
409  0 toggle private int bsR(final int n) throws IOException {
410  0 int bsLiveShadow = this.bsLive;
411  0 int bsBuffShadow = this.bsBuff;
412   
413  0 if (bsLiveShadow < n) {
414  0 final InputStream inShadow = this.in;
415  0 do {
416  0 int thech = read();//inShadow.read();
417   
418  0 if (thech < 0) {
419  0 throw new IOException("unexpected end of stream");
420    }
421   
422  0 bsBuffShadow = (bsBuffShadow << 8) | thech;
423  0 bsLiveShadow += 8;
424  0 } while (bsLiveShadow < n);
425   
426  0 this.bsBuff = bsBuffShadow;
427    }
428   
429  0 this.bsLive = bsLiveShadow - n;
430  0 return (bsBuffShadow >> (bsLiveShadow - n)) & ((1 << n) - 1);
431    }
432   
 
433  0 toggle private boolean bsGetBit() throws IOException {
434  0 int bsLiveShadow = this.bsLive;
435  0 int bsBuffShadow = this.bsBuff;
436   
437  0 if (bsLiveShadow < 1) {
438  0 int thech = read();
439   
440  0 if (thech < 0) {
441  0 throw new IOException("unexpected end of stream");
442    }
443   
444  0 bsBuffShadow = (bsBuffShadow << 8) | thech;
445  0 bsLiveShadow += 8;
446  0 this.bsBuff = bsBuffShadow;
447    }
448   
449  0 this.bsLive = bsLiveShadow - 1;
450  0 return ((bsBuffShadow >> (bsLiveShadow - 1)) & 1) != 0;
451    }
452   
 
453  0 toggle private char bsGetUByte() throws IOException {
454  0 return (char) bsR(8);
455    }
456   
 
457  0 toggle private int bsGetInt() throws IOException {
458  0 return (((((bsR(8) << 8) | bsR(8)) << 8) | bsR(8)) << 8) | bsR(8);
459    }
460   
461    /**
462    * Called by createHuffmanDecodingTables() exclusively.
463    * @param limit
464    * @param base
465    * @param perm
466    * @param length
467    * @param minLen
468    * @param maxLen
469    * @param alphaSize
470    */
 
471  0 toggle private static void hbCreateDecodeTables(final int[] limit,
472    final int[] base,
473    final int[] perm,
474    final char[] length,
475    final int minLen,
476    final int maxLen,
477    final int alphaSize) {
478  0 for (int i = minLen, pp = 0; i <= maxLen; i++) {
479  0 for (int j = 0; j < alphaSize; j++) {
480  0 if (length[j] == i) {
481  0 perm[pp++] = j;
482    }
483    }
484    }
485   
486  0 for (int i = MAX_CODE_LEN; --i > 0;) {
487  0 base[i] = 0;
488  0 limit[i] = 0;
489    }
490   
491  0 for (int i = 0; i < alphaSize; i++) {
492  0 base[length[i] + 1]++;
493    }
494   
495  0 for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) {
496  0 b += base[i];
497  0 base[i] = b;
498    }
499   
500  0 for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) {
501  0 final int nb = base[i + 1];
502  0 vec += nb - b;
503  0 b = nb;
504  0 limit[i] = vec - 1;
505  0 vec <<= 1;
506    }
507   
508  0 for (int i = minLen + 1; i <= maxLen; i++) {
509  0 base[i] = ((limit[i - 1] + 1) << 1) - base[i];
510    }
511    }
512   
 
513  0 toggle private void recvDecodingTables() throws IOException {
514  0 final Data dataShadow = this.data;
515  0 final boolean[] inUse = dataShadow.inUse;
516  0 final byte[] pos = dataShadow.recvDecodingTables_pos;
517  0 final byte[] selector = dataShadow.selector;
518  0 final byte[] selectorMtf = dataShadow.selectorMtf;
519   
520  0 int inUse16 = 0;
521   
522    /* Receive the mapping table */
523  0 for (int i = 0; i < 16; i++) {
524  0 if (bsGetBit()) {
525  0 inUse16 |= 1 << i;
526    }
527    }
528   
529  0 for (int i = 256; --i >= 0;) {
530  0 inUse[i] = false;
531    }
532   
533  0 for (int i = 0; i < 16; i++) {
534  0 if ((inUse16 & (1 << i)) != 0) {
535  0 final int i16 = i << 4;
536  0 for (int j = 0; j < 16; j++) {
537  0 if (bsGetBit()) {
538  0 inUse[i16 + j] = true;
539    }
540    }
541    }
542    }
543   
544  0 makeMaps();
545  0 final int alphaSize = this.nInUse + 2;
546   
547    /* Now the selectors */
548  0 final int nGroups = bsR(3);
549  0 final int nSelectors = bsR(15);
550   
551  0 for (int i = 0; i < nSelectors; i++) {
552  0 int j = 0;
553  0 while (bsGetBit()) {
554  0 j++;
555    }
556  0 selectorMtf[i] = (byte) j;
557    }
558   
559    /* Undo the MTF values for the selectors. */
560  0 for (int v = nGroups; --v >= 0;) {
561  0 pos[v] = (byte) v;
562    }
563   
564  0 for (int i = 0; i < nSelectors; i++) {
565  0 int v = selectorMtf[i] & 0xff;
566  0 final byte tmp = pos[v];
567  0 while (v > 0) {
568    // nearly all times v is zero, 4 in most other cases
569  0 pos[v] = pos[v - 1];
570  0 v--;
571    }
572  0 pos[0] = tmp;
573  0 selector[i] = tmp;
574    }
575   
576  0 final char[][] len = dataShadow.temp_charArray2d;
577   
578    /* Now the coding tables */
579  0 for (int t = 0; t < nGroups; t++) {
580  0 int curr = bsR(5);
581  0 final char[] len_t = len[t];
582  0 for (int i = 0; i < alphaSize; i++) {
583  0 while (bsGetBit()) {
584  0 curr += bsGetBit() ? -1 : 1;
585    }
586  0 len_t[i] = (char) curr;
587    }
588    }
589   
590    // finally create the Huffman tables
591  0 createHuffmanDecodingTables(alphaSize, nGroups);
592    }
593   
594    /**
595    * Called by recvDecodingTables() exclusively.
596    * @param alphaSize
597    * @param nGroups
598    */
 
599  0 toggle private void createHuffmanDecodingTables(final int alphaSize,
600    final int nGroups) {
601  0 final Data dataShadow = this.data;
602  0 final char[][] len = dataShadow.temp_charArray2d;
603  0 final int[] minLens = dataShadow.minLens;
604  0 final int[][] limit = dataShadow.limit;
605  0 final int[][] base = dataShadow.base;
606  0 final int[][] perm = dataShadow.perm;
607   
608  0 for (int t = 0; t < nGroups; t++) {
609  0 int minLen = 32;
610  0 int maxLen = 0;
611  0 final char[] len_t = len[t];
612  0 for (int i = alphaSize; --i >= 0;) {
613  0 final char lent = len_t[i];
614  0 if (lent > maxLen) {
615  0 maxLen = lent;
616    }
617  0 if (lent < minLen) {
618  0 minLen = lent;
619    }
620    }
621  0 hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen,
622    maxLen, alphaSize);
623  0 minLens[t] = minLen;
624    }
625    }
626   
 
627  0 toggle private void getAndMoveToFrontDecode() throws IOException {
628  0 this.origPtr = bsR(24);
629  0 recvDecodingTables();
630   
631  0 final InputStream inShadow = this.in;
632  0 final Data dataShadow = this.data;
633  0 final byte[] ll8 = dataShadow.ll8;
634  0 final int[] unzftab = dataShadow.unzftab;
635  0 final byte[] selector = dataShadow.selector;
636  0 final byte[] seqToUnseq = dataShadow.seqToUnseq;
637  0 final char[] yy = dataShadow.getAndMoveToFrontDecode_yy;
638  0 final int[] minLens = dataShadow.minLens;
639  0 final int[][] limit = dataShadow.limit;
640  0 final int[][] base = dataShadow.base;
641  0 final int[][] perm = dataShadow.perm;
642  0 final int limitLast = this.blockSize100k * 100000;
643   
644    /*
645    Setting up the unzftab entries here is not strictly
646    necessary, but it does save having to do it later
647    in a separate pass, and so saves a block's worth of
648    cache misses.
649    */
650  0 for (int i = 256; --i >= 0;) {
651  0 yy[i] = (char) i;
652  0 unzftab[i] = 0;
653    }
654   
655  0 int groupNo = 0;
656  0 int groupPos = G_SIZE - 1;
657  0 final int eob = this.nInUse + 1;
658  0 int nextSym = getAndMoveToFrontDecode0(0);
659  0 int bsBuffShadow = this.bsBuff;
660  0 int bsLiveShadow = this.bsLive;
661  0 int lastShadow = -1;
662  0 int zt = selector[groupNo] & 0xff;
663  0 int[] base_zt = base[zt];
664  0 int[] limit_zt = limit[zt];
665  0 int[] perm_zt = perm[zt];
666  0 int minLens_zt = minLens[zt];
667   
668  0 while (nextSym != eob) {
669  0 if ((nextSym == RUNA) || (nextSym == RUNB)) {
670  0 int s = -1;
671   
672  0 for (int n = 1; true; n <<= 1) {
673  0 if (nextSym == RUNA) {
674  0 s += n;
675  0 } else if (nextSym == RUNB) {
676  0 s += n << 1;
677    } else {
678  0 break;
679    }
680   
681  0 if (groupPos == 0) {
682  0 groupPos = G_SIZE - 1;
683  0 zt = selector[++groupNo] & 0xff;
684  0 base_zt = base[zt];
685  0 limit_zt = limit[zt];
686  0 perm_zt = perm[zt];
687  0 minLens_zt = minLens[zt];
688    } else {
689  0 groupPos--;
690    }
691   
692  0 int zn = minLens_zt;
693   
694    // Inlined:
695    // int zvec = bsR(zn);
696  0 while (bsLiveShadow < zn) {
697  0 final int thech = read();//inShadow.read();
698  0 if (thech < 0)
699  0 throw new IOException("unexpected end of stream");
700   
701  0 bsBuffShadow = (bsBuffShadow << 8) | thech;
702  0 bsLiveShadow += 8;
703  0 continue;
704    }
705  0 int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1);
706  0 bsLiveShadow -= zn;
707   
708  0 while (zvec > limit_zt[zn]) {
709  0 zn++;
710  0 while (bsLiveShadow < 1) {
711  0 final int thech = read();//inShadow.read();
712  0 if (thech < 0)
713  0 throw new IOException("unexpected end of stream");
714  0 bsBuffShadow = (bsBuffShadow << 8) | thech;
715  0 bsLiveShadow += 8;
716  0 continue;
717    }
718  0 bsLiveShadow--;
719  0 zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
720    }
721  0 nextSym = perm_zt[zvec - base_zt[zn]];
722    }
723   
724  0 final byte ch = seqToUnseq[yy[0]];
725  0 unzftab[ch & 0xff] += s + 1;
726   
727  0 while (s-- >= 0) {
728  0 ll8[++lastShadow] = ch;
729    }
730   
731  0 if (lastShadow >= limitLast) {
732  0 throw new IOException("block overrun");
733    }
734    } else {
735  0 if (++lastShadow >= limitLast) {
736  0 throw new IOException("block overrun");
737    }
738   
739  0 final char tmp = yy[nextSym - 1];
740  0 unzftab[seqToUnseq[tmp] & 0xff]++;
741  0 ll8[lastShadow] = seqToUnseq[tmp];
742   
743    /*
744    This loop is hammered during decompression,
745    hence avoid native method call overhead of
746    System.arraycopy for very small ranges to copy.
747    */
748  0 if (nextSym <= 16) {
749  0 for (int j = nextSym - 1; j > 0;) {
750  0 yy[j] = yy[--j];
751    }
752    } else {
753  0 System.arraycopy(yy, 0, yy, 1, nextSym - 1);
754    }
755   
756  0 yy[0] = tmp;
757   
758  0 if (groupPos == 0) {
759  0 groupPos = G_SIZE - 1;
760  0 zt = selector[++groupNo] & 0xff;
761  0 base_zt = base[zt];
762  0 limit_zt = limit[zt];
763  0 perm_zt = perm[zt];
764  0 minLens_zt = minLens[zt];
765    } else {
766  0 groupPos--;
767    }
768   
769  0 int zn = minLens_zt;
770   
771    // Inlined:
772    // int zvec = bsR(zn);
773  0 while (bsLiveShadow < zn) {
774  0 final int thech = read();//inShadow.read();
775  0 if (thech < 0)
776  0 throw new IOException("unexpected end of stream");
777  0 bsBuffShadow = (bsBuffShadow << 8) | thech;
778  0 bsLiveShadow += 8;
779  0 continue;
780    }
781  0 int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1);
782  0 bsLiveShadow -= zn;
783   
784  0 while (zvec > limit_zt[zn]) {
785  0 zn++;
786  0 while (bsLiveShadow < 1) {
787  0 final int thech = read();//inShadow.read();
788  0 if (thech <0)
789  0 throw new IOException("unexpected end of stream");
790  0 bsBuffShadow = (bsBuffShadow << 8) | thech;
791  0 bsLiveShadow += 8;
792  0 continue;
793    }
794  0 bsLiveShadow--;
795  0 zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
796    }
797  0 nextSym = perm_zt[zvec - base_zt[zn]];
798    }
799    }
800   
801  0 this.last = lastShadow;
802  0 this.bsLive = bsLiveShadow;
803  0 this.bsBuff = bsBuffShadow;
804    }
805   
 
806  0 toggle private int getAndMoveToFrontDecode0(final int groupNo) throws IOException {
807  0 final InputStream inShadow = this.in;
808  0 final Data dataShadow = this.data;
809  0 final int zt = dataShadow.selector[groupNo] & 0xff;
810  0 final int[] limit_zt = dataShadow.limit[zt];
811  0 int zn = dataShadow.minLens[zt];
812  0 int zvec = bsR(zn);
813  0 int bsLiveShadow = this.bsLive;
814  0 int bsBuffShadow = this.bsBuff;
815   
816  0 while (zvec > limit_zt[zn]) {
817  0 zn++;
818  0 while (bsLiveShadow < 1) {
819  0 final int thech = read();//inShadow.read();
820   
821  0 if (thech < 0)
822  0 throw new IOException("unexpected end of stream");
823   
824  0 bsBuffShadow = (bsBuffShadow << 8) | thech;
825  0 bsLiveShadow += 8;
826  0 continue;
827    }
828  0 bsLiveShadow--;
829  0 zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
830    }
831   
832  0 this.bsLive = bsLiveShadow;
833  0 this.bsBuff = bsBuffShadow;
834   
835  0 return dataShadow.perm[zt][zvec - dataShadow.base[zt][zn]];
836    }
837   
 
838  0 toggle private void setupBlock() throws IOException {
839  0 if (this.data == null) {
840  0 return;
841    }
842   
843  0 final int[] cftab = this.data.cftab;
844  0 final int[] tt = this.data.initTT(this.last + 1);
845  0 final byte[] ll8 = this.data.ll8;
846  0 cftab[0] = 0;
847  0 System.arraycopy(this.data.unzftab, 0, cftab, 1, 256);
848   
849  0 for (int i = 1, c = cftab[0]; i <= 256; i++) {
850  0 c += cftab[i];
851  0 cftab[i] = c;
852    }
853   
854  0 for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) {
855  0 tt[cftab[ll8[i] & 0xff]++] = i;
856    }
857   
858  0 if ((this.origPtr < 0) || (this.origPtr >= tt.length)) {
859  0 throw new IOException("stream corrupted");
860    }
861   
862  0 this.su_tPos = tt[this.origPtr];
863  0 this.su_count = 0;
864  0 this.su_i2 = 0;
865  0 this.su_ch2 = 256; /* not a char and not EOF */
866   
867  0 if (this.blockRandomised) {
868  0 this.su_rNToGo = 0;
869  0 this.su_rTPos = 0;
870  0 setupRandPartA();
871    } else {
872  0 setupNoRandPartA();
873    }
874    }
875   
 
876  0 toggle private void setupRandPartA() throws IOException {
877  0 if (this.su_i2 <= this.last) {
878  0 this.su_chPrev = this.su_ch2;
879  0 int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
880  0 this.su_tPos = this.data.tt[this.su_tPos];
881  0 if (this.su_rNToGo == 0) {
882  0 this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
883  0 if (++this.su_rTPos == 512) {
884  0 this.su_rTPos = 0;
885    }
886    } else {
887  0 this.su_rNToGo--;
888    }
889  0 this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0;
890  0 this.su_i2++;
891  0 this.currentChar = su_ch2Shadow;
892  0 this.currentState = RAND_PART_B_STATE;
893  0 this.crc.updateCRC(su_ch2Shadow);
894    } else {
895  0 endBlock();
896  0 initBlock();
897  0 setupBlock();
898    }
899    }
900   
 
901  0 toggle private void setupNoRandPartA() throws IOException {
902  0 if (this.su_i2 <= this.last) {
903  0 this.su_chPrev = this.su_ch2;
904  0 int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
905  0 this.su_ch2 = su_ch2Shadow;
906  0 this.su_tPos = this.data.tt[this.su_tPos];
907  0 this.su_i2++;
908  0 this.currentChar = su_ch2Shadow;
909  0 this.currentState = NO_RAND_PART_B_STATE;
910  0 this.crc.updateCRC(su_ch2Shadow);
911    } else {
912  0 this.currentState = NO_RAND_PART_A_STATE;
913  0 endBlock();
914  0 initBlock();
915  0 setupBlock();
916    }
917    }
918   
 
919  0 toggle private void setupRandPartB() throws IOException {
920  0 if (this.su_ch2 != this.su_chPrev) {
921  0 this.currentState = RAND_PART_A_STATE;
922  0 this.su_count = 1;
923  0 setupRandPartA();
924  0 } else if (++this.su_count >= 4) {
925  0 this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
926  0 this.su_tPos = this.data.tt[this.su_tPos];
927  0 if (this.su_rNToGo == 0) {
928  0 this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
929  0 if (++this.su_rTPos == 512) {
930  0 this.su_rTPos = 0;
931    }
932    } else {
933  0 this.su_rNToGo--;
934    }
935  0 this.su_j2 = 0;
936  0 this.currentState = RAND_PART_C_STATE;
937  0 if (this.su_rNToGo == 1) {
938  0 this.su_z ^= 1;
939    }
940  0 setupRandPartC();
941    } else {
942  0 this.currentState = RAND_PART_A_STATE;
943  0 setupRandPartA();
944    }
945    }
946   
 
947  0 toggle private void setupRandPartC() throws IOException {
948  0 if (this.su_j2 < this.su_z) {
949  0 this.currentChar = this.su_ch2;
950  0 this.crc.updateCRC(this.su_ch2);
951  0 this.su_j2++;
952    } else {
953  0 this.currentState = RAND_PART_A_STATE;
954  0 this.su_i2++;
955  0 this.su_count = 0;
956  0 setupRandPartA();
957    }
958    }
959   
 
960  0 toggle private void setupNoRandPartB() throws IOException {
961  0 if (this.su_ch2 != this.su_chPrev) {
962  0 this.su_count = 1;
963  0 setupNoRandPartA();
964  0 } else if (++this.su_count >= 4) {
965  0 this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
966  0 this.su_tPos = this.data.tt[this.su_tPos];
967  0 this.su_j2 = 0;
968  0 setupNoRandPartC();
969    } else {
970  0 setupNoRandPartA();
971    }
972    }
973   
 
974  0 toggle private void setupNoRandPartC() throws IOException {
975  0 if (this.su_j2 < this.su_z) {
976  0 int su_ch2Shadow = this.su_ch2;
977  0 this.currentChar = su_ch2Shadow;
978  0 this.crc.updateCRC(su_ch2Shadow);
979  0 this.su_j2++;
980  0 this.currentState = NO_RAND_PART_C_STATE;
981    } else {
982  0 this.su_i2++;
983  0 this.su_count = 0;
984  0 setupNoRandPartA();
985    }
986    }
987   
 
988    private static final class Data extends Object {
989   
990    // (with blockSize 900k)
991    final boolean[] inUse = new boolean[256]; // 256 byte
992   
993    final byte[] seqToUnseq = new byte[256]; // 256 byte
994    final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte
995    final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte
996   
997    /**
998    * Freq table collected to save a pass over the data during
999    * decompression.
1000    */
1001    final int[] unzftab = new int[256]; // 1024 byte
1002   
1003    final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
1004    final int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
1005    final int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
1006    final int[] minLens = new int[N_GROUPS]; // 24 byte
1007   
1008    final int[] cftab = new int[257]; // 1028 byte
1009    final char[] getAndMoveToFrontDecode_yy = new char[256]; // 512 byte
1010    final char[][] temp_charArray2d = new char[N_GROUPS][MAX_ALPHA_SIZE]; // 3096 byte
1011    final byte[] recvDecodingTables_pos = new byte[N_GROUPS]; // 6 byte
1012    //---------------
1013    // 60798 byte
1014   
1015    int[] tt; // 3600000 byte
1016    byte[] ll8; // 900000 byte
1017    //---------------
1018    // 4560782 byte
1019    //===============
1020   
 
1021  0 toggle Data(int blockSize100k) {
1022  0 super();
1023   
1024  0 this.ll8 = new byte[blockSize100k * BZip2Constants.baseBlockSize];
1025    }
1026   
1027    /**
1028    * Initializes the {@link #tt} array.
1029    *
1030    * This method is called when the required length of the array
1031    * is known. I don't initialize it at construction time to
1032    * avoid unnecessary memory allocation when compressing small
1033    * files.
1034    * @param length
1035    * @return int array
1036    */
 
1037  0 toggle final int[] initTT(int length) {
1038  0 int[] ttShadow = this.tt;
1039   
1040    // tt.length should always be >= length, but theoretically
1041    // it can happen, if the compressor mixed small and large
1042    // blocks. Normally only the last block will be smaller
1043    // than others.
1044  0 if ((ttShadow == null) || (ttShadow.length < length)) {
1045  0 this.tt = ttShadow = new int[length];
1046    }
1047   
1048  0 return ttShadow;
1049    }
1050   
1051    }
1052   
 
1053  0 toggle @SuppressWarnings("unused")
1054    private static void reportCRCError() throws IOException {
1055    // The clean way would be to throw an exception.
1056    //throw new IOException("crc error");
1057   
1058    // Just print a message, like the previous versions of this class did
1059  0 System.err.println("BZip2 CRC error");
1060    }
1061   
1062    }
1063