3 * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
4 * based upon libdemac from Dave Chapman.
6 * This file is part of FFmpeg.
8 * FFmpeg 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.
13 * FFmpeg 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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/dict.h"
28 #include "avio_internal.h"
32 #define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
33 #define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
34 #define APE_TAG_FLAG_IS_HEADER (1 << 29)
35 #define APE_TAG_FLAG_IS_BINARY (1 << 1)
37 static int ape_tag_read_field(AVFormatContext
*s
)
39 AVIOContext
*pb
= s
->pb
;
40 uint8_t key
[1024], *value
;
44 size
= avio_rl32(pb
); /* field size */
45 flags
= avio_rl32(pb
); /* field flags */
46 for (i
= 0; i
< sizeof(key
) - 1; i
++) {
48 if (c
< 0x20 || c
> 0x7E)
55 av_log(s
, AV_LOG_WARNING
, "Invalid APE tag key '%s'.\n", key
);
58 if (size
> INT32_MAX
- FF_INPUT_BUFFER_PADDING_SIZE
) {
59 av_log(s
, AV_LOG_ERROR
, "APE tag size too large.\n");
60 return AVERROR_INVALIDDATA
;
62 if (flags
& APE_TAG_FLAG_IS_BINARY
) {
63 uint8_t filename
[1024];
65 AVStream
*st
= avformat_new_stream(s
, NULL
);
67 return AVERROR(ENOMEM
);
69 size
-= avio_get_str(pb
, size
, filename
, sizeof(filename
));
71 av_log(s
, AV_LOG_WARNING
, "Skipping binary tag '%s'.\n", key
);
75 av_dict_set(&st
->metadata
, key
, filename
, 0);
77 if ((id
= ff_guess_image2_codec(filename
)) != AV_CODEC_ID_NONE
) {
81 ret
= av_get_packet(s
->pb
, &pkt
, size
);
83 av_log(s
, AV_LOG_ERROR
, "Error reading cover art.\n");
87 st
->disposition
|= AV_DISPOSITION_ATTACHED_PIC
;
88 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
89 st
->codec
->codec_id
= id
;
91 st
->attached_pic
= pkt
;
92 st
->attached_pic
.stream_index
= st
->index
;
93 st
->attached_pic
.flags
|= AV_PKT_FLAG_KEY
;
95 if (ff_get_extradata(st
->codec
, s
->pb
, size
) < 0)
96 return AVERROR(ENOMEM
);
97 st
->codec
->codec_type
= AVMEDIA_TYPE_ATTACHMENT
;
100 value
= av_malloc(size
+1);
102 return AVERROR(ENOMEM
);
103 c
= avio_read(pb
, value
, size
);
109 av_dict_set(&s
->metadata
, key
, value
, AV_DICT_DONT_STRDUP_VAL
);
114 int64_t ff_ape_parse_tag(AVFormatContext
*s
)
116 AVIOContext
*pb
= s
->pb
;
117 int64_t file_size
= avio_size(pb
);
118 uint32_t val
, fields
, tag_bytes
;
123 if (file_size
< APE_TAG_FOOTER_BYTES
)
126 avio_seek(pb
, file_size
- APE_TAG_FOOTER_BYTES
, SEEK_SET
);
128 avio_read(pb
, buf
, 8); /* APETAGEX */
129 if (strncmp(buf
, APE_TAG_PREAMBLE
, 8)) {
133 val
= avio_rl32(pb
); /* APE tag version */
134 if (val
> APE_TAG_VERSION
) {
135 av_log(s
, AV_LOG_ERROR
, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION
);
139 tag_bytes
= avio_rl32(pb
); /* tag size */
140 if (tag_bytes
- APE_TAG_FOOTER_BYTES
> (1024 * 1024 * 16)) {
141 av_log(s
, AV_LOG_ERROR
, "Tag size is way too big\n");
145 if (tag_bytes
> file_size
- APE_TAG_FOOTER_BYTES
) {
146 av_log(s
, AV_LOG_ERROR
, "Invalid tag size %"PRIu32
".\n", tag_bytes
);
149 tag_start
= file_size
- tag_bytes
- APE_TAG_FOOTER_BYTES
;
151 fields
= avio_rl32(pb
); /* number of fields */
152 if (fields
> 65536) {
153 av_log(s
, AV_LOG_ERROR
, "Too many tag fields (%"PRIu32
")\n", fields
);
157 val
= avio_rl32(pb
); /* flags */
158 if (val
& APE_TAG_FLAG_IS_HEADER
) {
159 av_log(s
, AV_LOG_ERROR
, "APE Tag is a header\n");
163 avio_seek(pb
, file_size
- tag_bytes
, SEEK_SET
);
165 for (i
=0; i
<fields
; i
++)
166 if (ape_tag_read_field(s
) < 0) break;
171 static int string_is_ascii(const uint8_t *str
)
173 while (*str
&& *str
>= 0x20 && *str
<= 0x7e ) str
++;
177 int ff_ape_write_tag(AVFormatContext
*s
)
179 AVDictionaryEntry
*e
= NULL
;
180 int size
, ret
, count
= 0;
181 AVIOContext
*dyn_bc
= NULL
;
182 uint8_t *dyn_buf
= NULL
;
184 if ((ret
= avio_open_dyn_buf(&dyn_bc
)) < 0)
188 avio_wl32(dyn_bc
, APE_TAG_FLAG_CONTAINS_HEADER
| APE_TAG_FLAG_CONTAINS_FOOTER
|
189 APE_TAG_FLAG_IS_HEADER
);
190 ffio_fill(dyn_bc
, 0, 8); // reserved
192 while ((e
= av_dict_get(s
->metadata
, "", e
, AV_DICT_IGNORE_SUFFIX
))) {
195 if (!string_is_ascii(e
->key
)) {
196 av_log(s
, AV_LOG_WARNING
, "Non ASCII keys are not allowed\n");
200 val_len
= strlen(e
->value
);
201 avio_wl32(dyn_bc
, val_len
); // value length
202 avio_wl32(dyn_bc
, 0); // item flags
203 avio_put_str(dyn_bc
, e
->key
); // key
204 avio_write(dyn_bc
, e
->value
, val_len
); // value
210 size
= avio_close_dyn_buf(dyn_bc
, &dyn_buf
);
216 avio_write(s
->pb
, "APETAGEX", 8); // id
217 avio_wl32(s
->pb
, APE_TAG_VERSION
); // version
218 avio_wl32(s
->pb
, size
);
219 avio_wl32(s
->pb
, count
);
221 avio_write(s
->pb
, dyn_buf
, size
- 20);
224 avio_write(s
->pb
, "APETAGEX", 8); // id
225 avio_wl32(s
->pb
, APE_TAG_VERSION
); // version
226 avio_wl32(s
->pb
, size
); // size
227 avio_wl32(s
->pb
, count
); // tag count
230 avio_wl32(s
->pb
, APE_TAG_FLAG_CONTAINS_HEADER
| APE_TAG_FLAG_CONTAINS_FOOTER
);
231 ffio_fill(s
->pb
, 0, 8); // reserved
234 if (dyn_bc
&& !dyn_buf
)
235 avio_close_dyn_buf(dyn_bc
, &dyn_buf
);