private bool SearchEntriesSingle(SearchParameters spIn,
                                         PwObjectList <PwEntry> listStorage, IDictionary <PwUuid, KeyValuePair <string, string> > resultContexts,
                                         IStatusLogger slStatus,
                                         ref ulong uCurEntries, ulong uTotalEntries)
        {
            SearchParameters sp = spIn.Clone();

            if (sp.SearchString == null)
            {
                Debug.Assert(false);
                return(true);
            }

            sp.SearchString = sp.SearchString.Trim();

            bool bTitle          = sp.SearchInTitles;
            bool bUserName       = sp.SearchInUserNames;
            bool bPassword       = sp.SearchInPasswords;
            bool bUrl            = sp.SearchInUrls;
            bool bNotes          = sp.SearchInNotes;
            bool bOther          = sp.SearchInOther;
            bool bUuids          = sp.SearchInUuids;
            bool bGroupName      = sp.SearchInGroupNames;
            bool bTags           = sp.SearchInTags;
            bool bExcludeExpired = sp.ExcludeExpired;
            bool bRespectEntrySearchingDisabled = sp.RespectEntrySearchingDisabled;

            DateTime dtNow = DateTime.Now;

            Regex rx = null;

            if (sp.RegularExpression)
            {
                RegexOptions ro = RegexOptions.None; // RegexOptions.Compiled
                if ((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) ||
#if !KeePassUAP
                    (sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) ||
#endif
                    (sp.ComparisonMode == StringComparison.OrdinalIgnoreCase))
                {
                    ro |= RegexOptions.IgnoreCase;
                }

                rx = new Regex(sp.SearchString, ro);
            }

            ulong uLocalCurEntries = uCurEntries;

            EntryHandler eh = null;
            if (sp.SearchString.Length <= 0) // Report all
            {
                eh = delegate(PwEntry pe)
                {
                    if (slStatus != null)
                    {
                        if (!slStatus.SetProgress((uint)((uLocalCurEntries *
                                                          100UL) / uTotalEntries)))
                        {
                            return(false);
                        }
                        ++uLocalCurEntries;
                    }

                    if (bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled())
                    {
                        return(true); // Skip
                    }
                    if (bExcludeExpired && pe.Expires && (dtNow > pe.ExpiryTime))
                    {
                        return(true); // Skip
                    }
                    listStorage.Add(pe);
                    return(true);
                };
            }
            else
            {
                eh = delegate(PwEntry pe)
                {
                    if (slStatus != null)
                    {
                        if (!slStatus.SetProgress((uint)((uLocalCurEntries *
                                                          100UL) / uTotalEntries)))
                        {
                            return(false);
                        }
                        ++uLocalCurEntries;
                    }

                    if (bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled())
                    {
                        return(true); // Skip
                    }
                    if (bExcludeExpired && pe.Expires && (dtNow > pe.ExpiryTime))
                    {
                        return(true); // Skip
                    }
                    uint uInitialResults = listStorage.UCount;

                    foreach (KeyValuePair <string, ProtectedString> kvp in pe.Strings)
                    {
                        string strKey = kvp.Key;

                        if (strKey == PwDefs.TitleField)
                        {
                            if (bTitle)
                            {
                                SearchEvalAdd(sp, kvp.Value.ReadString(),
                                              rx, pe, listStorage, resultContexts, strKey);
                            }
                        }
                        else if (strKey == PwDefs.UserNameField)
                        {
                            if (bUserName)
                            {
                                SearchEvalAdd(sp, kvp.Value.ReadString(),
                                              rx, pe, listStorage, resultContexts, strKey);
                            }
                        }
                        else if (strKey == PwDefs.PasswordField)
                        {
                            if (bPassword)
                            {
                                SearchEvalAdd(sp, kvp.Value.ReadString(),
                                              rx, pe, listStorage, resultContexts, strKey);
                            }
                        }
                        else if (strKey == PwDefs.UrlField)
                        {
                            if (bUrl)
                            {
                                SearchEvalAdd(sp, kvp.Value.ReadString(),
                                              rx, pe, listStorage, resultContexts, strKey);
                            }
                        }
                        else if (strKey == PwDefs.NotesField)
                        {
                            if (bNotes)
                            {
                                SearchEvalAdd(sp, kvp.Value.ReadString(),
                                              rx, pe, listStorage, resultContexts, strKey);
                            }
                        }
                        else if (bOther)
                        {
                            SearchEvalAdd(sp, kvp.Value.ReadString(),
                                          rx, pe, listStorage, resultContexts, strKey);
                        }

                        // An entry can match only once => break if we have added it
                        if (listStorage.UCount > uInitialResults)
                        {
                            break;
                        }
                    }

                    if (bUuids && (listStorage.UCount == uInitialResults))
                    {
                        SearchEvalAdd(sp, pe.Uuid.ToHexString(), rx, pe, listStorage, resultContexts,
                                      SearchContextTags);
                    }

                    if (bGroupName && (listStorage.UCount == uInitialResults) &&
                        (pe.ParentGroup != null))
                    {
                        SearchEvalAdd(sp, pe.ParentGroup.Name, rx, pe, listStorage, resultContexts,
                                      SearchContextParentGroup);
                    }

                    if (bTags)
                    {
                        foreach (string strTag in pe.Tags)
                        {
                            if (listStorage.UCount != uInitialResults)
                            {
                                break;                                        // Match
                            }
                            SearchEvalAdd(sp, strTag, rx, pe, listStorage, resultContexts, SearchContextTags);
                        }
                    }

                    return(true);
                };
            }

            if (!PreOrderTraverseTree(null, eh))
            {
                return(false);
            }
            uCurEntries = uLocalCurEntries;
            return(true);
        }
        private void SrsmSearch(SearchParameters sp, PwObjectList <PwEntry> lResults,
                                IStatusLogger sl)
        {
            PwObjectList <PwEntry> lAll = GetEntries(true);
            DateTime dtNow = DateTime.UtcNow;

            List <PwEntry> l = new List <PwEntry>();

            foreach (PwEntry pe in lAll)
            {
                if (sp.ExcludeExpired && pe.Expires && (pe.ExpiryTime <= dtNow))
                {
                    continue;
                }
                if (sp.RespectEntrySearchingDisabled && !pe.GetSearchingEnabled())
                {
                    continue;
                }

                l.Add(pe);
            }

            List <string> lTerms;

            if (sp.SearchMode == PwSearchMode.Simple)
            {
                lTerms = StrUtil.SplitSearchTerms(sp.SearchString);
            }
            else
            {
                lTerms = new List <string>();
                lTerms.Add(sp.SearchString);
            }

            // Search longer strings first (for improved performance)
            lTerms.Sort(StrUtil.CompareLengthGt);

            SearchParameters spSub = sp.Clone();

            for (int iTerm = 0; iTerm < lTerms.Count; ++iTerm)
            {
                string strTerm = lTerms[iTerm];                 // No trim
                if (string.IsNullOrEmpty(strTerm))
                {
                    continue;
                }

                bool bNegate = false;
                if ((sp.SearchMode == PwSearchMode.Simple) &&
                    (strTerm.Length >= 2) && (strTerm[0] == '-'))
                {
                    strTerm = strTerm.Substring(1);
                    bNegate = true;
                }

                spSub.SearchString = strTerm;

                ulong uStEntriesDone = (ulong)iTerm * (ulong)l.Count;
                ulong uStEntriesMax  = (ulong)lTerms.Count * (ulong)l.Count;

                List <PwEntry> lOut;
                if (!SrsmSearchSingle(spSub, l, out lOut, sl, uStEntriesDone,
                                      uStEntriesMax))
                {
                    l.Clear();                     // Do not return non-matching entries
                    break;
                }

                if (bNegate)
                {
                    List <PwEntry> lNew = new List <PwEntry>();
                    int            iNeg = 0;

                    foreach (PwEntry pe in l)
                    {
                        if ((iNeg < lOut.Count) && object.ReferenceEquals(lOut[iNeg], pe))
                        {
                            ++iNeg;
                        }
                        else
                        {
                            Debug.Assert(!lOut.Contains(pe));
                            lNew.Add(pe);
                        }
                    }
                    Debug.Assert(lNew.Count == (l.Count - lOut.Count));

                    l = lNew;
                }
                else
                {
                    l = lOut;
                }
            }

            lResults.Add(l);
        }