/// <summary>
        /// Returns an IFilter for the given <paramref name="stream"/>
        /// when there is no filter available
        /// </summary>
        /// <param name="stream">An <see cref="Stream"/></param>
        /// <param name="extension">The file extension</param>
        /// <param name="disableEmbeddedContent">When set to <c>true</c> embedded content is NOT read</param>
        /// <param name="fileName">The name of the file</param>
        /// <param name="readIntoMemory">When set to <c>true</c> the <paramref name="stream"/> is completely read
        /// into memory first before the iFilters starts to read chunks, when set to <c>false</c> the iFilter reads
        /// directly from the <paramref name="stream"/> and advances reading when the chunks are returned.
        /// Default set to <c>false</c></param>
        /// <returns><see cref="NativeMethods.IFilter"/> or null when no IFilter DLL is</returns>
        public static NativeMethods.IFilter LoadAndInitIFilter(Stream stream,
                                                               string extension,
                                                               bool disableEmbeddedContent,
                                                               string fileName     = "",
                                                               bool readIntoMemory = false)
        {
            // Find the dll and ClassID
            GetFilterDllAndClass(extension, out var dllName, out var filterPersistClass);

            var iFilter = LoadFilterFromDll(dllName, filterPersistClass);

            if (iFilter == null)
            {
                return(null);
            }

            var iflags = NativeMethods.IFILTER_INIT.CANON_HYPHENS |
                         NativeMethods.IFILTER_INIT.CANON_PARAGRAPHS |
                         NativeMethods.IFILTER_INIT.CANON_SPACES |
                         NativeMethods.IFILTER_INIT.APPLY_INDEX_ATTRIBUTES |
                         NativeMethods.IFILTER_INIT.APPLY_CRAWL_ATTRIBUTES |
                         NativeMethods.IFILTER_INIT.APPLY_OTHER_ATTRIBUTES |
                         NativeMethods.IFILTER_INIT.HARD_LINE_BREAKS |
                         NativeMethods.IFILTER_INIT.FILTER_OWNED_VALUE_OK |
                         NativeMethods.IFILTER_INIT.EMIT_FORMATTING;

            if (disableEmbeddedContent)
            {
                iflags = iflags | NativeMethods.IFILTER_INIT.DISABLE_EMBEDDED;
            }

            // ReSharper disable once SuspiciousTypeConversion.Global
            var iPersistStream = iFilter as NativeMethods.IPersistStream;

            // IPersistStream is asumed on 64 bits systems
            if (iPersistStream != null)
            {
                // Create a COM stream
                IStream comStream;

                if (readIntoMemory)
                {
                    // Copy the content to global memory
                    var buffer = new byte[stream.Length];
                    stream.Read(buffer, 0, buffer.Length);
                    var nativePtr = Marshal.AllocHGlobal(buffer.Length);
                    Marshal.Copy(buffer, 0, nativePtr, buffer.Length);
                    NativeMethods.CreateStreamOnHGlobal(nativePtr, true, out comStream);
                }
                else
                {
                    comStream = new IStreamWrapper(stream);
                }

                try
                {
                    iPersistStream.Load(comStream);

                    if (iFilter.Init(iflags, 0, IntPtr.Zero, out _) == NativeMethods.IFilterReturnCode.S_OK)
                    {
                        return(iFilter);
                    }
                }
                catch (Exception exception)
                {
                    if (string.IsNullOrWhiteSpace(fileName))
                    {
                        throw new IFOldFilterFormat("An error occured while trying to load a stream with the IPersistStream interface", exception);
                    }
                }
            }

            if (string.IsNullOrWhiteSpace(fileName))
            {
                throw new IFOldFilterFormat("The IFilter does not support the IPersistStream interface, supply a filename to use the IFilter");
            }

            // If we get here we probably are using an old IFilter so try to load it the old way
            // ReSharper disable once SuspiciousTypeConversion.Global
            if (iFilter is IPersistFile persistFile)
            {
                persistFile.Load(fileName, 0);
                if (iFilter.Init(iflags, 0, IntPtr.Zero, out _) == NativeMethods.IFilterReturnCode.S_OK)
                {
                    return(iFilter);
                }
            }

            // If we failed to retreive an IPersistStream or IPersistFile interface or to initialize
            // the filter, we release it and return null.
            Marshal.ReleaseComObject(iFilter);
            return(null);
        }
        /// <summary>
        /// Returns an IFilter for the given <paramref name="stream"/>
        /// when there is no filter available
        /// </summary>
        /// <param name="stream">An <see cref="Stream"/></param>
        /// <param name="extension">The file extension</param>
        /// <param name="disableEmbeddedContent">When set to <c>true</c> embedded content is NOT read</param>
        /// <param name="fileName">The name of the file</param>
        /// <param name="readIntoMemory">When set to <c>true</c> the <paramref name="stream"/> is completely read 
        /// into memory first before the iFilters starts to read chunks, when set to <c>false</c> the iFilter reads
        /// directly from the <paramref name="stream"/> and advances reading when the chunks are returned. 
        /// Default set to <c>false</c></param>
        /// <returns><see cref="NativeMethods.IFilter"/> or null when no IFilter DLL is</returns>
        public static NativeMethods.IFilter LoadAndInitIFilter(Stream stream, 
                                                               string extension,
                                                               bool disableEmbeddedContent,
                                                               string fileName = "",
                                                               bool readIntoMemory = false)
        {
            string dllName, filterPersistClass;

            // Find the dll and ClassID
            GetFilterDllAndClass(extension, out dllName, out filterPersistClass);

            var iFilter = LoadFilterFromDll(dllName, filterPersistClass);

            if (iFilter == null)
                return null;

            var iflags = NativeMethods.IFILTER_INIT.CANON_HYPHENS |
                         NativeMethods.IFILTER_INIT.CANON_PARAGRAPHS |
                         NativeMethods.IFILTER_INIT.CANON_SPACES |
                         NativeMethods.IFILTER_INIT.APPLY_INDEX_ATTRIBUTES |
                         NativeMethods.IFILTER_INIT.APPLY_CRAWL_ATTRIBUTES |
                         NativeMethods.IFILTER_INIT.APPLY_OTHER_ATTRIBUTES |
                         NativeMethods.IFILTER_INIT.HARD_LINE_BREAKS |
                         NativeMethods.IFILTER_INIT.FILTER_OWNED_VALUE_OK |
                         NativeMethods.IFILTER_INIT.EMIT_FORMATTING;

            if (disableEmbeddedContent)
                iflags = iflags | NativeMethods.IFILTER_INIT.DISABLE_EMBEDDED;

            // ReSharper disable once SuspiciousTypeConversion.Global
            var iPersistStream = iFilter as NativeMethods.IPersistStream;

            // IPersistStream is asumed on 64 bits systems
            if (iPersistStream != null)
            {
                // Create a COM stream
                IStream comStream;

                if (readIntoMemory)
                {
                    // Copy the content to global memory
                    var buffer = new byte[stream.Length];
                    stream.Read(buffer, 0, buffer.Length);
                    var nativePtr = Marshal.AllocHGlobal(buffer.Length);
                    Marshal.Copy(buffer, 0, nativePtr, buffer.Length);
                    NativeMethods.CreateStreamOnHGlobal(nativePtr, true, out comStream);
                }
                else
                    comStream = new IStreamWrapper(stream);

                iPersistStream.Load(comStream);
                NativeMethods.IFILTER_FLAGS flags;
                if (iFilter.Init(iflags, 0, IntPtr.Zero, out flags) == NativeMethods.IFilterReturnCode.S_OK)
                    return iFilter;
            }

            if (string.IsNullOrWhiteSpace(fileName))
                throw new IFOldFilterFormat("The IFilter does not support the IPersistStream interface, supply a filename to use the IFilter");

            // If we get here we probably are using an old IFilter so try to load it the old way
            // ReSharper disable once SuspiciousTypeConversion.Global
            var persistFile = iFilter as IPersistFile;
            if (persistFile != null)
            {
                persistFile.Load(fileName, 0);
                NativeMethods.IFILTER_FLAGS flags;
                if (iFilter.Init(iflags, 0, IntPtr.Zero, out flags) == NativeMethods.IFilterReturnCode.S_OK)
                    return iFilter;
            }

            // If we failed to retreive an IPersistStream or IPersistFile interface or to initialize
            // the filter, we release it and return null.
            Marshal.ReleaseComObject(iFilter);
            return null;
        }