File indexing completed on 2025-01-05 04:32:39
0001 /*************************************************************************** 0002 copyright : (C) 2014 by Urs Fleisch 0003 email : ufleisch@users.sourceforge.net 0004 ***************************************************************************/ 0005 0006 /*************************************************************************** 0007 * This library is free software; you can redistribute it and/or modify * 0008 * it under the terms of the GNU Lesser General Public License version * 0009 * 2.1 as published by the Free Software Foundation. * 0010 * * 0011 * This library is distributed in the hope that it will be useful, but * 0012 * WITHOUT ANY WARRANTY; without even the implied warranty of * 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0014 * Lesser General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU Lesser General Public * 0017 * License along with this library; if not, write to the Free Software * 0018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 0019 * 02110-1301 USA * 0020 * * 0021 * Alternatively, this file is available under the Mozilla Public * 0022 * License Version 1.1. You may obtain a copy of the License at * 0023 * http://www.mozilla.org/MPL/ * 0024 ***************************************************************************/ 0025 0026 #define BUILD_WITH_KID3 0027 #include "synchronizedlyricsframe.h" 0028 #include <tbytevectorlist.h> 0029 #include <id3v2tag.h> 0030 #ifdef BUILD_WITH_KID3 0031 #define debug(s) 0032 #else 0033 #include <tdebug.h> 0034 #endif 0035 #include <tstringlist.h> 0036 0037 using namespace TagLib; 0038 using namespace ID3v2; 0039 0040 class SynchronizedLyricsFrame::SynchronizedLyricsFramePrivate 0041 { 0042 public: 0043 SynchronizedLyricsFramePrivate() : 0044 textEncoding(String::Latin1), 0045 timestampFormat(SynchronizedLyricsFrame::AbsoluteMilliseconds), 0046 type(SynchronizedLyricsFrame::Lyrics) {} 0047 String::Type textEncoding; 0048 ByteVector language; 0049 SynchronizedLyricsFrame::TimestampFormat timestampFormat; 0050 SynchronizedLyricsFrame::Type type; 0051 String description; 0052 SynchronizedLyricsFrame::SynchedTextList synchedText; 0053 }; 0054 0055 //////////////////////////////////////////////////////////////////////////////// 0056 // public members 0057 //////////////////////////////////////////////////////////////////////////////// 0058 0059 SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) : 0060 Frame("SYLT") 0061 { 0062 d = new SynchronizedLyricsFramePrivate; 0063 d->textEncoding = encoding; 0064 } 0065 0066 SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) : 0067 Frame(data) 0068 { 0069 d = new SynchronizedLyricsFramePrivate; 0070 setData(data); 0071 } 0072 0073 SynchronizedLyricsFrame::~SynchronizedLyricsFrame() 0074 { 0075 delete d; 0076 } 0077 0078 String SynchronizedLyricsFrame::toString() const 0079 { 0080 return d->description; 0081 } 0082 0083 String::Type SynchronizedLyricsFrame::textEncoding() const 0084 { 0085 return d->textEncoding; 0086 } 0087 0088 ByteVector SynchronizedLyricsFrame::language() const 0089 { 0090 return d->language; 0091 } 0092 0093 SynchronizedLyricsFrame::TimestampFormat 0094 SynchronizedLyricsFrame::timestampFormat() const 0095 { 0096 return d->timestampFormat; 0097 } 0098 0099 SynchronizedLyricsFrame::Type SynchronizedLyricsFrame::type() const 0100 { 0101 return d->type; 0102 } 0103 0104 String SynchronizedLyricsFrame::description() const 0105 { 0106 return d->description; 0107 } 0108 0109 SynchronizedLyricsFrame::SynchedTextList 0110 SynchronizedLyricsFrame::synchedText() const 0111 { 0112 return d->synchedText; 0113 } 0114 0115 void SynchronizedLyricsFrame::setTextEncoding(String::Type encoding) 0116 { 0117 d->textEncoding = encoding; 0118 } 0119 0120 void SynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding) 0121 { 0122 d->language = languageEncoding.mid(0, 3); 0123 } 0124 0125 void SynchronizedLyricsFrame::setTimestampFormat( 0126 SynchronizedLyricsFrame::TimestampFormat f) 0127 { 0128 d->timestampFormat = f; 0129 } 0130 0131 void SynchronizedLyricsFrame::setType(SynchronizedLyricsFrame::Type t) 0132 { 0133 d->type = t; 0134 } 0135 0136 void SynchronizedLyricsFrame::setDescription(const String &s) 0137 { 0138 d->description = s; 0139 } 0140 0141 void SynchronizedLyricsFrame::setSynchedText( 0142 const SynchronizedLyricsFrame::SynchedTextList &t) 0143 { 0144 d->synchedText = t; 0145 } 0146 0147 //////////////////////////////////////////////////////////////////////////////// 0148 // protected members 0149 //////////////////////////////////////////////////////////////////////////////// 0150 0151 void SynchronizedLyricsFrame::parseFields(const ByteVector &data) 0152 { 0153 const int end = data.size(); 0154 if(end < 7) { 0155 debug("A synchronized lyrics frame must contain at least 7 bytes."); 0156 return; 0157 } 0158 0159 d->textEncoding = String::Type(data[0]); 0160 d->language = data.mid(1, 3); 0161 d->timestampFormat = TimestampFormat(data[4]); 0162 d->type = Type(data[5]); 0163 0164 int pos = 6; 0165 0166 d->description = readStringField(data, d->textEncoding, &pos); 0167 if(d->description.isNull()) 0168 return; 0169 0170 /* 0171 * If UTF16 strings are found in SYLT frames, a BOM may only be 0172 * present in the first string (content descriptor), and the strings of 0173 * the synchronized text have no BOM. Here the BOM is read from 0174 * the first string to have a specific encoding with endianness for the 0175 * case of strings without BOM so that readStringField() will work. 0176 */ 0177 String::Type encWithEndianness = d->textEncoding; 0178 if(d->textEncoding == String::UTF16) { 0179 #if (((TAGLIB_MAJOR_VERSION) << 16) + ((TAGLIB_MINOR_VERSION) << 8) + (TAGLIB_PATCH_VERSION)) >= 0x010700 0180 ushort bom = data.mid(6, 2).toUShort(true); 0181 #else 0182 ushort bom = static_cast<ushort>(data.mid(6, 2).toShort(true)); 0183 #endif 0184 if(bom == 0xfffe) { 0185 encWithEndianness = String::UTF16LE; 0186 } else if(bom == 0xfeff) { 0187 encWithEndianness = String::UTF16BE; 0188 } 0189 } 0190 0191 d->synchedText.clear(); 0192 while(pos < end) { 0193 String::Type enc = d->textEncoding; 0194 // If a UTF16 string has no BOM, use the encoding found above. 0195 if(enc == String::UTF16 && pos + 1 < end) { 0196 #if (((TAGLIB_MAJOR_VERSION) << 16) + ((TAGLIB_MINOR_VERSION) << 8) + (TAGLIB_PATCH_VERSION)) >= 0x010700 0197 ushort bom = data.mid(pos, 2).toUShort(true); 0198 #else 0199 ushort bom = static_cast<ushort>(data.mid(pos, 2).toShort(true)); 0200 #endif 0201 if(bom != 0xfffe && bom != 0xfeff) { 0202 enc = encWithEndianness; 0203 } 0204 } 0205 String text = readStringField(data, enc, &pos); 0206 if(text.isNull() || pos + 4 > end) 0207 return; 0208 0209 uint time = data.mid(pos, 4).toUInt(true); 0210 pos += 4; 0211 0212 d->synchedText.append(SynchedText(time, text)); 0213 } 0214 } 0215 0216 ByteVector SynchronizedLyricsFrame::renderFields() const 0217 { 0218 ByteVector v; 0219 0220 String::Type encoding = d->textEncoding; 0221 0222 #if (((TAGLIB_MAJOR_VERSION) << 16) + ((TAGLIB_MINOR_VERSION) << 8) + (TAGLIB_PATCH_VERSION)) >= 0x010701 0223 encoding = checkTextEncoding(d->description, encoding); 0224 for(SynchedTextList::ConstIterator it = d->synchedText.begin(); 0225 it != d->synchedText.end(); 0226 ++it) { 0227 encoding = checkTextEncoding(it->text, encoding); 0228 } 0229 #endif 0230 0231 v.append(char(encoding)); 0232 v.append(d->language.size() == 3 ? d->language : "XXX"); 0233 v.append(char(d->timestampFormat)); 0234 v.append(char(d->type)); 0235 v.append(d->description.data(encoding)); 0236 v.append(textDelimiter(encoding)); 0237 for(SynchedTextList::ConstIterator it = d->synchedText.begin(); 0238 it != d->synchedText.end(); 0239 ++it) { 0240 const SynchedText &entry = *it; 0241 v.append(entry.text.data(encoding)); 0242 v.append(textDelimiter(encoding)); 0243 v.append(ByteVector::fromUInt(entry.time)); 0244 } 0245 0246 return v; 0247 } 0248 0249 //////////////////////////////////////////////////////////////////////////////// 0250 // private members 0251 //////////////////////////////////////////////////////////////////////////////// 0252 0253 SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) 0254 : Frame(h) 0255 { 0256 d = new SynchronizedLyricsFramePrivate(); 0257 parseFields(fieldData(data)); 0258 }