examples/sfexamples/oggvorbiscodec/src/libogg/src/framing.c

00001 /********************************************************************
00002  *                                                                  *
00003  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
00004  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
00005  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
00006  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
00007  *                                                                  *
00008  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
00009  * by the Xiph.Org Foundation http://www.xiph.org/                  *
00010  *                                                                  *
00011  ********************************************************************
00012 
00013  function: code raw [Vorbis] packets into framed OggSquish stream and
00014            decode Ogg streams back into raw packets
00015  last mod: $Id: framing.c,v 1.23 2002/09/29 07:10:37 giles Exp $
00016 
00017  note: The CRC code is directly derived from public domain code by
00018  Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
00019  for details.
00020 
00021  ********************************************************************/
00022 
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include "ogg/ogg.h"
00026 
00027 /* A complete description of Ogg framing exists in docs/framing.html */
00028 
00029 int ogg_page_version(ogg_page *og){
00030   return((int)(og->header[4]));
00031 }
00032 
00033 int ogg_page_continued(ogg_page *og){
00034   return((int)(og->header[5]&0x01));
00035 }
00036 
00037 int ogg_page_bos(ogg_page *og){
00038   return((int)(og->header[5]&0x02));
00039 }
00040 
00041 int ogg_page_eos(ogg_page *og){
00042   return((int)(og->header[5]&0x04));
00043 }
00044 
00045 ogg_int64_t ogg_page_granulepos(ogg_page *og){
00046   unsigned char *page=og->header;
00047   ogg_int64_t granulepos=page[13]&(0xff);
00048   granulepos= (granulepos<<8)|(page[12]&0xff);
00049   granulepos= (granulepos<<8)|(page[11]&0xff);
00050   granulepos= (granulepos<<8)|(page[10]&0xff);
00051   granulepos= (granulepos<<8)|(page[9]&0xff);
00052   granulepos= (granulepos<<8)|(page[8]&0xff);
00053   granulepos= (granulepos<<8)|(page[7]&0xff);
00054   granulepos= (granulepos<<8)|(page[6]&0xff);
00055   return(granulepos);
00056 }
00057 
00058 int ogg_page_serialno(ogg_page *og){
00059   return(og->header[14] |
00060          (og->header[15]<<8) |
00061          (og->header[16]<<16) |
00062          (og->header[17]<<24));
00063 }
00064  
00065 long ogg_page_pageno(ogg_page *og){
00066   return(og->header[18] |
00067          (og->header[19]<<8) |
00068          (og->header[20]<<16) |
00069          (og->header[21]<<24));
00070 }
00071 
00072 
00073 
00074 /* returns the number of packets that are completed on this page (if
00075    the leading packet is begun on a previous page, but ends on this
00076    page, it's counted */
00077 
00078 /* NOTE:
00079 If a page consists of a packet begun on a previous page, and a new
00080 packet begun (but not completed) on this page, the return will be:
00081   ogg_page_packets(page)   ==1, 
00082   ogg_page_continued(page) !=0
00083 
00084 If a page happens to be a single packet that was begun on a
00085 previous page, and spans to the next page (in the case of a three or
00086 more page packet), the return will be: 
00087   ogg_page_packets(page)   ==0, 
00088   ogg_page_continued(page) !=0
00089 */
00090 
00091 int ogg_page_packets(ogg_page *og){
00092   int i,n=og->header[26],count=0;
00093   for(i=0;i<n;i++)
00094     if(og->header[27+i]<255)count++;
00095   return(count);
00096 }
00097 
00098 
00099 #if 0
00100 /* helper to initialize lookup for direct-table CRC (illustrative; we
00101    use the static init below) */
00102 
00103 static ogg_uint32_t _ogg_crc_entry(unsigned long index){
00104   int           i;
00105   unsigned long r;
00106 
00107   r = index << 24;
00108   for (i=0; i<8; i++)
00109     if (r & 0x80000000UL)
00110       r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
00111                                     polynomial, although we use an
00112                                     unreflected alg and an init/final
00113                                     of 0, not 0xffffffff */
00114     else
00115        r<<=1;
00116  return (r & 0xffffffffUL);
00117 }
00118 #endif
00119 
00120 const static ogg_uint32_t crc_lookup[256]={
00121   0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
00122   0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
00123   0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
00124   0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
00125   0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
00126   0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
00127   0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
00128   0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
00129   0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
00130   0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
00131   0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
00132   0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
00133   0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
00134   0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
00135   0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
00136   0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
00137   0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
00138   0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
00139   0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
00140   0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
00141   0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
00142   0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
00143   0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
00144   0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
00145   0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
00146   0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
00147   0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
00148   0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
00149   0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
00150   0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
00151   0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
00152   0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
00153   0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
00154   0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
00155   0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
00156   0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
00157   0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
00158   0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
00159   0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
00160   0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
00161   0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
00162   0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
00163   0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
00164   0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
00165   0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
00166   0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
00167   0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
00168   0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
00169   0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
00170   0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
00171   0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
00172   0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
00173   0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
00174   0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
00175   0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
00176   0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
00177   0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
00178   0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
00179   0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
00180   0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
00181   0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
00182   0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
00183   0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
00184   0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
00185 
00186 /* init the encode/decode logical stream state */
00187 
00188 int ogg_stream_init(ogg_stream_state *os,int serialno){
00189   if(os){
00190     memset(os,0,sizeof(*os));
00191     os->body_storage=16*1024;
00192     os->body_data=(unsigned char*)_ogg_malloc(os->body_storage*sizeof(*os->body_data));
00193 
00194     os->lacing_storage=1024;
00195     os->lacing_vals=(int*)_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
00196     os->granule_vals=(ogg_int64_t*)_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
00197 
00198     os->serialno=serialno;
00199 
00200     return(0);
00201   }
00202   return(-1);
00203 } 
00204 
00205 /* _clear does not free os, only the non-flat storage within */
00206 int ogg_stream_clear(ogg_stream_state *os){
00207   if(os){
00208     if(os->body_data)_ogg_free(os->body_data);
00209     if(os->lacing_vals)_ogg_free(os->lacing_vals);
00210     if(os->granule_vals)_ogg_free(os->granule_vals);
00211 
00212     memset(os,0,sizeof(*os));    
00213   }
00214   return(0);
00215 } 
00216 
00217 int ogg_stream_destroy(ogg_stream_state *os){
00218   if(os){
00219     ogg_stream_clear(os);
00220     _ogg_free(os);
00221   }
00222   return(0);
00223 } 
00224 
00225 /* Helpers for ogg_stream_encode; this keeps the structure and
00226    what's happening fairly clear */
00227 
00228 static void _os_body_expand(ogg_stream_state *os,int needed){
00229   if(os->body_storage<=os->body_fill+needed){
00230     os->body_storage+=(needed+1024);
00231     os->body_data=(unsigned char*)_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
00232   }
00233 }
00234 
00235 static void _os_lacing_expand(ogg_stream_state *os,int needed){
00236   if(os->lacing_storage<=os->lacing_fill+needed){
00237     os->lacing_storage+=(needed+32);
00238     os->lacing_vals=(int*)_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
00239     os->granule_vals=(ogg_int64_t*)_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
00240   }
00241 }
00242 
00243 /* checksum the page */
00244 /* Direct table CRC; note that this will be faster in the future if we
00245    perform the checksum silmultaneously with other copies */
00246 
00247 void ogg_page_checksum_set(ogg_page *og){
00248   if(og){
00249     ogg_uint32_t crc_reg=0;
00250     int i;
00251 
00252     /* safety; needed for API behavior, but not framing code */
00253     og->header[22]=0;
00254     og->header[23]=0;
00255     og->header[24]=0;
00256     og->header[25]=0;
00257     
00258     for(i=0;i<og->header_len;i++)
00259       crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
00260     for(i=0;i<og->body_len;i++)
00261       crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
00262     
00263     og->header[22]=crc_reg&0xff;
00264     og->header[23]=(crc_reg>>8)&0xff;
00265     og->header[24]=(crc_reg>>16)&0xff;
00266     og->header[25]=(crc_reg>>24)&0xff;
00267   }
00268 }
00269 
00270 /* submit data to the internal buffer of the framing engine */
00271 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
00272   int lacing_vals=op->bytes/255+1,i;
00273 
00274   if(os->body_returned){
00275     /* advance packet data according to the body_returned pointer. We
00276        had to keep it around to return a pointer into the buffer last
00277        call */
00278     
00279     os->body_fill-=os->body_returned;
00280     if(os->body_fill)
00281       memmove(os->body_data,os->body_data+os->body_returned,
00282               os->body_fill);
00283     os->body_returned=0;
00284   }
00285  
00286   /* make sure we have the buffer storage */
00287   _os_body_expand(os,op->bytes);
00288   _os_lacing_expand(os,lacing_vals);
00289 
00290   /* Copy in the submitted packet.  Yes, the copy is a waste; this is
00291      the liability of overly clean abstraction for the time being.  It
00292      will actually be fairly easy to eliminate the extra copy in the
00293      future */
00294 
00295   memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
00296   os->body_fill+=op->bytes;
00297 
00298   /* Store lacing vals for this packet */
00299   for(i=0;i<lacing_vals-1;i++){
00300     os->lacing_vals[os->lacing_fill+i]=255;
00301     os->granule_vals[os->lacing_fill+i]=os->granulepos;
00302   }
00303   os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
00304   os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos;
00305 
00306   /* flag the first segment as the beginning of the packet */
00307   os->lacing_vals[os->lacing_fill]|= 0x100;
00308 
00309   os->lacing_fill+=lacing_vals;
00310 
00311   /* for the sake of completeness */
00312   os->packetno++;
00313 
00314   if(op->e_o_s)os->e_o_s=1;
00315 
00316   return(0);
00317 }
00318 
00319 /* This will flush remaining packets into a page (returning nonzero),
00320    even if there is not enough data to trigger a flush normally
00321    (undersized page). If there are no packets or partial packets to
00322    flush, ogg_stream_flush returns 0.  Note that ogg_stream_flush will
00323    try to flush a normal sized page like ogg_stream_pageout; a call to
00324    ogg_stream_flush does not guarantee that all packets have flushed.
00325    Only a return value of 0 from ogg_stream_flush indicates all packet
00326    data is flushed into pages.
00327 
00328    since ogg_stream_flush will flush the last page in a stream even if
00329    it's undersized, you almost certainly want to use ogg_stream_pageout
00330    (and *not* ogg_stream_flush) unless you specifically need to flush 
00331    an page regardless of size in the middle of a stream. */
00332 
00333 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
00334   int i;
00335   int vals=0;
00336   int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
00337   int bytes=0;
00338   long acc=0;
00339   ogg_int64_t granule_pos=os->granule_vals[0];
00340 
00341   if(maxvals==0)return(0);
00342   
00343   /* construct a page */
00344   /* decide how many segments to include */
00345   
00346   /* If this is the initial header case, the first page must only include
00347      the initial header packet */
00348   if(os->b_o_s==0){  /* 'initial header page' case */
00349     granule_pos=0;
00350     for(vals=0;vals<maxvals;vals++){
00351       if((os->lacing_vals[vals]&0x0ff)<255){
00352         vals++;
00353         break;
00354       }
00355     }
00356   }else{
00357     for(vals=0;vals<maxvals;vals++){
00358       if(acc>4096)break;
00359       acc+=os->lacing_vals[vals]&0x0ff;
00360       granule_pos=os->granule_vals[vals];
00361     }
00362   }
00363   
00364   /* construct the header in temp storage */
00365   memcpy(os->header,"OggS",4);
00366   
00367   /* stream structure version */
00368   os->header[4]=0x00;
00369   
00370   /* continued packet flag? */
00371   os->header[5]=0x00;
00372   if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
00373   /* first page flag? */
00374   if(os->b_o_s==0)os->header[5]|=0x02;
00375   /* last page flag? */
00376   if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
00377   os->b_o_s=1;
00378 
00379   /* 64 bits of PCM position */
00380   for(i=6;i<14;i++){
00381     os->header[i]=(granule_pos&0xff);
00382     granule_pos>>=8;
00383   }
00384 
00385   /* 32 bits of stream serial number */
00386   {
00387     long serialno=os->serialno;
00388     for(i=14;i<18;i++){
00389       os->header[i]=(serialno&0xff);
00390       serialno>>=8;
00391     }
00392   }
00393 
00394   /* 32 bits of page counter (we have both counter and page header
00395      because this val can roll over) */
00396   if(os->pageno==-1)os->pageno=0; /* because someone called
00397                                      stream_reset; this would be a
00398                                      strange thing to do in an
00399                                      encode stream, but it has
00400                                      plausible uses */
00401   {
00402     long pageno=os->pageno++;
00403     for(i=18;i<22;i++){
00404       os->header[i]=(pageno&0xff);
00405       pageno>>=8;
00406     }
00407   }
00408   
00409   /* zero for computation; filled in later */
00410   os->header[22]=0;
00411   os->header[23]=0;
00412   os->header[24]=0;
00413   os->header[25]=0;
00414   
00415   /* segment table */
00416   os->header[26]=vals&0xff;
00417   for(i=0;i<vals;i++)
00418     bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
00419   
00420   /* set pointers in the ogg_page struct */
00421   og->header=os->header;
00422   og->header_len=os->header_fill=vals+27;
00423   og->body=os->body_data+os->body_returned;
00424   og->body_len=bytes;
00425   
00426   /* advance the lacing data and set the body_returned pointer */
00427   
00428   os->lacing_fill-=vals;
00429   memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
00430   memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
00431   os->body_returned+=bytes;
00432   
00433   /* calculate the checksum */
00434   
00435   ogg_page_checksum_set(og);
00436 
00437   /* done */
00438   return(1);
00439 }
00440 
00441 
00442 /* This constructs pages from buffered packet segments.  The pointers
00443 returned are to static buffers; do not free. The returned buffers are
00444 good only until the next call (using the same ogg_stream_state) */
00445 
00446 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
00447 
00448   if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
00449      os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */
00450      os->lacing_fill>=255 ||                  /* 'segment table full' case */
00451      (os->lacing_fill&&!os->b_o_s)){          /* 'initial header page' case */
00452         
00453     return(ogg_stream_flush(os,og));
00454   }
00455   
00456   /* not enough data to construct a page and not end of stream */
00457   return(0);
00458 }
00459 
00460 int ogg_stream_eos(ogg_stream_state *os){
00461   return os->e_o_s;
00462 }
00463 
00464 /* DECODING PRIMITIVES: packet streaming layer **********************/
00465 
00466 /* This has two layers to place more of the multi-serialno and paging
00467    control in the application's hands.  First, we expose a data buffer
00468    using ogg_sync_buffer().  The app either copies into the
00469    buffer, or passes it directly to read(), etc.  We then call
00470    ogg_sync_wrote() to tell how many bytes we just added.
00471 
00472    Pages are returned (pointers into the buffer in ogg_sync_state)
00473    by ogg_sync_pageout().  The page is then submitted to
00474    ogg_stream_pagein() along with the appropriate
00475    ogg_stream_state* (ie, matching serialno).  We then get raw
00476    packets out calling ogg_stream_packetout() with a
00477    ogg_stream_state.  See the 'frame-prog.txt' docs for details and
00478    example code. */
00479 
00480 /* initialize the struct to a known state */
00481 int ogg_sync_init(ogg_sync_state *oy){
00482   if(oy){
00483     memset(oy,0,sizeof(*oy));
00484   }
00485   return(0);
00486 }
00487 
00488 
00489 /* clear non-flat storage within */
00490 int ogg_sync_clear(ogg_sync_state *oy){
00491   if(oy){
00492     if(oy->data)_ogg_free(oy->data);
00493     ogg_sync_init(oy);
00494   }
00495   return(0);
00496 }
00497 
00498 int ogg_sync_destroy(ogg_sync_state *oy){
00499   if(oy){
00500     ogg_sync_clear(oy);
00501     _ogg_free(oy);
00502   }
00503   return(0);
00504 }
00505 
00506 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
00507 
00508   /* first, clear out any space that has been previously returned */
00509   if(oy->returned){
00510     oy->fill-=oy->returned;
00511     if(oy->fill>0)
00512       memmove(oy->data,oy->data+oy->returned,oy->fill);
00513     oy->returned=0;
00514   }
00515 
00516   if(size>oy->storage-oy->fill){
00517     /* We need to extend the internal buffer */
00518     long newsize=size+oy->fill+4096; /* an extra page to be nice */
00519 
00520     if(oy->data)
00521       oy->data=(unsigned char*)_ogg_realloc(oy->data,newsize);
00522     else
00523       oy->data=(unsigned char*)_ogg_malloc(newsize);
00524     oy->storage=newsize;
00525   }
00526 
00527   /* expose a segment at least as large as requested at the fill mark */
00528   return((char *)oy->data+oy->fill);
00529 }
00530 
00531 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
00532   if(oy->fill+bytes>oy->storage)return(-1);
00533   oy->fill+=bytes;
00534   return(0);
00535 }
00536 
00537 /* sync the stream.  This is meant to be useful for finding page
00538    boundaries.
00539 
00540    return values for this:
00541   -n) skipped n bytes
00542    0) page not ready; more data (no bytes skipped)
00543    n) page synced at current location; page length n bytes
00544    
00545 */
00546 
00547 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
00548   unsigned char *page=oy->data+oy->returned;
00549   unsigned char *next;
00550   long bytes=oy->fill-oy->returned;
00551   
00552   if(oy->headerbytes==0){
00553     int headerbytes,i;
00554     if(bytes<27)return(0); /* not enough for a header */
00555     
00556     /* verify capture pattern */
00557     if(memcmp(page,"OggS",4))goto sync_fail;
00558     
00559     headerbytes=page[26]+27;
00560     if(bytes<headerbytes)return(0); /* not enough for header + seg table */
00561     
00562     /* count up body length in the segment table */
00563     
00564     for(i=0;i<page[26];i++)
00565       oy->bodybytes+=page[27+i];
00566     oy->headerbytes=headerbytes;
00567   }
00568   
00569   if(oy->bodybytes+oy->headerbytes>bytes)return(0);
00570   
00571   /* The whole test page is buffered.  Verify the checksum */
00572   {
00573     /* Grab the checksum bytes, set the header field to zero */
00574     char chksum[4];
00575     ogg_page log;
00576     
00577     memcpy(chksum,page+22,4);
00578     memset(page+22,0,4);
00579     
00580     /* set up a temp page struct and recompute the checksum */
00581     log.header=page;
00582     log.header_len=oy->headerbytes;
00583     log.body=page+oy->headerbytes;
00584     log.body_len=oy->bodybytes;
00585     ogg_page_checksum_set(&log);
00586     
00587     /* Compare */
00588     if(memcmp(chksum,page+22,4)){
00589       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
00590          at all) */
00591       /* replace the computed checksum with the one actually read in */
00592       memcpy(page+22,chksum,4);
00593       
00594       /* Bad checksum. Lose sync */
00595       goto sync_fail;
00596     }
00597   }
00598   
00599   /* yes, have a whole page all ready to go */
00600   {
00601     unsigned char *page=oy->data+oy->returned;
00602     long bytes;
00603 
00604     if(og){
00605       og->header=page;
00606       og->header_len=oy->headerbytes;
00607       og->body=page+oy->headerbytes;
00608       og->body_len=oy->bodybytes;
00609     }
00610 
00611     oy->unsynced=0;
00612     oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
00613     oy->headerbytes=0;
00614     oy->bodybytes=0;
00615     return(bytes);
00616   }
00617   
00618  sync_fail:
00619   
00620   oy->headerbytes=0;
00621   oy->bodybytes=0;
00622   
00623   /* search for possible capture */
00624   next=(unsigned char*)memchr(page+1,'O',bytes-1);
00625   if(!next)
00626     next=oy->data+oy->fill;
00627 
00628   oy->returned=next-oy->data;
00629   return(-(next-page));
00630 }
00631 
00632 /* sync the stream and get a page.  Keep trying until we find a page.
00633    Supress 'sync errors' after reporting the first.
00634 
00635    return values:
00636    -1) recapture (hole in data)
00637     0) need more data
00638     1) page returned
00639 
00640    Returns pointers into buffered data; invalidated by next call to
00641    _stream, _clear, _init, or _buffer */
00642 
00643 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
00644 
00645   /* all we need to do is verify a page at the head of the stream
00646      buffer.  If it doesn't verify, we look for the next potential
00647      frame */
00648 
00649   while(1){
00650     long ret=ogg_sync_pageseek(oy,og);
00651     if(ret>0){
00652       /* have a page */
00653       return(1);
00654     }
00655     if(ret==0){
00656       /* need more data */
00657       return(0);
00658     }
00659     
00660     /* head did not start a synced page... skipped some bytes */
00661     if(!oy->unsynced){
00662       oy->unsynced=1;
00663       return(-1);
00664     }
00665 
00666     /* loop. keep looking */
00667 
00668   }
00669 }
00670 
00671 /* add the incoming page to the stream state; we decompose the page
00672    into packet segments here as well. */
00673 
00674 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
00675   unsigned char *header=og->header;
00676   unsigned char *body=og->body;
00677   long           bodysize=og->body_len;
00678   int            segptr=0;
00679 
00680   int version=ogg_page_version(og);
00681   int continued=ogg_page_continued(og);
00682   int bos=ogg_page_bos(og);
00683   int eos=ogg_page_eos(og);
00684   ogg_int64_t granulepos=ogg_page_granulepos(og);
00685   int serialno=ogg_page_serialno(og);
00686   long pageno=ogg_page_pageno(og);
00687   int segments=header[26];
00688   
00689   /* clean up 'returned data' */
00690   {
00691     long lr=os->lacing_returned;
00692     long br=os->body_returned;
00693 
00694     /* body data */
00695     if(br){
00696       os->body_fill-=br;
00697       if(os->body_fill)
00698         memmove(os->body_data,os->body_data+br,os->body_fill);
00699       os->body_returned=0;
00700     }
00701 
00702     if(lr){
00703       /* segment table */
00704       if(os->lacing_fill-lr){
00705         memmove(os->lacing_vals,os->lacing_vals+lr,
00706                 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
00707         memmove(os->granule_vals,os->granule_vals+lr,
00708                 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
00709       }
00710       os->lacing_fill-=lr;
00711       os->lacing_packet-=lr;
00712       os->lacing_returned=0;
00713     }
00714   }
00715 
00716   /* check the serial number */
00717   if(serialno!=os->serialno)return(-1);
00718   if(version>0)return(-1);
00719 
00720   _os_lacing_expand(os,segments+1);
00721 
00722   /* are we in sequence? */
00723   if(pageno!=os->pageno){
00724     int i;
00725 
00726     /* unroll previous partial packet (if any) */
00727     for(i=os->lacing_packet;i<os->lacing_fill;i++)
00728       os->body_fill-=os->lacing_vals[i]&0xff;
00729     os->lacing_fill=os->lacing_packet;
00730 
00731     /* make a note of dropped data in segment table */
00732     if(os->pageno!=-1){
00733       os->lacing_vals[os->lacing_fill++]=0x400;
00734       os->lacing_packet++;
00735     }
00736 
00737     /* are we a 'continued packet' page?  If so, we'll need to skip
00738        some segments */
00739     if(continued){
00740       bos=0;
00741       for(;segptr<segments;segptr++){
00742         int val=header[27+segptr];
00743         body+=val;
00744         bodysize-=val;
00745         if(val<255){
00746           segptr++;
00747           break;
00748         }
00749       }
00750     }
00751   }
00752   
00753   if(bodysize){
00754     _os_body_expand(os,bodysize);
00755     memcpy(os->body_data+os->body_fill,body,bodysize);
00756     os->body_fill+=bodysize;
00757   }
00758 
00759   {
00760     int saved=-1;
00761     while(segptr<segments){
00762       int val=header[27+segptr];
00763       os->lacing_vals[os->lacing_fill]=val;
00764       os->granule_vals[os->lacing_fill]=-1;
00765       
00766       if(bos){
00767         os->lacing_vals[os->lacing_fill]|=0x100;
00768         bos=0;
00769       }
00770       
00771       if(val<255)saved=os->lacing_fill;
00772       
00773       os->lacing_fill++;
00774       segptr++;
00775       
00776       if(val<255)os->lacing_packet=os->lacing_fill;
00777     }
00778   
00779     /* set the granulepos on the last granuleval of the last full packet */
00780     if(saved!=-1){
00781       os->granule_vals[saved]=granulepos;
00782     }
00783 
00784   }
00785 
00786   if(eos){
00787     os->e_o_s=1;
00788     if(os->lacing_fill>0)
00789       os->lacing_vals[os->lacing_fill-1]|=0x200;
00790   }
00791 
00792   os->pageno=pageno+1;
00793 
00794   return(0);
00795 }
00796 
00797 /* clear things to an initial state.  Good to call, eg, before seeking */
00798 int ogg_sync_reset(ogg_sync_state *oy){
00799   oy->fill=0;
00800   oy->returned=0;
00801   oy->unsynced=0;
00802   oy->headerbytes=0;
00803   oy->bodybytes=0;
00804   return(0);
00805 }
00806 
00807 int ogg_stream_reset(ogg_stream_state *os){
00808   os->body_fill=0;
00809   os->body_returned=0;
00810 
00811   os->lacing_fill=0;
00812   os->lacing_packet=0;
00813   os->lacing_returned=0;
00814 
00815   os->header_fill=0;
00816 
00817   os->e_o_s=0;
00818   os->b_o_s=0;
00819   os->pageno=-1;
00820   os->packetno=0;
00821   os->granulepos=0;
00822 
00823   return(0);
00824 }
00825 
00826 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
00827   ogg_stream_reset(os);
00828   os->serialno=serialno;
00829   return(0);
00830 }
00831 
00832 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
00833 
00834   /* The last part of decode. We have the stream broken into packet
00835      segments.  Now we need to group them into packets (or return the
00836      out of sync markers) */
00837 
00838   int ptr=os->lacing_returned;
00839 
00840   if(os->lacing_packet<=ptr)return(0);
00841 
00842   if(os->lacing_vals[ptr]&0x400){
00843     /* we need to tell the codec there's a gap; it might need to
00844        handle previous packet dependencies. */
00845     os->lacing_returned++;
00846     os->packetno++;
00847     return(-1);
00848   }
00849 
00850   if(!op && !adv)return(1); /* just using peek as an inexpensive way
00851                                to ask if there's a whole packet
00852                                waiting */
00853 
00854   /* Gather the whole packet. We'll have no holes or a partial packet */
00855   {
00856     int size=os->lacing_vals[ptr]&0xff;
00857     int bytes=size;
00858     int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
00859     int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
00860 
00861     while(size==255){
00862       int val=os->lacing_vals[++ptr];
00863       size=val&0xff;
00864       if(val&0x200)eos=0x200;
00865       bytes+=size;
00866     }
00867 
00868     if(op){
00869       op->e_o_s=eos;
00870       op->b_o_s=bos;
00871       op->packet=os->body_data+os->body_returned;
00872       op->packetno=os->packetno;
00873       op->granulepos=os->granule_vals[ptr];
00874       op->bytes=bytes;
00875     }
00876 
00877     if(adv){
00878       os->body_returned+=bytes;
00879       os->lacing_returned=ptr+1;
00880       os->packetno++;
00881     }
00882   }
00883   return(1);
00884 }
00885 
00886 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
00887   return _packetout(os,op,1);
00888 }
00889 
00890 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
00891   return _packetout(os,op,0);
00892 }
00893 
00894 void ogg_packet_clear(ogg_packet *op) {
00895   _ogg_free(op->packet);
00896   memset(op, 0, sizeof(*op));
00897 }
00898 
00899 #ifdef _V_SELFTEST
00900 #include <stdio.h>
00901 
00902 ogg_stream_state os_en, os_de;
00903 ogg_sync_state oy;
00904 
00905 void checkpacket(ogg_packet *op,int len, int no, int pos){
00906   long j;
00907   int sequence=0;
00908   int lastno=0;
00909 
00910   if(op->bytes!=len){
00911     fprintf(stderr,"incorrect packet length!\n");
00912     exit(1);
00913   }
00914   if(op->granulepos!=pos){
00915     fprintf(stderr,"incorrect packet position!\n");
00916     exit(1);
00917   }
00918 
00919   /* packet number just follows sequence/gap; adjust the input number
00920      for that */
00921   if(no==0){
00922     sequence=0;
00923   }else{
00924     sequence++;
00925     if(no>lastno+1)
00926       sequence++;
00927   }
00928   lastno=no;
00929   if(op->packetno!=sequence){
00930     fprintf(stderr,"incorrect packet sequence %ld != %d\n",
00931             (long)(op->packetno),sequence);
00932     exit(1);
00933   }
00934 
00935   /* Test data */
00936   for(j=0;j<op->bytes;j++)
00937     if(op->packet[j]!=((j+no)&0xff)){
00938       fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
00939               j,op->packet[j],(j+no)&0xff);
00940       exit(1);
00941     }
00942 }
00943 
00944 void check_page(unsigned char *data,const int *header,ogg_page *og){
00945   long j;
00946   /* Test data */
00947   for(j=0;j<og->body_len;j++)
00948     if(og->body[j]!=data[j]){
00949       fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
00950               j,data[j],og->body[j]);
00951       exit(1);
00952     }
00953 
00954   /* Test header */
00955   for(j=0;j<og->header_len;j++){
00956     if(og->header[j]!=header[j]){
00957       fprintf(stderr,"header content mismatch at pos %ld:\n",j);
00958       for(j=0;j<header[26]+27;j++)
00959         fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
00960       fprintf(stderr,"\n");
00961       exit(1);
00962     }
00963   }
00964   if(og->header_len!=header[26]+27){
00965     fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
00966             og->header_len,header[26]+27);
00967     exit(1);
00968   }
00969 }
00970 
00971 void print_header(ogg_page *og){
00972   int j;
00973   fprintf(stderr,"\nHEADER:\n");
00974   fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
00975           og->header[0],og->header[1],og->header[2],og->header[3],
00976           (int)og->header[4],(int)og->header[5]);
00977 
00978   fprintf(stderr,"  granulepos: %d  serialno: %d  pageno: %ld\n",
00979           (og->header[9]<<24)|(og->header[8]<<16)|
00980           (og->header[7]<<8)|og->header[6],
00981           (og->header[17]<<24)|(og->header[16]<<16)|
00982           (og->header[15]<<8)|og->header[14],
00983           ((long)(og->header[21])<<24)|(og->header[20]<<16)|
00984           (og->header[19]<<8)|og->header[18]);
00985 
00986   fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
00987           (int)og->header[22],(int)og->header[23],
00988           (int)og->header[24],(int)og->header[25],
00989           (int)og->header[26]);
00990 
00991   for(j=27;j<og->header_len;j++)
00992     fprintf(stderr,"%d ",(int)og->header[j]);
00993   fprintf(stderr,")\n\n");
00994 }
00995 
00996 void copy_page(ogg_page *og){
00997   unsigned char *temp=_ogg_malloc(og->header_len);
00998   memcpy(temp,og->header,og->header_len);
00999   og->header=temp;
01000 
01001   temp=_ogg_malloc(og->body_len);
01002   memcpy(temp,og->body,og->body_len);
01003   og->body=temp;
01004 }
01005 
01006 void error(void){
01007   fprintf(stderr,"error!\n");
01008   exit(1);
01009 }
01010 
01011 /* 17 only */
01012 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
01013                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01014                        0x01,0x02,0x03,0x04,0,0,0,0,
01015                        0x15,0xed,0xec,0x91,
01016                        1,
01017                        17};
01018 
01019 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
01020 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
01021                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01022                        0x01,0x02,0x03,0x04,0,0,0,0,
01023                        0x59,0x10,0x6c,0x2c,
01024                        1,
01025                        17};
01026 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
01027                        0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
01028                        0x01,0x02,0x03,0x04,1,0,0,0,
01029                        0x89,0x33,0x85,0xce,
01030                        13,
01031                        254,255,0,255,1,255,245,255,255,0,
01032                        255,255,90};
01033 
01034 /* nil packets; beginning,middle,end */
01035 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
01036                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01037                        0x01,0x02,0x03,0x04,0,0,0,0,
01038                        0xff,0x7b,0x23,0x17,
01039                        1,
01040                        0};
01041 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
01042                        0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
01043                        0x01,0x02,0x03,0x04,1,0,0,0,
01044                        0x5c,0x3f,0x66,0xcb,
01045                        17,
01046                        17,254,255,0,0,255,1,0,255,245,255,255,0,
01047                        255,255,90,0};
01048 
01049 /* large initial packet */
01050 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
01051                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01052                        0x01,0x02,0x03,0x04,0,0,0,0,
01053                        0x01,0x27,0x31,0xaa,
01054                        18,
01055                        255,255,255,255,255,255,255,255,
01056                        255,255,255,255,255,255,255,255,255,10};
01057 
01058 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
01059                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
01060                        0x01,0x02,0x03,0x04,1,0,0,0,
01061                        0x7f,0x4e,0x8a,0xd2,
01062                        4,
01063                        255,4,255,0};
01064 
01065 
01066 /* continuing packet test */
01067 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
01068                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01069                        0x01,0x02,0x03,0x04,0,0,0,0,
01070                        0xff,0x7b,0x23,0x17,
01071                        1,
01072                        0};
01073 
01074 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
01075                        0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01076                        0x01,0x02,0x03,0x04,1,0,0,0,
01077                        0x34,0x24,0xd5,0x29,
01078                        17,
01079                        255,255,255,255,255,255,255,255,
01080                        255,255,255,255,255,255,255,255,255};
01081 
01082 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
01083                        0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
01084                        0x01,0x02,0x03,0x04,2,0,0,0,
01085                        0xc8,0xc3,0xcb,0xed,
01086                        5,
01087                        10,255,4,255,0};
01088 
01089 
01090 /* page with the 255 segment limit */
01091 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
01092                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01093                        0x01,0x02,0x03,0x04,0,0,0,0,
01094                        0xff,0x7b,0x23,0x17,
01095                        1,
01096                        0};
01097 
01098 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
01099                        0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
01100                        0x01,0x02,0x03,0x04,1,0,0,0,
01101                        0xed,0x2a,0x2e,0xa7,
01102                        255,
01103                        10,10,10,10,10,10,10,10,
01104                        10,10,10,10,10,10,10,10,
01105                        10,10,10,10,10,10,10,10,
01106                        10,10,10,10,10,10,10,10,
01107                        10,10,10,10,10,10,10,10,
01108                        10,10,10,10,10,10,10,10,
01109                        10,10,10,10,10,10,10,10,
01110                        10,10,10,10,10,10,10,10,
01111                        10,10,10,10,10,10,10,10,
01112                        10,10,10,10,10,10,10,10,
01113                        10,10,10,10,10,10,10,10,
01114                        10,10,10,10,10,10,10,10,
01115                        10,10,10,10,10,10,10,10,
01116                        10,10,10,10,10,10,10,10,
01117                        10,10,10,10,10,10,10,10,
01118                        10,10,10,10,10,10,10,10,
01119                        10,10,10,10,10,10,10,10,
01120                        10,10,10,10,10,10,10,10,
01121                        10,10,10,10,10,10,10,10,
01122                        10,10,10,10,10,10,10,10,
01123                        10,10,10,10,10,10,10,10,
01124                        10,10,10,10,10,10,10,10,
01125                        10,10,10,10,10,10,10,10,
01126                        10,10,10,10,10,10,10,10,
01127                        10,10,10,10,10,10,10,10,
01128                        10,10,10,10,10,10,10,10,
01129                        10,10,10,10,10,10,10,10,
01130                        10,10,10,10,10,10,10,10,
01131                        10,10,10,10,10,10,10,10,
01132                        10,10,10,10,10,10,10,10,
01133                        10,10,10,10,10,10,10,10,
01134                        10,10,10,10,10,10,10};
01135 
01136 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
01137                        0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
01138                        0x01,0x02,0x03,0x04,2,0,0,0,
01139                        0x6c,0x3b,0x82,0x3d,
01140                        1,
01141                        50};
01142 
01143 
01144 /* packet that overspans over an entire page */
01145 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
01146                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01147                        0x01,0x02,0x03,0x04,0,0,0,0,
01148                        0xff,0x7b,0x23,0x17,
01149                        1,
01150                        0};
01151 
01152 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
01153                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
01154                        0x01,0x02,0x03,0x04,1,0,0,0,
01155                        0x3c,0xd9,0x4d,0x3f,
01156                        17,
01157                        100,255,255,255,255,255,255,255,255,
01158                        255,255,255,255,255,255,255,255};
01159 
01160 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
01161                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
01162                        0x01,0x02,0x03,0x04,2,0,0,0,
01163                        0xbd,0xd5,0xb5,0x8b,
01164                        17,
01165                        255,255,255,255,255,255,255,255,
01166                        255,255,255,255,255,255,255,255,255};
01167 
01168 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
01169                        0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
01170                        0x01,0x02,0x03,0x04,3,0,0,0,
01171                        0xef,0xdd,0x88,0xde,
01172                        7,
01173                        255,255,75,255,4,255,0};
01174 
01175 /* packet that overspans over an entire page */
01176 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
01177                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01178                        0x01,0x02,0x03,0x04,0,0,0,0,
01179                        0xff,0x7b,0x23,0x17,
01180                        1,
01181                        0};
01182 
01183 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
01184                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
01185                        0x01,0x02,0x03,0x04,1,0,0,0,
01186                        0x3c,0xd9,0x4d,0x3f,
01187                        17,
01188                        100,255,255,255,255,255,255,255,255,
01189                        255,255,255,255,255,255,255,255};
01190 
01191 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
01192                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
01193                        0x01,0x02,0x03,0x04,2,0,0,0,
01194                        0xd4,0xe0,0x60,0xe5,
01195                        1,0};
01196 
01197 void test_pack(const int *pl, const int **headers){
01198   unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
01199   long inptr=0;
01200   long outptr=0;
01201   long deptr=0;
01202   long depacket=0;
01203   long granule_pos=7,pageno=0;
01204   int i,j,packets,pageout=0;
01205   int eosflag=0;
01206   int bosflag=0;
01207 
01208   ogg_stream_reset(&os_en);
01209   ogg_stream_reset(&os_de);
01210   ogg_sync_reset(&oy);
01211 
01212   for(packets=0;;packets++)if(pl[packets]==-1)break;
01213 
01214   for(i=0;i<packets;i++){
01215     /* construct a test packet */
01216     ogg_packet op;
01217     int len=pl[i];
01218     
01219     op.packet=data+inptr;
01220     op.bytes=len;
01221     op.e_o_s=(pl[i+1]<0?1:0);
01222     op.granulepos=granule_pos;
01223 
01224     granule_pos+=1024;
01225 
01226     for(j=0;j<len;j++)data[inptr++]=i+j;
01227 
01228     /* submit the test packet */
01229     ogg_stream_packetin(&os_en,&op);
01230 
01231     /* retrieve any finished pages */
01232     {
01233       ogg_page og;
01234       
01235       while(ogg_stream_pageout(&os_en,&og)){
01236         /* We have a page.  Check it carefully */
01237 
01238         fprintf(stderr,"%ld, ",pageno);
01239 
01240         if(headers[pageno]==NULL){
01241           fprintf(stderr,"coded too many pages!\n");
01242           exit(1);
01243         }
01244 
01245         check_page(data+outptr,headers[pageno],&og);
01246 
01247         outptr+=og.body_len;
01248         pageno++;
01249 
01250         /* have a complete page; submit it to sync/decode */
01251 
01252         {
01253           ogg_page og_de;
01254           ogg_packet op_de,op_de2;
01255           char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
01256           memcpy(buf,og.header,og.header_len);
01257           memcpy(buf+og.header_len,og.body,og.body_len);
01258           ogg_sync_wrote(&oy,og.header_len+og.body_len);
01259 
01260           while(ogg_sync_pageout(&oy,&og_de)>0){
01261             /* got a page.  Happy happy.  Verify that it's good. */
01262             
01263             check_page(data+deptr,headers[pageout],&og_de);
01264             deptr+=og_de.body_len;
01265             pageout++;
01266 
01267             /* submit it to deconstitution */
01268             ogg_stream_pagein(&os_de,&og_de);
01269 
01270             /* packets out? */
01271             while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
01272               ogg_stream_packetpeek(&os_de,NULL);
01273               ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
01274               
01275               /* verify peek and out match */
01276               if(memcmp(&op_de,&op_de2,sizeof(op_de))){
01277                 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
01278                         depacket);
01279                 exit(1);
01280               }
01281 
01282               /* verify the packet! */
01283               /* check data */
01284               if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
01285                 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
01286                         depacket);
01287                 exit(1);
01288               }
01289               /* check bos flag */
01290               if(bosflag==0 && op_de.b_o_s==0){
01291                 fprintf(stderr,"b_o_s flag not set on packet!\n");
01292                 exit(1);
01293               }
01294               if(bosflag && op_de.b_o_s){
01295                 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
01296                 exit(1);
01297               }
01298               bosflag=1;
01299               depacket+=op_de.bytes;
01300               
01301               /* check eos flag */
01302               if(eosflag){
01303                 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
01304                 exit(1);
01305               }
01306 
01307               if(op_de.e_o_s)eosflag=1;
01308 
01309               /* check granulepos flag */
01310               if(op_de.granulepos!=-1){
01311                 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
01312               }
01313             }
01314           }
01315         }
01316       }
01317     }
01318   }
01319   _ogg_free(data);
01320   if(headers[pageno]!=NULL){
01321     fprintf(stderr,"did not write last page!\n");
01322     exit(1);
01323   }
01324   if(headers[pageout]!=NULL){
01325     fprintf(stderr,"did not decode last page!\n");
01326     exit(1);
01327   }
01328   if(inptr!=outptr){
01329     fprintf(stderr,"encoded page data incomplete!\n");
01330     exit(1);
01331   }
01332   if(inptr!=deptr){
01333     fprintf(stderr,"decoded page data incomplete!\n");
01334     exit(1);
01335   }
01336   if(inptr!=depacket){
01337     fprintf(stderr,"decoded packet data incomplete!\n");
01338     exit(1);
01339   }
01340   if(!eosflag){
01341     fprintf(stderr,"Never got a packet with EOS set!\n");
01342     exit(1);
01343   }
01344   fprintf(stderr,"ok.\n");
01345 }
01346 
01347 int main(void){
01348 
01349   ogg_stream_init(&os_en,0x04030201);
01350   ogg_stream_init(&os_de,0x04030201);
01351   ogg_sync_init(&oy);
01352 
01353   /* Exercise each code path in the framing code.  Also verify that
01354      the checksums are working.  */
01355 
01356   {
01357     /* 17 only */
01358     const int packets[]={17, -1};
01359     const int *headret[]={head1_0,NULL};
01360     
01361     fprintf(stderr,"testing single page encoding... ");
01362     test_pack(packets,headret);
01363   }
01364 
01365   {
01366     /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
01367     const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
01368     const int *headret[]={head1_1,head2_1,NULL};
01369     
01370     fprintf(stderr,"testing basic page encoding... ");
01371     test_pack(packets,headret);
01372   }
01373 
01374   {
01375     /* nil packets; beginning,middle,end */
01376     const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
01377     const int *headret[]={head1_2,head2_2,NULL};
01378     
01379     fprintf(stderr,"testing basic nil packets... ");
01380     test_pack(packets,headret);
01381   }
01382 
01383   {
01384     /* large initial packet */
01385     const int packets[]={4345,259,255,-1};
01386     const int *headret[]={head1_3,head2_3,NULL};
01387     
01388     fprintf(stderr,"testing initial-packet lacing > 4k... ");
01389     test_pack(packets,headret);
01390   }
01391 
01392   {
01393     /* continuing packet test */
01394     const int packets[]={0,4345,259,255,-1};
01395     const int *headret[]={head1_4,head2_4,head3_4,NULL};
01396     
01397     fprintf(stderr,"testing single packet page span... ");
01398     test_pack(packets,headret);
01399   }
01400 
01401   /* page with the 255 segment limit */
01402   {
01403 
01404     const int packets[]={0,10,10,10,10,10,10,10,10,
01405                    10,10,10,10,10,10,10,10,
01406                    10,10,10,10,10,10,10,10,
01407                    10,10,10,10,10,10,10,10,
01408                    10,10,10,10,10,10,10,10,
01409                    10,10,10,10,10,10,10,10,
01410                    10,10,10,10,10,10,10,10,
01411                    10,10,10,10,10,10,10,10,
01412                    10,10,10,10,10,10,10,10,
01413                    10,10,10,10,10,10,10,10,
01414                    10,10,10,10,10,10,10,10,
01415                    10,10,10,10,10,10,10,10,
01416                    10,10,10,10,10,10,10,10,
01417                    10,10,10,10,10,10,10,10,
01418                    10,10,10,10,10,10,10,10,
01419                    10,10,10,10,10,10,10,10,
01420                    10,10,10,10,10,10,10,10,
01421                    10,10,10,10,10,10,10,10,
01422                    10,10,10,10,10,10,10,10,
01423                    10,10,10,10,10,10,10,10,
01424                    10,10,10,10,10,10,10,10,
01425                    10,10,10,10,10,10,10,10,
01426                    10,10,10,10,10,10,10,10,
01427                    10,10,10,10,10,10,10,10,
01428                    10,10,10,10,10,10,10,10,
01429                    10,10,10,10,10,10,10,10,
01430                    10,10,10,10,10,10,10,10,
01431                    10,10,10,10,10,10,10,10,
01432                    10,10,10,10,10,10,10,10,
01433                    10,10,10,10,10,10,10,10,
01434                    10,10,10,10,10,10,10,10,
01435                    10,10,10,10,10,10,10,50,-1};
01436     const int *headret[]={head1_5,head2_5,head3_5,NULL};
01437     
01438     fprintf(stderr,"testing max packet segments... ");
01439     test_pack(packets,headret);
01440   }
01441 
01442   {
01443     /* packet that overspans over an entire page */
01444     const int packets[]={0,100,9000,259,255,-1};
01445     const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
01446     
01447     fprintf(stderr,"testing very large packets... ");
01448     test_pack(packets,headret);
01449   }
01450 
01451   {
01452     /* term only page.  why not? */
01453     const int packets[]={0,100,4080,-1};
01454     const int *headret[]={head1_7,head2_7,head3_7,NULL};
01455     
01456     fprintf(stderr,"testing zero data page (1 nil packet)... ");
01457     test_pack(packets,headret);
01458   }
01459 
01460 
01461 
01462   {
01463     /* build a bunch of pages for testing */
01464     unsigned char *data=_ogg_malloc(1024*1024);
01465     int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
01466     int inptr=0,i,j;
01467     ogg_page og[5];
01468     
01469     ogg_stream_reset(&os_en);
01470 
01471     for(i=0;pl[i]!=-1;i++){
01472       ogg_packet op;
01473       int len=pl[i];
01474       
01475       op.packet=data+inptr;
01476       op.bytes=len;
01477       op.e_o_s=(pl[i+1]<0?1:0);
01478       op.granulepos=(i+1)*1000;
01479 
01480       for(j=0;j<len;j++)data[inptr++]=i+j;
01481       ogg_stream_packetin(&os_en,&op);
01482     }
01483 
01484     _ogg_free(data);
01485 
01486     /* retrieve finished pages */
01487     for(i=0;i<5;i++){
01488       if(ogg_stream_pageout(&os_en,&og[i])==0){
01489         fprintf(stderr,"Too few pages output building sync tests!\n");
01490         exit(1);
01491       }
01492       copy_page(&og[i]);
01493     }
01494 
01495     /* Test lost pages on pagein/packetout: no rollback */
01496     {
01497       ogg_page temp;
01498       ogg_packet test;
01499 
01500       fprintf(stderr,"Testing loss of pages... ");
01501 
01502       ogg_sync_reset(&oy);
01503       ogg_stream_reset(&os_de);
01504       for(i=0;i<5;i++){
01505         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
01506                og[i].header_len);
01507         ogg_sync_wrote(&oy,og[i].header_len);
01508         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
01509         ogg_sync_wrote(&oy,og[i].body_len);
01510       }
01511 
01512       ogg_sync_pageout(&oy,&temp);
01513       ogg_stream_pagein(&os_de,&temp);
01514       ogg_sync_pageout(&oy,&temp);
01515       ogg_stream_pagein(&os_de,&temp);
01516       ogg_sync_pageout(&oy,&temp);
01517       /* skip */
01518       ogg_sync_pageout(&oy,&temp);
01519       ogg_stream_pagein(&os_de,&temp);
01520 
01521       /* do we get the expected results/packets? */
01522       
01523       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01524       checkpacket(&test,0,0,0);
01525       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01526       checkpacket(&test,100,1,-1);
01527       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01528       checkpacket(&test,4079,2,3000);
01529       if(ogg_stream_packetout(&os_de,&test)!=-1){
01530         fprintf(stderr,"Error: loss of page did not return error\n");
01531         exit(1);
01532       }
01533       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01534       checkpacket(&test,76,5,-1);
01535       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01536       checkpacket(&test,34,6,-1);
01537       fprintf(stderr,"ok.\n");
01538     }
01539 
01540     /* Test lost pages on pagein/packetout: rollback with continuation */
01541     {
01542       ogg_page temp;
01543       ogg_packet test;
01544 
01545       fprintf(stderr,"Testing loss of pages (rollback required)... ");
01546 
01547       ogg_sync_reset(&oy);
01548       ogg_stream_reset(&os_de);
01549       for(i=0;i<5;i++){
01550         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
01551                og[i].header_len);
01552         ogg_sync_wrote(&oy,og[i].header_len);
01553         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
01554         ogg_sync_wrote(&oy,og[i].body_len);
01555       }
01556 
01557       ogg_sync_pageout(&oy,&temp);
01558       ogg_stream_pagein(&os_de,&temp);
01559       ogg_sync_pageout(&oy,&temp);
01560       ogg_stream_pagein(&os_de,&temp);
01561       ogg_sync_pageout(&oy,&temp);
01562       ogg_stream_pagein(&os_de,&temp);
01563       ogg_sync_pageout(&oy,&temp);
01564       /* skip */
01565       ogg_sync_pageout(&oy,&temp);
01566       ogg_stream_pagein(&os_de,&temp);
01567 
01568       /* do we get the expected results/packets? */
01569       
01570       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01571       checkpacket(&test,0,0,0);
01572       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01573       checkpacket(&test,100,1,-1);
01574       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01575       checkpacket(&test,4079,2,3000);
01576       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01577       checkpacket(&test,2956,3,4000);
01578       if(ogg_stream_packetout(&os_de,&test)!=-1){
01579         fprintf(stderr,"Error: loss of page did not return error\n");
01580         exit(1);
01581       }
01582       if(ogg_stream_packetout(&os_de,&test)!=1)error();
01583       checkpacket(&test,300,13,14000);
01584       fprintf(stderr,"ok.\n");
01585     }
01586     
01587     /* the rest only test sync */
01588     {
01589       ogg_page og_de;
01590       /* Test fractional page inputs: incomplete capture */
01591       fprintf(stderr,"Testing sync on partial inputs... ");
01592       ogg_sync_reset(&oy);
01593       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
01594              3);
01595       ogg_sync_wrote(&oy,3);
01596       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01597       
01598       /* Test fractional page inputs: incomplete fixed header */
01599       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
01600              20);
01601       ogg_sync_wrote(&oy,20);
01602       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01603       
01604       /* Test fractional page inputs: incomplete header */
01605       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
01606              5);
01607       ogg_sync_wrote(&oy,5);
01608       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01609       
01610       /* Test fractional page inputs: incomplete body */
01611       
01612       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
01613              og[1].header_len-28);
01614       ogg_sync_wrote(&oy,og[1].header_len-28);
01615       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01616       
01617       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
01618       ogg_sync_wrote(&oy,1000);
01619       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01620       
01621       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
01622              og[1].body_len-1000);
01623       ogg_sync_wrote(&oy,og[1].body_len-1000);
01624       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
01625       
01626       fprintf(stderr,"ok.\n");
01627     }
01628 
01629     /* Test fractional page inputs: page + incomplete capture */
01630     {
01631       ogg_page og_de;
01632       fprintf(stderr,"Testing sync on 1+partial inputs... ");
01633       ogg_sync_reset(&oy); 
01634 
01635       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
01636              og[1].header_len);
01637       ogg_sync_wrote(&oy,og[1].header_len);
01638 
01639       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
01640              og[1].body_len);
01641       ogg_sync_wrote(&oy,og[1].body_len);
01642 
01643       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
01644              20);
01645       ogg_sync_wrote(&oy,20);
01646       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
01647       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01648 
01649       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
01650              og[1].header_len-20);
01651       ogg_sync_wrote(&oy,og[1].header_len-20);
01652       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
01653              og[1].body_len);
01654       ogg_sync_wrote(&oy,og[1].body_len);
01655       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
01656 
01657       fprintf(stderr,"ok.\n");
01658     }
01659     
01660     /* Test recapture: garbage + page */
01661     {
01662       ogg_page og_de;
01663       fprintf(stderr,"Testing search for capture... ");
01664       ogg_sync_reset(&oy); 
01665       
01666       /* 'garbage' */
01667       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
01668              og[1].body_len);
01669       ogg_sync_wrote(&oy,og[1].body_len);
01670 
01671       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
01672              og[1].header_len);
01673       ogg_sync_wrote(&oy,og[1].header_len);
01674 
01675       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
01676              og[1].body_len);
01677       ogg_sync_wrote(&oy,og[1].body_len);
01678 
01679       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
01680              20);
01681       ogg_sync_wrote(&oy,20);
01682       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01683       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
01684       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01685 
01686       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
01687              og[2].header_len-20);
01688       ogg_sync_wrote(&oy,og[2].header_len-20);
01689       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
01690              og[2].body_len);
01691       ogg_sync_wrote(&oy,og[2].body_len);
01692       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
01693 
01694       fprintf(stderr,"ok.\n");
01695     }
01696 
01697     /* Test recapture: page + garbage + page */
01698     {
01699       ogg_page og_de;
01700       fprintf(stderr,"Testing recapture... ");
01701       ogg_sync_reset(&oy); 
01702 
01703       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
01704              og[1].header_len);
01705       ogg_sync_wrote(&oy,og[1].header_len);
01706 
01707       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
01708              og[1].body_len);
01709       ogg_sync_wrote(&oy,og[1].body_len);
01710 
01711       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
01712              og[2].header_len);
01713       ogg_sync_wrote(&oy,og[2].header_len);
01714 
01715       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
01716              og[2].header_len);
01717       ogg_sync_wrote(&oy,og[2].header_len);
01718 
01719       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
01720 
01721       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
01722              og[2].body_len-5);
01723       ogg_sync_wrote(&oy,og[2].body_len-5);
01724 
01725       memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
01726              og[3].header_len);
01727       ogg_sync_wrote(&oy,og[3].header_len);
01728 
01729       memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
01730              og[3].body_len);
01731       ogg_sync_wrote(&oy,og[3].body_len);
01732 
01733       if(ogg_sync_pageout(&oy,&og_de)>0)error();
01734       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
01735 
01736       fprintf(stderr,"ok.\n");
01737     }
01738   }    
01739 
01740   return(0);
01741 }
01742 
01743 #endif
01744 
01745 
01746 
01747 

Generated by  doxygen 1.6.2