Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/hakchi2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2017-01-23 02:24:43 +0300
committerAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2017-01-23 02:24:43 +0300
commitfb6b8383c27560c30e7a3076c67b925a7f8ff363 (patch)
treed30a5008e0fb39bdbac6e275689c2b776c4dee66 /SevenZip/StreamWrappers.cs
parenta6328fb50012c128e41d23d2de81241aeab14de2 (diff)
Archives support
Diffstat (limited to 'SevenZip/StreamWrappers.cs')
-rw-r--r--SevenZip/StreamWrappers.cs545
1 files changed, 545 insertions, 0 deletions
diff --git a/SevenZip/StreamWrappers.cs b/SevenZip/StreamWrappers.cs
new file mode 100644
index 00000000..55821d3e
--- /dev/null
+++ b/SevenZip/StreamWrappers.cs
@@ -0,0 +1,545 @@
+/* This file is part of SevenZipSharp.
+
+ SevenZipSharp is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ SevenZipSharp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Runtime.InteropServices;
+#if MONO
+using SevenZip.Mono.COM;
+#endif
+
+namespace SevenZip
+{
+#if UNMANAGED
+
+ /// <summary>
+ /// A class that has DisposeStream property.
+ /// </summary>
+ internal class DisposeVariableWrapper
+ {
+ public bool DisposeStream { protected get; set; }
+
+ protected DisposeVariableWrapper(bool disposeStream) { DisposeStream = disposeStream; }
+ }
+
+ /// <summary>
+ /// Stream wrapper used in InStreamWrapper
+ /// </summary>
+ internal class StreamWrapper : DisposeVariableWrapper, IDisposable
+ {
+ /// <summary>
+ /// File name associated with the stream (for date fix)
+ /// </summary>
+ private readonly string _fileName;
+
+ private readonly DateTime _fileTime;
+
+ /// <summary>
+ /// Worker stream for reading, writing and seeking.
+ /// </summary>
+ private Stream _baseStream;
+
+ /// <summary>
+ /// Initializes a new instance of the StreamWrapper class
+ /// </summary>
+ /// <param name="baseStream">Worker stream for reading, writing and seeking</param>
+ /// <param name="fileName">File name associated with the stream (for attributes fix)</param>
+ /// <param name="time">File last write time (for attributes fix)</param>
+ /// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
+ protected StreamWrapper(Stream baseStream, string fileName, DateTime time, bool disposeStream)
+ : base(disposeStream)
+ {
+ _baseStream = baseStream;
+ _fileName = fileName;
+ _fileTime = time;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the StreamWrapper class
+ /// </summary>
+ /// <param name="baseStream">Worker stream for reading, writing and seeking</param>
+ /// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
+ protected StreamWrapper(Stream baseStream, bool disposeStream)
+ : base(disposeStream)
+ {
+ _baseStream = baseStream;
+ }
+
+ /// <summary>
+ /// Gets the worker stream for reading, writing and seeking.
+ /// </summary>
+ protected Stream BaseStream
+ {
+ get
+ {
+ return _baseStream;
+ }
+ }
+
+ #region IDisposable Members
+
+ /// <summary>
+ /// Cleans up any resources used and fixes file attributes.
+ /// </summary>
+ public void Dispose()
+ {
+ if (_baseStream != null && DisposeStream)
+ {
+ try
+ {
+ _baseStream.Dispose();
+ }
+ catch (ObjectDisposedException) { }
+ _baseStream = null;
+ }
+ if (!String.IsNullOrEmpty(_fileName) && File.Exists(_fileName))
+ {
+ try
+ {
+#if !WINCE
+
+ File.SetLastWriteTime(_fileName, _fileTime);
+ File.SetLastAccessTime(_fileName, _fileTime);
+ File.SetCreationTime(_fileName, _fileTime);
+#elif WINCE
+ OpenNETCF.IO.FileHelper.SetLastWriteTime(_fileName, _fileTime);
+ OpenNETCF.IO.FileHelper.SetLastAccessTime(_fileName, _fileTime);
+ OpenNETCF.IO.FileHelper.SetCreationTime(_fileName, _fileTime);
+#endif
+ //TODO: time support for Windows Phone
+ }
+ catch (ArgumentOutOfRangeException) {}
+ }
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+
+ public virtual void Seek(long offset, SeekOrigin seekOrigin, IntPtr newPosition)
+ {
+ if (BaseStream != null)
+ {
+ long position = BaseStream.Seek(offset, seekOrigin);
+ if (newPosition != IntPtr.Zero)
+ {
+ Marshal.WriteInt64(newPosition, position);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// IInStream wrapper used in stream read operations.
+ /// </summary>
+ internal sealed class InStreamWrapper : StreamWrapper, ISequentialInStream, IInStream
+ {
+ /// <summary>
+ /// Initializes a new instance of the InStreamWrapper class.
+ /// </summary>
+ /// <param name="baseStream">Stream for writing data</param>
+ /// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
+ public InStreamWrapper(Stream baseStream, bool disposeStream) : base(baseStream, disposeStream) { }
+
+ #region ISequentialInStream Members
+
+ /// <summary>
+ /// Reads data from the stream.
+ /// </summary>
+ /// <param name="data">A data array.</param>
+ /// <param name="size">The array size.</param>
+ /// <returns>The read bytes count.</returns>
+ public int Read(byte[] data, uint size)
+ {
+ int readCount = 0;
+ if (BaseStream != null)
+ {
+ readCount = BaseStream.Read(data, 0, (int) size);
+ if (readCount > 0)
+ {
+ OnBytesRead(new IntEventArgs(readCount));
+ }
+ }
+ return readCount;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Occurs when IntEventArgs.Value bytes were read from the source.
+ /// </summary>
+ public event EventHandler<IntEventArgs> BytesRead;
+
+ private void OnBytesRead(IntEventArgs e)
+ {
+ if (BytesRead != null)
+ {
+ BytesRead(this, e);
+ }
+ }
+ }
+
+ /// <summary>
+ /// IOutStream wrapper used in stream write operations.
+ /// </summary>
+ internal sealed class OutStreamWrapper : StreamWrapper, ISequentialOutStream, IOutStream
+ {
+ /// <summary>
+ /// Initializes a new instance of the OutStreamWrapper class
+ /// </summary>
+ /// <param name="baseStream">Stream for writing data</param>
+ /// <param name="fileName">File name (for attributes fix)</param>
+ /// <param name="time">Time of the file creation (for attributes fix)</param>
+ /// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
+ public OutStreamWrapper(Stream baseStream, string fileName, DateTime time, bool disposeStream) :
+ base(baseStream, fileName, time, disposeStream) {}
+
+ /// <summary>
+ /// Initializes a new instance of the OutStreamWrapper class
+ /// </summary>
+ /// <param name="baseStream">Stream for writing data</param>
+ /// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
+ public OutStreamWrapper(Stream baseStream, bool disposeStream) :
+ base(baseStream, disposeStream) {}
+
+ #region IOutStream Members
+
+ public int SetSize(long newSize)
+ {
+ BaseStream.SetLength(newSize);
+ return 0;
+ }
+
+ #endregion
+
+ #region ISequentialOutStream Members
+
+ /// <summary>
+ /// Writes data to the stream
+ /// </summary>
+ /// <param name="data">Data array</param>
+ /// <param name="size">Array size</param>
+ /// <param name="processedSize">Count of written bytes</param>
+ /// <returns>Zero if Ok</returns>
+ public int Write(byte[] data, uint size, IntPtr processedSize)
+ {
+ BaseStream.Write(data, 0, (int) size);
+ if (processedSize != IntPtr.Zero)
+ {
+ Marshal.WriteInt32(processedSize, (int) size);
+ }
+ OnBytesWritten(new IntEventArgs((int) size));
+ return 0;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Occurs when IntEventArgs.Value bytes were written.
+ /// </summary>
+ public event EventHandler<IntEventArgs> BytesWritten;
+
+ private void OnBytesWritten(IntEventArgs e)
+ {
+ if (BytesWritten != null)
+ {
+ BytesWritten(this, e);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Base multi volume stream wrapper class.
+ /// </summary>
+ internal class MultiStreamWrapper : DisposeVariableWrapper, IDisposable
+ {
+ protected readonly Dictionary<int, KeyValuePair<long, long>> StreamOffsets =
+ new Dictionary<int, KeyValuePair<long, long>>();
+
+ protected readonly List<Stream> Streams = new List<Stream>();
+ protected int CurrentStream;
+ protected long Position;
+ protected long StreamLength;
+
+ /// <summary>
+ /// Initializes a new instance of the MultiStreamWrapper class.
+ /// </summary>
+ /// <param name="dispose">Perform Dispose() if requested to.</param>
+ protected MultiStreamWrapper(bool dispose) : base(dispose) {}
+
+ /// <summary>
+ /// Gets the total length of input data.
+ /// </summary>
+ public long Length
+ {
+ get
+ {
+ return StreamLength;
+ }
+ }
+
+ #region IDisposable Members
+
+ /// <summary>
+ /// Cleans up any resources used and fixes file attributes.
+ /// </summary>
+ public virtual void Dispose()
+ {
+ if (DisposeStream)
+ {
+ foreach (Stream stream in Streams)
+ {
+ try
+ {
+ stream.Dispose();
+ }
+ catch (ObjectDisposedException) {}
+ }
+ Streams.Clear();
+ }
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+
+ protected static string VolumeNumber(int num)
+ {
+ if (num < 10)
+ {
+ return ".00" + num.ToString(CultureInfo.InvariantCulture);
+ }
+ if (num > 9 && num < 100)
+ {
+ return ".0" + num.ToString(CultureInfo.InvariantCulture);
+ }
+ if (num > 99 && num < 1000)
+ {
+ return "." + num.ToString(CultureInfo.InvariantCulture);
+ }
+ return String.Empty;
+ }
+
+ private int StreamNumberByOffset(long offset)
+ {
+ foreach (int number in StreamOffsets.Keys)
+ {
+ if (StreamOffsets[number].Key <= offset &&
+ StreamOffsets[number].Value >= offset)
+ {
+ return number;
+ }
+ }
+ return -1;
+ }
+
+ public void Seek(long offset, SeekOrigin seekOrigin, IntPtr newPosition)
+ {
+ long absolutePosition = (seekOrigin == SeekOrigin.Current)
+ ? Position + offset
+ : offset;
+ CurrentStream = StreamNumberByOffset(absolutePosition);
+ long delta = Streams[CurrentStream].Seek(
+ absolutePosition - StreamOffsets[CurrentStream].Key, SeekOrigin.Begin);
+ Position = StreamOffsets[CurrentStream].Key + delta;
+ if (newPosition != IntPtr.Zero)
+ {
+ Marshal.WriteInt64(newPosition, Position);
+ }
+ }
+ }
+
+ /// <summary>
+ /// IInStream wrapper used in stream multi volume read operations.
+ /// </summary>
+ internal sealed class InMultiStreamWrapper : MultiStreamWrapper, ISequentialInStream, IInStream
+ {
+ /// <summary>
+ /// Initializes a new instance of the InMultiStreamWrapper class.
+ /// </summary>
+ /// <param name="fileName">The archive file name.</param>
+ /// <param name="dispose">Perform Dispose() if requested to.</param>
+ public InMultiStreamWrapper(string fileName, bool dispose) :
+ base(dispose)
+ {
+ string baseName = fileName.Substring(0, fileName.Length - 4);
+ int i = 0;
+ while (File.Exists(fileName))
+ {
+ Streams.Add(new FileStream(fileName, FileMode.Open));
+ long length = Streams[i].Length;
+ StreamOffsets.Add(i++, new KeyValuePair<long, long>(StreamLength, StreamLength + length));
+ StreamLength += length;
+ fileName = baseName + VolumeNumber(i + 1);
+ }
+ }
+
+ #region ISequentialInStream Members
+
+ /// <summary>
+ /// Reads data from the stream.
+ /// </summary>
+ /// <param name="data">A data array.</param>
+ /// <param name="size">The array size.</param>
+ /// <returns>The read bytes count.</returns>
+ public int Read(byte[] data, uint size)
+ {
+ var readSize = (int) size;
+ int readCount = Streams[CurrentStream].Read(data, 0, readSize);
+ readSize -= readCount;
+ Position += readCount;
+ while (readCount < (int) size)
+ {
+ if (CurrentStream == Streams.Count - 1)
+ {
+ return readCount;
+ }
+ CurrentStream++;
+ Streams[CurrentStream].Seek(0, SeekOrigin.Begin);
+ int count = Streams[CurrentStream].Read(data, readCount, readSize);
+ readCount += count;
+ readSize -= count;
+ Position += count;
+ }
+ return readCount;
+ }
+
+ #endregion
+ }
+
+#if COMPRESS
+ /// <summary>
+ /// IOutStream wrapper used in multi volume stream write operations.
+ /// </summary>
+ internal sealed class OutMultiStreamWrapper : MultiStreamWrapper, ISequentialOutStream, IOutStream
+ {
+ private readonly string _archiveName;
+ private readonly int _volumeSize;
+ private long _overallLength;
+
+ /// <summary>
+ /// Initializes a new instance of the OutMultiStreamWrapper class.
+ /// </summary>
+ /// <param name="archiveName">The archive name.</param>
+ /// <param name="volumeSize">The volume size.</param>
+ public OutMultiStreamWrapper(string archiveName, int volumeSize) :
+ base(true)
+ {
+ _archiveName = archiveName;
+ _volumeSize = volumeSize;
+ CurrentStream = -1;
+ NewVolumeStream();
+ }
+
+ #region IOutStream Members
+
+ public int SetSize(long newSize)
+ {
+ return 0;
+ }
+
+ #endregion
+
+ #region ISequentialOutStream Members
+
+ public int Write(byte[] data, uint size, IntPtr processedSize)
+ {
+ int offset = 0;
+ var originalSize = (int) size;
+ Position += size;
+ _overallLength = Math.Max(Position + 1, _overallLength);
+ while (size > _volumeSize - Streams[CurrentStream].Position)
+ {
+ var count = (int) (_volumeSize - Streams[CurrentStream].Position);
+ Streams[CurrentStream].Write(data, offset, count);
+ size -= (uint) count;
+ offset += count;
+ NewVolumeStream();
+ }
+ Streams[CurrentStream].Write(data, offset, (int) size);
+ if (processedSize != IntPtr.Zero)
+ {
+ Marshal.WriteInt32(processedSize, originalSize);
+ }
+ return 0;
+ }
+
+ #endregion
+
+ public override void Dispose()
+ {
+ int lastIndex = Streams.Count - 1;
+ Streams[lastIndex].SetLength(lastIndex > 0? Streams[lastIndex].Position : _overallLength);
+ base.Dispose();
+ }
+
+ private void NewVolumeStream()
+ {
+ CurrentStream++;
+ Streams.Add(File.Create(_archiveName + VolumeNumber(CurrentStream + 1)));
+ Streams[CurrentStream].SetLength(_volumeSize);
+ StreamOffsets.Add(CurrentStream, new KeyValuePair<long, long>(0, _volumeSize - 1));
+ }
+ }
+#endif
+
+ internal sealed class FakeOutStreamWrapper : ISequentialOutStream, IDisposable
+ {
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+
+ #region ISequentialOutStream Members
+
+ /// <summary>
+ /// Does nothing except calling the BytesWritten event
+ /// </summary>
+ /// <param name="data">Data array</param>
+ /// <param name="size">Array size</param>
+ /// <param name="processedSize">Count of written bytes</param>
+ /// <returns>Zero if Ok</returns>
+ public int Write(byte[] data, uint size, IntPtr processedSize)
+ {
+ OnBytesWritten(new IntEventArgs((int) size));
+ if (processedSize != IntPtr.Zero)
+ {
+ Marshal.WriteInt32(processedSize, (int) size);
+ }
+ return 0;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Occurs when IntEventArgs.Value bytes were written
+ /// </summary>
+ public event EventHandler<IntEventArgs> BytesWritten;
+
+ private void OnBytesWritten(IntEventArgs e)
+ {
+ if (BytesWritten != null)
+ {
+ BytesWritten(this, e);
+ }
+ }
+ }
+#endif
+} \ No newline at end of file