示例#1
0
        /// <summary>
        ///     Loads the specified DLL, and then inspects that DLLs Module Reference Table to import any additional
        ///     references it might require recursively.
        /// </summary>
        /// <param name="dllToLoad"></param>
        private void LoadModuleDll(string dllToLoad)
        {
            var requiredDll = new MbbsDll(_fileUtility, _logger);

            if (!requiredDll.Load(dllToLoad, ModulePath, ModuleConfig.Patches?.Where(x => x.AbsoluteOffset > 0).ToList()))
            {
                _logger.Error($"Unable to load {dllToLoad}");
                return;
            }

            requiredDll.SegmentOffset = (ushort)ModuleDlls.Sum(x => x.File.SegmentTable.Count);
            ModuleDlls.Add(requiredDll);

            _logger.Info($"Loaded {dllToLoad}");

            //Pull records from ModuleReferenceTable that aren't of References handled internally by the emulator
            foreach (var import in ModuleDlls[0].File.ModuleReferenceTable
                     .Where(x => GetAllExportedModules().All(e => e != x.Name)).Select(x => x.Name))
            {
                //Only load a dependency if it's not already loaded by a previous library
                if (ModuleDlls.All(x => x.File.FileName.ToUpper().Split('.')[0] != import.ToUpper()))
                {
                    LoadModuleDll(import);
                }
            }
        }
示例#2
0
        /// <summary>
        ///     Constructor for MbbsModule
        ///
        ///     Pass in an empty/blank moduleIdentifier for a Unit Test/Fake Module
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="moduleIdentifier">Will be null in a test</param>
        /// <param name="path"></param>
        /// <param name="memoryCore"></param>
        /// <param name="fileUtility"></param>
        public MbbsModule(IFileUtility fileUtility, IClock clock, ILogger logger, string moduleIdentifier, string path = "", MemoryCore memoryCore = null)
        {
            _fileUtility = fileUtility;
            _logger      = logger;
            _clock       = clock;

            ModuleIdentifier = moduleIdentifier;
            ModuleDlls       = new List <MbbsDll>();


            //Sanitize and setup Path
            if (string.IsNullOrEmpty(path))
            {
                path = Directory.GetCurrentDirectory();
            }

            if (!Path.EndsInDirectorySeparator(path))
            {
                path += Path.DirectorySeparatorChar;
            }

            ModulePath = path;

            // will be null in tests
            if (string.IsNullOrEmpty(ModuleIdentifier))
            {
                Mdf = MdfFile.createForTest();
                ModuleDlls.Add(new MbbsDll(fileUtility, logger)
                {
                    File = NEFile.createForTest()
                });
            }
            else
            {
                //Verify MDF File Exists
                var mdfFile         = fileUtility.FindFile(ModulePath, $"{ModuleIdentifier}.MDF");
                var fullMdfFilePath = Path.Combine(ModulePath, mdfFile);
                if (!System.IO.File.Exists(fullMdfFilePath))
                {
                    throw new FileNotFoundException($"Unable to locate Module: {fullMdfFilePath}");
                }

                Mdf = new MdfFile(fullMdfFilePath);
                var moduleDll = new MbbsDll(fileUtility, logger);
                moduleDll.Load(Mdf.DLLFiles[0].Trim(), ModulePath);
                ModuleDlls.Add(moduleDll);


                if (Mdf.Requires.Count > 0)
                {
                    foreach (var r in Mdf.Requires)
                    {
                        var requiredDll = new MbbsDll(fileUtility, logger);
                        if (requiredDll.Load(r.Trim(), ModulePath))
                        {
                            requiredDll.SegmentOffset = (ushort)(ModuleDlls.Sum(x => x.File.SegmentTable.Count) + 1);
                            ModuleDlls.Add(requiredDll);
                        }
                    }
                }

                if (Mdf.MSGFiles.Count > 0)
                {
                    Msgs = new List <MsgFile>(Mdf.MSGFiles.Count);
                    foreach (var m in Mdf.MSGFiles)
                    {
                        Msgs.Add(new MsgFile(ModulePath, m));
                    }
                }
            }

            //Set Initial Values
            RtkickRoutines           = new PointerDictionary <RealTimeRoutine>();
            RtihdlrRoutines          = new PointerDictionary <RealTimeRoutine>();
            TaskRoutines             = new PointerDictionary <RealTimeRoutine>();
            TextVariables            = new Dictionary <string, FarPtr>();
            GlobalCommandHandlers    = new List <FarPtr>();
            ExportedModuleDictionary = new Dictionary <ushort, IExportedModule>(6);
            ExecutionUnits           = new Queue <ExecutionUnit>(2);

            Memory = memoryCore ?? new MemoryCore();

            //Declare PSP Segment
            var psp = new PSPStruct {
                NextSegOffset = 0x9FFF, EnvSeg = 0xFFFF
            };

            Memory.AddSegment(0x4000);
            Memory.SetArray(0x4000, 0, psp.Data);

            Memory.AllocateVariable("Int21h-PSP", sizeof(ushort));
            Memory.SetWord("Int21h-PSP", 0x4000);

            //Find _INIT_ values if any
            foreach (var dll in ModuleDlls)
            {
                //If it's a Test, setup a fake _INIT_
                if (string.IsNullOrEmpty(ModuleIdentifier))
                {
                    dll.EntryPoints["_INIT_"] = null;
                    return;
                }

                //Setup _INIT_ Entrypoint
                FarPtr initEntryPointPointer;
                var    initResidentName = dll.File.ResidentNameTable.FirstOrDefault(x => x.Name.StartsWith("_INIT__"));
                if (initResidentName == null)
                {
                    //This only happens with MajorMUD -- I have no idea why it's a special little snowflake ¯\_(ツ)_/¯
                    _logger.Warn($"({moduleIdentifier}) Unable to locate _INIT_ in Resident Name Table, checking Non-Resident Name Table...");

                    var initNonResidentName = dll.File.NonResidentNameTable.FirstOrDefault(x => x.Name.StartsWith("_INIT__"));

                    if (initNonResidentName == null)
                    {
                        throw new Exception("Unable to locate _INIT__ entry in Resident Name Table");
                    }

                    var initEntryPoint = dll.File.EntryTable.First(x => x.Ordinal == initNonResidentName.IndexIntoEntryTable);

                    initEntryPointPointer = new FarPtr((ushort)(initEntryPoint.SegmentNumber + dll.SegmentOffset), initEntryPoint.Offset);
                }
                else
                {
                    var initEntryPoint = dll.File.EntryTable.First(x => x.Ordinal == initResidentName.IndexIntoEntryTable);
                    initEntryPointPointer = new FarPtr((ushort)(initEntryPoint.SegmentNumber + dll.SegmentOffset), initEntryPoint.Offset);
                }


                _logger.Debug($"({ModuleIdentifier}) Located _INIT__: {initEntryPointPointer}");
                dll.EntryPoints["_INIT_"] = initEntryPointPointer;
            }
        }