Projektdateien hinzufügen.

This commit is contained in:
Manuel Kamper 2019-12-27 21:57:14 +01:00
parent 7f2ba0e620
commit 199e9d511e
15 changed files with 1847 additions and 0 deletions

25
Mk0.Software.Unzipper.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mk0.Software.Unzipper", "Mk0.Software.Unzipper\Mk0.Software.Unzipper.csproj", "{DE6795D6-1D34-491F-A279-E425A33E3AB0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DE6795D6-1D34-491F-A279-E425A33E3AB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE6795D6-1D34-491F-A279-E425A33E3AB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE6795D6-1D34-491F-A279-E425A33E3AB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE6795D6-1D34-491F-A279-E425A33E3AB0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {85CFD1B1-8147-48C7-818F-6F9F37369D25}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

187
Mk0.Software.Unzipper/Main.Designer.cs generated Normal file
View File

@ -0,0 +1,187 @@
namespace Mk0.Software.Unzipper
{
partial class Main
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.progressBar = new System.Windows.Forms.ProgressBar();
this.pictureBoxIcon = new System.Windows.Forms.PictureBox();
this.labelInformation = new System.Windows.Forms.Label();
this.buttonSelectZip = new System.Windows.Forms.Button();
this.buttonTargetDir = new System.Windows.Forms.Button();
this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
this.buttonExtract = new System.Windows.Forms.Button();
this.labelZipFile = new System.Windows.Forms.Label();
this.labelTarget = new System.Windows.Forms.Label();
this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxIcon)).BeginInit();
this.SuspendLayout();
//
// progressBar
//
this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar.Location = new System.Drawing.Point(96, 44);
this.progressBar.Margin = new System.Windows.Forms.Padding(5);
this.progressBar.Name = "progressBar";
this.progressBar.Size = new System.Drawing.Size(396, 35);
this.progressBar.TabIndex = 0;
this.progressBar.Visible = false;
//
// pictureBoxIcon
//
this.pictureBoxIcon.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.pictureBoxIcon.Image = global::Mk0.Software.Unzipper.Properties.Resources.Unzipper;
this.pictureBoxIcon.Location = new System.Drawing.Point(14, 14);
this.pictureBoxIcon.Margin = new System.Windows.Forms.Padding(5);
this.pictureBoxIcon.Name = "pictureBoxIcon";
this.pictureBoxIcon.Size = new System.Drawing.Size(72, 72);
this.pictureBoxIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.pictureBoxIcon.TabIndex = 2;
this.pictureBoxIcon.TabStop = false;
//
// labelInformation
//
this.labelInformation.AutoSize = true;
this.labelInformation.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelInformation.Location = new System.Drawing.Point(93, 14);
this.labelInformation.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.labelInformation.Name = "labelInformation";
this.labelInformation.Size = new System.Drawing.Size(68, 15);
this.labelInformation.TabIndex = 3;
this.labelInformation.Text = "Extrahiere...";
this.labelInformation.Visible = false;
//
// buttonSelectZip
//
this.buttonSelectZip.Location = new System.Drawing.Point(96, 14);
this.buttonSelectZip.Name = "buttonSelectZip";
this.buttonSelectZip.Size = new System.Drawing.Size(173, 23);
this.buttonSelectZip.TabIndex = 4;
this.buttonSelectZip.Text = "zu entpackendes ZIP wählen...";
this.buttonSelectZip.UseVisualStyleBackColor = true;
this.buttonSelectZip.Click += new System.EventHandler(this.ButtonSelectZip_Click);
//
// buttonTargetDir
//
this.buttonTargetDir.Enabled = false;
this.buttonTargetDir.Location = new System.Drawing.Point(275, 14);
this.buttonTargetDir.Name = "buttonTargetDir";
this.buttonTargetDir.Size = new System.Drawing.Size(121, 23);
this.buttonTargetDir.TabIndex = 5;
this.buttonTargetDir.Text = "Zielordner wählen...";
this.buttonTargetDir.UseVisualStyleBackColor = true;
this.buttonTargetDir.Click += new System.EventHandler(this.ButtonTargetDir_Click);
//
// openFileDialog
//
this.openFileDialog.DefaultExt = "*.zip";
this.openFileDialog.Filter = "ZIP-Dateien|*.zip";
this.openFileDialog.Title = "zu entpackendes ZIP wählen...";
//
// buttonExtract
//
this.buttonExtract.Enabled = false;
this.buttonExtract.Location = new System.Drawing.Point(402, 14);
this.buttonExtract.Name = "buttonExtract";
this.buttonExtract.Size = new System.Drawing.Size(90, 23);
this.buttonExtract.TabIndex = 6;
this.buttonExtract.Text = "Entpacken";
this.buttonExtract.UseVisualStyleBackColor = true;
this.buttonExtract.Click += new System.EventHandler(this.ButtonExtract_Click);
//
// labelZipFile
//
this.labelZipFile.AutoSize = true;
this.labelZipFile.Location = new System.Drawing.Point(94, 44);
this.labelZipFile.Name = "labelZipFile";
this.labelZipFile.Size = new System.Drawing.Size(98, 15);
this.labelZipFile.TabIndex = 7;
this.labelZipFile.Text = "ZIP: unknown.zip";
this.labelZipFile.Visible = false;
//
// labelTarget
//
this.labelTarget.AutoSize = true;
this.labelTarget.Location = new System.Drawing.Point(94, 59);
this.labelTarget.Name = "labelTarget";
this.labelTarget.Size = new System.Drawing.Size(160, 15);
this.labelTarget.TabIndex = 8;
this.labelTarget.Text = "entpacken nach C:\\unknown";
this.labelTarget.Visible = false;
//
// folderBrowserDialog
//
this.folderBrowserDialog.Description = "Zielordner zum entpacken wählen...";
//
// Main
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoSize = true;
this.ClientSize = new System.Drawing.Size(506, 100);
this.Controls.Add(this.labelTarget);
this.Controls.Add(this.labelZipFile);
this.Controls.Add(this.buttonExtract);
this.Controls.Add(this.buttonTargetDir);
this.Controls.Add(this.buttonSelectZip);
this.Controls.Add(this.labelInformation);
this.Controls.Add(this.pictureBoxIcon);
this.Controls.Add(this.progressBar);
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Margin = new System.Windows.Forms.Padding(5);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Main";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Unzipper v1.0 | © 2019-2020 by mk0.at";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing);
this.Shown += new System.EventHandler(this.Main_Shown);
((System.ComponentModel.ISupportInitialize)(this.pictureBoxIcon)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ProgressBar progressBar;
private System.Windows.Forms.PictureBox pictureBoxIcon;
private System.Windows.Forms.Label labelInformation;
private System.Windows.Forms.Button buttonSelectZip;
private System.Windows.Forms.Button buttonTargetDir;
private System.Windows.Forms.OpenFileDialog openFileDialog;
private System.Windows.Forms.Button buttonExtract;
private System.Windows.Forms.Label labelZipFile;
private System.Windows.Forms.Label labelTarget;
private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog;
}
}

View File

@ -0,0 +1,327 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Mk0.Software.Unzipper.Properties;
namespace Mk0.Software.Unzipper
{
public partial class Main : Form
{
private BackgroundWorker _backgroundWorker;
readonly StringBuilder _logBuilder = new StringBuilder();
private string zipfile, targetdir;
public Main()
{
InitializeComponent();
}
private void Main_Shown(object sender, EventArgs e)
{
_logBuilder.AppendLine(DateTime.Now.ToString("F"));
_logBuilder.AppendLine();
_logBuilder.AppendLine("Unzipper mit folgenden Kommandozeilenparametern gestartet.");
string[] args = Environment.GetCommandLineArgs();
for (var index = 0; index < args.Length; index++)
{
var arg = args[index];
_logBuilder.AppendLine($"[{index}] {arg}");
}
_logBuilder.AppendLine();
if (args.Length >= 3)
{
labelInformation.Visible = true;
progressBar.Visible = true;
Extract(args);
}
else
{
//manuell entpacken
}
}
private void Extract(string[] args)
{
// Extract all the files.
_backgroundWorker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_backgroundWorker.DoWork += (o, eventArgs) =>
{
foreach (var process in Process.GetProcesses())
{
try
{
if (process.MainModule.FileName.Equals(args[2]))
{
_logBuilder.AppendLine("Warte auf das Ende des Applikationsprozesses...");
_backgroundWorker.ReportProgress(0, "Warte auf das Beenden der Applikation...");
process.WaitForExit();
}
}
catch (Exception exception)
{
Debug.WriteLine(exception.Message);
}
}
_logBuilder.AppendLine("BackgroundWorker erfolgreich gestartet.");
var path = Path.GetDirectoryName(args[2]);
// Open an existing zip file for reading.
ZipStorer zip = ZipStorer.Open(args[1], FileAccess.Read);
// Read the central directory collection.
List<ZipStorer.ZipFileEntry> dir = zip.ReadCentralDir();
_logBuilder.AppendLine($"Insgesamt {dir.Count} Dateien und Ordner im ZIP-File gefunden.");
for (var index = 0; index < dir.Count; index++)
{
if (_backgroundWorker.CancellationPending)
{
eventArgs.Cancel = true;
zip.Close();
return;
}
ZipStorer.ZipFileEntry entry = dir[index];
zip.ExtractFile(entry, Path.Combine(path, entry.FilenameInZip));
string currentFile = string.Format(Resources.CurrentFileExtracting, entry.FilenameInZip);
int progress = (index + 1) * 100 / dir.Count;
_backgroundWorker.ReportProgress(progress, currentFile);
_logBuilder.AppendLine($"{currentFile} [{progress}%]");
}
zip.Close();
};
_backgroundWorker.ProgressChanged += (o, eventArgs) =>
{
progressBar.Value = eventArgs.ProgressPercentage;
labelInformation.Text = eventArgs.UserState.ToString();
};
_backgroundWorker.RunWorkerCompleted += (o, eventArgs) =>
{
try
{
if (eventArgs.Error != null)
{
throw eventArgs.Error;
}
if (!eventArgs.Cancelled)
{
labelInformation.Text = @"Fertig";
try
{
ProcessStartInfo processStartInfo = new ProcessStartInfo(args[2]);
if (args.Length > 3)
{
processStartInfo.Arguments = args[3];
}
Process.Start(processStartInfo);
_logBuilder.AppendLine("Applikation erfolgreich gestartet.");
}
catch (Win32Exception exception)
{
if (exception.NativeErrorCode != 1223)
{
throw;
}
}
}
}
catch (Exception exception)
{
_logBuilder.AppendLine();
_logBuilder.AppendLine(exception.ToString());
MessageBox.Show(exception.Message, exception.GetType().ToString(),
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_logBuilder.AppendLine();
Application.Exit();
}
};
_backgroundWorker.RunWorkerAsync();
}
private void ExtractGUI(string zipfile, string targetdir)
{
// Extract all the files.
_backgroundWorker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_backgroundWorker.DoWork += (o, eventArgs) =>
{
_logBuilder.AppendLine("BackgroundWorker erfolgreich gestartet.");
var path = targetdir;
// Open an existing zip file for reading.
ZipStorer zip = ZipStorer.Open(zipfile, FileAccess.Read);
// Read the central directory collection.
List<ZipStorer.ZipFileEntry> dir = zip.ReadCentralDir();
_logBuilder.AppendLine($"Insgesamt {dir.Count} Dateien und Ordner im ZIP-File gefunden.");
for (var index = 0; index < dir.Count; index++)
{
if (_backgroundWorker.CancellationPending)
{
eventArgs.Cancel = true;
zip.Close();
return;
}
ZipStorer.ZipFileEntry entry = dir[index];
zip.ExtractFile(entry, Path.Combine(path, entry.FilenameInZip));
string currentFile = string.Format(Resources.CurrentFileExtracting, entry.FilenameInZip);
int progress = (index + 1) * 100 / dir.Count;
_backgroundWorker.ReportProgress(progress, currentFile);
_logBuilder.AppendLine($"{currentFile} [{progress}%]");
}
zip.Close();
};
_backgroundWorker.ProgressChanged += (o, eventArgs) =>
{
progressBar.Value = eventArgs.ProgressPercentage;
labelInformation.Text = eventArgs.UserState.ToString();
};
_backgroundWorker.RunWorkerCompleted += (o, eventArgs) =>
{
try
{
if (eventArgs.Error != null)
{
throw eventArgs.Error;
}
if (!eventArgs.Cancelled)
{
labelInformation.Text = @"Fertig";
}
}
catch (Exception exception)
{
_logBuilder.AppendLine();
_logBuilder.AppendLine(exception.ToString());
MessageBox.Show(exception.Message, exception.GetType().ToString(),
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_logBuilder.AppendLine();
DialogResult res = MessageBox.Show("Alles entpackt." + Environment.NewLine + "Wollen sie ein neues ZIP entpacken?", "Unzipper ist fertig", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(res == DialogResult.Yes)
{
labelInformation.Visible = false;
progressBar.Visible = false;
buttonSelectZip.Visible = true;
buttonTargetDir.Enabled = false;
buttonTargetDir.Visible = true;
buttonExtract.Enabled = false;
buttonExtract.Visible = true;
zipfile = "";
targetdir = "";
}
else
{
Application.Exit();
}
}
};
_backgroundWorker.RunWorkerAsync();
}
private void Main_FormClosing(object sender, FormClosingEventArgs e)
{
_backgroundWorker?.CancelAsync();
_logBuilder.AppendLine();
File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Unzipper.log"), _logBuilder.ToString());
}
private void ButtonSelectZip_Click(object sender, EventArgs e)
{
DialogResult res = openFileDialog.ShowDialog();
if (res == DialogResult.OK)
{
buttonTargetDir.Enabled = true;
zipfile = openFileDialog.FileName;
labelZipFile.Text = "ZIP: " + Path.GetFileName(zipfile);
labelZipFile.Visible = true;
}
else
{
zipfile = "";
targetdir = "";
buttonTargetDir.Enabled = false;
labelZipFile.Visible = false;
labelTarget.Visible = false;
}
buttonExtract.Enabled = false;
}
private void ButtonTargetDir_Click(object sender, EventArgs e)
{
DialogResult res = folderBrowserDialog.ShowDialog();
if(res == DialogResult.OK)
{
buttonExtract.Enabled = true;
targetdir = folderBrowserDialog.SelectedPath;
labelTarget.Text = "entpacken nach " + targetdir;
labelTarget.Visible = true;
}
else
{
buttonExtract.Enabled = false;
targetdir = "";
labelTarget.Visible = false;
}
}
private void ButtonExtract_Click(object sender, EventArgs e)
{
buttonSelectZip.Visible = false;
buttonTargetDir.Visible = false;
buttonExtract.Visible = false;
labelZipFile.Visible = false;
labelTarget.Visible = false;
labelInformation.Visible = true;
progressBar.Visible = true;
ExtractGUI(zipfile, targetdir);
}
}
}

View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="openFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="folderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>150, 17</value>
</metadata>
</root>

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DE6795D6-1D34-491F-A279-E425A33E3AB0}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Mk0.Software.Unzipper</RootNamespace>
<AssemblyName>Unzipper</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Unzipper.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Main.Designer.cs">
<DependentUpon>Main.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ZipStorer.cs" />
<EmbeddedResource Include="Main.resx">
<DependentUpon>Main.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\Unzipper.png" />
</ItemGroup>
<ItemGroup>
<Content Include="Unzipper.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mk0.Software.Unzipper
{
static class Program
{
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Main());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("Unzipper")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("mk0.at")]
[assembly: AssemblyProduct("Mk0.Software.Unzipper")]
[assembly: AssemblyCopyright("Copyright © 2019-202 mk0.at")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("de6795d6-1d34-491f-a279-e425a33e3ab0")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// indem Sie "*" wie unten gezeigt eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,82 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Mk0.Software.Unzipper.Properties {
using System;
/// <summary>
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
/// </summary>
// Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
// -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
// mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Mk0.Software.Unzipper.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
/// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Entpacke {0} ähnelt.
/// </summary>
internal static string CurrentFileExtracting {
get {
return ResourceManager.GetString("CurrentFileExtracting", resourceCulture);
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Unzipper {
get {
object obj = ResourceManager.GetObject("Unzipper", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="CurrentFileExtracting" xml:space="preserve">
<value>Entpacke {0}</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Unzipper" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Unzipper.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Mk0.Software.Unzipper.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,778 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.IO.Compression;
namespace Mk0.Software.Unzipper
{
public class ZipStorer : IDisposable
{
// <summary>
// Compression method enumeration
// </summary>
public enum Compression : ushort
{
// <summary>Uncompressed storage</summary>
Store = 0,
// <summary>Deflate compression method</summary>
Deflate = 8
}
// <summary>
// Represents an entry in Zip file directory
// </summary>
public struct ZipFileEntry
{
// <summary>Compression method</summary>
public Compression Method;
// <summary>Full path and filename as stored in Zip</summary>
public string FilenameInZip;
// <summary>Original file size</summary>
public uint FileSize;
// <summary>Compressed file size</summary>
public uint CompressedSize;
// <summary>Offset of header information inside Zip storage</summary>
public uint HeaderOffset;
// <summary>Offset of file inside Zip storage</summary>
public uint FileOffset;
// <summary>Size of header information</summary>
public uint HeaderSize;
// <summary>32-bit checksum of entire file</summary>
public uint Crc32;
// <summary>Last modification time of file</summary>
public DateTime ModifyTime;
// <summary>User comment for file</summary>
public string Comment;
// <summary>True if UTF8 encoding for filename and comments, false if default (CP 437)</summary>
public bool EncodeUTF8;
// <summary>Overriden method</summary>
// <returns>Filename in Zip</returns>
public override string ToString()
{
return this.FilenameInZip;
}
}
// <summary>True if UTF8 encoding for filename and comments, false if default (CP 437)</summary>
public bool EncodeUTF8 = false;
// <summary>Force deflate algotithm even if it inflates the stored file. Off by default.</summary>
public bool ForceDeflating = false;
// List of files to store
private List<ZipFileEntry> Files = new List<ZipFileEntry>();
// Filename of storage file
private string FileName;
// Stream object of storage file
private Stream ZipFileStream;
// General comment
private string Comment = "";
// Central dir image
private byte[] CentralDirImage = null;
// Existing files in zip
private ushort ExistingFiles = 0;
// File access for Open method
private FileAccess Access;
// Leave the stream open after the ZipStorer object is disposed
private bool leaveOpen;
// Static CRC32 Table
private static UInt32[] CrcTable = null;
// Default filename encoder
private static Encoding DefaultEncoding = Encoding.GetEncoding(437);
// Static constructor. Just invoked once in order to create the CRC32 lookup table.
public ZipStorer()
{
// Generate CRC32 table
CrcTable = new UInt32[256];
for (int i = 0; i <= CrcTable.Length - 1; i++)
{
UInt32 c = System.Convert.ToUInt32(i);
for (int j = 0; j <= 7; j++)
{
if ((c & 1) != 0)
c = 3988292384 ^ (c >> 1);
else
c >>= 1;
}
CrcTable[i] = c;
}
}
// <summary>
// Method to create a new storage file
// </summary>
// <param name="_filename">Full path of Zip file to create</param>
// <param name="_comment">General comment for Zip file</param>
// <param name="_leaveOpen">true to leave the stream open after the ZipStorer object is disposed; otherwise, false (default).</param>
// <returns>A valid ZipStorer object</returns>
public static ZipStorer Create(string _filename, string _comment)
{
Stream stream = new FileStream(_filename, FileMode.Create, FileAccess.ReadWrite);
ZipStorer zip = Create(stream, _comment);
zip.Comment = _comment;
zip.FileName = _filename;
return zip;
}
// <summary>
// Method to create a new zip storage in a stream
// </summary>
// <param name="_stream"></param>
// <param name="_comment"></param>
// <returns>A valid ZipStorer object</returns>
public static ZipStorer Create(Stream _stream, string _comment, bool _leaveOpen = false)
{
ZipStorer zip = new ZipStorer();
zip.Comment = _comment;
zip.ZipFileStream = _stream;
zip.Access = FileAccess.Write;
zip.leaveOpen = _leaveOpen;
return zip;
}
// <summary>
// Method to open an existing storage file
// </summary>
// <param name="_filename">Full path of Zip file to open</param>
// <param name="_access">File access mode as used in FileStream constructor</param>
// <returns>A valid ZipStorer object</returns>
public static ZipStorer Open(string _filename, FileAccess _access)
{
Stream stream = (Stream)new FileStream(_filename, FileMode.Open, _access == FileAccess.Read ? FileAccess.Read : FileAccess.ReadWrite);
ZipStorer zip = Open(stream, _access);
zip.FileName = _filename;
return zip;
}
// <summary>
// Method to open an existing storage from stream
// </summary>
// <param name="_stream">Already opened stream with zip contents</param>
// <param name="_access">File access mode for stream operations</param>
// <returns>A valid ZipStorer object</returns>
public static ZipStorer Open(Stream _stream, FileAccess _access, bool _leaveOpen = false)
{
if (!_stream.CanSeek && _access != FileAccess.Read)
throw new InvalidOperationException("Stream cannot seek");
ZipStorer zip = new ZipStorer();
// zip.FileName = _filename
zip.ZipFileStream = _stream;
zip.Access = _access;
zip.leaveOpen = _leaveOpen;
if (zip.ReadFileInfo())
return zip;
if ((!_leaveOpen))
zip.Close();
throw new System.IO.InvalidDataException();
}
// <summary>
// Add full contents of a file into the Zip storage
// </summary>
// <param name="_method">Compression method</param>
// <param name="_pathname">Full path of file to add to Zip storage</param>
// <param name="_filenameInZip">Filename and path as desired in Zip directory</param>
// <param name="_comment">Comment for stored file</param>
public void AddFile(Compression _method, string _pathname, string _filenameInZip, string _comment)
{
if (Access == FileAccess.Read)
throw new InvalidOperationException("Writing is not alowed");
FileStream stream = new FileStream(_pathname, FileMode.Open, FileAccess.Read);
AddStream(_method, _filenameInZip, stream, File.GetLastWriteTime(_pathname), _comment);
stream.Close();
}
/// <summary>
/// ''' Add full contents of a directory into the Zip storage
/// ''' </summary>
/// ''' <param name="_method">Compression method</param>
/// ''' <param name="_pathname">Full path of directory to add to Zip storage</param>
/// ''' <param name="_pathnameInZip">Path name as desired in Zip directory</param>
/// ''' <param name="_comment">Comment for stored directory</param>
public void AddDirectory(Compression _method, string _pathname, string _pathnameInZip, string _comment)
{
if (Access == FileAccess.Read)
throw new InvalidOperationException("Writing is not allowed");
string foldername;
int pos = _pathname.LastIndexOf(Path.DirectorySeparatorChar);
if (pos >= 0)
foldername = _pathname.Remove(0, pos + 1);
else
foldername = _pathname;
if (_pathnameInZip != null && _pathnameInZip != "")
foldername = _pathnameInZip + foldername;
if (!foldername.EndsWith("/"))
foldername = foldername + "/";
// Process the list of files found in the directory.
string[] fileEntries = Directory.GetFiles(_pathname);
foreach (string fileName in fileEntries)
AddFile(_method, fileName, foldername + Path.GetFileName(fileName), "");
// Recurse into subdirectories of this directory.
string[] subdirectoryEntries = Directory.GetDirectories(_pathname);
foreach (string subdirectory in subdirectoryEntries)
AddDirectory(_method, subdirectory, foldername, "");
}
// <summary>
// Add full contents of a stream into the Zip storage
// </summary>
// <param name="_method">Compression method</param>
// <param name="_filenameInZip">Filename and path as desired in Zip directory</param>
// <param name="_source">Stream object containing the data to store in Zip</param>
// <param name="_modTime">Modification time of the data to store</param>
// <param name="_comment">Comment for stored file</param>
public void AddStream(Compression _method, string _filenameInZip, Stream _source, DateTime _modTime, string _comment)
{
if (Access == FileAccess.Read)
throw new InvalidOperationException("Writing is not alowed");
long offset;
if (this.Files.Count == 0)
offset = 0;
else
{
ZipFileEntry last = this.Files[this.Files.Count - 1];
offset = last.HeaderOffset + last.HeaderSize;
}
// Prepare the fileinfo
ZipFileEntry zfe = new ZipFileEntry();
zfe.Method = _method;
zfe.EncodeUTF8 = this.EncodeUTF8;
zfe.FilenameInZip = NormalizedFilename(_filenameInZip);
zfe.Comment = _comment == null ? "" : _comment;
// Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc.
zfe.Crc32 = 0; // to be updated later
zfe.HeaderOffset = System.Convert.ToUInt32(this.ZipFileStream.Position); // offset within file of the start of this local record
zfe.ModifyTime = _modTime;
// Write local header
WriteLocalHeader(ref zfe);
zfe.FileOffset = System.Convert.ToUInt32(this.ZipFileStream.Position);
// Write file to zip (store)
Store(ref zfe, _source);
_source.Close();
this.UpdateCrcAndSizes(ref zfe);
Files.Add(zfe);
}
// <summary>
// Updates central directory (if pertinent) and close the Zip storage
// </summary>
// <remarks>This is a required step, unless automatic dispose is used</remarks>
public void Close()
{
if (this.Access != FileAccess.Read && this.ZipFileStream != null)
{
uint centralOffset = System.Convert.ToUInt32(this.ZipFileStream.Position);
uint centralSize = 0;
if (this.CentralDirImage != null)
this.ZipFileStream.Write(CentralDirImage, 0, CentralDirImage.Length);
for (int i = 0; i <= Files.Count - 1; i++)
{
long pos = this.ZipFileStream.Position;
this.WriteCentralDirRecord(Files[i]);
centralSize += System.Convert.ToUInt32(this.ZipFileStream.Position - pos);
}
if ((this.CentralDirImage != null))
this.WriteEndRecord(centralSize + System.Convert.ToUInt32(CentralDirImage.Length), centralOffset);
else
this.WriteEndRecord(centralSize, centralOffset);
}
if (((this.ZipFileStream != null) & (!this.leaveOpen)))
{
this.ZipFileStream.Flush();
this.ZipFileStream.Dispose();
this.ZipFileStream = null;
}
}
// <summary>
// Read all the file records in the central directory
// </summary>
// <returns>List of all entries in directory</returns>
public List<ZipFileEntry> ReadCentralDir()
{
if (this.CentralDirImage == null)
throw new InvalidOperationException("Central directory currently does not exist");
List<ZipFileEntry> result = new List<ZipFileEntry>();
int pointer = 0;
while (pointer < this.CentralDirImage.Length - 3) // Need 4 bytes left for ToUInt32
{
uint signature = BitConverter.ToUInt32(CentralDirImage, pointer);
if (signature != 0x2014B50U)
break;
bool encodeUTF8 = (BitConverter.ToUInt16(CentralDirImage, pointer + 8) & 0x800U) != 0;
ushort method = BitConverter.ToUInt16(CentralDirImage, pointer + 10);
uint modifyTime = BitConverter.ToUInt32(CentralDirImage, pointer + 12);
uint crc32 = BitConverter.ToUInt32(CentralDirImage, pointer + 16);
uint comprSize = BitConverter.ToUInt32(CentralDirImage, pointer + 20);
uint fileSize = BitConverter.ToUInt32(CentralDirImage, pointer + 24);
ushort filenameSize = BitConverter.ToUInt16(CentralDirImage, pointer + 28);
ushort extraSize = BitConverter.ToUInt16(CentralDirImage, pointer + 30);
ushort commentSize = BitConverter.ToUInt16(CentralDirImage, pointer + 32);
uint headerOffset = BitConverter.ToUInt32(CentralDirImage, pointer + 42);
uint headerSize = System.Convert.ToUInt32(46 + filenameSize + extraSize + commentSize);
Encoding encoder = encodeUTF8 ? Encoding.UTF8 : DefaultEncoding;
ZipFileEntry zfe = new ZipFileEntry();
zfe.Method = (Compression)method;
zfe.FilenameInZip = encoder.GetString(CentralDirImage, pointer + 46, filenameSize);
zfe.FileOffset = GetFileOffset(headerOffset);
zfe.FileSize = fileSize;
zfe.CompressedSize = comprSize;
zfe.HeaderOffset = headerOffset;
zfe.HeaderSize = headerSize;
zfe.Crc32 = crc32;
zfe.ModifyTime = DosTimeToDateTime(modifyTime);
if (commentSize > 0)
zfe.Comment = encoder.GetString(CentralDirImage, pointer + 46 + filenameSize + extraSize, commentSize);
result.Add(zfe);
pointer += (46 + filenameSize + extraSize + commentSize);
}
return result;
}
// <summary>
// Copy the contents of a stored file into a physical file
// </summary>
// <param name="_zfe">Entry information of file to extract</param>
// <param name="_filename">Name of file to store uncompressed data</param>
// <returns>True if success, false if not.</returns>
// <remarks>Unique compression methods are Store and Deflate</remarks>
public bool ExtractFile(ZipFileEntry _zfe, string _filename)
{
// Make sure the parent directory exist
string path = System.IO.Path.GetDirectoryName(_filename);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
// Check it is directory. If so, do nothing
if ((Directory.Exists(_filename)))
return true;
Stream output = new FileStream(_filename, FileMode.Create, FileAccess.Write);
bool result = ExtractFile(_zfe, output);
if (result)
output.Close();
File.SetCreationTime(_filename, _zfe.ModifyTime);
File.SetLastWriteTime(_filename, _zfe.ModifyTime);
return result;
}
// <summary>
// Copy the contents of a stored file into an opened stream
// </summary>
// <param name="_zfe">Entry information of file to extract</param>
// <param name="_stream">Stream to store the uncompressed data</param>
// <returns>True if success, false if not.</returns>
// <remarks>Unique compression methods are Store and Deflate</remarks>
public bool ExtractFile(ZipFileEntry _zfe, Stream _stream)
{
if (!_stream.CanWrite)
throw new InvalidOperationException("Stream cannot be written");
// check signature
byte[] signature = new byte[4];
this.ZipFileStream.Seek(_zfe.HeaderOffset, SeekOrigin.Begin);
this.ZipFileStream.Read(signature, 0, 4);
if (BitConverter.ToUInt32(signature, 0) != 0x4034B50U)
return false;
// Select input stream for inflating or just reading
Stream inStream;
if (_zfe.Method == Compression.Store)
inStream = this.ZipFileStream;
else if (_zfe.Method == Compression.Deflate)
inStream = new DeflateStream(this.ZipFileStream, CompressionMode.Decompress, true);
else
return false;
// Buffered copy
byte[] buffer = new byte[16384];
this.ZipFileStream.Seek(_zfe.FileOffset, SeekOrigin.Begin);
uint bytesPending = _zfe.FileSize;
while (bytesPending > 0)
{
int bytesRead = inStream.Read(buffer, 0, System.Convert.ToInt32(Math.Min(bytesPending, buffer.Length)));
_stream.Write(buffer, 0, bytesRead);
bytesPending -= System.Convert.ToUInt32(bytesRead);
}
_stream.Flush();
if (_zfe.Method == Compression.Deflate)
inStream.Dispose();
return true;
}
// <summary>
// Removes one of many files in storage. It creates a new Zip file.
// </summary>
// <param name="_zip">Reference to the current Zip object</param>
// <param name="_zfes">List of Entries to remove from storage</param>
// <returns>True if success, false if not</returns>
// <remarks>This method only works for storage of type FileStream</remarks>
public static bool RemoveEntries(ref ZipStorer _zip, List<ZipFileEntry> _zfes)
{
if (!(_zip.ZipFileStream is FileStream))
throw new InvalidOperationException("RemoveEntries is allowed just over streams of type FileStream");
// Get full list of entries
List<ZipFileEntry> fullList = _zip.ReadCentralDir();
// In order to delete we need to create a copy of the zip file excluding the selected items
string tempZipName = Path.GetTempFileName();
string tempEntryName = Path.GetTempFileName();
try
{
ZipStorer tempZip = ZipStorer.Create(tempZipName, string.Empty);
foreach (ZipFileEntry zfe in fullList)
{
if (!_zfes.Contains(zfe))
{
if (_zip.ExtractFile(zfe, tempEntryName))
tempZip.AddFile(zfe.Method, tempEntryName, zfe.FilenameInZip, zfe.Comment);
}
}
_zip.Close();
tempZip.Close();
File.Delete(_zip.FileName);
File.Move(tempZipName, _zip.FileName);
_zip = ZipStorer.Open(_zip.FileName, _zip.Access);
}
catch (Exception ex)
{
return false;
}
finally
{
if ((File.Exists(tempZipName)))
File.Delete(tempZipName);
if ((File.Exists(tempEntryName)))
File.Delete(tempEntryName);
}
return true;
}
// Calculate the file offset by reading the corresponding local header
private uint GetFileOffset(uint _headerOffset)
{
byte[] buffer = new byte[2];
this.ZipFileStream.Seek(_headerOffset + 26, SeekOrigin.Begin);
this.ZipFileStream.Read(buffer, 0, 2);
ushort filenameSize = BitConverter.ToUInt16(buffer, 0);
this.ZipFileStream.Read(buffer, 0, 2);
ushort extraSize = BitConverter.ToUInt16(buffer, 0);
return System.Convert.ToUInt32(30 + filenameSize + extraSize + _headerOffset);
}
// Local file header:
// local file header signature 4 bytes (&H04034b50)
// version needed to extract 2 bytes
// general purpose bit flag 2 bytes
// compression method 2 bytes
// last mod file time 2 bytes
// last mod file date 2 bytes
// crc-32 4 bytes
// compressed size 4 bytes
// uncompressed size 4 bytes
// filename length 2 bytes
// extra field length 2 bytes
// filename (variable size)
// extra field (variable size)
private void WriteLocalHeader(ref ZipFileEntry _zfe)
{
long pos = this.ZipFileStream.Position;
Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding;
byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip);
this.ZipFileStream.Write(new byte[] { 80, 75, 3, 4, 20, 0 }, 0, 6); // No extra header
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(_zfe.EncodeUTF8 ? 0x800 : 0)), 0, 2); // filename and comment encoding
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(_zfe.Method)), 0, 2); // zipping method
this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time
this.ZipFileStream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 12); // unused CRC, un/compressed size, updated later
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(encodedFilename.Length)), 0, 2); // filename length
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(0)), 0, 2); // extra length
this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length);
_zfe.HeaderSize = System.Convert.ToUInt32(this.ZipFileStream.Position - pos);
}
private void WriteCentralDirRecord(ZipFileEntry _zfe)
{
Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding;
byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip);
byte[] encodedComment = encoder.GetBytes(_zfe.Comment);
this.ZipFileStream.Write(new byte[] { 80, 75, 1, 2, 23, 0xB, 20, 0 }, 0, 8);
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(_zfe.EncodeUTF8 ? 0x800 : 0)), 0, 2); // filename and comment encoding
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(_zfe.Method)), 0, 2); // zipping method
this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // file CRC
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // compressed file size
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // uncompressed file size
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(encodedFilename.Length)), 0, 2); // Filename in zip
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(0)), 0, 2); // extra length
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(encodedComment.Length)), 0, 2);
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(0)), 0, 2); // disk=0
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(0)), 0, 2); // file type: binary
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(0)), 0, 2); // Internal file attributes
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(0x8100)), 0, 2); // External file attributes (normal/readable)
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.HeaderOffset), 0, 4); // Offset of header
this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length);
this.ZipFileStream.Write(encodedComment, 0, encodedComment.Length);
}
// End of central dir record:
// end of central dir signature 4 bytes (&H06054b50)
// number of this disk 2 bytes
// number of the disk with the
// start of the central directory 2 bytes
// total number of entries in
// the central dir on this disk 2 bytes
// total number of entries in
// the central dir 2 bytes
// size of the central directory 4 bytes
// offset of start of central
// directory with respect to
// the starting disk number 4 bytes
// zipfile comment length 2 bytes
// zipfile comment (variable size)
private void WriteEndRecord(uint _size, uint _offset)
{
Encoding encoder = this.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding;
byte[] encodedComment = encoder.GetBytes(this.Comment);
this.ZipFileStream.Write(new byte[] { 80, 75, 5, 6, 0, 0, 0, 0 }, 0, 8);
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(Files.Count + ExistingFiles)), 0, 2);
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(Files.Count + ExistingFiles)), 0, 2);
this.ZipFileStream.Write(BitConverter.GetBytes(_size), 0, 4);
this.ZipFileStream.Write(BitConverter.GetBytes(_offset), 0, 4);
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(encodedComment.Length)), 0, 2);
this.ZipFileStream.Write(encodedComment, 0, encodedComment.Length);
}
// Copies all source file into storage file
private void Store(ref ZipFileEntry _zfe, Stream _source)
{
byte[] buffer = new byte[16384];
int bytesRead;
uint totalRead = 0;
Stream outStream;
long posStart = this.ZipFileStream.Position;
long sourceStart = _source.Position;
if (_zfe.Method == Compression.Store)
outStream = this.ZipFileStream;
else
outStream = new DeflateStream(this.ZipFileStream, CompressionMode.Compress, true);
_zfe.Crc32 = (0 ^ 0xFFFFFFFFU);
do
{
bytesRead = _source.Read(buffer, 0, buffer.Length);
totalRead += System.Convert.ToUInt32(bytesRead);
if (bytesRead > 0)
{
outStream.Write(buffer, 0, bytesRead);
for (uint i = 0; i <= bytesRead - 1; i++)
_zfe.Crc32 = ZipStorer.CrcTable[(_zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (_zfe.Crc32 >> 8);
}
}
while (bytesRead == buffer.Length);
outStream.Flush();
if (_zfe.Method == Compression.Deflate)
outStream.Dispose();
_zfe.Crc32 = _zfe.Crc32 ^ 0xFFFFFFFFU;
_zfe.FileSize = totalRead;
_zfe.CompressedSize = System.Convert.ToUInt32(this.ZipFileStream.Position - posStart);
// Verify for real compression
if (_zfe.Method == Compression.Deflate && !this.ForceDeflating && _source.CanSeek && _zfe.CompressedSize > _zfe.FileSize)
{
// Start operation again with Store algorithm
_zfe.Method = Compression.Store;
this.ZipFileStream.Position = posStart;
this.ZipFileStream.SetLength(posStart);
_source.Position = sourceStart;
this.Store(ref _zfe, _source);
}
}
// DOS Date and time:
// MS-DOS date. The date is a packed value with the following format. Bits Description
// 0-4 Day of the month (131)
// 5-8 Month (1 = January, 2 = February, and so on)
// 9-15 Year offset from 1980 (add 1980 to get actual year)
// MS-DOS time. The time is a packed value with the following format. Bits Description
// 0-4 Second divided by 2
// 5-10 Minute (059)
// 11-15 Hour (023 on a 24-hour clock)
private uint DateTimeToDosTime(DateTime _dt)
{
return System.Convert.ToUInt32((_dt.Second / 2) | (_dt.Minute << 5) | (_dt.Hour << 11) | (_dt.Day << 16) | (_dt.Month << 21) | ((_dt.Year - 1980) << 25));
}
private DateTime DosTimeToDateTime(uint _dt)
{
int year = System.Convert.ToInt32(_dt >> 25) + 1980;
int month = System.Convert.ToInt32(_dt >> 21) & 15;
int day = System.Convert.ToInt32(_dt >> 16) & 31;
int hours = System.Convert.ToInt32(_dt >> 11) & 31;
int minutes = System.Convert.ToInt32(_dt >> 5) & 63;
int seconds = System.Convert.ToInt32(_dt & 31) * 2;
if (((month == 0) | (day == 0)))
return DateTime.Now;
return new DateTime(year, month, day, hours, minutes, seconds);
}
// CRC32 algorithm
// The 'magic number' for the CRC is &Hdebb20e3.
// The proper CRC pre and post conditioning
// is used, meaning that the CRC register is
// pre-conditioned with all ones (a starting value
// of &Hffffffff) and the value is post-conditioned by
// taking the one's complement of the CRC residual.
// If bit 3 of the general purpose flag is set, this
// field is set to zero in the local header and the correct
// value is put in the data descriptor and in the central
// directory.
private void UpdateCrcAndSizes(ref ZipFileEntry _zfe)
{
long lastPos = this.ZipFileStream.Position; // remember position
this.ZipFileStream.Position = _zfe.HeaderOffset + 8;
this.ZipFileStream.Write(BitConverter.GetBytes(System.Convert.ToUInt16(_zfe.Method)), 0, 2); // zipping method
this.ZipFileStream.Position = _zfe.HeaderOffset + 14;
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // Update CRC
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // Compressed size
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // Uncompressed size
this.ZipFileStream.Position = lastPos; // restore position
}
// Replaces backslashes with slashes to store in zip header
private string NormalizedFilename(string _filename)
{
string filename = _filename.Replace('\\', '/');
int pos = filename.IndexOf(':');
if (pos >= 0)
filename = filename.Remove(0, pos + 1);
return filename.Trim('/');
}
// Reads the end-of-central-directory record
private bool ReadFileInfo()
{
if ((this.ZipFileStream.Length < 22))
return false;
try
{
this.ZipFileStream.Seek(-17, SeekOrigin.End);
BinaryReader br = new BinaryReader(this.ZipFileStream);
do
{
this.ZipFileStream.Seek(-5, SeekOrigin.Current);
UInt32 sig = br.ReadUInt32();
if (sig == 0x6054B50U)
{
this.ZipFileStream.Seek(6, SeekOrigin.Current);
UInt16 entries = br.ReadUInt16();
Int32 centralSize = br.ReadInt32();
UInt32 centralDirOffset = br.ReadUInt32();
UInt16 commentSize = br.ReadUInt16();
// check if comment field is the very last data in file
if ((this.ZipFileStream.Position + commentSize != this.ZipFileStream.Length))
return false;
// Copy entire central directory to a memory buffer
this.ExistingFiles = entries;
this.CentralDirImage = new byte[centralSize + 1];
this.ZipFileStream.Seek(centralDirOffset, SeekOrigin.Begin);
this.ZipFileStream.Read(this.CentralDirImage, 0, centralSize);
// Leave the pointer at the begining of central dir, to append new files
this.ZipFileStream.Seek(centralDirOffset, SeekOrigin.Begin);
return true;
}
}
while ((this.ZipFileStream.Position > 0));
}
catch
{
}
return false;
}
// <summary>
// Closes the Zip file stream
// </summary>
public void Dispose()
{
this.Close();
}
}
}