Libav
|
00001 /* 00002 * APE tag handling 00003 * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org> 00004 * based upon libdemac from Dave Chapman. 00005 * 00006 * This file is part of FFmpeg. 00007 * 00008 * FFmpeg is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * FFmpeg is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with FFmpeg; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 #include "libavutil/intreadwrite.h" 00024 #include "avformat.h" 00025 #include "apetag.h" 00026 00027 #define ENABLE_DEBUG 0 00028 00029 #define APE_TAG_VERSION 2000 00030 #define APE_TAG_FOOTER_BYTES 32 00031 #define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31) 00032 #define APE_TAG_FLAG_IS_HEADER (1 << 29) 00033 00034 static int ape_tag_read_field(AVFormatContext *s) 00035 { 00036 ByteIOContext *pb = s->pb; 00037 uint8_t key[1024], *value; 00038 uint32_t size, flags; 00039 int i, c; 00040 00041 size = get_le32(pb); /* field size */ 00042 flags = get_le32(pb); /* field flags */ 00043 for (i = 0; i < sizeof(key) - 1; i++) { 00044 c = get_byte(pb); 00045 if (c < 0x20 || c > 0x7E) 00046 break; 00047 else 00048 key[i] = c; 00049 } 00050 key[i] = 0; 00051 if (c != 0) { 00052 av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key); 00053 return -1; 00054 } 00055 if (size >= UINT_MAX) 00056 return -1; 00057 value = av_malloc(size+1); 00058 if (!value) 00059 return AVERROR(ENOMEM); 00060 get_buffer(pb, value, size); 00061 value[size] = 0; 00062 av_metadata_set2(&s->metadata, key, value, AV_METADATA_DONT_STRDUP_VAL); 00063 return 0; 00064 } 00065 00066 void ff_ape_parse_tag(AVFormatContext *s) 00067 { 00068 ByteIOContext *pb = s->pb; 00069 int file_size = url_fsize(pb); 00070 uint32_t val, fields, tag_bytes; 00071 uint8_t buf[8]; 00072 int i; 00073 00074 if (file_size < APE_TAG_FOOTER_BYTES) 00075 return; 00076 00077 url_fseek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET); 00078 00079 get_buffer(pb, buf, 8); /* APETAGEX */ 00080 if (strncmp(buf, "APETAGEX", 8)) { 00081 return; 00082 } 00083 00084 val = get_le32(pb); /* APE tag version */ 00085 if (val > APE_TAG_VERSION) { 00086 av_log(s, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION); 00087 return; 00088 } 00089 00090 tag_bytes = get_le32(pb); /* tag size */ 00091 if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) { 00092 av_log(s, AV_LOG_ERROR, "Tag size is way too big\n"); 00093 return; 00094 } 00095 00096 fields = get_le32(pb); /* number of fields */ 00097 if (fields > 65536) { 00098 av_log(s, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields); 00099 return; 00100 } 00101 00102 val = get_le32(pb); /* flags */ 00103 if (val & APE_TAG_FLAG_IS_HEADER) { 00104 av_log(s, AV_LOG_ERROR, "APE Tag is a header\n"); 00105 return; 00106 } 00107 00108 url_fseek(pb, file_size - tag_bytes, SEEK_SET); 00109 00110 for (i=0; i<fields; i++) 00111 if (ape_tag_read_field(s) < 0) break; 00112 }