-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Add ZipArchiveEntry.Open(FileAccess) overload #122032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f56ccb6
b977ca7
04ddf87
b35de54
24f7ebe
31f1476
0f2e2ce
a046dfa
a3cf84b
9878931
760a5aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -362,6 +362,50 @@ public Stream Open() | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Opens the entry with the specified access mode. This allows for more granular control over the returned stream's capabilities. | ||||||
| /// </summary> | ||||||
| /// <param name="access">The desired file access mode for the returned stream.</param> | ||||||
| /// <returns>A Stream that represents the contents of the entry with the specified access capabilities.</returns> | ||||||
|
||||||
| /// <returns>A Stream that represents the contents of the entry with the specified access capabilities.</returns> | |
| /// <returns>A <see cref="Stream"/> that represents the contents of the entry with the specified access capabilities.</returns> |
iremyux marked this conversation as resolved.
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2194,5 +2194,281 @@ private static byte[] GenerateInvalidExtraFieldData(byte modifiedVersionToExtrac | |
| // comment length | ||
| 0x00, 0x00 | ||
| }; | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_ReadMode_ReadAccess_Succeeds(bool async) | ||
| { | ||
| using MemoryStream ms = await StreamHelpers.CreateTempCopyStream(zfile("normal.zip")); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Read); | ||
|
|
||
| ZipArchiveEntry entry = archive.GetEntry("first.txt"); | ||
| Assert.NotNull(entry); | ||
|
|
||
| using Stream stream = entry.Open(FileAccess.Read); | ||
| Assert.True(stream.CanRead); | ||
| Assert.False(stream.CanWrite); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_ReadMode_WriteAccess_Throws(bool async) | ||
| { | ||
| using MemoryStream ms = await StreamHelpers.CreateTempCopyStream(zfile("normal.zip")); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Read); | ||
|
|
||
| ZipArchiveEntry entry = archive.GetEntry("first.txt"); | ||
| Assert.NotNull(entry); | ||
|
|
||
| Assert.Throws<ArgumentException>("access", () => entry.Open(FileAccess.Write)); | ||
| Assert.Throws<ArgumentException>("access", () => entry.Open(FileAccess.ReadWrite)); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_CreateMode_WriteAccess_Succeeds(bool async) | ||
| { | ||
| using var ms = new MemoryStream(); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Create, leaveOpen: true); | ||
|
|
||
| ZipArchiveEntry entry = archive.CreateEntry("test.txt"); | ||
|
|
||
| using Stream stream = entry.Open(FileAccess.Write); | ||
| Assert.False(stream.CanRead); | ||
| Assert.True(stream.CanWrite); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_CreateMode_ReadWriteAccess_Succeeds(bool async) | ||
| { | ||
| using var ms = new MemoryStream(); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Create, leaveOpen: true); | ||
|
|
||
| ZipArchiveEntry entry = archive.CreateEntry("test.txt"); | ||
|
|
||
| // ReadWrite should be allowed in Create mode (it opens in write mode) | ||
| using Stream stream = entry.Open(FileAccess.ReadWrite); | ||
| Assert.True(stream.CanWrite); | ||
|
Comment on lines
+2257
to
+2258
|
||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_CreateMode_ReadAccess_Throws(bool async) | ||
| { | ||
| using var ms = new MemoryStream(); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Create, leaveOpen: true); | ||
|
|
||
| ZipArchiveEntry entry = archive.CreateEntry("test.txt"); | ||
|
|
||
| Assert.Throws<ArgumentException>("access", () => entry.Open(FileAccess.Read)); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_UpdateMode_ReadAccess_Succeeds(bool async) | ||
| { | ||
| using MemoryStream ms = await StreamHelpers.CreateTempCopyStream(zfile("normal.zip")); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Update); | ||
|
|
||
| ZipArchiveEntry entry = archive.GetEntry("first.txt"); | ||
| Assert.NotNull(entry); | ||
|
|
||
| using Stream stream = entry.Open(FileAccess.Read); | ||
| Assert.True(stream.CanRead); | ||
| Assert.False(stream.CanWrite); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_UpdateMode_WriteAccess_Succeeds(bool async) | ||
| { | ||
| using MemoryStream ms = await StreamHelpers.CreateTempCopyStream(zfile("normal.zip")); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Update); | ||
|
|
||
| ZipArchiveEntry entry = archive.GetEntry("first.txt"); | ||
| Assert.NotNull(entry); | ||
|
|
||
| // In Update mode, FileAccess.Write uses OpenInUpdateMode which returns a read-write-seekable stream | ||
| using Stream stream = entry.Open(FileAccess.Write); | ||
| Assert.True(stream.CanWrite); | ||
| Assert.True(stream.CanRead); | ||
| Assert.True(stream.CanSeek); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_UpdateMode_ReadWriteAccess_Succeeds(bool async) | ||
| { | ||
| using MemoryStream ms = await StreamHelpers.CreateTempCopyStream(zfile("normal.zip")); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Update); | ||
|
|
||
| ZipArchiveEntry entry = archive.GetEntry("first.txt"); | ||
| Assert.NotNull(entry); | ||
|
|
||
| using Stream stream = entry.Open(FileAccess.ReadWrite); | ||
| Assert.True(stream.CanRead); | ||
| Assert.True(stream.CanWrite); | ||
| Assert.True(stream.CanSeek); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_ReadMode_InvalidAccess_Throws(bool async) | ||
| { | ||
| using MemoryStream ms = await StreamHelpers.CreateTempCopyStream(zfile("normal.zip")); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Read); | ||
|
|
||
| ZipArchiveEntry entry = archive.GetEntry("first.txt"); | ||
| Assert.NotNull(entry); | ||
|
|
||
| // Test with invalid FileAccess values | ||
| Assert.Throws<ArgumentException>("access", () => entry.Open((FileAccess)0)); | ||
| Assert.Throws<ArgumentException>("access", () => entry.Open((FileAccess)4)); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_CreateMode_InvalidAccess_Throws(bool async) | ||
| { | ||
| using var ms = new MemoryStream(); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Create, leaveOpen: true); | ||
|
|
||
| ZipArchiveEntry entry = archive.CreateEntry("test.txt"); | ||
|
|
||
| // Test with invalid FileAccess values | ||
| Assert.Throws<ArgumentException>("access", () => entry.Open((FileAccess)0)); | ||
| Assert.Throws<ArgumentException>("access", () => entry.Open((FileAccess)4)); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_UpdateMode_InvalidAccess_Throws(bool async) | ||
| { | ||
| using MemoryStream ms = await StreamHelpers.CreateTempCopyStream(zfile("normal.zip")); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Update); | ||
|
|
||
| ZipArchiveEntry entry = archive.GetEntry("first.txt"); | ||
| Assert.NotNull(entry); | ||
|
|
||
| // Test with invalid FileAccess values | ||
| Assert.Throws<ArgumentException>("access", () => entry.Open((FileAccess)0)); | ||
| Assert.Throws<ArgumentException>("access", () => entry.Open((FileAccess)4)); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_MatchesParameterlessOpen_ReadMode(bool async) | ||
| { | ||
| using MemoryStream ms1 = await StreamHelpers.CreateTempCopyStream(zfile("small.zip")); | ||
| using MemoryStream ms2 = await StreamHelpers.CreateTempCopyStream(zfile("small.zip")); | ||
|
|
||
| ZipArchive archive1 = await CreateZipArchive(async, ms1, ZipArchiveMode.Read); | ||
| ZipArchive archive2 = await CreateZipArchive(async, ms2, ZipArchiveMode.Read); | ||
|
|
||
| ZipArchiveEntry entry1 = archive1.Entries[0]; | ||
| ZipArchiveEntry entry2 = archive2.Entries[0]; | ||
|
|
||
| byte[] contents1, contents2; | ||
|
|
||
| using (Stream stream1 = entry1.Open()) | ||
| { | ||
| using var reader = new MemoryStream(); | ||
| stream1.CopyTo(reader); | ||
| contents1 = reader.ToArray(); | ||
| } | ||
|
|
||
| using (Stream stream2 = entry2.Open(FileAccess.Read)) | ||
| { | ||
| using var reader = new MemoryStream(); | ||
| stream2.CopyTo(reader); | ||
| contents2 = reader.ToArray(); | ||
| } | ||
|
|
||
| Assert.Equal(contents1, contents2); | ||
|
|
||
| await DisposeZipArchive(async, archive1); | ||
| await DisposeZipArchive(async, archive2); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_MatchesParameterlessOpen_UpdateMode(bool async) | ||
| { | ||
| using MemoryStream ms1 = await StreamHelpers.CreateTempCopyStream(zfile("small.zip")); | ||
| using MemoryStream ms2 = await StreamHelpers.CreateTempCopyStream(zfile("small.zip")); | ||
|
|
||
| ZipArchive archive1 = await CreateZipArchive(async, ms1, ZipArchiveMode.Update); | ||
| ZipArchive archive2 = await CreateZipArchive(async, ms2, ZipArchiveMode.Update); | ||
|
|
||
| ZipArchiveEntry entry1 = archive1.Entries[0]; | ||
| ZipArchiveEntry entry2 = archive2.Entries[0]; | ||
|
|
||
| byte[] contents1, contents2; | ||
|
|
||
| using (Stream stream1 = entry1.Open()) | ||
| { | ||
| Assert.True(stream1.CanRead); | ||
| Assert.True(stream1.CanWrite); | ||
| Assert.True(stream1.CanSeek); | ||
|
|
||
| using var reader = new MemoryStream(); | ||
| stream1.CopyTo(reader); | ||
| contents1 = reader.ToArray(); | ||
| } | ||
|
|
||
| using (Stream stream2 = entry2.Open(FileAccess.ReadWrite)) | ||
| { | ||
| Assert.True(stream2.CanRead); | ||
| Assert.True(stream2.CanWrite); | ||
| Assert.True(stream2.CanSeek); | ||
|
|
||
| using var reader = new MemoryStream(); | ||
| stream2.CopyTo(reader); | ||
| contents2 = reader.ToArray(); | ||
| } | ||
|
|
||
| Assert.Equal(contents1, contents2); | ||
|
|
||
| await DisposeZipArchive(async, archive1); | ||
| await DisposeZipArchive(async, archive2); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(Get_Booleans_Data))] | ||
| public static async Task OpenWithFileAccess_DisposedArchive_Throws(bool async) | ||
| { | ||
| using MemoryStream ms = await StreamHelpers.CreateTempCopyStream(zfile("normal.zip")); | ||
| ZipArchive archive = await CreateZipArchive(async, ms, ZipArchiveMode.Read); | ||
|
|
||
| ZipArchiveEntry entry = archive.GetEntry("first.txt"); | ||
| Assert.NotNull(entry); | ||
|
|
||
| await DisposeZipArchive(async, archive); | ||
|
|
||
| Assert.Throws<ObjectDisposedException>(() => entry.Open(FileAccess.Read)); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
<param>description should be a noun phrase that begins with an introductory article, per the documentation guidelines. Consider: "The file access mode for the returned stream."