private static LuigiFileHeader GetLuigiHeaderForFork(ExecuteDeviceCommandAsyncTaskData data, Fork fork) { LuigiFileHeader luigiHeader = null; using (var memory = new System.IO.MemoryStream()) { const uint Address = 0u; var bytesToRead = LuigiFileHeader.MaxHeaderSize; var succeeded = ReadForkToRam.Create(Address, fork.GlobalForkNumber, 0u, bytesToRead).Execute <bool>(data.Device.Port, data); byte[] dataRead = null; if (succeeded) { dataRead = (byte[])DownloadDataBlockFromRam.Create(Address, bytesToRead).Execute(data.Device.Port, data, out succeeded); } if (succeeded) { memory.Write(dataRead, 0, bytesToRead); memory.Seek(0, System.IO.SeekOrigin.Begin); try { luigiHeader = LuigiFileHeader.Inflate(memory); } catch (INTV.Core.UnexpectedFileTypeException) { } } } return(luigiHeader); }
private bool LuigiNeedsUpdate(IRom rom, out IRom luigiRom, out bool treatAsTemporary) { luigiRom = null; treatAsTemporary = false; System.Diagnostics.Debug.Assert(rom.Format != RomFormat.Luigi, "Only non-LUIGI format ROMs should be checked!"); var romPath = rom.RomPath; var luigiPath = Path.ChangeExtension(romPath, RomFormat.Luigi.FileExtension()); if (romPath.IsPathOnRemovableDevice()) { // look in app's local ROMs directory for a LUIGI file var localRomsDirectory = RomListConfiguration.Instance.RomsDirectory; luigiPath = Path.Combine(localRomsDirectory, Path.GetFileName(luigiPath)); treatAsTemporary = File.Exists(luigiPath); if (treatAsTemporary) { luigiPath = luigiPath.EnsureUniqueFileName(); } } var needsUpdate = !File.Exists(luigiPath); if (!needsUpdate) { var luigiHeader = LuigiFileHeader.GetHeader(luigiPath); if (luigiHeader != null) { needsUpdate = (rom.Format != luigiHeader.OriginalRomFormat) || (rom.Crc != luigiHeader.OriginalRomCrc32) || (rom.CfgCrc != luigiHeader.OriginalCfgCrc32); } else { needsUpdate = true; } } return(needsUpdate); }
public void LuigiFileHeader_ReadVersionZeroHeader_DoesNotThrowAndReportsVersionZero() { var romPath = LuigiFileHeaderTestStorageAccess.Initialize(TestRomResources.TestLuigiFromBinWithVersionZeroHeaderPath).First(); var header = LuigiFileHeader.GetHeader(romPath); Assert.Equal(0, header.Version); }
public void GZipAccess_WriteRomResourceToGZipFile_ProducesExpectedResult(CompressedArchiveAccessImplementation implementation) { var gzipFileName = TemporaryFile.GenerateUniqueFilePath("tagalong", ".luigi.gz"); using (TemporaryFile.CreateTemporaryFileWithPath(gzipFileName, createEmptyFile: false)) { // Create on-disk GZIP var inputLength = 0L; var fileStream = new FileStream(gzipFileName, FileMode.Create, FileAccess.Write); using (var gzip = CompressedArchiveAccess.Open(fileStream, CompressedArchiveFormat.GZip, CompressedArchiveAccessMode.Create, implementation)) { var testResourceName = "INTV.TestHelpers.Core.Resources.tagalong.luigi"; var newGZipEntryName = "tagalong.luigi"; var entry = gzip.CreateEntry(newGZipEntryName); using (var gzipStream = gzip.Open(entry.Name)) using (var sourceStream = typeof(TestRomResources).Assembly.GetManifestResourceStream(testResourceName)) { sourceStream.CopyTo(gzipStream); inputLength = sourceStream.Length; } } // Now, see if we can extract it! var extractedRomPath = Path.Combine(Path.GetDirectoryName(gzipFileName), Path.GetFileNameWithoutExtension(gzipFileName)); using (TemporaryFile.CreateTemporaryFileWithPath(extractedRomPath, createEmptyFile: false)) { var fileInfo = new FileInfo(gzipFileName); Assert.True(fileInfo.Exists); Assert.True(inputLength > fileInfo.Length); // Compressed we must be! On this, all depends. using (var gzip = CompressedArchiveAccess.Open(gzipFileName, CompressedArchiveAccessMode.Read, implementation)) { Assert.True(gzip.Entries.Any()); var entry = gzip.Entries.Single(); Assert.False(string.IsNullOrEmpty(entry.Name)); using (var outputFileStream = new FileStream(extractedRomPath, FileMode.Create, FileAccess.Write)) using (var gzipStream = gzip.OpenEntry(entry)) { gzipStream.CopyTo(outputFileStream); } } // Verify we have a valid LUIGI and it's got what we expect inside. Trust, but verify! LuigiFileHeader header = null; using (var outputFileStream = new FileStream(extractedRomPath, FileMode.Open, FileAccess.Read)) { header = LuigiFileHeader.Inflate(outputFileStream); } Assert.NotNull(header); Assert.Equal(RomFormat.Bin, header.OriginalRomFormat); Assert.Equal(TestRomResources.TestBinCrc, header.OriginalRomCrc32); } } }
public void LuigiFileHeader_IsPotentialLuigiFile_ProvidesCorrectResult(string resourceToRegister, string potentialLuigiFilePath, bool expectedIsPotentialLuigiFile) { var romFilePath = LuigiFileHeaderTestStorageAccess.Initialize(resourceToRegister).First(); if (string.IsNullOrEmpty(potentialLuigiFilePath)) { potentialLuigiFilePath = romFilePath; } Assert.Equal(expectedIsPotentialLuigiFile, LuigiFileHeader.PotentialLuigiFile(potentialLuigiFilePath)); }
public void LuigiFileHeader_SerializeHeaderFromTestRom_SerializesCorrectNumberOfBytes() { var romPath = LuigiFileHeaderTestStorageAccess.Initialize(TestRomResources.TestLuigiFromBinPath).First(); var header = LuigiFileHeader.GetHeader(romPath); using (var writer = new BinaryWriter(new System.IO.MemoryStream())) { var bytesSerialized = header.Serialize(writer); Assert.Equal(32, bytesSerialized); } }
public void LuigiFileHeader_DeserializeWithTruncatedMagicKey_ThrowsUnexpectedFileTypeException() { var bogusHeaderMagic = "LT"; using (var stream = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(bogusHeaderMagic))) { using (var reader = new BinaryReader(stream)) { Assert.Throws <UnexpectedFileTypeException>(() => LuigiFileHeader.Inflate(reader)); } } }
public void LuigiFileHeader_GetFromValidLuigiRom_DoesNotThrowAndReportsExpectedVersion() { IReadOnlyList <string> paths; var storage = LuigiFileHeaderTestStorageAccess.Initialize(out paths, TestRomResources.TestLuigiFromRomPath); using (var reader = new BinaryReader(storage.Open(paths.First()))) { var header = LuigiFileHeader.Inflate(reader); Assert.Equal(1, header.Version); Assert.Equal(32, header.DeserializeByteCount); } }
public void LuigiFileHeader_SerializeDefaultVersionZeroHeader_SerializesCorrectNumberOfBytes() { var header = new LuigiFileHeader() { Reserved = new byte[LuigiFileHeader.ReservedHeaderBytesSize] }; using (var writer = new BinaryWriter(new System.IO.MemoryStream())) { var bytesSerialized = header.Serialize(writer); Assert.Equal(16, bytesSerialized); } }
public void LuigiFileHeader_DeserializeWithTruncatedHeaderAfterKey_ThrowsEndOfStreamException() { var truncatedHeader = new byte[] { 0x4C, 0x54, 0x4F // LTO }; using (var stream = new System.IO.MemoryStream(truncatedHeader)) { using (var reader = new BinaryReader(stream)) { Assert.Throws <System.IO.EndOfStreamException>(() => LuigiFileHeader.Inflate(reader)); } } }
public void LuigiFileHeader_DeserializeWithTruncatedHeaderInUid_ThrowsEndOfStreamException() { var truncatedHeader = new byte[] { 0x4C, 0x54, 0x4F, 0x01, // LTO, version 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // features (v1) }; using (var stream = new System.IO.MemoryStream(truncatedHeader)) { using (var reader = new BinaryReader(stream)) { Assert.Throws <System.IO.EndOfStreamException>(() => LuigiFileHeader.Inflate(reader)); } } }
/// <summary> /// Initializes a new instance of the <see cref="INTV.Core.Model.Program.LuigiFileMetadataProgramInformation"/> class. /// </summary> /// <param name="header">A LUIGI file header that describes the ROM's features.</param> /// <param name="metadata">Additional ROM metadata, if any.</param> public LuigiFileMetadataProgramInformation(LuigiFileHeader header, LuigiMetadataBlock metadata) { _features = ProgramFeatures.Combine(header.Features.ToProgramFeatures(), header.Features2.ToProgramFeatures()); _crc = new CrcData(header.OriginalRomCrc32, string.Empty, _features.ToIncompatibilityFlags()); Metadata = metadata; if (metadata != null) { _title = metadata.LongNames.FirstOrDefault(); _vendor = metadata.Publishers.FirstOrDefault(); if (metadata.ReleaseDates.Any()) { _year = metadata.ReleaseDates.First().Date.Year.ToString(); } _shortName = metadata.ShortNames.FirstOrDefault(); } }
public void LuigiFileHeader_UpdateFeaturesOnScrambledLuigiRom_UpdatesFeatures(LuigiFeatureFlags newFeatures, bool forceFeatureUpdate) { var romPath = LuigiFileHeaderTestStorageAccess.Initialize(TestRomResources.TestLuigiScrambledForDevice0Path).First(); var header = LuigiFileHeader.GetHeader(romPath); var originalCrc = header.Crc; Assert.Equal(0xEC, header.Crc); var crcShouldChange = header.Features != newFeatures; header.UpdateFeatures(newFeatures, forceFeatureUpdate); Assert.Equal(newFeatures, header.Features); Assert.Equal(crcShouldChange, header.Crc != originalCrc); }
public void LuigiFileHeader_UpdateFeaturesOnLuigiWithMetadata_UpdatesFeatures(LuigiFeatureFlags newFeatures, bool forceFeatureUpdate) { var romPath = LuigiFileHeaderTestStorageAccess.Initialize(TestRomResources.TestLuigiScrambledForDevice1Path).First(); var header = LuigiFileHeader.GetHeader(romPath); var originalCrc = header.Crc; var expectedFeatures = header.WouldModifyFeatures(newFeatures, forceFeatureUpdate) ? newFeatures : header.Features; Assert.Equal(0x8B, originalCrc); var crcShouldChange = header.Features != expectedFeatures; header.UpdateFeatures(newFeatures, forceFeatureUpdate); Assert.Equal(expectedFeatures, header.Features); Assert.Equal(crcShouldChange, header.Crc != originalCrc); }
/// <inheritdoc /> internal override void LoadComplete(FileSystem fileSystem, bool updateRomList) { base.LoadComplete(fileSystem, updateRomList); if (Description == null) { if (Rom != null) { if (Crc32 == 0) { var filePath = Rom.FilePath; INTV.Core.Model.LuigiFileHeader luigiHeader = LuigiFileHeader.GetHeader(filePath); if (luigiHeader != null) { string cfgFile = null; string romFile = filePath; uint crc = 0u; if (luigiHeader.Version > 0) { crc = luigiHeader.OriginalRomCrc32; } else { var jzIntvConfiguration = INTV.Shared.Utility.SingleInstanceApplication.Instance.GetConfiguration <INTV.JzIntv.Model.Configuration>(); var luigiToBinPath = jzIntvConfiguration.GetProgramPath(JzIntv.Model.ProgramFile.Luigi2Bin); var luigiToBinResult = RunExternalProgram.Call(luigiToBinPath, "\"" + filePath + "\"", System.IO.Path.GetDirectoryName(filePath)); if (luigiToBinResult == 0) { romFile = System.IO.Path.ChangeExtension(filePath, RomFormat.Bin.FileExtension()); cfgFile = System.IO.Path.ChangeExtension(filePath, ProgramFileKind.CfgFile.FileExtension()); if (!System.IO.File.Exists(cfgFile)) { cfgFile = null; } } } var rom = INTV.Core.Model.Rom.Create(romFile, cfgFile); var programInfo = rom.GetProgramInformation(); var programDescription = new ProgramDescription(rom.Crc, rom, programInfo); Description = programDescription; } } } } }
public void LuigiFileHeader_DeserializeWithFutureVersion_ThrowsInvalidOperationException() { var futureHeader = new byte[] { 0x4C, 0x54, 0x4F, 0xD0, // LTO, version -- bogus instead of 0x01 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // features (v1) 0x81, 0x93, 0x43, 0xB0, 0x0C, 0x47, 0x3F, 0x12, // UID 0x00, 0x00, 0x00, // reserved 0x8B // CRC }; using (var stream = new System.IO.MemoryStream(futureHeader)) { using (var reader = new BinaryReader(stream)) { Assert.Throws <InvalidOperationException>(() => LuigiFileHeader.Inflate(reader)); } } }
/// <summary> /// Initializes a new instance of the <see cref="INTV.LtoFlash.Model.CacheIndexEntry"/> class. /// </summary> /// <param name="rom">The ROM described the entry.</param> /// <param name="romAbsolutePath">Absolute path to the ROM.</param> public CacheIndexEntry(IRom rom, string romAbsolutePath) { var romStagingArea = SingleInstanceApplication.Instance.GetConfiguration <Configuration>().RomsStagingAreaPath; RomPath = romAbsolutePath.Substring(romStagingArea.Length + 1); RomCrc32 = rom.Crc; RomSize = (uint)(new FileInfo(romAbsolutePath)).Length; if (rom.Format == RomFormat.Bin) { var cfgFilePath = Path.ChangeExtension(romAbsolutePath, ProgramFileKind.CfgFile.FileExtension()); if (File.Exists(cfgFilePath)) { CfgPath = cfgFilePath.Substring(romStagingArea.Length + 1); CfgCrc32 = INTV.Core.Utility.Crc32.OfFile(cfgFilePath); CfgSize = (uint)(new FileInfo(cfgFilePath)).Length; } } var luigiFilePath = rom.GetLtoFlashFilePath(); LuigiPath = luigiFilePath.Substring(romStagingArea.Length + 1); if (!System.IO.File.Exists(luigiFilePath) && LuigiFileHeader.PotentialLuigiFile(romAbsolutePath)) { // This has been known to happen in the transition between naming conventions, but also arises generally when // a ROM in the main ROM list has always been a LUIGI file. We have an original LUIGI file, // and find a cache entry, and are updating it -- we may not have the newly named LUIGI file yet. So, just copy it. // What happens is, *in the cache* we found foo.luigi, but the cached file path has become foo_luigi.luigi. if (System.IO.File.Exists(romAbsolutePath)) { System.IO.File.Copy(romAbsolutePath, luigiFilePath, true); } } LuigiCrc24 = INTV.Core.Utility.Crc24.OfFile(luigiFilePath); LuigiSize = (uint)(new FileInfo(luigiFilePath)).Length; }
private System.Exception UpdateFilePath(string filePath, bool forceUpdate) { #if REPORT_PERFORMANCE System.Diagnostics.Debug.WriteLine(">>>> ENTER Fork.UpdateFilePath(" + filePath + "," + forceUpdate + ") + T:" + System.Threading.Thread.CurrentThread.ManagedThreadId); var stopwatch = System.Diagnostics.Stopwatch.StartNew(); try { #endif // REPORT_PERFORMANCE System.Exception error = null; if ((FileSystem != null) && FileSystem.Frozen) { // During save, do not attempt to regenerate contents. return(error); } try { // Do some special work if this is a ROM fork. if ((FileSystem != null) && (FileSystem.GetForkKind(this) == ForkKind.Program)) { if (forceUpdate) { #if REPORT_PERFORMANCE System.Diagnostics.Debug.WriteLine(">>>>>> ENTER Fork.UpdateFilePath(forceUpdate): GetRom"); var stopwatch2 = System.Diagnostics.Stopwatch.StartNew(); try { #endif // REPORT_PERFORMANCE var filesUsingFork = FileSystem.GetFilesUsingForks(new[] { this }).Values; foreach (var program in filesUsingFork.OfType <Program>()) { // Since "Program" entries using the same Fork will all point to this one, // we don't need to re-do this work for every file that might point at the fork. var rom = program.Description.GetRom(); if ((rom != null) && !string.IsNullOrEmpty(rom.RomPath)) { var path = string.Empty; #if REPORT_PERFORMANCE var stopwatch3 = System.Diagnostics.Stopwatch.StartNew(); #endif // REPORT_PERFORMANCE path = rom.PrepareForDeployment(LuigiGenerationMode.Standard); #if REPORT_PERFORMANCE stopwatch3.Stop(); AccumulatedUpdateFilePathForcedPrepareTime += stopwatch3.Elapsed; #endif // REPORT_PERFORMANCE UpdateFilePath(path); } } #if REPORT_PERFORMANCE } finally { stopwatch2.Stop(); System.Diagnostics.Debug.WriteLine(">>>>>> EXIT Fork.UpdateFilePath(forceUpdate): GetRom"); // took: + " + stopwatch2.Elapsed.ToString()); AccumulatedUpdateFilePathForcedTime += stopwatch2.Elapsed; } #endif // REPORT_PERFORMANCE } else { var rom = Rom; var prepareForDeployment = string.IsNullOrEmpty(filePath) && (rom != null); if (!prepareForDeployment && (rom != null)) { // We think we don't have to prepare for deployment, but do have ROM set. // Let's just make sure that we have that LUIGI file, shall we? prepareForDeployment = string.IsNullOrEmpty(_filePath) || !System.IO.File.Exists(_filePath); if (!prepareForDeployment && System.IO.File.Exists(_filePath)) { // Check to see if it looks like a valid LUIGI file. prepareForDeployment = LuigiFileHeader.GetHeader(_filePath) == null; } } if (prepareForDeployment) { // No file path, but somehow we have a ROM. Force recreation of the LUIGI file. This can // occur during sync from device. UpdateFilePath(Rom.PrepareForDeployment(LuigiGenerationMode.Standard)); } else if (rom == null) { if (!System.IO.File.Exists(filePath)) { // No ROM, and the file we think we have does not exist. ILfsFileInfo file; rom = null; if (FileSystem.GetFilesUsingForks(new[] { this }).TryGetValue(this, out file)) { switch (FileSystem.Origin) { case FileSystemOrigin.HostComputer: var description = ((Program)file).Description; rom = description == null ? null : description.GetRom(); break; case FileSystemOrigin.LtoFlash: break; } } prepareForDeployment = (rom != null) && !System.IO.File.Exists(filePath) && !string.IsNullOrEmpty(rom.RomPath) && System.IO.File.Exists(rom.RomPath); if (prepareForDeployment) { _filePath = null; UpdateFilePath(rom.PrepareForDeployment(LuigiGenerationMode.Standard)); } } // We should *always* be a LUIGI file. If not, fix it! if (!string.IsNullOrEmpty(filePath) && System.IO.File.Exists(filePath)) { if (!LuigiFileHeader.PotentialLuigiFile(filePath)) { rom = INTV.Core.Model.Rom.Create(filePath, null); prepareForDeployment = rom != null; if (prepareForDeployment) { _filePath = null; UpdateFilePath(rom.PrepareForDeployment(LuigiGenerationMode.Standard)); } } } } } } else { if (forceUpdate) { _filePath = null; } UpdateFilePath(filePath); if (forceUpdate && !string.IsNullOrEmpty(_filePath) && !System.IO.File.Exists(_filePath)) { error = new System.IO.FileNotFoundException("File for fork " + GlobalForkNumber + " not found.", filePath, null); } } } catch (System.IO.IOException e) { error = e; if (!forceUpdate) { throw; } } return(error); #if REPORT_PERFORMANCE } finally { stopwatch.Stop(); System.Diagnostics.Debug.WriteLine(">>>> EXIT Fork.UpdateFilePath(" + filePath + ",force)"); // took: + " + stopwatch.Elapsed.ToString()); AccumulatedUpdateFilePathTime += stopwatch.Elapsed; } #endif // REPORT_PERFORMANCE }
public void LuigiFileHeader_DeserializeWithCorruptedFeatures_ThrowsInvalidDataException() { var badCrcHeader = new byte[] { 0x4C, 0x54, 0x4F, 0x01, // LTO, version 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // features (v1) (corrupted) 0x81, 0x93, 0x43, 0xB0, 0x0C, 0x47, 0x3F, 0x12, // UID 0x00, 0x00, 0x00, // reserved 0x8B // CRC }; using (var stream = new System.IO.MemoryStream(badCrcHeader)) { using (var reader = new BinaryReader(stream)) { var exception = Assert.Throws <System.IO.InvalidDataException>(() => LuigiFileHeader.Inflate(reader)); var expectedMessage = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.InvalidDataBlockChecksumFormat, 0x61, 0x8B); Assert.Equal(expectedMessage, exception.Message); } } }
public void LuigiFileHeader_SerializeByteCount_IsNegativeOne() { var header = new LuigiFileHeader(); Assert.Equal(-1, header.SerializeByteCount); }
private static bool SyncForkData(Fork fork, ForkKind forkKind, Dictionary <ushort, string> forkSourceFileMap, Action <Fork, ForkKind> errorAction, ref ProgramDescription description) { var succeeded = true; if (fork != null) { var crc = 0u; switch (forkKind) { case ForkKind.Program: var cfgCrc = 0u; var cacheEntry = CacheIndex.Find(fork.Crc24, fork.Size); if (cacheEntry != null) { crc = cacheEntry.RomCrc32; cfgCrc = cacheEntry.CfgCrc32; } else { string romPath; if (forkSourceFileMap.TryGetValue(fork.GlobalForkNumber, out romPath) && !string.IsNullOrEmpty(romPath) && System.IO.File.Exists(romPath)) { if (LuigiFileHeader.PotentialLuigiFile(romPath)) { var luigiHeader = LuigiFileHeader.GetHeader(romPath); if (luigiHeader.Version > 0) { crc = luigiHeader.OriginalRomCrc32; cfgCrc = luigiHeader.OriginalCfgCrc32; } } if (crc == 0u) { crc = Crc32.OfFile(romPath); } } else { System.Console.WriteLine("SDFS"); } } if (crc != 0) { var romListDescriptions = INTV.Shared.Model.Program.ProgramCollection.Roms.Where(d => d.Crc == crc); if (romListDescriptions.Any()) { var romListDescription = romListDescriptions.FirstOrDefault(d => (d.Rom != null) && (d.Rom.CfgCrc == cfgCrc)); if (romListDescription != null) { description = romListDescription.Copy(); } } } if (description == null) { var rom = fork.Rom; if (rom == null) { string romPath; succeeded = forkSourceFileMap.TryGetValue(fork.GlobalForkNumber, out romPath); if (succeeded) { rom = Rom.Create(romPath, null); fork.Rom = rom; if (string.IsNullOrEmpty(fork.FilePath)) { fork.FilePath = romPath; } } } if (rom != null) { var programInfo = rom.GetProgramInformation(); description = new ProgramDescription(rom.Crc, rom, programInfo); } } break; case ForkKind.Manual: string filePath; if (forkSourceFileMap.TryGetValue(fork.GlobalForkNumber, out filePath) && System.IO.File.Exists(filePath)) { fork.FilePath = filePath; if (description != null) { description.Files.DefaultManualTextPath = fork.FilePath; } } break; case ForkKind.JlpFlash: // TODO / FIXME : We don't do anything with JLP save data forks when syncing from the file system. break; case ForkKind.Vignette: case ForkKind.Reserved4: case ForkKind.Reserved5: case ForkKind.Reserved6: succeeded = false; break; } } if (!succeeded && (errorAction != null)) { errorAction(fork, forkKind); } return(succeeded); }
public void LuigiFileHeader_IsPotentialLuigiFile_ThrowsArgumentNullException() { LuigiFileHeaderTestStorageAccess.Initialize(); Assert.Throws <ArgumentNullException>(() => LuigiFileHeader.PotentialLuigiFile(null)); }
private static string GetPathForFork(ExecuteDeviceCommandAsyncTaskData data, Fork fork, FileSystem deviceFileSystem, IEnumerable <ProgramDescription> roms, RomListConfiguration romsConfiguration, ref string destinationDir, out bool retrievalNecessary) { retrievalNecessary = false; string forkPath = null; var forkFileKind = ProgramFileKind.None; var crc = 0u; var cfgCrc = 0u; var errors = data.Result as FileSystemSyncErrors; // Determine what kind of fork this is. ILfsFileInfo fileContainingFork = null; var forkKind = deviceFileSystem.GetForkKind(fork, out fileContainingFork); switch (forkKind) { case ForkKind.Program: // Try to fetch LUIGI header from the fork. forkFileKind = ProgramFileKind.LuigiFile; forkPath = GetRomPathForForkFromRomList(data, fork, roms, romsConfiguration.RomsDirectory, out crc, out cfgCrc); if (forkPath == null) { forkPath = GetRomPathForForkFromCache(fork, romsConfiguration.RomsDirectory); } if ((forkPath == null) && string.IsNullOrEmpty(destinationDir)) { destinationDir = romsConfiguration.RomsDirectory; } break; case ForkKind.JlpFlash: if (string.IsNullOrEmpty(destinationDir)) { destinationDir = romsConfiguration.RomsDirectory; // seems sensible to keep save data file(s) next to the ROM } forkFileKind = ProgramFileKind.SaveData; break; case ForkKind.Manual: if (string.IsNullOrEmpty(destinationDir)) { destinationDir = romsConfiguration.ManualsDirectory; } forkFileKind = ProgramFileKind.ManualText; break; case ForkKind.Vignette: if (string.IsNullOrEmpty(destinationDir)) { destinationDir = Configuration.Instance.VignetteDataAreaPath; // keep next to ROM? } forkFileKind = ProgramFileKind.Vignette; break; case ForkKind.Reserved4: case ForkKind.Reserved5: case ForkKind.Reserved6: if (string.IsNullOrEmpty(destinationDir)) { destinationDir = Configuration.Instance.ReservedDataAreaPath; // keep next to ROM? } forkFileKind = ProgramFileKind.GenericSupportFile; errors.UnsupportedForks.Add(new Tuple <ILfsFileInfo, Fork>(fileContainingFork, fork)); ////throw new UnsupportedForkKindException(forkKind); break; case ForkKind.None: // An orphaned fork. Retrieve it, but we can't really do much with it. if (string.IsNullOrEmpty(destinationDir)) { destinationDir = Configuration.Instance.RecoveredDataAreaPath; // orphaned fork } forkFileKind = ProgramFileKind.None; errors.OrphanedForks.Add(fork); break; default: throw new UnsupportedForkKindException(forkKind); } if ((destinationDir != null) && (forkPath == null)) { retrievalNecessary = true; var forkFileBaseName = (fileContainingFork == null) ? Configuration.Instance.GetForkDataFileName(fork.GlobalForkNumber) : fileContainingFork.LongName.EnsureValidFileName(); var extension = forkFileKind.FileExtension(); // For the menu position fork, use the default extension; since it's in the manual fork slot, we want // to override the .txt extension. if (string.IsNullOrEmpty(extension) || (fork.Uid == Fork.MenuPositionForkUid)) { extension = Configuration.ForkExtension; } var forkFileName = System.IO.Path.ChangeExtension(forkFileBaseName, extension); var destFile = System.IO.Path.Combine(destinationDir, forkFileName); if (System.IO.File.Exists(destFile)) { var existingCrc = 0u; var existingCfgCrc = 0u; var luigiHeader = LuigiFileHeader.GetHeader(destFile); if ((luigiHeader != null) && (luigiHeader.Version > 0)) { existingCrc = luigiHeader.OriginalRomCrc32; existingCfgCrc = luigiHeader.OriginalCfgCrc32; } if (existingCrc == 0) { existingCrc = Crc32.OfFile(destFile); } if (existingCfgCrc == 0) { var destCfgFile = System.IO.Path.ChangeExtension(destFile, ProgramFileKind.CfgFile.FileExtension()); if (System.IO.File.Exists(destCfgFile)) { existingCfgCrc = Crc32.OfFile(destCfgFile); } } // This is the equivalent of RomComparerStrict: We skip retrieval only if both the ROM CRCs match and, if available, the .cfg CRCs match. if ((crc != 0) && (existingCrc == crc) && ((cfgCrc == 0) || (existingCfgCrc == cfgCrc))) { retrievalNecessary = false; forkPath = destFile; } else { forkPath = destFile.EnsureUniqueFileName(); } } else { forkPath = destFile; } } if (!string.IsNullOrEmpty(forkPath) && !System.IO.File.Exists(forkPath)) { retrievalNecessary = true; destinationDir = System.IO.Path.GetDirectoryName(forkPath); } return(forkPath); }
/// <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); }
public void LuigiFileHeader_WouldModifyFeatures_ProducesCorrectResult(LuigiFeatureFlags newFeatures, bool forceFeatureUpdate, bool expectedWouldModify) { var header = new LuigiFileHeader(); Assert.Equal(expectedWouldModify, header.WouldModifyFeatures(newFeatures, forceFeatureUpdate)); }
private static bool RetrieveForkData(this Device device, ExecuteDeviceCommandAsyncTaskData data, IEnumerable <Fork> forksToRetrieve, string destinationDirectory, IEnumerable <string> fileNames) { var configuration = SingleInstanceApplication.Instance.GetConfiguration <Configuration>(); var succeeded = false; var numForks = forksToRetrieve.Count(); var forkFilenames = fileNames == null ? null : fileNames.ToList(); var forkBeingRetrieved = 0; foreach (var fork in forksToRetrieve) { if (data.AcceptCancelIfRequested()) { break; } ++forkBeingRetrieved; if (data != null) { data.UpdateTaskProgress((double)forkBeingRetrieved / numForks, string.Format(Resources.Strings.DeviceMultistageCommand_BackupFileSystem_RetrievingFiles_Format, forkBeingRetrieved, numForks)); } var bytesRemaining = (int)fork.Size; var offset = 0; succeeded = false; using (var memory = new System.IO.MemoryStream()) { do { const uint Address = 0u; var bytesToRead = System.Math.Min(bytesRemaining, Device.TotalRAMSize); succeeded = ReadForkToRam.Create(Address, fork.GlobalForkNumber, (uint)offset, bytesToRead).Execute <bool>(device.Port, data); byte[] dataRead = null; if (succeeded) { dataRead = (byte[])DownloadDataBlockFromRam.Create(Address, bytesToRead).Execute(device.Port, data, out succeeded); } if (succeeded) { memory.Write(dataRead, offset, bytesToRead); bytesRemaining -= bytesToRead; offset += bytesToRead; } }while (succeeded && (bytesRemaining > 0)); if (data != null) { data.UpdateTaskProgress((double)forkBeingRetrieved / numForks, string.Format(Resources.Strings.DeviceMultistageCommand_BackupFileSystem_SavingFiles_Format, forkBeingRetrieved, numForks)); } memory.Seek(0, System.IO.SeekOrigin.Begin); using (var tempFile = FileSystemFile.Inflate(memory)) { var fileName = (forkFilenames == null) ? configuration.GetForkDataFileName(fork.GlobalForkNumber) : forkFilenames[forkBeingRetrieved - 1]; var forkPath = System.IO.Path.Combine(destinationDirectory, fileName); forkPath = forkPath.EnsureUniqueFileName(); data.FailureMessage = forkPath; System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(forkPath)); try { // Test to see if this is a Fork containing a LUIGI file. memory.Seek(0, System.IO.SeekOrigin.Begin); LuigiFileHeader.Inflate(memory); forkPath = System.IO.Path.ChangeExtension(forkPath, ProgramFileKind.LuigiFile.FileExtension()); } catch (INTV.Core.UnexpectedFileTypeException) { // This is OK... we only want to execute certain functions if the file is a LUIGI file. } if (System.IO.File.Exists(forkPath)) { var crcOfTarget = Crc32.OfFile(forkPath); var crcOfSource = Crc32.OfFile(tempFile.FileInfo.FullName); if (crcOfTarget != crcOfSource) { forkPath = forkPath.EnsureUniqueFileName(); System.IO.File.Copy(tempFile.FileInfo.FullName, forkPath); } } else { System.IO.File.Copy(tempFile.FileInfo.FullName, forkPath); } fork.FilePath = forkPath; } } if (!succeeded) { break; } } return(succeeded); }
/// <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 }