ref: 9b57b0c248709eba740d7e768d59ec7251009184
parent: 073fe98cbf3853bdb15ca9dd8b3b1b928240ad09
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Sat Sep 22 09:37:38 EDT 2012
Fix some issues with trailing junk in files. 1) We were treating EOF in op_get_next_page() as a read error when called from op_get_prev_page_serial(). 2) We also assumed op_get_prev_page_serial() stopped scanning at the end of the page it returned, in order to compute the size of that page. Return the page size explicitly instead. 3) Finally, once we discover where the last page is, there is no reason to ever look at data past it. Update 'end' once we find it, and always pass that to op_get_next_page().
--- a/src/opusfile.c
+++ b/src/opusfile.c
@@ -183,7 +183,15 @@
/*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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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)){