Skip to content

Commit

Permalink
PMC support (#74)
Browse files Browse the repository at this point in the history
* PMC support
  • Loading branch information
temisu authored Jun 30, 2024
1 parent bae7c94 commit f5a679b
Show file tree
Hide file tree
Showing 15 changed files with 157 additions and 30 deletions.
6 changes: 4 additions & 2 deletions Ancient.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@
<ClCompile Include="src\ILZRDecompressor.cpp" />
<ClCompile Include="src\IMPDecompressor.cpp" />
<ClCompile Include="src\InputStream.cpp" />
<ClCompile Include="src\LHLBDecompressor.cpp" />
<ClCompile Include="src\LHDecompressor.cpp" />
<ClCompile Include="src\LIN1Decompressor.cpp" />
<ClCompile Include="src\LIN2Decompressor.cpp" />
<ClCompile Include="src\LOBDecompressor.cpp" />
Expand All @@ -248,6 +248,7 @@
<ClCompile Include="src\NUKEDecompressor.cpp" />
<ClCompile Include="src\OutputStream.cpp" />
<ClCompile Include="src\PackDecompressor.cpp" />
<ClCompile Include="src\PMCDecompressor.cpp" />
<ClCompile Include="src\PPDecompressor.cpp" />
<ClCompile Include="src\PPMQDecompressor.cpp" />
<ClCompile Include="src\RAKEDecompressor.cpp" />
Expand Down Expand Up @@ -309,7 +310,7 @@
<ClInclude Include="src\ILZRDecompressor.hpp" />
<ClInclude Include="src\IMPDecompressor.hpp" />
<ClInclude Include="src\InputStream.hpp" />
<ClInclude Include="src\LHLBDecompressor.hpp" />
<ClInclude Include="src\LHDecompressor.hpp" />
<ClInclude Include="src\LIN1Decompressor.hpp" />
<ClInclude Include="src\LIN2Decompressor.hpp" />
<ClInclude Include="src\LOBDecompressor.hpp" />
Expand All @@ -326,6 +327,7 @@
<ClInclude Include="src\NUKEDecompressor.hpp" />
<ClInclude Include="src\OutputStream.hpp" />
<ClInclude Include="src\PackDecompressor.hpp" />
<ClInclude Include="src\PMCDecompressor.hpp" />
<ClInclude Include="src\PPDecompressor.hpp" />
<ClInclude Include="src\PPMQDecompressor.hpp" />
<ClInclude Include="src\RAKEDecompressor.hpp" />
Expand Down
6 changes: 4 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ LIBANCIENT_FILES_SRC += src/IMPDecompressor.cpp
LIBANCIENT_FILES_SRC += src/IMPDecompressor.hpp
LIBANCIENT_FILES_SRC += src/InputStream.cpp
LIBANCIENT_FILES_SRC += src/InputStream.hpp
LIBANCIENT_FILES_SRC += src/LHLBDecompressor.cpp
LIBANCIENT_FILES_SRC += src/LHLBDecompressor.hpp
LIBANCIENT_FILES_SRC += src/LHDecompressor.cpp
LIBANCIENT_FILES_SRC += src/LHDecompressor.hpp
LIBANCIENT_FILES_SRC += src/LIN1Decompressor.cpp
LIBANCIENT_FILES_SRC += src/LIN1Decompressor.hpp
LIBANCIENT_FILES_SRC += src/LIN2Decompressor.cpp
Expand Down Expand Up @@ -118,6 +118,8 @@ LIBANCIENT_FILES_SRC += src/OutputStream.cpp
LIBANCIENT_FILES_SRC += src/OutputStream.hpp
LIBANCIENT_FILES_SRC += src/PackDecompressor.cpp
LIBANCIENT_FILES_SRC += src/PackDecompressor.hpp
LIBANCIENT_FILES_SRC += src/PMCDecompressor.cpp
LIBANCIENT_FILES_SRC += src/PMCDecompressor.hpp
LIBANCIENT_FILES_SRC += src/PPDecompressor.cpp
LIBANCIENT_FILES_SRC += src/PPDecompressor.hpp
LIBANCIENT_FILES_SRC += src/PPMQDecompressor.cpp
Expand Down
12 changes: 6 additions & 6 deletions Makefile.unix
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ OBJS_N = API.o Buffer.o Common.o MemoryBuffer.o StaticBuffer.o SubBuffer.o Wrapp
CYB2Decoder.o DEFLATEDecompressor.o DLTADecode.o DMSDecompressor.o \
FASTDecompressor.o FBR2Decompressor.o FreezeDecompressor.o FRLEDecompressor.o \
HFMNDecompressor.o HUFFDecompressor.o IceDecompressor.o ILZRDecompressor.o \
IMPDecompressor.o LHLBDecompressor.o LIN1Decompressor.o LIN2Decompressor.o \
IMPDecompressor.o LHDecompressor.o LIN1Decompressor.o LIN2Decompressor.o \
LOBDecompressor.o LZBSDecompressor.o LZCBDecompressor.o LZW2Decompressor.o \
LZW4Decompressor.o LZW5Decompressor.o LZXDecompressor.o MASHDecompressor.o \
MMCMPDecompressor.o NONEDecompressor.o NUKEDecompressor.o PackDecompressor.o \
PPDecompressor.o PPMQDecompressor.o RAKEDecompressor.o RDCNDecompressor.o \
RLENDecompressor.o RNCDecompressor.o SCOCompressDecompressor.o SDHCDecompressor.o \
SHRXDecompressor.o SLZ3Decompressor.o SMPLDecompressor.o StoneCrackerDecompressor.o \
SQSHDecompressor.o SXSCDecompressor.o TDCSDecompressor.o TPWMDecompressor.o \
VicXDecompressor.o XPKUnimplemented.o ZENODecompressor.o
PMCDecompressor.o PPDecompressor.o PPMQDecompressor.o RAKEDecompressor.o \
RDCNDecompressor.o RLENDecompressor.o RNCDecompressor.o SCOCompressDecompressor.o \
SDHCDecompressor.o SHRXDecompressor.o SLZ3Decompressor.o SMPLDecompressor.o \
StoneCrackerDecompressor.o SQSHDecompressor.o SXSCDecompressor.o TDCSDecompressor.o \
TPWMDecompressor.o VicXDecompressor.o XPKUnimplemented.o ZENODecompressor.o
TEST_N = test.o
TESTBIN = obj/test

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ Decompression algorithms provided:
* ID DXS9 (PowerPacker Clone)
* ID H.D. (PowerPacker Clone)
* ID RVV! (PowerPacker Clone)
* PowerPlayer Music Compressor (PMC)
* Supports both 1.x and 2.x versions
* Quasijarus Strong Compression
* Rob Northen compressors.
* RNC1: Supports both new and old format of RNC1
Expand Down
2 changes: 2 additions & 0 deletions src/Decompressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "LOBDecompressor.hpp"
#include "MMCMPDecompressor.hpp"
#include "PackDecompressor.hpp"
#include "PMCDecompressor.hpp"
#include "PPDecompressor.hpp"
#include "RNCDecompressor.hpp"
#include "SCOCompressDecompressor.hpp"
Expand All @@ -43,6 +44,7 @@ static std::vector<std::pair<bool(*)(uint32_t,uint32_t),std::shared_ptr<Decompre
{LOBDecompressor::detectHeader,LOBDecompressor::create},
{MMCMPDecompressor::detectHeader,MMCMPDecompressor::create},
{PackDecompressor::detectHeader,PackDecompressor::create},
{PMCDecompressor::detectHeader,PMCDecompressor::create},
{PPDecompressor::detectHeader,PPDecompressor::create},
{RNCDecompressor::detectHeader,RNCDecompressor::create},
{SCOCompressDecompressor::detectHeader,SCOCompressDecompressor::create},
Expand Down
4 changes: 2 additions & 2 deletions src/IceDecompressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ IceDecompressor::IceDecompressor(const Buffer &packedData,bool exactSizeKnown,bo

const std::string &IceDecompressor::getName() const noexcept
{
static std::string names[4]={
static std::string names[3]={
{"Ice: Pack-Ice v1.1 - v1.14"},
{"Ice: Pack-Ice v2.0 - v2.20"},
{"ICE: Pack-Ice v2.31+"}};
return names[static_cast<uint32_t>(_ver)];
return names[_ver];
}

size_t IceDecompressor::getPackedSize() const noexcept
Expand Down
27 changes: 16 additions & 11 deletions src/LHLBDecompressor.cpp → src/LHDecompressor.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Copyright (C) Teemu Suutari */

#include "LHLBDecompressor.hpp"
#include "LHDecompressor.hpp"

#include "InputStream.hpp"
#include "OutputStream.hpp"
Expand All @@ -11,48 +11,49 @@
namespace ancient::internal
{

bool LHLBDecompressor::detectHeaderXPK(uint32_t hdr) noexcept
bool LHDecompressor::detectHeaderXPK(uint32_t hdr) noexcept
{
return hdr==FourCC("LHLB");
}

std::shared_ptr<XPKDecompressor> LHLBDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify)
std::shared_ptr<XPKDecompressor> LHDecompressor::create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify)
{
return std::make_shared<LHLBDecompressor>(hdr,recursionLevel,packedData,state,verify);
return std::make_shared<LHDecompressor>(hdr,recursionLevel,packedData,state,verify);
}

LHLBDecompressor::LHLBDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify) :
LHDecompressor::LHDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify) :
XPKDecompressor{recursionLevel},
_packedData{packedData}
{
if (!detectHeaderXPK(hdr))
throw Decompressor::InvalidFormatError();
}

const std::string &LHLBDecompressor::getSubName() const noexcept
const std::string &LHDecompressor::getSubName() const noexcept
{
static std::string name{"XPK-LHLB: LZRW-compressor"};
return name;
}

void LHLBDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify)
// lh.library decompress
void LHDecompressor::decompressLhLib(Buffer &rawData,const Buffer &packedData)
{
ForwardInputStream inputStream{_packedData,0,_packedData.size()};
ForwardInputStream inputStream{packedData,0,packedData.size()};
MSBBitReader<ForwardInputStream> bitReader{inputStream};
auto readBits=[&](uint32_t count)->uint32_t
{
return bitReader.readBits8(count);
return bitReader.readBitsBE16(count);
};
auto readBit=[&]()->uint32_t
{
return bitReader.readBits8(1U);
return bitReader.readBitsBE16(1U);
};

ForwardOutputStream outputStream(rawData,0,rawData.size());

// Same logic as in Choloks pascal implementation
// Differences to LH1:
// - LHLB does not halve probabilities at 32k
// - LH does not halve probabilities at 32k
// - 314 vs. 317 sized huffman entry
// - no end code
// - different distance/count logic
Expand All @@ -77,5 +78,9 @@ void LHLBDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData
}
}
}
void LHDecompressor::decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify)
{
decompressLhLib(rawData,_packedData);
}

}
12 changes: 7 additions & 5 deletions src/LHLBDecompressor.hpp → src/LHDecompressor.hpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/* Copyright (C) Teemu Suutari */

#ifndef LHLBDECOMPRESSOR_HPP
#define LHLBDECOMPRESSOR_HPP
#ifndef LHDECOMPRESSOR_HPP
#define LHDECOMPRESSOR_HPP

#include "XPKDecompressor.hpp"

namespace ancient::internal
{

class LHLBDecompressor : public XPKDecompressor
class LHDecompressor : public XPKDecompressor
{
public:
LHLBDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify);
~LHLBDecompressor() noexcept=default;
LHDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify);
~LHDecompressor() noexcept=default;

const std::string &getSubName() const noexcept final;

Expand All @@ -21,6 +21,8 @@ class LHLBDecompressor : public XPKDecompressor
static bool detectHeaderXPK(uint32_t hdr) noexcept;
static std::shared_ptr<XPKDecompressor> create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify);

static void decompressLhLib(Buffer &rawData,const Buffer &packedData);

private:
const Buffer &_packedData;
};
Expand Down
70 changes: 70 additions & 0 deletions src/PMCDecompressor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/* Copyright (C) Teemu Suutari */

#include "PMCDecompressor.hpp"
#include "InputStream.hpp"
#include "OutputStream.hpp"
#include "DynamicHuffmanDecoder.hpp"
#include "VariableLengthCodeDecoder.hpp"
#include "common/Common.hpp"
#include "common/OverflowCheck.hpp"
#include "common/SubBuffer.hpp"
#include "LHDecompressor.hpp"
#include "DLTADecode.hpp"

namespace ancient::internal
{

bool PMCDecompressor::detectHeader(uint32_t hdr,uint32_t footer) noexcept
{
return (hdr==FourCC("SFHD"))||(hdr==FourCC("SFCD"));
}

std::shared_ptr<Decompressor> PMCDecompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify)
{
return std::make_shared<PMCDecompressor>(packedData,verify);
}

PMCDecompressor::PMCDecompressor(const Buffer &packedData,bool verify) :
_packedData{packedData}
{
uint32_t hdr{packedData.readBE32(0)};
if (!detectHeader(hdr,0) || packedData.size()<12)
throw InvalidFormatError();
_ver=(hdr==FourCC("SFHD"))?0:1;

_rawSize=packedData.readBE32(4U);
if (!_rawSize || _rawSize>getMaxRawSize())
throw InvalidFormatError();
_packedSize= OverflowCheck::sum(packedData.readBE32(8U),12U);
if (!_packedSize || _packedSize>packedData.size() || _packedSize>getMaxPackedSize())
throw InvalidFormatError();
}

const std::string &PMCDecompressor::getName() const noexcept
{
static std::string names[2]={
{"PMC: PowerPlayer Music Compressor 1.x"},
{"PMC: PowerPlayer Music Compressor 2.x"}};
return names[_ver];
}

size_t PMCDecompressor::getPackedSize() const noexcept
{
return _packedSize;
}

size_t PMCDecompressor::getRawSize() const noexcept
{
return _rawSize;
}

void PMCDecompressor::decompressImpl(Buffer &rawData,bool verify)
{
// thats all folks!
ConstSubBuffer subPackedData(_packedData,12,_packedSize-12);

LHDecompressor::decompressLhLib(rawData,subPackedData);
if (_ver) DLTADecode::decode(rawData,rawData,0,_rawSize);
}

}
36 changes: 36 additions & 0 deletions src/PMCDecompressor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* Copyright (C) Teemu Suutari */

#ifndef PMCDECOMPRESSOR_HPP
#define PMCDECOMPRESSOR_HPP

#include "Decompressor.hpp"

namespace ancient::internal
{

class PMCDecompressor : public Decompressor
{
public:
PMCDecompressor(const Buffer &packedData,bool verify);
~PMCDecompressor() noexcept=default;

const std::string &getName() const noexcept final;
size_t getPackedSize() const noexcept final;
size_t getRawSize() const noexcept final;

void decompressImpl(Buffer &rawData,bool verify) final;

static bool detectHeader(uint32_t hdr,uint32_t footer) noexcept;
static std::shared_ptr<Decompressor> create(const Buffer &packedData,bool exactSizeKnown,bool verify);

private:
const Buffer &_packedData;

uint32_t _rawSize{0};
size_t _packedSize{0};
uint32_t _ver;
};

}

#endif
4 changes: 2 additions & 2 deletions src/XPKMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include "HUFFDecompressor.hpp"
#include "ILZRDecompressor.hpp"
#include "IMPDecompressor.hpp"
#include "LHLBDecompressor.hpp"
#include "LHDecompressor.hpp"
#include "LIN1Decompressor.hpp"
#include "LIN2Decompressor.hpp"
#include "LZBSDecompressor.hpp"
Expand Down Expand Up @@ -85,7 +85,7 @@ static std::vector<std::pair<bool(*)(uint32_t),std::shared_ptr<XPKDecompressor>(
{HUFFDecompressor::detectHeaderXPK,HUFFDecompressor::create},
{ILZRDecompressor::detectHeaderXPK,ILZRDecompressor::create},
{IMPDecompressor::detectHeaderXPK,IMPDecompressor::create},
{LHLBDecompressor::detectHeaderXPK,LHLBDecompressor::create},
{LHDecompressor::detectHeaderXPK,LHDecompressor::create},
{LIN1Decompressor::detectHeaderXPK,LIN1Decompressor::create},
{LIN2Decompressor::detectHeaderXPK,LIN2Decompressor::create},
{LZBSDecompressor::detectHeaderXPK,LZBSDecompressor::create},
Expand Down
2 changes: 2 additions & 0 deletions testing/full_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ for a in $TEST_V/tsm_files/*.pack ; do $BIN verify $a $(echo $a | sed s/\\.pack/
for a in $TEST_V/tsm_files2/*.pack ; do $BIN verify $a $(echo $a | sed s/\\.pack/\\.raw/) || exit 1 ; done
for a in $TEST_V/she_files/*.pack ; do $BIN verify $a $(echo $a | sed s/\\.pack/\\.raw/) || exit 1 ; done

for a in $TEST_V/pmc_files/*.pmc ; do $BIN verify $a $(echo $a | sed s/\\.pmc/\\.raw/) || exit 1 ; done

for a in $TEST_V/pp_files/*.pp ; do $BIN verify $a $(echo $a | sed s/\\.pp/\\.raw/) || exit 1 ; done
for a in $TEST_V/pp_files2/*.pp ; do $BIN verify $a $(echo $a | sed s/\\.pp/\\.raw/) || exit 1 ; done
for a in $TEST_V/pp_files3/*.pp ; do $BIN verify $a $(echo $a | sed s/\\.pp/\\.raw/) || exit 1 ; done
Expand Down
4 changes: 4 additions & 0 deletions testing/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ int main(int argc,char **argv)
verifyFile(BASE_DIR "test_C1.ice_tmm",BASE_DIR "test_C1.raw");
verifyFile(BASE_DIR "test_C1.ice_tsm",BASE_DIR "test_C1.raw");

// PMC
verifyFile(BASE_DIR "test_C2.pmc1",BASE_DIR "test_C2.xm",true);
verifyFile(BASE_DIR "test_C2.pmc2",BASE_DIR "test_C2.xm",true);

// Powerpacker
verifyFile(BASE_DIR "test_C1.pp",BASE_DIR "test_C1.raw");
verifyFile(BASE_DIR "test_C1_px20.pp",BASE_DIR "test_C1.raw");
Expand Down
Binary file added testing/test_files/test_C2.pmc1
Binary file not shown.
Binary file added testing/test_files/test_C2.pmc2
Binary file not shown.

0 comments on commit f5a679b

Please sign in to comment.