Functions/GenXdev.FileSystem/Find-Item.Processing.cs

// ################################################################################
// Part of PowerShell module : GenXdev.FileSystem
// Original cmdlet filename : Find-Item.Processing.cs
// Original author : René Vaessen / GenXdev
// Version : 3.28.2026
// ################################################################################
// Copyright (c) 2026 René Vaessen / GenXdev
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ################################################################################



using Microsoft.PowerShell.Commands;
using System.Management.Automation;
using System.Runtime.InteropServices;
using GenXdev.Helpers;

namespace GenXdev.FileSystem
{
    public partial class FindItem : PSGenXdevCmdlet
    {
        /// <summary>
        /// Processes search tasks until completion using a producer-consumer pattern.
        /// </summary>
        /// <remarks>
        /// This method implements the main search loop that coordinates between:
        /// - Directory processing workers (consumers)
        /// - Output and verbose message queues
        /// - Progress tracking and cancellation handling
        ///
        /// The loop continues until all workers are complete and all queues are empty,
        /// ensuring no results are lost during parallel processing.
        /// </remarks>
        protected void ProcessSearchTasks()
        {

            // add initial worker tasks if needed to start processing
            AddWorkerTasksIfNeeded(cts.Token);

            /*
             * main loop to consume outputs while workers are active or queues
             * have items.
             * this ensures all results are processed before completion.
             */

            // continue loop until cancellation or all workers done and output
            // queue empty
            while (!cts.Token.IsCancellationRequested && (
                   !AllWorkersCompleted() || !OutputQueue.IsEmpty ||
                   !DirQueue.IsEmpty || !VerboseQueue.IsEmpty ||
                   !FileContentMatchQueue.IsEmpty))
            {

                // yield cpu time to other threads

                // short sleep to avoid high cpu usage in tight loop
                Thread.Sleep(25);

                // process all queues to handle outputs and messages
                EmptyQueues();

                if (!cts.Token.IsCancellationRequested)
                {
                    // restart paused workers
                    AddWorkerTasksIfNeeded(cts.Token);
                }
            }

            // Ensure all remaining queued items are processed after search completion
            EmptyQueues();
        }

        /// <summary>
        /// Worker task that processes directories from the work queue, performing
        /// file and directory enumeration according to search criteria.
        /// </summary>
        /// <remarks>
        /// The method implements a producer/consumer pattern where:
        /// - It consumes directories from the DirQueue
        /// - It produces both files (OutputQueue) and subdirectories (back to DirQueue)
        ///
        /// The search logic handles:
        /// - Complex path patterns with wildcards (** for recursion)
        /// - UNC and local paths with different enumeration strategies
        /// - Directory-only, file-only, or combined searches
        /// - Pattern-based recursion with configurable depth limits
        /// - Dynamic worker scaling based on system load
        /// - Upward searching for relative path patterns
        ///
        /// Error handling includes specific catches for access denied and I/O errors,
        /// with verbose logging for troubleshooting.
        /// </remarks>
        /// <param name="token">Cancellation token to support stopping the search
        /// operation</param>
        protected void DirectoryProcessor(CancellationToken token)
        {

            /*
             * process each directory from the queue until cancellation is requested
             * or queue is empty.
             * this loop enables parallel processing of multiple directories.
             */

            // loop while not canceled and dequeue succeeds
            // (FileContentMatchQueue.Count <= baseMemoryPerWorker / 256) &&
            while (!token.IsCancellationRequested)
            {
                lock (WorkersLock)
                {
                    // dynamic throttling: check at end of iteration if we should exit
                    var currentDirectoryProcessors = Interlocked.Read(ref directoryProcessors);
                    var maxDirectoryProcessors = maxDirectoryWorkersInParallel();
                    if (currentDirectoryProcessors > maxDirectoryProcessors)
                    {
                        if (UseVerboseOutput)
                        {
                            VerboseQueue.Enqueue($"Directory processor exiting: {currentDirectoryProcessors} > {maxDirectoryProcessors}");
                        }
                        break;
                    }
                    else
                    {
                        if (currentDirectoryProcessors < maxDirectoryProcessors)
                        {
                            AddWorkerTasksIfNeeded(token);
                        }
                    }
                }
                lock (UpwardsDirQueue)
                {
                    try
                    {
                        // if no more directories to process, but upwards dirs exist and
                        // no files found yet, start processing upwards dirs
                        if (DirQueue.Count == 0 && UpwardsDirQueue.Count > 0 && Interlocked.Read(ref filesFound) == 0)
                        {
                            // get the upwards dir with the lowest depth value
                            var firstKey = (from q in UpwardsDirQueue.Keys
                                            orderby UpwardsDirQueue[q]
                                            select q).FirstOrDefault();

                            // build path by prepending ..\ for each depth level
                            var value = UpwardsDirQueue[firstKey] + 1;
                            var path = CurrentDirectory;

                            // we don't want to find the current directory
                            if (value == 1) VisitedNodes.TryAdd(CurrentDirectory, true);

                            // create the necessary upwards directory traversals
                            for (int i = 0; i < value; i++)
                            {
                                path += "\\..";
                            }

                            // get rid of excess ..\ if already at root
                            path = System.IO.Path.GetFullPath(path);

                            // enqueue search
                            InitializeSearchDirectory(path + "\\" + firstKey, false);

                            // remove from upwards queue if max depth reached or at root
                            if (value == MaxSearchUpDepth || path.Length == 3)
                            {
                                if (UseVerboseOutput)
                                {
                                    VerboseQueue.Enqueue("Adding last upwards search directory for '" + firstKey + "' -> " + path);
                                }

                                UpwardsDirQueue.TryRemove(firstKey, out int _);
                            }
                            else
                            {
                                if (UseVerboseOutput)
                                {
                                    VerboseQueue.Enqueue("Adding upwards (" + value + "/" + MaxSearchUpDepth + ") search directory for '" + firstKey + "' -> " + path);
                                }

                                UpwardsDirQueue[firstKey] = value;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        // log unexpected error if verbose, providing full details for
                        // debugging unexpected issues
                        if (UseVerboseOutput)
                        {
                            // enqueue verbose message with path, message, and stack
                            VerboseQueue.Enqueue((
                                "Unexpected error in directory processor " +
                                ": \r\n" + e.Message +
                                "\r\n" + e.StackTrace.ToString()
                            ));

                            // log inner exception if present
                            if (e.InnerException != null)
                            {
                                // enqueue inner exception message
                                VerboseQueue.Enqueue((
                                    "Inner exception: " + e.InnerException.Message
                                ));
                            }
                        }
                    }
                }

                if (DirQueue.TryDequeue(out string name))
                {
                    try
                    {
                        // log processing directory if verbose mode enabled, providing
                        // details on current path for user to track search progress
                        if (UseVerboseOutput)
                        {
                            // enqueue verbose message with path details
                            VerboseQueue.Enqueue((
                                "Processing directory: " + name
                            ));
                        }

                        // try processing the directory
                        try
                        {

                            // declare workload variables
                            string remainingNameInput, remainingNameToRepeatWhenFound,
                                currentLocation, currentFileName,
                                uncMachineNameToEnumerate;

                            // more workload variables
                            bool isUncPath, hasLongPathPrefix, recurseSubDirectories,
                                noMoreCustomWildcards, shouldEnumerateFiles,
                                shouldEnumerateDirectories;

                            // depth variables
                            int currentRecursionDepth, currentRecursionLimit;

                            // get parameters for current workload
                            GetCurrentWorkloadParameters(

                                name,

                                out currentRecursionDepth,
                                out currentRecursionLimit,
                                out recurseSubDirectories,
                                out shouldEnumerateFiles,
                                out shouldEnumerateDirectories,
                                out isUncPath,
                                out noMoreCustomWildcards,
                                out hasLongPathPrefix,
                                out remainingNameInput,
                                out remainingNameToRepeatWhenFound,
                                out currentLocation,
                                out currentFileName,
                                out uncMachineNameToEnumerate
                            );

                            // check if this location + name has already been visited
                            if (LocationAreadyVisited(currentLocation,
                                currentFileName, token))
                            {

                                // skip to next if already visited
                                continue;
                            }

                            // check recursion depth limit

                            // enforce maximum recursion depth if specified to prevent stack
                            // overflows in deep directories
                            if (currentRecursionLimit > 0 && currentRecursionDepth >
                                currentRecursionLimit)
                            {

                                // log skip due to depth if verbose, informing user why
                                // certain deep paths are not searched
                                if (UseVerboseOutput)
                                {

                                    // enqueue verbose message with depth and path
                                    VerboseQueue.Enqueue((
                                        "Skipping path due to max recursion depth (" +
                                        MaxRecursionDepth + "): " + currentLocation
                                    ));
                                }

                                // skip this path
                                continue;
                            }

                            // enumerate files if needed
                            if (shouldEnumerateFiles)
                            {

                                // call file enumeration asynchronously
                                EnumerateDirectoryFiles(

                                    currentLocation,
                                    currentFileName,
                                    hasLongPathPrefix,
                                    noMoreCustomWildcards,
                                    isUncPath,
                                    token
                                );
                            }

                            // enumerate directories if needed
                            if (shouldEnumerateDirectories)
                            {

                                // log enumerating subdirectories if verbose, showing user
                                // where subfolder scanning occurs
                                if (UseVerboseOutput)
                                {

                                    // enqueue verbose message with location
                                    VerboseQueue.Enqueue((
                                        "Enumerating subdirectories in: " + currentLocation
                                    ));
                                }

                                // call subdirectory enumeration
                                EnumerateSubDirectories(

                                    currentLocation,
                                    currentFileName,
                                    remainingNameInput,
                                    remainingNameToRepeatWhenFound,
                                    uncMachineNameToEnumerate,
                                    recurseSubDirectories,
                                    noMoreCustomWildcards,
                                    hasLongPathPrefix,
                                    isUncPath,
                                    token
                                );
                            }
                        }
                        catch (UnauthorizedAccessException e)
                        {

                            // log access denied if verbose, helping user identify
                            // permission issues in paths
                            if (UseVerboseOutput)
                            {

                                // enqueue verbose message with path and error
                                VerboseQueue.Enqueue((
                                    "Access denied for path " +
                                    name + ": " + e.Message
                                ));
                            }
                        }
                        catch (IOException e)
                        {

                            // log io error if verbose, informing user of file system
                            // issues encountered
                            if (UseVerboseOutput)
                            {

                                // enqueue verbose message with path and error
                                VerboseQueue.Enqueue((
                                    "I/O error for path " + name +
                                    ": " + e.Message
                                ));
                            }
                        }
                        catch (Exception e)
                        {

                            // log unexpected error if verbose, providing full details for
                            // debugging unexpected issues
                            if (UseVerboseOutput)
                            {

                                // enqueue verbose message with path, message, and stack
                                VerboseQueue.Enqueue((
                                    "Unexpected error processing " +
                                    name + ": \r\n" + e.Message +
                                    "\r\n" + e.StackTrace.ToString()
                                ));

                                // log inner exception if present
                                if (e.InnerException != null)
                                {

                                    // enqueue inner exception message
                                    VerboseQueue.Enqueue((
                                        "Inner exception: " + e.InnerException.Message
                                    ));
                                }
                            }
                        }
                    }
                    finally
                    {
                        // increment count of unqueued directories
                        Interlocked.Increment(ref dirsCompleted);
                    }
                }
                else break;
            }
        }

        /// <summary>
        /// Gets parameters for current workload, parsing path patterns and determining
        /// enumeration settings.
        /// </summary>
        /// <remarks>
        /// This method analyzes the provided location string to extract:
        /// - Current directory location for enumeration
        /// - File name patterns with wildcards
        /// - Recursion settings based on ** patterns
        /// - UNC path detection and machine name extraction
        /// - Long path prefix handling
        ///
        /// The method coordinates with EnsureFullProvidedLocationAndNamePart and
        /// AdvanceNamePartToNextSearchLocation to fully parse complex paths.
        /// </remarks>
        /// <param name="ProvidedLocation">The provided location string.</param>
        /// <param name="CurrentRecursionDepth">Outputs the current recursion
        /// depth.</param>
        /// <param name="CurrentRecursionLimit">Outputs the current recursion
        /// limit.</param>
        /// <param name="RecurseSubDirectories">Outputs whether to recurse
        /// subdirectories.</param>
        /// <param name="ShouldEnumerateFiles">Outputs whether to enumerate
        /// files.</param>
        /// <param name="ShouldEnumerateDirectories">Outputs whether to enumerate
        /// directories.</param>
        /// <param name="IsUncPath">Outputs if it's a UNC path.</param>
        /// <param name="NoMoreCustomWildcards">Outputs if no more custom
        /// wildcards.</param>
        /// <param name="HasLongPathPrefix">Outputs if has long path
        /// prefix.</param>
        /// <param name="RemainingNamePart">Outputs the remaining search
        /// mask.</param>
        /// <param name="RemainingNameToRepeatWhenFound">Outputs the repeat
        /// mask when found.</param>
        /// <param name="CurrentLocation">Outputs the current location.</param>
        /// <param name="CurrentFileName">Outputs the current file search
        /// mask.</param>
        /// <param name="UncMachineNameToEnumerate">Outputs the UNC machine name
        /// to enumerate.</param>
        void GetCurrentWorkloadParameters(

            string ProvidedLocation,

            out int CurrentRecursionDepth,
            out int CurrentRecursionLimit,
            out bool RecurseSubDirectories,
            out bool ShouldEnumerateFiles,
            out bool ShouldEnumerateDirectories,
            out bool IsUncPath,
            out bool NoMoreCustomWildcards,
            out bool HasLongPathPrefix,
            out string RemainingNamePart,
            out string remainingNameToRepeatWhenFound,
            out string CurrentLocation,
            out string CurrentFileName,
            out string UncMachineNameToEnumerate
        )
        {

            // split the input into location and remaining namePart for
            // processing

            // handle long path prefixes and tilde expansion
            EnsureFullProvidedLocationAndNamePart(

                ref ProvidedLocation,

                out HasLongPathPrefix,
                out IsUncPath,
                out UncMachineNameToEnumerate
            );

            // separate the fixed path prefix from the wildcard-containing parts

            // advance to the next search location based on wildcards in the path

            // this sets up the current location and file namePart for
            // enumeration
            AdvanceNamePartToNextSearchLocation(
                ProvidedLocation,

                IsUncPath,
                out RecurseSubDirectories,
                out NoMoreCustomWildcards,
                out RemainingNamePart,
                out remainingNameToRepeatWhenFound,
                out CurrentLocation,
                out CurrentFileName
            );

            // get depth parameters
            GetCurrentDepthParameters(
                CurrentLocation,
                IsUncPath,
                out CurrentRecursionDepth,
                out CurrentRecursionLimit
            );

            // determine if enumerating unc shares
            bool enumUncShares = !string.IsNullOrEmpty(UncMachineNameToEnumerate);

            // set if should enumerate files
            ShouldEnumerateFiles = !enumUncShares &&
                (RemainingNamePart.IndexOf("\\") < 0) && (
                    FilesAndDirectories.ToBool() ||
                    !Directory.ToBool()
                );

            // set if should enumerate directories
            ShouldEnumerateDirectories = CurrentFileName.IndexOf(':') < 0 && (
                enumUncShares || RecurseSubDirectories || Directory.ToBool() ||
                FilesAndDirectories.ToBool()
            );

            // get full path for current location
            CurrentLocation = Path.GetFullPath(CurrentLocation);

            // adjust repeat mask if ends with *
            if (RemainingNamePart.EndsWith('*') &&
                !remainingNameToRepeatWhenFound.EndsWith("*"))
            {

                // append *
                remainingNameToRepeatWhenFound += "*";
            }

            // log exit parameters if verbose, summarizing all outputs for
            // complete overview
            if (UseVerboseOutput)
            {

                // enqueue verbose out message with all params
                VerboseQueue.Enqueue((
                    "GetCurrentWorkloadParameters\r\n" +
                    "RecurseSubDirectories: '" + RecurseSubDirectories + "'\r\n" +
                    "IsUncPath: '" + IsUncPath + "'\r\n" +
                    "NoMoreCustomWildcards: '" + NoMoreCustomWildcards + "'\r\n" +
                    "HasLongPathPrefix: '" + HasLongPathPrefix + "'\r\n" +
                    "RemainingNamePart: '" + RemainingNamePart + "'\r\n" +
                    "remainingNameToRepeatWhenFound: '" +
                    remainingNameToRepeatWhenFound + "'\r\n" +
                    "CurrentLocation: '" + CurrentLocation + "'\r\n" +
                    "CurrentFileName: '" + CurrentFileName + "'\r\n" +
                    "CurrentRecursionDepth: '" + CurrentRecursionDepth + "'\r\n" +
                    "CurrentRecursionLimit: '" + CurrentRecursionLimit + "'\t\n" +
                    "ShouldEnumerateFiles : '" + ShouldEnumerateFiles + "'\r\n" +
                    "ShouldEnumerateDirectories: '" +
                    ShouldEnumerateDirectories + "'\r\n---\r\n"
                ));
            }
        }

        /// <summary>
        /// Empties all queues and handles output processing.
        /// </summary>
        /// <remarks>
        /// This method processes all pending items in the output queues:
        /// - VerboseQueue: Writes verbose messages to the host
        /// - OutputQueue: Writes search results to the pipeline
        /// - Triggers worker task scaling based on current load
        /// - Updates progress status for user feedback
        ///
        /// Called repeatedly during the main search loop to ensure timely
        /// processing of results and prevent queue overflow.
        /// </remarks>
        private void EmptyQueues()
        {
            // dequeue and write verbose messages
            while (VerboseQueue.TryDequeue(out string msg))
            {
                WriteVerbose(msg);
            }

            // dequeue and write output
            while (OutputQueue.TryDequeue(out object result))
            {
                WriteObject(result);
            }

            AddWorkerTasksIfNeeded(cts.Token);

            // check all progress items in queue
            UpdateProgressStatus(true);
        }

        /// <summary>
        /// Ensures full provided location and name, handling prefixes and
        /// expansions.
        /// </summary>
        /// <remarks>
        /// This method normalizes and expands the input path by:
        /// - Converting separators to backslashes
        /// - Handling long path prefixes (\\?\)
        /// - Expanding tilde (~) to user home directory
        /// - Detecting and processing UNC paths
        /// - Resolving relative paths to absolute
        /// - Handling drive-relative paths
        /// - Adding default wildcards for directory paths
        ///
        /// The method modifies the ProvidedLocation in place and outputs
        /// path characteristics for further processing.
        /// </remarks>
        /// <param name="ProvidedLocation">The provided location, passed by
        /// reference.</param>
        /// <param name="HasLongPathPrefix">Outputs if has long path
        /// prefix.</param>
        /// <param name="IsUncPath">Outputs if it's a UNC path.</param>
        /// <param name="UncMachineNameToEnumerate">Outputs the UNC machine name
        /// to enumerate.</param>
        protected void EnsureFullProvidedLocationAndNamePart(

            ref string ProvidedLocation,

            out bool HasLongPathPrefix,
            out bool IsUncPath,
            out string UncMachineNameToEnumerate
        )
        {

            // normalize separators
            // Normalize separators to backslashes for consistency
            ProvidedLocation = ProvidedLocation.Replace("/", "\\");

            // normalize path
            // Normalize the path part for processing
            // var normPath = NormalizePathForNonFileSystemUse(ProvidedLocation);

            // adjust trailing recurse
            // Adjust for trailing recursive patterns
            if (RecurseEndPatternWithSlashAtStartMatcher.IsMatch(ProvidedLocation))
            {
                ProvidedLocation += "\\";
            }

            // Remove leading .\ for clean path
            if (ProvidedLocation.StartsWith(".\\"))
            {
                ProvidedLocation = ProvidedLocation.Substring(2);
            }

            // split the input string to separate location and search pattern for
            // independent processing

            // append * if ends with \
            if (ProvidedLocation.EndsWith("\\"))
            {

                // add wildcard
                ProvidedLocation += "*";
            }

            // check for long path prefix
            HasLongPathPrefix = ProvidedLocation.StartsWith(@"\\?\");

            // strip prefix if present
            if (HasLongPathPrefix)
            {

                // remove \\?\
                ProvidedLocation = ProvidedLocation.Substring(4);
            }

            // expand ~ to user home directory if requested
            if (ProvidedLocation.StartsWith("~"))
            {
                // get home path
                var homePath = Environment.GetFolderPath(
                    Environment.SpecialFolder.UserProfile
                );

                // combine with rest
                ProvidedLocation = Path.Combine(homePath,
                    ProvidedLocation.Substring(1).TrimStart('\\', '/')
                );
            }

            // init unc path flag
            IsUncPath = false;

            // handle long prefix for unc
            if (HasLongPathPrefix)
            {

                // check unc start
                if (ProvidedLocation.StartsWith(
                    @"UNC\", StringComparison.InvariantCultureIgnoreCase
                ))
                {

                    // adjust for unc
                    ProvidedLocation = @"\" + ProvidedLocation.Substring(3);

                    // set unc flag
                    IsUncPath = true;
                }
            }
            else
            {

                // check unc start
                IsUncPath = ProvidedLocation.StartsWith(@"\\");
            }

            // detect type and needs
            bool endsWithSeperator = ProvidedLocation.EndsWith("\\");
            bool isRooted = Path.IsPathRooted(ProvidedLocation);
            bool isRelative = !isRooted && !IsUncPath;
            bool needsCurrentDir = !IsUncPath && isRooted && (ProvidedLocation.Length < 3 || ProvidedLocation[2] != '\\');

            // handle relative
            if (isRelative)
            {

                // combine with current
                // Combine with current directory for relative paths
                ProvidedLocation = Path.Combine(CurrentDirectory, ProvidedLocation);
            }
            else if (needsCurrentDir)
            {

                // get drive current path
                // Get current path for the drive
                var currentPath = InvokeScript<string>($@"(Microsoft.PowerShell.Management\Get-Location -PSDrive {ProvidedLocation.Substring(0, 1)}).Path");

                // combine
                ProvidedLocation = Path.Combine(currentPath, ProvidedLocation.Substring(2));
            }

            // add separator if needed
            if (endsWithSeperator && !ProvidedLocation.EndsWith("\\"))
            {
                ProvidedLocation += "\\";
            }

            // init unc machine
            UncMachineNameToEnumerate = string.Empty;

            // handle unc paths
            if (IsUncPath)
            {

                // handle short unc
                if (ProvidedLocation.Length == 2)
                {

                    // use local machine
                    ProvidedLocation = @"\\" + Environment.MachineName + @"\>";
                }
                else
                {

                    // find first slash
                    int firstSlash = ProvidedLocation.IndexOf('\\', 2);

                    // append \ if no slash
                    if (firstSlash < 0)
                    {

                        // add trailing
                        ProvidedLocation += @"\>";
                    }
                }

                // find second slash
                int secondSlash = ProvidedLocation.IndexOf('\\', 2);

                // extract machine name
                UncMachineNameToEnumerate = ProvidedLocation.Substring(2,
                    secondSlash - 2).Trim();

                // handle local names
                if (UncMachineNameToEnumerate.Equals(".") ||
                    UncMachineNameToEnumerate.Equals(
                        "localhost", StringComparison.OrdinalIgnoreCase
                    ))
                {

                    // set to machine name
                    UncMachineNameToEnumerate = Environment.MachineName;
                }

                // rebuild provided location
                ProvidedLocation = @"\\" + UncMachineNameToEnumerate +
                    ProvidedLocation.Substring(secondSlash);

                // find second slash again
                secondSlash = ProvidedLocation.IndexOf('\\', 2);

                // init share name
                string uncShareName = string.Empty;

                // find third slash
                int thirdSlash = ProvidedLocation.IndexOf('\\', secondSlash + 1);

                // handle third slash
                if (thirdSlash >= 0)
                {

                    // extract share name
                    uncShareName = ProvidedLocation.Substring(secondSlash + 1,
                        thirdSlash - secondSlash - 1).Trim();

                    // rebuild if share not empty
                    if (!string.IsNullOrEmpty(uncShareName))
                    {

                        // combine parts
                        ProvidedLocation = ProvidedLocation.Substring(0,
                            secondSlash + 1) +
                            uncShareName + ProvidedLocation.Substring(thirdSlash);
                    }
                    else
                    {

                        // throw if double slashes
                        throw new InvalidOperationException((
                            "double slashes should have been removed"
                        ));
                    }
                }

                // clear machine if share no wildcards
                if (ProvidedLocation.Length > secondSlash + 1 &&
                    !uncShareName.Contains("*") && !uncShareName.Contains("?"))
                {

                    // clear
                    UncMachineNameToEnumerate = string.Empty;
                }
                else
                {

                    // append share
                    UncMachineNameToEnumerate += ";" +
                        (string.IsNullOrEmpty(uncShareName) ? "*" : uncShareName);
                }
            }
        }

        /// <summary>
        /// Determines and strips recurse pattern from path components.
        /// </summary>
        /// <remarks>
        /// This method identifies and removes recursive patterns (**)
        /// from file name masks. It handles nested recursive patterns
        /// by iteratively stripping them until no more are found.
        ///
        /// The method modifies the RemainingNamePart and CurrentFileName
        /// by reference to prepare them for further processing.
        /// </remarks>
        /// <param name="RemainingNamePart">Remaining namePart by
        /// ref.</param>
        /// <param name="CurrentFileName">Current filename by
        /// ref.</param>
        /// <returns>Whether it was a recurse pattern.</returns>
        bool DetermineAndStripRecursePattern(

            ref string RemainingNamePart,
            ref string CurrentFileName
        )
        {
            // check if recurse pattern
            bool result = RecursePatternMatcher.IsMatch(CurrentFileName);

            // init recurse flag
            bool isRecursePattern = result;

            // loop while recurse
            while (isRecursePattern)
            {

                // find first slash
                int firstSlash = RemainingNamePart.IndexOf('\\');

                // handle if slash and mask not empty
                if (!string.IsNullOrEmpty(CurrentFileName) &&
                    firstSlash >= 0)
                {

                    // set current mask
                    CurrentFileName = RemainingNamePart.Substring(0,
                        firstSlash);

                    // update remaining
                    RemainingNamePart = RemainingNamePart.Substring(
                        firstSlash + 1
                    );
                }
                else
                {

                    // set current to remaining
                    CurrentFileName = RemainingNamePart;

                    // clear remaining
                    RemainingNamePart = string.Empty;
                }

                // check again
                isRecursePattern = RecursePatternMatcher.IsMatch(
                    CurrentFileName
                );
            }

            // return result
            return result;
        }

        /// <summary>
        /// Advances namePart to next search location based on wildcards.
        /// </summary>
        /// <remarks>
        /// This method coordinates the parsing of complex path patterns by:
        /// - Determining the remaining wildcard portions of the path
        /// - Extracting the current directory location for enumeration
        /// - Setting up recursion flags based on pattern analysis
        /// - Preparing file name masks for matching
        ///
        /// It delegates to DetermineRemainingNamePart and DetermineCurrentNamePart
        /// for detailed parsing logic.
        /// </remarks>
        /// <param name="ProvidedLocation">Provided location.</param>
        /// <param name="IsUncPath">If UNC path.</param>
        /// <param name="RecurseSubDirectories">Outputs recurse
        /// subdirectories.</param>
        /// <param name="NoMoreCustomWildcards">Outputs no more custom
        /// wildcards.</param>
        /// <param name="RemainingNamePart">Outputs remaining search
        /// mask.</param>
        /// <param name="RemainingNameToRepeatWhenFound">Outputs repeat mask
        /// when found.</param>
        /// <param name="CurrentLocation">Outputs current location.</param>
        /// <param name="CurrentFileName">Outputs current file search
        /// mask.</param>
        protected void AdvanceNamePartToNextSearchLocation(

            string ProvidedLocation,
            bool IsUncPath,

            out bool RecurseSubDirectories,
            out bool NoMoreCustomWildcards,

            out string RemainingNamePart,
            out string RemainingNameToRepeatWhenFound,
            out string CurrentLocation,
            out string CurrentFileName
        )
        {
            // determine remaining mask
            DetermineRemainingNamePart(
                ProvidedLocation,
                IsUncPath,

                out RemainingNamePart,
                out CurrentLocation
            );

            // determine current mask
            DetermineCurrentNamePart(

                ref RemainingNamePart,
                out RemainingNameToRepeatWhenFound,

                out RecurseSubDirectories,
                out NoMoreCustomWildcards,
                out CurrentFileName
            );
        }

        /// <summary>
        /// Determines remaining namePart by separating fixed and wildcard portions.
        /// </summary>
        /// <remarks>
        /// This method splits the path into:
        /// - CurrentLocation: The fixed directory path to enumerate
        /// - RemainingNamePart: The wildcard portions for further processing
        ///
        /// It optimizes search start position by skipping non-wildcard directory
        /// components, improving performance for deep path patterns.
        ///
        /// Handles both UNC and local paths with different root structures.
        /// </remarks>
        /// <param name="ProvidedLocation">Provided location.</param>
        /// <param name="IsUncPath">If UNC path.</param>
        /// <param name="RemainingNamePart">Outputs remaining search
        /// mask.</param>
        /// <param name="CurrentLocation">Outputs current location.</param>
        protected void DetermineRemainingNamePart(

           string ProvidedLocation,
           bool IsUncPath,

           out string RemainingNamePart,
           out string CurrentLocation
        )
        {

            // calculate starting index for path based on whether it's unc or local
            // to handle root correctly

            // init index
            int idxS;

            // handle unc
            if (IsUncPath)
            {

                // unc path handling - skip server and share name

                // find first
                int first = ProvidedLocation.IndexOf('\\', 0);

                // find second
                int second = ProvidedLocation.IndexOf('\\', first + 2);

                // find third
                int third = ProvidedLocation.IndexOf('\\', second + 2);

                // set index
                idxS = third >= 0 ? third + 1 : ProvidedLocation.Length;
            }
            else
            {

                // local path handling - skip drive letter

                // find first
                int first = ProvidedLocation.IndexOf('\\');

                // set index
                idxS = first >= 0 ? first + 1 : ProvidedLocation.Length;
            }

            // init remaining
            RemainingNamePart = string.Empty;

            // separate the fixed path prefix from the wildcard-containing parts

            // set current location
            CurrentLocation = ProvidedLocation.Substring(0, idxS);

            // get remaining
            var remainingDetermined = ProvidedLocation.Substring(idxS);

            // split parts
            var remainingDeterminedParts = remainingDetermined.Split(
                    '\\',
                    StringSplitOptions.RemoveEmptyEntries
                ).ToArray<string>();

            // skip non-wildcard parts to optimize the starting point for search

            // init skipped
            var iSkipped = 0;

            // get length
            var l = remainingDeterminedParts.Length;

            // loop parts
            foreach (var part in remainingDeterminedParts)
            {

                // break if wildcard
                if (part.Contains('*') || part.Contains('?'))
                    break;

                // break if last and no wildcard
                if (iSkipped == l - 1 && !(part.Contains('*') ||
                    part.Contains('?')))
                    break;

                // increment skipped
                iSkipped++;

                // combine to current
                CurrentLocation = System.IO.Path.Combine(CurrentLocation, part);
            }

            // join remaining parts that may contain wildcards
            RemainingNamePart = string.Join('\\',
                remainingDeterminedParts.Skip(iSkipped).ToList<string>()
            );
        }

        /// <summary>
        /// Determines current namePart and sets recursion flags.
        /// </summary>
        /// <remarks>
        /// This method extracts the current directory level's file pattern and
        /// determines recursion behavior based on:
        /// - Presence of ** recursive wildcards
        /// - Remaining path components with wildcards
        /// - NoRecurse parameter settings
        ///
        /// It modifies RemainingNamePart by reference to prepare for the next
        /// iteration of path processing.
        /// </remarks>
        /// <param name="RemainingNamePart">Remaining namePart by
        /// ref.</param>
        /// <param name="RemainingNameToRepeatWhenFound">Outputs repeat mask
        /// when found.</param>
        /// <param name="RecurseSubDirectories">Outputs recurse
        /// subdirectories.</param>
        /// <param name="NoMoreCustomWildcards">Outputs no more custom
        /// wildcards.</param>
        /// <param name="CurrentFileName">Outputs current file search
        /// mask.</param>
        protected void DetermineCurrentNamePart(

            ref string RemainingNamePart,
            out string RemainingNameToRepeatWhenFound,

            out bool RecurseSubDirectories,
            out bool NoMoreCustomWildcards,
            out string CurrentFileName)
        {
            // init recurse pattern flag
            bool wasRecursePattern = false;

            // set no more wildcards
            NoMoreCustomWildcards = true;
            bool moreCustomWildcards = false;

            // default current mask
            CurrentFileName = "*";

            // set recurse based on switch
            RecurseSubDirectories = !(NoRecurse.ToBool());

            // set repeat to remaining
            RemainingNameToRepeatWhenFound = RemainingNamePart;

            // extract the pattern for the current directory level

            // find first slash
            int firstSlash = RemainingNamePart.IndexOf('\\');

            // handle if slash found
            if (firstSlash >= 0)
            {
                // set current mask
                CurrentFileName = RemainingNamePart.Substring(0,
                    firstSlash);

                // update remaining
                RemainingNamePart = RemainingNamePart.Substring(
                    firstSlash + 1
                );

                // strip recurse
                wasRecursePattern = DetermineAndStripRecursePattern(

                    ref RemainingNamePart,
                    ref CurrentFileName
                );

                // find next slash
                firstSlash = RemainingNamePart.IndexOf('\\');

                // set repeat
                RemainingNameToRepeatWhenFound = RemainingNamePart;

                // check no more wildcards
                NoMoreCustomWildcards = RemainingNamePart == string.Empty ||
                    RemainingNamePart == "*";

                // more wildcards flag
                moreCustomWildcards = !NoMoreCustomWildcards;

                // update recurse
                RecurseSubDirectories |= wasRecursePattern | moreCustomWildcards;

                // build repeated
                var repeatedMask = string.IsNullOrEmpty(RemainingNamePart) ?
                            CurrentFileName :
                            (CurrentFileName + "\\" + RemainingNamePart);

                // handle recurse pattern
                if (wasRecursePattern)
                {

                    // prepend **
                    RemainingNamePart = "**\\" + repeatedMask;
                }
                else
                {
                    // set if recurse
                    if (RecurseSubDirectories)
                    {

                        // set to repeated
                        RemainingNamePart = repeatedMask;
                    }
                }

                // found slash
                return;
            }

            // done?
            if (string.IsNullOrEmpty(RemainingNamePart))
            {
                return;
            }

            // check recurse
            wasRecursePattern = RecursePatternMatcher.IsMatch(
                RemainingNamePart
            );

            // update recurse
            RecurseSubDirectories |= wasRecursePattern;

            // check no more
            NoMoreCustomWildcards = RemainingNamePart == string.Empty ||
                RemainingNamePart == "*";
            moreCustomWildcards = !NoMoreCustomWildcards;

            // set current
            CurrentFileName = RemainingNamePart;

            // set remaining based on recurse
            RemainingNamePart = wasRecursePattern ? "**" :
                CurrentFileName;

            // set repeat
            RemainingNameToRepeatWhenFound = CurrentFileName;
        }

        /// <summary>
        /// Checks if current location + name already visited to prevent duplicates.
        /// </summary>
        /// <remarks>
        /// This method maintains a thread-safe set of visited paths to avoid
        /// redundant processing in recursive searches. It combines the current
        /// location and file name pattern to create a unique key.
        ///
        /// Returns true if the path was already processed, with optional
        /// verbose logging for debugging.
        /// </remarks>
        /// <param name="CurrentLocation">Current location.</param>
        /// <param name="CurrentFileName">Current filename.</param>
        /// <param name="token">Cancellation token.</param>
        /// <returns>If already visited.</returns>
        private bool LocationAreadyVisited(
            string CurrentLocation,
            string CurrentFileName,
            CancellationToken token)
        {

            // try add to visited
            if (!VisitedNodes.TryAdd(Path.Combine(CurrentLocation,
                CurrentFileName), true))
            {
                // log skip if verbose
                if (UseVerboseOutput)
                {

                    // enqueue skip
                    VerboseQueue.Enqueue((
                        "Skipping already processed path: " + CurrentLocation +
                        " with pattern " + CurrentFileName
                    ));
                }

                // check cancel
                token.ThrowIfCancellationRequested();

                // return visited
                return true;
            }

            // not visited
            return false;
        }

        /// <summary>
        /// Enumerates directory files matching patterns and applying filters.
        /// </summary>
        /// <remarks>
        /// This method performs the core file enumeration with:
        /// - Wildcard pattern matching
        /// - Size and date filtering
        /// - Alternate data stream handling
        /// - Content-based searching queueing
        /// - Thread-safe output queuing
        ///
        /// Handles both regular files and alternate data streams,
        /// with comprehensive exclusion logic for performance.
        /// </remarks>
        /// <param name="StartLocation">Start location.</param>
        /// <param name="CurrentFileName">Current filename.</param>
        /// <param name="HasLongPathPrefix">Has long path prefix.</param>
        /// <param name="NoMoreCustomWildcards">No more custom wildcards.</param>
        /// <param name="IsUncPath">Is UNC path.</param>
        /// <param name="token">Cancellation token.</param>
        protected void EnumerateDirectoryFiles(

            string StartLocation,
            string CurrentFileName,
            bool HasLongPathPrefix,
            bool NoMoreCustomWildcards,
            bool IsUncPath,
            CancellationToken token
        )
        {

            // options for enumeration to ignore inaccessible items and reparse
            // points

            // create options
            System.IO.EnumerationOptions options =
                new System.IO.EnumerationOptions
                {

                    // no recurse
                    RecurseSubdirectories = false, // Handle recursion manually

                    // ignore access
                    IgnoreInaccessible = true,

                    // set casing
                    MatchCasing = CaseNameMatching,

                    // set buffer
                    BufferSize = 163840,

                    // set skip attributes
                    AttributesToSkip = AttributesToSkip
                };

            // skip reparse if not follow
            if (!FollowSymlinkAndJunctions.ToBool())
            {

                // set skip
                options.AttributesToSkip = FileAttributes.ReparsePoint;
            }

            // find stream index
            int idp = CurrentFileName.IndexOf(':');

            // set has stream
            bool hasStreamPattern = idp >= 0;

            // init stream name
            string streamName = null;

            // handle stream pattern
            if (hasStreamPattern)
            {

                // get stream name
                streamName = CurrentFileName.Substring(idp + 1);

                // default *
                if (streamName == string.Empty) streamName = "*";

                // update mask
                CurrentFileName = CurrentFileName.Substring(0, idp);
            }

            // create matcher
            var patternMatcher = new WildcardPattern(
                EscapeBracketsInPattern(CurrentFileName),
                CurrentWildCardOptions);

            // enumerate files in top directory only

            // loop files
            foreach (var filePath in System.IO.Directory.EnumerateFiles(
                (
                IsUncPath ?
                    ("\\\\?\\UNC" + StartLocation.Substring(1)) :
                    ("\\\\?\\" + StartLocation)
                ),
                CurrentFileName,
                SearchOption.TopDirectoryOnly
            ))
            {

                // check cancel
                token.ThrowIfCancellationRequested();

                // normalize path
                var normalizedFilePath = HasLongPathPrefix ? filePath :
                    NormalizePathForNonFileSystemUse(filePath);

                // create file info
                var fileInfo = new FileInfo(normalizedFilePath);

                // check exclusion
                bool noExclusion = NoMoreCustomWildcards ||
                    patternMatcher.IsMatch(fileInfo.Name);

                // set have exclusion
                bool haveExclusion = !noExclusion;

                // skip if exclusion
                if (haveExclusion)
                {

                    // log mismatch if verbose
                    if (UseVerboseOutput)
                    {

                        // enqueue mismatch
                        VerboseQueue.Enqueue((
                            "Skipping file " + normalizedFilePath +
                            " due to pattern mismatch with " +
                            CurrentFileName
                        ));
                    }

                    // skip
                    continue;
                }

                haveExclusion = ShouldFileBeExcluded(fileInfo);

                // skip if exclusion
                if (haveExclusion)
                {

                    // skip
                    continue;
                }

                // set only ads
                bool onlyAds = !string.IsNullOrEmpty(streamName);

                // handle not only ads
                if (!onlyAds)
                {

                    // skip excluded patterns

                    // if have pattern
                    if (matchingFileContent)
                    {

                        // check if content search should be performed based on
                        // switches and extension

                        // if include or not skip ext
                        if (IncludeNonTextFileMatching ||
                            !ExtensionsToSkip.Contains(
                                Path.GetExtension(normalizedFilePath)
                            ))
                        {
                            FileContentMatchQueue.Enqueue(fileInfo);
                            Interlocked.Increment(ref matchesQueued);
                            AddWorkerTasksIfNeeded(token);
                        }
                    }
                    else
                    {

                        // log output if verbose
                        if (UseVerboseOutput)
                        {

                            // enqueue output
                            VerboseQueue.Enqueue((
                                "Outputting file: " + normalizedFilePath
                            ));
                        }

                        // output file info if no content pattern
                        AddToOutputQueue(new FileInfo(normalizedFilePath));
                    }
                }

                // process alternate data streams if the switch is set

                // if include or only ads
                if (IncludeAlternateFileStreams.ToBool() || SearchADSContent.ToBool() || onlyAds)
                {

                    // get streams
                    GetFileAlternateFileStreams(normalizedFilePath,
                        cts!.Token, streamName);
                }
            }
        }

        /// <summary>
        /// Determines if a file should be excluded based on size, date, and pattern filters.
        /// </summary>
        /// <remarks>
        /// This method applies multiple exclusion criteria:
        /// - File size limits (MinFileSize/MaxFileSize)
        /// - Modification date ranges (ModifiedAfter/ModifiedBefore)
        /// - Pattern-based exclusions (FileExcludePatterns)
        /// - Category-based filtering
        ///
        /// Returns true if the file should be skipped, with verbose logging
        /// for each exclusion reason.
        /// </remarks>
        /// <param name="fileInfo">File information to check.</param>
        /// <returns>True if file should be excluded.</returns>
        private bool ShouldFileBeExcluded(FileInfo fileInfo)
        {
            bool haveExclusion = false;

            // check size constraints
            if ((MaxFileSize > 0 && fileInfo.Length > MaxFileSize) ||
                (MinFileSize > 0 && fileInfo.Length < MinFileSize))
            {

                // log skip size if verbose
                if (UseVerboseOutput)
                {
                    // enqueue skip size
                    VerboseQueue.Enqueue((
                        "Skipping file " + fileInfo.FullName +
                        " due to size constraints. Size: " +
                        fileInfo.Length + " bytes"
                    ));
                }

                // skip
                haveExclusion = true;
            }

            // check mod dates
            if (!haveExclusion && (ModifiedAfter.HasValue &&
                fileInfo.LastWriteTimeUtc < ModifiedAfter.Value) ||
                (ModifiedBefore.HasValue &&
                fileInfo.LastWriteTimeUtc > ModifiedBefore.Value))
            {

                // log skip date if verbose
                if (UseVerboseOutput)
                {

                    // enqueue skip date
                    VerboseQueue.Enqueue((
                        "Skipping file " + fileInfo.FullName +
                        " due to modification date constraints. " +
                        "LastWriteTimeUtc: " + fileInfo.LastWriteTimeUtc
                    ));
                }

                // skip
                haveExclusion = true;
            }

            // check exclude patterns
            if (!haveExclusion)
                foreach (var pattern in FileExcludePatterns)
                {

                    // if match
                    if (pattern.IsMatch(WildcardPattern.Escape(fileInfo.FullName)))
                    {

                        // set exclusion
                        haveExclusion = true;

                        // log exclude if verbose
                        if (UseVerboseOutput)
                        {

                            // enqueue exclude
                            VerboseQueue.Enqueue((
                                "Excluding file " + fileInfo.FullName +
                                " due to pattern " + pattern
                            ));
                        }

                        // break
                        break;
                    }
                }

            // check file categories
            if (!haveExclusion && Category != null && Category.Length > 0)
            {
                haveExclusion = true;
                var extension = Path.GetExtension(fileInfo.FullName);

                foreach (var pattern in Category)
                {
                    if (FileGroups.Groups.TryGetValue(pattern, out var group))
                    {
                        if (group.Contains(extension))
                        {

                            if (UseVerboseOutput)
                            {
                                // enqueue exclude
                                VerboseQueue.Enqueue((
                                    "Including file " + fileInfo.FullName +
                                    " for being member of: " + pattern
                                ));

                            }

                            haveExclusion = false;
                            break;
                        }
                    }
                }
            }

            return haveExclusion;
        }

        /// <summary>
        /// Gets file alternate data streams using Windows API.
        /// </summary>
        /// <remarks>
        /// This method enumerates NTFS alternate data streams using:
        /// - FindFirstStreamW/FindNextStreamW Windows API calls
        /// - Pattern matching for stream names
        /// - Content searching within streams if enabled
        /// - Thread-safe output queuing
        ///
        /// Handles both regular ADS enumeration and content-based searching
        /// within alternate streams.
        /// </remarks>
        /// <param name="FilePath">File path.</param>
        /// <param name="token">Cancellation token.</param>
        /// <param name="StreamName">Stream name optional.</param>
        protected void GetFileAlternateFileStreams(string FilePath,
            CancellationToken token, string StreamName = null)
        {

            // create pattern if name
            WildcardPattern wildcardPattern = string.IsNullOrEmpty(StreamName) ?
                null :
              new WildcardPattern(
                  EscapeBracketsInPattern(StreamName),
                  CurrentWildCardOptions
            );

            // try process
            try
            {

                // init stream data
                var streamData = new WIN32_FIND_STREAM_DATA();

                // init handle
                IntPtr handle = IntPtr.Zero;

                // try finally
                try
                {

                    // start enumerating streams using win32 api
                    handle = FindFirstStreamW(FilePath, 0, ref streamData, 0);

                    // handle invalid
                    if (handle == IntPtr.Zero || handle == new IntPtr(-1))
                    {

                        // get error
                        int error = Marshal.GetLastWin32Error();

                        // if error
                        if (error != 0)
                        {

                            // log error if verbose
                            if (UseVerboseOutput)
                            {

                                // enqueue error
                                VerboseQueue.Enqueue((
                                    "Error accessing ADS for " + FilePath +
                                    ": Win32 error " + error
                                ));
                            }
                        }
                    }
                    else
                    {

                        // loop through all streams
                        do
                        {

                            // filter non-standard streams

                            // if name and not data
                            if (!string.IsNullOrEmpty(streamData.StreamName) &&
                                streamData.StreamName != ":$DATA" &&
                                streamData.StreamName != "::$DATA")
                            {

                                // clean stream name

                                // trim :
                                var streamName = streamData.StreamName.TrimStart(
                                    ':');

                                // find data index
                                int dataIdx = streamName.IndexOf(
                                    ":$DATA", StringComparison.OrdinalIgnoreCase
                                );

                                // substring if found
                                if (dataIdx > 0)
                                    streamName = streamName.Substring(0, dataIdx);

                                // skip if no match
                                if (wildcardPattern != null &&
                                    !wildcardPattern.IsMatch(WildcardPattern.Escape(streamName)))
                                {
                                    continue;
                                }

                                // if not empty
                                if (!string.IsNullOrEmpty(streamName))
                                {

                                    // build ads path
                                    var adsPath = $"{FilePath}:{streamName}";

                                    // if have pattern and search ads
                                    if (matchingFileContent && SearchADSContent.ToBool())
                                    {

                                        // perform content search in ads if enabled

                                        // if include or not skip
                                        if (IncludeNonTextFileMatching ||
                                            !ExtensionsToSkip.Contains(
                                                Path.GetExtension(streamName)
                                            ))
                                        {
                                            FileContentMatchQueue.Enqueue(new FileInfo(adsPath));
                                            Interlocked.Increment(ref matchesQueued);
                                            AddWorkerTasksIfNeeded(token);
                                        }
                                        else if (UseVerboseOutput)
                                        {

                                            // enqueue skip ext
                                            VerboseQueue.Enqueue((
                                                "Skipping content search in ADS " +
                                                "due to extension filter: " +
                                                adsPath
                                            ));
                                        }

                                        continue;
                                    }

                                    // log found if verbose
                                    if (UseVerboseOutput)
                                    {

                                        // enqueue found
                                        VerboseQueue.Enqueue((
                                            "Found alternate data streams for: " + adsPath
                                        ));
                                    }

                                    // output ads info
                                    AddToOutputQueue(new FileInfo(adsPath));
                                }
                            }
                        }
                        while (FindNextStreamW(handle, ref streamData));
                    }
                }
                finally
                {

                    // close the find handle

                    // if valid handle
                    if (handle != IntPtr.Zero && handle != new IntPtr(-1))
                        FindClose(handle);
                }
            }
            catch (Exception ex)
            {

                // log error if verbose
                if (UseVerboseOutput)
                {

                    // enqueue error
                    VerboseQueue.Enqueue((
                        "Error processing ADS for " + FilePath + ": " +
                        ex.Message
                    ));

                    // log inner if present
                    if (ex.InnerException != null)
                    {

                        // enqueue inner
                        VerboseQueue.Enqueue((
                            "Inner exception: " + ex.InnerException.Message
                        ));
                    }
                }
            }

            // check cancel
            token.ThrowIfCancellationRequested();
        }

        /// <summary>
        /// Processes file content for pattern matching asynchronously.
        /// </summary>
        /// <remarks>
        /// This method performs content-based searching using:
        /// - Asynchronous stream processing for performance
        /// - Regex or simple pattern matching
        /// - Configurable encoding and context display
        /// - Thread-safe result queuing
        /// - Memory-efficient processing with object pooling
        ///
        /// Handles both match and not-match modes, with special logic
        /// for Quiet mode file-level inversion.
        /// </remarks>
        /// <param name="fileInfo">File path to process.</param>
        /// <param name="token">Cancellation token.</param>
        protected async Task FileContentProcessor(
            FileInfo fileInfo,
            CancellationToken token)
        {

            // early exit if cancellation requested
            if (token.IsCancellationRequested) return;

            bool found = false;
            MatchContentProcessor selectString = null;

            try
            {
                // update counter
                Interlocked.Increment(ref fileMatchesActive);
                Interlocked.Increment(ref fileMatchesStarted);

                if (!MatchContentProcessors.TryDequeue(out selectString))
                {
                    selectString = new MatchContentProcessor(
                            (int)baseMemoryPerWorker,
                            Content,
                            SimpleMatch.ToBool(),
                            AllMatches.ToBool(),
                            NotMatch.ToBool(),
                            CaseSensitive.ToBool(),
                            Encoding,
                            List.ToBool(),
                            Context,
                            Culture,
                            Quiet.ToBool(),
                            NoEmphasis.ToBool(),
                            token
                        );
                }

                await foreach (MatchInfo result in selectString.SearchAsync(fileInfo))
                {
                    found = true;

                    if (!Quiet.ToBool())
                    {
                        AddToOutputQueue(result);
                    }
                    else
                    {
                        break;
                    }
                }

                // Apply NotMatch inversion at file level for Quiet mode
                found = NotMatch.ToBool() ? !selectString.HasMatched : selectString.HasMatched;
            }
            catch (Exception e)
            {
                // log failure if verbose
                VerboseQueue.Enqueue((
                    "Failed to read file: " + fileInfo + "\r\n Error: " + e.Message + "\r\n" + e.TargetSite + "\r\n" + e.StackTrace + "\r\nSource:" + e.Source)
                );

                return;
            }
            finally
            {
                // update counter
                Interlocked.Decrement(ref fileMatchesActive);
                Interlocked.Increment(ref fileMatchesCompleted);

                if (selectString != null)
                {
                    MatchContentProcessors.Enqueue(selectString);
                }
            }

            if (!found || (NoLinks.ToBool() && !Quiet.ToBool())) return;

            // log match if verbose
            if (UseVerboseOutput)
            {
                // enqueue output
                VerboseQueue.Enqueue((
                    "Outputting file with pattern match: " + fileInfo
                ));
            }

            // enqueue output
            AddToOutputQueue(fileInfo);
        }

        /// <summary>
        /// Enumerates subdirectories matching patterns and handles recursion.
        /// </summary>
        /// <remarks>
        /// This method manages subdirectory enumeration with:
        /// - Pattern-based filtering of directory names
        /// - Recursive pattern handling (**)
        /// - UNC share enumeration for network paths
        /// - Thread-safe directory queuing
        /// - Dynamic worker scaling
        ///
        /// Supports both local directory enumeration and UNC network share
        /// discovery, with comprehensive error handling.
        /// </remarks>
        /// <param name="CurrentLocation">Location.</param>
        /// <param name="CurrentFileName">File mask.</param>
        /// <param name="RemainingNamePart">Remaining mask.</param>
        /// <param name="RemainingNameToRepeatWhenFound">Repeat mask.</param>
        /// <param name="uncMachineNameToEnumerate">UNC machine.</param>
        /// <param name="RecurseSubDirectories">Recurse.</param>
        /// <param name="NoMoreCustomWildcards">No wild.</param>
        /// <param name="HasLongPathPrefix">Long prefix.</param>
        /// <param name="IsUncPath">UNC.</param>
        /// <param name="token">Token.</param>
        void EnumerateSubDirectories(
        string CurrentLocation,
        string CurrentFileName,
        string RemainingNamePart,
        string RemainingNameToRepeatWhenFound,
        string uncMachineNameToEnumerate,
        bool RecurseSubDirectories,
        bool NoMoreCustomWildcards,
        bool HasLongPathPrefix,
        bool IsUncPath,
        CancellationToken token
        )
        {
            // adjust wildcards flag based on mask
            NoMoreCustomWildcards &= CurrentFileName == "*";

            // init found flag for subdirs
            var found = false;

            // create wildcard pattern matcher
            var patternMatcher = new WildcardPattern(
                EscapeBracketsInPattern(CurrentFileName),
                CurrentWildCardOptions);

            // set remaining full mask
            var remainingFull = RemainingNamePart;

            // handle leading recursive wildcard
            if (remainingFull.StartsWith("**\\"))
            {
                // trim recursive prefix
                remainingFull = remainingFull.Substring(3);

                // clear if no more wildcards or default
                if (NoMoreCustomWildcards || remainingFull == "*")
                {
                    // set to empty
                    remainingFull = "";
                }
            }

            // combine full pattern path
            var fullPattern = Path.Combine(CurrentLocation, remainingFull);

            // combine recursive pattern path
            var fullPatternRecurse = Path.Combine(CurrentLocation,
                RemainingNamePart);

            // add long path prefix if needed
            if (HasLongPathPrefix)
            {

                // handle unc paths
                if (IsUncPath)
                {

                    // escape and add unc prefix
                    fullPattern = WildcardPattern.Escape("\\\\?\\UNC") +
                        fullPattern.Substring(1);

                    // same for recurse
                    fullPatternRecurse = WildcardPattern.Escape("\\\\?\\UNC") +
                        fullPatternRecurse.Substring(1);
                }
                else
                {

                    // add local long prefix
                    fullPattern = WildcardPattern.Escape("\\\\?\\") + fullPattern;

                    // same for recurse
                    fullPatternRecurse = WildcardPattern.Escape("\\\\?\\") +
                        fullPatternRecurse;
                }
            }

            // create matcher for full pattern
            var patternMatcherFull = new WildcardPattern(
                EscapeBracketsInPattern(fullPattern),
                CurrentWildCardOptions);

            // create matcher for recursive full
            var patternMatcherFullRecurse = new WildcardPattern(
                EscapeBracketsInPattern(fullPatternRecurse),
                CurrentWildCardOptions);

            // handle unc share enumeration if machine specified
            if (!string.IsNullOrEmpty(uncMachineNameToEnumerate))
            {

                // split unc parts by semicolon
                var uncParts = uncMachineNameToEnumerate.Split(';');

                // set machine name
                uncMachineNameToEnumerate = uncParts[0];

                // set share name
                var shareName = uncParts[1];

                // log enumerating unc if verbose, showing network scan details
                if (UseVerboseOutput)
                {

                    // enqueue unc enumeration message
                    VerboseQueue.Enqueue((
                        "Enumerating unc networkshares for " +
                        uncMachineNameToEnumerate
                    ));
                }

                // create matcher for unc shares
                var uncShareMatcher = new WildcardPattern(
                    EscapeBracketsInPattern(shareName),
                    CurrentWildCardOptions);

                // list disk shares on unc machine
                var shares = ListDiskSharesUNC(uncMachineNameToEnumerate);

                // get remaining parts after skipping unc prefix
                var partsLeft = string.Join('\\', Path.Combine(CurrentLocation,
                    RemainingNamePart).Split('\\').Skip<string>(4).ToArray());

                // add backslash if parts left
                partsLeft = string.IsNullOrEmpty(partsLeft) ? string.Empty :
                    ('\\' + partsLeft);

                // process each share
                foreach (var share in shares)
                {

                    // skip if share does not match
                    if (!uncShareMatcher.IsMatch(share)) continue;

                    // build full name with prefix
                    string name = (HasLongPathPrefix ? (
                        "\\\\?\\UNC\\" + uncMachineNameToEnumerate + "\\" + share +
                        partsLeft
                    ) : (
                        "\\\\" + uncMachineNameToEnumerate + "\\" + share +
                        partsLeft
                    ));

                    // log queueing share if verbose
                    if (UseVerboseOutput)
                    {

                        // enqueue queueing message
                        VerboseQueue.Enqueue((
                            "Queueing networkshares: " + name
                        ));
                    }

                    // set found flag
                    found = true;

                    // Validate path when LimitToRoot is enabled
                    if (IsPathAllowed(name))
                    {
                        // enqueue the name to dir queue
                        DirQueue.Enqueue(name);

                        // increment queued count
                        Interlocked.Increment(ref dirsQueued);

                        // add worker tasks if needed
                        AddWorkerTasksIfNeeded(token);
                    }
                    else if (UseVerboseOutput)
                    {
                        VerboseQueue.Enqueue($"LimitToRoot: Blocked directory traversal to '{name}'");
                    }
                }
            }
            // enumerate directories matching the pattern
            else
            {

                // set enumeration options
                System.IO.EnumerationOptions options =
                    new System.IO.EnumerationOptions
                    {

                        // no automatic recursion
                        RecurseSubdirectories = false, // Handle recursion manually

                        // ignore inaccessible items
                        IgnoreInaccessible = true,

                        // set match casing
                        MatchCasing = CaseNameMatching
                    };

                // skip reparse points if not following symlinks
                if (!FollowSymlinkAndJunctions.ToBool())
                {

                    // set attributes to skip
                    options.AttributesToSkip = FileAttributes.ReparsePoint;
                }

                // enumerate directories with options
                foreach (var subDir in System.IO.Directory.EnumerateDirectories(
                    (IsUncPath ?
                        ("\\\\?\\UNC" + CurrentLocation.Substring(1)) :
                        ("\\\\?\\" + CurrentLocation)
                    ),
                    "*",
                    options
                )
             )
                {

                    // check for cancellation
                    token.ThrowIfCancellationRequested();

                    // set found flag
                    found = true;

                    // normalize subdirectory path
                    var normalizedSubDir = HasLongPathPrefix ? subDir :
                        NormalizePathForNonFileSystemUse(subDir);

                    // check if filename matches pattern
                    bool isMatch = patternMatcher.IsMatch(Path.GetFileName(
                        normalizedSubDir));

                    // handle recursion if recurse and match or wildcards remain
                    if (RecurseSubDirectories && (isMatch ||
                        !NoMoreCustomWildcards))
                    {

                        // select remaining mask based on match
                        var remaining = (isMatch ?
                            RemainingNameToRepeatWhenFound :
                            RemainingNamePart);

                        // default to * if empty
                        if (string.IsNullOrEmpty(remaining))
                        {

                            // set default
                            remaining = "*";
                        }

                        // log queueing subdir if verbose, showing remaining parts
                        if (UseVerboseOutput)
                        {

                            // enqueue queueing message
                            VerboseQueue.Enqueue((
                                "Queuing subdirectory for processing: " +
                                normalizedSubDir + " with remaining parts: " +
                                remaining
                            ));
                        }

                        var combinedPath = Path.Combine(normalizedSubDir, remaining);

                        // Validate path when LimitToRoot is enabled
                        if (IsPathAllowed(combinedPath))
                        {
                            DirQueue.Enqueue(combinedPath);

                            Interlocked.Increment(ref dirsQueued);

                            AddWorkerTasksIfNeeded(token);
                        }
                        else if (UseVerboseOutput)
                        {
                            VerboseQueue.Enqueue($"LimitToRoot: Blocked directory traversal to '{combinedPath}'");
                        }
                    }
                    else
                    {
                        // log queueing subdir if verbose, showing remaining parts
                        if (UseVerboseOutput)
                        {

                            // enqueue queueing message
                            VerboseQueue.Enqueue((
                                "Skipping subdirectory for processing: " +
                                normalizedSubDir + " with remaining parts: " +
                                RemainingNamePart
                            ));
                        }
                    }

                    // check full pattern match
                    bool isMatch1 = patternMatcherFull.IsMatch(normalizedSubDir);

                    // check recursive full match
                    bool isMatch2 = patternMatcherFullRecurse.IsMatch(
                        normalizedSubDir);

                    // combine match results
                    isMatch = isMatch1 || isMatch2;

                    // output if searching directories or both
                    if ((Directory.ToBool() || FilesAndDirectories.ToBool()) &&
                        isMatch)
                    {

                        // init exclusion flag
                        bool haveExclusion = false;

                        // check each exclude pattern
                        foreach (var pattern in DirectoryExcludePatterns)
                        {

                            // set exclusion if matches
                            if (pattern.IsMatch(normalizedSubDir))
                            {

                                // set flag
                                haveExclusion = true;

                                // log exclusion if verbose
                                if (UseVerboseOutput)
                                {

                                    // enqueue exclusion message
                                    VerboseQueue.Enqueue((
                                        "Excluding file " + normalizedSubDir +
                                        " due to pattern " + pattern
                                    ));
                                }

                                // break loop
                                break;
                            }
                        }

                        // skip if excluded
                        if (haveExclusion)
                        {

                            // log skip if verbose, explaining exclusion
                            if (UseVerboseOutput)
                            {

                                // enqueue skip message
                                VerboseQueue.Enqueue((
                                    "Skipping directory " + normalizedSubDir +
                                    " due to exclusion patterns"
                                ));
                            }

                            // continue to next
                            continue;
                        }

                        // log outputting if verbose
                        if (UseVerboseOutput)
                        {

                            // enqueue output message
                            VerboseQueue.Enqueue((
                                "Outputting directory: " + normalizedSubDir
                            ));
                        }

                        // enqueue directory info
                        AddToOutputQueue(new DirectoryInfo(normalizedSubDir));
                    }
                }
            }

            // log no subdirs found if verbose and none found
            if (!found && UseVerboseOutput)
            {

                // enqueue no found message, helping user see empty results
                VerboseQueue.Enqueue((
                    "No subdirectories found in: " + CurrentLocation +
                    " matching pattern: " + CurrentFileName
                ));
            }
        }
    }
}