You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

CBZip2InputStream.java 33 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  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. * This package is based on the work done by Keiron Liddle, Aftex Software
  20. * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
  21. * great code.
  22. */
  23. package org.apache.tools.bzip2;
  24. import java.io.InputStream;
  25. import java.io.IOException;
  26. /**
  27. * An input stream that decompresses from the BZip2 format (without the file
  28. * header chars) to be read as any other stream.
  29. *
  30. * <p>The decompression requires large amounts of memory. Thus you
  31. * should call the {@link #close() close()} method as soon as
  32. * possible, to force <tt>CBZip2InputStream</tt> to release the
  33. * allocated memory. See {@link CBZip2OutputStream
  34. * CBZip2OutputStream} for information about memory usage.</p>
  35. *
  36. * <p><tt>CBZip2InputStream</tt> reads bytes from the compressed
  37. * source stream via the single byte {@link java.io.InputStream#read()
  38. * read()} method exclusively. Thus you should consider to use a
  39. * buffered source stream.</p>
  40. *
  41. * <p>Instances of this class are not threadsafe.</p>
  42. */
  43. public class CBZip2InputStream extends InputStream implements BZip2Constants {
  44. private static void reportCRCError() throws IOException {
  45. // The clean way would be to throw an exception.
  46. //throw new IOException("crc error");
  47. // Just print a message, like the previous versions of this class did
  48. System.err.println("BZip2 CRC error");
  49. }
  50. private void makeMaps() {
  51. final boolean[] inUse = this.data.inUse;
  52. final byte[] seqToUnseq = this.data.seqToUnseq;
  53. int nInUseShadow = 0;
  54. for (int i = 0; i < 256; i++) {
  55. if (inUse[i])
  56. seqToUnseq[nInUseShadow++] = (byte) i;
  57. }
  58. this.nInUse = nInUseShadow;
  59. }
  60. /**
  61. * Index of the last char in the block, so the block size == last + 1.
  62. */
  63. private int last;
  64. /**
  65. * Index in zptr[] of original string after sorting.
  66. */
  67. private int origPtr;
  68. /**
  69. * always: in the range 0 .. 9.
  70. * The current block size is 100000 * this number.
  71. */
  72. private int blockSize100k;
  73. private boolean blockRandomised;
  74. private int bsBuff;
  75. private int bsLive;
  76. private final CRC crc = new CRC();
  77. private int nInUse;
  78. private InputStream in;
  79. private int currentChar = -1;
  80. private static final int EOF = 0;
  81. private static final int START_BLOCK_STATE = 1;
  82. private static final int RAND_PART_A_STATE = 2;
  83. private static final int RAND_PART_B_STATE = 3;
  84. private static final int RAND_PART_C_STATE = 4;
  85. private static final int NO_RAND_PART_A_STATE = 5;
  86. private static final int NO_RAND_PART_B_STATE = 6;
  87. private static final int NO_RAND_PART_C_STATE = 7;
  88. private int currentState = START_BLOCK_STATE;
  89. private int storedBlockCRC, storedCombinedCRC;
  90. private int computedBlockCRC, computedCombinedCRC;
  91. // Variables used by setup* methods exclusively
  92. private int su_count;
  93. private int su_ch2;
  94. private int su_chPrev;
  95. private int su_i2;
  96. private int su_j2;
  97. private int su_rNToGo;
  98. private int su_rTPos;
  99. private int su_tPos;
  100. private char su_z;
  101. /**
  102. * All memory intensive stuff.
  103. * This field is initialized by initBlock().
  104. */
  105. private CBZip2InputStream.Data data;
  106. /**
  107. * Constructs a new CBZip2InputStream which decompresses bytes read from
  108. * the specified stream.
  109. *
  110. * <p>Although BZip2 headers are marked with the magic
  111. * <tt>"Bz"</tt> this constructor expects the next byte in the
  112. * stream to be the first one after the magic. Thus callers have
  113. * to skip the first two bytes. Otherwise this constructor will
  114. * throw an exception. </p>
  115. *
  116. * @throws IOException
  117. * if the stream content is malformed or an I/O error occurs.
  118. * @throws NullPointerException
  119. * if <tt>in == null</tt>
  120. */
  121. public CBZip2InputStream(final InputStream in) throws IOException {
  122. super();
  123. this.in = in;
  124. init();
  125. }
  126. public int read() throws IOException {
  127. if (this.in != null) {
  128. return read0();
  129. } else {
  130. throw new IOException("stream closed");
  131. }
  132. }
  133. public int read(final byte[] dest, final int offs, final int len)
  134. throws IOException {
  135. if (offs < 0) {
  136. throw new IndexOutOfBoundsException("offs(" + offs + ") < 0.");
  137. }
  138. if (len < 0) {
  139. throw new IndexOutOfBoundsException("len(" + len + ") < 0.");
  140. }
  141. if (offs + len > dest.length) {
  142. throw new IndexOutOfBoundsException("offs(" + offs + ") + len("
  143. + len + ") > dest.length("
  144. + dest.length + ").");
  145. }
  146. if (this.in == null) {
  147. throw new IOException("stream closed");
  148. }
  149. final int hi = offs + len;
  150. int destOffs = offs;
  151. for (int b; (destOffs < hi) && ((b = read0()) >= 0);) {
  152. dest[destOffs++] = (byte) b;
  153. }
  154. return (destOffs == offs) ? -1 : (destOffs - offs);
  155. }
  156. private int read0() throws IOException {
  157. final int retChar = this.currentChar;
  158. switch (this.currentState) {
  159. case EOF:
  160. return -1;
  161. case START_BLOCK_STATE:
  162. throw new IllegalStateException();
  163. case RAND_PART_A_STATE:
  164. throw new IllegalStateException();
  165. case RAND_PART_B_STATE:
  166. setupRandPartB();
  167. break;
  168. case RAND_PART_C_STATE:
  169. setupRandPartC();
  170. break;
  171. case NO_RAND_PART_A_STATE:
  172. throw new IllegalStateException();
  173. case NO_RAND_PART_B_STATE:
  174. setupNoRandPartB();
  175. break;
  176. case NO_RAND_PART_C_STATE:
  177. setupNoRandPartC();
  178. break;
  179. default:
  180. throw new IllegalStateException();
  181. }
  182. return retChar;
  183. }
  184. private void init() throws IOException {
  185. int magic2 = this.in.read();
  186. if (magic2 != 'h') {
  187. throw new IOException("Stream is not BZip2 formatted: expected 'h'"
  188. + " as first byte but got '" + (char) magic2
  189. + "'");
  190. }
  191. int blockSize = this.in.read();
  192. if ((blockSize < '1') || (blockSize > '9')) {
  193. throw new IOException("Stream is not BZip2 formatted: illegal "
  194. + "blocksize " + (char) blockSize);
  195. }
  196. this.blockSize100k = blockSize - '0';
  197. initBlock();
  198. setupBlock();
  199. }
  200. private void initBlock() throws IOException {
  201. char magic0 = bsGetUByte();
  202. char magic1 = bsGetUByte();
  203. char magic2 = bsGetUByte();
  204. char magic3 = bsGetUByte();
  205. char magic4 = bsGetUByte();
  206. char magic5 = bsGetUByte();
  207. if (magic0 == 0x17 &&
  208. magic1 == 0x72 &&
  209. magic2 == 0x45 &&
  210. magic3 == 0x38 &&
  211. magic4 == 0x50 &&
  212. magic5 == 0x90) {
  213. complete(); // end of file
  214. } else if (magic0 != 0x31 || // '1'
  215. magic1 != 0x41 || // ')'
  216. magic2 != 0x59 || // 'Y'
  217. magic3 != 0x26 || // '&'
  218. magic4 != 0x53 || // 'S'
  219. magic5 != 0x59 // 'Y'
  220. ) {
  221. this.currentState = EOF;
  222. throw new IOException("bad block header");
  223. } else {
  224. this.storedBlockCRC = bsGetInt();
  225. this.blockRandomised = bsR(1) == 1;
  226. /**
  227. * Allocate data here instead in constructor, so we do not
  228. * allocate it if the input file is empty.
  229. */
  230. if (this.data == null) {
  231. this.data = new Data(this.blockSize100k);
  232. }
  233. // currBlockNo++;
  234. getAndMoveToFrontDecode();
  235. this.crc.initialiseCRC();
  236. this.currentState = START_BLOCK_STATE;
  237. }
  238. }
  239. private void endBlock() throws IOException {
  240. this.computedBlockCRC = this.crc.getFinalCRC();
  241. // A bad CRC is considered a fatal error.
  242. if (this.storedBlockCRC != this.computedBlockCRC) {
  243. // make next blocks readable without error
  244. // (repair feature, not yet documented, not tested)
  245. this.computedCombinedCRC
  246. = (this.storedCombinedCRC << 1)
  247. | (this.storedCombinedCRC >>> 31);
  248. this.computedCombinedCRC ^= this.storedBlockCRC;
  249. reportCRCError();
  250. }
  251. this.computedCombinedCRC
  252. = (this.computedCombinedCRC << 1)
  253. | (this.computedCombinedCRC >>> 31);
  254. this.computedCombinedCRC ^= this.computedBlockCRC;
  255. }
  256. private void complete() throws IOException {
  257. this.storedCombinedCRC = bsGetInt();
  258. this.currentState = EOF;
  259. this.data = null;
  260. if (this.storedCombinedCRC != this.computedCombinedCRC) {
  261. reportCRCError();
  262. }
  263. }
  264. public void close() throws IOException {
  265. InputStream inShadow = this.in;
  266. if (inShadow != null) {
  267. try {
  268. if (inShadow != System.in) {
  269. inShadow.close();
  270. }
  271. } finally {
  272. this.data = null;
  273. this.in = null;
  274. }
  275. }
  276. }
  277. private int bsR(final int n) throws IOException {
  278. int bsLiveShadow = this.bsLive;
  279. int bsBuffShadow = this.bsBuff;
  280. if (bsLiveShadow < n) {
  281. final InputStream inShadow = this.in;
  282. do {
  283. int thech = inShadow.read();
  284. if (thech < 0) {
  285. throw new IOException("unexpected end of stream");
  286. }
  287. bsBuffShadow = (bsBuffShadow << 8) | thech;
  288. bsLiveShadow += 8;
  289. } while (bsLiveShadow < n);
  290. this.bsBuff = bsBuffShadow;
  291. }
  292. this.bsLive = bsLiveShadow - n;
  293. return (bsBuffShadow >> (bsLiveShadow - n)) & ((1 << n) - 1);
  294. }
  295. private boolean bsGetBit() throws IOException {
  296. int bsLiveShadow = this.bsLive;
  297. int bsBuffShadow = this.bsBuff;
  298. if (bsLiveShadow < 1) {
  299. int thech = this.in.read();
  300. if (thech < 0) {
  301. throw new IOException("unexpected end of stream");
  302. }
  303. bsBuffShadow = (bsBuffShadow << 8) | thech;
  304. bsLiveShadow += 8;
  305. this.bsBuff = bsBuffShadow;
  306. }
  307. this.bsLive = bsLiveShadow - 1;
  308. return ((bsBuffShadow >> (bsLiveShadow - 1)) & 1) != 0;
  309. }
  310. private char bsGetUByte() throws IOException {
  311. return (char) bsR(8);
  312. }
  313. private int bsGetInt() throws IOException {
  314. return (((((bsR(8) << 8) | bsR(8)) << 8) | bsR(8)) << 8) | bsR(8);
  315. }
  316. /**
  317. * Called by createHuffmanDecodingTables() exclusively.
  318. */
  319. private static void hbCreateDecodeTables(final int[] limit,
  320. final int[] base,
  321. final int[] perm,
  322. final char[] length,
  323. final int minLen,
  324. final int maxLen,
  325. final int alphaSize) {
  326. for (int i = minLen, pp = 0; i <= maxLen; i++) {
  327. for (int j = 0; j < alphaSize; j++) {
  328. if (length[j] == i) {
  329. perm[pp++] = j;
  330. }
  331. }
  332. }
  333. for (int i = MAX_CODE_LEN; --i > 0;) {
  334. base[i] = 0;
  335. limit[i] = 0;
  336. }
  337. for (int i = 0; i < alphaSize; i++) {
  338. base[length[i] + 1]++;
  339. }
  340. for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) {
  341. b += base[i];
  342. base[i] = b;
  343. }
  344. for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) {
  345. final int nb = base[i + 1];
  346. vec += nb - b;
  347. b = nb;
  348. limit[i] = vec - 1;
  349. vec <<= 1;
  350. }
  351. for (int i = minLen + 1; i <= maxLen; i++) {
  352. base[i] = ((limit[i - 1] + 1) << 1) - base[i];
  353. }
  354. }
  355. private void recvDecodingTables() throws IOException {
  356. final Data dataShadow = this.data;
  357. final boolean[] inUse = dataShadow.inUse;
  358. final byte[] pos = dataShadow.recvDecodingTables_pos;
  359. final byte[] selector = dataShadow.selector;
  360. final byte[] selectorMtf = dataShadow.selectorMtf;
  361. int inUse16 = 0;
  362. /* Receive the mapping table */
  363. for (int i = 0; i < 16; i++) {
  364. if (bsGetBit()) {
  365. inUse16 |= 1 << i;
  366. }
  367. }
  368. for (int i = 256; --i >= 0;) {
  369. inUse[i] = false;
  370. }
  371. for (int i = 0; i < 16; i++) {
  372. if ((inUse16 & (1 << i)) != 0) {
  373. final int i16 = i << 4;
  374. for (int j = 0; j < 16; j++) {
  375. if (bsGetBit()) {
  376. inUse[i16 + j] = true;
  377. }
  378. }
  379. }
  380. }
  381. makeMaps();
  382. final int alphaSize = this.nInUse + 2;
  383. /* Now the selectors */
  384. final int nGroups = bsR(3);
  385. final int nSelectors = bsR(15);
  386. for (int i = 0; i < nSelectors; i++) {
  387. int j = 0;
  388. while (bsGetBit()) {
  389. j++;
  390. }
  391. selectorMtf[i] = (byte) j;
  392. }
  393. /* Undo the MTF values for the selectors. */
  394. for (int v = nGroups; --v >= 0;) {
  395. pos[v] = (byte) v;
  396. }
  397. for (int i = 0; i < nSelectors; i++) {
  398. int v = selectorMtf[i] & 0xff;
  399. final byte tmp = pos[v];
  400. while (v > 0) {
  401. // nearly all times v is zero, 4 in most other cases
  402. pos[v] = pos[v - 1];
  403. v--;
  404. }
  405. pos[0] = tmp;
  406. selector[i] = tmp;
  407. }
  408. final char[][] len = dataShadow.temp_charArray2d;
  409. /* Now the coding tables */
  410. for (int t = 0; t < nGroups; t++) {
  411. int curr = bsR(5);
  412. final char[] len_t = len[t];
  413. for (int i = 0; i < alphaSize; i++) {
  414. while (bsGetBit()) {
  415. curr += bsGetBit() ? -1 : 1;
  416. }
  417. len_t[i] = (char) curr;
  418. }
  419. }
  420. // finally create the Huffman tables
  421. createHuffmanDecodingTables(alphaSize, nGroups);
  422. }
  423. /**
  424. * Called by recvDecodingTables() exclusively.
  425. */
  426. private void createHuffmanDecodingTables(final int alphaSize,
  427. final int nGroups) {
  428. final Data dataShadow = this.data;
  429. final char[][] len = dataShadow.temp_charArray2d;
  430. final int[] minLens = dataShadow.minLens;
  431. final int[][] limit = dataShadow.limit;
  432. final int[][] base = dataShadow.base;
  433. final int[][] perm = dataShadow.perm;
  434. for (int t = 0; t < nGroups; t++) {
  435. int minLen = 32;
  436. int maxLen = 0;
  437. final char[] len_t = len[t];
  438. for (int i = alphaSize; --i >= 0;) {
  439. final char lent = len_t[i];
  440. if (lent > maxLen) {
  441. maxLen = lent;
  442. }
  443. if (lent < minLen) {
  444. minLen = lent;
  445. }
  446. }
  447. hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen,
  448. maxLen, alphaSize);
  449. minLens[t] = minLen;
  450. }
  451. }
  452. private void getAndMoveToFrontDecode() throws IOException {
  453. this.origPtr = bsR(24);
  454. recvDecodingTables();
  455. final InputStream inShadow = this.in;
  456. final Data dataShadow = this.data;
  457. final byte[] ll8 = dataShadow.ll8;
  458. final int[] unzftab = dataShadow.unzftab;
  459. final byte[] selector = dataShadow.selector;
  460. final byte[] seqToUnseq = dataShadow.seqToUnseq;
  461. final char[] yy = dataShadow.getAndMoveToFrontDecode_yy;
  462. final int[] minLens = dataShadow.minLens;
  463. final int[][] limit = dataShadow.limit;
  464. final int[][] base = dataShadow.base;
  465. final int[][] perm = dataShadow.perm;
  466. final int limitLast = this.blockSize100k * 100000;
  467. /*
  468. Setting up the unzftab entries here is not strictly
  469. necessary, but it does save having to do it later
  470. in a separate pass, and so saves a block's worth of
  471. cache misses.
  472. */
  473. for (int i = 256; --i >= 0;) {
  474. yy[i] = (char) i;
  475. unzftab[i] = 0;
  476. }
  477. int groupNo = 0;
  478. int groupPos = G_SIZE - 1;
  479. final int eob = this.nInUse + 1;
  480. int nextSym = getAndMoveToFrontDecode0(0);
  481. int bsBuffShadow = this.bsBuff;
  482. int bsLiveShadow = this.bsLive;
  483. int lastShadow = -1;
  484. int zt = selector[groupNo] & 0xff;
  485. int[] base_zt = base[zt];
  486. int[] limit_zt = limit[zt];
  487. int[] perm_zt = perm[zt];
  488. int minLens_zt = minLens[zt];
  489. while (nextSym != eob) {
  490. if ((nextSym == RUNA) || (nextSym == RUNB)) {
  491. int s = -1;
  492. for (int n = 1; true; n <<= 1) {
  493. if (nextSym == RUNA) {
  494. s += n;
  495. } else if (nextSym == RUNB) {
  496. s += n << 1;
  497. } else {
  498. break;
  499. }
  500. if (groupPos == 0) {
  501. groupPos = G_SIZE - 1;
  502. zt = selector[++groupNo] & 0xff;
  503. base_zt = base[zt];
  504. limit_zt = limit[zt];
  505. perm_zt = perm[zt];
  506. minLens_zt = minLens[zt];
  507. } else {
  508. groupPos--;
  509. }
  510. int zn = minLens_zt;
  511. // Inlined:
  512. // int zvec = bsR(zn);
  513. while (bsLiveShadow < zn) {
  514. final int thech = inShadow.read();
  515. if (thech >= 0) {
  516. bsBuffShadow = (bsBuffShadow << 8) | thech;
  517. bsLiveShadow += 8;
  518. continue;
  519. } else {
  520. throw new IOException("unexpected end of stream");
  521. }
  522. }
  523. int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1);
  524. bsLiveShadow -= zn;
  525. while (zvec > limit_zt[zn]) {
  526. zn++;
  527. while (bsLiveShadow < 1) {
  528. final int thech = inShadow.read();
  529. if (thech >= 0) {
  530. bsBuffShadow = (bsBuffShadow << 8) | thech;
  531. bsLiveShadow += 8;
  532. continue;
  533. } else {
  534. throw new IOException("unexpected end of stream");
  535. }
  536. }
  537. bsLiveShadow--;
  538. zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
  539. }
  540. nextSym = perm_zt[zvec - base_zt[zn]];
  541. }
  542. final byte ch = seqToUnseq[yy[0]];
  543. unzftab[ch & 0xff] += s + 1;
  544. while (s-- >= 0) {
  545. ll8[++lastShadow] = ch;
  546. }
  547. if (lastShadow >= limitLast) {
  548. throw new IOException("block overrun");
  549. }
  550. } else {
  551. if (++lastShadow >= limitLast) {
  552. throw new IOException("block overrun");
  553. }
  554. final char tmp = yy[nextSym - 1];
  555. unzftab[seqToUnseq[tmp] & 0xff]++;
  556. ll8[lastShadow] = seqToUnseq[tmp];
  557. /*
  558. This loop is hammered during decompression,
  559. hence avoid native method call overhead of
  560. System.arraycopy for very small ranges to copy.
  561. */
  562. if (nextSym <= 16) {
  563. for (int j = nextSym - 1; j > 0;) {
  564. yy[j] = yy[--j];
  565. }
  566. } else {
  567. System.arraycopy(yy, 0, yy, 1, nextSym - 1);
  568. }
  569. yy[0] = tmp;
  570. if (groupPos == 0) {
  571. groupPos = G_SIZE - 1;
  572. zt = selector[++groupNo] & 0xff;
  573. base_zt = base[zt];
  574. limit_zt = limit[zt];
  575. perm_zt = perm[zt];
  576. minLens_zt = minLens[zt];
  577. } else {
  578. groupPos--;
  579. }
  580. int zn = minLens_zt;
  581. // Inlined:
  582. // int zvec = bsR(zn);
  583. while (bsLiveShadow < zn) {
  584. final int thech = inShadow.read();
  585. if (thech >= 0) {
  586. bsBuffShadow = (bsBuffShadow << 8) | thech;
  587. bsLiveShadow += 8;
  588. continue;
  589. } else {
  590. throw new IOException("unexpected end of stream");
  591. }
  592. }
  593. int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1);
  594. bsLiveShadow -= zn;
  595. while (zvec > limit_zt[zn]) {
  596. zn++;
  597. while (bsLiveShadow < 1) {
  598. final int thech = inShadow.read();
  599. if (thech >= 0) {
  600. bsBuffShadow = (bsBuffShadow << 8) | thech;
  601. bsLiveShadow += 8;
  602. continue;
  603. } else {
  604. throw new IOException("unexpected end of stream");
  605. }
  606. }
  607. bsLiveShadow--;
  608. zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
  609. }
  610. nextSym = perm_zt[zvec - base_zt[zn]];
  611. }
  612. }
  613. this.last = lastShadow;
  614. this.bsLive = bsLiveShadow;
  615. this.bsBuff = bsBuffShadow;
  616. }
  617. private int getAndMoveToFrontDecode0(final int groupNo)
  618. throws IOException {
  619. final InputStream inShadow = this.in;
  620. final Data dataShadow = this.data;
  621. final int zt = dataShadow.selector[groupNo] & 0xff;
  622. final int[] limit_zt = dataShadow.limit[zt];
  623. int zn = dataShadow.minLens[zt];
  624. int zvec = bsR(zn);
  625. int bsLiveShadow = this.bsLive;
  626. int bsBuffShadow = this.bsBuff;
  627. while (zvec > limit_zt[zn]) {
  628. zn++;
  629. while (bsLiveShadow < 1) {
  630. final int thech = inShadow.read();
  631. if (thech >= 0) {
  632. bsBuffShadow = (bsBuffShadow << 8) | thech;
  633. bsLiveShadow += 8;
  634. continue;
  635. } else {
  636. throw new IOException("unexpected end of stream");
  637. }
  638. }
  639. bsLiveShadow--;
  640. zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
  641. }
  642. this.bsLive = bsLiveShadow;
  643. this.bsBuff = bsBuffShadow;
  644. return dataShadow.perm[zt][zvec - dataShadow.base[zt][zn]];
  645. }
  646. private void setupBlock() throws IOException {
  647. if (this.data == null) {
  648. return;
  649. }
  650. final int[] cftab = this.data.cftab;
  651. final int[] tt = this.data.initTT(this.last + 1);
  652. final byte[] ll8 = this.data.ll8;
  653. cftab[0] = 0;
  654. System.arraycopy(this.data.unzftab, 0, cftab, 1, 256);
  655. for (int i = 1, c = cftab[0]; i <= 256; i++) {
  656. c += cftab[i];
  657. cftab[i] = c;
  658. }
  659. for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) {
  660. tt[cftab[ll8[i] & 0xff]++] = i;
  661. }
  662. if ((this.origPtr < 0) || (this.origPtr >= tt.length)) {
  663. throw new IOException("stream corrupted");
  664. }
  665. this.su_tPos = tt[this.origPtr];
  666. this.su_count = 0;
  667. this.su_i2 = 0;
  668. this.su_ch2 = 256; /* not a char and not EOF */
  669. if (this.blockRandomised) {
  670. this.su_rNToGo = 0;
  671. this.su_rTPos = 0;
  672. setupRandPartA();
  673. } else {
  674. setupNoRandPartA();
  675. }
  676. }
  677. private void setupRandPartA() throws IOException {
  678. if (this.su_i2 <= this.last) {
  679. this.su_chPrev = this.su_ch2;
  680. int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
  681. this.su_tPos = this.data.tt[this.su_tPos];
  682. if (this.su_rNToGo == 0) {
  683. this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
  684. if (++this.su_rTPos == 512) {
  685. this.su_rTPos = 0;
  686. }
  687. } else {
  688. this.su_rNToGo--;
  689. }
  690. this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0;
  691. this.su_i2++;
  692. this.currentChar = su_ch2Shadow;
  693. this.currentState = RAND_PART_B_STATE;
  694. this.crc.updateCRC(su_ch2Shadow);
  695. } else {
  696. endBlock();
  697. initBlock();
  698. setupBlock();
  699. }
  700. }
  701. private void setupNoRandPartA() throws IOException {
  702. if (this.su_i2 <= this.last) {
  703. this.su_chPrev = this.su_ch2;
  704. int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
  705. this.su_ch2 = su_ch2Shadow;
  706. this.su_tPos = this.data.tt[this.su_tPos];
  707. this.su_i2++;
  708. this.currentChar = su_ch2Shadow;
  709. this.currentState = NO_RAND_PART_B_STATE;
  710. this.crc.updateCRC(su_ch2Shadow);
  711. } else {
  712. this.currentState = NO_RAND_PART_A_STATE;
  713. endBlock();
  714. initBlock();
  715. setupBlock();
  716. }
  717. }
  718. private void setupRandPartB() throws IOException {
  719. if (this.su_ch2 != this.su_chPrev) {
  720. this.currentState = RAND_PART_A_STATE;
  721. this.su_count = 1;
  722. setupRandPartA();
  723. } else if (++this.su_count >= 4) {
  724. this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
  725. this.su_tPos = this.data.tt[this.su_tPos];
  726. if (this.su_rNToGo == 0) {
  727. this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
  728. if (++this.su_rTPos == 512) {
  729. this.su_rTPos = 0;
  730. }
  731. } else {
  732. this.su_rNToGo--;
  733. }
  734. this.su_j2 = 0;
  735. this.currentState = RAND_PART_C_STATE;
  736. if (this.su_rNToGo == 1) {
  737. this.su_z ^= 1;
  738. }
  739. setupRandPartC();
  740. } else {
  741. this.currentState = RAND_PART_A_STATE;
  742. setupRandPartA();
  743. }
  744. }
  745. private void setupRandPartC() throws IOException {
  746. if (this.su_j2 < this.su_z) {
  747. this.currentChar = this.su_ch2;
  748. this.crc.updateCRC(this.su_ch2);
  749. this.su_j2++;
  750. } else {
  751. this.currentState = RAND_PART_A_STATE;
  752. this.su_i2++;
  753. this.su_count = 0;
  754. setupRandPartA();
  755. }
  756. }
  757. private void setupNoRandPartB() throws IOException {
  758. if (this.su_ch2 != this.su_chPrev) {
  759. this.su_count = 1;
  760. setupNoRandPartA();
  761. } else if (++this.su_count >= 4) {
  762. this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
  763. this.su_tPos = this.data.tt[this.su_tPos];
  764. this.su_j2 = 0;
  765. setupNoRandPartC();
  766. } else {
  767. setupNoRandPartA();
  768. }
  769. }
  770. private void setupNoRandPartC() throws IOException {
  771. if (this.su_j2 < this.su_z) {
  772. int su_ch2Shadow = this.su_ch2;
  773. this.currentChar = su_ch2Shadow;
  774. this.crc.updateCRC(su_ch2Shadow);
  775. this.su_j2++;
  776. this.currentState = NO_RAND_PART_C_STATE;
  777. } else {
  778. this.su_i2++;
  779. this.su_count = 0;
  780. setupNoRandPartA();
  781. }
  782. }
  783. private static final class Data extends Object {
  784. // (with blockSize 900k)
  785. final boolean[] inUse = new boolean[256]; // 256 byte
  786. final byte[] seqToUnseq = new byte[256]; // 256 byte
  787. final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte
  788. final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte
  789. /**
  790. * Freq table collected to save a pass over the data during
  791. * decompression.
  792. */
  793. final int[] unzftab = new int[256]; // 1024 byte
  794. final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
  795. final int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
  796. final int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
  797. final int[] minLens = new int[N_GROUPS]; // 24 byte
  798. final int[] cftab = new int[257]; // 1028 byte
  799. final char[] getAndMoveToFrontDecode_yy = new char[256]; // 512 byte
  800. final char[][] temp_charArray2d = new char[N_GROUPS][MAX_ALPHA_SIZE]; // 3096 byte
  801. final byte[] recvDecodingTables_pos = new byte[N_GROUPS]; // 6 byte
  802. //---------------
  803. // 60798 byte
  804. int[] tt; // 3600000 byte
  805. byte[] ll8; // 900000 byte
  806. //---------------
  807. // 4560782 byte
  808. //===============
  809. Data(int blockSize100k) {
  810. super();
  811. this.ll8 = new byte[blockSize100k * BZip2Constants.baseBlockSize];
  812. }
  813. /**
  814. * Initializes the {@link #tt} array.
  815. *
  816. * This method is called when the required length of the array
  817. * is known. I don't initialize it at construction time to
  818. * avoid unneccessary memory allocation when compressing small
  819. * files.
  820. */
  821. final int[] initTT(int length) {
  822. int[] ttShadow = this.tt;
  823. // tt.length should always be >= length, but theoretically
  824. // it can happen, if the compressor mixed small and large
  825. // blocks. Normally only the last block will be smaller
  826. // than others.
  827. if ((ttShadow == null) || (ttShadow.length < length)) {
  828. this.tt = ttShadow = new int[length];
  829. }
  830. return ttShadow;
  831. }
  832. }
  833. }