예제 #1
0
        private async Task <SaveResult> SaveAndReplaceStateAsync(IFileState fileState, IFileSystem destinationFileSystem, UPath savePath, SaveInfo saveInfo)
        {
            // 1. Save state to a temporary destination
            var temporaryContainer = _streamMonitor.CreateTemporaryFileSystem();
            var saveStateResult    = await TrySaveState(fileState.PluginState as ISaveFiles, temporaryContainer, savePath, saveInfo);

            if (!saveStateResult.IsSuccessful)
            {
                return(saveStateResult);
            }

            // TODO: If reload fails then the original files get closed already, which makes future save actions impossible due to disposed streams

            // 2. Dispose of all streams in this state
            _streamMonitor.GetStreamManager(temporaryContainer).ReleaseAll();
            fileState.StreamManager.ReleaseAll();

            // 3. Replace files in destination file system
            var moveResult = await MoveFiles(fileState, temporaryContainer, destinationFileSystem);

            if (!moveResult.IsSuccessful)
            {
                return(moveResult);
            }

            // 4. Release temporary destination
            _streamMonitor.ReleaseTemporaryFileSystem(temporaryContainer);

            return(SaveResult.SuccessfulResult);
        }
예제 #2
0
 public FormInfo(IFileState fileState, IFormCommunicator formCommunicator, IProgressContext progress, ILogger logger)
 {
     FileState        = fileState;
     FormCommunicator = formCommunicator;
     Progress         = progress;
     Logger           = logger;
 }
예제 #3
0
        public VirtualLoadInfo(IFileState parentFileState, IArchiveState archiveState, ArchiveFileInfo afi, IFilePlugin plugin) :
            this(parentFileState, archiveState, afi)
        {
            ContractAssertions.IsNotNull(plugin, nameof(plugin));

            Plugin = plugin;
        }
예제 #4
0
        private async Task <SaveResult> ReloadInternalAsync(IFileState fileState, IFileSystem destinationFileSystem, UPath savePath, SaveInfo saveInfo)
        {
            // 1. Reload current state
            var temporaryStreamProvider = fileState.StreamManager.CreateTemporaryStreamProvider();

            var internalDialogManager = new InternalDialogManager(saveInfo.DialogManager, fileState.DialogOptions);
            var loadContext           = new LoadContext(temporaryStreamProvider, saveInfo.Progress, internalDialogManager);
            var reloadResult          = await TryLoadStateAsync(fileState.PluginState, destinationFileSystem, savePath.ToAbsolute(), loadContext);

            if (!reloadResult.IsSuccessful)
            {
                return(new SaveResult(reloadResult.Exception));
            }

            // 2. Set new file input, if state was loaded from a physical medium
            if (!fileState.HasParent)
            {
                fileState.SetNewFileInput(destinationFileSystem, savePath);
            }

            // 3. Reload all child states
            foreach (var archiveChild in fileState.ArchiveChildren)
            {
                var destination       = archiveChild.FileSystem.Clone(archiveChild.StreamManager);
                var reloadChildResult = await ReloadInternalAsync(archiveChild, destination, archiveChild.FilePath, saveInfo);

                if (!reloadChildResult.IsSuccessful)
                {
                    return(reloadChildResult);
                }
            }

            return(SaveResult.SuccessfulResult);
        }
예제 #5
0
        public void Save(Stream output, IFileManager fileManager)
        {
            var images = (_state.PluginState as IImageState).Images;

            using var bw = new BinaryWriterX(output);

            // Create header
            var header = new TotxHeader
            {
                width  = (short)images[0].ImageSize.Width,
                height = (short)images[0].ImageSize.Height
            };

            // Prepare image info
            images[0].ImageInfo.ImageSize = images[0].ImageInfo.PadSize.Build(images[0].ImageSize);

            // Write CTPK
            var ctpkStream = _state.StateChanged ?
                             fileManager.SaveStream(_state).Result.SavedStream[0].Stream :
                             _state.FileSystem.OpenFile(_state.FilePath);

            ctpkStream.Position = 0;
            output.Position     = 0x80;
            ctpkStream.CopyTo(output);

            // Write header
            output.Position = 0;
            bw.WriteType(header);

            // Finalize file manager
            fileManager.Close(_state);
            _state = null;
        }
예제 #6
0
        /// <summary>
        /// Represents an open file in the runtime of Kuriimu.
        /// </summary>
        /// <param name="filePlugin">The entry class of the plugin for this file.</param>
        /// <param name="pluginState">The plugin state of this file.</param>
        /// <param name="parentFileState">The parent state for this file.</param>
        /// <param name="fileSystem">The file system around the initially opened file.</param>
        /// <param name="filePath">The path of the file to be opened in the file system.</param>
        /// <param name="streamManager">The stream manager used for this opened state.</param>
        /// <param name="fileManager">The plugin manager for this state.</param>
        public DefaultFileState(IFilePlugin filePlugin, IPluginState pluginState, IFileState parentFileState,
                                IFileSystem fileSystem, UPath filePath,
                                IStreamManager streamManager, IFileManager fileManager)
        {
            ContractAssertions.IsNotNull(filePlugin, nameof(filePlugin));
            ContractAssertions.IsNotNull(pluginState, nameof(pluginState));
            ContractAssertions.IsNotNull(fileSystem, nameof(fileSystem));
            ContractAssertions.IsNotNull(streamManager, nameof(streamManager));
            ContractAssertions.IsNotNull(fileManager, nameof(fileManager));

            if (filePath == UPath.Empty || filePath.IsDirectory)
            {
                throw new InvalidOperationException($"'{filePath}' has to be a path to a file.");
            }
            if (!fileSystem.FileExists(filePath))
            {
                throw FileSystemExceptionHelper.NewFileNotFoundException(filePath);
            }

            FilePlugin    = filePlugin;
            PluginState   = pluginState;
            FilePath      = filePath;
            FileSystem    = fileSystem;
            StreamManager = streamManager;
            FileManager   = fileManager;

            ParentFileState = parentFileState;

            ArchiveChildren = new List <IFileState>();
        }
예제 #7
0
        public LoadResult(IFileState fileState) :
            this(LoadStatus.Successful)
        {
            ContractAssertions.IsNotNull(fileState, nameof(fileState));

            LoadedFileState = fileState;
        }
예제 #8
0
        private async Task <IImageState> LoadKtx(Stream fileStream, UPath filePath, IFileManager pluginManager)
        {
            var imgData = new SubStream(fileStream, _header.tableDataOffset, _header.imgDataSize);

            _dataCompressionFormat = Level5Compressor.PeekCompressionMethod(imgData);

            var ktxFile = new MemoryStream();

            Level5Compressor.Decompress(imgData, ktxFile);
            ktxFile.Position = 0;

            var loadResult = await pluginManager.LoadFile(new StreamFile(ktxFile, filePath.GetNameWithoutExtension() + ".ktx"), KtxPluginId);

            if (!loadResult.IsSuccessful)
            {
                throw new InvalidOperationException(loadResult.Message);
            }
            if (!(loadResult.LoadedFileState.PluginState is IImageState))
            {
                throw new InvalidOperationException("The embedded KTX version is not supported.");
            }

            _ktxState = loadResult.LoadedFileState;
            return((IImageState)_ktxState.PluginState);
        }
예제 #9
0
        public ContextNode Add(IContext parentContext, IFileState stateInfo)
        {
            var newNode = new ContextNode(parentContext, this, stateInfo);

            Children.Add(newNode);

            return(newNode);
        }
예제 #10
0
        public FormCommunicator(IFileState fileState, IMainForm mainForm)
        {
            ContractAssertions.IsNotNull(fileState, nameof(fileState));
            ContractAssertions.IsNotNull(mainForm, nameof(mainForm));

            _fileState = fileState;
            _mainForm  = mainForm;
        }
예제 #11
0
        /// <summary>
        /// Create a <see cref="AfiFileSystem"/> based on the given <see cref="IFileState"/>.
        /// </summary>
        /// <param name="fileState"><see cref="IFileState"/> to create the file system from.</param>
        /// <param name="path">The path of the virtual file system.</param>
        /// <returns>The created <see cref="IFileSystem"/> for this state.</returns>
        public static IFileSystem CreateAfiFileSystem(IFileState fileState, UPath path)
        {
            if (!(fileState.PluginState is IArchiveState))
            {
                throw new InvalidOperationException("This state is not an archive.");
            }

            return(CreateAfiFileSystem(fileState, path, fileState.StreamManager));
        }
예제 #12
0
        public TextContext(IFileState stateInfo, IContext parentContext, IProgressContext progressContext) :
            base(progressContext)
        {
            ContractAssertions.IsNotNull(stateInfo, nameof(stateInfo));
            ContractAssertions.IsNotNull(parentContext, nameof(parentContext));

            _stateInfo     = stateInfo;
            _parentContext = parentContext;
        }
예제 #13
0
        private ContextNode(IContext parentContext, ContextNode parentNode, IFileState parentState) : this()
        {
            ContractAssertions.IsNotNull(parentContext, nameof(parentContext));
            ContractAssertions.IsNotNull(parentNode, nameof(parentNode));
            ContractAssertions.IsNotNull(parentState, nameof(parentState));

            _parentNode    = parentNode;
            _parentContext = parentContext;
            StateInfo      = parentState;
        }
예제 #14
0
        public CloseResult Close(IFileState fileState)
        {
            ContractAssertions.IsElementContained(_loadedFiles, fileState, "loadedFiles", nameof(fileState));

            var closeResult = _parentFileManager.Close(fileState);

            _loadedFiles.Remove(fileState);

            return(closeResult);
        }
예제 #15
0
        public ImageContext(IFileState stateInfo, IContext parentContext, IProgressContext progressContext) :
            base(progressContext)
        {
            ContractAssertions.IsNotNull(stateInfo, nameof(stateInfo));
            ContractAssertions.IsNotNull(parentContext, nameof(parentContext));

            _stateInfo     = stateInfo;
            _imageState    = _stateInfo.PluginState as IImageState;
            _parentContext = parentContext;
        }
예제 #16
0
        /// <summary>
        /// Create a <see cref="AfiFileSystem"/> based on the given <see cref="IArchiveState"/>.
        /// </summary>
        /// <param name="fileState"><see cref="IFileState"/> to create the file system from.</param>
        /// <param name="path">The path of the virtual file system.</param>
        /// <param name="streamManager">The stream manager for this file system.</param>
        /// <returns>The created <see cref="IFileSystem"/> for this state.</returns>
        public static IFileSystem CreateAfiFileSystem(IFileState fileState, UPath path, IStreamManager streamManager)
        {
            var fileSystem = (IFileSystem) new AfiFileSystem(fileState, streamManager);

            if (path != UPath.Empty && path != UPath.Root)
            {
                fileSystem = new SubFileSystem(fileSystem, path);
            }

            return(fileSystem);
        }
예제 #17
0
        public ArchiveContext(ContextNode contextNode, IContext parentContext, IInternalFileManager pluginManager, IProgressContext progressContext) :
            base(pluginManager, contextNode, progressContext)
        {
            ContractAssertions.IsNotNull(contextNode, nameof(contextNode));
            ContractAssertions.IsNotNull(parentContext, nameof(parentContext));

            _stateInfo         = contextNode.StateInfo;
            _archiveState      = _stateInfo.PluginState as IArchiveState;
            _archiveFileSystem = FileSystemFactory.CreateAfiFileSystem(_stateInfo);
            _parentContext     = parentContext;
        }
예제 #18
0
        public VirtualLoadInfo(IFileState parentFileState, IArchiveState archiveState, ArchiveFileInfo afi)
        {
            ContractAssertions.IsNotNull(parentFileState, nameof(parentFileState));
            ContractAssertions.IsNotNull(archiveState, nameof(archiveState));
            ContractAssertions.IsNotNull(afi, nameof(afi));
            ContractAssertions.IsElementContained(archiveState.Files, afi, nameof(archiveState), nameof(afi));

            ParentFileState = parentFileState;
            ArchiveState    = archiveState;
            Afi             = afi;
        }
예제 #19
0
        /// <summary>
        /// Replace files in destination file system.
        /// </summary>
        /// <param name="fileState">The state to save in the destination.</param>
        /// <param name="sourceFileSystem">The file system to take the files from.</param>
        /// <param name="destinationFileSystem">The file system to replace the files in.</param>
        private async Task <SaveResult> MoveFiles(IFileState fileState, IFileSystem sourceFileSystem, IFileSystem destinationFileSystem)
        {
            if (fileState.HasParent)
            {
                // Put source filesystem into final destination
                var replaceResult = await TryReplaceFiles(sourceFileSystem, destinationFileSystem, fileState.ParentFileState.StreamManager);

                return(replaceResult);
            }

            // Put source filesystem into final destination
            var copyResult = await TryCopyFiles(sourceFileSystem, destinationFileSystem);

            return(copyResult);
        }
예제 #20
0
        public IList <IKanvasImage> Load(Stream input, IFileManager fileManager)
        {
            using var br = new BinaryReaderX(input, true, ByteOrder.BigEndian);

            // Read FBRC tree
            _root = FabNode.Read(br);
            var dataNode = _root.Nodes.FirstOrDefault(x => x.Type == "PDAT");

            // Read CTPK
            var result = fileManager.LoadFile(new StreamFile(dataNode.Data, "file.ctpk"), CtpkId).Result;

            if (!result.IsSuccessful)
            {
                throw new InvalidOperationException(result.Message);
            }

            _ctpkState = result.LoadedFileState;
            return((_ctpkState.PluginState as IImageState).Images);
        }
예제 #21
0
        protected async Task SaveFile(IFileState fileState)
        {
            SaveResult saveResult;

            try
            {
                saveResult = await FileManager.SaveFile(fileState);
            }
            catch (Exception e)
            {
                Logger.Fatal(e, "Saving file '{0}' threw an error.", fileState.FilePath.FullName);
                return;
            }

            if (!saveResult.IsSuccessful)
            {
                Logger.Error("Could not save '{0}'.", fileState.FilePath.FullName);
            }
        }
예제 #22
0
        private async Task <SaveResult> SaveInternalAsync(IFileState fileState, IFileSystem destinationFileSystem, UPath savePath,
                                                          SaveInfo saveInfo, bool isStart = true)
        {
            // 1. Check if state is saveable and if the contents are changed
            if (!(fileState.PluginState.CanSave) || !fileState.StateChanged)
            {
                return(new SaveResult(true, "The file had no changes and was not saved."));
            }

            // 2. Save child states
            foreach (var archiveChild in fileState.ArchiveChildren)
            {
                var childDestination = archiveChild.FileSystem.Clone(archiveChild.StreamManager);
                var saveChildResult  = await SaveInternalAsync(archiveChild, childDestination, archiveChild.FilePath, saveInfo, false);

                if (!saveChildResult.IsSuccessful)
                {
                    return(saveChildResult);
                }
            }

            // 3. Save and replace state
            var saveAndReplaceResult = await SaveAndReplaceStateAsync(fileState, destinationFileSystem, savePath, saveInfo);

            if (!saveAndReplaceResult.IsSuccessful)
            {
                return(saveAndReplaceResult);
            }

            // If this was not the first call into the save action, return a successful result
            if (!isStart)
            {
                return(SaveResult.SuccessfulResult);
            }

            // 4. Reload the current state and all its children
            var reloadResult = await ReloadInternalAsync(fileState, destinationFileSystem, savePath, saveInfo);

            return(reloadResult);
        }
예제 #23
0
        public void Save(Stream output, IFileManager fileManager)
        {
            var imageState = _ctpkState.PluginState as IImageState;
            var buffer     = new byte[4];

            // Save CTPK
            var ctpkStream = _ctpkState.StateChanged
                ? fileManager.SaveStream(_ctpkState).Result.SavedStream[0].Stream
                : _ctpkState.FileSystem.OpenFile(_ctpkState.FilePath);

            // Set saved CTPK
            var dataNode = _root.Nodes.FirstOrDefault(x => x.Type == "PDAT");

            dataNode.Data = ctpkStream;

            // Save node tree
            using var bw = new BinaryWriterX(output, ByteOrder.BigEndian);
            _root.Write(bw);

            // Clean CTPK state
            fileManager.Close(_ctpkState);
            _ctpkState = null;
        }
예제 #24
0
        private async Task SaveFileInternal(IFileState selectedState, string savePathArgument)
        {
            if (!(selectedState.PluginState is ISaveFiles))
            {
                Console.WriteLine($"File '{selectedState.FilePath}' is not savable.");
                return;
            }

            if (!selectedState.StateChanged)
            {
                Console.WriteLine($"File '{selectedState.FilePath.ToRelative()}' has no changes.");
                return;
            }

            SaveResult saveResult;

            try
            {
                saveResult = await(string.IsNullOrEmpty(savePathArgument)
                    ? PluginManager.SaveFile(selectedState)
                    : PluginManager.SaveFile(selectedState, savePathArgument));
            }
            catch (Exception e)
            {
                Console.WriteLine($"Save Error: {e.Message}");
                return;
            }

            if (!saveResult.IsSuccessful)
            {
                Console.WriteLine($"Save Error: {saveResult.Message}");
                return;
            }

            Console.WriteLine($"Saved '{selectedState.FilePath.ToRelative()}' successfully.");
        }
예제 #25
0
        public IList <IKanvasImage> Load(Stream input, IFileManager fileManager)
        {
            using var br = new BinaryReaderX(input);

            // Read header
            var header = br.ReadType <TotxHeader>();

            // Read CTPK
            var ctpkState = fileManager.LoadFile(new StreamFile(new SubStream(input, 0x80, input.Length - 0x80), "file.ctpk"), CtpkId).Result;

            if (!ctpkState.IsSuccessful)
            {
                throw new InvalidOperationException(ctpkState.Message);
            }

            _state = ctpkState.LoadedFileState;
            var images = (_state.PluginState as IImageState).Images;

            // Edit image info
            images[0].ImageInfo.ImageSize = new Size(header.width, header.height);
            images[0].ImageInfo.PadSize.ToMultiple(8);

            return(images);
        }
예제 #26
0
        public void RegisterStateInfo(IFileState fileState)
        {
            ContractAssertions.IsNotNull(fileState, nameof(fileState));

            _fileState = fileState;
        }
예제 #27
0
 public FileStateChangedEventArgs(IFileState state)
 {
     FileState = state;
 }
예제 #28
0
 /// <inheritdoc />
 public Task <SaveResult> SaveAsync(IFileState fileState, IFileSystem fileSystem, UPath savePath, SaveInfo saveInfo)
 {
     return(SaveInternalAsync(fileState, fileSystem, savePath, saveInfo));
 }
예제 #29
0
 /// <inheritdoc />
 public bool IsClosing(IFileState fileState)
 {
     return(_parentFileManager.IsClosing(fileState));
 }
예제 #30
0
 public Task <SaveStreamResult> SaveStream(IFileState fileState)
 {
     return(_parentFileManager.SaveStream(fileState));
 }