Steps to reproduce:
1.Create a zip archive for a txt file with password protection
2. Try updating the protected file and insert a new text line for example
The settings used for decrypting the file don't seem to be used encrypting again after the update operation. Here is a sample code snippet for reproducing the error message:
Sub Main()
Dim sZipFilePath As String = "..\..\test.zip"
File.Delete(sZipFilePath)
CreateArchive(sZipFilePath)
Dim decryptionSettings As DecryptionSettings = EncryptionSettings.CreateDecryptionSettings()
AddHandler decryptionSettings.PasswordRequired, AddressOf DecryptionSettings_PasswordRequired
Dim compressionSettings As CompressionSettings = Nothing
Dim encoding As Encoding = Nothing
Using oFS As FileStream = File.Open(sZipFilePath, FileMode.OpenOrCreate)
Using oArchive As ZipArchive = ZipArchive.Update(oFS, encoding, compressionSettings, decryptionSettings)
For Each entry As ZipArchiveEntry In oArchive.Entries
Using entryStream As Stream = entry.Open()
Dim reader As New StreamReader(entryStream)
Dim content As String = reader.ReadToEnd()
entryStream.Seek(0, SeekOrigin.End)
Dim writer As New StreamWriter(entryStream)
writer.WriteLine("Updated line.")
writer.Flush()
End Using
Next
End Using
End Using
End Sub
Private Sub CreateArchive(sZipFilePath As String)
Using stream As Stream = File.Open(sZipFilePath, FileMode.Create)
Dim encryptionSettings As PasswordEncryptionSettings = encryptionSettings.CreatePkzipPasswordEncryptionSettings()
encryptionSettings.Password = "MyPassword"
Dim compressionSettings As CompressionSettings = Nothing
Dim encoding As Encoding = Nothing
Using archive As ZipArchive = ZipArchive.Create(stream, encoding, compressionSettings, encryptionSettings)
Using entry As ZipArchiveEntry = archive.CreateEntry("text.txt")
Dim writer As StreamWriter = New StreamWriter(entry.Open())
writer.WriteLine("Hello world!")
writer.Flush()
End Using
End Using
End Using
End Sub
Private Sub DecryptionSettings_PasswordRequired(ByVal sender As Object, ByVal e As PasswordRequiredEventArgs)
e.Password = "MyPassword"
End Sub
Add support for extraction of AES-encrypted archives.
There is a related feature request for the creation of such archives: ZipLibrary: Add support for creation of AES-encrypted archives.
I'm trying to implement the IXmlSerialization for class SerializableDictionary. When starts the serialization of class to xml, I'm catching the System.NotSupportedException: 'Can't flush final block twice'. The problem occurs when second serializer trying to call Serialize method on same XmlWriter.
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, false, null))
{
foreach (var item in array)
{
using (var entry = archive.CreateEntry($"{item.Name}.reg-ext"))
{
XmlInOut<RegulationItem>.SaveToStream(entry.Open(), item);
}
}
}
Could it be bug with the ArchiveEntry Stream?
I've placed a solution into a github repo. Also I tried to replace the stream of entry with the MemoryStream, and it helps. But I would to do it directly, if it's possible.
MemoryStream ms1 = new MemoryStream();
using (ZipArchive archive = new ZipArchive(ms1, ZipArchiveMode.Create, false, null))
{
using (PdfFileSource fileSource = new PdfFileSource(File.OpenRead(documentToSplit)))
{
string splitDocumentName = "1st page.pdf";
using (ZipArchiveEntry entry = archive.CreateEntry(splitDocumentName))
{
using (PdfStreamWriter writer = new PdfStreamWriter(entry.Open()))
{
PdfPageSource page = fileSource.Pages[0];
writer.WritePage(page);
}
}
}
}
File.WriteAllBytes("exported.zip", ms1.ToArray());
Provide a simple method to detect that a password for a ZIP file is not valid.
The current implemention usually throws an exception (which does not definitively identify the password as wrong), but not always. Sometimes it just returns corrupt data.
It would be nice to either have a typed exception consistently thrown, or a method to specifically check for an invalid password.
Thanks.
When updating ZIP archive, there is no need for loading it fully in the memory. Each entry is represented as a separate stream; when the ZipArchive is disposed, each entry is written in the OutputStream which is MemoryStream. When an entry is written in the OutputStream it is read from the source file if it is not changed. The MemoryStream is used because the source file is needed to get the entries contents. A temporary file can be used instead and there will be no need of the memory stream, so that large files will be updated without using much memory (which causes OutOfMemoryException).