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

index.js 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /*
  2. seek-bzip - a pure-javascript module for seeking within bzip2 data
  3. Copyright (C) 2013 C. Scott Ananian
  4. Copyright (C) 2012 Eli Skeggs
  5. Copyright (C) 2011 Kevin Kwok
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  10. This library 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 GNU
  13. Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public
  15. License along with this library; if not, see
  16. http://www.gnu.org/licenses/lgpl-2.1.html
  17. Adapted from node-bzip, copyright 2012 Eli Skeggs.
  18. Adapted from bzip2.js, copyright 2011 Kevin Kwok (antimatter15@gmail.com).
  19. Based on micro-bunzip by Rob Landley (rob@landley.net).
  20. Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
  21. which also acknowledges contributions by Mike Burrows, David Wheeler,
  22. Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
  23. Robert Sedgewick, and Jon L. Bentley.
  24. */
  25. var BitReader = require('./bitreader');
  26. var Stream = require('./stream');
  27. var CRC32 = require('./crc32');
  28. var pjson = require('../package.json');
  29. var MAX_HUFCODE_BITS = 20;
  30. var MAX_SYMBOLS = 258;
  31. var SYMBOL_RUNA = 0;
  32. var SYMBOL_RUNB = 1;
  33. var MIN_GROUPS = 2;
  34. var MAX_GROUPS = 6;
  35. var GROUP_SIZE = 50;
  36. var WHOLEPI = "314159265359";
  37. var SQRTPI = "177245385090";
  38. var mtf = function(array, index) {
  39. var src = array[index], i;
  40. for (i = index; i > 0; i--) {
  41. array[i] = array[i-1];
  42. }
  43. array[0] = src;
  44. return src;
  45. };
  46. var Err = {
  47. OK: 0,
  48. LAST_BLOCK: -1,
  49. NOT_BZIP_DATA: -2,
  50. UNEXPECTED_INPUT_EOF: -3,
  51. UNEXPECTED_OUTPUT_EOF: -4,
  52. DATA_ERROR: -5,
  53. OUT_OF_MEMORY: -6,
  54. OBSOLETE_INPUT: -7,
  55. END_OF_BLOCK: -8
  56. };
  57. var ErrorMessages = {};
  58. ErrorMessages[Err.LAST_BLOCK] = "Bad file checksum";
  59. ErrorMessages[Err.NOT_BZIP_DATA] = "Not bzip data";
  60. ErrorMessages[Err.UNEXPECTED_INPUT_EOF] = "Unexpected input EOF";
  61. ErrorMessages[Err.UNEXPECTED_OUTPUT_EOF] = "Unexpected output EOF";
  62. ErrorMessages[Err.DATA_ERROR] = "Data error";
  63. ErrorMessages[Err.OUT_OF_MEMORY] = "Out of memory";
  64. ErrorMessages[Err.OBSOLETE_INPUT] = "Obsolete (pre 0.9.5) bzip format not supported.";
  65. var _throw = function(status, optDetail) {
  66. var msg = ErrorMessages[status] || 'unknown error';
  67. if (optDetail) { msg += ': '+optDetail; }
  68. var e = new TypeError(msg);
  69. e.errorCode = status;
  70. throw e;
  71. };
  72. var Bunzip = function(inputStream, outputStream) {
  73. this.writePos = this.writeCurrent = this.writeCount = 0;
  74. this._start_bunzip(inputStream, outputStream);
  75. };
  76. Bunzip.prototype._init_block = function() {
  77. var moreBlocks = this._get_next_block();
  78. if ( !moreBlocks ) {
  79. this.writeCount = -1;
  80. return false; /* no more blocks */
  81. }
  82. this.blockCRC = new CRC32();
  83. return true;
  84. };
  85. /* XXX micro-bunzip uses (inputStream, inputBuffer, len) as arguments */
  86. Bunzip.prototype._start_bunzip = function(inputStream, outputStream) {
  87. /* Ensure that file starts with "BZh['1'-'9']." */
  88. var buf = new Buffer(4);
  89. if (inputStream.read(buf, 0, 4) !== 4 ||
  90. String.fromCharCode(buf[0], buf[1], buf[2]) !== 'BZh')
  91. _throw(Err.NOT_BZIP_DATA, 'bad magic');
  92. var level = buf[3] - 0x30;
  93. if (level < 1 || level > 9)
  94. _throw(Err.NOT_BZIP_DATA, 'level out of range');
  95. this.reader = new BitReader(inputStream);
  96. /* Fourth byte (ascii '1'-'9'), indicates block size in units of 100k of
  97. uncompressed data. Allocate intermediate buffer for block. */
  98. this.dbufSize = 100000 * level;
  99. this.nextoutput = 0;
  100. this.outputStream = outputStream;
  101. this.streamCRC = 0;
  102. };
  103. Bunzip.prototype._get_next_block = function() {
  104. var i, j, k;
  105. var reader = this.reader;
  106. // this is get_next_block() function from micro-bunzip:
  107. /* Read in header signature and CRC, then validate signature.
  108. (last block signature means CRC is for whole file, return now) */
  109. var h = reader.pi();
  110. if (h === SQRTPI) { // last block
  111. return false; /* no more blocks */
  112. }
  113. if (h !== WHOLEPI)
  114. _throw(Err.NOT_BZIP_DATA);
  115. this.targetBlockCRC = reader.read(32) >>> 0; // (convert to unsigned)
  116. this.streamCRC = (this.targetBlockCRC ^
  117. ((this.streamCRC << 1) | (this.streamCRC>>>31))) >>> 0;
  118. /* We can add support for blockRandomised if anybody complains. There was
  119. some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
  120. it didn't actually work. */
  121. if (reader.read(1))
  122. _throw(Err.OBSOLETE_INPUT);
  123. var origPointer = reader.read(24);
  124. if (origPointer > this.dbufSize)
  125. _throw(Err.DATA_ERROR, 'initial position out of bounds');
  126. /* mapping table: if some byte values are never used (encoding things
  127. like ascii text), the compression code removes the gaps to have fewer
  128. symbols to deal with, and writes a sparse bitfield indicating which
  129. values were present. We make a translation table to convert the symbols
  130. back to the corresponding bytes. */
  131. var t = reader.read(16);
  132. var symToByte = new Buffer(256), symTotal = 0;
  133. for (i = 0; i < 16; i++) {
  134. if (t & (1 << (0xF - i))) {
  135. var o = i * 16;
  136. k = reader.read(16);
  137. for (j = 0; j < 16; j++)
  138. if (k & (1 << (0xF - j)))
  139. symToByte[symTotal++] = o + j;
  140. }
  141. }
  142. /* How many different huffman coding groups does this block use? */
  143. var groupCount = reader.read(3);
  144. if (groupCount < MIN_GROUPS || groupCount > MAX_GROUPS)
  145. _throw(Err.DATA_ERROR);
  146. /* nSelectors: Every GROUP_SIZE many symbols we select a new huffman coding
  147. group. Read in the group selector list, which is stored as MTF encoded
  148. bit runs. (MTF=Move To Front, as each value is used it's moved to the
  149. start of the list.) */
  150. var nSelectors = reader.read(15);
  151. if (nSelectors === 0)
  152. _throw(Err.DATA_ERROR);
  153. var mtfSymbol = new Buffer(256);
  154. for (i = 0; i < groupCount; i++)
  155. mtfSymbol[i] = i;
  156. var selectors = new Buffer(nSelectors); // was 32768...
  157. for (i = 0; i < nSelectors; i++) {
  158. /* Get next value */
  159. for (j = 0; reader.read(1); j++)
  160. if (j >= groupCount) _throw(Err.DATA_ERROR);
  161. /* Decode MTF to get the next selector */
  162. selectors[i] = mtf(mtfSymbol, j);
  163. }
  164. /* Read the huffman coding tables for each group, which code for symTotal
  165. literal symbols, plus two run symbols (RUNA, RUNB) */
  166. var symCount = symTotal + 2;
  167. var groups = [], hufGroup;
  168. for (j = 0; j < groupCount; j++) {
  169. var length = new Buffer(symCount), temp = new Uint16Array(MAX_HUFCODE_BITS + 1);
  170. /* Read huffman code lengths for each symbol. They're stored in
  171. a way similar to mtf; record a starting value for the first symbol,
  172. and an offset from the previous value for everys symbol after that. */
  173. t = reader.read(5); // lengths
  174. for (i = 0; i < symCount; i++) {
  175. for (;;) {
  176. if (t < 1 || t > MAX_HUFCODE_BITS) _throw(Err.DATA_ERROR);
  177. /* If first bit is 0, stop. Else second bit indicates whether
  178. to increment or decrement the value. */
  179. if(!reader.read(1))
  180. break;
  181. if(!reader.read(1))
  182. t++;
  183. else
  184. t--;
  185. }
  186. length[i] = t;
  187. }
  188. /* Find largest and smallest lengths in this group */
  189. var minLen, maxLen;
  190. minLen = maxLen = length[0];
  191. for (i = 1; i < symCount; i++) {
  192. if (length[i] > maxLen)
  193. maxLen = length[i];
  194. else if (length[i] < minLen)
  195. minLen = length[i];
  196. }
  197. /* Calculate permute[], base[], and limit[] tables from length[].
  198. *
  199. * permute[] is the lookup table for converting huffman coded symbols
  200. * into decoded symbols. base[] is the amount to subtract from the
  201. * value of a huffman symbol of a given length when using permute[].
  202. *
  203. * limit[] indicates the largest numerical value a symbol with a given
  204. * number of bits can have. This is how the huffman codes can vary in
  205. * length: each code with a value>limit[length] needs another bit.
  206. */
  207. hufGroup = {};
  208. groups.push(hufGroup);
  209. hufGroup.permute = new Uint16Array(MAX_SYMBOLS);
  210. hufGroup.limit = new Uint32Array(MAX_HUFCODE_BITS + 2);
  211. hufGroup.base = new Uint32Array(MAX_HUFCODE_BITS + 1);
  212. hufGroup.minLen = minLen;
  213. hufGroup.maxLen = maxLen;
  214. /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
  215. var pp = 0;
  216. for (i = minLen; i <= maxLen; i++) {
  217. temp[i] = hufGroup.limit[i] = 0;
  218. for (t = 0; t < symCount; t++)
  219. if (length[t] === i)
  220. hufGroup.permute[pp++] = t;
  221. }
  222. /* Count symbols coded for at each bit length */
  223. for (i = 0; i < symCount; i++)
  224. temp[length[i]]++;
  225. /* Calculate limit[] (the largest symbol-coding value at each bit
  226. * length, which is (previous limit<<1)+symbols at this level), and
  227. * base[] (number of symbols to ignore at each bit length, which is
  228. * limit minus the cumulative count of symbols coded for already). */
  229. pp = t = 0;
  230. for (i = minLen; i < maxLen; i++) {
  231. pp += temp[i];
  232. /* We read the largest possible symbol size and then unget bits
  233. after determining how many we need, and those extra bits could
  234. be set to anything. (They're noise from future symbols.) At
  235. each level we're really only interested in the first few bits,
  236. so here we set all the trailing to-be-ignored bits to 1 so they
  237. don't affect the value>limit[length] comparison. */
  238. hufGroup.limit[i] = pp - 1;
  239. pp <<= 1;
  240. t += temp[i];
  241. hufGroup.base[i + 1] = pp - t;
  242. }
  243. hufGroup.limit[maxLen + 1] = Number.MAX_VALUE; /* Sentinal value for reading next sym. */
  244. hufGroup.limit[maxLen] = pp + temp[maxLen] - 1;
  245. hufGroup.base[minLen] = 0;
  246. }
  247. /* We've finished reading and digesting the block header. Now read this
  248. block's huffman coded symbols from the file and undo the huffman coding
  249. and run length encoding, saving the result into dbuf[dbufCount++]=uc */
  250. /* Initialize symbol occurrence counters and symbol Move To Front table */
  251. var byteCount = new Uint32Array(256);
  252. for (i = 0; i < 256; i++)
  253. mtfSymbol[i] = i;
  254. /* Loop through compressed symbols. */
  255. var runPos = 0, dbufCount = 0, selector = 0, uc;
  256. var dbuf = this.dbuf = new Uint32Array(this.dbufSize);
  257. symCount = 0;
  258. for (;;) {
  259. /* Determine which huffman coding group to use. */
  260. if (!(symCount--)) {
  261. symCount = GROUP_SIZE - 1;
  262. if (selector >= nSelectors) { _throw(Err.DATA_ERROR); }
  263. hufGroup = groups[selectors[selector++]];
  264. }
  265. /* Read next huffman-coded symbol. */
  266. i = hufGroup.minLen;
  267. j = reader.read(i);
  268. for (;;i++) {
  269. if (i > hufGroup.maxLen) { _throw(Err.DATA_ERROR); }
  270. if (j <= hufGroup.limit[i])
  271. break;
  272. j = (j << 1) | reader.read(1);
  273. }
  274. /* Huffman decode value to get nextSym (with bounds checking) */
  275. j -= hufGroup.base[i];
  276. if (j < 0 || j >= MAX_SYMBOLS) { _throw(Err.DATA_ERROR); }
  277. var nextSym = hufGroup.permute[j];
  278. /* We have now decoded the symbol, which indicates either a new literal
  279. byte, or a repeated run of the most recent literal byte. First,
  280. check if nextSym indicates a repeated run, and if so loop collecting
  281. how many times to repeat the last literal. */
  282. if (nextSym === SYMBOL_RUNA || nextSym === SYMBOL_RUNB) {
  283. /* If this is the start of a new run, zero out counter */
  284. if (!runPos){
  285. runPos = 1;
  286. t = 0;
  287. }
  288. /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
  289. each bit position, add 1 or 2 instead. For example,
  290. 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
  291. You can make any bit pattern that way using 1 less symbol than
  292. the basic or 0/1 method (except all bits 0, which would use no
  293. symbols, but a run of length 0 doesn't mean anything in this
  294. context). Thus space is saved. */
  295. if (nextSym === SYMBOL_RUNA)
  296. t += runPos;
  297. else
  298. t += 2 * runPos;
  299. runPos <<= 1;
  300. continue;
  301. }
  302. /* When we hit the first non-run symbol after a run, we now know
  303. how many times to repeat the last literal, so append that many
  304. copies to our buffer of decoded symbols (dbuf) now. (The last
  305. literal used is the one at the head of the mtfSymbol array.) */
  306. if (runPos){
  307. runPos = 0;
  308. if (dbufCount + t > this.dbufSize) { _throw(Err.DATA_ERROR); }
  309. uc = symToByte[mtfSymbol[0]];
  310. byteCount[uc] += t;
  311. while (t--)
  312. dbuf[dbufCount++] = uc;
  313. }
  314. /* Is this the terminating symbol? */
  315. if (nextSym > symTotal)
  316. break;
  317. /* At this point, nextSym indicates a new literal character. Subtract
  318. one to get the position in the MTF array at which this literal is
  319. currently to be found. (Note that the result can't be -1 or 0,
  320. because 0 and 1 are RUNA and RUNB. But another instance of the
  321. first symbol in the mtf array, position 0, would have been handled
  322. as part of a run above. Therefore 1 unused mtf position minus
  323. 2 non-literal nextSym values equals -1.) */
  324. if (dbufCount >= this.dbufSize) { _throw(Err.DATA_ERROR); }
  325. i = nextSym - 1;
  326. uc = mtf(mtfSymbol, i);
  327. uc = symToByte[uc];
  328. /* We have our literal byte. Save it into dbuf. */
  329. byteCount[uc]++;
  330. dbuf[dbufCount++] = uc;
  331. }
  332. /* At this point, we've read all the huffman-coded symbols (and repeated
  333. runs) for this block from the input stream, and decoded them into the
  334. intermediate buffer. There are dbufCount many decoded bytes in dbuf[].
  335. Now undo the Burrows-Wheeler transform on dbuf.
  336. See http://dogma.net/markn/articles/bwt/bwt.htm
  337. */
  338. if (origPointer < 0 || origPointer >= dbufCount) { _throw(Err.DATA_ERROR); }
  339. /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
  340. j = 0;
  341. for (i = 0; i < 256; i++) {
  342. k = j + byteCount[i];
  343. byteCount[i] = j;
  344. j = k;
  345. }
  346. /* Figure out what order dbuf would be in if we sorted it. */
  347. for (i = 0; i < dbufCount; i++) {
  348. uc = dbuf[i] & 0xff;
  349. dbuf[byteCount[uc]] |= (i << 8);
  350. byteCount[uc]++;
  351. }
  352. /* Decode first byte by hand to initialize "previous" byte. Note that it
  353. doesn't get output, and if the first three characters are identical
  354. it doesn't qualify as a run (hence writeRunCountdown=5). */
  355. var pos = 0, current = 0, run = 0;
  356. if (dbufCount) {
  357. pos = dbuf[origPointer];
  358. current = (pos & 0xff);
  359. pos >>= 8;
  360. run = -1;
  361. }
  362. this.writePos = pos;
  363. this.writeCurrent = current;
  364. this.writeCount = dbufCount;
  365. this.writeRun = run;
  366. return true; /* more blocks to come */
  367. };
  368. /* Undo burrows-wheeler transform on intermediate buffer to produce output.
  369. If start_bunzip was initialized with out_fd=-1, then up to len bytes of
  370. data are written to outbuf. Return value is number of bytes written or
  371. error (all errors are negative numbers). If out_fd!=-1, outbuf and len
  372. are ignored, data is written to out_fd and return is RETVAL_OK or error.
  373. */
  374. Bunzip.prototype._read_bunzip = function(outputBuffer, len) {
  375. var copies, previous, outbyte;
  376. /* james@jamestaylor.org: writeCount goes to -1 when the buffer is fully
  377. decoded, which results in this returning RETVAL_LAST_BLOCK, also
  378. equal to -1... Confusing, I'm returning 0 here to indicate no
  379. bytes written into the buffer */
  380. if (this.writeCount < 0) { return 0; }
  381. var gotcount = 0;
  382. var dbuf = this.dbuf, pos = this.writePos, current = this.writeCurrent;
  383. var dbufCount = this.writeCount, outputsize = this.outputsize;
  384. var run = this.writeRun;
  385. while (dbufCount) {
  386. dbufCount--;
  387. previous = current;
  388. pos = dbuf[pos];
  389. current = pos & 0xff;
  390. pos >>= 8;
  391. if (run++ === 3){
  392. copies = current;
  393. outbyte = previous;
  394. current = -1;
  395. } else {
  396. copies = 1;
  397. outbyte = current;
  398. }
  399. this.blockCRC.updateCRCRun(outbyte, copies);
  400. while (copies--) {
  401. this.outputStream.writeByte(outbyte);
  402. this.nextoutput++;
  403. }
  404. if (current != previous)
  405. run = 0;
  406. }
  407. this.writeCount = dbufCount;
  408. // check CRC
  409. if (this.blockCRC.getCRC() !== this.targetBlockCRC) {
  410. _throw(Err.DATA_ERROR, "Bad block CRC "+
  411. "(got "+this.blockCRC.getCRC().toString(16)+
  412. " expected "+this.targetBlockCRC.toString(16)+")");
  413. }
  414. return this.nextoutput;
  415. };
  416. var coerceInputStream = function(input) {
  417. if ('readByte' in input) { return input; }
  418. var inputStream = new Stream();
  419. inputStream.pos = 0;
  420. inputStream.readByte = function() { return input[this.pos++]; };
  421. inputStream.seek = function(pos) { this.pos = pos; };
  422. inputStream.eof = function() { return this.pos >= input.length; };
  423. return inputStream;
  424. };
  425. var coerceOutputStream = function(output) {
  426. var outputStream = new Stream();
  427. var resizeOk = true;
  428. if (output) {
  429. if (typeof(output)==='number') {
  430. outputStream.buffer = new Buffer(output);
  431. resizeOk = false;
  432. } else if ('writeByte' in output) {
  433. return output;
  434. } else {
  435. outputStream.buffer = output;
  436. resizeOk = false;
  437. }
  438. } else {
  439. outputStream.buffer = new Buffer(16384);
  440. }
  441. outputStream.pos = 0;
  442. outputStream.writeByte = function(_byte) {
  443. if (resizeOk && this.pos >= this.buffer.length) {
  444. var newBuffer = new Buffer(this.buffer.length*2);
  445. this.buffer.copy(newBuffer);
  446. this.buffer = newBuffer;
  447. }
  448. this.buffer[this.pos++] = _byte;
  449. };
  450. outputStream.getBuffer = function() {
  451. // trim buffer
  452. if (this.pos !== this.buffer.length) {
  453. if (!resizeOk)
  454. throw new TypeError('outputsize does not match decoded input');
  455. var newBuffer = new Buffer(this.pos);
  456. this.buffer.copy(newBuffer, 0, 0, this.pos);
  457. this.buffer = newBuffer;
  458. }
  459. return this.buffer;
  460. };
  461. outputStream._coerced = true;
  462. return outputStream;
  463. };
  464. /* Static helper functions */
  465. Bunzip.Err = Err;
  466. // 'input' can be a stream or a buffer
  467. // 'output' can be a stream or a buffer or a number (buffer size)
  468. Bunzip.decode = function(input, output, multistream) {
  469. // make a stream from a buffer, if necessary
  470. var inputStream = coerceInputStream(input);
  471. var outputStream = coerceOutputStream(output);
  472. var bz = new Bunzip(inputStream, outputStream);
  473. while (true) {
  474. if ('eof' in inputStream && inputStream.eof()) break;
  475. if (bz._init_block()) {
  476. bz._read_bunzip();
  477. } else {
  478. var targetStreamCRC = bz.reader.read(32) >>> 0; // (convert to unsigned)
  479. if (targetStreamCRC !== bz.streamCRC) {
  480. _throw(Err.DATA_ERROR, "Bad stream CRC "+
  481. "(got "+bz.streamCRC.toString(16)+
  482. " expected "+targetStreamCRC.toString(16)+")");
  483. }
  484. if (multistream &&
  485. 'eof' in inputStream &&
  486. !inputStream.eof()) {
  487. // note that start_bunzip will also resync the bit reader to next byte
  488. bz._start_bunzip(inputStream, outputStream);
  489. } else break;
  490. }
  491. }
  492. if ('getBuffer' in outputStream)
  493. return outputStream.getBuffer();
  494. };
  495. Bunzip.decodeBlock = function(input, pos, output) {
  496. // make a stream from a buffer, if necessary
  497. var inputStream = coerceInputStream(input);
  498. var outputStream = coerceOutputStream(output);
  499. var bz = new Bunzip(inputStream, outputStream);
  500. bz.reader.seek(pos);
  501. /* Fill the decode buffer for the block */
  502. var moreBlocks = bz._get_next_block();
  503. if (moreBlocks) {
  504. /* Init the CRC for writing */
  505. bz.blockCRC = new CRC32();
  506. /* Zero this so the current byte from before the seek is not written */
  507. bz.writeCopies = 0;
  508. /* Decompress the block and write to stdout */
  509. bz._read_bunzip();
  510. // XXX keep writing?
  511. }
  512. if ('getBuffer' in outputStream)
  513. return outputStream.getBuffer();
  514. };
  515. /* Reads bzip2 file from stream or buffer `input`, and invoke
  516. * `callback(position, size)` once for each bzip2 block,
  517. * where position gives the starting position (in *bits*)
  518. * and size gives uncompressed size of the block (in *bytes*). */
  519. Bunzip.table = function(input, callback, multistream) {
  520. // make a stream from a buffer, if necessary
  521. var inputStream = new Stream();
  522. inputStream.delegate = coerceInputStream(input);
  523. inputStream.pos = 0;
  524. inputStream.readByte = function() {
  525. this.pos++;
  526. return this.delegate.readByte();
  527. };
  528. if (inputStream.delegate.eof) {
  529. inputStream.eof = inputStream.delegate.eof.bind(inputStream.delegate);
  530. }
  531. var outputStream = new Stream();
  532. outputStream.pos = 0;
  533. outputStream.writeByte = function() { this.pos++; };
  534. var bz = new Bunzip(inputStream, outputStream);
  535. var blockSize = bz.dbufSize;
  536. while (true) {
  537. if ('eof' in inputStream && inputStream.eof()) break;
  538. var position = inputStream.pos*8 + bz.reader.bitOffset;
  539. if (bz.reader.hasByte) { position -= 8; }
  540. if (bz._init_block()) {
  541. var start = outputStream.pos;
  542. bz._read_bunzip();
  543. callback(position, outputStream.pos - start);
  544. } else {
  545. var crc = bz.reader.read(32); // (but we ignore the crc)
  546. if (multistream &&
  547. 'eof' in inputStream &&
  548. !inputStream.eof()) {
  549. // note that start_bunzip will also resync the bit reader to next byte
  550. bz._start_bunzip(inputStream, outputStream);
  551. console.assert(bz.dbufSize === blockSize,
  552. "shouldn't change block size within multistream file");
  553. } else break;
  554. }
  555. }
  556. };
  557. Bunzip.Stream = Stream;
  558. Bunzip.version = pjson.version;
  559. Bunzip.license = pjson.license;
  560. module.exports = Bunzip;