blob: 976aeb5fceb0aaa7798495bd4124a51e53956785 [file] [log] [blame]
part of archive;
/**
* Compress data using the BZip2 format.
* Derived from libbzip2 (http://www.bzip.org).
*/
class BZip2Encoder {
List<int> encode(List<int> data) {
input = new InputStream(data, byteOrder: BIG_ENDIAN);
OutputStream output = new OutputStream(byteOrder: BIG_ENDIAN);
bw = new Bz2BitWriter(output);
final int blockSize100k = 9;
bw.writeBytes(BZip2.BZH_SIGNATURE);
bw.writeByte(BZip2.HDR_0 + blockSize100k);
_nblockMax = 100000 * blockSize100k - 19;
_workFactor = 30;
int combinedCRC = 0;
int n = 100000 * blockSize100k;
_arr1 = new Uint32List(n);
_arr2 = new Uint32List(n + BZ_N_OVERSHOOT);
_ftab = new Uint32List(65537);
_block = new Uint8List.view(_arr2.buffer);
_mtfv = new Uint16List.view(_arr1.buffer);
_unseqToSeq = new Uint8List(256);
_blockNo = 0;
_origPtr = 0;
_selector = new Uint8List(BZ_MAX_SELECTORS);
_selectorMtf = new Uint8List(BZ_MAX_SELECTORS);
_len = new List<Uint8List>(BZ_N_GROUPS);
_code = new List<Int32List>(BZ_N_GROUPS);
_rfreq = new List<Int32List>(BZ_N_GROUPS);
for (int i = 0; i < BZ_N_GROUPS; ++i) {
_len[i] = new Uint8List(BZ_MAX_ALPHA_SIZE);
_code[i] = new Int32List(BZ_MAX_ALPHA_SIZE);
_rfreq[i] = new Int32List(BZ_MAX_ALPHA_SIZE);
}
_lenPack = new List<Uint32List>(BZ_MAX_ALPHA_SIZE);
for (int i = 0; i < BZ_MAX_ALPHA_SIZE; ++i) {
_lenPack[i] = new Uint32List(4);
}
// Write blocks
while (!input.isEOS) {
int blockCRC = _writeBlock();
combinedCRC = ((combinedCRC << 1) | (combinedCRC >> 31)) & 0xffffffff;
combinedCRC ^= blockCRC;
_blockNo++;
}
bw.writeBytes(BZip2.EOS_MAGIC);
bw.writeUint32(combinedCRC);
bw.flush();
return output.getBytes();
}
int _writeBlock() {
_inUse = new Uint8List(256);
_nblock = 0;
_blockCRC = BZip2.INITIAL_CRC;
// copy_input_until_stop
_state_in_ch = 256;
_state_in_len = 0;
while (_nblock < _nblockMax && !input.isEOS) {
_addCharToBlock(input.readByte());
}
if (_state_in_ch < 256) {
_addPairToBlock();
}
_state_in_ch = 256;
_state_in_len = 0;
_blockCRC = BZip2.finalizeCrc(_blockCRC);
_compressBlock();
return _blockCRC;
}
void _compressBlock() {
if (_nblock > 0) {
_blockSort();
}
if (_nblock > 0) {
bw.writeBytes(BZip2.COMPRESSED_MAGIC);
bw.writeUint32(_blockCRC);
bw.writeBits(1, 0); // set randomize to 'no'
bw.writeBits(24, _origPtr);
_generateMTFValues();
_sendMTFValues();
}
}
void _generateMTFValues() {
Uint8List yy = new Uint8List(256);
// After sorting (eg, here),
// s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
// and
// ((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
// holds the original block data.
//
// The first thing to do is generate the MTF values,
// and put them in
// ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
// Because there are strictly fewer or equal MTF values
// than block values, ptr values in this area are overwritten
// with MTF values only when they are no longer needed.
//
// The final compressed bitstream is generated into the
// area starting at
// (UChar*) (&((UChar*)s->arr2)[s->nblock])
_nInUse = 0;
for (int i = 0; i < 256; i++) {
if (_inUse[i] != 0) {
_unseqToSeq[i] = _nInUse;
_nInUse++;
}
}
final int EOB = _nInUse + 1;
_mtfFreq = new Int32List(BZ_MAX_ALPHA_SIZE);
int wr = 0;
int zPend = 0;
for (int i = 0; i < _nInUse; i++) {
yy[i] = i;
}
for (int i = 0; i < _nblock; i++) {
_assert(wr <= i);
int j = _arr1[i] - 1;
if (j < 0) {
j += _nblock;
}
int ll_i = _unseqToSeq[_block[j]];
_assert(ll_i < _nInUse);
if (yy[0] == ll_i) {
zPend++;
} else {
if (zPend > 0) {
zPend--;
while (true) {
if (zPend & 1 != 0) {
_mtfv[wr] = BZ_RUNB;
wr++;
_mtfFreq[BZ_RUNB]++;
} else {
_mtfv[wr] = BZ_RUNA;
wr++;
_mtfFreq[BZ_RUNA]++;
}
if (zPend < 2) {
break;
}
zPend = (zPend - 2) ~/ 2;
}
zPend = 0;
}
int rtmp = yy[1];
yy[1] = yy[0];
int ryy_j = 1;
int rll_i = ll_i;
while ( rll_i != rtmp ) {
ryy_j++;
int rtmp2 = rtmp;
rtmp = yy[ryy_j];
yy[ryy_j] = rtmp2;
}
yy[0] = rtmp;
j = ryy_j;
_mtfv[wr] = j + 1;
wr++;
_mtfFreq[j + 1]++;
}
}
if (zPend > 0) {
zPend--;
while (true) {
if (zPend & 1 != 0) {
_mtfv[wr] = BZ_RUNB;
wr++;
_mtfFreq[BZ_RUNB]++;
} else {
_mtfv[wr] = BZ_RUNA;
wr++;
_mtfFreq[BZ_RUNA]++;
}
if (zPend < 2) {
break;
}
zPend = (zPend - 2) ~/ 2;
}
zPend = 0;
}
_mtfv[wr] = EOB;
wr++;
_mtfFreq[EOB]++;
_nMTF = wr;
}
void _sendMTFValues() {
Uint16List cost = new Uint16List(BZ_N_GROUPS);
Int32List fave = new Int32List(BZ_N_GROUPS);
int nSelectors = 0;
int alphaSize = _nInUse + 2;
for (int t = 0; t < BZ_N_GROUPS; t++) {
for (int v = 0; v < alphaSize; v++) {
_len[t][v] = BZ_GREATER_ICOST;
}
}
// Decide how many coding tables to use
int nGroups;
_assert(_nMTF > 0);
if (_nMTF < 200) {
nGroups = 2;
} else if (_nMTF < 600) {
nGroups = 3;
} else if (_nMTF < 1200) {
nGroups = 4;
} else if (_nMTF < 2400) {
nGroups = 5;
} else {
nGroups = 6;
}
// Generate an initial set of coding tables
int nPart = nGroups;
int remF = _nMTF;
int gs = 0;
int ge = 0;
while (nPart > 0) {
int tFreq = remF ~/ nPart;
int aFreq = 0;
ge = gs - 1;
while (aFreq < tFreq && ge < alphaSize-1) {
ge++;
aFreq += _mtfFreq[ge];
}
if (ge > gs && nPart != nGroups && nPart != 1 &&
((nGroups - nPart) % 2 == 1)) {
aFreq -= _mtfFreq[ge];
ge--;
}
for (int v = 0; v < alphaSize; v++) {
if (v >= gs && v <= ge) {
_len[nPart - 1][v] = BZ_LESSER_ICOST;
} else {
_len[nPart - 1][v] = BZ_GREATER_ICOST;
}
}
nPart--;
gs = ge + 1;
remF -= aFreq;
}
// Iterate up to BZ_N_ITERS times to improve the tables.
for (int iter = 0; iter < BZ_N_ITERS; iter++) {
for (int t = 0; t < nGroups; t++) {
fave[t] = 0;
}
for (int t = 0; t < nGroups; t++) {
for (int v = 0; v < alphaSize; v++) {
_rfreq[t][v] = 0;
}
}
// Set up an auxiliary length table which is used to fast-track
// the common case (nGroups == 6).
if (nGroups == 6) {
for (int v = 0; v < alphaSize; v++) {
_lenPack[v][0] = (_len[1][v] << 16) | _len[0][v];
_lenPack[v][1] = (_len[3][v] << 16) | _len[2][v];
_lenPack[v][2] = (_len[5][v] << 16) | _len[4][v];
}
}
nSelectors = 0;
int totc = 0; // ignore: unused_local_variable
gs = 0;
while (true) {
// Set group start & end marks.
if (gs >= _nMTF) {
break;
}
int ge = gs + BZ_G_SIZE - 1;
if (ge >= _nMTF) {
ge = _nMTF - 1;
}
// Calculate the cost of this group as coded
// by each of the coding tables.
for (int t = 0; t < nGroups; t++) {
cost[t] = 0;
}
if (nGroups == 6 && 50 == ge - gs + 1) {
// fast track the common case
int cost01 = 0;
int cost23 = 0;
int cost45 = 0;
void BZ_ITER(int nn) {
int icv = _mtfv[gs + nn];
cost01 += _lenPack[icv][0];
cost23 += _lenPack[icv][1];
cost45 += _lenPack[icv][2];
}
BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
cost[0] = cost01 & 0xffff;
cost[1] = cost01 >> 16;
cost[2] = cost23 & 0xffff;
cost[3] = cost23 >> 16;
cost[4] = cost45 & 0xffff;
cost[5] = cost45 >> 16;
} else {
// slow version which correctly handles all situations
for (int i = gs; i <= ge; i++) {
int icv = _mtfv[i];
for (int t = 0; t < nGroups; t++) {
cost[t] += _len[t][icv];
}
}
}
// Find the coding table which is best for this group,
// and record its identity in the selector table.
int bc = 999999999;
int bt = -1;
for (int t = 0; t < nGroups; t++) {
if (cost[t] < bc) {
bc = cost[t];
bt = t;
}
}
totc += bc;
fave[bt]++;
_selector[nSelectors] = bt;
nSelectors++;
// Increment the symbol frequencies for the selected table.
if (nGroups == 6 && 50 == ge - gs + 1) {
// fast track the common case
void BZ_ITUR(int nn) {
_rfreq[bt][_mtfv[gs + nn]]++;
}
BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
} else {
// slow version which correctly handles all situations
for (int i = gs; i <= ge; i++) {
_rfreq[bt][_mtfv[i]]++;
}
}
gs = ge + 1;
}
// Recompute the tables based on the accumulated frequencies.
for (int t = 0; t < nGroups; t++) {
_hbMakeCodeLengths(_len[t], _rfreq[t], alphaSize, 17);
}
}
_assert(nGroups < 8);
_assert(nSelectors < 32768 && nSelectors <= (2 + (900000 ~/ BZ_G_SIZE)));
// Compute MTF values for the selectors.
Uint8List pos = new Uint8List(BZ_N_GROUPS);
for (int i = 0; i < nGroups; i++) {
pos[i] = i;
}
for (int i = 0; i < nSelectors; i++) {
int ll_i = _selector[i];
int j = 0;
int tmp = pos[j];
while (ll_i != tmp) {
j++;
int tmp2 = tmp;
tmp = pos[j];
pos[j] = tmp2;
}
pos[0] = tmp;
_selectorMtf[i] = j;
}
// Assign actual codes for the tables.
for (int t = 0; t < nGroups; t++) {
int minLen = 32;
int maxLen = 0;
for (int i = 0; i < alphaSize; i++) {
if (_len[t][i] > maxLen) {
maxLen = _len[t][i];
}
if (_len[t][i] < minLen) {
minLen = _len[t][i];
}
}
_assert(!(maxLen > 17));
_assert(!(minLen < 1));
_hbAssignCodes(_code[t], _len[t], minLen, maxLen, alphaSize );
}
// Transmit the mapping table.
Uint8List inUse16 = new Uint8List(16);
for (int i = 0; i < 16; i++) {
inUse16[i] = 0;
for (int j = 0; j < 16; j++) {
if (_inUse[i * 16 + j] != 0) {
inUse16[i] = 1;
}
}
}
for (int i = 0; i < 16; i++) {
if (inUse16[i] != 0) {
bw.writeBits(1, 1);
} else {
bw.writeBits(1, 0);
}
}
for (int i = 0; i < 16; i++) {
if (inUse16[i] != 0) {
for (int j = 0; j < 16; j++) {
if (_inUse[i * 16 + j] != 0) {
bw.writeBits(1, 1);
} else {
bw.writeBits(1, 0);
}
}
}
}
// Now the selectors.
bw.writeBits(3, nGroups);
bw.writeBits(15, nSelectors);
for (int i = 0; i < nSelectors; i++) {
for (int j = 0; j < _selectorMtf[i]; j++) {
bw.writeBits(1, 1);
}
bw.writeBits(1, 0);
}
// Now the coding tables.
for (int t = 0; t < nGroups; t++) {
int curr = _len[t][0];
bw.writeBits(5, curr);
for (int i = 0; i < alphaSize; i++) {
while (curr < _len[t][i]) {
bw.writeBits(2, 2);
curr++; // 10
}
while (curr > _len[t][i]) {
bw.writeBits(2, 3);
curr--; // 11
}
bw.writeBits(1, 0);
}
}
// And finally, the block data proper
int selCtr = 0;
gs = 0;
while (true) {
if (gs >= _nMTF) {
break;
}
int ge = gs + BZ_G_SIZE - 1;
if (ge >= _nMTF) {
ge = _nMTF - 1;
}
_assert(_selector[selCtr] < nGroups);
if (nGroups == 6 && 50 == ge - gs + 1) {
// fast track the common case
int mtfv_i;
Uint8List s_len_sel_selCtr = _len[_selector[selCtr]];
Int32List s_code_sel_selCtr = _code[_selector[selCtr]];
void BZ_ITAH(int nn) {
mtfv_i = _mtfv[gs + nn];
bw.writeBits(s_len_sel_selCtr[mtfv_i], s_code_sel_selCtr[mtfv_i]);
}
BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
} else {
// slow version which correctly handles all situations
for (int i = gs; i <= ge; i++) {
bw.writeBits(_len[_selector[selCtr]][_mtfv[i]],
_code[_selector[selCtr]][_mtfv[i]]);
}
}
gs = ge + 1;
selCtr++;
}
_assert(selCtr == nSelectors);
}
void _hbMakeCodeLengths(Uint8List len, Int32List freq,
int alphaSize, int maxLen) {
// Nodes and heap entries run from 1. Entry 0
// for both the heap and nodes is a sentinel.
Int32List heap = new Int32List(BZ_MAX_ALPHA_SIZE + 2);
Int32List weight = new Int32List(BZ_MAX_ALPHA_SIZE * 2);
Int32List parent = new Int32List(BZ_MAX_ALPHA_SIZE * 2);
int nHeap;
int nNodes;
for (int i = 0; i < alphaSize; i++) {
weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
}
void UPHEAP(int z) {
int zz = z;
int tmp = heap[zz];
while (weight[tmp] < weight[heap[zz >> 1]]) {
heap[zz] = heap[zz >> 1];
zz >>= 1;
}
heap[zz] = tmp;
}
void DOWNHEAP(int z) {
int zz = z;
int tmp = heap[zz];
while (true) {
int yy = zz << 1;
if (yy > nHeap) {
break;
}
if (yy < nHeap && weight[heap[yy+1]] < weight[heap[yy]]) {
yy++;
}
if (weight[tmp] < weight[heap[yy]]) {
break;
}
heap[zz] = heap[yy];
zz = yy;
}
heap[zz] = tmp;
}
int WEIGHTOF(int zz0) => ((zz0) & 0xffffff00);
int DEPTHOF(int zz1) => ((zz1) & 0x000000ff);
int MYMAX(int zz2, int zz3) => ((zz2) > (zz3) ? (zz2) : (zz3));
int ADDWEIGHTS(int zw1, int zw2) =>
(WEIGHTOF(zw1) + WEIGHTOF(zw2)) |
(1 + MYMAX(DEPTHOF(zw1), DEPTHOF(zw2)));
while (true) {
nNodes = alphaSize;
nHeap = 0;
heap[0] = 0;
weight[0] = 0;
parent[0] = -2;
for (int i = 1; i <= alphaSize; i++) {
parent[i] = -1;
nHeap++;
heap[nHeap] = i;
UPHEAP(nHeap);
}
_assert(nHeap < (BZ_MAX_ALPHA_SIZE + 2));
while (nHeap > 1) {
int n1 = heap[1];
heap[1] = heap[nHeap];
nHeap--;
DOWNHEAP(1);
int n2 = heap[1];
heap[1] = heap[nHeap];
nHeap--;
DOWNHEAP(1);
nNodes++;
parent[n1] = parent[n2] = nNodes;
weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
parent[nNodes] = -1;
nHeap++;
heap[nHeap] = nNodes;
UPHEAP(nHeap);
}
_assert(nNodes < (BZ_MAX_ALPHA_SIZE * 2));
bool tooLong = false;
for (int i = 1; i <= alphaSize; i++) {
int j = 0;
int k = i;
while (parent[k] >= 0) {
k = parent[k];
j++;
}
len[i - 1] = j;
if (j > maxLen) {
tooLong = true;
}
}
if (!tooLong) {
break;
}
for (int i = 1; i <= alphaSize; i++) {
int j = weight[i] >> 8;
j = 1 + (j ~/ 2);
weight[i] = j << 8;
}
}
}
void _hbAssignCodes(Int32List codes, Uint8List length,
int minLen, int maxLen, int alphaSize) {
int vec = 0;
for (int n = minLen; n <= maxLen; n++) {
for (int i = 0; i < alphaSize; i++) {
if (length[i] == n) {
codes[i] = vec;
vec++;
}
}
vec <<= 1;
}
}
void _blockSort() {
if (_nblock < 10000) {
_fallbackSort(_arr1, _arr2, _ftab, _nblock);
} else {
// Calculate the location for quadrant, remembering to get
// the alignment right. Assumes that &(block[0]) is at least
// 2-byte aligned -- this should be ok since block is really
// the first section of arr2.
int i = _nblock + BZ_N_OVERSHOOT;
if (i & 1 != 0) {
i++;
}
Uint16List quadrant = new Uint16List.view(_block.buffer, i);
int wfact = _workFactor;
// (wfact-1) / 3 puts the default-factor-30
// transition point at very roughly the same place as
// with v0.1 and v0.9.0.
// Not that it particularly matters any more, since the
// resulting compressed stream is now the same regardless
// of whether or not we use the main sort or fallback sort.
if (wfact < 1) {
wfact = 1;
}
if (wfact > 100) {
wfact = 100;
}
int budgetInit = _nblock * ((wfact - 1) ~/ 3);
_budget = budgetInit;
_mainSort(_arr1, _block, quadrant, _ftab, _nblock);
if (_budget < 0) {
_fallbackSort(_arr1, _arr2, _ftab, _nblock);
}
}
_origPtr = -1;
for (int i = 0; i < _nblock; i++) {
if (_arr1[i] == 0) {
_origPtr = i;
break;
}
}
_assert(_origPtr != -1);
}
void _assert(bool cond) {
if (!cond) {
throw new ArchiveException('Data error');
}
}
void _fallbackSort(Uint32List fmap, Uint32List eclass,
Uint32List bhtab, int nblock) {
Int32List ftab = new Int32List(257);
Int32List ftabCopy = new Int32List(256);
Uint8List eclass8 = new Uint8List.view(eclass.buffer);
int SET_BH(int zz) => bhtab[zz >> 5] |= (1 << (zz & 31));
int CLEAR_BH(int zz) => bhtab[zz >> 5] &= ~(1 << (zz & 31));
bool ISSET_BH(int zz) => (bhtab[zz >> 5] & (1 << (zz & 31)) != 0);
int WORD_BH(int zz) => bhtab[(zz) >> 5];
bool UNALIGNED_BH(int zz) => ((zz) & 0x01f) != 0;
// Initial 1-char radix sort to generate
// initial fmap and initial BH bits.
for (int i = 0; i < 257; i++) {
ftab[i] = 0;
}
for (int i = 0; i < nblock; i++) {
ftab[eclass8[i]]++;
}
for (int i = 0; i < 256; i++) {
ftabCopy[i] = ftab[i];
}
for (int i = 1; i < 257; i++) {
ftab[i] += ftab[i - 1];
}
for (int i = 0; i < nblock; i++) {
int j = eclass8[i];
int k = ftab[j] - 1;
ftab[j] = k;
fmap[k] = i;
}
int nBhtab = 2 + (nblock ~/ 32);
for (int i = 0; i < nBhtab; i++) {
bhtab[i] = 0;
}
for (int i = 0; i < 256; i++) {
SET_BH(ftab[i]);
}
// Inductively refine the buckets. Kind-of an
// "exponential radix sort" (!), inspired by the
// Manber-Myers suffix array construction algorithm.
// set sentinel bits for block-end detection
for (int i = 0; i < 32; i++) {
SET_BH(nblock + 2*i);
CLEAR_BH(nblock + 2*i + 1);
}
// the log(N) loop
int H = 1;
while (true) {
int j = 0;
for (int i = 0; i < nblock; i++) {
if (ISSET_BH(i)) {
j = i;
}
int k = fmap[i] - H;
if (k < 0) {
k += nblock;
}
eclass[k] = j;
}
int nNotDone = 0;
int r = -1;
while (true) {
// find the next non-singleton bucket
int k = r + 1;
while (ISSET_BH(k) && UNALIGNED_BH(k)) {
k++;
}
if (ISSET_BH(k)) {
while (WORD_BH(k) == 0xffffffff) {
k += 32;
}
while (ISSET_BH(k)) {
k++;
}
}
int l = k - 1;
if (l >= nblock) {
break;
}
while (!ISSET_BH(k) && UNALIGNED_BH(k)) {
k++;
}
if (!ISSET_BH(k)) {
while (WORD_BH(k) == 0x00000000) {
k += 32;
}
while (!ISSET_BH(k)) {
k++;
}
}
r = k - 1;
if (r >= nblock) {
break;
}
// now [l, r] bracket current bucket
if (r > l) {
nNotDone += (r - l + 1);
_fallbackQSort3(fmap, eclass, l, r);
// scan bucket and generate header bits
int cc = -1;
for (int i = l; i <= r; i++) {
int cc1 = eclass[fmap[i]];
if (cc != cc1) {
SET_BH(i);
cc = cc1;
}
}
}
}
H *= 2;
if (H > nblock || nNotDone == 0) {
break;
}
}
// Reconstruct the original block in
// eclass8 [0 .. nblock-1], since the
// previous phase destroyed it.
int j = 0;
for (int i = 0; i < nblock; i++) {
while (ftabCopy[j] == 0) {
j++;
}
ftabCopy[j]--;
eclass8[fmap[i]] = j;
}
_assert(j < 256);
}
void _fallbackQSort3(Uint32List fmap, Uint32List eclass,
int loSt, int hiSt) {
const int FALLBACK_QSORT_SMALL_THRESH = 10;
const int FALLBACK_QSORT_STACK_SIZE = 100;
Int32List stackLo = new Int32List(FALLBACK_QSORT_STACK_SIZE);
Int32List stackHi = new Int32List(FALLBACK_QSORT_STACK_SIZE);
int sp = 0;
void fpush(int lz, int hz) {
stackLo[sp] = lz;
stackHi[sp] = hz;
sp++;
}
int fmin(int a, int b) => ((a) < (b)) ? (a) : (b);
void fvswap(yyp1, yyp2, yyn) {
while (yyn > 0) {
int t = fmap[yyp1];
fmap[yyp1] = fmap[yyp2];
fmap[yyp2] = t;
yyp1++;
yyp2++;
yyn--;
}
}
int r = 0;
fpush(loSt, hiSt);
while (sp > 0) {
_assert(sp < FALLBACK_QSORT_STACK_SIZE - 1);
sp--;
int lo = stackLo[sp];
int hi = stackHi[sp];
if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
_fallbackSimpleSort(fmap, eclass, lo, hi);
continue;
}
// Random partitioning. Median of 3 sometimes fails to
// avoid bad cases. Median of 9 seems to help but
// looks rather expensive. This too seems to work but
// is cheaper. Guidance for the magic constants
// 7621 and 32768 is taken from Sedgewick's algorithms
// book, chapter 35.
r = ((r * 7621) + 1) % 32768;
int r3 = r % 3;
int med;
if (r3 == 0) {
med = eclass[fmap[lo]];
} else if (r3 == 1) {
med = eclass[fmap[(lo+hi)>>1]];
} else {
med = eclass[fmap[hi]];
}
int unLo = lo;
int ltLo = lo;
int unHi = hi;
int gtHi = hi;
while (true) {
while (true) {
if (unLo > unHi) {
break;
}
int n = eclass[fmap[unLo]] - med;
if (n == 0) {
int t = fmap[unLo];
fmap[unLo] = fmap[ltLo];
fmap[ltLo] = t;
ltLo++;
unLo++;
continue;
}
if (n > 0) {
break;
}
unLo++;
}
while (true) {
if (unLo > unHi) {
break;
}
int n = eclass[fmap[unHi]] - med;
if (n == 0) {
int t = fmap[unHi];
fmap[unHi] = fmap[gtHi];
fmap[gtHi] = t;
gtHi--;
unHi--;
continue;
}
if (n < 0) {
break;
}
unHi--;
}
if (unLo > unHi) {
break;
}
int t = fmap[unLo];
fmap[unLo] = fmap[unHi];
fmap[unHi] = t;
unLo++;
unHi--;
}
_assert(unHi == unLo - 1);
if (gtHi < ltLo) {
continue;
}
int n = fmin(ltLo - lo, unLo - ltLo);
fvswap(lo, unLo - n, n);
int m = fmin(hi - gtHi, gtHi - unHi);
fvswap(unLo, hi - m + 1, m);
n = lo + unLo - ltLo - 1;
m = hi - (gtHi - unHi) + 1;
if (n - lo > hi - m) {
fpush(lo, n);
fpush(m, hi);
} else {
fpush(m, hi);
fpush(lo, n);
}
}
}
void _fallbackSimpleSort(Uint32List fmap, Uint32List eclass,
int lo, int hi) {
if (lo == hi) {
return;
}
if (hi - lo > 3) {
for (int i = hi - 4; i >= lo; i--) {
int tmp = fmap[i];
int ec_tmp = eclass[tmp];
int j;
for (j = i + 4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4) {
fmap[j - 4] = fmap[j];
}
fmap[j - 4] = tmp;
}
}
for (int i = hi - 1; i >= lo; i--) {
int tmp = fmap[i];
int ec_tmp = eclass[tmp];
int j;
for (j = i + 1; j <= hi && ec_tmp > eclass[fmap[j]]; j++) {
fmap[j - 1] = fmap[j];
}
fmap[j - 1] = tmp;
}
}
void _mainSort(Uint32List ptr, Uint8List block,
Uint16List quadrant, Uint32List ftab,
int nblock) {
Int32List runningOrder = new Int32List(256);
Uint8List bigDone = new Uint8List(256);
Int32List copyStart = new Int32List(256);
Int32List copyEnd = new Int32List(256);
int BIGFREQ(int b) =>
(_ftab[((b) + 1) << 8] - _ftab[(b) << 8]);
const int SETMASK = 2097152;
const int CLEARMASK = 4292870143;
// set up the 2-byte frequency table
for (int i = 65536; i >= 0; i--) {
ftab[i] = 0;
}
int j = block[0] << 8;
int i = nblock - 1;
for (; i >= 3; i -= 4) {
quadrant[i] = 0;
j = (j >> 8) | ((block[i]) << 8);
ftab[j]++;
quadrant[i - 1] = 0;
j = (j >> 8) | ((block[i - 1]) << 8);
ftab[j]++;
quadrant[i - 2] = 0;
j = (j >> 8) | ((block[i - 2]) << 8);
ftab[j]++;
quadrant[i - 3] = 0;
j = (j >> 8) | ((block[i - 3]) << 8);
ftab[j]++;
}
for (; i >= 0; i--) {
quadrant[i] = 0;
j = (j >> 8) | ((block[i]) << 8);
ftab[j]++;
}
// (emphasises close relationship of block & quadrant)
for (i = 0; i < BZ_N_OVERSHOOT; i++) {
block[nblock + i] = block[i];
quadrant[nblock + i] = 0;
}
// Complete the initial radix sort
for (i = 1; i <= 65536; i++) {
ftab[i] += ftab[i - 1];
}
int s = block[0] << 8;
i = nblock - 1;
for (; i >= 3; i -= 4) {
s = (s >> 8) | (block[i] << 8);
j = ftab[s] -1;
ftab[s] = j;
ptr[j] = i;
s = (s >> 8) | (block[i - 1] << 8);
j = ftab[s] -1;
ftab[s] = j;
ptr[j] = i-1;
s = (s >> 8) | (block[i - 2] << 8);
j = ftab[s] -1;
ftab[s] = j;
ptr[j] = i-2;
s = (s >> 8) | (block[i - 3] << 8);
j = ftab[s] -1;
ftab[s] = j;
ptr[j] = i-3;
}
for (; i >= 0; i--) {
s = (s >> 8) | (block[i] << 8);
j = ftab[s] -1;
ftab[s] = j;
ptr[j] = i;
}
// Now ftab contains the first loc of every small bucket.
// Calculate the running order, from smallest to largest
// big bucket.
for (i = 0; i <= 255; i++) {
bigDone[i] = 0;
runningOrder[i] = i;
}
int h = 1;
do {
h = 3 * h + 1;
} while (h <= 256);
do {
h = h ~/ 3;
for (i = h; i <= 255; i++) {
int vv = runningOrder[i];
j = i;
while (BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv)) {
runningOrder[j] = runningOrder[j-h];
j = j - h;
if (j <= (h - 1)) {
break;
}
}
runningOrder[j] = vv;
}
} while (h != 1);
// The main sorting loop.
int numQSorted = 0; // ignore: unused_local_variable
for (i = 0; i <= 255; i++) {
// Process big buckets, starting with the least full.
// Basically this is a 3-step process in which we call
// mainQSort3 to sort the small buckets [ss, j], but
// also make a big effort to avoid the calls if we can.
int ss = runningOrder[i];
// Step 1:
// Complete the big bucket [ss] by quicksorting
// any unsorted small buckets [ss, j], for j != ss.
// Hopefully previous pointer-scanning phases have already
// completed many of the small buckets [ss, j], so
// we don't have to sort them at all.
for (j = 0; j <= 255; j++) {
if (j != ss) {
int sb = (ss << 8) + j;
if ((_ftab[sb] & SETMASK) == 0) {
int lo = _ftab[sb] & CLEARMASK;
int hi = (_ftab[sb + 1] & CLEARMASK) - 1;
if (hi > lo) {
_mainQSort3(ptr, block, quadrant, nblock,
lo, hi, BZ_N_RADIX);
numQSorted += (hi - lo + 1);
if (_budget < 0) {
return;
}
}
}
_ftab[sb] |= SETMASK;
}
}
_assert(bigDone[ss] == 0);
// Step 2:
// Now scan this big bucket [ss] so as to synthesise the
// sorted order for small buckets [t, ss] for all t,
// including, magically, the bucket [ss,ss] too.
// This will avoid doing Real Work in subsequent Step 1's.
for (j = 0; j <= 255; j++) {
copyStart[j] = _ftab[(j << 8) + ss] & CLEARMASK;
copyEnd[j] = (_ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
}
for (j = _ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
int k = ptr[j]-1; if (k < 0) k += nblock;
int c1 = block[k];
if (bigDone[c1] == 0) {
ptr[ copyStart[c1]++ ] = k;
}
}
for (j = (_ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
int k = ptr[j] - 1;
if (k < 0) {
k += nblock;
}
int c1 = block[k];
if (bigDone[c1] == 0) {
ptr[copyEnd[c1]--] = k;
}
}
_assert((copyStart[ss] - 1 == copyEnd[ss]) ||
// Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
// Necessity for this case is demonstrated by compressing
// a sequence of approximately 48.5 million of character
// 251; 1.0.0/1.0.1 will then die here.
(copyStart[ss] == 0 && copyEnd[ss] == nblock - 1));
for (j = 0; j <= 255; j++) {
_ftab[(j << 8) + ss] |= SETMASK;
}
// Step 3:
// The [ss] big bucket is now done. Record this fact,
// and update the quadrant descriptors. Remember to
// update quadrants in the overshoot area too, if
// necessary. The "if (i < 255)" test merely skips
// this updating for the last bucket processed, since
// updating for the last bucket is pointless.
//
// The quadrant array provides a way to incrementally
// cache sort orderings, as they appear, so as to
// make subsequent comparisons in fullGtU() complete
// faster. For repetitive blocks this makes a big
// difference (but not big enough to be able to avoid
// the fallback sorting mechanism, exponential radix sort).
//
// The precise meaning is: at all times:
//
// for 0 <= i < nblock and 0 <= j <= nblock
//
// if block[i] != block[j],
//
// then the relative values of quadrant[i] and
// quadrant[j] are meaningless.
//
// else {
// if quadrant[i] < quadrant[j]
// then the string starting at i lexicographically
// precedes the string starting at j
//
// else if quadrant[i] > quadrant[j]
// then the string starting at j lexicographically
// precedes the string starting at i
//
// else
// the relative ordering of the strings starting
// at i and j has not yet been determined.
// }
bigDone[ss] = 1;
if (i < 255) {
int bbStart = _ftab[ss << 8] & CLEARMASK;
int bbSize = (_ftab[(ss + 1) << 8] & CLEARMASK) - bbStart;
int shifts = 0;
while ((bbSize >> shifts) > 65534) {
shifts++;
}
for (j = bbSize - 1; j >= 0; j--) {
int a2update = ptr[bbStart + j];
int qVal = (j >> shifts) & 0xffff;
quadrant[a2update] = qVal;
if (a2update < BZ_N_OVERSHOOT)
quadrant[a2update + nblock] = qVal;
}
_assert(((bbSize - 1) >> shifts) <= 65535);
}
}
}
void _mainQSort3(Uint32List ptr, Uint8List block,
Uint16List quadrant, int nblock,
int loSt, int hiSt, int dSt) {
const MAIN_QSORT_STACK_SIZE = 100;
const MAIN_QSORT_SMALL_THRESH = 20;
const MAIN_QSORT_DEPTH_THRESH = (BZ_N_RADIX + BZ_N_QSORT);
Int32List stackLo = new Int32List(MAIN_QSORT_STACK_SIZE);
Int32List stackHi = new Int32List(MAIN_QSORT_STACK_SIZE);
Int32List stackD = new Int32List(MAIN_QSORT_STACK_SIZE);
Int32List nextLo = new Int32List(3);
Int32List nextHi = new Int32List(3);
Int32List nextD = new Int32List(3);
int sp = 0;
void mpush(int lz, int hz, int dz) {
stackLo[sp] = lz;
stackHi[sp] = hz;
stackD[sp] = dz;
sp++;
}
int mmed3(int a, int b, int c) {
if (a > b) {
int t = a;
a = b;
b = t;
}
if (b > c) {
b = c;
if (a > b) {
b = a;
}
}
return b;
}
void mvswap(int yyp1, int yyp2, int yyn) {
while (yyn > 0) {
int t = ptr[yyp1];
ptr[yyp1] = ptr[yyp2];
ptr[yyp2] = t;
yyp1++;
yyp2++;
yyn--;
}
}
int mmin(int a, int b) => ((a) < (b)) ? (a) : (b);
int mnextsize(int az) => (nextHi[az] - nextLo[az]);
void mnextswap(int az, int bz) {
int tz = nextLo[az];
nextLo[az] = nextLo[bz];
nextLo[bz] = tz;
tz = nextHi[az];
nextHi[az] = nextHi[bz];
nextHi[bz] = tz;
tz = nextD[az];
nextD[az] = nextD[bz];
nextD[bz] = tz;
}
mpush(loSt, hiSt, dSt);
while (sp > 0) {
_assert(sp < MAIN_QSORT_STACK_SIZE - 2);
sp--;
int lo = stackLo[sp];
int hi = stackHi[sp];
int d = stackD[sp];
if (hi - lo < MAIN_QSORT_SMALL_THRESH || d > MAIN_QSORT_DEPTH_THRESH) {
_mainSimpleSort(ptr, block, quadrant, nblock, lo, hi, d);
if (_budget < 0) {
return;
}
continue;
}
int med = mmed3(block[ptr[lo] + d],
block[ptr[hi] + d],
block[ptr[(lo + hi) >> 1] + d]);
int unLo = lo;
int ltLo = lo;
int unHi = hi;
int gtHi = hi;
while (true) {
while (true) {
if (unLo > unHi) {
break;
}
int n = (block[ptr[unLo] + d]) - med;
if (n == 0) {
int t = ptr[unLo];
ptr[unLo] = ptr[ltLo];
ptr[ltLo] = t;
ltLo++;
unLo++;
continue;
}
if (n > 0) {
break;
}
unLo++;
}
while (true) {
if (unLo > unHi) {
break;
}
int n = (block[ptr[unHi] + d]) - med;
if (n == 0) {
int t = ptr[unHi];
ptr[unHi] = ptr[gtHi];
ptr[gtHi] = t;
gtHi--;
unHi--;
continue;
}
if (n < 0) {
break;
}
unHi--;
}
if (unLo > unHi) {
break;
}
int t = ptr[unLo];
ptr[unLo] = ptr[unHi];
ptr[unHi] = t;
unLo++;
unHi--;
}
_assert(unHi == unLo - 1);
if (gtHi < ltLo) {
mpush(lo, hi, d+1 );
continue;
}
int n = mmin(ltLo - lo, unLo - ltLo);
mvswap(lo, unLo - n, n);
int m = mmin(hi - gtHi, gtHi - unHi);
mvswap(unLo, hi - m + 1, m);
n = lo + unLo - ltLo - 1;
m = hi - (gtHi - unHi) + 1;
nextLo[0] = lo;
nextHi[0] = n;
nextD[0] = d;
nextLo[1] = m;
nextHi[1] = hi;
nextD[1] = d;
nextLo[2] = n + 1;
nextHi[2] = m - 1;
nextD[2] = d + 1;
if (mnextsize(0) < mnextsize(1)) {
mnextswap(0, 1);
}
if (mnextsize(1) < mnextsize(2)) {
mnextswap(1, 2);
}
if (mnextsize(0) < mnextsize(1)) {
mnextswap(0, 1);
}
_assert(mnextsize(0) >= mnextsize(1));
_assert(mnextsize(1) >= mnextsize(2));
mpush(nextLo[0], nextHi[0], nextD[0]);
mpush(nextLo[1], nextHi[1], nextD[1]);
mpush(nextLo[2], nextHi[2], nextD[2]);
}
}
void _mainSimpleSort(Uint32List ptr, Uint8List block,
Uint16List quadrant,
int nblock, int lo, int hi, int d) {
int bigN = hi - lo + 1;
if (bigN < 2) {
return;
}
const List<int> incs = const [
1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720,
797161, 2391484];
int hp = 0;
while (incs[hp] < bigN) {
hp++;
}
hp--;
for (; hp >= 0; hp--) {
int h = incs[hp];
int i = lo + h;
while (true) {
// copy 1
if (i > hi) {
break;
}
int v = ptr[i];
int j = i;
while (_mainGtU(ptr[j - h] + d, v + d, block, quadrant, nblock)) {
ptr[j] = ptr[j - h];
j = j - h;
if (j <= (lo + h - 1)) {
break;
}
}
ptr[j] = v;
i++;
// copy 2
if (i > hi) {
break;
}
v = ptr[i];
j = i;
while (_mainGtU(ptr[j - h] + d, v + d, block, quadrant, nblock)) {
ptr[j] = ptr[j - h];
j = j - h;
if (j <= (lo + h - 1)) {
break;
}
}
ptr[j] = v;
i++;
// copy 3
if (i > hi) {
break;
}
v = ptr[i];
j = i;
while (_mainGtU(ptr[j - h] + d, v + d, block, quadrant, nblock)) {
ptr[j] = ptr[j - h];
j = j - h;
if (j <= (lo + h - 1)) {
break;
}
}
ptr[j] = v;
i++;
if (_budget < 0) {
return;
}
}
}
}
bool _mainGtU(int i1, int i2, Uint8List block,
Uint16List quadrant, int nblock) {
_assert(i1 != i2);
// 1
int c1 = block[i1];
int c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 2
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 3
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 4
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 5
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 6
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 7
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 8
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 9
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 10
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 11
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
// 12
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
i1++;
i2++;
int k = nblock + 8;
do {
// 1
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
int s1 = quadrant[i1];
int s2 = quadrant[i2];
if (s1 != s2) {
return (s1 > s2);
}
i1++;
i2++;
// 2
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
s1 = quadrant[i1];
s2 = quadrant[i2];
if (s1 != s2) {
return (s1 > s2);
}
i1++;
i2++;
// 3
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
s1 = quadrant[i1];
s2 = quadrant[i2];
if (s1 != s2) {
return (s1 > s2);
}
i1++;
i2++;
// 4
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
s1 = quadrant[i1];
s2 = quadrant[i2];
if (s1 != s2) {
return (s1 > s2);
}
i1++;
i2++;
// 5
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
s1 = quadrant[i1];
s2 = quadrant[i2];
if (s1 != s2) {
return (s1 > s2);
}
i1++;
i2++;
// 6
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
s1 = quadrant[i1];
s2 = quadrant[i2];
if (s1 != s2) {
return (s1 > s2);
}
i1++;
i2++;
// 7
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
s1 = quadrant[i1];
s2 = quadrant[i2];
if (s1 != s2) {
return (s1 > s2);
}
i1++;
i2++;
// 8
c1 = block[i1];
c2 = block[i2];
if (c1 != c2) {
return (c1 > c2);
}
s1 = quadrant[i1];
s2 = quadrant[i2];
if (s1 != s2) {
return (s1 > s2);
}
i1++;
i2++;
if (i1 >= nblock) {
i1 -= nblock;
}
if (i2 >= nblock) {
i2 -= nblock;
}
k -= 8;
_budget--;
} while (k >= 0);
return false;
}
void _addCharToBlock(int b) {
if (b != _state_in_ch && _state_in_len == 1) {
_blockCRC = BZip2.updateCrc(_state_in_ch, _blockCRC);
_inUse[_state_in_ch] = 1;
_block[_nblock] = _state_in_ch;
_nblock++;
_state_in_ch = b;
} else {
if (b != _state_in_ch || _state_in_len == 255) {
if (_state_in_ch < 256) {
_addPairToBlock();
}
_state_in_ch = b;
_state_in_len = 1;
} else {
_state_in_len++;
}
}
}
void _addPairToBlock() {
for (int i = 0; i < _state_in_len; i++) {
_blockCRC = BZip2.updateCrc(_state_in_ch, _blockCRC);
}
_inUse[_state_in_ch] = 1;
switch (_state_in_len) {
case 1:
_block[_nblock] = _state_in_ch;
_nblock++;
break;
case 2:
_block[_nblock] = _state_in_ch;
_nblock++;
_block[_nblock] = _state_in_ch;
_nblock++;
break;
case 3:
_block[_nblock] = _state_in_ch;
_nblock++;
_block[_nblock] = _state_in_ch;
_nblock++;
_block[_nblock] = _state_in_ch;
_nblock++;
break;
default:
_inUse[_state_in_len - 4] = 1;
_block[_nblock] = _state_in_ch;
_nblock++;
_block[_nblock] = _state_in_ch;
_nblock++;
_block[_nblock] = _state_in_ch;
_nblock++;
_block[_nblock] = _state_in_ch;
_nblock++;
_block[_nblock] = _state_in_len - 4;
_nblock++;
break;
}
}
InputStream input;
Bz2BitWriter bw;
int _nblockMax;
int _state_in_ch;
int _state_in_len;
int _nblock;
int _blockCRC;
int _blockNo; // ignore: unused_field
int _workFactor;
int _budget;
int _origPtr;
Uint32List _arr1;
Uint32List _arr2;
Uint32List _ftab;
Uint8List _block;
Uint8List _inUse;
Uint16List _mtfv;
int _nInUse;
int _nMTF;
Int32List _mtfFreq;
Uint8List _unseqToSeq;
List<Uint8List> _len;
List<Int32List> _code;
List<Int32List> _rfreq;
List<Uint32List> _lenPack;
Uint8List _selector;
Uint8List _selectorMtf;
static const int BZ_N_RADIX = 2;
static const int BZ_N_QSORT = 12;
static const int BZ_N_SHELL = 18;
static const int BZ_N_OVERSHOOT = (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2);
static const int BZ_MAX_ALPHA_SIZE = 258;
static const int BZ_RUNA = 0;
static const int BZ_RUNB = 1;
static const int BZ_N_GROUPS = 6;
static const int BZ_G_SIZE = 50;
static const int BZ_N_ITERS = 4;
static const int BZ_LESSER_ICOST = 0;
static const int BZ_GREATER_ICOST = 15;
static const int BZ_MAX_SELECTORS = (2 + (900000 ~/ BZ_G_SIZE));
}