1/* 2 * APE tag handling 3 * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org> 4 * based upon libdemac from Dave Chapman. 5 * 6 * This file is part of Libav. 7 * 8 * Libav is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * Libav is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with Libav; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include "libavutil/intreadwrite.h" 24#include "libavutil/dict.h" 25#include "avformat.h" 26#include "apetag.h" 27 28#define APE_TAG_VERSION 2000 29#define APE_TAG_FOOTER_BYTES 32 30#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31) 31#define APE_TAG_FLAG_IS_HEADER (1 << 29) 32 33static int ape_tag_read_field(AVFormatContext *s) 34{ 35 AVIOContext *pb = s->pb; 36 uint8_t key[1024], *value; 37 uint32_t size; 38 int i, c; 39 40 size = avio_rl32(pb); /* field size */ 41 avio_skip(pb, 4); /* field flags */ 42 for (i = 0; i < sizeof(key) - 1; i++) { 43 c = avio_r8(pb); 44 if (c < 0x20 || c > 0x7E) 45 break; 46 else 47 key[i] = c; 48 } 49 key[i] = 0; 50 if (c != 0) { 51 av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key); 52 return -1; 53 } 54 if (size >= UINT_MAX) 55 return -1; 56 value = av_malloc(size+1); 57 if (!value) 58 return AVERROR(ENOMEM); 59 avio_read(pb, value, size); 60 value[size] = 0; 61 av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL); 62 return 0; 63} 64 65void ff_ape_parse_tag(AVFormatContext *s) 66{ 67 AVIOContext *pb = s->pb; 68 int64_t file_size = avio_size(pb); 69 uint32_t val, fields, tag_bytes; 70 uint8_t buf[8]; 71 int i; 72 73 if (file_size < APE_TAG_FOOTER_BYTES) 74 return; 75 76 avio_seek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET); 77 78 avio_read(pb, buf, 8); /* APETAGEX */ 79 if (strncmp(buf, "APETAGEX", 8)) { 80 return; 81 } 82 83 val = avio_rl32(pb); /* APE tag version */ 84 if (val > APE_TAG_VERSION) { 85 av_log(s, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION); 86 return; 87 } 88 89 tag_bytes = avio_rl32(pb); /* tag size */ 90 if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) { 91 av_log(s, AV_LOG_ERROR, "Tag size is way too big\n"); 92 return; 93 } 94 95 fields = avio_rl32(pb); /* number of fields */ 96 if (fields > 65536) { 97 av_log(s, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields); 98 return; 99 } 100 101 val = avio_rl32(pb); /* flags */ 102 if (val & APE_TAG_FLAG_IS_HEADER) { 103 av_log(s, AV_LOG_ERROR, "APE Tag is a header\n"); 104 return; 105 } 106 107 avio_seek(pb, file_size - tag_bytes, SEEK_SET); 108 109 for (i=0; i<fields; i++) 110 if (ape_tag_read_field(s) < 0) break; 111} 112