diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml index 32861038c..e77fc6bb8 100644 --- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml +++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml @@ -422,6 +422,7 @@ + diff --git a/DiscImageChef.Core/PluginBase.cs b/DiscImageChef.Core/PluginBase.cs index 65bed8741..8eb694e0d 100644 --- a/DiscImageChef.Core/PluginBase.cs +++ b/DiscImageChef.Core/PluginBase.cs @@ -34,7 +34,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Text; using DiscImageChef.Console; using DiscImageChef.DiscImages; using DiscImageChef.Filesystems; @@ -60,23 +59,29 @@ namespace DiscImageChef.Core /// public readonly SortedDictionary PluginsList; /// - /// List of all filesystem plugins + /// List of read-only filesystem plugins /// public readonly SortedDictionary ReadOnlyFilesystems; + /// + /// List of writable media image plugins + /// + public readonly SortedDictionary WritableImages; /// /// Initializes the plugins lists /// public PluginBase() { - PluginsList = new SortedDictionary(); + PluginsList = new SortedDictionary(); ReadOnlyFilesystems = new SortedDictionary(); - PartPluginsList = new SortedDictionary(); - ImagePluginsList = new SortedDictionary(); - + PartPluginsList = new SortedDictionary(); + ImagePluginsList = new SortedDictionary(); + WritableImages = new SortedDictionary(); + Assembly assembly = Assembly.GetAssembly(typeof(IMediaImage)); - foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IMediaImage))).Where(t=>t.IsClass)) + foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IMediaImage))) + .Where(t => t.IsClass)) try { IMediaImage plugin = (IMediaImage)type.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); @@ -86,35 +91,49 @@ namespace DiscImageChef.Core assembly = Assembly.GetAssembly(typeof(IPartition)); - foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IPartition))).Where(t=>t.IsClass)) + foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IPartition))) + .Where(t => t.IsClass)) try { - IPartition plugin = - (IPartition)type.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); + IPartition plugin = (IPartition)type.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); RegisterPartPlugin(plugin); } catch(Exception exception) { DicConsole.ErrorWriteLine("Exception {0}", exception); } assembly = Assembly.GetAssembly(typeof(IFilesystem)); - foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IFilesystem))).Where(t=>t.IsClass)) + foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IFilesystem))) + .Where(t => t.IsClass)) try { IFilesystem plugin = (IFilesystem)type.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); RegisterPlugin(plugin); } catch(Exception exception) { DicConsole.ErrorWriteLine("Exception {0}", exception); } - - + assembly = Assembly.GetAssembly(typeof(IReadOnlyFilesystem)); - foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IReadOnlyFilesystem))).Where(t=>t.IsClass)) + foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IReadOnlyFilesystem))) + .Where(t => t.IsClass)) try { - IReadOnlyFilesystem plugin = (IReadOnlyFilesystem)type.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); + IReadOnlyFilesystem plugin = + (IReadOnlyFilesystem)type.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); RegisterReadOnlyFilesystem(plugin); } catch(Exception exception) { DicConsole.ErrorWriteLine("Exception {0}", exception); } + + assembly = Assembly.GetAssembly(typeof(IWritableImage)); + + foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IWritableImage))) + .Where(t => t.IsClass)) + try + { + IWritableImage plugin = + (IWritableImage)type.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); + RegisterWritableMedia(plugin); + } + catch(Exception exception) { DicConsole.ErrorWriteLine("Exception {0}", exception); } } void RegisterImagePlugin(IMediaImage plugin) @@ -130,7 +149,13 @@ namespace DiscImageChef.Core void RegisterReadOnlyFilesystem(IReadOnlyFilesystem plugin) { - if(!ReadOnlyFilesystems.ContainsKey(plugin.Name.ToLower())) ReadOnlyFilesystems.Add(plugin.Name.ToLower(), plugin); + if(!ReadOnlyFilesystems.ContainsKey(plugin.Name.ToLower())) + ReadOnlyFilesystems.Add(plugin.Name.ToLower(), plugin); + } + + void RegisterWritableMedia(IWritableImage plugin) + { + if(!WritableImages.ContainsKey(plugin.Name.ToLower())) WritableImages.Add(plugin.Name.ToLower(), plugin); } void RegisterPartPlugin(IPartition partplugin) diff --git a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj index fc5b8a55e..8f55d81ed 100644 --- a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj +++ b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj @@ -54,6 +54,7 @@ + diff --git a/DiscImageChef.DiscImages/IWritableImage.cs b/DiscImageChef.DiscImages/IWritableImage.cs new file mode 100644 index 000000000..f5e4697b4 --- /dev/null +++ b/DiscImageChef.DiscImages/IWritableImage.cs @@ -0,0 +1,134 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : IWritableImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines interface to be implemented by writable image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2018 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using DiscImageChef.CommonTypes; + +namespace DiscImageChef.DiscImages +{ + /// + /// Abstract class to implement disk image writing plugins. + /// TODO: This interface is subject to change until notice. + /// + public interface IWritableImage : IMediaImage + { + /// + /// Gets a list of that are supported by the media image format + /// + List SupportedMediaTags { get; } + /// + /// Gets a list of that are supported by the media image format + /// + List SupportedSectorTags { get; } + /// + /// Gets a list of that are supported by the media image format + /// + List SupportedMediaTypes { get; } + /// + /// Retrieves a list of options supported by the filesystem, with name, type and description + /// + IEnumerable<(string name, Type type, string description)> SupportedOptions { get; } + /// + /// Gets a list of known extensions for format auto-chosing + /// + List KnownExtensions { get; } + + /// + /// Creates a new image in the specified path, for the specified , with the + /// specified options to hold a media with the specified number of sectors + /// + /// Path to the new image, with extension + /// that will be written in the image + /// Options to be used when creating new image + /// How many sectors the media has. + /// true if operating completed successfully, false otherwise + bool Create(string path, MediaType mediaType, Dictionary options, ulong sectors); + + /// + /// Writes a media tag to the image + /// + /// Media tag + /// + /// + /// + /// true if operating completed successfully, false otherwise + bool WriteMediaTag(byte[] data, MediaTagType tag); + + /// + /// Writes a sector to the image + /// + /// Sector data + /// Sector address + /// true if operating completed successfully, false otherwise + bool WriteSector(byte[] data, ulong sectorAddress); + + /// + /// Writes several sectors to the image + /// + /// Sectors data + /// Sector starting address + /// How many sectors to write + /// true if operating completed successfully, false otherwise + bool WriteSectors(byte[] data, ulong sectorAddress, uint length); + + /// + /// Writes a sector to the image with tags attached + /// + /// Sector data with its tags attached + /// Sector address + /// true if operating completed successfully, false otherwise + bool WriteSectorLong(byte[] data, ulong sectorAddress); + + /// + /// Writes several sectors to the image + /// + /// Sector data with their tags attached + /// Sector starting address + /// How many sectors to write + /// true if operating completed successfully, false otherwise + bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length); + + /// + /// Sets tracks for optical media + /// + /// List of tracks + /// true if operating completed successfully, false otherwise + bool SetTracks(List tracks); + + /// + /// Closes and flushes to disk the image + /// + /// true if operating completed successfully, false otherwise + bool Close(); + } +} \ No newline at end of file diff --git a/DiscImageChef/Commands/Formats.cs b/DiscImageChef/Commands/Formats.cs index 5cba693ac..759f5e21c 100644 --- a/DiscImageChef/Commands/Formats.cs +++ b/DiscImageChef/Commands/Formats.cs @@ -45,38 +45,61 @@ namespace DiscImageChef.Commands { internal static void ListFormats(FormatsOptions formatsOptions) { - PluginBase plugins = new PluginBase(); + PluginBase plugins = new PluginBase(); FiltersList filtersList = new FiltersList(); DicConsole.WriteLine("Supported filters ({0}):", filtersList.Filters.Count); if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tFilter"); foreach(KeyValuePair kvp in filtersList.Filters) - if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); - else DicConsole.WriteLine(kvp.Value.Name); + if(formatsOptions.Verbose) + DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); + else + DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(); - DicConsole.WriteLine("Supported disc image formats ({0}):", plugins.ImagePluginsList.Count); + DicConsole.WriteLine("Read-only media image formats ({0}):", + plugins.ImagePluginsList.Count(t => !t.Value.GetType().GetInterfaces() + .Contains(typeof(IWritableImage)))); if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); foreach(KeyValuePair kvp in plugins.ImagePluginsList) if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); - else DicConsole.WriteLine(kvp.Value.Name); + else + DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(); - DicConsole.WriteLine("Supported filesystems for identification and information only ({0}):", plugins.PluginsList.Count(t => !t.Value.GetType().GetInterfaces().Contains(typeof(IReadOnlyFilesystem)))); + DicConsole.WriteLine("Read/write media image formats ({0}):", plugins.WritableImages.Count); if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); - foreach(KeyValuePair kvp in plugins.PluginsList.Where(t => !t.Value.GetType().GetInterfaces().Contains(typeof(IReadOnlyFilesystem)))) + foreach(KeyValuePair kvp in plugins.WritableImages) if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); - else DicConsole.WriteLine(kvp.Value.Name); + else + DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(); - DicConsole.WriteLine("Supported filesystems that can read their contents ({0}):", plugins.ReadOnlyFilesystems.Count); + DicConsole.WriteLine("Supported filesystems for identification and information only ({0}):", + plugins.PluginsList.Count(t => !t.Value.GetType().GetInterfaces() + .Contains(typeof(IReadOnlyFilesystem)))); + if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); + foreach(KeyValuePair kvp in plugins.PluginsList.Where(t => !t.Value.GetType() + .GetInterfaces() + .Contains(typeof( + IReadOnlyFilesystem + )))) + if(formatsOptions.Verbose) + DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); + else + DicConsole.WriteLine(kvp.Value.Name); + + DicConsole.WriteLine(); + DicConsole.WriteLine("Supported filesystems that can read their contents ({0}):", + plugins.ReadOnlyFilesystems.Count); if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); foreach(KeyValuePair kvp in plugins.ReadOnlyFilesystems) if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); - else DicConsole.WriteLine(kvp.Value.Name); + else + DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(); DicConsole.WriteLine("Supported partitioning schemes ({0}):", plugins.PartPluginsList.Count); @@ -84,7 +107,8 @@ namespace DiscImageChef.Commands foreach(KeyValuePair kvp in plugins.PartPluginsList) if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); - else DicConsole.WriteLine(kvp.Value.Name); + else + DicConsole.WriteLine(kvp.Value.Name); Core.Statistics.AddCommand("formats"); } diff --git a/DiscImageChef/Commands/ListOptions.cs b/DiscImageChef/Commands/ListOptions.cs index 608f2159b..77ba66638 100644 --- a/DiscImageChef/Commands/ListOptions.cs +++ b/DiscImageChef/Commands/ListOptions.cs @@ -35,6 +35,7 @@ using System.Collections.Generic; using System.Linq; using DiscImageChef.Console; using DiscImageChef.Core; +using DiscImageChef.DiscImages; using DiscImageChef.Filesystems; namespace DiscImageChef.Commands @@ -45,15 +46,28 @@ namespace DiscImageChef.Commands { PluginBase plugins = new PluginBase(); + DicConsole.WriteLine("Read-only filesystems options:"); foreach(KeyValuePair kvp in plugins.ReadOnlyFilesystems) { List<(string name, Type type, string description)> options = kvp.Value.SupportedOptions.ToList(); options.Add(("debug", typeof(bool), "Enables debug features if available")); - DicConsole.WriteLine("Options for {0}:", kvp.Value.Name); - DicConsole.WriteLine("{0,-16} {1,-16} {2,-8}", "Name", "Type", "Description"); + DicConsole.WriteLine("\tOptions for {0}:", kvp.Value.Name); + DicConsole.WriteLine("\t\t{0,-16} {1,-16} {2,-8}", "Name", "Type", "Description"); foreach((string name, Type type, string description) option in options.OrderBy(t => t.name)) - DicConsole.WriteLine("{0,-16} {1,-16} {2,-8}", option.name, option.type, option.description); + DicConsole.WriteLine("\t\t{0,-16} {1,-16} {2,-8}", option.name, option.type, option.description); + DicConsole.WriteLine(); + } + + DicConsole.WriteLine("Read/Write media images options:"); + foreach(KeyValuePair kvp in plugins.WritableImages) + { + List<(string name, Type type, string description)> options = kvp.Value.SupportedOptions.ToList(); + + DicConsole.WriteLine("\tOptions for {0}:", kvp.Value.Name); + DicConsole.WriteLine("\t\t{0,-16} {1,-16} {2,-8}", "Name", "Type", "Description"); + foreach((string name, Type type, string description) option in options.OrderBy(t => t.name)) + DicConsole.WriteLine("\t\t{0,-16} {1,-16} {2,-8}", option.name, option.type, option.description); DicConsole.WriteLine(); } } diff --git a/DiscImageChef/Options.cs b/DiscImageChef/Options.cs index e56f24f5b..e3d7b008d 100644 --- a/DiscImageChef/Options.cs +++ b/DiscImageChef/Options.cs @@ -351,6 +351,6 @@ namespace DiscImageChef [Verb("list-encodings", HelpText = "Lists all supported text encodings and code pages.")] public class ListEncodingsOptions : CommonOptions { } - [Verb("list-options", HelpText = "Lists all options supported by read-only filesystems.")] + [Verb("list-options", HelpText = "Lists all options supported by read-only filesystems and writable media images.")] public class ListOptionsOptions : CommonOptions { } } \ No newline at end of file