Template
*
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Packer{
|
||||
class Program{
|
||||
|
||||
static readonly List<Extensions> extensions = new List<Extensions>(
|
||||
new Extensions[] {
|
||||
new Extensions { Source = ".mmm", Destination = ".mad" },
|
||||
new Extensions { Source = ".mtm", Destination = ".mtd" },
|
||||
new Extensions { Source = ".pmm", Destination = ".pmg" },
|
||||
new Extensions { Source = ".pom", Destination = ".pog" },
|
||||
new Extensions { Source = ".ptm", Destination = ".ptg" }
|
||||
});
|
||||
|
||||
|
||||
static byte[] Decompress(byte[] source) {
|
||||
int offset = 0;
|
||||
|
||||
List<byte> outBuffer = new List<byte>();
|
||||
|
||||
|
||||
|
||||
while (source[offset] != 0) {
|
||||
byte blockType = source[offset];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
while (source[offset] != 0) {
|
||||
byte blockType = source[offset];
|
||||
|
||||
if (blockType < 0x40) {
|
||||
outBuffer.AddRange(source.AsSpan(offset + 1, blockType).ToArray());
|
||||
offset += 1 + blockType;
|
||||
} else if (blockType < 0x50) {
|
||||
var count = (blockType - 0x40) + 3;
|
||||
|
||||
byte v0 = outBuffer[outBuffer.Count - 2];
|
||||
byte v1 = outBuffer[outBuffer.Count - 1];
|
||||
|
||||
//byte v0 = source[offset - 2];
|
||||
//byte v1 = source[offset - 1];
|
||||
|
||||
v0 = (byte)(v1 - v0);
|
||||
do {
|
||||
v1 += v0;
|
||||
outBuffer.Add(v1);
|
||||
--count;
|
||||
}
|
||||
while (count != 0);
|
||||
|
||||
offset += 1;
|
||||
|
||||
} else if (blockType < 0x60) {
|
||||
var count = (blockType - 0x50) + 2;
|
||||
|
||||
short v0 = (short)(outBuffer[outBuffer.Count - 4] | ((short)outBuffer[outBuffer.Count - 3] << 8));
|
||||
short v1 = (short)(outBuffer[outBuffer.Count - 2] | ((short)outBuffer[outBuffer.Count - 1] << 8));
|
||||
|
||||
//short v0 = (short)(source[offset - 4] | ((short)source[offset - 3] << 8));
|
||||
//short v1 = (short)(source[offset - 2] | ((short)source[offset - 1] << 8));
|
||||
|
||||
v0 = (short)(v1 - v0);
|
||||
do {
|
||||
v1 += v0;
|
||||
outBuffer.Add((byte)(v1 & 0xff));
|
||||
outBuffer.Add((byte)((v1 >> 8) & 0xff));
|
||||
--count;
|
||||
}
|
||||
while (count != 0);
|
||||
|
||||
offset += 1;
|
||||
} else if (blockType < 0x70) { //Copy last written byte (base 3)
|
||||
var b = outBuffer[outBuffer.Count - 1];
|
||||
var copyCount = (blockType - 0x60) + 3;
|
||||
for (int i = 0; i < copyCount; ++i) {
|
||||
outBuffer.Add(b);
|
||||
}
|
||||
offset += 1;
|
||||
} else if (blockType < 0x80) {
|
||||
var b0 = outBuffer[outBuffer.Count - 2];
|
||||
var b1 = outBuffer[outBuffer.Count - 1];
|
||||
|
||||
var copyCount = (blockType - 0x70) + 2;
|
||||
for (int i = 0; i < copyCount; ++i) {
|
||||
outBuffer.Add(b0);
|
||||
outBuffer.Add(b1);
|
||||
}
|
||||
offset += 1;
|
||||
} else if (blockType < 0xC0) { //Copy 3 bytes
|
||||
var backOffset = (blockType - 0x80) + 3;
|
||||
var readOffset = (outBuffer.Count) - backOffset;
|
||||
outBuffer.Add(outBuffer[readOffset + 0]);
|
||||
outBuffer.Add(outBuffer[readOffset + 1]);
|
||||
outBuffer.Add(outBuffer[readOffset + 2]);
|
||||
offset += 1;
|
||||
} else if (blockType < 0xE0) {
|
||||
|
||||
var copyCount = ((blockType - 0xC0) >> 2) + 4;
|
||||
var backOffset = ((blockType - 0xC0) & 3) << 8;
|
||||
|
||||
backOffset += (source[offset + 1] + 3);
|
||||
|
||||
var readStart = (outBuffer.Count) - backOffset;
|
||||
|
||||
|
||||
var block = outBuffer.ToArray().AsSpan(readStart, Math.Min(copyCount, backOffset));
|
||||
|
||||
for(int i = 0; i < copyCount; ++i) {
|
||||
outBuffer.Add(block[i % block.Length]);
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
} else {
|
||||
var backOffset = ((blockType - 0xE0) * 256) + (source[offset + 1] + 3);
|
||||
var bytesCount = source[offset + 2] + 5;
|
||||
var readStart = (outBuffer.Count) - backOffset;
|
||||
for (int i = 0; i < bytesCount; ++i) {
|
||||
outBuffer.Add(outBuffer[readStart + (i % backOffset)]);
|
||||
}
|
||||
offset += 3;
|
||||
}
|
||||
}
|
||||
return outBuffer.ToArray();
|
||||
}
|
||||
|
||||
static void DecompressFile(string input, string output) {
|
||||
var bytes = File.ReadAllBytes(input);
|
||||
var decompressed = Decompress(bytes);
|
||||
File.WriteAllBytes(output, decompressed);
|
||||
}
|
||||
|
||||
struct Extensions {
|
||||
public string Source;
|
||||
public string Destination;
|
||||
}
|
||||
|
||||
static void DecompressDirectory(string directory) {
|
||||
var files = Directory.GetFiles(directory);
|
||||
files = files.Where(v => extensions.Any( g=> g.Source == Path.GetExtension(v).ToLower())).ToArray();
|
||||
|
||||
foreach(var file in files) {
|
||||
var referenceFilePath = Path.GetDirectoryName(file);
|
||||
referenceFilePath = Path.Combine(referenceFilePath, "Decompressed",
|
||||
Path.GetFileNameWithoutExtension(file) + extensions.First(v => v.Source == Path.GetExtension(file).ToLower()).Destination);
|
||||
|
||||
if (!File.Exists(referenceFilePath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var compressedData = File.ReadAllBytes(file);
|
||||
var referenceData = File.ReadAllBytes(referenceFilePath);
|
||||
|
||||
var decompressedData = Decompress(compressedData);
|
||||
|
||||
|
||||
|
||||
var equal = decompressedData.SequenceEqual(referenceData);
|
||||
if (!equal) {
|
||||
throw new Exception("Invalid bytes :(");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
static void Main(string[] args) {
|
||||
string input = @"C:\Users\l-pro\Downloads\!HOW\COLD1.PMM";
|
||||
string output = @"C:\Users\l-pro\Downloads\!HOW\COLD1.PMM_UNK";
|
||||
|
||||
DecompressFile(input, output);
|
||||
|
||||
DecompressDirectory(@"C:\Users\l-pro\Downloads\!HOW\Test");
|
||||
|
||||
Console.WriteLine("Done");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user