public void TestDullahanPsb() { var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); //var path = Path.Combine(resPath, "e-mote38_KRKR-pure.psb"); //var path = Path.Combine(resPath, "HD愛子a_春服.psb"); //var path2 = Path.Combine(resPath, "HD愛子a_春服-pure.psb"); //var path = Path.Combine(resPath, "akira_guide.psb"); //var path2 = Path.Combine(resPath, "akira_guide-pure.psb"); //var path = Path.Combine(resPath, "dx_真闇_裸_impure.psb"); //var path2 = Path.Combine(resPath, "dx_真闇_裸-pure.psb"); //var path = Path.Combine(resPath, "emote396-win.psb"); //var path2 = Path.Combine(resPath, "emote396-win.pure.psb"); var path = Path.Combine(resPath, "ca01_l_body_1.psz.psb"); var path2 = Path.Combine(resPath, "ca01_l_body_1-pure.psb"); var psb = PSB.DullahanLoad(new FileStream(path, FileMode.Open), 64); var p2 = new PsbFile(path2); var offset1 = psb.Header.OffsetChunkData; var offset2 = p2.Header.OffsetChunkData; Assert.AreEqual(offset1, offset2); var obj = psb.Objects.First(); //if (psb.Platform == PsbSpec.krkr) //{ // psb.SwitchSpec(PsbSpec.win); //} //psb.Merge(); //var r = psb.Resources[0].Data.Length; //File.WriteAllBytes("Dullahan.psb", psb.Build()); }
public void TestEncode() { //Debug.WriteLine(Environment.CurrentDirectory); uint targetKey = 504890837; //give your model key var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); foreach (var file in Directory.EnumerateFiles(resPath)) { if (!file.ToLowerInvariant().EndsWith(".psb")) { continue; } var fileName = Path.GetFileNameWithoutExtension(file).Split(new[] { '-' }, 2); //rename your file as key-name.psb if (fileName.Length < 2) { continue; } var key = UInt32.Parse(fileName[0]); if (key != targetKey) { continue; } PsbFile psb = new PsbFile(file); psb.EncodeToFile(targetKey, file + ".pure", EncodeMode.Encrypt, EncodePosition.Auto); } }
public GbaVcExtractor(string dumpPath, PsbFile psbFile) { string gbaDictionaryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, GBA_DICTIONARY_CSV_PATH); gbaDictionary = new RomNameDictionary(gbaDictionaryPath); this.psbFile = psbFile; }
/// <summary> /// Initializes a new instance of the <see cref="GbaVcExtractor"/> class. /// </summary> /// <param name="psbFile">PSB file to parse.</param> /// <param name="verbose">whether to provide verbose output.</param> public GbaVcExtractor(PsbFile psbFile, bool verbose = false) { this.verbose = verbose; string gbaDictionaryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, GbaDictionaryCsvPath); this.gbaDictionary = new RomNameDictionary(gbaDictionaryPath); this.psbFile = psbFile; }
/// <summary> /// Compile Json to PSB /// </summary> /// <param name="inputJson">Json text</param> /// <param name="inputResJson">Resource Json text</param> /// <param name="baseDir">If resource Json uses relative paths (usually it does), specify the base dir</param> /// <param name="version">PSB version</param> /// <param name="cryptKey">CryptKey, if you need to use it outside FreeMote</param> /// <param name="spec">PSB Platform</param> /// <returns></returns> public static byte[] Compile(string inputJson, string inputResJson, string baseDir = null, ushort?version = null, uint?cryptKey = null, PsbSpec?spec = null) { //Parse PSB psb = Parse(inputJson, version ?? 3); //Link if (!string.IsNullOrWhiteSpace(inputResJson)) { if (inputResJson.Trim().StartsWith("{")) //resx.json { PsbResourceJson resx = JsonConvert.DeserializeObject <PsbResourceJson>(inputResJson); if (resx.PsbType != null) { psb.Type = resx.PsbType.Value; } if (resx.PsbVersion != null && version == null) { psb.Header.Version = resx.PsbVersion.Value; } if (resx.Platform != null && spec == null) { spec = resx.Platform; } if (resx.CryptKey != null & cryptKey == null) { cryptKey = resx.CryptKey; } if (resx.ExternalTextures) { Console.WriteLine("[INFO] External Texture mode ON, no resource will be compiled."); } else { psb.Link(resx, baseDir); } } else { List <string> resources = JsonConvert.DeserializeObject <List <string> >(inputResJson); psb.Link(resources, baseDir); } } //Build psb.Merge(); if (spec != null && spec != psb.Platform) { psb.SwitchSpec(spec.Value, spec.Value.DefaultPixelFormat()); psb.Merge(); } var bytes = psb.Build(); //Convert return(cryptKey != null?PsbFile.EncodeToBytes(cryptKey.Value, bytes, EncodeMode.Encrypt, EncodePosition.Auto) : bytes); }
static bool Convert(uint?key, string path) { if (!key.HasValue) { Console.WriteLine("Key not valid."); return(false); } if (!File.Exists(path)) { Console.WriteLine($"File:{path} not exists."); return(false); } try { PsbFile psb = new PsbFile(path); if (psb.Version > 2) { if (psb.TestHeaderEncrypted()) //Decrypt { psb.EncodeToFile(key.Value, path + ".decrypted", EncodeMode.Decrypt); } else { psb.EncodeToFile(key.Value, path + ".encrypted", EncodeMode.Encrypt); } } else { if (psb.TestBodyEncrypted()) //Decrypt { psb.EncodeToFile(key.Value, path + ".decrypted", EncodeMode.Decrypt); } else { psb.EncodeToFile(key.Value, path + ".encrypted", EncodeMode.Encrypt); } } } catch (Exception e) { Console.WriteLine("Error: This file is not valid."); Console.WriteLine(e); return(false); } return(true); }
/// <summary> /// Save as pure MDF /// </summary> /// <param name="psb"></param> /// <param name="key"></param> /// <returns></returns> public static byte[] SaveAsMdf(this PSB psb, uint?key = null) { psb.Merge(); var bytes = psb.Build(); Adler32 adler = new Adler32(); uint checksum = 0; if (key == null) { adler.Update(bytes); checksum = (uint)adler.Checksum; } MemoryStream ms = new MemoryStream(bytes); using (MemoryStream fs = new MemoryStream()) { if (key != null) { MemoryStream nms = new MemoryStream((int)ms.Length); PsbFile.Encode(key.Value, EncodeMode.Encrypt, EncodePosition.Auto, ms, nms); ms.Dispose(); ms = nms; var pos = ms.Position; adler.Update(ms); checksum = (uint)adler.Checksum; ms.Position = pos; } BinaryWriter bw = new BinaryWriter(fs); bw.WriteStringZeroTrim(MdfFile.Signature); bw.Write((uint)ms.Length); //bw.Write(ZlibCompress.Compress(ms)); ZlibCompress.CompressToBinaryWriter(bw, ms); bw.WriteBE(checksum); ms.Dispose(); bw.Flush(); return(fs.ToArray()); } }
/// <summary> /// Save PSB as MDF file /// </summary> /// <param name="psb"></param> /// <param name="path"></param> /// <param name="key"></param> public static void SaveAsMdfFile(this PSB psb, string path, uint?key = null) { psb.Merge(); var bytes = psb.Build(); Adler32 checksumer = new Adler32(); uint checksum = 0; if (key == null) { checksumer.Update(bytes); checksum = (uint)checksumer.Checksum; } MemoryStream ms = new MemoryStream(bytes); using (Stream fs = new FileStream(path, FileMode.Create)) { if (key != null) { MemoryStream nms = new MemoryStream((int)ms.Length); PsbFile.Encode(key.Value, EncodeMode.Encrypt, EncodePosition.Auto, ms, nms); ms.Dispose(); ms = nms; var pos = ms.Position; checksumer.Update(ms); checksum = (uint)checksumer.Checksum; ms.Position = pos; } BinaryWriter bw = new BinaryWriter(fs); bw.WriteStringZeroTrim(MdfFile.Signature); bw.Write((uint)ms.Length); bw.Write(ZlibCompress.Compress(ms)); bw.WriteBE(checksum); ms.Dispose(); bw.Flush(); } }
/// <summary> /// Decompile Pure PSB as Json /// </summary> /// <param name="path"></param> /// <param name="psb"></param> /// <param name="context"></param> /// <param name="psbType"></param> /// <returns></returns> public static string Decompile(string path, out PSB psb, Dictionary <string, object> context = null, PsbType psbType = PsbType.PSB) { using var fs = File.OpenRead(path); var ctx = FreeMount.CreateContext(context); string type = null; Stream stream = fs; using var ms = ctx.OpenFromShell(fs, ref type); if (ms != null) { ctx.Context[Consts.Context_PsbShellType] = type; fs.Dispose(); stream = ms; } try { psb = new PSB(stream, false); } catch (PsbBadFormatException e) when(e.Reason == PsbBadFormatReason.Header || e.Reason == PsbBadFormatReason.Array || e.Reason == PsbBadFormatReason.Body) //maybe encrypted { stream.Position = 0; uint?key = null; if (ctx.Context.ContainsKey(Consts.Context_CryptKey)) { key = ctx.Context[Consts.Context_CryptKey] as uint?; } else { key = ctx.GetKey(stream); } stream.Position = 0; if (key != null) //try use key { try { using (var mms = new MemoryStream((int)stream.Length)) { PsbFile.Encode(key.Value, EncodeMode.Decrypt, EncodePosition.Auto, stream, mms); stream.Dispose(); psb = new PSB(mms); ctx.Context[Consts.Context_CryptKey] = key; } } catch { throw e; } } else //key = null { if (e.Reason == PsbBadFormatReason.Header || e.Reason == PsbBadFormatReason.Array) //now try Dullahan loading { psb = PSB.DullahanLoad(stream); } else { throw; } } } if (psbType != PsbType.PSB) { psb.Type = psbType; } return(Decompile(psb)); }
/// <summary> /// Compile Json to PSB /// </summary> /// <param name="inputJson">Json text</param> /// <param name="inputResJson">Resource Json text</param> /// <param name="baseDir">If resource Json uses relative paths (usually it does), specify the base dir</param> /// <param name="version">PSB version</param> /// <param name="cryptKey">CryptKey, use null for pure PSB</param> /// <param name="spec">PSB Platform</param> /// <param name="keepShell">If true, try to compress PSB to shell type (MDF/LZ4 etc.) specified in resx.json; otherwise just output PSB</param> /// <returns></returns> public static byte[] Compile(string inputJson, string inputResJson, string baseDir = null, ushort?version = null, uint?cryptKey = null, PsbSpec?spec = null, bool keepShell = true) { var context = FreeMount.CreateContext(); //Parse PSB psb = Parse(inputJson, version ?? 3); //Link if (!string.IsNullOrWhiteSpace(inputResJson)) { if (inputResJson.Trim().StartsWith("{")) //resx.json { PsbResourceJson resx = JsonConvert.DeserializeObject <PsbResourceJson>(inputResJson); if (resx.PsbType != null) { psb.Type = resx.PsbType.Value; } if (resx.PsbVersion != null && version == null) { psb.Header.Version = resx.PsbVersion.Value; } if (resx.Platform != null && spec == null) { spec = resx.Platform; } if (resx.CryptKey != null & cryptKey == null) { cryptKey = resx.CryptKey; } context = FreeMount.CreateContext(resx.Context); if (resx.HasExtraResources) { PsbResHelper.LinkExtraResources(psb, context, resx.ExtraResources, resx.ExtraFlattenArrays, baseDir); } if (resx.ExternalTextures) { #if DEBUG Console.WriteLine("[INFO] External Texture mode ON, no resource will be compiled."); #endif } else { psb.Link(resx, baseDir); } } else { List <string> resources = JsonConvert.DeserializeObject <List <string> >(inputResJson); psb.Link(resources, baseDir); } } //Build psb.Merge(); if (spec != null && spec != psb.Platform) { psb.SwitchSpec(spec.Value, spec.Value.DefaultPixelFormat()); psb.Merge(); } var bytes = psb.Build(); //Convert if (cryptKey != null) { bytes = PsbFile.EncodeToBytes(cryptKey.Value, bytes, EncodeMode.Encrypt, EncodePosition.Auto); } if (context.HasShell && keepShell) { using var outStream = context.PackToShell(new MemoryStream(bytes)); bytes = outStream.ToArray(); } return(bytes); }
static bool Convert(uint?key, string path) { if (!File.Exists(path)) { Console.WriteLine($"File:{path} not exists."); return(false); } try { using (var fs = new FileStream(path, FileMode.Open)) { Stream stream = fs; string type = null; var ms = FreeMount.CreateContext().OpenFromShell(fs, ref type); bool hasShell = false; if (ms != null) { Console.WriteLine($"Shell type: {type}"); stream = ms; hasShell = true; } BinaryReader br = new BinaryReader(stream, Encoding.UTF8); if (!key.HasValue) { var k = FreeMount.CreateContext().GetKey(stream); if (k != null) { key = k; Console.WriteLine($"Using key: {key}"); } else if (hasShell) { File.WriteAllBytes(Path.ChangeExtension(path, ".decompressed.psb"), ms.ToArray()); return(true); } else { Console.WriteLine("No Key and No Shell."); return(false); } } var header = PsbHeader.Load(br); using (var outMs = new MemoryStream((int)stream.Length)) { if (header.Version > 2) { if (PsbFile.TestHeaderEncrypted(stream, header)) //Decrypt { //psb.EncodeToFile(key.Value, path + ".decrypted", EncodeMode.Decrypt); PsbFile.Encode(key.Value, EncodeMode.Decrypt, EncodePosition.Auto, stream, outMs); File.WriteAllBytes(Path.ChangeExtension(path, ".pure.psb"), outMs.ToArray()); } else { //psb.EncodeToFile(key.Value, path + ".encrypted", EncodeMode.Encrypt); PsbFile.Encode(key.Value, EncodeMode.Encrypt, EncodePosition.Auto, stream, outMs); File.WriteAllBytes(Path.ChangeExtension(path, ".encrypted.psb"), outMs.ToArray()); } } else { if (PsbFile.TestBodyEncrypted(br, header)) //Decrypt { PsbFile.Encode(key.Value, EncodeMode.Decrypt, EncodePosition.Auto, stream, outMs); File.WriteAllBytes(Path.ChangeExtension(path, ".pure.psb"), outMs.ToArray()); } else { PsbFile.Encode(key.Value, EncodeMode.Encrypt, EncodePosition.Auto, stream, outMs); File.WriteAllBytes(Path.ChangeExtension(path, ".encrypted.psb"), outMs.ToArray()); } } } } } catch (Exception e) { Console.WriteLine("Error: This file is not valid."); Console.WriteLine(e); return(false); } return(true); }
static void Main(string[] args) { Console.WriteLine("FreeMote PSB Converter"); Console.WriteLine("by Ulysses, [email protected]"); FreeMount.Init(); Console.WriteLine($"{FreeMount.PluginsCount} Plugins Loaded."); Console.WriteLine(); var app = new CommandLineApplication(); app.OptionsComparison = StringComparison.OrdinalIgnoreCase; //help app.HelpOption(); app.ExtendedHelpText = PrintHelp(); //options var optKey = app.Option <uint>("-k|--key <KEY>", "PSB key (uint, dec)", CommandOptionType.SingleValue); var optNewKey = app.Option <uint>("-nk|--new-key <KEY>", "New PSB key for transfer (uint, dec)", CommandOptionType.SingleValue); //args var argPath = app.Argument("Files", "File paths", multipleValues: true); //command: pack app.Command("pack", packCmd => { //help packCmd.Description = "Pack/Unpack PSBs to/from shell (FreeMote.Plugins required)"; packCmd.HelpOption(); packCmd.ExtendedHelpText = @" Example: EmtConvert pack -s LZ4 sample.psb "; //options var optType = packCmd.Option("-s|--shell <SHELL>", "Set shell type. No need to specify if unpack", CommandOptionType.SingleValue); //args var argPsbPaths = packCmd.Argument("PSB", "MDF/PSB Paths", true); packCmd.OnExecute(() => { string type = optType.HasValue() ? optType.Value() : null; foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { ShellConvert(s, type); } } }); }); //command: print app.Command("print", printCmd => { //help printCmd.Description = "Print an EMT PSB (for its initial state, don't expect it working)"; printCmd.HelpOption(); printCmd.ExtendedHelpText = @" Example: EmtConvert print -w 4096 -h 4096 sample.psb "; //options var optWidth = printCmd.Option <int>("-w|--width <INT>", "Set width. Default=-1 (auto)", CommandOptionType.SingleValue); var optHeight = printCmd.Option <int>("-h|--height <INT>", "Set height. Default=-1 (auto)", CommandOptionType.SingleValue); //args var argPsbPaths = printCmd.Argument("PSB", "MDF/PSB Paths", true); printCmd.OnExecute(() => { int width = optWidth.HasValue() ? optWidth.ParsedValue : -1; int height = optHeight.HasValue() ? optHeight.ParsedValue : -1; foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { Draw(s, width, height); } } }); }); //mdf app.Command("mdf", mdfCmd => { //help mdfCmd.Description = "Pack/Unpack MT19937 encrypted MDF (FreeMote.Plugins required)"; mdfCmd.HelpOption(); mdfCmd.ExtendedHelpText = @" Example: EmtConvert mdf -k 1234567890ab -l 131 sample.psb EmtConvert mdf -s 1234567890absample.psb -l 131 sample.psb Hint: To pack a normal MDF, use `EmtConvert pack -s MDF <MDF file>` "; //options //var optMdfPack = mdfCmd.Option("-p|--pack", // "Pack (Encrypt) a PSB to MT19937 MDF", // CommandOptionType.NoValue); var optMdfSeed = mdfCmd.Option("-s|--seed <SEED>", "Set complete seed (Key+FileName)", CommandOptionType.SingleValue); var optMdfKey = mdfCmd.Option("-k|--key <KEY>", "Set key (Infer file name from path)", CommandOptionType.SingleValue); var optMdfKeyLen = mdfCmd.Option <uint>("-l|--length <LEN>", "Set key length (not required if decrypt all bytes)", CommandOptionType.SingleValue); //args var argPsbPaths = mdfCmd.Argument("PSB", "PSB Paths", true); mdfCmd.OnExecute(() => { string key = optMdfKey.HasValue() ? optMdfKey.Value() : null; string seed = optMdfSeed.HasValue() ? optMdfSeed.Value() : null; if (string.IsNullOrEmpty(key) && string.IsNullOrEmpty(seed)) { throw new ArgumentNullException(nameof(key), "No key or seed specified."); } uint?keyLen = optMdfKeyLen.HasValue() ? optMdfKeyLen.ParsedValue : (uint?)null; Dictionary <string, object> context = new Dictionary <string, object>(); if (keyLen.HasValue) { context["MdfKeyLength"] = keyLen; } foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { var fileName = Path.GetFileName(s); string finalSeed = seed; if (key != null) { finalSeed = key + fileName; } context["MdfKey"] = finalSeed; ShellConvert(s, "MDF", context); } } }); }); app.OnExecute(() => { uint?key = optKey.HasValue() ? optKey.ParsedValue : (uint?)null; uint?newKey = optNewKey.HasValue() ? optNewKey.ParsedValue : (uint?)null; foreach (var s in argPath.Values) { if (File.Exists(s)) { if (key != null && newKey != null) //Transfer { File.WriteAllBytes(Path.ChangeExtension(s, ".converted.psb"), PsbFile.Transfer(key.Value, newKey.Value, File.ReadAllBytes(s))); } else { Convert(key, s); } } } }); if (args.Length == 0) { app.ShowHelp(); Console.WriteLine("Convert all PSBs in current directory:"); AskForKey(); AskForNewKey(); DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory); uint count = 0; foreach (var file in di.EnumerateFiles("*.psb")) { if (NewKey != null) { try { File.WriteAllBytes(Path.ChangeExtension(file.FullName, ".converted.psb"), PsbFile.Transfer(Key.Value, NewKey.Value, File.ReadAllBytes(file.FullName))); count++; } catch (Exception e) { Console.WriteLine("Error: This file is not valid."); Console.WriteLine(e); } } else { if (Convert(Key, file.FullName)) { count++; } } } Console.WriteLine($"Completed! {count} files processed in total."); Console.WriteLine("Press ENTER to exit..."); Console.ReadLine(); return; } app.Execute(args); Console.WriteLine("Done."); }
static void Main(string[] args) { Console.WriteLine("FreeMote PSB Converter"); Console.WriteLine("by Ulysses, [email protected]"); FreeMount.Init(); Console.WriteLine($"{FreeMount.PluginsCount} Plugins Loaded."); Console.WriteLine(); var app = new CommandLineApplication(); app.OptionsComparison = StringComparison.OrdinalIgnoreCase; //help app.HelpOption(); app.ExtendedHelpText = PrintHelp(); //options var optKey = app.Option <uint>("-k|--key <KEY>", "PSB key (uint, dec)", CommandOptionType.SingleValue); var optNewKey = app.Option <uint>("-nk|--new-key <KEY>", "New PSB key for transfer (uint, dec)", CommandOptionType.SingleValue); //args var argPath = app.Argument("Files", "File paths", multipleValues: true); //command: pixel app.Command("pixel", pixelCmd => { //help pixelCmd.Description = "Convert pixel colors of extracted images (RGBA BMP/PNG)"; pixelCmd.HelpOption(); pixelCmd.ExtendedHelpText = @" Example: EmtConvert pixel -m Switch02 sample.png "; //options var optMethod = pixelCmd.Option <PsbImageConvertMethod>("-m|--method <METHOD>", "Set convert method", CommandOptionType.SingleValue); //args var argPaths = pixelCmd.Argument("Image", "Image Paths", true); pixelCmd.OnExecute(() => { if (!optMethod.HasValue()) { Console.WriteLine("Convert Method is not specified!"); return; } foreach (var path in argPaths.Values) { if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { continue; } int width = 0; int height = 0; PixelFormat pixelFormat = PixelFormat.Format32bppArgb; try { var img = Image.FromFile(path); width = img.Width; height = img.Height; pixelFormat = img.PixelFormat; } catch (Exception e) { Console.WriteLine(e); continue; } var bts = RL.GetPixelBytesFromImageFile(path); switch (optMethod.ParsedValue) { case PsbImageConvertMethod.Switch02: RL.Switch_0_2(ref bts); break; case PsbImageConvertMethod.ROR: RL.Rgba2Argb(ref bts); break; case PsbImageConvertMethod.ROL: RL.Rgba2Argb(ref bts, true); break; case PsbImageConvertMethod.RGBA428: bts = RL.Rgba428(bts); break; case PsbImageConvertMethod.RGBA2L8Grayscale: bts = RL.Rgba2L8(bts); bts = RL.ReadL8(bts, height, width); break; case PsbImageConvertMethod.Untile: bts = PostProcessing.UntileTexture(bts, width, height, pixelFormat); break; case PsbImageConvertMethod.Unswizzle: bts = PostProcessing.UnswizzleTexture(bts, width, height, pixelFormat); break; case PsbImageConvertMethod.Tile: bts = PostProcessing.TileTexture(bts, width, height, pixelFormat); break; case PsbImageConvertMethod.Swizzle: bts = PostProcessing.SwizzleTexture(bts, width, height, pixelFormat); break; default: continue; } RL.ConvertToImageFile(bts, Path.ChangeExtension(path, ".converted.png"), height, width, PsbImageFormat.png); } }); }); //command: pack app.Command("pack", packCmd => { //help packCmd.Description = "Pack/Unpack PSBs to/from shell (FreeMote.Plugins required)"; packCmd.HelpOption(); packCmd.ExtendedHelpText = @" Example: EmtConvert pack -s LZ4 sample.psb "; //options var optType = packCmd.Option("-s|--shell <SHELL>", "Set shell type. No need to specify if unpack", CommandOptionType.SingleValue); //args var argPsbPaths = packCmd.Argument("PSB", "MDF/PSB Paths", true); packCmd.OnExecute(() => { string type = optType.HasValue() ? optType.Value() : null; foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { ShellConvert(s, type); } } }); }); //command: print app.Command("print", printCmd => { //help printCmd.Description = "Print an EMT PSB (for its initial state, don't expect it working)"; printCmd.HelpOption(); printCmd.ExtendedHelpText = @" Example: EmtConvert print -w 4096 -h 4096 sample.psb "; //options var optWidth = printCmd.Option <int>("-w|--width <INT>", "Set width. Default=-1 (auto)", CommandOptionType.SingleValue); var optHeight = printCmd.Option <int>("-h|--height <INT>", "Set height. Default=-1 (auto)", CommandOptionType.SingleValue); //args var argPsbPaths = printCmd.Argument("PSB", "MDF/PSB Paths", true); printCmd.OnExecute(() => { int width = optWidth.HasValue() ? optWidth.ParsedValue : -1; int height = optHeight.HasValue() ? optHeight.ParsedValue : -1; foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { Draw(s, width, height); } } }); }); //mdf app.Command("mdf", mdfCmd => { //help mdfCmd.Description = "Pack/Unpack MT19937 encrypted MDF (FreeMote.Plugins required)"; mdfCmd.HelpOption(); mdfCmd.ExtendedHelpText = @" Example: EmtConvert mdf -k 1234567890ab -l 131 sample.psb EmtConvert mdf -s 1234567890absample.psb -l 131 sample.psb Hint: To pack a pure MDF, use `EmtConvert pack -s MDF <MDF file>` "; //options //var optMdfPack = mdfCmd.Option("-p|--pack", // "Pack (Encrypt) a PSB to MT19937 MDF", // CommandOptionType.NoValue); var optMdfSeed = mdfCmd.Option("-s|--seed <SEED>", "Set complete seed (Key+FileName)", CommandOptionType.SingleValue); var optMdfKey = mdfCmd.Option("-k|--key <KEY>", "Set key (Infer file name from path)", CommandOptionType.SingleValue); var optMdfKeyLen = mdfCmd.Option <uint>("-l|--length <LEN>", "Set key length (not required if decrypt all bytes)", CommandOptionType.SingleValue); //args var argPsbPaths = mdfCmd.Argument("PSB", "PSB Paths", true); mdfCmd.OnExecute(() => { string key = optMdfKey.HasValue() ? optMdfKey.Value() : null; string seed = optMdfSeed.HasValue() ? optMdfSeed.Value() : null; if (string.IsNullOrEmpty(key) && string.IsNullOrEmpty(seed)) { //throw new ArgumentNullException(nameof(key), "No key or seed specified."); Console.WriteLine("No key or seed specified. Packing to pure MDF."); foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { ShellConvert(s, "MDF"); } } return; } Dictionary <string, object> context = new Dictionary <string, object>(); uint?keyLen = optMdfKeyLen.HasValue() ? optMdfKeyLen.ParsedValue : (uint?)null; if (keyLen.HasValue) { context[Context_MdfKeyLength] = keyLen; } foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { var fileName = Path.GetFileName(s); string finalSeed = seed; if (key != null) { finalSeed = key + fileName; } context[Context_MdfKey] = finalSeed; ShellConvert(s, "MDF", context); } } }); }); app.OnExecute(() => { uint?key = optKey.HasValue() ? optKey.ParsedValue : (uint?)null; uint?newKey = optNewKey.HasValue() ? optNewKey.ParsedValue : (uint?)null; foreach (var s in argPath.Values) { if (File.Exists(s)) { if (key != null && newKey != null) //Transfer { File.WriteAllBytes(Path.ChangeExtension(s, ".converted.psb"), PsbFile.Transfer(key.Value, newKey.Value, File.ReadAllBytes(s))); } else { Convert(key, s); } } } }); if (args.Length == 0) { app.ShowHelp(); Console.WriteLine("Convert all PSBs in current directory:"); AskForKey(); AskForNewKey(); DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory); uint count = 0; foreach (var file in di.EnumerateFiles("*.psb")) { if (NewKey != null) { try { File.WriteAllBytes(Path.ChangeExtension(file.FullName, ".converted.psb"), PsbFile.Transfer(Key.Value, NewKey.Value, File.ReadAllBytes(file.FullName))); count++; } catch (Exception e) { Console.WriteLine("Error: This file is not valid."); Console.WriteLine(e); } } else { if (Convert(Key, file.FullName)) { count++; } } } Console.WriteLine($"Completed! {count} files processed in total."); Console.WriteLine("Press ENTER to exit..."); Console.ReadLine(); return; } app.Execute(args); Console.WriteLine("Done."); }
static void Main(string[] args) { Console.WriteLine("FreeMote PSB Converter"); Console.WriteLine("by Ulysses, [email protected]"); Console.WriteLine(); if (args.Length >= 3) { if (!File.Exists(args[0])) { Console.WriteLine("File not exists."); return; } uint key; if (!uint.TryParse(args[1], out key)) { Console.WriteLine("Key is not valid."); return; } Key = key; if (!uint.TryParse(args[2], out key)) { Console.WriteLine("New key is not valid."); return; } NewKey = key; byte[] bytes = File.ReadAllBytes(args[0]); File.WriteAllBytes(args[0] + ".converted", PsbFile.Transfer(Key.Value, NewKey.Value, bytes)); } else if (args.Length == 2) { if (!File.Exists(args[0])) { Console.WriteLine("File not exists."); return; } uint key; if (!uint.TryParse(args[1], out key)) { Console.WriteLine("Key is not valid."); return; } Key = key; Convert(Key, args[0]); } else if (args.Length == 1) { if (!File.Exists(args[0])) { PrintHelp(); return; } AskForKey(); Convert(Key, args[0]); } else { PrintHelp(); AskForKey(); AskForNewKey(); DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory); uint count = 0; foreach (var file in di.EnumerateFiles("*.psb")) { if (NewKey != null) { try { File.WriteAllBytes(file.FullName + ".converted", PsbFile.Transfer(Key.Value, NewKey.Value, File.ReadAllBytes(file.FullName))); count++; } catch (Exception e) { Console.WriteLine("Error: This file is not valid."); Console.WriteLine(e); } } else { if (Convert(Key, file.FullName)) { count++; } } } Console.WriteLine($"Completed! {count} files processed in total."); Console.WriteLine("Press ENTER to exit..."); Console.ReadLine(); } }
static void Main(string[] args) { if (args.Length == 0 || args.Length > 2) { PrintUsage(); return; } if (args.Length == 1) { if (args[0] == "--version") { PrintVersion(); return; } } bool verbose = false; if (args[0] == "-v") { verbose = true; Console.WriteLine("Verbose output mode is set"); } string sourcePath = args[args.Length - 1]; if (verbose) { Console.WriteLine("Source extract file is " + Path.GetFullPath(sourcePath)); } if (!File.Exists(sourcePath)) { Console.WriteLine("Could not find file at " + sourcePath + ". Please ensure that your filename is correct."); return; } Console.WriteLine("============================================================================"); Console.WriteLine("Starting extraction of rom from " + sourcePath + "..."); Console.WriteLine("============================================================================"); string extractedRomPath = ""; RpxFile rpxFile = null; PsbFile psbFile = null; PkgFile pkgFile = null; SrlFile srlFile = null; // Identifies filetype of the file argument, // then instantiates file with file's location and verbose if (RpxFile.IsRpx(sourcePath)) { Console.WriteLine("RPX file detected!"); rpxFile = new RpxFile(sourcePath, verbose); } else if (PsbFile.IsPsb(sourcePath)) { Console.WriteLine("PSB file detected!"); psbFile = new PsbFile(sourcePath, verbose); } else if (PkgFile.IsPkg(sourcePath)) { pkgFile = new PkgFile(sourcePath, verbose); } else if (SrlFile.IsSrl(sourcePath)) { Console.WriteLine("SRL file detected!"); srlFile = new SrlFile(sourcePath, verbose); } // Create the list of rom extractors List <IRomExtractor> romExtractors = new List <IRomExtractor>(); if (rpxFile != null) { romExtractors.Add(new NesVcExtractor(rpxFile, verbose)); romExtractors.Add(new SnesVcExtractor(rpxFile.DecompressedPath, verbose)); romExtractors.Add(new FdsVcExtractor(rpxFile, verbose)); } else if (psbFile != null) { romExtractors.Add(new GbaVcExtractor(psbFile, verbose)); } else if (pkgFile != null) { romExtractors.Add(new PceVcExtractor(pkgFile, verbose)); } else if (Path.GetExtension(sourcePath) == ".sfrom") { romExtractors.Add(new SnesVcExtractor(sourcePath, verbose)); } else if (srlFile != null) { romExtractors.Add(new DsVcExtractor(srlFile, verbose)); } // Check with each extractor until a valid rom is found, // Then extract the rom with the appropriate extractor foreach (var romExtractor in romExtractors) { if (romExtractor.IsValidRom()) { extractedRomPath = romExtractor.ExtractRom(); break; } } if (!String.IsNullOrEmpty(extractedRomPath)) { Console.WriteLine("============================================================================"); Console.WriteLine(sourcePath + " has been extracted to " + extractedRomPath + " successfully."); Console.WriteLine("============================================================================"); } else { Console.WriteLine("============================================================================"); Console.WriteLine("FAILURE: Could not successfully identify the rom type for " + sourcePath); Console.WriteLine("============================================================================"); } }
static void Main(string[] args) { if (args.Length != 1) { PrintUsage(); return; } string sourcePath = args[0]; if (!File.Exists(sourcePath)) { Console.WriteLine("Could not find file at " + sourcePath + ". Please ensure that your filename is correct."); return; } Console.WriteLine("============================================================================"); Console.WriteLine("Starting extraction of rom from " + sourcePath + "..."); Console.WriteLine("============================================================================"); string extractedRomPath = ""; RpxFile rpxFile = null; PsbFile psbFile = null; if (RpxFile.IsRpx(sourcePath)) { Console.WriteLine("RPX file detected!"); rpxFile = new RpxFile(sourcePath); } else if (PsbFile.IsPsb(sourcePath)) { Console.WriteLine("PSB file detected!"); psbFile = new PsbFile(sourcePath); } // Create the list of rom extractors List <IRomExtractor> romExtractors = new List <IRomExtractor>(); if (rpxFile != null) { romExtractors.Add(new NesVcExtractor(sourcePath, rpxFile)); romExtractors.Add(new SnesVcExtractor(sourcePath, rpxFile)); } else if (psbFile != null) { romExtractors.Add(new GbaVcExtractor(sourcePath, psbFile)); } foreach (var romExtractor in romExtractors) { if (romExtractor.IsValidRom()) { extractedRomPath = romExtractor.ExtractRom(); break; } } if (!String.IsNullOrEmpty(extractedRomPath)) { Console.WriteLine("============================================================================"); Console.WriteLine(sourcePath + " has been extracted to " + extractedRomPath + " successfully."); Console.WriteLine("============================================================================"); } else { Console.WriteLine("============================================================================"); Console.WriteLine("FAILURE: Could not successfully identify the rom type for " + sourcePath); Console.WriteLine("============================================================================"); } }