Skip to content

Commit 90bd285

Browse files
committed
rework
1 parent 19b9394 commit 90bd285

File tree

1 file changed

+82
-16
lines changed

1 file changed

+82
-16
lines changed

LibZipSharp/Xamarin.Tools.Zip/ZipArchive.cs

Lines changed: 82 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,33 @@ namespace Xamarin.Tools.Zip
4040
/// </summary>
4141
public abstract partial class ZipArchive : IDisposable, IEnumerable <ZipEntry>
4242
{
43+
internal class CallbackContext : IDisposable {
44+
bool disposed;
45+
public Stream Source = null;
46+
public Stream Destination = null;
47+
48+
protected virtual void Dispose (bool disposing)
49+
{
50+
if (!disposed) {
51+
if (disposing) {
52+
if (Source != null) {
53+
Source.Dispose ();
54+
Source = null;
55+
}
56+
if (Destination != null) {
57+
Destination.Dispose ();
58+
Destination = null;
59+
}
60+
}
61+
disposed = true;
62+
}
63+
}
64+
public void Dispose ()
65+
{
66+
Dispose (true);
67+
GC.SuppressFinalize (this);
68+
}
69+
}
4370
public const EntryPermissions DefaultFilePermissions = EntryPermissions.OwnerRead | EntryPermissions.OwnerWrite | EntryPermissions.GroupRead | EntryPermissions.WorldRead;
4471
public const EntryPermissions DefaultDirectoryPermissions = EntryPermissions.OwnerAll | EntryPermissions.GroupRead | EntryPermissions.GroupExecute | EntryPermissions.WorldRead | EntryPermissions.WorldExecute;
4572

@@ -87,9 +114,12 @@ internal ZipArchive (Stream stream, IPlatformOptions options, OpenFlags flags =
87114
throw new ArgumentNullException (nameof (options));
88115
Options = options;
89116
Native.zip_error_t errorp;
90-
var streamHandle = GCHandle.Alloc (stream, GCHandleType.Normal);
91-
IntPtr h = GCHandle.ToIntPtr (streamHandle);
92-
IntPtr source = Native.zip_source_function_create (callback, h, out errorp);
117+
CallbackContext context = new CallbackContext () {
118+
Source = stream,
119+
Destination = null,
120+
};
121+
var contextHandle = GCHandle.Alloc (context, GCHandleType.Normal);
122+
IntPtr source = Native.zip_source_function_create (callback, GCHandle.ToIntPtr (contextHandle), out errorp);
93123
archive = Native.zip_open_from_source (source, flags, out errorp);
94124
if (archive == IntPtr.Zero) {
95125
// error;
@@ -323,7 +353,10 @@ public ZipEntry AddStream (Stream stream, string archivePath, EntryPermissions p
323353
throw new ArgumentNullException (nameof (stream));
324354
sources.Add (stream);
325355
string destPath = EnsureArchivePath (archivePath);
326-
var handle = GCHandle.Alloc (stream, GCHandleType.Normal);
356+
var context = new CallbackContext () {
357+
Source = stream,
358+
};
359+
var handle = GCHandle.Alloc (context, GCHandleType.Normal);
327360
IntPtr h = GCHandle.ToIntPtr (handle);
328361
IntPtr source = Native.zip_source_function (archive, callback, h);
329362
long index = Native.zip_file_add (archive, destPath, source, overwriteExisting ? OperationFlags.Overwrite : OperationFlags.None);
@@ -758,9 +791,13 @@ internal static unsafe Int64 stream_callback (IntPtr state, IntPtr data, UInt64
758791
var handle = GCHandle.FromIntPtr (state);
759792
if (!handle.IsAllocated)
760793
return -1;
761-
var stream = handle.Target as Stream;
794+
var context = handle.Target as CallbackContext;
795+
if (context == null)
796+
return -1;
797+
var stream = context.Source;
762798
if (stream == null)
763799
return -1;
800+
var destination = context.Destination ?? context.Source;
764801
switch (cmd) {
765802
case SourceCommand.Stat:
766803
if (len < (UInt64)sizeof (Native.zip_stat_t))
@@ -773,36 +810,56 @@ internal static unsafe Int64 stream_callback (IntPtr state, IntPtr data, UInt64
773810
return (Int64)sizeof (Native.zip_stat_t);
774811

775812
case SourceCommand.Tell:
776-
case SourceCommand.TellWrite:
777813
return (Int64)stream.Position;
814+
case SourceCommand.TellWrite:
815+
return (Int64)destination.Position;
778816

779817
case SourceCommand.Write:
780818
buffer = ArrayPool<byte>.Shared.Rent (length);
781819
try {
782820
Marshal.Copy (data, buffer, 0, length);
783-
stream.Write (buffer, 0, length);
821+
destination.Write (buffer, 0, length);
784822
return length;
785823
} finally {
786824
ArrayPool<byte>.Shared.Return (buffer);
787825
}
788826

789827
case SourceCommand.SeekWrite:
790-
case SourceCommand.Seek:
791828
Native.zip_error_t error;
792-
Int64 offset = Native.zip_source_seek_compute_offset ((UInt64)stream.Position, (UInt64)stream.Length, data, len, out error);
793-
if (offset < 0)
829+
Int64 offset = Native.zip_source_seek_compute_offset ((UInt64)destination.Position, (UInt64)destination.Length, data, len, out error);
830+
if (offset < 0) {
831+
return offset;
832+
}
833+
if (offset != stream.Seek (offset, SeekOrigin.Begin)) {
834+
return -1;
835+
}
836+
break;
837+
case SourceCommand.Seek:
838+
offset = Native.zip_source_seek_compute_offset ((UInt64)stream.Position, (UInt64)stream.Length, data, len, out error);
839+
if (offset < 0) {
794840
return offset;
795-
stream.Seek ((long)offset, SeekOrigin.Begin);
841+
}
842+
if (offset != stream.Seek (offset, SeekOrigin.Begin)) {
843+
return -1;
844+
}
796845
break;
797846

798847
case SourceCommand.CommitWrite:
799-
stream.Flush ();
848+
destination.Flush ();
849+
stream.Position = 0;
850+
destination.Position = 0;
851+
stream.SetLength (destination.Length);
852+
destination.CopyTo (stream);
853+
stream.Position = 0;
854+
destination.Dispose ();
855+
context.Destination = null;
856+
break;
857+
case SourceCommand.RollbackWrite:
858+
// err do something?
800859
break;
801860

802861
case SourceCommand.Read:
803-
if (length > stream.Length - stream.Position) {
804-
length = (int)(stream.Length - stream.Position);
805-
}
862+
length = (int)Math.Min (stream.Length - stream.Position, length);
806863
buffer = ArrayPool<byte>.Shared.Rent (length);
807864
try {
808865
int bytesRead = stream.Read (buffer, 0, length);
@@ -811,8 +868,11 @@ internal static unsafe Int64 stream_callback (IntPtr state, IntPtr data, UInt64
811868
} finally {
812869
ArrayPool<byte>.Shared.Return (buffer);
813870
}
814-
815871
case SourceCommand.BeginWrite:
872+
context.Destination = new MemoryStream ();
873+
destination = context.Destination;
874+
destination.Position = 0;
875+
break;
816876
case SourceCommand.Open:
817877
stream.Position = 0;
818878
return 0;
@@ -826,6 +886,12 @@ internal static unsafe Int64 stream_callback (IntPtr state, IntPtr data, UInt64
826886
handle.Free ();
827887
break;
828888

889+
case SourceCommand.Error:
890+
break;
891+
892+
case SourceCommand.Remove:
893+
break;
894+
829895
case SourceCommand.Supports:
830896
var supports = (Int64)Native.zip_source_make_command_bitmap (
831897
SourceCommand.Open,

0 commit comments

Comments
 (0)