I've uploaded xine-lib 1.1.14-4 to testing-proposed-updates. This is required due to a versioned dependency on libjack0 which would be generated were it uploaded to unstable (to which I've uploaded 1.1.16.1-1). Most of the changes since 1.1.14-3 are security-related, and one fixes a possible FTBFS. A complete diff is attached; if you want to view the changes individually, see http://hg.debian.org/hg/xine-lib/pkg/xine-lib-deb-lenny. (The packaging VCS URL in debian/control is wrong, but for this upload that doesn't matter since the information is all there in the "wrong" place.) -- | Darren Salt | linux or ds at | nr. Ashington, | Toon | RISC OS, Linux | youmustbejoking,demon,co,uk | Northumberland | Army | + Output less CO2 => avoid boiling weather. TIME IS RUNNING OUT *FAST*. Fatal error in Reality (invalid parameter '-utopia')
diff --git a/debian/changelog b/debian/changelog --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,27 @@ xine-lib (1.1.14-3) unstable; urgency=hi +xine-lib (1.1.14-4) testing-proposed-updates; urgency=high + + * Security fixes backported from 1.1.16: + - CVE-2008-5234: Heap overflow in Quicktime atom parsing. + (Closes: #508313) + - CVE-2008-5236: Multiple buffer overflows. (Closes: #509521) + - CVE-2008-5237: Multiple integer overflows. (Closes: #509265) + - CVE-2008-5239: Unchecked or incompletely-checked read function results. + (Closes: #509353) + - CVE-2008-5240 & CVE-2008-5242: Unchecked memory allocations using + untrusted values. (Closes: #509352, #507165) + - CVE-2008-5241: Integer underflow in qt compressed atom handling. + (Closes: #509008) + - CVE-2008-5243: Buffer indexing using untrusted or unchecked values. + - Avoid segfault on invalid track type in Matroska files. + - Avoid underflow (compressed atoms) in the Qt demuxer. + * Other backports from 1.1.16: + - Fix a couple of potential hangs, both of which can be triggered by an + MMS stream in which the demuxer cannot find a valid GUID. + - Avoid possible hangs with xxmc, reported to happen with openchrome. + * Fix FTBFS on i386 (with amd64 kernel). (Closes: #510662) + + -- Darren Salt <linux@youmustbejoking.demon.co.uk> Wed, 07 Jan 2009 18:57:29 +0000 + xine-lib (1.1.14-3) unstable; urgency=high * More security fixes from upstream hg: diff --git a/debian/rules b/debian/rules --- a/debian/rules +++ b/debian/rules @@ -44,6 +44,8 @@ endif # set configure flags here CONFIGURE_FLAGS := \ + --build $(DEB_BUILD_GNU_TYPE) \ + --host $(DEB_HOST_GNU_TYPE) \ --prefix=/usr \ --mandir=\$${prefix}/share/man \ --with-external-libmad \ diff --git a/misc/cdda_server.c b/misc/cdda_server.c --- a/misc/cdda_server.c +++ b/misc/cdda_server.c @@ -480,6 +480,12 @@ static int process_commands( int socket sscanf(cmd,"%*s %d %d", &start_frame, &num_frames); + if (num_frames > INT_MAX / CD_RAW_FRAME_SIZE) + { + printf ("fatal error: integer overflow\n"); + exit (1); + } + n = num_frames * CD_RAW_FRAME_SIZE; buf = malloc( n ); if( !buf ) @@ -556,6 +562,11 @@ static int process_commands( int socket char *buf; sscanf(cmd,"%*s %d %d", &blocks, &flags); + if (blocks > INT_MAX / DVD_BLOCK_SIZE) + { + printf ("fatal error: integer overflow\n"); + exit (1); + } n = blocks * DVD_BLOCK_SIZE; buf = malloc( n ); diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -247,6 +247,8 @@ static void ff_audio_decode_data (audio_ if (extradata + data_len > this->size) break; /* abort early - extradata length is bad */ + if (extradata > INT_MAX - data_len) + break;/*integer overflow*/ this->context->extradata_size = data_len; this->context->extradata = malloc(this->context->extradata_size + @@ -365,6 +367,11 @@ static void ff_audio_decode_data (audio_ /* dispatch the decoded audio */ out = 0; while (out < decode_buffer_size) { + int stream_status = xine_get_status(this->stream); + + if (stream_status == XINE_STATUS_QUIT || stream_status == XINE_STATUS_STOP) + return; + audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); if (audio_buffer->mem_size == 0) { diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -605,6 +605,10 @@ static void ff_convert_frame(ff_video_de su = this->av_frame->data[1]; sv = this->av_frame->data[2]; + /* Some segfaults & heap corruption have been observed with img->height, + * so we use this->bih.biHeight instead (which is the displayed height) + */ + if (this->context->pix_fmt == PIX_FMT_YUV410P) { yuv9_to_yv12( @@ -625,7 +629,7 @@ static void ff_convert_frame(ff_video_de img->pitches[2], /* width x height */ img->width, - img->height); + this->bih.biHeight); } else if (this->context->pix_fmt == PIX_FMT_YUV411P) { @@ -647,7 +651,7 @@ static void ff_convert_frame(ff_video_de img->pitches[2], /* width x height */ img->width, - img->height); + this->bih.biHeight); } else if (this->context->pix_fmt == PIX_FMT_RGBA32) { @@ -655,7 +659,7 @@ static void ff_convert_frame(ff_video_de uint32_t *argb_pixels; uint32_t argb; - for(y = 0; y < img->height; y++) { + for(y = 0; y < this->bih.biHeight; y++) { argb_pixels = (uint32_t *)sy; for(x = 0; x < img->width; x++) { uint8_t r, g, b; @@ -683,7 +687,7 @@ static void ff_convert_frame(ff_video_de uint8_t *src; uint16_t pixel16; - for(y = 0; y < img->height; y++) { + for(y = 0; y < this->bih.biHeight; y++) { src = sy; for(x = 0; x < img->width; x++) { uint8_t r, g, b; @@ -712,7 +716,7 @@ static void ff_convert_frame(ff_video_de uint8_t *src; uint16_t pixel16; - for(y = 0; y < img->height; y++) { + for(y = 0; y < this->bih.biHeight; y++) { src = sy; for(x = 0; x < img->width; x++) { uint8_t r, g, b; @@ -740,7 +744,7 @@ static void ff_convert_frame(ff_video_de int x, plane_ptr = 0; uint8_t *src; - for(y = 0; y < img->height; y++) { + for(y = 0; y < this->bih.biHeight; y++) { src = sy; for(x = 0; x < img->width; x++) { uint8_t r, g, b; @@ -764,7 +768,7 @@ static void ff_convert_frame(ff_video_de int x, plane_ptr = 0; uint8_t *src; - for(y = 0; y < img->height; y++) { + for(y = 0; y < this->bih.biHeight; y++) { src = sy; for(x = 0; x < img->width; x++) { uint8_t r, g, b; @@ -807,7 +811,7 @@ static void ff_convert_frame(ff_video_de v_palette[x] = COMPUTE_V(r, g, b); } - for(y = 0; y < img->height; y++) { + for(y = 0; y < this->bih.biHeight; y++) { src = sy; for(x = 0; x < img->width; x++) { pixel = *src++; @@ -824,7 +828,7 @@ static void ff_convert_frame(ff_video_de } else { - for (y=0; y<img->height; y++) { + for (y = 0; y < this->bih.biHeight; y++) { xine_fast_memcpy (dy, sy, img->width); dy += img->pitches[0]; @@ -832,7 +836,7 @@ static void ff_convert_frame(ff_video_de sy += this->av_frame->linesize[0]; } - for (y=0; y<(img->height/2); y++) { + for (y = 0; y < this->bih.biHeight / 2; y++) { if (this->context->pix_fmt != PIX_FMT_YUV444P) { diff --git a/src/demuxers/demux_aac.c b/src/demuxers/demux_aac.c --- a/src/demuxers/demux_aac.c +++ b/src/demuxers/demux_aac.c @@ -176,7 +176,7 @@ static int demux_aac_send_chunk(demux_pl buf->extra_info->input_time = (8*current_pos) / (bitrate/1000); bytes_read = this->input->read(this->input, buf->content, buf->max_size); - if (bytes_read == 0) { + if (bytes_read <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; diff --git a/src/demuxers/demux_ac3.c b/src/demuxers/demux_ac3.c --- a/src/demuxers/demux_ac3.c +++ b/src/demuxers/demux_ac3.c @@ -308,13 +308,7 @@ static int demux_ac3_send_chunk (demux_p this->frame_size); } - if (buf->size == 0) { - buf->free_buffer(buf); - this->status = DEMUX_FINISHED; - return this->status; - } - - if (buf->size == 0) { + if (buf->size <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c --- a/src/demuxers/demux_asf.c +++ b/src/demuxers/demux_asf.c @@ -738,7 +738,10 @@ static void asf_send_buffer_nodefrag (de bufsize = stream->fifo->buffer_pool_buf_size; buf = stream->fifo->buffer_pool_alloc (stream->fifo); - this->input->read (this->input, buf->content, bufsize); + if (this->input->read (this->input, buf->content, bufsize) != bufsize) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: input buffer starved\n"); + return ; + } lprintf ("data: %d %d %d %d\n", buf->content[0], buf->content[1], buf->content[2], buf->content[3]); @@ -817,7 +820,10 @@ static void asf_send_buffer_defrag (demu if( stream->frag_offset + frag_len > DEFRAG_BUFSIZE ) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: buffer overflow on defrag!\n"); } else { - this->input->read (this->input, &stream->buffer[stream->frag_offset], frag_len); + if (this->input->read (this->input, &stream->buffer[stream->frag_offset], frag_len) != frag_len) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: input buffer starved\n"); + return ; + } stream->frag_offset += frag_len; } diff --git a/src/demuxers/demux_dts.c b/src/demuxers/demux_dts.c --- a/src/demuxers/demux_dts.c +++ b/src/demuxers/demux_dts.c @@ -269,7 +269,7 @@ static int demux_dts_send_chunk (demux_p this->frame_size); } - if (buf->size == 0) { + if (buf->size <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c --- a/src/demuxers/demux_matroska.c +++ b/src/demuxers/demux_matroska.c @@ -607,6 +607,8 @@ static void init_codec_xiph(demux_matros int i; uint8_t *data; + if (track->codec_private_len < 3) + return; nb_lace = track->codec_private[0]; if (nb_lace != 2) return; @@ -614,6 +616,8 @@ static void init_codec_xiph(demux_matros frame[0] = track->codec_private[1]; frame[1] = track->codec_private[2]; frame[2] = track->codec_private_len - frame[0] - frame[1] - 3; + if (frame[2] < 0) + return; data = track->codec_private + 3; for (i = 0; i < 3; i++) { @@ -1179,7 +1183,12 @@ static int parse_track_entry(demux_matro break; case MATROSKA_ID_TR_CODECPRIVATE: { - char *codec_private = malloc (elem.len); + char *codec_private; + if (elem.len >= 0x80000000) + return 0; + codec_private = malloc (elem.len); + if (! codec_private) + return 0; lprintf("CodecPrivate\n"); if (!ebml_read_binary(ebml, &elem, codec_private)) { free(codec_private); @@ -1283,12 +1292,14 @@ static int parse_track_entry(demux_matro if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_VFW_FOURCC)) { xine_bmiheader *bih; - lprintf("MATROSKA_CODEC_ID_V_VFW_FOURCC\n"); - bih = (xine_bmiheader*)track->codec_private; - _x_bmiheader_le2me(bih); + if (track->codec_private_len >= sizeof(xine_bmiheader)) { + lprintf("MATROSKA_CODEC_ID_V_VFW_FOURCC\n"); + bih = (xine_bmiheader*)track->codec_private; + _x_bmiheader_le2me(bih); - track->buf_type = _x_fourcc_to_buf_video(bih->biCompression); - init_codec = init_codec_video; + track->buf_type = _x_fourcc_to_buf_video(bih->biCompression); + init_codec = init_codec_video; + } } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_UNCOMPRESSED)) { } else if ((!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MPEG4_SP)) || @@ -1297,6 +1308,9 @@ static int parse_track_entry(demux_matro xine_bmiheader *bih; lprintf("MATROSKA_CODEC_ID_V_MPEG4_*\n"); + if (track->codec_private_len > 0x7fffffff - sizeof(xine_bmiheader)) + track->codec_private_len = 0x7fffffff - sizeof(xine_bmiheader); + /* create a bitmap info header struct for MPEG 4 */ bih = malloc(sizeof(xine_bmiheader) + track->codec_private_len); bih->biSize = sizeof(xine_bmiheader) + track->codec_private_len; @@ -1318,6 +1332,9 @@ static int parse_track_entry(demux_matro xine_bmiheader *bih; lprintf("MATROSKA_CODEC_ID_V_MPEG4_AVC\n"); + if (track->codec_private_len > 0x7fffffff - sizeof(xine_bmiheader)) + track->codec_private_len = 0x7fffffff - sizeof(xine_bmiheader); + /* create a bitmap info header struct for h264 */ bih = malloc(sizeof(xine_bmiheader) + track->codec_private_len); bih->biSize = sizeof(xine_bmiheader) + track->codec_private_len; @@ -1394,11 +1411,13 @@ static int parse_track_entry(demux_matro xine_waveformatex *wfh; lprintf("MATROSKA_CODEC_ID_A_ACM\n"); - wfh = (xine_waveformatex*)track->codec_private; - _x_waveformatex_le2me(wfh); + if (track->codec_private_len >= sizeof(xine_waveformatex)) { + wfh = (xine_waveformatex*)track->codec_private; + _x_waveformatex_le2me(wfh); - track->buf_type = _x_formattag_to_buf_audio(wfh->wFormatTag); - init_codec = init_codec_audio; + track->buf_type = _x_formattag_to_buf_audio(wfh->wFormatTag); + init_codec = init_codec_audio; + } } else if (!strncmp(track->codec_id, MATROSKA_CODEC_ID_A_AAC, sizeof(MATROSKA_CODEC_ID_A_AAC) - 1)) { lprintf("MATROSKA_CODEC_ID_A_AAC\n"); @@ -1479,9 +1498,14 @@ static int parse_track_entry(demux_matro break; } - if (init_codec) + if (init_codec) { + if (! track->fifo) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: Error: fifo not set up for track of type type %" PRIu32 "\n", track->track_type); + return 0; + } init_codec(this, track); - + } } } @@ -1807,6 +1831,11 @@ static int read_block_data (demux_matros alloc_block_data(this, len); /* block datas */ + if (! this->block_data) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: memory allocation error\n"); + return 0; + } if (this->input->read(this->input, this->block_data, len) != len) { off_t pos = this->input->get_current_pos(this->input); xprintf(this->stream->xine, XINE_VERBOSITY_LOG, diff --git a/src/demuxers/demux_mng.c b/src/demuxers/demux_mng.c --- a/src/demuxers/demux_mng.c +++ b/src/demuxers/demux_mng.c @@ -104,13 +104,21 @@ static mng_bool mymng_read_stream(mng_ha static mng_bool mymng_read_stream(mng_handle mngh, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread){ demux_mng_t *this = (demux_mng_t*)mng_get_userdata(mngh); - *bytesread = this->input->read(this->input, buffer, size); + off_t n = this->input->read(this->input, buffer, size); + if (n < 0) { + *bytesread = 0; + return MNG_FALSE; + } + *bytesread = n; return MNG_TRUE; } static mng_bool mymng_process_header(mng_handle mngh, mng_uint32 width, mng_uint32 height){ demux_mng_t *this = (demux_mng_t*)mng_get_userdata(mngh); + + if (width > 0x8000 || height > 0x8000) + return MNG_FALSE; this->bih.biWidth = (width + 7) & ~7; this->bih.biHeight = height; diff --git a/src/demuxers/demux_mod.c b/src/demuxers/demux_mod.c --- a/src/demuxers/demux_mod.c +++ b/src/demuxers/demux_mod.c @@ -130,9 +130,16 @@ static int probe_mod_file(demux_mod_t *t /* returns 1 if the MOD file was opened successfully, 0 otherwise */ static int open_mod_file(demux_mod_t *this) { int total_read; + off_t input_length; /* Get size and create buffer */ - this->filesize = this->input->get_length(this->input); + input_length = this->input->get_length(this->input); + /* Avoid potential issues with signed variables and e.g. read() returning -1 */ + if (input_length > 0x7FFFFFFF || input_length < 0) { + xine_log(this->stream->xine, XINE_LOG_PLUGIN, "modplug - size overflow\n"); + return 0; + } + this->filesize = input_length; this->buffer = (char *)malloc(this->filesize); if(!this->buffer) { xine_log(this->stream->xine, XINE_LOG_PLUGIN, "modplug - allocation failure\n"); diff --git a/src/demuxers/demux_mpc.c b/src/demuxers/demux_mpc.c --- a/src/demuxers/demux_mpc.c +++ b/src/demuxers/demux_mpc.c @@ -214,7 +214,7 @@ static int demux_mpc_send_chunk(demux_pl /* Read data */ bytes_read = this->input->read(this->input, buf->content, bytes_to_read); - if(bytes_read == 0) { + if(bytes_read <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; diff --git a/src/demuxers/demux_mpeg.c b/src/demuxers/demux_mpeg.c --- a/src/demuxers/demux_mpeg.c +++ b/src/demuxers/demux_mpeg.c @@ -279,6 +279,10 @@ static void parse_mpeg2_packet (demux_mp if((this->dummy_space[0] & 0xE0) == 0x20) { buf = this->input->read_block (this->input, this->video_fifo, len-1); + if (! buf) { + this->status = DEMUX_FINISHED; + return; + } track = (this->dummy_space[0] & 0x1f); @@ -298,6 +302,10 @@ static void parse_mpeg2_packet (demux_mp int spu_id = this->dummy_space[1] & 0x03; buf = this->input->read_block (this->input, this->video_fifo, len-1); + if (! buf) { + this->status = DEMUX_FINISHED; + return; + } buf->type = BUF_SPU_SVCD + spu_id; buf->pts = pts; @@ -318,6 +326,10 @@ static void parse_mpeg2_packet (demux_mp if((this->dummy_space[0] & 0xfc) == 0x00) { buf = this->input->read_block (this->input, this->video_fifo, len-1); + if (! buf) { + this->status = DEMUX_FINISHED; + return; + } buf->type = BUF_SPU_CVD + (this->dummy_space[0] & 0x03); buf->pts = pts; @@ -376,6 +388,10 @@ static void parse_mpeg2_packet (demux_mp i = this->input->read (this->input, this->dummy_space+1, 6); buf = this->input->read_block (this->input, this->video_fifo, len-7); + if (! buf) { + this->status = DEMUX_FINISHED; + return; + } buf->type = BUF_AUDIO_LPCM_BE + track; buf->decoder_flags |= BUF_FLAG_SPECIAL; @@ -920,7 +936,7 @@ static void demux_mpeg_resync (demux_mpe if (pos == len) { len = this->input->read(this->input, dummy_buf, sizeof(dummy_buf)); pos = 0; - if (len == 0) { + if (len <= 0) { this->status = DEMUX_FINISHED; break; } diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c --- a/src/demuxers/demux_mpeg_block.c +++ b/src/demuxers/demux_mpeg_block.c @@ -1190,14 +1190,14 @@ static int demux_mpeg_detect_blocksize(d input_plugin_t *input) { input->seek(input, 2048, SEEK_SET); - if (!input->read(input, this->scratch, 4)) + if (input->read(input, this->scratch, 4) != 4) return 0; if (this->scratch[0] || this->scratch[1] || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) { input->seek(input, 2324, SEEK_SET); - if (!input->read(input, this->scratch, 4)) + if (input->read(input, this->scratch, 4) != 4) return 0; if (this->scratch[0] || this->scratch[1] || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) @@ -1417,7 +1417,7 @@ static demux_plugin_t *open_plugin (demu } input->seek(input, 0, SEEK_SET); - if (input->read(input, this->scratch, this->blocksize)) { + if (input->read(input, this->scratch, this->blocksize) == this->blocksize) { lprintf("open_plugin:read worked\n"); if (this->scratch[0] || this->scratch[1] diff --git a/src/demuxers/demux_mpeg_pes.c b/src/demuxers/demux_mpeg_pes.c --- a/src/demuxers/demux_mpeg_pes.c +++ b/src/demuxers/demux_mpeg_pes.c @@ -1687,7 +1687,7 @@ static demux_plugin_t *open_plugin (demu if (((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) ) { input->seek(input, 0, SEEK_SET); - if (input->read(input, (char *)this->scratch, 6)) { + if (input->read(input, (char *)this->scratch, 6) == 6) { lprintf("open_plugin:read worked\n"); if (this->scratch[0] || this->scratch[1] diff --git a/src/demuxers/demux_nsf.c b/src/demuxers/demux_nsf.c --- a/src/demuxers/demux_nsf.c +++ b/src/demuxers/demux_nsf.c @@ -128,7 +128,7 @@ static int demux_nsf_send_chunk(demux_pl buf->type = BUF_AUDIO_NSF; bytes_read = this->input->read(this->input, buf->content, buf->max_size); - if (bytes_read == 0) { + if (bytes_read <= 0) { /* the file has been completely loaded, free the buffer and start * sending control buffers */ buf->free_buffer(buf); diff --git a/src/demuxers/demux_ogg.c b/src/demuxers/demux_ogg.c --- a/src/demuxers/demux_ogg.c +++ b/src/demuxers/demux_ogg.c @@ -237,7 +237,7 @@ static int read_ogg_packet (demux_ogg_t while (ogg_sync_pageout(&this->oy,&this->og)!=1) { buffer = ogg_sync_buffer(&this->oy, CHUNKSIZE); bytes = this->input->read(this->input, buffer, CHUNKSIZE); - if (bytes == 0) { + if (bytes <= 0) { if (total == 0) { lprintf("read_ogg_packet read nothing\n"); return 0; diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -738,6 +738,8 @@ static void parse_meta_atom(qt_info *inf if (current_atom == ART_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->artist = xine_xmalloc(string_size); if (info->artist) { strncpy(info->artist, &meta_atom[i + 20], string_size - 1); @@ -745,6 +747,8 @@ static void parse_meta_atom(qt_info *inf } } else if (current_atom == NAM_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->name = xine_xmalloc(string_size); if (info->name) { strncpy(info->name, &meta_atom[i + 20], string_size - 1); @@ -752,6 +756,8 @@ static void parse_meta_atom(qt_info *inf } } else if (current_atom == ALB_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->album = xine_xmalloc(string_size); if (info->album) { strncpy(info->album, &meta_atom[i + 20], string_size - 1); @@ -759,6 +765,8 @@ static void parse_meta_atom(qt_info *inf } } else if (current_atom == GEN_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->genre = xine_xmalloc(string_size); if (info->genre) { strncpy(info->genre, &meta_atom[i + 20], string_size - 1); @@ -766,6 +774,8 @@ static void parse_meta_atom(qt_info *inf } } else if (current_atom == TOO_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->comment = xine_xmalloc(string_size); if (info->comment) { strncpy(info->comment, &meta_atom[i + 20], string_size - 1); @@ -773,6 +783,8 @@ static void parse_meta_atom(qt_info *inf } } else if (current_atom == WRT_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->composer = xine_xmalloc(string_size); if (info->composer) { strncpy(info->composer, &meta_atom[i + 20], string_size - 1); @@ -780,6 +792,8 @@ static void parse_meta_atom(qt_info *inf } } else if (current_atom == DAY_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->year = xine_xmalloc(string_size); if (info->year) { strncpy(info->year, &meta_atom[i + 20], string_size - 1); @@ -947,6 +961,10 @@ static qt_error parse_trak_atom (qt_trak /* allocate space for each of the properties unions */ trak->stsd_atoms_count = _X_BE_32(&trak_atom[i + 8]); + if (trak->stsd_atoms_count <= 0) { + last_error = QT_HEADER_TROUBLE; + goto free_trak; + } trak->stsd_atoms = calloc(trak->stsd_atoms_count, sizeof(properties_t)); if (!trak->stsd_atoms) { last_error = QT_NO_MEMORY; @@ -958,6 +976,10 @@ static qt_error parse_trak_atom (qt_trak for (k = 0; k < trak->stsd_atoms_count; k++) { current_stsd_atom_size = _X_BE_32(&trak_atom[atom_pos - 4]); + if (current_stsd_atom_size < 4) { + last_error = QT_HEADER_TROUBLE; + goto free_trak; + } if (trak->type == MEDIA_VIDEO) { @@ -1575,13 +1597,16 @@ static qt_error parse_reference_atom (re qt_atom current_atom; unsigned int current_atom_size; + if (ref_atom_size >= 0x80000000) + return QT_NOT_A_VALID_FILE; + /* initialize reference atom */ ref->url = NULL; ref->data_rate = 0; ref->qtim_version = 0; /* traverse through the atom looking for the key atoms */ - for (i = ATOM_PREAMBLE_SIZE; i < ref_atom_size - 4; i++) { + for (i = ATOM_PREAMBLE_SIZE; i + 4 < ref_atom_size; i++) { current_atom_size = _X_BE_32(&ref_atom[i - 4]); current_atom = _X_BE_32(&ref_atom[i]); @@ -1590,7 +1615,7 @@ static qt_error parse_reference_atom (re size_t string_size = _X_BE_32(&ref_atom[i + 12]); size_t url_offset = 0; - if (string_size >= current_atom_size || i + string_size >= ref_atom_size) + if (string_size >= current_atom_size || string_size >= ref_atom_size - i) return QT_NOT_A_VALID_FILE; /* if the URL starts with "http://", copy it */ @@ -1598,6 +1623,8 @@ static qt_error parse_reference_atom (re memcmp(&ref_atom[i + 16], "rtsp://", 7) && base_mrl ) url_offset = strlen(base_mrl); + if (url_offset >= 0x80000000) + return QT_NOT_A_VALID_FILE; /* otherwise, append relative URL to base MRL */ string_size += url_offset; @@ -2181,7 +2208,7 @@ static qt_error open_qt_file(qt_info *in } /* check if moov is compressed */ - if (_X_BE_32(&moov_atom[12]) == CMOV_ATOM) { + if (_X_BE_32(&moov_atom[12]) == CMOV_ATOM && moov_atom_size >= 0x28) { info->compressed_header = 1; diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c --- a/src/demuxers/demux_real.c +++ b/src/demuxers/demux_real.c @@ -58,12 +58,10 @@ #include "real_common.h" #define FOURCC_TAG BE_FOURCC -#define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') #define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') #define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') #define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') #define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') -#define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') #define RA_TAG FOURCC_TAG('.', 'r', 'a', 0xfd) #define VIDO_TAG FOURCC_TAG('V', 'I', 'D', 'O') @@ -176,6 +174,18 @@ typedef struct { demux_class_t demux_class; } demux_real_class_t; +static int is_indx_tag(const void *ptr) { + return memcmp(ptr, "INDX", 4) == 0; +} + +static int is_data_tag(const void *ptr) { + return memcmp(ptr, "DATA", 4) == 0; +} + +static int is_rmf_tag(const void *ptr) { + return memcmp(ptr, ".RMF", 4) == 0; +} + static void real_parse_index(demux_real_t *this) { off_t next_index_chunk = this->index_start; @@ -183,8 +193,6 @@ static void real_parse_index(demux_real_ unsigned char index_chunk_header[INDEX_CHUNK_HEADER_SIZE]; unsigned char index_record[INDEX_RECORD_SIZE]; int i; - unsigned int entries, stream_num; - real_index_entry_t **index; while(next_index_chunk) { lprintf("reading index chunk at %"PRIX64"\n", next_index_chunk); @@ -200,70 +208,68 @@ static void real_parse_index(demux_real_ } /* Check chunk is actually an index chunk */ - if(_X_BE_32(&index_chunk_header[0]) == INDX_TAG) { - unsigned short version; + if(!is_indx_tag(&index_chunk_header[0])) { + lprintf("expected index chunk found chunk type: %.4s\n", &index_chunk_header[0]); + break; + } - /* Check version */ - version = _X_BE_16(&index_chunk_header[8]); - if(version != 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: unknown object version in INDX: 0x%04x\n", version); - break; + /* Check version */ + const uint16_t version = _X_BE_16(&index_chunk_header[8]); + if(version != 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: unknown object version in INDX: 0x%04x\n", version); + break; + } + + /* Read data from header */ + const uint32_t entries = _X_BE_32(&index_chunk_header[10]); + const uint16_t stream_num = _X_BE_16(&index_chunk_header[14]); + next_index_chunk = _X_BE_32(&index_chunk_header[16]); + + /* Find which stream this index is for */ + real_index_entry_t **index = NULL; + for(i = 0; i < this->num_video_streams; i++) { + if(stream_num == this->video_streams[i].mdpr->stream_number) { + index = &this->video_streams[i].index; + this->video_streams[i].index_entries = entries; + lprintf("found index chunk for video stream with num %d\n", stream_num); + break; } + } - /* Read data from header */ - entries = _X_BE_32(&index_chunk_header[10]); - stream_num = _X_BE_16(&index_chunk_header[14]); - next_index_chunk = _X_BE_32(&index_chunk_header[16]); + if(!index) { + for(i = 0; i < this->num_audio_streams; i++) { + if(stream_num == this->audio_streams[i].mdpr->stream_number) { + index = &this->audio_streams[i].index; + this->audio_streams[i].index_entries = entries; + lprintf("found index chunk for audio stream with num %d\n", stream_num); + break; + } + } + } - /* Find which stream this index is for */ - index = NULL; - for(i = 0; i < this->num_video_streams; i++) { - if(stream_num == this->video_streams[i].mdpr->stream_number) { - index = &this->video_streams[i].index; - this->video_streams[i].index_entries = entries; - lprintf("found index chunk for video stream with num %d\n", stream_num); - break; - } - } + if(index && entries) + /* Allocate memory for index */ + *index = calloc(entries, sizeof(real_index_entry_t)); + + if(index && entries && *index) { + /* Read index */ + for(i = 0; i < entries; i++) { + if(this->input->read(this->input, index_record, INDEX_RECORD_SIZE) + != INDEX_RECORD_SIZE) { + lprintf("index record not read\n"); + free(*index); + *index = NULL; + break; + } - if(!index) { - for(i = 0; i < this->num_audio_streams; i++) { - if(stream_num == this->audio_streams[i].mdpr->stream_number) { - index = &this->audio_streams[i].index; - this->audio_streams[i].index_entries = entries; - lprintf("found index chunk for audio stream with num %d\n", stream_num); - break; - } - } - } - - if(index && entries) - /* Allocate memory for index */ - *index = calloc(entries, sizeof(real_index_entry_t)); - - if(index && entries && *index) { - /* Read index */ - for(i = 0; i < entries; i++) { - if(this->input->read(this->input, index_record, INDEX_RECORD_SIZE) - != INDEX_RECORD_SIZE) { - lprintf("index record not read\n"); - free(*index); - *index = NULL; - break; - } - - (*index)[i].timestamp = _X_BE_32(&index_record[2]); - (*index)[i].offset = _X_BE_32(&index_record[6]); - (*index)[i].packetno = _X_BE_32(&index_record[10]); - } - } else { - lprintf("unused index chunk with %d entries for stream num %d\n", - entries, stream_num); + (*index)[i].timestamp = _X_BE_32(&index_record[2]); + (*index)[i].offset = _X_BE_32(&index_record[6]); + (*index)[i].packetno = _X_BE_32(&index_record[10]); } } else { - lprintf("expected index chunk found chunk type: %.4s\n", &index_chunk_header[0]); - break; + lprintf("unused index chunk with %d entries for stream num %d\n", + entries, stream_num); } } @@ -324,18 +330,19 @@ static void real_free_mdpr (mdpr_t *mdpr } static void real_parse_audio_specific_data (demux_real_t *this, - real_stream_t * stream, - uint8_t * data, int len) + real_stream_t * stream) { - int coded_frame_size; - int codec_data_length; - int coded_frame_size2; - int subpacket_size; + if (stream->mdpr->type_specific_len < 46) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "demux_real: audio data size smaller than header length!\n"); + return; + } - coded_frame_size = _X_BE_32 (data+24); - codec_data_length = _X_BE_16 (data+40); - coded_frame_size2 = _X_BE_16 (data+42); - subpacket_size = _X_BE_16 (data+44); + uint8_t * data = stream->mdpr->type_specific_data; + const uint32_t coded_frame_size = _X_BE_32 (data+24); + const uint16_t codec_data_length = _X_BE_16 (data+40); + const uint16_t coded_frame_size2 = _X_BE_16 (data+42); + const uint16_t subpacket_size = _X_BE_16 (data+44); stream->sps = subpacket_size; stream->w = coded_frame_size2; @@ -365,15 +372,20 @@ static void real_parse_audio_specific_da "demux_real: error, i don't handle buf type 0x%08x\n", stream->buf_type); } - if (stream->sps) { - stream->frame_size = stream->w / stream->sps * stream->h * stream->sps; - stream->frame_buffer = xine_xmalloc (stream->frame_size); - stream->frame_num_bytes = 0; + /* + * when stream->sps is set it used to do this: + * stream->frame_size = stream->w / stream->sps * stream->h * stream->sps; + * but it looks pointless? the compiler will probably optimise it away, I suppose? + */ + if (stream->w < 32768 && stream->h < 32768) { + stream->frame_size = stream->w * stream->h; + stream->frame_buffer = calloc(stream->frame_size, 1); } else { - stream->frame_size = stream->w * stream->h; - stream->frame_buffer = xine_xmalloc (stream->frame_size); - stream->frame_num_bytes = 0; + stream->frame_size = 0; + stream->frame_buffer = NULL; } + + stream->frame_num_bytes = 0; stream->sub_packet_cnt = 0; if (!stream->frame_buffer) @@ -391,37 +403,35 @@ static void real_parse_headers (demux_re char preamble[PREAMBLE_SIZE]; unsigned int chunk_type = 0; unsigned int chunk_size; - unsigned short version; - unsigned char *chunk_buffer; - int field_size; - int stream_ptr; - unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE]; - unsigned char signature[REAL_SIGNATURE_SIZE]; + + if (INPUT_IS_SEEKABLE(this->input)) + this->input->seek (this->input, 0, SEEK_SET); + + { + uint8_t signature[REAL_SIGNATURE_SIZE]; + if (this->input->read(this->input, signature, REAL_SIGNATURE_SIZE) != + REAL_SIGNATURE_SIZE) { + + lprintf ("signature not read\n"); + this->status = DEMUX_FINISHED; + return; + } + + if ( !is_rmf_tag(signature) ) { + this->status = DEMUX_FINISHED; + lprintf ("signature not found '%.4s'\n", signature); + return; + } + + /* skip to the start of the first chunk and start traversing */ + chunk_size = _X_BE_32(&signature[4]); + } this->data_start = 0; this->data_size = 0; this->num_video_streams = 0; this->num_audio_streams = 0; - if (INPUT_IS_SEEKABLE(this->input)) - this->input->seek (this->input, 0, SEEK_SET); - - if (this->input->read(this->input, signature, REAL_SIGNATURE_SIZE) != - REAL_SIGNATURE_SIZE) { - - lprintf ("signature not read\n"); - this->status = DEMUX_FINISHED; - return; - } - - if (_X_BE_32(signature) != RMF_TAG) { - this->status = DEMUX_FINISHED; - lprintf ("signature not found '%.4s'\n", signature); - return; - } - - /* skip to the start of the first chunk and start traversing */ - chunk_size = _X_BE_32(&signature[4]); this->input->seek(this->input, chunk_size-8, SEEK_CUR); /* iterate through chunks and gather information until the first DATA @@ -442,183 +452,185 @@ static void real_parse_headers (demux_re case PROP_TAG: case MDPR_TAG: case CONT_TAG: + { + if (chunk_size < PREAMBLE_SIZE+1) { + this->status = DEMUX_FINISHED; + return; + } + chunk_size -= PREAMBLE_SIZE; + uint8_t *const chunk_buffer = malloc(chunk_size); + if (! chunk_buffer || + this->input->read(this->input, chunk_buffer, chunk_size) != + chunk_size) { + free (chunk_buffer); + this->status = DEMUX_FINISHED; + return; + } + + uint16_t version = _X_BE_16(&chunk_buffer[0]); - chunk_size -= PREAMBLE_SIZE; - chunk_buffer = malloc(chunk_size); - if (this->input->read(this->input, chunk_buffer, chunk_size) != - chunk_size) { - free (chunk_buffer); - this->status = DEMUX_FINISHED; - return; - } + if (chunk_type == PROP_TAG) { - version = _X_BE_16(&chunk_buffer[0]); + if(version != 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demuxe_real: unknown object version in PROP: 0x%04x\n", version); + free(chunk_buffer); + this->status = DEMUX_FINISHED; + return; + } - if (chunk_type == PROP_TAG) { - - if(version != 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demuxe_real: unknown object version in PROP: 0x%04x\n", version); - free(chunk_buffer); - this->status = DEMUX_FINISHED; - return; - } + this->duration = _X_BE_32(&chunk_buffer[22]); + this->index_start = _X_BE_32(&chunk_buffer[30]); + this->data_start = _X_BE_32(&chunk_buffer[34]); + this->avg_bitrate = _X_BE_32(&chunk_buffer[6]); - this->duration = _X_BE_32(&chunk_buffer[22]); - this->index_start = _X_BE_32(&chunk_buffer[30]); - this->data_start = _X_BE_32(&chunk_buffer[34]); - this->avg_bitrate = _X_BE_32(&chunk_buffer[6]); + lprintf("PROP: duration: %d ms\n", this->duration); + lprintf("PROP: index start: %"PRIX64"\n", this->index_start); + lprintf("PROP: data start: %"PRIX64"\n", this->data_start); + lprintf("PROP: average bit rate: %"PRId64"\n", this->avg_bitrate); - lprintf("PROP: duration: %d ms\n", this->duration); - lprintf("PROP: index start: %"PRIX64"\n", this->index_start); - lprintf("PROP: data start: %"PRIX64"\n", this->data_start); - lprintf("PROP: average bit rate: %"PRId64"\n", this->avg_bitrate); + if (this->avg_bitrate<1) + this->avg_bitrate = 1; - if (this->avg_bitrate<1) - this->avg_bitrate = 1; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, + _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, this->avg_bitrate); - } else if (chunk_type == MDPR_TAG) { + } else if (chunk_type == MDPR_TAG) { + if (version != 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: unknown object version in MDPR: 0x%04x\n", version); + free(chunk_buffer); + continue; + } + + mdpr_t *const mdpr = real_parse_mdpr (chunk_buffer); - mdpr_t *mdpr; - uint32_t fourcc; + lprintf ("parsing type specific data...\n"); + if(!strcmp(mdpr->mime_type, "audio/X-MP3-draft-00")) { + lprintf ("mpeg layer 3 audio detected...\n"); - if (version != 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: unknown object version in MDPR: 0x%04x\n", version); - free(chunk_buffer); - continue; - } - - mdpr = real_parse_mdpr (chunk_buffer); + static const uint32_t fourcc = ME_FOURCC('a', 'd', 'u', 0x55); + this->audio_streams[this->num_audio_streams].fourcc = fourcc; + this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); + this->audio_streams[this->num_audio_streams].index = NULL; + this->audio_streams[this->num_audio_streams].mdpr = mdpr; + this->num_audio_streams++; + } else if(_X_BE_32(mdpr->type_specific_data) == RA_TAG && + mdpr->type_specific_len >= 6) { + if(this->num_audio_streams == MAX_AUDIO_STREAMS) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: maximum number of audio stream exceeded\n"); + goto unknown; + } + + const uint16_t version = _X_BE_16(mdpr->type_specific_data + 4); - lprintf ("parsing type specific data...\n"); - if(!strcmp(mdpr->mime_type, "audio/X-MP3-draft-00")) { - lprintf ("mpeg layer 3 audio detected...\n"); + lprintf("audio version %d detected\n", version); - fourcc = ME_FOURCC('a', 'd', 'u', 0x55); - this->audio_streams[this->num_audio_streams].fourcc = fourcc; - this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); - this->audio_streams[this->num_audio_streams].index = NULL; - this->audio_streams[this->num_audio_streams].mdpr = mdpr; - this->num_audio_streams++; - } else if(_X_BE_32(mdpr->type_specific_data) == RA_TAG) { - int version, len; - - if(this->num_audio_streams == MAX_AUDIO_STREAMS) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: maximum number of audio stream exceeded\n"); - goto unknown; - } - - version = _X_BE_16(mdpr->type_specific_data + 4); - - lprintf("audio version %d detected\n", version); - - switch(version) { + char *fourcc_ptr = "\0\0\0"; + switch(version) { case 3: /* Version 3 header stores fourcc after meta info - cheat by reading backwards from the * end of the header instead of having to parse it all */ - fourcc = _X_ME_32(mdpr->type_specific_data + mdpr->type_specific_len - 5); + if (mdpr->type_specific_len >= 5) + fourcc_ptr = mdpr->type_specific_data + mdpr->type_specific_len - 5; break; - case 4: - len = *(mdpr->type_specific_data + 56); - fourcc = _X_ME_32(mdpr->type_specific_data + 58 + len); + case 4: { + if (mdpr->type_specific_len >= 57) { + const uint8_t len = *(mdpr->type_specific_data + 56); + if (mdpr->type_specific_len >= 62 + len) + fourcc_ptr = mdpr->type_specific_data + 58 + len; + } + } break; case 5: - fourcc = _X_ME_32(mdpr->type_specific_data + 66); + if (mdpr->type_specific_len >= 70) + fourcc_ptr = mdpr->type_specific_data + 66; break; default: lprintf("unsupported audio header version %d\n", version); goto unknown; - } + } + lprintf("fourcc = %.4s\n", fourcc_ptr); - lprintf("fourcc = %.4s\n", (char *) &fourcc); + const uint32_t fourcc = _X_ME_32(fourcc_ptr); - this->audio_streams[this->num_audio_streams].fourcc = fourcc; - this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); - this->audio_streams[this->num_audio_streams].index = NULL; - this->audio_streams[this->num_audio_streams].mdpr = mdpr; + this->audio_streams[this->num_audio_streams].fourcc = fourcc; + this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); + this->audio_streams[this->num_audio_streams].index = NULL; + this->audio_streams[this->num_audio_streams].mdpr = mdpr; - real_parse_audio_specific_data (this, - &this->audio_streams[this->num_audio_streams], - mdpr->type_specific_data, - mdpr->type_specific_len); - this->num_audio_streams++; + real_parse_audio_specific_data (this, + &this->audio_streams[this->num_audio_streams]); + this->num_audio_streams++; - } else if(_X_BE_32(mdpr->type_specific_data + 4) == VIDO_TAG) { + } else if(_X_BE_32(mdpr->type_specific_data + 4) == VIDO_TAG && + mdpr->type_specific_len >= 34) { - if(this->num_video_streams == MAX_VIDEO_STREAMS) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: maximum number of video stream exceeded\n"); - goto unknown; - } + if(this->num_video_streams == MAX_VIDEO_STREAMS) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: maximum number of video stream exceeded\n"); + goto unknown; + } - lprintf ("video detected\n"); - fourcc = _X_ME_32(mdpr->type_specific_data + 8); - lprintf("fourcc = %.4s\n", (char *) &fourcc); + lprintf ("video detected\n"); + const uint32_t fourcc = _X_ME_32(mdpr->type_specific_data + 8); + lprintf("fourcc = %.4s\n", (char *) &fourcc); - this->video_streams[this->num_video_streams].fourcc = fourcc; - this->video_streams[this->num_video_streams].buf_type = _x_fourcc_to_buf_video(fourcc); - this->video_streams[this->num_video_streams].format = _X_BE_32(mdpr->type_specific_data + 30); - this->video_streams[this->num_video_streams].index = NULL; - this->video_streams[this->num_video_streams].mdpr = mdpr; + this->video_streams[this->num_video_streams].fourcc = fourcc; + this->video_streams[this->num_video_streams].buf_type = _x_fourcc_to_buf_video(fourcc); + this->video_streams[this->num_video_streams].format = _X_BE_32(mdpr->type_specific_data + 30); + this->video_streams[this->num_video_streams].index = NULL; + this->video_streams[this->num_video_streams].mdpr = mdpr; - this->num_video_streams++; + this->num_video_streams++; - } else { - lprintf("unrecognised type specific data\n"); + } else { + lprintf("unrecognised type specific data\n"); -unknown: - real_free_mdpr(mdpr); - } + unknown: + real_free_mdpr(mdpr); + } - } else if (chunk_type == CONT_TAG) { + } else if (chunk_type == CONT_TAG) { - if(version != 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: unknown object version in CONT: 0x%04x\n", version); - free(chunk_buffer); - continue; - } + if(version != 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: unknown object version in CONT: 0x%04x\n", version); + free(chunk_buffer); + continue; + } - stream_ptr = 2; + int stream_ptr = 2; +#define SET_METADATA_STRING(type) \ + do { \ + const uint16_t field_size = _X_BE_16(&chunk_buffer[stream_ptr]); \ + stream_ptr += 2; \ + _x_meta_info_n_set(this->stream, type, \ + &chunk_buffer[stream_ptr], field_size); \ + stream_ptr += field_size; \ + } while(0) - /* load the title string */ - field_size = _X_BE_16(&chunk_buffer[stream_ptr]); - stream_ptr += 2; - _x_meta_info_n_set(this->stream, XINE_META_INFO_TITLE, - &chunk_buffer[stream_ptr], field_size); - stream_ptr += field_size; + /* load the title string */ + SET_METADATA_STRING(XINE_META_INFO_TITLE); + + /* load the author string */ + SET_METADATA_STRING(XINE_META_INFO_ARTIST); - /* load the author string */ - field_size = _X_BE_16(&chunk_buffer[stream_ptr]); - stream_ptr += 2; - _x_meta_info_n_set(this->stream, XINE_META_INFO_ARTIST, - &chunk_buffer[stream_ptr], field_size); - stream_ptr += field_size; + /* load the copyright string as the year */ + SET_METADATA_STRING(XINE_META_INFO_YEAR); - /* load the copyright string as the year */ - field_size = _X_BE_16(&chunk_buffer[stream_ptr]); - stream_ptr += 2; - _x_meta_info_n_set(this->stream, XINE_META_INFO_YEAR, - &chunk_buffer[stream_ptr], field_size); - stream_ptr += field_size; + /* load the comment string */ + SET_METADATA_STRING(XINE_META_INFO_COMMENT); + } - /* load the comment string */ - field_size = _X_BE_16(&chunk_buffer[stream_ptr]); - stream_ptr += 2; - _x_meta_info_n_set(this->stream, XINE_META_INFO_COMMENT, - &chunk_buffer[stream_ptr], field_size); - stream_ptr += field_size; + free(chunk_buffer); } - - free(chunk_buffer); break; - case DATA_TAG: + case DATA_TAG: { + uint8_t data_chunk_header[DATA_CHUNK_HEADER_SIZE]; + if (this->input->read(this->input, data_chunk_header, DATA_CHUNK_HEADER_SIZE) != DATA_CHUNK_HEADER_SIZE) { this->status = DEMUX_FINISHED; @@ -626,7 +638,7 @@ unknown: } /* check version */ - version = _X_BE_16(&data_chunk_header[0]); + const uint16_t version = _X_BE_16(&data_chunk_header[0]); if(version != 0) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: unknown object version in DATA: 0x%04x\n", version); @@ -637,7 +649,8 @@ unknown: this->current_data_chunk_packet_count = _X_BE_32(&data_chunk_header[2]); this->next_data_chunk_offset = _X_BE_32(&data_chunk_header[6]); this->data_chunk_size = chunk_size; - break; + } + break; default: /* this should not occur, but in case it does, skip the chunk */ @@ -653,16 +666,9 @@ unknown: real_parse_index(this); /* Simple stream selection case - 0/1 audio/video streams */ - if(this->num_video_streams == 1) - this->video_stream = &this->video_streams[0]; - else - this->video_stream = NULL; + this->video_stream = (this->num_video_streams == 1) ? &this->video_streams[0] : NULL; + this->audio_stream = (this->num_audio_streams == 1) ? &this->audio_streams[0] : NULL; - if(this->num_audio_streams == 1) - this->audio_stream = &this->audio_streams[0]; - else - this->audio_stream = NULL; - /* In the case of multiple audio/video streams select the first streams found in the file */ if((this->num_video_streams > 1) || (this->num_audio_streams > 1)) { @@ -702,15 +708,13 @@ unknown: while((offset < len) && ((!this->video_stream && (this->num_video_streams > 0)) || (!this->audio_stream && (this->num_audio_streams > 0)))) { - uint32_t id; - int i, stream; + int i; /* Check for end of the data chunk */ - if(((id = _X_BE_32(&search_buffer[offset])) == DATA_TAG) || - (id == INDX_TAG)) - break; + if (is_indx_tag(&search_buffer[offset]) || is_data_tag(&search_buffer[offset])) + break; - stream = _X_BE_16(&search_buffer[offset + 4]); + const int stream = _X_BE_16(&search_buffer[offset + 4]); for(i = 0; !this->video_stream && (i < this->num_video_streams); i++) { if(stream == this->video_streams[i].mdpr->stream_number) { @@ -744,14 +748,12 @@ unknown: /* Send headers and set meta info */ if(this->video_stream) { - buf_element_t *buf; - /* Check for recognised codec*/ if(!this->video_stream->buf_type) this->video_stream->buf_type = BUF_VIDEO_UNKNOWN; /* Send header */ - buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); + buf_element_t *const buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); buf->content = buf->mem; memcpy(buf->content, this->video_stream->mdpr->type_specific_data, @@ -784,10 +786,9 @@ unknown: /* Send headers */ if(this->audio_fifo) { - mdpr_t *mdpr = this->audio_stream->mdpr; - buf_element_t *buf; + mdpr_t *const mdpr = this->audio_stream->mdpr; - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf_element_t *buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = this->audio_stream->buf_type; buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END; @@ -797,7 +798,7 @@ unknown: * The second is the codec initialisation data found at the end of * the type specific data for the audio stream */ if(buf->type == BUF_AUDIO_AAC) { - int version = _X_BE_16(mdpr->type_specific_data + 4); + const uint16_t version = _X_BE_16(mdpr->type_specific_data + 4); if(version != 5) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, @@ -958,9 +959,7 @@ static int demux_real_parse_references( #define PTS_VIDEO 1 static void check_newpts (demux_real_t *this, int64_t pts, int video, int preview) { - int64_t diff; - - diff = pts - this->last_pts[video]; + const int64_t diff = pts - this->last_pts[video]; lprintf ("check_newpts %"PRId64"\n", pts); if (!preview && pts && @@ -1066,19 +1065,14 @@ static int demux_real_send_chunk(demux_p demux_real_t *this = (demux_real_t *) this_gen; char header[DATA_PACKET_HEADER_SIZE]; - int stream, size, keyframe, input_time = 0; - unsigned short version; - uint32_t id, timestamp; - int64_t pts; - off_t offset, input_length = 0; + int keyframe, input_time = 0; int normpos = 0; - read_next_packet: if(this->reference_mode) return demux_real_parse_references(this); /* load a header from wherever the stream happens to be pointing */ - if ( (size=this->input->read(this->input, header, DATA_PACKET_HEADER_SIZE)) != + if ( this->input->read(this->input, header, DATA_PACKET_HEADER_SIZE) != DATA_PACKET_HEADER_SIZE) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, @@ -1089,15 +1083,14 @@ static int demux_real_send_chunk(demux_p } /* Check to see if we've gone past the end of the data chunk */ - if(((id = _X_BE_32(&header[0])) == DATA_TAG) || - (id == INDX_TAG)) { + if (is_indx_tag(&header[0]) || is_data_tag(&header[0])) { lprintf("finished reading data chunk\n"); this->status = DEMUX_FINISHED; return this->status; } /* check version */ - version = _X_BE_16(&header[0]); + const uint16_t version = _X_BE_16(&header[0]); if(version > 1) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: unknown object version in data packet: 0x%04x\n", version); @@ -1106,11 +1099,11 @@ static int demux_real_send_chunk(demux_p } /* read the packet information */ - stream = _X_BE_16(&header[4]); - offset = this->input->get_current_pos(this->input); - size = _X_BE_16(&header[2]) - DATA_PACKET_HEADER_SIZE; - timestamp= _X_BE_32(&header[6]); - pts = (int64_t) timestamp * 90; + const uint16_t stream = _X_BE_16(&header[4]); + const off_t offset = this->input->get_current_pos(this->input); + uint16_t size = _X_BE_16(&header[2]) - DATA_PACKET_HEADER_SIZE; + const uint32_t timestamp= _X_BE_32(&header[6]); + int64_t pts = (int64_t) timestamp * 90; /* Data packet header with version 1 contains 1 extra byte */ if(version == 0) @@ -1125,11 +1118,9 @@ static int demux_real_send_chunk(demux_p if (this->video_stream && (stream == this->video_stream->mdpr->stream_number)) { - int vpkg_header, vpkg_length, vpkg_offset; int vpkg_seqnum = -1; int vpkg_subseq = 0; buf_element_t *buf; - int n, fragment_size; uint32_t decoder_flags; lprintf ("video chunk detected.\n"); @@ -1144,21 +1135,20 @@ static int demux_real_send_chunk(demux_p * bit 6: 1=short header (only one block?) */ - vpkg_header = stream_read_char (this); size--; + const int vpkg_header = stream_read_char (this); size--; lprintf ("vpkg_hdr: %02x (size=%d)\n", vpkg_header, size); + int vpkg_length, vpkg_offset; if (0x40==(vpkg_header&0xc0)) { /* * seems to be a very short header * 2 bytes, purpose of the second byte yet unknown */ - int bummer; - - bummer = stream_read_char (this); size--; + const int bummer = stream_read_char (this); lprintf ("bummer == %02X\n",bummer); vpkg_offset = 0; - vpkg_length = size; + vpkg_length = --size; } else { @@ -1219,9 +1209,8 @@ static int demux_real_send_chunk(demux_p input_time = (int)((int64_t) this->input->get_current_pos(this->input) * 8 * 1000 / this->avg_bitrate); - if(this->data_start && this->data_chunk_size) - input_length = this->data_start + 18 + this->data_chunk_size; - if( input_length ) + const off_t input_length = this->data_start + 18 + this->data_chunk_size; + if( input_length > 18 ) normpos = (int)((double) this->input->get_current_pos(this->input) * 65535 / input_length); check_newpts (this, pts, PTS_VIDEO, 0); @@ -1266,13 +1255,17 @@ static int demux_real_send_chunk(demux_p * calc size of fragment */ - if ((vpkg_header & 0xc0) == 0x080) + int fragment_size; + switch(vpkg_header & 0xc0) { + case 0x80: fragment_size = vpkg_offset; - else { - if (0x00 == (vpkg_header&0xc0)) - fragment_size = size; - else - fragment_size = vpkg_length; + break; + case 0x00: + fragment_size = size; + break; + default: + fragment_size = vpkg_length; + break; } lprintf ("fragment size is %d\n", fragment_size); @@ -1280,14 +1273,11 @@ static int demux_real_send_chunk(demux_p * read fragment_size bytes of data */ - n = fragment_size; + int n = fragment_size; while(n) { buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); - if(n>buf->max_size) - buf->size = buf->max_size; - else - buf->size = n; + buf->size = MIN(n, buf->max_size); buf->decoder_flags = decoder_flags; decoder_flags &= ~BUF_FLAG_FRAME_START; @@ -1371,12 +1361,9 @@ static int demux_real_send_chunk(demux_p input_time = (int)((int64_t) this->input->get_current_pos(this->input) * 8 * 1000 / this->avg_bitrate); - if(this->data_start && this->data_chunk_size) - input_length = this->data_start + 18 + this->data_chunk_size; - else - input_length = 0; + const off_t input_length = this->data_start + 18 + this->data_chunk_size; - if( input_length ) + if( input_length > 18 ) normpos = (int)((double) this->input->get_current_pos(this->input) * 65535 / input_length); check_newpts (this, pts, PTS_AUDIO, 0); @@ -1384,13 +1371,14 @@ static int demux_real_send_chunk(demux_p /* Each packet of AAC is made up of several AAC frames preceded by a * header defining the size of the frames */ if(this->audio_stream->buf_type == BUF_AUDIO_AAC) { - int i, frames, *sizes; + int i; /* Upper 4 bits of second byte is frame count */ - frames = (stream_read_word(this) & 0xf0) >> 4; + const int frames = (stream_read_word(this) & 0xf0) >> 4; /* 2 bytes per frame size */ - sizes = calloc(frames, sizeof(int)); + int sizes[frames]; + for(i = 0; i < frames; i++) sizes[i] = stream_read_word(this); @@ -1402,15 +1390,12 @@ static int demux_real_send_chunk(demux_p xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: failed to read AAC frame\n"); - free(sizes); this->status = DEMUX_FINISHED; return this->status; } pts = 0; /* Only set pts on first frame */ } - - free(sizes); } else if (this->audio_stream->buf_type == BUF_AUDIO_COOK || this->audio_stream->buf_type == BUF_AUDIO_ATRK || this->audio_stream->buf_type == BUF_AUDIO_28_8 || @@ -1508,18 +1493,10 @@ discard: /* check if it's time to reload */ if (!this->current_data_chunk_packet_count && this->next_data_chunk_offset) { - char preamble[PREAMBLE_SIZE]; unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE]; /* seek to the next DATA chunk offset */ - this->input->seek(this->input, this->next_data_chunk_offset, SEEK_SET); - - /* load the DATA chunk preamble */ - if (this->input->read(this->input, preamble, PREAMBLE_SIZE) != - PREAMBLE_SIZE) { - this->status = DEMUX_FINISHED; - return this->status; - } + this->input->seek(this->input, this->next_data_chunk_offset + PREAMBLE_SIZE, SEEK_SET); /* load the rest of the DATA chunk header */ if (this->input->read(this->input, data_chunk_header, @@ -1658,21 +1635,16 @@ static void demux_real_dispose (demux_pl for(i = 0; i < this->num_video_streams; i++) { real_free_mdpr(this->video_streams[i].mdpr); - if(this->video_streams[i].index) - free(this->video_streams[i].index); + free(this->video_streams[i].index); } for(i = 0; i < this->num_audio_streams; i++) { real_free_mdpr(this->audio_streams[i].mdpr); - if(this->audio_streams[i].index) - free(this->audio_streams[i].index); - if(this->audio_streams[i].frame_buffer) - free(this->audio_streams[i].frame_buffer); + free(this->audio_streams[i].index); + free(this->audio_streams[i].frame_buffer); } - if(this->fragment_tab) - free(this->fragment_tab); - + free(this->fragment_tab); free(this); } @@ -1699,21 +1671,27 @@ static int demux_real_get_optional_data( } /* help function to discover stream type. returns: + * -1 if couldn't read * 0 if not known. * 1 if normal stream. * 2 if reference stream. */ -static int real_check_stream_type(uint8_t *buf, int len) +static int real_check_stream_type(input_plugin_t *input) { - if ((buf[0] == 0x2e) - && (buf[1] == 'R') - && (buf[2] == 'M') - && (buf[3] == 'F')) + uint8_t buf[1024]; + off_t len = _x_demux_read_header(input, buf, sizeof(buf)); + + if ( len < 4 ) + return -1; + + if ( memcmp(buf, "\x2eRMF", 4) == 0 ) return 1; - buf[len] = '\0'; - if( strstr(buf,"pnm://") || strstr(buf,"rtsp://") || strstr(buf,"<smil>") || - !strncmp(buf,"http://",7) ) +#define my_strnstr(haystack, haystacklen, needle) \ + memmem(haystack, haystacklen, needle, sizeof(needle)) + + if( my_strnstr(buf, len, "pnm://") || my_strnstr(buf, len, "rtsp://") || + my_strnstr(buf, len, "<smil>") || !strncmp(buf, "http://", MIN(7, len)) ) return 2; return 0; @@ -1722,32 +1700,24 @@ static demux_plugin_t *open_plugin (demu static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input) { - demux_real_t *this; - uint8_t buf[1024+1]; - int len, stream_type=0; + /* discover stream type */ + const int stream_type = real_check_stream_type(input); + + if ( stream_type < 0 ) + return NULL; switch (stream->content_detection_method) { - case METHOD_BY_CONTENT:{ - - if (! (len = _x_demux_read_header(input, buf, 1024)) ) + case METHOD_BY_CONTENT: + if ( stream_type < 1 ) return NULL; - - lprintf ("read 4 bytes: %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3]); - - if (!(stream_type = real_check_stream_type(buf,len))) - return NULL; - } - - lprintf ("by content accepted.\n"); - break; + + lprintf ("by content accepted.\n"); + break; case METHOD_BY_EXTENSION: { - const char *extensions, *mrl; - - mrl = input->get_mrl (input); - extensions = class_gen->get_extensions (class_gen); + const char *const mrl = input->get_mrl (input); + const char *const extensions = class_gen->get_extensions (class_gen); lprintf ("by extension '%s'\n", mrl); @@ -1766,16 +1736,10 @@ static demux_plugin_t *open_plugin (demu return NULL; } - - this = calloc(1, sizeof(demux_real_t)); + demux_real_t *this = calloc(1, sizeof(demux_real_t)); this->stream = stream; this->input = input; - - /* discover stream type */ - if(!stream_type) - if ( (len = _x_demux_read_header(this->input, buf, 1024)) ) - stream_type = real_check_stream_type(buf,len); if(stream_type == 2){ this->reference_mode = 1; @@ -1823,9 +1787,7 @@ static void class_dispose (demux_class_t } static void *init_class (xine_t *xine, void *data) { - demux_real_class_t *this; - - this = calloc(1, sizeof(demux_real_class_t)); + demux_real_class_t *const this = calloc(1, sizeof(demux_real_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_realaudio.c b/src/demuxers/demux_realaudio.c --- a/src/demuxers/demux_realaudio.c +++ b/src/demuxers/demux_realaudio.c @@ -64,7 +64,9 @@ typedef struct { off_t data_start; off_t data_size; - int sps, cfs, w, h; + uint32_t cfs; + uint16_t w, h; + int frame_len; size_t frame_size; uint8_t *frame_buffer; @@ -77,27 +79,22 @@ typedef struct { } demux_ra_class_t; /* Map flavour to bytes per second */ -static int sipr_fl2bps[4] = {813, 1062, 625, 2000}; // 6.5, 8.5, 5, 16 kbit per second +static const int sipr_fl2bps[4] = {813, 1062, 625, 2000}; // 6.5, 8.5, 5, 16 kbit per second /* returns 1 if the RealAudio file was opened successfully, 0 otherwise */ static int open_ra_file(demux_ra_t *this) { - unsigned char file_header[RA_FILE_HEADER_PREV_SIZE], len; - unsigned short version; - off_t offset; - + uint8_t file_header[RA_FILE_HEADER_PREV_SIZE]; /* check the signature */ if (_x_demux_read_header(this->input, file_header, RA_FILE_HEADER_PREV_SIZE) != RA_FILE_HEADER_PREV_SIZE) return 0; - if ((file_header[0] != '.') || - (file_header[1] != 'r') || - (file_header[2] != 'a')) + if ( memcmp(file_header, ".ra", 3) != 0 ) return 0; /* read version */ - version = _X_BE_16(&file_header[0x04]); + const uint16_t version = _X_BE_16(&file_header[0x04]); /* read header size according to version */ if (version == 3) @@ -118,6 +115,7 @@ static int open_ra_file(demux_ra_t *this return 0; } + off_t offset; /* read header data according to version */ if((version == 3) && (this->header_size >= 32)) { this->data_size = _X_BE_32(&this->header[0x12]); @@ -147,31 +145,37 @@ static int open_ra_file(demux_ra_t *this } /* Read title */ - len = this->header[offset]; - if(len && ((offset+len+2) < this->header_size)) { - _x_meta_info_n_set(this->stream, XINE_META_INFO_TITLE, - &this->header[offset+1], len); - offset += len+1; - } else - offset++; + { + const uint8_t len = this->header[offset]; + if(len && ((offset+len+2) < this->header_size)) { + _x_meta_info_n_set(this->stream, XINE_META_INFO_TITLE, + &this->header[offset+1], len); + offset += len+1; + } else + offset++; + } /* Author */ - len = this->header[offset]; - if(len && ((offset+len+1) < this->header_size)) { - _x_meta_info_n_set(this->stream, XINE_META_INFO_ARTIST, - &this->header[offset+1], len); - offset += len+1; - } else - offset++; + { + const uint8_t len = this->header[offset]; + if(len && ((offset+len+1) < this->header_size)) { + _x_meta_info_n_set(this->stream, XINE_META_INFO_ARTIST, + &this->header[offset+1], len); + offset += len+1; + } else + offset++; + } /* Copyright/Date */ - len = this->header[offset]; - if(len && ((offset+len) <= this->header_size)) { - _x_meta_info_n_set(this->stream, XINE_META_INFO_YEAR, - &this->header[offset+1], len); - offset += len+1; - } else - offset++; + { + const uint8_t len = this->header[offset]; + if(len && ((offset+len) <= this->header_size)) { + _x_meta_info_n_set(this->stream, XINE_META_INFO_YEAR, + &this->header[offset+1], len); + offset += len+1; + } else + offset++; + } /* Fourcc for version 3 comes after meta info */ if(version == 3) { @@ -193,16 +197,23 @@ static int open_ra_file(demux_ra_t *this this->audio_type = _x_formattag_to_buf_audio(this->fourcc); if (version == 4) { - this->sps = _X_BE_16 (this->header+44); + const uint16_t sps = _X_BE_16 (this->header+44) ? : 1; this->w = _X_BE_16 (this->header+42); this->h = _X_BE_16 (this->header+40); this->cfs = _X_BE_32 (this->header+24); - if (this->sps) { - this->frame_size = this->sps * this->h * this->sps; - this->frame_buffer = xine_xmalloc (this->frame_size); - } else { - this->frame_size = this->w * this->h; - this->frame_buffer = xine_xmalloc (this->frame_size); + + if (this->w < 0x8000 && this->h < 0x8000) { + uint64_t fs; + this->frame_len = this->w * this->h; + fs = (uint64_t) this->frame_len * sps; + if (fs < 0x80000000) { + this->frame_size = fs; + this->frame_buffer = calloc(this->frame_size, 1); + } + } + if (! this->frame_buffer) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_realaudio: malloc failed\n"); + return 0; } if (this->audio_type == BUF_AUDIO_28_8 || this->audio_type == BUF_AUDIO_SIPRO) @@ -227,7 +238,6 @@ static int demux_ra_send_chunk(demux_plu demux_ra_t *this = (demux_ra_t *) this_gen; off_t current_normpos = 0; - int64_t current_pts; /* just load data chunks from wherever the stream happens to be * pointing; issue a DEMUX_FINISHED status if EOF is reached */ @@ -235,7 +245,7 @@ static int demux_ra_send_chunk(demux_plu current_normpos = (int)( (double) (this->input->get_current_pos (this->input) - this->data_start) * 65535 / this->data_size ); - current_pts = 0; /* let the engine sort out the pts for now */ + const int64_t current_pts = 0; /* let the engine sort out the pts for now */ if (this->seek_flag) { _x_demux_control_newpts(this->stream, current_pts, BUF_FLAG_SEEK); @@ -243,26 +253,21 @@ static int demux_ra_send_chunk(demux_plu } if (this->audio_type == BUF_AUDIO_28_8 || this->audio_type == BUF_AUDIO_SIPRO) { - uint8_t * buffer; - - buffer = this->frame_buffer; if (this->audio_type == BUF_AUDIO_SIPRO) { - int len = this->h * this->w; - if(this->input->read(this->input, this->frame_buffer, len) < len) { + if(this->input->read(this->input, this->frame_buffer, this->frame_len) < this->frame_len) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_realaudio: failed to read audio chunk\n"); this->status = DEMUX_FINISHED; return this->status; } - demux_real_sipro_swap (this->frame_buffer, len * 2 / 96); + demux_real_sipro_swap (this->frame_buffer, this->frame_len * 2 / 96); } else { int x, y; - int pos; for (y = 0; y < this->h; y++) for (x = 0; x < this->h / 2; x++) { - pos = x * 2 * this->w + y * this->cfs; + const int pos = x * 2 * this->w + y * this->cfs; if(this->input->read(this->input, this->frame_buffer + pos, this->cfs) < this->cfs) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, @@ -275,7 +280,7 @@ static int demux_ra_send_chunk(demux_plu } _x_demux_send_data(this->audio_fifo, - buffer, this->frame_size, + this->frame_buffer, this->frame_size, current_pts, this->audio_type, 0, current_normpos, current_pts / 90, 0, 0); } else if(_x_demux_read_send_data(this->audio_fifo, this->input, this->block_align, @@ -310,10 +315,7 @@ static void demux_ra_send_headers(demux_ buf->type = this->audio_type; buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END; - if(this->header_size > buf->max_size) - buf->size = buf->max_size; - else - buf->size = this->header_size; + buf->size = MIN(this->header_size, buf->max_size); memcpy(buf->content, this->header, buf->size); diff --git a/src/demuxers/demux_shn.c b/src/demuxers/demux_shn.c --- a/src/demuxers/demux_shn.c +++ b/src/demuxers/demux_shn.c @@ -88,7 +88,7 @@ static int demux_shn_send_chunk(demux_pl buf->pts = 0; bytes_read = this->input->read(this->input, buf->content, buf->max_size); - if (bytes_read == 0) { + if (bytes_read <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; diff --git a/src/demuxers/demux_slave.c b/src/demuxers/demux_slave.c --- a/src/demuxers/demux_slave.c +++ b/src/demuxers/demux_slave.c @@ -90,10 +90,11 @@ static int demux_slave_next (demux_slave /* fill the scratch buffer */ n = this->input->read(this->input, &this->scratch[this->scratch_used], SCRATCH_SIZE - this->scratch_used); - this->scratch_used += n; + if (n > 0) + this->scratch_used += n; this->scratch[this->scratch_used] = '\0'; - if( !n ) { + if (n <= 0) { lprintf("connection closed\n"); this->status = DEMUX_FINISHED; return 0; diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c --- a/src/demuxers/demux_ts.c +++ b/src/demuxers/demux_ts.c @@ -1573,7 +1573,7 @@ static unsigned char * demux_synchronise do { read_length = this->input->read(this->input, this->buf, PKT_SIZE * NPKT_PER_READ); - if (read_length % PKT_SIZE) { + if (read_length < 0 || read_length % PKT_SIZE) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: read returned %d bytes (not a multiple of %d!)\n", read_length, PKT_SIZE); diff --git a/src/demuxers/demux_tta.c b/src/demuxers/demux_tta.c --- a/src/demuxers/demux_tta.c +++ b/src/demuxers/demux_tta.c @@ -126,6 +126,10 @@ static int demux_tta_send_chunk(demux_pl /* buf->extra_info->input_time = this->current_sample / this->samplerate; */ bytes_read = this->input->read(this->input, buf->content, ( bytes_to_read > buf->max_size ) ? buf->max_size : bytes_to_read); + if (bytes_read < 0) { + this->status = DEMUX_FINISHED; + break; + } buf->size = bytes_read; diff --git a/src/demuxers/demux_vox.c b/src/demuxers/demux_vox.c --- a/src/demuxers/demux_vox.c +++ b/src/demuxers/demux_vox.c @@ -77,7 +77,7 @@ static int demux_vox_send_chunk (demux_p buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_DIALOGIC_IMA; bytes_read = this->input->read(this->input, buf->content, buf->max_size); - if (bytes_read == 0) { + if (bytes_read <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; diff --git a/src/demuxers/demux_yuv_frames.c b/src/demuxers/demux_yuv_frames.c --- a/src/demuxers/demux_yuv_frames.c +++ b/src/demuxers/demux_yuv_frames.c @@ -129,13 +129,19 @@ static void demux_yuv_frames_send_header if(_x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO)) { buf = this->input->read_block(this->input, this->audio_fifo, 0); - this->audio_fifo->put(this->audio_fifo, buf); + if (buf) + this->audio_fifo->put(this->audio_fifo, buf); + else + this->status = DEMUX_FINISHED; } if(_x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO)) { buf = this->input->read_block(this->input, this->video_fifo, 0); - this->video_fifo->put(this->video_fifo, buf); + if (buf) + this->video_fifo->put(this->video_fifo, buf); + else + this->status = DEMUX_FINISHED; } this->status = DEMUX_OK; diff --git a/src/input/input_dvb.c b/src/input/input_dvb.c --- a/src/input/input_dvb.c +++ b/src/input/input_dvb.c @@ -2601,6 +2601,10 @@ static buf_element_t *dvb_plugin_read_bl buf_element_t *buf = fifo->buffer_pool_alloc (fifo); int total_bytes; + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; diff --git a/src/input/input_dvd.c b/src/input/input_dvd.c --- a/src/input/input_dvd.c +++ b/src/input/input_dvd.c @@ -849,6 +849,9 @@ static buf_element_t *dvd_plugin_read_bl static off_t dvd_plugin_read (input_plugin_t *this_gen, char *ch_buf, off_t len) { /* dvd_input_plugin_t *this = (dvd_input_plugin_t*)this_gen; */ + + if (len < 4) + return -1; /* FIXME: Tricking the demux_mpeg_block plugin */ ch_buf[0] = 0; diff --git a/src/input/input_file.c b/src/input/input_file.c --- a/src/input/input_file.c +++ b/src/input/input_file.c @@ -145,6 +145,9 @@ static off_t file_plugin_read (input_plu static off_t file_plugin_read (input_plugin_t *this_gen, char *buf, off_t len) { file_input_plugin_t *this = (file_input_plugin_t *) this_gen; + if (len < 0) + return -1; + #ifdef HAVE_MMAP if ( check_mmap_file(this) ) { off_t l = len; @@ -165,6 +168,11 @@ static buf_element_t *file_plugin_read_b file_input_plugin_t *this = (file_input_plugin_t *) this_gen; buf_element_t *buf = fifo->buffer_pool_alloc (fifo); + + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->type = BUF_DEMUX_BLOCK; diff --git a/src/input/input_gnome_vfs.c b/src/input/input_gnome_vfs.c --- a/src/input/input_gnome_vfs.c +++ b/src/input/input_gnome_vfs.c @@ -120,6 +120,11 @@ gnomevfs_plugin_read_block (input_plugin { off_t total_bytes; buf_element_t *buf = fifo->buffer_pool_alloc (fifo); + + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; diff --git a/src/input/input_http.c b/src/input/input_http.c --- a/src/input/input_http.c +++ b/src/input/input_http.c @@ -421,6 +421,9 @@ static off_t http_plugin_read (input_plu num_bytes = 0; + if (nlen < 0) + return -1; + if (this->curpos < this->preview_size) { if (nlen > (this->preview_size - this->curpos)) @@ -437,7 +440,7 @@ static off_t http_plugin_read (input_plu n = nlen - num_bytes; - if (n) { + if (n > 0) { int read_bytes; read_bytes = http_plugin_read_int (this, &buf[num_bytes], n); @@ -503,6 +506,11 @@ static buf_element_t *http_plugin_read_b off_t total_bytes; buf_element_t *buf = fifo->buffer_pool_alloc (fifo); + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } + buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; @@ -554,7 +562,7 @@ static off_t http_plugin_seek(input_plug if ((origin == SEEK_CUR) && (offset >= 0)) { for (;((int)offset) - BUFSIZE > 0; offset -= BUFSIZE) { - if( !this_gen->read (this_gen, this->seek_buf, BUFSIZE) ) + if( this_gen->read (this_gen, this->seek_buf, BUFSIZE) <= 0 ) return this->curpos; } @@ -576,7 +584,7 @@ static off_t http_plugin_seek(input_plug offset -= this->curpos; for (;((int)offset) - BUFSIZE > 0; offset -= BUFSIZE) { - if( !this_gen->read (this_gen, this->seek_buf, BUFSIZE) ) + if( this_gen->read (this_gen, this->seek_buf, BUFSIZE) <= 0 ) return this->curpos; } @@ -996,6 +1004,7 @@ static int http_plugin_open (input_plugi this->preview_size = http_plugin_read_int (this, this->preview, MAX_PREVIEW_SIZE); } if (this->preview_size < 0) { + this->preview_size = 0; xine_log (this->stream->xine, XINE_LOG_MSG, _("input_http: read error %d\n"), errno); return -12; } diff --git a/src/input/input_mms.c b/src/input/input_mms.c --- a/src/input/input_mms.c +++ b/src/input/input_mms.c @@ -121,6 +121,11 @@ static buf_element_t *mms_plugin_read_bl int total_bytes; lprintf ("mms_plugin_read_block: %"PRId64" bytes...\n", todo); + + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; diff --git a/src/input/input_net.c b/src/input/input_net.c --- a/src/input/input_net.c +++ b/src/input/input_net.c @@ -253,6 +253,9 @@ static off_t net_plugin_read (input_plug lprintf("reading %" PRIdMAX " bytes...\n", (intmax_t)len); + if (len < 0) + return -1; + total=0; if (this->curpos < this->preview_size) { n = this->preview_size - this->curpos; @@ -287,6 +290,11 @@ static buf_element_t *net_plugin_read_bl /* net_input_plugin_t *this = (net_input_plugin_t *) this_gen; */ buf_element_t *buf = fifo->buffer_pool_alloc (fifo); off_t total_bytes; + + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; @@ -331,7 +339,7 @@ static off_t net_plugin_seek (input_plug if ((origin == SEEK_CUR) && (offset >= 0)) { for (;((int)offset) - BUFSIZE > 0; offset -= BUFSIZE) { - if( !this_gen->read (this_gen, this->seek_buf, BUFSIZE) ) + if( this_gen->read (this_gen, this->seek_buf, BUFSIZE) <= 0 ) return this->curpos; } @@ -353,7 +361,7 @@ static off_t net_plugin_seek (input_plug offset -= this->curpos; for (;((int)offset) - BUFSIZE > 0; offset -= BUFSIZE) { - if( !this_gen->read (this_gen, this->seek_buf, BUFSIZE) ) + if( this_gen->read (this_gen, this->seek_buf, BUFSIZE) <= 0 ) return this->curpos; } diff --git a/src/input/input_pnm.c b/src/input/input_pnm.c --- a/src/input/input_pnm.c +++ b/src/input/input_pnm.c @@ -83,7 +83,8 @@ static off_t pnm_plugin_read (input_plug lprintf ("pnm_plugin_read: %"PRId64" bytes ...\n", len); n = pnm_read (this->pnm, buf, len); - this->curpos += n; + if (n >= 0) + this->curpos += n; return n; } @@ -95,6 +96,11 @@ static buf_element_t *pnm_plugin_read_bl int total_bytes; lprintf ("pnm_plugin_read_block: %"PRId64" bytes...\n", todo); + + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; @@ -123,10 +129,16 @@ static off_t pnm_plugin_seek (input_plug if ((origin == SEEK_CUR) && (offset >= 0)) { for (;((int)offset) - BUFSIZE > 0; offset -= BUFSIZE) { - this->curpos += pnm_plugin_read (this_gen, this->scratch, BUFSIZE); + off_t n = pnm_plugin_read (this_gen, this->scratch, BUFSIZE); + if (n <= 0) + return this->curpos; + this->curpos += n; } - this->curpos += pnm_plugin_read (this_gen, this->scratch, offset); + off_t n = pnm_plugin_read (this_gen, this->scratch, offset); + if (n <= 0) + return this->curpos; + this->curpos += n; } return this->curpos; diff --git a/src/input/input_pvr.c b/src/input/input_pvr.c --- a/src/input/input_pvr.c +++ b/src/input/input_pvr.c @@ -423,6 +423,9 @@ static uint32_t pvr_plugin_get_capabilit static off_t pvr_plugin_read (input_plugin_t *this_gen, char *buf, off_t len) { /*pvr_input_plugin_t *this = (pvr_input_plugin_t *) this_gen;*/ + + if (len < 4) + return -1; /* FIXME: Tricking the demux_mpeg_block plugin */ buf[0] = 0; @@ -1199,6 +1202,9 @@ static buf_element_t *pvr_plugin_read_bl buf_element_t *buf; int speed = _x_get_speed(this->stream); + if (todo < 0 || todo > buf->size) + return NULL; + if( !this->pvr_running ) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_pvr: thread died, aborting\n"); return NULL; diff --git a/src/input/input_rtp.c b/src/input/input_rtp.c --- a/src/input/input_rtp.c +++ b/src/input/input_rtp.c @@ -453,6 +453,9 @@ static off_t rtp_plugin_read (input_plug struct timespec timeout; off_t copied = 0; + if (length < 0) + return -1; + while(length > 0) { off_t n; @@ -524,6 +527,10 @@ static buf_element_t *rtp_plugin_read_bl buf_element_t *buf = fifo->buffer_pool_alloc (fifo); int total_bytes; + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; @@ -609,11 +616,14 @@ static int rtp_plugin_get_optional_data if (data_type == INPUT_OPTIONAL_DATA_PREVIEW) { if (!this->preview_read_done) { this->preview_size = rtp_plugin_read(this_gen, this->preview, MAX_PREVIEW_SIZE); + if (this->preview_size < 0) + this->preview_size = 0; lprintf("Preview data length = %d\n", this->preview_size); this->preview_read_done = 1; } - memcpy(data, this->preview, this->preview_size); + if (this->preview_size) + memcpy(data, this->preview, this->preview_size); return this->preview_size; } else { diff --git a/src/input/input_rtsp.c b/src/input/input_rtsp.c --- a/src/input/input_rtsp.c +++ b/src/input/input_rtsp.c @@ -84,7 +84,8 @@ static off_t rtsp_plugin_read (input_plu lprintf ("rtsp_plugin_read: %"PRId64" bytes ...\n", len); n = rtsp_session_read (this->rtsp, buf, len); - this->curpos += n; + if (n > 0) + this->curpos += n; return n; } @@ -96,6 +97,11 @@ static buf_element_t *rtsp_plugin_read_b int total_bytes; lprintf ("rtsp_plugin_read_block: %"PRId64" bytes...\n", todo); + + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; @@ -123,10 +129,16 @@ static off_t rtsp_plugin_seek (input_plu if ((origin == SEEK_CUR) && (offset >= 0)) { for (;((int)offset) - BUFSIZE > 0; offset -= BUFSIZE) { - this->curpos += rtsp_plugin_read (this_gen, this->scratch, BUFSIZE); + off_t n = rtsp_plugin_read (this_gen, this->scratch, BUFSIZE); + if (n <= 0) + return this->curpos; + this->curpos += n; } - this->curpos += rtsp_plugin_read (this_gen, this->scratch, offset); + off_t n = rtsp_plugin_read (this_gen, this->scratch, offset); + if (n <= 0) + return this->curpos; + this->curpos += n; } return this->curpos; diff --git a/src/input/input_smb.c b/src/input/input_smb.c --- a/src/input/input_smb.c +++ b/src/input/input_smb.c @@ -69,6 +69,8 @@ smb_plugin_read (input_plugin_t *this_ge smb_input_t *this = (smb_input_t *) this_gen; off_t n, num_bytes; + if (len < 0) + return -1; num_bytes = 0; while (num_bytes < len) @@ -88,6 +90,11 @@ smb_plugin_read_block (input_plugin_t *t { off_t total_bytes; buf_element_t *buf = fifo->buffer_pool_alloc (fifo); + + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; diff --git a/src/input/input_stdin_fifo.c b/src/input/input_stdin_fifo.c --- a/src/input/input_stdin_fifo.c +++ b/src/input/input_stdin_fifo.c @@ -85,6 +85,8 @@ static off_t stdin_plugin_read (input_pl off_t n, total; lprintf ("reading %"PRId64" bytes...\n", len); + if (len < 0) + return -1; total=0; if (this->curpos < this->preview_size) { @@ -121,6 +123,11 @@ static buf_element_t *stdin_plugin_read_ /* stdin_input_plugin_t *this = (stdin_input_plugin_t *) this_gen; */ buf_element_t *buf = fifo->buffer_pool_alloc (fifo); + if (todo < 0 || todo > buf->size) { + buf->free_buffer (buf); + return NULL; + } + buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; @@ -146,7 +153,7 @@ static off_t stdin_plugin_seek (input_pl if ((origin == SEEK_CUR) && (offset >= 0)) { for (;((int)offset) - BUFSIZE > 0; offset -= BUFSIZE) { - if( !this_gen->read (this_gen, this->seek_buf, BUFSIZE) ) + if( this_gen->read (this_gen, this->seek_buf, BUFSIZE) <= 0 ) return this->curpos; } @@ -168,7 +175,7 @@ static off_t stdin_plugin_seek (input_pl offset -= this->curpos; for (;((int)offset) - BUFSIZE > 0; offset -= BUFSIZE) { - if( !this_gen->read (this_gen, this->seek_buf, BUFSIZE) ) + if( this_gen->read (this_gen, this->seek_buf, BUFSIZE) <= 0 ) return this->curpos; } @@ -270,6 +277,8 @@ static int stdin_plugin_open (input_plug this->preview_size = stdin_plugin_read (&this->input_plugin, this->preview, MAX_PREVIEW_SIZE); + if (this->preview_size < 0) + this->preview_size = 0; this->curpos = 0; return 1; diff --git a/src/libsputext/demux_sputext.c b/src/libsputext/demux_sputext.c --- a/src/libsputext/demux_sputext.c +++ b/src/libsputext/demux_sputext.c @@ -149,7 +149,7 @@ static char *read_line_from_input(demux_ char *s; int linelen; - if ((len - this->buflen) > 512) { + if ((len - this->buflen) > 512 && len < SUB_BUFSIZE) { if((nread = this->input->read(this->input, &this->buf[this->buflen], len - this->buflen)) < 0) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "read failed.\n"); diff --git a/src/video_out/xxmc.h b/src/video_out/xxmc.h --- a/src/video_out/xxmc.h +++ b/src/video_out/xxmc.h @@ -36,6 +36,14 @@ #define _XXMC_H #define XVMC_THREAD_SAFE + +/* + * some implementations are not aware of the display having been locked + * already before calling the xvmc function and may therefore deadlock. + */ +/* +#define XVMC_LOCKDISPLAY_SAFE +*/ #ifdef HAVE_CONFIG_H #include "config.h" @@ -171,7 +179,7 @@ typedef struct context_lock_s { return; \ } -#ifdef XVMC_THREAD_SAFE +#if defined(XVMC_THREAD_SAFE) && defined(XVMC_LOCKDISPLAY_SAFE) #define XVMCLOCKDISPLAY(display) #define XVMCUNLOCKDISPLAY(display) #else diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c --- a/src/xine-engine/demux.c +++ b/src/xine-engine/demux.c @@ -138,6 +138,28 @@ void _x_demux_control_newpts( xine_strea pthread_mutex_unlock(&stream->demux_mutex); } +/* avoid ao_loop being stuck in a pthread_cond_wait, waiting for data; + * return 1 if the stream is stopped + * (better fix wanted!) + */ +static int demux_unstick_ao_loop (xine_stream_t *stream) +{ + if (!stream->audio_thread_created) + return 0; + + int status = xine_get_status (stream); + if (status != XINE_STATUS_QUIT && status != XINE_STATUS_STOP) + return 0; + + /* right, stream is stopped... */ + audio_buffer_t *buf = stream->audio_out->get_buffer (stream->audio_out); + buf->num_frames = 0; + buf->stream = NULL; + stream->audio_out->put_buffer (stream->audio_out, buf, stream); + + return 1; +} + /* sync with decoder fifos, making sure everything gets processed */ void _x_demux_control_headers_done (xine_stream_t *stream) { @@ -190,6 +212,9 @@ void _x_demux_control_headers_done (xine ts.tv_nsec = tv.tv_usec * 1000; /* use timedwait to workaround buggy pthread broadcast implementations */ pthread_cond_timedwait (&stream->counter_changed, &stream->counter_lock, &ts); + + if (demux_unstick_ao_loop (stream)) + break; } stream->demux_action_pending = 0; @@ -347,6 +372,9 @@ static void *demux_loop (void *stream_ge (stream->finished_count_video < finished_count_video)) { lprintf ("waiting for finisheds.\n"); pthread_cond_wait (&stream->counter_changed, &stream->counter_lock); + + if (demux_unstick_ao_loop (stream)) + break; } pthread_mutex_unlock (&stream->counter_lock);
Attachment:
pgp_lju9S39HE.pgp
Description: PGP signature