mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-18 13:20:11 +10:00
Initial commit - WPinternals 2.6
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the Adler-32 checksum algorithm.
|
||||
/// </summary>
|
||||
public class Adler32
|
||||
{
|
||||
private uint _a;
|
||||
private uint _b;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Adler32 class.
|
||||
/// </summary>
|
||||
public Adler32()
|
||||
{
|
||||
_a = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the checksum of all data processed so far.
|
||||
/// </summary>
|
||||
public int Value
|
||||
{
|
||||
get { return (int)(_b << 16 | _a); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides data that should be checksummed.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Buffer containing the data to checksum.</param>
|
||||
/// <param name="offset">Offset of the first byte to checksum.</param>
|
||||
/// <param name="count">The number of bytes to checksum.</param>
|
||||
/// <remarks>
|
||||
/// Call this method repeatedly until all checksummed
|
||||
/// data has been processed.
|
||||
/// </remarks>
|
||||
public void Process(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if (offset < 0 || offset > buffer.Length)
|
||||
{
|
||||
throw new ArgumentException("Offset outside of array bounds", "offset");
|
||||
}
|
||||
|
||||
if (count < 0 || offset + count > buffer.Length)
|
||||
{
|
||||
throw new ArgumentException("Array index out of bounds", "count");
|
||||
}
|
||||
|
||||
int processed = 0;
|
||||
while (processed < count)
|
||||
{
|
||||
int innerEnd = Math.Min(count, processed + 2000);
|
||||
while (processed < innerEnd)
|
||||
{
|
||||
_a += buffer[processed++];
|
||||
_b += _a;
|
||||
}
|
||||
|
||||
_a %= 65521;
|
||||
_b %= 65521;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
internal class BZip2BlockDecoder
|
||||
{
|
||||
private InverseBurrowsWheeler _inverseBurrowsWheeler;
|
||||
private uint _crc;
|
||||
|
||||
public BZip2BlockDecoder(int blockSize)
|
||||
{
|
||||
_inverseBurrowsWheeler = new InverseBurrowsWheeler(blockSize);
|
||||
}
|
||||
|
||||
public uint Crc
|
||||
{
|
||||
get { return _crc; }
|
||||
}
|
||||
|
||||
public int Process(BitStream bitstream, byte[] outputBuffer, int outputBufferOffset)
|
||||
{
|
||||
_crc = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
_crc = (_crc << 8) | bitstream.Read(8);
|
||||
}
|
||||
|
||||
bool rand = bitstream.Read(1) != 0;
|
||||
int origPtr = (int)bitstream.Read(24);
|
||||
|
||||
int thisBlockSize = ReadBuffer(bitstream, outputBuffer, outputBufferOffset);
|
||||
|
||||
_inverseBurrowsWheeler.OriginalIndex = origPtr;
|
||||
_inverseBurrowsWheeler.Process(outputBuffer, outputBufferOffset, thisBlockSize, outputBuffer, outputBufferOffset);
|
||||
|
||||
if (rand)
|
||||
{
|
||||
BZip2Randomizer randomizer = new BZip2Randomizer();
|
||||
randomizer.Process(outputBuffer, outputBufferOffset, thisBlockSize, outputBuffer, outputBufferOffset);
|
||||
}
|
||||
|
||||
return thisBlockSize;
|
||||
}
|
||||
|
||||
private static int ReadBuffer(BitStream bitstream, byte[] buffer, int offset)
|
||||
{
|
||||
// The MTF state
|
||||
int numInUse = 0;
|
||||
MoveToFront moveFrontTransform = new MoveToFront();
|
||||
bool[] inUseGroups = new bool[16];
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
inUseGroups[i] = bitstream.Read(1) != 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
if (inUseGroups[i / 16])
|
||||
{
|
||||
if (bitstream.Read(1) != 0)
|
||||
{
|
||||
moveFrontTransform.Set(numInUse, (byte)i);
|
||||
numInUse++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize 'virtual' Huffman tree from bitstream
|
||||
BZip2CombinedHuffmanTrees huffmanTree = new BZip2CombinedHuffmanTrees(bitstream, numInUse + 2);
|
||||
|
||||
// Main loop reading data
|
||||
int readBytes = 0;
|
||||
while (true)
|
||||
{
|
||||
uint symbol = huffmanTree.NextSymbol();
|
||||
|
||||
if (symbol < 2)
|
||||
{
|
||||
// RLE, with length stored in a binary-style format
|
||||
uint runLength = 0;
|
||||
int bitShift = 0;
|
||||
while (symbol < 2)
|
||||
{
|
||||
runLength += (symbol + 1) << bitShift;
|
||||
bitShift++;
|
||||
|
||||
symbol = huffmanTree.NextSymbol();
|
||||
}
|
||||
|
||||
byte b = moveFrontTransform.Head;
|
||||
while (runLength > 0)
|
||||
{
|
||||
buffer[offset + readBytes] = b;
|
||||
++readBytes;
|
||||
--runLength;
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol <= numInUse)
|
||||
{
|
||||
// Single byte
|
||||
byte b = moveFrontTransform.GetAndMove((int)symbol - 1);
|
||||
buffer[offset + readBytes] = b;
|
||||
++readBytes;
|
||||
}
|
||||
else if (symbol == numInUse + 1)
|
||||
{
|
||||
// End of block marker
|
||||
return readBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException("Invalid symbol from Huffman table");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Represents scheme used by BZip2 where multiple Huffman trees are used as a
|
||||
/// virtual Huffman tree, with a logical selector every 50 bits in the bit stream.
|
||||
/// </summary>
|
||||
internal class BZip2CombinedHuffmanTrees
|
||||
{
|
||||
private BitStream _bitstream;
|
||||
private byte[] _selectors;
|
||||
private HuffmanTree[] _trees;
|
||||
|
||||
private HuffmanTree _activeTree;
|
||||
private int _symbolsToNextSelector;
|
||||
private int _nextSelector;
|
||||
|
||||
public BZip2CombinedHuffmanTrees(BitStream bitstream, int maxSymbols)
|
||||
{
|
||||
_bitstream = bitstream;
|
||||
|
||||
Initialize(maxSymbols);
|
||||
}
|
||||
|
||||
public uint NextSymbol()
|
||||
{
|
||||
if (_symbolsToNextSelector == 0)
|
||||
{
|
||||
_symbolsToNextSelector = 50;
|
||||
_activeTree = _trees[_selectors[_nextSelector]];
|
||||
_nextSelector++;
|
||||
}
|
||||
|
||||
_symbolsToNextSelector--;
|
||||
|
||||
return _activeTree.NextSymbol(_bitstream);
|
||||
}
|
||||
|
||||
private void Initialize(int maxSymbols)
|
||||
{
|
||||
int numTrees = (int)_bitstream.Read(3);
|
||||
if (numTrees < 2 || numTrees > 6)
|
||||
{
|
||||
throw new InvalidDataException("Invalid number of tables");
|
||||
}
|
||||
|
||||
int numSelectors = (int)_bitstream.Read(15);
|
||||
if (numSelectors < 1)
|
||||
{
|
||||
throw new InvalidDataException("Invalid number of selectors");
|
||||
}
|
||||
|
||||
_selectors = new byte[numSelectors];
|
||||
MoveToFront mtf = new MoveToFront(numTrees, true);
|
||||
for (int i = 0; i < numSelectors; ++i)
|
||||
{
|
||||
_selectors[i] = mtf.GetAndMove(CountSetBits(numTrees));
|
||||
}
|
||||
|
||||
_trees = new HuffmanTree[numTrees];
|
||||
for (int t = 0; t < numTrees; ++t)
|
||||
{
|
||||
uint[] lengths = new uint[maxSymbols];
|
||||
|
||||
uint len = _bitstream.Read(5);
|
||||
for (int i = 0; i < maxSymbols; ++i)
|
||||
{
|
||||
if (len < 1 || len > 20)
|
||||
{
|
||||
throw new InvalidDataException("Invalid length constructing Huffman tree");
|
||||
}
|
||||
|
||||
while (_bitstream.Read(1) != 0)
|
||||
{
|
||||
len = (_bitstream.Read(1) == 0) ? len + 1 : len - 1;
|
||||
|
||||
if (len < 1 || len > 20)
|
||||
{
|
||||
throw new InvalidDataException("Invalid length constructing Huffman tree");
|
||||
}
|
||||
}
|
||||
|
||||
lengths[i] = len;
|
||||
}
|
||||
|
||||
_trees[t] = new HuffmanTree(lengths);
|
||||
}
|
||||
|
||||
_symbolsToNextSelector = 0;
|
||||
_nextSelector = 0;
|
||||
}
|
||||
|
||||
private byte CountSetBits(int max)
|
||||
{
|
||||
byte val = 0;
|
||||
while (_bitstream.Read(1) != 0)
|
||||
{
|
||||
val++;
|
||||
if (val >= max)
|
||||
{
|
||||
throw new InvalidDataException("Exceeded max number of consecutive bits");
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of a BZip2 decoder.
|
||||
/// </summary>
|
||||
public sealed class BZip2DecoderStream : Stream
|
||||
{
|
||||
private long _position;
|
||||
private Stream _compressedStream;
|
||||
private Ownership _ownsCompressed;
|
||||
private BitStream _bitstream;
|
||||
private BZip2RleStream _rleStream;
|
||||
private BZip2BlockDecoder _blockDecoder;
|
||||
private Crc32 _calcBlockCrc;
|
||||
|
||||
private byte[] _blockBuffer;
|
||||
private uint _blockCrc;
|
||||
private uint _compoundCrc;
|
||||
private uint _calcCompoundCrc;
|
||||
|
||||
private bool _eof;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BZip2DecoderStream class.
|
||||
/// </summary>
|
||||
/// <param name="stream">The compressed input stream.</param>
|
||||
/// <param name="ownsStream">Whether ownership of stream passes to the new instance.</param>
|
||||
public BZip2DecoderStream(Stream stream, Ownership ownsStream)
|
||||
{
|
||||
_compressedStream = stream;
|
||||
_ownsCompressed = ownsStream;
|
||||
|
||||
_bitstream = new BigEndianBitStream(new BufferedStream(stream));
|
||||
|
||||
// The Magic BZh
|
||||
byte[] magic = new byte[3];
|
||||
magic[0] = (byte)_bitstream.Read(8);
|
||||
magic[1] = (byte)_bitstream.Read(8);
|
||||
magic[2] = (byte)_bitstream.Read(8);
|
||||
if (magic[0] != 0x42 || magic[1] != 0x5A || magic[2] != 0x68)
|
||||
{
|
||||
throw new InvalidDataException("Bad magic at start of stream");
|
||||
}
|
||||
|
||||
// The size of the decompression blocks in multiples of 100,000
|
||||
int blockSize = (int)_bitstream.Read(8) - 0x30;
|
||||
if (blockSize < 1 || blockSize > 9)
|
||||
{
|
||||
throw new InvalidDataException("Unexpected block size in header: " + blockSize);
|
||||
}
|
||||
|
||||
blockSize *= 100000;
|
||||
|
||||
_rleStream = new BZip2RleStream();
|
||||
_blockDecoder = new BZip2BlockDecoder(blockSize);
|
||||
_blockBuffer = new byte[blockSize];
|
||||
|
||||
if (ReadBlock() == 0)
|
||||
{
|
||||
_eof = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indication of whether read access is permitted.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indication of whether seeking is permitted.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indication of whether write access is permitted.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the stream (the capacity of the underlying buffer).
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the current position within the stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get { return _position; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes all data to the underlying storage.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a number of bytes from the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The destination buffer.</param>
|
||||
/// <param name="offset">The start offset within the destination buffer.</param>
|
||||
/// <param name="count">The number of bytes to read.</param>
|
||||
/// <returns>The number of bytes read.</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if (buffer.Length < offset + count)
|
||||
{
|
||||
throw new ArgumentException("Buffer smaller than declared");
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
throw new ArgumentException("Offset less than zero", "offset");
|
||||
}
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
throw new ArgumentException("Count less than zero", "count");
|
||||
}
|
||||
|
||||
if (_eof)
|
||||
{
|
||||
throw new IOException("Attempt to read beyond end of stream");
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numRead = _rleStream.Read(buffer, offset, count);
|
||||
if (numRead == 0)
|
||||
{
|
||||
// If there was an existing block, check it's crc.
|
||||
if (_calcBlockCrc != null)
|
||||
{
|
||||
if (_blockCrc != _calcBlockCrc.Value)
|
||||
{
|
||||
throw new InvalidDataException("Decompression failed - block CRC mismatch");
|
||||
}
|
||||
|
||||
_calcCompoundCrc = ((_calcCompoundCrc << 1) | (_calcCompoundCrc >> 31)) ^ _blockCrc;
|
||||
}
|
||||
|
||||
// Read a new block (if any), if none - check the overall CRC before returning
|
||||
if (ReadBlock() == 0)
|
||||
{
|
||||
_eof = true;
|
||||
if (_calcCompoundCrc != _compoundCrc)
|
||||
{
|
||||
throw new InvalidDataException("Decompression failed - compound CRC");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
numRead = _rleStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
_calcBlockCrc.Process(buffer, offset, numRead);
|
||||
|
||||
// Pre-read next block, so a client that knows the decompressed length will still
|
||||
// have the overall CRC calculated.
|
||||
if (_rleStream.AtEof)
|
||||
{
|
||||
// If there was an existing block, check it's crc.
|
||||
if (_calcBlockCrc != null)
|
||||
{
|
||||
if (_blockCrc != _calcBlockCrc.Value)
|
||||
{
|
||||
throw new InvalidDataException("Decompression failed - block CRC mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
_calcCompoundCrc = ((_calcCompoundCrc << 1) | (_calcCompoundCrc >> 31)) ^ _blockCrc;
|
||||
if (ReadBlock() == 0)
|
||||
{
|
||||
_eof = true;
|
||||
if (_calcCompoundCrc != _compoundCrc)
|
||||
{
|
||||
throw new InvalidDataException("Decompression failed - compound CRC mismatch");
|
||||
}
|
||||
|
||||
return numRead;
|
||||
}
|
||||
}
|
||||
|
||||
_position += numRead;
|
||||
return numRead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the current stream position.
|
||||
/// </summary>
|
||||
/// <param name="offset">The origin-relative stream position.</param>
|
||||
/// <param name="origin">The origin for the stream position.</param>
|
||||
/// <returns>The new stream position.</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of the stream (the underlying buffer's capacity).
|
||||
/// </summary>
|
||||
/// <param name="value">The new length of the stream.</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a buffer to the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to write.</param>
|
||||
/// <param name="offset">The starting offset within buffer.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases underlying resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Whether this method is called from Dispose.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_compressedStream != null && _ownsCompressed == Ownership.Dispose)
|
||||
{
|
||||
_compressedStream.Dispose();
|
||||
}
|
||||
|
||||
_compressedStream = null;
|
||||
|
||||
if (_rleStream != null)
|
||||
{
|
||||
_rleStream.Dispose();
|
||||
_rleStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadBlock()
|
||||
{
|
||||
ulong marker = ReadMarker();
|
||||
if (marker == 0x314159265359)
|
||||
{
|
||||
int blockSize = _blockDecoder.Process(_bitstream, _blockBuffer, 0);
|
||||
_rleStream.Reset(_blockBuffer, 0, blockSize);
|
||||
_blockCrc = _blockDecoder.Crc;
|
||||
_calcBlockCrc = new Crc32BigEndian(Crc32Algorithm.Common);
|
||||
return blockSize;
|
||||
}
|
||||
else if (marker == 0x177245385090)
|
||||
{
|
||||
_compoundCrc = ReadUint();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException("Found invalid marker in stream");
|
||||
}
|
||||
}
|
||||
|
||||
private uint ReadUint()
|
||||
{
|
||||
uint val = 0;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
val = (val << 8) | _bitstream.Read(8);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private ulong ReadMarker()
|
||||
{
|
||||
ulong marker = 0;
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
marker = (marker << 8) | _bitstream.Read(8);
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System;
|
||||
|
||||
internal class BZip2Randomizer : DataBlockTransform
|
||||
{
|
||||
private static readonly int[] RandomVals =
|
||||
{
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
};
|
||||
|
||||
protected override bool BuffersMustNotOverlap
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected override int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
|
||||
{
|
||||
if (input != output || inputOffset != outputOffset)
|
||||
{
|
||||
Array.Copy(input, inputOffset, output, outputOffset, inputCount);
|
||||
}
|
||||
|
||||
int randIndex = 1;
|
||||
int nextByte = RandomVals[0] - 2;
|
||||
|
||||
while (nextByte < inputCount)
|
||||
{
|
||||
output[nextByte] ^= 1;
|
||||
nextByte += RandomVals[randIndex++];
|
||||
randIndex &= 0x1FF;
|
||||
}
|
||||
|
||||
return inputCount;
|
||||
}
|
||||
|
||||
protected override int MaxOutputCount(int inputCount)
|
||||
{
|
||||
return inputCount;
|
||||
}
|
||||
|
||||
protected override int MinOutputCount(int inputCount)
|
||||
{
|
||||
return inputCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
internal class BZip2RleStream : Stream
|
||||
{
|
||||
private long _position;
|
||||
private byte[] _blockBuffer;
|
||||
private int _blockOffset;
|
||||
private int _blockRemaining;
|
||||
|
||||
private int _numSame;
|
||||
private byte _lastByte;
|
||||
private int _runBytesOutstanding;
|
||||
|
||||
public BZip2RleStream()
|
||||
{
|
||||
}
|
||||
|
||||
public bool AtEof
|
||||
{
|
||||
get { return _runBytesOutstanding == 0 && _blockRemaining == 0; }
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { return _position; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public void Reset(byte[] buffer, int offset, int count)
|
||||
{
|
||||
_position = 0;
|
||||
_blockBuffer = buffer;
|
||||
_blockOffset = offset;
|
||||
_blockRemaining = count;
|
||||
_numSame = -1;
|
||||
_lastByte = 0;
|
||||
_runBytesOutstanding = 0;
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int numRead = 0;
|
||||
|
||||
while (numRead < count && _runBytesOutstanding > 0)
|
||||
{
|
||||
int runCount = Math.Min(_runBytesOutstanding, count);
|
||||
for (int i = 0; i < runCount; ++i)
|
||||
{
|
||||
buffer[offset + numRead] = _lastByte;
|
||||
}
|
||||
|
||||
_runBytesOutstanding -= runCount;
|
||||
numRead += runCount;
|
||||
}
|
||||
|
||||
while (numRead < count && _blockRemaining > 0)
|
||||
{
|
||||
byte b = _blockBuffer[_blockOffset];
|
||||
++_blockOffset;
|
||||
--_blockRemaining;
|
||||
|
||||
if (_numSame == 4)
|
||||
{
|
||||
int runCount = Math.Min(b, count - numRead);
|
||||
for (int i = 0; i < runCount; ++i)
|
||||
{
|
||||
buffer[offset + numRead] = _lastByte;
|
||||
numRead++;
|
||||
}
|
||||
|
||||
_runBytesOutstanding = b - runCount;
|
||||
_numSame = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b != _lastByte || _numSame <= 0)
|
||||
{
|
||||
_lastByte = b;
|
||||
_numSame = 0;
|
||||
}
|
||||
|
||||
buffer[offset + numRead] = b;
|
||||
numRead++;
|
||||
_numSame++;
|
||||
}
|
||||
}
|
||||
|
||||
_position += numRead;
|
||||
return numRead;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a byte stream into a bit stream.
|
||||
/// </summary>
|
||||
internal class BigEndianBitStream : BitStream
|
||||
{
|
||||
private Stream _byteStream;
|
||||
|
||||
private uint _buffer;
|
||||
private int _bufferAvailable;
|
||||
|
||||
private byte[] _readBuffer = new byte[2];
|
||||
|
||||
public BigEndianBitStream(Stream byteStream)
|
||||
{
|
||||
_byteStream = byteStream;
|
||||
}
|
||||
|
||||
public override int MaxReadAhead
|
||||
{
|
||||
get { return 16; }
|
||||
}
|
||||
|
||||
public override uint Read(int count)
|
||||
{
|
||||
if (count > 16)
|
||||
{
|
||||
uint result = Read(16) << (count - 16);
|
||||
return result | Read(count - 16);
|
||||
}
|
||||
|
||||
EnsureBufferFilled();
|
||||
|
||||
_bufferAvailable -= count;
|
||||
|
||||
uint mask = (uint)((1 << count) - 1);
|
||||
|
||||
return (uint)((_buffer >> _bufferAvailable) & mask);
|
||||
}
|
||||
|
||||
public override uint Peek(int count)
|
||||
{
|
||||
EnsureBufferFilled();
|
||||
|
||||
uint mask = (uint)((1 << count) - 1);
|
||||
|
||||
return (uint)((_buffer >> (_bufferAvailable - count)) & mask);
|
||||
}
|
||||
|
||||
public override void Consume(int count)
|
||||
{
|
||||
EnsureBufferFilled();
|
||||
|
||||
_bufferAvailable -= count;
|
||||
}
|
||||
|
||||
private void EnsureBufferFilled()
|
||||
{
|
||||
if (_bufferAvailable < 16)
|
||||
{
|
||||
_readBuffer[0] = 0;
|
||||
_readBuffer[1] = 0;
|
||||
_byteStream.Read(_readBuffer, 0, 2);
|
||||
|
||||
_buffer = (uint)((uint)(_buffer << 16) | (uint)(_readBuffer[0] << 8) | (uint)_readBuffer[1]);
|
||||
_bufferAvailable += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for bit streams.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The rules for conversion of a byte stream to a bit stream vary
|
||||
/// between implementations.
|
||||
/// </remarks>
|
||||
internal abstract class BitStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the maximum number of bits that can be peeked on the stream.
|
||||
/// </summary>
|
||||
public abstract int MaxReadAhead { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Reads bits from the stream.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bits to read.</param>
|
||||
/// <returns>The bits as a UInt32.</returns>
|
||||
public abstract uint Read(int count);
|
||||
|
||||
/// <summary>
|
||||
/// Queries data from the stream.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bits to query.</param>
|
||||
/// <returns>The bits as a UInt32.</returns>
|
||||
/// <remarks>This method does not consume the bits (i.e. move the file pointer).</remarks>
|
||||
public abstract uint Peek(int count);
|
||||
|
||||
/// <summary>
|
||||
/// Consumes bits from the stream without returning them.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bits to consume.</param>
|
||||
public abstract void Consume(int count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for block compression algorithms.
|
||||
/// </summary>
|
||||
public abstract class BlockCompressor
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the block size parameter to the algorithm.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Some algorithms may use this to control both compression and decompression, others may
|
||||
/// only use it to control compression. Some may ignore it entirely.
|
||||
/// </remarks>
|
||||
public int BlockSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compresses some data.
|
||||
/// </summary>
|
||||
/// <param name="source">The uncompressed input.</param>
|
||||
/// <param name="sourceOffset">Offset of the input data in <c>source</c>.</param>
|
||||
/// <param name="sourceLength">The amount of uncompressed data.</param>
|
||||
/// <param name="compressed">The destination for the output compressed data.</param>
|
||||
/// <param name="compressedOffset">Offset for the output data in <c>compressed</c>.</param>
|
||||
/// <param name="compressedLength">The maximum size of the compressed data on input, and the actual size on output.</param>
|
||||
/// <returns>Indication of success, or indication the data could not compress into the requested space.</returns>
|
||||
public abstract CompressionResult Compress(byte[] source, int sourceOffset, int sourceLength, byte[] compressed, int compressedOffset, ref int compressedLength);
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses some data.
|
||||
/// </summary>
|
||||
/// <param name="source">The compressed input.</param>
|
||||
/// <param name="sourceOffset">Offset of the input data in <c>source</c>.</param>
|
||||
/// <param name="sourceLength">The amount of compressed data.</param>
|
||||
/// <param name="decompressed">The destination for the output decompressed data.</param>
|
||||
/// <param name="decompressedOffset">Offset for the output data in <c>decompressed</c>.</param>
|
||||
/// <returns>The amount of decompressed data.</returns>
|
||||
public abstract int Decompress(byte[] source, int sourceOffset, int sourceLength, byte[] decompressed, int decompressedOffset);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Possible results of attempting to compress data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A compression routine <i>may</i> return <c>Compressed</c>, even if the data
|
||||
/// was 'all zeros' or increased in size. The <c>AllZeros</c> and <c>Incompressible</c>
|
||||
/// values are for algorithms that include special detection for these cases.
|
||||
/// </remarks>
|
||||
public enum CompressionResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The data compressed succesfully.
|
||||
/// </summary>
|
||||
Compressed,
|
||||
|
||||
/// <summary>
|
||||
/// The data was all-zero's.
|
||||
/// </summary>
|
||||
AllZeros,
|
||||
|
||||
/// <summary>
|
||||
/// The data was incompressible (could not fit into destination buffer).
|
||||
/// </summary>
|
||||
Incompressible
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
internal abstract class DataBlockTransform
|
||||
{
|
||||
protected abstract bool BuffersMustNotOverlap { get; }
|
||||
|
||||
public int Process(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
|
||||
{
|
||||
if (output.Length < outputOffset + (long)MinOutputCount(inputCount))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Output buffer to small, must be at least {0} bytes may need to be {1} bytes",
|
||||
MinOutputCount(inputCount),
|
||||
MaxOutputCount(inputCount)));
|
||||
}
|
||||
|
||||
if (BuffersMustNotOverlap)
|
||||
{
|
||||
int maxOut = MaxOutputCount(inputCount);
|
||||
|
||||
if (input == output
|
||||
&& (inputOffset + (long)inputCount > outputOffset)
|
||||
&& (inputOffset <= outputOffset + (long)maxOut))
|
||||
{
|
||||
byte[] tempBuffer = new byte[maxOut];
|
||||
|
||||
int outCount = DoProcess(input, inputOffset, inputCount, tempBuffer, 0);
|
||||
Array.Copy(tempBuffer, 0, output, outputOffset, outCount);
|
||||
|
||||
return outCount;
|
||||
}
|
||||
}
|
||||
|
||||
return DoProcess(input, inputOffset, inputCount, output, outputOffset);
|
||||
}
|
||||
|
||||
protected abstract int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset);
|
||||
|
||||
protected abstract int MaxOutputCount(int inputCount);
|
||||
|
||||
protected abstract int MinOutputCount(int inputCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// A canonical Huffman tree implementation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A lookup table is created that will take any bit sequence (max tree depth in length),
|
||||
/// indicating the output symbol. In WIM files, in practice, no chunk exceeds 32768 bytes
|
||||
/// in length, so we often end up generating a bigger lookup table than the data it's
|
||||
/// encoding. This makes for exceptionally fast symbol lookups O(1), but is inefficient
|
||||
/// overall.
|
||||
/// </remarks>
|
||||
internal sealed class HuffmanTree
|
||||
{
|
||||
private int _numBits; // Max bits per symbol
|
||||
private int _numSymbols; // Max symbols
|
||||
private uint[] _lengths;
|
||||
private uint[] _buffer;
|
||||
|
||||
public HuffmanTree(uint[] lengths)
|
||||
{
|
||||
_lengths = lengths;
|
||||
_numSymbols = lengths.Length;
|
||||
|
||||
uint maxLength = 0;
|
||||
for (int i = 0; i < _lengths.Length; ++i)
|
||||
{
|
||||
if (_lengths[i] > maxLength)
|
||||
{
|
||||
maxLength = _lengths[i];
|
||||
}
|
||||
}
|
||||
|
||||
_numBits = (int)maxLength;
|
||||
_buffer = new uint[1 << _numBits];
|
||||
|
||||
Build();
|
||||
}
|
||||
|
||||
public uint[] Lengths
|
||||
{
|
||||
get
|
||||
{
|
||||
return _lengths;
|
||||
}
|
||||
}
|
||||
|
||||
public uint NextSymbol(BitStream bitStream)
|
||||
{
|
||||
uint symbol = _buffer[bitStream.Peek(_numBits)];
|
||||
|
||||
// We may have over-read, reset bitstream position
|
||||
bitStream.Consume((int)_lengths[symbol]);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
private void Build()
|
||||
{
|
||||
int position = 0;
|
||||
|
||||
// For each bit-length...
|
||||
for (int i = 1; i <= _numBits; ++i)
|
||||
{
|
||||
// Check each symbol
|
||||
for (uint symbol = 0; symbol < _numSymbols; ++symbol)
|
||||
{
|
||||
if (_lengths[symbol] == i)
|
||||
{
|
||||
int numToFill = 1 << (_numBits - i);
|
||||
for (int n = 0; n < numToFill; ++n)
|
||||
{
|
||||
_buffer[position + n] = symbol;
|
||||
}
|
||||
|
||||
position += numToFill;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = position; i < _buffer.Length; ++i)
|
||||
{
|
||||
_buffer[i] = uint.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System;
|
||||
|
||||
internal sealed class InverseBurrowsWheeler : DataBlockTransform
|
||||
{
|
||||
private int[] _pointers;
|
||||
private int[] _nextPos;
|
||||
|
||||
public InverseBurrowsWheeler(int bufferSize)
|
||||
{
|
||||
_pointers = new int[bufferSize];
|
||||
_nextPos = new int[256];
|
||||
}
|
||||
|
||||
public int OriginalIndex { get; set; }
|
||||
|
||||
protected override bool BuffersMustNotOverlap
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected override int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
|
||||
{
|
||||
int outputCount = inputCount;
|
||||
|
||||
// First find the frequency of each value
|
||||
Array.Clear(_nextPos, 0, _nextPos.Length);
|
||||
for (int i = inputOffset; i < inputOffset + inputCount; ++i)
|
||||
{
|
||||
_nextPos[input[i]]++;
|
||||
}
|
||||
|
||||
// We know they're 'sorted' in the first column, so now can figure
|
||||
// out the position of the first instance of each.
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int tempSum = sum;
|
||||
sum += _nextPos[i];
|
||||
_nextPos[i] = tempSum;
|
||||
}
|
||||
|
||||
// For each value in the final column, put a pointer to to the
|
||||
// 'next' character in the first (sorted) column.
|
||||
for (int i = 0; i < inputCount; ++i)
|
||||
{
|
||||
_pointers[_nextPos[input[inputOffset + i]]++] = i;
|
||||
}
|
||||
|
||||
// The 'next' character after the end of the original string is the
|
||||
// first character of the original string.
|
||||
int focus = _pointers[OriginalIndex];
|
||||
|
||||
// We can now just walk the pointers to reconstruct the original string
|
||||
for (int i = 0; i < outputCount; ++i)
|
||||
{
|
||||
output[outputOffset + i] = input[inputOffset + focus];
|
||||
focus = _pointers[focus];
|
||||
}
|
||||
|
||||
return outputCount;
|
||||
}
|
||||
|
||||
protected override int MaxOutputCount(int inputCount)
|
||||
{
|
||||
return inputCount;
|
||||
}
|
||||
|
||||
protected override int MinOutputCount(int inputCount)
|
||||
{
|
||||
return inputCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
internal class MoveToFront
|
||||
{
|
||||
private byte[] _buffer;
|
||||
|
||||
public MoveToFront()
|
||||
: this(256, false)
|
||||
{
|
||||
}
|
||||
|
||||
public MoveToFront(int size, bool autoInit)
|
||||
{
|
||||
_buffer = new byte[size];
|
||||
|
||||
if (autoInit)
|
||||
{
|
||||
for (byte i = 0; i < size; ++i)
|
||||
{
|
||||
_buffer[i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte Head
|
||||
{
|
||||
get { return _buffer[0]; }
|
||||
}
|
||||
|
||||
public void Set(int pos, byte val)
|
||||
{
|
||||
_buffer[pos] = val;
|
||||
}
|
||||
|
||||
public byte GetAndMove(int pos)
|
||||
{
|
||||
byte val = _buffer[pos];
|
||||
|
||||
for (int i = pos; i > 0; --i)
|
||||
{
|
||||
_buffer[i] = _buffer[i - 1];
|
||||
}
|
||||
|
||||
_buffer[0] = val;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
//
|
||||
// Copyright (c) 2008-2011, Kenneth Bell
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the Zlib compression algorithm.
|
||||
/// </summary>
|
||||
/// <remarks>Only decompression is currently implemented.</remarks>
|
||||
public class ZlibStream : Stream
|
||||
{
|
||||
private Stream _stream;
|
||||
private CompressionMode _mode;
|
||||
private DeflateStream _deflateStream;
|
||||
private Adler32 _adler32;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ZlibStream class.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to compress of decompress.</param>
|
||||
/// <param name="mode">Whether to compress or decompress.</param>
|
||||
/// <param name="leaveOpen">Whether closing this stream should leave <c>stream</c> open.</param>
|
||||
public ZlibStream(Stream stream, CompressionMode mode, bool leaveOpen)
|
||||
{
|
||||
_stream = stream;
|
||||
_mode = mode;
|
||||
|
||||
if (mode == CompressionMode.Decompress)
|
||||
{
|
||||
// We just sanity check against expected header values...
|
||||
byte[] headerBuffer = Utilities.ReadFully(stream, 2);
|
||||
ushort header = Utilities.ToUInt16BigEndian(headerBuffer, 0);
|
||||
|
||||
if ((header % 31) != 0)
|
||||
{
|
||||
throw new IOException("Invalid Zlib header found");
|
||||
}
|
||||
|
||||
if ((header & 0x0F00) != (8 << 8))
|
||||
{
|
||||
throw new NotSupportedException("Zlib compression not using DEFLATE algorithm");
|
||||
}
|
||||
|
||||
if ((header & 0x0020) != 0)
|
||||
{
|
||||
throw new NotSupportedException("Zlib compression using preset dictionary");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ushort header =
|
||||
(8 << 8) // DEFLATE
|
||||
| (7 << 12) // 32K window size
|
||||
| 0x80; // Default algorithm
|
||||
header |= (ushort)(31 - (header % 31));
|
||||
|
||||
byte[] headerBuffer = new byte[2];
|
||||
Utilities.WriteBytesBigEndian(header, headerBuffer, 0);
|
||||
stream.Write(headerBuffer, 0, 2);
|
||||
}
|
||||
|
||||
_deflateStream = new DeflateStream(stream, mode, leaveOpen);
|
||||
_adler32 = new Adler32();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the stream can be read.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return _deflateStream.CanRead; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the stream pointer can be changed.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the stream can be written to.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return _deflateStream.CanWrite; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the stream.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the stream position.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the stream.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
if (_mode == CompressionMode.Decompress)
|
||||
{
|
||||
// Can only check Adler checksum on seekable streams. Since DeflateStream
|
||||
// aggresively caches input, it normally has already consumed the footer.
|
||||
if (_stream.CanSeek)
|
||||
{
|
||||
_stream.Seek(-4, SeekOrigin.End);
|
||||
byte[] footerBuffer = Utilities.ReadFully(_stream, 4);
|
||||
if (Utilities.ToInt32BigEndian(footerBuffer, 0) != _adler32.Value)
|
||||
{
|
||||
throw new InvalidDataException("Corrupt decompressed data detected");
|
||||
}
|
||||
}
|
||||
|
||||
_deflateStream.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
_deflateStream.Close();
|
||||
|
||||
byte[] footerBuffer = new byte[4];
|
||||
Utilities.WriteBytesBigEndian(_adler32.Value, footerBuffer, 0);
|
||||
_stream.Write(footerBuffer, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
_deflateStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to populate.</param>
|
||||
/// <param name="offset">The first byte to write.</param>
|
||||
/// <param name="count">The number of bytes requested.</param>
|
||||
/// <returns>The number of bytes read.</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
CheckParams(buffer, offset, count);
|
||||
|
||||
int numRead = _deflateStream.Read(buffer, offset, count);
|
||||
_adler32.Process(buffer, offset, numRead);
|
||||
return numRead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seeks to a new position.
|
||||
/// </summary>
|
||||
/// <param name="offset">Relative position to seek to.</param>
|
||||
/// <param name="origin">The origin of the seek.</param>
|
||||
/// <returns>The new position.</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the length of the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The new desired length of the stream.</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Buffer containing the data to write.</param>
|
||||
/// <param name="offset">Offset of the first byte to write.</param>
|
||||
/// <param name="count">Number of bytes to write.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
CheckParams(buffer, offset, count);
|
||||
|
||||
_adler32.Process(buffer, offset, count);
|
||||
_deflateStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
private static void CheckParams(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if (offset < 0 || offset > buffer.Length)
|
||||
{
|
||||
throw new ArgumentException("Offset outside of array bounds", "offset");
|
||||
}
|
||||
|
||||
if (count < 0 || offset + count > buffer.Length)
|
||||
{
|
||||
throw new ArgumentException("Array index out of bounds", "count");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user