summaryrefslogtreecommitdiff
path: root/drivers/ogg/framing.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ogg/framing.c')
-rw-r--r--drivers/ogg/framing.c202
1 files changed, 112 insertions, 90 deletions
diff --git a/drivers/ogg/framing.c b/drivers/ogg/framing.c
index 25f0e88dbc..3a2f0a6058 100644
--- a/drivers/ogg/framing.c
+++ b/drivers/ogg/framing.c
@@ -12,7 +12,7 @@
function: code raw packets into framed OggSquish stream and
decode Ogg streams back into raw packets
- last mod: $Id: framing.c 17592 2010-11-01 20:27:54Z xiphmont $
+ last mod: $Id: framing.c 18758 2013-01-08 16:29:56Z tterribe $
note: The CRC code is directly derived from public domain code by
Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
@@ -21,6 +21,7 @@
********************************************************************/
#include <stdlib.h>
+#include <limits.h>
#include <string.h>
#include <ogg/ogg.h>
@@ -61,7 +62,7 @@ int ogg_page_serialno(const ogg_page *og){
(og->header[16]<<16) |
(og->header[17]<<24));
}
-
+
long ogg_page_pageno(const ogg_page *og){
return(og->header[18] |
(og->header[19]<<8) |
@@ -76,16 +77,16 @@ long ogg_page_pageno(const ogg_page *og){
page, it's counted */
/* NOTE:
-If a page consists of a packet begun on a previous page, and a new
-packet begun (but not completed) on this page, the return will be:
- ogg_page_packets(page) ==1,
- ogg_page_continued(page) !=0
-
-If a page happens to be a single packet that was begun on a
-previous page, and spans to the next page (in the case of a three or
-more page packet), the return will be:
- ogg_page_packets(page) ==0,
- ogg_page_continued(page) !=0
+ If a page consists of a packet begun on a previous page, and a new
+ packet begun (but not completed) on this page, the return will be:
+ ogg_page_packets(page) ==1,
+ ogg_page_continued(page) !=0
+
+ If a page happens to be a single packet that was begun on a
+ previous page, and spans to the next page (in the case of a three or
+ more page packet), the return will be:
+ ogg_page_packets(page) ==0,
+ ogg_page_continued(page) !=0
*/
int ogg_page_packets(const ogg_page *og){
@@ -205,7 +206,7 @@ int ogg_stream_init(ogg_stream_state *os,int serialno){
return(0);
}
return(-1);
-}
+}
/* async/delayed error detection for the ogg_stream_state */
int ogg_stream_check(ogg_stream_state *os){
@@ -220,10 +221,10 @@ int ogg_stream_clear(ogg_stream_state *os){
if(os->lacing_vals)_ogg_free(os->lacing_vals);
if(os->granule_vals)_ogg_free(os->granule_vals);
- memset(os,0,sizeof(*os));
+ memset(os,0,sizeof(*os));
}
return(0);
-}
+}
int ogg_stream_destroy(ogg_stream_state *os){
if(os){
@@ -231,44 +232,56 @@ int ogg_stream_destroy(ogg_stream_state *os){
_ogg_free(os);
}
return(0);
-}
+}
/* Helpers for ogg_stream_encode; this keeps the structure and
what's happening fairly clear */
-static int _os_body_expand(ogg_stream_state *os,int needed){
- if(os->body_storage<=os->body_fill+needed){
+static int _os_body_expand(ogg_stream_state *os,long needed){
+ if(os->body_storage-needed<=os->body_fill){
+ long body_storage;
void *ret;
- ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)*
- sizeof(*os->body_data));
+ if(os->body_storage>LONG_MAX-needed){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ body_storage=os->body_storage+needed;
+ if(body_storage<LONG_MAX-1024)body_storage+=1024;
+ ret=_ogg_realloc(os->body_data,body_storage*sizeof(*os->body_data));
if(!ret){
ogg_stream_clear(os);
return -1;
}
- os->body_storage+=(needed+1024);
+ os->body_storage=body_storage;
os->body_data=ret;
}
return 0;
}
-static int _os_lacing_expand(ogg_stream_state *os,int needed){
- if(os->lacing_storage<=os->lacing_fill+needed){
+static int _os_lacing_expand(ogg_stream_state *os,long needed){
+ if(os->lacing_storage-needed<=os->lacing_fill){
+ long lacing_storage;
void *ret;
- ret=_ogg_realloc(os->lacing_vals,(os->lacing_storage+needed+32)*
- sizeof(*os->lacing_vals));
+ if(os->lacing_storage>LONG_MAX-needed){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ lacing_storage=os->lacing_storage+needed;
+ if(lacing_storage<LONG_MAX-32)lacing_storage+=32;
+ ret=_ogg_realloc(os->lacing_vals,lacing_storage*sizeof(*os->lacing_vals));
if(!ret){
ogg_stream_clear(os);
return -1;
}
os->lacing_vals=ret;
- ret=_ogg_realloc(os->granule_vals,(os->lacing_storage+needed+32)*
+ ret=_ogg_realloc(os->granule_vals,lacing_storage*
sizeof(*os->granule_vals));
if(!ret){
ogg_stream_clear(os);
return -1;
}
os->granule_vals=ret;
- os->lacing_storage+=(needed+32);
+ os->lacing_storage=lacing_storage;
}
return 0;
}
@@ -287,12 +300,12 @@ void ogg_page_checksum_set(ogg_page *og){
og->header[23]=0;
og->header[24]=0;
og->header[25]=0;
-
+
for(i=0;i<og->header_len;i++)
crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
for(i=0;i<og->body_len;i++)
crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
-
+
og->header[22]=(unsigned char)(crc_reg&0xff);
og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
@@ -304,26 +317,31 @@ void ogg_page_checksum_set(ogg_page *og){
int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
long e_o_s, ogg_int64_t granulepos){
- int bytes = 0, lacing_vals, i;
+ long bytes = 0, lacing_vals;
+ int i;
if(ogg_stream_check(os)) return -1;
if(!iov) return 0;
-
- for (i = 0; i < count; ++i) bytes += (int)iov[i].iov_len;
+
+ for (i = 0; i < count; ++i){
+ if(iov[i].iov_len>LONG_MAX) return -1;
+ if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1;
+ bytes += (long)iov[i].iov_len;
+ }
lacing_vals=bytes/255+1;
if(os->body_returned){
/* advance packet data according to the body_returned pointer. We
had to keep it around to return a pointer into the buffer last
call */
-
+
os->body_fill-=os->body_returned;
if(os->body_fill)
memmove(os->body_data,os->body_data+os->body_returned,
os->body_fill);
os->body_returned=0;
}
-
+
/* make sure we have the buffer storage */
if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
return -1;
@@ -467,33 +485,33 @@ static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int
pageno>>=8;
}
}
-
+
/* zero for computation; filled in later */
os->header[22]=0;
os->header[23]=0;
os->header[24]=0;
os->header[25]=0;
-
+
/* segment table */
os->header[26]=(unsigned char)(vals&0xff);
for(i=0;i<vals;i++)
bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
-
+
/* set pointers in the ogg_page struct */
og->header=os->header;
og->header_len=os->header_fill=vals+27;
og->body=os->body_data+os->body_returned;
og->body_len=bytes;
-
+
/* advance the lacing data and set the body_returned pointer */
-
+
os->lacing_fill-=vals;
memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
os->body_returned+=bytes;
-
+
/* calculate the checksum */
-
+
ogg_page_checksum_set(og);
/* done */
@@ -512,12 +530,20 @@ static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int
since ogg_stream_flush will flush the last page in a stream even if
it's undersized, you almost certainly want to use ogg_stream_pageout
(and *not* ogg_stream_flush) unless you specifically need to flush
- an page regardless of size in the middle of a stream. */
+ a page regardless of size in the middle of a stream. */
int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
return ogg_stream_flush_i(os,og,1,4096);
}
+/* Like the above, but an argument is provided to adjust the nominal
+ page size for applications which are smart enough to provide their
+ own delay based flushing */
+
+int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
+ return ogg_stream_flush_i(os,og,1,nfill);
+}
+
/* This constructs pages from buffered packet segments. The pointers
returned are to static buffers; do not free. The returned buffers are
good only until the next call (using the same ogg_stream_state) */
@@ -533,10 +559,10 @@ int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
return(ogg_stream_flush_i(os,og,force,4096));
}
-/* Like the above, but an argument is provided to adjust the nominal
+/* Like the above, but an argument is provided to adjust the nominal
page size for applications which are smart enough to provide their
own delay based flushing */
-
+
int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
int force=0;
if(ogg_stream_check(os)) return 0;
@@ -645,7 +671,7 @@ int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
-n) skipped n bytes
0) page not ready; more data (no bytes skipped)
n) page synced at current location; page length n bytes
-
+
*/
long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
@@ -654,54 +680,54 @@ long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
long bytes=oy->fill-oy->returned;
if(ogg_sync_check(oy))return 0;
-
+
if(oy->headerbytes==0){
int headerbytes,i;
if(bytes<27)return(0); /* not enough for a header */
-
+
/* verify capture pattern */
if(memcmp(page,"OggS",4))goto sync_fail;
-
+
headerbytes=page[26]+27;
if(bytes<headerbytes)return(0); /* not enough for header + seg table */
-
+
/* count up body length in the segment table */
-
+
for(i=0;i<page[26];i++)
oy->bodybytes+=page[27+i];
oy->headerbytes=headerbytes;
}
-
+
if(oy->bodybytes+oy->headerbytes>bytes)return(0);
-
+
/* The whole test page is buffered. Verify the checksum */
{
/* Grab the checksum bytes, set the header field to zero */
char chksum[4];
ogg_page log;
-
+
memcpy(chksum,page+22,4);
memset(page+22,0,4);
-
+
/* set up a temp page struct and recompute the checksum */
log.header=page;
log.header_len=oy->headerbytes;
log.body=page+oy->headerbytes;
log.body_len=oy->bodybytes;
ogg_page_checksum_set(&log);
-
+
/* Compare */
if(memcmp(chksum,page+22,4)){
/* D'oh. Mismatch! Corrupt page (or miscapture and not a page
at all) */
/* replace the computed checksum with the one actually read in */
memcpy(page+22,chksum,4);
-
+
/* Bad checksum. Lose sync */
goto sync_fail;
}
}
-
+
/* yes, have a whole page all ready to go */
{
unsigned char *page=oy->data+oy->returned;
@@ -720,12 +746,12 @@ long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
oy->bodybytes=0;
return(bytes);
}
-
+
sync_fail:
-
+
oy->headerbytes=0;
oy->bodybytes=0;
-
+
/* search for possible capture */
next=memchr(page+1,'O',bytes-1);
if(!next)
@@ -764,7 +790,7 @@ int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
/* need more data */
return(0);
}
-
+
/* head did not start a synced page... skipped some bytes */
if(!oy->unsynced){
oy->unsynced=1;
@@ -793,7 +819,7 @@ int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
int serialno=ogg_page_serialno(og);
long pageno=ogg_page_pageno(og);
int segments=header[26];
-
+
if(ogg_stream_check(os)) return -1;
/* clean up 'returned data' */
@@ -848,7 +874,7 @@ int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
/* are we a 'continued packet' page? If so, we may need to skip
some segments */
if(continued){
- if(os->lacing_fill<1 ||
+ if(os->lacing_fill<1 ||
os->lacing_vals[os->lacing_fill-1]==0x400){
bos=0;
for(;segptr<segments;segptr++){
@@ -862,7 +888,7 @@ int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
}
}
}
-
+
if(bodysize){
if(_os_body_expand(os,bodysize)) return -1;
memcpy(os->body_data+os->body_fill,body,bodysize);
@@ -875,20 +901,20 @@ int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
int val=header[27+segptr];
os->lacing_vals[os->lacing_fill]=val;
os->granule_vals[os->lacing_fill]=-1;
-
+
if(bos){
os->lacing_vals[os->lacing_fill]|=0x100;
bos=0;
}
-
+
if(val<255)saved=os->lacing_fill;
-
+
os->lacing_fill++;
segptr++;
-
+
if(val<255)os->lacing_packet=os->lacing_fill;
}
-
+
/* set the granulepos on the last granuleval of the last full packet */
if(saved!=-1){
os->granule_vals[saved]=granulepos;
@@ -1493,7 +1519,7 @@ void test_pack(const int *pl, const int **headers, int byteskip,
/* construct a test packet */
ogg_packet op;
int len=pl[i];
-
+
op.packet=data+inptr;
op.bytes=len;
op.e_o_s=(pl[i+1]<0?1:0);
@@ -1509,7 +1535,7 @@ void test_pack(const int *pl, const int **headers, int byteskip,
/* retrieve any finished pages */
{
ogg_page og;
-
+
while(ogg_stream_pageout(&os_en,&og)){
/* We have a page. Check it carefully */
@@ -1558,7 +1584,7 @@ void test_pack(const int *pl, const int **headers, int byteskip,
if(ret==0)break;
if(ret<0)continue;
/* got a page. Happy happy. Verify that it's good. */
-
+
fprintf(stderr,"(%d), ",pageout);
check_page(data+deptr,headers[pageout],&og_de);
@@ -1572,7 +1598,7 @@ void test_pack(const int *pl, const int **headers, int byteskip,
while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
ogg_stream_packetpeek(&os_de,NULL);
ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
-
+
/* verify peek and out match */
if(memcmp(&op_de,&op_de2,sizeof(op_de))){
fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
@@ -1598,7 +1624,7 @@ void test_pack(const int *pl, const int **headers, int byteskip,
}
bosflag=1;
depacket+=op_de.bytes;
-
+
/* check eos flag */
if(eosflag){
fprintf(stderr,"Multiple decoded packets with eos flag!\n");
@@ -1745,7 +1771,7 @@ int main(void){
10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,50,-1};
const int *headret[]={head1_5,head2_5,head3_5,NULL};
-
+
fprintf(stderr,"testing max packet segments... ");
test_pack(packets,headret,0,0,0);
}
@@ -1754,7 +1780,7 @@ int main(void){
/* packet that overspans over an entire page */
const int packets[]={0,100,130049,259,255,-1};
const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
-
+
fprintf(stderr,"testing very large packets... ");
test_pack(packets,headret,0,0,0);
}
@@ -1764,7 +1790,7 @@ int main(void){
found by Josh Coalson) */
const int packets[]={0,100,130049,259,255,-1};
const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
-
+
fprintf(stderr,"testing continuation resync in very large packets... ");
test_pack(packets,headret,100,2,3);
}
@@ -1773,7 +1799,7 @@ int main(void){
/* term only page. why not? */
const int packets[]={0,100,64770,-1};
const int *headret[]={head1_7,head2_7,head3_7,NULL};
-
+
fprintf(stderr,"testing zero data page (1 nil packet)... ");
test_pack(packets,headret,0,0,0);
}
@@ -1786,13 +1812,13 @@ int main(void){
int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
int inptr=0,i,j;
ogg_page og[5];
-
+
ogg_stream_reset(&os_en);
for(i=0;pl[i]!=-1;i++){
ogg_packet op;
int len=pl[i];
-
+
op.packet=data+inptr;
op.bytes=len;
op.e_o_s=(pl[i+1]<0?1:0);
@@ -1840,7 +1866,7 @@ int main(void){
ogg_stream_pagein(&os_de,&temp);
/* do we get the expected results/packets? */
-
+
if(ogg_stream_packetout(&os_de,&test)!=1)error();
checkpacket(&test,0,0,0);
if(ogg_stream_packetout(&os_de,&test)!=1)error();
@@ -1991,13 +2017,13 @@ int main(void){
fprintf(stderr,"ok.\n");
}
-
+
/* Test recapture: garbage + page */
{
ogg_page og_de;
fprintf(stderr,"Testing search for capture... ");
- ogg_sync_reset(&oy);
-
+ ogg_sync_reset(&oy);
+
/* 'garbage' */
memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
og[1].body_len);
@@ -2033,7 +2059,7 @@ int main(void){
{
ogg_page og_de;
fprintf(stderr,"Testing recapture... ");
- ogg_sync_reset(&oy);
+ ogg_sync_reset(&oy);
memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
og[1].header_len);
@@ -2077,13 +2103,9 @@ int main(void){
free_page(&og[i]);
}
}
- }
+ }
return(0);
}
#endif
-
-
-
-