asf/asffile.cpp
asf/asfproperties.cpp
asf/asfattribute.cpp
+asf/asfpicture.cpp
)
ELSE(WITH_ASF)
SET(asf_SRCS)
-INSTALL( FILES asffile.h asfproperties.h asftag.h asfattribute.h DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
+INSTALL( FILES asffile.h asfproperties.h asftag.h asfattribute.h asfpicture.h DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
noinst_LTLIBRARIES = libasf.la
-libasf_la_SOURCES = asfattribute.cpp asffile.cpp asfproperties.cpp asftag.cpp
+libasf_la_SOURCES = asfattribute.cpp asffile.cpp asfproperties.cpp asftag.cpp asfpicture.cpp
-taglib_include_HEADERS = asfattribute.h asffile.h asfproperties.h asftag.h
+taglib_include_HEADERS = asfattribute.h asffile.h asfproperties.h asftag.h asfpicture.h
taglib_includedir = $(includedir)/taglib
{
public:
AttributePrivate()
- : stream(0),
+ : pictureValue(ASF::Picture::fromInvalid()),
+ stream(0),
language(0) {}
AttributeTypes type;
String stringValue;
ByteVector byteVectorValue;
+ ASF::Picture pictureValue;
union {
unsigned int intValue;
unsigned short shortValue;
d->byteVectorValue = value;
}
+ASF::Attribute::Attribute(const ASF::Picture &value)
+{
+ d = new AttributePrivate;
+ d->type = BytesType;
+ d->pictureValue = value;
+}
+
ASF::Attribute::Attribute(unsigned int value)
{
d = new AttributePrivate;
ByteVector
ASF::Attribute::toByteVector() const
{
+ if(d->pictureValue.isValid())
+ return d->pictureValue.render();
return d->byteVectorValue;
}
return d->longLongValue;
}
+ASF::Picture
+ASF::Attribute::toPicture() const
+{
+ return d->pictureValue;
+}
+
String
ASF::Attribute::parse(ASF::File &f, int kind)
{
- int size, nameLength;
+ uint size, nameLength;
String name;
-
+ d->pictureValue = Picture::fromInvalid();
// extended content descriptor
if(kind == 0) {
nameLength = f.readWORD();
break;
}
+ if(d->type == BytesType && name == "WM/Picture") {
+ d->pictureValue.parse(d->byteVectorValue);
+ if(d->pictureValue.isValid()) {
+ d->byteVectorValue.clear();
+ }
+ }
+
return name;
}
case UnicodeType:
return d->stringValue.size() * 2 + 2;
case BytesType:
+ if(d->pictureValue.isValid())
+ return d->pictureValue.dataSize();
case GuidType:
return d->byteVectorValue.size();
}
break;
case BytesType:
+ if(d->pictureValue.isValid()) {
+ data.append(d->pictureValue.render());
+ break;
+ }
case GuidType:
data.append(d->byteVectorValue);
break;
#include "tstring.h"
#include "tbytevector.h"
#include "taglib_export.h"
+#include "asfpicture.h"
namespace TagLib
{
{
class File;
+ class Picture;
class TAGLIB_EXPORT Attribute
{
/*!
* Constructs an attribute with \a key and a BytesType \a value.
*/
- Attribute(const ByteVector &value);
+ Attribute(const ByteVector &value);
+
+ /*!
+ * Constructs an attribute with \a key and a Picture \a value.
+ *
+ * This attribute is compatible with the ID3 frame, APIC. The ID3 specification for the APIC frame stipulates that,
+ * while there may be any number of APIC frames associated with a file,
+ * only one may be of type 1 and only one may be of type 2.
+ *
+ * The specification also states that the description of the picture can be no longer than 64 characters, but can be empty.
+ * WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications.
+ * You must add code in your application to perform validations if you want to maintain complete compatibility with ID3.
+ */
+ Attribute(const Picture &value);
/*!
* Constructs an attribute with \a key and a DWordType \a value.
*/
ByteVector toByteVector() const;
+ /*!
+ * Returns the Picture \a value.
+ */
+ Picture toPicture() const;
+
/*!
* Returns the language number, or 0 is no stream number was set.
*/
class AttributePrivate;
AttributePrivate *d;
};
-
}
}
int ASF::File::readWORD()
{
ByteVector v = readBlock(2);
- return v.toShort(false);
+ return v.toUShort(false);
}
unsigned int ASF::File::readDWORD()
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
friend class Attribute;
+ friend class Picture;
class BaseObject;
class UnknownObject;
--- /dev/null
+/**************************************************************************
+ copyright : (C) 2005-2007 by Lukáš Lalinský
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+ * 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/ *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_ASF
+
+#include <taglib.h>
+#include <tdebug.h>
+#include "asfattribute.h"
+#include "asffile.h"
+#include "asfpicture.h"
+
+using namespace TagLib;
+
+class ASF::Picture::PicturePriavte : public RefCounter
+{
+public:
+ bool valid;
+ Type type;
+ String mimeType;
+ String description;
+ ByteVector picture;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Picture class members
+////////////////////////////////////////////////////////////////////////////////
+
+ASF::Picture::Picture()
+{
+ d = new PicturePriavte();
+ d->valid = true;
+}
+
+ASF::Picture::Picture(const Picture& other)
+ : d(other.d)
+{
+ d->ref();
+}
+
+ASF::Picture::~Picture()
+{
+ if(d->deref())
+ delete d;
+}
+
+bool ASF::Picture::isValid() const
+{
+ return d->valid;
+}
+
+String ASF::Picture::mimeType() const
+{
+ return d->mimeType;
+}
+
+void ASF::Picture::setMimeType(const String &value)
+{
+ d->mimeType = value;
+}
+
+ASF::Picture::Type ASF::Picture::type() const
+{
+ return d->type;
+}
+
+void ASF::Picture::setType(const ASF::Picture::Type& t)
+{
+ d->type = t;
+}
+
+String ASF::Picture::description() const
+{
+ return d->description;
+}
+
+void ASF::Picture::setDescription(const String &desc)
+{
+ d->description = desc;
+}
+
+ByteVector ASF::Picture::picture() const
+{
+ return d->picture;
+}
+
+void ASF::Picture::setPicture(const ByteVector &p)
+{
+ d->picture = p;
+}
+
+int ASF::Picture::dataSize() const
+{
+ return
+ 9 + (d->mimeType.length() + d->description.length()) * 2 +
+ d->picture.size();
+}
+
+ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other)
+{
+ if(other.d != d) {
+ if(d->deref())
+ delete d;
+ d = other.d;
+ d->ref();
+ }
+ return *this;
+}
+
+ByteVector ASF::Picture::render() const
+{
+ if(!isValid())
+ return ByteVector::null;
+ return
+ ByteVector((char)d->type) +
+ ByteVector::fromUInt(d->picture.size(), false) +
+ ASF::File::renderString(d->mimeType) +
+ ASF::File::renderString(d->description) +
+ d->picture;
+}
+
+void ASF::Picture::parse(const ByteVector& bytes)
+{
+ d->valid = false;
+ if(bytes.size() < 9)
+ return;
+ int pos = 0;
+ d->type = (Type)bytes[0]; ++pos;
+ uint dataLen = bytes.mid(pos, 4).toUInt(false); pos+=4;
+
+ const ByteVector nullStringTerminator(2, 0);
+
+ int endPos = bytes.find(nullStringTerminator, pos, 2);
+ if(endPos < 0)
+ return;
+ d->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
+ pos = endPos+2;
+
+ endPos = bytes.find(nullStringTerminator, pos, 2);
+ if(endPos < 0)
+ return;
+ d->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
+ pos = endPos+2;
+
+ if(dataLen + pos != bytes.size())
+ return;
+
+ d->picture = bytes.mid(pos, dataLen);
+ d->valid = true;
+ return;
+}
+
+ASF::Picture ASF::Picture::fromInvalid()
+{
+ Picture ret;
+ ret.d->valid = false;
+ return ret;
+}
+
+#endif
--- /dev/null
+#ifndef ASFPICTURE_H
+#define ASFPICTURE_H
+
+#include "tstring.h"
+#include "tbytevector.h"
+#include "taglib_export.h"
+#include "attachedpictureframe.h"
+
+namespace TagLib
+{
+ namespace ASF
+ {
+
+ //! An ASF attached picture interface implementation
+
+ /*!
+ * This is an implementation of ASF attached pictures interface. Pictures may be
+ * included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture
+ * attribute in a single tag). These pictures are usually in either JPEG or
+ * PNG format.
+ * \see Attribute::toPicture()
+ * \see Attribute::Attribute(const Picture& picture)
+ */
+ class TAGLIB_EXPORT Picture {
+ public:
+
+ /*!
+ * This describes the function or content of the picture.
+ */
+ enum Type {
+ //! A type not enumerated below
+ Other = 0x00,
+ //! 32x32 PNG image that should be used as the file icon
+ FileIcon = 0x01,
+ //! File icon of a different size or format
+ OtherFileIcon = 0x02,
+ //! Front cover image of the album
+ FrontCover = 0x03,
+ //! Back cover image of the album
+ BackCover = 0x04,
+ //! Inside leaflet page of the album
+ LeafletPage = 0x05,
+ //! Image from the album itself
+ Media = 0x06,
+ //! Picture of the lead artist or soloist
+ LeadArtist = 0x07,
+ //! Picture of the artist or performer
+ Artist = 0x08,
+ //! Picture of the conductor
+ Conductor = 0x09,
+ //! Picture of the band or orchestra
+ Band = 0x0A,
+ //! Picture of the composer
+ Composer = 0x0B,
+ //! Picture of the lyricist or text writer
+ Lyricist = 0x0C,
+ //! Picture of the recording location or studio
+ RecordingLocation = 0x0D,
+ //! Picture of the artists during recording
+ DuringRecording = 0x0E,
+ //! Picture of the artists during performance
+ DuringPerformance = 0x0F,
+ //! Picture from a movie or video related to the track
+ MovieScreenCapture = 0x10,
+ //! Picture of a large, coloured fish
+ ColouredFish = 0x11,
+ //! Illustration related to the track
+ Illustration = 0x12,
+ //! Logo of the band or performer
+ BandLogo = 0x13,
+ //! Logo of the publisher (record company)
+ PublisherLogo = 0x14
+ };
+
+ /*!
+ * Constructs an empty picture.
+ */
+ Picture();
+
+ /*!
+ * Construct an picture as a copy of \a other.
+ */
+ Picture(const Picture& other);
+
+ /*!
+ * Destroys the picture.
+ */
+ virtual ~Picture();
+
+ /*!
+ * Copies the contents of \a other into this picture.
+ */
+ Picture& operator=(const Picture& other);
+
+ /*!
+ * Returns true if Picture stores valid picture
+ */
+ bool isValid() const;
+
+ /*!
+ * Returns the mime type of the image. This should in most cases be
+ * "image/png" or "image/jpeg".
+ * \see setMimeType(const String &)
+ * \see picture()
+ * \see setPicture(const ByteArray&)
+ */
+ String mimeType() const;
+
+ /*!
+ * Sets the mime type of the image. This should in most cases be
+ * "image/png" or "image/jpeg".
+ * \see setMimeType(const String &)
+ * \see picture()
+ * \see setPicture(const ByteArray&)
+ */
+ void setMimeType(const String &value);
+
+ /*!
+ * Returns the type of the image.
+ *
+ * \see Type
+ * \see setType()
+ */
+ Type type() const;
+
+ /*!
+ * Sets the type for the image.
+ *
+ * \see Type
+ * \see type()
+ */
+ void setType(const ASF::Picture::Type& t);
+
+ /*!
+ * Returns a text description of the image.
+ *
+ * \see setDescription()
+ */
+ String description() const;
+
+ /*!
+ * Sets a textual description of the image to \a desc.
+ *
+ * \see description()
+ */
+ void setDescription(const String &desc);
+
+ /*!
+ * Returns the image data as a ByteVector.
+ *
+ * \note ByteVector has a data() method that returns a const char * which
+ * should make it easy to export this data to external programs.
+ *
+ * \see setPicture()
+ * \see mimeType()
+ */
+ ByteVector picture() const;
+
+ /*!
+ * Sets the image data to \a p. \a p should be of the type specified in
+ * this frame's mime-type specification.
+ *
+ * \see picture()
+ * \see mimeType()
+ * \see setMimeType()
+ */
+ void setPicture(const ByteVector &p);
+
+ /*!
+ * Returns picture as binary raw data \a value
+ */
+ ByteVector render() const;
+
+ /*!
+ * Returns picture as binary raw data \a value
+ */
+ int dataSize() const;
+
+#ifndef DO_NOT_DOCUMENT
+ /* THIS IS PRIVATE, DON'T TOUCH IT! */
+ void parse(const ByteVector& );
+ static Picture fromInvalid();
+ friend class Attribute;
+#endif
+ private:
+ struct PicturePriavte;
+ PicturePriavte *d;
+ };
+ }
+}
+
+#endif // ASFPICTURE_H
ape/apetag.h \
flac/flacfile.h \
flac/flacproperties.h \
+ flac/flacpicture.h \
mpc/mpcfile.h \
mpc/mpcproperties.h \
mp4/mp4atom.h \
asf/asffile.cpp \
asf/asfproperties.cpp \
asf/asftag.cpp \
+ asf/asfpicture.cpp \
audioproperties.cpp \
fileref.cpp \
flac/flacfile.cpp \
flac/flacproperties.cpp \
+ flac/flacpicture.cpp \
mp4/mp4atom.cpp \
mp4/mp4coverart.cpp \
mp4/mp4file.cpp \
asf/asffile.h \
asf/asfproperties.h \
asf/asftag.h \
+ asf/asfpicture.h \
audioproperties.h \
fileref.h \
flac/flacfile.h \
return toNumber<unsigned short>(d->data, mostSignificantByteFirst);
}
+unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const
+{
+ return toNumber<unsigned short>(d->data, mostSignificantByteFirst);
+}
+
long long ByteVector::toLongLong(bool mostSignificantByteFirst) const
{
return toNumber<unsigned long long>(d->data, mostSignificantByteFirst);
*/
short toShort(bool mostSignificantByteFirst = true) const;
+ /*!
+ * Converts the first 2 bytes of the vector to a unsigned short.
+ *
+ * If \a mostSignificantByteFirst is true this will operate left to right
+ * evaluating the integer. For example if \a mostSignificantByteFirst is
+ * true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1.
+ *
+ * \see fromShort()
+ */
+ unsigned short toUShort(bool mostSignificantByteFirst = true) const;
+
/*!
* Converts the first 8 bytes of the vector to a (signed) long long.
*
CPPUNIT_TEST(testSaveLanguage);
CPPUNIT_TEST(testDWordTrackNumber);
CPPUNIT_TEST(testSaveLargeValue);
+ CPPUNIT_TEST(testSavePicture);
+ CPPUNIT_TEST(testSaveMultiplePictures);
CPPUNIT_TEST_SUITE_END();
public:
delete f;
}
+ void testSavePicture()
+ {
+ ScopedFileCopy copy("silence-1", ".wma");
+ string newname = copy.fileName();
+
+ ASF::File *f = new ASF::File(newname.c_str());
+ ASF::AttributeList values;
+ ASF::Picture picture;
+ picture.setMimeType("image/jpeg");
+ picture.setType(ASF::Picture::FrontCover);
+ picture.setDescription("description");
+ picture.setPicture("data");
+ ASF::Attribute attr(picture);
+ values.append(attr);
+ f->tag()->attributeListMap()["WM/Picture"] = values;
+ f->save();
+ delete f;
+
+ f = new ASF::File(newname.c_str());
+ ASF::AttributeList values2 = f->tag()->attributeListMap()["WM/Picture"];
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), values2.size());
+ ASF::Attribute attr2 = values2.front();
+ ASF::Picture picture2 = attr2.toPicture();
+ CPPUNIT_ASSERT(picture2.isValid());
+ CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), picture2.mimeType());
+ CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, picture2.type());
+ CPPUNIT_ASSERT_EQUAL(String("description"), picture2.description());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("data"), picture2.picture());
+ delete f;
+ }
+
+ void testSaveMultiplePictures()
+ {
+ ScopedFileCopy copy("silence-1", ".wma");
+ string newname = copy.fileName();
+
+ ASF::File *f = new ASF::File(newname.c_str());
+ ASF::AttributeList values;
+ ASF::Picture picture;
+ picture.setMimeType("image/jpeg");
+ picture.setType(ASF::Picture::FrontCover);
+ picture.setDescription("description");
+ picture.setPicture("data");
+ values.append(ASF::Attribute(picture));
+ ASF::Picture picture2;
+ picture2.setMimeType("image/png");
+ picture2.setType(ASF::Picture::BackCover);
+ picture2.setDescription("back cover");
+ picture2.setPicture("PNG data");
+ values.append(ASF::Attribute(picture2));
+ f->tag()->attributeListMap()["WM/Picture"] = values;
+ f->save();
+ delete f;
+
+ f = new ASF::File(newname.c_str());
+ ASF::AttributeList values2 = f->tag()->attributeListMap()["WM/Picture"];
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), values2.size());
+ ASF::Picture picture3 = values2[1].toPicture();
+ CPPUNIT_ASSERT(picture3.isValid());
+ CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), picture3.mimeType());
+ CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, picture3.type());
+ CPPUNIT_ASSERT_EQUAL(String("description"), picture3.description());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("data"), picture3.picture());
+ ASF::Picture picture4 = values2[0].toPicture();
+ CPPUNIT_ASSERT(picture4.isValid());
+ CPPUNIT_ASSERT_EQUAL(String("image/png"), picture4.mimeType());
+ CPPUNIT_ASSERT_EQUAL(ASF::Picture::BackCover, picture4.type());
+ CPPUNIT_ASSERT_EQUAL(String("back cover"), picture4.description());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("PNG data"), picture4.picture());
+ delete f;
+ }
+
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestASF);
CPPUNIT_TEST(testRfind1);
CPPUNIT_TEST(testRfind2);
CPPUNIT_TEST(testToHex);
+ CPPUNIT_TEST(testToUShort);
CPPUNIT_TEST_SUITE_END();
public:
CPPUNIT_ASSERT_EQUAL(ByteVector("f0e1d2c3b4a5968778695a4b3c2d1e0f"), v.toHex());
}
+ void testToUShort()
+ {
+ CPPUNIT_ASSERT_EQUAL((unsigned short)0xFFFF, ByteVector("\xff\xff", 2).toUShort());
+ CPPUNIT_ASSERT_EQUAL((unsigned short)0x0001, ByteVector("\x00\x01", 2).toUShort());
+ CPPUNIT_ASSERT_EQUAL((unsigned short)0x0100, ByteVector("\x00\x01", 2).toUShort(false));
+ CPPUNIT_ASSERT_EQUAL((unsigned short)0xFF01, ByteVector("\xFF\x01", 2).toUShort());
+ CPPUNIT_ASSERT_EQUAL((unsigned short)0x01FF, ByteVector("\xFF\x01", 2).toUShort(false));
+ }
+
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVector);