Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * id3tag.c -- Write ID3 version 1 and 2 tags.
3
 *
4
 * Copyright (C) 2000 Don Melton.
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Library General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Library General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Library General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19
 */
20
 
21
/*
22
 * HISTORY: This source file is part of LAME (see http://www.mp3dev.org/mp3/)
23
 * and was originally adapted by Conrad Sanderson <c.sanderson@me.gu.edu.au>
24
 * from mp3info by Ricardo Cerqueira <rmc@rccn.net> to write only ID3 version 1
25
 * tags.  Don Melton <don@blivet.com> COMPLETELY rewrote it to support version
26
 * 2 tags and be more conformant to other standards while remaining flexible.
27
 *
28
 * NOTE: See http://id3.org/ for more information about ID3 tag formats.
29
 */
30
 
31
/* $Id: id3tag.c,v 1.18 2001/01/15 15:16:09 aleidinger Exp $ */
32
 
33
#ifdef HAVE_CONFIG_H
34
#include <config.h>
35
#endif
36
 
37
#ifdef STDC_HEADERS
38
# include <stddef.h>
39
# include <stdlib.h>
40
# include <string.h>
41
#else
42
# ifndef HAVE_STRCHR
43
#  define strchr index
44
#  define strrchr rindex
45
# endif
46
char *strchr (), *strrchr ();
47
# ifndef HAVE_MEMCPY
48
#  define memcpy(d, s, n) bcopy ((s), (d), (n))
49
#  define memmove(d, s, n) bcopy ((s), (d), (n))
50
# endif
51
#endif
52
 
53
#include "lame.h"
54
#include "id3tag.h"
55
#include "util.h"
56
#include "bitstream.h"
57
 
58
#ifdef WITH_DMALLOC
59
#include <dmalloc.h>
60
#endif
61
 
62
static const char *const genre_names[] =
63
{
64
    /*
65
     * NOTE: The spelling of these genre names is identical to those found in
66
     * Winamp and mp3info.
67
     */
68
    "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
69
    "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
70
    "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
71
    "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
72
    "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
73
    "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alt. Rock",
74
    "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
75
    "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
76
    "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
77
    "Cult", "Gangsta Rap", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
78
    "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave",
79
    "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
80
    "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
81
    "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin",
82
    "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
83
    "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
84
    "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
85
    "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
86
    "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
87
    "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
88
    "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall",
89
    "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
90
    "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap",
91
    "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
92
    "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
93
    "Synthpop"
94
};
95
 
96
#define GENRE_NAME_COUNT \
97
    ((int)(sizeof genre_names / sizeof (const char *const)))
98
 
99
static const int genre_alpha_map [] = {
100
    123, 34, 74, 73, 99, 20, 40, 26, 145, 90, 116, 41, 135, 85, 96, 138, 89, 0,
101
    107, 132, 65, 88, 104, 102, 97, 136, 61, 141, 32, 1, 112, 128, 57, 140, 2,
102
    139, 58, 3, 125, 50, 22, 4, 55, 127, 122, 120, 98, 52, 48, 54, 124, 25, 84,
103
    80, 115, 81, 119, 5, 30, 36, 59, 126, 38, 49, 91, 6, 129, 79, 137, 7, 35,
104
    100, 131, 19, 33, 46, 47, 8, 29, 146, 63, 86, 71, 45, 142, 9, 77, 82, 64,
105
    133, 10, 66, 39, 11, 103, 12, 75, 134, 13, 53, 62, 109, 117, 23, 108, 92,
106
    67, 93, 43, 121, 15, 68, 14, 16, 76, 87, 118, 17, 78, 143, 114, 110, 69, 21,
107
    111, 95, 105, 42, 37, 24, 56, 44, 101, 83, 94, 106, 147, 113, 18, 51, 130,
108
    144, 60, 70, 31, 72, 27, 28
109
};
110
 
111
#define GENRE_ALPHA_COUNT ((int)(sizeof genre_alpha_map / sizeof (int)))
112
 
113
void
114
id3tag_genre_list(void (*handler)(int, const char *, void *), void *cookie)
115
{
116
    if (handler) {
117
        int i;
118
        for (i = 0; i < GENRE_NAME_COUNT; ++i) {
119
            if (i < GENRE_ALPHA_COUNT) {
120
                int j = genre_alpha_map[i];
121
                handler(j, genre_names[j], cookie);
122
            }
123
        }
124
    }
125
}
126
 
127
#define GENRE_NUM_UNKNOWN 255
128
 
129
void
130
id3tag_init(lame_global_flags *gfp)
131
{
132
    lame_internal_flags *gfc = gfp->internal_flags;
133
    memset(&gfc->tag_spec, 0, sizeof gfc->tag_spec);
134
    gfc->tag_spec.genre = GENRE_NUM_UNKNOWN;
135
}
136
 
137
#define CHANGED_FLAG    (1U << 0)
138
#define ADD_V2_FLAG     (1U << 1)
139
#define V1_ONLY_FLAG    (1U << 2)
140
#define V2_ONLY_FLAG    (1U << 3)
141
#define SPACE_V1_FLAG   (1U << 4)
142
#define PAD_V2_FLAG     (1U << 5)
143
 
144
void
145
id3tag_add_v2(lame_global_flags *gfp)
146
{
147
    lame_internal_flags *gfc = gfp->internal_flags;
148
    gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
149
    gfc->tag_spec.flags |= ADD_V2_FLAG;
150
}
151
 
152
void
153
id3tag_v1_only(lame_global_flags *gfp)
154
{
155
    lame_internal_flags *gfc = gfp->internal_flags;
156
    gfc->tag_spec.flags &= ~(ADD_V2_FLAG | V2_ONLY_FLAG);
157
    gfc->tag_spec.flags |= V1_ONLY_FLAG;
158
}
159
 
160
void
161
id3tag_v2_only(lame_global_flags *gfp)
162
{
163
    lame_internal_flags *gfc = gfp->internal_flags;
164
    gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
165
    gfc->tag_spec.flags |= V2_ONLY_FLAG;
166
}
167
 
168
void
169
id3tag_space_v1(lame_global_flags *gfp)
170
{
171
    lame_internal_flags *gfc = gfp->internal_flags;
172
    gfc->tag_spec.flags &= ~V2_ONLY_FLAG;
173
    gfc->tag_spec.flags |= SPACE_V1_FLAG;
174
}
175
 
176
void
177
id3tag_pad_v2(lame_global_flags *gfp)
178
{
179
    lame_internal_flags *gfc = gfp->internal_flags;
180
    gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
181
    gfc->tag_spec.flags |= PAD_V2_FLAG;
182
}
183
 
184
void
185
id3tag_set_title(lame_global_flags *gfp, const char *title)
186
{
187
    lame_internal_flags *gfc = gfp->internal_flags;
188
    if (title && *title) {
189
        gfc->tag_spec.title = title;
190
        gfc->tag_spec.flags |= CHANGED_FLAG;
191
    }
192
}
193
 
194
void
195
id3tag_set_artist(lame_global_flags *gfp, const char *artist)
196
{
197
    lame_internal_flags *gfc = gfp->internal_flags;
198
    if (artist && *artist) {
199
        gfc->tag_spec.artist = artist;
200
        gfc->tag_spec.flags |= CHANGED_FLAG;
201
    }
202
}
203
 
204
void
205
id3tag_set_album(lame_global_flags *gfp, const char *album)
206
{
207
    lame_internal_flags *gfc = gfp->internal_flags;
208
    if (album && *album) {
209
        gfc->tag_spec.album = album;
210
        gfc->tag_spec.flags |= CHANGED_FLAG;
211
    }
212
}
213
 
214
void
215
id3tag_set_year(lame_global_flags *gfp, const char *year)
216
{
217
    lame_internal_flags *gfc = gfp->internal_flags;
218
    if (year && *year) {
219
        int num = atoi(year);
220
        if (num < 0) {
221
            num = 0;
222
        }
223
        /* limit a year to 4 digits so it fits in a version 1 tag */
224
        if (num > 9999) {
225
            num = 9999;
226
        }
227
        if (num) {
228
            gfc->tag_spec.year = num;
229
            gfc->tag_spec.flags |= CHANGED_FLAG;
230
        }
231
    }
232
}
233
 
234
void
235
id3tag_set_comment(lame_global_flags *gfp, const char *comment)
236
{
237
    lame_internal_flags *gfc = gfp->internal_flags;
238
    if (comment && *comment) {
239
        gfc->tag_spec.comment = comment;
240
        gfc->tag_spec.flags |= CHANGED_FLAG;
241
    }
242
}
243
 
244
void
245
id3tag_set_track(lame_global_flags *gfp, const char *track)
246
{
247
    lame_internal_flags *gfc = gfp->internal_flags;
248
    if (track && *track) {
249
        int num = atoi(track);
250
        if (num < 0) {
251
            num = 0;
252
        }
253
        /* limit a track to 255 so it fits in a version 1 tag even though CD
254
         * audio doesn't allow more than 99 tracks */
255
        if (num > 255) {
256
            num = 255;
257
        }
258
        if (num) {
259
            gfc->tag_spec.track = num;
260
            gfc->tag_spec.flags |= CHANGED_FLAG;
261
        }
262
    }
263
}
264
 
265
/* would use real "strcasecmp" but it isn't portable */
266
static int
267
local_strcasecmp(const char *s1, const char *s2)
268
{
269
    unsigned char c1;
270
    unsigned char c2;
271
    do {
272
        c1 = tolower(*s1);
273
        c2 = tolower(*s2);
274
        if (!c1) {
275
            break;
276
        }
277
        ++s1;
278
        ++s2;
279
    } while (c1 == c2);
280
    return c1 - c2;
281
}
282
 
283
int
284
id3tag_set_genre(lame_global_flags *gfp, const char *genre)
285
{
286
    lame_internal_flags *gfc = gfp->internal_flags;
287
    if (genre && *genre) {
288
        char *str;
289
        int num = strtol(genre, &str, 10);
290
        /* is the input a string or a valid number? */
291
        if (*str) {
292
            int i;
293
            for (i = 0; i < GENRE_NAME_COUNT; ++i) {
294
                if (!local_strcasecmp(genre, genre_names[i])) {
295
                    num = i;
296
                    break;
297
                }
298
            }
299
            if (i == GENRE_NAME_COUNT) {
300
                return -1;
301
            }
302
        } else if ((num < 0) || (num >= GENRE_NAME_COUNT)) {
303
            return -1;
304
        }
305
        gfc->tag_spec.genre = num;
306
        gfc->tag_spec.flags |= CHANGED_FLAG;
307
    }
308
    return 0;
309
}
310
 
311
static unsigned char *
312
set_4_byte_value(unsigned char *bytes, unsigned long value)
313
{
314
    int index;
315
    for (index = 3; index >= 0; --index) {
316
        bytes[index] = value & 0xfful;
317
        value >>= 8;
318
    }
319
    return bytes + 4;
320
}
321
 
322
#define FRAME_ID(a, b, c, d) \
323
    ( ((unsigned long)(a) << 24) \
324
    | ((unsigned long)(b) << 16) \
325
    | ((unsigned long)(c) <<  8) \
326
    | ((unsigned long)(d) <<  0) )
327
#define TITLE_FRAME_ID FRAME_ID('T', 'I', 'T', '2')
328
#define ARTIST_FRAME_ID FRAME_ID('T', 'P', 'E', '1')
329
#define ALBUM_FRAME_ID FRAME_ID('T', 'A', 'L', 'B')
330
#define YEAR_FRAME_ID FRAME_ID('T', 'Y', 'E', 'R')
331
#define COMMENT_FRAME_ID FRAME_ID('C', 'O', 'M', 'M')
332
#define TRACK_FRAME_ID FRAME_ID('T', 'R', 'C', 'K')
333
#define GENRE_FRAME_ID FRAME_ID('T', 'C', 'O', 'N')
334
 
335
static unsigned char *
336
set_frame(unsigned char *frame, unsigned long id, const char *text,
337
    size_t length)
338
{
339
    if (length) {
340
        frame = set_4_byte_value(frame, id);
341
        /* Set frame size = total size - header size.  Frame header and field
342
         * bytes include 2-byte header flags, 1 encoding descriptor byte, and
343
         * for comment frames: 3-byte language descriptor and 1 content
344
         * descriptor byte */
345
        frame = set_4_byte_value(frame, ((id == COMMENT_FRAME_ID) ? 5 : 1)
346
                + length);
347
        /* clear 2-byte header flags */
348
        *frame++ = 0;
349
        *frame++ = 0;
350
        /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */
351
        *frame++ = 0;
352
        if (id == COMMENT_FRAME_ID) {
353
            /* use id3lib-compatible bogus language descriptor */
354
            *frame++ = 'X';
355
            *frame++ = 'X';
356
            *frame++ = 'X';
357
            /* clear 1 byte to make content descriptor empty string */
358
            *frame++ = 0;
359
        }
360
        while (length--) {
361
            *frame++ = *text++;
362
        }
363
    }
364
    return frame;
365
}
366
 
367
int
368
id3tag_write_v2(lame_global_flags *gfp)
369
{
370
    lame_internal_flags *gfc = gfp->internal_flags;
371
    if ((gfc->tag_spec.flags & CHANGED_FLAG)
372
            && !(gfc->tag_spec.flags & V1_ONLY_FLAG)) {
373
        /* calculate length of four fields which may not fit in verion 1 tag */
374
        size_t title_length = gfc->tag_spec.title
375
            ? strlen(gfc->tag_spec.title) : 0;
376
        size_t artist_length = gfc->tag_spec.artist
377
            ? strlen(gfc->tag_spec.artist) : 0;
378
        size_t album_length = gfc->tag_spec.album
379
            ? strlen(gfc->tag_spec.album) : 0;
380
        size_t comment_length = gfc->tag_spec.comment
381
            ? strlen(gfc->tag_spec.comment) : 0;
382
        /* write tag if explicitly requested or if fields overflow */
383
        if ((gfc->tag_spec.flags & (ADD_V2_FLAG | V2_ONLY_FLAG))
384
                || (title_length > 30)
385
                || (artist_length > 30) || (album_length > 30)
386
                || (comment_length > 30)
387
                || (gfc->tag_spec.track && (comment_length > 28))) {
388
            size_t tag_size;
389
            char year[5];
390
            size_t year_length;
391
            char track[3];
392
            size_t track_length;
393
            char genre[6];
394
            size_t genre_length;
395
            unsigned char *tag;
396
            unsigned char *p;
397
            size_t adjusted_tag_size;
398
            unsigned int index;
399
            /* calulate size of tag starting with 10-byte tag header */
400
            tag_size = 10;
401
            if (title_length) {
402
                /* add 10-byte frame header, 1 encoding descriptor byte ... */
403
                tag_size += 11 + title_length;
404
            }
405
            if (artist_length) {
406
                tag_size += 11 + artist_length;
407
            }
408
            if (album_length) {
409
                tag_size += 11 + album_length;
410
            }
411
            if (gfc->tag_spec.year) {
412
                year_length = sprintf(year, "%d", gfc->tag_spec.year);
413
                tag_size += 11 + year_length;
414
            } else {
415
                year_length = 0;
416
            }
417
            if (comment_length) {
418
                /* add 10-byte frame header, 1 encoding descriptor byte,
419
                 * 3-byte language descriptor, 1 content descriptor byte ... */
420
                tag_size += 15 + comment_length;
421
            }
422
            if (gfc->tag_spec.track) {
423
                track_length = sprintf(track, "%d", gfc->tag_spec.track);
424
                tag_size += 11 + track_length;
425
            } else {
426
                track_length = 0;
427
            }
428
            if (gfc->tag_spec.genre != GENRE_NUM_UNKNOWN) {
429
                genre_length = sprintf(genre, "(%d)", gfc->tag_spec.genre);
430
                tag_size += 11 + genre_length;
431
            } else {
432
                genre_length = 0;
433
            }
434
            if (gfc->tag_spec.flags & PAD_V2_FLAG) {
435
                /* add 128 bytes of padding */
436
                tag_size += 128;
437
            }
438
            tag = (unsigned char *)malloc(tag_size);
439
            if (!tag) {
440
                return -1;
441
            }
442
            p = tag;
443
            /* set tag header starting with file identifier */
444
            *p++ = 'I'; *p++ = 'D'; *p++ = '3';
445
            /* set version number word */
446
            *p++ = 3; *p++ = 0;
447
            /* clear flags byte */
448
            *p++ = 0;
449
            /* calculate and set tag size = total size - header size */
450
            adjusted_tag_size = tag_size - 10;
451
            /* encode adjusted size into four bytes where most significant 
452
             * bit is clear in each byte, for 28-bit total */
453
            *p++ = (adjusted_tag_size >> 21) & 0x7fu;
454
            *p++ = (adjusted_tag_size >> 14) & 0x7fu;
455
            *p++ = (adjusted_tag_size >> 7) & 0x7fu;
456
            *p++ = adjusted_tag_size & 0x7fu;
457
 
458
            /*
459
             * NOTE: The remainder of the tag (frames and padding, if any)
460
             * are not "unsynchronized" to prevent false MPEG audio headers
461
             * from appearing in the bitstream.  Why?  Well, most players
462
             * and utilities know how to skip the ID3 version 2 tag by now
463
             * even if they don't read its contents, and it's actually
464
             * very unlikely that such a false "sync" pattern would occur
465
             * in just the simple text frames added here.
466
             */
467
 
468
            /* set each frame in tag */
469
            p = set_frame(p, TITLE_FRAME_ID, gfc->tag_spec.title, title_length);
470
            p = set_frame(p, ARTIST_FRAME_ID, gfc->tag_spec.artist,
471
                    artist_length);
472
            p = set_frame(p, ALBUM_FRAME_ID, gfc->tag_spec.album, album_length);
473
            p = set_frame(p, YEAR_FRAME_ID, year, year_length);
474
            p = set_frame(p, COMMENT_FRAME_ID, gfc->tag_spec.comment,
475
                    comment_length);
476
            p = set_frame(p, TRACK_FRAME_ID, track, track_length);
477
            p = set_frame(p, GENRE_FRAME_ID, genre, genre_length);
478
            /* clear any padding bytes */
479
            memset(p, 0, tag_size - (p - tag));
480
            /* write tag directly into bitstream at current position */
481
            for (index = 0; index < tag_size; ++index) {
482
                add_dummy_byte(gfp, tag[index]);
483
            }
484
            free(tag);
485
            return tag_size;
486
        }
487
    }
488
    return 0;
489
}
490
 
491
static unsigned char *
492
set_text_field(unsigned char *field, const char *text, size_t size, int pad)
493
{
494
    while (size--) {
495
        if (text && *text) {
496
            *field++ = *text++;
497
        } else {
498
            *field++ = pad;
499
        }
500
    }
501
    return field;
502
}
503
 
504
int
505
id3tag_write_v1(lame_global_flags *gfp)
506
{
507
    lame_internal_flags *gfc = gfp->internal_flags;
508
    if ((gfc->tag_spec.flags & CHANGED_FLAG)
509
            && !(gfc->tag_spec.flags & V2_ONLY_FLAG)) {
510
        unsigned char tag[128];
511
        unsigned char *p = tag;
512
        int pad = (gfc->tag_spec.flags & SPACE_V1_FLAG) ? ' ' : 0;
513
        char year[5];
514
        unsigned int index;
515
        /* set tag identifier */
516
        *p++ = 'T'; *p++ = 'A'; *p++ = 'G';
517
        /* set each field in tag */
518
        p = set_text_field(p, gfc->tag_spec.title, 30, pad);
519
        p = set_text_field(p, gfc->tag_spec.artist, 30, pad);
520
        p = set_text_field(p, gfc->tag_spec.album, 30, pad);
521
        sprintf(year, "%d", gfc->tag_spec.year);
522
        p = set_text_field(p, gfc->tag_spec.year ? year : NULL, 4, pad);
523
        /* limit comment field to 28 bytes if a track is specified */
524
        p = set_text_field(p, gfc->tag_spec.comment, gfc->tag_spec.track
525
                ? 28 : 30, pad);
526
        if (gfc->tag_spec.track) {
527
            /* clear the next byte to indicate a version 1.1 tag */
528
            *p++ = 0;
529
            *p++ = gfc->tag_spec.track;
530
        }
531
        *p++ = gfc->tag_spec.genre;
532
        /* write tag directly into bitstream at current position */
533
        for (index = 0; index < 128; ++index) {
534
            add_dummy_byte(gfp, tag[index]);
535
        }
536
        return 128;
537
    }
538
    return 0;
539
}