123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using SharpCompress.Common;
- using SharpCompress.Readers;
- namespace SharpCompress.Archives
- {
- public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveExtractionListener
- where TEntry : IArchiveEntry
- where TVolume : IVolume
- {
- private readonly LazyReadOnlyCollection<TVolume> lazyVolumes;
- private readonly LazyReadOnlyCollection<TEntry> lazyEntries;
- public event EventHandler<ArchiveExtractionEventArgs<IArchiveEntry>> EntryExtractionBegin;
- public event EventHandler<ArchiveExtractionEventArgs<IArchiveEntry>> EntryExtractionEnd;
- public event EventHandler<CompressedBytesReadEventArgs> CompressedBytesRead;
- public event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
- protected ReaderOptions ReaderOptions { get; }
- private bool disposed;
- #if !NO_FILE
- internal AbstractArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerOptions)
- {
- Type = type;
- if (!fileInfo.Exists)
- {
- throw new ArgumentException("File does not exist: " + fileInfo.FullName);
- }
- ReaderOptions = readerOptions;
- readerOptions.LeaveStreamOpen = false;
- lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(fileInfo));
- lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
- }
- protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file);
- #endif
- internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, ReaderOptions readerOptions)
- {
- Type = type;
- ReaderOptions = readerOptions;
- lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select(CheckStreams)));
- lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
- }
- internal AbstractArchive(ArchiveType type)
- {
- Type = type;
- lazyVolumes = new LazyReadOnlyCollection<TVolume>(Enumerable.Empty<TVolume>());
- lazyEntries = new LazyReadOnlyCollection<TEntry>(Enumerable.Empty<TEntry>());
- }
- public ArchiveType Type { get; }
- void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry)
- {
- EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
- }
- void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry)
- {
- EntryExtractionEnd?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
- }
- private static Stream CheckStreams(Stream stream)
- {
- if (!stream.CanSeek || !stream.CanRead)
- {
- throw new ArgumentException("Archive streams must be Readable and Seekable");
- }
- return stream;
- }
- /// <summary>
- /// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
- /// </summary>
- public virtual ICollection<TEntry> Entries { get { return lazyEntries; } }
- /// <summary>
- /// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
- /// </summary>
- public ICollection<TVolume> Volumes { get { return lazyVolumes; } }
- /// <summary>
- /// The total size of the files compressed in the archive.
- /// </summary>
- public virtual long TotalSize { get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); } }
- /// <summary>
- /// The total size of the files as uncompressed in the archive.
- /// </summary>
- public virtual long TotalUncompressSize { get { return Entries.Aggregate(0L, (total, cf) => total + cf.Size); } }
- protected abstract IEnumerable<TVolume> LoadVolumes(IEnumerable<Stream> streams);
- protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
- IEnumerable<IArchiveEntry> IArchive.Entries { get { return Entries.Cast<IArchiveEntry>(); } }
- IEnumerable<IVolume> IArchive.Volumes { get { return lazyVolumes.Cast<IVolume>(); } }
- public virtual void Dispose()
- {
- if (!disposed)
- {
- lazyVolumes.ForEach(v => v.Dispose());
- lazyEntries.GetLoaded().Cast<Entry>().ForEach(x => x.Close());
- disposed = true;
- }
- }
- void IArchiveExtractionListener.EnsureEntriesLoaded()
- {
- lazyEntries.EnsureFullyLoaded();
- lazyVolumes.EnsureFullyLoaded();
- }
- void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
- {
- CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs
- {
- CurrentFilePartCompressedBytesRead = currentPartCompressedBytes,
- CompressedBytesRead = compressedReadBytes
- });
- }
- void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
- {
- FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs
- {
- CompressedSize = compressedSize,
- Size = size,
- Name = name
- });
- }
- /// <summary>
- /// Use this method to extract all entries in an archive in order.
- /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
- /// extracted sequentially for the best performance.
- ///
- /// This method will load all entry information from the archive.
- ///
- /// WARNING: this will reuse the underlying stream for the archive. Errors may
- /// occur if this is used at the same time as other extraction methods on this instance.
- /// </summary>
- /// <returns></returns>
- public IReader ExtractAllEntries()
- {
- ((IArchiveExtractionListener)this).EnsureEntriesLoaded();
- return CreateReaderForSolidExtraction();
- }
- protected abstract IReader CreateReaderForSolidExtraction();
- /// <summary>
- /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
- /// </summary>
- public virtual bool IsSolid { get { return false; } }
- /// <summary>
- /// The archive can find all the parts of the archive needed to fully extract the archive. This forces the parsing of the entire archive.
- /// </summary>
- public bool IsComplete
- {
- get
- {
- ((IArchiveExtractionListener)this).EnsureEntriesLoaded();
- return Entries.All(x => x.IsComplete);
- }
- }
- }
- }
|