Main Page | Class List | Directories | File List | Class Members | File Members

framing.c

Go to the documentation of this file.
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 9601 2005-07-23 00:19:14Z giles $
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 static const 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=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
00193 
00194     os->lacing_storage=1024;
00195     os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
00196     os->granule_vals=_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=_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=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
00239     os->granule_vals=_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]=(unsigned char)(crc_reg&0xff);
00264     og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
00265     og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
00266     og->header[25]=(unsigned char)((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=-1;
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       if((os->lacing_vals[vals]&0xff)<255)
00361         granule_pos=os->granule_vals[vals];
00362     }
00363   }
00364   
00365   /* construct the header in temp storage */
00366   memcpy(os->header,"OggS",4);
00367   
00368   /* stream structure version */
00369   os->header[4]=0x00;
00370   
00371   /* continued packet flag? */
00372   os->header[5]=0x00;
00373   if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
00374   /* first page flag? */
00375   if(os->b_o_s==0)os->header[5]|=0x02;
00376   /* last page flag? */
00377   if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
00378   os->b_o_s=1;
00379 
00380   /* 64 bits of PCM position */
00381   for(i=6;i<14;i++){
00382     os->header[i]=(unsigned char)(granule_pos&0xff);
00383     granule_pos>>=8;
00384   }
00385 
00386   /* 32 bits of stream serial number */
00387   {
00388     long serialno=os->serialno;
00389     for(i=14;i<18;i++){
00390       os->header[i]=(unsigned char)(serialno&0xff);
00391       serialno>>=8;
00392     }
00393   }
00394 
00395   /* 32 bits of page counter (we have both counter and page header
00396      because this val can roll over) */
00397   if(os->pageno==-1)os->pageno=0; /* because someone called
00398                                      stream_reset; this would be a
00399                                      strange thing to do in an
00400                                      encode stream, but it has
00401                                      plausible uses */
00402   {
00403     long pageno=os->pageno++;
00404     for(i=18;i<22;i++){
00405       os->header[i]=(unsigned char)(pageno&0xff);
00406       pageno>>=8;
00407     }
00408   }
00409   
00410   /* zero for computation; filled in later */
00411   os->header[22]=0;
00412   os->header[23]=0;
00413   os->header[24]=0;
00414   os->header[25]=0;
00415   
00416   /* segment table */
00417   os->header[26]=(unsigned char)(vals&0xff);
00418   for(i=0;i<vals;i++)
00419     bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
00420   
00421   /* set pointers in the ogg_page struct */
00422   og->header=os->header;
00423   og->header_len=os->header_fill=vals+27;
00424   og->body=os->body_data+os->body_returned;
00425   og->body_len=bytes;
00426   
00427   /* advance the lacing data and set the body_returned pointer */
00428   
00429   os->lacing_fill-=vals;
00430   memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
00431   memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
00432   os->body_returned+=bytes;
00433   
00434   /* calculate the checksum */
00435   
00436   ogg_page_checksum_set(og);
00437 
00438   /* done */
00439   return(1);
00440 }
00441 
00442 
00443 /* This constructs pages from buffered packet segments.  The pointers
00444 returned are to static buffers; do not free. The returned buffers are
00445 good only until the next call (using the same ogg_stream_state) */
00446 
00447 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
00448 
00449   if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
00450      os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */
00451      os->lacing_fill>=255 ||                  /* 'segment table full' case */
00452      (os->lacing_fill&&!os->b_o_s)){          /* 'initial header page' case */
00453         
00454     return(ogg_stream_flush(os,og));
00455   }
00456   
00457   /* not enough data to construct a page and not end of stream */
00458   return(0);
00459 }
00460 
00461 int ogg_stream_eos(ogg_stream_state *os){
00462   return os->e_o_s;
00463 }
00464 
00465 /* DECODING PRIMITIVES: packet streaming layer **********************/
00466 
00467 /* This has two layers to place more of the multi-serialno and paging
00468    control in the application's hands.  First, we expose a data buffer
00469    using ogg_sync_buffer().  The app either copies into the
00470    buffer, or passes it directly to read(), etc.  We then call
00471    ogg_sync_wrote() to tell how many bytes we just added.
00472 
00473    Pages are returned (pointers into the buffer in ogg_sync_state)
00474    by ogg_sync_pageout().  The page is then submitted to
00475    ogg_stream_pagein() along with the appropriate
00476    ogg_stream_state* (ie, matching serialno).  We then get raw
00477    packets out calling ogg_stream_packetout() with a
00478    ogg_stream_state. */
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 /* clear non-flat storage within */
00489 int ogg_sync_clear(ogg_sync_state *oy){
00490   if(oy){
00491     if(oy->data)_ogg_free(oy->data);
00492     ogg_sync_init(oy);
00493   }
00494   return(0);
00495 }
00496 
00497 int ogg_sync_destroy(ogg_sync_state *oy){
00498   if(oy){
00499     ogg_sync_clear(oy);
00500     _ogg_free(oy);
00501   }
00502   return(0);
00503 }
00504 
00505 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
00506 
00507   /* first, clear out any space that has been previously returned */
00508   if(oy->returned){
00509     oy->fill-=oy->returned;
00510     if(oy->fill>0)
00511       memmove(oy->data,oy->data+oy->returned,oy->fill);
00512     oy->returned=0;
00513   }
00514 
00515   if(size>oy->storage-oy->fill){
00516     /* We need to extend the internal buffer */
00517     long newsize=size+oy->fill+4096; /* an extra page to be nice */
00518 
00519     if(oy->data)
00520       oy->data=_ogg_realloc(oy->data,newsize);
00521     else
00522       oy->data=_ogg_malloc(newsize);
00523     oy->storage=newsize;
00524   }
00525 
00526   /* expose a segment at least as large as requested at the fill mark */
00527   return((char *)oy->data+oy->fill);
00528 }
00529 
00530 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
00531   if(oy->fill+bytes>oy->storage)return(-1);
00532   oy->fill+=bytes;
00533   return(0);
00534 }
00535 
00536 /* sync the stream.  This is meant to be useful for finding page
00537    boundaries.
00538 
00539    return values for this:
00540   -n) skipped n bytes
00541    0) page not ready; more data (no bytes skipped)
00542    n) page synced at current location; page length n bytes
00543    
00544 */
00545 
00546 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
00547   unsigned char *page=oy->data+oy->returned;
00548   unsigned char *next;
00549   long bytes=oy->fill-oy->returned;
00550   
00551   if(oy->headerbytes==0){
00552     int headerbytes,i;
00553     if(bytes<27)return(0); /* not enough for a header */
00554     
00555     /* verify capture pattern */
00556     if(memcmp(page,"OggS",4))goto sync_fail;
00557     
00558     headerbytes=page[26]+27;
00559     if(bytes<headerbytes)return(0); /* not enough for header + seg table */
00560     
00561     /* count up body length in the segment table */
00562     
00563     for(i=0;i<page[26];i++)
00564       oy->bodybytes+=page[27+i];
00565     oy->headerbytes=headerbytes;
00566   }
00567   
00568   if(oy->bodybytes+oy->headerbytes>bytes)return(0);
00569   
00570   /* The whole test page is buffered.  Verify the checksum */
00571   {
00572     /* Grab the checksum bytes, set the header field to zero */
00573     char chksum[4];
00574     ogg_page log;
00575     
00576     memcpy(chksum,page+22,4);
00577     memset(page+22,0,4);
00578     
00579     /* set up a temp page struct and recompute the checksum */
00580     log.header=page;
00581     log.header_len=oy->headerbytes;
00582     log.body=page+oy->headerbytes;
00583     log.body_len=oy->bodybytes;
00584     ogg_page_checksum_set(&log);
00585     
00586     /* Compare */
00587     if(memcmp(chksum,page+22,4)){
00588       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
00589          at all) */
00590       /* replace the computed checksum with the one actually read in */
00591       memcpy(page+22,chksum,4);
00592       
00593       /* Bad checksum. Lose sync */
00594       goto sync_fail;
00595     }
00596   }
00597   
00598   /* yes, have a whole page all ready to go */
00599   {
00600     unsigned char *page=oy->data+oy->returned;
00601     long bytes;
00602 
00603     if(og){
00604       og->header=page;
00605       og->header_len=oy->headerbytes;
00606       og->body=page+oy->headerbytes;
00607       og->body_len=oy->bodybytes;
00608     }
00609 
00610     oy->unsynced=0;
00611     oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
00612     oy->headerbytes=0;
00613     oy->bodybytes=0;
00614     return(bytes);
00615   }
00616   
00617  sync_fail:
00618   
00619   oy->headerbytes=0;
00620   oy->bodybytes=0;
00621   
00622   /* search for possible capture */
00623   next=memchr(page+1,'O',bytes-1);
00624   if(!next)
00625     next=oy->data+oy->fill;
00626 
00627   oy->returned=next-oy->data;
00628   return(-(next-page));
00629 }
00630 
00631 /* sync the stream and get a page.  Keep trying until we find a page.
00632    Supress 'sync errors' after reporting the first.
00633 
00634    return values:
00635    -1) recapture (hole in data)
00636     0) need more data
00637     1) page returned
00638 
00639    Returns pointers into buffered data; invalidated by next call to
00640    _stream, _clear, _init, or _buffer */
00641 
00642 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
00643 
00644   /* all we need to do is verify a page at the head of the stream
00645      buffer.  If it doesn't verify, we look for the next potential
00646      frame */
00647 
00648   for(;;){
00649     long ret=ogg_sync_pageseek(oy,og);
00650     if(ret>0){
00651       /* have a page */
00652       return(1);
00653     }
00654     if(ret==0){
00655       /* need more data */
00656       return(0);
00657     }
00658     
00659     /* head did not start a synced page... skipped some bytes */
00660     if(!oy->unsynced){
00661       oy->unsynced=1;
00662       return(-1);
00663     }
00664 
00665     /* loop. keep looking */
00666 
00667   }
00668 }
00669 
00670 /* add the incoming page to the stream state; we decompose the page
00671    into packet segments here as well. */
00672 
00673 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
00674   unsigned char *header=og->header;
00675   unsigned char *body=og->body;
00676   long           bodysize=og->body_len;
00677   int            segptr=0;
00678 
00679   int version=ogg_page_version(og);
00680   int continued=ogg_page_continued(og);
00681   int bos=ogg_page_bos(og);
00682   int eos=ogg_page_eos(og);
00683   ogg_int64_t granulepos=ogg_page_granulepos(og);
00684   int serialno=ogg_page_serialno(og);
00685   long pageno=ogg_page_pageno(og);
00686   int segments=header[26];
00687   
00688   /* clean up 'returned data' */
00689   {
00690     long lr=os->lacing_returned;
00691     long br=os->body_returned;
00692 
00693     /* body data */
00694     if(br){
00695       os->body_fill-=br;
00696       if(os->body_fill)
00697         memmove(os->body_data,os->body_data+br,os->body_fill);
00698       os->body_returned=0;
00699     }
00700 
00701     if(lr){
00702       /* segment table */
00703       if(os->lacing_fill-lr){
00704         memmove(os->lacing_vals,os->lacing_vals+lr,
00705                 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
00706         memmove(os->granule_vals,os->granule_vals+lr,
00707                 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
00708       }
00709       os->lacing_fill-=lr;
00710       os->lacing_packet-=lr;
00711       os->lacing_returned=0;
00712     }
00713   }
00714 
00715   /* check the serial number */
00716   if(serialno!=os->serialno)return(-1);
00717   if(version>0)return(-1);
00718 
00719   _os_lacing_expand(os,segments+1);
00720 
00721   /* are we in sequence? */
00722   if(pageno!=os->pageno){
00723     int i;
00724 
00725     /* unroll previous partial packet (if any) */
00726     for(i=os->lacing_packet;i<os->lacing_fill;i++)
00727       os->body_fill-=os->lacing_vals[i]&0xff;
00728     os->lacing_fill=os->lacing_packet;
00729 
00730     /* make a note of dropped data in segment table */
00731     if(os->pageno!=-1){
00732       os->lacing_vals[os->lacing_fill++]=0x400;
00733       os->lacing_packet++;
00734     }
00735   }
00736 
00737   /* are we a 'continued packet' page?  If so, we may need to skip
00738      some segments */
00739   if(continued){
00740     if(os->lacing_fill<1 || 
00741        os->lacing_vals[os->lacing_fill-1]==0x400){
00742       bos=0;
00743       for(;segptr<segments;segptr++){
00744         int val=header[27+segptr];
00745         body+=val;
00746         bodysize-=val;
00747         if(val<255){
00748           segptr++;
00749           break;
00750         }
00751       }
00752     }
00753   }
00754   
00755   if(bodysize){
00756     _os_body_expand(os,bodysize);
00757     memcpy(os->body_data+os->body_fill,body,bodysize);
00758     os->body_fill+=bodysize;
00759   }
00760 
00761   {
00762     int saved=-1;
00763     while(segptr<segments){
00764       int val=header[27+segptr];
00765       os->lacing_vals[os->lacing_fill]=val;
00766       os->granule_vals[os->lacing_fill]=-1;
00767       
00768       if(bos){
00769         os->lacing_vals[os->lacing_fill]|=0x100;
00770         bos=0;
00771       }
00772       
00773       if(val<255)saved=os->lacing_fill;
00774       
00775       os->lacing_fill++;
00776       segptr++;
00777       
00778       if(val<255)os->lacing_packet=os->lacing_fill;
00779     }
00780   
00781     /* set the granulepos on the last granuleval of the last full packet */
00782     if(saved!=-1){
00783       os->granule_vals[saved]=granulepos;
00784     }
00785 
00786   }
00787 
00788   if(eos){
00789     os->e_o_s=1;
00790     if(os->lacing_fill>0)
00791       os->lacing_vals[os->lacing_fill-1]|=0x200;
00792   }
00793 
00794   os->pageno=pageno+1;
00795 
00796   return(0);
00797 }
00798 
00799 /* clear things to an initial state.  Good to call, eg, before seeking */
00800 int ogg_sync_reset(ogg_sync_state *oy){
00801   oy->fill=0;
00802   oy->returned=0;
00803   oy->unsynced=0;
00804   oy->headerbytes=0;
00805   oy->bodybytes=0;
00806   return(0);
00807 }
00808 
00809 int ogg_stream_reset(ogg_stream_state *os){
00810   os->body_fill=0;
00811   os->body_returned=0;
00812 
00813   os->lacing_fill=0;
00814   os->lacing_packet=0;
00815   os->lacing_returned=0;
00816 
00817   os->header_fill=0;
00818 
00819   os->e_o_s=0;
00820   os->b_o_s=0;
00821   os->pageno=-1;
00822   os->packetno=0;
00823   os->granulepos=0;
00824 
00825   return(0);
00826 }
00827 
00828 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
00829   ogg_stream_reset(os);
00830   os->serialno=serialno;
00831   return(0);
00832 }
00833 
00834 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
00835 
00836   /* The last part of decode. We have the stream broken into packet
00837      segments.  Now we need to group them into packets (or return the
00838      out of sync markers) */
00839 
00840   int ptr=os->lacing_returned;
00841 
00842   if(os->lacing_packet<=ptr)return(0);
00843 
00844   if(os->lacing_vals[ptr]&0x400){
00845     /* we need to tell the codec there's a gap; it might need to
00846        handle previous packet dependencies. */
00847     os->lacing_returned++;
00848     os->packetno++;
00849     return(-1);
00850   }
00851 
00852   if(!op && !adv)return(1); /* just using peek as an inexpensive way
00853                                to ask if there's a whole packet
00854                                waiting */
00855 
00856   /* Gather the whole packet. We'll have no holes or a partial packet */
00857   {
00858     int size=os->lacing_vals[ptr]&0xff;
00859     int bytes=size;
00860     int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
00861     int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
00862 
00863     while(size==255){
00864       int val=os->lacing_vals[++ptr];
00865       size=val&0xff;
00866       if(val&0x200)eos=0x200;
00867       bytes+=size;
00868     }
00869 
00870     if(op){
00871       op->e_o_s=eos;
00872       op->b_o_s=bos;
00873       op->packet=os->body_data+os->body_returned;
00874       op->packetno=os->packetno;
00875       op->granulepos=os->granule_vals[ptr];
00876       op->bytes=bytes;
00877     }
00878 
00879     if(adv){
00880       os->body_returned+=bytes;
00881       os->lacing_returned=ptr+1;
00882       os->packetno++;
00883     }
00884   }
00885   return(1);
00886 }
00887 
00888 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
00889   return _packetout(os,op,1);
00890 }
00891 
00892 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
00893   return _packetout(os,op,0);
00894 }
00895 
00896 void ogg_packet_clear(ogg_packet *op) {
00897   _ogg_free(op->packet);
00898   memset(op, 0, sizeof(*op));
00899 }
00900 
00901 #ifdef _V_SELFTEST
00902 #include <stdio.h>
00903 
00904 ogg_stream_state os_en, os_de;
00905 ogg_sync_state oy;
00906 
00907 void checkpacket(ogg_packet *op,int len, int no, int pos){
00908   long j;
00909   static int sequence=0;
00910   static int lastno=0;
00911 
00912   if(op->bytes!=len){
00913     fprintf(stderr,"incorrect packet length!\n");
00914     exit(1);
00915   }
00916   if(op->granulepos!=pos){
00917     fprintf(stderr,"incorrect packet position!\n");
00918     exit(1);
00919   }
00920 
00921   /* packet number just follows sequence/gap; adjust the input number
00922      for that */
00923   if(no==0){
00924     sequence=0;
00925   }else{
00926     sequence++;
00927     if(no>lastno+1)
00928       sequence++;
00929   }
00930   lastno=no;
00931   if(op->packetno!=sequence){
00932     fprintf(stderr,"incorrect packet sequence %ld != %d\n",
00933             (long)(op->packetno),sequence);
00934     exit(1);
00935   }
00936 
00937   /* Test data */
00938   for(j=0;j<op->bytes;j++)
00939     if(op->packet[j]!=((j+no)&0xff)){
00940       fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
00941               j,op->packet[j],(j+no)&0xff);
00942       exit(1);
00943     }
00944 }
00945 
00946 void check_page(unsigned char *data,const int *header,ogg_page *og){
00947   long j;
00948   /* Test data */
00949   for(j=0;j<og->body_len;j++)
00950     if(og->body[j]!=data[j]){
00951       fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
00952               j,data[j],og->body[j]);
00953       exit(1);
00954     }
00955 
00956   /* Test header */
00957   for(j=0;j<og->header_len;j++){
00958     if(og->header[j]!=header[j]){
00959       fprintf(stderr,"header content mismatch at pos %ld:\n",j);
00960       for(j=0;j<header[26]+27;j++)
00961         fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
00962       fprintf(stderr,"\n");
00963       exit(1);
00964     }
00965   }
00966   if(og->header_len!=header[26]+27){
00967     fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
00968             og->header_len,header[26]+27);
00969     exit(1);
00970   }
00971 }
00972 
00973 void print_header(ogg_page *og){
00974   int j;
00975   fprintf(stderr,"\nHEADER:\n");
00976   fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
00977           og->header[0],og->header[1],og->header[2],og->header[3],
00978           (int)og->header[4],(int)og->header[5]);
00979 
00980   fprintf(stderr,"  granulepos: %d  serialno: %d  pageno: %ld\n",
00981           (og->header[9]<<24)|(og->header[8]<<16)|
00982           (og->header[7]<<8)|og->header[6],
00983           (og->header[17]<<24)|(og->header[16]<<16)|
00984           (og->header[15]<<8)|og->header[14],
00985           ((long)(og->header[21])<<24)|(og->header[20]<<16)|
00986           (og->header[19]<<8)|og->header[18]);
00987 
00988   fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
00989           (int)og->header[22],(int)og->header[23],
00990           (int)og->header[24],(int)og->header[25],
00991           (int)og->header[26]);
00992 
00993   for(j=27;j<og->header_len;j++)
00994     fprintf(stderr,"%d ",(int)og->header[j]);
00995   fprintf(stderr,")\n\n");
00996 }
00997 
00998 void copy_page(ogg_page *og){
00999   unsigned char *temp=_ogg_malloc(og->header_len);
01000   memcpy(temp,og->header,og->header_len);
01001   og->header=temp;
01002 
01003   temp=_ogg_malloc(og->body_len);
01004   memcpy(temp,og->body,og->body_len);
01005   og->body=temp;
01006 }
01007 
01008 void free_page(ogg_page *og){
01009   _ogg_free (og->header);
01010   _ogg_free (og->body);
01011 }
01012 
01013 void error(void){
01014   fprintf(stderr,"error!\n");
01015   exit(1);
01016 }
01017 
01018 /* 17 only */
01019 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
01020                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01021                        0x01,0x02,0x03,0x04,0,0,0,0,
01022                        0x15,0xed,0xec,0x91,
01023                        1,
01024                        17};
01025 
01026 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
01027 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
01028                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01029                        0x01,0x02,0x03,0x04,0,0,0,0,
01030                        0x59,0x10,0x6c,0x2c,
01031                        1,
01032                        17};
01033 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
01034                        0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
01035                        0x01,0x02,0x03,0x04,1,0,0,0,
01036                        0x89,0x33,0x85,0xce,
01037                        13,
01038                        254,255,0,255,1,255,245,255,255,0,
01039                        255,255,90};
01040 
01041 /* nil packets; beginning,middle,end */
01042 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
01043                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01044                        0x01,0x02,0x03,0x04,0,0,0,0,
01045                        0xff,0x7b,0x23,0x17,
01046                        1,
01047                        0};
01048 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
01049                        0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
01050                        0x01,0x02,0x03,0x04,1,0,0,0,
01051                        0x5c,0x3f,0x66,0xcb,
01052                        17,
01053                        17,254,255,0,0,255,1,0,255,245,255,255,0,
01054                        255,255,90,0};
01055 
01056 /* large initial packet */
01057 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
01058                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01059                        0x01,0x02,0x03,0x04,0,0,0,0,
01060                        0x01,0x27,0x31,0xaa,
01061                        18,
01062                        255,255,255,255,255,255,255,255,
01063                        255,255,255,255,255,255,255,255,255,10};
01064 
01065 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
01066                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
01067                        0x01,0x02,0x03,0x04,1,0,0,0,
01068                        0x7f,0x4e,0x8a,0xd2,
01069                        4,
01070                        255,4,255,0};
01071 
01072 
01073 /* continuing packet test */
01074 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
01075                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01076                        0x01,0x02,0x03,0x04,0,0,0,0,
01077                        0xff,0x7b,0x23,0x17,
01078                        1,
01079                        0};
01080 
01081 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
01082                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
01083                        0x01,0x02,0x03,0x04,1,0,0,0,
01084                        0x54,0x05,0x51,0xc8,
01085                        17,
01086                        255,255,255,255,255,255,255,255,
01087                        255,255,255,255,255,255,255,255,255};
01088 
01089 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
01090                        0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
01091                        0x01,0x02,0x03,0x04,2,0,0,0,
01092                        0xc8,0xc3,0xcb,0xed,
01093                        5,
01094                        10,255,4,255,0};
01095 
01096 
01097 /* page with the 255 segment limit */
01098 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
01099                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01100                        0x01,0x02,0x03,0x04,0,0,0,0,
01101                        0xff,0x7b,0x23,0x17,
01102                        1,
01103                        0};
01104 
01105 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
01106                        0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
01107                        0x01,0x02,0x03,0x04,1,0,0,0,
01108                        0xed,0x2a,0x2e,0xa7,
01109                        255,
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,10,
01135                        10,10,10,10,10,10,10,10,
01136                        10,10,10,10,10,10,10,10,
01137                        10,10,10,10,10,10,10,10,
01138                        10,10,10,10,10,10,10,10,
01139                        10,10,10,10,10,10,10,10,
01140                        10,10,10,10,10,10,10,10,
01141                        10,10,10,10,10,10,10};
01142 
01143 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
01144                        0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
01145                        0x01,0x02,0x03,0x04,2,0,0,0,
01146                        0x6c,0x3b,0x82,0x3d,
01147                        1,
01148                        50};
01149 
01150 
01151 /* packet that overspans over an entire page */
01152 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
01153                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01154                        0x01,0x02,0x03,0x04,0,0,0,0,
01155                        0xff,0x7b,0x23,0x17,
01156                        1,
01157                        0};
01158 
01159 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
01160                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
01161                        0x01,0x02,0x03,0x04,1,0,0,0,
01162                        0x3c,0xd9,0x4d,0x3f,
01163                        17,
01164                        100,255,255,255,255,255,255,255,255,
01165                        255,255,255,255,255,255,255,255};
01166 
01167 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
01168                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
01169                        0x01,0x02,0x03,0x04,2,0,0,0,
01170                        0x01,0xd2,0xe5,0xe5,
01171                        17,
01172                        255,255,255,255,255,255,255,255,
01173                        255,255,255,255,255,255,255,255,255};
01174 
01175 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
01176                        0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
01177                        0x01,0x02,0x03,0x04,3,0,0,0,
01178                        0xef,0xdd,0x88,0xde,
01179                        7,
01180                        255,255,75,255,4,255,0};
01181 
01182 /* packet that overspans over an entire page */
01183 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
01184                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
01185                        0x01,0x02,0x03,0x04,0,0,0,0,
01186                        0xff,0x7b,0x23,0x17,
01187                        1,
01188                        0};
01189 
01190 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
01191                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
01192                        0x01,0x02,0x03,0x04,1,0,0,0,
01193                        0x3c,0xd9,0x4d,0x3f,
01194                        17,
01195                        100,255,255,255,255,255,255,255,255,
01196                        255,255,255,255,255,255,255,255};
01197 
01198 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
01199                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
01200                        0x01,0x02,0x03,0x04,2,0,0,0,
01201                        0xd4,0xe0,0x60,0xe5,
01202                        1,0};
01203 
01204 void test_pack(const int *pl, const int **headers, int byteskip, 
01205                int pageskip, int packetskip){
01206   unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
01207   long inptr=0;
01208   long outptr=0;
01209   long deptr=0;
01210   long depacket=0;
01211   long granule_pos=7,pageno=0;
01212   int i,j,packets,pageout=pageskip;
01213   int eosflag=0;
01214   int bosflag=0;
01215 
01216   int byteskipcount=0;
01217 
01218   ogg_stream_reset(&os_en);
01219   ogg_stream_reset(&os_de);
01220   ogg_sync_reset(&oy);
01221 
01222   for(packets=0;packets<packetskip;packets++)
01223     depacket+=pl[packets];
01224 
01225   for(packets=0;;packets++)if(pl[packets]==-1)break;
01226 
01227   for(i=0;i<packets;i++){
01228     /* construct a test packet */
01229     ogg_packet op;
01230     int len=pl[i];
01231     
01232     op.packet=data+inptr;
01233     op.bytes=len;
01234     op.e_o_s=(pl[i+1]<0?1:0);
01235     op.granulepos=granule_pos;
01236 
01237     granule_pos+=1024;
01238 
01239     for(j=0;j<len;j++)data[inptr++]=i+j;
01240 
01241     /* submit the test packet */
01242     ogg_stream_packetin(&os_en,&op);
01243 
01244     /* retrieve any finished pages */
01245     {
01246       ogg_page og;
01247       
01248       while(ogg_stream_pageout(&os_en,&og)){
01249         /* We have a page.  Check it carefully */
01250 
01251         fprintf(stderr,"%ld, ",pageno);
01252 
01253         if(headers[pageno]==NULL){
01254           fprintf(stderr,"coded too many pages!\n");
01255           exit(1);
01256         }
01257 
01258         check_page(data+outptr,headers[pageno],&og);
01259 
01260         outptr+=og.body_len;
01261         pageno++;
01262         if(pageskip){
01263           bosflag=1;
01264           pageskip--;
01265           deptr+=og.body_len;
01266         }
01267 
01268         /* have a complete page; submit it to sync/decode */
01269 
01270         {
01271           ogg_page og_de;
01272           ogg_packet op_de,op_de2;
01273           char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
01274           char *next=buf;
01275           byteskipcount+=og.header_len;
01276           if(byteskipcount>byteskip){
01277             memcpy(next,og.header,byteskipcount-byteskip);
01278             next+=byteskipcount-byteskip;
01279             byteskipcount=byteskip;
01280           }
01281 
01282           byteskipcount+=og.body_len;
01283           if(byteskipcount>byteskip){
01284             memcpy(next,og.body,byteskipcount-byteskip);
01285             next+=byteskipcount-byteskip;
01286             byteskipcount=byteskip;
01287           }
01288 
01289           ogg_sync_wrote(&oy,next-buf);
01290 
01291           while(1){
01292             int ret=ogg_sync_pageout(&oy,&og_de);
01293             if(ret==0)break;
01294             if(ret<0)continue;
01295             /* got a page.  Happy happy.  Verify that it's good. */
01296             
01297             fprintf(stderr,"(%ld), ",pageout);
01298 
01299             check_page(data+deptr,headers[pageout],&og_de);
01300             deptr+=og_de.body_len;
01301             pageout++;
01302 
01303             /* submit it to deconstitution */
01304             ogg_stream_pagein(&os_de,&og_de);
01305 
01306             /* packets out? */
01307             while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
01308               ogg_stream_packetpeek(&os_de,NULL);
01309               ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
01310               
01311               /* verify peek and out match */
01312               if(memcmp(&op_de,&op_de2,sizeof(op_de))){
01313                 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
01314                         depacket);
01315                 exit(1);
01316               }
01317 
01318               /* verify the packet! */
01319               /* check data */
01320               if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
01321                 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
01322                         depacket);
01323                 exit(1);
01324               }
01325               /* check bos flag */
01326               if(bosflag==0 && op_de.b_o_s==0){
01327                 fprintf(stderr,"b_o_s flag not set on packet!\n");
01328                 exit(1);
01329               }
01330               if(bosflag && op_de.b_o_s){
01331                 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
01332