Skip to content

Commit

Permalink
fix DotNetZip Read() requiring buffer fill
Browse files Browse the repository at this point in the history
  • Loading branch information
sahlaysta committed Sep 4, 2024
1 parent a6b82fe commit adaf8bc
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 96 deletions.
79 changes: 77 additions & 2 deletions Sahlaysta.PortableTerrariaCommon/DotNetZip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ public static void ExtractZipArchive(
throw new ArgumentNullException();
}

HashSet<string> entryNameSet = new HashSet<string>(entryNames);

Type zipFileType = ReflectionHelper.GetType(dotNetZipAssembly, "Ionic.Zip.ZipFile");
Type zipEntryType = ReflectionHelper.GetType(dotNetZipAssembly, "Ionic.Zip.ZipEntry");
MethodInfo readMethod = ReflectionHelper.GetMethod(zipFileType, "Read", new Type[] { typeof(Stream) });
Expand All @@ -124,6 +122,9 @@ public static void ExtractZipArchive(
MethodInfo extractMethod = ReflectionHelper.GetMethod(
zipEntryType, "Extract", new Type[] { typeof(Stream) });

HashSet<string> entryNameSet = new HashSet<string>(entryNames);
inStream = new DotNetZipCompatibilityReadStream(inStream);

IDisposable zipEntry = (IDisposable)readMethod.Invoke(null, new object[] { inStream });
using (zipEntry)
{
Expand Down Expand Up @@ -191,6 +192,7 @@ public static string[] ReadZipArchiveEntryNames(Assembly dotNetZipAssembly, Stre
MethodInfo extractMethod = ReflectionHelper.GetMethod(
zipEntryType, "Extract", new Type[] { typeof(Stream) });

inStream = new DotNetZipCompatibilityReadStream(inStream);
IDisposable zipEntry = (IDisposable)readMethod.Invoke(null, new object[] { inStream });
List<string> entryNames = new List<string>();
using (zipEntry)
Expand Down Expand Up @@ -263,5 +265,78 @@ public void OnEvent(object sender, object e)

}

/*
* On Read() calls, fill the entire buffer as possible.
* Required because DotNetZip is poorly written, and has errors otherwise...
*/
private class DotNetZipCompatibilityReadStream : Stream
{

private readonly Stream stream;

public DotNetZipCompatibilityReadStream(Stream stream)
{
this.stream = stream;
}

public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = 0;
while (true)
{
int r = stream.Read(buffer, offset + bytesRead, count - bytesRead);
if (r == 0 || bytesRead == count)
{
break;
}
bytesRead += r;
}
return bytesRead;
}

public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}

public override long Length
{
get
{
return stream.Length;
}
}

public override long Position
{
get
{
return stream.Position;
}
set
{
stream.Position = value;
}
}

protected override void Dispose(bool disposing)
{

}

public override void Flush()
{

}

public override void Write(byte[] buffer, int offset, int count) {
throw new NotSupportedException(); }
public override bool CanRead { get { return stream.CanRead; } }
public override bool CanWrite { get { return false; } }
public override bool CanSeek { get { return stream.CanSeek; } }
public override void SetLength(long value) { throw new NotSupportedException(); }

}

}
}
3 changes: 1 addition & 2 deletions Sahlaysta.PortableTerrariaLauncher/GuiForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,7 @@ private void InstallAudioButtonClicked()
}
}

using (Stream zipStream = new GuiLauncherAssemblyReader.DotNetZipCompatibilityStream(
GuiLauncherAssemblyReader.GetZipStream()))
using (Stream zipStream = GuiLauncherAssemblyReader.GetZipStream())
{
string dllEntryName = "Dlls/" + dllName;
string[] entryNames = DotNetZip.ReadZipArchiveEntryNames(dotNetZipAssembly, zipStream);
Expand Down
90 changes: 0 additions & 90 deletions Sahlaysta.PortableTerrariaLauncher/GuiLauncherAssemblyReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -305,95 +305,5 @@ public override void Write(byte[] buffer, int offset, int count) {

}

/*
* On Read() calls, fill the entire buffer as possible.
* Required because DotNetZip is poorly written, and has errors otherwise...
*/
public class DotNetZipCompatibilityStream : Stream
{

private Stream stream;
private bool disposed;

public DotNetZipCompatibilityStream(Stream stream)
{
this.stream = stream;
}

public override int Read(byte[] buffer, int offset, int count)
{
if (disposed) { throw new ObjectDisposedException(GetType().FullName); }

int bytesRead = 0;
while (true)
{
int r = stream.Read(buffer, offset + bytesRead, count - bytesRead);
if (r == 0 || bytesRead == count)
{
break;
}
bytesRead += r;
}
return bytesRead;
}

public override long Seek(long offset, SeekOrigin origin)
{
if (disposed) { throw new ObjectDisposedException(GetType().FullName); }
return stream.Seek(offset, origin);
}

public override long Length
{
get
{
if (disposed) { throw new ObjectDisposedException(GetType().FullName); }
return stream.Length;
}
}

public override long Position
{
get
{
if (disposed) { throw new ObjectDisposedException(GetType().FullName); }
return stream.Position;
}
set
{
if (disposed) { throw new ObjectDisposedException(GetType().FullName); }
stream.Position = value;
}
}

protected override void Dispose(bool disposing)
{
if (disposed) return;
disposed = true;
if (stream != null)
{
Stream theStream = stream;
stream = null;
if (disposing)
{
theStream.Close();
}
}
}

public override void Flush()
{
if (disposed) { throw new ObjectDisposedException(GetType().FullName); }
}

public override void Write(byte[] buffer, int offset, int count) {
throw new NotSupportedException(); }
public override bool CanRead { get { return !disposed; } }
public override bool CanWrite { get { return false; } }
public override bool CanSeek { get { return !disposed && stream.CanSeek; } }
public override void SetLength(long value) { throw new NotSupportedException(); }

}

}
}
3 changes: 1 addition & 2 deletions Sahlaysta.PortableTerrariaLauncher/GuiTerrariaInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ private static void Run(
};
}

using (Stream zipStream = new GuiLauncherAssemblyReader.DotNetZipCompatibilityStream(
GuiLauncherAssemblyReader.GetZipStream()))
using (Stream zipStream = GuiLauncherAssemblyReader.GetZipStream())
{
string[] entryNames = DotNetZip.ReadZipArchiveEntryNames(dotNetZipAssembly, zipStream);

Expand Down

0 comments on commit adaf8bc

Please sign in to comment.