public XnaToFnaUtil() { Modder = new XnaToFnaModder(this); Modder.ReadingMode = ReadingMode.Immediate; Modder.Strict = false; Modder.AssemblyResolver = AssemblyResolver; Modder.DependencyDirs = Directories; Modder.MissingDependencyResolver = MissingDependencyResolver; using (FileStream xtfStream = new FileStream(Assembly.GetExecutingAssembly().Location, FileMode.Open, FileAccess.Read)) ThisModule = MonoModExt.ReadModule(xtfStream, new ReaderParameters(ReadingMode.Immediate)); Modder.DependencyCache[ThisModule.Assembly.Name.Name] = ThisModule; Modder.DependencyCache[ThisModule.Assembly.Name.FullName] = ThisModule; }
public static bool Is(this MemberReference member, MemberInfo other) => MonoModExt.Is(member, other);
public void ScanPath(string path) { if (Directory.Exists(path)) { // Use the directory as "dependency directory" and scan in it. if (Directories.Contains(path)) { // No need to scan the dir if the dir is scanned... return; } RestoreBackup(path); Log($"[ScanPath] Scanning directory {path}"); Directories.Add(path); AssemblyResolver.AddSearchDirectory(path); // Needs to be added manually as DependencyDirs was already added // Most probably the actual game directory - let's just copy XnaToFna.exe to there to be referenced properly. string xtfPath = Path.Combine(path, Path.GetFileName(ThisAssembly.Location)); if (Path.GetDirectoryName(ThisAssembly.Location) != path) { Log($"[ScanPath] Found separate game directory - copying XnaToFna.exe and FNA.dll"); File.Copy(ThisAssembly.Location, xtfPath, true); string dbExt = null; if (File.Exists(Path.ChangeExtension(ThisAssembly.Location, "pdb"))) { dbExt = "pdb"; } if (File.Exists(Path.ChangeExtension(ThisAssembly.Location, "mdb"))) { dbExt = "mdb"; } if (dbExt != null) { File.Copy(Path.ChangeExtension(ThisAssembly.Location, dbExt), Path.ChangeExtension(xtfPath, dbExt), true); } if (File.Exists(Path.Combine(Path.GetDirectoryName(ThisAssembly.Location), "FNA.dll"))) { File.Copy(Path.Combine(Path.GetDirectoryName(ThisAssembly.Location), "FNA.dll"), Path.Combine(path, "FNA.dll"), true); } else if (File.Exists(Path.Combine(Path.GetDirectoryName(ThisAssembly.Location), "FNA.dll.tmp"))) { File.Copy(Path.Combine(Path.GetDirectoryName(ThisAssembly.Location), "FNA.dll.tmp"), Path.Combine(path, "FNA.dll"), true); } } ScanPaths(Directory.GetFiles(path)); return; } if (File.Exists(path + ".xex")) { if (!ExtractedXEX.Contains(path)) { // Remove the original file - let XnaToFna unpack and handle it later. File.Delete(path); } else { // XnaToFna will handle the .xex instead. } return; } if (path.EndsWith(".xex")) { string pathTarget = path.Substring(0, path.Length - 4); if (string.IsNullOrEmpty(Path.GetExtension(pathTarget))) { return; } using (Stream streamXEX = File.OpenRead(path)) using (BinaryReader reader = new BinaryReader(streamXEX)) using (Stream streamRAW = File.OpenWrite(pathTarget)) { XEXImageData data = new XEXImageData(reader); int offset = 0; int size = data.m_memorySize; // Check if this file is a PE containing an embedded PE. if (data.m_memorySize > 0x10000) // One default segment alignment. { using (MemoryStream streamMEM = new MemoryStream(data.m_memoryData)) using (BinaryReader mem = new BinaryReader(streamMEM)) { if (mem.ReadUInt32() != 0x00905A4D) // MZ { goto WriteRaw; } // This is horrible. streamMEM.Seek(0x00000280, SeekOrigin.Begin); if (mem.ReadUInt64() != 0x000061746164692E) // ".idata\0\0" { goto WriteRaw; } streamMEM.Seek(0x00000288, SeekOrigin.Begin); mem.ReadInt32(); // Virtual size; It's somewhat incorrect? offset = mem.ReadInt32(); // Virtual offset. // mem.ReadInt32(); // Raw size; Still incorrect. // Let's just write everything... size = data.m_memorySize - offset; } } WriteRaw: streamRAW.Write(data.m_memoryData, offset, size); } path = pathTarget; ExtractedXEX.Add(pathTarget); } else if (!path.EndsWith(".dll") && !path.EndsWith(".exe")) { return; } // Check if .dll is CLR assembly AssemblyName name; try { name = AssemblyName.GetAssemblyName(path); } catch { return; } ReaderParameters modReaderParams = Modder.GenReaderParameters(false); // Don't ReadWrite if the module being read is XnaToFna or a relink target. bool isReadWrite = #if !CECIL0_9 modReaderParams.ReadWrite = #endif path != ThisAssembly.Location && !Mappings.Exists(mappings => name.Name == mappings.Target); // Only read debug info if it exists if (!File.Exists(path + ".mdb") && !File.Exists(Path.ChangeExtension(path, "pdb"))) { modReaderParams.ReadSymbols = false; } Log($"[ScanPath] Checking assembly {name.Name} ({(isReadWrite ? "rw" : "r-")})"); ModuleDefinition mod; try { mod = MonoModExt.ReadModule(path, modReaderParams); } catch (Exception e) { Log($"[ScanPath] WARNING: Cannot load assembly: {e}"); return; } bool add = !isReadWrite || name.Name == ThisAssemblyName; if ((mod.Attributes & ModuleAttributes.ILOnly) != ModuleAttributes.ILOnly) { // Mono.Cecil can't handle mixed mode assemblies. Log($"[ScanPath] WARNING: Cannot handle mixed mode assembly {name.Name}"); if (MixedDeps == MixedDepAction.Stub) { ModulesToStub.Add(mod); add = true; } else { if (MixedDeps == MixedDepAction.Remove) { RemoveDeps.Add(name.Name); } #if !CECIL0_9 mod.Dispose(); #endif return; } } if (add && !isReadWrite) // XNA replacement { foreach (XnaToFnaMapping mapping in Mappings) { if (name.Name == mapping.Target) { mapping.IsActive = true; mapping.Module = mod; foreach (string from in mapping.Sources) { Log($"[ScanPath] Mapping {from} -> {name.Name}"); Modder.RelinkModuleMap[from] = mod; } } } } else if (!add) { foreach (XnaToFnaMapping mapping in Mappings) { if (mod.AssemblyReferences.Any(dep => mapping.Sources.Contains(dep.Name))) { add = true; Log($"[ScanPath] XnaToFna-ing {name.Name}"); goto BreakMappings; } } } BreakMappings: if (add) { Modules.Add(mod); ModulePaths[mod] = path; } else { #if !CECIL0_9 mod.Dispose(); #endif } }