/// <summary>
        ///     Generates Parameters that can be passed into a method
        ///
        ///     Memory must be Reset() between runs or else string will remain allocated in the heap
        /// </summary>
        /// <param name="values"></param>
        /// <returns></returns>
        protected List <ushort> GenerateParameters(object[] values)
        {
            var parameters = new List <ushort>();

            foreach (var v in values)
            {
                switch (v)
                {
                case string @parameterString:
                {
                    var stringParameterPointer = mbbsEmuMemoryCore.AllocateVariable(Guid.NewGuid().ToString(), (ushort)(@parameterString.Length + 1));
                    mbbsEmuMemoryCore.SetArray(stringParameterPointer, Encoding.ASCII.GetBytes(@parameterString));
                    parameters.Add(stringParameterPointer.Offset);
                    parameters.Add(stringParameterPointer.Segment);
                    break;
                }

                case uint @parameterULong:
                {
                    var longBytes = BitConverter.GetBytes(@parameterULong);
                    parameters.Add(BitConverter.ToUInt16(longBytes, 0));
                    parameters.Add(BitConverter.ToUInt16(longBytes, 2));
                    break;
                }

                case int @parameterLong:
                {
                    var longBytes = BitConverter.GetBytes(@parameterLong);
                    parameters.Add(BitConverter.ToUInt16(longBytes, 0));
                    parameters.Add(BitConverter.ToUInt16(longBytes, 2));
                    break;
                }

                case ushort @parameterUInt:
                    parameters.Add(@parameterUInt);
                    break;

                case short @parameterInt:
                    parameters.Add((ushort)@parameterInt);
                    break;
                }
            }

            return(parameters);
        }
Exemple #2
0
 private static void CreateDataSegment(ReadOnlySpan <byte> data, ushort segmentOrdinal = 2)
 {
     mbbsEmuMemoryCore.AddSegment(segmentOrdinal);
     mbbsEmuMemoryCore.SetArray(segmentOrdinal, 0, data);
 }
Exemple #3
0
 protected void CreateDataSegment(ReadOnlySpan <byte> data, ushort segmentOrdinal = 2)
 {
     mbbsEmuProtectedModeMemoryCore.AddSegment(segmentOrdinal);
     mbbsEmuMemoryCore.SetArray(segmentOrdinal, 0, data);
 }
Exemple #4
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;
            }
        }
Exemple #5
0
        /// <summary>
        ///     Constructor for MbbsModule
        ///
        ///     Pass in an empty/blank moduleIdentifier for a Unit Test/Fake Module
        /// </summary>
        /// <param name="fileUtility"></param>
        /// <param name="clock"></param>
        /// <param name="logger"></param>
        /// <param name="moduleConfig"></param>
        /// <param name="memoryCore"></param>
        public MbbsModule(IFileUtility fileUtility, IClock clock, ILogger logger, ModuleConfiguration moduleConfig, ProtectedModeMemoryCore memoryCore = null)
        {
            _fileUtility = fileUtility;
            _logger      = logger;
            _clock       = clock;

            ModuleConfig     = moduleConfig;
            ModuleIdentifier = moduleConfig.ModuleIdentifier;

            ModuleDlls = new List <MbbsDll>();

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

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

            ModulePath = moduleConfig.ModulePath;

            // will be null in tests
            if (string.IsNullOrEmpty(ModuleIdentifier))
            {
                Mdf = MdfFile.createForTest();
                ModuleDlls.Add(new MbbsDll(fileUtility, logger)
                {
                    File = NEFile.createForTest()
                });
            }
            else
            {
                //Verify Module Path Exists
                if (!Directory.Exists(ModulePath))
                {
                    _logger.Error($"Unable to find the specified directory for the module {ModuleIdentifier.ToUpper()}: {ModulePath}");
                    _logger.Error("Please verify your Command Line Argument or the path specified in your Module JSON File and try again.");
                    throw new DirectoryNotFoundException($"Unable to locate {ModulePath}");
                }

                //Verify MDF File Exists
                var mdfFile         = fileUtility.FindFile(ModulePath, $"{ModuleIdentifier}.MDF");
                var fullMdfFilePath = Path.Combine(ModulePath, mdfFile);
                if (!File.Exists(fullMdfFilePath))
                {
                    _logger.Error($"Unable to locate {fullMdfFilePath}");
                    _logger.Error($"Please verify your Command Line Argument or the Module JSON File to ensure {ModuleIdentifier} is the correct Module Identifier and that the Module is installed properly.");
                    throw new FileNotFoundException($"Unable to locate Module: {fullMdfFilePath}");
                }
                Mdf = new MdfFile(fullMdfFilePath);

                LoadModuleDll(Mdf.DLLFiles[0].Trim());

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

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

            Memory          = memoryCore ?? new ProtectedModeMemoryCore(logger);
            ProtectedMemory = (ProtectedModeMemoryCore)Memory;

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

            ProtectedMemory.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($"({moduleConfig.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)
                    {
                        _logger.Error($"Unable to locate _INIT__ entry in Resident Name Table for {dll.File.FileName}");
                        continue;
                    }

                    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;
            }
        }