mirror of
https://github.com/taglib/taglib.git
synced 2025-06-04 01:28:21 -04:00
Merge branch 'abstract-io'
This commit is contained in:
commit
8eb32577bd
@ -239,7 +239,10 @@ set(toolkit_SRCS
|
||||
toolkit/tstringlist.cpp
|
||||
toolkit/tbytevector.cpp
|
||||
toolkit/tbytevectorlist.cpp
|
||||
toolkit/tbytevectorstream.cpp
|
||||
toolkit/tiostream.cpp
|
||||
toolkit/tfile.cpp
|
||||
toolkit/tfilestream.cpp
|
||||
toolkit/tdebug.cpp
|
||||
toolkit/unicode.cpp
|
||||
)
|
||||
|
@ -92,6 +92,13 @@ APE::File::File(FileName file, bool readProperties,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
APE::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
APE::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -91,6 +91,14 @@ namespace TagLib {
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an WavPack file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -369,6 +369,13 @@ ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle proper
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
ASF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle)
|
||||
: TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
ASF::File::~File()
|
||||
{
|
||||
for(unsigned int i = 0; i < d->objects.size(); i++) {
|
||||
|
@ -57,6 +57,16 @@ namespace TagLib {
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an ASF file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -119,6 +119,15 @@ FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
d->ID3v2FrameFactory = frameFactory;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
FLAC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -90,6 +90,19 @@ namespace TagLib {
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a FLAC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* If this file contains and ID3v2 tag the frames will be created using
|
||||
* \a frameFactory.
|
||||
*/
|
||||
// BIC: merge with the above constructor
|
||||
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -72,6 +72,13 @@ MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle a
|
||||
read(readProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
: TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
MP4::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -58,6 +58,16 @@ namespace TagLib {
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a MP4 file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -96,6 +96,13 @@ MPC::File::File(FileName file, bool readProperties,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
MPC::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
MPC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -88,6 +88,14 @@ namespace TagLib {
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an MPC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -113,6 +113,16 @@ MPEG::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
MPEG::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate(frameFactory);
|
||||
|
||||
if(isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
MPEG::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -85,9 +85,22 @@ namespace TagLib {
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored. The frames will be created using
|
||||
* \a frameFactory.
|
||||
*
|
||||
* \deprecated This constructor will be dropped in favor of the one below
|
||||
* in a future version.
|
||||
*/
|
||||
File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an MPEG file from \a stream. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored. The frames will be created using
|
||||
* \a frameFactory.
|
||||
*/
|
||||
// BIC: merge with the above constructor
|
||||
File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
|
@ -75,6 +75,13 @@ Ogg::FLAC::File::File(FileName file, bool readProperties,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Ogg::FLAC::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : Ogg::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Ogg::FLAC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -71,6 +71,14 @@ namespace TagLib {
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an Ogg/FLAC file from \a file. If \a readProperties is true
|
||||
* the file's audio properties will also be read using \a propertiesStyle.
|
||||
* If false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -213,6 +213,11 @@ Ogg::File::File(FileName file) : TagLib::File(file)
|
||||
d = new FilePrivate;
|
||||
}
|
||||
|
||||
Ogg::File::File(IOStream *stream) : TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -92,6 +92,17 @@ namespace TagLib {
|
||||
*/
|
||||
File(FileName file);
|
||||
|
||||
/*!
|
||||
* Contructs an Ogg file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note This constructor is protected since Ogg::File shouldn't be
|
||||
* instantiated directly but rather should be used through the codec
|
||||
* specific subclasses.
|
||||
*/
|
||||
File(IOStream *stream);
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
@ -65,6 +65,13 @@ Speex::File::File(FileName file, bool readProperties,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Speex::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : Ogg::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Speex::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -63,6 +63,14 @@ namespace TagLib {
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a Speex file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -68,6 +68,13 @@ Vorbis::File::File(FileName file, bool readProperties,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Vorbis::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : Ogg::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Vorbis::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -70,6 +70,14 @@ namespace TagLib {
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a Vorbis file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -65,6 +65,14 @@ RIFF::AIFF::File::File(FileName file, bool readProperties,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
RIFF::AIFF::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : RIFF::File(stream, BigEndian)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
if(isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
RIFF::AIFF::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -65,6 +65,14 @@ namespace TagLib {
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an AIFF file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -79,6 +79,15 @@ RIFF::File::File(FileName file, Endianness endianness) : TagLib::File(file)
|
||||
read();
|
||||
}
|
||||
|
||||
RIFF::File::File(IOStream *stream, Endianness endianness) : TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
d->endianness = endianness;
|
||||
|
||||
if(isOpen())
|
||||
read();
|
||||
}
|
||||
|
||||
TagLib::uint RIFF::File::riffSize() const
|
||||
{
|
||||
return d->size;
|
||||
|
@ -56,6 +56,7 @@ namespace TagLib {
|
||||
enum Endianness { BigEndian, LittleEndian };
|
||||
|
||||
File(FileName file, Endianness endianness);
|
||||
File(IOStream *stream, Endianness endianness);
|
||||
|
||||
/*!
|
||||
* \return The size of the main RIFF chunk.
|
||||
|
@ -65,6 +65,14 @@ RIFF::WAV::File::File(FileName file, bool readProperties,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
RIFF::WAV::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : RIFF::File(stream, LittleEndian)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
if(isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
RIFF::WAV::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -65,6 +65,14 @@ namespace TagLib {
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an WAV file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
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
|
@ -24,161 +24,71 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "tfile.h"
|
||||
#include "tfilestream.h"
|
||||
#include "tstring.h"
|
||||
#include "tdebug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <wchar.h>
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# define ftruncate _chsize
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef R_OK
|
||||
# define R_OK 4
|
||||
#endif
|
||||
#ifndef W_OK
|
||||
# define W_OK 2
|
||||
#endif
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef FileName FileNameHandle;
|
||||
|
||||
#else
|
||||
|
||||
struct FileNameHandle : public std::string
|
||||
{
|
||||
FileNameHandle(FileName name) : std::string(name) {}
|
||||
operator FileName () const { return c_str(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate(FileName fileName);
|
||||
FilePrivate(IOStream *stream);
|
||||
|
||||
FILE *file;
|
||||
|
||||
FileNameHandle name;
|
||||
|
||||
bool readOnly;
|
||||
IOStream *stream;
|
||||
bool valid;
|
||||
ulong size;
|
||||
static const uint bufferSize = 1024;
|
||||
};
|
||||
|
||||
File::FilePrivate::FilePrivate(FileName fileName) :
|
||||
file(0),
|
||||
name(fileName),
|
||||
readOnly(true),
|
||||
valid(true),
|
||||
size(0)
|
||||
File::FilePrivate::FilePrivate(IOStream *stream) :
|
||||
stream(stream),
|
||||
valid(true)
|
||||
{
|
||||
// First try with read / write mode, if that fails, fall back to read only.
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
if(wcslen((const wchar_t *) fileName) > 0) {
|
||||
|
||||
file = _wfopen(name, L"rb+");
|
||||
|
||||
if(file)
|
||||
readOnly = false;
|
||||
else
|
||||
file = _wfopen(name, L"rb");
|
||||
|
||||
if(file)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
file = fopen(name, "rb+");
|
||||
|
||||
if(file)
|
||||
readOnly = false;
|
||||
else
|
||||
file = fopen(name, "rb");
|
||||
|
||||
if(!file)
|
||||
{
|
||||
debug("Could not open file " + String((const char *) name));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
File::File(FileName file)
|
||||
File::File(FileName fileName)
|
||||
{
|
||||
d = new FilePrivate(file);
|
||||
IOStream *stream = new FileStream(fileName);
|
||||
d = new FilePrivate(stream);
|
||||
}
|
||||
|
||||
File::File(IOStream *stream)
|
||||
{
|
||||
d = new FilePrivate(stream);
|
||||
}
|
||||
|
||||
File::~File()
|
||||
{
|
||||
if(d->file)
|
||||
fclose(d->file);
|
||||
if(d->stream)
|
||||
delete d->stream;
|
||||
delete d;
|
||||
}
|
||||
|
||||
FileName File::name() const
|
||||
{
|
||||
return d->name;
|
||||
return d->stream->name();
|
||||
}
|
||||
|
||||
ByteVector File::readBlock(ulong length)
|
||||
{
|
||||
if(!d->file) {
|
||||
debug("File::readBlock() -- Invalid File");
|
||||
return ByteVector::null;
|
||||
}
|
||||
|
||||
if(length == 0)
|
||||
return ByteVector::null;
|
||||
|
||||
if(length > FilePrivate::bufferSize &&
|
||||
length > ulong(File::length()))
|
||||
{
|
||||
length = File::length();
|
||||
}
|
||||
|
||||
ByteVector v(static_cast<uint>(length));
|
||||
const int count = fread(v.data(), sizeof(char), length, d->file);
|
||||
v.resize(count);
|
||||
return v;
|
||||
return d->stream->readBlock(length);
|
||||
}
|
||||
|
||||
void File::writeBlock(const ByteVector &data)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
if(d->readOnly) {
|
||||
debug("File::writeBlock() -- attempted to write to a file that is not writable");
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(data.data(), sizeof(char), data.size(), d->file);
|
||||
d->stream->writeBlock(data);
|
||||
}
|
||||
|
||||
long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &before)
|
||||
{
|
||||
if(!d->file || pattern.size() > d->bufferSize)
|
||||
if(!d->stream || pattern.size() > d->bufferSize)
|
||||
return -1;
|
||||
|
||||
// The position in the file that the current buffer starts at.
|
||||
@ -274,7 +184,7 @@ long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &be
|
||||
|
||||
long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &before)
|
||||
{
|
||||
if(!d->file || pattern.size() > d->bufferSize)
|
||||
if(!d->stream || pattern.size() > d->bufferSize)
|
||||
return -1;
|
||||
|
||||
// The position in the file that the current buffer starts at.
|
||||
@ -342,147 +252,22 @@ long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &b
|
||||
|
||||
void File::insert(const ByteVector &data, ulong start, ulong replace)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
if(data.size() == replace) {
|
||||
seek(start);
|
||||
writeBlock(data);
|
||||
return;
|
||||
}
|
||||
else if(data.size() < replace) {
|
||||
seek(start);
|
||||
writeBlock(data);
|
||||
removeBlock(start + data.size(), replace - data.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore
|
||||
// and avoid TagLib's high level API for rendering just copying parts of
|
||||
// the file that don't contain tag data.
|
||||
//
|
||||
// Now I'll explain the steps in this ugliness:
|
||||
|
||||
// First, make sure that we're working with a buffer that is longer than
|
||||
// the *differnce* in the tag sizes. We want to avoid overwriting parts
|
||||
// that aren't yet in memory, so this is necessary.
|
||||
|
||||
ulong bufferLength = bufferSize();
|
||||
|
||||
while(data.size() - replace > bufferLength)
|
||||
bufferLength += bufferSize();
|
||||
|
||||
// Set where to start the reading and writing.
|
||||
|
||||
long readPosition = start + replace;
|
||||
long writePosition = start;
|
||||
|
||||
ByteVector buffer;
|
||||
ByteVector aboutToOverwrite(static_cast<uint>(bufferLength));
|
||||
|
||||
// This is basically a special case of the loop below. Here we're just
|
||||
// doing the same steps as below, but since we aren't using the same buffer
|
||||
// size -- instead we're using the tag size -- this has to be handled as a
|
||||
// special case. We're also using File::writeBlock() just for the tag.
|
||||
// That's a bit slower than using char *'s so, we're only doing it here.
|
||||
|
||||
seek(readPosition);
|
||||
int bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
|
||||
readPosition += bufferLength;
|
||||
|
||||
seek(writePosition);
|
||||
writeBlock(data);
|
||||
writePosition += data.size();
|
||||
|
||||
buffer = aboutToOverwrite;
|
||||
|
||||
// In case we've already reached the end of file...
|
||||
|
||||
buffer.resize(bytesRead);
|
||||
|
||||
// Ok, here's the main loop. We want to loop until the read fails, which
|
||||
// means that we hit the end of the file.
|
||||
|
||||
while(!buffer.isEmpty()) {
|
||||
|
||||
// Seek to the current read position and read the data that we're about
|
||||
// to overwrite. Appropriately increment the readPosition.
|
||||
|
||||
seek(readPosition);
|
||||
bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
|
||||
aboutToOverwrite.resize(bytesRead);
|
||||
readPosition += bufferLength;
|
||||
|
||||
// Check to see if we just read the last block. We need to call clear()
|
||||
// if we did so that the last write succeeds.
|
||||
|
||||
if(ulong(bytesRead) < bufferLength)
|
||||
clear();
|
||||
|
||||
// Seek to the write position and write our buffer. Increment the
|
||||
// writePosition.
|
||||
|
||||
seek(writePosition);
|
||||
fwrite(buffer.data(), sizeof(char), buffer.size(), d->file);
|
||||
writePosition += buffer.size();
|
||||
|
||||
// Make the current buffer the data that we read in the beginning.
|
||||
|
||||
buffer = aboutToOverwrite;
|
||||
|
||||
// Again, we need this for the last write. We don't want to write garbage
|
||||
// at the end of our file, so we need to set the buffer size to the amount
|
||||
// that we actually read.
|
||||
|
||||
bufferLength = bytesRead;
|
||||
}
|
||||
d->stream->insert(data, start, replace);
|
||||
}
|
||||
|
||||
void File::removeBlock(ulong start, ulong length)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
ulong bufferLength = bufferSize();
|
||||
|
||||
long readPosition = start + length;
|
||||
long writePosition = start;
|
||||
|
||||
ByteVector buffer(static_cast<uint>(bufferLength));
|
||||
|
||||
ulong bytesRead = 1;
|
||||
|
||||
while(bytesRead != 0) {
|
||||
seek(readPosition);
|
||||
bytesRead = fread(buffer.data(), sizeof(char), bufferLength, d->file);
|
||||
readPosition += bytesRead;
|
||||
|
||||
// Check to see if we just read the last block. We need to call clear()
|
||||
// if we did so that the last write succeeds.
|
||||
|
||||
if(bytesRead < bufferLength)
|
||||
clear();
|
||||
|
||||
seek(writePosition);
|
||||
fwrite(buffer.data(), sizeof(char), bytesRead, d->file);
|
||||
writePosition += bytesRead;
|
||||
}
|
||||
truncate(writePosition);
|
||||
d->stream->removeBlock(start, length);
|
||||
}
|
||||
|
||||
bool File::readOnly() const
|
||||
{
|
||||
return d->readOnly;
|
||||
}
|
||||
|
||||
bool File::isReadable(const char *file)
|
||||
{
|
||||
return access(file, R_OK) == 0;
|
||||
return d->stream->readOnly();
|
||||
}
|
||||
|
||||
bool File::isOpen() const
|
||||
{
|
||||
return (d->file != NULL);
|
||||
return d->stream->isOpen();
|
||||
}
|
||||
|
||||
bool File::isValid() const
|
||||
@ -492,53 +277,32 @@ bool File::isValid() const
|
||||
|
||||
void File::seek(long offset, Position p)
|
||||
{
|
||||
if(!d->file) {
|
||||
debug("File::seek() -- trying to seek in a file that isn't opened.");
|
||||
return;
|
||||
}
|
||||
d->stream->seek(offset, IOStream::Position(p));
|
||||
}
|
||||
|
||||
switch(p) {
|
||||
case Beginning:
|
||||
fseek(d->file, offset, SEEK_SET);
|
||||
break;
|
||||
case Current:
|
||||
fseek(d->file, offset, SEEK_CUR);
|
||||
break;
|
||||
case End:
|
||||
fseek(d->file, offset, SEEK_END);
|
||||
break;
|
||||
}
|
||||
void File::truncate(long length)
|
||||
{
|
||||
d->stream->truncate(length);
|
||||
}
|
||||
|
||||
void File::clear()
|
||||
{
|
||||
clearerr(d->file);
|
||||
d->stream->clear();
|
||||
}
|
||||
|
||||
long File::tell() const
|
||||
{
|
||||
return ftell(d->file);
|
||||
return d->stream->tell();
|
||||
}
|
||||
|
||||
long File::length()
|
||||
{
|
||||
// Do some caching in case we do multiple calls.
|
||||
return d->stream->length();
|
||||
}
|
||||
|
||||
if(d->size > 0)
|
||||
return d->size;
|
||||
|
||||
if(!d->file)
|
||||
return 0;
|
||||
|
||||
long curpos = tell();
|
||||
|
||||
seek(0, End);
|
||||
long endpos = tell();
|
||||
|
||||
seek(curpos, Beginning);
|
||||
|
||||
d->size = endpos;
|
||||
return endpos;
|
||||
bool File::isReadable(const char *file)
|
||||
{
|
||||
return access(file, R_OK) == 0;
|
||||
}
|
||||
|
||||
bool File::isWritable(const char *file)
|
||||
@ -550,18 +314,13 @@ bool File::isWritable(const char *file)
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void File::setValid(bool valid)
|
||||
{
|
||||
d->valid = valid;
|
||||
}
|
||||
|
||||
void File::truncate(long length)
|
||||
{
|
||||
ftruncate(fileno(d->file), length);
|
||||
}
|
||||
|
||||
TagLib::uint File::bufferSize()
|
||||
{
|
||||
return FilePrivate::bufferSize;
|
||||
}
|
||||
|
||||
void File::setValid(bool valid)
|
||||
{
|
||||
d->valid = valid;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "taglib_export.h"
|
||||
#include "taglib.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tiostream.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
@ -36,22 +37,6 @@ namespace TagLib {
|
||||
class Tag;
|
||||
class AudioProperties;
|
||||
|
||||
#ifdef _WIN32
|
||||
class TAGLIB_EXPORT FileName
|
||||
{
|
||||
public:
|
||||
FileName(const wchar_t *name) : m_wname(name) {}
|
||||
FileName(const char *name) : m_name(name) {}
|
||||
operator const wchar_t *() const { return m_wname.c_str(); }
|
||||
operator const char *() const { return m_name.c_str(); }
|
||||
private:
|
||||
std::string m_name;
|
||||
std::wstring m_wname;
|
||||
};
|
||||
#else
|
||||
typedef const char *FileName;
|
||||
#endif
|
||||
|
||||
//! A file class with some useful methods for tag manipulation
|
||||
|
||||
/*!
|
||||
@ -240,6 +225,14 @@ namespace TagLib {
|
||||
*/
|
||||
File(FileName file);
|
||||
|
||||
/*!
|
||||
* Construct a File object and use the \a stream instance.
|
||||
*
|
||||
* \note Constructor is protected since this class should only be
|
||||
* instantiated through subclasses.
|
||||
*/
|
||||
File(IOStream *stream);
|
||||
|
||||
/*!
|
||||
* Marks the file as valid or invalid.
|
||||
*
|
||||
|
380
taglib/toolkit/tfilestream.cpp
Normal file
380
taglib/toolkit/tfilestream.cpp
Normal file
@ -0,0 +1,380 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 "tfilestream.h"
|
||||
#include "tstring.h"
|
||||
#include "tdebug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <wchar.h>
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# define ftruncate _chsize
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef R_OK
|
||||
# define R_OK 4
|
||||
#endif
|
||||
#ifndef W_OK
|
||||
# define W_OK 2
|
||||
#endif
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef FileName FileNameHandle;
|
||||
|
||||
#else
|
||||
|
||||
struct FileNameHandle : public std::string
|
||||
{
|
||||
FileNameHandle(FileName name) : std::string(name) {}
|
||||
operator FileName () const { return c_str(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class FileStream::FileStreamPrivate
|
||||
{
|
||||
public:
|
||||
FileStreamPrivate(FileName fileName);
|
||||
|
||||
FILE *file;
|
||||
|
||||
FileNameHandle name;
|
||||
|
||||
bool readOnly;
|
||||
ulong size;
|
||||
static const uint bufferSize = 1024;
|
||||
};
|
||||
|
||||
FileStream::FileStreamPrivate::FileStreamPrivate(FileName fileName) :
|
||||
file(0),
|
||||
name(fileName),
|
||||
readOnly(true),
|
||||
size(0)
|
||||
{
|
||||
// First try with read / write mode, if that fails, fall back to read only.
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
if(wcslen((const wchar_t *) fileName) > 0) {
|
||||
|
||||
file = _wfopen(name, L"rb+");
|
||||
|
||||
if(file)
|
||||
readOnly = false;
|
||||
else
|
||||
file = _wfopen(name, L"rb");
|
||||
|
||||
if(file)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
file = fopen(name, "rb+");
|
||||
|
||||
if(file)
|
||||
readOnly = false;
|
||||
else
|
||||
file = fopen(name, "rb");
|
||||
|
||||
if(!file)
|
||||
{
|
||||
debug("Could not open file " + String((const char *) name));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FileStream::FileStream(FileName file)
|
||||
{
|
||||
d = new FileStreamPrivate(file);
|
||||
}
|
||||
|
||||
FileStream::~FileStream()
|
||||
{
|
||||
if(d->file)
|
||||
fclose(d->file);
|
||||
delete d;
|
||||
}
|
||||
|
||||
FileName FileStream::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
ByteVector FileStream::readBlock(ulong length)
|
||||
{
|
||||
if(!d->file) {
|
||||
debug("FileStream::readBlock() -- Invalid File");
|
||||
return ByteVector::null;
|
||||
}
|
||||
|
||||
if(length == 0)
|
||||
return ByteVector::null;
|
||||
|
||||
if(length > FileStreamPrivate::bufferSize &&
|
||||
length > ulong(FileStream::length()))
|
||||
{
|
||||
length = FileStream::length();
|
||||
}
|
||||
|
||||
ByteVector v(static_cast<uint>(length));
|
||||
const int count = fread(v.data(), sizeof(char), length, d->file);
|
||||
v.resize(count);
|
||||
return v;
|
||||
}
|
||||
|
||||
void FileStream::writeBlock(const ByteVector &data)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
if(d->readOnly) {
|
||||
debug("File::writeBlock() -- attempted to write to a file that is not writable");
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(data.data(), sizeof(char), data.size(), d->file);
|
||||
}
|
||||
|
||||
void FileStream::insert(const ByteVector &data, ulong start, ulong replace)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
if(data.size() == replace) {
|
||||
seek(start);
|
||||
writeBlock(data);
|
||||
return;
|
||||
}
|
||||
else if(data.size() < replace) {
|
||||
seek(start);
|
||||
writeBlock(data);
|
||||
removeBlock(start + data.size(), replace - data.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore
|
||||
// and avoid TagLib's high level API for rendering just copying parts of
|
||||
// the file that don't contain tag data.
|
||||
//
|
||||
// Now I'll explain the steps in this ugliness:
|
||||
|
||||
// First, make sure that we're working with a buffer that is longer than
|
||||
// the *differnce* in the tag sizes. We want to avoid overwriting parts
|
||||
// that aren't yet in memory, so this is necessary.
|
||||
|
||||
ulong bufferLength = bufferSize();
|
||||
|
||||
while(data.size() - replace > bufferLength)
|
||||
bufferLength += bufferSize();
|
||||
|
||||
// Set where to start the reading and writing.
|
||||
|
||||
long readPosition = start + replace;
|
||||
long writePosition = start;
|
||||
|
||||
ByteVector buffer;
|
||||
ByteVector aboutToOverwrite(static_cast<uint>(bufferLength));
|
||||
|
||||
// This is basically a special case of the loop below. Here we're just
|
||||
// doing the same steps as below, but since we aren't using the same buffer
|
||||
// size -- instead we're using the tag size -- this has to be handled as a
|
||||
// special case. We're also using File::writeBlock() just for the tag.
|
||||
// That's a bit slower than using char *'s so, we're only doing it here.
|
||||
|
||||
seek(readPosition);
|
||||
int bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
|
||||
readPosition += bufferLength;
|
||||
|
||||
seek(writePosition);
|
||||
writeBlock(data);
|
||||
writePosition += data.size();
|
||||
|
||||
buffer = aboutToOverwrite;
|
||||
|
||||
// In case we've already reached the end of file...
|
||||
|
||||
buffer.resize(bytesRead);
|
||||
|
||||
// Ok, here's the main loop. We want to loop until the read fails, which
|
||||
// means that we hit the end of the file.
|
||||
|
||||
while(!buffer.isEmpty()) {
|
||||
|
||||
// Seek to the current read position and read the data that we're about
|
||||
// to overwrite. Appropriately increment the readPosition.
|
||||
|
||||
seek(readPosition);
|
||||
bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
|
||||
aboutToOverwrite.resize(bytesRead);
|
||||
readPosition += bufferLength;
|
||||
|
||||
// Check to see if we just read the last block. We need to call clear()
|
||||
// if we did so that the last write succeeds.
|
||||
|
||||
if(ulong(bytesRead) < bufferLength)
|
||||
clear();
|
||||
|
||||
// Seek to the write position and write our buffer. Increment the
|
||||
// writePosition.
|
||||
|
||||
seek(writePosition);
|
||||
fwrite(buffer.data(), sizeof(char), buffer.size(), d->file);
|
||||
writePosition += buffer.size();
|
||||
|
||||
// Make the current buffer the data that we read in the beginning.
|
||||
|
||||
buffer = aboutToOverwrite;
|
||||
|
||||
// Again, we need this for the last write. We don't want to write garbage
|
||||
// at the end of our file, so we need to set the buffer size to the amount
|
||||
// that we actually read.
|
||||
|
||||
bufferLength = bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
void FileStream::removeBlock(ulong start, ulong length)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
ulong bufferLength = bufferSize();
|
||||
|
||||
long readPosition = start + length;
|
||||
long writePosition = start;
|
||||
|
||||
ByteVector buffer(static_cast<uint>(bufferLength));
|
||||
|
||||
ulong bytesRead = 1;
|
||||
|
||||
while(bytesRead != 0) {
|
||||
seek(readPosition);
|
||||
bytesRead = fread(buffer.data(), sizeof(char), bufferLength, d->file);
|
||||
readPosition += bytesRead;
|
||||
|
||||
// Check to see if we just read the last block. We need to call clear()
|
||||
// if we did so that the last write succeeds.
|
||||
|
||||
if(bytesRead < bufferLength)
|
||||
clear();
|
||||
|
||||
seek(writePosition);
|
||||
fwrite(buffer.data(), sizeof(char), bytesRead, d->file);
|
||||
writePosition += bytesRead;
|
||||
}
|
||||
truncate(writePosition);
|
||||
}
|
||||
|
||||
bool FileStream::readOnly() const
|
||||
{
|
||||
return d->readOnly;
|
||||
}
|
||||
|
||||
bool FileStream::isOpen() const
|
||||
{
|
||||
return (d->file != NULL);
|
||||
}
|
||||
|
||||
void FileStream::seek(long offset, Position p)
|
||||
{
|
||||
if(!d->file) {
|
||||
debug("File::seek() -- trying to seek in a file that isn't opened.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(p) {
|
||||
case Beginning:
|
||||
fseek(d->file, offset, SEEK_SET);
|
||||
break;
|
||||
case Current:
|
||||
fseek(d->file, offset, SEEK_CUR);
|
||||
break;
|
||||
case End:
|
||||
fseek(d->file, offset, SEEK_END);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FileStream::clear()
|
||||
{
|
||||
clearerr(d->file);
|
||||
}
|
||||
|
||||
long FileStream::tell() const
|
||||
{
|
||||
return ftell(d->file);
|
||||
}
|
||||
|
||||
long FileStream::length()
|
||||
{
|
||||
// Do some caching in case we do multiple calls.
|
||||
|
||||
if(d->size > 0)
|
||||
return d->size;
|
||||
|
||||
if(!d->file)
|
||||
return 0;
|
||||
|
||||
long curpos = tell();
|
||||
|
||||
seek(0, End);
|
||||
long endpos = tell();
|
||||
|
||||
seek(curpos, Beginning);
|
||||
|
||||
d->size = endpos;
|
||||
return endpos;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FileStream::truncate(long length)
|
||||
{
|
||||
ftruncate(fileno(d->file), length);
|
||||
}
|
||||
|
||||
TagLib::uint FileStream::bufferSize()
|
||||
{
|
||||
return FileStreamPrivate::bufferSize;
|
||||
}
|
154
taglib/toolkit/tfilestream.h
Normal file
154
taglib/toolkit/tfilestream.h
Normal file
@ -0,0 +1,154 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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_FILESTREAM_H
|
||||
#define TAGLIB_FILESTREAM_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "taglib.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tiostream.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class String;
|
||||
class Tag;
|
||||
class AudioProperties;
|
||||
|
||||
//! A file class with some useful methods for tag manipulation
|
||||
|
||||
/*!
|
||||
* This class is a basic file class with some methods that are particularly
|
||||
* useful for tag editors. It has methods to take advantage of
|
||||
* ByteVector and a binary search method for finding patterns in a file.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT FileStream : 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.
|
||||
*/
|
||||
FileStream(FileName file);
|
||||
|
||||
/*!
|
||||
* Destroys this FileStream instance.
|
||||
*/
|
||||
virtual ~FileStream();
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
protected:
|
||||
|
||||
/*!
|
||||
* Returns the buffer size that is used for internal buffering.
|
||||
*/
|
||||
static uint bufferSize();
|
||||
|
||||
private:
|
||||
class FileStreamPrivate;
|
||||
FileStreamPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
45
taglib/toolkit/tiostream.cpp
Normal file
45
taglib/toolkit/tiostream.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
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 "tiostream.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IOStream::IOStream()
|
||||
{
|
||||
}
|
||||
|
||||
IOStream::~IOStream()
|
||||
{
|
||||
}
|
||||
|
||||
void IOStream::clear()
|
||||
{
|
||||
}
|
||||
|
160
taglib/toolkit/tiostream.h
Normal file
160
taglib/toolkit/tiostream.h
Normal file
@ -0,0 +1,160 @@
|
||||
/***************************************************************************
|
||||
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_IOSTREAM_H
|
||||
#define TAGLIB_IOSTREAM_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "taglib.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
#ifdef _WIN32
|
||||
class TAGLIB_EXPORT FileName
|
||||
{
|
||||
public:
|
||||
FileName(const wchar_t *name) : m_wname(name) {}
|
||||
FileName(const char *name) : m_name(name) {}
|
||||
operator const wchar_t *() const { return m_wname.c_str(); }
|
||||
operator const char *() const { return m_name.c_str(); }
|
||||
private:
|
||||
std::string m_name;
|
||||
std::wstring m_wname;
|
||||
};
|
||||
#else
|
||||
typedef const char *FileName;
|
||||
#endif
|
||||
|
||||
//! An abstract class that provides operations on a sequence of bytes
|
||||
|
||||
class TAGLIB_EXPORT IOStream
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Position in the file used for seeking.
|
||||
*/
|
||||
enum Position {
|
||||
//! Seek from the beginning of the file.
|
||||
Beginning,
|
||||
//! Seek from the current position in the file.
|
||||
Current,
|
||||
//! Seek from the end of the file.
|
||||
End
|
||||
};
|
||||
|
||||
IOStream();
|
||||
|
||||
/*!
|
||||
* Destroys this IOStream instance.
|
||||
*/
|
||||
virtual ~IOStream();
|
||||
|
||||
/*!
|
||||
* Returns the stream name in the local file system encoding.
|
||||
*/
|
||||
virtual FileName name() const = 0;
|
||||
|
||||
/*!
|
||||
* Reads a block of size \a length at the current get pointer.
|
||||
*/
|
||||
virtual ByteVector readBlock(ulong length) = 0;
|
||||
|
||||
/*!
|
||||
* 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[].
|
||||
*/
|
||||
virtual void writeBlock(const ByteVector &data) = 0;
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*/
|
||||
virtual void insert(const ByteVector &data, ulong start = 0, ulong replace = 0) = 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.
|
||||
*/
|
||||
virtual void removeBlock(ulong start = 0, ulong length = 0) = 0;
|
||||
|
||||
/*!
|
||||
* Returns true if the file is read only (or if the file can not be opened).
|
||||
*/
|
||||
virtual bool readOnly() const = 0;
|
||||
|
||||
/*!
|
||||
* Since the file can currently only be opened as an argument to the
|
||||
* constructor (sort-of by design), this returns if that open succeeded.
|
||||
*/
|
||||
virtual bool isOpen() const = 0;
|
||||
|
||||
/*!
|
||||
* Move the I/O pointer to \a offset in the stream from position \a p. This
|
||||
* defaults to seeking from the beginning of the stream.
|
||||
*
|
||||
* \see Position
|
||||
*/
|
||||
virtual void seek(long offset, Position p = Beginning) = 0;
|
||||
|
||||
/*!
|
||||
* Reset the end-of-stream and error flags on the stream.
|
||||
*/
|
||||
virtual void clear();
|
||||
|
||||
/*!
|
||||
* Returns the current offset within the stream.
|
||||
*/
|
||||
virtual long tell() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the length of the stream.
|
||||
*/
|
||||
virtual long length() = 0;
|
||||
|
||||
/*!
|
||||
* Truncates the stream to a \a length.
|
||||
*/
|
||||
virtual void truncate(long length) = 0;
|
||||
|
||||
private:
|
||||
IOStream(const IOStream &);
|
||||
IOStream &operator=(const IOStream &);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -99,6 +99,23 @@ TrueAudio::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
TrueAudio::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
if(isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
TrueAudio::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate(frameFactory);
|
||||
if(isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
TrueAudio::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -96,6 +96,24 @@ namespace TagLib {
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an TrueAudio file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an TrueAudio file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored. The frames will be created using
|
||||
* \a frameFactory.
|
||||
*/
|
||||
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -88,6 +88,13 @@ WavPack::File::File(FileName file, bool readProperties,
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
WavPack::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
WavPack::File::~File()
|
||||
{
|
||||
delete d;
|
||||
|
@ -87,6 +87,14 @@ namespace TagLib {
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an WavPack file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
|
@ -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