Fix map chunk decompressing with Mono.

This commit is contained in:
UnknownShadow200 2015-06-19 11:16:15 +10:00
parent ac3b1b0571
commit 8898d0722b
8 changed files with 1531 additions and 18 deletions

View file

@ -124,6 +124,10 @@
<Compile Include="Commands\Command.cs" />
<Compile Include="Commands\DefaultCommands.cs" />
<Compile Include="GraphicsAPI\VertexFormats.cs" />
<Compile Include="Ionic.Zlib\DeflateStream.cs" />
<Compile Include="Ionic.Zlib\Inflate.cs" />
<Compile Include="Ionic.Zlib\InfTree.cs" />
<Compile Include="Ionic.Zlib\ZlibCodec.cs" />
<Compile Include="Map\ChunkMeshBuilder.cs" />
<Compile Include="Map\ChunkMeshBuilderTex2Col4.cs" />
<Compile Include="Map\Map.cs" />
@ -212,6 +216,7 @@
<Folder Include="Blocks" />
<Folder Include="GraphicsAPI" />
<Folder Include="Entities" />
<Folder Include="Ionic.Zlib" />
<Folder Include="Map" />
<Folder Include="Game" />
<Folder Include="Model" />

View file

@ -0,0 +1,75 @@
// Originally copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
// See license.txt, section Ionic.Zlib license
#if __MonoCS__
using System;
using System.IO;
namespace Ionic.Zlib {
internal class DeflateStream {
ZlibCodec z;
bool _leaveOpen;
byte[] workBuffer;
Stream _stream;
public DeflateStream( Stream stream, bool leaveOpen ) {
_stream = stream;
_leaveOpen = leaveOpen;
workBuffer = new byte[16384]; // TODO: 1024 bytes?
z = new ZlibCodec();
}
public void Close() {
z.EndInflate();
z = null;
if( !_leaveOpen )
_stream.Close();
_stream = null;
}
public int Read( byte[] buffer, int offset, int count ) {
// According to MS documentation, any implementation of the IO.Stream.Read function must:
// (a) throw an exception if offset & count reference an invalid part of the buffer,
// or if count < 0, or if buffer is null
// (b) return 0 only upon EOF, or if count = 0
// (c) if not EOF, then return at least 1 byte, up to <count> bytes
if( count == 0 ) return 0;
int rc = 0;
// set up the output of the deflate/inflate codec:
z.OutputBuffer = buffer;
z.NextOut = offset;
z.AvailableBytesOut = count;
z.InputBuffer = workBuffer;
bool endOfInput = false;
do {
// need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any.
if( z.AvailableBytesIn == 0 && !endOfInput ) {
// No data available, so try to Read data from the captive stream.
z.NextIn = 0;
z.AvailableBytesIn = _stream.Read(workBuffer, 0, workBuffer.Length);
if( z.AvailableBytesIn == 0 )
endOfInput = true;
}
rc = z.Inflate();
if (endOfInput && rc == RCode.BufferError)
return 0;
if (rc != RCode.Okay && rc != RCode.StreamEnd)
throw new InvalidDataException( "inflating: rc=" + rc );
if ((endOfInput || rc == RCode.StreamEnd) && z.AvailableBytesOut == count)
break; // nothing more to read
} while( z.AvailableBytesOut > 0 && !endOfInput && rc == RCode.Okay );
return count - z.AvailableBytesOut;
}
}
}
#endif

296
Ionic.Zlib/InfTree.cs Normal file
View file

@ -0,0 +1,296 @@
// Originally copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
// See license.txt, section Ionic.Zlib license
#if __MonoCS__
using System;
namespace Ionic.Zlib {
sealed class InfTree {
const int MANY = 1440;
static readonly int[] fixed_tl = {96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186,
0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8,
14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255};
static readonly int[] fixed_td = {80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577};
// Tables for deflate from PKZIP's appnote.txt.
static readonly int[] cplens = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
// see note #13 above about 258
static readonly int[] cplext = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112};
static readonly int[] cpdist = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
static readonly int[] cpdext = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
// If BMAX needs to be larger than 16, then h and x[] should be uLong.
const int BMAX = 15; // maximum bit length of any code
int hn = 0; // hufts used in space
int[] v = null; // work area for huft_build
int[] c = new int[BMAX + 1]; // bit length count table
int r0 = 0, r1 = 0, r2 = 0; // table entry for structure assignment
int[] tableStack = new int[BMAX]; // table stack
int[] x = new int[BMAX + 1]; // bit offsets, then code stack
int BuildTree(int[] b, int bindex, int n, int s, int[] d, int[] e, ref int t, ref int m, int[] hp) {
// Given a list of code lengths and a maximum table size, make a set of
// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
// if the given code set is incomplete (the tables are still built in this
// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
// lengths), or Z_MEM_ERROR if not enough memory.
int f; // i repeats in table every f entries
int i; // counter, current code
int j; // counter
int p = 0; // pointer into c[], b[], or v[]
int y; // number of dummy codes added
// Generate counts for each bit length
i = n;
do {
c[b[bindex + p]]++;
p++;
i--; // assume all entries <= BMAX
} while (i != 0);
if (c[0] == n) {
// null input--all zero length codes
t = -1;
m = 0;
return RCode.Okay;
}
// Find minimum and maximum length, bound *m by those
int bitsPerTable = m; // bits per table (returned in m)
for (j = 1; j <= BMAX; j++)
if (c[j] != 0)
break;
int curCodeBits = j; // number of bits in current code (starting at minimum code length)
if (bitsPerTable < curCodeBits) {
bitsPerTable = curCodeBits;
}
for (i = BMAX; i != 0; i--) {
if (c[i] != 0)
break;
}
int maxCodeLen = i; // maximum code length
if (bitsPerTable > maxCodeLen) {
bitsPerTable = maxCodeLen;
}
m = bitsPerTable;
// Adjust last length count to fill out codes, if needed
for (y = 1 << j; j < i; j++, y <<= 1) {
if ((y -= c[j]) < 0) {
return RCode.DataError;
}
}
if ((y -= c[i]) < 0) {
return RCode.DataError;
}
c[i] += y;
// Generate starting offsets into the value table for each length
x[1] = j = 0;
p = 1;
int xIndex = 2; // pointer into x
while (--i != 0) {
// note that i == g from above
x[xIndex++] = (j += c[p]);
p++;
}
// Make a table of values in order of bit lengths
i = 0;
p = 0;
do {
if ((j = b[bindex + p]) != 0) {
v[x[j]++] = i;
}
p++;
} while (++i < n);
n = x[maxCodeLen]; // set n to length of v
// Generate the Huffman codes and for each, make the table entries
x[0] = i = 0; // first Huffman code is zero
p = 0; // grab values in bit order
int h = -1; // table level, no tables yet so level is -1
int w = -bitsPerTable; // bits before this table == (l * h), bits decoded == (l * h)
tableStack[0] = 0; // just to keep compilers happy
int q = 0; // points to current table
int z = 0; // number of entries in current table
// go through the bit lengths (k already is bits in shortest code)
for (; curCodeBits <= maxCodeLen; curCodeBits++)
{
int a = c[curCodeBits]; // counter for codes of length k
while (a-- != 0)
{
// here i is the Huffman code of length k bits for value *p
// make tables up to required level
while (curCodeBits > w + bitsPerTable)
{
h++;
w += bitsPerTable; // previous table always l bits
// compute minimum size table less than or equal to l bits
z = maxCodeLen - w;
z = (z > bitsPerTable)?bitsPerTable:z; // table size upper limit
if ((f = 1 << (j = curCodeBits - w)) > a + 1)
{
// try a k-w bit table
// too few codes for k-w bit table
f -= (a + 1); // deduct codes from patterns left
xIndex = curCodeBits;
if (j < z)
{
while (++j < z)
{
// try smaller tables up to z bits
if ((f <<= 1) <= c[++xIndex])
break; // enough codes to use up j bits
f -= c[xIndex]; // else deduct codes from patterns
}
}
}
z = 1 << j; // table entries for j-bit table
// allocate new table
if (hn + z > MANY) {
return RCode.DataError; // overflow of MANY
}
tableStack[h] = q = hn; // DEBUG
hn += z;
// connect to last table, if there is one
if (h != 0) {
x[h] = i; // save pattern for backing up
r0 = (sbyte) j; // bits in this table
r1 = (sbyte) bitsPerTable; // bits to dump before this table
j = URShift(i, (w - bitsPerTable));
r2 = (q - tableStack[h - 1] - j); // offset to this table
int dstIndex = (tableStack[h - 1] + j) * 3; // connect to last table
hp[dstIndex++] = r0;
hp[dstIndex++] = r1;
hp[dstIndex++] = r2;
} else {
t = q; // first table is returned result
}
}
// set up table entry in r
r1 = (sbyte) (curCodeBits - w);
if (p >= n) {
r0 = 128 + 64; // out of values--invalid code
} else if (v[p] < s) {
r0 = (sbyte) (v[p] < 256 ? 0: 32 + 64); // 256 is end-of-block
r2 = v[p++]; // simple code is just the value
} else {
r0 = (sbyte) (e[v[p] - s] + 16 + 64); // non-simple--look up in lists
r2 = d[v[p++] - s];
}
// fill code-like entries with r
f = 1 << (curCodeBits - w);
for (j = URShift(i, w); j < z; j += f) {
int dstIndex = (q + j) * 3;
hp[dstIndex++] = r0;
hp[dstIndex++] = r1;
hp[dstIndex++] = r2;
}
// backwards increment the k-bit code i
for (j = 1 << (curCodeBits - 1); (i & j) != 0; j = URShift(j, 1)) {
i ^= j;
}
i ^= j;
// backup over finished tables
int mask = (1 << w) - 1;
while ((i & mask) != x[h]) {
h--; // don't need to update q
w -= bitsPerTable;
mask = (1 << w) - 1;
}
}
}
// Return Z_BUF_ERROR if we were given an incomplete table
return y != 0 && maxCodeLen != 1 ? RCode.BufferError : RCode.Okay;
}
internal void InflateTreeBits(int[] c, ref int bb, ref int tb, int[] hp, ZlibCodec z) {
ResetWorkArea( 19 );
hn = 0;
int result = BuildTree(c, 0, 19, 19, null, null, ref tb, ref bb, hp);
if (result == RCode.DataError) {
throw new InvalidOperationException( "oversubscribed dynamic bit lengths tree" );
} else if (result == RCode.BufferError || bb == 0) {
throw new InvalidOperationException( "incomplete dynamic bit lengths tree" );
}
}
internal void InflateTreesDynamic(int nl, int nd, int[] c, ref int bl, ref int bd,
ref int tl, ref int td, int[] hp, ZlibCodec z) {
// build literal/length tree
ResetWorkArea( 288 );
hn = 0;
int result = BuildTree(c, 0, nl, 257, cplens, cplext, ref tl, ref bl, hp);
if (result != RCode.Okay || bl == 0) {
string message = null;
if (result == RCode.DataError) {
message = "oversubscribed literal/length tree";
} else {
message = "incomplete literal/length tree";
}
throw new InvalidOperationException( "Unable to inflate dynamic tree: " + message );
}
// build distance tree
ResetWorkArea( 288 );
result = BuildTree(c, nl, nd, 0, cpdist, cpdext, ref td, ref bd, hp);
if (result != RCode.Okay || (bd == 0 && nl > 257)) {
string message = null;
if (result == RCode.DataError) {
message = "oversubscribed distance tree";
} else if (result == RCode.BufferError) {
message = "incomplete distance tree";
} else {
message = "empty distance tree with lengths";
}
throw new InvalidOperationException( "Unable to inflate dynamic tree: " + message );
}
}
internal static void InflateTreesFixed( out int bl, out int bd, out int[] tl, out int[] td ) {
bl = 9;
bd = 5;
tl = fixed_tl;
td = fixed_td;
}
void ResetWorkArea( int vsize ) {
if( v == null || v.Length < vsize ) {
v = new int[vsize];
}
Array.Clear(v, 0, vsize);
Array.Clear(c, 0, BMAX + 1);
r0 = 0; r1 = 0; r2 = 0;
Array.Clear(tableStack, 0, BMAX);
Array.Clear(x, 0, BMAX + 1);
}
static int URShift( int value, int bits ) {
return (int)( (uint)value >> bits );
}
}
}
#endif

981
Ionic.Zlib/Inflate.cs Normal file
View file

@ -0,0 +1,981 @@
// Originally copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
// See license.txt, section Ionic.Zlib license
#if __MonoCS__
using System;
using System.IO;
namespace Ionic.Zlib
{
sealed class InflateBlocks
{
const int MANY = 1440;
// Table for deflate from PKZIP's appnote.txt.
static readonly int[] border = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
enum InflateBlockMode {
TYPE = 0, // get type bits (3, including end bit)
LENS = 1, // get lengths for stored
STORED = 2, // processing stored block
TABLE = 3, // get table lengths
BTREE = 4, // get bit lengths tree for a dynamic block
DTREE = 5, // get length, distance trees for a dynamic block
CODES = 6, // processing fixed or dynamic block
DRY = 7, // output remaining window bytes
DONE = 8, // finished last block, done
}
InflateBlockMode mode; // current inflate_block mode
int left; // if STORED, bytes left to copy
int table; // table lengths (14 bits)
int index; // index into blens (or border)
int[] blens; // bit lengths of codes
int bb; // bit length tree depth
int tb; // bit length decoding tree
InflateCodes codes = new InflateCodes(); // if CODES, current state
int last; // true if this block is the last block
internal ZlibCodec codec; // pointer back to this zlib stream
// mode independent information
internal int bitk; // bits in bit buffer
internal int bitb; // bit buffer
internal int[] hufts; // single malloc for tree space
internal byte[] window; // sliding window
internal int end; // one byte after sliding window
internal int readAt; // window read pointer
internal int writeAt; // window write pointer
InfTree inftree = new InfTree();
internal InflateBlocks(ZlibCodec codec, int w) {
this.codec = codec;
hufts = new int[MANY * 3];
window = new byte[w];
end = w;
mode = InflateBlockMode.TYPE;
Reset();
}
internal void Reset() {
mode = InflateBlockMode.TYPE;
bitk = 0;
bitb = 0;
readAt = writeAt = 0;
}
internal int Process(int r) {
int t; // temporary storage
int nextIn = codec.NextIn; // input data pointer
int availIn = codec.AvailableBytesIn; // bytes available there
int bits = bitb; // bit buffer
int bitsNum = bitk; // bits in bit buffer
int q = writeAt; // output window write pointer
int m = q < readAt ? readAt - q - 1 : end - q; // bytes to end of window or read pointer
// process input based on current state
while (true)
{
switch (mode)
{
case InflateBlockMode.TYPE:
while( bitsNum < 3 ) {
if (availIn != 0) {
r = RCode.Okay;
} else {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= codec.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
last = bits & 0x1;
switch( ( bits & 0x7 ) >> 1 ) {
case 0: // stored
bits >>= 3; bitsNum -= 3;
t = bitsNum & 7; // go to byte boundary
bits >>= t; bitsNum -= t;
mode = InflateBlockMode.LENS; // get length of stored block
break;
case 1: // fixed
int bl, bd;
int[] tl, td;
InfTree.InflateTreesFixed(out bl, out bd, out tl, out td);
codes.Init(bl, bd, tl, 0, td, 0);
bits >>= 3; bitsNum -= 3;
mode = InflateBlockMode.CODES;
break;
case 2: // dynamic
bits >>= 3; bitsNum -= 3;
mode = InflateBlockMode.TABLE;
break;
case 3: // illegal
throw new InvalidDataException( "invalid block type" );
} break;
case InflateBlockMode.LENS:
while( bitsNum < 32 ) {
if( availIn != 0 ) {
r = RCode.Okay;
} else {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= codec.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
if ( ( ( ~bits >> 16 ) & 0xffff ) != ( bits & 0xffff ) ) {
throw new InvalidDataException( "invalid stored block lengths" );
}
left = bits & 0xffff;
bits = bitsNum = 0; // dump bits
mode = left != 0 ? InflateBlockMode.STORED : (last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE);
break;
case InflateBlockMode.STORED:
if( availIn == 0 ) {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
if( m == 0 ) {
if( q == end && readAt != 0 ) {
q = 0;
m = q < readAt ? readAt - q - 1 : end - q;
}
if( m == 0 ) {
writeAt = q;
r = Flush(r);
q = writeAt;
m = q < readAt ? readAt - q - 1 : end - q;
if( q == end && readAt != 0 ) {
q = 0;
m = q < readAt ? readAt - q - 1 : end - q;
}
if( m == 0 ) {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
}
}
r = RCode.Okay;
t = left;
if (t > availIn)
t = availIn;
if (t > m)
t = m;
Array.Copy(codec.InputBuffer, nextIn, window, q, t);
nextIn += t; availIn -= t;
q += t; m -= t;
if ((left -= t) != 0)
break;
mode = last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE;
break;
case InflateBlockMode.TABLE:
while (bitsNum < 14) {
if( availIn != 0 ) {
r = RCode.Okay;
} else {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= codec.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
table = t = (bits & 0x3fff);
if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) {
throw new InvalidDataException( "too many length or distance symbols" );
}
t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
if (blens == null || blens.Length < t) {
blens = new int[t];
} else {
Array.Clear(blens, 0, t);
}
bits >>= 14;
bitsNum -= 14;
index = 0;
mode = InflateBlockMode.BTREE;
goto case InflateBlockMode.BTREE;
case InflateBlockMode.BTREE:
while (index < 4 + (table >> 10)) {
while( bitsNum < 3 ) {
if( availIn != 0 ) {
r = RCode.Okay;
} else {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= codec.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
blens[border[index++]] = bits & 7;
bits >>= 3; bitsNum -= 3;
}
while (index < 19) {
blens[border[index++]] = 0;
}
bb = 7;
inftree.InflateTreeBits(blens, ref bb, ref tb, hufts, codec);
index = 0;
mode = InflateBlockMode.DTREE;
goto case InflateBlockMode.DTREE;
case InflateBlockMode.DTREE:
while (true) {
t = table;
if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))) {
break;
}
t = bb;
while (bitsNum < t) {
if (availIn != 0) {
r = RCode.Okay;
} else {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= codec.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
t = hufts[(tb + (bits & Constants.InflateMask[t])) * 3 + 1];
int c = hufts[(tb + (bits & Constants.InflateMask[t])) * 3 + 2];
if( c < 16 ) {
bits >>= t; bitsNum -= t;
blens[index++] = c;
} else {
// c == 16..18
int i = c == 18 ? 7 : c - 14;
int j = c == 18 ? 11 : 3;
while( bitsNum < ( t + i ) ) {
if( availIn != 0 ) {
r = RCode.Okay;
} else {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= codec.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
bits >>= t; bitsNum -= t;
j += (bits & Constants.InflateMask[i]);
bits >>= i; bitsNum -= i;
i = index;
if (i + j > 258 + (table & 0x1f) + ((table >> 5) & 0x1f) || (c == 16 && i < 1)) {
throw new InvalidDataException( "invalid bit length repeat" );
}
c = (c == 16) ? blens[i-1] : 0;
do {
blens[i++] = c;
} while (--j != 0);
index = i;
}
}
tb = -1;
{
int bl = 9; // must be <= 9 for lookahead assumptions
int bd = 6; // must be <= 9 for lookahead assumptions
int tl = 0;
int td = 0;
inftree.InflateTreesDynamic(257 + (table & 0x1f), 1 + ((table >> 5) & 0x1f), blens,
ref bl, ref bd, ref tl, ref td, hufts, codec);
codes.Init(bl, bd, hufts, tl, hufts, td);
}
mode = InflateBlockMode.CODES;
goto case InflateBlockMode.CODES;
case InflateBlockMode.CODES:
UpdateState( bits, bitsNum, availIn, nextIn, q );
r = codes.Process(this, r);
if( r != RCode.StreamEnd ) {
return Flush(r);
}
r = RCode.Okay;
nextIn = codec.NextIn;
availIn = codec.AvailableBytesIn;
bits = bitb;
bitsNum = bitk;
q = writeAt;
m = q < readAt ? readAt - q - 1 : end - q;
if (last == 0)
{
mode = InflateBlockMode.TYPE;
break;
}
mode = InflateBlockMode.DRY;
goto case InflateBlockMode.DRY;
case InflateBlockMode.DRY:
writeAt = q;
r = Flush(r);
q = writeAt;
m = q < readAt ? readAt - q - 1 : end - q;
if (readAt != writeAt) {
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
mode = InflateBlockMode.DONE;
goto case InflateBlockMode.DONE;
case InflateBlockMode.DONE:
return RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
default:
throw new InvalidOperationException( "Invalid inflate block mode: " + mode );
}
}
}
internal int RanOutOfInput( int bits, int bitsNum, int availIn, int nextIn, int q, int r ) {
bitb = bits;
bitk = bitsNum;
codec.AvailableBytesIn = availIn;
codec.NextIn = nextIn;
writeAt = q;
return Flush(r);
}
internal void UpdateState( int bits, int bitsNum, int availIn, int nextIn, int q ) {
bitb = bits;
bitk = bitsNum;
codec.AvailableBytesIn = availIn;
codec.NextIn = nextIn;
writeAt = q;
}
internal void Free() {
Reset();
window = null;
hufts = null;
}
// copy as much as possible from the sliding window to the output area
internal int Flush( int r ) {
for( int pass = 0; pass < 2; pass++ ) {
int nBytes = pass == 0 ?
// compute number of bytes to copy as far as end of window
((readAt <= writeAt ? writeAt : end) - readAt) :
// compute bytes to copy
writeAt - readAt;
// workitem 8870
if (nBytes == 0) {
if (r == RCode.BufferError)
r = RCode.Okay;
return r;
}
if (nBytes > codec.AvailableBytesOut)
nBytes = codec.AvailableBytesOut;
if (nBytes != 0 && r == RCode.BufferError)
r = RCode.Okay;
// update counters
codec.AvailableBytesOut -= nBytes;
// copy as far as end of window
Array.Copy(window, readAt, codec.OutputBuffer, codec.NextOut, nBytes);
codec.NextOut += nBytes;
readAt += nBytes;
// see if more to copy at beginning of window
if (readAt == end && pass == 0) {
// wrap pointers
readAt = 0;
if (writeAt == end)
writeAt = 0;
} else {
pass++;
}
}
return r;
}
}
internal static class Constants {
// And'ing with mask[n] masks the lower n bits
internal static readonly int[] InflateMask = {
0x00000000, 0x00000001, 0x00000003, 0x00000007,
0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff };
}
sealed class InflateCodes
{
// waiting for "i:"=input, "o:"=output, "x:"=nothing
const int START = 0; // x: set up for LEN
const int LEN = 1; // i: get length/literal/eob next
const int LENEXT = 2; // i: getting length extra (have base)
const int DIST = 3; // i: get distance next
const int DISTEXT = 4; // i: getting distance extra
const int COPY = 5; // o: copying bytes in window, waiting for space
const int LIT = 6; // o: got literal, waiting for output space
const int WASH = 7; // o: got eob, possibly still output waiting
const int END = 8; // x: got eob and all data flushed
const int BADCODE = 9; // x: got error
int mode; // current inflate_codes mode
// mode dependent information
int len;
int[] tree; // pointer into tree
int tree_index = 0;
int need; // bits needed
int lit;
// if EXT or COPY, where and how much
int bitsToGet; // bits to get for extra
int dist; // distance back to copy from
byte lbits; // ltree bits decoded per branch
byte dbits; // dtree bits decoder per branch
int[] ltree; // literal/length/eob tree
int ltree_index; // literal/length/eob tree
int[] dtree; // distance tree
int dtree_index; // distance tree
internal void Init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index) {
mode = START;
lbits = (byte)bl;
dbits = (byte)bd;
ltree = tl;
ltree_index = tl_index;
dtree = td;
dtree_index = td_index;
tree = null;
}
internal int Process(InflateBlocks blocks, int r)
{
int tindex; // temporary pointer
int e; // extra bits or operation
ZlibCodec z = blocks.codec;
int nextIn = z.NextIn;// input data pointer
int availIn = z.AvailableBytesIn; // bytes available there
int bits = blocks.bitb; // bit buffer
int bitsNum = blocks.bitk; // bits in bit buffer
int q = blocks.writeAt; // output window write pointer
int m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; // bytes to end of window or read pointer
// 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 && availIn >= 10) {
blocks.UpdateState( bits, bitsNum, availIn, nextIn, q );
r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, z);
nextIn = z.NextIn;
availIn = z.AvailableBytesIn;
bits = blocks.bitb;
bitsNum = blocks.bitk;
q = blocks.writeAt;
m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
if (r != RCode.Okay)
{
mode = (r == RCode.StreamEnd) ? WASH : BADCODE;
break;
}
}
need = lbits;
tree = ltree;
tree_index = ltree_index;
mode = LEN;
goto case LEN;
case LEN: // i: get length/literal/eob next
while (bitsNum < need) {
if (availIn != 0) {
r = RCode.Okay;
} else {
return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= z.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
tindex = (tree_index + (bits & Constants.InflateMask[need])) * 3;
bits >>= (tree[tindex + 1]);
bitsNum -= (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;
}
throw new InvalidDataException( "invalid literal/length code" );
case LENEXT: // i: getting length extra (have base)
while (bitsNum < bitsToGet) {
if (availIn != 0) {
r = RCode.Okay;
} else {
return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= z.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
len += (bits & Constants.InflateMask[bitsToGet]);
bits >>= bitsToGet;
bitsNum -= bitsToGet;
need = dbits;
tree = dtree;
tree_index = dtree_index;
mode = DIST;
goto case DIST;
case DIST: // i: get distance next
while (bitsNum < need) {
if (availIn != 0) {
r = RCode.Okay;
} else {
return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= z.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
tindex = (tree_index + (bits & Constants.InflateMask[need])) * 3;
bits >>= tree[tindex + 1];
bitsNum -= 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;
}
throw new InvalidDataException( "invalid distance code" );
case DISTEXT: // i: getting distance extra
while (bitsNum < bitsToGet) {
if (availIn != 0) {
r = RCode.Okay;
} else {
return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
availIn--;
bits |= z.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
dist += (bits & Constants.InflateMask[bitsToGet]);
bits >>= bitsToGet;
bitsNum -= bitsToGet;
mode = COPY;
goto case COPY;
case COPY: // o: copying bytes in window, waiting for space
int f = q - dist; // pointer to copy strings from
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) {
return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, 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) {
return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
}
}
r = RCode.Okay;
blocks.window[q++] = (byte)lit;
m--;
mode = START;
break;
case WASH: // o: got eob, possibly more output
if (bitsNum > 7)
{
// return unused byte, if any
bitsNum -= 8;
availIn++;
nextIn--; // 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) {
return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
}
mode = END;
goto case END;
case END:
r = RCode.StreamEnd;
return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r );
default:
throw new InvalidDataException( "Encountered error: " + mode );
}
}
}
// Called with number of bytes left to write in window at least 258
// (the maximum string length) and number of input bytes available
// at least ten. The ten bytes are six bytes for the longest length/
// distance pair plus four bytes for overloading the bit buffer.
internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, ZlibCodec z)
{
int e; // extra bits or operation
int c; // bytes to copy
int nextIn = z.NextIn; // input data pointer
int availIn = z.AvailableBytesIn; // bytes available there
int bits = s.bitb; // bit buffer
int bitsNum = s.bitk; // bits in bit buffer
int q = s.writeAt; // output window write pointer
int m = q < s.readAt ? s.readAt - q - 1 : s.end - q; // bytes to end of window or read pointer
int ml = Constants.InflateMask[bl]; // mask for literal/length tree
int md = Constants.InflateMask[bd]; // mask for distance tree
// do until not enough input or output space for fast loop
do {
// assume called with m >= 258 && n >= 10
// get literal/length code
while (bitsNum < 20) {
// max bits for literal/length code
availIn--;
bits |= z.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
int t = bits & ml; // temporary pointer
int[] tp = tl;// temporary pointer
int tp_index = tl_index;// temporary pointer
int tp_index_t_3 = (tp_index + t) * 3;
if ((e = tp[tp_index_t_3]) == 0) {
bits >>= tp[tp_index_t_3 + 1];
bitsNum -= tp[tp_index_t_3 + 1];
s.window[q++] = (byte)tp[tp_index_t_3 + 2];
m--;
continue;
}
do {
bits >>= tp[tp_index_t_3 + 1];
bitsNum -= tp[tp_index_t_3 + 1];
if ((e & 16) != 0) {
e &= 15;
c = tp[tp_index_t_3 + 2] + (bits & Constants.InflateMask[e]);
bits >>= e; bitsNum -= e;
// decode distance base of block to copy
while (bitsNum < 15) {
// max bits for distance code
availIn--;
bits |= z.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
t = bits & md;
tp = td;
tp_index = td_index;
tp_index_t_3 = (tp_index + t) * 3;
e = tp[tp_index_t_3];
do {
bits >>= (tp[tp_index_t_3 + 1]);
bitsNum -= (tp[tp_index_t_3 + 1]);
if ((e & 16) != 0) {
// get extra bits to add to distance base
e &= 15;
while (bitsNum < e) {
// get extra bits (up to 13)
availIn--;
bits |= z.InputBuffer[nextIn++] << bitsNum;
bitsNum += 8;
}
int d = tp[tp_index_t_3 + 2] + (bits & Constants.InflateMask[e]); // distance back to copy from
bits >>= e; bitsNum -= e;
// do the copy
int r = q - d; // copy source pointer
m -= c;
if (q >= d) {
// offset before dest, just copy
if (q - r > 0 && 2 > (q - r)) {
s.window[q++] = s.window[r++]; // minimum count is three,
s.window[q++] = s.window[r++]; // so unroll loop a little
} else {
Array.Copy(s.window, r, s.window, q, 2);
q += 2; r += 2;
}
c -= 2;
} else {
// else offset after destination
do {
r += s.end; // force pointer in window
} while (r < 0); // covers invalid distances
e = s.end - r;
if (c > e) {
// if source crosses,
c -= e; // wrapped copy
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; // copy rest from start of window
}
}
// copy all or what's left
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[tp_index_t_3 + 2];
t += (bits & Constants.InflateMask[e]);
tp_index_t_3 = (tp_index + t) * 3;
e = tp[tp_index_t_3];
} else {
throw new InvalidDataException( "invalid distance code" );
}
} while (true);
break;
}
if ( ( e & 64 ) == 0 ) {
t += tp[tp_index_t_3 + 2];
t += (bits & Constants.InflateMask[e]);
tp_index_t_3 = (tp_index + t) * 3;
if ((e = tp[tp_index_t_3]) == 0)
{
bits >>= (tp[tp_index_t_3 + 1]); bitsNum -= (tp[tp_index_t_3 + 1]);
s.window[q++] = (byte)tp[tp_index_t_3 + 2];
m--;
break;
}
} else if ( ( e & 32 ) != 0 ) {
c = z.AvailableBytesIn - availIn;
c = (bitsNum >> 3) < c ? bitsNum >> 3 : c;
availIn += c;
nextIn -= c;
bitsNum -= (c << 3);
s.UpdateState( bits, bitsNum, availIn, nextIn, q );
return RCode.StreamEnd;
} else {
throw new InvalidDataException( "invalid literal/length code" );
}
} while (true);
} while (m >= 258 && availIn >= 10);
// not enough input or output--restore pointers and return
c = z.AvailableBytesIn - availIn;
c = (bitsNum >> 3) < c ? bitsNum >> 3 : c;
availIn += c;
nextIn -= c;
bitsNum -= (c << 3);
s.UpdateState( bits, bitsNum, availIn, nextIn, q );
return RCode.Okay;
}
}
internal sealed class InflateManager
{
bool done = false;
ZlibCodec _codec; // pointer back to this zlib stream
int wbits; // log2(window size) (8..15, defaults to 15)
InflateBlocks blocks; // current inflate_blocks state
internal void Reset() {
done = false;
blocks.Reset();
}
internal void End() {
if (blocks != null)
blocks.Free();
blocks = null;
}
internal void Initialize( ZlibCodec codec, int w ) {
_codec = codec;
blocks = null;
wbits = w;
blocks = new InflateBlocks( codec, 1 << w );
Reset();
}
internal int Inflate() {
if (_codec.InputBuffer == null)
throw new InvalidOperationException("InputBuffer is null. ");
int r = RCode.BufferError;
if( !done ) {
r = blocks.Process(r);
if( r == RCode.DataError ) {
throw new InvalidDataException( "Bad state" );
}
if (r != RCode.StreamEnd)
return r;
blocks.Reset();
done = true;
}
return RCode.StreamEnd;
}
}
}
#endif

44
Ionic.Zlib/ZlibCodec.cs Normal file
View file

@ -0,0 +1,44 @@
// Originally copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
// See license.txt, section Ionic.Zlib license
#if __MonoCS__
using System;
namespace Ionic.Zlib {
public sealed class ZlibCodec {
public byte[] InputBuffer;
public int NextIn;
public int AvailableBytesIn;
public byte[] OutputBuffer;
public int NextOut;
public int AvailableBytesOut;
InflateManager istate;
public ZlibCodec() {
istate = new InflateManager();
const int windowBits = 15; // 32K LZ77 window (max value 15, min value 8)
istate.Initialize( this, windowBits );
}
public int Inflate() {
return istate.Inflate();
}
public void EndInflate() {
istate.End();
istate = null;
}
}
public static class RCode {
public const int Okay = 0;
public const int StreamEnd = 1;
public const int DataError = -3;
public const int BufferError = -5;
}
}
#endif

View file

@ -1,13 +1,16 @@
//#define NET_DEBUG
using System;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Sockets;
using System.Text;
using ClassicalSharp.Network;
using OpenTK;
using System;
using System.Drawing;
using System.IO;
#if __MonoCS__
using Ionic.Zlib;
#else
using System.IO.Compression;
#endif
using System.Net;
using System.Net.Sockets;
using ClassicalSharp.Network;
using OpenTK;
namespace ClassicalSharp {
@ -288,7 +291,13 @@ namespace ClassicalSharp {
}
receivedFirstPosition = false;
gzipHeader = new GZipHeaderReader();
// Workaround because built in mono stream assumes that the end of stream
// has been reached the first time a read call returns 0. (MS.NET doesn't)
#if __MonoCS__
gzipStream = new DeflateStream( gzippedMap, true );
#else
gzipStream = new DeflateStream( gzippedMap, CompressionMode.Decompress );
#endif
mapSizeIndex = 0;
mapIndex = 0;
receiveStart = DateTime.UtcNow;
@ -330,7 +339,7 @@ namespace ClassicalSharp {
Window.Map.UseRawMap( map, mapWidth, mapHeight, mapLength );
Window.RaiseOnNewMapLoaded();
map = null;
gzipStream.Dispose();
gzipStream.Close();
if( sendWomId && !sentWomId ) {
SendChat( "/womid WoMClient-2.0.6" );
sentWomId = true;

View file

@ -226,11 +226,12 @@ namespace ClassicalSharp {
Graphics.AlphaBlending = true;
Graphics.Texturing = true;
Graphics.ColourWrite = true;
//Graphics.DepthWrite = false; TODO: test if this makes a difference.
for( int batch = 0; batch < _1Dcount; batch++ ) {
Graphics.Bind2DTexture( texIds[batch] );
RenderTranslucentBatch( batch );
}
//Graphics.DepthWrite = true;
Graphics.AlphaTest = false;
Graphics.AlphaBlending = false;
Graphics.Texturing = false;

View file

@ -36,7 +36,9 @@ Unless otherwise noted, you may use any and all code examples provided herein in
ClassicalSharp uses the OpenTK library. The license of OpenTK is reproduced below:
OpenTK license
===============
The Open Toolkit library license
Copyright (c) 2006 - 2010 The Open Toolkit library.
@ -48,11 +50,6 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Third parties
OpenTK.Platform.Windows and OpenTK.Platform.X11 include portions of the Mono class library. These portions are covered by the following license:
Copyright (c) 2004 Novell, Inc.
@ -61,4 +58,109 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Ionic.Zlib license
==================
Microsoft Public License (Ms-PL)
This license governs use of the accompanying software, the DotNetZip library ("the software"). If you use the software, you accept this license. If you do not accept the license, do not use the software.
1. Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
A "contribution" is the original software, or any additions or changes to the software.
A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
2. Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
3. Conditions and Limitations
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
The following licenses govern use of the accompanying software, the
DotNetZip library ("the software"). If you use the software, you accept
these licenses. If you do not accept the license, do not use the software.
The managed ZLIB code included in Ionic.Zlib.dll and Ionic.Zip.dll is
modified code, based on jzlib.
The following notice applies to jzlib:
-----------------------------------------------------------------------
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------
jzlib is based on zlib-1.1.3.
The following notice applies to zlib:
-----------------------------------------------------------------------
Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
The ZLIB software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly jloup@gzip.org
Mark Adler madler@alumni.caltech.edu
-----------------------------------------------------------------------