|
@@ -26,6 +26,12 @@ |
|
|
* http://id3.org/Developer_Information |
|
|
* http://id3.org/Developer_Information |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
#include "config.h" |
|
|
|
|
|
|
|
|
|
|
|
#if CONFIG_ZLIB |
|
|
|
|
|
#include <zlib.h> |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
#include "id3v2.h" |
|
|
#include "id3v2.h" |
|
|
#include "id3v1.h" |
|
|
#include "id3v1.h" |
|
|
#include "libavutil/avstring.h" |
|
|
#include "libavutil/avstring.h" |
|
@@ -432,6 +438,8 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t |
|
|
unsigned char *buffer = NULL; |
|
|
unsigned char *buffer = NULL; |
|
|
int buffer_size = 0; |
|
|
int buffer_size = 0; |
|
|
const ID3v2EMFunc *extra_func; |
|
|
const ID3v2EMFunc *extra_func; |
|
|
|
|
|
unsigned char *compressed_buffer = NULL; |
|
|
|
|
|
int compressed_buffer_size = 0; |
|
|
|
|
|
|
|
|
switch (version) { |
|
|
switch (version) { |
|
|
case 2: |
|
|
case 2: |
|
@@ -476,6 +484,9 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t |
|
|
while (len >= taghdrlen) { |
|
|
while (len >= taghdrlen) { |
|
|
unsigned int tflags = 0; |
|
|
unsigned int tflags = 0; |
|
|
int tunsync = 0; |
|
|
int tunsync = 0; |
|
|
|
|
|
int tcomp = 0; |
|
|
|
|
|
int tencr = 0; |
|
|
|
|
|
int dlen; |
|
|
|
|
|
|
|
|
if (isv34) { |
|
|
if (isv34) { |
|
|
avio_read(s->pb, tag, 4); |
|
|
avio_read(s->pb, tag, 4); |
|
@@ -509,24 +520,65 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t |
|
|
if (tflags & ID3v2_FLAG_DATALEN) { |
|
|
if (tflags & ID3v2_FLAG_DATALEN) { |
|
|
if (tlen < 4) |
|
|
if (tlen < 4) |
|
|
break; |
|
|
break; |
|
|
avio_rb32(s->pb); |
|
|
|
|
|
|
|
|
dlen = avio_rb32(s->pb); |
|
|
tlen -= 4; |
|
|
tlen -= 4; |
|
|
} |
|
|
|
|
|
|
|
|
} else |
|
|
|
|
|
dlen = tlen; |
|
|
|
|
|
|
|
|
|
|
|
tcomp = tflags & ID3v2_FLAG_COMPRESSION; |
|
|
|
|
|
tencr = tflags & ID3v2_FLAG_ENCRYPTION; |
|
|
|
|
|
|
|
|
|
|
|
/* skip encrypted tags and, if no zlib, compressed tags */ |
|
|
|
|
|
if (tencr || (!CONFIG_ZLIB && tcomp)) { |
|
|
|
|
|
const char *type; |
|
|
|
|
|
if (!tcomp) |
|
|
|
|
|
type = "encrypted"; |
|
|
|
|
|
else if (!tencr) |
|
|
|
|
|
type = "compressed"; |
|
|
|
|
|
else |
|
|
|
|
|
type = "encrypted and compressed"; |
|
|
|
|
|
|
|
|
if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) { |
|
|
|
|
|
av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag); |
|
|
|
|
|
|
|
|
av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag); |
|
|
avio_skip(s->pb, tlen); |
|
|
avio_skip(s->pb, tlen); |
|
|
/* check for text tag or supported special meta tag */ |
|
|
/* check for text tag or supported special meta tag */ |
|
|
} else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)))) { |
|
|
} else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)))) { |
|
|
if (unsync || tunsync) { |
|
|
|
|
|
|
|
|
if (unsync || tunsync || tcomp) { |
|
|
int i, j; |
|
|
int i, j; |
|
|
av_fast_malloc(&buffer, &buffer_size, tlen); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
av_fast_malloc(&buffer, &buffer_size, dlen); |
|
|
if (!buffer) { |
|
|
if (!buffer) { |
|
|
av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen); |
|
|
|
|
|
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", dlen); |
|
|
goto seek; |
|
|
goto seek; |
|
|
} |
|
|
} |
|
|
for (i = 0, j = 0; i < tlen; i++, j++) { |
|
|
|
|
|
buffer[j] = avio_r8(s->pb); |
|
|
|
|
|
|
|
|
#if CONFIG_ZLIB |
|
|
|
|
|
if (tcomp) { |
|
|
|
|
|
int n, err; |
|
|
|
|
|
|
|
|
|
|
|
av_log(s, AV_LOG_DEBUG, "Compresssed frame %s tlen=%d dlen=%d\n", tag, tlen, dlen); |
|
|
|
|
|
|
|
|
|
|
|
av_fast_malloc(&compressed_buffer, &compressed_buffer_size, tlen); |
|
|
|
|
|
if (!compressed_buffer) { |
|
|
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen); |
|
|
|
|
|
goto seek; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
n = avio_read(s->pb, compressed_buffer, tlen); |
|
|
|
|
|
if (n < 0) { |
|
|
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n"); |
|
|
|
|
|
goto seek; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = uncompress(buffer, &dlen, compressed_buffer, n); |
|
|
|
|
|
if (err != Z_OK) { |
|
|
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err); |
|
|
|
|
|
goto seek; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0, j = 0; i < dlen; i++, j++) { |
|
|
|
|
|
if (!tcomp) |
|
|
|
|
|
buffer[j] = avio_r8(s->pb); |
|
|
if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) { |
|
|
if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) { |
|
|
/* Unsynchronised byte, skip it */ |
|
|
/* Unsynchronised byte, skip it */ |
|
|
j--; |
|
|
j--; |
|
@@ -564,6 +616,7 @@ seek: |
|
|
av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); |
|
|
av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); |
|
|
avio_seek(s->pb, end, SEEK_SET); |
|
|
avio_seek(s->pb, end, SEEK_SET); |
|
|
av_free(buffer); |
|
|
av_free(buffer); |
|
|
|
|
|
av_free(compressed_buffer); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|