Beispiel #1
0
 /// <summary>
 /// Compare two ROM instances.
 /// </summary>
 /// <param name="x">The first ROM to compare.</param>
 /// <param name="programInformationRomX">Additional information about the <paramref name="x"/> ROM.</param>
 /// <param name="y">The second ROM to compare.</param>
 /// <param name="programInformationRomY">Additional information about the <paramref name="y"/> ROM.</param>
 /// <returns>If the two ROMs are considered equal, zero; if <paramref name="x"/> is considered 'greater than' <paramref name="y"/>, a positive number;
 /// if <paramref name="x"/> is considered 'less than' <paramref name="y"/>, a negative number.</returns>
 public abstract int Compare(IRom x, IProgramInformation programInformationRomX, IRom y, IProgramInformation programInformationRomY);
Beispiel #2
0
        public void IProgramInformation_GetNameFOrCrcOnNullInformation_ThrowsNullReferenceException()
        {
            IProgramInformation information = null;

            Assert.Throws <NullReferenceException>(() => information.GetNameForCrc(1u));
        }
Beispiel #3
0
 /// <summary>
 /// Add a new CRC value to the program information.
 /// </summary>
 /// <param name="programInformation">The program information to which a new CRC is to be added.</param>
 /// <param name="newCrc">The new CRC by which the program may be identified.</param>
 /// <returns><c>true</c> if the new Crc value was added, <c>false</c> if the Crc was already present.</returns>
 /// <remarks>No description or incompatibility flags will be assigned. It is assumed the ROM is compatible with all Intellivision hardware
 /// and needs no special identification.</remarks>
 public static bool AddCrc(this IProgramInformation programInformation, uint newCrc)
 {
     return(programInformation.AddCrc(newCrc, string.Empty));
 }
Beispiel #4
0
 /// <summary>
 /// Add a new CRC value to the program information.
 /// </summary>
 /// <param name="programInformation">The program information to which a new CRC is to be added.</param>
 /// <param name="newCrc">The new CRC by which the program may be identified.</param>
 /// <param name="crcDescription">A brief (one or two word) description, if applicable.</param>
 /// <returns><c>true</c> if the new Crc value was added, <c>false</c> if the Crc was already present.</returns>
 /// <remarks>No incompatibility flags will be assigned. It is assumed the ROM is compatible with all Intellivision hardware
 /// and needs no special identification.</remarks>
 public static bool AddCrc(this IProgramInformation programInformation, uint newCrc, string crcDescription)
 {
     return(programInformation.AddCrc(newCrc, crcDescription, IncompatibilityFlags.None));
 }
Beispiel #5
0
        /// <inheritdoc />
        public override int Compare(IRom x, IProgramInformation programInformationRomX, IRom y, IProgramInformation programInformationRomY)
        {
            var result = base.Compare(x, programInformationRomX, y, programInformationRomY);

            if ((result == 0) && (x != null))
            {
                switch (x.Format)
                {
                case RomFormat.Bin:
                    result = CheckCrcs(x, programInformationRomX, y, programInformationRomY);
                    break;

                case RomFormat.Luigi:
                    result = CheckCrcs(x, programInformationRomX, y, programInformationRomY);
                    if ((result == 0) && (y.Format == RomFormat.Luigi))
                    {
                        // It's possible LUIGI files' original CRCs match, but the LUIGI files themselves do not.
                        // This once occurred when additional bytes were somehow appended to a downloaded LUIGI. In
                        // that case, all the CRC data matched, so even the "strict" CRC check, which compared the
                        // full 8 bytes of the ID in the header, still matched. However, the additional data at the
                        // end of the corrupted file resulted in failure to load on LTO Flash! hardware. Therefore,
                        // when comparing what appear to be two identical LUIGI files, still compare full file CRCs.
                        result = (int)(Rom.AsSpecificRomType <LuigiFormatRom>(x).Crc24 - Rom.AsSpecificRomType <LuigiFormatRom>(y).Crc24);
                    }
                    break;

                default:
                    break;
                }
            }
            return(result);
        }
        private IProgramFeatures GetInitialProgramFeatures(IProgramDescription programDescription, IProgramInformation programInformation)
        {
            IProgramFeatures initialProgramFeatures = null;

            if (programDescription != null)
            {
                initialProgramFeatures = programDescription.Features;
            }
            if ((initialProgramFeatures == null) && (programInformation != null))
            {
                initialProgramFeatures = programInformation.Features;
            }
            return(initialProgramFeatures);
        }
 public void AddProgram(IProgramInformation programInformation)
 {
     _programs.Add(programInformation);
 }
Beispiel #8
0
        public void IProgramInformation_AddCrcWithDescriptionToNullInformation_ThrowsNullReferenceException()
        {
            IProgramInformation information = null;

            Assert.Throws <NullReferenceException>(() => information.AddCrc(1u, "description"));
        }
Beispiel #9
0
        /// <inheritdoc />
        public override int Compare(IRom x, IProgramInformation programInformationRomX, IRom y, IProgramInformation programInformationRomY)
        {
            var result = BaseComparer.Compare(x, programInformationRomX, y, programInformationRomY);

            if (result != 0)
            {
                result = CanonicalCompare(x, y, false);
            }
            return(result);
        }
Beispiel #10
0
        /// <summary>
        /// Gets program information from a ROM.
        /// </summary>
        /// <param name="rom">The ROM from which to retrieve information.</param>
        /// <returns>The program information.</returns>
        /// <remarks>Program information will be honored according to the following order or precedence rules:
        /// 1. Program databases
        /// 2. ROM-specific metadata
        ///   a. LUIGI metadata check
        ///   b. ROM ID tag metadata check
        ///   c. CFGVAR metadata check
        /// 3. intvname utility check (which has its own internal order-of-precedence, likely overlapping with this)
        /// If multiple sources are available, an attempt is made to merge the results.</remarks>
        public static IProgramInformation GetProgramInformation(this IRom rom)
        {
            // NOTE: ROM database is still CRC-based, and does not use a RomComparer!
            var programInfo = ProgramInformationTable.Default.FindProgram(rom.Crc);

            rom.EnsureCfgFileProvided(programInfo);
            IProgramInformation metadataProgramInfo = rom.GetLuigiFileMetadata();

            if (metadataProgramInfo == null)
            {
                metadataProgramInfo = rom.GetRomFileMetadata();
            }
            if (metadataProgramInfo == null)
            {
                metadataProgramInfo = rom.GetBinFileMetadata();
            }

            var programInfoData  = rom.GetRomInformation();
            var programName      = programInfoData.GetRomInfoString(RomInfoIndex.Name);
            var programYear      = programInfoData.GetRomInfoString(RomInfoIndex.Copyright);
            var programShortName = programInfoData.GetRomInfoString(RomInfoIndex.ShortName);
            var intvNameInfo     = new UserSpecifiedProgramInformation(rom.Crc, programName, programYear, rom.GetProgramFeatures());

            if (programInfoData.Any(s => !string.IsNullOrEmpty(s)))
            {
                if (!string.IsNullOrEmpty(programShortName))
                {
                    intvNameInfo.ShortName = programShortName;
                }

                if (programInfo != null)
                {
                    // If we have a database entry, which is the ultimate arbiter of "known" -- either a-priory, or as specified
                    // explicitly by the user as a new entry for the database, then strip the "unrecognized-ness" from the intvname
                    // data.  Presumably, the database entry specified these values. We do not want to re-mark the features as unknown
                    // when merging intvname information into a database entry's information. The ROM metadata that can be directly
                    // harvested from a program, however, does not track these aspects of a program, hence we will retain the values
                    // in the situation where we may have nearly complete feature data about a program aside from what the database tracks.
                    intvNameInfo.Features.ClearUnrecongizedRomFeatures();
                }
            }
            else if ((programInfo != null) || (metadataProgramInfo != null))
            {
                intvNameInfo = null;
            }

            if ((programInfo == null) && (metadataProgramInfo != null))
            {
                // Mark features with unrecognized settings, since we don't have a database entry.
                metadataProgramInfo.Features.SetUnrecongizedRomFeatures();
            }

            var primaryInfo   = programInfo ?? metadataProgramInfo ?? intvNameInfo;
            var secondaryInfo = object.ReferenceEquals(primaryInfo, metadataProgramInfo) ? intvNameInfo : metadataProgramInfo ?? intvNameInfo;
            var tertiaryInfo  = object.ReferenceEquals(secondaryInfo, intvNameInfo) ? null : intvNameInfo;

            if (secondaryInfo != null)
            {
                if (tertiaryInfo != null)
                {
                    programInfo = primaryInfo.Merge(
                        ProgramInformationMergeFieldsFlags.All,
                        new Tuple <IProgramInformation, ProgramInformationMergeFieldsFlags>(secondaryInfo, ProgramInformationMergeFieldsFlags.All),
                        new Tuple <IProgramInformation, ProgramInformationMergeFieldsFlags>(tertiaryInfo, ProgramInformationMergeFieldsFlags.All));
                }
                else
                {
                    programInfo = primaryInfo.Merge(
                        ProgramInformationMergeFieldsFlags.All,
                        new Tuple <IProgramInformation, ProgramInformationMergeFieldsFlags>(secondaryInfo, ProgramInformationMergeFieldsFlags.All));
                }
            }
            else
            {
                programInfo = primaryInfo;
            }

            return(programInfo);
        }
Beispiel #11
0
        /// <summary>
        /// Given a list of files and / or directories, enumerate what appear to be valid program ROM files.
        /// </summary>
        /// <param name="files">A list of files and / or directories to inspect to locate ROM files.</param>
        /// <param name="acceptCancellation">Delegate to call to determine if the operation should accept being cancelled by the user.</param>
        /// <param name="progressFunc">Delegate to call to update progress of the operation.</param>
        /// <returns>An enumerable of valid program ROM files.</returns>
        public static IEnumerable <IRom> IdentifyRomFiles(this IEnumerable <string> files, Func <bool> acceptCancellation, Action <string> progressFunc)
        {
            var potentialRomFilePaths = GetPotentialProgramRomFiles(files, acceptCancellation, progressFunc).Where(f => ProgramFileKind.Rom.IsProgramFile(f));

            foreach (var romFilePath in potentialRomFilePaths)
            {
                if (acceptCancellation())
                {
                    yield break;
                }
                if (progressFunc != null)
                {
                    progressFunc(romFilePath);
                }
                var configFilePath = INTV.Shared.Model.Program.ProgramFileKindHelpers.GetConfigFilePath(romFilePath);
                if (!string.IsNullOrEmpty(configFilePath) && File.Exists(configFilePath))
                {
                    INTV.Core.Model.IRom programRom = null;
                    try
                    {
                        programRom = INTV.Core.Model.Rom.Create(romFilePath, configFilePath);
                    }
                    catch (IOException)
                    {
                        // TODO: Report error here -- this has been found to occur of scanning SkyDrive / OneDrive in Windows 8.1.
                    }
                    if (programRom != null)
                    {
                        yield return(programRom);
                    }
                }
                else
                {
                    INTV.Core.Model.IRom programRom = null;
                    try
                    {
                        programRom = INTV.Core.Model.Rom.Create(romFilePath, null);
                    }
                    catch (IOException)
                    {
                        // TODO: Report error here -- this has been found to occur of scanning SkyDrive / OneDrive in Windows 8.1.
                    }
                    if (programRom != null)
                    {
                        yield return(programRom);
                    }
                    else
                    {
                        // Might be a lone 'bin' file, such as EXEC or GROM. Run a checksum. This will result in a second checksum later, but oh, well.
                        IProgramInformation programInfo = null;
                        try
                        {
                            var crc = INTV.Core.Utility.Crc32.OfFile(romFilePath);
                            programInfo = ProgramInformationTable.Default.FindProgram(crc);
                        }
                        catch (IOException)
                        {
                            // TODO: Report error here -- this has been found to occur of scanning SkyDrive / OneDrive in Windows 8.1.
                        }
                        if (programInfo != null)
                        {
                            if (INTV.Core.Model.Rom.CheckRomFormat(romFilePath) != RomFormat.None)
                            {
                                yield return(INTV.Core.Model.Rom.Create(romFilePath, null));
                            }
                        }
                    }
                }
            }
        }
Beispiel #12
0
        public void IProgramInformationToXmlRomInformationConverter_ConvertNullInformation_ThrowsNullReferenceException()
        {
            IProgramInformation information = null;

            Assert.Throws <NullReferenceException>(() => IProgramInformationToXmlRomInformationConverter.Instance.Convert(information).Any());
        }
        private IProgramMetadata GetInitialProgramMetadatda(IProgramDescription programDescription, IProgramInformation programInformation)
        {
            IProgramMetadata initialProgramMetadata = null;

            if ((programDescription != null) && (programDescription.Rom != null))
            {
                initialProgramMetadata = programDescription.Rom.GetProgramMetadata();
            }
            if ((initialProgramMetadata == null) && (programInformation != null))
            {
                // Several implementations of IProgramInformation also implement IProgramMetadata.
                initialProgramMetadata = programInformation as IProgramMetadata;
            }
            return(initialProgramMetadata);
        }
Beispiel #14
0
        public void IProgramInformation_GetDatabaseCodeOnNullInformation_ReturnsNullCode()
        {
            IProgramInformation information = null;

            Assert.Null(information.GetDatabaseCode());
        }
Beispiel #15
0
        /// <inheritdoc />
        public override int Compare(IRom x, IProgramInformation programInformationX, IRom y, IProgramInformation programInformationY)
        {
            var result = BaseComparer.Compare(x, programInformationX, y, programInformationY);

            if (result != 0)
            {
                result = CanonicalCompare(x, y, true); // require features to match as well
            }
            return(result);
        }
Beispiel #16
0
        public void IProgramInformation_MergeNullInformatoin_ThrowsArgumentException()
        {
            IProgramInformation information = null;

            Assert.Throws <ArgumentException>(() => information.Merge(ProgramInformationMergeFieldsFlags.None));
        }
Beispiel #17
0
 public void UserSpecifiedProgramInformation_ConstructWithEmptyMetadataProgramInformationWithNullMetadataFields_ThrowsArgumentNullException(IProgramInformation sourceInformation)
 {
     Assert.Throws <ArgumentNullException>(() => new UserSpecifiedProgramInformation(sourceInformation));
 }
Beispiel #18
0
        public void IProgramInformation_ModifyCrcOnNullInformation_ThrowsNullReferenceException()
        {
            IProgramInformation information = null;

            Assert.Throws <NullReferenceException>(() => information.ModifyCrc(1u, "description", IncompatibilityFlags.Ntsc));
        }
Beispiel #19
0
        /// <summary>
        /// Merges the given IProgramInformation data to form a new, combined version of the information.
        /// </summary>
        /// <param name="programInformation">The "primary" source of information.</param>
        /// <param name="fieldsToMerge">Identifies which fields to merge.</param>
        /// <param name="otherSources">The other information sources to merge, and how to merge them. See Remarks.</param>
        /// <returns>The merged program information.</returns>
        /// <remarks>Each of the additional information sources in the merge will be combined with the primary. The newly
        /// merged information is initialized using the data from <paramref name="programInformation"/>. The
        /// other sources should be ordered such that the first entry is the "most important" and the final entry the
        /// "least important". Each entry also describes which fields it is allowed to override in the merge.
        /// This is to offer a means of conflict resolution in situations arising from multiple sources containing
        /// the same information and attempting to override the default. For example, consider the case in which
        /// <paramref name="programInformation"/> and two entries are provided via <paramref name="otherSources"/>,
        /// all three of which define a value for <see cref="IProgramInformation.Title"/>. Here are some ways in which
        /// this can be configured:
        /// <code>
        /// fieldsToMerge = ProgramInformationMergeFieldsFlags.None;
        /// </code>
        /// In this case, the information in <paramref name="programInformation"/> will not be changed. A copy of the
        /// data within it will be returned. Note, however, that the specific implementation of <see cref="IProgramInformation"/>
        /// used to deliver the resulting data may be different than the original!
        /// Now, consider this scenario:
        /// <code>
        /// fieldsToMerge = ProgramInformationMergeFieldsFlags.Title;
        /// otherSources[0].Item2 = ProgramInformationMergeFieldsFlags.Title;
        /// otherSources[1].Item2 = ProgramInformationMergeFieldsFlags.Title;
        /// </code>
        /// In this case, each entry allows 'Title' to be set. Because <paramref name="programInformation"/> is
        /// treated as the highest priority, its value will be retained unless it is not set (in this case, a <c>null</c>
        /// or empty string). So, if programInformation.Title has no value, but otherSources[0].Item1.Title does, then
        /// the final result contains otherSources[0].Item1.Title, regardless of the value of otherSources[1].Item1.Title.
        /// By carefully considering these flags, you can have a reasonably rich order-of-precedence defined for establishing
        /// the data in the merged result.
        /// </remarks>
        /// <exception cref="System.ArgumentException">Thrown if unrecognized flags are provided in <paramref name="fieldsToMerge"/> or via <paramref name="otherSources"/>.</exception>
        public static IProgramInformation Merge(this IProgramInformation programInformation, ProgramInformationMergeFieldsFlags fieldsToMerge, params Tuple <IProgramInformation, ProgramInformationMergeFieldsFlags>[] otherSources)
        {
            // Grr.... PCLs (at least in .NET 4.0) don't support Enum.GetValues()
            var flagsToProcess = new[] { ProgramInformationMergeFieldsFlags.Title, ProgramInformationMergeFieldsFlags.Vendor, ProgramInformationMergeFieldsFlags.Year, ProgramInformationMergeFieldsFlags.Features, ProgramInformationMergeFieldsFlags.ShortName, ProgramInformationMergeFieldsFlags.Crcs };

            var unknownFlagsForMerge = otherSources.Select(s => s.Item2).Concat(new[] { fieldsToMerge }).Except(flagsToProcess).Except(new[] { ProgramInformationMergeFieldsFlags.None, ProgramInformationMergeFieldsFlags.All });

            if (unknownFlagsForMerge.Any())
            {
                var unknownFlags = unknownFlagsForMerge.Aggregate((all, flag) => all | flag);
                throw new ArgumentException(string.Format(Resources.Strings.ProgramInformation_InvalidFieldFormat, unknownFlags));
            }

            var mergedProgramInformation = new UserSpecifiedProgramInformation(programInformation);
            var mergedPriorityFlags      = fieldsToMerge; // accumulates if a "higher priority" info has already claimed a field

            foreach (var otherSource in otherSources)
            {
                var otherInformation = otherSource.Item1;
                var updateFlags      = otherSource.Item2;
                foreach (var flag in flagsToProcess)
                {
                    if (updateFlags.HasFlag(flag))
                    {
                        switch (flag)
                        {
                        case ProgramInformationMergeFieldsFlags.Title:
                            if (string.IsNullOrEmpty(mergedProgramInformation.Title) || !mergedPriorityFlags.HasFlag(flag))
                            {
                                mergedProgramInformation.Title = otherInformation.Title;
                                if (!string.IsNullOrEmpty(mergedProgramInformation.Title))
                                {
                                    mergedPriorityFlags |= flag;
                                }
                            }
                            break;

                        case ProgramInformationMergeFieldsFlags.Vendor:
                            if (string.IsNullOrEmpty(mergedProgramInformation.Vendor) || !mergedPriorityFlags.HasFlag(flag))
                            {
                                mergedProgramInformation.Vendor = otherInformation.Vendor;
                                if (!string.IsNullOrEmpty(mergedProgramInformation.Vendor))
                                {
                                    mergedPriorityFlags |= flag;
                                }
                            }
                            break;

                        case ProgramInformationMergeFieldsFlags.Year:
                            if (string.IsNullOrEmpty(mergedProgramInformation.Year) || !mergedPriorityFlags.HasFlag(flag))
                            {
                                mergedProgramInformation.Year = otherInformation.Year;
                                if (!string.IsNullOrEmpty(mergedProgramInformation.Year))
                                {
                                    mergedPriorityFlags |= flag;
                                }
                            }
                            break;

                        case ProgramInformationMergeFieldsFlags.Features:
                            // This runs the risk of combining conflicting flags...
                            mergedProgramInformation.Features = ProgramFeatures.Combine(mergedProgramInformation.Features, otherInformation.Features);
                            mergedPriorityFlags |= flag;
                            break;

                        case ProgramInformationMergeFieldsFlags.ShortName:
                            if (string.IsNullOrEmpty(mergedProgramInformation.ShortName) || !mergedPriorityFlags.HasFlag(flag))
                            {
                                mergedProgramInformation.ShortName = otherInformation.ShortName;
                                if (!string.IsNullOrEmpty(mergedProgramInformation.ShortName))
                                {
                                    mergedPriorityFlags |= flag;
                                }
                            }
                            break;

                        case ProgramInformationMergeFieldsFlags.Crcs:
                            var crcsToMerge = otherInformation.Crcs.Where(o => !mergedProgramInformation.Crcs.Any(m => m.Crc == o.Crc));
                            foreach (var crc in crcsToMerge)
                            {
                                mergedProgramInformation.AddCrc(crc.Crc, crc.Description, crc.Incompatibilities);
                                mergedPriorityFlags |= flag;
                            }
                            break;
                        }
                    }
                }
            }
            return(mergedProgramInformation);
        }
Beispiel #20
0
        private static int CheckCrcs(IRom x, IProgramInformation programInformationRomX, IRom y, IProgramInformation programInformationRomY)
        {
            var cfgCrcRomX = x.CfgCrc;
            var cfgCrcRomY = y.CfgCrc;
            var result     = (int)cfgCrcRomX - (int)cfgCrcRomY;

            if ((result != 0) && ((cfgCrcRomX == 0) || (cfgCrcRomY == 0)))
            {
                if (cfgCrcRomX == 0)
                {
                    var programInfo = programInformationRomX;
                    if (programInfo == null)
                    {
                        programInfo = x.GetProgramInformation();
                    }
                    var cfgFilePath = x.GetStockCfgFile(programInfo);
                    if (!string.IsNullOrEmpty(cfgFilePath))
                    {
                        cfgCrcRomX = INTV.Core.Utility.Crc32.OfFile(cfgFilePath);
                    }
                }
                if (cfgCrcRomY == 0)
                {
                    var programInfo = programInformationRomY;
                    if (programInfo == null)
                    {
                        programInfo = y.GetProgramInformation();
                    }
                    var cfgFilePath = y.GetStockCfgFile(programInfo);
                    if (!string.IsNullOrEmpty(cfgFilePath))
                    {
                        cfgCrcRomY = INTV.Core.Utility.Crc32.OfFile(cfgFilePath);
                    }
                }
                result = (int)cfgCrcRomX - (int)cfgCrcRomY;
            }
            return(result);
        }
Beispiel #21
0
 /// <summary>
 /// Adds an entry to the table if it does not already exist.
 /// </summary>
 /// <param name="programInfo">The program information to add.</param>
 /// <returns><c>true</c> if the entry was added, otherwise <c>false</c>.</returns>
 public bool AddEntry(IProgramInformation programInfo)
 {
     throw new System.NotImplementedException(Resources.Strings.ProgramInformationTable_NoEditsToDefaultDatabase);
 }