diff options
author | Kostya Shishkov <kostya.shishkov@gmail.com> | 2009-08-11 17:08:09 +0000 |
---|---|---|
committer | Kostya Shishkov <kostya.shishkov@gmail.com> | 2009-08-11 17:08:09 +0000 |
commit | 191e34cd67e46e125782073283346fda459d2146 (patch) | |
tree | 19cf4176190e39df9d13dbfe110eea808f64e3f7 /libavformat/apetag.c | |
parent | 6984380c6123ec4305c5cf0396ae997a06868d9e (diff) | |
download | ffmpeg-191e34cd67e46e125782073283346fda459d2146.tar.gz |
Move APE tag parsing into separate module.
Based on patch by Matti Hamalainen (mhamalai<mot>students<punkt>oamk<punkt>)
Originally committed as revision 19629 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/apetag.c')
-rw-r--r-- | libavformat/apetag.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/libavformat/apetag.c b/libavformat/apetag.c new file mode 100644 index 0000000000..435dd3fdcf --- /dev/null +++ b/libavformat/apetag.c @@ -0,0 +1,122 @@ +/* + * APE tag handling + * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org> + * based upon libdemac from Dave Chapman. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" +#include "avformat.h" + +#define ENABLE_DEBUG 0 + +#define APE_TAG_VERSION 2000 +#define APE_TAG_FOOTER_BYTES 32 +#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31) +#define APE_TAG_FLAG_IS_HEADER (1 << 29) + +static int ape_tag_read_field(AVFormatContext *s) +{ + ByteIOContext *pb = s->pb; + uint8_t key[1024], value[1024]; + uint32_t size, flags; + int i, l, c; + + size = get_le32(pb); /* field size */ + flags = get_le32(pb); /* field flags */ + for (i = 0; i < sizeof(key) - 1; i++) { + c = get_byte(pb); + if (c < 0x20 || c > 0x7E) + break; + else + key[i] = c; + } + key[i] = 0; + if (c != 0) { + av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key); + return -1; + } + l = FFMIN(size, sizeof(value)-1); + get_buffer(pb, value, l); + value[l] = 0; + url_fskip(pb, size-l); + if (l < size) + av_log(s, AV_LOG_WARNING, "Too long '%s' tag was truncated.\n", key); + av_metadata_set(&s->metadata, key, value); + return 0; +} + +void ff_ape_parse_tag(AVFormatContext *s) +{ + ByteIOContext *pb = s->pb; + int file_size = url_fsize(pb); + uint32_t val, fields, tag_bytes; + uint8_t buf[8]; + int i; + + if (file_size < APE_TAG_FOOTER_BYTES) + return; + + url_fseek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET); + + get_buffer(pb, buf, 8); /* APETAGEX */ + if (strncmp(buf, "APETAGEX", 8)) { + return; + } + + val = get_le32(pb); /* APE tag version */ + if (val > APE_TAG_VERSION) { + av_log(s, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION); + return; + } + + tag_bytes = get_le32(pb); /* tag size */ + if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) { + av_log(s, AV_LOG_ERROR, "Tag size is way too big\n"); + return; + } + + fields = get_le32(pb); /* number of fields */ + if (fields > 65536) { + av_log(s, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields); + return; + } + + val = get_le32(pb); /* flags */ + if (val & APE_TAG_FLAG_IS_HEADER) { + av_log(s, AV_LOG_ERROR, "APE Tag is a header\n"); + return; + } + + url_fseek(pb, file_size - tag_bytes, SEEK_SET); + + for (i=0; i<fields; i++) + if (ape_tag_read_field(s) < 0) break; + +#if ENABLE_DEBUG + av_log(s, AV_LOG_DEBUG, "\nAPE Tags:\n\n"); + av_log(s, AV_LOG_DEBUG, "title = %s\n", s->title); + av_log(s, AV_LOG_DEBUG, "author = %s\n", s->author); + av_log(s, AV_LOG_DEBUG, "copyright = %s\n", s->copyright); + av_log(s, AV_LOG_DEBUG, "comment = %s\n", s->comment); + av_log(s, AV_LOG_DEBUG, "album = %s\n", s->album); + av_log(s, AV_LOG_DEBUG, "year = %d\n", s->year); + av_log(s, AV_LOG_DEBUG, "track = %d\n", s->track); + av_log(s, AV_LOG_DEBUG, "genre = %s\n", s->genre); +#endif +} |