Ejemplo n.º 1
0
        public IExtractor ExtractFile(UInt64 index, Stream outputStream)
        {
            if (index >= (ulong)_Files.LongLength)
            {
                throw new ArgumentOutOfRangeException($"Index `{index}` is out of range.");
            }

            if (outputStream == null || !outputStream.CanWrite)
            {
                throw new ArgumentException($"Stream `{nameof(outputStream)}` is invalid or cannot be written to.");
            }

            SevenZipArchiveFile file = _Files[index];

            if (file.IsEmpty)
            {
                Trace.TraceWarning($"Filename: {file.Name} is a directory, empty file or anti file, nothing to output to stream.");
            }
            else
            {
                Trace.TraceInformation($"Filename: `{file.Name}`, file size: `{file.Size} bytes`.");

                var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo);
                sx.Extract((UInt64)file.UnPackIndex, outputStream);
            }

            return(this);
        }
Ejemplo n.º 2
0
        public IExtractor ExtractFile(UInt64 index, string outputDirectory)
        {
            if (index >= (ulong)_Files.LongLength)
            {
                throw new ArgumentOutOfRangeException($"Index `{index}` is out of range.");
            }

            SevenZipArchiveFile file = _Files[index];

            if (!preProcessFile(outputDirectory, file))
            {
                string fullPath = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name));

                // progress provider
                SevenZipProgressProvider szpp = null;
                if (ProgressDelegate != null)
                {
                    szpp = new SevenZipProgressProvider(_Files, new[] { index }, ProgressDelegate);
                }

                // extraction
                Trace.TraceInformation($"Filename: `{file.Name}`, file size: `{file.Size} bytes`.");
                var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo, Password);
                using (Stream fileStream = File.Create(fullPath))
                    sx.Extract((UInt64)file.UnPackIndex, fileStream, szpp);
                if (file.Time != null)
                {
                    File.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time);
                }
            }

            return(this);
        }
Ejemplo n.º 3
0
        private void compressFilesNonSolid(ulong numStreams, Dictionary <ulong, ulong> streamToFileIndex, SevenZipProgressProvider progressProvider)
        {
            var sc = new SevenZipStreamsCompressor(stream);

            sc.Method = Compression.Registry.Method.LZMA;

            // actual compression (into a single packed stream per file)
            SevenZipStreamsCompressor.PackedStream[] css = new SevenZipStreamsCompressor.PackedStream[numStreams];
            ulong numPackStreams = 0;

            for (ulong i = 0; i < numStreams; ++i)
            {
                SevenZipArchiveFile file = _Files[(int)streamToFileIndex[i]];

                Trace.TraceInformation($"Compressing `{file.Name}`, Size: `{file.Size} bytes`...");
                using (Stream source = file.Source.Get(FileAccess.Read))
                    css[i] = sc.Compress(source, progressProvider);

                numPackStreams += css[i].NumStreams;
            }

            // build headers
            var streamsInfo = this.header.RawHeader.MainStreamsInfo;

            streamsInfo.PackInfo = new SevenZipHeader.PackInfo()
            {
                NumPackStreams = numPackStreams,
                PackPos        = 0,
                Sizes          = new UInt64[numPackStreams],
                Digests        = new SevenZipHeader.Digests(numPackStreams)
            };
            streamsInfo.UnPackInfo = new SevenZipHeader.UnPackInfo()
            {
                NumFolders = numStreams,
                Folders    = new SevenZipHeader.Folder[numStreams]
            };

            streamsInfo.SubStreamsInfo = new SevenZipHeader.SubStreamsInfo(streamsInfo.UnPackInfo)
            {
                NumUnPackStreamsInFolders = Enumerable.Repeat((UInt64)1, (int)numStreams).ToArray(),
                NumUnPackStreamsTotal     = numStreams,
                UnPackSizes = new List <UInt64>((int)numStreams),
                Digests     = new SevenZipHeader.Digests(numStreams)
            };

            for (ulong i = 0, k = 0; i < numStreams; ++i)
            {
                for (ulong j = 0; j < css[i].NumStreams; ++j, ++k)
                {
                    streamsInfo.PackInfo.Sizes[k]        = css[i].Sizes[j];
                    streamsInfo.PackInfo.Digests.CRCs[k] = css[i].CRCs[j];
                }
                streamsInfo.SubStreamsInfo.UnPackSizes.Add((UInt64)css[i].Folder.GetUnPackSize());
                streamsInfo.SubStreamsInfo.Digests.CRCs[i] = css[i].Folder.UnPackCRC;
                css[i].Folder.UnPackCRC           = null;
                streamsInfo.UnPackInfo.Folders[i] = css[i].Folder;
            }
        }
Ejemplo n.º 4
0
        bool processFile(string outputDirectory, SevenZipArchiveFile file)
        {
            string fullPath = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name));

            if (file.IsDeleted)
            {
                if (AllowFileDeletions && File.Exists(fullPath))
                {
                    Trace.TraceInformation($"Deleting file \"{file.Name}\"");
                    File.Delete(fullPath);
                }
            }
            else if (file.IsDirectory)
            {
                if (!PreserveDirectoryStructure)
                {
                    Trace.TraceWarning($"Directory `{file.Name}` ignored, PreserveDirectoryStructure is disabled.");
                }
                else if (!Directory.Exists(fullPath))
                {
                    Trace.TraceInformation($"Create directory \"{file.Name}\"");
                    Directory.CreateDirectory(fullPath);
                    if (file.Time != null)
                    {
                        Directory.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time);
                    }
                }
            }
            else if (file.IsEmpty)
            {
                if (File.Exists(fullPath) && !OverwriteExistingFiles && !SkipExistingFiles)
                {
                    throw new IOException($"File `{file.Name}` already exists.");
                }
                if (!File.Exists(fullPath) || OverwriteExistingFiles)
                {
                    Trace.TraceInformation($"Creating empty file \"{file.Name}\"");
                    File.WriteAllBytes(fullPath, new byte[0]);
                    if (file.Time != null)
                    {
                        File.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time);
                    }
                }
                else
                {
                    Trace.TraceWarning($"File `{file.Name}` already exists. Skipping.");
                }
            }
            else
            {
                // regular file, not "processed"
                return(false);
            }

            // it's been "processed", no further processing necessary
            return(true);
        }
Ejemplo n.º 5
0
        public IExtractor ExtractFile(UInt64 index, string outputDirectory)
        {
            if (index >= (ulong)_Files.LongLength)
            {
                throw new ArgumentOutOfRangeException($"Index `{index}` is out of range.");
            }

            SevenZipArchiveFile file = _Files[index];

            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            if (!processFile(outputDirectory, file))
            {
                string fullPath = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name));
                if (File.Exists(fullPath) && !OverwriteExistingFiles && !SkipExistingFiles)
                {
                    throw new IOException($"File `{file.Name}` already exists.");
                }
                if (!File.Exists(fullPath) || OverwriteExistingFiles)
                {
                    Trace.TraceInformation($"Filename: `{file.Name}`, file size: `{file.Size} bytes`.");

                    var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo);
                    using (Stream fileStream = File.Create(fullPath))
                        sx.Extract((UInt64)file.UnPackIndex, fileStream);
                    if (file.Time != null)
                    {
                        File.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time);
                    }
                }
                else
                {
                    Trace.TraceWarning($"File `{file.Name} already exists, skipping.");
                }
            }

            return(this);
        }
Ejemplo n.º 6
0
        void buildFilesIndex()
        {
            // build empty index

            var filesInfo = header.RawHeader.FilesInfo;

            _Files = new SevenZipArchiveFile[filesInfo.NumFiles];
            for (ulong i = 0; i < filesInfo.NumFiles; ++i)
            {
                _Files[i] = new SevenZipArchiveFile();
            }
            Files = new ReadOnlyCollection <SevenZipArchiveFile>(_Files);

            // set properties that are contained in FileProperties structures

            foreach (var properties in filesInfo.Properties)
            {
                switch (properties.PropertyID)
                {
                case SevenZipHeader.PropertyID.kEmptyStream:
                    for (long i = 0; i < _Files.LongLength; ++i)
                    {
                        bool val = (properties as SevenZipHeader.PropertyEmptyStream).IsEmptyStream[i];
                        _Files[i].IsEmpty     = val;
                        _Files[i].IsDirectory = val;
                    }
                    break;

                case SevenZipHeader.PropertyID.kEmptyFile:
                    for (long i = 0, j = 0; i < _Files.LongLength; ++i)
                    {
                        if (_Files[i].IsEmpty)
                        {
                            bool val = (properties as SevenZipHeader.PropertyEmptyFile).IsEmptyFile[j++];
                            _Files[i].IsDirectory = !val;
                        }
                    }
                    break;

                case SevenZipHeader.PropertyID.kAnti:
                    for (long i = 0, j = 0; i < _Files.LongLength; ++i)
                    {
                        if (_Files[i].IsEmpty)
                        {
                            _Files[i].IsDeleted = (properties as SevenZipHeader.PropertyAnti).IsAnti[j++];
                        }
                    }
                    break;

                case SevenZipHeader.PropertyID.kMTime:
                    for (long i = 0; i < _Files.LongLength; ++i)
                    {
                        _Files[i].Time = (properties as SevenZipHeader.PropertyTime).Times[i];
                    }
                    break;

                case SevenZipHeader.PropertyID.kName:
                    for (long i = 0; i < _Files.LongLength; ++i)
                    {
                        _Files[i].Name = (properties as SevenZipHeader.PropertyName).Names[i];
                    }
                    break;

                case SevenZipHeader.PropertyID.kWinAttributes:
                    for (long i = 0; i < _Files.LongLength; ++i)
                    {
                        _Files[i].Attributes = (properties as SevenZipHeader.PropertyAttributes).Attributes[i];
                    }
                    break;
                }
            }

            // set output sizes from the overly complex 7zip headers

            var streamsInfo = header.RawHeader.MainStreamsInfo;
            var ui          = streamsInfo.UnPackInfo;
            var ssi         = streamsInfo.SubStreamsInfo;

            if (ui == null)
            {
                Trace.TraceWarning("7zip: Missing header information to calculate output file sizes.");
                return;
            }

            int upsIndex = 0;
            int upcIndex = 0;

            long fileIndex   = 0;
            long streamIndex = 0;

            for (long i = 0; i < (long)streamsInfo.UnPackInfo.NumFolders; ++i)
            {
                SevenZipHeader.Folder folder = ui.Folders[i];
                long ups = 1;
                if (ssi != null && ssi.NumUnPackStreamsInFolders.Any())
                {
                    ups = (long)ssi.NumUnPackStreamsInFolders[i];
                }
                if (ups == 0)
                {
                    throw new SevenZipException("Unexpected, no UnPackStream in Folder.");
                }

                UInt64 size = folder.GetUnPackSize();
                UInt32?crc  = folder.UnPackCRC;
                for (long j = 0; j < ups; ++j)
                {
                    if (ssi != null && ssi.UnPackSizes.Any())
                    {
                        if (upsIndex > ssi.UnPackSizes.Count())
                        {
                            throw new SevenZipException("Unexpected, missing UnPackSize entry(ies).");
                        }
                        size = ssi.UnPackSizes[upsIndex++];
                    }
                    else
                    {
                        if (ups > 1)
                        {
                            throw new SevenZipException("Missing SubStreamsInfo header chunk.");
                        }
                    }

                    if (crc == null || ups > 1)
                    {
                        if (ssi != null && ssi.Digests != null && (int)ssi.Digests.NumStreams() > upcIndex)
                        {
                            crc = ssi.Digests.CRCs[upcIndex];
                        }
                        upcIndex++;
                    }

                    while (_Files[fileIndex].IsEmpty)
                    {
                        if (++fileIndex >= _Files.LongLength)
                        {
                            throw new SevenZipException("Missing Files entries for defined sizes.");
                        }
                    }
                    _Files[fileIndex].Size        = size;
                    _Files[fileIndex].CRC         = crc;
                    _Files[fileIndex].UnPackIndex = (UInt64?)streamIndex;

                    fileIndex++;
                    streamIndex++;
                }
            }
        }
Ejemplo n.º 7
0
        public IExtractor ExtractFiles(UInt64[] indices, string outputDirectory)
        {
            if (indices.Any(index => index >= (ulong)_Files.LongLength))
            {
                throw new ArgumentOutOfRangeException("An index given in `indices[]` array is out of range.");
            }

            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            var   streamToFileIndex = new Dictionary <ulong, ulong>();
            var   streamIndices     = new List <ulong>();
            ulong streamIndex       = 0;

            for (ulong i = 0; i < (ulong)_Files.LongLength; ++i)
            {
                if (!indices.Any() || Array.IndexOf(indices, i) != -1)
                {
                    if (!processFile(outputDirectory, _Files[i]))
                    {
                        if (indices.Any())
                        {
                            streamIndices.Add(streamIndex);
                        }
                    }
                }
                if (!_Files[i].IsEmpty)
                {
                    streamToFileIndex[streamIndex++] = i;
                }
            }

            var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo);

            sx.ExtractMultiple(
                streamIndices.ToArray(),

                (ulong index) => {
                SevenZipArchiveFile file = _Files[streamToFileIndex[index]];
                string fullPath          = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name));

                Trace.TraceInformation($"File index {index}, filename: {file.Name}, file size: {file.Size}");

                if (File.Exists(fullPath) && !OverwriteExistingFiles && !SkipExistingFiles)
                {
                    throw new IOException($"File `{file.Name}` already exists.");
                }
                if (!File.Exists(fullPath) || OverwriteExistingFiles)
                {
                    return(new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.None, 128 * 1024));
                }

                Trace.TraceWarning($"File `{file.Name} already exists, skipping.");
                return(null);
            },

                (ulong index, Stream stream) => {
                stream.Close();
                SevenZipArchiveFile file = _Files[streamToFileIndex[index]];
                string fullPath          = Path.Combine(outputDirectory, file.Name);
                if (file.Time != null)
                {
                    File.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time);
                }
            });

            return(this);
        }
Ejemplo n.º 8
0
        private bool preProcessFile(string outputDirectory, SevenZipArchiveFile file)
        {
            string fullPath = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name));

            if (file.IsDeleted)
            {
                if (AllowFileDeletions && File.Exists(fullPath))
                {
                    Trace.TraceInformation($"Deleting file \"{file.Name}\"");
                    File.Delete(fullPath);
                }
            }
            else if (file.IsDirectory)
            {
                if (!PreserveDirectoryStructure)
                {
                    Trace.TraceWarning($"Directory `{file.Name}` ignored, PreserveDirectoryStructure is disabled.");
                }
                else if (!Directory.Exists(fullPath))
                {
                    Trace.TraceInformation($"Create directory \"{file.Name}\"");
                    Directory.CreateDirectory(fullPath);
                    if (file.Time != null)
                    {
                        Directory.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time);
                    }
                }
            }
            else
            {
                FeedbackResult result = FeedbackResult.Yes;
                if (File.Exists(fullPath))
                {
                    if (OverwriteExistingFiles)
                    {
                        if (OverwriteDelegate != null)
                        {
                            result = OverwriteDelegate(new[] { file });
                            if (result == FeedbackResult.Cancel)
                            {
                                throw new OperationCanceledException("User feedback cancelled extraction.");
                            }
                        }
                    }
                    else
                    {
                        if (!SkipExistingFiles)
                        {
                            throw new SevenZipFileAlreadyExistsException(file);
                        }
                        result = FeedbackResult.No;
                    }
                }
                if (result == FeedbackResult.Yes)
                {
                    // make sure path exists
                    if (!string.IsNullOrEmpty(Path.GetDirectoryName(file.Name)))
                    {
                        if (!Directory.Exists(Path.GetDirectoryName(fullPath)))
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
                        }
                    }

                    // if file is not empty, it will need extraction
                    if (!file.IsEmpty)
                    {
                        Trace.TraceInformation($"File included for extraction: {file.Name}, file size: {file.Size}");
                        return(false);
                    }

                    // create empty file right away
                    Trace.TraceInformation($"Creating empty file \"{file.Name}\"");
                    File.WriteAllBytes(fullPath, new byte[0]);
                    if (file.Time != null)
                    {
                        File.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time);
                    }
                }
                else
                {
                    // skipping file, so leave it as "processed" to avoid useless decoding
                    Trace.TraceWarning($"File `{file.Name}` already exists. Skipping.");
                }
            }

            // it's been "processed", no further processing necessary
            return(true);
        }
Ejemplo n.º 9
0
        public IExtractor ExtractFiles(UInt64[] indices, string outputDirectory)
        {
            if (indices.Any(index => index >= (ulong)_Files.LongLength))
            {
                throw new ArgumentOutOfRangeException("An index given in `indices[]` array is out of range.");
            }

            // preprocess files and keep track of streams to decompress
            var   streamToFileIndex = new Dictionary <ulong, ulong>();
            var   streamIndices     = new List <ulong>();
            ulong streamIndex       = 0;

            for (ulong i = 0; i < (ulong)_Files.LongLength; ++i)
            {
                if (!indices.Any() || Array.IndexOf(indices, i) != -1)
                {
                    if (!preProcessFile(outputDirectory, _Files[i]))
                    {
                        streamIndices.Add(streamIndex);
                    }
                }
                if (!_Files[i].IsEmpty)
                {
                    streamToFileIndex[streamIndex++] = i;
                }
            }

            // no file to decompress
            if (!streamIndices.Any())
            {
                Trace.TraceWarning("ExtractFiles: No decoding required.");
                return(this);
            }

            // progress provider
            SevenZipProgressProvider szpp = null;

            if (ProgressDelegate != null)
            {
                szpp = new SevenZipProgressProvider(_Files, indices, ProgressDelegate);
            }

            // extraction
            Trace.TraceInformation("Extracting...");
            var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo, Password);

            sx.ExtractMultiple(
                streamIndices.ToArray(),
                (ulong index) => {
                SevenZipArchiveFile file = _Files[streamToFileIndex[index]];
                string fullPath          = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name));

                Trace.TraceInformation($"File index {index}, filename: {file.Name}, file size: {file.Size}");
                return(new FileStream(fullPath,
                                      FileMode.Create,
                                      FileAccess.Write,
                                      FileShare.None,
                                      bufferSize));
            },
                (ulong index, Stream stream) => {
                stream.Close();
                SevenZipArchiveFile file = _Files[streamToFileIndex[index]];
                string fullPath          = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name));
                if (file.Time != null)
                {
                    File.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time);
                }
            },
                szpp);

            return(this);
        }
Ejemplo n.º 10
0
 internal SevenZipFileAlreadyExistsException(SevenZipArchiveFile file)
     : base($"File `{file.Name}` already exists.")
 {
 }