private static string GetRomPathForForkFromCache(Fork fork, string destDir)
        {
            string romPath = null;
            var    entry   = CacheIndex.Find(fork.Crc24, fork.Size);

            if (entry != null)
            {
                var destFile = System.IO.Path.Combine(destDir, System.IO.Path.GetFileName(entry.RomPath));
                if (System.IO.File.Exists(destFile))
                {
                    var crc = Crc32.OfFile(destFile);
                    if (crc == entry.RomCrc32)
                    {
                        romPath = destFile;
                    }
                    else
                    {
                        destFile = destFile.EnsureUniqueFileName();
                    }
                }
                if (romPath == null)
                {
                    var copySourceDir = System.IO.Path.GetDirectoryName(CacheIndex.Path);
                    var sourceFile    = System.IO.Path.Combine(copySourceDir, entry.RomPath);
                    System.IO.File.Copy(sourceFile, destFile);
                    romPath = destFile;
                }
            }
            return(romPath);
        }
Пример #2
0
        /// <summary>
        /// Assigns a fork.
        /// </summary>
        /// <param name="kind">The kind of fork to assign.</param>
        /// <param name="fork">The actual fork to assign.</param>
        protected void SetFork(ForkKind kind, Fork fork)
        {
            switch (kind)
            {
            case ForkKind.NumberOfForkKinds:
            case ForkKind.None:
                break;

            default:
                var previousFork = _forks[(int)kind];
                _forks[(int)kind] = fork;
                if (previousFork != null)
                {
#if DEBUG_ENTRY_REMOVAL
                    var activityBuilder = new System.Text.StringBuilder();
                    var oldForkString   = (previousFork == null) ? "<null>" : previousFork.ToString();
                    var newForkString   = (fork == null) ? "<null>" : fork.ToString();
                    activityBuilder.AppendLine("Removing fork from file system in SetForks:");
                    activityBuilder.AppendFormat("  old: {0}", oldForkString).AppendLine();
                    activityBuilder.AppendFormat("  new: {0}", newForkString).AppendLine();
                    if (fork == null)
                    {
                        activityBuilder.AppendLine("  Stack Trace when setting to null:");
                        activityBuilder.Append(System.Environment.StackTrace);
                    }
                    FileSystem.Forks.LogActivity(activityBuilder.ToString());
#endif // DEBUG_ENTRY_REMOVAL
                    FileSystem.Forks.Remove(previousFork);
                }
                break;
            }
        }
Пример #3
0
        private Fork GetFork(ForkKind which)
        {
            Fork fork             = null;
            var  globalForkNumber = _forks[(int)which];

            if (globalForkNumber < GlobalForkTable.TableSize)
            {
                fork = FileSystem.Forks[globalForkNumber];
            }
            return(fork);
        }
Пример #4
0
        /// <summary>
        /// Finishes initializing the MenuLayout after it is loaded into memory.
        /// </summary>
        /// <param name="updateRomList">If <c>true</c>, also update the ROM list.</param>
        public void LoadComplete(bool updateRomList)
        {
            LoadComplete(FileSystem, updateRomList);
#if DEBUG_RESERVED_FORKS
            foreach (var file in FileSystem.Files)
            {
                if (file != null)
                {
                    var reservedFork = new Fork(CacheIndex.Path);
                    FileSystem.Forks.Add(reservedFork);
                    file.ReservedFork4 = reservedFork;
                }
            }
#endif // DEBUG_RESERVED_FORKS
        }
Пример #5
0
        /// <summary>
        /// Determines whether the given fork entry is contained in the fork add, update or delete differences.
        /// </summary>
        /// <param name="fork">The fork to search for.</param>
        /// <param name="operation">Which kind of operations to search for.</param>
        /// <returns><c>true</c> if the given fork participates in any of the given operations.</returns>
        public bool Contains(Fork fork, LfsOperations operation)
        {
            var isInDiff = false;

            if (operation.HasFlag(LfsOperations.Add))
            {
                isInDiff |= ForkDifferences.ToAdd.Any(f => f.GlobalForkNumber == fork.GlobalForkNumber);
            }
            if (operation.HasFlag(LfsOperations.Update))
            {
                isInDiff |= ForkDifferences.ToUpdate.Any(f => f.GlobalForkNumber == fork.GlobalForkNumber);
            }
            if (operation.HasFlag(LfsOperations.Remove))
            {
                isInDiff |= ForkDifferences.ToDelete.Contains(fork.GlobalForkNumber) || ForkDifferences.ToUpdate.Any(f => f.GlobalForkNumber == fork.GlobalForkNumber);
            }
            return(isInDiff);
        }
Пример #6
0
        /// <summary>
        /// Determines whether a file is using a particular Fork.
        /// </summary>
        /// <param name="file">The file whose Forks are being searched.</param>
        /// <param name="fork">The fork of interest.</param>
        /// <returns><c>true</c> if the file uses the given Fork.</returns>
        public static bool UsesFork(this ILfsFileInfo file, Fork fork)
        {
            bool usesFork = false;

            if (file != null && fork != null)
            {
                Fork[] forks = new Fork[(int)ForkKind.NumberOfForkKinds]
                {
                    file.Rom,
                    file.Manual,
                    file.JlpFlash,
                    file.Vignette,
                    file.ReservedFork4,
                    file.ReservedFork5,
                    file.ReservedFork6,
                };
                usesFork = forks.Contains(fork);
            }
            return(usesFork);
        }
Пример #7
0
        /// <inheritdoc/>
        public override int Deserialize(INTV.Core.Utility.BinaryReader reader)
        {
            var asciiReader = (INTV.Shared.Utility.ASCIIBinaryReader)reader;
            var bytesRead   = Directories.Deserialize(asciiReader);

            bytesRead += Files.Deserialize(asciiReader);
            bytesRead += Forks.Deserialize(asciiReader);

#if FORCE_JLPFLASH_FORKS
            foreach (var file in Files.Where(f => (f != null)))
            {
                var fakeDataFork = new Fork();
                fakeDataFork.Size  = 0x0600;
                fakeDataFork.Crc24 = INTV.Core.Utility.RandomUtilities.Next24();
                Forks.Add(fakeDataFork);
                file.JlpFlash = fakeDataFork;
            }
#endif // FORCE_JLPFLASH_FORKS

            return(bytesRead);
        }
Пример #8
0
        private void UpdateFork(ForkKind kind, string filePath)
        {
            Fork fork = null;

            switch (kind)
            {
            case ForkKind.Program:
                if (!string.IsNullOrWhiteSpace(filePath))
                {
                    fork = FileSystem.Forks.AddFork(Description.GetRom());
                    if (PathComparer.Instance.Compare(filePath, fork.FilePath) != 0)
                    {
                        // Hmmm.... The path changed. It's possible we got a de-dupe here. So only complain if we have zero file size or default CRC.
                        if ((fork.Size == 0) || (fork.Crc24 == INTV.Core.Utility.Crc24.InvalidCrc))
                        {
                            var forkFilePath = string.IsNullOrEmpty(fork.FilePath) ? "<null>" : fork.FilePath;
                            var description  = string.Format(Resources.Strings.RomToLuigiFailed_FilePathsDoNotMatchFormat, filePath, forkFilePath);
                            throw new LuigiFileGenerationException(Resources.Strings.RomToLuigiFailed_FilePathsDoNotMatchMessage, description);
                        }
                    }
                    if (!System.IO.File.Exists(fork.FilePath))
                    {
                        var message = string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.RomToLuigiFailed_OutputFileNotFound_Error_Format, Description.Rom.RomPath, fork.FilePath);
                        throw new LuigiFileGenerationException(message, Resources.Strings.RomToLuigiFailed_OutputFileNotFound_Error_Description_Format);
                    }
                }
                break;

            default:
                if (!string.IsNullOrWhiteSpace(filePath))
                {
                    if (System.IO.File.Exists(filePath))
                    {
                        fork = FileSystem.Forks.AddFork(filePath);
                    }
                }
                break;
            }
            SetFork(kind, fork);
        }
Пример #9
0
 private void SetFork(ForkKind which, Fork fork)
 {
     _forks[(int)which] = (fork == null) ? GlobalForkTable.InvalidForkNumber : fork.GlobalForkNumber;
 }
 private static void ReportForkSyncError(Fork fork, ForkKind forkKind, ILfsFileInfo localFile, FileSystemSyncErrors syncErrors)
 {
     System.Diagnostics.Debug.WriteLine("What to do with " + forkKind + " for file number " + localFile.GlobalFileNumber + "??");
     syncErrors.UnsupportedForks.Add(new Tuple <ILfsFileInfo, Fork>(localFile, fork));
 }
        private static void SyncDeviceToHost(AsyncTaskData taskData)
        {
            var data   = (ExecuteDeviceCommandAsyncTaskData)taskData;
            var device = data.Device;

            data.Task.UpdateTaskProgress(0, Resources.Strings.DeviceMultistageCommand_UpdatingMenuLayout_ComputingChangesProgress);

            var customData        = (Tuple <MenuLayout, bool>)data.Data;
            var currentDirtyFlags = GetDirtyFlags.Instance.Execute <LfsDirtyFlags>(device.Port, data);
            var syncErrors        = new FileSystemSyncErrors(currentDirtyFlags);

            data.Result = syncErrors;

            // If customData.Item2 is true, that means we should ignore file system inconsistencies, ergo if it's false, we should NOT ignore them.
            if (currentDirtyFlags.HasFlag(LfsDirtyFlags.FileSystemUpdateInProgress) && !customData.Item2)
            {
                throw new InconsistentFileSystemException(Resources.Strings.DeviceMultistageCommand_UpdatingMenuLayout_InconsistentState, device.UniqueId);
            }
            var deviceFileSystem = DownloadFileSystemTables.Instance.Execute <FileSystem>(device.Port, data);

            deviceFileSystem.Status = currentDirtyFlags;
            if (data.AcceptCancelIfRequested())
            {
                return;
            }
            var hostFileSystem = customData.Item1.FileSystem;

            deviceFileSystem.RemoveMenuPositionData(); // we should not preserve the menu position fork
            hostFileSystem.PopulateSaveDataForksFromDevice(deviceFileSystem);
            var allDifferences = deviceFileSystem.CompareTo(hostFileSystem);

            if (!allDifferences.Any())
            {
                data.Task.CancelTask();
            }

            // We're going to apply the changes to a clone of the original file system.
            if (data.AcceptCancelIfRequested())
            {
                return;
            }
            var fileSystemToModify = hostFileSystem.Clone();

            if (data.AcceptCancelIfRequested())
            {
                return;
            }

            // Before we change anything, create backups of the ROM list and current menu layout.
            var configuration     = SingleInstanceApplication.Instance.GetConfiguration <Configuration>();
            var romsConfiguration = SingleInstanceApplication.Instance.GetConfiguration <INTV.Shared.Model.RomListConfiguration>();

            if (System.IO.File.Exists(configuration.MenuLayoutPath) || System.IO.File.Exists(romsConfiguration.RomFilesPath))
            {
                var backupTimestamp    = INTV.Shared.Utility.PathUtils.GetTimeString();
                var backupSubdirectory = configuration.SyncFromDeviceBackupFilenameFragment + "-" + backupTimestamp;
                var backupDirectory    = System.IO.Path.Combine(configuration.HostBackupDataAreaPath, backupSubdirectory);
                if (!System.IO.Directory.Exists(backupDirectory))
                {
                    System.IO.Directory.CreateDirectory(backupDirectory);
                }
                if (System.IO.File.Exists(configuration.MenuLayoutPath))
                {
                    var backupMenuLayoutPath = System.IO.Path.Combine(backupDirectory, configuration.DefaultMenuLayoutFileName);
                    System.IO.File.Copy(configuration.MenuLayoutPath, backupMenuLayoutPath);
                }
                if (System.IO.File.Exists(romsConfiguration.RomFilesPath))
                {
                    var backupRomListPath = System.IO.Path.Combine(backupDirectory, romsConfiguration.DefaultRomsFileName);
                    System.IO.File.Copy(romsConfiguration.RomFilesPath, backupRomListPath);
                }
            }

            // First, directory deletion.
            if (!data.CancelRequsted)
            {
                foreach (var directory in allDifferences.DirectoryDifferences.ToDelete)
                {
                    if (data.AcceptCancelIfRequested())
                    {
                        break;
                    }

                    // We don't use RemoveAt because of the collateral damage it may cause.
                    fileSystemToModify.Directories[(int)directory] = null;
                }
            }

            // Then, we process file deletion.
            if (!data.CancelRequsted)
            {
                foreach (var file in allDifferences.FileDifferences.ToDelete)
                {
                    if (data.AcceptCancelIfRequested())
                    {
                        break;
                    }

                    // We don't use RemoveAt because of the collateral damage it may cause.
                    fileSystemToModify.Files[(int)file] = null;
                }
            }

            // Finally, fork deletion.
            if (!data.CancelRequsted)
            {
                foreach (var fork in allDifferences.ForkDifferences.ToDelete)
                {
                    if (data.AcceptCancelIfRequested())
                    {
                        break;
                    }

                    // We don't use RemoveAt because of the collateral damage it may cause.
                    fileSystemToModify.Forks[(int)fork] = null;
                }
            }

            var roms              = SingleInstanceApplication.Instance.Roms;
            var romsToAdd         = new HashSet <string>();
            var forkNumberMap     = new Dictionary <ushort, ushort>(); // maps device -> local
            var forkSourceFileMap = new Dictionary <ushort, string>(); // maps local fork number -> source file for fork

            // Add new forks.
            if (!data.CancelRequsted)
            {
                foreach (var fork in allDifferences.ForkDifferences.ToAdd)
                {
                    if (data.AcceptCancelIfRequested())
                    {
                        break;
                    }

                    // Forks on device but not in our menu must be added.
                    System.Diagnostics.Debug.WriteLine("Fork adds! This means CRC24 of a LUIGI -> ???");

                    Fork newLocalFork   = null;
                    var  forkSourcePath = GetSourcePathForFork(data, fork, deviceFileSystem, roms, romsConfiguration); // retrieves the fork if necessary
                    if (forkSourcePath != null)
                    {
                        newLocalFork = new Fork(forkSourcePath)
                        {
                            GlobalForkNumber = fork.GlobalForkNumber
                        };
                        romsToAdd.Add(forkSourcePath);
                    }
                    else
                    {
                        // Is this code even reachable any more??? Looking at GetSourcePathForFork, I would think not.
                        newLocalFork = new Fork(fork.Crc24, fork.Size, fork.GlobalForkNumber);
                        var cacheEntry = CacheIndex.Find(fork.Crc24, fork.Size);
                        if (cacheEntry != null)
                        {
                            newLocalFork.FilePath = System.IO.Path.Combine(configuration.RomsStagingAreaPath, cacheEntry.LuigiPath);
                        }
                    }
                    newLocalFork.FileSystem = fileSystemToModify;
                    fileSystemToModify.Forks.AddAndRelocate(newLocalFork);
                    forkNumberMap[fork.GlobalForkNumber] = newLocalFork.GlobalForkNumber;
                    if (string.IsNullOrEmpty(forkSourcePath))
                    {
                        System.Diagnostics.Debug.WriteLine("Bad path in Fork add.");
                        syncErrors.UnableToRetrieveForks.Add(newLocalFork);
                    }
                    forkSourceFileMap[newLocalFork.GlobalForkNumber] = forkSourcePath;
                }
            }

            // Update forks.
            if (!data.CancelRequsted)
            {
                foreach (var fork in allDifferences.ForkDifferences.ToUpdate)
                {
                    if (data.AcceptCancelIfRequested())
                    {
                        break;
                    }

                    // Forks on the device don't store file paths.
                    var localFork = fileSystemToModify.Forks[fork.GlobalForkNumber];
                    forkNumberMap[fork.GlobalForkNumber] = localFork.GlobalForkNumber;
                    var forkSourcePath = GetSourcePathForFork(data, fork, deviceFileSystem, roms, romsConfiguration);
                    if (string.IsNullOrEmpty(forkSourcePath))
                    {
                        System.Diagnostics.Debug.WriteLine("Bad path in Fork update.");
                        syncErrors.UnableToRetrieveForks.Add(localFork);
                    }
                    forkSourceFileMap[localFork.GlobalForkNumber] = forkSourcePath;
                    localFork.FilePath = forkSourcePath;
                    if ((localFork.Crc24 != fork.Crc24) || (localFork.Size != fork.Size))
                    {
                        localFork.FilePath = null; // May need to regenerate the LUIGI file...
                        System.Diagnostics.Debug.WriteLine("Fork at path doesn't match! " + forkSourcePath);
                        syncErrors.UnableToRetrieveForks.Add(localFork);
                    }
                    ProgramDescription description = null;
                    var forkKind = deviceFileSystem.GetForkKind(fork);
                    if (SyncForkData(localFork, forkKind, forkSourceFileMap, null, ref description))
                    {
                        IEnumerable <ILfsFileInfo> filesUsingFork;
                        if (fileSystemToModify.GetAllFilesUsingForks(new[] { localFork }).TryGetValue(localFork, out filesUsingFork))
                        {
                            foreach (var program in filesUsingFork.OfType <Program>())
                            {
                                // This situation can arise when we have a ROM on the local system that has the
                                // same CRC as the one in the device's file system, but whose .cfg file has drifted
                                // from what was in place when the LUIGI file on the device was initially created
                                // and deployed. What we need to do in this case, then, is to force the programs
                                // pointing to this fork to actually use the LUIGI file now.
                                // The LUIGI file has already been put into the right place -- it's now a matter of
                                // forcing the program to actually point to it. This runs a bit counter to how several
                                // IRom implementations are wrappers around other types of ROMs.
                                romsToAdd.Add(forkSourcePath);
                            }
                        }
                    }
                    else
                    {
                        syncErrors.UnableToRetrieveForks.Add(localFork);
                    }
                }
            }

            var recoveredRomFiles = romsToAdd.IdentifyRomFiles(data.AcceptCancelIfRequested, (f) => data.UpdateTaskProgress(0, f));
            var recoveredRoms     = ProgramCollection.GatherRomsFromFileList(recoveredRomFiles, roms, null, data.AcceptCancelIfRequested, (f) => data.UpdateTaskProgress(0, f), null, null);

            if (roms.AddNewItemsFromList(recoveredRoms).Any())
            {
                roms.Save(romsConfiguration.RomFilesPath, false); // this may throw an error, which, in this case, will terminate the operation
            }

            // Add files.
            if (!data.CancelRequsted)
            {
                foreach (var file in allDifferences.FileDifferences.ToAdd)
                {
                    if (data.AcceptCancelIfRequested())
                    {
                        break;
                    }
                    var fileNode = FileNode.Create((LfsFileInfo)file);
                    fileNode.FileSystem = fileSystemToModify;
                    fileSystemToModify.Files.AddAndRelocate(fileNode);
                    if (file.FileType == FileType.Folder)
                    {
                        fileSystemToModify.Directories.AddAndRelocate((IDirectory)fileNode);
                    }
                    SyncFileData(fileNode, file, false, forkNumberMap, forkSourceFileMap, syncErrors);
                }
            }

            // Update files.
            var fixups = new Dictionary <FileNode, ILfsFileInfo>();

            if (!data.CancelRequsted)
            {
                foreach (var file in allDifferences.FileDifferences.ToUpdate)
                {
                    if (data.AcceptCancelIfRequested())
                    {
                        break;
                    }
                    var localFile = (FileNode)fileSystemToModify.Files[file.GlobalFileNumber];
                    if (localFile.FileType != file.FileType)
                    {
                        // We've got a case of a file changing to / from a directory, which must be handled differently.
                        // Simply null out the entry to prevent unwanted collateral damage, such as deleted forks or other files.
                        fileSystemToModify.Files[localFile.GlobalFileNumber] = null;
                        var localParent   = (Folder)localFile.Parent;
                        var localGdn      = localFile.GlobalDirectoryNumber;
                        var indexInParent = localParent.IndexOfChild(localFile);
                        localFile                  = FileNode.Create((LfsFileInfo)file);
                        localFile.FileSystem       = fileSystemToModify;
                        localFile.GlobalFileNumber = file.GlobalFileNumber;
                        fileSystemToModify.Files.Add(localFile);
                        SyncFileData(localFile, file, true, forkNumberMap, forkSourceFileMap, syncErrors);

                        switch (file.FileType)
                        {
                        case FileType.File:
                            ////System.Diagnostics.Debug.Assert(localFile.FileType == file.FileType, "File type mutation! Need to implement!");
                            // The directory on the local file system is being replaced with a file. It's possible that the directory
                            // itself has been reparented to a new location, so we do not 'destructively' remove it. Instead, we will
                            // null out its entry in the GDT / GFT and replace the GFT entry with a new file.
                            fileSystemToModify.Directories[localGdn] = null;     // so we don't accidentally nuke files and their forks - directories will be updated later
                            break;

                        case FileType.Folder:
                            // The file on the local file system is a standard file, but on the device, it's now a directory.
                            // Need to remove the file and create a directory in its place. We'll also need to populate the directory.
                            // The directory population will need to happen after we've completely finished all the adds / updates.
                            localFile.GlobalDirectoryNumber = file.GlobalDirectoryNumber;
                            fileSystemToModify.Directories.Add((Folder)localFile);
                            break;
                        }
                        localParent.Files[indexInParent] = localFile;
                        fixups[localFile] = file;
                    }
                    else
                    {
                        SyncFileData(localFile, file, true, forkNumberMap, forkSourceFileMap, syncErrors);
                    }
                }
            }

            // Add directories.
            if (!data.CancelRequsted)
            {
                foreach (var directory in allDifferences.DirectoryDifferences.ToAdd)
                {
                    if (data.AcceptCancelIfRequested())
                    {
                        break;
                    }

                    // Directory itself may already be in the file system. Now, we need to set contents correctly.
                    var localFolder = (Folder)fileSystemToModify.Directories[directory.GlobalDirectoryNumber];
                    if (localFolder == null)
                    {
                        System.Diagnostics.Debug.WriteLine("Where's my dir?");
                        syncErrors.FailedToCreateEntries.Add(directory);
                    }
                    for (var i = 0; i < directory.PresentationOrder.ValidEntryCount; ++i)
                    {
                        if (data.AcceptCancelIfRequested())
                        {
                            break;
                        }
                        var childToAdd = fileSystemToModify.Files[directory.PresentationOrder[i]];
                        localFolder.AddChild((IFile)childToAdd, false);
                    }
                }
            }

            // Update directories.
            if (!data.CancelRequsted)
            {
                foreach (var directory in allDifferences.DirectoryDifferences.ToUpdate)
                {
                    // Need to keep contents in sync. All other changes were handled by file update.
                    var localFolder = (Folder)fileSystemToModify.Directories[directory.GlobalDirectoryNumber];
                    if (localFolder == null)
                    {
                        localFolder = new Folder(fileSystemToModify, directory.GlobalDirectoryNumber, string.Empty);
                    }
                    var localNumEntries         = localFolder.PresentationOrder.ValidEntryCount;
                    var devicePresentationOrder = directory.PresentationOrder;
                    for (var i = devicePresentationOrder.ValidEntryCount; !data.CancelRequsted && (i < localNumEntries); ++i)
                    {
                        if (data.AcceptCancelIfRequested())
                        {
                            break;
                        }
                        var prevFile   = localFolder.Files[devicePresentationOrder.ValidEntryCount];
                        var prevParent = prevFile.Parent;
                        localFolder.Files.RemoveAt(devicePresentationOrder.ValidEntryCount);
                        prevFile.Parent = prevParent;
                    }
                    localNumEntries = localFolder.PresentationOrder.ValidEntryCount;
                    for (var i = 0; !data.CancelRequsted && (i < (devicePresentationOrder.ValidEntryCount - localNumEntries)); ++i)
                    {
                        if (data.AcceptCancelIfRequested())
                        {
                            break;
                        }
                        localFolder.Files.Add((FileNode)fileSystemToModify.Files[devicePresentationOrder[i]]);
                    }
                    System.Diagnostics.Debug.Assert(localFolder.Files.Count == devicePresentationOrder.ValidEntryCount, "Incorrect number of children in directory!");
                    for (var i = 0; !data.CancelRequsted && (i < devicePresentationOrder.ValidEntryCount); ++i)
                    {
                        if (data.AcceptCancelIfRequested())
                        {
                            break;
                        }
                        var localFile = (FileNode)fileSystemToModify.Files[devicePresentationOrder[i]];
                        if (!ReferenceEquals(localFolder.Files[i], localFile))
                        {
                            var prevFile       = localFolder.Files[i];
                            var prevFileParent = prevFile == null ? null : prevFile.Parent;
                            localFolder.Files[i] = localFile;
                            localFile.Parent     = localFolder;
                            if (prevFile != null)
                            {
                                // The default behavior of item replacement is to null the parent of the existing item.
                                // Therefore, because some item rearrangement results in a file shuffling 'up' or 'down'
                                // in the same folder, we need to retain the parent. So if the item is still in here,
                                // reset its parent.
                                prevFile.Parent = prevFileParent;
                            }
                        }
                    }
                }
            }

            // Now, pass back the new MenuLayout so UI thread can update and save.
            if (!data.CancelRequsted && data.Succeeded)
            {
                syncErrors.Data = (MenuLayout)fileSystemToModify.Directories[GlobalDirectoryTable.RootDirectoryNumber];
            }
        }
        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);
        }
        private static string GetRomPathForForkFromRomList(ExecuteDeviceCommandAsyncTaskData data, Fork fork, IEnumerable <ProgramDescription> roms, string destDir, out uint crc32, out uint cfgCrc32)
        {
            string romPath = null;

            crc32    = 0;
            cfgCrc32 = 0;
            var luigiHeader = GetLuigiHeaderForFork(data, fork);

            if ((luigiHeader != null) && (luigiHeader.Version > 0))
            {
                crc32    = luigiHeader.OriginalRomCrc32;
                cfgCrc32 = luigiHeader.OriginalCfgCrc32;
                var rom = roms.FirstOrDefault(r => (r.Crc == luigiHeader.OriginalRomCrc32) && ((luigiHeader.OriginalCfgCrc32 == 0) || (luigiHeader.OriginalCfgCrc32 == r.Rom.CfgCrc)));
                if (rom != null)
                {
                    romPath = rom.Rom.RomPath;
                }
            }
            return(romPath);
        }
        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);
        }
        private static string GetSourcePathForFork(ExecuteDeviceCommandAsyncTaskData data, Fork fork, FileSystem deviceFileSystem, IEnumerable <ProgramDescription> roms, RomListConfiguration romsConfiguration)
        {
            bool   retrievalNecessary;
            string destinationDir = null;
            var    forkSourcePath = GetPathForFork(data, fork, deviceFileSystem, roms, romsConfiguration, ref destinationDir, out retrievalNecessary);

            if (retrievalNecessary)
            {
                if (!data.Device.RetrieveForkData(data, new[] { fork }, destinationDir, new[] { System.IO.Path.GetFileName(forkSourcePath) }))
                {
                    var syncErrors = data.Result as FileSystemSyncErrors;
                    syncErrors.UnableToRetrieveForks.Add(fork);
                    forkSourcePath = null;
                }
            }
            return(forkSourcePath);
        }
Пример #16
0
 private FileNode()
 {
     _color = Color.White;
     _forks = new Fork[(int)ForkKind.NumberOfForkKinds];
 }
        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);
        }