/// <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