/*
Zlib – библиотека сжатия данных общего назначения. Версия 1.1.0
Это изменённая объектно-ориентированная версия библиотеки, полностью
совместимая с оригинальной библиотекой.
Copyright © 1995–2005 Jean-loup Gailly и Mark Adler
Copyright © 2000–2011 ymnk, JCraft, Inc.
Copyright © 2016, 2019 Малик Разработчик
Эта библиотека поставляется «как есть», без каких-либо явных или
подразумеваемых гарантий. Ни при каких обстоятельствах авторы не
несут какой-либо ответственности в случае потери данных вследствие
использования данной библиотеки.
Разрешается всем использовать эту библиотеку для любых целей, в том
числе и для коммерческих приложений, а также изменять её и
распространять свободно при соблюдении следующих условий:
1. Оригинал библиотеки не должен быть искажён; вы не должны
заявлять, что именно вы написали оригинальную библиотеку. Если вы
используете эту библиотеку в своём программном продукте, то ссылка
на авторов библиотеки была бы желательна, но это не является
обязательным требованием.
2. Изменённые версии исходных текстов должны быть отчётливо
маркированы и не должны выдаваться за оригинал библиотеки.
3. Эти замечания не могут быть удалены либо изменены при
каком-либо варианте распространения исходных текстов.
*/
package malik.emulator.compression.zlib;
final class InfCodes extends Zlib
{
private static final int START = 0;
private static final int LEN = 1;
private static final int LENEXT = 2;
private static final int DIST = 3;
private static final int DISTEXT = 4;
private static final int COPY = 5;
private static final int LIT = 6;
private static final int WASH = 7;
private static final int END = 8;
private static final int BADCODE = 9;
private static final int[] INFLATE_MASK;
static
{
INFLATE_MASK = new int[] {
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
0x00007fff, 0x0000ffff
};
}
private int lbits;
private int dbits;
private int mode;
private int len;
private int need;
private int lit;
private int get;
private int dist;
private int treeIndex;
private int ltreeIndex;
private int dtreeIndex;
private int[] tree;
private int[] ltree;
private int[] dtree;
InfCodes()
{
}
public void init(int bl, int bd, int[] tl, int tlIndex, int[] td, int tdIndex, ZStream z)
{
mode = START;
lbits = (byte) bl;
dbits = (byte) bd;
ltree = tl;
ltreeIndex = tlIndex;
dtree = td;
dtreeIndex = tdIndex;
tree = null;
}
public int proc(InfBlocks s, ZStream z, int r)
{
int j;
int tindex;
int e;
int b = 0;
int k = 0;
int p = 0;
int n;
int q;
int m;
int f;
p = z.nextInIndex;
n = z.availIn;
b = s.bitb;
k = s.bitk;
q = s.write;
m = q < s.read ? s.read - q - 1 : s.end - q;
do
{
switch(mode)
{
default:
r = STREAM_ERROR;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
case START:
if(m >= 258 && n >= 10)
{
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
r = inflateFast(lbits, dbits, ltree, ltreeIndex, dtree, dtreeIndex, s, z);
p = z.nextInIndex;
n = z.availIn;
b = s.bitb;
k = s.bitk;
q = s.write;
m = q < s.read ? s.read - q - 1 : s.end - q;
if(r != OK)
{
mode = r == STREAM_END ? WASH : BADCODE;
break;
}
}
need = lbits;
tree = ltree;
treeIndex = ltreeIndex;
mode = LEN;
/* fall through */
case LEN:
j = need;
while(k < j)
{
if(n != 0)
{
r = OK;
} else
{
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
}
n--;
b |= (z.nextIn[p++] & 0xff) << k;
k += 8;
}
tindex = (treeIndex + (b & INFLATE_MASK[j])) * 3;
b >>>= tree[tindex + 1];
k -= tree[tindex + 1];
e = tree[tindex];
if(e == 0)
{
lit = tree[tindex + 2];
mode = LIT;
break;
}
if((e & 16) != 0)
{
get = e & 15;
len = tree[tindex + 2];
mode = LENEXT;
break;
}
if((e & 64) == 0)
{
need = e;
treeIndex = tindex / 3 + tree[tindex + 2];
break;
}
if((e & 32) != 0)
{
mode = WASH;
break;
}
mode = BADCODE;
z.msg = "invalid literal/length code";
r = DATA_ERROR;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
case LENEXT:
j = get;
while(k < j)
{
if(n != 0)
{
r = OK;
} else
{
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
}
n--;
b |= (z.nextIn[p++] & 0xff) << k;
k += 8;
}
len += (b & INFLATE_MASK[j]);
b >>= j;
k -= j;
need = dbits;
tree = dtree;
treeIndex = dtreeIndex;
mode = DIST;
/* fall through */
case DIST:
j = need;
while(k < j)
{
if(n != 0)
{
r = OK;
} else
{
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
}
n--;
b |= (z.nextIn[p++] & 0xff) << k;
k += 8;
}
tindex = (treeIndex + (b & INFLATE_MASK[j])) * 3;
b >>= tree[tindex + 1];
k -= tree[tindex + 1];
e = (tree[tindex]);
if((e & 16) != 0)
{
get = e & 15;
dist = tree[tindex + 2];
mode = DISTEXT;
break;
}
if((e & 64) == 0)
{
need = e;
treeIndex = tindex / 3 + tree[tindex + 2];
break;
}
mode = BADCODE;
z.msg = "invalid distance code";
r = DATA_ERROR;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
case DISTEXT:
j = get;
while(k < j)
{
if(n != 0)
{
r = OK;
} else
{
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
}
n--;
b |= (z.nextIn[p++] & 0xff) << k;
k += 8;
}
dist += b & INFLATE_MASK[j];
b >>= j;
k -= j;
mode = COPY;
/* fall through */
case COPY:
f = q - dist;
while(f < 0)
{
f += s.end;
}
while(len != 0)
{
if(m == 0)
{
if(q == s.end && s.read != 0)
{
q = 0;
m = q < s.read ? s.read - q - 1 : s.end - q;
}
if(m == 0)
{
s.write = q;
r = s.inflateFlush(z, r);
q = s.write;
m = q < s.read ? s.read - q - 1 : s.end - q;
if(q == s.end && s.read != 0)
{
q = 0;
m = q < s.read ? s.read - q - 1 : s.end - q;
}
if(m == 0)
{
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
}
}
}
s.window[q++] = s.window[f++];
m--;
if(f == s.end)
{
f = 0;
}
len--;
}
mode = START;
break;
case LIT:
if(m == 0)
{
if(q == s.end && s.read != 0)
{
q = 0;
m = q < s.read ? s.read - q - 1 : s.end - q;
}
if(m == 0)
{
s.write = q;
r = s.inflateFlush(z, r);
q = s.write;
m = q < s.read ? s.read - q - 1 : s.end - q;
if(q == s.end && s.read != 0)
{
q = 0;
m = q < s.read ? s.read - q - 1 : s.end - q;
}
if(m == 0)
{
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
}
}
}
r = OK;
s.window[q++] = (byte) lit;
m--;
mode = START;
break;
case WASH:
if(k > 7)
{
k -= 8;
n++;
p--;
}
s.write = q;
r = s.inflateFlush(z, r);
q = s.write;
m = q < s.read ? s.read - q - 1 : s.end - q;
if(s.read != s.write)
{
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
}
mode = END;
/* fall through */
case END:
r = STREAM_END;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
case BADCODE:
r = DATA_ERROR;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return s.inflateFlush(z, r);
}
} while(true);
}
private int inflateFast(int bl, int bd, int[] tl, int tlIndex, int[] td, int tdIndex,
InfBlocks s, ZStream z)
{
int t;
int tpIndex;
int e;
int b;
int k;
int p;
int n;
int q;
int m;
int ml;
int md;
int c;
int d;
int r;
int tpIndexT3;
int[] tp;
p = z.nextInIndex;
n = z.availIn;
b = s.bitb;
k = s.bitk;
q = s.write;
m = q < s.read ? s.read - q - 1 : s.end - q;
ml = INFLATE_MASK[bl];
md = INFLATE_MASK[bd];
do
{
while(k < 20)
{
n--;
b |= (z.nextIn[p++] & 0xff) << k;
k += 8;
}
t = b & ml;
tp = tl;
tpIndex = tlIndex;
tpIndexT3 = (tpIndex + t) * 3;
if((e = tp[tpIndexT3]) == 0)
{
b >>= (tp[tpIndexT3 + 1]);
k -= (tp[tpIndexT3 + 1]);
s.window[q++] = (byte) tp[tpIndexT3 + 2];
m--;
continue;
}
do
{
b >>= tp[tpIndexT3 + 1];
k -= tp[tpIndexT3 + 1];
if((e & 16) != 0)
{
e &= 15;
c = tp[tpIndexT3 + 2] + (b & INFLATE_MASK[e]);
b >>= e;
k -= e;
while(k < 15)
{
n--;
b |= (z.nextIn[p++] & 0xff) << k;
k += 8;
}
t = b & md;
tp = td;
tpIndex = tdIndex;
tpIndexT3 = (tpIndex + t) * 3;
e = tp[tpIndexT3];
do
{
b >>= tp[tpIndexT3 + 1];
k -= tp[tpIndexT3 + 1];
if((e & 16) != 0)
{
e &= 15;
while(k < e)
{
n--;
b |= (z.nextIn[p++] & 0xff) << k;
k += 8;
}
d = tp[tpIndexT3 + 2] + (b & INFLATE_MASK[e]);
b >>= e;
k -= e;
m -= c;
if(q >= d)
{
r = q - d;
if(q - r > 0 && q - r < 2)
{
s.window[q++] = s.window[r++];
s.window[q++] = s.window[r++];
c -= 2;
} else
{
Array.copy(s.window, r, s.window, q, 2);
q += 2;
r += 2;
c -= 2;
}
} else
{
r = q - d;
do
{
r += s.end;
} while(r < 0);
e = s.end - r;
if(c > e)
{
c -= e;
if(q - r > 0 && e > q - r)
{
do
{
s.window[q++] = s.window[r++];
} while(--e != 0);
} else
{
Array.copy(s.window, r, s.window, q, e);
q += e;
r += e;
e = 0;
}
r = 0;
}
}
if(q - r > 0 && c > q - r)
{
do
{
s.window[q++] = s.window[r++];
} while(--c != 0);
} else
{
Array.copy(s.window, r, s.window, q, c);
q += c;
r += c;
c = 0;
}
break;
}
else if((e & 64) == 0)
{
t += tp[tpIndexT3 + 2];
t += (b & INFLATE_MASK[e]);
tpIndexT3 = (tpIndex + t) * 3;
e = tp[tpIndexT3];
}
else
{
z.msg = "invalid distance code";
c = z.availIn - n;
c = (k >> 3) < c ? k >> 3 : c;
n += c;
p -= c;
k -= c << 3;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return DATA_ERROR;
}
} while(true);
break;
}
if((e & 64) == 0)
{
t += tp[tpIndexT3 + 2];
t += (b & INFLATE_MASK[e]);
tpIndexT3 = (tpIndex + t) * 3;
if((e = tp[tpIndexT3]) == 0)
{
b >>= tp[tpIndexT3 + 1];
k -= tp[tpIndexT3 + 1];
s.window[q++] = (byte) tp[tpIndexT3 + 2];
m--;
break;
}
}
else if((e & 32) != 0)
{
c = z.availIn - n;
c = (k >> 3) < c ? k >> 3 : c;
n += c;
p -= c;
k -= c << 3;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return STREAM_END;
}
else
{
z.msg = "invalid literal/length code";
c = z.availIn - n;
c = (k >> 3) < c ? k >> 3 : c;
n += c;
p -= c;
k -= c << 3;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return DATA_ERROR;
}
} while(true);
} while(m >= 258 && n >= 10);
c = z.availIn - n;
c = (k >> 3) < c ? k >> 3 : c;
n += c;
p -= c;
k -= c << 3;
s.bitb = b;
s.bitk = k;
z.availIn = n;
z.totalIn += p - z.nextInIndex;
z.nextInIndex = p;
s.write = q;
return OK;
}
}