public void DetectKnownFrameworksAndFilterPaths(ref string[] sources, ref string[] headers, ref string[] includeDirs, ref string[] preprocesorMacros, ref VendorSampleRelocator.ParsedDependency[] dependencies, HashSet <string> frameworks, Dictionary <string, string> requestedConfiguration)
        {
            var sourceList  = sources?.ToList() ?? new List <string>();
            var headerList  = headers?.ToList() ?? new List <string>();
            var includeList = includeDirs?.ToList() ?? new List <string>();
            var macroList   = preprocesorMacros?.ToList() ?? new List <string>();

            var dependencyList = dependencies.Select(d => d.MappedFile).ToList();

            MatchingFlags flags = MatchingFlags.None;

            var frameworkObjects = new HashSet <FrameworkReference>();

            LocateAndRemoveMatchingEntries(sourceList, _ConfigurationByFile, requestedConfiguration, frameworkObjects, ref flags);
            LocateAndRemoveMatchingEntries(macroList, _ConfigurationByMacro, requestedConfiguration, frameworkObjects, ref flags);

            LocateAndRemoveMatchingEntries(headerList, _ConfigurationByFile, requestedConfiguration, frameworkObjects, ref flags, ObjectMatchingMode.MatchIfConfigurationMatches);
            LocateAndRemoveMatchingEntries(dependencyList, _ConfigurationByFile, requestedConfiguration, frameworkObjects, ref flags, ObjectMatchingMode.MatchIfConfigurationMatches);

            LocateAndRemoveMatchingEntries(includeList, _ConfigurationByIncludeDir, requestedConfiguration, frameworkObjects, ref flags, ObjectMatchingMode.MatchIfConfigurationMatches);

            for (int i = 0; i < macroList.Count; i++)
            {
                bool match = false;
                foreach (var rule in _FreeFormMacros)
                {
                    var m = rule.Regex.Match(macroList[i]);
                    if (m.Success)
                    {
                        if (requestedConfiguration.TryGetValue(rule.VariableName, out string oldValue) && oldValue != m.Groups[1].Value)
                        {
                            flags |= MatchingFlags.FoundInconsistencies;
                            continue;
                        }

                        requestedConfiguration[rule.VariableName] = m.Groups[1].Value;
                        match = true;
                        break;
                    }
                }

                if (match)
                {
                    macroList.RemoveAt(i--);
                }
            }

            if (((flags & MatchingFlags.FoundItems) != MatchingFlags.None) &&
                ((flags & MatchingFlags.FoundInconsistencies) == MatchingFlags.None))
            {
                //No inconsistencies found. We can attach the discovered frameworks to the sample.
                sources           = sourceList.ToArray();
                headers           = headerList.ToArray();
                preprocesorMacros = macroList.ToArray();
                includeDirs       = includeList.ToArray();

                foreach (var fwObj in frameworkObjects)
                {
                    frameworks.Add(fwObj.ID);
                    foreach (var kv in fwObj.MinimalConfiguration ?? new SysVarEntry[0])
                    {
                        //Unless a configuration value was explicitly detected from the macros/files, set it to 'disabled' (that might be different from the GUI default).
                        //This ensures that each vendor sample excludes the conditional items that were present in the original vendor sample, even if they are enabled by default.
                        if (!requestedConfiguration.ContainsKey(kv.Key))
                        {
                            requestedConfiguration[kv.Key] = kv.Value;
                        }
                    }
                }

                var dependencySet = new HashSet <string>();
                foreach (var dep in dependencyList)
                {
                    dependencySet.Add(dep);
                }

                dependencies = dependencies.Where(d => dependencySet.Contains(d.MappedFile)).ToArray();
            }
        }
        static void LocateAndRemoveMatchingEntries(List <string> items,
                                                   Dictionary <string, RequestedConfiguration> rules,
                                                   Dictionary <string, string> requestedConfiguration,
                                                   HashSet <FrameworkReference> frameworks,
                                                   ref MatchingFlags flags,
                                                   ObjectMatchingMode mode = ObjectMatchingMode.MatchAndUpdateConfiguration)
        {
            for (int i = 0; i < items.Count; i++)
            {
                if (!rules.TryGetValue(items[i], out var rule))
                {
                    continue;
                }

                flags |= MatchingFlags.FoundItems;

                if (rule.Framework != null)
                {
                    if (mode == ObjectMatchingMode.MatchIfConfigurationMatches)
                    {
                        //We are matching the secondary objects (e.g. headers).
                        //If the framework (and configuration) providing them is already pulled, just remove the file from the list.
                        //If not, don't remove it and don't pull the framework.
                        if (!frameworks.Contains(rule.Framework))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        frameworks.Add(rule.Framework);
                    }
                }

                bool skip = false;

                foreach (var entry in rule.Configuration ?? new SysVarEntry[0])
                {
                    if (mode == ObjectMatchingMode.MatchIfConfigurationMatches)
                    {
                        if (!requestedConfiguration.TryGetValue(entry.Key, out string oldValue) || oldValue != entry.Value)
                        {
                            //This is a secondary object (e.g. header file) and it won't be normally pulled by the current configuration.
                            //Keep an explicit reference to it.
                            skip = true;
                        }
                    }
                    else
                    {
                        if (requestedConfiguration.TryGetValue(entry.Key, out string oldValue) && oldValue != entry.Value)
                        {
                            flags |= MatchingFlags.FoundInconsistencies;
                            continue;
                        }

                        requestedConfiguration[entry.Key] = entry.Value;
                    }
                }

                if (!skip)
                {
                    items.RemoveAt(i--);
                }
            }
        }
        private MatchingFlags CreateMatchTypeMenu(
            MatchingFlags MatchFlags)
        {
            MatchingFlags FirstFlag = 0;

            // Count the single bit matching options and dynamically create the menus
            foreach (MatchingFlags fl in Enum.GetValues(typeof(MatchingFlags)))
            {
                if (!MatchFlags.HasFlag(fl))
                    continue;

                // Skip multiflag options
                if (Sys.Utils.CountSetBits((long)fl) > 1)
                    continue;

                // Create the menu item
                var menu = new ToolStripMenuItem()
                {
                    Text = fl.ToString(),
                    Tag = fl,
                };

                // Menu handler is generic
                menu.Click += ctxmenuMatchTypeClick;
                ctxmenuMatchOptions.Items.Add(menu);

                // Remember the first default option
                if (FirstFlag == 0)
                    FirstFlag = fl;
            }
            return FirstFlag;
        }
        private bool SetMatchMenu(MatchingFlags CurMatch)
        {
            bool bFound = false;

            // Uncheck all other items but the current one.
            foreach (ToolStripMenuItem mi in ctxmenuMatchOptions.Items)
            {
                if ((MatchingFlags)mi.Tag == CurMatch)
                {
                    mi.Checked = true;
                    bFound = true;
                }
                else
                {
                    mi.Checked = false;
                }
            }

            m_Filter.MatchType = CurMatch;
            return bFound;
        }
        public StringsPicker(
            string [] Items,
            bool MultiSelect = false,
            string Title = null,
            bool AllowAddItems = false,
            bool AllowFilter = true,
            string FreeStyleValuesCaption = null,
            bool InstantFilter = true,
            bool SingleColumnList = false,
            bool UseBasicLVExtensions = true,
            int Width = -1,
            int Height = -1,
            MatchingFlags MatchFlags = MatchingFlags.Basic,
            MatchingFlags DefaultMatchFlag = 0)
        {
            InitializeComponent();

            // Multiselect option means: enable checkboxes
            lvItems.MultiSelect = false;
            lvItems.CheckBoxes = MultiSelect;

            // Set instant filter
            this.InstantFilter = InstantFilter;

            // Override the title if given
            if (!string.IsNullOrEmpty(Title))
                Text = Title;

            // Create match options menu
            var FirstFlag = CreateMatchTypeMenu(MatchFlags);
            if (!SetMatchMenu(DefaultMatchFlag))
                SetMatchMenu(FirstFlag);

            bool AllowFreeStyleValues = !string.IsNullOrEmpty(FreeStyleValuesCaption);

            if (AllowFreeStyleValues)
                lblFreeStyleValues.Text = FreeStyleValuesCaption;

            //
            // Re-layout the needed controls
            //
            LayoutControls(
                AllowAddItems,
                AllowFilter,
                AllowFreeStyleValues);

            m_Filter.Items = new ItemsCache(Items);

            // Enable single columns by changing the view style to "Details"
            if (SingleColumnList)
            {
                lvItems.View = View.Details;
                lvItems.HeaderStyle = ColumnHeaderStyle.None;
                lvItems.Columns.Add(new ColumnHeader()
                {
                    Text = "Items"
                });
            }

            // Pass dimensions. Those dimensions are passed to the LV, howver since
            // the form and the layout containers are autosize, then everything will shrink or grow accordingly
            if (Width != -1)
                pnlLV.Width = Width;

            if (Height != -1)
                pnlLV.Height = Height;

            //
            // Enable LV extensions
            //
            if (UseBasicLVExtensions)
            {
                ListViewExtensions.CreateCommonMenuItems(
                    ctxmenuLV,
                    lvItems,
                    new ListViewExtensions.Options()
                    {
                        MFlags = ListViewExtensions.MenuFlags.Find | ListViewExtensions.MenuFlags.CopyAndSelect
                    }
                );
            }
        }