-/////////////////////////////////////////////////////////////////////////////
-// License (GPLv2+):
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2 of the License, or (at your
-// option) any later version.
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-/////////////////////////////////////////////////////////////////////////////
+// SPDX-License-Identifier: GPL-2.0-or-later
/**
* @file FileFilterMgr.cpp
*
* @brief Implementation of FileFilterMgr and supporting routines
*/
+#include "pch.h"
#include "FileFilterMgr.h"
#include <vector>
#include <Poco/String.h>
#include <Poco/Glob.h>
-#include <Poco/DirectoryIterator.h>
#include <Poco/RegularExpression.h>
+#include "DirTravel.h"
+#include "DirItem.h"
#include "UnicodeString.h"
#include "FileFilter.h"
#include "UniFile.h"
#include "paths.h"
using std::vector;
-using Poco::DirectoryIterator;
using Poco::Glob;
using Poco::icompare;
using Poco::RegularExpression;
-static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String & str);
+static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String & str, bool fileFilter);
/**
* @brief Destructor, frees all filters.
{
int errorcode = FILTER_OK;
FileFilter * pFilter = LoadFilterFile(szFilterFile, errorcode);
- if (pFilter)
+ if (pFilter != nullptr)
m_filters.push_back(FileFilterPtr(pFilter));
return errorcode;
}
*/
void FileFilterMgr::LoadFromDirectory(const String& dir, const String& szPattern, const String& szExt)
{
- const std::string u8ext = ucr::toUTF8(szExt);
- const size_t extlen = u8ext.length();
-
try
{
- DirectoryIterator it(ucr::toUTF8(dir));
- DirectoryIterator end;
+ DirItemArray dirs, files;
+ LoadAndSortFiles(dir, &dirs, &files, false);
Glob glb(ucr::toUTF8(szPattern));
- for (; it != end; ++it)
+ for (DirItem& item: files)
{
- if (it->isDirectory())
- continue;
- std::string filename = it.name();
- if (!glb.match(filename))
+ String filename = item.filename;
+ if (!glb.match(ucr::toUTF8(filename)))
continue;
- if (extlen)
+ if (!szExt.empty())
{
// caller specified a specific extension
// (This is really a workaround for brokenness in windows, which
// doesn't screen correctly on extension in pattern)
- std::string ext = filename.substr(filename.length() - extlen);
- if (icompare(u8ext, ext) != 0)
+ const String ext = filename.substr(filename.length() - szExt.length());
+ if (strutils::compare_nocase(szExt, ext) != 0)
return;
}
- String filterpath = paths_ConcatPath(dir, ucr::toTString(filename));
+ String filterpath = paths::ConcatPath(dir, filename);
AddFilter(filterpath);
}
}
vector<FileFilterPtr>::iterator iter = m_filters.begin();
while (iter != m_filters.end())
{
- if (string_compare_nocase((*iter)->fullpath, szFilterFile) == 0)
+ if (strutils::compare_nocase((*iter)->fullpath, szFilterFile) == 0)
{
m_filters.erase(iter);
break;
* @param [in] filterList List where pattern is added.
* @param [in] str Temporary variable (ie, it may be altered)
*/
-static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String & str)
+static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String & str, bool fileFilter)
{
const String& commentLeader = _T("##"); // Starts comment
- str = string_trim_ws_begin(str);
+ str = strutils::trim_ws_begin(str);
// Ignore lines beginning with '##'
size_t pos = str.find(commentLeader);
// Remove comment and whitespaces before it
if (pos != std::string::npos)
str = str.substr(0, pos);
- str = string_trim_ws_end(str);
+ str = strutils::trim_ws_end(str);
if (str.empty())
return;
re_opts |= RegularExpression::RE_UTF8;
try
{
- filterList->push_back(FileFilterElementPtr(new FileFilterElement(regexString, re_opts)));
+ filterList->push_back(FileFilterElementPtr(new FileFilterElement(regexString, re_opts, fileFilter)));
}
catch (...)
{
* @brief Parse a filter file, and add it to array if valid.
*
* @param [in] szFilePath Path (w/ filename) to file to load.
- * @param [out] error Error-code if loading failed (returned NULL).
- * @return Pointer to new filter, or NULL if error (check error code too).
+ * @param [out] error Error-code if loading failed (returned `nullptr`).
+ * @return Pointer to new filter, or `nullptr` if error (check error code too).
*/
FileFilter * FileFilterMgr::LoadFilterFile(const String& szFilepath, int & error)
{
if (!file.OpenReadOnly(szFilepath))
{
error = FILTER_ERROR_FILEACCESS;
- return NULL;
+ return nullptr;
}
file.ReadBom(); // in case it is a Unicode file, let UniMemFile handle BOM
+ if (!file.IsUnicode() && !ucr::CheckForInvalidUtf8(
+ reinterpret_cast<const char*>(file.GetBase()), static_cast<size_t>(file.GetFileSize())))
+ file.SetUnicoding(ucr::UTF8);
String fileName;
- paths_SplitFilename(szFilepath, NULL, &fileName, NULL);
+ paths::SplitFilename(szFilepath, nullptr, &fileName, nullptr);
FileFilter *pfilter = new FileFilter;
pfilter->fullpath = szFilepath;
- pfilter->name = fileName; // Filename is the default name
+ pfilter->name = std::move(fileName); // Filename is the default name
String sLine;
bool lossy = false;
// Returns false when last line is read
String tmpLine;
bLinesLeft = file.ReadString(tmpLine, &lossy);
- sLine = tmpLine;
- sLine = string_trim_ws(sLine);
+ sLine = std::move(tmpLine);
+ sLine = strutils::trim_ws(sLine);
if (0 == sLine.compare(0, 5, _T("name:"), 5))
{
// specifies display name
String str = sLine.substr(5);
- str = string_trim_ws_begin(str);
+ str = strutils::trim_ws_begin(str);
if (!str.empty())
- pfilter->name = str;
+ pfilter->name = std::move(str);
}
else if (0 == sLine.compare(0, 5, _T("desc:"), 5))
{
// specifies display name
String str = sLine.substr(5);
- str = string_trim_ws_begin(str);
+ str = strutils::trim_ws_begin(str);
if (!str.empty())
- pfilter->description = str;
+ pfilter->description = std::move(str);
}
else if (0 == sLine.compare(0, 4, _T("def:"), 4))
{
// specifies default
String str = sLine.substr(4);
- str = string_trim_ws_begin(str);
+ str = strutils::trim_ws_begin(str);
if (str == _T("0") || str == _T("no") || str == _T("exclude"))
pfilter->default_include = false;
else if (str == _T("1") || str == _T("yes") || str == _T("include"))
{
// file filter
String str = sLine.substr(2);
- AddFilterPattern(&pfilter->filefilters, str);
+ AddFilterPattern(&pfilter->filefilters, str, true);
}
else if (0 == sLine.compare(0, 2, _T("d:"), 2))
{
// directory filter
String str = sLine.substr(2);
- AddFilterPattern(&pfilter->dirfilters, str);
+ AddFilterPattern(&pfilter->dirfilters, str, false);
+ }
+ else if (0 == sLine.compare(0, 3, _T("f!:"), 3))
+ {
+ // file filter
+ String str = sLine.substr(3);
+ AddFilterPattern(&pfilter->filefiltersExclude, str, true);
+ }
+ else if (0 == sLine.compare(0, 3, _T("d!:"), 3))
+ {
+ // directory filter
+ String str = sLine.substr(3);
+ AddFilterPattern(&pfilter->dirfiltersExclude, str, false);
}
} while (bLinesLeft);
* @brief Give client back a pointer to the actual filter.
*
* @param [in] szFilterPath Full path to filterfile.
- * @return Pointer to found filefilter or NULL;
+ * @return Pointer to found filefilter or `nullptr`;
* @note We just do a linear search, because this is seldom called
*/
FileFilter * FileFilterMgr::GetFilterByPath(const String& szFilterPath)
vector<FileFilterPtr>::const_iterator iter = m_filters.begin();
while (iter != m_filters.end())
{
- if (string_compare_nocase((*iter)->fullpath, szFilterPath) == 0)
+ if (strutils::compare_nocase((*iter)->fullpath, szFilterPath) == 0)
return (*iter).get();
++iter;
}
}
/**
+ * @brief Give client back a pointer to the actual filter.
+ *
+ * @param [in] i Index of filter.
+ * @return Pointer to filefilter in given index or `nullptr`.
+ */
+FileFilter * FileFilterMgr::GetFilterByIndex(int i)
+{
+ if (i < 0 || i >= m_filters.size())
+ return nullptr;
+
+ return m_filters[i].get();
+}
+
+/**
* @brief Test given string against given regexp list.
*
* @param [in] filterList List of regexps to test against.
if (filterList->size() == 0)
return false;
- std::string compString;
+ std::string compString, compStringFileName;
ucr::toUTF8(szTest, compString);
vector<FileFilterElementPtr>::const_iterator iter = filterList->begin();
while (iter != filterList->end())
RegularExpression::Match match;
try
{
- if ((*iter)->regexp.match(compString, 0, match) > 0)
+ if ((*iter)->_fileNameOnly && compStringFileName.empty())
+ ucr::toUTF8(paths::FindFileName(szTest), compStringFileName);
+ if ((*iter)->regexp.match((*iter)->_fileNameOnly ? compStringFileName : compString, 0, match) > 0)
return true;
}
catch (...)
bool FileFilterMgr::TestFileNameAgainstFilter(const FileFilter * pFilter,
const String& szFileName) const
{
- if (!pFilter)
+ if (pFilter == nullptr)
return true;
if (TestAgainstRegList(&pFilter->filefilters, szFileName))
- return !pFilter->default_include;
+ {
+ if (pFilter->filefiltersExclude.empty() || !TestAgainstRegList(&pFilter->filefiltersExclude, szFileName))
+ return !pFilter->default_include;
+ }
return pFilter->default_include;
}
bool FileFilterMgr::TestDirNameAgainstFilter(const FileFilter * pFilter,
const String& szDirName) const
{
- if (!pFilter)
+ if (pFilter == nullptr)
return true;
if (TestAgainstRegList(&pFilter->dirfilters, szDirName))
- return !pFilter->default_include;
+ {
+ if (pFilter->dirfiltersExclude.empty() || !TestAgainstRegList(&pFilter->dirfiltersExclude, szDirName))
+ return !pFilter->default_include;
+ }
return pFilter->default_include;
}
/**
- * @brief Return name of filter.
- *
- * @param [in] i Index of filter.
- * @return Name of filter in given index.
- */
-String FileFilterMgr::GetFilterName(int i) const
-{
- return m_filters[i]->name;
-}
-
-/**
- * @brief Return name of filter.
- * @param [in] pFilter Filter to get name for.
- * @return Given filter's name.
- */
-String FileFilterMgr::GetFilterName(const FileFilter *pFilter) const
-{
- return pFilter->name;
-}
-
-/**
- * @brief Return description of filter.
- *
- * @param [in] i Index of filter.
- * @return Description of filter in given index.
- */
-String FileFilterMgr::GetFilterDesc(int i) const
-{
- return m_filters[i]->description;
-}
-
-/**
- * @brief Return description of filter.
- * @param [in] pFilter Filter to get description for.
- * @return Given filter's description.
- */
-String FileFilterMgr::GetFilterDesc(const FileFilter *pFilter) const
-{
- return pFilter->description;
-}
-
-/**
- * @brief Return full path to filter.
- *
- * @param [in] i Index of filter.
- * @return Full path of filter in given index.
- */
-String FileFilterMgr::GetFilterPath(int i) const
-{
- return m_filters[i]->fullpath;
-}
-
-/**
- * @brief Return full path to filter.
- *
- * @param [in] pFilter Pointer to filter.
- * @return Full path of filter.
- */
-String FileFilterMgr::GetFullpath(FileFilter * pfilter) const
-{
- return pfilter->fullpath;
-}
-
-/**
* @brief Reload filter from disk
*
* Reloads filter from disk. This is done by creating a new one
int errorcode = FILTER_OK;
FileFilter * newfilter = LoadFilterFile(pfilter->fullpath, errorcode);
- if (newfilter == NULL)
+ if (newfilter == nullptr)
{
return errorcode;
}
errorcode = FILTER_NOTFOUND;
return errorcode;
}
+
+/**
+ * @brief Clone file filter manager from another file filter Manager.
+ * This function clones file filter manager from another file filter manager.
+ * Current contents in the file filter manager are removed and new contents added from the given file filter manager.
+ * @param [in] fileFilterManager File filter manager to clone.
+ */
+void FileFilterMgr::CloneFrom(const FileFilterMgr* fileFilterMgr)
+{
+ if (!fileFilterMgr)
+ return;
+
+ m_filters.clear();
+
+ size_t count = fileFilterMgr->m_filters.size();
+ for (size_t i = 0; i < count; i++)
+ {
+ auto ptr = std::make_shared<FileFilter>(FileFilter());
+ ptr->CloneFrom(fileFilterMgr->m_filters[i].get());
+ m_filters.push_back(ptr);
+ }
+}