internal int Process(InflateBlocks blocks, int r)
{
int j; // temporary storage
int tindex; // temporary pointer
int e; // extra bits or operation
int b = 0; // bit buffer
int k = 0; // bits in bit buffer
int p = 0; // input data pointer
int n; // bytes available there
int q; // output window write pointer
int m; // bytes to end of window or read pointer
int f; // pointer to copy strings from
ZlibCodec z = blocks._codec;
// copy input/output information to locals (UPDATE macro restores)
p = z.NextIn;
n = z.AvailableBytesIn;
b = blocks.bitb;
k = blocks.bitk;
q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
// process input and output based on current state
while (true)
{
switch (mode)
{
// waiting for "i:"=input, "o:"=output, "x:"=nothing
case START: // x: set up for LEN
if (m >= 258 && n >= 10)
{
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n;
z.TotalBytesIn += p - z.NextIn;
z.NextIn = p;
blocks.writeAt = q;
r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, z);
p = z.NextIn;
n = z.AvailableBytesIn;
b = blocks.bitb;
k = blocks.bitk;
q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
if (r != ZlibConstants.Z_OK)
{
mode = (r == ZlibConstants.Z_STREAM_END) ? WASH : BADCODE;
break;
}
}
need = lbits;
tree = ltree;
tree_index = ltree_index;
mode = LEN;
goto case LEN;
case LEN: // i: get length/literal/eob next
j = need;
while (k < j)
{
if (n != 0)
r = ZlibConstants.Z_OK;
else
{
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n;
z.TotalBytesIn += p - z.NextIn;
z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
}
n--;
b |= (z.InputBuffer[p++] & 0xff) << k;
k += 8;
}
tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j])) * 3;
b >>= (tree[tindex + 1]);
k -= (tree[tindex + 1]);
e = tree[tindex];
if (e == 0)
{
// literal
lit = tree[tindex + 2];
mode = LIT;
break;
}
if ((e & 16) != 0)
{
// length
bitsToGet = e & 15;
len = tree[tindex + 2];
mode = LENEXT;
break;
}
if ((e & 64) == 0)
{
// next table
need = e;
tree_index = tindex / 3 + tree[tindex + 2];
break;
}
if ((e & 32) != 0)
{
// end of block
mode = WASH;
break;
}
mode = BADCODE; // invalid code
z.Message = "invalid literal/length code";
r = ZlibConstants.Z_DATA_ERROR;
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n;
z.TotalBytesIn += p - z.NextIn;
z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
case LENEXT: // i: getting length extra (have base)
j = bitsToGet;
while (k < j)
{
if (n != 0)
r = ZlibConstants.Z_OK;
else
{
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
}
n--; b |= (z.InputBuffer[p++] & 0xff) << k;
k += 8;
}
len += (b & InternalInflateConstants.InflateMask[j]);
b >>= j;
k -= j;
need = dbits;
tree = dtree;
tree_index = dtree_index;
mode = DIST;
goto case DIST;
case DIST: // i: get distance next
j = need;
while (k < j)
{
if (n != 0)
r = ZlibConstants.Z_OK;
else
{
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
}
n--; b |= (z.InputBuffer[p++] & 0xff) << k;
k += 8;
}
tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j])) * 3;
b >>= tree[tindex + 1];
k -= tree[tindex + 1];
e = (tree[tindex]);
if ((e & 0x10) != 0)
{
// distance
bitsToGet = e & 15;
dist = tree[tindex + 2];
mode = DISTEXT;
break;
}
if ((e & 64) == 0)
{
// next table
need = e;
tree_index = tindex / 3 + tree[tindex + 2];
break;
}
mode = BADCODE; // invalid code
z.Message = "invalid distance code";
r = ZlibConstants.Z_DATA_ERROR;
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
case DISTEXT: // i: getting distance extra
j = bitsToGet;
while (k < j)
{
if (n != 0)
r = ZlibConstants.Z_OK;
else
{
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
}
n--; b |= (z.InputBuffer[p++] & 0xff) << k;
k += 8;
}
dist += (b & InternalInflateConstants.InflateMask[j]);
b >>= j;
k -= j;
mode = COPY;
goto case COPY;
case COPY: // o: copying bytes in window, waiting for space
f = q - dist;
while (f < 0)
{
// modulo window size-"while" instead
f += blocks.end; // of "if" handles invalid distances
}
while (len != 0)
{
if (m == 0)
{
if (q == blocks.end && blocks.readAt != 0)
{
q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
}
if (m == 0)
{
blocks.writeAt = q; r = blocks.Flush(r);
q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
if (q == blocks.end && blocks.readAt != 0)
{
q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
}
if (m == 0)
{
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n;
z.TotalBytesIn += p - z.NextIn;
z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
}
}
}
blocks.window[q++] = blocks.window[f++]; m--;
if (f == blocks.end)
f = 0;
len--;
}
mode = START;
break;
case LIT: // o: got literal, waiting for output space
if (m == 0)
{
if (q == blocks.end && blocks.readAt != 0)
{
q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
}
if (m == 0)
{
blocks.writeAt = q; r = blocks.Flush(r);
q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
if (q == blocks.end && blocks.readAt != 0)
{
q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
}
if (m == 0)
{
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
}
}
}
r = ZlibConstants.Z_OK;
blocks.window[q++] = (byte)lit; m--;
mode = START;
break;
case WASH: // o: got eob, possibly more output
if (k > 7)
{
// return unused byte, if any
k -= 8;
n++;
p--; // can always return one
}
blocks.writeAt = q; r = blocks.Flush(r);
q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
if (blocks.readAt != blocks.writeAt)
{
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
}
mode = END;
goto case END;
case END:
r = ZlibConstants.Z_STREAM_END;
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
case BADCODE: // x: got error
r = ZlibConstants.Z_DATA_ERROR;
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
default:
r = ZlibConstants.Z_STREAM_ERROR;
blocks.bitb = b; blocks.bitk = k;
z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
blocks.writeAt = q;
return blocks.Flush(r);
}
}
}