Template
185 lines
6.6 KiB
C#
185 lines
6.6 KiB
C#
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");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|