Index: patched-ffmpeg-mt/libavformat/mov.c |
=================================================================== |
--- patched-ffmpeg-mt/libavformat/mov.c (revision 41250) |
+++ patched-ffmpeg-mt/libavformat/mov.c (working copy) |
@@ -93,6 +93,43 @@ |
return 0; |
} |
+static const uint32_t mac_to_unicode[128] = { |
+ 0x00C4,0x00C5,0x00C7,0x00C9,0x00D1,0x00D6,0x00DC,0x00E1, |
+ 0x00E0,0x00E2,0x00E4,0x00E3,0x00E5,0x00E7,0x00E9,0x00E8, |
+ 0x00EA,0x00EB,0x00ED,0x00EC,0x00EE,0x00EF,0x00F1,0x00F3, |
+ 0x00F2,0x00F4,0x00F6,0x00F5,0x00FA,0x00F9,0x00FB,0x00FC, |
+ 0x2020,0x00B0,0x00A2,0x00A3,0x00A7,0x2022,0x00B6,0x00DF, |
+ 0x00AE,0x00A9,0x2122,0x00B4,0x00A8,0x2260,0x00C6,0x00D8, |
+ 0x221E,0x00B1,0x2264,0x2265,0x00A5,0x00B5,0x2202,0x2211, |
+ 0x220F,0x03C0,0x222B,0x00AA,0x00BA,0x03A9,0x00E6,0x00F8, |
+ 0x00BF,0x00A1,0x00AC,0x221A,0x0192,0x2248,0x2206,0x00AB, |
+ 0x00BB,0x2026,0x00A0,0x00C0,0x00C3,0x00D5,0x0152,0x0153, |
+ 0x2013,0x2014,0x201C,0x201D,0x2018,0x2019,0x00F7,0x25CA, |
+ 0x00FF,0x0178,0x2044,0x20AC,0x2039,0x203A,0xFB01,0xFB02, |
+ 0x2021,0x00B7,0x201A,0x201E,0x2030,0x00C2,0x00CA,0x00C1, |
+ 0x00CB,0x00C8,0x00CD,0x00CE,0x00CF,0x00CC,0x00D3,0x00D4, |
+ 0xF8FF,0x00D2,0x00DA,0x00DB,0x00D9,0x0131,0x02C6,0x02DC, |
+ 0x00AF,0x02D8,0x02D9,0x02DA,0x00B8,0x02DD,0x02DB,0x02C7, |
+}; |
+ |
+static int mov_read_mac_string(MOVContext *c, ByteIOContext *pb, int len, |
+ char *dst, int dstlen) |
+{ |
+ char *p = dst; |
+ char *end = dst+dstlen-1; |
+ int i; |
+ |
+ for (i = 0; i < len; i++) { |
+ uint8_t t, c = get_byte(pb); |
+ if (c < 0x80 && p < end) |
+ *p++ = c; |
+ else |
+ PUT_UTF8(mac_to_unicode[c-0x80], t, if (p < end) *p++ = t;); |
+ } |
+ *p = 0; |
+ return p - dst; |
+} |
+ |
static int mov_read_udta_string(MOVContext *c, ByteIOContext *pb, MOVAtom atom) |
{ |
#ifdef MOV_EXPORT_ALL_METADATA |
@@ -100,7 +137,8 @@ |
#endif |
char str[1024], key2[16], language[4] = {0}; |
const char *key = NULL; |
- uint16_t str_size; |
+ uint16_t str_size, langcode = 0; |
+ uint32_t data_type = 0; |
int (*parse)(MOVContext*, ByteIOContext*, unsigned) = NULL; |
switch (atom.type) { |
@@ -130,14 +168,15 @@ |
int data_size = get_be32(pb); |
int tag = get_le32(pb); |
if (tag == MKTAG('d','a','t','a')) { |
- get_be32(pb); // type |
+ data_type = get_be32(pb); // type |
get_be32(pb); // unknown |
str_size = data_size - 16; |
atom.size -= 16; |
} else return 0; |
} else if (atom.size > 4 && key && !c->itunes_metadata) { |
str_size = get_be16(pb); // string length |
- ff_mov_lang_to_iso639(get_be16(pb), language); |
+ langcode = get_be16(pb); |
+ ff_mov_lang_to_iso639(langcode, language); |
atom.size -= 4; |
} else |
str_size = atom.size; |
@@ -159,8 +198,12 @@ |
if (parse) |
parse(c, pb, str_size); |
else { |
- get_buffer(pb, str, str_size); |
- str[str_size] = 0; |
+ if (data_type == 3 || (data_type == 0 && langcode < 0x800)) { // MAC Encoded |
+ mov_read_mac_string(c, pb, str_size, str, sizeof(str)); |
+ } else { |
+ get_buffer(pb, str, str_size); |
+ str[str_size] = 0; |
+ } |
av_metadata_set(&c->fc->metadata, key, str); |
if (*language && strcmp(language, "und")) { |
snprintf(key2, sizeof(key2), "%s-%s", key, language); |
@@ -398,7 +441,7 @@ |
return len; |
} |
-int mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag) |
+static int mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag) |
{ |
int len; |
*tag = get_byte(pb); |
@@ -913,8 +956,7 @@ |
(format >> 24) & 0xff, st->codec->codec_type); |
if(st->codec->codec_type==CODEC_TYPE_VIDEO) { |
- uint8_t codec_name[32]; |
- unsigned int color_depth; |
+ unsigned int color_depth, len; |
int color_greyscale; |
st->codec->codec_id = id; |
@@ -932,19 +974,15 @@ |
get_be32(pb); /* data size, always 0 */ |
get_be16(pb); /* frames per samples */ |
- get_buffer(pb, codec_name, 32); /* codec name, pascal string */ |
- if (codec_name[0] <= 31) { |
- int i; |
- int pos = 0; |
- for (i = 0; i < codec_name[0] && pos < sizeof(st->codec->codec_name) - 3; i++) { |
- uint8_t tmp; |
- PUT_UTF8(codec_name[i+1], tmp, st->codec->codec_name[pos++] = tmp;) |
- } |
- st->codec->codec_name[pos] = 0; |
- /* codec_tag YV12 triggers an UV swap in rawdec.c */ |
- if (!memcmp(st->codec->codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25)) |
- st->codec->codec_tag=MKTAG('I', '4', '2', '0'); |
- } |
+ len = get_byte(pb); /* codec name, pascal string */ |
+ if (len > 31) |
+ len = 31; |
+ mov_read_mac_string(c, pb, len, st->codec->codec_name, 32); |
+ if (len < 31) |
+ url_fskip(pb, 31 - len); |
+ /* codec_tag YV12 triggers an UV swap in rawdec.c */ |
+ if (!memcmp(st->codec->codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25)) |
+ st->codec->codec_tag=MKTAG('I', '4', '2', '0'); |
st->codec->bits_per_coded_sample = get_be16(pb); /* depth */ |
st->codec->color_table_id = get_be16(pb); /* colortable id */ |
@@ -1464,6 +1502,13 @@ |
current_dts -= sc->dts_shift; |
+ if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries)) |
+ return; |
+ st->index_entries = av_malloc(sc->sample_count*sizeof(*st->index_entries)); |
+ if (!st->index_entries) |
+ return; |
+ st->index_entries_allocated_size = sc->sample_count*sizeof(*st->index_entries); |
+ |
for (i = 0; i < sc->chunk_count; i++) { |
current_offset = sc->chunk_offsets[i]; |
if (stsc_index + 1 < sc->stsc_count && |
@@ -1490,8 +1535,12 @@ |
sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample]; |
if(sc->pseudo_stream_id == -1 || |
sc->stsc_data[stsc_index].id - 1 == sc->pseudo_stream_id) { |
- av_add_index_entry(st, current_offset, current_dts, sample_size, distance, |
- keyframe ? AVINDEX_KEYFRAME : 0); |
+ AVIndexEntry *e = &st->index_entries[st->nb_index_entries++]; |
+ e->pos = current_offset; |
+ e->timestamp = current_dts; |
+ e->size = sample_size; |
+ e->min_distance = distance; |
+ e->flags = keyframe ? AVINDEX_KEYFRAME : 0; |
dprintf(mov->fc, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", " |
"size %d, distance %d, keyframe %d\n", st->index, current_sample, |
current_offset, current_dts, sample_size, distance, keyframe); |
@@ -1512,21 +1561,52 @@ |
if (st->duration > 0) |
st->codec->bit_rate = stream_size*8*sc->time_scale/st->duration; |
} else { |
+ unsigned chunk_samples, total = 0; |
+ |
+ // compute total chunk count |
+ for (i = 0; i < sc->stsc_count; i++) { |
+ unsigned count, chunk_count; |
+ |
+ chunk_samples = sc->stsc_data[i].count; |
+ if (sc->samples_per_frame && chunk_samples % sc->samples_per_frame) { |
+ av_log(mov->fc, AV_LOG_ERROR, "error unaligned chunk\n"); |
+ return; |
+ } |
+ |
+ if (sc->samples_per_frame >= 160) { // gsm |
+ count = chunk_samples / sc->samples_per_frame; |
+ } else if (sc->samples_per_frame > 1) { |
+ unsigned samples = (1024/sc->samples_per_frame)*sc->samples_per_frame; |
+ count = (chunk_samples+samples-1) / samples; |
+ } else { |
+ count = (chunk_samples+1023) / 1024; |
+ } |
+ |
+ if (i < sc->stsc_count - 1) |
+ chunk_count = sc->stsc_data[i+1].first - sc->stsc_data[i].first; |
+ else |
+ chunk_count = sc->chunk_count - (sc->stsc_data[i].first - 1); |
+ total += chunk_count * count; |
+ } |
+ |
+ dprintf(mov->fc, "chunk count %d\n", total); |
+ if (total >= UINT_MAX / sizeof(*st->index_entries)) |
+ return; |
+ st->index_entries = av_malloc(total*sizeof(*st->index_entries)); |
+ if (!st->index_entries) |
+ return; |
+ st->index_entries_allocated_size = total*sizeof(*st->index_entries); |
+ |
+ // populate index |
for (i = 0; i < sc->chunk_count; i++) { |
- unsigned chunk_samples; |
- |
current_offset = sc->chunk_offsets[i]; |
if (stsc_index + 1 < sc->stsc_count && |
i + 1 == sc->stsc_data[stsc_index + 1].first) |
stsc_index++; |
chunk_samples = sc->stsc_data[stsc_index].count; |
- if (sc->samples_per_frame && chunk_samples % sc->samples_per_frame) { |
- av_log(mov->fc, AV_LOG_ERROR, "error unaligned chunk\n"); |
- return; |
- } |
- |
while (chunk_samples > 0) { |
+ AVIndexEntry *e; |
unsigned size, samples; |
if (sc->samples_per_frame >= 160) { // gsm |
@@ -1543,7 +1623,16 @@ |
} |
} |
- av_add_index_entry(st, current_offset, current_dts, size, 0, AVINDEX_KEYFRAME); |
+ if (st->nb_index_entries >= total) { |
+ av_log(mov->fc, AV_LOG_ERROR, "wrong chunk count %d\n", total); |
+ return; |
+ } |
+ e = &st->index_entries[st->nb_index_entries++]; |
+ e->pos = current_offset; |
+ e->timestamp = current_dts; |
+ e->size = size; |
+ e->min_distance = 0; |
+ e->flags = AVINDEX_KEYFRAME; |
dprintf(mov->fc, "AVIndex stream %d, chunk %d, offset %"PRIx64", dts %"PRId64", " |
"size %d, duration %d\n", st->index, i, current_offset, current_dts, |
size, samples); |
@@ -1558,11 +1647,8 @@ |
static int mov_open_dref(ByteIOContext **pb, char *src, MOVDref *ref) |
{ |
- /* try absolute path */ |
- if (!url_fopen(pb, ref->path, URL_RDONLY)) |
- return 0; |
- |
- /* try relative path */ |
+ /* try relative path, we do not try the absolute because it can leak information about our |
+ system to an attacker */ |
if (ref->nlvl_to > 0 && ref->nlvl_from > 0) { |
char filename[1024]; |
char *src_path; |
@@ -1585,7 +1671,7 @@ |
} |
/* compose filename if next level down to target was found */ |
- if (i == ref->nlvl_to - 1) { |
+ if (i == ref->nlvl_to - 1 && src_path - src < sizeof(filename)) { |
memcpy(filename, src, src_path - src); |
filename[src_path - src] = 0; |