diff options
author | Mathias Panzenböck <grosser.meister.morti@gmx.net> | 2011-06-14 00:46:23 +0200 |
---|---|---|
committer | Mathias Panzenböck <grosser.meister.morti@gmx.net> | 2011-06-14 00:46:23 +0200 |
commit | f6dbd32ed395c4ed856e13ff6520fedf1da18fe1 (patch) | |
tree | a1f936a04e4fac3677eb1bd738f03782d3145fa0 | |
parent | 5332fb5cf80a71ee1e9e1c382ce1b7be562c69d2 (diff) |
refactored for ABI compat and write support of some tags of s3m/it/xm files
tags that can be written:
* s3m: title
* it: title
* xm: title, trackerName
25 files changed, 1456 insertions, 733 deletions
diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index d72f5f85..55bcdefd 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -104,13 +104,10 @@ set(tag_HDRS mod/modfile.h mod/modtag.h it/itfile.h - it/itfiletyperesolver.h it/itproperties.h s3m/s3mfile.h - s3m/s3mfiletyperesolver.h s3m/s3mproperties.h xm/xmfile.h - xm/xmfiletyperesolver.h xm/xmproperties.h xm/xmtag.h ) @@ -255,21 +252,23 @@ set(wav_SRCS set(mod_SRCS mod/modfile.cpp + mod/modtag.cpp ) set(s3m_SRCS s3m/s3mfile.cpp - s3m/s3mfiletyperesolver.cpp + s3m/s3mproperties.cpp ) set(it_SRCS it/itfile.cpp - it/itfiletyperesolver.cpp + it/itproperties.cpp ) set(xm_SRCS xm/xmfile.cpp - xm/xmfiletyperesolver.cpp + xm/xmtag.cpp + xm/xmproperties.cpp ) set(toolkit_SRCS diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index d18a3aeb..8bb9c01b 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -49,6 +49,9 @@ #include "aifffile.h" #include "wavfile.h" #include "apefile.h" +#include "s3mfile.h" +#include "itfile.h" +#include "xmfile.h" using namespace TagLib; @@ -162,6 +165,9 @@ StringList FileRef::defaultFileExtensions() l.append("aiff"); l.append("wav"); l.append("ape"); + l.append("s3m"); + l.append("it"); + l.append("xm"); return l; } @@ -260,6 +266,12 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "APE") return new APE::File(fileName, readAudioProperties, audioPropertiesStyle); + if(ext == "S3M") + return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle); + if(ext == "IT") + return new IT::File(fileName, readAudioProperties, audioPropertiesStyle); + if(ext == "XM") + return new XM::File(fileName, readAudioProperties, audioPropertiesStyle); } return 0; diff --git a/taglib/it/itfile.cpp b/taglib/it/itfile.cpp index f0c4d779..dfe6e0af 100644 --- a/taglib/it/itfile.cpp +++ b/taglib/it/itfile.cpp @@ -21,147 +21,165 @@ #include "tstringlist.h" #include "itfile.h" +#include "modfileprivate.h" + +using namespace TagLib; +using namespace IT; + +// Just copied this array from some example code. +// I think this might be unneccesarry and only needed if +// you convert IT to XM to keep your mod player more simple. +static const uchar AUTOVIB_IT_TO_XM[] = {0, 3, 1, 4, 2, 0, 0, 0}; + +class IT::File::FilePrivate +{ +public: + FilePrivate(AudioProperties::ReadStyle propertiesStyle) + : tag(), properties(propertiesStyle) + { + } -namespace TagLib { - - namespace IT { - -uint8_t AUTOVIB_IT_TO_XM[] = {0, 3, 1, 4, 2, 0, 0, 0}; + Mod::Tag tag; + IT::Properties properties; +}; -File::File(FileName file, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::File(file), m_tag(0), m_properties(0) { - read(readProperties, propertiesStyle); +IT::File::File(FileName file, bool readProperties, + AudioProperties::ReadStyle propertiesStyle) : + Mod::File(file), + d(new FilePrivate(propertiesStyle)) +{ + read(readProperties); } -File::~File() { - delete m_tag; - delete m_properties; +IT::File::File(IOStream *stream, bool readProperties, + AudioProperties::ReadStyle propertiesStyle) : + Mod::File(stream), + d(new FilePrivate(propertiesStyle)) +{ + read(readProperties); } -Mod::Tag *File::tag() const { - return m_tag; +IT::File::~File() +{ + delete d; } -IT::Properties *File::audioProperties() const { - return m_properties; +Mod::Tag *IT::File::tag() const +{ + return &d->tag; } -bool File::save() { - return false; +IT::Properties *IT::File::audioProperties() const +{ + return &d->properties; } -void File::read(bool, AudioProperties::ReadStyle propertiesStyle) { - delete m_tag; - delete m_properties; - - m_tag = new Mod::Tag(); - m_properties = new IT::Properties(propertiesStyle); +bool IT::File::save() +{ + seek(4); + writeString(d->tag.title(), 26); + // TODO: write comment as instrument and sample names + return true; +} - if (!isOpen()) +void IT::File::read(bool) +{ + if(!isOpen()) return; - try { - ByteVector mod_id(readBytes(4UL)); - if (mod_id != "IMPM") { - throw Mod::ReadError(); - } + seek(0); + READ_ASSERT(readBlock(4) == "IMPM"); + READ_STRING(d->tag.setTitle, 26); - m_tag->setTitle(readString(26)); - seek(2, Current); + seek(2, Current); - uint16_t length = readU16L(); - uint16_t instrumentCount = readU16L(); - uint16_t sampleCount = readU16L(); + READ_U16L_AS(length); + READ_U16L_AS(instrumentCount); + READ_U16L_AS(sampleCount); - m_properties->setSampleLength(length); - m_properties->setInstrumentCount(instrumentCount); - m_properties->setSampleCount(sampleCount); - m_properties->setPatternCount(readU16L()); - m_properties->setVersion(readU16L()); - m_properties->setCmwt(readU16L()); - m_properties->setFlags(readU16L()); - - uint16_t special = readU16L(); + d->properties.setSampleLength(length); + d->properties.setInstrumentCount(instrumentCount); + d->properties.setSampleCount(sampleCount); + READ_U16L(d->properties.setPatternCount); + READ_U16L(d->properties.setVersion); + READ_U16L(d->properties.setCmwt); + READ_U16L(d->properties.setFlags); - m_properties->setSpecial(special); - m_properties->setBaseVolume(readU16L()); + READ_U16L_AS(special); - seek(1, Current); + d->properties.setSpecial(special); + READ_U16L(d->properties.setBaseVolume); - m_properties->setTempo(readByte()); - m_properties->setBpmSpeed(readByte()); + seek(1, Current); - StringList comment; + READ_BYTE(d->properties.setTempo); + READ_BYTE(d->properties.setBpmSpeed); - for (uint16_t i = 0; i < instrumentCount; ++ i) { - seek(192 + length + (i << 2)); - uint32_t instrumentOffset = readU32L(); - seek(instrumentOffset); + StringList comment; - ByteVector instrumentMagic = readBytes(4); - if (instrumentMagic != "IMPS" && instrumentMagic != "IMPI") { - throw Mod::ReadError(); - } + for(ushort i = 0; i < instrumentCount; ++ i) + { + seek(192 + length + (i << 2)); + READ_U32L_AS(instrumentOffset); + seek(instrumentOffset); - String dosFileName = readString(13); + ByteVector instrumentMagic = readBlock(4); + // TODO: find out if it can really be both here and not just IMPI + READ_ASSERT(instrumentMagic == "IMPS" || instrumentMagic == "IMPI"); - seek(15, Current); + READ_STRING_AS(dosFileName, 13); - String instrumentName = readString(26); + seek(15, Current); - comment.append(instrumentName); - } + READ_STRING_AS(instrumentName, 26); + comment.append(instrumentName); + } - for (uint16_t i = 0; i < sampleCount; ++ i) { - seek(192 + length + (instrumentCount << 2) + (i << 2)); - uint32_t sampleOffset = readU32L(); - seek(sampleOffset); - - ByteVector sampleMagic = readBytes(4); - if (sampleMagic != "IMPS" && sampleMagic != "IMPI") { - throw Mod::ReadError(); - } - - String dosFileName = readString(13); - uint8_t globalVolume = readByte(); - uint8_t sampleFlags = readByte(); - uint8_t sampleValume = readByte(); - String sampleName = readString(26); - uint8_t sampleCvt = readByte(); - uint8_t samplePanning = readByte(); - uint32_t sampleLength = readU32L(); - uint32_t repeatStart = readU32L(); - uint32_t repeatStop = readU32L(); - uint32_t c4speed = readU32L(); - uint32_t sustainLoopStart = readU32L(); - uint32_t sustainLoopEnd = readU32L(); - uint32_t sampleDataOffset = readU32L(); - uint8_t vibratoRate = readByte(); - uint8_t vibratoDepth = readByte(); - uint8_t vibratoSweep = readByte(); - uint8_t vibratoType = readByte(); - - if (c4speed == 0) { - c4speed = 8363; - } - else if (c4speed < 256) { - c4speed = 256; - } - - vibratoDepth = vibratoDepth & 0x7F; - vibratoSweep = (vibratoSweep + 3) >> 2; - vibratoType = AUTOVIB_IT_TO_XM[vibratoType & 0x07]; - - comment.append(sampleName); + for(ushort i = 0; i < sampleCount; ++ i) + { + seek(192 + length + (instrumentCount << 2) + (i << 2)); + READ_U32L_AS(sampleOffset); + + seek(sampleOffset); + + ByteVector sampleMagic = readBlock(4); + // TODO: find out if it can really be both here and not just IMPS + READ_ASSERT(sampleMagic == "IMPS" || sampleMagic == "IMPI"); + + READ_STRING_AS(dosFileName, 13); + READ_BYTE_AS(globalVolume); + READ_BYTE_AS(sampleFlags); + READ_BYTE_AS(sampleValume); + READ_STRING_AS(sampleName, 26); + READ_BYTE_AS(sampleCvt); + READ_BYTE_AS(samplePanning); + READ_U32L_AS(sampleLength); + READ_U32L_AS(repeatStart); + READ_U32L_AS(repeatStop); + READ_U32L_AS(c4speed); + READ_U32L_AS(sustainLoopStart); + READ_U32L_AS(sustainLoopEnd); + READ_U32L_AS(sampleDataOffset); + READ_BYTE_AS(vibratoRate); + READ_BYTE_AS(vibratoDepth); + READ_BYTE_AS(vibratoSweep); + READ_BYTE_AS(vibratoType); + + if(c4speed == 0) + { + c4speed = 8363; + } + else if(c4speed < 256) + { + c4speed = 256; } + + vibratoDepth = vibratoDepth & 0x7F; + vibratoSweep = (vibratoSweep + 3) >> 2; + vibratoType = AUTOVIB_IT_TO_XM[vibratoType & 0x07]; - m_tag->setComment(comment.toString("\n")); - } - catch (const Mod::ReadError&) { - setValid(false); + comment.append(sampleName); } -} - } + d->tag.setComment(comment.toString("\n")); } diff --git a/taglib/it/itfile.h b/taglib/it/itfile.h index 2647d451..bc6ac3ef 100644 --- a/taglib/it/itfile.h +++ b/taglib/it/itfile.h @@ -42,22 +42,31 @@ namespace TagLib { * is true the file's audio properties will also be read using * \a propertiesStyle. If false, \a propertiesStyle is ignored. */ - explicit File(FileName file, bool readProperties = true, - AudioProperties::ReadStyle propertiesStyle = - AudioProperties::Average); + File(FileName file, bool readProperties = true, + AudioProperties::ReadStyle propertiesStyle = + AudioProperties::Average); + + /*! + * Contructs a Impulse Tracker 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. + */ + File(IOStream *stram, bool readProperties = true, + AudioProperties::ReadStyle propertiesStyle = + AudioProperties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); - virtual Mod::Tag *tag() const; + Mod::Tag *tag() const; /*! * Returns the IT::Properties for this file. If no audio properties * were read then this will return a null pointer. */ - virtual IT::Properties *audioProperties() const; + IT::Properties *audioProperties() const; /*! * Save the file. @@ -65,17 +74,16 @@ namespace TagLib { * * \note Saving Impulse Tracker tags is not supported. */ - virtual bool save(); - - void read(bool readProperties, - AudioProperties::ReadStyle propertiesStyle); + bool save(); private: File(const File &); File &operator=(const File &); - Mod::Tag *m_tag; - IT::Properties *m_properties; + void read(bool readProperties); + + class FilePrivate; + FilePrivate *d; }; } } diff --git a/taglib/it/itfiletyperesolver.cpp b/taglib/it/itfiletyperesolver.cpp deleted file mode 100644 index e35ad25c..00000000 --- a/taglib/it/itfiletyperesolver.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "itfiletyperesolver.h" -#include "itfile.h" - -TagLib::File *ITFileTypeResolver::createFile( - TagLib::FileName fileName, - bool readProperties, - TagLib::AudioProperties::ReadStyle propertiesStyle) const { - TagLib::IT::File *f = new TagLib::IT::File(fileName, readProperties, propertiesStyle); - if (f->isValid()) { - return f; - } - else { - delete f; - return 0; - } -} diff --git a/taglib/it/itproperties.cpp b/taglib/it/itproperties.cpp new file mode 100644 index 00000000..8cf04fd7 --- /dev/null +++ b/taglib/it/itproperties.cpp @@ -0,0 +1,208 @@ +/*************************************************************************** + copyright :(C) 2011 by Mathias Panzenböck + email : grosser.meister.morti@gmx.net + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301 USA * + ***************************************************************************/ + +#include "itproperties.h" + +using namespace TagLib; +using namespace IT; + +class IT::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate() : + sampleLength(0), + stereo(false), + instrumentCount(0), + sampleCount(0), + patternCount(0), + version(0), + cmwt(0), + flags(0), + special(0), + baseVolume(0), + tempo(0), + bpmSpeed(0) + { + } + + ushort sampleLength; + bool stereo; + ushort instrumentCount; + ushort sampleCount; + ushort patternCount; + ushort version; + ushort cmwt; + ushort flags; + ushort special; + int baseVolume; + uchar tempo; + uchar bpmSpeed; +}; + +IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : + AudioProperties(propertiesStyle), + d(new PropertiesPrivate) +{ +} + +IT::Properties::~Properties() +{ + delete d; +} + +int IT::Properties::length() const +{ + return 0; +} + +int IT::Properties::bitrate() const +{ + return 0; +} + +int IT::Properties::sampleRate() const +{ + return 0; +} + +int IT::Properties::channels() const +{ + return d->stereo ? 2 : 1; +} + +ushort IT::Properties::sampleLength() const +{ + return d->sampleLength; +} + +bool IT::Properties::stereo() const +{ + return d->stereo; +} + +ushort IT::Properties::instrumentCount() const +{ + return d->instrumentCount; +} + +ushort IT::Properties::sampleCount() const +{ + return d->sampleCount; +} + +ushort IT::Properties::patternCount() const +{ + return d->patternCount; +} + +ushort IT::Properties::version() const +{ + return d->version; +} + +ushort IT::Properties::cmwt() const +{ + return d->cmwt; +} + +ushort IT::Properties::flags() const +{ + return d->flags; +} + +ushort IT::Properties::special() const +{ + return d->special; +} + +int IT::Properties::baseVolume() const +{ + return d->baseVolume; +} + +uchar IT::Properties::tempo() const +{ + return d->tempo; +} + +uchar IT::Properties::bpmSpeed() const +{ + return d->bpmSpeed; +} + +void IT::Properties::setSampleLength(ushort sampleLength) +{ + d->sampleLength = sampleLength; +} + +void IT::Properties::setStereo(bool stereo) +{ + d->stereo = stereo; +} + +void IT::Properties::setInstrumentCount(ushort instrumentCount) { + d->instrumentCount = instrumentCount; +} + +void IT::Properties::setSampleCount(ushort sampleCount) +{ + d->sampleCount = sampleCount; +} + +void IT::Properties::setPatternCount(ushort patternCount) +{ + d->patternCount = patternCount; +} + +void IT::Properties::setFlags(ushort flags) +{ + d->flags = flags; +} + +void IT::Properties::setSpecial(ushort special) +{ + d->special = special; +} + +void IT::Properties::setCmwt(ushort cmwt) +{ + d->cmwt = cmwt; +} + +void IT::Properties::setVersion(ushort version) +{ + d->version = version; +} + +void IT::Properties::setBaseVolume(int baseVolume) +{ + d->baseVolume = baseVolume; +} + +void IT::Properties::setTempo(uchar tempo) +{ + d->tempo = tempo; +} + +void IT::Properties::setBpmSpeed(uchar bpmSpeed) +{ + d->bpmSpeed = bpmSpeed; +} diff --git a/taglib/it/itproperties.h b/taglib/it/itproperties.h index 9e1155e3..cc53b828 100644 --- a/taglib/it/itproperties.h +++ b/taglib/it/itproperties.h @@ -22,8 +22,7 @@ #ifndef TAGLIB_ITPROPERTIES_H #define TAGLIB_ITPROPERTIES_H -#include <stdint.h> - +#include "taglib.h" #include "audioproperties.h" namespace TagLib { @@ -31,69 +30,48 @@ namespace TagLib { class TAGLIB_EXPORT Properties : public AudioProperties { friend class File; public: - Properties(AudioProperties::ReadStyle propertiesStyle) : - AudioProperties(propertiesStyle), - m_sampleLength(0), - m_stereo(false), - m_instrumentCount(0), - m_sampleCount(0), - m_patternCount(0), - m_version(0), - m_cmwt(0), - m_flags(0), - m_special(0), - m_baseVolume(0), - m_tempo(0), - m_bpmSpeed(0) {} + Properties(AudioProperties::ReadStyle propertiesStyle); + virtual ~Properties(); - int length() const { return 0; } - int bitrate() const { return 0; } - int sampleRate() const { return 0; } - int channels() const { return m_stereo ? 2 : 1; } + int length() const; + int bitrate() const; + int sampleRate() const; + int channels() const; - uint16_t sampleLength() const { return m_sampleLength; } - bool stereo() const { return m_stereo; } - uint16_t instrumentCount() const { return m_instrumentCount; } - uint16_t sampleCount() const { return m_sampleCount; } - uint16_t patternCount() const { return m_patternCount; } - uint16_t version() const { return m_version; } - uint16_t cmwt() const { return m_cmwt; } - uint16_t flags() const { return m_flags; } - uint16_t special() const { return m_special; } - int baseVolume() const { return m_baseVolume; } - uint8_t tempo() const { return m_tempo; } - uint8_t bpmSpeed() const { return m_bpmSpeed; } + ushort sampleLength() const; + bool stereo() const; + ushort instrumentCount() const; + ushort sampleCount() const; + ushort patternCount() const; + ushort version() const; + ushort cmwt() const; + ushort flags() const; + ushort special() const; + int baseVolume() const; + uchar tempo() const; + uchar bpmSpeed() const; protected: - void setSampleLength(uint16_t sampleLength) { m_sampleLength = sampleLength; } - void setStereo(bool stereo) { m_stereo = stereo; } + void setSampleLength(ushort sampleLength); + void setStereo(bool stereo); - void setInstrumentCount (uint16_t instrumentCount) { - m_instrumentCount = instrumentCount; - } - void setSampleCount (uint16_t sampleCount) { m_sampleCount = sampleCount; } - void setPatternCount(uint16_t patternCount) { m_patternCount = patternCount; } - void setFlags (uint16_t flags) { m_flags = flags; } - void setSpecial (uint16_t special) { m_special = special; } - void setCmwt (uint16_t cmwt) { m_cmwt = cmwt; } - void setVersion (uint16_t version) { m_version = version; } - void setBaseVolume (int baseVolume) { m_baseVolume = baseVolume; } - void setTempo (uint8_t tempo) { m_tempo = tempo; } - void setBpmSpeed (uint8_t bpmSpeed) { m_bpmSpeed = bpmSpeed; } + void setInstrumentCount(ushort instrumentCount); + void setSampleCount (ushort sampleCount); + void setPatternCount(ushort patternCount); + void setFlags (ushort flags); + void setSpecial (ushort special); + void setCmwt (ushort cmwt); + void setVersion (ushort version); + void setBaseVolume (int baseVolume); + void setTempo (uchar tempo); + void setBpmSpeed (uchar bpmSpeed); private: - uint16_t m_sampleLength; - bool m_stereo; - uint16_t m_instrumentCount; - uint16_t m_sampleCount; - uint16_t m_patternCount; - uint16_t m_version; - uint16_t m_cmwt; - uint16_t m_flags; - uint16_t m_special; - int m_baseVolume; - uint8_t m_tempo; - uint8_t m_bpmSpeed; + Properties(const Properties&); + Properties &operator=(const Properties&); + + class PropertiesPrivate; + PropertiesPrivate *d; }; } } diff --git a/taglib/mod/modfile.cpp b/taglib/mod/modfile.cpp index eedd20c9..ec9bbbc1 100644 --- a/taglib/mod/modfile.cpp +++ b/taglib/mod/modfile.cpp @@ -21,69 +21,58 @@ #include "modfile.h" -#ifdef HAVE_ENDIAN_H -#include <endian.h> -#endif +using namespace TagLib; +using namespace Mod; -namespace TagLib { +Mod::File::File(FileName file) : TagLib::File(file) +{ +} - namespace Mod { +Mod::File::File(IOStream *stream) : TagLib::File(stream) +{ +} -ByteVector File::readBytes(unsigned long size) { - ByteVector data(readBlock(size)); - if (data.size() != size) throw ReadError(); - return data; +void Mod::File::writeString(const String &s, ulong size) +{ + ByteVector data(s.data(String::Latin1)); + data.resize(size, 0); + writeBlock(data); } -String File::readString(unsigned long size) { - ByteVector data(readBytes(size)); +bool Mod::File::readString(String &s, ulong size) +{ + ByteVector data(readBlock(size)); + if(data.size() < size) return false; int index = data.find((char) 0); - if (index > -1) { + if(index > -1) + { data.resize(index); } data.replace((char) 0xff, ' '); - return String(data); -} - -uint8_t File::readByte() { - return readBytes(1)[0]; -} - -#ifdef HAVE_ENDIAN_H -uint16_t File::readU16B() { - return be16toh(*(uint16_t*) readBytes(2).data()); -} - -uint16_t File::readU16L() { - return le16toh(*(uint16_t*) readBytes(2).data()); + s = data; + return true; } -uint32_t File::readU32B() { - return be32toh(*(uint32_t*) readBytes(4).data()); +bool Mod::File::readByte(uchar &byte) +{ + ByteVector data(readBlock(1)); + if(data.size() < 1) return false; + byte = data[0]; + return true; } -uint32_t File::readU32L() { - return le32toh(*(uint32_t*) readBytes(4).data()); -} -#else -uint16_t File::readU16B() { - return readBytes(2).toUShort(true); +bool Mod::File::readU16L(ushort &number) +{ + ByteVector data(readBlock(2)); + if(data.size() < 2) return false; + number = data.toUShort(false); + return true; } -uint16_t File::readU16L() { - return readBytes(2).toUShort(false); -} - -// XXX: who knows if this works if sizeof(int) > 4? -uint32_t File::readU32B() { - return readBytes(4).toUInt(true); -} - -uint32_t File::readU32L() { - return readBytes(4).toUInt(false); -} -#endif - - } +bool Mod::File::readU32L(ulong &number) { + ByteVector data(readBlock(4)); + if(data.size() < 4) return false; + number = data.toUInt(false); + return true; } diff --git a/taglib/mod/modfile.h b/taglib/mod/modfile.h index d2f9e217..ff385ce1 100644 --- a/taglib/mod/modfile.h +++ b/taglib/mod/modfile.h @@ -22,28 +22,23 @@ #ifndef TAGLIB_MODFILE_H #define TAGLIB_MODFILE_H -#include <stdint.h> - +#include "taglib.h" #include "tfile.h" #include "tstring.h" #include "taglib_export.h" namespace TagLib { namespace Mod { - class ReadError { - }; - class TAGLIB_EXPORT File : public TagLib::File { - public: - File(FileName file) : TagLib::File(file) {} - - ByteVector readBytes(unsigned long size); - String readString(unsigned long size); - uint8_t readByte(); - uint16_t readU16B(); - uint16_t readU16L(); - uint32_t readU32B(); - uint32_t readU32L(); + protected: + File(FileName file); + File(IOStream *stream); + + void writeString(const String &s, ulong size); + bool readString(String &s, ulong size); + bool readByte(uchar &byte); + bool readU16L(ushort &number); + bool readU32L(ulong &number); }; } } diff --git a/taglib/xm/xmfiletyperesolver.h b/taglib/mod/modfileprivate.h index 48709888..17268115 100644 --- a/taglib/xm/xmfiletyperesolver.h +++ b/taglib/mod/modfileprivate.h @@ -1,6 +1,6 @@ /*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net + copyright : (C) 2011 by Mathias Panzenböck + email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** @@ -19,17 +19,45 @@ * MA 02110-1301 USA * ***************************************************************************/ -#ifndef TAGLIB_XMFILETYPERESOLVER_H -#define TAGLIB_XMFILETYPERESOLVER_H +#ifndef TAGLIB_MODFILEPRIVATE_H +#define TAGLIB_MODFILEPRIVATE_H -#include "fileref.h" -#include "taglib_export.h" +// some helper-macros only used internally by (s3m|it|xm)file.cpp +#define READ_ASSERT(cond) \ + if(!(cond)) \ + { \ + setValid(false); \ + return; \ + } -class TAGLIB_EXPORT XMFileTypeResolver : public TagLib::FileRef::FileTypeResolver { - TagLib::File *createFile(TagLib::FileName fileName, - bool readAudioProperties, - TagLib::AudioProperties::ReadStyle audioPropertiesStyle) const; - ~XMFileTypeResolver() {} -}; +#define READ(setter,type,read) \ + { \ + type number; \ + READ_ASSERT(read(number)); \ + setter(number); \ + } + +#define READ_BYTE(setter) READ(setter,uchar,readByte) +#define READ_U16L(setter) READ(setter,ushort,readU16L) +#define READ_U32L(setter) READ(setter,ulong,readU32L) + +#define READ_STRING(setter,size) \ + { \ + String s; \ + READ_ASSERT(readString(s, size)); \ + setter(s); \ + } + +#define READ_AS(type,name,read) \ + type name = 0; \ + READ_ASSERT(read(name)); + +#define READ_BYTE_AS(name) READ_AS(uchar,name,readByte) +#define READ_U16L_AS(name) READ_AS(ushort,name,readU16L) +#define READ_U32L_AS(name) READ_AS(ulong,name,readU32L) + +#define READ_STRING_AS(name,size) \ + String name; \ + READ_ASSERT(readString(name, size)); #endif diff --git a/taglib/it/itfiletyperesolver.h b/taglib/mod/modtag.cpp index 2faaa3b5..77e7fd18 100644 --- a/taglib/it/itfiletyperesolver.h +++ b/taglib/mod/modtag.cpp @@ -1,6 +1,6 @@ /*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net + copyright : (C) 2011 by Mathias Panzenböck + email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** @@ -19,17 +19,91 @@ * MA 02110-1301 USA * ***************************************************************************/ -#ifndef TAGLIB_ITFILETYPERESOLVER_H -#define TAGLIB_ITFILETYPERESOLVER_H +#include "modtag.h" -#include "fileref.h" -#include "taglib_export.h" +using namespace TagLib; +using namespace Mod; -class TAGLIB_EXPORT ITFileTypeResolver : public TagLib::FileRef::FileTypeResolver { - TagLib::File *createFile(TagLib::FileName fileName, - bool readAudioProperties, - TagLib::AudioProperties::ReadStyle audioPropertiesStyle) const; - ~ITFileTypeResolver() {} +class Mod::Tag::TagPrivate +{ +public: + TagPrivate() {} + + String title; + String comment; }; -#endif +Mod::Tag::Tag() : TagLib::Tag() +{ + d = new TagPrivate; +} + +Mod::Tag::~Tag() +{ + delete d; +} + +String Mod::Tag::title() const +{ + return d->title; +} + +String Mod::Tag::artist() const +{ + return String::null; +} + +String Mod::Tag::album() const +{ + return String::null; +} + +String Mod::Tag::comment() const +{ + return d->comment; +} + +String Mod::Tag::genre() const +{ + return String::null; +} + +uint Mod::Tag::year() const +{ + return 0; +} + +uint Mod::Tag::track() const +{ + return 0; +} + +void Mod::Tag::setTitle(const String &title) +{ + d->title = title; +} + +void Mod::Tag::setArtist(const String &) +{ +} + +void Mod::Tag::setAlbum(const String &) +{ +} + +void Mod::Tag::setComment(const String &comment) +{ + d->comment = comment; +} + +void Mod::Tag::setGenre(const String &) +{ +} + +void Mod::Tag::setYear(uint) +{ +} + +void Mod::Tag::setTrack(uint) +{ +} diff --git a/taglib/mod/modtag.h b/taglib/mod/modtag.h index 2b53efbd..fa4f7a24 100644 --- a/taglib/mod/modtag.h +++ b/taglib/mod/modtag.h @@ -22,31 +22,37 @@ #ifndef TAGLIB_MODTAG_H #define TAGLIB_MODTAG_H -#include <taglib/tag.h> +#include "tag.h" namespace TagLib { namespace Mod { class TAGLIB_EXPORT Tag : public TagLib::Tag { public: - String title() const { return m_title; } - String artist() const { return String::null; } - String album() const { return String::null; } - String comment() const { return m_comment; } - String genre() const { return String::null; } - uint year() const { return 0; } - uint track() const { return 0; } - - void setTitle (const String &title) { m_title = title; } - void setArtist (const String &) {} - void setAlbum (const String &) {} - void setComment(const String &comment) { m_comment = comment; } - void setGenre (const String &) {} - void setYear (uint) {} - void setTrack(uint) {} + Tag(); + virtual ~Tag(); + + String title() const; + String artist() const; + String album() const; + String comment() const; + String genre() const; + uint year() const; + uint track() const; + + void setTitle (const String &title); + void setArtist (const String &artist); + void setAlbum (const String &album); + void setComment(const String &comment); + void setGenre (const String &genre); + void setYear (uint year); + void setTrack(uint track); private: - String m_title; - String m_comment; + Tag(const Tag &); + Tag &operator=(const Tag &); + + class TagPrivate; + TagPrivate *d; }; } } diff --git a/taglib/s3m/s3mfile.cpp b/taglib/s3m/s3mfile.cpp index 5bc24e20..5fee5a2c 100644 --- a/taglib/s3m/s3mfile.cpp +++ b/taglib/s3m/s3mfile.cpp @@ -20,124 +20,142 @@ ***************************************************************************/ #include "s3mfile.h" - #include "tstringlist.h" +#include "modfileprivate.h" + +using namespace TagLib; +using namespace S3M; -namespace TagLib { +class S3M::File::FilePrivate +{ +public: + FilePrivate(AudioProperties::ReadStyle propertiesStyle) + : properties(propertiesStyle) + { + } - namespace S3M { + Mod::Tag tag; + S3M::Properties properties; +}; -File::File(FileName file, bool readProperties, +S3M::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : - Mod::File(file), m_tag(0), m_properties(0) { - read(readProperties, propertiesStyle); + Mod::File(file) +{ + d = new FilePrivate(propertiesStyle); + read(readProperties); } -File::~File() { - delete m_tag; - delete m_properties; +S3M::File::File(IOStream *stream, bool readProperties, + AudioProperties::ReadStyle propertiesStyle) : + Mod::File(stream) +{ + d = new FilePrivate(propertiesStyle); + read(readProperties); } -Mod::Tag *File::tag() const { - return m_tag; +S3M::File::~File() +{ + delete d; } -S3M::Properties *File::audioProperties() const { - return m_properties; +Mod::Tag *S3M::File::tag() const +{ + return &d->tag; } -bool File::save() { - return false; +S3M::Properties *S3M::File::audioProperties() const +{ + return &d->properties; } -void File::read(bool, AudioProperties::ReadStyle propertiesStyle) { - delete m_tag; - delete m_properties; - - m_tag = new Mod::Tag(); - m_properties = new S3M::Properties(propertiesStyle); +bool S3M::File::save() +{ + // note: if title starts with "Extended Module: " + // the file would look like an .xm file + seek(0); + writeString(d->tag.title(), 28); + // TODO: write comment as sample names + return true; +} - if (!isOpen()) +void S3M::File::read(bool) +{ + if(!isOpen()) return; - try { - m_tag->setTitle(readString(28)); + READ_STRING(d->tag.setTitle, 28); + READ_BYTE_AS(mark); + READ_BYTE_AS(type); - uint8_t mark = readByte(); - uint8_t type = readByte(); + READ_ASSERT(mark == 0x1A && type == 0x10); - if (mark != 0x1A || type != 0x10) { - throw Mod::ReadError(); - } + seek(32); - seek(32); + READ_U16L_AS(length); + READ_U16L_AS(sampleCount); - uint16_t length = readU16L(); - uint16_t sampleCount = readU16L(); - m_properties->setSampleLength(length); - m_properties->setSampleCount(sampleCount); - m_properties->setPatternCount(readU16L()); - m_properties->setFlags(readU16L()); - m_properties->setVersion(readU16L()); - m_properties->setSamplesType(readU16L()); + d->properties.setSampleLength(length); + d->properties.setSampleCount(sampleCount); - ByteVector mod_id(readBytes(4UL)); + READ_U16L(d->properties.setPatternCount); + READ_U16L(d->properties.setFlags); + READ_U16L(d->properties.setVersion); + READ_U16L(d->properties.setSamplesType); - if (mod_id != "SCRM") { - throw Mod::ReadError(); - } + READ_ASSERT(readBlock(4) == "SCRM"); - m_properties->setBaseVolume(readByte() << 1); - m_properties->setTempo(readByte()); - m_properties->setBpmSpeed(readByte()); - m_properties->setStereo((readByte() & 0x80) != 0); - m_properties->setUltraClick(readByte()); - m_properties->setUsePanningValues(readByte() == 0xFC); + READ_BYTE_AS(baseVolume); + d->properties.setBaseVolume(baseVolume << 1); - seek(10, Current); + READ_BYTE(d->properties.setTempo); + READ_BYTE(d->properties.setBpmSpeed); - int channels = 0; - for (int i = 0; i < 32; ++ i) { - if (readByte() != 0xff) ++ channels; - } - m_properties->setChannels(channels); + READ_BYTE_AS(stereo); + d->properties.setStereo((stereo & 0x80) != 0); + READ_BYTE(d->properties.setUltraClick); - seek(channels, Current); + READ_BYTE_AS(usePanningValues); + d->properties.setUsePanningValues(usePanningValues == 0xFC); - StringList comment; - for (uint16_t i = 0; i < sampleCount; ++ i) { - seek(96 + length + (i << 1)); + seek(10, Current); - uint16_t instrumentOffset = readU16L(); - seek(instrumentOffset << 4); + int channels = 0; + for(int i = 0; i < 32; ++ i) + { + READ_BYTE_AS(terminator); + if (terminator != 0xff) ++ channels; + } + d->properties.setChannels(channels); - uint8_t sampleType = readByte(); - String dosFileName = readString(13); + seek(channels, Current); - uint16_t sampleOffset = readU16L(); - uint32_t sampleLength = readU32L(); - uint32_t repeatStart = readU32L(); - uint32_t repeatStop = readU32L(); - uint8_t sampleColume = readByte(); + StringList comment; + for(ushort i = 0; i < sampleCount; ++ i) + { + seek(96 + length + (i << 1)); - seek(2, Current); + READ_U16L_AS(instrumentOffset); + seek(instrumentOffset << 4); - uint8_t sampleFlags = readByte(); - uint32_t baseFrequency = readU32L(); + READ_BYTE_AS(sampleType); + READ_STRING_AS(dosFileName, 13); + READ_U16L_AS(sampleOffset); + READ_U32L_AS(sampleLength); + READ_U32L_AS(repeatStart); + READ_U32L_AS(repeatStop); + READ_BYTE_AS(sampleVolume); - seek(12, Current); + seek(2, Current); - String sampleName = readString(28); + READ_BYTE_AS(sampleFlags); + READ_U32L_AS(baseFrequency); - comment.append(sampleName); - } + seek(12, Current); - m_tag->setComment(comment.toString("\n")); - } - catch (const Mod::ReadError&) { - setValid(false); + READ_STRING_AS(sampleName, 28); + comment.append(sampleName); } -} - } + d->tag.setComment(comment.toString("\n")); } diff --git a/taglib/s3m/s3mfile.h b/taglib/s3m/s3mfile.h index 8cc11943..97606576 100644 --- a/taglib/s3m/s3mfile.h +++ b/taglib/s3m/s3mfile.h @@ -42,22 +42,31 @@ namespace TagLib { * is true the file's audio properties will also be read using * \a propertiesStyle. If false, \a propertiesStyle is ignored. */ - explicit File(FileName file, bool readProperties = true, - AudioProperties::ReadStyle propertiesStyle = - AudioProperties::Average); + File(FileName file, bool readProperties = true, + AudioProperties::ReadStyle propertiesStyle = + AudioProperties::Average); + + /*! + * Contructs a ScreamTracker III 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. + */ + File(IOStream *stream, bool readProperties = true, + AudioProperties::ReadStyle propertiesStyle = + AudioProperties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); - virtual Mod::Tag *tag() const; + Mod::Tag *tag() const; /*! * Returns the S3M::Properties for this file. If no audio properties * were read then this will return a null pointer. */ - virtual S3M::Properties *audioProperties() const; + S3M::Properties *audioProperties() const; /*! * Save the file. @@ -65,16 +74,16 @@ namespace TagLib { * * \note Saving ScreamTracker III tags is not supported. */ - virtual bool save(); - - void read(bool readProperties, AudioProperties::ReadStyle propertiesStyle); + bool save(); private: File(const File &); File &operator=(const File &); - Mod::Tag *m_tag; - S3M::Properties *m_properties; + void read(bool readProperties); + + class FilePrivate; + FilePrivate *d; }; } } diff --git a/taglib/s3m/s3mfiletyperesolver.cpp b/taglib/s3m/s3mfiletyperesolver.cpp deleted file mode 100644 index 7ac67f15..00000000 --- a/taglib/s3m/s3mfiletyperesolver.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "s3mfiletyperesolver.h" -#include "s3mfile.h" - -TagLib::File *S3MFileTypeResolver::createFile( - TagLib::FileName fileName, - bool readProperties, - TagLib::AudioProperties::ReadStyle propertiesStyle) const { - TagLib::S3M::File *f = new TagLib::S3M::File(fileName, readProperties, propertiesStyle); - if (f->isValid()) { - return f; - } - else { - delete f; - return 0; - } -} diff --git a/taglib/s3m/s3mproperties.cpp b/taglib/s3m/s3mproperties.cpp new file mode 100644 index 00000000..de1468d7 --- /dev/null +++ b/taglib/s3m/s3mproperties.cpp @@ -0,0 +1,214 @@ +/*************************************************************************** + copyright : (C) 2011 by Mathias Panzenböck + email : grosser.meister.morti@gmx.net + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301 USA * + ***************************************************************************/ + +#include "s3mproperties.h" + +using namespace TagLib; +using namespace S3M; + +class S3M::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate() : + sampleLength(0), + channels(0), + stereo(0), + sampleCount(0), + patternCount(0), + flags(0), + version(0), + samplesType(0), + baseVolume(0), + tempo(0), + bpmSpeed(0), + ultraClick(0), + usePanningValues(false) {} + + ushort sampleLength; + int channels; + bool stereo; + ushort sampleCount; + ushort patternCount; + ushort flags; + ushort version; + ushort samplesType; + int baseVolume; + uchar tempo; + uchar bpmSpeed; + uchar ultraClick; + bool usePanningValues; +}; + +S3M::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : + AudioProperties(propertiesStyle), + d(new PropertiesPrivate) +{ +} + +S3M::Properties::~Properties() +{ + delete d; +} + +int S3M::Properties::length() const +{ + return 0; +} + +int S3M::Properties::bitrate() const +{ + return 0; +} + +int S3M::Properties::sampleRate() const +{ + return 0; +} + +int S3M::Properties::channels() const +{ + return d->channels; +} + +ushort S3M::Properties::sampleLength() const +{ + return d->sampleLength; +} + +bool S3M::Properties::stereo() const +{ + return d->stereo; +} + +ushort S3M::Properties::sampleCount() const +{ + return d->sampleCount; +} + +ushort S3M::Properties::patternCount() const +{ + return d->patternCount; +} + +ushort S3M::Properties::flags() const +{ + return d->flags; +} + +ushort S3M::Properties::version() const +{ + return d->version; +} + +ushort S3M::Properties::samplesType() const +{ + return d->samplesType; +} + +int S3M::Properties::baseVolume() const +{ + return d->baseVolume; +} + +uchar S3M::Properties::tempo() const +{ + return d->tempo; +} + +uchar S3M::Properties::bpmSpeed() const +{ + return d->bpmSpeed; +} + +uchar S3M::Properties::ultraClick() const +{ + return d->ultraClick; +} + +bool S3M::Properties::usePanningValues() const +{ + return d->usePanningValues; +} + +void S3M::Properties::setSampleLength(ushort sampleLength) +{ + d->sampleLength = sampleLength; +} + +void S3M::Properties::setChannels(int channels) +{ + d->channels = channels; +} + +void S3M::Properties::setStereo(bool stereo) +{ + d->stereo = stereo; +} + +void S3M::Properties::setSampleCount(ushort sampleCount) +{ + d->sampleCount = sampleCount; +} + +void S3M::Properties::setPatternCount(ushort patternCount) +{ + d->patternCount = patternCount; +} + +void S3M::Properties::setFlags(ushort flags) +{ + d->flags = flags; +} + +void S3M::Properties::setVersion(ushort version) +{ + d->version = version; +} + +void S3M::Properties::setSamplesType(ushort samplesType) +{ + d->samplesType = samplesType; +} + +void S3M::Properties::setBaseVolume(int baseVolume) +{ + d->baseVolume = baseVolume; +} + +void S3M::Properties::setTempo(uchar tempo) +{ + d->tempo = tempo; +} + +void S3M::Properties::setBpmSpeed(uchar bpmSpeed) +{ + d->bpmSpeed = bpmSpeed; +} + +void S3M::Properties::setUltraClick(uchar ultraClick) +{ + d->ultraClick = ultraClick; +} + +void S3M::Properties::setUsePanningValues(bool usePanningValues) +{ + d->usePanningValues = usePanningValues; +} diff --git a/taglib/s3m/s3mproperties.h b/taglib/s3m/s3mproperties.h index 202a3d9b..83697feb 100644 --- a/taglib/s3m/s3mproperties.h +++ b/taglib/s3m/s3mproperties.h @@ -22,7 +22,7 @@ #ifndef TAGLIB_S3MPROPERTIES_H #define TAGLIB_S3MPROPERTIES_H -#include <stdint.h> +#include "taglib.h" #include "audioproperties.h" namespace TagLib { @@ -30,72 +30,49 @@ namespace TagLib { class TAGLIB_EXPORT Properties : public AudioProperties { friend class File; public: - Properties(AudioProperties::ReadStyle propertiesStyle) : - AudioProperties(propertiesStyle), - m_sampleLength(0), - m_channels(0), - m_stereo(false), - m_sampleCount(0), - m_patternCount(0), - m_flags(0), - m_version(0), - m_samplesType(0), - m_baseVolume(0), - m_tempo(0), - m_bpmSpeed(0), - m_ultraClick(0), - m_usePanningValues(false) {} + Properties(AudioProperties::ReadStyle propertiesStyle); + virtual ~Properties(); - int length() const { return 0; } - int bitrate() const { return 0; } - int sampleRate() const { return 0; } - int channels() const { return m_channels; } + int length() const; + int bitrate() const; + int sampleRate() const; + int channels() const; - uint16_t sampleLength() const { return m_sampleLength; } - bool stereo() const { return m_stereo; } - uint16_t sampleCount() const { return m_sampleCount; } - uint16_t patternCount() const { return m_patternCount; } - uint16_t flags() const { return m_flags; } - uint16_t version() const { return m_version; } - uint16_t samplesType() const { return m_samplesType; } - int baseVolume() const { return m_baseVolume; } - uint8_t tempo() const { return m_tempo; } - uint8_t bpmSpeed() const { return m_bpmSpeed; } - uint8_t ultraClick() const { return m_ultraClick; } - bool usePanningValues() const { return m_usePanningValues; } + ushort sampleLength() const; + bool stereo() const; + ushort sampleCount() const; + ushort patternCount() const; + ushort flags() const; + ushort version() const; + ushort samplesType() const; + int baseVolume() const; + uchar tempo() const; + uchar bpmSpeed() const; + uchar ultraClick() const; + bool usePanningValues() const; protected: - void setSampleLength(uint16_t sampleLength) { m_sampleLength = sampleLength; } - void setChannels(int channels) { m_channels = channels; } + void setSampleLength(ushort sampleLength); + void setChannels(int channels); - void setStereo (bool stereo) { m_stereo = stereo; } - void setSampleCount (uint16_t sampleCount) { m_sampleCount = sampleCount; } - void setPatternCount(uint16_t patternCount) { m_patternCount = patternCount; } - void setFlags (uint16_t flags) { m_flags = flags; } - void setVersion (uint16_t version) { m_version = version; } - void setSamplesType (uint16_t samplesType) { m_samplesType = samplesType; } - void setBaseVolume (int baseVolume) { m_baseVolume = baseVolume; } - void setTempo (uint8_t tempo) { m_tempo = tempo; } - void setBpmSpeed (uint8_t bpmSpeed) { m_bpmSpeed = bpmSpeed; } - void setUltraClick (uint8_t ultraClick) { m_ultraClick = ultraClick; } - void setUsePanningValues(bool usePanningValues) { - m_usePanningValues = usePanningValues; - } + void setStereo (bool stereo); + void setSampleCount (ushort sampleCount); + void setPatternCount(ushort patternCount); + void setFlags (ushort flags); + void setVersion (ushort version); + void setSamplesType (ushort samplesType); + void setBaseVolume (int baseVolume); + void setTempo (uchar tempo); + void setBpmSpeed (uchar bpmSpeed); + void setUltraClick (uchar ultraClick); + void setUsePanningValues(bool usePanningValues); private: - uint16_t m_sampleLength; - int m_channels; - bool m_stereo; - uint16_t m_sampleCount; - uint16_t m_patternCount; - uint16_t m_flags; - uint16_t m_version; - uint16_t m_samplesType; - int m_baseVolume; - uint8_t m_tempo; - uint8_t m_bpmSpeed; - uint8_t m_ultraClick; - bool m_usePanningValues; + Properties(const Properties&); + Properties &operator=(const Properties&); + + class PropertiesPrivate; + PropertiesPrivate *d; }; } } diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index c42f1bde..eebafbc5 100644 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -76,9 +76,10 @@ namespace TagLib { class String; typedef wchar_t wchar; - typedef unsigned char uchar; - typedef unsigned int uint; - typedef unsigned long ulong; + typedef unsigned char uchar; + typedef unsigned short ushort; + typedef unsigned int uint; + typedef unsigned long ulong; /*! * Unfortunately std::wstring isn't defined on some systems, (i.e. GCC < 3) diff --git a/taglib/xm/xmfile.cpp b/taglib/xm/xmfile.cpp index a71a56a9..a7cc9ccc 100644 --- a/taglib/xm/xmfile.cpp +++ b/taglib/xm/xmfile.cpp @@ -21,138 +21,175 @@ #include "tstringlist.h" #include "xmfile.h" +#include "modfileprivate.h" #include <algorithm> -namespace TagLib { +using namespace TagLib; +using namespace XM; - namespace XM { +class XM::File::FilePrivate +{ +public: + FilePrivate(AudioProperties::ReadStyle propertiesStyle) + : tag(), properties(propertiesStyle) + { + } -File::File(FileName file, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::File(file), m_tag(0), m_properties(0) { - read(readProperties, propertiesStyle); -} + XM::Tag tag; + XM::Properties properties; +}; -File::~File() { - delete m_tag; - delete m_properties; +XM::File::File(FileName file, bool readProperties, + AudioProperties::ReadStyle propertiesStyle) : + Mod::File(file), + d(new FilePrivate(propertiesStyle)) +{ + read(readProperties); } -XM::Tag *File::tag() const { - return m_tag; +XM::File::File(IOStream *stream, bool readProperties, + AudioProperties::ReadStyle propertiesStyle) : + Mod::File(stream), + d(new FilePrivate(propertiesStyle)) +{ + read(readProperties); } -XM::Properties *File::audioProperties() const { - return m_properties; +XM::File::~File() +{ + delete d; } -bool File::save() { - return false; +XM::Tag *XM::File::tag() const +{ + return &d->tag; } -void File::read(bool, AudioProperties::ReadStyle propertiesStyle) { - delete m_tag; - delete m_properties; +XM::Properties *XM::File::audioProperties() const +{ + return &d->properties; +} - m_tag = new XM::Tag(); - m_properties = new XM::Properties(propertiesStyle); +bool XM::File::save() +{ + seek(17); + writeString(d->tag.title(), 20); + seek(1, Current); + writeString(d->tag.trackerName(), 20); + // TODO: write comment as instrument and sample names + return true; +} - if (!isOpen()) +void XM::File::read(bool) +{ + if(!isOpen()) return; - try { - if (readBytes(17) != "Extended Module: ") { - throw Mod::ReadError(); - } - - m_tag->setTitle(readString(20)); - - if (readByte() != 0x1A) { - throw Mod::ReadError(); - } - - m_tag->setTrackerName(readString(20)); - m_properties->setVersion(readU16L()); - uint32_t headerSize = readU32L(); - m_properties->setSampleLength(readU16L()); - m_properties->setRestartPosition(readU16L()); - m_properties->setChannels(readU16L()); - uint32_t patternCount = readU16L(); - m_properties->setPatternCount(patternCount); - uint32_t instrumentCount = readU16L(); - m_properties->setInstrumentCount(instrumentCount); - m_properties->setFlags(readU16L()); - m_properties->setTempo(readU16L()); - m_properties->setBpmSpeed(readU16L()); - - seek(60 + headerSize); + READ_ASSERT(readBlock(17) == "Extended Module: "); + + READ_STRING(d->tag.setTitle, 20); + READ_BYTE_AS(mark); + READ_ASSERT(mark == 0x1A); + + READ_STRING(d->tag.setTrackerName, 20); + READ_U16L(d->properties.setVersion); + READ_U32L_AS(headerSize); + READ_U16L(d->properties.setSampleLength); + READ_U16L(d->properties.setRestartPosition); + READ_U16L(d->properties.setChannels); + READ_U16L_AS(patternCount); + d->properties.setPatternCount(patternCount); + READ_U16L_AS(instrumentCount); + d->properties.setInstrumentCount(instrumentCount); + READ_U16L(d->properties.setFlags); + READ_U16L(d->properties.setTempo); + READ_U16L(d->properties.setBpmSpeed); + + seek(60 + headerSize); - for (uint16_t i = 0; i < patternCount; ++ i) { - uint32_t patternHeaderLength = readU32L(); - uint8_t patternType = readByte(); - uint16_t rowCount = readU16L(); - uint16_t patternDataSize = readU16L(); - - seek(patternHeaderLength - (4+1+2+2) + patternDataSize, Current); - } + for(ushort i = 0; i < patternCount; ++ i) + { + READ_U32L_AS(patternHeaderLength); + READ_BYTE_AS(patternType); + READ_U16L_AS(rowCount); + READ_U16L_AS(patternDataSize); + + seek(patternHeaderLength - (4+1+2+2) + patternDataSize, Current); + } - StringList intrumentNames; - StringList sampleNames; - for (uint16_t i = 0; i < instrumentCount; ++ i) { - long pos = tell(); - uint32_t instrumentSize = readU32L(); - - String instrumentName; - uint8_t instrumentType = 0; - uint16_t sampleCount = 0; + StringList intrumentNames; + StringList sampleNames; + for(ushort i = 0; i < instrumentCount; ++ i) + { + long pos = tell(); + READ_U32L_AS(instrumentSize); + + String instrumentName; + uchar instrumentType = 0; + ushort sampleCount = 0; - if (instrumentSize > 4) { - instrumentName = readString(std::min((uint32_t)22,instrumentSize-4)); + if(instrumentSize > 4) + { + if(!readString(instrumentName, std::min(22UL, instrumentSize-4))) + { + setValid(false); + return; + } - if (instrumentSize >= (4+22+1)) { - instrumentType = readByte(); + if(instrumentSize >= (4+22+1)) + { + if(!readByte(instrumentType)) + { + setValid(false); + return; + } - if (instrumentSize >= (4+22+1+2)) { - sampleCount = readU16L(); + if (instrumentSize >= (4+22+1+2)) + { + if(!readU16L(sampleCount)) + { + setValid(false); + return; } } } + } - uint32_t sampleHeaderSize = 0; - uint32_t sumSampleLength = 0; - if (sampleCount > 0) { - sampleHeaderSize = readU32L(); - seek(pos + instrumentSize); - - long sampleheaderPos = tell(); - for (uint16_t j = 0; j < sampleCount; ++ j) { - seek(sampleheaderPos + sampleHeaderSize * j); - uint32_t length = readU32L(); - uint32_t loopStart = readU32L(); - uint32_t loopLength = readU32L(); - uint8_t volume = readByte(); - uint8_t finetune = readByte(); - uint8_t sampleType = readByte(); - uint8_t panning = readByte(); - uint8_t noteNumber = readByte(); - uint8_t compression = readByte(); - String sampleName = readString(22); - - sumSampleLength += length; - sampleNames.append(sampleName); - } + ulong sumSampleLength = 0; + ulong sampleHeaderSize = 0; + if (sampleCount > 0) + { + if(!readU32L(sampleHeaderSize)) + { + setValid(false); + return; } - intrumentNames.append(instrumentName); - seek(pos + instrumentSize + sampleHeaderSize * sampleCount + sumSampleLength); - } - m_tag->setComment(intrumentNames.toString("\n") + "\n" + sampleNames.toString("\n")); - } - catch (const Mod::ReadError&) { - setValid(false); + seek(pos + instrumentSize); + + long sampleheaderPos = tell(); + for (ushort j = 0; j < sampleCount; ++ j) + { + seek(sampleheaderPos + sampleHeaderSize * j); + READ_U32L_AS(length); + READ_U32L_AS(loopStart); + READ_U32L_AS(loopLength); + READ_BYTE_AS(volume); + READ_BYTE_AS(finetune); + READ_BYTE_AS(sampleType); + READ_BYTE_AS(panning); + READ_BYTE_AS(noteNumber); + READ_BYTE_AS(compression); + READ_STRING_AS(sampleName, 22); + + sumSampleLength += length; + sampleNames.append(sampleName); + } + } + intrumentNames.append(instrumentName); + seek(pos + instrumentSize + sampleHeaderSize * sampleCount + sumSampleLength); } -} - } + d->tag.setComment(intrumentNames.toString("\n") + "\n" + sampleNames.toString("\n")); } diff --git a/taglib/xm/xmfile.h b/taglib/xm/xmfile.h index 3dfadec8..05c19e58 100644 --- a/taglib/xm/xmfile.h +++ b/taglib/xm/xmfile.h @@ -42,22 +42,31 @@ namespace TagLib { * is true the file's audio properties will also be read using * \a propertiesStyle. If false, \a propertiesStyle is ignored. */ - explicit File(FileName file, bool readProperties = true, - AudioProperties::ReadStyle propertiesStyle = - AudioProperties::Average); + File(FileName file, bool readProperties = true, + AudioProperties::ReadStyle propertiesStyle = + AudioProperties::Average); + + /*! + * Contructs a Extended Module 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. + */ + File(IOStream *stream, bool readProperties = true, + AudioProperties::ReadStyle propertiesStyle = + AudioProperties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); - virtual XM::Tag *tag() const; + XM::Tag *tag() const; /*! * Returns the XM::Properties for this file. If no audio properties * were read then this will return a null pointer. */ - virtual XM::Properties *audioProperties() const; + XM::Properties *audioProperties() const; /*! * Save the file. @@ -65,16 +74,16 @@ namespace TagLib { * * \note Saving Extended Module tags is not supported. */ - virtual bool save(); - - void read(bool readProperties, AudioProperties::ReadStyle propertiesStyle); + bool save(); private: File(const File &); File &operator=(const File &); - XM::Tag *m_tag; - XM::Properties *m_properties; + void read(bool readProperties); + + class FilePrivate; + FilePrivate *d; }; } } diff --git a/taglib/xm/xmfiletyperesolver.cpp b/taglib/xm/xmfiletyperesolver.cpp deleted file mode 100644 index 16541bdc..00000000 --- a/taglib/xm/xmfiletyperesolver.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "xmfiletyperesolver.h" -#include "xmfile.h" - -TagLib::File *XMFileTypeResolver::createFile( - TagLib::FileName fileName, - bool readProperties, - TagLib::AudioProperties::ReadStyle propertiesStyle) const { - TagLib::XM::File *f = new TagLib::XM::File(fileName, readProperties, propertiesStyle); - if (f->isValid()) { - return f; - } - else { - delete f; - return 0; - } -} diff --git a/taglib/xm/xmproperties.cpp b/taglib/xm/xmproperties.cpp new file mode 100644 index 00000000..5114a864 --- /dev/null +++ b/taglib/xm/xmproperties.cpp @@ -0,0 +1,168 @@ +/*************************************************************************** + copyright :(C) 2011 by Mathias Panzenböck + email : grosser.meister.morti@gmx.net + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301 USA * + ***************************************************************************/ + +#include "xmproperties.h" + +using namespace TagLib; +using namespace XM; + +class XM::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate() : + sampleLength(0), + channels(0), + version(0), + restartPosition(0), + patternCount(0), + instrumentCount(0), + flags(0), + tempo(0), + bpmSpeed(0) + { + } + + ushort sampleLength; + int channels; + ushort version; + ushort restartPosition; + ushort patternCount; + ushort instrumentCount; + ushort flags; + ushort tempo; + ushort bpmSpeed; +}; + +XM::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : + AudioProperties(propertiesStyle), + d(new PropertiesPrivate) +{ +} + +XM::Properties::~Properties() +{ + delete d; +} + +int XM::Properties::length() const +{ + return 0; +} + +int XM::Properties::bitrate() const +{ + return 0; +} + +int XM::Properties::sampleRate() const +{ + return 0; +} + +int XM::Properties::channels() const +{ + return d->channels; +} + +ushort XM::Properties::sampleLength() const +{ + return d->sampleLength; +} + +ushort XM::Properties::version() const +{ + return d->version; +} + +ushort XM::Properties::restartPosition() const +{ + return d->restartPosition; +} + +ushort XM::Properties::patternCount() const +{ + return d->patternCount; +} + +ushort XM::Properties::instrumentCount() const +{ + return d->instrumentCount; +} + +ushort XM::Properties::flags() const +{ + return d->flags; +} + +ushort XM::Properties::tempo() const +{ + return d->tempo; +} + +ushort XM::Properties::bpmSpeed() const +{ + return d->bpmSpeed; +} + +void XM::Properties::setSampleLength(int sampleLength) +{ + d->sampleLength = sampleLength; +} + +void XM::Properties::setChannels(int channels) +{ + d->channels = channels; +} + +void XM::Properties::setVersion(ushort version) +{ + d->version = version; +} + +void XM::Properties::setRestartPosition(ushort restartPosition) +{ + d->restartPosition = restartPosition; +} + +void XM::Properties::setPatternCount(ushort patternCount) +{ + d->patternCount = patternCount; +} + +void XM::Properties::setInstrumentCount(ushort instrumentCount) +{ + d->instrumentCount = instrumentCount; +} + +void XM::Properties::setFlags(ushort flags) +{ + d->flags = flags; +} + +void XM::Properties::setTempo(ushort tempo) +{ + d->tempo = tempo; +} + +void XM::Properties::setBpmSpeed(ushort bpmSpeed) +{ + d->bpmSpeed = bpmSpeed; +} diff --git a/taglib/xm/xmproperties.h b/taglib/xm/xmproperties.h index aee086f4..3506833c 100644 --- a/taglib/xm/xmproperties.h +++ b/taglib/xm/xmproperties.h @@ -22,8 +22,7 @@ #ifndef TAGLIB_XMPROPERTIES_H #define TAGLIB_XMPROPERTIES_H -#include <stdint.h> - +#include "taglib.h" #include "tstring.h" #include "audioproperties.h" @@ -32,58 +31,41 @@ namespace TagLib { class Properties : public AudioProperties { friend class File; public: - Properties(AudioProperties::ReadStyle propertiesStyle) : - AudioProperties(propertiesStyle), - m_sampleLength(0), - m_channels(0), - m_version(0), - m_restartPosition(0), - m_patternCount(0), - m_instrumentCount(0), - m_flags(0), - m_tempo(0), - m_bpmSpeed(0) {} + Properties(AudioProperties::ReadStyle propertiesStyle); + virtual ~Properties(); - int length() const { return 0; } - int bitrate() const { return 0; } - int sampleRate() const { return 0; } - int channels() const { return m_channels; } + int length() const; + int bitrate() const; + int sampleRate() const; + int channels() const; - uint16_t sampleLength() const { return m_sampleLength; } - uint16_t version() const { return m_version; } - uint16_t restartPosition() const { return m_restartPosition; } - uint16_t patternCount() const { return m_patternCount; } - uint16_t instrumentCount() const { return m_instrumentCount; } - uint16_t flags() const { return m_flags; } - uint16_t tempo() const { return m_tempo; } - uint16_t bpmSpeed() const { return m_bpmSpeed; } + ushort sampleLength() const; + ushort version() const; + ushort restartPosition() const; + ushort patternCount() const; + ushort instrumentCount() const; + ushort flags() const; + ushort tempo() const; + ushort bpmSpeed() const; protected: - void setSampleLength(int sampleLength) { m_sampleLength = sampleLength; } - void setChannels(int channels) { m_channels = channels; } + void setSampleLength(int sampleLength); + void setChannels(int channels); - void setVersion(uint16_t version) { m_version = version; } - void setRestartPosition(uint16_t restartPosition) { - m_restartPosition = restartPosition; - } - void setPatternCount(uint16_t patternCount) { m_patternCount = patternCount; } - void setInstrumentCount(uint16_t instrumentCount) { - m_instrumentCount = instrumentCount; - } - void setFlags (uint16_t flags) { m_flags = flags; } - void setTempo (uint16_t tempo) { m_tempo = tempo; } - void setBpmSpeed(uint16_t bpmSpeed) { m_bpmSpeed = bpmSpeed; } + void setVersion(ushort version); + void setRestartPosition(ushort restartPosition); + void setPatternCount(ushort patternCount); + void setInstrumentCount(ushort instrumentCount); + void setFlags(ushort flags); + void setTempo(ushort tempo); + void setBpmSpeed(ushort bpmSpeed); private: - uint16_t m_sampleLength; - int m_channels; - uint16_t m_version; - uint16_t m_restartPosition; - uint16_t m_patternCount; - uint16_t m_instrumentCount; - uint16_t m_flags; - uint16_t m_tempo; - uint16_t m_bpmSpeed; + Properties(const Properties&); + Properties &operator=(const Properties&); + + class PropertiesPrivate; + PropertiesPrivate *d; }; } } diff --git a/taglib/s3m/s3mfiletyperesolver.h b/taglib/xm/xmtag.cpp index bbf87e12..8de85282 100644 --- a/taglib/s3m/s3mfiletyperesolver.h +++ b/taglib/xm/xmtag.cpp @@ -1,6 +1,6 @@ /*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net + copyright : (C) 2011 by Mathias Panzenböck + email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** @@ -19,17 +19,102 @@ * MA 02110-1301 USA * ***************************************************************************/ -#ifndef TAGLIB_S3MFILETYPERESOLVER_H -#define TAGLIB_S3MFILETYPERESOLVER_H +#include "xmtag.h" -#include "fileref.h" -#include "taglib_export.h" +using namespace TagLib; +using namespace XM; -class TAGLIB_EXPORT S3MFileTypeResolver : public TagLib::FileRef::FileTypeResolver { - TagLib::File *createFile(TagLib::FileName fileName, - bool readAudioProperties, - TagLib::AudioProperties::ReadStyle audioPropertiesStyle) const; - ~S3MFileTypeResolver() {} +class XM::Tag::TagPrivate +{ +public: + TagPrivate() {} + + String title; + String comment; + String trackerName; }; -#endif +XM::Tag::Tag() : TagLib::Tag() +{ + d = new TagPrivate; +} + +XM::Tag::~Tag() +{ + delete d; +} + +String XM::Tag::title() const +{ + return d->title; +} + +String XM::Tag::artist() const +{ + return String::null; +} + +String XM::Tag::album() const +{ + return String::null; +} + +String XM::Tag::comment() const +{ + return d->comment; +} + +String XM::Tag::genre() const +{ + return String::null; +} + +uint XM::Tag::year() const +{ + return 0; +} + +uint XM::Tag::track() const +{ + return 0; +} + +String XM::Tag::trackerName() const +{ + return d->trackerName; +} + +void XM::Tag::setTitle(const String &title) +{ + d->title = title; +} + +void XM::Tag::setArtist(const String &) +{ +} + +void XM::Tag::setAlbum(const String &) +{ +} + +void XM::Tag::setComment(const String &comment) +{ + d->comment = comment; +} + +void XM::Tag::setGenre(const String &) +{ +} + +void XM::Tag::setYear(uint) +{ +} + +void XM::Tag::setTrack(uint) +{ +} + +void XM::Tag::setTrackerName(const String &trackerName) +{ + d->trackerName = trackerName; +} diff --git a/taglib/xm/xmtag.h b/taglib/xm/xmtag.h index adbc5468..48525cec 100644 --- a/taglib/xm/xmtag.h +++ b/taglib/xm/xmtag.h @@ -26,16 +26,35 @@ namespace TagLib { namespace XM { - class Tag : public Mod::Tag { + class Tag : public TagLib::Tag { public: - String trackerName() const { return m_trackerName; } + Tag(); + virtual ~Tag(); - void setTrackerName(const String &trackerName) { - m_trackerName = trackerName; - } + String title() const; + String artist() const; + String album() const; + String comment() const; + String genre() const; + uint year() const; + uint track() const; + String trackerName() const; + + void setTitle (const String &title); + void setArtist (const String &artist); + void setAlbum (const String &album); + void setComment(const String &comment); + void setGenre (const String &genre); + void setYear (uint year); + void setTrack(uint track); + void setTrackerName(const String &trackerName); private: - String m_trackerName; + Tag(const Tag &); + Tag &operator=(const Tag &); + + class TagPrivate; + TagPrivate *d; }; } } |