using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; namespace PKHeX.Core { /// /// Logic for detecting supported binary object formats. /// public static class FileUtil { /// /// Attempts to get a binary object from the provided path. /// /// /// Reference savefile used for PC Binary compatibility checks. /// Supported file object reference, null if none found. public static object GetSupportedFile(string path, SaveFile reference = null) { try { var fi = new FileInfo(path); if (IsFileTooBig(fi.Length) || IsFileTooSmall(fi.Length)) return null; var data = File.ReadAllBytes(path); var ext = Path.GetExtension(path); return GetSupportedFile(data, ext, reference); } catch (Exception e) { Debug.WriteLine(MessageStrings.MsgFileInUse); Debug.WriteLine(e.Message); return null; } } /// /// Attempts to get a binary object from the provided inputs. /// /// Binary data for the file. /// File extension used as a hint. /// Reference savefile used for PC Binary compatibility checks. /// Supported file object reference, null if none found. public static object GetSupportedFile(byte[] data, string ext, SaveFile reference = null) { if (TryGetSAV(data, out var sav)) return sav; if (TryGetMemoryCard(data, out var mc)) return mc; if (TryGetPKM(data, out var pk, ext)) return pk; if (TryGetPCBoxBin(data, out IEnumerable pks, reference)) return pks; if (TryGetBattleVideo(data, out BattleVideo bv)) return bv; if (TryGetMysteryGift(data, out MysteryGift g, ext)) return g; return null; } /// /// Checks if the length is too big to be a detectable file. /// /// File size public static bool IsFileTooBig(long length) { if (length <= 0x100000) return false; if (length == SaveUtil.SIZE_G4BR) return false; if (SAV3GCMemoryCard.IsMemoryCardSize(length)) return false; // pbr/GC have size > 1MB return true; } /// /// Checks if the length is too small to be a detectable file. /// /// File size public static bool IsFileTooSmall(long length) => length < 0x20; /// /// Tries to get an object from the input parameters. /// /// Binary data /// Output result /// True if file object reference is valid, false if none found. public static bool TryGetSAV(byte[] data, out SaveFile sav) { sav = SaveUtil.GetVariantSAV(data); return sav != null; } /// /// Tries to get an object from the input parameters. /// /// Binary data /// Output result /// True if file object reference is valid, false if none found. public static bool TryGetMemoryCard(byte[] data, out SAV3GCMemoryCard memcard) { if (!SAV3GCMemoryCard.IsMemoryCardSize(data)) { memcard = null; return false; } memcard = new SAV3GCMemoryCard(data); return true; } /// /// Tries to get an object from the input parameters. /// /// Binary data /// Output result /// Format hint /// Reference savefile used for PC Binary compatibility checks. /// True if file object reference is valid, false if none found. public static bool TryGetPKM(byte[] data, out PKM pk, string ext, ITrainerInfo sav = null) { if (ext == ".pgt") // size collision with pk6 { pk = default(PKM); return false; } var format = PKX.GetPKMFormatFromExtension(ext, sav?.Generation ?? 6); pk = PKMConverter.GetPKMfromBytes(data, prefer: format); return pk != null; } /// /// Tries to get an object from the input parameters. /// /// Binary data /// Output result /// Reference savefile used for PC Binary compatibility checks. /// True if file object reference is valid, false if none found. public static bool TryGetPCBoxBin(byte[] data, out IEnumerable pkms, SaveFile SAV) { if (SAV == null) { pkms = Enumerable.Empty(); return false; } var length = data.Length; if (PKX.IsPKM(length / SAV.SlotCount) || PKX.IsPKM(length / SAV.BoxSlotCount)) { pkms = PKX.GetPKMDataFromConcatenatedBinary(data, length); return true; } pkms = Enumerable.Empty(); return false; } /// /// Tries to get a object from the input parameters. /// /// Binary data /// Output result /// True if file object reference is valid, false if none found. public static bool TryGetBattleVideo(byte[] data, out BattleVideo bv) { bv = BattleVideo.GetVariantBattleVideo(data); return bv != null; } /// /// Tries to get a object from the input parameters. /// /// Binary data /// Output result /// Format hint /// True if file object reference is valid, false if none found. public static bool TryGetMysteryGift(byte[] data, out MysteryGift mg, string ext) { mg = MysteryGift.GetMysteryGift(data, ext); return mg != null; } /// /// Gets a Temp location File Name for the . /// /// Data to be exported /// Data is to be encrypted /// Path to temporary file location to write to. public static string GetPKMTempFileName(PKM pk, bool encrypt) { string fn = pk.FileNameWithoutExtension; string filename = fn + (encrypt ? $".ek{pk.Format}" : $".{pk.Extension}"); return Path.Combine(Path.GetTempPath(), Util.CleanFileName(filename)); } /// /// Gets a from the provided path, which is to be loaded to the . /// /// or file path. /// Generation Info /// New reference from the file. public static PKM GetSingleFromPath(string file, ITrainerInfo SAV) { var fi = new FileInfo(file); if (!fi.Exists) return null; if (!PKX.IsPKM(fi.Length) && !MysteryGift.IsMysteryGift(fi.Length)) return null; var data = File.ReadAllBytes(file); var ext = fi.Extension; var mg = MysteryGift.GetMysteryGift(data, ext); var gift = mg?.ConvertToPKM(SAV); if (gift != null) return gift; int prefer = PKX.GetPKMFormatFromExtension(ext, SAV.Generation); return PKMConverter.GetPKMfromBytes(data, prefer: prefer); } } }