1
/***************************************************************************
2
copyright : (C) 2005 by Brian Nickel
3
email : brian.nickel@gmail.com
4
based on : id3v2framefactory.cpp from TagLib
5
***************************************************************************/
7
/***************************************************************************
8
* This library is free software; you can redistribute it and/or modify *
9
* it under the terms of the GNU Lesser General Public License version *
10
* 2.1 as published by the Free Software Foundation. *
12
* This library is distributed in the hope that it will be useful, but *
13
* WITHOUT ANY WARRANTY; without even the implied warranty of *
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15
* Lesser General Public License for more details. *
17
* You should have received a copy of the GNU Lesser General Public *
18
* License along with this library; if not, write to the Free Software *
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
21
***************************************************************************/
23
using System.Collections.Generic;
25
namespace TagLib.Id3v2
27
public class FrameFactory
29
public delegate Frame FrameCreator (ByteVector data, int offset, FrameHeader header, uint version);
31
//////////////////////////////////////////////////////////////////////////
33
//////////////////////////////////////////////////////////////////////////
34
private static StringType default_encoding = StringType.UTF8;
35
private static bool use_default_encoding = false;
36
private static List<FrameCreator> frame_creators = new List<FrameCreator> ();
38
//////////////////////////////////////////////////////////////////////////
40
//////////////////////////////////////////////////////////////////////////
41
public static Frame CreateFrame (ByteVector data, int offset, uint version)
43
FrameHeader header = new FrameHeader (data.Mid (offset, (int) FrameHeader.Size (version)), version);
44
ByteVector frame_id = header.FrameId;
45
// A quick sanity check -- make sure that the frame_id is 4 uppercase
46
// Latin1 characters. Also make sure that there is data in the frame.
48
if(frame_id == null || frame_id.Count != (version < 3 ? 3 : 4) || header.FrameSize < 0)
51
foreach (byte b in frame_id)
54
if ((c < 'A' || c > 'Z') && (c < '1' || c > '9'))
58
// Windows Media Player may create zero byte frames. Just send them
59
// off as unknown and delete them.
60
if (header.FrameSize == 0)
62
header.TagAlterPreservation = true;
63
return new UnknownFrame (data, offset, header, version);
66
// TagLib doesn't mess with encrypted frames, so just treat them
69
if (header.Compression)
71
Debugger.Debug ("Compressed frames are currently not supported.");
72
return new UnknownFrame (data, offset, header, version);
75
if (header.Encryption)
77
Debugger.Debug ("Encrypted frames are currently not supported.");
78
return new UnknownFrame (data, offset, header, version);
81
if (!UpdateFrame (header, version))
83
header.TagAlterPreservation = true;
84
return new UnknownFrame (data, offset, header, version);
87
foreach (FrameCreator creator in frame_creators)
89
Frame frame = creator (data, offset, header, version);
95
// UpdateFrame () might have updated the frame ID.
97
frame_id = header.FrameId;
99
// This is where things get necissarily nasty. Here we determine which
100
// Frame subclass (or if none is found simply an Frame) based
101
// on the frame ID. Since there are a lot of possibilities, that means
102
// a lot of if blocks.
104
// Text Identification (frames 4.2)
106
if(frame_id.StartsWith ("T"))
108
TextIdentificationFrame f = frame_id != "TXXX"
109
? new TextIdentificationFrame (data, offset, header, version)
110
: new UserTextIdentificationFrame (data, offset, header, version);
112
if(use_default_encoding)
113
f.TextEncoding = default_encoding;
115
if (frame_id == "TCON" && version < 4)
121
// Unsynchronized Lyrics (frames 4.8)
123
if (frame_id == "USLT")
125
UnsynchronisedLyricsFrame f = new UnsynchronisedLyricsFrame (data, offset, header, version);
127
if(use_default_encoding)
128
f.TextEncoding = default_encoding;
133
// Comments (frames 4.10)
135
if (frame_id == "COMM")
137
CommentsFrame f = new CommentsFrame (data, offset, header, version);
139
if(use_default_encoding)
140
f.TextEncoding = default_encoding;
145
// Attached Picture (frames 4.14)
147
if (frame_id == "APIC")
149
AttachedPictureFrame f = new AttachedPictureFrame (data, offset, header, version);
151
if(use_default_encoding)
152
f.TextEncoding = default_encoding;
157
// Relative Volume Adjustment (frames 4.11)
159
if (frame_id == "RVA2")
160
return new RelativeVolumeFrame (data, offset, header, version);
162
// Unique File Identifier (frames 4.1)
164
if (frame_id == "UFID")
165
return new UniqueFileIdentifierFrame (data, offset, header, version);
167
// Private (frames 4.27)
169
if (frame_id == "PRIV")
170
return new PrivateFrame (data, offset, header, version);
172
// General Encapsulated Object (frames 4.15)
174
if(frame_id == "GEOB")
175
return new GeneralEncapsulatedObjectFrame (data, offset, header, version);
177
return new UnknownFrame (data, offset, header, version);
180
public static StringType DefaultTextEncoding
184
return default_encoding;
188
use_default_encoding = true;
189
default_encoding = value;
193
public static void AddFrameCreator (FrameCreator creator)
196
frame_creators.Insert (0, creator);
199
public static void UpdateGenre (TextIdentificationFrame frame)
201
StringList fields = new StringList ();
202
string s = frame.ToString ();
204
while (s.Length > 1 && s [0] == '(')
206
int closing = s.IndexOf (')');
210
fields.Add (s.Substring (1, closing - 1));
212
s = s.Substring (closing + 1);
215
if(s != string.Empty)
221
frame.SetText (fields);
225
//////////////////////////////////////////////////////////////////////////
227
//////////////////////////////////////////////////////////////////////////
228
private FrameFactory () {}
230
private static bool UpdateFrame (FrameHeader header, uint version)
232
ByteVector frame_id = header.FrameId;
238
if(frame_id == "CRM" ||
245
Debugger.Debug ("ID3v2.4 no longer supports the frame type "
246
+ frame_id.ToString () + ". It will be discarded from the tag.");
251
// ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of
252
// the frames to their 4 byte ID3v2.4 equivalent.
254
ConvertFrame ("BUF", "RBUF", header);
255
ConvertFrame ("CNT", "PCNT", header);
256
ConvertFrame ("COM", "COMM", header);
257
ConvertFrame ("CRA", "AENC", header);
258
ConvertFrame ("ETC", "ETCO", header);
259
ConvertFrame ("GEO", "GEOB", header);
260
ConvertFrame ("IPL", "TIPL", header);
261
ConvertFrame ("MCI", "MCDI", header);
262
ConvertFrame ("MLL", "MLLT", header);
263
ConvertFrame ("PIC", "APIC", header);
264
ConvertFrame ("POP", "POPM", header);
265
ConvertFrame ("REV", "RVRB", header);
266
ConvertFrame ("SLT", "SYLT", header);
267
ConvertFrame ("STC", "SYTC", header);
268
ConvertFrame ("TAL", "TALB", header);
269
ConvertFrame ("TBP", "TBPM", header);
270
ConvertFrame ("TCM", "TCOM", header);
271
ConvertFrame ("TCO", "TCON", header);
272
ConvertFrame ("TCR", "TCOP", header);
273
ConvertFrame ("TDA", "TDRC", header);
274
ConvertFrame ("TDY", "TDLY", header);
275
ConvertFrame ("TEN", "TENC", header);
276
ConvertFrame ("TFT", "TFLT", header);
277
ConvertFrame ("TKE", "TKEY", header);
278
ConvertFrame ("TLA", "TLAN", header);
279
ConvertFrame ("TLE", "TLEN", header);
280
ConvertFrame ("TMT", "TMED", header);
281
ConvertFrame ("TOA", "TOAL", header);
282
ConvertFrame ("TOF", "TOFN", header);
283
ConvertFrame ("TOL", "TOLY", header);
284
ConvertFrame ("TOR", "TDOR", header);
285
ConvertFrame ("TOT", "TOAL", header);
286
ConvertFrame ("TP1", "TPE1", header);
287
ConvertFrame ("TP2", "TPE2", header);
288
ConvertFrame ("TP3", "TPE3", header);
289
ConvertFrame ("TP4", "TPE4", header);
290
ConvertFrame ("TPA", "TPOS", header);
291
ConvertFrame ("TPB", "TPUB", header);
292
ConvertFrame ("TRC", "TSRC", header);
293
ConvertFrame ("TRD", "TDRC", header);
294
ConvertFrame ("TRK", "TRCK", header);
295
ConvertFrame ("TSS", "TSSE", header);
296
ConvertFrame ("TT1", "TIT1", header);
297
ConvertFrame ("TT2", "TIT2", header);
298
ConvertFrame ("TT3", "TIT3", header);
299
ConvertFrame ("TXT", "TOLY", header);
300
ConvertFrame ("TXX", "TXXX", header);
301
ConvertFrame ("TYE", "TDRC", header);
302
ConvertFrame ("UFI", "UFID", header);
303
ConvertFrame ("ULT", "USLT", header);
304
ConvertFrame ("WAF", "WOAF", header);
305
ConvertFrame ("WAR", "WOAR", header);
306
ConvertFrame ("WAS", "WOAS", header);
307
ConvertFrame ("WCM", "WCOM", header);
308
ConvertFrame ("WCP", "WCOP", header);
309
ConvertFrame ("WPB", "WPUB", header);
310
ConvertFrame ("WXX", "WXXX", header);
317
if(frame_id == "EQUA" ||
318
frame_id == "RVAD" ||
319
frame_id == "TIME" ||
320
frame_id == "TRDA" ||
321
frame_id == "TSIZ" ||
324
Debugger.Debug ("ID3v2.4 no longer supports the frame type "
325
+ frame_id.ToString () + ". It will be discarded from the tag.");
330
ConvertFrame ("TORY", "TDOR", header);
331
ConvertFrame ("TYER", "TDRC", header);
338
// This should catch a typo that existed in TagLib up to and including
339
// version 1.1 where TRDC was used for the year rather than TDRC.
341
ConvertFrame ("TRDC", "TDRC", header);
349
private static void ConvertFrame (string from, string to, FrameHeader header)
351
if (header.FrameId != from)