/// <summary> /// Attempts to select a compatible adapter that is capable of identifying files. /// </summary> /// <param name="kli">The file to be selected against.</param> /// <returns>Returns a working ILoadFiles plugin or null.</returns> private ILoadFiles SelectAdapter(KoreLoadInfo kli) { // Return an adapter that can Identify, whose extension matches that of our filename and successfully identifies the file. return(_pluginLoader.GetAdapters <ILoadFiles>(). Where(x => _pluginLoader.GetMetadata <PluginExtensionInfoAttribute>(x) != null).Where(x => _pluginLoader.GetMetadata <PluginExtensionInfoAttribute>(x).Extension. ToLower().TrimEnd(';').Split(';').Any(s => kli.FileName.ToLower().EndsWith(s.TrimStart('*'))) ).FirstOrDefault(adapter => CheckAdapter(adapter, kli))); }
/// <summary> /// Toggles an event for the UI to let the user select a blind adapter manually. /// </summary> /// <returns>The selected adapter or null.</returns> private ILoadFiles SelectAdapterManually(KoreLoadInfo kli) { var blindAdapters = _pluginLoader.GetAdapters <ILoadFiles>().Where(a => !(a is IIdentifyFiles)).ToList(); var args = new IdentificationFailedEventArgs(kli.FileName, blindAdapters); IdentificationFailed?.Invoke(this, args); return(args.SelectedAdapter); }
/// <summary> /// Does the actual identification with IIdentifyFiles and checks the availablity of the data stream. /// </summary> /// <param name="adapter">Adapter to identify with.</param> /// <param name="kli">Kore information for identification.</param> /// <returns>Returns if the adapter was capable of identifying the file.</returns> private bool CheckAdapter(ILoadFiles adapter, KoreLoadInfo kli) { if (!(adapter is IIdentifyFiles iif)) { return(false); } adapter.LeaveOpen = true; kli.FileData.Position = 0; var info = new StreamInfo { FileData = kli.FileData, FileName = kli.FileName }; var res = iif.Identify(info, kli.FileSystem); if (!kli.FileData.CanRead) { throw new InvalidOperationException($"Plugin with ID '{_pluginLoader.GetMetadata<PluginInfoAttribute>(adapter).ID}' closed the stream(s) while identifying the file(s)."); } return(res); }
// TODO: We want to somehow reflect these names and also possibly return a class holding the Type and a DisplayName vs. the plain interface name. /// <summary> /// Load a file using Kore. /// </summary> /// <param name="kli"></param> /// <returns></returns> public KoreFileInfo LoadFile(KoreLoadInfo kli) { if (kli.Adapter == null) { // Select adapter automatically and if failed select it manually var adapter = SelectAdapter(kli) ?? SelectAdapterManually(kli); // If still no adapter was chosen, return if (adapter == null) { return(null); } kli.Adapter = adapter; } // Instantiate a new instance of the adapter // ReSharper disable once SuspiciousTypeConversion.Global kli.Adapter = _pluginLoader.CreateNewAdapter <ILoadFiles>((IPlugin)kli.Adapter); // Load files(s) // TODO: Make KLI contain a StreamInfo of the given file kli.FileData.Position = 0; var streamInfo = new StreamInfo { FileData = kli.FileData, FileName = kli.FileName }; try { // TODO: Subject to remove kli.Adapter.LeaveOpen = kli.LeaveOpen; // Try to load the file via adapter kli.Adapter.Load(streamInfo, kli.FileSystem); } catch (Exception ex) { // Catch any exception thrown by the plugin and expose it var pi = _pluginLoader.GetMetadata <PluginInfoAttribute>(kli.Adapter); var msg = $"The {pi?.Name} plugin failed to load \"{Path.GetFileName(kli.FileName)}\"."; throw new LoadFileException(msg, ex); } // TODO: Subject to remove // Check if the stream still follows the LeaveOpen restriction if (!kli.FileData.CanRead && kli.LeaveOpen) { throw new InvalidOperationException($"Plugin with ID {_pluginLoader.GetMetadata<PluginInfoAttribute>(kli.Adapter).ID} closed the streams while loading the file."); } // Create a KoreFileInfo to keep track of the now open file. var kfi = new KoreFileInfo { StreamFileInfo = streamInfo, HasChanges = false, Adapter = kli.Adapter }; if (kli.TrackFile) { OpenFiles.Add(kfi); } return(kfi); }