mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
141 lines
No EOL
4.8 KiB
C#
141 lines
No EOL
4.8 KiB
C#
//
|
|
// 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.
|
|
//
|
|
|
|
using System.IO;
|
|
|
|
namespace DiscUtils.Compression
|
|
{
|
|
internal class BZip2BlockDecoder
|
|
{
|
|
private readonly InverseBurrowsWheeler _inverseBurrowsWheeler;
|
|
|
|
public BZip2BlockDecoder(int blockSize)
|
|
{
|
|
_inverseBurrowsWheeler = new InverseBurrowsWheeler(blockSize);
|
|
}
|
|
|
|
public uint Crc { get; private set; }
|
|
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |