You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using DotNetCTFDumper.MMFParser.EXE.Loaders;
using DotNetCTFDumper.MMFParser.EXE.Loaders.Banks;
using DotNetCTFDumper.MMFParser.EXE.Loaders.Events;
using DotNetCTFDumper.Utils;
namespace DotNetCTFDumper.MMFParser.EXE
{
public class ChunkList
{
public List<Chunk> Chunks = new List<Chunk>();
public bool Verbose = false;
public List<Frame> Frames = new List<Frame>();
public void Read(ByteReader exeReader)
{
Chunks.Clear();
while (true)
{
Chunk chunk = new Chunk(Chunks.Count, this);
chunk.Verbose = Verbose;
chunk.Read(exeReader);
chunk.Loader = LoadChunk(chunk);
Chunks.Add(chunk);
if (chunk.Id == 8750) chunk.BuildKey();
if (exeReader.Tell() >= exeReader.Size()) break;
if (chunk.Id == 32639) break; //LAST chunkID
}
}
public class Chunk
{
ChunkList _chunkList;
public string Name = "UNKNOWN";
int _uid;
public int Id = 0;
public ChunkLoader Loader;
public byte[] ChunkData;
public byte[] RawData;
public ChunkFlags Flag;
public int Size = 0;
public int DecompressedSize = -1;
public bool Verbose = false;
public Chunk(int actualuid, ChunkList actualChunkList)
{
_uid = actualuid;
_chunkList = actualChunkList;
}
public ByteReader get_reader()
{
return new ByteReader(ChunkData);
}
public void Read(ByteReader exeReader)
{
Id = exeReader.ReadInt16();
Name = _chunkList.GetNameByID(Id);
Flag = (ChunkFlags) exeReader.ReadInt16();
Size = exeReader.ReadInt32();
if((Id!=26214&&Id!=26216)) //To prevent RAM from commiting suicide
{
RawData = exeReader.ReadBytes(Size);
exeReader.BaseStream.Position -= Size;
//Saving raw data cuz why not
}
switch (Flag)
{
case ChunkFlags.Encrypted:
ChunkData = Decryption.DecodeChunk(exeReader.ReadBytes(Size),Size);
break;
case ChunkFlags.CompressedAndEncrypyed:
ChunkData = Decryption.DecodeMode3(exeReader.ReadBytes(Size), Size,Id,out DecompressedSize);
break;
case ChunkFlags.Compressed:
ChunkData = Decompressor.Decompress(exeReader,out DecompressedSize);
break;
case ChunkFlags.NotCompressed:
ChunkData = exeReader.ReadBytes(Size);
break;
}
}
public void Save()
{
if (ChunkData != null)
{
string path = $"{Settings.ChunkPath}\\{Name}.chunk";
File.WriteAllBytes(path, ChunkData);
}
}
public void Print(bool extented)
{
if(extented)
{
Logger.Log($"Chunk: {Name} ({_uid})", true, ConsoleColor.DarkCyan);
Logger.Log($" ID: {Id} - 0x{Id.ToString("X")}", true, ConsoleColor.DarkCyan);
Logger.Log($" Flags: {Flag}", true, ConsoleColor.DarkCyan);
Logger.Log($" Loader: {(Loader != null ? Loader.GetType().Name : "Empty Loader")}", true,ConsoleColor.DarkCyan);
Logger.Log($" Size: {Size} B", true, ConsoleColor.DarkCyan);
Logger.Log($" Decompressed Size: {DecompressedSize} B", true, ConsoleColor.DarkCyan);
Logger.Log("---------------------------------------------", true, ConsoleColor.DarkCyan);
}
else
{
Logger.Log($"Chunk: {Name} ({_uid})", true, ConsoleColor.DarkCyan);
Logger.Log($" ID: {Id} - 0x{Id.ToString("X")}", true, ConsoleColor.DarkCyan);
Logger.Log($" Decompressed Size: {DecompressedSize} B", true, ConsoleColor.DarkCyan);
Logger.Log($" Flags: {Flag}", true, ConsoleColor.DarkCyan);
Logger.Log("---------------------------------------------", true, ConsoleColor.DarkCyan);
}
}
public void BuildKey()
{
Settings.AppName=_chunkList.GetChunk<AppName>()?.Value??"";
Settings.Copyright = _chunkList.GetChunk<Copyright>()?.Value??"";
Settings.ProjectPath = _chunkList.GetChunk<EditorFilename>()?.Value??"";
if (Exe.Instance.GameData.ProductBuild > 284)Decryption.MakeKey(Settings.AppName,Settings.Copyright,Settings.ProjectPath);
else Decryption.MakeKey(Settings.ProjectPath, Settings.AppName, Settings.Copyright);
}
}
public enum ChunkFlags
{
NotCompressed = 0,
Compressed = 1,
Encrypted = 2,
CompressedAndEncrypyed = 3
}
public ChunkLoader LoadChunk(Chunk chunk)
{
ChunkLoader loader = null;
switch (chunk.Id)
{
case 8739:
loader = new AppHeader(chunk);
break;
case 8740:
loader = new AppName(chunk);
break;
case 8741:
loader = new AppAuthor(chunk);
break;
case 8743:
loader = new ExtPath(chunk);
break;
case 8750:
loader = new EditorFilename(chunk);
break;
case 8751:
loader = new TargetFilename(chunk);
break;
case 8752:
loader = new AppDoc(chunk);
break;
case 8745:
loader = new FrameItems(chunk);
break;
case 8757:
loader = new AppIcon(chunk);
break;
case 8762:
loader = new AboutText(chunk);
break;
case 8763:
loader = new Copyright(chunk);
break;
case 13123:
loader = new DemoFilePath(chunk);
break;
case 13109:
loader = new FrameName(chunk);
break;
case 13107:
loader = new Frame(chunk);
Frames.Add((Frame)loader);
break;
case 13108:
loader = new FrameHeader(chunk);
break;
case 13111:
loader = new FramePalette(chunk);
break;
case 13112:
loader = new ObjectInstances(chunk);
break;
case 13115:
loader = new Transition(chunk);
break;
case 13116:
loader = new Transition(chunk);
break;
case 13121:
loader = new Layers(chunk);
break;
case 26214:
loader = new ImageBank(chunk);
break;
case 26216:
loader = new SoundBank(chunk);
break;
case 26217:
loader = new MusicBank(chunk);
break;
case 17477:
loader = new ObjectName(chunk);
break;
case 17476:
loader = new ObjectHeader(chunk);
break;
case 17478:
loader = new ObjectProperties(chunk);
return loader;
break;
case 8788:
//loader = new ObjectNames(chunk);
break;
case 8754:
loader = new GlobalValues(chunk);
break;
case 8755:
loader = new GlobalStrings(chunk);
break;
case 13117:
// loader = new Events(chunk);//NOT WORKING
break;
}
if (loader != null) loader.Read();
return loader;
}
public T GetChunk<T>() where T : ChunkLoader
{
foreach (Chunk chunk in Chunks)
{
if (chunk.Loader != null)
{
if (chunk.Loader.GetType().Name == typeof(T).Name)
{
return (T) chunk.Loader;
}
}
}
//Logger.Log($"ChunkLoader {typeof(T).Name} not found", true, ConsoleColor.Red);
return null;
}
public T PopChunk<T>() where T : ChunkLoader
{
for(int i=0;i<Chunks.Count;i++)
{
var chunk = Chunks[i];
if (chunk.Loader != null)
{
if (chunk.Loader.GetType().Name == typeof(T).Name)
{
Chunks.Remove(chunk);
return (T) chunk.Loader;
}
}
}
return null;
}
public string GetNameByID(int id)
{
switch (id)
{
case 4386: return "PREVIEW";
case 8738: return "Mini Header";
case 8739: return "Header";
case 8740: return "Title";
case 8741: return "Author";
case 8742: return "Menu";
case 8743: return "Extra Path";
case 8744: return "Extensions";
case 8745: return "Object Bank";
case 8746: return "Global Events";
case 8747: return "Frame Handles";
case 8748: return "Extra Data";
case 8749: return "Additional Extensions";
case 8750: return "Project Path";
case 8751: return "Output Path";
case 8752: return "App Doc";
case 8753: return "Other Extensions";
case 8754: return "Global Values";
case 8755: return "Global Strings";
case 8756: return "Extensions List";
case 8757: return "Icon";
case 8758: return "Demo Version";
case 8759: return "Security Number";
case 8760: return "Binary Files";
case 8761: return "Menu Images";
case 8762: return "About";
case 8763: return "Copyright";
case 8764: return "Global Value Names";
case 8765: return "Global String Names";
case 8766: return "Movement Extensions";
case 8767: return "Object Bank 2";
case 8768: return "EXE Only";
case 8770: return "Protection";
case 8771: return "Shaders";
case 8773: return "Extended Header";
case 13107:return "Frame";
case 13108:return "Frame Header";
case 13109:return "Frame Name";
case 13110:return "Frame Password";
case 13111:return "Frame Palette";
case 13112:return "Frame Objects";
case 13113:return "Frame Fade In Frame";
case 13114:return "Frame Fade Out Frame";
case 13115:return "Frame Fade In";
case 13116:return "Frame Fade Out";
case 13117:return "Frame Events";
case 13118:return "Frame Play Header";
case 13119:return "Additional Frame Item";
case 13120:return "Additional Object Instance";
case 13121:return "Frame Layers";
case 13122:return "Frame Virtual Rect";
case 13123:return "Demo File Path";
case 13124:return "Random Seed";
case 13125:return "Frame Layer Effects";
case 13126:return "Bluray Options";
case 13127:return "MVTimer Base";
case 13128:return "Mosaic Image Table";
case 13129:return "Frame Effects";
case 13130:return "Frame Iphone Options";
case 17476:return "Object Header";
case 17477:return "Object Name";
case 17478:return "Object Common";
case 17479:return "Object Unknown";
case 17480:return "Object Effects";
case 21845:return "Image Offsets";
case 21846:return "Font Offsets";
case 21847:return "Sound Offsets";
case 21848:return "Music Offsets";
case 26214:return "Image Bank";
case 26215:return "Font Bank";
case 26216:return "Sound Bank";
case 26217:return "Music Bank";
case 32639:return "Last";
default: return $"Unknown-{id}";
}
}
}
}