diff --git a/src/opusfile.c b/src/opusfile.c index b224fc59c438036caaa07f77a2c452d42ea589b9..788689797105b4db1b37062103a1b5e0bf71a62f 100644 --- a/src/opusfile.c +++ b/src/opusfile.c @@ -183,7 +183,15 @@ static opus_int64 op_get_next_page(OggOpusFile *_of,ogg_page *_og, /*Send more paramedics.*/ if(!_boundary)return OP_FALSE; ret=op_get_data(_of); - if(OP_UNLIKELY(ret<0))return ret; + if(OP_UNLIKELY(ret<0)){ + opus_int64 read_offset; + /*If we read up to the boundary (or EOF in a seekable stream), + including buffered sync data, then treat this as EOF. + Otherwise treat it as a read error.*/ + if(_boundary<0)_boundary=_of->end; + read_offset=_of->offset+_of->oy.fill-_of->oy.returned; + return read_offset>=_boundary?OP_FALSE:ret; + } } else{ /*Got a page. @@ -251,7 +259,7 @@ static int op_lookup_page_serialno(ogg_page *_og, start of the stream.*/ static opus_int64 op_get_prev_page_serial(OggOpusFile *_of, const ogg_uint32_t *_serialnos,int _nserialnos,opus_int32 *_chunk_size, - ogg_uint32_t *_serialno,ogg_int64_t *_gp){ + ogg_uint32_t *_serialno,opus_int32 *_page_size,ogg_int64_t *_gp){ ogg_page og; opus_int64 begin; opus_int64 end; @@ -260,6 +268,7 @@ static opus_int64 op_get_prev_page_serial(OggOpusFile *_of, opus_int64 preferred_offset; ogg_uint32_t preferred_serialno; ogg_int64_t ret_serialno; + ogg_int64_t ret_size; ogg_int64_t ret_gp; opus_int32 chunk_size; original_end=end=begin=_of->offset; @@ -282,8 +291,12 @@ static opus_int64 op_get_prev_page_serial(OggOpusFile *_of, ret_serialno=ogg_page_serialno(&og); ret_gp=ogg_page_granulepos(&og); offset=llret; + OP_ASSERT(_of->offset-offset>=0); + OP_ASSERT(_of->offset-offset<=OP_PAGE_SIZE); + ret_size=(opus_int32)(_of->offset-offset); if(ret_serialno==preferred_serialno){ preferred_offset=offset; + *_page_size=ret_size; *_gp=ret_gp; } if(!op_lookup_serialno(ret_serialno,_serialnos,_nserialnos)){ @@ -306,9 +319,10 @@ static opus_int64 op_get_prev_page_serial(OggOpusFile *_of, while(offset==-1); if(_chunk_size!=NULL)*_chunk_size=chunk_size; /*We're not interested in the page... just the serial number, byte offset, - and granule position.*/ + page size, and granule position.*/ if(preferred_offset>=0)return preferred_offset; *_serialno=ret_serialno; + *_page_size=ret_size; *_gp=ret_gp; return offset; } @@ -672,7 +686,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, do{ /*We should get a page unless the file is truncated or mangled. Otherwise there are no audio data packets in the whole logical stream.*/ - if(OP_UNLIKELY(op_get_next_page(_of,_og,-1)<0)){ + if(OP_UNLIKELY(op_get_next_page(_of,_og,_of->end)<0)){ /*Fail if the pre-skip is non-zero, since it's asking us to skip more samples than exist.*/ if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP; @@ -805,10 +819,11 @@ static int op_find_final_pcm_offset(OggOpusFile *_of, chunk_size=OP_CHUNK_SIZE; offset=_of->offset; while(_end_gp==-1||test_serialno!=cur_serialno){ + opus_int32 page_size; test_serialno=cur_serialno; _of->offset=offset; offset=op_get_prev_page_serial(_of,_serialnos,_nserialnos, - &chunk_size,&test_serialno,&_end_gp); + &chunk_size,&test_serialno,&page_size,&_end_gp); if(OP_UNLIKELY(offset<0))return (int)offset; } /*This implementation requires that difference between the first and last @@ -915,7 +930,7 @@ static int op_bisect_forward_serialno(OggOpusFile *_of, ret=op_seek_helper(_of,bisect); if(OP_UNLIKELY(ret<0))return ret; } - last=op_get_next_page(_of,&og,-1); + last=op_get_next_page(_of,&og,_of->end); /*At the worst we should have hit the page at _sr[sri-1].offset.*/ if(OP_UNLIKELY(last<0))return OP_EBADLINK; OP_ASSERT(nsr<_csr); @@ -1053,12 +1068,11 @@ static int op_open_seekable2(OggOpusFile *_of){ contain a single logical bitstream.*/ sr[0].serialno=_of->links[0].serialno; sr[0].offset=op_get_prev_page_serial(_of,_of->serialnos,_of->nserialnos, - NULL,&sr[0].serialno,&end_gp); + NULL,&sr[0].serialno,&sr[0].size,&end_gp); if(OP_UNLIKELY(sr[0].offset<0))return (int)sr[0].offset; + /*If there's any trailing junk, forget about it.*/ + _of->end=sr[0].offset+sr[0].size; /*Now enumerate the bitstream structure.*/ - OP_ASSERT(_of->offset-sr[0].offset>=0); - OP_ASSERT(_of->offset-sr[0].offset<=OP_PAGE_SIZE); - sr[0].size=(opus_int32)(_of->offset-sr[0].offset); data_offset=_of->links[0].data_offset; ret=op_bisect_forward_serialno(_of,data_offset,end_gp,sr, sizeof(sr)/sizeof(*sr),&_of->serialnos,&_of->nserialnos,&_of->cserialnos); @@ -1110,6 +1124,7 @@ static int op_open1(OggOpusFile *_of, int seekable; int ret; memset(_of,0,sizeof(*_of)); + _of->end=-1; _of->source=_source; *&_of->callbacks=*_cb; /*At a minimum, we need to be able to read data.*/ @@ -1487,7 +1502,7 @@ static int op_fetch_and_process_page(OggOpusFile *_of, bitstream.*/ do{ /*Keep reading until we get a page with the correct serialno.*/ - page_pos=op_get_next_page(_of,&og,-1); + page_pos=op_get_next_page(_of,&og,_of->end); /*EOF: Leave uninitialized.*/ if(page_pos<0)return OP_EOF; if(OP_LIKELY(_of->ready_state>=OP_STREAMSET)){