Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
apetag.c
Go to the documentation of this file.
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
33
static
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
65
void
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
}