Skip to content

Commit 81cde02

Browse files
authored
Attack of the clone compressors - adding some of them (#53)
1 parent fa4700f commit 81cde02

14 files changed

+136
-65
lines changed

README.md

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,25 @@ Decompression algorithms provided:
2626
* Crm!: Crunch-Mania standard-mode, sampled
2727
* CrM2: Crunch-Mania LZH-mode
2828
* Crm2: Crunch-Mania LZH-mode, sampled
29+
* ID 0x18051973 (CrunchMania CrM2 Clone)
30+
* ID CD³¹ (CrunchMania CrM2 Clone)
31+
* ID DCS! (CrunchMania CrM! Clone)
32+
* ID Iron (CrunchMania CrM2 Clone)
33+
* ID MSS! (CrunchMania CrM2 Clone)
34+
* ID mss! (CrunchMania Crm2 Clone)
2935
* Disk Masher System a.k.a. DMS
3036
* Supports all different compression methods (NONE,SIMPLE,QUICK,MEDIUM,DEEP,HEAVY1,HEAVY2)
3137
* Supports password bypassing
32-
* File Imploder (and most of its clones)
33-
* ATN!
34-
* BDPI
35-
* CHFI
36-
* EDAM
37-
* IMP!
38-
* M.H.
39-
* RDC9
40-
* FLT! (verification missing)
41-
* Dupa (verification missing)
42-
* PARA (verification missing)
38+
* File Imploder
39+
* ID ATN! (Imploder Clone)
40+
* ID BDPI (Imploder Clone)
41+
* ID CHFI (Imploder Clone)
42+
* ID EDAM (Imploder Clone)
43+
* ID M.H. (Imploder Clone)
44+
* ID RDC9 (Imploder Clone)
45+
* ID FLT! (Imploder Clone) (verification missing)
46+
* ID Dupa (Imploder Clone) (verification missing)
47+
* ID PARA (Imploder Clone) (verification missing)
4348
* Freeze/Melt
4449
* Supports both old and new formats
4550
* gzip
@@ -52,10 +57,16 @@ Decompression algorithms provided:
5257
* PP 1.1 (verification missing)
5358
* PP 2.0
5459
* PX20: Supports bypassing password protected files.
60+
* ID CHFC (PowerPacker Clone)
61+
* ID DEN! (PowerPacker Clone)
62+
* ID DXS9 (PowerPacker Clone)
63+
* ID H.D. (PowerPacker Clone)
64+
* ID RVV! (PowerPacker Clone)
5565
* Quasijarus Strong Compression
5666
* Rob Northen compressors.
5767
* RNC1: Both old and formats utilizing the same header. heuristics for detecting the correct one
5868
* RNC2: RNC version 2 stream
69+
* ID ...1 (RNC1 Clone)
5970
* Turbo Packer by Wolfgang Mayerle.
6071
* MMCMP: Music Module Compressor
6172
* SCO Compress LZH
@@ -68,6 +79,11 @@ Decompression algorithms provided:
6879
* S401: StoneCracker v4.01
6980
* S403: StoneCracker v4.02a
7081
* S404: StoneCracker v4.10
82+
* ID 1AM (StoneCracker S300 Clone)
83+
* ID 2AM (StoneCracker S404 Clone)
84+
* ID AYS! (StoneCracker S404 Clone)
85+
* ID Z&G! (StoneCracker S403 Clone)
86+
* ID ZULU (StoneCracker S403 Clone)
7187
* XPK-encapsulated files
7288
* ACCA: Andre's Code Compression Algorithm
7389
* ARTM: Arithmetic encoding compressor

main.cpp

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -229,54 +229,43 @@ int main(int argc,char **argv)
229229
processDir(name);
230230
} else if (st.st_mode&S_IFREG) {
231231
auto packed{readFile(name)};
232-
size_t scanPos=0;
233-
size_t scanSize=packed->size();
234232
for (size_t i=0;i<packed->size();)
235233
{
236-
scanPos+=1;
237-
scanSize-=1;
238234
// We will detect first, before trying the format for real
239-
if (!ancient::Decompressor::detect(packed->data()+scanPos,scanSize))
235+
if (!ancient::Decompressor::detect(packed->data()+i,packed->size()-i))
240236
{
241237
i++;
242238
continue;
243239
}
244240
try
245241
{
246-
ancient::Decompressor decompressor{packed->data()+scanPos,scanSize,false,true};
247-
// for formats that do not encode packed size.
248-
// we will get it from decompressor
242+
ancient::Decompressor decompressor{packed->data()+i,packed->size()-i,false,true};
243+
244+
printf("trying %s\n",decompressor.getName().c_str());
249245
if (!decompressor.getPackedSize())
250246
{
251-
try
252-
{
253-
decompressor.decompress(true);
254-
} catch (const std::bad_alloc&) {
255-
fprintf(stderr,"Out of memory\n");
256-
i++;
257-
continue;
258-
}
247+
// for formats that do not encode packed size.
248+
// we will get it from decompressor
249+
decompressor.decompress(true);
259250
}
260-
if (decompressor.getPackedSize())
251+
252+
// final checks with the limited buffer and fresh decompressor
253+
const uint8_t *finalData=packed->data()+i;
254+
size_t finalSize=decompressor.getPackedSize().value();
255+
ancient::Decompressor decompressor2{finalData,finalSize,true,true};
256+
try
261257
{
262-
// final checks with the limited buffer and fresh decompressor
263-
const uint8_t *finalData=packed->data()+scanPos;
264-
size_t finalSize=decompressor.getPackedSize().value();
265-
ancient::Decompressor decompressor2{finalData,finalSize,true,true};
266-
try
267-
{
268-
decompressor2.decompress(true);
269-
} catch (const std::bad_alloc&) {
270-
fprintf(stderr,"Out of memory\n");
271-
i++;
272-
continue;
273-
}
274-
std::string outputName=std::string(argv[3])+"/file"+std::to_string(fileIndex++)+".pack";
275-
printf("Found compressed stream at %zu, size %zu in file %s with type '%s', storing it into %s\n",i,decompressor2.getPackedSize().value(),name.c_str(),decompressor2.getName().c_str(),outputName.c_str());
276-
writeFile(outputName,finalData,finalSize);
277-
i+=finalSize;
258+
decompressor2.decompress(true);
259+
} catch (const std::bad_alloc&) {
260+
fprintf(stderr,"Out of memory\n");
261+
i++;
278262
continue;
279263
}
264+
std::string outputName=std::string(argv[3])+"/file"+std::to_string(fileIndex++)+".pack";
265+
printf("Found compressed stream at %zu, size %zu in file %s with type '%s', storing it into %s\n",i,decompressor2.getPackedSize().value(),name.c_str(),decompressor2.getName().c_str(),outputName.c_str());
266+
writeFile(outputName,finalData,finalSize);
267+
i+=finalSize;
268+
continue;
280269
} catch (const ancient::Error&) {
281270
// full steam ahead (with next offset)
282271
} catch (const std::bad_alloc&) {

src/CRMDecompressor.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ bool CRMDecompressor::detectHeader(uint32_t hdr) noexcept
2424
case FourCC("Crm!"):
2525
[[fallthrough]];
2626
case FourCC("Crm2"):
27+
[[fallthrough]];
28+
case 0x1805'1973U:// Fears
29+
[[fallthrough]];
30+
case FourCC("CD\xb3\xb9"):// BiFi 2
31+
[[fallthrough]];
32+
case FourCC("DCS!"):// Sonic Attack/DualCrew-Shining
33+
[[fallthrough]];
34+
case FourCC("Iron"):// Sun / TRSI
35+
[[fallthrough]];
36+
case FourCC("MSS!"):// Infection / Mystic
37+
[[fallthrough]];
38+
case FourCC("mss!"):
2739
return true;
2840

2941
default:
@@ -53,6 +65,10 @@ CRMDecompressor::CRMDecompressor(const Buffer &packedData,uint32_t recursionLeve
5365
uint32_t hdr{packedData.readBE32(0)};
5466
if (!detectHeader(hdr) || packedData.size()<20)
5567
throw Decompressor::InvalidFormatError();
68+
if (hdr==0x1805'1973U || hdr==FourCC("CD\xb3\xb9") ||
69+
hdr==FourCC("Iron") || hdr==FourCC("MSS!")) hdr=FourCC("CrM2");
70+
if (hdr==FourCC("mss!")) hdr=FourCC("Crm2");
71+
if (hdr==FourCC("DCS!")) hdr=FourCC("CrM!");
5672

5773
_rawSize=packedData.readBE32(6);
5874
_packedSize=packedData.readBE32(10);

src/CRMDecompressor.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ class CRMDecompressor : public Decompressor, public XPKDecompressor
3434
private:
3535
const Buffer &_packedData;
3636

37-
uint32_t_packedSize=0;
38-
uint32_t_rawSize=0;
39-
bool_isLZH=false;// "normal" compression or LZH compression
40-
bool_isSampled=false;// normal or "sampled" i.e. obsfuscated
41-
bool_isXPKDelta=false;// If delta encoding defined in XPK
37+
uint32_t_packedSize{0};
38+
uint32_t_rawSize{0};
39+
bool_isLZH{false};// "normal" compression or LZH compression
40+
bool_isSampled{false};// normal or "sampled" i.e. obsfuscated
41+
bool_isXPKDelta{false};// If delta encoding defined in XPK
4242
};
4343

4444
}

src/CompactDecompressor.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ std::shared_ptr<Decompressor> CompactDecompressor::create(const Buffer &packedDa
2626
}
2727

2828
CompactDecompressor::CompactDecompressor(const Buffer &packedData,bool exactSizeKnown,bool verify) :
29-
_packedData(packedData),
30-
_exactSizeKnown(exactSizeKnown)
29+
_packedData{packedData},
30+
_exactSizeKnown{exactSizeKnown}
3131
{
3232
if (_packedData.size()<2U)
3333
throw InvalidFormatError();

src/CompressDecompressor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ std::shared_ptr<Decompressor> CompressDecompressor::create(const Buffer &packedD
2121
}
2222

2323
CompressDecompressor::CompressDecompressor(const Buffer &packedData,bool exactSizeKnown,bool verify) :
24-
_packedData(packedData)
24+
_packedData{packedData}
2525
{
2626
// Can't do anything with undefined size stream
2727
if (!exactSizeKnown)

src/Decompressor.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ static std::vector<std::pair<bool(*)(uint32_t),std::shared_ptr<Decompressor>(*)(
4646
{TPWMDecompressor::detectHeader,TPWMDecompressor::create},
4747
{XPKMain::detectHeader,XPKMain::create},
4848
// Putting StoneCracker last since detection can be accidentally be detected instead of correct format
49-
{StoneCrackerDecompressor::detectHeader,StoneCrackerDecompressor::create}};
49+
{StoneCrackerDecompressor::detectHeader,StoneCrackerDecompressor::create}
50+
};
5051

5152
std::shared_ptr<Decompressor> Decompressor::create(const Buffer &packedData,bool exactSizeKnown,bool verify)
5253
{
@@ -65,6 +66,7 @@ std::shared_ptr<Decompressor> Decompressor::create(const Buffer &packedData,bool
6566

6667
bool Decompressor::detect(const Buffer &packedData) noexcept
6768
{
69+
if (packedData.size()<2) return false;
6870
try
6971
{
7072
uint32_t hdr{(packedData.size()>=4)?packedData.readBE32(0):(uint32_t(packedData.readBE16(0))<<16)};

src/HFMNDecompressor.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ class HFMNDecompressor : public XPKDecompressor
1414
HFMNDecompressor(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify);
1515
~HFMNDecompressor() noexcept=default;
1616

17-
virtual const std::string &getSubName() const noexcept final;
17+
const std::string &getSubName() const noexcept final;
1818

19-
virtual void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) final;
19+
void decompressImpl(Buffer &rawData,const Buffer &previousData,bool verify) final;
2020

2121
static bool detectHeaderXPK(uint32_t hdr) noexcept;
2222
static std::shared_ptr<XPKDecompressor> create(uint32_t hdr,uint32_t recursionLevel,const Buffer &packedData,std::shared_ptr<XPKDecompressor::State> &state,bool verify);

src/IMPDecompressor.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,25 @@ static bool readIMPHeader(uint32_t hdr,uint32_t &addition) noexcept
1616
{
1717
switch (hdr)
1818
{
19-
case FourCC("ATN!"):
19+
case FourCC("ATN!"):// Team 17 games
2020
[[fallthrough]];
21-
case FourCC("EDAM"):
21+
case FourCC("EDAM"):// Indy Heat
2222
[[fallthrough]];
23-
case FourCC("IMP!"):
23+
case FourCC("IMP!"):// Original!!
2424
[[fallthrough]];
25-
case FourCC("M.H."):
25+
case FourCC("M.H."):// Georg Glaxo
2626
addition=7;
2727
return true;
2828

29-
case FourCC("BDPI"):
29+
case FourCC("BDPI"):// Dizzy's excellent adventures
3030
addition=0x6e8;
3131
return true;
3232

33-
case FourCC("CHFI"):
33+
case FourCC("CHFI"):// Dizzy's excellent adventures, Bubble and Squeak
3434
addition=0xfe4;
3535
return true;
3636

37-
case FourCC("RDC9"):// Files do not contain checksum
37+
case FourCC("RDC9"):// Telekommando 2 (Files do not contain checksum)
3838
[[fallthrough]];
3939
// I haven't got these files to be sure what is the addition
4040
case FourCC("Dupa"):

src/PPDecompressor.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ PPDecompressor::PPState::PPState(uint32_t mode) noexcept :
1919

2020
bool PPDecompressor::detectHeader(uint32_t hdr) noexcept
2121
{
22-
return (hdr==FourCC("PP11") || hdr==FourCC("PP20") || hdr==FourCC("PX20"));
22+
return hdr==FourCC("PP11") || hdr==FourCC("PP20") || hdr==FourCC("PX20")
23+
|| hdr==FourCC("CHFC")// Sky High Stuntman
24+
|| hdr==FourCC("DEN!")// Jewels - Crossroads
25+
|| hdr==FourCC("DXS9")// Hopp oder Top, Punkt Punkt Punkt
26+
|| hdr==FourCC("H.D.")// F1 Challenge
27+
|| hdr==FourCC("RVV!");// Hoi AGA Remix
2328
}
2429

2530
bool PPDecompressor::detectHeaderXPK(uint32_t hdr) noexcept

0 commit comments

Comments
 (0)