/// <summary> /// Creates an instance of <see cref="ICompressedArchiveAccess"/> that can be used to access a nested archive. /// </summary> /// <param name="parentArchiveAccess">The parent archive, which contains the nested archive indicated by <paramref name="entry"/>.</param> /// <param name="entry">The entry within <paramref name="parentArchiveAccess"/> that indicates a nested archive.</param> /// <returns>An instance of <see cref="NestedCompressedArchiveAccess"/>, which provides access to the nested archive.</returns> /// <remarks>This wrapper type takes care of cleaning up any temporary files that may be required to access the nested archive. /// For example, some data streams used to access an archive are not navigable from the parent stream (GZIP).</remarks> public static NestedCompressedArchiveAccess Create(ICompressedArchiveAccess parentArchiveAccess, ICompressedArchiveEntry entry) { NestedCompressedArchiveAccess nestedCompressedArchive = null; var entryName = entry.Name; var nestedArchiveFormats = Path.GetExtension(entryName).GetCompressedArchiveFormatsFromFileExtension(); var nestedArchiveFormat = nestedArchiveFormats.FirstOrDefault(); if (nestedArchiveFormat.IsCompressedArchiveFormatSupported()) { TemporaryDirectory temporaryLocation = null; var entryData = parentArchiveAccess.OpenEntry(entry); if (FormatMustBeExtracted(parentArchiveAccess.Format) || FormatMustBeExtracted(nestedArchiveFormat)) { // We can't fully navigate the nested stream, so extract to disk, then proceed. temporaryLocation = new TemporaryDirectory(); var temporaryEntryFilePath = Path.Combine(temporaryLocation.Path, entryName); if (Directory.CreateDirectory(Path.GetDirectoryName(temporaryEntryFilePath)).Exists) { System.Diagnostics.Debug.WriteLine("Extracted entry " + entryName + " to " + temporaryLocation.Path); var fileStream = new FileStream(temporaryEntryFilePath, FileMode.Create, FileAccess.ReadWrite); entryData.CopyTo(fileStream); fileStream.Seek(0, SeekOrigin.Begin); entryData.Dispose(); entryData = fileStream; } } var compressedArchive = CompressedArchiveAccess.Open(entryData, nestedArchiveFormat, CompressedArchiveAccessMode.Read); nestedCompressedArchive = new NestedCompressedArchiveAccess(parentArchiveAccess, compressedArchive, temporaryLocation); nestedCompressedArchive.NestedArchiveFormats = nestedArchiveFormats; } return(nestedCompressedArchive); }
/// <summary> /// Creates an instance of <see cref="CompressedArchiveFileAccess"/>, depending on <paramref name="mode"/>. /// </summary> /// <param name="filePath">The absolute path for the compressed archive.</param> /// <param name="mode">The access mode to use for operations on the compressed archive.</param> /// <param name="implementation">If not <c>null</c>, use a specific implementation if possible. Otherwise, use default, or any.</param> /// <returns>An instance of <see cref="CompressedArchiveFileAccess"/> that provides access to the compressed archive located at <paramref name="filePath"/>.</returns> /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="filePath"/> is <c>null</c>.</exception> /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the file is accessed incorrectly for the given <paramref name="mode"/>.</exception> /// <exception cref="System.ArgumentException">Thrown if <paramref name="filePath"/> is empty or white space, contains invalid characters, or is otherwise invalid</exception> /// <exception cref="System.NotSupportedException">Thrown if <paramref name="filePath"/> refers to a non-file device, e.g. a COM port, et. al.</exception> /// <exception cref="System.IO.FileNotFoundException">Thrown if <paramref name="filePath"/> cannot be found.</exception> /// <exception cref="System.IO.IOException">Thrown if an I/O error occurs.</exception> /// <exception cref="System.Security.SecurityException">Thrown if the requested action on <paramref name="filePath"/> cannot be performed, e.g. no read / create access is granted, et. al.</exception> /// <exception cref="System.IO.DirectoryNotFoundException">Thrown if the directory cannot be found, e.g. an unavailable network drive forms part of the file path.</exception> /// <exception cref="System.UnauthorizedAccessException">Thrown if access is denied, e.g. read/write access requested for a read-only file or directory.</exception> /// <exception cref="System.IO.PathTooLongException">Thrown if <paramref name="filePath"/> is too long.</exception> /// <exception cref="System.InvalidOperationException">Thrown if it is not possible to create an instance of <see cref="CompressedArchiveFileAccess"/> from the file at <paramref name="filePath"/>, /// despite the file appearing to be valid.</exception> public static CompressedArchiveFileAccess Create(string filePath, CompressedArchiveAccessMode mode, CompressedArchiveAccessImplementation?implementation) { var fileMode = CompressedArchiveAccessModeToFileMode(mode); var fileAccess = CompressedArchiveAccessModeToFileAccess(mode); var fileName = Path.GetFileName(filePath); var successfullyAccessedFormats = new List <CompressedArchiveFormat>(); var fileStream = new FileStream(filePath, fileMode, fileAccess); var formats = filePath.GetCompressedArchiveFormatsFromFileName(); ICompressedArchiveAccess compressedArchiveAccess = null; #if OPEN_NESTED_FORMAT_IMMEDIATELY Stream stream = fileStream; foreach (var format in formats) { compressedArchiveAccess = Utility.CompressedArchiveAccess.Open(stream, format, mode); if (compressedArchiveAccess != null) { successfullyAccessedFormats.Add(format); if (!compressedArchiveAccess.IsArchive) { fileName = Path.GetFileNameWithoutExtension(fileName); var entry = compressedArchiveAccess.FindEntry(fileName); stream = entry == null ? null : compressedArchiveAccess.OpenEntry(entry); if (stream == null) { compressedArchiveAccess = null; break; } } } else { break; } } #else var format = formats.FirstOrDefault(); if (format != CompressedArchiveFormat.None) { compressedArchiveAccess = Utility.CompressedArchiveAccess.Open(fileStream, format, mode, implementation); } #endif if (compressedArchiveAccess == null) { var identifiedFormats = string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, formats); var successfullyCreatedFormats = string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, successfullyAccessedFormats); var failedFormats = string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, formats.Except(successfullyAccessedFormats)); var errorMessage = string.Format(CultureInfo.CurrentCulture, Resources.Strings.CompressedArchiveAccess_UnableToProcessError_Format, filePath, identifiedFormats, successfullyCreatedFormats, failedFormats); throw new InvalidOperationException(errorMessage); } var compressedArchiveFileAccess = new CompressedArchiveFileAccess(filePath, compressedArchiveAccess) { Stream = fileStream }; return(compressedArchiveFileAccess); }