mirror of
https://github.com/taglib/taglib.git
synced 2025-06-04 01:28:21 -04:00
Add a ByteVector-backed stream class
This commit is contained in:
parent
26c130c387
commit
65ca29b3e2
@ -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
|
||||
|
167
taglib/toolkit/tbytevectorstream.cpp
Normal file
167
taglib/toolkit/tbytevectorstream.cpp
Normal file
@ -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;
|
||||
}
|
145
taglib/toolkit/tbytevectorstream.h
Normal file
145
taglib/toolkit/tbytevectorstream.h
Normal file
@ -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
|
@ -80,38 +80,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.
|
||||
|
@ -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
|
||||
|
92
tests/test_bytevectorstream.cpp
Normal file
92
tests/test_bytevectorstream.cpp
Normal file
@ -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);
|
Loading…
x
Reference in New Issue
Block a user