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 >
INT32_MAX
-
FF_INPUT_BUFFER_PADDING_SIZE
) {
55
av_log
(s,
AV_LOG_ERROR
,
"APE tag size too large.\n"
);
56
return
AVERROR_INVALIDDATA
;
57
}
58
value =
av_malloc
(size+1);
59
if
(!value)
60
return
AVERROR
(ENOMEM);
61
avio_read
(pb, value, size);
62
value[
size
] = 0;
63
av_dict_set
(&s->
metadata
, key, value,
AV_DICT_DONT_STRDUP_VAL
);
64
return
0;
65
}
66
67
void
ff_ape_parse_tag
(
AVFormatContext
*s)
68
{
69
AVIOContext
*pb = s->
pb
;
70
int64_t file_size =
avio_size
(pb);
71
uint32_t val, fields, tag_bytes;
72
uint8_t buf[8];
73
int
i;
74
75
if
(file_size <
APE_TAG_FOOTER_BYTES
)
76
return
;
77
78
avio_seek
(pb, file_size -
APE_TAG_FOOTER_BYTES
, SEEK_SET);
79
80
avio_read
(pb, buf, 8);
/* APETAGEX */
81
if
(strncmp(buf,
"APETAGEX"
, 8)) {
82
return
;
83
}
84
85
val =
avio_rl32
(pb);
/* APE tag version */
86
if
(val >
APE_TAG_VERSION
) {
87
av_log
(s,
AV_LOG_ERROR
,
"Unsupported tag version. (>=%d)\n"
,
APE_TAG_VERSION
);
88
return
;
89
}
90
91
tag_bytes =
avio_rl32
(pb);
/* tag size */
92
if
(tag_bytes -
APE_TAG_FOOTER_BYTES
> (1024 * 1024 * 16)) {
93
av_log
(s,
AV_LOG_ERROR
,
"Tag size is way too big\n"
);
94
return
;
95
}
96
97
fields =
avio_rl32
(pb);
/* number of fields */
98
if
(fields > 65536) {
99
av_log
(s,
AV_LOG_ERROR
,
"Too many tag fields (%d)\n"
, fields);
100
return
;
101
}
102
103
val =
avio_rl32
(pb);
/* flags */
104
if
(val &
APE_TAG_FLAG_IS_HEADER
) {
105
av_log
(s,
AV_LOG_ERROR
,
"APE Tag is a header\n"
);
106
return
;
107
}
108
109
avio_seek
(pb, file_size - tag_bytes, SEEK_SET);
110
111
for
(i=0; i<fields; i++)
112
if
(
ape_tag_read_field
(s) < 0)
break
;
113
}