Initial commit - WPinternals 2.6

This commit is contained in:
Rene Lergner
2018-10-25 22:35:49 +02:00
commit 396ae57f05
483 changed files with 159677 additions and 0 deletions
+93
View File
@@ -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;
}
}
}
}
+144
View File
@@ -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;
}
}
}
+349
View File
@@ -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;
}
}
}
+124
View File
@@ -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;
}
}
}
+161
View File
@@ -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;
}
}
}
}
+60
View File
@@ -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);
}
}
+62
View File
@@ -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);
}
}
+109
View File
@@ -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;
}
}
}
+70
View File
@@ -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;
}
}
}
+237
View File
@@ -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");
}
}
}
}