61
|
1 /*********************************************************************
|
|
2 *
|
|
3 * Copyright (C) 1999-2000, 2001, Espen Skoglund
|
|
4 * Department of Computer Science, University of Tromsų
|
|
5 *
|
|
6 * Filename: id3_frame.c
|
|
7 * Description: Code for handling ID3 frames.
|
|
8 * Author: Espen Skoglund <espensk@stud.cs.uit.no>
|
|
9 * Created at: Fri Feb 5 23:47:08 1999
|
|
10 *
|
|
11 * $Id: id3_frame.c,v 1.5 2004/07/20 21:47:22 descender Exp $
|
|
12 *
|
|
13 * This program is free software; you can redistribute it and/or
|
|
14 * modify it under the terms of the GNU General Public License
|
|
15 * as published by the Free Software Foundation; either version 2
|
|
16 * of the License, or (at your option) any later version.
|
|
17 *
|
|
18 * This program is distributed in the hope that it will be useful,
|
|
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21 * GNU General Public License for more details.
|
|
22 *
|
|
23 * You should have received a copy of the GNU General Public License
|
|
24 * along with this program; if not, write to the Free Software
|
|
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
26 *
|
|
27 ********************************************************************/
|
|
28 #include "config.h"
|
|
29
|
|
30 #ifdef HAVE_LIBZ
|
|
31 #include <zlib.h>
|
|
32 #endif
|
|
33 #include <glib.h>
|
|
34 #include <stdio.h>
|
|
35 #include <string.h>
|
|
36 #include <stdlib.h>
|
|
37 #include <stdarg.h>
|
|
38
|
|
39 #include "xmms-id3.h"
|
|
40 #include "id3_header.h"
|
|
41
|
|
42 static void *id3_frame_get_dataptr(struct id3_frame *frame);
|
|
43 static int id3_frame_get_size(struct id3_frame *frame);
|
|
44 static int id3_read_frame_v22(struct id3_tag *id3);
|
|
45
|
|
46
|
|
47 /*
|
|
48 * Description of all valid ID3v2 frames.
|
|
49 */
|
|
50 static struct id3_framedesc framedesc[] = {
|
|
51 {ID3_AENC, "AENC", "Audio encryption"},
|
|
52 {ID3_APIC, "APIC", "Attached picture"},
|
|
53 {ID3_ASPI, "ASPI", "Audio seek point index"}, /* v4 only */
|
|
54
|
|
55 {ID3_COMM, "COMM", "Comments"},
|
|
56 {ID3_COMR, "COMR", "Commercial frame"},
|
|
57
|
|
58 {ID3_ENCR, "ENCR", "Encryption method registration"},
|
|
59 {ID3_EQUA, "EQUA", "Equalization"}, /* v3 only */
|
|
60 {ID3_EQU2, "EQU2", "Equalization (2)"}, /* v4 only */
|
|
61 {ID3_ETCO, "ETCO", "Event timing codes"},
|
|
62
|
|
63 {ID3_GEOB, "GEOB", "General encapsulated object"},
|
|
64 {ID3_GRID, "GRID", "Group identification registration"},
|
|
65
|
|
66 {ID3_IPLS, "IPLS", "Involved people list"}, /* v3 only */
|
|
67
|
|
68 {ID3_LINK, "LINK", "Linked information"},
|
|
69
|
|
70 {ID3_MCDI, "MCDI", "Music CD identifier"},
|
|
71 {ID3_MLLT, "MLLT", "MPEG location lookup table"},
|
|
72
|
|
73 {ID3_OWNE, "OWNE", "Ownership frame"},
|
|
74
|
|
75 {ID3_PRIV, "PRIV", "Private frame"},
|
|
76 {ID3_PCNT, "PCNT", "Play counter"},
|
|
77 {ID3_POPM, "POPM", "Popularimeter"},
|
|
78 {ID3_POSS, "POSS", "Position synchronisation frame"},
|
|
79
|
|
80 {ID3_RBUF, "RBUF", "Recommended buffer size"},
|
|
81 {ID3_RVAD, "RVAD", "Relative volume adjustment"}, /* v3 only */
|
|
82 {ID3_RVA2, "RVA2", "RVA2 Relative volume adjustment (2)"}, /* v4 only */
|
|
83 {ID3_RVRB, "RVRB", "Reverb"},
|
|
84
|
|
85 {ID3_SEEK, "SEEK", "Seek frame"}, /* v4 only */
|
|
86 {ID3_SIGN, "SIGN", "Signature frame"}, /* v4 only */
|
|
87 {ID3_SYLT, "SYLT", "Synchronized lyric/text"},
|
|
88 {ID3_SYTC, "SYTC", "Synchronized tempo codes"},
|
|
89
|
|
90 {ID3_TALB, "TALB", "Album/Movie/Show title"},
|
|
91 {ID3_TBPM, "TBPM", "BPM (beats per minute)"},
|
|
92 {ID3_TCOM, "TCOM", "Composer"},
|
|
93 {ID3_TCON, "TCON", "Content type"},
|
|
94 {ID3_TCOP, "TCOP", "Copyright message"},
|
|
95 {ID3_TDAT, "TDAT", "Date"}, /* v3 only */
|
|
96 {ID3_TDEN, "TDEN", "Encoding time"}, /* v4 only */
|
|
97 {ID3_TDLY, "TDLY", "Playlist delay"},
|
|
98 {ID3_TDOR, "TDOR", "Original release time"}, /* v4 only */
|
|
99 {ID3_TDRC, "TDRC", "Recording time"}, /* v4 only */
|
|
100 {ID3_TDRL, "TDRL", "Release time"}, /* v4 only */
|
|
101 {ID3_TDTG, "TDTG", "Tagging time"}, /* v4 only */
|
|
102
|
|
103 {ID3_TENC, "TENC", "Encoded by"},
|
|
104 {ID3_TEXT, "TEXT", "Lyricist/Text writer"},
|
|
105 {ID3_TFLT, "TFLT", "File type"},
|
|
106 {ID3_TIME, "TIME", "Time"}, /* v3 only */
|
|
107 {ID3_TIPL, "TIPL", "Involved people list"}, /* v4 only */
|
|
108 {ID3_TIT1, "TIT1", "Content group description"},
|
|
109 {ID3_TIT2, "TIT2", "Title/songname/content description"},
|
|
110 {ID3_TIT3, "TIT3", "Subtitle/Description refinement"},
|
|
111 {ID3_TKEY, "TKEY", "Initial key"},
|
|
112 {ID3_TLAN, "TLAN", "Language(s)"},
|
|
113 {ID3_TLEN, "TLEN", "Length"},
|
|
114 {ID3_TMCL, "TMCL", "Musician credits list"}, /* v4 only */
|
|
115 {ID3_TMOO, "TMOO", "Mood"}, /* v4 only */
|
|
116 {ID3_TMED, "TMED", "Media type"},
|
|
117 {ID3_TOAL, "TOAL", "Original album/movie/show title"},
|
|
118 {ID3_TOFN, "TOFN", "Original filename"},
|
|
119 {ID3_TOLY, "TOLY", "Original lyricist(s)/text writer(s)"},
|
|
120 {ID3_TOPE, "TOPE", "Original artist(s)/performer(s)"},
|
|
121 {ID3_TORY, "TORY", "Original release year"}, /* v3 only */
|
|
122 {ID3_TOWN, "TOWN", "File owner/licensee"},
|
|
123 {ID3_TPE1, "TPE1", "Lead performer(s)/Soloist(s)"},
|
|
124 {ID3_TPE2, "TPE2", "Band/orchestra/accompaniment"},
|
|
125 {ID3_TPE3, "TPE3", "Conductor/performer refinement"},
|
|
126 {ID3_TPE4, "TPE4", "Interpreted, remixed, or otherwise modified by"},
|
|
127 {ID3_TPOS, "TPOS", "Part of a set"},
|
|
128 {ID3_TPRO, "TPRO", "Produced notice"}, /* v4 only */
|
|
129 {ID3_TPUB, "TPUB", "Publisher"},
|
|
130 {ID3_TRCK, "TRCK", "Track number/Position in set"},
|
|
131 {ID3_TRDA, "TRDA", "Recording dates"}, /* v3 only */
|
|
132 {ID3_TRSN, "TRSN", "Internet radio station name"},
|
|
133 {ID3_TRSO, "TRSO", "Internet radio station owner"},
|
|
134 {ID3_TSIZ, "TSIZ", "Size"}, /* v3 only */
|
|
135 {ID3_TSOA, "TSOA", "Album sort order"}, /* v4 only */
|
|
136 {ID3_TSOP, "TSOP", "Performer sort order"}, /* v4 only */
|
|
137 {ID3_TSOT, "TSOT", "Title sort order"}, /* v4 only */
|
|
138
|
|
139 {ID3_TSRC, "TSRC", "ISRC (international standard recording code)"},
|
|
140 {ID3_TSSE, "TSSE", "Software/Hardware and settings used for encoding"},
|
|
141 {ID3_TSST, "TSST", "Set subtitle"}, /* v4 only */
|
|
142 {ID3_TYER, "TYER", "Year"}, /* v3 only */
|
|
143 {ID3_TXXX, "TXXX", "User defined text information frame"},
|
|
144
|
|
145 {ID3_UFID, "UFID", "Unique file identifier"},
|
|
146 {ID3_USER, "USER", "Terms of use"},
|
|
147 {ID3_USLT, "USLT", "Unsychronized lyric/text transcription"},
|
|
148
|
|
149 {ID3_WCOM, "WCOM", "Commercial information"},
|
|
150 {ID3_WCOP, "WCOP", "Copyright/Legal information"},
|
|
151 {ID3_WOAF, "WOAF", "Official audio file webpage"},
|
|
152 {ID3_WOAR, "WOAR", "Official artist/performer webpage"},
|
|
153 {ID3_WOAS, "WOAS", "Official audio source webpage"},
|
|
154 {ID3_WORS, "WORS", "Official internet radio station homepage"},
|
|
155 {ID3_WPAY, "WPAY", "Payment"},
|
|
156 {ID3_WPUB, "WPUB", "Publishers official webpage"},
|
|
157 {ID3_WXXX, "WXXX", "User defined URL link frame"},
|
|
158 };
|
|
159
|
|
160 struct id3_framedesc22 {
|
|
161 guint32 fd_v22, fd_v24;
|
|
162 };
|
|
163
|
|
164 static struct id3_framedesc22 framedesc22[] = {
|
|
165 {ID3_BUF, ID3_RBUF}, /* Recommended buffer size */
|
|
166
|
|
167 {ID3_CNT, ID3_PCNT}, /* Play counter */
|
|
168 {ID3_COM, ID3_COMM}, /* Comments */
|
|
169 {ID3_CRA, ID3_AENC}, /* Audio encryption */
|
|
170 {ID3_CRM, 0}, /* Encrypted meta frame */
|
|
171
|
|
172 {ID3_ETC, ID3_ETCO}, /* Event timing codes */
|
|
173 /* Could be converted to EQU2 */
|
|
174 {ID3_EQU, 0}, /* Equalization */
|
|
175
|
|
176 {ID3_GEO, ID3_GEOB}, /* General encapsulated object */
|
|
177
|
|
178 /* Would need conversion to TIPL */
|
|
179 {ID3_IPL, 0}, /* Involved people list */
|
|
180
|
|
181 /* This is so fragile it's not worth trying to save */
|
|
182 {ID3_LNK, 0}, /* Linked information */
|
|
183
|
|
184 {ID3_MCI, ID3_MCDI}, /* Music CD Identifier */
|
|
185 {ID3_MLL, ID3_MLLT}, /* MPEG location lookup table */
|
|
186
|
|
187 /* Would need to convert header for APIC */
|
|
188 {ID3_PIC, 0}, /* Attached picture */
|
|
189 {ID3_POP, ID3_POPM}, /* Popularimeter */
|
|
190
|
|
191 {ID3_REV, ID3_RVRB}, /* Reverb */
|
|
192 /* Could be converted to RVA2 */
|
|
193 {ID3_RVA, 0}, /* Relative volume adjustment */
|
|
194
|
|
195 {ID3_SLT, ID3_SYLT}, /* Synchronized lyric/text */
|
|
196 {ID3_STC, ID3_SYTC}, /* Synced tempo codes */
|
|
197
|
|
198 {ID3_TAL, ID3_TALB}, /* Album/Movie/Show title */
|
|
199 {ID3_TBP, ID3_TBPM}, /* BPM (Beats Per Minute) */
|
|
200 {ID3_TCM, ID3_TCOM}, /* Composer */
|
|
201 {ID3_TCO, ID3_TCON}, /* Content type */
|
|
202 {ID3_TCR, ID3_TCOP}, /* Copyright message */
|
|
203 /* This could be incorporated into TDRC */
|
|
204 {ID3_TDA, 0}, /* Date */
|
|
205 {ID3_TDY, ID3_TDLY}, /* Playlist delay */
|
|
206 {ID3_TEN, ID3_TENC}, /* Encoded by */
|
|
207 {ID3_TFT, ID3_TFLT}, /* File type */
|
|
208 /* This could be incorporated into TDRC */
|
|
209 {ID3_TIM, 0}, /* Time */
|
|
210 {ID3_TKE, ID3_TKEY}, /* Initial key */
|
|
211 {ID3_TLA, ID3_TLAN}, /* Language(s) */
|
|
212 {ID3_TLE, ID3_TLEN}, /* Length */
|
|
213 {ID3_TMT, ID3_TMED}, /* Media type */
|
|
214 {ID3_TOA, ID3_TOPE}, /* Original artist(s)/performer(s) */
|
|
215 {ID3_TOF, ID3_TOFN}, /* Original filename */
|
|
216 {ID3_TOL, ID3_TOLY}, /* Original Lyricist(s)/text writer(s) */
|
|
217 /*
|
|
218 * The docs says that original release year should be in
|
|
219 * milliseconds! Hopefully that is a typo.
|
|
220 */
|
|
221 {ID3_TOR, ID3_TDOR}, /* Original release year */
|
|
222 {ID3_TOT, ID3_TOAL}, /* Original album/Movie/Show title */
|
|
223 {ID3_TP1, ID3_TPE1}, /* Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group */
|
|
224 {ID3_TP2, ID3_TPE2}, /* Band/Orchestra/Accompaniment */
|
|
225 {ID3_TP3, ID3_TPE3}, /* Conductor/Performer refinement */
|
|
226 {ID3_TP4, ID3_TPE4}, /* Interpreted, remixed, or otherwise modified by */
|
|
227 {ID3_TPA, ID3_TPOS}, /* Part of a set */
|
|
228 {ID3_TPB, ID3_TPUB}, /* Publisher */
|
|
229 {ID3_TRC, ID3_TSRC}, /* ISRC (International Standard Recording Code) */
|
|
230 {ID3_TRD, 0}, /* Recording dates */
|
|
231 {ID3_TRK, ID3_TRCK}, /* Track number/Position in set */
|
|
232 {ID3_TSI, 0}, /* Size */
|
|
233 {ID3_TSS, ID3_TSSE}, /* Software/hardware and settings used for encoding */
|
|
234 {ID3_TT1, ID3_TIT1}, /* Content group description */
|
|
235 {ID3_TT2, ID3_TIT2}, /* Title/Songname/Content description */
|
|
236 {ID3_TT3, ID3_TIT3}, /* Subtitle/Description refinement */
|
|
237 {ID3_TXT, ID3_TEXT}, /* Lyricist/text writer */
|
|
238 {ID3_TXX, ID3_TXXX}, /* User defined text information frame */
|
|
239 {ID3_TYE, ID3_TDRC}, /* Year */
|
|
240
|
|
241 {ID3_UFI, ID3_UFID}, /* Unique file identifier */
|
|
242 {ID3_ULT, ID3_USLT}, /* Unsychronized lyric/text transcription */
|
|
243
|
|
244 {ID3_WAF, ID3_WOAF}, /* Official audio file webpage */
|
|
245 {ID3_WAR, ID3_WOAR}, /* Official artist/performer webpage */
|
|
246 {ID3_WAS, ID3_WOAS}, /* Official audio source webpage */
|
|
247 {ID3_WCM, ID3_WCOM}, /* Commercial information */
|
|
248 {ID3_WCP, ID3_WCOP}, /* Copyright/Legal information */
|
|
249 {ID3_WPB, ID3_WPUB}, /* Publishers official webpage */
|
|
250 {ID3_WXX, ID3_WXXX}, /* User defined URL link frame */
|
|
251 };
|
|
252
|
|
253 static struct id3_framedesc *
|
|
254 find_frame_description(guint32 id)
|
|
255 {
|
|
256 int i;
|
|
257 for (i = 0; i < sizeof(framedesc) / sizeof(struct id3_framedesc); i++)
|
|
258 if (framedesc[i].fd_id == id)
|
|
259 return &framedesc[i];
|
|
260 return NULL;
|
|
261 }
|
|
262
|
|
263
|
|
264 /*
|
|
265 * Function id3_read_frame (id3)
|
|
266 *
|
|
267 * Read next frame from the indicated ID3 tag. Return 0 upon
|
|
268 * success, or -1 if an error occured.
|
|
269 *
|
|
270 */
|
|
271 int
|
|
272 id3_read_frame(struct id3_tag *id3)
|
|
273 {
|
|
274 struct id3_frame *frame;
|
|
275 guint32 id;
|
|
276 char *buf;
|
|
277
|
|
278 if (id3->id3_version == 2)
|
|
279 return id3_read_frame_v22(id3);
|
|
280
|
|
281 /*
|
|
282 * Read frame header.
|
|
283 */
|
|
284 buf = id3->id3_read(id3, NULL, ID3_FRAMEHDR_SIZE);
|
|
285 if (buf == NULL)
|
|
286 return -1;
|
|
287
|
|
288 /*
|
|
289 * If we encounter an invalid frame id, we assume that there is
|
|
290 * some padding in the header. We just skip the rest of the ID3
|
|
291 * tag.
|
|
292 */
|
|
293 if (!((buf[0] >= '0' && buf[0] <= '9')
|
|
294 || (buf[0] >= 'A' && buf[0] <= 'Z'))) {
|
|
295 id3->id3_seek(id3, id3->id3_tagsize - id3->id3_pos);
|
|
296 return 0;
|
|
297 }
|
|
298 id = ID3_FRAME_ID(buf[0], buf[1], buf[2], buf[3]);
|
|
299
|
|
300 /*
|
|
301 * Allocate frame.
|
|
302 */
|
|
303 frame = g_malloc0(sizeof(*frame));
|
|
304
|
|
305 frame->fr_owner = id3;
|
|
306 /* FIXME v2.4.0 */
|
|
307 frame->fr_raw_size = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7];
|
|
308 if (frame->fr_raw_size < 0 || frame->fr_raw_size > 1000000) {
|
|
309 g_free(frame);
|
|
310 return -1;
|
|
311 }
|
|
312 frame->fr_flags = buf[8] << 8 | buf[9];
|
|
313
|
|
314 /*
|
|
315 * Determine the type of the frame.
|
|
316 */
|
|
317
|
|
318 frame->fr_desc = find_frame_description(id);
|
|
319
|
|
320 /*
|
|
321 * Check if frame had a valid id.
|
|
322 */
|
|
323 if (frame->fr_desc == NULL) {
|
|
324 /*
|
|
325 * No. Ignore the frame.
|
|
326 */
|
|
327 if (id3->id3_seek(id3, frame->fr_raw_size) < 0) {
|
|
328 g_free(frame);
|
|
329 return -1;
|
|
330 }
|
|
331 return 0;
|
|
332 }
|
|
333
|
|
334 /*
|
|
335 * Initialize frame.
|
|
336 */
|
|
337
|
|
338 /*
|
|
339 * We allocate 2 extra bytes. This simplifies retrieval of
|
|
340 * text strings.
|
|
341 */
|
|
342 frame->fr_raw_data = g_malloc0(frame->fr_raw_size + 2);
|
|
343 if (id3->id3_read(id3, frame->fr_raw_data, frame->fr_raw_size) == NULL) {
|
|
344 g_free(frame->fr_raw_data);
|
|
345 g_free(frame);
|
|
346 return -1;
|
|
347 }
|
|
348
|
|
349 /*
|
|
350 * Insert frame into linked list.
|
|
351 */
|
|
352 id3->id3_frame = g_list_append(id3->id3_frame, frame);
|
|
353
|
|
354 /*
|
|
355 * Check if frame is compressed using zlib.
|
|
356 */
|
|
357 if (frame->fr_flags & ID3_FHFLAG_COMPRESS)
|
|
358 return 0;
|
|
359
|
|
360 frame->fr_data = id3_frame_get_dataptr(frame);
|
|
361 frame->fr_size = id3_frame_get_size(frame);
|
|
362
|
|
363 return 0;
|
|
364 }
|
|
365
|
|
366
|
|
367 /*
|
|
368 * Function id3_get_frame (id3, type, num)
|
|
369 *
|
|
370 * Search in the list of frames for the ID3-tag, and return a frame
|
|
371 * of the indicated type. If tag contains several frames of the
|
|
372 * indicated type, the third argument tells which of the frames to
|
|
373 * return.
|
|
374 *
|
|
375 */
|
|
376 struct id3_frame *
|
|
377 id3_get_frame(struct id3_tag *id3, guint32 type, int num)
|
|
378 {
|
|
379 GList *node;
|
|
380
|
|
381 for (node = id3->id3_frame; node != NULL; node = node->next) {
|
|
382 struct id3_frame *fr = node->data;
|
|
383 if (fr->fr_desc && fr->fr_desc->fd_id == type) {
|
|
384 if (--num <= 0)
|
|
385 return fr;
|
|
386 }
|
|
387 }
|
|
388 return NULL;
|
|
389 }
|
|
390
|
|
391 /*
|
|
392 * Function decompress_frame(frame)
|
|
393 *
|
|
394 * Uncompress the indicated frame. Return 0 upon success, or -1 if
|
|
395 * an error occured.
|
|
396 *
|
|
397 */
|
|
398 static int
|
|
399 decompress_frame(struct id3_frame *frame)
|
|
400 {
|
|
401 #ifdef HAVE_LIBZ
|
|
402 z_stream z;
|
|
403 int r;
|
|
404
|
|
405 /*
|
|
406 * Fetch the size of the decompressed data.
|
|
407 */
|
|
408 frame->fr_size_z = g_ntohl(*((guint32 *) frame->fr_raw_data));
|
|
409 if (frame->fr_size_z < 0 || frame->fr_size_z > 1000000)
|
|
410 return -1;
|
|
411
|
|
412 /*
|
|
413 * Allocate memory to hold uncompressed frame.
|
|
414 */
|
|
415 frame->fr_data_z = g_malloc(frame->fr_size_z +
|
|
416 (id3_frame_is_text(frame) ? 2 : 0));
|
|
417
|
|
418 /*
|
|
419 * Initialize zlib.
|
|
420 */
|
|
421 z.next_in = id3_frame_get_dataptr(frame);
|
|
422 z.avail_in = id3_frame_get_size(frame);
|
|
423 z.zalloc = NULL;
|
|
424 z.zfree = NULL;
|
|
425 z.opaque = NULL;
|
|
426
|
|
427 r = inflateInit(&z);
|
|
428 switch (r) {
|
|
429 case Z_OK:
|
|
430 break;
|
|
431 case Z_MEM_ERROR:
|
|
432 id3_error(frame->fr_owner, "zlib - no memory");
|
|
433 goto Error_init;
|
|
434 case Z_VERSION_ERROR:
|
|
435 id3_error(frame->fr_owner, "zlib - invalid version");
|
|
436 goto Error_init;
|
|
437 default:
|
|
438 id3_error(frame->fr_owner, "zlib - unknown error");
|
|
439 goto Error_init;
|
|
440 }
|
|
441
|
|
442 /*
|
|
443 * Decompress frame.
|
|
444 */
|
|
445 z.next_out = frame->fr_data_z;
|
|
446 z.avail_out = frame->fr_size_z;
|
|
447 r = inflate(&z, Z_SYNC_FLUSH);
|
|
448 switch (r) {
|
|
449 case Z_STREAM_END:
|
|
450 break;
|
|
451 case Z_OK:
|
|
452 if (z.avail_in == 0)
|
|
453 /*
|
|
454 * This should not be possible with a correct stream.
|
|
455 * We will be nice however, and try to go on.
|
|
456 */
|
|
457 break;
|
|
458 id3_error(frame->fr_owner, "zlib - buffer exhausted");
|
|
459 goto Error_inflate;
|
|
460 default:
|
|
461 id3_error(frame->fr_owner, "zlib - unknown error");
|
|
462 goto Error_inflate;
|
|
463 }
|
|
464
|
|
465 r = inflateEnd(&z);
|
|
466 if (r != Z_OK)
|
|
467 id3_error(frame->fr_owner, "zlib - inflateEnd error");
|
|
468
|
|
469 /*
|
|
470 * Null-terminate text frames.
|
|
471 */
|
|
472 if (id3_frame_is_text(frame)) {
|
|
473 ((char *) frame->fr_data_z)[frame->fr_size_z] = 0;
|
|
474 ((char *) frame->fr_data_z)[frame->fr_size_z + 1] = 0;
|
|
475 }
|
|
476 frame->fr_data = frame->fr_data_z;
|
|
477 frame->fr_size = frame->fr_size_z + (id3_frame_is_text(frame) ? 2 : 0);
|
|
478
|
|
479 return 0;
|
|
480
|
|
481 /*
|
|
482 * Cleanup code.
|
|
483 */
|
|
484 Error_inflate:
|
|
485 r = inflateEnd(&z);
|
|
486 Error_init:
|
|
487 g_free(frame->fr_data_z);
|
|
488 frame->fr_data_z = NULL;
|
|
489 #endif
|
|
490 return -1;
|
|
491 }
|
|
492
|
|
493 /*
|
|
494 * Function id3_decompress_frame(frame)
|
|
495 *
|
|
496 * Check if frame is compressed, and uncompress if necessary.
|
|
497 * Return 0 upon success, or -1 if an error occured.
|
|
498 *
|
|
499 */
|
|
500 int
|
|
501 id3_decompress_frame(struct id3_frame *frame)
|
|
502 {
|
|
503 if (!(frame->fr_flags & ID3_FHFLAG_COMPRESS))
|
|
504 /* Frame not compressed */
|
|
505 return 0;
|
|
506 if (frame->fr_data_z)
|
|
507 /* Frame already decompressed */
|
|
508 return 0;
|
|
509 /* Do decompression */
|
|
510 return decompress_frame(frame);
|
|
511 }
|
|
512
|
|
513
|
|
514 /*
|
|
515 * Function id3_delete_frame (frame)
|
|
516 *
|
|
517 * Remove frame from ID3 tag and release memory ocupied by it.
|
|
518 *
|
|
519 */
|
|
520 int
|
|
521 id3_delete_frame(struct id3_frame *frame)
|
|
522 {
|
|
523 GList *list = frame->fr_owner->id3_frame;
|
|
524 int ret;
|
|
525
|
|
526 /*
|
|
527 * Search for frame in list.
|
|
528 */
|
|
529
|
|
530 if (g_list_find(list, frame) != NULL) {
|
|
531 /*
|
|
532 * Frame does not exist in frame list.
|
|
533 */
|
|
534 ret = -1;
|
|
535
|
|
536 }
|
|
537 else {
|
|
538 /*
|
|
539 * Remove frame from frame list.
|
|
540 */
|
|
541 list = g_list_remove(list, frame);
|
|
542 frame->fr_owner->id3_altered = 1;
|
|
543 ret = 0;
|
|
544 }
|
|
545
|
|
546 /*
|
|
547 * Release memory occupied by frame.
|
|
548 */
|
|
549 if (frame->fr_raw_data)
|
|
550 g_free(frame->fr_raw_data);
|
|
551 if (frame->fr_data_z)
|
|
552 g_free(frame->fr_data_z);
|
|
553 g_free(frame);
|
|
554
|
|
555 return ret;
|
|
556 }
|
|
557
|
|
558
|
|
559 /*
|
|
560 * Function id3_add_frame (id3, type)
|
|
561 *
|
|
562 * Add a new frame to the ID3 tag. Return a pointer to the new
|
|
563 * frame, or NULL if an error occured.
|
|
564 *
|
|
565 */
|
|
566 struct id3_frame *
|
|
567 id3_add_frame(struct id3_tag *id3, guint32 type)
|
|
568 {
|
|
569 struct id3_frame *frame;
|
|
570 int i;
|
|
571
|
|
572 /*
|
|
573 * Allocate frame.
|
|
574 */
|
|
575 frame = g_malloc0(sizeof(*frame));
|
|
576
|
|
577 /*
|
|
578 * Initialize frame
|
|
579 */
|
|
580 frame->fr_owner = id3;
|
|
581
|
|
582 /*
|
|
583 * Try finding the correct frame descriptor.
|
|
584 */
|
|
585 for (i = 0; i < sizeof(framedesc) / sizeof(struct id3_framedesc); i++) {
|
|
586 if (framedesc[i].fd_id == type) {
|
|
587 frame->fr_desc = &framedesc[i];
|
|
588 break;
|
|
589 }
|
|
590 }
|
|
591
|
|
592 /*
|
|
593 * Insert frame into linked list.
|
|
594 */
|
|
595 id3->id3_frame = g_list_append(id3->id3_frame, frame);
|
|
596 id3->id3_altered = 1;
|
|
597
|
|
598 return frame;
|
|
599 }
|
|
600
|
|
601
|
|
602 /*
|
|
603 * Destroy all frames in an id3 tag, and free all data
|
|
604 */
|
|
605 void
|
|
606 id3_destroy_frames(struct id3_tag *id)
|
|
607 {
|
|
608 GList *node;
|
|
609
|
|
610 for (node = id->id3_frame; node != NULL; node = node->next) {
|
|
611 struct id3_frame *frame = node->data;
|
|
612 /*
|
|
613 * Release memory occupied by frame.
|
|
614 */
|
|
615 if (frame->fr_raw_data)
|
|
616 g_free(frame->fr_raw_data);
|
|
617 if (frame->fr_data_z)
|
|
618 g_free(frame->fr_data_z);
|
|
619 g_free(frame);
|
|
620 }
|
|
621 g_list_free(id->id3_frame);
|
|
622 id->id3_frame = NULL;
|
|
623 }
|
|
624
|
|
625 static int
|
|
626 id3_frame_extra_headers(struct id3_frame *frame)
|
|
627 {
|
|
628 int retv = 0;
|
|
629 /*
|
|
630 * If frame is encrypted, we have four extra bytes in the
|
|
631 * header.
|
|
632 */
|
|
633 if (frame->fr_flags & ID3_FHFLAG_COMPRESS)
|
|
634 retv += 4;
|
|
635 /*
|
|
636 * If frame is encrypted, we have one extra byte in the
|
|
637 * header.
|
|
638 */
|
|
639 if (frame->fr_flags & ID3_FHFLAG_ENCRYPT)
|
|
640 retv += 1;
|
|
641
|
|
642 /*
|
|
643 * If frame has grouping identity, we have one extra byte in
|
|
644 * the header.
|
|
645 */
|
|
646 if (frame->fr_flags & ID3_FHFLAG_GROUP)
|
|
647 retv += 1;
|
|
648
|
|
649 return retv;
|
|
650 }
|
|
651
|
|
652 static void *
|
|
653 id3_frame_get_dataptr(struct id3_frame *frame)
|
|
654 {
|
|
655 char *ptr = frame->fr_raw_data;
|
|
656
|
|
657 ptr += id3_frame_extra_headers(frame);
|
|
658
|
|
659 return ptr;
|
|
660 }
|
|
661
|
|
662 static int
|
|
663 id3_frame_get_size(struct id3_frame *frame)
|
|
664 {
|
|
665 return frame->fr_raw_size - id3_frame_extra_headers(frame);
|
|
666 }
|
|
667
|
|
668 void
|
|
669 id3_frame_clear_data(struct id3_frame *frame)
|
|
670 {
|
|
671 if (frame->fr_raw_data)
|
|
672 g_free(frame->fr_raw_data);
|
|
673 if (frame->fr_data_z)
|
|
674 g_free(frame->fr_data_z);
|
|
675 frame->fr_raw_data = NULL;
|
|
676 frame->fr_raw_size = 0;
|
|
677 frame->fr_data = NULL;
|
|
678 frame->fr_size = 0;
|
|
679 frame->fr_data_z = NULL;
|
|
680 frame->fr_size_z = 0;
|
|
681 }
|
|
682
|
|
683 static guint32
|
|
684 find_v24_id(guint32 v22)
|
|
685 {
|
|
686 int i;
|
|
687 for (i = 0; i < sizeof(framedesc22) / sizeof(framedesc22[0]); i++)
|
|
688 if (framedesc22[i].fd_v22 == v22)
|
|
689 return framedesc22[i].fd_v24;
|
|
690
|
|
691 return 0;
|
|
692 }
|
|
693
|
|
694 static int
|
|
695 id3_read_frame_v22(struct id3_tag *id3)
|
|
696 {
|
|
697 struct id3_frame *frame;
|
|
698 guint32 id, idv24;
|
|
699 char *buf;
|
|
700 int size;
|
|
701
|
|
702 /*
|
|
703 * Read frame header.
|
|
704 */
|
|
705 buf = id3->id3_read(id3, NULL, ID3_FRAMEHDR_SIZE_22);
|
|
706 if (buf == NULL)
|
|
707 return -1;
|
|
708
|
|
709 /*
|
|
710 * If we encounter an invalid frame id, we assume that there
|
|
711 * is some. We just skip the rest of the ID3 tag.
|
|
712 */
|
|
713 if (!((buf[0] >= '0' && buf[0] <= '9')
|
|
714 || (buf[0] >= 'A' && buf[0] <= 'Z'))) {
|
|
715 id3->id3_seek(id3, id3->id3_tagsize - id3->id3_pos);
|
|
716 return 0;
|
|
717 }
|
|
718
|
|
719 id = ID3_FRAME_ID_22(buf[0], buf[1], buf[2]);
|
|
720 size = buf[3] << 16 | buf[4] << 8 | buf[5];
|
|
721
|
|
722 if ((idv24 = find_v24_id(id)) == 0) {
|
|
723 if (id3->id3_seek(id3, size) < 0)
|
|
724 return -1;
|
|
725 return 0;
|
|
726 }
|
|
727
|
|
728 /*
|
|
729 * Allocate frame.
|
|
730 */
|
|
731 frame = g_malloc0(sizeof(*frame));
|
|
732
|
|
733 frame->fr_owner = id3;
|
|
734 frame->fr_raw_size = size;
|
|
735 if (frame->fr_raw_size < 0 || frame->fr_raw_size > 1000000) {
|
|
736 g_free(frame);
|
|
737 return -1;
|
|
738 }
|
|
739
|
|
740 /*
|
|
741 * Initialize frame.
|
|
742 */
|
|
743 frame->fr_desc = find_frame_description(idv24);
|
|
744
|
|
745 /*
|
|
746 * We allocate 2 extra bytes. This simplifies retrieval of
|
|
747 * text strings.
|
|
748 */
|
|
749 frame->fr_raw_data = g_malloc0(frame->fr_raw_size + 2);
|
|
750 if (id3->id3_read(id3, frame->fr_raw_data, frame->fr_raw_size) == NULL) {
|
|
751 g_free(frame->fr_raw_data);
|
|
752 g_free(frame);
|
|
753 return -1;
|
|
754 }
|
|
755
|
|
756 /*
|
|
757 * Insert frame into linked list.
|
|
758 */
|
|
759 id3->id3_frame = g_list_append(id3->id3_frame, frame);
|
|
760
|
|
761 frame->fr_data = frame->fr_raw_data;
|
|
762 frame->fr_size = frame->fr_raw_size;
|
|
763
|
|
764 return 0;
|
|
765 }
|