Several chunked formats (AIFF, IFF,DSF) store ID3 metadata within an 'ID3 '
chunk tag. If such chunks are stored sequentially, it is possible for the
ID3v2 parser to confuse the chunk tag for the ID3 magic number. e.g.
[1st chunk tag ('ID3 ') | chunk size] [ID3 magic number | metadata ...]
[2nd chunk tag ('ID3 ') | chunk size] [ID3 magic number | metadata ...]
Fixes ticket #3530.
Signed-off-by: Peter Ross <pross@xvid.org>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
tags/n2.3
| @@ -237,7 +237,7 @@ static int aiff_read_header(AVFormatContext *s) | |||||
| break; | break; | ||||
| case MKTAG('I', 'D', '3', ' '): | case MKTAG('I', 'D', '3', ' '): | ||||
| position = avio_tell(pb); | position = avio_tell(pb); | ||||
| ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); | |||||
| ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); | |||||
| if (id3v2_extra_meta) | if (id3v2_extra_meta) | ||||
| if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) { | if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) { | ||||
| ff_id3v2_free_extra_meta(&id3v2_extra_meta); | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | ||||
| @@ -268,7 +268,7 @@ static void get_id3_tag(AVFormatContext *s, int len) | |||||
| { | { | ||||
| ID3v2ExtraMeta *id3v2_extra_meta = NULL; | ID3v2ExtraMeta *id3v2_extra_meta = NULL; | ||||
| ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); | |||||
| ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, len); | |||||
| if (id3v2_extra_meta) | if (id3v2_extra_meta) | ||||
| ff_id3v2_parse_apic(s, &id3v2_extra_meta); | ff_id3v2_parse_apic(s, &id3v2_extra_meta); | ||||
| ff_id3v2_free_extra_meta(&id3v2_extra_meta); | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | ||||
| @@ -52,7 +52,7 @@ static void read_id3(AVFormatContext *s, uint64_t id3pos) | |||||
| if (avio_seek(s->pb, id3pos, SEEK_SET) < 0) | if (avio_seek(s->pb, id3pos, SEEK_SET) < 0) | ||||
| return; | return; | ||||
| ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); | |||||
| ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0); | |||||
| if (id3v2_extra_meta) | if (id3v2_extra_meta) | ||||
| ff_id3v2_parse_apic(s, &id3v2_extra_meta); | ff_id3v2_parse_apic(s, &id3v2_extra_meta); | ||||
| ff_id3v2_free_extra_meta(&id3v2_extra_meta); | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | ||||
| @@ -880,16 +880,25 @@ error: | |||||
| static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata, | static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata, | ||||
| AVFormatContext *s, const char *magic, | AVFormatContext *s, const char *magic, | ||||
| ID3v2ExtraMeta **extra_meta) | |||||
| ID3v2ExtraMeta **extra_meta, int64_t max_search_size) | |||||
| { | { | ||||
| int len, ret; | int len, ret; | ||||
| uint8_t buf[ID3v2_HEADER_SIZE]; | uint8_t buf[ID3v2_HEADER_SIZE]; | ||||
| int found_header; | int found_header; | ||||
| int64_t off; | |||||
| int64_t start, off; | |||||
| if (max_search_size && max_search_size < ID3v2_HEADER_SIZE) | |||||
| return; | |||||
| start = avio_tell(pb); | |||||
| do { | do { | ||||
| /* save the current offset in case there's nothing to read/skip */ | /* save the current offset in case there's nothing to read/skip */ | ||||
| off = avio_tell(pb); | off = avio_tell(pb); | ||||
| if (max_search_size && off - start >= max_search_size - ID3v2_HEADER_SIZE) { | |||||
| avio_seek(pb, off, SEEK_SET); | |||||
| break; | |||||
| } | |||||
| ret = avio_read(pb, buf, ID3v2_HEADER_SIZE); | ret = avio_read(pb, buf, ID3v2_HEADER_SIZE); | ||||
| if (ret != ID3v2_HEADER_SIZE) { | if (ret != ID3v2_HEADER_SIZE) { | ||||
| avio_seek(pb, off, SEEK_SET); | avio_seek(pb, off, SEEK_SET); | ||||
| @@ -916,13 +925,13 @@ static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata, | |||||
| void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, | void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, | ||||
| const char *magic, ID3v2ExtraMeta **extra_meta) | const char *magic, ID3v2ExtraMeta **extra_meta) | ||||
| { | { | ||||
| id3v2_read_internal(pb, metadata, NULL, magic, extra_meta); | |||||
| id3v2_read_internal(pb, metadata, NULL, magic, extra_meta, 0); | |||||
| } | } | ||||
| void ff_id3v2_read(AVFormatContext *s, const char *magic, | void ff_id3v2_read(AVFormatContext *s, const char *magic, | ||||
| ID3v2ExtraMeta **extra_meta) | |||||
| ID3v2ExtraMeta **extra_meta, unsigned int max_search_size) | |||||
| { | { | ||||
| id3v2_read_internal(s->pb, &s->metadata, s, magic, extra_meta); | |||||
| id3v2_read_internal(s->pb, &s->metadata, s, magic, extra_meta, max_search_size); | |||||
| } | } | ||||
| void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) | void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) | ||||
| @@ -112,8 +112,10 @@ void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, const char *ma | |||||
| * | * | ||||
| * @param extra_meta If not NULL, extra metadata is parsed into a list of | * @param extra_meta If not NULL, extra metadata is parsed into a list of | ||||
| * ID3v2ExtraMeta structs and *extra_meta points to the head of the list | * ID3v2ExtraMeta structs and *extra_meta points to the head of the list | ||||
| * @param[opt] max_search_search restrict ID3 magic number search (bytes from start) | |||||
| */ | */ | ||||
| void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta); | |||||
| void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta, | |||||
| unsigned int max_search_size); | |||||
| /** | /** | ||||
| * Initialize an ID3v2 tag. | * Initialize an ID3v2 tag. | ||||
| @@ -295,7 +295,7 @@ static int oma_read_header(AVFormatContext *s) | |||||
| ID3v2ExtraMeta *extra_meta = NULL; | ID3v2ExtraMeta *extra_meta = NULL; | ||||
| OMAContext *oc = s->priv_data; | OMAContext *oc = s->priv_data; | ||||
| ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta); | |||||
| ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta, 0); | |||||
| ret = avio_read(s->pb, buf, EA3_HEADER_SIZE); | ret = avio_read(s->pb, buf, EA3_HEADER_SIZE); | ||||
| if (ret < EA3_HEADER_SIZE) | if (ret < EA3_HEADER_SIZE) | ||||
| return -1; | return -1; | ||||
| @@ -574,7 +574,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, | |||||
| /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */ | /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */ | ||||
| if (s->pb) | if (s->pb) | ||||
| ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); | |||||
| ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0); | |||||
| if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) | if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) | ||||
| if ((ret = s->iformat->read_header(s)) < 0) | if ((ret = s->iformat->read_header(s)) < 0) | ||||