From: hama Date: Mon, 21 Sep 2015 22:05:06 +0000 (+0200) Subject: ReFileSystem, memory leaks in ReEdit X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=8ddb2dbb63e50a297198457d7937b7e9606e8402;p=reqt ReFileSystem, memory leaks in ReEdit --- diff --git a/base/ReFileUtils.cpp b/base/ReFileUtils.cpp index ca78ec3..c5f9286 100644 --- a/base/ReFileUtils.cpp +++ b/base/ReFileUtils.cpp @@ -63,6 +63,43 @@ bool ReFileUtils::isAbsolutPath(const char* path) return rc; } +/** Sets the read position of a file. + * @param file file to process + * @param offset the position. @see whence + * @param whence SEEK_SET: offset is absolute (from file's start) + * SEEK_END: offset is relative to the file' end + * SEEK_CUR: offset is relative to the current position + * @return 0: success
+ * otherwise: error code + */ +int ReFileUtils::seek(FILE* file, int64_t offset, int whence){ + int rc; +#if defined __linux__ + rc = fseeko(file, offset, whence); +#elif defined __WIN32__ + rc = _fseek64(file, offset, whence); +#endif + return rc; +} + +/** + * Returns the current file position. + * + * @param file file to process + * @return < 0: error occurred
+ * otherwise: the current read/write position (from the file's start) + */ +int64_t ReFileUtils::tell(FILE* file) +{ + int64_t rc; +#if defined __linux__ + rc = ftello(file); +#elif defined __WIN32__ + rc = _ftell64(file); +#endif + return rc; +} + /** * Delete a directory tree. * diff --git a/base/ReFileUtils.hpp b/base/ReFileUtils.hpp index c8844b3..d27181f 100644 --- a/base/ReFileUtils.hpp +++ b/base/ReFileUtils.hpp @@ -28,17 +28,18 @@ public: */ class ReFileUtils { public: + static bool deleteTree(const QString& path, bool withBase, ReLogger* logger); static bool isAbsolutPath(const QString& path); static bool isAbsolutPath(const char* path); + static int seek(FILE* file, int64_t offset, int whence); + static int64_t tell(FILE* file); static QByteArray tempDir(const char* node, const char* parent = NULL, - bool withSeparator = true); + bool withSeparator = true); static QByteArray tempFile(const char* node, const char* parent = NULL, - bool deleteIfExists = true); + bool deleteIfExists = true); static QByteArray& readFromFile(const char* filename, QByteArray& buffer); static void writeToFile(const char* filename, const char* content, - size_t contentLength = (size_t) - 1, const char* mode = "w"); - static bool deleteTree(const QString& path, bool withBase, - ReLogger* logger); + size_t contentLength = (size_t) - 1, const char* mode = "w"); }; #endif // REFILEUTILS_HPP diff --git a/base/ReMatcher.cpp b/base/ReMatcher.cpp index 2d86b27..b32b218 100644 --- a/base/ReMatcher.cpp +++ b/base/ReMatcher.cpp @@ -36,6 +36,7 @@ ReListMatcher* ReListMatcher::m_allMatcher = NULL; ReMatcher::ReMatcher(const QString& pattern, Qt::CaseSensitivity caseSensivity, bool anchored) : + m_pattern(), m_needles(), m_restLengths(), m_anchored(anchored), @@ -50,20 +51,31 @@ ReMatcher::ReMatcher(const QString& pattern, Qt::CaseSensitivity caseSensivity, * @return true: the pattern matches */ bool ReMatcher::matches(const QString& text) { - bool found = m_needles.size() == 0; - if (!found) { - found = - m_anchored ? - text.startsWith(m_needles.at(0), m_caseSensivitiy) : true; - if (found) { - int startIx = m_anchored ? 1 : 0; - int textIndex = m_anchored ? m_needles.at(0).length() : 0; - for (int ix = startIx; found && ix < m_needles.size(); ix++) { - found = text.size() - textIndex >= m_restLengths.at(ix); - if (found) - found = (textIndex = text.indexOf(m_needles.at(ix), - textIndex, m_caseSensivitiy)) >= 0; - } + bool found = m_allMatching || m_needles.size() == 0; + int endIx = m_needles.size() - 1; + if (! found && m_anchored){ + found = m_needles.at(0).size() == 0 + || text.startsWith(m_needles.at(0), m_caseSensivitiy); + if (found && (endIx > 0 || text.length() != m_pattern.length())){ + found = m_needles.at(endIx).size() == 0 + || text.endsWith(m_needles.at(endIx), m_caseSensivitiy); + } + } + if (!found || m_anchored && endIx > 1) { + int startIx = 0; + int textIndex = 0; + if (! m_anchored) + found = true; + else { + startIx++; + endIx--; + textIndex = m_needles.at(0).length(); + } + for (int ix = startIx; found && ix <= endIx; ix++) { + found = text.size() - textIndex >= m_restLengths.at(ix); + if (found) + found = (textIndex = text.indexOf(m_needles.at(ix), + textIndex, m_caseSensivitiy)) >= 0; } } return found; @@ -79,17 +91,14 @@ bool ReMatcher::matches(const QString& text) { void ReMatcher::setPattern(const QString& pattern, bool anchored) { m_anchored = anchored; m_allMatching = false; + m_pattern = pattern; + m_needles.clear(); if (pattern.isEmpty()) m_needles.clear(); else { - if (pattern.startsWith("*")){ - m_anchored = false; - if (pattern.length() == 1) - m_allMatching = true; - } m_needles = pattern.split('*'); - // Eliminate empty entries: - for (int ix = m_needles.size() - 1; ix >= 0; ix--) { + // Eliminate empty entries but not first and next: + for (int ix = m_needles.size() - 2; ix > 0; ix--) { if (m_needles.at(ix).length() == 0) m_needles.removeAt(ix); else @@ -103,6 +112,16 @@ void ReMatcher::setPattern(const QString& pattern, bool anchored) { } } } +/** + * Returns the current pattern. + * + * @return the current pattern + */ +const QString& ReMatcher::pattern() const +{ + return m_pattern; +} + /** * Returns whether the matcher accepts all strings (pattern "*"). * @@ -240,15 +259,17 @@ bool ReListMatcher::empty() const /** * Tests whether at least one pattern of the list matches the given text + * * @param text text to test - * @return true: one of the stored patterns matches the text
+ * @return true: empty list or one of the stored patterns + * matches the text
* false: none of the patterns matches */ bool ReListMatcher::matches(const QString& text) { QList::const_iterator it; - bool rc = false; - for (it = m_list.constBegin(); ! rc && it != m_list.cend(); ++it){ + bool rc = m_list.size() == 0; + for (it = m_list.cbegin(); ! rc && it != m_list.cend(); ++it){ rc = (*it)->matches(text); } return rc; diff --git a/base/ReMatcher.hpp b/base/ReMatcher.hpp index 3ba8e8f..0c5cb40 100644 --- a/base/ReMatcher.hpp +++ b/base/ReMatcher.hpp @@ -26,10 +26,13 @@ public: bool allMatching() const; Qt::CaseSensitivity caseSensivitiy() const; bool matches(const QString& text); + const QString& pattern() const; void setCaseSensivitiy(const Qt::CaseSensitivity& caseSensivitiy); void setPattern(const QString& pattern, bool anchored = false); + protected: + QString m_pattern; QStringList m_needles; // m_restLengths[ix] = sum(m_needles[ix..last].size() QList m_restLengths; diff --git a/cunit/allTests.cpp b/cunit/allTests.cpp index ddd8169..cad6fc2 100644 --- a/cunit/allTests.cpp +++ b/cunit/allTests.cpp @@ -89,6 +89,7 @@ static void testOs() { testReFileSystem(); } void allTests() { + testOs(); testBase(); testGui(); if (s_allTest) { diff --git a/cunit/cuReFileSystem.cpp b/cunit/cuReFileSystem.cpp index 743d32e..2ed6ad6 100644 --- a/cunit/cuReFileSystem.cpp +++ b/cunit/cuReFileSystem.cpp @@ -39,23 +39,24 @@ protected: fn.append("text").append(QByteArray::number(ix)); ReFileUtils::writeToFile(fn.constData(), fn.constData()); } + ReFileUtils::tempFile("abc.txt", "refilesytem", true); } - void testContains(const char* name, QList nodes){ + void testContains(const char* name, ReFileMetaDataList nodes){ bool rc = false; - QList::const_iterator it; + ReFileMetaDataList::const_iterator it; for (it = nodes.cbegin(); it != nodes.cend(); ++it){ - if ((*it)->m_node == name) + if ((*it).m_node == name) rc = true; } if (! rc) checkT(rc); } - void testReLocalFileSystem() { - ReLocalFileSytem fs(m_base); + void testReListInfos() { + ReLocalFileSytem fs(m_base, &m_logger); checkEqu(QString(m_base), fs.directory()); checkEqu(QString(m_base), fs.basePath()); - QList nodes; + ReFileMetaDataList nodes; ReIncludeExcludeMatcher matcher(ReListMatcher::allMatchingList(), ReQStringUtils::m_emptyList, Qt::CaseInsensitive, false); fs.listInfos(matcher, nodes); @@ -63,9 +64,35 @@ protected: testContains("test1.txt", nodes); testContains("test7.txt", nodes); } + void testReadWrite(){ + ReLocalFileSytem fs(m_base, &m_logger); + QByteArray buffer; + buffer.append("abcdefghijklmnopqrstuvwxyz"); + checkEqu(0, fs.write("abc.txt", 0LL, buffer)); + checkEqu(0, fs.write("abc.txt", 26LL, buffer)); + QByteArray buffer2; + ReFileMetaDataList nodes; + QStringList names; + names.append("abc.txt"); + ReIncludeExcludeMatcher matcher(names, + ReQStringUtils::m_emptyList, Qt::CaseInsensitive, true); + checkEqu(1, fs.listInfos(matcher, nodes)); + checkEqu(1, nodes.size()); + checkEqu(0, fs.read(nodes.at(0), 0LL, 3, buffer2)); + checkEqu("abc", buffer2); + checkEqu(0, fs.read(nodes.at(0), 3LL, 7, buffer2)); + checkEqu("defghij", buffer2); + checkEqu(0, fs.read(nodes.at(0), 10LL, 99, buffer2)); + checkEqu("klmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", buffer2); + } + void testCopy(){ + + } + virtual void run() { init(); - testReLocalFileSystem(); + testReListInfos(); + testReadWrite(); } }; void testReFileSystem() { diff --git a/cunit/cuReFileUtils.cpp b/cunit/cuReFileUtils.cpp index d6895b5..2b033c1 100644 --- a/cunit/cuReFileUtils.cpp +++ b/cunit/cuReFileUtils.cpp @@ -97,8 +97,31 @@ public: #endif checkF(ReFileUtils::isAbsolutPath("")); } + void testSeekTell(){ + QByteArray fn(ReFileUtils::tempFile("seektest.txt", NULL, false)); + ReFileUtils::writeToFile(fn.constData(), "0123456789"); + FILE* fp = fopen(fn.constData(), "rb"); + checkNN(fp); + if (fp != NULL){ + checkEqu(0LL, ReFileUtils::tell(fp)); + checkEqu(0, ReFileUtils::seek(fp, 3, SEEK_SET)); + checkEqu(3LL, ReFileUtils::tell(fp)); + char cc; + checkEqu(1, fread(&cc, 1, 1, fp)); + checkEqu('3', cc); + checkEqu(4LL, ReFileUtils::tell(fp)); + + checkEqu(0, ReFileUtils::seek(fp, -2, SEEK_CUR)); + checkEqu(2LL, ReFileUtils::tell(fp)); + + checkEqu(0, ReFileUtils::seek(fp, -2, SEEK_END)); + checkEqu(8LL, ReFileUtils::tell(fp)); + } + + } virtual void run() { + testSeekTell(); testIsAbsolutePath(); testDeleteTree(); testTempDir(); diff --git a/cunit/cuReMatcher.cpp b/cunit/cuReMatcher.cpp index 4321c28..b14aa71 100644 --- a/cunit/cuReMatcher.cpp +++ b/cunit/cuReMatcher.cpp @@ -23,7 +23,7 @@ public: public: void testBasics() { - ReMatcher m1("a*b*c", Qt::CaseSensitive, true); + ReMatcher m1("a*b*c*", Qt::CaseSensitive, true); checkT(m1.matches("a b c d")); checkT(m1.matches("abc d")); checkT(m1.matches("ababc")); @@ -34,14 +34,15 @@ public: checkT(m2.matches("a b c d")); checkT(m2.matches("ababc")); checkT(m2.matches("a b a b c")); - checkT(m2.matches(" abc")); + checkT(m2.matches(" abc ")); checkF(m2.matches(" ab")); ReMatcher m3("a**B*C", Qt::CaseInsensitive, true); - checkT(m3.matches("a b c d")); - checkT(m3.matches("abc d")); + checkT(m3.matches("a b C")); + checkT(m3.matches("ab c")); checkT(m3.matches("ababc")); checkT(m3.matches("abc")); + checkF(m3.matches("abcd")); ReMatcher m4("A*B*c", Qt::CaseInsensitive, false); checkT(m4.matches("a b c d")); @@ -55,11 +56,107 @@ public: m4.setPattern(""); checkT(m4.matches("any")); } + void test1Star(){ + ReMatcher matcher("*abc", Qt::CaseSensitive, true); + checkT(matcher.matches("abc")); + checkF(matcher.matches("aBc")); + checkT(matcher.matches("xyzabc")); + checkF(matcher.matches("abc ")); + + matcher.setCaseSensivitiy(Qt::CaseInsensitive); + checkT(matcher.matches("abc")); + checkT(matcher.matches("aBc")); + checkT(matcher.matches("xyzabc")); + checkF(matcher.matches("abc ")); + + checkT(matcher.matches("AbC")); + checkT(matcher.matches("aBc")); + checkT(matcher.matches("xyzAbc")); + checkF(matcher.matches("abC ")); + + matcher.setPattern(matcher.pattern(), false); + matcher.setCaseSensivitiy(Qt::CaseSensitive); + checkT(matcher.matches("abc")); + checkF(matcher.matches("aBc")); + checkT(matcher.matches("xyzabc")); + checkT(matcher.matches("abc ")); + checkT(matcher.matches("_abc_")); + checkF(matcher.matches("_a bc_")); + + matcher.setCaseSensivitiy(Qt::CaseInsensitive); + checkT(matcher.matches("abc")); + checkT(matcher.matches("aBc")); + checkT(matcher.matches("xyzAbc")); + checkT(matcher.matches("aBc ")); + checkT(matcher.matches("_abC_")); + checkF(matcher.matches("_a bc_")); + + matcher.setPattern("x*y", true); + matcher.setCaseSensivitiy(Qt::CaseSensitive); + checkT(matcher.matches("x y")); + checkF(matcher.matches("X y")); + checkF(matcher.matches("x Y")); + checkT(matcher.matches("xy")); + checkF(matcher.matches("Xy")); + checkF(matcher.matches(" xy")); + checkF(matcher.matches("xy ")); + + matcher.setCaseSensivitiy(Qt::CaseInsensitive); + checkT(matcher.matches("X Y")); + checkT(matcher.matches("xY")); + checkT(matcher.matches("Xy")); + checkF(matcher.matches(" xy")); + checkF(matcher.matches("xy ")); + + matcher.setPattern(matcher.pattern(), false); + matcher.setCaseSensivitiy(Qt::CaseSensitive); + checkT(matcher.matches("x y")); + checkT(matcher.matches("ax y")); + checkT(matcher.matches("x y!")); + checkT(matcher.matches("123xyz!")); + checkF(matcher.matches("x")); + checkF(matcher.matches("xY")); + checkF(matcher.matches("Xy")); + + matcher.setCaseSensivitiy(Qt::CaseInsensitive); + checkT(matcher.matches("X y")); + checkT(matcher.matches("aX y")); + checkT(matcher.matches("x Y!")); + checkT(matcher.matches("123XY!")); + checkF(matcher.matches("x")); + checkF(matcher.matches("xY")); + checkF(matcher.matches("Xy")); + } + void test0Star(){ + ReMatcher matcher("abc", Qt::CaseSensitive, true); + checkT(matcher.matches("abc")); + checkF(matcher.matches("aBc")); + checkF(matcher.matches(" abc")); + checkF(matcher.matches("abc ")); + + checkT(matcher.caseSensivitiy()); + matcher.setCaseSensivitiy(Qt::CaseInsensitive); + checkF(matcher.caseSensivitiy()); + + checkT(matcher.matches("abc")); + checkT(matcher.matches("aBc")); + checkF(matcher.matches(" aBc")); + checkF(matcher.matches("aBc ")); + + matcher.setPattern(matcher.pattern(), false); + matcher.setCaseSensivitiy(Qt::CaseSensitive); + checkT(matcher.matches("abc")); + checkF(matcher.matches("aBc")); + checkT(matcher.matches(" abc")); + checkT(matcher.matches("abc ")); + } + void testList(){ QStringList patterns; patterns << "*.txt" << "*.doc"; ReListMatcher matcher(patterns, Qt::CaseInsensitive, true); checkT(matcher.matches("README.TXT")); + checkF(matcher.matches("readme_txt")); checkT(matcher.matches("Xyz.Doc")); checkF(matcher.matches("a.doc.bak")); @@ -70,6 +167,8 @@ public: virtual void run(void) { testBasics(); + test0Star(); + test1Star(); testList(); } }; diff --git a/cunit/cuReQStringUtils.cpp b/cunit/cuReQStringUtils.cpp index e3dd466..0711f78 100644 --- a/cunit/cuReQStringUtils.cpp +++ b/cunit/cuReQStringUtils.cpp @@ -17,7 +17,7 @@ class TestReQStringUtil: public ReTest { public: TestReQStringUtil() : - ReTest("ReQStringUtil") { + ReTest("ReQStringUtil") { doIt(); } @@ -35,20 +35,20 @@ public: void testLengthOfUInt64() { quint64 value = -3; checkEqu(1, - ReQStringUtils::lengthOfUInt64(ReString("0"), 0, 10, &value)); + ReQStringUtils::lengthOfUInt64(ReString("0"), 0, 10, &value)); checkEqu(int64_t(0), value); checkEqu(3, ReQStringUtils::lengthOfUInt64("x432", 1, 10, &value)); checkEqu(int64_t(432LL), value); checkEqu(3, ReQStringUtils::lengthOfUInt64("x432 x", 1, 10, &value)); checkEqu(int64_t(432LL), value); checkEqu(3, - ReQStringUtils::lengthOfUInt64("x432fabc x", 1, 10, &value)); + ReQStringUtils::lengthOfUInt64("x432fabc x", 1, 10, &value)); checkEqu(int64_t(432LL), value); checkEqu(16, - ReQStringUtils::lengthOfUInt64("a1234567890123567", 1, 10, &value)); + ReQStringUtils::lengthOfUInt64("a1234567890123567", 1, 10, &value)); checkEqu(int64_t(1234567890123567LL), value); checkEqu(10, - ReQStringUtils::lengthOfUInt64("x1234abcdef", 1, 16, &value)); + ReQStringUtils::lengthOfUInt64("x1234abcdef", 1, 16, &value)); checkEqu(int64_t(0x1234abcdefLL), value); checkEqu(3, ReQStringUtils::lengthOfUInt64("432", 0, 8, &value)); checkEqu(int64_t(0432LL), value); @@ -85,19 +85,19 @@ public: checkEqu(1, ReQStringUtils::lengthOfReal(ReString(" 0"), 1, &value)); checkEqu(0.0, value); checkEqu(17, - ReQStringUtils::lengthOfReal(ReString("X12345678901234567"), 1, - &value)); + ReQStringUtils::lengthOfReal(ReString("X12345678901234567"), 1, + &value)); checkEqu(12345678901234567.0, value); checkEqu(2, ReQStringUtils::lengthOfReal(ReString(".5"), 0, &value)); checkEqu(0.5, value); checkEqu(5, - ReQStringUtils::lengthOfReal(ReString("2.5e2x"), 0, &value)); + ReQStringUtils::lengthOfReal(ReString("2.5e2x"), 0, &value)); checkEqu(250.0, value); checkEqu(6, - ReQStringUtils::lengthOfReal(ReString("2.5e+2"), 0, &value)); + ReQStringUtils::lengthOfReal(ReString("2.5e+2"), 0, &value)); checkEqu(250.0, value); checkEqu(7, - ReQStringUtils::lengthOfReal(ReString("2.5E-33"), 0, &value)); + ReQStringUtils::lengthOfReal(ReString("2.5E-33"), 0, &value)); checkEqu(2.5e-33, value); checkEqu(3, ReQStringUtils::lengthOfReal(ReString("2.5E"), 0, &value)); @@ -105,7 +105,7 @@ public: checkEqu(3, ReQStringUtils::lengthOfReal(ReString("2.5E+"), 0, &value)); checkEqu(2.5, value); checkEqu(3, - ReQStringUtils::lengthOfReal(ReString("2.5E-a"), 0, &value)); + ReQStringUtils::lengthOfReal(ReString("2.5E-a"), 0, &value)); checkEqu(2.5, value); } @@ -128,7 +128,7 @@ public: ReString name = "Heinz Müller"; char buffer[32]; checkEqu("Heinz Müller", - ReQStringUtils::utf8(name, buffer, sizeof buffer)); + ReQStringUtils::utf8(name, buffer, sizeof buffer)); memset(buffer, 'x', sizeof buffer); checkEqu("Heinz", ReQStringUtils::utf8(name, buffer, (size_t)(5 + 1))); checkEqu(buffer[6], 'x'); @@ -186,42 +186,8 @@ public: checkEqu(8, ReQStringUtils::lengthOfTime("301:02:09x", 1, &time)); checkEqu(QTime(1, 2, 9), time); } - void testReMatcher() { - ReMatcher m1("a*b*c", Qt::CaseSensitive, true); - checkT(m1.matches("a b c d")); - checkT(m1.matches("abc d")); - checkT(m1.matches("ababc")); - checkT(m1.matches("abc")); - checkF(m1.matches("aBc")); - - ReMatcher m2("a*b*c", Qt::CaseSensitive, false); - checkT(m2.matches("a b c d")); - checkT(m2.matches("ababc")); - checkT(m2.matches("a b a b c")); - checkT(m2.matches(" abc")); - checkF(m2.matches(" ab")); - - ReMatcher m3("a**B*C", Qt::CaseInsensitive, true); - checkT(m3.matches("a b c d")); - checkT(m3.matches("abc d")); - checkT(m3.matches("ababc")); - checkT(m3.matches("abc")); - - ReMatcher m4("A*B*c", Qt::CaseInsensitive, false); - checkT(m4.matches("a b c d")); - checkT(m4.matches("ababc")); - checkT(m4.matches("a b a b c")); - checkT(m4.matches(" abc")); - checkF(m4.matches(" ab")); - - m4.setPattern("*"); - checkT(m4.matches("x")); - m4.setPattern(""); - checkT(m4.matches("any")); - } virtual void run(void) { - testReMatcher(); testLengtOfTime(); testLengtOfDate(); testDateTimeParser(); diff --git a/gui/ReEdit.cpp b/gui/ReEdit.cpp index 3007ba8..cedf156 100644 --- a/gui/ReEdit.cpp +++ b/gui/ReEdit.cpp @@ -36,11 +36,11 @@ inline int heightToFullHeight(int height) { * @param edit the parent */ ReLook::ReLook() : - m_font(NULL), - m_metrics(NULL), - m_foreground(FG_STANDARD), - m_background(BG_STANDARD), - m_edit(NULL) { + m_font(NULL), + m_metrics(NULL), + m_foreground(FG_STANDARD), + m_background(BG_STANDARD), + m_edit(NULL) { } /** @@ -50,8 +50,8 @@ ReLook::ReLook() : * @param look the presentation of the text */ ReEditText::ReEditText(const QString& text, ReLook* look) : - m_text(text), - m_look(look) { + m_text(text), + m_look(look) { } @@ -64,7 +64,7 @@ ReEditText::ReEditText(const QString& text, ReLook* look) : * @param edit the edit field (parent) */ void ReCursortLineBuilder::buildParagraph(ReParagraph& paragraph, int lineNo, - ReEdit* edit) { + ReEdit* edit) { if (lineNo == edit->cursorLineNo()) { for (int ix = 0; ix < paragraph.length(); ix++) { ReEditText* text = paragraph.at(ix); @@ -100,32 +100,32 @@ void ReCursortLineBuilder::buildParagraph(ReParagraph& paragraph, int lineNo, * @param parent NULL or a widget which destroy the instance */ ReEdit::ReEdit(QWidget* parent) : - QWidget(parent), - ReMouseCatcher(), - m_widthEdit(0), - m_heightEdit(0), - m_insertMode(true), - m_breakLines(false), - m_widthLineNumbers(50), - m_widthVScrollBar(16), - m_heightHScrollBar(16), - m_looks(), - m_standardBrush(new QBrush(Qt::SolidPattern)), - m_scrollbarBrush(new QBrush(Qt::SolidPattern)), - m_sliderBrush(new QBrush(Qt::ConicalGradientPattern)), - m_brushColors(), - m_standardPen(new QPen(Qt::SolidLine)), - m_standardFont(NULL), - m_standardMetrics(NULL), - m_fontColors(), - m_keyAlt(), - m_keyAltControl(), - m_keyAltControlShift(), - m_keyAltShift(), - m_keyControl(), - m_keyControlShift(), - m_keyRaw(), - m_keyShift() { + QWidget(parent), + ReMouseCatcher(), + m_widthEdit(0), + m_heightEdit(0), + m_insertMode(true), + m_breakLines(false), + m_widthLineNumbers(50), + m_widthVScrollBar(16), + m_heightHScrollBar(16), + m_looks(), + m_standardBrush(new QBrush(Qt::SolidPattern)), + m_scrollbarBrush(new QBrush(Qt::SolidPattern)), + m_sliderBrush(new QBrush(Qt::ConicalGradientPattern)), + m_brushColors(), + m_standardPen(new QPen(Qt::SolidLine)), + m_standardFont(NULL), + m_standardMetrics(NULL), + m_fontColors(), + m_keyAlt(), + m_keyAltControl(), + m_keyAltControlShift(), + m_keyAltShift(), + m_keyControl(), + m_keyControlShift(), + m_keyRaw(), + m_keyShift() { setFocusPolicy(Qt::WheelFocus); m_standardFont = new QFont("Courier"); m_standardFont->setStyleHint(QFont::TypeWriter); @@ -145,6 +145,23 @@ ReEdit::ReEdit(QWidget* parent) : appendBuilder(new ReCursortLineBuilder()); assignKeysStandard(); } + +/** + * Destructor. + */ +ReEdit::~ReEdit() +{ + for (size_t ix = 0; ix < sizeof(m_fontColors) / sizeof m_fontColors[0]; ix++) + delete m_fontColors[ix]; + for (size_t ix = 0; ix < sizeof(m_brushColors) / sizeof m_brushColors[0]; ix++) + delete m_brushColors[ix]; + delete m_standardBrush; + delete m_scrollbarBrush; + delete m_sliderBrush; + delete m_standardPen; + delete m_standardFont; + delete m_standardMetrics; +} /** * Assigns a standard version of colors to symbolic colors. */ @@ -230,7 +247,7 @@ void ReEdit::assignKeysStandard() { * @param length OUT: the slider length in pixel */ void calcSliderSize(int size, int minSize, double sizeFactor, double posFactor, - int& position, int& length) { + int& position, int& length) { if (sizeFactor > 1.0) sizeFactor = 1.0; if (posFactor > 100) @@ -277,8 +294,8 @@ int ReEdit::cursorLineNo() const { * @param posHorizontal the position of the scrollbar as factor [0..1] */ void ReEdit::drawScrollbars(QPainter& painter, const QRect& rect, - double sizeVertical, double posVertical, double sizeHorizontal, - double posHorizontal) { + double sizeVertical, double posVertical, double sizeHorizontal, + double posHorizontal) { // We paint the vertical scrollbar: QBrush brush(*m_brushColors[ReLook::BG_SCROLLBAR], Qt::SolidPattern); painter.setBrush(brush); @@ -287,14 +304,14 @@ void ReEdit::drawScrollbars(QPainter& painter, const QRect& rect, static int width = 1; static int width2 = 2 * width; m_vScrollBar->setRect(x + width2, rect.top(), m_widthVScrollBar - width2, - rect.height() - m_heightHScrollBar - width); + rect.height() - m_heightHScrollBar - width); painter.drawRect(*m_vScrollBar); // We paint the horizontal scrollbar: m_hScrollBar->setRect(rect.left() + m_widthLineNumbers, - rect.bottom() - m_heightHScrollBar + width, - rect.width() - m_widthVScrollBar - m_widthLineNumbers, - m_heightHScrollBar - width2); + rect.bottom() - m_heightHScrollBar + width, + rect.width() - m_widthVScrollBar - m_widthLineNumbers, + m_heightHScrollBar - width2); painter.drawRect(*m_hScrollBar); // Slider (vertical) @@ -303,36 +320,36 @@ void ReEdit::drawScrollbars(QPainter& painter, const QRect& rect, int sliderSize = 0; int sliderPos = 0; calcSliderSize(rect.height() - m_heightHScrollBar, m_heightHScrollBar, - sizeVertical, posVertical, sliderPos, sliderSize); + sizeVertical, posVertical, sliderPos, sliderSize); m_vSlider->setRect(x + width2, rect.top() + sliderPos + width, - m_widthVScrollBar - width2, sliderSize - width2); + m_widthVScrollBar - width2, sliderSize - width2); painter.drawRect(*m_vSlider); int middle = m_vSlider->top() + m_vSlider->height() / 2; painter.drawLine(m_vSlider->left() + 2, middle, m_vSlider->right() - 2, - middle); + middle); middle -= m_heightHScrollBar / 2 - 2; painter.drawLine(m_vSlider->left() + 2, middle, m_vSlider->right() - 2, - middle); + middle); middle += m_heightHScrollBar - 4; painter.drawLine(m_vSlider->left() + 2, middle, m_vSlider->right() - 2, - middle); + middle); // Slider (horizontal) calcSliderSize(rect.width() - m_widthLineNumbers - m_widthVScrollBar, - m_heightHScrollBar, sizeHorizontal, posHorizontal, sliderPos, - sliderSize); + m_heightHScrollBar, sizeHorizontal, posHorizontal, sliderPos, + sliderSize); m_hSlider->setRect(rect.left() + m_widthLineNumbers + sliderPos, - rect.bottom() - m_heightHScrollBar + width, sliderSize - width, - m_heightHScrollBar - width2); + rect.bottom() - m_heightHScrollBar + width, sliderSize - width, + m_heightHScrollBar - width2); painter.drawRect(*m_hSlider); middle = m_hSlider->left() + m_hSlider->width() / 2; painter.drawLine(middle, m_hSlider->top() + 2, middle, - m_hSlider->bottom() - 2); + m_hSlider->bottom() - 2); middle -= m_heightHScrollBar / 2 - 2; painter.drawLine(middle, m_hSlider->top() + 2, middle, - m_hSlider->bottom() - 2); + m_hSlider->bottom() - 2); middle += m_heightHScrollBar - 4; painter.drawLine(middle, m_hSlider->top() + 2, middle, - m_hSlider->bottom() - 2); + m_hSlider->bottom() - 2); } /** @@ -420,7 +437,7 @@ void ReEdit::editorAction(ReEdit::EditorAction action) { m_cursorCol = m_lines->lineAt(m_cursorLineNo - 1).length() - 1; } if (m_lines->removePart(m_cursorLineNo, columnToIndex(currentCol), 1, - true)) + true)) m_cursorLineNo = max(0, m_cursorLineNo - 1); break; @@ -429,7 +446,7 @@ void ReEdit::editorAction(ReEdit::EditorAction action) { int lastIx = lastColOfCurrent(); if (m_cursorCol <= lastIx) { m_lines->removePart(m_cursorLineNo, m_cursorCol + 1, - lastIx - m_cursorCol, true); + lastIx - m_cursorCol, true); ensureCursorVisible(); } break; @@ -476,7 +493,7 @@ void ReEdit::editorAction(ReEdit::EditorAction action) { */ void ReEdit::ensureCursorVisible() { if (m_cursorLineNo < m_firstLine - || m_cursorLineNo >= m_firstLine + pageSize()) { + || m_cursorLineNo >= m_firstLine + pageSize()) { reposition(m_cursorLineNo, m_cursorCol); } if (m_cursorCol < 0) @@ -518,7 +535,7 @@ void ReEdit::keyPressEvent(QKeyEvent* event) { break; } } else if (shift && !keyText.isEmpty() && key != Qt::Key_Delete - && key != Qt::Key_Backspace) { + && key != Qt::Key_Backspace) { m_lines->insertText(m_cursorLineNo, m_cursorCol + 1, keyText); m_cursorCol++; } else { @@ -564,7 +581,7 @@ ReLines& ReEdit::lines() { * @return */ ReLook* ReEdit::lookOf(ReLook::ForeGround foreground, - ReLook::BackGround background) { + ReLook::BackGround background) { int index = foreground * ReLook::BG_COUNT + background; ReLook* rc = m_looks[index]; if (rc == NULL) { @@ -591,8 +608,8 @@ ReLook* ReEdit::lookOf(ReLook::ForeGround foreground, */ void ReEdit::mouseMoveEvent(QMouseEvent* event) { if (m_lastMousePosition.x() >= 0 - && (handleHScrollBar(event, true, this) - || handleVScrollBar(event, true, this))) { + && (handleHScrollBar(event, true, this) + || handleVScrollBar(event, true, this))) { emit repaint(); } } @@ -610,12 +627,12 @@ void ReEdit::mousePressEvent(QMouseEvent* event) { } else { QPoint position = event->pos(); m_cursorLineNo = position.y() - / heightToFullHeight(m_standardMetrics->height()) + m_firstLine; + / heightToFullHeight(m_standardMetrics->height()) + m_firstLine; int x = position.x(); int charWidth = m_standardMetrics->width('x'); x -= m_widthLineNumbers; if (x >= 0 - && x < m_widthEdit - m_widthLineNumbers - m_widthVScrollBar) { + && x < m_widthEdit - m_widthLineNumbers - m_widthVScrollBar) { if (x <= +charWidth / 2) m_cursorCol = m_firstCol - 1; else @@ -658,14 +675,14 @@ void ReEdit::paintEvent(QPaintEvent* event) { int pageSize = (rect.height() - m_heightHScrollBar) / lineHeight; int charWidth = m_standardMetrics->averageCharWidth(); int pageWidth = (rect.width() - m_widthVScrollBar - m_widthLineNumbers) - / charWidth; + / charWidth; int firstLine = m_firstLine; load(firstLine, pageSize, pageWidth, this); QPainter painter(this); ReLook* look = lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD); painter.setBrush(*look->m_brush); QRect editArea(rect.left() + m_widthLineNumbers, rect.top(), - rect.right() - m_widthVScrollBar, rect.bottom() - m_heightHScrollBar); + rect.right() - m_widthVScrollBar, rect.bottom() - m_heightHScrollBar); // Painting the frame of the edit field: painter.drawRect(editArea); // Painting the edit field area (text...) @@ -680,13 +697,13 @@ void ReEdit::paintEvent(QPaintEvent* event) { for (int ix = 0; ix < maxIx; ix++, lineNo++) { QString number = QString::number(lineNo); ReLook* look = - lineNo == m_cursorLineNo + 1 ? - lookOf(ReLook::FG_CURRENT_LINE, ReLook::BG_CURRENT_LINE) : - lookStd; + lineNo == m_cursorLineNo + 1 ? + lookOf(ReLook::FG_CURRENT_LINE, ReLook::BG_CURRENT_LINE) : + lookStd; int width = look->m_metrics->width(number); if (ix == 0) y = rect.top() + look->m_metrics->height() - - look->m_metrics->descent(); + - look->m_metrics->descent(); painter.setFont(*look->m_font); painter.setPen(*look->m_pen); painter.drawText(left + m_widthLineNumbers - width - 5, y, number); @@ -694,13 +711,13 @@ void ReEdit::paintEvent(QPaintEvent* event) { } // We paint the cursor: if (m_cursorVisible && m_cursorLineNo >= firstLine - && m_cursorLineNo < firstLine + pageSize) { + && m_cursorLineNo < firstLine + pageSize) { ReParagraph* cursorPara = cursorParagraph(); int col = min(m_cursorCol, cursorPara->m_columns - 1); col = indexToColumn(col + 1, m_tabWidth, - m_lines->lineAt(m_cursorLineNo)) - m_firstCol; + m_lines->lineAt(m_cursorLineNo)) - m_firstCol; int x = rect.left() + m_widthLineNumbers + 1 - + col * lookStd->m_metrics->width('x'); + + col * lookStd->m_metrics->width('x'); int y = rect.top() + (m_cursorLineNo - firstLine) * lineHeight; painter.setPen(*look->m_pen); painter.drawLine(x, y, x, y + lineHeight); @@ -708,11 +725,11 @@ void ReEdit::paintEvent(QPaintEvent* event) { int maxLines = max(1, m_lines->lineCount() - pageSize); drawScrollbars(painter, rect, fraction(pageSize, maxLines, 1.0), - fraction(m_firstLine, maxLines, 0.0), - fraction(m_screenWidth, m_maxCols, 1.0), - fraction(m_firstCol, max(0, m_maxCols - m_screenWidth), 0.0)); + fraction(m_firstLine, maxLines, 0.0), + fraction(m_screenWidth, m_maxCols, 1.0), + fraction(m_firstCol, max(0, m_maxCols - m_screenWidth), 0.0)); ReLogger::globalLogger()->logv(LOG_INFO, 3, "draw: %.4f", - double(clock() - start) / CLOCKS_PER_SEC); + double(clock() - start) / CLOCKS_PER_SEC); } /** @@ -772,16 +789,16 @@ void ReEdit::setTabStrings(int tabWidth) { * Constructor. */ ReParagraphs::ReParagraphs() : - m_builders(), - m_firstLine(0), - m_firstCol(0), - m_cursorLineNo(0), - m_cursorCol(-1), - m_lines(NULL), - m_list(), - m_maxCols(0), - m_screenWidth(0), - m_cursorVisible(true) { + m_builders(), + m_firstLine(0), + m_firstCol(0), + m_cursorLineNo(0), + m_cursorCol(-1), + m_lines(NULL), + m_list(), + m_maxCols(0), + m_screenWidth(0), + m_cursorVisible(true) { } /** @@ -823,7 +840,7 @@ void ReParagraphs::clear() { * expanded tabs */ int ReParagraphs::columnToIndex(int column, int tabWidth, - const QString& string) { + const QString& string) { int rc = 0; if (column < 0) rc = -1; @@ -855,7 +872,7 @@ int ReParagraphs::columnToIndex(int column, int tabWidth, ReParagraph* ReParagraphs::cursorParagraph() { ReParagraph* rc = NULL; if (m_cursorLineNo >= m_firstLine - && m_cursorLineNo < m_firstLine + m_list.length()) { + && m_cursorLineNo < m_firstLine + m_list.length()) { rc = m_list.at(m_cursorLineNo - m_firstLine); } return rc; @@ -869,7 +886,7 @@ ReParagraph* ReParagraphs::cursorParagraph() { */ int ReParagraphs::columnToIndex(int cursorCol) { int rc = columnToIndex(cursorCol, m_tabWidth, - m_lines->lineAt(m_cursorLineNo)); + m_lines->lineAt(m_cursorLineNo)); return rc; } @@ -907,7 +924,7 @@ void ReParagraphs::draw(QPainter& painter, int top, int left) { * @return */ int ReParagraphs::indexToColumn(int index, int tabWidth, - const QString& string) { + const QString& string) { int rc = 0; if (index > 0) { int length = string.length(); @@ -974,13 +991,13 @@ void ReParagraphs::setLines(ReLines* lines) { * @param edit the parent, the edit field */ void ReParagraphBuilder::buildParagraph(ReParagraph& paragraph, int lineNo, - ReEdit* edit) { + ReEdit* edit) { if (paragraph.length() == 0) { int firstCol = edit->m_firstCol; const QString& text = edit->lines().lineAt(lineNo); ReLook* look = edit->lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD); ReLook* lookTab = edit->lookOf(ReLook::FG_GREY_LIGHT, - ReLook::BG_STANDARD); + ReLook::BG_STANDARD); paragraph.m_columns = 0; int ixTab; ReEditText* part; @@ -1067,14 +1084,14 @@ void ReParagraph::draw(QPainter& painter, int& top, int left) { * Constructor. */ ReMouseCatcher::ReMouseCatcher() : - m_clickObjects(), - m_vScrollBar(new ClickPosition(CO_VSCROLLBAR)), - m_hScrollBar(new ClickPosition(CO_HSCROLLBAR)), - m_hSlider(new ClickPosition(CO_HSLIDER)), - m_vSlider(new ClickPosition(CO_VSLIDER)), - m_lastMousePosition(), - m_lastTopVSlider(0), - m_lastLeftHSlider(0) { + m_clickObjects(), + m_vScrollBar(new ClickPosition(CO_VSCROLLBAR)), + m_hScrollBar(new ClickPosition(CO_HSCROLLBAR)), + m_hSlider(new ClickPosition(CO_HSLIDER)), + m_vSlider(new ClickPosition(CO_VSLIDER)), + m_lastMousePosition(), + m_lastTopVSlider(0), + m_lastLeftHSlider(0) { } /** @@ -1107,10 +1124,10 @@ void ReMouseCatcher::insertClickObject(ReMouseCatcher::ClickPosition* object) { * @return true: the mouse click is inside the horizontal sb */ bool ReMouseCatcher::handleHScrollBar(QMouseEvent* event, bool isDragged, - ReEdit* edit) { + ReEdit* edit) { QPoint pos = event->pos(); bool rc = rectContains(*m_hScrollBar, pos, "hScrollBar") - || (isDragged && m_hScrollBar->contains(m_lastMousePosition)); + || (isDragged && m_hScrollBar->contains(m_lastMousePosition)); if (rc) { if (isDragged) { int distance = pos.x() - m_lastMousePosition.x(); @@ -1118,8 +1135,8 @@ bool ReMouseCatcher::handleHScrollBar(QMouseEvent* event, bool isDragged, int moveGap = m_hScrollBar->width() - m_hSlider->width(); double position = moveGap == 0 ? 0.0 : double(sliderPos) / moveGap; int col = roundInt( - (edit->m_maxCols - edit->m_screenWidth) - * max(0.0, min(position, 1.0))); + (edit->m_maxCols - edit->m_screenWidth) + * max(0.0, min(position, 1.0))); //ReLogger::globalLogger()->logv(LOG_INFO, 4, // "x: %d dist: %d last: %d slPos: %d pos: %.2f gap: %d col: %d / %d scw: %d", // pos.x(), distance, m_lastLeftHSlider, sliderPos, position, moveGap, @@ -1144,10 +1161,10 @@ bool ReMouseCatcher::handleHScrollBar(QMouseEvent* event, bool isDragged, * @return true: the mouse click is inside the vertical sb */ bool ReMouseCatcher::handleVScrollBar(QMouseEvent* event, bool isDragged, - ReEdit* edit) { + ReEdit* edit) { QPoint pos = event->pos(); bool rc = rectContains(*m_vScrollBar, pos, "vScrollBar") - || (isDragged && m_vScrollBar->contains(m_lastMousePosition)); + || (isDragged && m_vScrollBar->contains(m_lastMousePosition)); if (rc) { if (isDragged) { int distance = pos.y() - m_lastMousePosition.y(); @@ -1155,8 +1172,8 @@ bool ReMouseCatcher::handleVScrollBar(QMouseEvent* event, bool isDragged, int moveGap = m_vScrollBar->height() - m_vSlider->height(); double position = moveGap == 0 ? 0.0 : double(sliderPos) / moveGap; int line = roundInt( - (edit->lines().lineCount() - edit->pageSize()) - * max(0.0, min(position, 1.0))); + (edit->lines().lineCount() - edit->pageSize()) + * max(0.0, min(position, 1.0))); edit->reposition(line, edit->m_cursorCol); } else { if (pos.y() < m_vSlider->top()) diff --git a/gui/ReEdit.hpp b/gui/ReEdit.hpp index 127be85..e10cde4 100644 --- a/gui/ReEdit.hpp +++ b/gui/ReEdit.hpp @@ -85,8 +85,8 @@ public: * @param source source to copy */ inline ReEditText(const ReEditText& source) : - m_text(source.m_text), - m_look(source.m_look) { + m_text(source.m_text), + m_look(source.m_look) { } /** Assignment operator. * @param source source to copy @@ -146,14 +146,14 @@ public: class ReParagraphBuilder { public: virtual void buildParagraph(ReParagraph& paragraph, int lineNo, - ReEdit* edit); + ReEdit* edit); }; class ReCursortLineBuilder: public ReParagraphBuilder { // ReParagraphBuilder interface public: virtual void buildParagraph(ReParagraph& paragraph, int lineNo, - ReEdit* edit); + ReEdit* edit); }; /** @@ -234,10 +234,10 @@ public: class ClickPosition: public QRect { public: ClickPosition(ClickObjType type) : - QRect(0, 0, 0, 0), - m_type(type), - m_title(), - m_object(NULL) { + QRect(0, 0, 0, 0), + m_type(type), + m_title(), + m_object(NULL) { } public: bool operator <(const ClickPosition& op) { @@ -302,6 +302,7 @@ public: }; public: explicit ReEdit(QWidget *parent = 0); + virtual ~ReEdit(); public: void assignColorsStandard(); void assignKeysStandard(); @@ -317,7 +318,7 @@ public: } ReLines& lines(); ReLook* lookOf(ReLook::ForeGround foreground, - ReLook::BackGround background); + ReLook::BackGround background); /** Returns the current page size. * return number of visible lines in the edit field */ @@ -342,8 +343,8 @@ public: protected: QBrush* createBrush(ReLook::BackGround background); void drawScrollbars(QPainter& painter, const QRect& rect, - double sizeVertical, double posVertical, double sizeHorizontal, - double posHorizontal); + double sizeVertical, double posVertical, double sizeHorizontal, + double posHorizontal); void ensureCursorVisible();protected slots: void keyPressEvent(QKeyEvent* event); void paintEvent(QPaintEvent *); diff --git a/gui/ReSettings.cpp b/gui/ReSettings.cpp index cde1280..ea6556f 100644 --- a/gui/ReSettings.cpp +++ b/gui/ReSettings.cpp @@ -114,6 +114,14 @@ ReSettings::ReSettings(const QString& path, const QString& prefix, setPath(path); } +/** + * Destructor. + */ +ReSettings::~ReSettings() +{ + +} + /* * Adds an entry to a history item at the first position. * diff --git a/gui/ReSettings.hpp b/gui/ReSettings.hpp index eca2444..eb4e73d 100644 --- a/gui/ReSettings.hpp +++ b/gui/ReSettings.hpp @@ -66,12 +66,16 @@ private: ReLogger* m_logger; }; +typedef QMap RePropertyMap; +typedef QMap*> ReChapterMap; + class ReSettings { public: static QString TRUE; static QString FALSE; public: ReSettings(const QString& path, const QString& prefix, ReLogger* logger); + ~ReSettings(); public: void addHistoryEntry(const char* key, const QString& value, char separator, int maxEntries); @@ -95,8 +99,8 @@ protected: QString m_path; QString m_fileHistory; QString m_fileSettings; - QMap m_settings; - QMap*> m_chapters; + RePropertyMap m_settings; + ReChapterMap m_chapters; ReLogger* m_logger; }; diff --git a/os/ReFileSystem.cpp b/os/ReFileSystem.cpp index b88f0a3..e1f99dd 100644 --- a/os/ReFileSystem.cpp +++ b/os/ReFileSystem.cpp @@ -12,14 +12,32 @@ #include "base/rebase.hpp" #include "os/reos.hpp" +enum { + LOC_READ_1 = LOC_FIRST_OF(LOC_FILESYSTEM), // 12001 + LOC_WRITE_1, // 12002 + LOC_WRITE_2, // 12003 + LOC_WRITE_3, // 12004 + LOC_WRITE_4, // 12005 + LOC_READ_2, // 12006 + LOC_MAKE_DIR_1, // 12007 + LOC_MAKE_DIR_2, // 12008 + LOC_MAKE_DIR_3, // 12009 + LOC_SET_PROPERTIES_1, // 12010 + LOC_SET_PROPERTIES_2, // 12011 + LOC_SET_PROPERTIES_3, // 12012 + LOC_REMOVE_1, // 12013 + LOC_REMOVE_2, // 12014 + LOC_REMOVE_3, // 12015 +}; /** * Constructor. * * @param name the name of the filesystem */ -ReFileSystem::ReFileSystem(const QString& name) : - m_name(name), m_writeable(false) +ReFileSystem::ReFileSystem(const QString& name, ReLogger* logger) : + m_name(name), m_writeable(false), m_logger(logger), m_buffer(), + m_blocksize(4*1024*1024), m_undefinedTime() { } @@ -29,7 +47,33 @@ ReFileSystem::ReFileSystem(const QString& name) : */ ReFileSystem::~ReFileSystem() { +} +/** + * Copy a file from a source filesystem to the current directory of the instance. + * + * @param source meta data of the source file (in current directory) + * @param sourceFS the filesystem containing the source + * @return EC_SUCCESS: success
+ * + */ +ReFileSystem::ErrorCode ReFileSystem::copy(ReFileMetaData& source, + ReFileSystem& sourceFS) +{ + int blocksize = min(m_blocksize, sourceFS.blocksize()); + ErrorCode rc = EC_SUCCESS; + ErrorCode rc2; + int64_t size = 0; + while(rc == EC_SUCCESS && size < source.m_size){ + if ( (rc2 = sourceFS.read(source, size, blocksize, m_buffer)) != EC_SUCCESS) + rc = rc2; + else if ( (rc2 = write(source.m_node, size, m_buffer)) != EC_SUCCESS) + rc = rc2; + size += blocksize; + } + close(); + sourceFS.close(); + return rc; } /** @@ -52,17 +96,66 @@ void ReFileSystem::setWriteable(bool writeable) { m_writeable = writeable; } +/** + * Returns the current blocksize (for copy operations). + * + * @return the current blocksize + */ +int ReFileSystem::blocksize() const +{ + return m_blocksize; +} + +/** + * Finds the first file given by a pattern. + * + * @param pattern pattern to find + * @param file OUT: the found file (valid only if return code is true + * @return true: at least one file found
+ * false: no file found + */ +bool ReFileSystem::first(const QString& pattern, ReFileMetaData& file) +{ + ReFileMetaDataList list; + QStringList names; + names.append(pattern); + ReIncludeExcludeMatcher matcher(names, + ReQStringUtils::m_emptyList, Qt::CaseInsensitive, true); + listInfos(matcher, list); + bool rc = list.size() > 0; + if (rc) + file = list.at(0); + return rc; +} + +/** + * Sets the size of the internal buffer for copy operations. + * + * @param blocksize the new blocksize + */ +void ReFileSystem::setBlocksize(int blocksize) +{ + m_blocksize = blocksize; +} + /** * Constructor. + * + * @param basePath the root directory of the filesystem
+ * Windows: e.g. "c:\" or "\\server\data"
+ * Linux: Mount point, e.g. "/" or "/media/data" + * @param logger */ -ReLocalFileSytem::ReLocalFileSytem(const QString& basePath) : - ReFileSystem("localfs"), +ReLocalFileSytem::ReLocalFileSytem(const QString& basePath, ReLogger* logger) : + ReFileSystem("localfs", logger), m_basePath(basePath), m_currentPath(basePath), - m_dir(basePath) + m_dir(basePath), + m_readFile(NULL), + m_writeFile(NULL) { - + setWriteable(true); } /** @@ -83,6 +176,21 @@ const QString& ReLocalFileSytem::basePath() const return m_basePath; } +/** + * Closes the open files. + */ +void ReLocalFileSytem::close() +{ + if (m_readFile != NULL){ + fclose(m_readFile); + m_readFile = NULL; + } + if (m_writeFile != NULL){ + fclose(m_writeFile); + m_writeFile = NULL; + } +} + /** * Returns the name of the current directory. * @@ -100,7 +208,7 @@ const QString& ReLocalFileSytem::directory() const * @return the count of the found entries (list.size()) */ int ReLocalFileSytem::listInfos(const ReIncludeExcludeMatcher& matcher, - QList& list) + ReFileMetaDataList& list) { list.clear(); const QStringList& patterns = matcher.includes().patterns(); @@ -116,16 +224,41 @@ int ReLocalFileSytem::listInfos(const ReIncludeExcludeMatcher& matcher, full.resize(pathLength); full.append(node.toUtf8()); if (stat(full.constData(), &info) == 0){ - ReFileMetaData* meta = new ReFileMetaData(node, - QDateTime::fromTime_t(info.st_mtime), - QDateTime::fromTime_t(info.st_ctime), - info.st_uid, info.st_gid, info.st_mode); - list.append(meta); + list.append(ReFileMetaData(node, + QDateTime::fromTime_t(info.st_mtime), + QDateTime::fromTime_t(info.st_ctime), + info.st_uid, info.st_gid, info.st_mode, info.st_size)); } } return list.size(); } +/** Creates a directory. + * @param node the name without path (in the current directory) + * @return EC_SUCCESS: successful
+ * EC_FS_READ_ONLY: the filesystem is readonly
+ * EC_ALREADY_EXISTS: a file with this name exists
+ * EC_NOT_ACCESSIBLE: creation failed + */ +ReFileSystem::ErrorCode ReLocalFileSytem::makeDir(const QString& node) +{ + ErrorCode rc = EC_SUCCESS; + if (! m_writeable){ + m_logger->log(LOG_ERROR, LOC_MAKE_DIR_1, + "filesystem is readonly"); + rc = EC_FS_READ_ONLY; + } else if (m_dir.exists(node)) { + m_logger->logv(LOG_ERROR, LOC_MAKE_DIR_2, + "node exists already: %s", fullNameAsUTF8(node).constData()); + rc = EC_ALREADY_EXISTS; + } else if (! m_dir.mkdir(node)){ + m_logger->logv(LOG_ERROR, LOC_MAKE_DIR_2, + "cannot create directory: %s", fullNameAsUTF8(node).constData()); + rc = EC_NOT_ACCESSIBLE; + } + return rc; +} + /** * Changes the current directory of the filesystem. * @@ -141,6 +274,211 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setDirectory(const QString& path) return rc; } +/** + * Reads a part of a file into a buffer. + * + * @param source the file to move + * @param offset first position to read + * @param size number of bytes to read + * @param buffer OUT: content of the file + * @return EC_SUCCESS: success
+ * EC_NOT_READABLE: file can't be opened
+ * EC_READ: error while reading + */ +ReFileSystem::ErrorCode ReLocalFileSytem::read(const ReFileMetaData& source, + int64_t offset, int size, QByteArray& buffer) +{ + ErrorCode rc = EC_SUCCESS; + if (offset == 0){ + if (m_readFile != NULL) + fclose(m_readFile); + QString fn = m_currentPath + source.m_node; + if ( (m_readFile = fopen(fn.toUtf8().constData(), "rb")) == NULL){ + m_logger->logv(LOG_ERROR, LOC_READ_1, + "cannot open for reading (%d): %s", + errno, fn.toUtf8().constData()); + rc = EC_NOT_READABLE; + } + } + if (m_readFile != NULL){ + ReFileUtils::seek(m_readFile, offset, SEEK_SET); + buffer.reserve(size); + int nRead = fread(buffer.data(), 1, size, m_readFile); + if (nRead < 0){ + m_logger->logv(LOG_ERROR, LOC_READ_2, + "cannot read (%d): %s", + errno, source.m_node.toUtf8().constData()); + nRead = 0; + rc = EC_READ; + } + buffer.resize(nRead); + if (feof(m_readFile)){ + fclose(m_readFile); + m_readFile = NULL; + } else { + fflush(m_readFile); + } + } + return rc; +} + +/** + * Sets the properties of a file in the current directory. + * + * @param source the properties to copy + * @param target the properties of the file to change + * @return EC_SUCCESS: successful
+ * EC_FS_READ_ONLY: filesystem is readonly
+ * EC_ALREADY_EXISTS: renaming failed: target node exists already
+ * EC_RENAME: renaming failed + * + */ +ReFileSystem::ErrorCode ReLocalFileSytem::setProperties( + const ReFileMetaData& source, const ReFileMetaData& target) +{ + ErrorCode rc = EC_SUCCESS; + if (! m_writeable){ + m_logger->log(LOG_ERROR, LOC_SET_PROPERTIES_1, + "filesystem is readonly"); + rc = EC_FS_READ_ONLY; + } else { + if (target.m_node != source.m_node){ + if (m_dir.exists(source.m_node)){ + rc = EC_ALREADY_EXISTS; + m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_2, + "renaming impossible: node exists: %s", + fullNameAsUTF8(target.m_node).constData()); + } else if (! m_dir.rename(target.m_node, source.m_node)){ + rc = EC_RENAME; + m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_3, + "renaming impossible: %s -> %s", + source.m_node.toUtf8().constData(), + fullNameAsUTF8(target.m_node).constData()); + } + } + if (rc == EC_SUCCESS && source.m_modified != target.m_modified + && source.m_modified != m_undefinedTime){ + } + if (rc == EC_SUCCESS && source.m_created != target.m_created + && source.m_created != m_undefinedTime){ + } + if (rc == EC_SUCCESS && source.m_mode != target.m_mode + && source.m_mode != (mode_t) -1){ + } + if (rc == EC_SUCCESS && source.m_owner != target.m_owner + && source.m_owner != -1){ + } + if (rc == EC_SUCCESS && source.m_group != target.m_group + && source.m_group != -1){ + } + } + return rc; +} + +/** + * Removes a file or directory. + * + * @param node the properties ot the node (in the current directory) + * @return EC_SUCCESS: successful
+ * EC_FS_READ_ONLY: filesystem is readonly
+ * EC_NOT_EXISTS: the node does not exist + * EC_NOT_ACCESSIBLE: removing failed + * + */ +ReFileSystem::ErrorCode ReLocalFileSytem::remove(const ReFileMetaData& node) +{ + ErrorCode rc = EC_SUCCESS; + if (! m_writeable){ + m_logger->log(LOG_ERROR, LOC_REMOVE_1, + "filesystem is readonly"); + rc = EC_FS_READ_ONLY; + } else if (! m_dir.exists(node.m_node)) { + m_logger->logv(LOG_ERROR, LOC_REMOVE_2, + "node does not exists: %s", fullNameAsUTF8(node.m_node).constData()); + rc = EC_NOT_EXISTS; + } else { + if (S_ISDIR(node.m_mode)){ + if (! m_dir.rmdir(node.m_node)){ + m_logger->logv(LOG_ERROR, LOC_REMOVE_3, + "cannot remove directory: %s", fullNameAsUTF8(node.m_node).constData()); + rc = EC_NOT_ACCESSIBLE; + } + } else { + if (! m_dir.remove(node.m_node)){ + m_logger->logv(LOG_ERROR, LOC_REMOVE_3, + "cannot remove file: %s", fullNameAsUTF8(node.m_node).constData()); + rc = EC_NOT_ACCESSIBLE; + } + } + } + return rc; +} + +/** + * Writes a buffer to a file. + * + * @param node the file to write (without path, inside the current directory) + * @param offset first position to write + * @param buffer content to write + * @return EC_SUCCESS: successful
+ * EC_FS_READ_ONLY: filesystem is readonly
+ * EC_NOT_WRITEABLE: open for writing failed + * EC_POSITION: file position not equals to offset + * EC_WRITE: writing failed + * + */ +ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node, + int64_t offset, const QByteArray& buffer) +{ + ErrorCode rc = EC_SUCCESS; + if (! writeable()){ + m_logger->log(LOG_ERROR, LOC_WRITE_1, + "filesystem is readonly"); + rc = EC_FS_READ_ONLY; + } else { + if (offset == 0){ + if (m_writeFile != NULL) + fclose(m_writeFile); + QString fn = m_currentPath + node; + if ( (m_writeFile = fopen(fn.toUtf8().constData(), "wb")) == NULL){ + m_logger->logv(LOG_ERROR, LOC_WRITE_2, + "cannot open for writing (%d): %s", + errno, fn.toUtf8().constData()); + rc = EC_NOT_WRITEABLE; + } + } + if (m_writeFile != NULL){ + int64_t position = ReFileUtils::tell(m_writeFile); + if (position != offset){ + rc = EC_POSITION; + m_logger->logv(LOG_ERROR, LOC_WRITE_4, + "wrong file position: %lld/%lld", + offset, position); + } else { + int nWritten = fwrite(buffer.constData(), + 1, buffer.length(), m_writeFile); + if (nWritten != buffer.length()){ + m_logger->logv(LOG_ERROR, LOC_WRITE_3, + "cannot write (%d): %s written: %d/%d", + errno, node.toUtf8().constData(), + nWritten, buffer.length()); + rc = EC_WRITE; + } + fflush(m_writeFile); + } + } + } + return rc; +} + + +/** + * Constructor. + */ +ReFileMetaData::ReFileMetaData() : m_node(), m_modified(), m_created(), + m_owner(0), m_group(0), m_mode(0), m_size(-1){ + +} /** * Constructor. @@ -151,15 +489,18 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setDirectory(const QString& path) * @param owner the owner of the file (UID) * @param group the group of the file (GID) * @param mode rights and attributs of the file + * @param size the filesize (0 for directories) */ ReFileMetaData::ReFileMetaData(const QString& node, const QDateTime& modified, - const QDateTime& created, int owner, int group, mode_t mode) : + const QDateTime& created, int owner, int group, mode_t mode, + int64_t size) : m_node(node), m_modified(modified), m_created(created), m_owner(owner), m_group(group), - m_mode(mode) + m_mode(mode), + m_size(size) { } @@ -171,3 +512,37 @@ ReFileMetaData::~ReFileMetaData() { } +/** + * Copy constructor. + * + * @param source source to copy + */ +ReFileMetaData::ReFileMetaData(const ReFileMetaData& source) : + m_node(source.m_node), + m_modified(source.m_modified), + m_created(source.m_created), + m_owner(source.m_owner), + m_group(source.m_group), + m_mode(source.m_mode), + m_size(source.m_size) +{ + +} + +/** + * Assign operator. + * + * @param source source to copy + * @return the instance itself + */ +ReFileMetaData&ReFileMetaData::operator =(const ReFileMetaData& source) +{ + m_node = source.m_node; + m_modified = source.m_modified; + m_created = source.m_created; + m_owner = source.m_owner; + m_group = source.m_group; + m_mode = source.m_mode; + m_size = source.m_size; + return *this; +} diff --git a/os/ReFileSystem.hpp b/os/ReFileSystem.hpp index b194c13..c0cf4d5 100644 --- a/os/ReFileSystem.hpp +++ b/os/ReFileSystem.hpp @@ -14,10 +14,13 @@ class ReFileMetaData { public: + ReFileMetaData(); ReFileMetaData(const QString& node, const QDateTime& modified, const QDateTime& created, - int owner, int group, mode_t mode); + int owner, int group, mode_t mode, int64_t size); virtual ~ReFileMetaData(); + ReFileMetaData(const ReFileMetaData& source); + ReFileMetaData& operator =(const ReFileMetaData& source); public: QString m_node; QDateTime m_modified; @@ -25,7 +28,9 @@ public: int16_t m_owner; int16_t m_group; mode_t m_mode; + int64_t m_size; }; +typedef QList ReFileMetaDataList; class ReFileSystem { public: @@ -41,19 +46,24 @@ public: EC_SUCCESS, EC_PATH_NOT_FOUND, EC_NOT_ACCESSIBLE, + EC_NOT_READABLE, + EC_READ, + EC_FS_READ_ONLY, + EC_NOT_WRITEABLE, + EC_WRITE, + EC_POSITION, + EC_ALREADY_EXISTS, + EC_NOT_EXISTS, + EC_RENAME, }; public: - ReFileSystem(const QString& name); + ReFileSystem(const QString& name, ReLogger* logger); virtual ~ReFileSystem(); public: - /** Changes the current directory of the filesystem. - * @param path the new current directory - * @return 0: success
- * EC_PATH_NOT_FOUND directory does not exist
- * EC_NOT_ACCESSIBLE parent not readable + /** Frees resources like open files. */ - virtual ErrorCode setDirectory(const QString& path) = 0; + virtual void close() = 0; /** Returns the name of the current directory. * @return the name of the current directory */ @@ -63,31 +73,111 @@ public: * @return the count of the found entries (list.size()) */ virtual int listInfos(const ReIncludeExcludeMatcher& matcher, - QList& list) = 0; + ReFileMetaDataList& list) = 0; + /** Creates a directory. + * @param node the name without path (in the current directory) + * @return EC_SUCCESS or error code + */ + virtual ErrorCode makeDir(const QString& node) = 0; + /** Reads a part of a file into a buffer. + * @param source the file to read (inside the current directory) + * @param offset first position to read + * @param size number of bytes to read + * @param buffer OUT: content of the file + * @return EC_SUCCESS or error code + */ + virtual ErrorCode read(const ReFileMetaData& source, + int64_t offset, int size, + QByteArray& buffer) = 0; + /** Removes a file or directory. + * @param node the properties ot the node (in the current directory) + * @return EC_SUCCESS or error code + */ + virtual ErrorCode remove(const ReFileMetaData& node) = 0; + /** Sets the current directory. + * @param path relative or absolute path. If absolute it must be part of the + * base path + * @return EC_SUCCESS or error code + */ + virtual ErrorCode setDirectory(const QString& path) = 0; + /** Sets the properties of a file in the current directory. + * @param source the properties to copy + * @param target the properties of the file to change + * @return EC_SUCCESS or error code + */ + virtual ErrorCode setProperties(const ReFileMetaData& source, + const ReFileMetaData& target) = 0; + /** Writes a buffer to a file. + * @param node the file to write (without path, inside the current directory) + * @param offset first position to write + * @param buffer content to write + * @return EC_SUCCESS or error code + */ + virtual ErrorCode write(const QString& target, + int64_t offset, const QByteArray& buffer) = 0; public: - bool writeable() const; + virtual ErrorCode copy(ReFileMetaData& source, ReFileSystem& sourceFS); +public: + int blocksize() const; + bool first(const QString& pattern, ReFileMetaData& file); + /** Returns the full name (with path). + * @param node the name without path + * @return the full filename + */ + inline QString fullName(const QString& node) const{ + return m_directory + node; + } + /** Returns the full name (with path) as UTF-8 string. + * @param node the name without path + * @return the full filename + */ + QByteArray fullNameAsUTF8(const QString& node) const{ + return (m_directory + node).toUtf8(); + } void setWriteable(bool writeable); + void setBlocksize(int blocksize); + bool writeable() const; + protected: QString m_name; QString m_directory; bool m_writeable; + ReLogger* m_logger; + QByteArray m_buffer; + int m_blocksize; + QDateTime m_undefinedTime; }; class ReLocalFileSytem : public ReFileSystem { public: - ReLocalFileSytem(const QString& basePath); + ReLocalFileSytem(const QString& basePath, ReLogger* logger); virtual ~ReLocalFileSytem(); public: const QString& basePath() const; const QString& directory() const; - virtual int listInfos(const ReIncludeExcludeMatcher& matcher, - QList& list); ErrorCode setDirectory(const QString& path); +public: + // ReFileSystem interface + virtual void close(); + virtual int listInfos(const ReIncludeExcludeMatcher& matcher, + ReFileMetaDataList& list); + ErrorCode makeDir(const QString& node); + virtual ErrorCode read(const ReFileMetaData& source, int64_t offset, + int size, QByteArray& buffer); + ErrorCode remove(const ReFileMetaData& node); + ErrorCode setProperties(const ReFileMetaData& source, const ReFileMetaData& target); + virtual ErrorCode write(const QString& target, int64_t offset, + const QByteArray& buffer); + protected: QString m_basePath; QString m_currentPath; QDir m_dir; + + FILE* m_readFile; + FILE* m_writeFile; + }; #endif /* OS_REFILESYSTEM_HPP_ */ diff --git a/remodules.hpp b/remodules.hpp index e7d5407..3f5aff9 100644 --- a/remodules.hpp +++ b/remodules.hpp @@ -32,6 +32,7 @@ enum { LOC_FILE, LOC_FILETREE, LOC_STATESTORAGE, // 120 + LOC_FILESYSTEM, }; #define LOC_FIRST_OF(moduleNo) (moduleNo*100+1) class RplModules {