Skip to content

Fix the elusive invalid zip archive issue that has been a problem for ages! #142

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

Merged
merged 2 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 4 additions & 16 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{
"label": "Build LibZipSharp",
"type": "shell",
"command": "msbuild LibZipSharp/libZipSharp.csproj /restore /t:Build",
"command": "dotnet build LibZipSharp/libZipSharp.csproj -t:Build",
"group": {
"kind": "build",
"isDefault": true
Expand All @@ -18,7 +18,7 @@
{
"label": "Pack LibZipSharp Nuget",
"type": "shell",
"command": "msbuild LibZipSharp/libZipSharp.csproj /t:Pack",
"command": "dotnet pack LibZipSharp/libZipSharp.csproj",
"group": {
"kind": "build",
"isDefault": true
Expand All @@ -30,7 +30,7 @@
{
"label": "Clean LibZipSharp",
"type": "shell",
"command": "msbuild LibZipSharp/libZipSharp.csproj /restore /t:Clean",
"command": "dotnet build LibZipSharp/libZipSharp.csproj -t:Clean",
"group": {
"kind": "build",
"isDefault": true
Expand All @@ -42,7 +42,7 @@
{
"label": "Build LibZipSharp Unit Tests",
"type": "shell",
"command": "msbuild LibZipSharp.UnitTest/LibZipSharp.UnitTest.csproj /restore /t:Build /p:ReferenceNuget=False",
"command": "dotnet build LibZipSharp.UnitTest/LibZipSharp.UnitTest.csproj -t:Build -p:ReferenceNuget=False",
"group": {
"kind": "build",
"isDefault": true
Expand All @@ -51,17 +51,5 @@
"$msCompile"
]
},
{
"label": "Run LibZipSharp Unit Tests",
"type": "shell",
"command": "msbuild LibZipSharp.UnitTest/LibZipSharp.UnitTest.csproj /restore /t:RunNunitTests /p:ReferenceNuget=False",
"group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": [
"$msCompile"
]
}
]
}
38 changes: 36 additions & 2 deletions LibZipSharp.UnitTest/ZipTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ public void InMemoryZipFile ()
}

stream.Position = 0;
using (var zip = ZipArchive.Open (stream)) {
using (var zip = ZipArchive.Open (stream, strictConsistencyChecks: true)) {
Assert.AreEqual (3, zip.EntryCount);
foreach (var e in zip) {
Console.WriteLine (e.FullName);
Expand All @@ -354,7 +354,7 @@ public void InMemoryZipFile ()
}

stream.Position = 0;
using (var zip = ZipArchive.Open (stream)) {
using (var zip = ZipArchive.Open (stream, strictConsistencyChecks: true)) {
Assert.AreEqual (2, zip.EntryCount);
zip.AddEntry ("info.json", File.ReadAllText (filePath), Encoding.UTF8, CompressionMethod.Deflate);
}
Expand All @@ -377,6 +377,40 @@ public void InMemoryZipFile ()
}
}

[Test]
public void EnumerateOnEmptyThenAddFiles ()
{
File.WriteAllText ("file1.txt", TEXT);
File.WriteAllText ("file2.txt", TEXT);
string filePath = Path.GetFullPath ("file1.txt");
if (File.Exists ("enumerateonempty.zip"))
File.Delete ("enumerateonempty.zip");


using (var stream = File.Create ("test-archive-write.zip"))
using (var zip = ZipArchive.Create (stream)) {
foreach (var entry in zip) {
Console.Write (entry.FullName);
}
ZipEntry e;
e = zip.AddFile (filePath, "/path/ZipTestCopy1.exe");
filePath = Path.GetFullPath ("file2.txt");
e = zip.AddFile (filePath, "/path/ZipTestCopy2.exe");

foreach (var entry in zip) {
Console.Write (entry.FullName);
}

zip.Close ();
}

using (var zip = ZipArchive.Open ("test-archive-write.zip", FileMode.Open, strictConsistencyChecks: true)) {
foreach (var entry in zip) {
Console.Write (entry.FullName);
}
}
}

[TestCase (false)]
[TestCase (true)]
public void EnumerateSkipDeletedEntries (bool deleteFromExistingFile)
Expand Down
2 changes: 1 addition & 1 deletion LibZipSharp.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LibZipSharpAssemblyVersionMajor>3</_LibZipSharpAssemblyVersionMajor>
<_LibZipSharpAssemblyVersionMinor>2</_LibZipSharpAssemblyVersionMinor>
<_LibZipSharpAssemblyVersionMinor>3</_LibZipSharpAssemblyVersionMinor>
<_LibZipSharpAssemblyVersionPatch>0</_LibZipSharpAssemblyVersionPatch>
<_LibZipSharpAssemblyVersion>$(_LibZipSharpAssemblyVersionMajor).$(_LibZipSharpAssemblyVersionMinor).$(_LibZipSharpAssemblyVersionPatch)</_LibZipSharpAssemblyVersion>
<_NativeLibraryVersionForName>$(_LibZipSharpAssemblyVersionMajor)-$(_LibZipSharpAssemblyVersionMinor)</_NativeLibraryVersionForName>
Expand Down
45 changes: 23 additions & 22 deletions LibZipSharp/Xamarin.Tools.Zip/ZipArchive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
Expand Down Expand Up @@ -195,19 +196,26 @@ ErrorCode Open (string path, OpenFlags flags)
/// </summary>
/// <param name="stream">The stream to open</param>
/// <param name="options">Platform-specific options</param>
public static ZipArchive Open (Stream stream, IPlatformOptions options = null)
/// <param name="strictConsistencyChecks"></param>
public static ZipArchive Open (Stream stream, IPlatformOptions options = null, bool strictConsistencyChecks = false)
{
return ZipArchive.CreateInstanceFromStream (stream, OpenFlags.None, options);
OpenFlags flags = OpenFlags.None;
if (strictConsistencyChecks)
flags |= OpenFlags.CheckCons;
return ZipArchive.CreateInstanceFromStream (stream, flags, options);
}

/// <summary>
/// Create a new archive using the Stream provided. The steam should be an empty stream, any existing data will be overwritten.
/// </summary>
/// <param name="stream">The stream to create the arhive in</param>
/// <param name="options">Platform-specific options</param>
public static ZipArchive Create (Stream stream, IPlatformOptions options = null)
public static ZipArchive Create (Stream stream, IPlatformOptions options = null, bool strictConsistencyChecks = false)
{
return ZipArchive.CreateInstanceFromStream (stream, OpenFlags.Create | OpenFlags.Truncate, options);
OpenFlags flags = OpenFlags.Create | OpenFlags.Truncate;
if (strictConsistencyChecks)
flags |= OpenFlags.CheckCons;
return ZipArchive.CreateInstanceFromStream (stream, flags, options);
}

/// <summary>
Expand Down Expand Up @@ -788,6 +796,7 @@ internal ZipException GetErrorException ()
internal static unsafe Int64 stream_callback (IntPtr state, IntPtr data, UInt64 len, SourceCommand cmd)
{
byte [] buffer = null;
Native.zip_error_t error;
int length = (int)len;
var handle = GCHandle.FromIntPtr (state);
if (!handle.IsAllocated)
Expand Down Expand Up @@ -833,30 +842,26 @@ internal static unsafe Int64 stream_callback (IntPtr state, IntPtr data, UInt64
return -1;
}

long firstOffset, secondOffset;
SeekOrigin seek = Native.ConvertWhence (args.whence);
if (args.offset > Int64.MaxValue) {
// Stream.Seek uses a signed 64-bit value for the offset, we need to split it up
firstOffset = Int64.MaxValue;
secondOffset = (long)(args.offset - Int64.MaxValue);
if (!Seek (destination, seek, Int64.MaxValue) || !Seek (destination, seek, (long)(args.offset - Int64.MaxValue))) {
return -1;
}
} else {
firstOffset = (long)args.offset;
secondOffset = 0;
}

SeekOrigin seek = Native.ConvertWhence (args.whence);
Native.zip_error_t error;

if (!SeekIfNeeded (destination, seek, firstOffset) || !SeekIfNeeded (destination, seek, secondOffset)) {
return -1;
if (!Seek (destination, seek, (long)args.offset)) {
return -1;
}
}

break;

case SourceCommand.Seek:
long offset = Native.zip_source_seek_compute_offset ((UInt64)stream.Position, (UInt64)stream.Length, data, len, out error);
if (offset < 0) {
return offset;
}
if (offset != stream.Seek (offset, SeekOrigin.Begin)) {
if (!Seek (stream, SeekOrigin.Begin, offset)) {
return -1;
}
break;
Expand Down Expand Up @@ -962,12 +967,8 @@ internal static unsafe Int64 stream_callback (IntPtr state, IntPtr data, UInt64

return 0;

bool SeekIfNeeded (Stream s, SeekOrigin origin, long offset)
bool Seek (Stream s, SeekOrigin origin, long offset)
{
if (offset == 0) {
return true;
}

return s.Seek (offset, origin) == offset;
}
}
Expand Down
5 changes: 5 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ extends:
archiveType: 7z
replaceExistingArchive: true
archiveFile: $(Build.ArtifactStagingDirectory)\libzip-windows-arm-x64.7z
- script: |
7z t $(Build.ArtifactStagingDirectory)\libzip-windows-arm-x64.7z
7z t $(Build.ArtifactStagingDirectory)\libzip-windows-x64.7z
7z t $(Build.ArtifactStagingDirectory)\libzip-windows-x86.7z
displayName: Test Archives

- job: buildLinux
pool:
Expand Down