aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukáš Lalinský <lalinsky@gmail.com>2011-04-12 14:28:02 +0200
committerLukáš Lalinský <lalinsky@gmail.com>2011-04-12 14:28:02 +0200
commit65ca29b3e28e52a9c47158115418816b0e93cb00 (patch)
tree080aea1eb55c004e717f6a9c32f9629c167a24f5
parent26c130c3879a1eb2c07c784a91464911c42e5bab (diff)
Add a ByteVector-backed stream class
-rw-r--r--taglib/CMakeLists.txt1
-rw-r--r--taglib/toolkit/tbytevectorstream.cpp167
-rw-r--r--taglib/toolkit/tbytevectorstream.h145
-rw-r--r--taglib/toolkit/tfilestream.h32
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/test_bytevectorstream.cpp92
6 files changed, 406 insertions, 32 deletions
diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt
index 3647caed..645d5546 100644
--- a/taglib/CMakeLists.txt
+++ b/taglib/CMakeLists.txt
@@ -161,6 +161,7 @@ set(toolkit_SRCS
toolkit/tstringlist.cpp
toolkit/tbytevector.cpp
toolkit/tbytevectorlist.cpp
+ toolkit/tbytevectorstream.cpp
toolkit/tiostream.cpp
toolkit/tfile.cpp
toolkit/tfilestream.cpp
diff --git a/taglib/toolkit/tbytevectorstream.cpp b/taglib/toolkit/tbytevectorstream.cpp
new file mode 100644
index 00000000..a01da552
--- /dev/null
+++ b/taglib/toolkit/tbytevectorstream.cpp
@@ -0,0 +1,167 @@
+/***************************************************************************
+ copyright : (C) 2011 by Lukas Lalinsky
+ email : lalinsky@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * 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 *
+ * *
+ * Alternatively, this file is available under the Mozilla Public *
+ * License Version 1.1. You may obtain a copy of the License at *
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
+#include "tbytevectorstream.h"
+#include "tstring.h"
+#include "tdebug.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <stdlib.h>
+
+using namespace TagLib;
+
+class ByteVectorStream::ByteVectorStreamPrivate
+{
+public:
+ ByteVectorStreamPrivate(const ByteVector &data);
+
+ ByteVector data;
+ long position;
+};
+
+ByteVectorStream::ByteVectorStreamPrivate::ByteVectorStreamPrivate(const ByteVector &data) :
+ data(data),
+ position(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+ByteVectorStream::ByteVectorStream(const ByteVector &data)
+{
+ d = new ByteVectorStreamPrivate(data);
+}
+
+ByteVectorStream::~ByteVectorStream()
+{
+ delete d;
+}
+
+FileName ByteVectorStream::name() const
+{
+ return FileName(""); // XXX do we need a name?
+}
+
+ByteVector ByteVectorStream::readBlock(ulong length)
+{
+ if(length == 0)
+ return ByteVector::null;
+
+ ByteVector v = d->data.mid(d->position, length);
+ d->position += v.size();
+ return v;
+}
+
+void ByteVectorStream::writeBlock(const ByteVector &data)
+{
+ uint size = data.size();
+ if(d->position + size > length()) {
+ truncate(d->position + size);
+ }
+ memcpy(d->data.data() + d->position, data.data(), size);
+ d->position += size;
+}
+
+void ByteVectorStream::insert(const ByteVector &data, ulong start, ulong replace)
+{
+ long sizeDiff = data.size() - replace;
+ if(sizeDiff < 0) {
+ removeBlock(start + data.size(), -sizeDiff);
+ }
+ else if(sizeDiff > 0) {
+ truncate(length() + sizeDiff);
+ ulong readPosition = start + replace;
+ ulong writePosition = start + data.size();
+ memmove(d->data.data() + writePosition, d->data.data() + readPosition, length() - sizeDiff - readPosition);
+ }
+ seek(start);
+ writeBlock(data);
+}
+
+void ByteVectorStream::removeBlock(ulong start, ulong length)
+{
+ ulong readPosition = start + length;
+ ulong writePosition = start;
+ if(readPosition < ulong(ByteVectorStream::length())) {
+ ulong bytesToMove = ByteVectorStream::length() - readPosition;
+ memmove(d->data.data() + writePosition, d->data.data() + readPosition, bytesToMove);
+ writePosition += bytesToMove;
+ }
+ d->position = writePosition;
+ truncate(writePosition);
+}
+
+bool ByteVectorStream::readOnly() const
+{
+ return false;
+}
+
+bool ByteVectorStream::isOpen() const
+{
+ return true;
+}
+
+void ByteVectorStream::seek(long offset, Position p)
+{
+ switch(p) {
+ case Beginning:
+ d->position = offset;
+ break;
+ case Current:
+ d->position += offset;
+ break;
+ case End:
+ d->position = length() - offset;
+ break;
+ }
+}
+
+void ByteVectorStream::clear()
+{
+}
+
+long ByteVectorStream::tell() const
+{
+ return d->position;
+}
+
+long ByteVectorStream::length()
+{
+ return d->data.size();
+}
+
+void ByteVectorStream::truncate(long length)
+{
+ d->data.resize(length);
+}
+
+ByteVector *ByteVectorStream::data()
+{
+ return &d->data;
+}
diff --git a/taglib/toolkit/tbytevectorstream.h b/taglib/toolkit/tbytevectorstream.h
new file mode 100644
index 00000000..456b854e
--- /dev/null
+++ b/taglib/toolkit/tbytevectorstream.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+ copyright : (C) 2011 by Lukas Lalinsky
+ email : lalinsky@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * 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 *
+ * *
+ * Alternatively, this file is available under the Mozilla Public *
+ * License Version 1.1. You may obtain a copy of the License at *
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
+#ifndef TAGLIB_BYTEVECTORSTREAM_H
+#define TAGLIB_BYTEVECTORSTREAM_H
+
+#include "taglib_export.h"
+#include "taglib.h"
+#include "tbytevector.h"
+#include "tiostream.h"
+
+namespace TagLib {
+
+ class String;
+ class Tag;
+ class AudioProperties;
+
+ //! In-memory Stream class using ByteVector for its storage.
+
+ class TAGLIB_EXPORT ByteVectorStream : public IOStream
+ {
+ public:
+ /*!
+ * Construct a File object and opens the \a file. \a file should be a
+ * be a C-string in the local file system encoding.
+ */
+ ByteVectorStream(const ByteVector &data);
+
+ /*!
+ * Destroys this ByteVectorStream instance.
+ */
+ virtual ~ByteVectorStream();
+
+ /*!
+ * Returns the file name in the local file system encoding.
+ */
+ FileName name() const;
+
+ /*!
+ * Reads a block of size \a length at the current get pointer.
+ */
+ ByteVector readBlock(ulong length);
+
+ /*!
+ * Attempts to write the block \a data at the current get pointer. If the
+ * file is currently only opened read only -- i.e. readOnly() returns true --
+ * this attempts to reopen the file in read/write mode.
+ *
+ * \note This should be used instead of using the streaming output operator
+ * for a ByteVector. And even this function is significantly slower than
+ * doing output with a char[].
+ */
+ void writeBlock(const ByteVector &data);
+
+ /*!
+ * Insert \a data at position \a start in the file overwriting \a replace
+ * bytes of the original content.
+ *
+ * \note This method is slow since it requires rewriting all of the file
+ * after the insertion point.
+ */
+ void insert(const ByteVector &data, ulong start = 0, ulong replace = 0);
+
+ /*!
+ * Removes a block of the file starting a \a start and continuing for
+ * \a length bytes.
+ *
+ * \note This method is slow since it involves rewriting all of the file
+ * after the removed portion.
+ */
+ void removeBlock(ulong start = 0, ulong length = 0);
+
+ /*!
+ * Returns true if the file is read only (or if the file can not be opened).
+ */
+ bool readOnly() const;
+
+ /*!
+ * Since the file can currently only be opened as an argument to the
+ * constructor (sort-of by design), this returns if that open succeeded.
+ */
+ bool isOpen() const;
+
+ /*!
+ * Move the I/O pointer to \a offset in the file from position \a p. This
+ * defaults to seeking from the beginning of the file.
+ *
+ * \see Position
+ */
+ void seek(long offset, Position p = Beginning);
+
+ /*!
+ * Reset the end-of-file and error flags on the file.
+ */
+ void clear();
+
+ /*!
+ * Returns the current offset within the file.
+ */
+ long tell() const;
+
+ /*!
+ * Returns the length of the file.
+ */
+ long length();
+
+ /*!
+ * Truncates the file to a \a length.
+ */
+ void truncate(long length);
+
+ ByteVector *data();
+
+ protected:
+
+ private:
+ class ByteVectorStreamPrivate;
+ ByteVectorStreamPrivate *d;
+ };
+
+}
+
+#endif
diff --git a/taglib/toolkit/tfilestream.h b/taglib/toolkit/tfilestream.h
index ac17ef06..65ed5fb5 100644
--- a/taglib/toolkit/tfilestream.h
+++ b/taglib/toolkit/tfilestream.h
@@ -81,38 +81,6 @@ namespace TagLib {
void writeBlock(const ByteVector &data);
/*!
- * Returns the offset in the file that \a pattern occurs at or -1 if it can
- * not be found. If \a before is set, the search will only continue until the
- * pattern \a before is found. This is useful for tagging purposes to search
- * for a tag before the synch frame.
- *
- * Searching starts at \a fromOffset, which defaults to the beginning of the
- * file.
- *
- * \note This has the practial limitation that \a pattern can not be longer
- * than the buffer size used by readBlock(). Currently this is 1024 bytes.
- */
- long find(const ByteVector &pattern,
- long fromOffset = 0,
- const ByteVector &before = ByteVector::null);
-
- /*!
- * Returns the offset in the file that \a pattern occurs at or -1 if it can
- * not be found. If \a before is set, the search will only continue until the
- * pattern \a before is found. This is useful for tagging purposes to search
- * for a tag before the synch frame.
- *
- * Searching starts at \a fromOffset and proceeds from the that point to the
- * beginning of the file and defaults to the end of the file.
- *
- * \note This has the practial limitation that \a pattern can not be longer
- * than the buffer size used by readBlock(). Currently this is 1024 bytes.
- */
- long rfind(const ByteVector &pattern,
- long fromOffset = 0,
- const ByteVector &before = ByteVector::null);
-
- /*!
* Insert \a data at position \a start in the file overwriting \a replace
* bytes of the original content.
*
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 86408af0..d169a626 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -30,6 +30,7 @@ SET(test_runner_SRCS
test_trueaudio.cpp
test_bytevector.cpp
test_bytevectorlist.cpp
+ test_bytevectorstream.cpp
test_string.cpp
test_fileref.cpp
test_id3v1.cpp
diff --git a/tests/test_bytevectorstream.cpp b/tests/test_bytevectorstream.cpp
new file mode 100644
index 00000000..b5114679
--- /dev/null
+++ b/tests/test_bytevectorstream.cpp
@@ -0,0 +1,92 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <tbytevectorstream.h>
+
+using namespace std;
+using namespace TagLib;
+
+class TestByteVectorStream : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestByteVectorStream);
+ CPPUNIT_TEST(testInitialData);
+ CPPUNIT_TEST(testWriteBlock);
+ CPPUNIT_TEST(testWriteBlockResize);
+ CPPUNIT_TEST(testReadBlock);
+ CPPUNIT_TEST(testRemoveBlock);
+ CPPUNIT_TEST(testInsert);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ void testInitialData()
+ {
+ ByteVector v("abcd");
+ ByteVectorStream stream(v);
+
+ CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), *stream.data());
+ }
+
+ void testWriteBlock()
+ {
+ ByteVector v("abcd");
+ ByteVectorStream stream(v);
+
+ stream.seek(1);
+ stream.writeBlock(ByteVector("xx"));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("axxd"), *stream.data());
+ }
+
+ void testWriteBlockResize()
+ {
+ ByteVector v("abcd");
+ ByteVectorStream stream(v);
+
+ stream.seek(3);
+ stream.writeBlock(ByteVector("xx"));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("abcxx"), *stream.data());
+ stream.seek(5);
+ stream.writeBlock(ByteVector("yy"));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("abcxxyy"), *stream.data());
+ }
+
+ void testReadBlock()
+ {
+ ByteVector v("abcd");
+ ByteVectorStream stream(v);
+
+ CPPUNIT_ASSERT_EQUAL(ByteVector("a"), stream.readBlock(1));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("bc"), stream.readBlock(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("d"), stream.readBlock(3));
+ CPPUNIT_ASSERT_EQUAL(ByteVector::null, stream.readBlock(3));
+ }
+
+ void testRemoveBlock()
+ {
+ ByteVector v("abcd");
+ ByteVectorStream stream(v);
+
+ stream.removeBlock(1, 1);
+ CPPUNIT_ASSERT_EQUAL(ByteVector("acd"), *stream.data());
+ stream.removeBlock(0, 2);
+ CPPUNIT_ASSERT_EQUAL(ByteVector("d"), *stream.data());
+ stream.removeBlock(0, 2);
+ CPPUNIT_ASSERT_EQUAL(ByteVector(""), *stream.data());
+ }
+
+ void testInsert()
+ {
+ ByteVector v("abcd");
+ ByteVectorStream stream(v);
+
+ stream.insert(ByteVector("xx"), 1, 1);
+ CPPUNIT_ASSERT_EQUAL(ByteVector("axxcd"), *stream.data());
+ stream.insert(ByteVector("yy"), 0, 2);
+ CPPUNIT_ASSERT_EQUAL(ByteVector("yyxcd"), *stream.data());
+ stream.insert(ByteVector("foa"), 3, 2);
+ CPPUNIT_ASSERT_EQUAL(ByteVector("yyxfoa"), *stream.data());
+ stream.insert(ByteVector("123"), 3, 0);
+ CPPUNIT_ASSERT_EQUAL(ByteVector("yyx123foa"), *stream.data());
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVectorStream);