My task is to create the password protected ZIP with the SevenZipSharp library.
I managed to make the files contents locked with the password, however the archive structure - file names, directories hierarchy can be viewed in any of the WinZip, 7-Zip or Compressed folder.
I use the cmp.EncryptHeaders = true; however it seems to have no effect...
How can I encrypt the files and directories names? Thanks.
static void Main(string[] args)
{
const string LibraryPath = #"C:\Program Files\7-Zip\7z.dll";
SevenZipCompressor.SetLibraryPath(LibraryPath);
var cmp = new SevenZipCompressor();
cmp.CompressionMethod = CompressionMethod.Default;
cmp.CompressionLevel = CompressionLevel.Fast;
cmp.ArchiveFormat = OutArchiveFormat.Zip; // compatible with WinZip and Compressed folder
cmp.ZipEncryptionMethod = ZipEncryptionMethod.ZipCrypto; // compatible with old WinZip
cmp.EncryptHeaders = true;
cmp.FileCompressionStarted += (sender, e) =>
{
Console.WriteLine(((FileNameEventArgs)e).FileName);
};
const string archive = #"C:\temp\12.3G.zip";
File.Delete(archive);
cmp.CompressDirectory(#"C:\temp\Photos", archive, "password");
}
Looking at the source code, it appears the only way for that flag to take effect is to use SevenZip for the OutArchiveFormat.
From the source code:
if (EncryptHeaders && _archiveFormat == OutArchiveFormat.SevenZip && !SwitchIsInCustomParameters("he"))
{
names.Add(Marshal.StringToBSTR("he"));
var tmp = new PropVariant {VarType = VarEnum.VT_BSTR, Value = Marshal.StringToBSTR("on")};
values.Add(tmp);
}
Related
I have a compressed file .rar .7z, .tar and .zip and I want to rename physical file name available in above compressed archived using C#.
I have tried this using a sharpcompress library but I can't find such a feature for rename file or folder name within .rar .7z, .tar and .zip file.
I also have tried using the DotNetZip library but its only support.Zip see what I have tried using DotNetZip library.
private static void RenameZipEntries(string file)
{
try
{
int renameCount = 0;
using (ZipFile zip2 = ZipFile.Read(file))
{
foreach (ZipEntry e in zip2.ToList())
{
if (!e.IsDirectory)
{
if (e.FileName.EndsWith(".txt"))
{
var newname = e.FileName.Split('.')[0] + "_new." + e.FileName.Split('.')[1];
e.FileName = newname;
e.Comment = "renamed";
zip2.Save();
renameCount++;
}
}
}
zip2.Comment = String.Format("This archive has been modified. {0} files have been renamed.", renameCount);
zip2.Save();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
But actually the same as above I also want for .7z, .rar and .tar, I tried many libraries but still I didn't get any accurate solution.
Please help me.
This is a simple console application to rename files in .zip
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
namespace Renamer
{
class Program
{
static void Main(string[] args)
{
using var archive = new ZipArchive(File.Open(#"<Your File>.zip", FileMode.Open, FileAccess.ReadWrite), ZipArchiveMode.Update);
var entries = archive.Entries.ToArray();
//foreach (ZipArchiveEntry entry in entries)
//{
// //If ZipArchiveEntry is a directory it will have its FullName property ending with "/" (e.g. "some_dir/")
// //and its Name property will be empty string ("").
// if (!string.IsNullOrEmpty(entry.Name))
// {
// var newEntry = archive.CreateEntry($"{entry.FullName.Replace(entry.Name, $"{RandomString(10, false)}{Path.GetExtension(entry.Name)}")}");
// using (var a = entry.Open())
// using (var b = newEntry.Open())
// a.CopyTo(b);
// entry.Delete();
// }
//}
Parallel.ForEach(entries, entry =>
{
//If ZipArchiveEntry is a directory it will have its FullName property ending with "/" (e.g. "some_dir/")
//and its Name property will be empty string ("").
if (!string.IsNullOrEmpty(entry.Name))
{
ZipArchiveEntry newEntry = archive.CreateEntry($"{entry.FullName.Replace(entry.Name, $"{RandomString(10, false)}{Path.GetExtension(entry.Name)}")}");
using (var a = entry.Open())
using (var b = newEntry.Open())
a.CopyTo(b);
entry.Delete();
}
});
}
//To Generate random name for the file
public static string RandomString(int size, bool lowerCase)
{
StringBuilder builder = new StringBuilder();
Random random = new Random();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
if (lowerCase)
return builder.ToString().ToLower();
return builder.ToString();
}
}
}
Consider 7zipsharp:
https://www.nuget.org/packages/SevenZipSharp.Net45/
7zip itself supports lots of archive formats (I believe all you mentioned) and 7zipsharp uses the real 7zip. I've used 7zipsharp for .7z files only but I bet it works for others.
Here's a sample of a test that appears to rename a file using ModifyArchive method, I suggest you go to school in it:
https://github.com/squid-box/SevenZipSharp/blob/f2bee350e997b0f4b1258dff520f36409198f006/SevenZip.Tests/SevenZipCompressorTests.cs
Here's the code simplified a bit. Note that the test compresses a 7z file for its test; that's immaterial it could be .txt, etc. Also note it finds the file by index in the dictionary passed to ModifyArchive. Consult documentation for how to get that index from a filename (maybe you have to loop and compare).
var compressor = new SevenZipCompressor( ... snip ...);
compressor.CompressFiles("tmp.7z", #"Testdata\7z_LZMA2.7z");
compressor.ModifyArchive("tmp.7z", new Dictionary<int, string> { { 0, "renamed.7z" }});
using (var extractor = new SevenZipExtractor("tmp.7z"))
{
Assert.AreEqual(1, extractor.FilesCount);
extractor.ExtractArchive(OutputDirectory);
}
Assert.IsTrue(File.Exists(Path.Combine(OutputDirectory, "renamed.7z")));
Assert.IsFalse(File.Exists(Path.Combine(OutputDirectory, "7z_LZMA2.7z")));
I'm trying to implement the file sharing from other apps in Xamarin.Forms.
And I have some issues with Android implementation.
I'm referring to code of https://codemilltech.com/sending-files-to-a-xamarin-forms-app-part-2-android/.
if (Intent.Action == Intent.ActionSend)
{
var uriFromExtras = Intent.GetParcelableExtra(Intent.ExtraStream) as Android.Net.Uri;
string path = Intent.GetParcelableExtra(Intent.ExtraStream).ToString();
var subject = Intent.GetStringExtra(Intent.ExtraSubject);
// Get the info from ClipData
var pdf = Intent.ClipData.GetItemAt(0);
// Open a stream from the URI
var pdfStream = ContentResolver.OpenInputStream(pdf.Uri);
// Save it over
var memOfPdf = new System.IO.MemoryStream();
pdfStream.CopyTo(memOfPdf);
var docsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var filePath = System.IO.Path.Combine(docsPath, "temp");
System.IO.File.WriteAllBytes(filePath, memOfPdf.ToArray());
mainForms.ShareFile(memOfPdf.ToArray(), System.IO.Path.GetFileName(path));
}
And I need to get the original name of shared file from File Manager.
Can anyone help me?
Here is a solution that gets the original file name of a shared file through an intent.
if (Intent.Action == Intent.ActionSend)
{
ClipData clip = Intent.ClipData;
Uri uri = clip.GetItemAt(0).Uri;
ICursor returnCursor = ContentResolver.Query(uri, null, null, null, null);
int nameIndex = returnCursor.GetColumnIndex(IOpenableColumns.DisplayName);
returnCursor.MoveToFirst();
var fileName = returnCursor.GetString(nameIndex);
Toast.MakeText(this,"fileName == " + fileName, ToastLength.Short).Show();
}
Examples: .png file and an xls file.
Can someone helps me out with my problem.
I have to take a file's directory in zip file so i can calculate its MD5 hash (without unzip it). I am using DotNetZip Library but i can't find the solution of the problem. I'll show you what i've tryed and hope you will help as fast as possible.
Thanks!
if (ofd.ShowDialog() == DialogResult.OK)
{
using (ZipFile zip = ZipFile.Read(ofd.FileName))
{
foreach (ZipEntry f in zip)
{
GetMD5HashFromFile(ofd.FileName+"\\"+f.FileName);
}
}
}
The problem is that you do not extract the Zip entry, it is still in the archive. That is why it does not find the path.
I recommend to use the stream and calculate on that, without extracting.
Be aware of that MD5 is no collision safe.
You have to reference in your project the System.IO.Compression.FileSystem.dll.
Full working console application:
public class Program
{
static void Main(string[] args)
{
var z = ZipFile.OpenRead(#"C:\directory\anyfile.zip");
foreach (ZipArchiveEntry f in z.Entries)
{
var yourhash = GetMD5HashFromFile(f.Open());
}
}
public static string GetMD5HashFromFile(Stream stream)
{
using (var md5 = new MD5CryptoServiceProvider())
{
var buffer = md5.ComputeHash(stream);
var sb = new StringBuilder();
for (int i = 0; i < buffer.Length; i++)
{
sb.Append(buffer[i].ToString("x2"));
}
return sb.ToString();
}
}
I've got some strange behavior during execution in a ASP.NET application.
It doesn't matter if I set workingFolder (see code below) to System.IO.Path.GetTempPath or any other public folder (current case).
I receive a ZIP file, unpack that file (using SharpZipLib) and try to digest the files in that folder, but the System.IO GetFiles returns an empty list.
I've tried to use DirectoryInfo.GetFiles and Directory.GetFiles : both an empty list.
If I breakpoint on the Directory.Delete and look at the folder I can see the files, they're not locked and I can do anything with the files - even if I set the "run from cursor" point at the beginning of the foreach no luck - the GetFiles still return an empty list (although I can see the files in explorer).
private const string EXTENSION_LOG_FILE = ".txt";
private const string VALID_EXTENSION_MASK = "*." + EXTENSION_LOG_FILE;
var zipFolder = unpackZip(filePath, workingFolder);
foreach (var zipFileInfo in new DirectoryInfo(zipFolder).GetFiles(VALID_EXTENSION_MASK, SearchOption.TopDirectoryOnly))
{
// never get's here
value.AddRange(getLogItems(zipFileInfo.FullName));
File.Delete(zipFileInfo.FullName);
}
// this fails: folder is not empty
Directory.Delete(zipFolder);
and the unpackZip method:
private static string unpackZip(string zipFile, string workingFolder)
{
// doesn't matter what name I use, GUID or no GUID the GetFiles still returns an empty lists
var tempFolder = Path.Combine(workingFolder, Guid.NewGuid().ToString());
Directory.CreateDirectory(tempFolder);
using (var unzipStream = new ZipInputStream(File.OpenRead(zipFile)))
{
ZipEntry entry;
while ((entry = unzipStream.GetNextEntry()) != null)
{
var fileName = Path.GetFileName(entry.Name);
if (fileName == string.Empty) continue;
using (var streamWriter = File.Create(Path.Combine(tempFolder, Path.GetFileName(entry.Name))))
{
var size = 2048;
var data = new byte[2048];
while (size > 0)
{
size = unzipStream.Read(data, 0, data.Length);
streamWriter.Write(data, 0, size);
}
}
}
}
return tempFolder;
}
any suggestions?
Problem which I guessed in
private const string VALID_EXTENSION_MASK = "*." + EXTENSION_LOG_FILE;
retruns *..txt because EXTENSION_LOG_FILE = ".txt"
I have sfx files from the program that I created using sevenzipsharp library. still when I execute directly with double-click the file sfx if using the wrong password but still extract the files in it with a size of 0 bytes, if anyone should I add another mode to function 'Compress' so that when I execute the file sfx wrong password files are not extracted at all.
Compress code:
public void Compress()
{
SevenZipCompressor.SetLibraryPath("7z.dll");
SevenZipCompressor cmp = new SevenZipCompressor();
cmp.Compressing += new EventHandler<ProgressEventArgs>(cmp_Compressing);
cmp.FileCompressionStarted += new EventHandler<FileNameEventArgs>(cmp_StartCompress);
cmp.CompressionFinished += new EventHandler<EventArgs>(cmp_CompleteCompressed);
cmp.ArchiveFormat = OutArchiveFormat.SevenZip;
cmp.CompressionLevel = CompressionLevel.Normal;
cmp.CompressionMethod = CompressionMethod.Lzma;
cmp.CompressionMode = CompressionMode.Create;
string password = txtPasswordEn.Text;
string DirFile = tempFolder;
string NameFileCompress = Path.Combine(txtOutputFileEn.Text, txtNameFile.Text) + (".zip");
cmp.BeginCompressDirectory(DirFile, NameFileCompress, password, ".",true);
}
Create SFX Code:
public void CreateSfx()
{
string location = Path.Combine(txtOutputFileEn.Text, txtNameFile.Text);
string nameZip = location + (".zip");
string nameExe = location + (".exe");
SfxModule mdl = SfxModule.Extended;
SevenZipSfx sfx = new SevenZipSfx(mdl);
sfx.ModuleFileName = #"7z.sfx";
sfx.MakeSfx(nameZip, nameExe);
}
I've just seen that you're not creating a .zip file but a .7z file (and then convert it to a self extracting archive).
For that file format, you can achieve file name encryption using the EncryptHeaders property:
cmp.EncryptHeaders = true;