From 6adcaebacee0bf825a5631def7be255e83379fe3 Mon Sep 17 00:00:00 2001 From: tombogle Date: Thu, 7 Nov 2024 16:49:52 -0600 Subject: [PATCH 1/2] +semver:major Replaced dependency on DotNetZip with System.IO.Compression.ZipFile --- CHANGELOG.md | 1 + Palaso.sln.DotSettings | 2 + .../RampArchivingDlgViewModelTests.cs | 51 ++++++++++-------- .../SIL.Archiving.Tests.csproj | 3 +- SIL.Archiving/RampArchivingDlgViewModel.cs | 53 ++++++++----------- SIL.Archiving/SIL.Archiving.csproj | 3 +- SIL.DblBundle.Tests/BundleTests.cs | 15 +++--- .../SIL.DblBundle.Tests.csproj | 2 +- SIL.DblBundle.Tests/Text/TextBundleTests.cs | 34 +++++++----- SIL.DblBundle/SIL.DblBundle.csproj | 1 + .../SIL.Windows.Forms.Archiving.csproj | 3 +- 11 files changed, 88 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48ee9b792..ea5254138 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- BREAKING CHANGE: Replaced dependency on DotNetZip with System.IO.Compression.ZipFile (Client installers will need to be changed.) - BREAKING CHANGE: Changed to target .Net Framework 4.6.2 instead of 4.6.1 - [SIL.Windows.Forms] Look for PNG data on clipboard before checking for plain image in WindowsClipboard.GetImageFromClipboard() in order to preserve transparency in copied images. - [SIL.Windows.Forms] Changed layout of SILAboutBox to accommodate wider SIL logo. diff --git a/Palaso.sln.DotSettings b/Palaso.sln.DotSettings index 7b82e81f3..6bfe95d19 100644 --- a/Palaso.sln.DotSettings +++ b/Palaso.sln.DotSettings @@ -62,6 +62,8 @@ True True True + True + True True True True diff --git a/SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs b/SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs index 7783b3340..474851574 100644 --- a/SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs +++ b/SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; +using System.IO.Packaging; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -using Ionic.Zip; using NUnit.Framework; using SIL.Core.ClearShare; using SIL.IO; @@ -120,23 +121,24 @@ public void GetMode_MultipleTypesInList_ReturnsCorrectMetsList() [Test] public void GetMode_ZipFileWithMultipleTypesInList_ReturnsCorrectMetsList() { - ZipFile zipFile = new ZipFile(); - zipFile.AddEntry("blah.mp3", "whatever"); - zipFile.AddEntry("blah.doc", "whatever"); - zipFile.AddEntry("blah.niff", "whatever"); var tempFile = TempFile.WithExtension("zip"); try { - zipFile.Save(tempFile.Path); - var mode = m_model.GetMode(new[] { zipFile.Name }); - Assert.AreEqual("\"" + RampArchivingDlgViewModel.kFileTypeModeList + "\":[\"" + + RobustFile.Delete(tempFile.Path); + using (var zipFile = ZipFile.Open(tempFile.Path, ZipArchiveMode.Create)) + { + zipFile.CreateEntry("blah.mp3"); + zipFile.CreateEntry("blah.doc"); + zipFile.CreateEntry("blah.niff"); + } + var mode = m_model.GetMode(new[] { tempFile.Path }); + Assert.That(mode, Is.EqualTo("\"" + RampArchivingDlgViewModel.kFileTypeModeList + "\":[\"" + RampArchivingDlgViewModel.kModeSpeech + "\",\"" + RampArchivingDlgViewModel.kModeText + "\",\"" + - RampArchivingDlgViewModel.kModeMusicalNotation + "\"]", mode); + RampArchivingDlgViewModel.kModeMusicalNotation + "\"]")); } finally { - zipFile.Dispose(); tempFile.Dispose(); } } @@ -145,24 +147,25 @@ public void GetMode_ZipFileWithMultipleTypesInList_ReturnsCorrectMetsList() [Test] public void GetMode_FwBackupFileWithMultipleTypesInList_ReturnsCorrectMetsList() { - ZipFile zipFile = new ZipFile(); - zipFile.AddEntry("blah.fwdata", "whatever"); - zipFile.AddEntry("fonts/blah.ttf", "whatever"); - zipFile.AddEntry("images/blah.jpeg", "whatever"); var tempFile = TempFile.WithExtension("fwbackup"); try { - zipFile.Save(tempFile.Path); - var mode = m_model.GetMode(new[] { zipFile.Name }); - Assert.AreEqual("\"" + RampArchivingDlgViewModel.kFileTypeModeList + "\":[\"" + + RobustFile.Delete(tempFile.Path); + using (var zipFile = ZipFile.Open(tempFile.Path, ZipArchiveMode.Create)) + { + zipFile.CreateEntry("blah.fwdata"); + zipFile.CreateEntry("fonts/blah.ttf"); + zipFile.CreateEntry("images/blah.jpeg"); + } + var mode = m_model.GetMode(new[] { tempFile.Path }); + Assert.That(mode, Is.EqualTo("\"" + RampArchivingDlgViewModel.kFileTypeModeList + "\":[\"" + RampArchivingDlgViewModel.kModeText + "\",\"" + RampArchivingDlgViewModel.kModeDataset + "\",\"" + RampArchivingDlgViewModel.kModeSoftwareOrFont + "\",\"" + - RampArchivingDlgViewModel.kModePhotograph + "\"]", mode); + RampArchivingDlgViewModel.kModePhotograph + "\"]")); } finally { - zipFile.Dispose(); tempFile.Dispose(); } } @@ -407,10 +410,12 @@ public void SetAbstract_Null_ThrowsArgumentNullException() [Test] public void SetAbstract_ThreeLanguages_IncludedInMetsData() { - Dictionary abstracts = new Dictionary(); - abstracts["eng"] = "This is pretty abstract"; - abstracts["fra"] = "C'est assez abstrait"; - abstracts["spa"] = "Esto es bastante abstracto"; + Dictionary abstracts = new Dictionary + { + ["eng"] = "This is pretty abstract", + ["fra"] = "C'est assez abstrait", + ["spa"] = "Esto es bastante abstracto" + }; m_model.SetAbstract(abstracts); var data = m_model.GetMetadata(); Assert.AreEqual("{\"dc.title\":\"Test Title\"," + diff --git a/SIL.Archiving.Tests/SIL.Archiving.Tests.csproj b/SIL.Archiving.Tests/SIL.Archiving.Tests.csproj index 99850ec00..8f644e42e 100644 --- a/SIL.Archiving.Tests/SIL.Archiving.Tests.csproj +++ b/SIL.Archiving.Tests/SIL.Archiving.Tests.csproj @@ -12,10 +12,11 @@ - + + diff --git a/SIL.Archiving/RampArchivingDlgViewModel.cs b/SIL.Archiving/RampArchivingDlgViewModel.cs index cd5780a83..bf6762085 100644 --- a/SIL.Archiving/RampArchivingDlgViewModel.cs +++ b/SIL.Archiving/RampArchivingDlgViewModel.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using System.IO.Compression; using System.Linq; using System.Security; using System.Text; using System.Threading; using System.Threading.Tasks; -using Ionic.Zip; using JetBrains.Annotations; using SIL.Core.ClearShare; using SIL.Extensions; @@ -267,8 +267,8 @@ private void AddModesToSet(IEnumerable files) { if (FileUtils.GetIsZipFile(file)) { - using (var zipFile = new ZipFile(file)) - AddModesToSet(zipFile.EntryFileNames); + using (var zipArchive = ZipFile.OpenRead(file)) + AddModesToSet(zipArchive.Entries.Select(e => e.FullName)); continue; } @@ -1674,41 +1674,34 @@ private void CreateZipFile(CancellationToken cancellationToken) ReportMajorProgressPoint(StringId.SavingFilesInPackage, cancellationToken); - using (var zip = new ZipFile()) + using (var zip = ZipFile.Open(PackagePath, ZipArchiveMode.Create)) { - // RAMP packages must not be compressed or RAMP can't read them. - zip.UseZip64WhenSaving = Zip64Option.AsNecessary; // See SP-2291 - zip.CompressionLevel = Ionic.Zlib.CompressionLevel.None; - zip.AddFiles(filesToCopyAndZip.Values, @"\"); - zip.AddFile(_metsFilePath, Empty); - zip.SaveProgress += delegate(object sender, SaveProgressEventArgs args) - { - HandleZipSaveProgress(args, cancellationToken); - }; - zip.Save(PackagePath); + foreach (var filePath in filesToCopyAndZip.Values) + AddFileToZipArchive(zip, filePath, cancellationToken); - if (!cancellationToken.IsCancellationRequested) - Thread.Sleep(800); + AddFileToZipArchive(zip, _metsFilePath, cancellationToken); } } /// ------------------------------------------------------------------------------------ /// - /// This is called by the Save method on the ZipFile class as the zip file is being - /// saved to the disk. + /// Add the requested file to the zip archive after reporting progress and checking for + /// cancellation by user. /// + /// RAMP packages must not be compressed or RAMP can't read them. /// ------------------------------------------------------------------------------------ - private void HandleZipSaveProgress(SaveProgressEventArgs e, + private void AddFileToZipArchive(ZipArchive zip, string filePath, CancellationToken cancellationToken) { - if (e.EventType != ZipProgressEventType.Saving_BeforeWriteEntry) - return; - - if (_progressMessages.TryGetValue(e.CurrentEntry.FileName, out var msg)) + if (_progressMessages.TryGetValue(filePath, out var msg)) DisplayMessage(msg, MessageType.Progress); - ReportProgress(Path.GetFileName(e.CurrentEntry.FileName), MessageType.Detail, cancellationToken); + var fileName = Path.GetFileName(filePath); + + ReportProgress(fileName, MessageType.Detail, cancellationToken); + + zip.CreateEntryFromFile(filePath, fileName, CompressionLevel.NoCompression); } #endregion @@ -1759,17 +1752,17 @@ private static string GetLanguageFileLocation() // get the data directory dir = Path.Combine(dir, "data"); if (!Directory.Exists(dir)) - throw new DirectoryNotFoundException(Format("The path {0} is not valid.", dir)); + throw new DirectoryNotFoundException($"The path {dir} is not valid."); // get the options directory dir = Path.Combine(dir, "options"); if (!Directory.Exists(dir)) - throw new DirectoryNotFoundException(Format("The path {0} is not valid.", dir)); + throw new DirectoryNotFoundException($"The path {dir} is not valid."); // get the languages.yaml file var langFile = Path.Combine(dir, "languages.yaml"); if (!File.Exists(langFile)) - throw new FileNotFoundException(Format("The file {0} was not found.", langFile), langFile); + throw new FileNotFoundException($"The file {langFile} was not found.", langFile); return langFile; } @@ -1815,12 +1808,12 @@ private Dictionary GetLanguageList() /// ------------------------------------------------------------------------------------ public string GetLanguageName(string iso3Code) { - var langs = GetLanguageList(); + var languages = GetLanguageList(); - if (langs == null) + if (languages == null) throw new Exception("The language list for RAMP was not retrieved."); - return langs.ContainsKey(iso3Code) ? langs[iso3Code] : null; + return languages.TryGetValue(iso3Code, out var lang) ? lang : null; } #endregion diff --git a/SIL.Archiving/SIL.Archiving.csproj b/SIL.Archiving/SIL.Archiving.csproj index a14d1c35d..9d9b29865 100644 --- a/SIL.Archiving/SIL.Archiving.csproj +++ b/SIL.Archiving/SIL.Archiving.csproj @@ -20,13 +20,14 @@ - All + + diff --git a/SIL.DblBundle.Tests/BundleTests.cs b/SIL.DblBundle.Tests/BundleTests.cs index 3cdeeaf83..57190b9a8 100644 --- a/SIL.DblBundle.Tests/BundleTests.cs +++ b/SIL.DblBundle.Tests/BundleTests.cs @@ -1,7 +1,7 @@ using System; using System.IO; +using System.IO.Compression; using System.Xml.Serialization; -using Ionic.Zip; using NUnit.Framework; using SIL.DblBundle.Text; using SIL.IO; @@ -33,10 +33,7 @@ public TestBundle(string pathToZippedBundle) : base(pathToZippedBundle) { } - public override string Name - { - get { return "Test"; } - } + public override string Name => "Test"; } /// @@ -65,14 +62,14 @@ public void LanguageIso_NoLanguageCodeSpecified_ReturnsCodeForUnlistedLanguage() private static TempFile CreateDummyVersion1_5ZippedTestBundle() { - TempFile bundle = TempFile.WithExtension(DblBundleFileUtils.kDblBundleExtension); + var bundle = TempFile.WithExtension(DblBundleFileUtils.kDblBundleExtension); + RobustFile.Delete(bundle.Path); using (var metadataXml = TempFile.WithFilename("metadata.xml")) - using (var zip = new ZipFile()) + using (var zip = ZipFile.Open(bundle.Path, ZipArchiveMode.Create)) { File.WriteAllText(metadataXml.Path, @""); - zip.AddFile(metadataXml.Path, string.Empty); - zip.Save(bundle.Path); + zip.CreateEntryFromFile(metadataXml.Path, Path.GetFileName(metadataXml.Path)); } return bundle; diff --git a/SIL.DblBundle.Tests/SIL.DblBundle.Tests.csproj b/SIL.DblBundle.Tests/SIL.DblBundle.Tests.csproj index bae661f9d..5101e6f3b 100644 --- a/SIL.DblBundle.Tests/SIL.DblBundle.Tests.csproj +++ b/SIL.DblBundle.Tests/SIL.DblBundle.Tests.csproj @@ -9,12 +9,12 @@ - + diff --git a/SIL.DblBundle.Tests/Text/TextBundleTests.cs b/SIL.DblBundle.Tests/Text/TextBundleTests.cs index df6326c53..2f5f59055 100644 --- a/SIL.DblBundle.Tests/Text/TextBundleTests.cs +++ b/SIL.DblBundle.Tests/Text/TextBundleTests.cs @@ -1,14 +1,15 @@ using System; using System.Globalization; using System.IO; +using System.IO.Compression; using System.Linq; -using Ionic.Zip; using NUnit.Framework; using SIL.DblBundle.Tests.Properties; using SIL.DblBundle.Text; using SIL.DblBundle.Usx; using SIL.IO; using SIL.WritingSystems; +using static System.String; namespace SIL.DblBundle.Tests.Text { @@ -139,8 +140,7 @@ public void CreateBundle_ProperlyLoadsWritingSystemDefinition(bool legacy) public void TryGetBook(bool legacy) { var bundle = legacy ? _legacyBundle : _bundle; - UsxDocument book; - Assert.IsTrue(bundle.TryGetBook("MAT", out book)); + Assert.IsTrue(bundle.TryGetBook("MAT", out var book)); Assert.AreEqual("MAT", book.BookId); } @@ -252,6 +252,7 @@ private static TempFile CreateZippedTextBundleFromResources(MetadataVersion vers bool includeLdml = true, bool invalidUsxDirectory = false, bool includeFont = false) { TempFile bundle = TempFile.WithExtension(DblBundleFileUtils.kDblBundleExtension); + RobustFile.Delete(bundle.Path); using (var englishLds = TempFile.WithFilename("English.lds")) using (var metadataXml = TempFile.WithFilename("metadata.xml")) @@ -260,7 +261,7 @@ private static TempFile CreateZippedTextBundleFromResources(MetadataVersion vers using (var ldmlXml = TempFile.WithFilename(DblBundleFileUtils.kLegacyLdmlFileName)) using (var ttf = TempFile.WithFilename("AppSILI.ttf")) using (var matUsx = TempFile.WithFilename("MAT.usx")) - using (var zip = new ZipFile()) + using (var zip = ZipFile.Open(bundle.Path, ZipArchiveMode.Create)) { string xml; var subdirectory = "release"; @@ -268,7 +269,7 @@ private static TempFile CreateZippedTextBundleFromResources(MetadataVersion vers { case MetadataVersion.V1_4: xml = Resources.metadata_xml; - subdirectory = string.Empty; + subdirectory = Empty; break; case MetadataVersion.V2_1: xml = Resources.metadataVersion2_1_xml; @@ -280,30 +281,35 @@ private static TempFile CreateZippedTextBundleFromResources(MetadataVersion vers throw new ArgumentOutOfRangeException(nameof(version), version, null); } File.WriteAllText(metadataXml.Path, xml); - zip.AddFile(metadataXml.Path, string.Empty); + zip.CreateEntryFromFile(metadataXml.Path, Path.GetFileName(metadataXml.Path)); File.WriteAllBytes(englishLds.Path, Resources.English_lds); - zip.AddFile(englishLds.Path, subdirectory); + zip.CreateEntryFromFile(englishLds.Path, + Path.Combine(subdirectory, Path.GetFileName(englishLds.Path))); File.WriteAllText(stylesXml.Path, Resources.styles_xml); - zip.AddFile(stylesXml.Path, subdirectory); + zip.CreateEntryFromFile(stylesXml.Path, + Path.Combine(subdirectory, Path.GetFileName(stylesXml.Path))); File.WriteAllBytes(versificationVrs.Path, Resources.versification_vrs); - zip.AddFile(versificationVrs.Path, subdirectory); + zip.CreateEntryFromFile(versificationVrs.Path, + Path.Combine(subdirectory, Path.GetFileName(versificationVrs.Path))); if (includeLdml) { File.WriteAllText(ldmlXml.Path, Resources.ldml_xml); - zip.AddFile(ldmlXml.Path, subdirectory); + zip.CreateEntryFromFile(ldmlXml.Path, + Path.Combine(subdirectory, Path.GetFileName(ldmlXml.Path))); } if (includeFont) { File.WriteAllBytes(ttf.Path, (byte[])Resources.ResourceManager.GetObject("AppSILI", CultureInfo.InvariantCulture)); - zip.AddFile(ttf.Path, subdirectory); + zip.CreateEntryFromFile(ttf.Path, + Path.Combine(subdirectory, Path.GetFileName(ttf.Path))); } File.WriteAllBytes(matUsx.Path, Resources.MAT_usx); - if (subdirectory != String.Empty) + if (subdirectory != Empty) subdirectory += "/"; - zip.AddFile(matUsx.Path, subdirectory + (invalidUsxDirectory ? "USX_999" : "USX_1")); - zip.Save(bundle.Path); + zip.CreateEntryFromFile(matUsx.Path, Path.Combine(subdirectory + + (invalidUsxDirectory ? "USX_999" : "USX_1"), Path.GetFileName(matUsx.Path))); } return bundle; diff --git a/SIL.DblBundle/SIL.DblBundle.csproj b/SIL.DblBundle/SIL.DblBundle.csproj index e2395fc01..c40c8d0d3 100644 --- a/SIL.DblBundle/SIL.DblBundle.csproj +++ b/SIL.DblBundle/SIL.DblBundle.csproj @@ -11,6 +11,7 @@ + diff --git a/SIL.Windows.Forms.Archiving/SIL.Windows.Forms.Archiving.csproj b/SIL.Windows.Forms.Archiving/SIL.Windows.Forms.Archiving.csproj index 87cfb58a8..168baac41 100644 --- a/SIL.Windows.Forms.Archiving/SIL.Windows.Forms.Archiving.csproj +++ b/SIL.Windows.Forms.Archiving/SIL.Windows.Forms.Archiving.csproj @@ -14,7 +14,6 @@ - All @@ -22,6 +21,8 @@ + + From aae892cac63e73cd3cb08a372e8eb27d88dbdfb2 Mon Sep 17 00:00:00 2001 From: tombogle Date: Thu, 7 Nov 2024 23:07:57 -0600 Subject: [PATCH 2/2] Tweaked test to demonstrate that zip files can handle filenames with Unicode surrogate pairs --- SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs b/SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs index 474851574..f12a87531 100644 --- a/SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs +++ b/SIL.Archiving.Tests/RampArchivingDlgViewModelTests.cs @@ -127,7 +127,8 @@ public void GetMode_ZipFileWithMultipleTypesInList_ReturnsCorrectMetsList() RobustFile.Delete(tempFile.Path); using (var zipFile = ZipFile.Open(tempFile.Path, ZipArchiveMode.Create)) { - zipFile.CreateEntry("blah.mp3"); + // For good measure, make sure we can handle filenames with Unicode surrogate pairs + zipFile.CreateEntry("blah\uD800\uDC00\ud803\ude6d\udbff\udfff.mp3"); zipFile.CreateEntry("blah.doc"); zipFile.CreateEntry("blah.niff"); }