123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using SharpCompress.Common;
- using SharpCompress.Common.SevenZip;
- using SharpCompress.Compressors.LZMA.Utilites;
- using SharpCompress.IO;
- using SharpCompress.Readers;
- namespace SharpCompress.Archives.SevenZip
- {
- public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVolume>
- {
- private ArchiveDatabase database;
- #if !NO_FILE
- /// <summary>
- /// Constructor expects a filepath to an existing file.
- /// </summary>
- /// <param name="filePath"></param>
- /// <param name="readerOptions"></param>
- public static SevenZipArchive Open(string filePath, ReaderOptions readerOptions = null)
- {
- filePath.CheckNotNullOrEmpty("filePath");
- return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
- }
- /// <summary>
- /// Constructor with a FileInfo object to an existing file.
- /// </summary>
- /// <param name="fileInfo"></param>
- /// <param name="readerOptions"></param>
- public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
- {
- fileInfo.CheckNotNull("fileInfo");
- return new SevenZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
- }
- #endif
- /// <summary>
- /// Takes a seekable Stream as a source
- /// </summary>
- /// <param name="stream"></param>
- /// <param name="readerOptions"></param>
- public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
- {
- stream.CheckNotNull("stream");
- return new SevenZipArchive(stream, readerOptions ?? new ReaderOptions());
- }
- #if !NO_FILE
- internal SevenZipArchive(FileInfo fileInfo, ReaderOptions readerOptions)
- : base(ArchiveType.SevenZip, fileInfo, readerOptions)
- {
- }
- protected override IEnumerable<SevenZipVolume> LoadVolumes(FileInfo file)
- {
- return new SevenZipVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
- }
- public static bool IsSevenZipFile(string filePath)
- {
- return IsSevenZipFile(new FileInfo(filePath));
- }
- public static bool IsSevenZipFile(FileInfo fileInfo)
- {
- if (!fileInfo.Exists)
- {
- return false;
- }
- using (Stream stream = fileInfo.OpenRead())
- {
- return IsSevenZipFile(stream);
- }
- }
- #endif
- internal SevenZipArchive(Stream stream, ReaderOptions readerOptions)
- : base(ArchiveType.SevenZip, stream.AsEnumerable(), readerOptions)
- {
- }
- internal SevenZipArchive()
- : base(ArchiveType.SevenZip)
- {
- }
- protected override IEnumerable<SevenZipVolume> LoadVolumes(IEnumerable<Stream> streams)
- {
- foreach (Stream s in streams)
- {
- if (!s.CanRead || !s.CanSeek)
- {
- throw new ArgumentException("Stream is not readable and seekable");
- }
- SevenZipVolume volume = new SevenZipVolume(s, ReaderOptions);
- yield return volume;
- }
- }
- protected override IEnumerable<SevenZipArchiveEntry> LoadEntries(IEnumerable<SevenZipVolume> volumes)
- {
- var stream = volumes.Single().Stream;
- LoadFactory(stream);
- for (int i = 0; i < database._files.Count; i++)
- {
- var file = database._files[i];
- yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding));
- }
- }
- private void LoadFactory(Stream stream)
- {
- if (database == null)
- {
- stream.Position = 0;
- var reader = new ArchiveReader();
- reader.Open(stream);
- database = reader.ReadDatabase(new PasswordProvider(ReaderOptions.Password));
- }
- }
- public static bool IsSevenZipFile(Stream stream)
- {
- try
- {
- return SignatureMatch(stream);
- }
- catch
- {
- return false;
- }
- }
- private static readonly byte[] SIGNATURE = {(byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C};
- private static bool SignatureMatch(Stream stream)
- {
- BinaryReader reader = new BinaryReader(stream);
- byte[] signatureBytes = reader.ReadBytes(6);
- return signatureBytes.BinaryEquals(SIGNATURE);
- }
- protected override IReader CreateReaderForSolidExtraction()
- {
- return new SevenZipReader(ReaderOptions, this);
- }
- public override bool IsSolid { get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } }
- public override long TotalSize
- {
- get
- {
- int i = Entries.Count;
- return database._packSizes.Aggregate(0L, (total, packSize) => total + packSize);
- }
- }
- private class SevenZipReader : AbstractReader<SevenZipEntry, SevenZipVolume>
- {
- private readonly SevenZipArchive archive;
- private CFolder currentFolder;
- private Stream currentStream;
- private CFileItem currentItem;
- internal SevenZipReader(ReaderOptions readerOptions, SevenZipArchive archive)
- : base(readerOptions, ArchiveType.SevenZip)
- {
- this.archive = archive;
- }
- public override SevenZipVolume Volume => archive.Volumes.Single();
- protected override IEnumerable<SevenZipEntry> GetEntries(Stream stream)
- {
- List<SevenZipArchiveEntry> entries = archive.Entries.ToList();
- stream.Position = 0;
- foreach (var dir in entries.Where(x => x.IsDirectory))
- {
- yield return dir;
- }
- foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder))
- {
- currentFolder = group.Key;
- if (group.Key == null)
- {
- currentStream = Stream.Null;
- }
- else
- {
- currentStream = archive.database.GetFolderStream(stream, currentFolder, new PasswordProvider(Options.Password));
- }
- foreach (var entry in group)
- {
- currentItem = entry.FilePart.Header;
- yield return entry;
- }
- }
- }
- protected override EntryStream GetEntryStream()
- {
- return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
- }
- }
-
- private class PasswordProvider : IPasswordProvider
- {
- private readonly string _password;
- public PasswordProvider(string password)
- {
- _password = password;
- }
- public string CryptoGetTextPassword()
- {
- return _password;
- }
- }
- }
- }
|