// (2) The search pattern is wholly contained within the current buffer.
//
// (3) The current buffer ends with a partial match of the pattern. We will
- // note this for use in the next itteration, where we will check for the rest
+ // note this for use in the next iteration, where we will check for the rest
// of the pattern.
//
// All three of these are done in two steps. First we check for the pattern
// Start the search at the offset.
- long bufferOffset;
- if(fromOffset == 0) {
- seek(-1 * int(bufferSize()), End);
- bufferOffset = tell();
- }
- else {
- seek(fromOffset + -1 * int(bufferSize()), Beginning);
- bufferOffset = tell();
- }
+ if(fromOffset == 0)
+ fromOffset = length();
+
+ long bufferLength = bufferSize();
+ long bufferOffset = fromOffset + pattern.size();
// See the notes in find() for an explanation of this algorithm.
- for(buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) {
+ while(true) {
+
+ if(bufferOffset > bufferLength) {
+ bufferOffset -= bufferLength;
+ }
+ else {
+ bufferLength = bufferOffset;
+ bufferOffset = 0;
+ }
+ seek(bufferOffset);
+
+ buffer = readBlock(bufferLength);
+ if(buffer.isEmpty())
+ break;
// TODO: (1) previous partial match
// (2) pattern contained in current buffer
- long location = buffer.rfind(pattern);
+ const long location = buffer.rfind(pattern);
if(location >= 0) {
seek(originalPosition);
return bufferOffset + location;
}
// TODO: (3) partial match
-
- bufferOffset -= bufferSize();
- seek(bufferOffset);
}
// Since we hit the end of the file, reset the status before continuing.
--- /dev/null
+/***************************************************************************
+ copyright : (C) 2014 by Lukas Lalinsky
+ email : lukas@oxygene.sk
+ ***************************************************************************/
+
+/***************************************************************************
+ * This library is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License version *
+ * 2.1 as published by the Free Software Foundation. *
+ * *
+ * This library 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this library; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
+ * MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include <tfile.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "utils.h"
+
+using namespace TagLib;
+
+// File subclass that gives tests access to filesystem operations
+class PlainFile : public File {
+public:
+ PlainFile(FileName name) : File(name) { }
+ Tag *tag() const { return NULL; }
+ AudioProperties *audioProperties() const { return NULL; }
+ bool save(){ return false; }
+ void truncate(long length) { File::truncate(length); }
+};
+
+class TestFile : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestFile);
+ CPPUNIT_TEST(testFindInSmallFile);
+ CPPUNIT_TEST(testRFindInSmallFile);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ void testFindInSmallFile()
+ {
+ ScopedFileCopy copy("empty", ".ogg");
+ std::string name = copy.fileName();
+ {
+ PlainFile file(name.c_str());
+ file.seek(0);
+ file.writeBlock(ByteVector("0123456239", 10));
+ file.truncate(10);
+ }
+ {
+ PlainFile file(name.c_str());
+ CPPUNIT_ASSERT_EQUAL(10l, file.length());
+
+ CPPUNIT_ASSERT_EQUAL(2l, file.find(ByteVector("23", 2)));
+ CPPUNIT_ASSERT_EQUAL(2l, file.find(ByteVector("23", 2), 2));
+ CPPUNIT_ASSERT_EQUAL(7l, file.find(ByteVector("23", 2), 3));
+
+ file.seek(0);
+ const ByteVector v = file.readBlock(file.length());
+ CPPUNIT_ASSERT_EQUAL((uint)10, v.size());
+
+ CPPUNIT_ASSERT_EQUAL((long)v.find("23"), file.find("23"));
+ CPPUNIT_ASSERT_EQUAL((long)v.find("23", 2), file.find("23", 2));
+ CPPUNIT_ASSERT_EQUAL((long)v.find("23", 3), file.find("23", 3));
+ }
+ }
+
+ void testRFindInSmallFile()
+ {
+ ScopedFileCopy copy("empty", ".ogg");
+ std::string name = copy.fileName();
+ {
+ PlainFile file(name.c_str());
+ file.seek(0);
+ file.writeBlock(ByteVector("0123456239", 10));
+ file.truncate(10);
+ }
+ {
+ PlainFile file(name.c_str());
+ CPPUNIT_ASSERT_EQUAL(10l, file.length());
+
+ CPPUNIT_ASSERT_EQUAL(7l, file.rfind(ByteVector("23", 2)));
+ CPPUNIT_ASSERT_EQUAL(7l, file.rfind(ByteVector("23", 2), 7));
+ CPPUNIT_ASSERT_EQUAL(2l, file.rfind(ByteVector("23", 2), 6));
+
+ file.seek(0);
+ const ByteVector v = file.readBlock(file.length());
+ CPPUNIT_ASSERT_EQUAL((uint)10, v.size());
+
+ CPPUNIT_ASSERT_EQUAL((long)v.rfind("23"), file.rfind("23"));
+ CPPUNIT_ASSERT_EQUAL((long)v.rfind("23", 7), file.rfind("23", 7));
+ CPPUNIT_ASSERT_EQUAL((long)v.rfind("23", 6), file.rfind("23", 6));
+ }
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestFile);