#include "mainwindow.hpp"
#include "filefinder.hpp"
+/**
+ * Constructor.
+ */
FileFinder::FileFinder() :
m_lines(0),
m_patterns(),
m_countFiles(0),
m_countDirs(0),
m_bytes(0),
- m_excludedDirs()
-{
+ m_excludedDirs(){
m_youngerThan.setMSecsSinceEpoch(0);
m_olderThan.setMSecsSinceEpoch(0);
}
QString typeOf(QFileInfo& info){
QString rc;
if (info.isSymLink()){
- if (info.isDir())
- rc = QObject::tr("link (dir)");
- else
- rc = QObject::tr("link (file)");
- } else if (info.isDir())
+ if (info.isDir())
+ rc = QObject::tr("link (dir)");
+ else
+ rc = QObject::tr("link (file)");
+ }else if (info.isDir())
rc = QObject::tr("dir");
else
rc = QObject::tr("file");
QDir dir(path);
QDir::Filters filters = m_fileTypes | QDir::NoDotAndDotDot;
if (m_patterns.count() == 0)
- entries = dir.entryInfoList(filters, QDir::NoSort);
- else
- entries = dir.entryInfoList(m_patterns, filters, QDir::NoSort);
+ entries = dir.entryInfoList(filters, QDir::NoSort);
+ else
+ entries = dir.entryInfoList(m_patterns, filters, QDir::NoSort);
QList <QFileInfo>::iterator it;
QString relativePath = path.mid(1 + m_baseDir.length());
QString node, ext;
bool filtered = m_excludedDirs.length() > 0;
for (it = entries.begin(); it != entries.end(); ++it){
QString node = it->fileName();
- if (! filtered || !isExcludedDir(node))
- fillTable(path + QDir::separator() + node, depth + 1, table);
+ if (!filtered || !isExcludedDir(node))
+ fillTable(path + QDir::separator() + node, depth + 1, table);
}
}
table->setRowCount(m_lines);
* @return <code>true</code>: the node is part of the excluded dirs
*/
bool FileFinder::isExcludedDir(const QString& node){
- bool rc = false;
- QList <QString>::iterator it;
- for (it = m_excludedDirs.begin(); it != m_excludedDirs.end(); ++it){
- if (QString::compare(node, *it, Qt::CaseInsensitive) == 0){
- rc = true;
- break;
- }
- }
- return rc;
+ bool rc = false;
+ QList <QString>::iterator it;
+ for (it = m_excludedDirs.begin(); it != m_excludedDirs.end(); ++it){
+ if (QString::compare(node, *it, Qt::CaseInsensitive) == 0){
+ rc = true;
+ break;
+ }
+ }
+ return rc;
}
/**
* @param baseDir the directory where the search starts
*/
void FileFinder::setBaseDir(const QString& baseDir){
- m_baseDir = baseDir;
+ m_baseDir = baseDir;
}
/**
* Sets the list of excluded directories.
* @param excludedDirs each entry of this list will not be entered for search
*/
-void FileFinder::setExcludedDirs(const QStringList& excludedDirs)
-{
- m_excludedDirs = excludedDirs;
+void FileFinder::setExcludedDirs(const QStringList& excludedDirs){
+ m_excludedDirs = excludedDirs;
}
/**
m_errors(0){
ui->setupUi(this);
m_statusMessage = new QLabel(tr("Willkommen bei refind"));
- ui->comboBoxDirectory->setCurrentText(startDir.isEmpty() ? QDir::currentPath() : startDir);
+ ui->comboBoxDirectory->setCurrentText(
+ startDir.isEmpty() ? QDir::currentPath() : startDir);
statusBar()->addWidget(m_statusMessage);
connect(ui->pushButtonSearch, SIGNAL(clicked()), this, SLOT(search()));
connect(ui->pushButtonSearch2, SIGNAL(clicked()), this, SLOT(search()));
connect(ui->pushButtonUp, SIGNAL(clicked()), this, SLOT(up()));
- connect(ui->pushButtonDirectory, SIGNAL(clicked()), this, SLOT(selectDirectory()));
+ connect(ui->pushButtonDirectory, SIGNAL(clicked()), this,
+ SLOT(selectDirectory()));
ui->tableWidget->setColumnWidth(TC_NODE, 200);
ui->tableWidget->setColumnWidth(TC_EXT, 40);
ui->tableWidget->setColumnWidth(TC_SIZE, 125);
* @return the filetypes selected by the checkboxes
*/
QDir::Filters MainWindow::buildFileTypes(){
- QDir::Filters rc = 0;
- if (ui->checkBoxDirs->isChecked())
- rc |= QDir::Dirs;
- if (ui->checkBoxFiles->isChecked())
- rc |= QDir::Files;
- if (rc == 0)
- rc |= QDir::Dirs | QDir::Files;
- if (! ui->checkBoxLinks->isChecked())
- rc |= QDir::NoSymLinks;
- if (ui->checkBoxHidden)
- rc |= QDir::Hidden | QDir::System;
- QDir::Filters mask = 0;
- if (ui->checkBoxWritable->isChecked())
- mask |= QDir::Writable;
- if (ui->checkBoxReadable->isChecked())
- mask |= QDir::Readable;
- if (ui->checkBoxExecutable->isChecked())
- mask |= QDir::Executable;
- if (mask == 0)
- mask |= QDir::PermissionMask;
- rc |= mask;
- return rc;
+ QDir::Filters rc = 0;
+ if (ui->checkBoxDirs->isChecked())
+ rc |= QDir::Dirs;
+ if (ui->checkBoxFiles->isChecked())
+ rc |= QDir::Files;
+ if (rc == 0)
+ rc |= QDir::Dirs | QDir::Files;
+ if (!ui->checkBoxLinks->isChecked())
+ rc |= QDir::NoSymLinks;
+ if (ui->checkBoxHidden)
+ rc |= QDir::Hidden | QDir::System;
+ QDir::Filters mask = 0;
+ if (ui->checkBoxWritable->isChecked())
+ mask |= QDir::Writable;
+ if (ui->checkBoxReadable->isChecked())
+ mask |= QDir::Readable;
+ if (ui->checkBoxExecutable->isChecked())
+ mask |= QDir::Executable;
+ if (mask == 0)
+ mask |= QDir::PermissionMask;
+ rc |= mask;
+ return rc;
}
/**
patterns = value.split(",");
finder.setPatterns(patterns);
value = ui->comboBoxExcludedDirs->currentText();
- if (value.indexOf('/')>= 0 || value.indexOf('\\') >= 0)
- guiError(ui->comboBoxExcludedDirs, tr("no path delimiter allowed"));
- else if (value.indexOf('*')>= 0)
- guiError(ui->comboBoxExcludedDirs, tr("no patterns allowed. Do not use '*"));
+ if (value.indexOf('/') >= 0 || value.indexOf('\\') >= 0)
+ guiError(ui->comboBoxExcludedDirs, tr("no path delimiter allowed"));
+ else if (value.indexOf('*') >= 0)
+ guiError(ui->comboBoxExcludedDirs,
+ tr("no patterns allowed. Do not use '*"));
else if (!value.isEmpty())
- patterns = value.split(",");
+ patterns = value.split(",");
finder.setExcludedDirs(patterns);
if (m_errors == 0){
clock_t start = clock();
* Handles the push of the button "select directory".
*/
void MainWindow::selectDirectory(){
- QString dir = QFileDialog::getExistingDirectory(this,
- tr("Select Directory"), ui->comboBoxDirectory->currentText(),
- QFileDialog::ShowDirsOnly);
- if (! dir.isEmpty())
- ui->comboBoxDirectory->setCurrentText(dir);
+ QString dir = QFileDialog::getExistingDirectory(this, tr("Select Directory"),
+ ui->comboBoxDirectory->currentText(), QFileDialog::ShowDirsOnly);
+ if (!dir.isEmpty())
+ ui->comboBoxDirectory->setCurrentText(dir);
}
/**
* @brief Handles the "up" button: go to the parent directory.
*/
void MainWindow::up(){
- QString path = ui->comboBoxDirectory->currentText();
+ QString path = ui->comboBoxDirectory->currentText();
QDir dir(path);
if (dir.exists()){
- dir.cdUp();
- if (dir.exists()){
- path = dir.absolutePath();
- ui->comboBoxDirectory->setEditText(path);
- setInHistory(ui->comboBoxDirectory, path);
- }
+ dir.cdUp();
+ if (dir.exists()){
+ path = dir.absolutePath();
+ ui->comboBoxDirectory->setEditText(path);
+ setInHistory(ui->comboBoxDirectory, path);
+ }
}
}
explicit MainWindow(const QString& startDir, QWidget *parent = 0);
~MainWindow();
-
private slots:
- void search();
- void up();
- void selectDirectory();
+ void search();
+ void up();
+ void selectDirectory();
private:
QDir::Filters buildFileTypes();
-#-------------------------------------------------\r
-#\r
-# Project created by QtCreator 2015-04-02T23:48:19\r
-#\r
-#-------------------------------------------------\r
-\r
-QT += core gui\r
-\r
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets\r
-\r
-TARGET = refind\r
-TEMPLATE = app\r
-\r
-INCLUDEPATH = ../.. /usr/include/c++/4.9\r
-\r
-SOURCES += main.cpp\\r
- mainwindow.cpp \\r
- ../../base/ReException.cpp \\r
- ../../base/ReQStringUtil.cpp \\r
- ../../base/ReLogger.cpp \\r
- filefinder.cpp\r
-\r
-\r
-HEADERS += mainwindow.hpp \\r
- ../../base/rebase.hpp \\r
- filefinder.hpp \\r
- ../../base/ReQStringUtil.hpp\r
-\r
-\r
-FORMS += mainwindow.ui\r
+#-------------------------------------------------
+#
+# Project created by QtCreator 2015-04-02T23:48:19
+#
+#-------------------------------------------------
+
+QT += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = refind
+TEMPLATE = app
+
+INCLUDEPATH = ../.. /usr/include/c++/4.9
+
+SOURCES += main.cpp\
+ mainwindow.cpp \
+ ../../base/ReException.cpp \
+ ../../base/ReQStringUtil.cpp \
+ ../../base/ReLogger.cpp \
+ filefinder.cpp \
+ textfinder.cpp
+
+
+HEADERS += mainwindow.hpp \
+ ../../base/rebase.hpp \
+ filefinder.hpp \
+ ../../base/ReQStringUtil.hpp \
+ textfinder.hpp
+
+
+FORMS += mainwindow.ui
--- /dev/null
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+
+#include "base/rebase.hpp"
+#include "textfinder.hpp"
+
+/**
+ * Constructor.
+ *
+ * @param fullName path and name of the file
+ * @param length length of the file
+ * @param ignoreBinary <code>true</code>: binary files will be ignored
+ */
+TextFinder::TextFinder(const QString& fullName, int64_t length,
+ bool ignoreBinary) :
+ m_ignoreBinary(ignoreBinary),
+ m_filename(fullName),
+ m_length(length),
+ m_file(fullName),
+ m_valid(false){
+ m_valid = m_file.open(QIODevice::ReadOnly);
+}
+
+/**
+ * Destructor.
+ */
+TextFinder::~TextFinder(){
+}
+
+/**
+ * Search a text pattern in the given file.
+ *
+ * @param pattern a text pattern to search
+ * @param ignoreCase <code>true</code>: the search must be case insensitive
+ * @param isRegular <code>true</code>: the pattern is a regular expression
+ * @return <code>true</code>: the patter was found
+ */
+bool TextFinder::contains(const QString& pattern, bool ignoreCase,
+ bool isRegular){
+ bool rc = false;
+ if (!m_ignoreBinary || !isBinary()){
+ m_file.seek(0);
+ QTextStream stream(&m_file);
+ QString line;
+ if (isRegular){
+ QRegularExpression::PatternOption option =
+ ignoreCase ?
+ QRegularExpression::CaseInsensitiveOption :
+ QRegularExpression::NoPatternOption;
+ QRegularExpression expr(pattern, option);
+ QRegularExpressionMatch match;
+ while (!stream.atEnd()){
+ line = stream.readLine();
+ match = expr.match(line);
+ if (match.hasMatch()){
+ rc = true;
+ break;
+ }
+ }
+ }else{
+ Qt::CaseSensitivity mode =
+ ignoreCase ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ while (!stream.atEnd()){
+ line = stream.readLine();
+ if (line.indexOf(pattern, 0, mode) >= 0){
+ rc = true;
+ break;
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+/**
+ * Tests whether the file is a binary file.
+ *
+ * @return <code>true</code>: the file is a binary file
+ */
+bool TextFinder::isBinary(){
+ QByteArray data = m_file.read(64 * 1024);
+ int length = data.length();
+ const char* ptr = reinterpret_cast <const char*>(memchr(data.constData(),
+ '\0', length));
+ bool rc = int(ptr - data.constData()) != length;
+
+ if (!rc)
+ rc = !isText(data);
+
+ return rc;
+}
+
+/**
+ * Tests whether a string contains only text characters.
+ *
+ * @param data data to inspect
+ * @param trueAscii OUT: <code>true</code>: only 7-bit ASCII character are present
+ * @return <code>true</code>: the file is a text file
+ */
+bool TextFinder::isText(const QByteArray& data, bool* trueAscii){
+ const uint8_t* ptr = reinterpret_cast <const uint8_t*>(data.constData());
+ bool isAscii = true;
+ uint8_t byte1;
+ bool rc = true;
+ while ((byte1 = *ptr++) != '\0'){
+ // ASCII with control chars:
+ if (byte1 < ' ' && byte1 != '\t' && byte1 != '\n' && byte1 != '\r'){
+ rc = false;
+ break;
+ }
+ if (rc > 0x7f)
+ isAscii = false;
+ }
+ if (trueAscii != NULL)
+ *trueAscii = rc && isAscii;
+ return rc;
+}
+
+/**
+ * Tests whether the file is a binary file.
+ *
+ * @param data data to inspect
+ * @param trueAscii OUT: <code>true</code>: only 7-bit ASCII character are present
+ * @return <code>true</code>: the file is an UTF-8 file
+ */
+bool TextFinder::isUTF8(const QByteArray& data, bool* trueAscii) const{
+ const uint8_t* ptr = reinterpret_cast <const uint8_t*>(data.constData());
+ bool isAscii = true;
+ uint8_t byte1;
+ bool rc = true;
+ while ((byte1 = *ptr++) != '\0'){
+ // ASCII with control chars:
+ if ((0x20 <= byte1 && byte1 <= 0x7E) || byte1 == '\t' || byte1 == '\n'
+ || byte1 == '\r'){
+ continue;
+ }
+ isAscii = false;
+ uint8_t byte2 = *ptr++;
+ // non-overlong 2-byte
+ if (0xC2 <= byte1 && byte1 <= 0xDF && 0x80 <= byte2 && byte2 <= 0xBF){
+ continue;
+ }
+ uint8_t byte3 = *ptr++;
+ // excluding overlongs
+ if ((byte1 == 0xE0 && 0xA0 <= byte2 && byte2 <= 0xBF && 0x80 <= byte3
+ && byte3 <= 0xBF)
+ // straight 3-byte
+ || (((0xE1 <= byte1 && byte1 <= 0xEC) || byte1 == 0xEE || byte1 == 0xEF)
+ && 0x80 <= byte2 && byte2 <= 0xBF && 0x80 <= byte3 && byte3 <= 0xBF)
+ // excluding surrogates
+ || (byte1 == 0xED && (0x80 <= byte2 && byte2 <= 0x9F)
+ && (0x80 <= byte3 && byte3 <= 0xBF))){
+ continue;
+ }
+ uint8_t byte4 = *ptr++;
+ if ( // planes 1-3
+ (byte1 == 0xF0 && 0x90 <= byte2 && byte2 <= 0xBF && 0x80 <= byte3
+ && byte3 <= 0xBF && 0x80 <= byte4 && byte4 <= 0xBF)
+ // planes 4-15
+ || (0xF1 <= byte1 && byte1 <= 0xF3 && 0x80 <= byte2 && byte2 <= 0xBF
+ && 0x80 <= byte3 && byte3 <= 0xBF && 0x80 <= byte4 && byte4 <= 0xBF)
+ // plane 16
+ || (byte1 == 0xF4 && 0x80 <= byte2 && byte2 <= 0x8F && 0x80 <= byte3
+ && byte3 <= 0xBF && 0x80 <= byte4 && byte4 <= 0xBF)){
+ continue;
+ }
+
+ rc = false;
+ break;
+ }
+ if (trueAscii != NULL)
+ *trueAscii = rc && isAscii;
+ return rc;
+}
+/**
+ * Tests wether the file was opened correctly
+ * @return <code>true</code>: the file can be read
+ */
+bool TextFinder::isValid() const{
+ return m_valid;
+}
+
--- /dev/null
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+
+#ifndef TEXTFINDER_HPP
+#define TEXTFINDER_HPP
+
+class TextFinder {
+public:
+ TextFinder(const QString& fullName, int64_t length, bool ignoreBinary);
+ ~TextFinder();
+public:
+ bool contains(const QString& pattern, bool ignoreCase, bool isRegular);
+ bool isBinary();
+ bool isText(const QByteArray& data, bool* trueAscii = NULL);
+ bool isUTF8(const QByteArray& data, bool* trueAscii) const;
+ bool isValid() const;
+
+private:
+ bool m_ignoreBinary;
+ QString m_filename;
+ int64_t m_length;
+ QFile m_file;
+ bool m_valid;
+};
+
+#endif // TEXTFINDER_HPP