From 3b8c7d4e3a5d82298680d3b0b92be5feeb73ea4f Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 30 Dec 2014 23:53:40 +0900 Subject: [PATCH] Add support for AIFF-C files. --- taglib/fileref.cpp | 2 +- taglib/riff/aiff/aiffproperties.cpp | 33 ++++++++++++++++++++++++---- taglib/riff/aiff/aiffproperties.h | 24 ++++++++++++++++++++ tests/data/alaw.aifc | Bin 0 -> 1890 bytes tests/data/segfault.aif | Bin 0 -> 31 bytes tests/test_aiff.cpp | 20 +++++++++++++++++ 6 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 tests/data/alaw.aifc create mode 100644 tests/data/segfault.aif diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 4403a5fb..2b5d5f23 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -265,7 +265,7 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WMA" || ext == "ASF") return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "AIF" || ext == "AIFF") + if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC") return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WAV") return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle); diff --git a/taglib/riff/aiff/aiffproperties.cpp b/taglib/riff/aiff/aiffproperties.cpp index 1afb4a99..63fed45f 100644 --- a/taglib/riff/aiff/aiffproperties.cpp +++ b/taglib/riff/aiff/aiffproperties.cpp @@ -38,16 +38,17 @@ public: sampleRate(0), channels(0), sampleWidth(0), - sampleFrames(0) - { - - } + sampleFrames(0) {} int length; int bitrate; int sampleRate; int channels; int sampleWidth; + + ByteVector compressionType; + String compressionName; + uint sampleFrames; }; @@ -96,12 +97,31 @@ TagLib::uint RIFF::AIFF::Properties::sampleFrames() const return d->sampleFrames; } +bool RIFF::AIFF::Properties::isAiffC() const +{ + return (!d->compressionType.isEmpty()); +} + +ByteVector RIFF::AIFF::Properties::compressionType() const +{ + return d->compressionType; +} + +String RIFF::AIFF::Properties::compressionName() const +{ + return d->compressionName; +} //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void RIFF::AIFF::Properties::read(const ByteVector &data) { + if(data.size() < 18) { + debug("RIFF::AIFF::Properties::read() - \"COMM\" chunk is too short for AIFF."); + return; + } + d->channels = data.toShort(0U); d->sampleFrames = data.toUInt(2U); d->sampleWidth = data.toShort(6U); @@ -109,4 +129,9 @@ void RIFF::AIFF::Properties::read(const ByteVector &data) d->sampleRate = (int)sampleRate; d->bitrate = (int)((sampleRate * d->sampleWidth * d->channels) / 1000.0); d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; + + if(data.size() >= 23) { + d->compressionType = data.mid(18, 4); + d->compressionName = String(data.mid(23, static_cast(data[22]))); + } } diff --git a/taglib/riff/aiff/aiffproperties.h b/taglib/riff/aiff/aiffproperties.h index 68e90b79..d0778704 100644 --- a/taglib/riff/aiff/aiffproperties.h +++ b/taglib/riff/aiff/aiffproperties.h @@ -67,6 +67,30 @@ namespace TagLib { int sampleWidth() const; uint sampleFrames() const; + /*! + * Returns true if the file is in AIFF-C format, false if AIFF format. + */ + bool isAiffC() const; + + /*! + * Returns the compression type of the AIFF-C file. For example, "NONE" for + * not compressed, "ACE2" for ACE 2-to-1. + * + * If the file is in AIFF format, always returns an empty vector. + * + * \see isAiffC() + */ + ByteVector compressionType() const; + + /*! + * Returns the concrete compression name of the AIFF-C file. + * + * If the file is in AIFF format, always returns an empty string. + * + * \see isAiffC() + */ + String compressionName() const; + private: Properties(const Properties &); Properties &operator=(const Properties &); diff --git a/tests/data/alaw.aifc b/tests/data/alaw.aifc new file mode 100644 index 0000000000000000000000000000000000000000..33b4ea2a5734c10af92aa556de6c50aa102efac6 GIT binary patch literal 1890 zcmX|B2~d+~8vb*iBm@uwf(e)eaX^Vl{)7;~EUlJSP=Q*Zvn~oOpa_aq?d(j=eIJC| zaD+e(?1G$0AV6@{+3u+9+6ubuw2Kr$%28cfS9i3#`_plKXTF*5d*0`J-s_uh-@)8$ z0KgQAv-V}~JMwNW0077?$>F`32eTm@NCaR2fIb2Q?a zKcBvT7oW|hi<2skU(6QgegF~P2aub$004iYw2Xd^URhmz1_0o{BBfO&ZxO^>PR$z* z@-62Ll9iK}4`E><0Jsdhyy=CMH5b`&Sjp))nJ`pl;_ z6=mh;>Fksgb|U@%{v2`kyO1AuvAVkCL}hjHDIhN|2dW8u3_^dk**7*b^Kd3_U)FCI zlq!laDQPJ+ISExx0J&9OfuK9vuW`Fj?E_q7&M|5v|8N zJnHJ}bE=3Lse+U=He0}ArH6X_F1vetK;xV8PpAO_9m*w{NCx+S(ZuB%tOC#+?mkw^qLB{nfJR)qOMEjMZg$Gflf^f^6$hJ&1B zPDvZ_1hJB`bRC?0RoxA8l4!k_y;&JwV{y7vvcaO*gMe&I{5)xS=Oq1R_ zG-~hfx!ULUm4PWjA(IuCm_$z{{NnSwT%BG0*ZMmr8o=1Z-El0YkjWHsqD<~hy4^Y9 zH8n?Z81%R}db}`=Po&fhxcYl~dR>#ohTKqWI(>J-t~e&|c)iLnGUe{NcCE{)seu}l zA&iIautaE!XDBf4bh|n`9m7|m*eOf~BR)Q!kxqK$3AkM@$9Q03K+}K%1@W;gW{N18 zhrDhaa@srXj=+FUeFMeKV8qg6nIb+=S+ALNLSuD}jVKFHygeyQ7Cn}cMmpK98xHs# z(4fY23rN050M*A}q;i0l+DWIw;SWqr`XoOi`58i{P>`OH1_l*dy`yfs9SS~Vc!37f z8LU_qL%_iWHyQ@V98glDLmtIl8W|J`p!l$m7(9qbCL)kw&pM=1wW8J5-rjDRKO3VI&>_K`WYjw7k65Xj93h*4p(O7fUan zF9}8yNko8JIlZvUGHHS2tvZEbm779NQvbCdUQ_;AY2<_@LG zsNeLM>o3#LP`BA>86ptH|QPF7>sgN`^HH$ zmb;1bNSLYxg~mHD;Psegs+QG*F+?y;#Np#$FL7(Qqu6izmaV z71vkmuc)*>?}%2?v3NWt3JH+0SR6DyYRQ^art^7ydYPj3<@u@*43q&I-Ld-M6cr%hxjX_1i2jX5W!7p*(Nfo;JzG+I{15Ma_0Ly}|GD$s%vaZ+zxes~7y0{h z4v60oAIv(ixA4&1%^Tm`fAHmZU*Ebpee3?=V;_HfwBT4l!S8ZEdU)^Nmk(!VXa5J= CPx9XY literal 0 HcmV?d00001 diff --git a/tests/data/segfault.aif b/tests/data/segfault.aif new file mode 100644 index 0000000000000000000000000000000000000000..5dce192b05e0219b947cefde7573b7df1f3393b1 GIT binary patch literal 31 icmZ?s5AtP9KB4F6>E`C_@9WC|0>Qz4EaudioProperties()->isAiffC()); + CPPUNIT_ASSERT_EQUAL(ByteVector("ALAW"), f->audioProperties()->compressionType()); + CPPUNIT_ASSERT_EQUAL(String("SGI CCITT G.711 A-law"), f->audioProperties()->compressionName()); + delete f; + } + + void testFuzzedFiles() + { + RIFF::AIFF::File f(TEST_FILE_PATH_C("segfault.aif")); + CPPUNIT_ASSERT(!f.isValid()); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestAIFF); -- 2.40.0