Add options parsing and passing to plugins.

This commit is contained in:
2018-01-17 19:10:46 +00:00
parent fa1efee24a
commit 87c0f628eb
7 changed files with 211 additions and 13 deletions

View File

@@ -145,6 +145,7 @@
<e p="IBGLog.cs" t="Include" /> <e p="IBGLog.cs" t="Include" />
<e p="MHDDLog.cs" t="Include" /> <e p="MHDDLog.cs" t="Include" />
</e> </e>
<e p="Options.cs" t="Include" />
<e p="Partitions.cs" t="Include" /> <e p="Partitions.cs" t="Include" />
<e p="PluginBase.cs" t="Include" /> <e p="PluginBase.cs" t="Include" />
<e p="Properties" t="Include"> <e p="Properties" t="Include">

View File

@@ -37,6 +37,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Options.cs" />
<Compile Include="PluginBase.cs" /> <Compile Include="PluginBase.cs" />
<Compile Include="ImageFormat.cs" /> <Compile Include="ImageFormat.cs" />
<Compile Include="Statistics.cs" /> <Compile Include="Statistics.cs" />

View File

@@ -0,0 +1,170 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Partitions.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Core algorithms.
//
// --[ Description ] ----------------------------------------------------------
//
// Logic to handle name=value option pairs.
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2018 Natalia Portillo
// ****************************************************************************/
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace DiscImageChef.Core
{
public static class Options
{
public static Dictionary<string, string> Parse(string options)
{
Dictionary<string, string> parsed = new Dictionary<string, string>();
bool escaped = false;
bool quoted = false;
bool inValue = false;
string name = null;
string value = null;
StringBuilder sb = new StringBuilder();
if(options == null) return parsed;
for(int index = 0; index < options.Length; index++)
{
char c = options[index];
switch(c)
{
case '\\' when !escaped:
escaped = true;
break;
case '"' when !escaped:
quoted = !quoted;
break;
case '=' when quoted:
sb.Append(c);
break;
case '=':
name = sb.ToString().ToLower(CultureInfo.CurrentCulture);
sb = new StringBuilder();
inValue = true;
break;
case ',' when quoted:
sb.Append(c);
break;
case ',' when inValue:
value = sb.ToString();
sb = new StringBuilder();
inValue = false;
if(string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) continue;
if(parsed.ContainsKey(name)) parsed.Remove(name);
parsed.Add(name, value);
break;
default:
if(escaped)
switch(c)
{
case 'a':
sb.Append('\a');
escaped = false;
break;
case 'b':
sb.Append('\b');
escaped = false;
break;
case 'f':
sb.Append('\f');
escaped = false;
break;
case 'n':
sb.Append('\n');
escaped = false;
break;
case 'r':
sb.Append('\r');
escaped = false;
break;
case 't':
sb.Append('\t');
escaped = false;
break;
case 'v':
sb.Append('\v');
escaped = false;
break;
case '\\':
sb.Append('\\');
escaped = false;
break;
case '\'':
sb.Append('\'');
escaped = false;
break;
case '"':
sb.Append('"');
escaped = false;
break;
case '0':
sb.Append('\0');
escaped = false;
break;
case 'u':
string unicode = options.Substring(index + 1, 4);
sb.Append((char)int.Parse(unicode, NumberStyles.HexNumber));
escaped = false;
index += 4;
break;
case 'U':
string longUnicode = options.Substring(index + 1, 8);
sb.Append((char)int.Parse(longUnicode, NumberStyles.HexNumber));
escaped = false;
index += 8;
break;
default:
sb.Append(c);
escaped = false;
break;
}
else sb.Append(c);
break;
}
}
if(!inValue) return parsed;
value = sb.ToString();
if(string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) return parsed;
if(parsed.ContainsKey(name)) parsed.Remove(name);
parsed.Add(name, value);
return parsed;
}
}
}

View File

@@ -67,6 +67,12 @@ namespace DiscImageChef.Commands
DicConsole.DebugWriteLine("Analyze command", "--drive-model={0}", options.DriveModel); DicConsole.DebugWriteLine("Analyze command", "--drive-model={0}", options.DriveModel);
DicConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", options.DriveSerialNumber); DicConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", options.DriveSerialNumber);
DicConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", options.DriveFirmwareRevision); DicConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", options.DriveFirmwareRevision);
DicConsole.DebugWriteLine("Analyze command", "--options={0}", options.Options);
Dictionary<string, string> parsedOptions = Options.Parse(options.Options);
DicConsole.DebugWriteLine("Analyze command", "Parsed options:");
foreach(KeyValuePair<string,string> parsedOption in parsedOptions)
DicConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
if(options.Count == 0) if(options.Count == 0)
{ {
@@ -193,7 +199,7 @@ namespace DiscImageChef.Commands
return; return;
} }
if(!outputFormat.Create(options.OutputFile, inputFormat.Info.MediaType, new Dictionary<string, string>(), if(!outputFormat.Create(options.OutputFile, inputFormat.Info.MediaType, parsedOptions,
inputFormat.Info.Sectors, inputFormat.Info.SectorSize)) inputFormat.Info.Sectors, inputFormat.Info.SectorSize))
{ {
DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage); DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage);

View File

@@ -56,8 +56,12 @@ namespace DiscImageChef.Commands
FiltersList filtersList = new FiltersList(); FiltersList filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(options.InputFile); IFilter inputFilter = filtersList.GetFilter(options.InputFile);
Dictionary<string, string> optionsDict =
new Dictionary<string, string> {{"debug", options.Debug.ToString()}}; Dictionary<string, string> parsedOptions = Options.Parse(options.Options);
DicConsole.DebugWriteLine("Extract-Files command", "Parsed options:");
foreach(KeyValuePair<string,string> parsedOption in parsedOptions)
DicConsole.DebugWriteLine("Extract-Files command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
parsedOptions.Add("debug", options.Debug.ToString());
if(inputFilter == null) if(inputFilter == null)
{ {
@@ -165,7 +169,7 @@ namespace DiscImageChef.Commands
.GetConstructor(Type.EmptyTypes) .GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { }); ?.Invoke(new object[] { });
error = fs.Mount(imageFormat, partitions[i], encoding, optionsDict); error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
List<string> rootDir = new List<string>(); List<string> rootDir = new List<string>();
@@ -321,7 +325,7 @@ namespace DiscImageChef.Commands
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType().GetConstructor(Type.EmptyTypes) .GetType().GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { }); ?.Invoke(new object[] { });
error = fs.Mount(imageFormat, partitions[i], encoding, optionsDict); error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
List<string> rootDir = new List<string>(); List<string> rootDir = new List<string>();
@@ -482,7 +486,7 @@ namespace DiscImageChef.Commands
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType().GetConstructor(Type.EmptyTypes) .GetType().GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { }); ?.Invoke(new object[] { });
error = fs.Mount(imageFormat, wholePart, encoding, optionsDict); error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
List<string> rootDir = new List<string>(); List<string> rootDir = new List<string>();
@@ -627,7 +631,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine($"Identified by {plugin.Name}."); DicConsole.WriteLine($"Identified by {plugin.Name}.");
IReadOnlyFilesystem fs = IReadOnlyFilesystem fs =
(IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { });
error = fs.Mount(imageFormat, wholePart, encoding, optionsDict); error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
List<string> rootDir = new List<string>(); List<string> rootDir = new List<string>();

View File

@@ -52,8 +52,12 @@ namespace DiscImageChef.Commands
FiltersList filtersList = new FiltersList(); FiltersList filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(options.InputFile); IFilter inputFilter = filtersList.GetFilter(options.InputFile);
Dictionary<string, string> optionsDict =
new Dictionary<string, string> {{"debug", options.Debug.ToString()}}; Dictionary<string, string> parsedOptions = Options.Parse(options.Options);
DicConsole.DebugWriteLine("Ls command", "Parsed options:");
foreach(KeyValuePair<string,string> parsedOption in parsedOptions)
DicConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
parsedOptions.Add("debug", options.Debug.ToString());
if(inputFilter == null) if(inputFilter == null)
{ {
@@ -154,7 +158,7 @@ namespace DiscImageChef.Commands
if(fs == null) continue; if(fs == null) continue;
error = fs.Mount(imageFormat, partitions[i], encoding, optionsDict); error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
List<string> rootDir = new List<string>(); List<string> rootDir = new List<string>();
@@ -184,7 +188,7 @@ namespace DiscImageChef.Commands
?.Invoke(new object[] { }); ?.Invoke(new object[] { });
if(fs == null) continue; if(fs == null) continue;
error = fs.Mount(imageFormat, partitions[i], encoding, optionsDict); error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
List<string> rootDir = new List<string>(); List<string> rootDir = new List<string>();
@@ -224,7 +228,7 @@ namespace DiscImageChef.Commands
?.Invoke(new object[] { }); ?.Invoke(new object[] { });
if(fs == null) continue; if(fs == null) continue;
error = fs.Mount(imageFormat, wholePart, encoding, optionsDict); error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
List<string> rootDir = new List<string>(); List<string> rootDir = new List<string>();
@@ -251,7 +255,7 @@ namespace DiscImageChef.Commands
.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); .GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { });
if(fs != null) if(fs != null)
{ {
error = fs.Mount(imageFormat, wholePart, encoding, optionsDict); error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
List<string> rootDir = new List<string>(); List<string> rootDir = new List<string>();

View File

@@ -326,6 +326,10 @@ namespace DiscImageChef
[Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")] [Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")]
public string EncodingName { get; set; } public string EncodingName { get; set; }
[Option('O', "options", Default = null,
HelpText = "Comma separated name=value pairs of options to pass to filesystem plugin")]
public string Options { get; set; }
} }
[Verb("extract-files", HelpText = "Extracts all files in disc image.")] [Verb("extract-files", HelpText = "Extracts all files in disc image.")]
@@ -343,6 +347,10 @@ namespace DiscImageChef
[Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")] [Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")]
public string EncodingName { get; set; } public string EncodingName { get; set; }
[Option('O', "options", Default = null,
HelpText = "Comma separated name=value pairs of options to pass to filesystem plugin")]
public string Options { get; set; }
} }
[Verb("list-devices", HelpText = "Lists all connected devices.")] [Verb("list-devices", HelpText = "Lists all connected devices.")]
@@ -412,5 +420,9 @@ namespace DiscImageChef
HelpText = HelpText =
"Firmware revision of the drive used to read the media represented by the image")] "Firmware revision of the drive used to read the media represented by the image")]
public string DriveFirmwareRevision { get; set; } public string DriveFirmwareRevision { get; set; }
[Option('O', "options", Default = null,
HelpText = "Comma separated name=value pairs of options to pass to output image plugin")]
public string Options { get; set; }
} }
} }