499 lines
19 KiB
C#
499 lines
19 KiB
C#
/* This file is part of SevenZipSharp.
|
|
|
|
SevenZipSharp 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
SevenZipSharp 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 SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
|
|
namespace SevenZip
|
|
{
|
|
#if SFX
|
|
using SfxSettings = Dictionary<string, string>;
|
|
|
|
/// <summary>
|
|
/// Sfx module choice enumeration
|
|
/// </summary>
|
|
public enum SfxModule
|
|
{
|
|
/// <summary>
|
|
/// Default module (leave this if unsure)
|
|
/// </summary>
|
|
Default,
|
|
/// <summary>
|
|
/// The simple sfx module by Igor Pavlov with no adjustable parameters
|
|
/// </summary>
|
|
Simple,
|
|
/// <summary>
|
|
/// The installer sfx module by Igor Pavlov
|
|
/// </summary>
|
|
Installer,
|
|
/// <summary>
|
|
/// The extended installer sfx module by Oleg Scherbakov
|
|
/// </summary>
|
|
Extended,
|
|
/// <summary>
|
|
/// The custom sfx module. First you must specify the module file name.
|
|
/// </summary>
|
|
Custom
|
|
}
|
|
|
|
/// <summary>
|
|
/// The class for making 7-zip based self-extracting archives.
|
|
/// </summary>
|
|
public class SevenZipSfx
|
|
{
|
|
private static readonly Dictionary<SfxModule, List<string>> SfxSupportedModuleNames =
|
|
new Dictionary<SfxModule, List<string>>(3)
|
|
{
|
|
{SfxModule.Default, new List<string>(1) {"7zxSD_All.sfx"}},
|
|
{SfxModule.Simple, new List<string>(2) {"7z.sfx", "7zCon.sfx"}},
|
|
{SfxModule.Installer, new List<string>(2) {"7zS.sfx", "7zSD.sfx"}},
|
|
{
|
|
SfxModule.Extended,
|
|
new List<string>(4) {"7zxSD_All.sfx", "7zxSD_Deflate", "7zxSD_LZMA", "7zxSD_PPMd"}
|
|
}
|
|
};
|
|
|
|
private SfxModule _module = SfxModule.Default;
|
|
private string _moduleFileName;
|
|
private Dictionary<SfxModule, List<string>> _sfxCommands;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the SevenZipSfx class.
|
|
/// </summary>
|
|
public SevenZipSfx()
|
|
{
|
|
_module = SfxModule.Default;
|
|
CommonInit();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the SevenZipSfx class.
|
|
/// </summary>
|
|
/// <param name="module">The sfx module to use as a front-end.</param>
|
|
public SevenZipSfx(SfxModule module)
|
|
{
|
|
if (module == SfxModule.Custom)
|
|
{
|
|
throw new ArgumentException("You must specify the custom module executable.", "module");
|
|
}
|
|
_module = module;
|
|
CommonInit();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the SevenZipSfx class.
|
|
/// </summary>
|
|
/// <param name="moduleFileName"></param>
|
|
public SevenZipSfx(string moduleFileName)
|
|
{
|
|
_module = SfxModule.Custom;
|
|
ModuleFileName = moduleFileName;
|
|
CommonInit();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the sfx module type.
|
|
/// </summary>
|
|
public SfxModule SfxModule
|
|
{
|
|
get
|
|
{
|
|
return _module;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the custom sfx module file name
|
|
/// </summary>
|
|
public string ModuleFileName
|
|
{
|
|
get
|
|
{
|
|
return _moduleFileName;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (!File.Exists(value))
|
|
{
|
|
throw new ArgumentException("The specified file does not exist.");
|
|
}
|
|
_moduleFileName = value;
|
|
_module = SfxModule.Custom;
|
|
string sfxName = Path.GetFileName(value);
|
|
foreach (SfxModule mod in SfxSupportedModuleNames.Keys)
|
|
{
|
|
if (SfxSupportedModuleNames[mod].Contains(sfxName))
|
|
{
|
|
_module = mod;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CommonInit()
|
|
{
|
|
LoadCommandsFromResource("Configs");
|
|
}
|
|
|
|
private static string GetResourceString(string str)
|
|
{
|
|
#if !WINCE
|
|
return "SevenZip.sfx." + str;
|
|
#else
|
|
return "SevenZipSharpMobile.sfx." + str;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the sfx module enum by the list of supported modules
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
/// <returns></returns>
|
|
private static SfxModule GetModuleByName(string name)
|
|
{
|
|
if (name.IndexOf("7z.sfx", StringComparison.Ordinal) > -1)
|
|
{
|
|
return SfxModule.Simple;
|
|
}
|
|
if (name.IndexOf("7zS.sfx", StringComparison.Ordinal) > -1)
|
|
{
|
|
return SfxModule.Installer;
|
|
}
|
|
if (name.IndexOf("7zxSD_All.sfx", StringComparison.Ordinal) > -1)
|
|
{
|
|
return SfxModule.Extended;
|
|
}
|
|
throw new SevenZipSfxValidationException("The specified configuration is unsupported.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads the commands for each supported sfx module configuration
|
|
/// </summary>
|
|
/// <param name="xmlDefinitions">The resource name for xml definitions</param>
|
|
private void LoadCommandsFromResource(string xmlDefinitions)
|
|
{
|
|
using (Stream cfg = Assembly.GetExecutingAssembly().GetManifestResourceStream(
|
|
GetResourceString(xmlDefinitions + ".xml")))
|
|
{
|
|
if (cfg == null)
|
|
{
|
|
throw new SevenZipSfxValidationException("The configuration \"" + xmlDefinitions +
|
|
"\" does not exist.");
|
|
}
|
|
using (Stream schm = Assembly.GetExecutingAssembly().GetManifestResourceStream(
|
|
GetResourceString(xmlDefinitions + ".xsd")))
|
|
{
|
|
if (schm == null)
|
|
{
|
|
throw new SevenZipSfxValidationException("The configuration schema \"" + xmlDefinitions +
|
|
"\" does not exist.");
|
|
}
|
|
var sc = new XmlSchemaSet();
|
|
using (XmlReader scr = XmlReader.Create(schm))
|
|
{
|
|
sc.Add(null, scr);
|
|
var settings = new XmlReaderSettings {ValidationType = ValidationType.Schema, Schemas = sc};
|
|
string validationErrors = "";
|
|
settings.ValidationEventHandler +=
|
|
((s, t) =>
|
|
{
|
|
validationErrors += String.Format(CultureInfo.InvariantCulture, "[{0}]: {1}\n",
|
|
t.Severity.ToString(), t.Message);
|
|
});
|
|
using (XmlReader rdr = XmlReader.Create(cfg, settings))
|
|
{
|
|
_sfxCommands = new Dictionary<SfxModule, List<string>>();
|
|
rdr.Read();
|
|
rdr.Read();
|
|
rdr.Read();
|
|
rdr.Read();
|
|
rdr.Read();
|
|
rdr.ReadStartElement("sfxConfigs");
|
|
rdr.Read();
|
|
do
|
|
{
|
|
SfxModule mod = GetModuleByName(rdr["modules"]);
|
|
rdr.ReadStartElement("config");
|
|
rdr.Read();
|
|
if (rdr.Name == "id")
|
|
{
|
|
var cmds = new List<string>();
|
|
_sfxCommands.Add(mod, cmds);
|
|
do
|
|
{
|
|
cmds.Add(rdr["command"]);
|
|
rdr.Read();
|
|
rdr.Read();
|
|
} while (rdr.Name == "id");
|
|
rdr.ReadEndElement();
|
|
rdr.Read();
|
|
}
|
|
else
|
|
{
|
|
_sfxCommands.Add(mod, null);
|
|
}
|
|
} while (rdr.Name == "config");
|
|
}
|
|
if (!String.IsNullOrEmpty(validationErrors))
|
|
{
|
|
throw new SevenZipSfxValidationException(
|
|
"\n" + validationErrors.Substring(0, validationErrors.Length - 1));
|
|
}
|
|
_sfxCommands.Add(SfxModule.Default, _sfxCommands[SfxModule.Extended]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates the sfx scenario commands.
|
|
/// </summary>
|
|
/// <param name="settings">The sfx settings dictionary to validate.</param>
|
|
private void ValidateSettings(SfxSettings settings)
|
|
{
|
|
if (_module == SfxModule.Custom)
|
|
{
|
|
return;
|
|
}
|
|
List<string> commands = _sfxCommands[_module];
|
|
if (commands == null)
|
|
{
|
|
return;
|
|
}
|
|
var invalidCommands = new List<string>();
|
|
foreach (string command in settings.Keys)
|
|
{
|
|
if (!commands.Contains(command))
|
|
{
|
|
invalidCommands.Add(command);
|
|
}
|
|
}
|
|
if (invalidCommands.Count > 0)
|
|
{
|
|
var invalidText = new StringBuilder("\nInvalid commands:\n");
|
|
foreach (string str in invalidCommands)
|
|
{
|
|
invalidText.Append(str);
|
|
}
|
|
throw new SevenZipSfxValidationException(invalidText.ToString());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the stream containing the sfx settings.
|
|
/// </summary>
|
|
/// <param name="settings">The sfx settings dictionary.</param>
|
|
/// <returns></returns>
|
|
private static Stream GetSettingsStream(SfxSettings settings)
|
|
{
|
|
var ms = new MemoryStream();
|
|
byte[] buf = Encoding.UTF8.GetBytes(@";!@Install@!UTF-8!" + '\n');
|
|
ms.Write(buf, 0, buf.Length);
|
|
foreach (string command in settings.Keys)
|
|
{
|
|
buf =
|
|
Encoding.UTF8.GetBytes(String.Format(CultureInfo.InvariantCulture, "{0}=\"{1}\"\n", command,
|
|
settings[command]));
|
|
ms.Write(buf, 0, buf.Length);
|
|
}
|
|
buf = Encoding.UTF8.GetBytes(@";!@InstallEnd@!");
|
|
ms.Write(buf, 0, buf.Length);
|
|
return ms;
|
|
}
|
|
|
|
private SfxSettings GetDefaultSettings()
|
|
{
|
|
switch (_module)
|
|
{
|
|
default:
|
|
return null;
|
|
case SfxModule.Installer:
|
|
var settings = new Dictionary<string, string> {{"Title", "7-Zip self-extracting archive"}};
|
|
return settings;
|
|
case SfxModule.Default:
|
|
case SfxModule.Extended:
|
|
settings = new Dictionary<string, string>
|
|
{
|
|
{"GUIMode", "0"},
|
|
{"InstallPath", "."},
|
|
{"GUIFlags", "128+8"},
|
|
{"ExtractPathTitle", "7-Zip self-extracting archive"},
|
|
{"ExtractPathText", "Specify the path where to extract the files:"}
|
|
};
|
|
return settings;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the whole to the other one.
|
|
/// </summary>
|
|
/// <param name="src">The source stream to read from.</param>
|
|
/// <param name="dest">The destination stream to wrie to.</param>
|
|
private static void WriteStream(Stream src, Stream dest)
|
|
{
|
|
src.Seek(0, SeekOrigin.Begin);
|
|
var buf = new byte[32768];
|
|
int bytesRead;
|
|
while ((bytesRead = src.Read(buf, 0, buf.Length)) > 0)
|
|
{
|
|
dest.Write(buf, 0, bytesRead);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the self-extracting archive.
|
|
/// </summary>
|
|
/// <param name="archive">The archive stream.</param>
|
|
/// <param name="sfxFileName">The name of the self-extracting executable.</param>
|
|
public void MakeSfx(Stream archive, string sfxFileName)
|
|
{
|
|
using (Stream sfxStream = File.Create(sfxFileName))
|
|
{
|
|
MakeSfx(archive, GetDefaultSettings(), sfxStream);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the self-extracting archive.
|
|
/// </summary>
|
|
/// <param name="archive">The archive stream.</param>
|
|
/// <param name="sfxStream">The stream to write the self-extracting executable to.</param>
|
|
public void MakeSfx(Stream archive, Stream sfxStream)
|
|
{
|
|
MakeSfx(archive, GetDefaultSettings(), sfxStream);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the self-extracting archive.
|
|
/// </summary>
|
|
/// <param name="archive">The archive stream.</param>
|
|
/// <param name="settings">The sfx settings.</param>
|
|
/// <param name="sfxFileName">The name of the self-extracting executable.</param>
|
|
public void MakeSfx(Stream archive, SfxSettings settings, string sfxFileName)
|
|
{
|
|
using (Stream sfxStream = File.Create(sfxFileName))
|
|
{
|
|
MakeSfx(archive, settings, sfxStream);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the self-extracting archive.
|
|
/// </summary>
|
|
/// <param name="archive">The archive stream.</param>
|
|
/// <param name="settings">The sfx settings.</param>
|
|
/// <param name="sfxStream">The stream to write the self-extracting executable to.</param>
|
|
public void MakeSfx(Stream archive, SfxSettings settings, Stream sfxStream)
|
|
{
|
|
if (!sfxStream.CanWrite)
|
|
{
|
|
throw new ArgumentException("The specified output stream can not write.", "sfxStream");
|
|
}
|
|
ValidateSettings(settings);
|
|
using (Stream sfx = _module == SfxModule.Default
|
|
? Assembly.GetExecutingAssembly().GetManifestResourceStream(
|
|
GetResourceString(SfxSupportedModuleNames[_module][0]))
|
|
: new FileStream(_moduleFileName, FileMode.Open, FileAccess.Read,
|
|
FileShare.ReadWrite))
|
|
{
|
|
WriteStream(sfx, sfxStream);
|
|
}
|
|
if (_module == SfxModule.Custom || _sfxCommands[_module] != null)
|
|
{
|
|
using (Stream set = GetSettingsStream(settings))
|
|
{
|
|
WriteStream(set, sfxStream);
|
|
}
|
|
}
|
|
WriteStream(archive, sfxStream);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the self-extracting archive.
|
|
/// </summary>
|
|
/// <param name="archiveFileName">The archive file name.</param>
|
|
/// <param name="sfxFileName">The name of the self-extracting executable.</param>
|
|
public void MakeSfx(string archiveFileName, string sfxFileName)
|
|
{
|
|
using (Stream sfxStream = File.Create(sfxFileName))
|
|
{
|
|
using (
|
|
Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
|
)
|
|
{
|
|
MakeSfx(archive, GetDefaultSettings(), sfxStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the self-extracting archive.
|
|
/// </summary>
|
|
/// <param name="archiveFileName">The archive file name.</param>
|
|
/// <param name="sfxStream">The stream to write the self-extracting executable to.</param>
|
|
public void MakeSfx(string archiveFileName, Stream sfxStream)
|
|
{
|
|
using (Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
|
)
|
|
{
|
|
MakeSfx(archive, GetDefaultSettings(), sfxStream);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the self-extracting archive.
|
|
/// </summary>
|
|
/// <param name="archiveFileName">The archive file name.</param>
|
|
/// <param name="settings">The sfx settings.</param>
|
|
/// <param name="sfxFileName">The name of the self-extracting executable.</param>
|
|
public void MakeSfx(string archiveFileName, SfxSettings settings, string sfxFileName)
|
|
{
|
|
using (Stream sfxStream = File.Create(sfxFileName))
|
|
{
|
|
using (
|
|
Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
|
)
|
|
{
|
|
MakeSfx(archive, settings, sfxStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the self-extracting archive.
|
|
/// </summary>
|
|
/// <param name="archiveFileName">The archive file name.</param>
|
|
/// <param name="settings">The sfx settings.</param>
|
|
/// <param name="sfxStream">The stream to write the self-extracting executable to.</param>
|
|
public void MakeSfx(string archiveFileName, SfxSettings settings, Stream sfxStream)
|
|
{
|
|
using (Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
|
)
|
|
{
|
|
MakeSfx(archive, settings, sfxStream);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
} |