using System; using System.Collections.Generic; using System.IO; using System.Linq; using SharpCompress.Common; using SharpCompress.Common.GZip; using SharpCompress.Reader; using SharpCompress.Reader.GZip; using SharpCompress.Writer.GZip; namespace SharpCompress.Archive.GZip { public class GZipArchive : AbstractWritableArchive { #if !PORTABLE /// /// Constructor expects a filepath to an existing file. /// /// public static GZipArchive Open(string filePath) { return Open(filePath, Options.None); } /// /// Constructor with a FileInfo object to an existing file. /// /// public static GZipArchive Open(FileInfo fileInfo) { return Open(fileInfo, Options.None); } /// /// Constructor expects a filepath to an existing file. /// /// /// public static GZipArchive Open(string filePath, Options options) { filePath.CheckNotNullOrEmpty("filePath"); return Open(new FileInfo(filePath), options); } /// /// Constructor with a FileInfo object to an existing file. /// /// /// public static GZipArchive Open(FileInfo fileInfo, Options options) { fileInfo.CheckNotNull("fileInfo"); return new GZipArchive(fileInfo, options); } #endif /// /// Takes a seekable Stream as a source /// /// public static GZipArchive Open(Stream stream) { stream.CheckNotNull("stream"); return Open(stream, Options.None); } /// /// Takes a seekable Stream as a source /// /// /// public static GZipArchive Open(Stream stream, Options options) { stream.CheckNotNull("stream"); return new GZipArchive(stream, options); } #if !PORTABLE /// /// Constructor with a FileInfo object to an existing file. /// /// /// internal GZipArchive(FileInfo fileInfo, Options options) : base(ArchiveType.GZip, fileInfo, options) { } protected override IEnumerable LoadVolumes(FileInfo file, Options options) { return new GZipVolume(file, options).AsEnumerable(); } public static bool IsGZipFile(string filePath) { return IsGZipFile(new FileInfo(filePath)); } public static bool IsGZipFile(FileInfo fileInfo) { if (!fileInfo.Exists) { return false; } using (Stream stream = fileInfo.OpenRead()) { return IsGZipFile(stream); } } public void SaveTo(string filePath) { SaveTo(new FileInfo(filePath)); } public void SaveTo(FileInfo fileInfo) { using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write)) { SaveTo(stream); } } #endif public static bool IsGZipFile(Stream stream) { // read the header on the first read byte[] header = new byte[10]; int n = stream.Read(header, 0, header.Length); // workitem 8501: handle edge case (decompress empty stream) if (n == 0) return false; if (n != 10) return false; if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) return false; return true; } /// /// Takes multiple seekable Streams for a multi-part archive /// /// /// internal GZipArchive(Stream stream, Options options) : base(ArchiveType.GZip, stream.AsEnumerable(), options) { } internal GZipArchive() : base(ArchiveType.GZip) { } public void SaveTo(Stream stream) { this.SaveTo(stream, CompressionType.GZip); } protected override GZipArchiveEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified, bool closeStream) { if (Entries.Any()) { throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); } return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); } protected override void SaveTo(Stream stream, CompressionInfo compressionInfo, IEnumerable oldEntries, IEnumerable newEntries) { if (Entries.Count > 1) { throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); } using (var writer = new GZipWriter(stream)) { foreach (var entry in oldEntries.Concat(newEntries) .Where(x => !x.IsDirectory)) { using (var entryStream = entry.OpenEntryStream()) { writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime); } } } } protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) { return new GZipVolume(streams.First(), options).AsEnumerable(); } protected override IEnumerable LoadEntries(IEnumerable volumes) { Stream stream = volumes.Single().Stream; yield return new GZipArchiveEntry(this, new GZipFilePart(stream)); } protected override IReader CreateReaderForSolidExtraction() { var stream = Volumes.Single().Stream; stream.Position = 0; return GZipReader.Open(stream); } } }