diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml
index 283708d5c..3f6f648b6 100644
--- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml
+++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml
@@ -145,6 +145,7 @@
+
diff --git a/DiscImageChef.Core/DiscImageChef.Core.csproj b/DiscImageChef.Core/DiscImageChef.Core.csproj
index 48a106884..269fd5da7 100644
--- a/DiscImageChef.Core/DiscImageChef.Core.csproj
+++ b/DiscImageChef.Core/DiscImageChef.Core.csproj
@@ -37,6 +37,7 @@
+
diff --git a/DiscImageChef.Core/Options.cs b/DiscImageChef.Core/Options.cs
new file mode 100644
index 000000000..e47a552a8
--- /dev/null
+++ b/DiscImageChef.Core/Options.cs
@@ -0,0 +1,170 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : Partitions.cs
+// Author(s) : Natalia Portillo
+//
+// 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 .
+//
+// ----------------------------------------------------------------------------
+// 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 Parse(string options)
+ {
+ Dictionary parsed = new Dictionary();
+ 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscImageChef/Commands/ConvertImage.cs b/DiscImageChef/Commands/ConvertImage.cs
index 57640352f..5bda8b58f 100644
--- a/DiscImageChef/Commands/ConvertImage.cs
+++ b/DiscImageChef/Commands/ConvertImage.cs
@@ -67,6 +67,12 @@ namespace DiscImageChef.Commands
DicConsole.DebugWriteLine("Analyze command", "--drive-model={0}", options.DriveModel);
DicConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", options.DriveSerialNumber);
DicConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", options.DriveFirmwareRevision);
+ DicConsole.DebugWriteLine("Analyze command", "--options={0}", options.Options);
+
+ Dictionary parsedOptions = Options.Parse(options.Options);
+ DicConsole.DebugWriteLine("Analyze command", "Parsed options:");
+ foreach(KeyValuePair parsedOption in parsedOptions)
+ DicConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
if(options.Count == 0)
{
@@ -193,7 +199,7 @@ namespace DiscImageChef.Commands
return;
}
- if(!outputFormat.Create(options.OutputFile, inputFormat.Info.MediaType, new Dictionary(),
+ if(!outputFormat.Create(options.OutputFile, inputFormat.Info.MediaType, parsedOptions,
inputFormat.Info.Sectors, inputFormat.Info.SectorSize))
{
DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage);
diff --git a/DiscImageChef/Commands/ExtractFiles.cs b/DiscImageChef/Commands/ExtractFiles.cs
index 8889a311d..55d90723c 100644
--- a/DiscImageChef/Commands/ExtractFiles.cs
+++ b/DiscImageChef/Commands/ExtractFiles.cs
@@ -56,9 +56,13 @@ namespace DiscImageChef.Commands
FiltersList filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(options.InputFile);
- Dictionary optionsDict =
- new Dictionary {{"debug", options.Debug.ToString()}};
+ Dictionary parsedOptions = Options.Parse(options.Options);
+ DicConsole.DebugWriteLine("Extract-Files command", "Parsed options:");
+ foreach(KeyValuePair parsedOption in parsedOptions)
+ DicConsole.DebugWriteLine("Extract-Files command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
+ parsedOptions.Add("debug", options.Debug.ToString());
+
if(inputFilter == null)
{
DicConsole.ErrorWriteLine("Cannot open specified file.");
@@ -165,7 +169,7 @@ namespace DiscImageChef.Commands
.GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { });
- error = fs.Mount(imageFormat, partitions[i], encoding, optionsDict);
+ error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions);
if(error == Errno.NoError)
{
List rootDir = new List();
@@ -321,7 +325,7 @@ namespace DiscImageChef.Commands
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType().GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { });
- error = fs.Mount(imageFormat, partitions[i], encoding, optionsDict);
+ error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions);
if(error == Errno.NoError)
{
List rootDir = new List();
@@ -482,7 +486,7 @@ namespace DiscImageChef.Commands
IReadOnlyFilesystem fs = (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)
{
List rootDir = new List();
@@ -627,7 +631,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine($"Identified by {plugin.Name}.");
IReadOnlyFilesystem fs =
(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)
{
List rootDir = new List();
diff --git a/DiscImageChef/Commands/Ls.cs b/DiscImageChef/Commands/Ls.cs
index e3215898b..1326d5c42 100644
--- a/DiscImageChef/Commands/Ls.cs
+++ b/DiscImageChef/Commands/Ls.cs
@@ -52,8 +52,12 @@ namespace DiscImageChef.Commands
FiltersList filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(options.InputFile);
- Dictionary optionsDict =
- new Dictionary {{"debug", options.Debug.ToString()}};
+
+ Dictionary parsedOptions = Options.Parse(options.Options);
+ DicConsole.DebugWriteLine("Ls command", "Parsed options:");
+ foreach(KeyValuePair parsedOption in parsedOptions)
+ DicConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
+ parsedOptions.Add("debug", options.Debug.ToString());
if(inputFilter == null)
{
@@ -154,7 +158,7 @@ namespace DiscImageChef.Commands
if(fs == null) continue;
- error = fs.Mount(imageFormat, partitions[i], encoding, optionsDict);
+ error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions);
if(error == Errno.NoError)
{
List rootDir = new List();
@@ -184,7 +188,7 @@ namespace DiscImageChef.Commands
?.Invoke(new object[] { });
if(fs == null) continue;
- error = fs.Mount(imageFormat, partitions[i], encoding, optionsDict);
+ error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions);
if(error == Errno.NoError)
{
List rootDir = new List();
@@ -224,7 +228,7 @@ namespace DiscImageChef.Commands
?.Invoke(new object[] { });
if(fs == null) continue;
- error = fs.Mount(imageFormat, wholePart, encoding, optionsDict);
+ error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions);
if(error == Errno.NoError)
{
List rootDir = new List();
@@ -251,7 +255,7 @@ namespace DiscImageChef.Commands
.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { });
if(fs != null)
{
- error = fs.Mount(imageFormat, wholePart, encoding, optionsDict);
+ error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions);
if(error == Errno.NoError)
{
List rootDir = new List();
diff --git a/DiscImageChef/Options.cs b/DiscImageChef/Options.cs
index 9830c20a2..8487b0799 100644
--- a/DiscImageChef/Options.cs
+++ b/DiscImageChef/Options.cs
@@ -326,6 +326,10 @@ namespace DiscImageChef
[Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")]
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.")]
@@ -343,6 +347,10 @@ namespace DiscImageChef
[Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")]
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.")]
@@ -412,5 +420,9 @@ namespace DiscImageChef
HelpText =
"Firmware revision of the drive used to read the media represented by the image")]
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; }
}
}
\ No newline at end of file