예제 #1
0
        private void AddEntry(CacheIndexEntry entry, bool save)
        {
            var anyMatching = Entries.Any(e => (e.LuigiCrc24 == entry.LuigiCrc24) && (e.LuigiSize == entry.LuigiSize) && (e.RomCrc32 == entry.RomCrc32) && (e.RomSize == entry.RomSize));

            if (!anyMatching)
            {
                Entries.Add(entry);
                if (save)
                {
                    Save();
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Gathers cache data to rebuild it if the index file is missing.
        /// </summary>
        /// <param name="cacheIndexDirectory">The director for which to rebuild the index.</param>
        /// <param name="rebuildIndexErrorMessages">Accumulates any errors encountered during the rebuild..</param>
        /// <returns>An enumerable containing index entries from the rebuild process.</returns>
        public static IEnumerable <CacheIndexEntry> GatherCacheData(string cacheIndexDirectory, IList <string> rebuildIndexErrorMessages)
        {
            var jzIntvConfiguration = SingleInstanceApplication.Instance.GetConfiguration <INTV.JzIntv.Model.Configuration>();
            var cachedRoms          = (new[] { cacheIndexDirectory }).IdentifyRomFiles(() => false, f => { }).ToList();
            var cachedLuigiRoms     = cachedRoms.Where(r => r.Format == RomFormat.Luigi).ToList();
            var nonLuigiRoms        = cachedRoms.Except(cachedLuigiRoms).ToList();

            var restoredCacheEntries = new List <CacheIndexEntry>();
            var cacheDirectoryLength = cacheIndexDirectory.Length + 1; // for cutting backslash out later...

            using (var comparer = CanonicalRomComparerStrict.Default)
            {
                foreach (var cachedLuigiRom in cachedLuigiRoms)
                {
                    // Get the LUIGI header.
                    LuigiFileHeader luigiHeader = LuigiFileHeader.GetHeader(cachedLuigiRom.RomPath);

                    // Initialize the LUIGI part of the cache entry.
                    var cacheEntry = new CacheIndexEntry();
                    cacheEntry.LuigiPath  = cachedLuigiRom.RomPath.Substring(cacheDirectoryLength);
                    cacheEntry.LuigiCrc24 = INTV.Core.Utility.Crc24.OfFile(cachedLuigiRom.RomPath);
                    cacheEntry.LuigiSize  = (uint)(new FileInfo(cachedLuigiRom.RomPath)).Length;

                    // Now fetch or recreate the ROM if missing. RomFormat.None indicates that the
                    // original has been located on disk. Otherwise, indicates the format to recreate from the LUIGI file.
                    var originalRomFormat = RomFormat.None;

                    if (luigiHeader.Version > 0)
                    {
                        // LUIGI format 1 and later contains information about the original ROM.
                        cacheEntry.RomCrc32 = luigiHeader.OriginalRomCrc32;
                        var originalRom = nonLuigiRoms.FirstOrDefault(r => (r.Format == luigiHeader.OriginalRomFormat) && r.IsEquivalentTo(cachedLuigiRom, comparer));
                        if (originalRom != null)
                        {
                            cacheEntry.RomPath = originalRom.RomPath.Substring(cacheDirectoryLength);
                            cacheEntry.RomSize = (uint)(new FileInfo(originalRom.RomPath)).Length;
                            restoredCacheEntries.Add(cacheEntry);
                            nonLuigiRoms.RemoveAll(r => (r.Format == luigiHeader.OriginalRomFormat) && r.IsEquivalentTo(cachedLuigiRom, comparer));
                        }
                        else
                        {
                            // Write down the format to reconstruct.
                            originalRomFormat = luigiHeader.OriginalRomFormat;
                        }
                    }
                    else
                    {
                        // Check for a .bin or .rom file.
                        originalRomFormat = RomFormat.Rom;
                        var originalFile = System.IO.Path.ChangeExtension(cachedLuigiRom.RomPath, originalRomFormat.FileExtension());
                        if (!File.Exists(originalFile))
                        {
                            originalRomFormat = RomFormat.Bin;
                            foreach (var binFormatExtension in ProgramFileKindHelpers.RomFileExtensionsThatUseCfgFiles)
                            {
                                if (!string.IsNullOrEmpty(binFormatExtension))
                                {
                                    originalFile = System.IO.Path.ChangeExtension(cachedLuigiRom.RomPath, binFormatExtension);
                                }
                                else
                                {
                                    originalFile = System.IO.Path.GetFileNameWithoutExtension(cachedLuigiRom.RomPath);
                                }
                                if (File.Exists(originalFile))
                                {
                                    break;
                                }
                            }
                        }
                        if (File.Exists(originalFile))
                        {
                            cacheEntry.RomCrc32 = INTV.Core.Utility.Crc32.OfFile(originalFile);
                            cacheEntry.RomPath  = originalFile.Substring(cacheDirectoryLength);
                            cacheEntry.RomSize  = (uint)(new FileInfo(originalFile)).Length;

                            if (originalRomFormat == RomFormat.Bin)
                            {
                                var cfgPath = System.IO.Path.ChangeExtension(cachedLuigiRom.RomPath, ProgramFileKind.CfgFile.FileExtension());
                                if (!File.Exists(cfgPath))
                                {
                                    cacheEntry.RestoreCfgFile();
                                }
                            }

                            restoredCacheEntries.Add(cacheEntry);
                            nonLuigiRoms.RemoveAll(r => (r.Format == originalRomFormat) && r.IsEquivalentTo(cachedLuigiRom, comparer));
                            originalRomFormat = RomFormat.None;
                        }
                    }

                    if (originalRomFormat != RomFormat.None)
                    {
                        // Need to recreate the ROM from LUIGI.
                        var sourcePath       = "\"" + System.IO.Path.GetFileNameWithoutExtension(cachedLuigiRom.RomPath) + "\"";
                        var workingDir       = System.IO.Path.GetDirectoryName(cachedLuigiRom.RomPath);
                        var conversionApps   = jzIntvConfiguration.GetConverterApps(cachedLuigiRom, luigiHeader.OriginalRomFormat);
                        var conversionResult = 0;
                        foreach (var conversionApp in conversionApps)
                        {
                            var argument = luigiHeader.OriginalRomFormat.GetCommandLineArgForBin2Rom() + sourcePath;
                            conversionResult = INTV.Shared.Utility.RunExternalProgram.Call(conversionApp.Item1, argument, workingDir);
                            if (conversionResult != 0)
                            {
                                rebuildIndexErrorMessages.Add("Failed to reconstruct " + sourcePath + luigiHeader.OriginalRomFormat.FileExtension());
                                break;
                            }
                        }
                        if (conversionResult == 0)
                        {
                            cacheEntry.RomPath = System.IO.Path.ChangeExtension(cacheEntry.LuigiPath, luigiHeader.OriginalRomFormat.FileExtension());
                            cacheEntry.RomSize = (uint)(new FileInfo(System.IO.Path.Combine(cacheIndexDirectory, cacheEntry.RomPath))).Length;

                            if (originalRomFormat == RomFormat.Bin)
                            {
                                var cfgPath = System.IO.Path.ChangeExtension(cachedLuigiRom.RomPath, ProgramFileKind.CfgFile.FileExtension());
                                if (!File.Exists(cfgPath))
                                {
                                    cacheEntry.RestoreCfgFile();
                                }
#if false
                                if (File.Exists(cfgPath))
                                {
                                    cacheEntry.CfgCrc32 = INTV.Core.Utility.Crc32.OfFile(cfgPath);
                                    cacheEntry.CfgPath  = cfgPath.Substring(cacheDirectoryLength);
                                    cacheEntry.CfgSize  = (uint)(new FileInfo(cfgPath)).Length;
                                }
#endif // false
                            }

                            restoredCacheEntries.Add(cacheEntry);
                        }
                    }
                }

                foreach (var nonLuigiRom in nonLuigiRoms)
                {
                    var cacheEntry = new CacheIndexEntry();
                    cacheEntry.RomPath  = nonLuigiRom.RomPath.Substring(cacheDirectoryLength);
                    cacheEntry.RomCrc32 = nonLuigiRom.Crc;
                    cacheEntry.RomSize  = (uint)(new FileInfo(nonLuigiRom.RomPath)).Length;

                    if (nonLuigiRom.Format == RomFormat.Bin)
                    {
                        var cfgPath = System.IO.Path.ChangeExtension(nonLuigiRom.RomPath, ProgramFileKind.CfgFile.FileExtension());
                        if (!File.Exists(cfgPath))
                        {
                            cacheEntry.RestoreCfgFile();
#if false
                            var programInfo = ProgramInformationTable.Default.FindProgram(cacheEntry.RomCrc32);
                            var cfgFilePath = nonLuigiRom.GenerateStockCfgFile(programInfo);
                            if (string.Compare(cfgFilePath, cfgPath, true) != 0)
                            {
                                System.Diagnostics.Debug.WriteLine("LSDKFLSKDFJLSJDF");
                            }
#endif // false
                        }
#if false
                        if (File.Exists(cfgPath))
                        {
                            cacheEntry.CfgCrc32 = INTV.Core.Utility.Crc32.OfFile(cfgPath);
                            cacheEntry.CfgPath  = cfgPath.Substring(cacheDirectoryLength);
                            cacheEntry.CfgSize  = (uint)(new FileInfo(cfgPath)).Length;
                        }
#endif // false
                    }

                    var sourcePath    = System.IO.Path.GetFileNameWithoutExtension(nonLuigiRom.RomPath);
                    var workingDir    = System.IO.Path.GetDirectoryName(nonLuigiRom.RomPath);
                    var conversionApp = jzIntvConfiguration.GetConverterApps(nonLuigiRom, RomFormat.Luigi).First();
                    var result        = INTV.Shared.Utility.RunExternalProgram.Call(conversionApp.Item1, "\"" + sourcePath + "\"", workingDir);
                    if (result != 0)
                    {
                        rebuildIndexErrorMessages.Add(string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RestoreCacheIndex_FailedToReconstructFormat, sourcePath + RomFormat.Luigi.FileExtension()));
                    }
                    else
                    {
                        cacheEntry.LuigiPath = System.IO.Path.ChangeExtension(cacheEntry.RomPath, RomFormat.Luigi.FileExtension());
                        var fullLuigiPath = System.IO.Path.Combine(cacheIndexDirectory, cacheEntry.LuigiPath);
                        cacheEntry.LuigiCrc24 = INTV.Core.Utility.Crc24.OfFile(fullLuigiPath);
                        cacheEntry.LuigiSize  = (uint)(new FileInfo(fullLuigiPath)).Length;
                        restoredCacheEntries.Add(cacheEntry);
                    }
                }
            }

            return(restoredCacheEntries);
        }
예제 #3
0
 /// <summary>
 /// Adds an entry to the index if appropriate.
 /// </summary>
 /// <param name="entry">The entry to add.</param>
 public void AddEntry(CacheIndexEntry entry)
 {
     AddEntry(entry, true);
 }
예제 #4
0
        /// <summary>
        /// Prepares a ROM for deployment to a Locutus device.
        /// </summary>
        /// <param name="rom">The ROM being prepared.</param>
        /// <param name="updateMode">Specifies the behavior of the LUIGI file generation.</param>
        /// <returns>The fully qualified path of the prepared output data file to deploy to Locutus.</returns>
        public static string PrepareForDeployment(this IRom rom, LuigiGenerationMode updateMode)
        {
#if REPORT_PERFORMANCE
#if RECORD_PREPARE_FOR_DEPLOYMENT_VISITS
            int visits;
            if (PrepareForDeploymentVisits.TryGetValue(rom.RomPath, out visits))
            {
                PrepareForDeploymentVisits[rom.RomPath] = ++visits;
            }
            else
            {
                PrepareForDeploymentVisits[rom.RomPath] = 1;
            }
#endif // RECORD_PREPARE_FOR_DEPLOYMENT_VISITS
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            try
            {
                var stopwatch2 = System.Diagnostics.Stopwatch.StartNew();
#endif // REPORT_PERFORMANCE
            rom.Validate();
#if REPORT_PERFORMANCE
            stopwatch2.Stop();
            _accumulatedPrepareValidateTime += stopwatch2.Elapsed;
#endif // REPORT_PERFORMANCE
            if ((updateMode == LuigiGenerationMode.Passthrough) && (rom.Format == RomFormat.Luigi))
            {
                return(rom.RomPath);
            }
#if REPORT_PERFORMANCE
            stopwatch2.Restart();
            var stopwatch3 = System.Diagnostics.Stopwatch.StartNew();
#endif // REPORT_PERFORMANCE
            var jzIntvConfiguration = SingleInstanceApplication.Instance.GetConfiguration <INTV.JzIntv.Model.Configuration>();
            var converterApps       = jzIntvConfiguration.GetConverterApps(rom, RomFormat.Luigi);
            if (!converterApps.Any())
            {
                converterApps = new[] { new Tuple <string, RomFormat>(JustCopy, RomFormat.Luigi) };
            }
            var converterApp = converterApps.First(); // rom.GetConverterApp(jzIntvConfiguration);
            if ((converterApp.Item1 != JustCopy) && (string.IsNullOrEmpty(converterApp.Item1) || !System.IO.File.Exists(converterApp.Item1)) && (rom.Format != RomFormat.Luigi))
            {
                var message = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RomToLuigiFailed_ConversionToolNotFound_Error_Format, converterApp);
                throw new LuigiFileGenerationException(message, Resources.Strings.RomToLuigiFailed_ConversionToolNotFound_Error_Description);
            }
#if REPORT_PERFORMANCE
            stopwatch3.Stop();
            _accumulatedPrepareConverterAppsTime += stopwatch3.Elapsed;
            stopwatch3.Restart();
#endif // REPORT_PERFORMANCE
            var romStagingArea   = SingleInstanceApplication.Instance.GetConfiguration <Configuration>().RomsStagingAreaPath;
            var stagingAreaPath  = rom.GetStagingAreaPath(romStagingArea);
            var cachedRomPath    = rom.GetCachedRomFilePath(stagingAreaPath);
            var cachedConfigPath = rom.GetCachedConfigFilePath(stagingAreaPath);
            var luigiFile        = rom.GetOutputFilePath(stagingAreaPath, ProgramFileKind.LuigiFile);
#if REPORT_PERFORMANCE
            stopwatch3.Stop();
            _accumulatedPrepareStagingTime += stopwatch3.Elapsed;
            stopwatch3.Restart();
#endif // REPORT_PERFORMANCE

            bool createLuigiFile = true;
            bool changed;
            bool isSourceFileInCache = rom.IsInCache(stagingAreaPath, out changed);
#if REPORT_PERFORMANCE
            stopwatch3.Stop();
            _accumulatedPrepareCacheLookupTime += stopwatch3.Elapsed;
#endif // REPORT_PERFORMANCE

#if REPORT_PERFORMANCE
            stopwatch2.Stop();
            _accumulatedPrepareSetupTime += stopwatch2.Elapsed;

            stopwatch2.Restart();
#endif // REPORT_PERFORMANCE
            var luigiHeader = rom.GetLuigiHeader();
            if (luigiHeader != null)
            {
                // If the given ROM is already a LUIGI file, see if we can determine whether it's already in our cache.
#if REPORT_OLD_LUIGI_FILES
                System.Diagnostics.Debug.Assert(luigiHeader.Version > 0, "Really, you've got some OLD LUIGI files. Delete them.");
#endif // REPORT_OLD_LUIGI_FILES
                var crc24 = INTV.Core.Utility.Crc24.OfFile(rom.RomPath);
                var size  = new System.IO.FileInfo(rom.RomPath).Length;
                var entry = CacheIndex.Find(crc24, (uint)size);
                isSourceFileInCache = entry != null;
                if (isSourceFileInCache)
                {
                    // Cases have been found in which, by moving files around on disk, the staging area path can change.
                    // The result of this, though, is that the *new* path in the cache is different than the extant one
                    // found in the cache. In this case, if the entry's location is different than the newly computed
                    // one, ignore the cache entry and make a new one by acting as if the file is not in the cache.
                    // FIXME This is a lazy fix. A better fix would be to remove the cached files and existing cache
                    // entry and re-add this new one. Or patch up the existing entry. Hell, maybe scrap the entire cache
                    // altogether as it's a bit of a bug farm and creating LUIGI files isn't all *that* expensive.
                    var stagingDirectory   = System.IO.Path.GetFileName(stagingAreaPath);
                    var stagingPathChanged = !entry.LuigiPath.StartsWith(stagingDirectory);
                    if (stagingPathChanged)
                    {
                        isSourceFileInCache = false;
                    }
                    else
                    {
                        luigiFile     = System.IO.Path.Combine(romStagingArea, entry.LuigiPath);
                        cachedRomPath = System.IO.Path.Combine(romStagingArea, entry.RomPath);
                        if (!string.IsNullOrEmpty(entry.CfgPath))
                        {
                            cachedConfigPath = System.IO.Path.Combine(romStagingArea, entry.CfgPath);
                        }
                    }
                }
            }
#if REPORT_PERFORMANCE
            stopwatch2.Stop();
            _accumulatedPrepareLuigiHeaderTime += stopwatch2.Elapsed;

            stopwatch2.Restart();
#endif // REPORT_PERFORMANCE

            if (isSourceFileInCache)
            {
                createLuigiFile = changed || !System.IO.File.Exists(luigiFile);
            }
            if (!isSourceFileInCache || changed)
            {
                cachedRomPath.ClearReadOnlyAttribute();
                cachedConfigPath.ClearReadOnlyAttribute();
                System.IO.File.Copy(rom.RomPath, cachedRomPath, true);
                if (!string.IsNullOrWhiteSpace(cachedConfigPath) && !string.IsNullOrEmpty(rom.ConfigPath) && System.IO.File.Exists(rom.ConfigPath) && (rom.ConfigPath != rom.RomPath))
                {
                    System.IO.File.Copy(rom.ConfigPath, cachedConfigPath, true);
                }
                else if ((string.IsNullOrEmpty(rom.ConfigPath) || !System.IO.File.Exists(rom.ConfigPath)) && System.IO.File.Exists(cachedConfigPath))
                {
                    // The ROM's configuration file path doesn't exist, but there's one in the cache. Remove it.
                    FileUtilities.DeleteFile(cachedConfigPath, false, 2);
                    cachedConfigPath = null; // this is OK, because the ClearReadOnlyAttribute() extension method is null-safe
                }
                cachedRomPath.ClearReadOnlyAttribute();
                cachedConfigPath.ClearReadOnlyAttribute();
            }
#if REPORT_PERFORMANCE
            stopwatch2.Stop();
            _accumulatedPrepareCachedChangedTime += stopwatch2.Elapsed;

            stopwatch2.Restart();
#endif // REPORT_PERFORMANCE

            if (createLuigiFile || ((updateMode == LuigiGenerationMode.FeatureUpdate) || (updateMode == LuigiGenerationMode.Reset)))
            {
                var argument = "\"" + cachedRomPath + "\"" + " \"" + luigiFile + "\"";
                var result   = -1;
                if (JustCopy == converterApp.Item1)
                {
                    System.IO.File.Copy(rom.RomPath, luigiFile, true);
                    result = 0;
                }
                else
                {
                    result = INTV.Shared.Utility.RunExternalProgram.Call(converterApp.Item1, argument, stagingAreaPath);
                }
                if (result == 0)
                {
                    if (!System.IO.File.Exists(luigiFile))
                    {
                        var message = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RomToLuigiFailed_OutputFileNotFound_Error_Format, rom.RomPath, System.IO.Path.GetFileNameWithoutExtension(luigiFile));
                        throw new LuigiFileGenerationException(message, Resources.Strings.RomToLuigiFailed_OutputFileNotFound_Error_Description_Format);
                    }
                    else if ((new System.IO.FileInfo(luigiFile)).Length > Device.TotalRAMSize)
                    {
                        var message = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RomToLuigiFailed_TooLarge_Error_Message_Format, rom.RomPath, luigiFile);
                        throw new LuigiFileGenerationException(message, Resources.Strings.RomToLuigiFailed_TooLarge_Description);
                    }

                    var description = INTV.Shared.Model.Program.ProgramCollection.Roms.FirstOrDefault(d => rom.IsEquivalentTo(d.Rom, RomComparerStrict.Default));
                    if (description != null)
                    {
                        LuigiFeatureFlags features = LuigiFeatureFlags.None;
#if DEBUG
                        var complainAboutOldLuigiFile = false;
#endif // DEBUG
                        luigiHeader = LuigiFileHeader.GetHeader(luigiFile);
                        features    = description.Features.LuigiFeaturesLo;
#if DEBUG
                        var isRecognizedRom     = !description.Features.GeneralFeatures.HasFlag(GeneralFeatures.UnrecognizedRom);
                        var hasFlagsFromCfgFile = luigiHeader.Features.HasFlag(LuigiFeatureFlags.FeatureFlagsExplicitlySet);
                        complainAboutOldLuigiFile = isRecognizedRom && hasFlagsFromCfgFile && ((luigiHeader.Features & ~LuigiFeatureFlags.FeatureFlagsExplicitlySet) != features);
#endif // DEBUG
#if DEBUG
                        if (complainAboutOldLuigiFile)
                        {
                            var message = "Known ROM has explicit flags from utility that are different than those set by LUI:\n\n";
                            message += "  LUI: " + features + "\n";
                            message += "  Utility: " + (luigiHeader.Features & ~LuigiFeatureFlags.FeatureFlagsExplicitlySet);
                            INTV.Shared.View.OSMessageBox.Show(message, "Feature Flags Inconsistency");
                        }
#endif // DEBUG
                        if (luigiHeader.WouldModifyFeatures(features, updateMode == LuigiGenerationMode.FeatureUpdate))
                        {
                            using (var file = System.IO.File.Open(luigiFile, System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite))
                            {
                                luigiHeader.UpdateFeatures(features, updateMode == LuigiGenerationMode.FeatureUpdate);
                                file.Seek(0, System.IO.SeekOrigin.Begin);
                                luigiHeader.Serialize(new Core.Utility.BinaryWriter(file));
                            }
                        }
                    }
                    try
                    {
                        var cacheIndexEntry = new CacheIndexEntry(rom, cachedRomPath);
                        CacheIndex.Instance.AddEntry(cacheIndexEntry);
                    }
                    catch (Exception e)
                    {
                        var message = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.PrepareForDeployment_ErrorCreatingCacheEntryFormat, rom.RomPath);
                        throw new LuigiFileGenerationException(message, e.Message, e);
                    }
                }
                else
                {
                    var message     = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RomToLuigiFailed_InvalidOperation_Error_Message_Format, result);
                    var description = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RomToLuigiFailed_Error_Description_Format, converterApp);
                    throw new LuigiFileGenerationException(message, description);
                }
            }
            else
            {
                // If this is a different ROM that produces the same LUIGI, add an entry.
                var crc24 = INTV.Core.Utility.Crc24.OfFile(luigiFile);
                var size  = (uint)(new System.IO.FileInfo(luigiFile)).Length;
                if (CacheIndex.Find(crc24, size) == null)
                {
                    try
                    {
                        var cacheIndexEntry = new CacheIndexEntry(rom, cachedRomPath);
                        CacheIndex.Instance.AddEntry(cacheIndexEntry);
                    }
                    catch (Exception e)
                    {
                        var message = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.PrepareForDeployment_ErrorCreatingCacheEntryFormat, rom.RomPath);
                        throw new LuigiFileGenerationException(message, e.Message, e);
                    }
                }
            }
            ////catch (System.IO.PathTooLongException e)
            ////catch (System.IO.IOException e)
            ////catch (UnauthorizedAccessException e)
            ////catch (InvalidOperationException e)
            ////catch (LuigiFileGenerationException e)
#if REPORT_PERFORMANCE
            stopwatch2.Stop();
            _accumulatedPrepareLuigiUpdateTime += stopwatch2.Elapsed;
#endif // REPORT_PERFORMANCE

            if (string.IsNullOrEmpty(luigiFile) || !System.IO.File.Exists(luigiFile))
            {
                var message     = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RomToLuigiFailed_Error_Description_Format, rom);
                var description = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RomToLuigiFailed_InvalidOutputFileFormat, luigiFile);
                throw new LuigiFileGenerationException(message, description);
            }

#if REPORT_PERFORMANCE
            stopwatch.Stop();
#endif // REPORT_PERFORMANCE
            return(luigiFile);

#if REPORT_PERFORMANCE
        }

        finally
        {
            stopwatch.Stop();
            _accumulatedPrepareTime += stopwatch.Elapsed;
        }
#endif // REPORT_PERFORMANCE
        }