using System; using System.IO; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; namespace ByteFX.Data.MySqlClient { /// /// Summary description for CompressedStream. /// internal class CompressedStream : Stream { private Stream srcStream; private byte[] buffer; private int index; public CompressedStream( Stream src ) { srcStream = src; index = 0; buffer = new byte[0]; } #region Properties public override bool CanRead { get { return srcStream.CanRead; } } public override bool CanWrite { get { return srcStream.CanWrite; } } public override bool CanSeek { get { return srcStream.CanSeek; } } public override long Length { get { return srcStream.Length; } } public override long Position { get { return srcStream.Position; } set { srcStream.Position = value; } } #endregion public override void Close() { srcStream.Close(); base.Close (); } public override void Flush() { srcStream.Flush(); } public override void SetLength(long value) { srcStream.SetLength( value ); } public override int ReadByte() { EnsureData(1); return (int)buffer[index++]; } public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) throw new ArgumentNullException( "buffer", "Buffer must not be null" ); if (offset < 0 || offset >= buffer.Length) throw new ArgumentOutOfRangeException( "Offset must be a valid position in buffer" ); if ((offset + count) > buffer.Length) throw new ArgumentException( "Buffer is not large enough to complete operation" ); EnsureData( count ); for (int i=0; i < count; i++) buffer[offset+i] = this.buffer[index++]; return count; } public override void Write(byte[] buffer, int offset, int count) { srcStream.Write( buffer, offset, count ); } public override long Seek(long offset, SeekOrigin origin) { return srcStream.Seek( offset, origin ); } private void ReadBuffer( Stream s, byte[] buf, int offset, int length ) { while (length > 0) { int amountRead = s.Read( buf, offset, length ); if (amountRead == 0) throw new MySqlException("Unexpected end of data encountered"); length -= amountRead; offset += amountRead; } } private void ReadNextPacket() { // read off the uncompressed and compressed lengths int compressedLen = srcStream.ReadByte() + (srcStream.ReadByte() << 8) + (srcStream.ReadByte() << 16); byte seq = (byte)srcStream.ReadByte(); int unCompressedLen = srcStream.ReadByte() + (srcStream.ReadByte() << 8) + (srcStream.ReadByte() << 16); // if the data is in fact compressed, then uncompress it byte[] unCompressedBuffer = null; if (unCompressedLen > 0) { unCompressedBuffer = new byte[ unCompressedLen ]; InflaterInputStream iis = new InflaterInputStream( srcStream ); ReadBuffer( iis, unCompressedBuffer, 0, unCompressedLen ); } else { unCompressedBuffer = new byte[ compressedLen ]; ReadBuffer( srcStream, unCompressedBuffer, 0, compressedLen ); } // now join this buffer to our existing one int left = buffer.Length - index; byte[] newBuffer = new byte[ left + unCompressedBuffer.Length ]; int newIndex = 0; // first copy in the rest of the original for (int i=index; i < buffer.Length; i++) newBuffer[newIndex++] = buffer[i]; unCompressedBuffer.CopyTo( newBuffer, newIndex ); buffer = newBuffer; index = 0; } private void EnsureData( int size ) { while ((buffer.Length - index) < size) ReadNextPacket(); } } }