/* 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 . */ #define DOTNET20 #define UNMANAGED #define COMPRESS 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; /// /// Sfx module choice enumeration /// public enum SfxModule { /// /// Default module (leave this if unsure) /// Default, /// /// The simple sfx module by Igor Pavlov with no adjustable parameters /// Simple, /// /// The installer sfx module by Igor Pavlov /// Installer, /// /// The extended installer sfx module by Oleg Scherbakov /// Extended, /// /// The custom sfx module. First you must specify the module file name. /// Custom } /// /// The class for making 7-zip based self-extracting archives. /// public class SevenZipSfx { private static readonly Dictionary> SfxSupportedModuleNames = new Dictionary>(3) { {SfxModule.Default, new List(1) {"7zxSD_All.sfx"}}, {SfxModule.Simple, new List(2) {"7z.sfx", "7zCon.sfx"}}, {SfxModule.Installer, new List(2) {"7zS.sfx", "7zSD.sfx"}}, { SfxModule.Extended, new List(4) {"7zxSD_All.sfx", "7zxSD_Deflate", "7zxSD_LZMA", "7zxSD_PPMd"} } }; private SfxModule _module = SfxModule.Default; private string _moduleFileName; private Dictionary> _sfxCommands; /// /// Initializes a new instance of the SevenZipSfx class. /// public SevenZipSfx() { _module = SfxModule.Default; CommonInit(); } /// /// Initializes a new instance of the SevenZipSfx class. /// /// The sfx module to use as a front-end. public SevenZipSfx(SfxModule module) { if (module == SfxModule.Custom) { throw new ArgumentException("You must specify the custom module executable.", "module"); } _module = module; CommonInit(); } /// /// Initializes a new instance of the SevenZipSfx class. /// /// public SevenZipSfx(string moduleFileName) { _module = SfxModule.Custom; ModuleFileName = moduleFileName; CommonInit(); } /// /// Gets the sfx module type. /// public SfxModule SfxModule { get { return _module; } } /// /// Gets or sets the custom sfx module file name /// 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 } /// /// Gets the sfx module enum by the list of supported modules /// /// /// 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."); } /// /// Loads the commands for each supported sfx module configuration /// /// The resource name for xml definitions 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>(); 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(); _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]); } } } } /// /// Validates the sfx scenario commands. /// /// The sfx settings dictionary to validate. private void ValidateSettings(SfxSettings settings) { if (_module == SfxModule.Custom) { return; } List commands = _sfxCommands[_module]; if (commands == null) { return; } var invalidCommands = new List(); 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()); } } /// /// Gets the stream containing the sfx settings. /// /// The sfx settings dictionary. /// 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 {{"Title", "7-Zip self-extracting archive"}}; return settings; case SfxModule.Default: case SfxModule.Extended: settings = new Dictionary { {"GUIMode", "0"}, {"InstallPath", "."}, {"GUIFlags", "128+8"}, {"ExtractPathTitle", "7-Zip self-extracting archive"}, {"ExtractPathText", "Specify the path where to extract the files:"} }; return settings; } } /// /// Writes the whole to the other one. /// /// The source stream to read from. /// The destination stream to wrie to. 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); } } /// /// Makes the self-extracting archive. /// /// The archive stream. /// The name of the self-extracting executable. public void MakeSfx(Stream archive, string sfxFileName) { using (Stream sfxStream = File.Create(sfxFileName)) { MakeSfx(archive, GetDefaultSettings(), sfxStream); } } /// /// Makes the self-extracting archive. /// /// The archive stream. /// The stream to write the self-extracting executable to. public void MakeSfx(Stream archive, Stream sfxStream) { MakeSfx(archive, GetDefaultSettings(), sfxStream); } /// /// Makes the self-extracting archive. /// /// The archive stream. /// The sfx settings. /// The name of the self-extracting executable. public void MakeSfx(Stream archive, SfxSettings settings, string sfxFileName) { using (Stream sfxStream = File.Create(sfxFileName)) { MakeSfx(archive, settings, sfxStream); } } /// /// Makes the self-extracting archive. /// /// The archive stream. /// The sfx settings. /// The stream to write the self-extracting executable to. 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); } /// /// Makes the self-extracting archive. /// /// The archive file name. /// The name of the self-extracting executable. 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); } } } /// /// Makes the self-extracting archive. /// /// The archive file name. /// The stream to write the self-extracting executable to. public void MakeSfx(string archiveFileName, Stream sfxStream) { using (Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) ) { MakeSfx(archive, GetDefaultSettings(), sfxStream); } } /// /// Makes the self-extracting archive. /// /// The archive file name. /// The sfx settings. /// The name of the self-extracting executable. 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); } } } /// /// Makes the self-extracting archive. /// /// The archive file name. /// The sfx settings. /// The stream to write the self-extracting executable to. 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 }