From 3d4428726ea90264d6814b4477c1d32e364a3dde Mon Sep 17 00:00:00 2001 From: Urs Fleisch Date: Tue, 14 May 2024 13:27:17 +0200 Subject: [PATCH] Fix parsing of ID3v2.2 frames (#1228) --- taglib/mpeg/id3v2/id3v2tag.cpp | 16 +++++++++-- tests/data/itunes10.mp3 | Bin 0 -> 12312 bytes tests/test_mpeg.cpp | 51 +++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 tests/data/itunes10.mp3 diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index 4f8390ee..f97be59e 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -843,8 +843,10 @@ void ID3v2::Tag::parse(const ByteVector &origData) break; } - Frame *frame = d->factory->createFrame(data.mid(frameDataPosition), - &d->header); + const ByteVector origData = data.mid(frameDataPosition); + const Header *tagHeader = &d->header; + unsigned int headerVersion = tagHeader->majorVersion(); + Frame *frame = d->factory->createFrame(origData, tagHeader); if(!frame) return; @@ -856,7 +858,15 @@ void ID3v2::Tag::parse(const ByteVector &origData) return; } - frameDataPosition += frame->size() + frame->headerSize(); + if(frame->header()->version() == headerVersion) { + frameDataPosition += frame->size() + frame->headerSize(); + } else { + // The frame was converted to another version, e.g. from 2.2 to 2.4. + // We must advance the frame data position according to the original + // frame, not the converted frame because its header size might differ. + Frame::Header origHeader(origData, headerVersion); + frameDataPosition += origHeader.frameSize() + origHeader.size(); + } addFrame(frame); } diff --git a/tests/data/itunes10.mp3 b/tests/data/itunes10.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..1c944a646fb06ee22b343748b19d9d5e6497fa2c GIT binary patch literal 12312 zcmeI2c{G%5AIEQE45OGw)?_bPvds{ZbuhzNXAmY!3??SB^pGZ`LiVPT%96FQWF9Kn zm&q259<LosMh*ptCU^kg`8@_862Z^;0L#$eh!DzAe}L#{4FE7eQ(aR7OlATA++bS^AiA1w zy0tVkH36cj{dc!67-43&Sr3-%eLPCWh8*r41en=@vuy*&U@mY*D*0%57#IeAu?5fs zobW^d;Qu~|j|!#ugaP(AGk_Nf*xOnHKoa=e$|u1GE_Evoi*W?s8k;v920mRlKPP|- z9l&8shymR5uDEnboH(t{#qY`R{<}f%q`0KG;*Diw?{lb)X08fJ>V?g88cpi{GjM4hH{+n-Y?#By9BIZ^*`eTxu z%e7tTSJgRwCWwg!w-3mPy=i0ryfjs_bA4`E=hk{{a?Y*fiS;kF2i-h!b|lqhXWWkX zWySt^U>Y`uhm!WCAigT*DXaJsDPUU4aP`esA8P$ORvq$@#14%yS$-%oQTniq$wjvNV ze6Ffi=oHU3PQQd50k5Q%8Y&b`td;$-p1HUQACpFJ52|H>Vac4V^Y#&|AC(-(A!x9^fhp;oL#n8!y^n#Ee){2$HJS3g;igwl=FSLG zV98d64mvhwt$Ubd9xAy>CsON>{<0$6XOs^W4mO<{a!+4x+0H>R%zjKOL{UujMK!fD zdy87rtuQ*XaoSC2c_)7BY=;`Bgjd4LD#DDcW@W0yTJFA6bDI8RJ|dK!qK6Var9rtr zoot`r_pUFsFhbNNdWUF;cel533?8PkP?KSuB0&PIZvZWoAXJ2}L3P5|?`rz>sBU*KPtZo_e z>Y~$yAD;0XWHzz1IiB)7QpO6gM{nv{`rdjq6TClbw^y>%r4HHklv7^VF^8|Pcqzv+ zJN&gz;T&yKl@mflWwkds?P&bbT4JHHEw%XeI{K%WE z9zN6(Lt!_^XZ**@&fNGMHTLs>S%vmp?s;eAYY{FZ<^lYSLl?c-#^rv6(pBwu=N)rN z=VLLsKR-ocXy)y9j3lM1s4J46%X(h#Cl7g5XqcDvl{oY>48{F%GWkW@a5uYlHYghC z$PFWfN=mX=2k3=0Q4YVkPnT}z5KnTstTvf!cLjF=qs#9ta7MpR^<_Oi|3OE#MHp`O zx`znsDQ_-Y+0tl=mL6^15G^ts&1-7tUQA!}k7zvM(DC491DRP~U+mOftr{+!)5Y!x zgx{;L)=PwaI1#`5LL;7Gt4i!f^AXD~FU7d(8=O|KxDLm(NwN8rfa|+#ceH*T9EpkH zF^gd&W-@b3LWhV9d$m{zN(2@!_TgJ+NNPNmp~%5!F! zf85iOZq`kWoi0GcjJ1xuos+#V=CKJBO`hIx#Nb{RJ%4ak z2F_V`pn&~KRMNn@b%6c4&f|l_FlHUN@V{)Ug;%%;=u7p+xWW%&ZUPpu`x%f>FI=Wur^EF`walltqQPK@DyX~ zW*s9nd)zh$Ap0i~_`c%=-U9#ytQrm;caQ-94)7`hyI>O?3jkby{&_V`rypTIINgsZ f3Ci)mBe1bn?YoiwpLg7kt_Iq2Kbq)2D&M~VPm!H5 literal 0 HcmV?d00001 diff --git a/tests/test_mpeg.cpp b/tests/test_mpeg.cpp index 2ebfc407..d6aa3a40 100644 --- a/tests/test_mpeg.cpp +++ b/tests/test_mpeg.cpp @@ -71,6 +71,7 @@ class TestMPEG : public CppUnit::TestFixture CPPUNIT_TEST(testIgnoreGarbage); CPPUNIT_TEST(testExtendedHeader); CPPUNIT_TEST(testReadStyleFast); + CPPUNIT_TEST(testID3v22Properties); CPPUNIT_TEST_SUITE_END(); public: @@ -618,6 +619,56 @@ public: } } + void testID3v22Properties() + { + ScopedFileCopy copy("itunes10", ".mp3"); + + MPEG::File f(copy.fileName().c_str()); + PropertyMap expectedProperties(SimplePropertyMap{ + {"ALBUM", {"Album"}}, + {"ALBUMARTIST", {"Album Artist"}}, + {"ALBUMARTISTSORT", {"Sort Album Artist"}}, + {"ALBUMSORT", {"Sort Album"}}, + {"ARTIST", {"Artist"}}, + {"ARTISTSORT", {"Sort Artist"}}, + {"BPM", {"180"}}, + {"COMMENT", {"Comments"}}, + {"COMMENT:ITUNPGAP", {"1"}}, + {"COMPILATION", {"1"}}, + {"COMPOSER", {"Composer"}}, + {"COMPOSERSORT", {"Sort Composer"}}, + {"DATE", {"2011"}}, + {"DISCNUMBER", {"1/2"}}, + {"GENRE", {"Heavy Metal"}}, + {"LYRICS", {"Lyrics"}}, + {"SUBTITLE", {"Description"}}, + {"TITLE", {"iTunes10MP3"}}, + {"TITLESORT", {"Sort Name"}}, + {"TRACKNUMBER", {"1/10"}}, + {"WORK", {"Grouping"}} + }); + expectedProperties.addUnsupportedData("APIC"); + expectedProperties.addUnsupportedData("UNKNOWN/RVA"); + + PropertyMap properties = f.properties(); + if (expectedProperties != properties) { + CPPUNIT_ASSERT_EQUAL(expectedProperties.toString(), properties.toString()); + } + CPPUNIT_ASSERT(expectedProperties == properties); + + const String PICTURE_KEY("PICTURE"); + CPPUNIT_ASSERT_EQUAL(StringList(PICTURE_KEY), f.complexPropertyKeys()); + auto pictures = f.complexProperties(PICTURE_KEY); + CPPUNIT_ASSERT_EQUAL(1U, pictures.size()); + auto picture = pictures.front(); + CPPUNIT_ASSERT_EQUAL(String("image/png"), picture.value("mimeType").toString()); + CPPUNIT_ASSERT(picture.value("description").toString().isEmpty()); + CPPUNIT_ASSERT_EQUAL(String("Other"), picture.value("pictureType").toString()); + auto data = picture.value("data").toByteVector(); + CPPUNIT_ASSERT(data.startsWith("\x89PNG\x0d\x0a\x1a\x0a")); + CPPUNIT_ASSERT_EQUAL(2315U, data.size()); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMPEG);