Libav 0.7.1
|
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 Libav. 00007 * 00008 * Libav 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 * Libav 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 Libav; 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 "libavutil/dict.h" 00025 #include "avformat.h" 00026 #include "apetag.h" 00027 00028 #define APE_TAG_VERSION 2000 00029 #define APE_TAG_FOOTER_BYTES 32 00030 #define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31) 00031 #define APE_TAG_FLAG_IS_HEADER (1 << 29) 00032 00033 static int ape_tag_read_field(AVFormatContext *s) 00034 { 00035 AVIOContext *pb = s->pb; 00036 uint8_t key[1024], *value; 00037 uint32_t size; 00038 int i, c; 00039 00040 size = avio_rl32(pb); /* field size */ 00041 avio_skip(pb, 4); /* field flags */ 00042 for (i = 0; i < sizeof(key) - 1; i++) { 00043 c = avio_r8(pb); 00044 if (c < 0x20 || c > 0x7E) 00045 break; 00046 else 00047 key[i] = c; 00048 } 00049 key[i] = 0; 00050 if (c != 0) { 00051 av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key); 00052 return -1; 00053 } 00054 if (size >= UINT_MAX) 00055 return -1; 00056 value = av_malloc(size+1); 00057 if (!value) 00058 return AVERROR(ENOMEM); 00059 avio_read(pb, value, size); 00060 value[size] = 0; 00061 av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL); 00062 return 0; 00063 } 00064 00065 void ff_ape_parse_tag(AVFormatContext *s) 00066 { 00067 AVIOContext *pb = s->pb; 00068 int file_size = avio_size(pb); 00069 uint32_t val, fields, tag_bytes; 00070 uint8_t buf[8]; 00071 int i; 00072 00073 if (file_size < APE_TAG_FOOTER_BYTES) 00074 return; 00075 00076 avio_seek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET); 00077 00078 avio_read(pb, buf, 8); /* APETAGEX */ 00079 if (strncmp(buf, "APETAGEX", 8)) { 00080 return; 00081 } 00082 00083 val = avio_rl32(pb); /* APE tag version */ 00084 if (val > APE_TAG_VERSION) { 00085 av_log(s, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION); 00086 return; 00087 } 00088 00089 tag_bytes = avio_rl32(pb); /* tag size */ 00090 if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) { 00091 av_log(s, AV_LOG_ERROR, "Tag size is way too big\n"); 00092 return; 00093 } 00094 00095 fields = avio_rl32(pb); /* number of fields */ 00096 if (fields > 65536) { 00097 av_log(s, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields); 00098 return; 00099 } 00100 00101 val = avio_rl32(pb); /* flags */ 00102 if (val & APE_TAG_FLAG_IS_HEADER) { 00103 av_log(s, AV_LOG_ERROR, "APE Tag is a header\n"); 00104 return; 00105 } 00106 00107 avio_seek(pb, file_size - tag_bytes, SEEK_SET); 00108 00109 for (i=0; i<fields; i++) 00110 if (ape_tag_read_field(s) < 0) break; 00111 }