|
|
@ -135,37 +135,40 @@ static void mpc8_get_chunk_header(AVIOContext *pb, int *tag, int64_t *size) |
|
|
|
*size += pos; |
|
|
|
*size += pos; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) |
|
|
|
static int mpc8_parse_seektable(AVFormatContext *s, int64_t off) |
|
|
|
{ |
|
|
|
{ |
|
|
|
MPCContext *c = s->priv_data; |
|
|
|
MPCContext *c = s->priv_data; |
|
|
|
int tag; |
|
|
|
int tag; |
|
|
|
int64_t size, pos, ppos[2]; |
|
|
|
int64_t size, pos, ppos[2]; |
|
|
|
uint8_t *buf; |
|
|
|
uint8_t *buf; |
|
|
|
int i, t, seekd, ret; |
|
|
|
int i, t, seekd, ret; |
|
|
|
|
|
|
|
int64_t ret64; |
|
|
|
GetBitContext gb; |
|
|
|
GetBitContext gb; |
|
|
|
|
|
|
|
|
|
|
|
if (s->nb_streams == 0) { |
|
|
|
if (s->nb_streams == 0) { |
|
|
|
av_log(s, AV_LOG_ERROR, "No stream added before parsing seek table\n"); |
|
|
|
av_log(s, AV_LOG_ERROR, "No stream added before parsing seek table\n"); |
|
|
|
return; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
avio_seek(s->pb, off, SEEK_SET); |
|
|
|
ret64 = avio_seek(s->pb, off, SEEK_SET); |
|
|
|
|
|
|
|
if (ret64 < 0) |
|
|
|
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
mpc8_get_chunk_header(s->pb, &tag, &size); |
|
|
|
mpc8_get_chunk_header(s->pb, &tag, &size); |
|
|
|
if(tag != TAG_SEEKTABLE){ |
|
|
|
if(tag != TAG_SEEKTABLE || avio_feof(s->pb)){ |
|
|
|
av_log(s, AV_LOG_ERROR, "No seek table at given position\n"); |
|
|
|
av_log(s, AV_LOG_ERROR, "No seek table at given position\n"); |
|
|
|
return; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
if (size > INT_MAX/10 || size<=0) { |
|
|
|
if (size > INT_MAX/10 || size<=0) { |
|
|
|
av_log(s, AV_LOG_ERROR, "Bad seek table size\n"); |
|
|
|
av_log(s, AV_LOG_ERROR, "Bad seek table size\n"); |
|
|
|
return; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
if(!(buf = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE))) |
|
|
|
if(!(buf = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE))) |
|
|
|
return; |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
ret = avio_read(s->pb, buf, size); |
|
|
|
ret = avio_read(s->pb, buf, size); |
|
|
|
if (ret != size) { |
|
|
|
if (ret != size) { |
|
|
|
av_log(s, AV_LOG_ERROR, "seek table truncated\n"); |
|
|
|
av_log(s, AV_LOG_ERROR, "seek table truncated\n"); |
|
|
|
av_free(buf); |
|
|
|
av_free(buf); |
|
|
|
return; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
memset(buf+size, 0, AV_INPUT_BUFFER_PADDING_SIZE); |
|
|
|
memset(buf+size, 0, AV_INPUT_BUFFER_PADDING_SIZE); |
|
|
|
|
|
|
|
|
|
|
@ -174,14 +177,14 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) |
|
|
|
if(size > UINT_MAX/4 || size > c->samples/1152){ |
|
|
|
if(size > UINT_MAX/4 || size > c->samples/1152){ |
|
|
|
av_log(s, AV_LOG_ERROR, "Seek table is too big\n"); |
|
|
|
av_log(s, AV_LOG_ERROR, "Seek table is too big\n"); |
|
|
|
av_free(buf); |
|
|
|
av_free(buf); |
|
|
|
return; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
seekd = get_bits(&gb, 4); |
|
|
|
seekd = get_bits(&gb, 4); |
|
|
|
for(i = 0; i < 2; i++){ |
|
|
|
for(i = 0; i < 2; i++){ |
|
|
|
pos = gb_get_v(&gb); |
|
|
|
pos = gb_get_v(&gb); |
|
|
|
if (av_sat_add64(pos, c->header_pos) != pos + (uint64_t)c->header_pos) { |
|
|
|
if (av_sat_add64(pos, c->header_pos) != pos + (uint64_t)c->header_pos) { |
|
|
|
av_free(buf); |
|
|
|
av_free(buf); |
|
|
|
return; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pos += c->header_pos; |
|
|
|
pos += c->header_pos; |
|
|
@ -191,7 +194,7 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) |
|
|
|
for(; i < size; i++){ |
|
|
|
for(; i < size; i++){ |
|
|
|
if (get_bits_left(&gb) < 13) { |
|
|
|
if (get_bits_left(&gb) < 13) { |
|
|
|
av_free(buf); |
|
|
|
av_free(buf); |
|
|
|
return; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
t = get_unary(&gb, 1, 33) << 12; |
|
|
|
t = get_unary(&gb, 1, 33) << 12; |
|
|
|
t += get_bits(&gb, 12); |
|
|
|
t += get_bits(&gb, 12); |
|
|
@ -203,26 +206,31 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) |
|
|
|
ppos[0] = pos; |
|
|
|
ppos[0] = pos; |
|
|
|
} |
|
|
|
} |
|
|
|
av_free(buf); |
|
|
|
av_free(buf); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void mpc8_handle_chunk(AVFormatContext *s, int tag, int64_t chunk_pos, int64_t size) |
|
|
|
static int mpc8_handle_chunk(AVFormatContext *s, int tag, int64_t chunk_pos, int64_t size) |
|
|
|
{ |
|
|
|
{ |
|
|
|
AVIOContext *pb = s->pb; |
|
|
|
AVIOContext *pb = s->pb; |
|
|
|
int64_t pos, off; |
|
|
|
int64_t pos, off; |
|
|
|
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
switch(tag){ |
|
|
|
switch(tag){ |
|
|
|
case TAG_SEEKTBLOFF: |
|
|
|
case TAG_SEEKTBLOFF: |
|
|
|
pos = avio_tell(pb); |
|
|
|
pos = avio_tell(pb); |
|
|
|
off = ffio_read_varlen(pb); |
|
|
|
off = ffio_read_varlen(pb); |
|
|
|
if (pos > INT64_MAX - size || off < 0 || off > INT64_MAX - chunk_pos) |
|
|
|
if (pos > INT64_MAX - size || off < 0 || off > INT64_MAX - chunk_pos) |
|
|
|
return; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
pos += size; |
|
|
|
pos += size; |
|
|
|
mpc8_parse_seektable(s, chunk_pos + off); |
|
|
|
ret = mpc8_parse_seektable(s, chunk_pos + off); |
|
|
|
|
|
|
|
if (ret < 0) |
|
|
|
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
avio_seek(pb, pos, SEEK_SET); |
|
|
|
avio_seek(pb, pos, SEEK_SET); |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
avio_skip(pb, size); |
|
|
|
avio_skip(pb, size); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int mpc8_read_header(AVFormatContext *s) |
|
|
|
static int mpc8_read_header(AVFormatContext *s) |
|
|
@ -249,7 +257,9 @@ static int mpc8_read_header(AVFormatContext *s) |
|
|
|
} |
|
|
|
} |
|
|
|
if(tag == TAG_STREAMHDR) |
|
|
|
if(tag == TAG_STREAMHDR) |
|
|
|
break; |
|
|
|
break; |
|
|
|
mpc8_handle_chunk(s, tag, pos, size); |
|
|
|
ret = mpc8_handle_chunk(s, tag, pos, size); |
|
|
|
|
|
|
|
if (ret < 0) |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
if(tag != TAG_STREAMHDR){ |
|
|
|
if(tag != TAG_STREAMHDR){ |
|
|
|
av_log(s, AV_LOG_ERROR, "Stream header not found\n"); |
|
|
|
av_log(s, AV_LOG_ERROR, "Stream header not found\n"); |
|
|
|