예제 #1
0
        /// <summary>
        /// Checks whether the file is of the desired kind for a program.
        /// </summary>
        /// <param name="fileKind">The kind of file to look for.</param>
        /// <param name="filePath">The file to check.</param>
        /// <param name="rootFile">When not null or empty, require the file name of the given file path to begin with this value.</param>
        /// <returns><c>true</c> if the file is a ROM file or a support file for the given root file.</returns>
        public static bool IsProgramSupportFile(this ProgramFileKind fileKind, string filePath, string rootFile)
        {
            // First, check if file is in the blacklist.
            if (!string.IsNullOrEmpty(filePath) && _romFileBlacklist.Contains(Path.GetFileName(filePath), PathComparer.Instance))
            {
                return(false);
            }

            // Now, check if it has appropriate extension. If rootFile is not null or empty, check that FilePath has the same 'base name'.
            var hasExpectedExtension  = fileKind.HasCorrectExtension(filePath);
            var hasCustomRomExtension = !hasExpectedExtension && fileKind.HasCustomRomExtension(filePath);

            if (hasCustomRomExtension)
            {
                DebugOutput("We have a custom extension!");
            }

            // Don't care about case sensitivity of file system.
            bool isProgramFile = (hasExpectedExtension || hasCustomRomExtension) && (string.IsNullOrEmpty(rootFile) || Path.GetFileName(filePath).StartsWith(Path.GetFileNameWithoutExtension(rootFile), StringComparison.InvariantCultureIgnoreCase));

            if (isProgramFile)
            {
                // Check if file name has proper suffix. Don't care about case sensitivity of file system.
                var suffix = fileKind.GetSuffix();
                isProgramFile = string.IsNullOrEmpty(suffix) || Path.GetFileNameWithoutExtension(filePath).EndsWith(suffix, StringComparison.InvariantCultureIgnoreCase);

                if (!isProgramFile)
                {
                    // Check if it's in a proper directory.
                    var subdirectoriesForFile = fileKind.GetSubdirectories();
                    isProgramFile = !subdirectoriesForFile.Any() || subdirectoriesForFile.Contains(Path.GetFileName(Path.GetDirectoryName(filePath)), PathComparer.Instance);
                }
            }
            return(isProgramFile);
        }
예제 #2
0
        private void UpdateProgramRom(ProgramFileKind whichFile, object data)
        {
            if (_programRom == null)
            {
                _programRom = new XmlRom();
            }
            var xmlRom = _programRom as XmlRom;

            switch (whichFile)
            {
            case ProgramFileKind.Rom:
                System.Diagnostics.Debug.Assert(!xmlRom.IsValid, "When is this called on a valid ROM?");
                xmlRom.UpdateRomPath(data as string);     // ugh... why is this here?
                ////if (!_supportFiles[ProgramFileKind.Rom].Contains(RomImagePath, System.StringComparer.OrdinalIgnoreCase))
                ////{
                ////    _supportFiles[ProgramFileKind.Rom].Add(RomImagePath);
                ////}
                break;

            case ProgramFileKind.CfgFile:
                if (!string.IsNullOrEmpty(data as string))
                {
                    xmlRom.UpdateConfigPath(data as string);
                    ////if (!_supportFiles[ProgramFileKind.CfgFile].Contains(RomConfigurationFilePath, System.StringComparer.OrdinalIgnoreCase))
                    ////{
                    ////    _supportFiles[ProgramFileKind.CfgFile].Add(RomConfigurationFilePath);
                    ////}
                }
                break;
            }
        }
예제 #3
0
        /// <summary>
        /// Checks whether the file extension is valid for the given program file kind.
        /// </summary>
        /// <param name="fileKind">The kind of program file for which the extension is to be validated.</param>
        /// <param name="filePath">The file path to be checked.</param>
        /// <returns>If the file has an extension that is valid for the given file kind, returns <c>true</c>; <c>false</c> otherwise.</returns>
        public static bool HasCorrectExtension(this ProgramFileKind fileKind, string filePath)
        {
            var fileTypes            = fileKind.FileExtensions();
            var extension            = GetExtension(filePath);
            var hasStandardExtension = (extension != null) && fileTypes.Any(e => e.Equals(extension, System.StringComparison.OrdinalIgnoreCase));

            return(hasStandardExtension);
        }
예제 #4
0
        /// <summary>
        /// Retrieves the current validation state of the given support file.
        /// </summary>
        /// <param name="whichFile">Which support file to get a validation state for.</param>
        /// <returns>The validation state of the file.</returns>
        public ProgramSupportFileState GetSupportFileState(ProgramFileKind whichFile)
        {
            var state = ProgramSupportFileState.None;

            if (!_supportFileStates.TryGetValue(whichFile, out state))
            {
                state = ProgramSupportFileState.None;
            }
            return(state);
        }
예제 #5
0
 /// <summary>
 /// Removes the custom extension.
 /// </summary>
 /// <param name="fileKind">The file kind for which to remove a custom extension.</param>
 /// <param name="extension">The custom file extension to no longer associate with the given file kind.</param>
 public static void RemoveCustomExtension(this ProgramFileKind fileKind, string extension)
 {
     if ((fileKind == ProgramFileKind.Rom) && !string.IsNullOrEmpty(extension))
     {
         lock (CustomRomExtensions.Value)
         {
             CustomRomExtensions.Value.Remove(extension);
         }
     }
 }
예제 #6
0
        /// <summary>
        /// Determines if the given file has a custom ROM extension.
        /// </summary>
        /// <returns><c>true</c> if the file has a custom rom extension; otherwise, <c>false</c>.</returns>
        /// <param name="fileKind">File kind.</param>
        /// <param name="filePath">File path.</param>
        public static bool HasCustomRomExtension(this ProgramFileKind fileKind, string filePath)
        {
            var hasCustomRomExtension = false;

            if (filePath != null)
            {
                if (fileKind == ProgramFileKind.Rom)
                {
                    var extension = GetExtension(filePath);
                    if (extension == null)
                    {
                        extension = string.Empty;
                    }
                    lock (CustomRomExtensions.Value)
                    {
                        hasCustomRomExtension = CustomRomExtensions.Value.Any(e => e.Equals(extension, System.StringComparison.OrdinalIgnoreCase));
                    }
                }
            }
            return(hasCustomRomExtension);
        }
예제 #7
0
        private string SetDefaultSupportFilePath(ProgramFileKind whichFile, string filePath)
        {
            string previousValue = null;
            var    files         = _supportFiles[whichFile];
            bool   anyFiles      = files.Any();

            if (anyFiles)
            {
                previousValue = files[0];
            }
            if (string.IsNullOrEmpty(filePath))
            {
                if (anyFiles)
                {
                    // When the default support file path is set to null, it is removed.
                    // TODO: Should we be setting the path to <null>? The way this works, if
                    // we have more entries, then the second in the list will become the new
                    // default, which is not intuitive.
                    files.RemoveAt(0);
                }
            }
            else
            {
                var existingMatch = files.FirstOrDefault(f => System.StringComparer.OrdinalIgnoreCase.Compare(f, filePath) == 0);
                if (existingMatch != null)
                {
                    files.Remove(existingMatch);
                    files.Insert(0, filePath);
                }
                else if (anyFiles)
                {
                    files[0] = filePath;
                }
                else
                {
                    files.Insert(0, filePath);
                }
            }
            return(previousValue);
        }
예제 #8
0
        /// <summary>
        /// Shows a dialog to select a support file for the program.
        /// </summary>
        /// <param name="program">The program for which a support file is being selected.</param>
        /// <param name="kind">The kind of support file to browse for.</param>
        /// <returns>The selected support file.</returns>
        internal static string BrowseForSupportFile(ProgramViewModel program, ProgramFileKind kind)
        {
            string filter = null;
            string prompt = null;

            switch (kind)
            {
            case ProgramFileKind.ManualText:
                filter = RomListViewModel.SelectManualFilter;
                prompt = string.Format(System.Globalization.CultureInfo.CurrentCulture, RomListViewModel.SelectManualPromptFormat, program.ProgramDescription.Name);
                break;

            case ProgramFileKind.SaveData:
                filter = RomListViewModel.SelectJlpSaveDataFilter;
                prompt = string.Format(System.Globalization.CultureInfo.CurrentCulture, RomListViewModel.SelectJlpSavePromptFormat, program.ProgramDescription.Name);
                break;

            default:
                ErrorReporting.ReportNotImplementedError("ProgramViewModel.BrowseForSupportFile");
                break;
            }

            string supportFilePath = null;
            var    fileBrowser     = FileDialogHelpers.Create();

            fileBrowser.IsFolderBrowser = false;
            fileBrowser.AddFilter(filter, kind.FileExtensions());
            fileBrowser.AddFilter(FileDialogHelpers.AllFilesFilter, new string[] { ".*" });
            fileBrowser.Title            = prompt;
            fileBrowser.EnsureFileExists = true;
            fileBrowser.EnsurePathExists = true;
            fileBrowser.Multiselect      = false;
            var result = fileBrowser.ShowDialog();

            if (result == FileBrowserDialogResult.Ok)
            {
                supportFilePath = fileBrowser.FileNames.First();
            }
            return(supportFilePath);
        }
예제 #9
0
        private ProgramSupportFileState GetSupportFileState(ProgramFileKind kind)
        {
            var state = ProgramSupportFileState.None;

            switch (LtoFlashViewModel.SyncMode)
            {
            case MenuLayoutSynchronizationMode.None:
                break;

            case MenuLayoutSynchronizationMode.RomList:
                if (ProgramDescription != null)
                {
                    state = ProgramDescription.Files.GetSupportFileState(kind);
                }
                break;

            case MenuLayoutSynchronizationMode.ToLtoFlash:
            case MenuLayoutSynchronizationMode.FromLtoFlash:
                state = State;
                break;
            }
            return(state);
        }
 public void ProgramFileKind_HasCorrectExtensionForUnsupportedFileKind_ThrowsKeyNotFoundException(ProgramFileKind fileKind)
 {
     Assert.Throws <KeyNotFoundException>(() => fileKind.HasCorrectExtension(@"I:\ntellivision\Rules.forever"));
 }
 public void ProgramFileKind_HasCorrectExtension_ReturnsCorrectFileExtensions(ProgramFileKind fileKind, string filePath, bool expectedHasCorrectExtension)
 {
     Assert.Equal(expectedHasCorrectExtension, fileKind.HasCorrectExtension(filePath));
 }
 public void ProgramFileKind_FileExtensionForUnsupportedFileKind_ThrowsKeyNotFoundException(ProgramFileKind fileKind)
 {
     Assert.Throws <KeyNotFoundException>(() => fileKind.FileExtension());
 }
 public void ProgramFileKind_FileExtension_ReturnsCorrectFileExtension(ProgramFileKind fileKind, string expectedFileExtension)
 {
     Assert.Equal(expectedFileExtension, fileKind.FileExtension());
 }
 public void ProgramFileKind_FileExtensions_ReturnsCorrectFileExtensions(ProgramFileKind fileKind, IEnumerable <string> expectedFileExtensions)
 {
     AssertCollectionsAreEquivalent(expectedFileExtensions, fileKind.FileExtensions());
 }
 public void ProgramFileKind_GetSubdirectoriesForUnsupportedFileKind_ThrowsKeyNotFoundException(ProgramFileKind fileKind)
 {
     Assert.Throws <KeyNotFoundException>(() => fileKind.GetSubdirectories());
 }
예제 #16
0
 /// <summary>
 /// Get the suffix to append to a file name for a particular <see cref="ProgramFileKind"/>, such as a manual or overlay.
 /// </summary>
 /// <param name="fileKind">The kind of program file for which a suffix is desired.</param>
 /// <returns>The suffix to use. May be empty.</returns>
 /// <exception cref="KeyNotFoundException">Thrown if <paramref name="fileKind"/> does not support a suffix.</exception>
 public static string GetSuffix(this ProgramFileKind fileKind)
 {
     return(FileSuffixForFileKind.Value[fileKind]);
 }
 public void ProgramFileKind_GetSuffix_ReturnsCorrectSuffix(ProgramFileKind fileKind, string expectedSuffix)
 {
     Assert.Equal(expectedSuffix, fileKind.GetSuffix());
 }
예제 #18
0
        /// <summary>
        /// Checks whether a file path is a program ROM file.
        /// </summary>
        /// <param name="fileKind">The kind of program file to check.</param>
        /// <param name="filePath">The file path to inspect to determine if it is of the indicated program file kind.</param>
        /// <returns><c>true</c> if the given file is of the given type.</returns>
        public static bool IsProgramFile(this ProgramFileKind fileKind, string filePath)
        {
            var isProgram = fileKind.IsProgramSupportFile(filePath, null);

            return(isProgram);
        }
예제 #19
0
 /// <summary>
 /// Unconditionally adds a support file to the support files associated with a program.
 /// </summary>
 /// <param name="whichFile">Which support file to add.</param>
 /// <param name="filePath">Absolute path of the support file being added.</param>
 public void AddSupportFile(ProgramFileKind whichFile, string filePath)
 {
     _supportFiles[whichFile].Add(filePath);
 }
예제 #20
0
 /// <summary>
 /// Gets the default file extension for a program file kind.
 /// </summary>
 /// <param name="fileKind">The kind of program file for which an extension is desired.</param>
 /// <returns>The file extension.</returns>
 /// <exception cref="KeyNotFoundException">Thrown if <paramref name="fileKind"/> is not supported.</exception>
 public static string FileExtension(this ProgramFileKind fileKind)
 {
     return(fileKind.FileExtensions().First());
 }
예제 #21
0
 /// <summary>
 /// Get the file extension for a program file.
 /// </summary>
 /// <param name="fileKind">The kind of program file for which an extension is desired.</param>
 /// <returns>The file extensions. May be empty.</returns>
 /// <exception cref="KeyNotFoundException">Thrown if <paramref name="fileKind"/> is not supported.</exception>
 public static IEnumerable <string> FileExtensions(this ProgramFileKind fileKind)
 {
     return(FileExtensionsForFileKind.Value[fileKind]);
 }
예제 #22
0
 /// <summary>
 /// Get the subdirectories into which to store a support file for a particular <see cref="ProgramFileKind"/>, such as a manual or overlay.
 /// </summary>
 /// <param name="fileKind">The kind of program file for which a subdirectory is desired.</param>
 /// <returns>The subdirectories that may be used. File kinds that refer to known ROM types, or are unrecognized, will return an empty enumerable.</returns>
 /// <exception cref="KeyNotFoundException">Thrown if <paramref name="fileKind"/> is not valid.</exception>
 public static IEnumerable <string> GetSubdirectories(this ProgramFileKind fileKind)
 {
     return(FileSubdirectoriesForFileKind.Value[fileKind]);
 }
 public void ProgramFileKind_HasCustomRomExtensionForNullPath_ReturnsFalse(ProgramFileKind fileKind)
 {
     Assert.False(fileKind.HasCustomRomExtension(null));
 }
 public void ProgramFileKind_GetSubdirectories_ReturnsCorrectSubdirectories(ProgramFileKind fileKind, IEnumerable <string> expectedSubdirecories)
 {
     AssertCollectionsAreEquivalent(expectedSubdirecories, fileKind.GetSubdirectories());
 }
        public void ProgramFileKind_HasCustomRomExtensionForEmptyPath_ReturnsFalseExceptForRomKind(ProgramFileKind fileKind)
        {
            var expectedResult = fileKind == ProgramFileKind.Rom;

            Assert.Equal(expectedResult, fileKind.HasCustomRomExtension(string.Empty));
        }
예제 #26
0
        /// <summary>
        /// Updates the validation state of the given support file.
        /// </summary>
        /// <param name="whichFile">Which file to validate.</param>
        /// <param name="crc">If non-zero, the CRC of the program ROM to compare against if validating the ROM file.</param>
        /// <param name="programDescription">The program description being validated (if applicable).</param>
        /// <param name="peripherals">The peripherals attached to the system, used for compatibility checks.</param>
        /// <param name="connectedPeripheralsHistory">The peripherals that have been attached to the system over time.</param>
        /// <param name="reportIfModified">If <c>true</c>, check if the file has been modified, not just whether it exists.</param>
        /// <returns>The updated state of the file.</returns>
        public ProgramSupportFileState ValidateSupportFile(ProgramFileKind whichFile, uint crc, IProgramDescription programDescription, IEnumerable <IPeripheral> peripherals, IEnumerable <IPeripheral> connectedPeripheralsHistory, bool reportIfModified)
        {
            var validationState = ProgramSupportFileState.None;

            switch (whichFile)
            {
            case ProgramFileKind.Rom:
                var isValid = Rom.Validate();
                if (!string.IsNullOrEmpty(RomImagePath))
                {
                    var previousValidationState = ProgramSupportFileState.None;
                    _supportFileStates.TryGetValue(whichFile, out previousValidationState);
                    if (!StreamUtilities.FileExists(RomImagePath))
                    {
                        validationState = ProgramSupportFileState.Missing;
                        if (AlternateRomImagePaths.Any(p => StreamUtilities.FileExists(p)))
                        {
                            validationState = ProgramSupportFileState.MissingWithAlternateFound;
                        }
                    }
                    else if (reportIfModified)
                    {
                        isValid = _programRom.IsValid;
                        if (crc != 0)
                        {
                            // In some cases, the CRC provided is actually Rom.Crc, so if they match, recompute the CRC.
                            var cfgCrc = 0u;
                            isValid = (Rom.Crc == crc) && (crc == GetRefreshedCrcForRom(RomImagePath, RomConfigurationFilePath, out cfgCrc) && (Rom.CfgCrc == cfgCrc));
                        }
                        validationState = isValid ? ProgramSupportFileState.PresentAndUnchanged : ProgramSupportFileState.PresentButModified;
                    }
                    switch (validationState)
                    {
                    case ProgramSupportFileState.PresentAndUnchanged:
                    case ProgramSupportFileState.None:
                        // Treat a ROM file's missing or modified state as higher priority to report than peripheral-related information.
                        // This bit of code is entirely LTO Flash!-specific in its assumptions. If there should ever be other
                        // peripheral-specific needs to address here, a larger architectural change may be necessary. While the
                        // language of the states here is neutral, the basis of this check is not.
                        var rom = programDescription == null ? Rom : programDescription.Rom;
                        var requiresPeripheral = rom.IsLtoFlashOnlyRom();
                        if (requiresPeripheral)
                        {
                            var isUniversallyCompatible          = rom.GetTargetDeviceUniqueId() == LuigiScrambleKeyBlock.AnyLTOFlashId;
                            var matchesPeripheralInDeviceHistory = isUniversallyCompatible || ((connectedPeripheralsHistory != null) && (connectedPeripheralsHistory.FirstOrDefault(p => p.IsRomCompatible(programDescription)) != null));
                            var canRunOnConnected = isUniversallyCompatible || ((peripherals != null) && (peripherals.FirstOrDefault(p => p.IsRomCompatible(programDescription)) != null));

                            if (peripherals == null)
                            {
                                // If previous validation state was due to peripheral, retain it, since we don't
                                // have any peripherals to check against.
                                if (validationState != previousValidationState)
                                {
                                    switch (previousValidationState)
                                    {
                                    case ProgramSupportFileState.RequiredPeripheralAvailable:
                                    case ProgramSupportFileState.RequiredPeripheralIncompatible:
                                    case ProgramSupportFileState.RequiredPeripheralNotAttached:
                                    case ProgramSupportFileState.RequiredPeripheralUnknown:
                                        validationState = previousValidationState;
                                        break;

                                    case ProgramSupportFileState.None:
                                        validationState = matchesPeripheralInDeviceHistory ? ProgramSupportFileState.RequiredPeripheralNotAttached : ProgramSupportFileState.RequiredPeripheralUnknown;
                                        break;

                                    default:
                                        // TODO: Decide if the following is a bug:
                                        // 0: Presume a scrambled (unique) LUIGI, no device or device history provided (null)
                                        // 1. Initially ROM's file is missing, but its alternate is found - this caches the 'MissingButAlternateFound' state
                                        // 2. Update ROM to use alternate path as primary path
                                        // 3. Re-validate
                                        // At this point, the "Present and unmodified" state is used -- despite the ROM requiring
                                        // a specific device.
                                        // Why is this considered correct at this time?
                                        // a) When no devices or device history are give (nulls), it's impossible to know. So just use the simple state of he file.
                                        // b) It MAY be a bug that, if we pass in EMPTY peripheral / history lists that we should consider something different... but
                                        //    then again, should we report 'unknown peripheral' at that time? Or would reporting 'not attached' be better?
                                        //    What about 'universally' scrambled ROMs? Using 'not attached' may be more accurate then as well...
                                        // The case of scrambled ROMs likely needs more careful consideration generally...
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                if (peripherals.Any())
                                {
                                    if (canRunOnConnected)
                                    {
                                        validationState = ProgramSupportFileState.RequiredPeripheralAvailable;
                                    }
                                    else
                                    {
                                        validationState = ProgramSupportFileState.RequiredPeripheralIncompatible;
                                    }
                                }
                                else
                                {
                                    validationState = matchesPeripheralInDeviceHistory ? ProgramSupportFileState.RequiredPeripheralNotAttached : ProgramSupportFileState.RequiredPeripheralUnknown;
                                }
                            }
                        }
                        break;

                    default:
                        break;
                    }
                }
                break;

            default:
                // TODO: Implement remaining validation code.
                break;
            }
            _supportFileStates[whichFile] = validationState;
            return(validationState);
        }