/// <summary> /// Extract the Stream given. /// </summary> /// <param name="filename">The filename to use for the stream.</param> /// <param name="stream">The Stream to extract from</param> /// <param name="opts">The Extractor Options to use.</param> /// <returns></returns> public IEnumerable <FileEntry> Extract(string filename, Stream stream, ExtractorOptions?opts = null) { var options = opts ?? new ExtractorOptions(); var governor = new ResourceGovernor(options); governor.ResetResourceGovernor(stream); FileEntry?fileEntry = null; try { fileEntry = new FileEntry(Path.GetFileName(filename), stream); governor.ResetResourceGovernor(stream); } catch (Exception ex) { Logger.Debug(ex, "Failed to extract file {0}", filename); } if (fileEntry != null) { foreach (var result in Extract(fileEntry, opts, governor)) { governor.GovernorStopwatch.Stop(); yield return(result); governor.GovernorStopwatch.Start(); } } governor.GovernorStopwatch.Stop(); }
/// <summary> /// Extract from a FileEntry. /// </summary> /// <param name="fileEntry">The FileEntry containing the Conteant stream to parse.</param> /// <param name="opts">The ExtractorOptions to use</param> /// <param name="governor">The Resource governor to use (or null to create a new one).</param> /// <returns>The FileEntries found.</returns> public IEnumerable <FileEntry> Extract(FileEntry fileEntry, ExtractorOptions?opts = null, ResourceGovernor?governor = null) { var options = opts ?? new ExtractorOptions(); var Governor = governor; if (Governor == null) { Governor = new ResourceGovernor(options); Governor.ResetResourceGovernor(fileEntry.Content); } Logger.Trace("ExtractFile({0})", fileEntry.FullPath); Governor.CurrentOperationProcessedBytesLeft -= fileEntry.Content.Length; Governor.CheckResourceGovernor(); IEnumerable <FileEntry> result = Array.Empty <FileEntry>(); var useRaw = false; try { var type = MiniMagic.DetectFileType(fileEntry); if (type == ArchiveFileType.UNKNOWN || !Extractors.ContainsKey(type)) { useRaw = true; result = new[] { fileEntry }; } else { result = Extractors[type].Extract(fileEntry, options, Governor); } } catch (Exception ex) { Logger.Debug(ex, "Error extracting {0}: {1}", fileEntry.FullPath, ex.Message); useRaw = true; result = new[] { fileEntry }; } // After we are done with an archive subtract its bytes. Contents have been counted now separately if (!useRaw) { Governor.CurrentOperationProcessedBytesLeft += fileEntry.Content.Length; } return(result); }
/// <summary> /// Get the FileEntries contained in the FileEntry representing an Ar file /// </summary> /// <param name="fileEntry">The FileEntry to parse</param> /// <param name="options">The ExtractorOptions</param> /// <param name="governor">The RsourceGovernor to use</param> /// <returns>The FileEntries found.</returns> public static IEnumerable <FileEntry> GetFileEntries(FileEntry fileEntry, ExtractorOptions options, ResourceGovernor governor) { if (fileEntry == null) { yield break; } // First, cut out the file signature (8 bytes) fileEntry.Content.Position = 8; var filenameLookup = new Dictionary <int, string>(); var headerBuffer = new byte[60]; while (true) { if (fileEntry.Content.Length - fileEntry.Content.Position < 60) // The header for each file is 60 bytes { break; } fileEntry.Content.Read(headerBuffer, 0, 60); var headerString = Encoding.ASCII.GetString(headerBuffer); if (long.TryParse(Encoding.ASCII.GetString(headerBuffer[48..58]), out var size))// header size in bytes
/// <summary> /// Enumerate the FileEntries in the given Deb file /// </summary> /// <param name="fileEntry">The Deb file FileEntry</param> /// <param name="options">The ExtractorOptions to use</param> /// <param name="governor">The ResourceGovernor to use</param> /// <returns>The FileEntries found</returns> public static IEnumerable <FileEntry> GetFileEntries(FileEntry fileEntry, ExtractorOptions options, ResourceGovernor governor) { if (fileEntry == null) { yield break; } // First, cut out the file signature (8 bytes) and global header (64 bytes) fileEntry.Content.Position = 72; var headerBytes = new byte[60]; while (true) { if (fileEntry.Content.Length - fileEntry.Content.Position < 60) // The header for each file is 60 bytes { break; } fileEntry.Content.Read(headerBytes, 0, 60); var filename = Encoding.ASCII.GetString(headerBytes[0..16]).Trim(); // filename is 16 bytes