]> git.jsancho.org Git - lugaru.git/blob - libogg-1.0/src/framing.c
Removed static library GLU, added SGI's GLU sources.
[lugaru.git] / libogg-1.0 / src / framing.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
9  * by the Xiph.Org Foundation http://www.xiph.org/                  *
10  *                                                                  *
11  ********************************************************************
12
13  function: code raw [Vorbis] packets into framed OggSquish stream and
14            decode Ogg streams back into raw packets
15  last mod: $Id: framing.c,v 1.22 2002/07/11 09:09:08 xiphmont Exp $
16
17  note: The CRC code is directly derived from public domain code by
18  Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
19  for details.
20
21  ********************************************************************/
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ogg/ogg.h>
26
27 /* A complete description of Ogg framing exists in docs/framing.html */
28
29 int ogg_page_version(ogg_page *og){
30   return((int)(og->header[4]));
31 }
32
33 int ogg_page_continued(ogg_page *og){
34   return((int)(og->header[5]&0x01));
35 }
36
37 int ogg_page_bos(ogg_page *og){
38   return((int)(og->header[5]&0x02));
39 }
40
41 int ogg_page_eos(ogg_page *og){
42   return((int)(og->header[5]&0x04));
43 }
44
45 ogg_int64_t ogg_page_granulepos(ogg_page *og){
46   unsigned char *page=og->header;
47   ogg_int64_t granulepos=page[13]&(0xff);
48   granulepos= (granulepos<<8)|(page[12]&0xff);
49   granulepos= (granulepos<<8)|(page[11]&0xff);
50   granulepos= (granulepos<<8)|(page[10]&0xff);
51   granulepos= (granulepos<<8)|(page[9]&0xff);
52   granulepos= (granulepos<<8)|(page[8]&0xff);
53   granulepos= (granulepos<<8)|(page[7]&0xff);
54   granulepos= (granulepos<<8)|(page[6]&0xff);
55   return(granulepos);
56 }
57
58 int ogg_page_serialno(ogg_page *og){
59   return(og->header[14] |
60          (og->header[15]<<8) |
61          (og->header[16]<<16) |
62          (og->header[17]<<24));
63 }
64  
65 long ogg_page_pageno(ogg_page *og){
66   return(og->header[18] |
67          (og->header[19]<<8) |
68          (og->header[20]<<16) |
69          (og->header[21]<<24));
70 }
71
72
73
74 /* returns the number of packets that are completed on this page (if
75    the leading packet is begun on a previous page, but ends on this
76    page, it's counted */
77
78 /* NOTE:
79 If a page consists of a packet begun on a previous page, and a new
80 packet begun (but not completed) on this page, the return will be:
81   ogg_page_packets(page)   ==1, 
82   ogg_page_continued(page) !=0
83
84 If a page happens to be a single packet that was begun on a
85 previous page, and spans to the next page (in the case of a three or
86 more page packet), the return will be: 
87   ogg_page_packets(page)   ==0, 
88   ogg_page_continued(page) !=0
89 */
90
91 int ogg_page_packets(ogg_page *og){
92   int i,n=og->header[26],count=0;
93   for(i=0;i<n;i++)
94     if(og->header[27+i]<255)count++;
95   return(count);
96 }
97
98
99 #if 0
100 /* helper to initialize lookup for direct-table CRC (illustrative; we
101    use the static init below) */
102
103 static ogg_uint32_t _ogg_crc_entry(unsigned long index){
104   int           i;
105   unsigned long r;
106
107   r = index << 24;
108   for (i=0; i<8; i++)
109     if (r & 0x80000000UL)
110       r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
111                                     polynomial, although we use an
112                                     unreflected alg and an init/final
113                                     of 0, not 0xffffffff */
114     else
115        r<<=1;
116  return (r & 0xffffffffUL);
117 }
118 #endif
119
120 static ogg_uint32_t crc_lookup[256]={
121   0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
122   0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
123   0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
124   0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
125   0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
126   0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
127   0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
128   0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
129   0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
130   0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
131   0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
132   0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
133   0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
134   0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
135   0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
136   0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
137   0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
138   0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
139   0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
140   0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
141   0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
142   0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
143   0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
144   0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
145   0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
146   0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
147   0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
148   0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
149   0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
150   0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
151   0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
152   0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
153   0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
154   0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
155   0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
156   0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
157   0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
158   0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
159   0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
160   0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
161   0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
162   0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
163   0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
164   0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
165   0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
166   0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
167   0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
168   0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
169   0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
170   0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
171   0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
172   0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
173   0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
174   0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
175   0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
176   0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
177   0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
178   0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
179   0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
180   0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
181   0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
182   0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
183   0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
184   0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
185
186 /* init the encode/decode logical stream state */
187
188 int ogg_stream_init(ogg_stream_state *os,int serialno){
189   if(os){
190     memset(os,0,sizeof(*os));
191     os->body_storage=16*1024;
192     os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
193
194     os->lacing_storage=1024;
195     os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
196     os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
197
198     os->serialno=serialno;
199
200     return(0);
201   }
202   return(-1);
203
204
205 /* _clear does not free os, only the non-flat storage within */
206 int ogg_stream_clear(ogg_stream_state *os){
207   if(os){
208     if(os->body_data)_ogg_free(os->body_data);
209     if(os->lacing_vals)_ogg_free(os->lacing_vals);
210     if(os->granule_vals)_ogg_free(os->granule_vals);
211
212     memset(os,0,sizeof(*os));    
213   }
214   return(0);
215
216
217 int ogg_stream_destroy(ogg_stream_state *os){
218   if(os){
219     ogg_stream_clear(os);
220     _ogg_free(os);
221   }
222   return(0);
223
224
225 /* Helpers for ogg_stream_encode; this keeps the structure and
226    what's happening fairly clear */
227
228 static void _os_body_expand(ogg_stream_state *os,int needed){
229   if(os->body_storage<=os->body_fill+needed){
230     os->body_storage+=(needed+1024);
231     os->body_data=_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
232   }
233 }
234
235 static void _os_lacing_expand(ogg_stream_state *os,int needed){
236   if(os->lacing_storage<=os->lacing_fill+needed){
237     os->lacing_storage+=(needed+32);
238     os->lacing_vals=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
239     os->granule_vals=_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
240   }
241 }
242
243 /* checksum the page */
244 /* Direct table CRC; note that this will be faster in the future if we
245    perform the checksum silmultaneously with other copies */
246
247 void ogg_page_checksum_set(ogg_page *og){
248   if(og){
249     ogg_uint32_t crc_reg=0;
250     int i;
251
252     /* safety; needed for API behavior, but not framing code */
253     og->header[22]=0;
254     og->header[23]=0;
255     og->header[24]=0;
256     og->header[25]=0;
257     
258     for(i=0;i<og->header_len;i++)
259       crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
260     for(i=0;i<og->body_len;i++)
261       crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
262     
263     og->header[22]=crc_reg&0xff;
264     og->header[23]=(crc_reg>>8)&0xff;
265     og->header[24]=(crc_reg>>16)&0xff;
266     og->header[25]=(crc_reg>>24)&0xff;
267   }
268 }
269
270 /* submit data to the internal buffer of the framing engine */
271 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
272   int lacing_vals=op->bytes/255+1,i;
273
274   if(os->body_returned){
275     /* advance packet data according to the body_returned pointer. We
276        had to keep it around to return a pointer into the buffer last
277        call */
278     
279     os->body_fill-=os->body_returned;
280     if(os->body_fill)
281       memmove(os->body_data,os->body_data+os->body_returned,
282               os->body_fill);
283     os->body_returned=0;
284   }
285  
286   /* make sure we have the buffer storage */
287   _os_body_expand(os,op->bytes);
288   _os_lacing_expand(os,lacing_vals);
289
290   /* Copy in the submitted packet.  Yes, the copy is a waste; this is
291      the liability of overly clean abstraction for the time being.  It
292      will actually be fairly easy to eliminate the extra copy in the
293      future */
294
295   memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
296   os->body_fill+=op->bytes;
297
298   /* Store lacing vals for this packet */
299   for(i=0;i<lacing_vals-1;i++){
300     os->lacing_vals[os->lacing_fill+i]=255;
301     os->granule_vals[os->lacing_fill+i]=os->granulepos;
302   }
303   os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
304   os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos;
305
306   /* flag the first segment as the beginning of the packet */
307   os->lacing_vals[os->lacing_fill]|= 0x100;
308
309   os->lacing_fill+=lacing_vals;
310
311   /* for the sake of completeness */
312   os->packetno++;
313
314   if(op->e_o_s)os->e_o_s=1;
315
316   return(0);
317 }
318
319 /* This will flush remaining packets into a page (returning nonzero),
320    even if there is not enough data to trigger a flush normally
321    (undersized page). If there are no packets or partial packets to
322    flush, ogg_stream_flush returns 0.  Note that ogg_stream_flush will
323    try to flush a normal sized page like ogg_stream_pageout; a call to
324    ogg_stream_flush does not gurantee that all packets have flushed.
325    Only a return value of 0 from ogg_stream_flush indicates all packet
326    data is flushed into pages.
327
328    ogg_stream_page will flush the last page in a stream even if it's
329    undersized; you almost certainly want to use ogg_stream_pageout
330    (and *not* ogg_stream_flush) unless you need to flush an undersized
331    page in the middle of a stream for some reason. */
332
333 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
334   int i;
335   int vals=0;
336   int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
337   int bytes=0;
338   long acc=0;
339   ogg_int64_t granule_pos=os->granule_vals[0];
340
341   if(maxvals==0)return(0);
342   
343   /* construct a page */
344   /* decide how many segments to include */
345   
346   /* If this is the initial header case, the first page must only include
347      the initial header packet */
348   if(os->b_o_s==0){  /* 'initial header page' case */
349     granule_pos=0;
350     for(vals=0;vals<maxvals;vals++){
351       if((os->lacing_vals[vals]&0x0ff)<255){
352         vals++;
353         break;
354       }
355     }
356   }else{
357     for(vals=0;vals<maxvals;vals++){
358       if(acc>4096)break;
359       acc+=os->lacing_vals[vals]&0x0ff;
360       granule_pos=os->granule_vals[vals];
361     }
362   }
363   
364   /* construct the header in temp storage */
365   memcpy(os->header,"OggS",4);
366   
367   /* stream structure version */
368   os->header[4]=0x00;
369   
370   /* continued packet flag? */
371   os->header[5]=0x00;
372   if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
373   /* first page flag? */
374   if(os->b_o_s==0)os->header[5]|=0x02;
375   /* last page flag? */
376   if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
377   os->b_o_s=1;
378
379   /* 64 bits of PCM position */
380   for(i=6;i<14;i++){
381     os->header[i]=(granule_pos&0xff);
382     granule_pos>>=8;
383   }
384
385   /* 32 bits of stream serial number */
386   {
387     long serialno=os->serialno;
388     for(i=14;i<18;i++){
389       os->header[i]=(serialno&0xff);
390       serialno>>=8;
391     }
392   }
393
394   /* 32 bits of page counter (we have both counter and page header
395      because this val can roll over) */
396   if(os->pageno==-1)os->pageno=0; /* because someone called
397                                      stream_reset; this would be a
398                                      strange thing to do in an
399                                      encode stream, but it has
400                                      plausible uses */
401   {
402     long pageno=os->pageno++;
403     for(i=18;i<22;i++){
404       os->header[i]=(pageno&0xff);
405       pageno>>=8;
406     }
407   }
408   
409   /* zero for computation; filled in later */
410   os->header[22]=0;
411   os->header[23]=0;
412   os->header[24]=0;
413   os->header[25]=0;
414   
415   /* segment table */
416   os->header[26]=vals&0xff;
417   for(i=0;i<vals;i++)
418     bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
419   
420   /* set pointers in the ogg_page struct */
421   og->header=os->header;
422   og->header_len=os->header_fill=vals+27;
423   og->body=os->body_data+os->body_returned;
424   og->body_len=bytes;
425   
426   /* advance the lacing data and set the body_returned pointer */
427   
428   os->lacing_fill-=vals;
429   memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
430   memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
431   os->body_returned+=bytes;
432   
433   /* calculate the checksum */
434   
435   ogg_page_checksum_set(og);
436
437   /* done */
438   return(1);
439 }
440
441
442 /* This constructs pages from buffered packet segments.  The pointers
443 returned are to static buffers; do not free. The returned buffers are
444 good only until the next call (using the same ogg_stream_state) */
445
446 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
447
448   if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
449      os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */
450      os->lacing_fill>=255 ||                  /* 'segment table full' case */
451      (os->lacing_fill&&!os->b_o_s)){          /* 'initial header page' case */
452         
453     return(ogg_stream_flush(os,og));
454   }
455   
456   /* not enough data to construct a page and not end of stream */
457   return(0);
458 }
459
460 int ogg_stream_eos(ogg_stream_state *os){
461   return os->e_o_s;
462 }
463
464 /* DECODING PRIMITIVES: packet streaming layer **********************/
465
466 /* This has two layers to place more of the multi-serialno and paging
467    control in the application's hands.  First, we expose a data buffer
468    using ogg_sync_buffer().  The app either copies into the
469    buffer, or passes it directly to read(), etc.  We then call
470    ogg_sync_wrote() to tell how many bytes we just added.
471
472    Pages are returned (pointers into the buffer in ogg_sync_state)
473    by ogg_sync_pageout().  The page is then submitted to
474    ogg_stream_pagein() along with the appropriate
475    ogg_stream_state* (ie, matching serialno).  We then get raw
476    packets out calling ogg_stream_packetout() with a
477    ogg_stream_state.  See the 'frame-prog.txt' docs for details and
478    example code. */
479
480 /* initialize the struct to a known state */
481 int ogg_sync_init(ogg_sync_state *oy){
482   if(oy){
483     memset(oy,0,sizeof(*oy));
484   }
485   return(0);
486 }
487
488 /* clear non-flat storage within */
489 int ogg_sync_clear(ogg_sync_state *oy){
490   if(oy){
491     if(oy->data)_ogg_free(oy->data);
492     ogg_sync_init(oy);
493   }
494   return(0);
495 }
496
497 int ogg_sync_destroy(ogg_sync_state *oy){
498   if(oy){
499     ogg_sync_clear(oy);
500     _ogg_free(oy);
501   }
502   return(0);
503 }
504
505 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
506
507   /* first, clear out any space that has been previously returned */
508   if(oy->returned){
509     oy->fill-=oy->returned;
510     if(oy->fill>0)
511       memmove(oy->data,oy->data+oy->returned,oy->fill);
512     oy->returned=0;
513   }
514
515   if(size>oy->storage-oy->fill){
516     /* We need to extend the internal buffer */
517     long newsize=size+oy->fill+4096; /* an extra page to be nice */
518
519     if(oy->data)
520       oy->data=_ogg_realloc(oy->data,newsize);
521     else
522       oy->data=_ogg_malloc(newsize);
523     oy->storage=newsize;
524   }
525
526   /* expose a segment at least as large as requested at the fill mark */
527   return((char *)oy->data+oy->fill);
528 }
529
530 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
531   if(oy->fill+bytes>oy->storage)return(-1);
532   oy->fill+=bytes;
533   return(0);
534 }
535
536 /* sync the stream.  This is meant to be useful for finding page
537    boundaries.
538
539    return values for this:
540   -n) skipped n bytes
541    0) page not ready; more data (no bytes skipped)
542    n) page synced at current location; page length n bytes
543    
544 */
545
546 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
547   unsigned char *page=oy->data+oy->returned;
548   unsigned char *next;
549   long bytes=oy->fill-oy->returned;
550   
551   if(oy->headerbytes==0){
552     int headerbytes,i;
553     if(bytes<27)return(0); /* not enough for a header */
554     
555     /* verify capture pattern */
556     if(memcmp(page,"OggS",4))goto sync_fail;
557     
558     headerbytes=page[26]+27;
559     if(bytes<headerbytes)return(0); /* not enough for header + seg table */
560     
561     /* count up body length in the segment table */
562     
563     for(i=0;i<page[26];i++)
564       oy->bodybytes+=page[27+i];
565     oy->headerbytes=headerbytes;
566   }
567   
568   if(oy->bodybytes+oy->headerbytes>bytes)return(0);
569   
570   /* The whole test page is buffered.  Verify the checksum */
571   {
572     /* Grab the checksum bytes, set the header field to zero */
573     char chksum[4];
574     ogg_page log;
575     
576     memcpy(chksum,page+22,4);
577     memset(page+22,0,4);
578     
579     /* set up a temp page struct and recompute the checksum */
580     log.header=page;
581     log.header_len=oy->headerbytes;
582     log.body=page+oy->headerbytes;
583     log.body_len=oy->bodybytes;
584     ogg_page_checksum_set(&log);
585     
586     /* Compare */
587     if(memcmp(chksum,page+22,4)){
588       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
589          at all) */
590       /* replace the computed checksum with the one actually read in */
591       memcpy(page+22,chksum,4);
592       
593       /* Bad checksum. Lose sync */
594       goto sync_fail;
595     }
596   }
597   
598   /* yes, have a whole page all ready to go */
599   {
600     unsigned char *page=oy->data+oy->returned;
601     long bytes;
602
603     if(og){
604       og->header=page;
605       og->header_len=oy->headerbytes;
606       og->body=page+oy->headerbytes;
607       og->body_len=oy->bodybytes;
608     }
609
610     oy->unsynced=0;
611     oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
612     oy->headerbytes=0;
613     oy->bodybytes=0;
614     return(bytes);
615   }
616   
617  sync_fail:
618   
619   oy->headerbytes=0;
620   oy->bodybytes=0;
621   
622   /* search for possible capture */
623   next=memchr(page+1,'O',bytes-1);
624   if(!next)
625     next=oy->data+oy->fill;
626
627   oy->returned=next-oy->data;
628   return(-(next-page));
629 }
630
631 /* sync the stream and get a page.  Keep trying until we find a page.
632    Supress 'sync errors' after reporting the first.
633
634    return values:
635    -1) recapture (hole in data)
636     0) need more data
637     1) page returned
638
639    Returns pointers into buffered data; invalidated by next call to
640    _stream, _clear, _init, or _buffer */
641
642 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
643
644   /* all we need to do is verify a page at the head of the stream
645      buffer.  If it doesn't verify, we look for the next potential
646      frame */
647
648   while(1){
649     long ret=ogg_sync_pageseek(oy,og);
650     if(ret>0){
651       /* have a page */
652       return(1);
653     }
654     if(ret==0){
655       /* need more data */
656       return(0);
657     }
658     
659     /* head did not start a synced page... skipped some bytes */
660     if(!oy->unsynced){
661       oy->unsynced=1;
662       return(-1);
663     }
664
665     /* loop. keep looking */
666
667   }
668 }
669
670 /* add the incoming page to the stream state; we decompose the page
671    into packet segments here as well. */
672
673 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
674   unsigned char *header=og->header;
675   unsigned char *body=og->body;
676   long           bodysize=og->body_len;
677   int            segptr=0;
678
679   int version=ogg_page_version(og);
680   int continued=ogg_page_continued(og);
681   int bos=ogg_page_bos(og);
682   int eos=ogg_page_eos(og);
683   ogg_int64_t granulepos=ogg_page_granulepos(og);
684   int serialno=ogg_page_serialno(og);
685   long pageno=ogg_page_pageno(og);
686   int segments=header[26];
687   
688   /* clean up 'returned data' */
689   {
690     long lr=os->lacing_returned;
691     long br=os->body_returned;
692
693     /* body data */
694     if(br){
695       os->body_fill-=br;
696       if(os->body_fill)
697         memmove(os->body_data,os->body_data+br,os->body_fill);
698       os->body_returned=0;
699     }
700
701     if(lr){
702       /* segment table */
703       if(os->lacing_fill-lr){
704         memmove(os->lacing_vals,os->lacing_vals+lr,
705                 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
706         memmove(os->granule_vals,os->granule_vals+lr,
707                 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
708       }
709       os->lacing_fill-=lr;
710       os->lacing_packet-=lr;
711       os->lacing_returned=0;
712     }
713   }
714
715   /* check the serial number */
716   if(serialno!=os->serialno)return(-1);
717   if(version>0)return(-1);
718
719   _os_lacing_expand(os,segments+1);
720
721   /* are we in sequence? */
722   if(pageno!=os->pageno){
723     int i;
724
725     /* unroll previous partial packet (if any) */
726     for(i=os->lacing_packet;i<os->lacing_fill;i++)
727       os->body_fill-=os->lacing_vals[i]&0xff;
728     os->lacing_fill=os->lacing_packet;
729
730     /* make a note of dropped data in segment table */
731     if(os->pageno!=-1){
732       os->lacing_vals[os->lacing_fill++]=0x400;
733       os->lacing_packet++;
734     }
735
736     /* are we a 'continued packet' page?  If so, we'll need to skip
737        some segments */
738     if(continued){
739       bos=0;
740       for(;segptr<segments;segptr++){
741         int val=header[27+segptr];
742         body+=val;
743         bodysize-=val;
744         if(val<255){
745           segptr++;
746           break;
747         }
748       }
749     }
750   }
751   
752   if(bodysize){
753     _os_body_expand(os,bodysize);
754     memcpy(os->body_data+os->body_fill,body,bodysize);
755     os->body_fill+=bodysize;
756   }
757
758   {
759     int saved=-1;
760     while(segptr<segments){
761       int val=header[27+segptr];
762       os->lacing_vals[os->lacing_fill]=val;
763       os->granule_vals[os->lacing_fill]=-1;
764       
765       if(bos){
766         os->lacing_vals[os->lacing_fill]|=0x100;
767         bos=0;
768       }
769       
770       if(val<255)saved=os->lacing_fill;
771       
772       os->lacing_fill++;
773       segptr++;
774       
775       if(val<255)os->lacing_packet=os->lacing_fill;
776     }
777   
778     /* set the granulepos on the last granuleval of the last full packet */
779     if(saved!=-1){
780       os->granule_vals[saved]=granulepos;
781     }
782
783   }
784
785   if(eos){
786     os->e_o_s=1;
787     if(os->lacing_fill>0)
788       os->lacing_vals[os->lacing_fill-1]|=0x200;
789   }
790
791   os->pageno=pageno+1;
792
793   return(0);
794 }
795
796 /* clear things to an initial state.  Good to call, eg, before seeking */
797 int ogg_sync_reset(ogg_sync_state *oy){
798   oy->fill=0;
799   oy->returned=0;
800   oy->unsynced=0;
801   oy->headerbytes=0;
802   oy->bodybytes=0;
803   return(0);
804 }
805
806 int ogg_stream_reset(ogg_stream_state *os){
807   os->body_fill=0;
808   os->body_returned=0;
809
810   os->lacing_fill=0;
811   os->lacing_packet=0;
812   os->lacing_returned=0;
813
814   os->header_fill=0;
815
816   os->e_o_s=0;
817   os->b_o_s=0;
818   os->pageno=-1;
819   os->packetno=0;
820   os->granulepos=0;
821
822   return(0);
823 }
824
825 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
826   ogg_stream_reset(os);
827   os->serialno=serialno;
828   return(0);
829 }
830
831 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
832
833   /* The last part of decode. We have the stream broken into packet
834      segments.  Now we need to group them into packets (or return the
835      out of sync markers) */
836
837   int ptr=os->lacing_returned;
838
839   if(os->lacing_packet<=ptr)return(0);
840
841   if(os->lacing_vals[ptr]&0x400){
842     /* we need to tell the codec there's a gap; it might need to
843        handle previous packet dependencies. */
844     os->lacing_returned++;
845     os->packetno++;
846     return(-1);
847   }
848
849   if(!op && !adv)return(1); /* just using peek as an inexpensive way
850                                to ask if there's a whole packet
851                                waiting */
852
853   /* Gather the whole packet. We'll have no holes or a partial packet */
854   {
855     int size=os->lacing_vals[ptr]&0xff;
856     int bytes=size;
857     int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
858     int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
859
860     while(size==255){
861       int val=os->lacing_vals[++ptr];
862       size=val&0xff;
863       if(val&0x200)eos=0x200;
864       bytes+=size;
865     }
866
867     if(op){
868       op->e_o_s=eos;
869       op->b_o_s=bos;
870       op->packet=os->body_data+os->body_returned;
871       op->packetno=os->packetno;
872       op->granulepos=os->granule_vals[ptr];
873       op->bytes=bytes;
874     }
875
876     if(adv){
877       os->body_returned+=bytes;
878       os->lacing_returned=ptr+1;
879       os->packetno++;
880     }
881   }
882   return(1);
883 }
884
885 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
886   return _packetout(os,op,1);
887 }
888
889 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
890   return _packetout(os,op,0);
891 }
892
893 void ogg_packet_clear(ogg_packet *op) {
894   _ogg_free(op->packet);
895   memset(op, 0, sizeof(*op));
896 }
897
898 #ifdef _V_SELFTEST
899 #include <stdio.h>
900
901 ogg_stream_state os_en, os_de;
902 ogg_sync_state oy;
903
904 void checkpacket(ogg_packet *op,int len, int no, int pos){
905   long j;
906   static int sequence=0;
907   static int lastno=0;
908
909   if(op->bytes!=len){
910     fprintf(stderr,"incorrect packet length!\n");
911     exit(1);
912   }
913   if(op->granulepos!=pos){
914     fprintf(stderr,"incorrect packet position!\n");
915     exit(1);
916   }
917
918   /* packet number just follows sequence/gap; adjust the input number
919      for that */
920   if(no==0){
921     sequence=0;
922   }else{
923     sequence++;
924     if(no>lastno+1)
925       sequence++;
926   }
927   lastno=no;
928   if(op->packetno!=sequence){
929     fprintf(stderr,"incorrect packet sequence %ld != %d\n",
930             (long)(op->packetno),sequence);
931     exit(1);
932   }
933
934   /* Test data */
935   for(j=0;j<op->bytes;j++)
936     if(op->packet[j]!=((j+no)&0xff)){
937       fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
938               j,op->packet[j],(j+no)&0xff);
939       exit(1);
940     }
941 }
942
943 void check_page(unsigned char *data,const int *header,ogg_page *og){
944   long j;
945   /* Test data */
946   for(j=0;j<og->body_len;j++)
947     if(og->body[j]!=data[j]){
948       fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
949               j,data[j],og->body[j]);
950       exit(1);
951     }
952
953   /* Test header */
954   for(j=0;j<og->header_len;j++){
955     if(og->header[j]!=header[j]){
956       fprintf(stderr,"header content mismatch at pos %ld:\n",j);
957       for(j=0;j<header[26]+27;j++)
958         fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
959       fprintf(stderr,"\n");
960       exit(1);
961     }
962   }
963   if(og->header_len!=header[26]+27){
964     fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
965             og->header_len,header[26]+27);
966     exit(1);
967   }
968 }
969
970 void print_header(ogg_page *og){
971   int j;
972   fprintf(stderr,"\nHEADER:\n");
973   fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
974           og->header[0],og->header[1],og->header[2],og->header[3],
975           (int)og->header[4],(int)og->header[5]);
976
977   fprintf(stderr,"  granulepos: %d  serialno: %d  pageno: %ld\n",
978           (og->header[9]<<24)|(og->header[8]<<16)|
979           (og->header[7]<<8)|og->header[6],
980           (og->header[17]<<24)|(og->header[16]<<16)|
981           (og->header[15]<<8)|og->header[14],
982           ((long)(og->header[21])<<24)|(og->header[20]<<16)|
983           (og->header[19]<<8)|og->header[18]);
984
985   fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
986           (int)og->header[22],(int)og->header[23],
987           (int)og->header[24],(int)og->header[25],
988           (int)og->header[26]);
989
990   for(j=27;j<og->header_len;j++)
991     fprintf(stderr,"%d ",(int)og->header[j]);
992   fprintf(stderr,")\n\n");
993 }
994
995 void copy_page(ogg_page *og){
996   unsigned char *temp=_ogg_malloc(og->header_len);
997   memcpy(temp,og->header,og->header_len);
998   og->header=temp;
999
1000   temp=_ogg_malloc(og->body_len);
1001   memcpy(temp,og->body,og->body_len);
1002   og->body=temp;
1003 }
1004
1005 void error(void){
1006   fprintf(stderr,"error!\n");
1007   exit(1);
1008 }
1009
1010 /* 17 only */
1011 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1012                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1013                        0x01,0x02,0x03,0x04,0,0,0,0,
1014                        0x15,0xed,0xec,0x91,
1015                        1,
1016                        17};
1017
1018 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1019 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1020                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1021                        0x01,0x02,0x03,0x04,0,0,0,0,
1022                        0x59,0x10,0x6c,0x2c,
1023                        1,
1024                        17};
1025 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1026                        0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1027                        0x01,0x02,0x03,0x04,1,0,0,0,
1028                        0x89,0x33,0x85,0xce,
1029                        13,
1030                        254,255,0,255,1,255,245,255,255,0,
1031                        255,255,90};
1032
1033 /* nil packets; beginning,middle,end */
1034 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1035                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1036                        0x01,0x02,0x03,0x04,0,0,0,0,
1037                        0xff,0x7b,0x23,0x17,
1038                        1,
1039                        0};
1040 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1041                        0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1042                        0x01,0x02,0x03,0x04,1,0,0,0,
1043                        0x5c,0x3f,0x66,0xcb,
1044                        17,
1045                        17,254,255,0,0,255,1,0,255,245,255,255,0,
1046                        255,255,90,0};
1047
1048 /* large initial packet */
1049 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1050                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1051                        0x01,0x02,0x03,0x04,0,0,0,0,
1052                        0x01,0x27,0x31,0xaa,
1053                        18,
1054                        255,255,255,255,255,255,255,255,
1055                        255,255,255,255,255,255,255,255,255,10};
1056
1057 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1058                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1059                        0x01,0x02,0x03,0x04,1,0,0,0,
1060                        0x7f,0x4e,0x8a,0xd2,
1061                        4,
1062                        255,4,255,0};
1063
1064
1065 /* continuing packet test */
1066 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1067                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1068                        0x01,0x02,0x03,0x04,0,0,0,0,
1069                        0xff,0x7b,0x23,0x17,
1070                        1,
1071                        0};
1072
1073 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1074                        0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1075                        0x01,0x02,0x03,0x04,1,0,0,0,
1076                        0x34,0x24,0xd5,0x29,
1077                        17,
1078                        255,255,255,255,255,255,255,255,
1079                        255,255,255,255,255,255,255,255,255};
1080
1081 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1082                        0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1083                        0x01,0x02,0x03,0x04,2,0,0,0,
1084                        0xc8,0xc3,0xcb,0xed,
1085                        5,
1086                        10,255,4,255,0};
1087
1088
1089 /* page with the 255 segment limit */
1090 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1091                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1092                        0x01,0x02,0x03,0x04,0,0,0,0,
1093                        0xff,0x7b,0x23,0x17,
1094                        1,
1095                        0};
1096
1097 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1098                        0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1099                        0x01,0x02,0x03,0x04,1,0,0,0,
1100                        0xed,0x2a,0x2e,0xa7,
1101                        255,
1102                        10,10,10,10,10,10,10,10,
1103                        10,10,10,10,10,10,10,10,
1104                        10,10,10,10,10,10,10,10,
1105                        10,10,10,10,10,10,10,10,
1106                        10,10,10,10,10,10,10,10,
1107                        10,10,10,10,10,10,10,10,
1108                        10,10,10,10,10,10,10,10,
1109                        10,10,10,10,10,10,10,10,
1110                        10,10,10,10,10,10,10,10,
1111                        10,10,10,10,10,10,10,10,
1112                        10,10,10,10,10,10,10,10,
1113                        10,10,10,10,10,10,10,10,
1114                        10,10,10,10,10,10,10,10,
1115                        10,10,10,10,10,10,10,10,
1116                        10,10,10,10,10,10,10,10,
1117                        10,10,10,10,10,10,10,10,
1118                        10,10,10,10,10,10,10,10,
1119                        10,10,10,10,10,10,10,10,
1120                        10,10,10,10,10,10,10,10,
1121                        10,10,10,10,10,10,10,10,
1122                        10,10,10,10,10,10,10,10,
1123                        10,10,10,10,10,10,10,10,
1124                        10,10,10,10,10,10,10,10,
1125                        10,10,10,10,10,10,10,10,
1126                        10,10,10,10,10,10,10,10,
1127                        10,10,10,10,10,10,10,10,
1128                        10,10,10,10,10,10,10,10,
1129                        10,10,10,10,10,10,10,10,
1130                        10,10,10,10,10,10,10,10,
1131                        10,10,10,10,10,10,10,10,
1132                        10,10,10,10,10,10,10,10,
1133                        10,10,10,10,10,10,10};
1134
1135 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1136                        0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1137                        0x01,0x02,0x03,0x04,2,0,0,0,
1138                        0x6c,0x3b,0x82,0x3d,
1139                        1,
1140                        50};
1141
1142
1143 /* packet that overspans over an entire page */
1144 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1145                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1146                        0x01,0x02,0x03,0x04,0,0,0,0,
1147                        0xff,0x7b,0x23,0x17,
1148                        1,
1149                        0};
1150
1151 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1152                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1153                        0x01,0x02,0x03,0x04,1,0,0,0,
1154                        0x3c,0xd9,0x4d,0x3f,
1155                        17,
1156                        100,255,255,255,255,255,255,255,255,
1157                        255,255,255,255,255,255,255,255};
1158
1159 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1160                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1161                        0x01,0x02,0x03,0x04,2,0,0,0,
1162                        0xbd,0xd5,0xb5,0x8b,
1163                        17,
1164                        255,255,255,255,255,255,255,255,
1165                        255,255,255,255,255,255,255,255,255};
1166
1167 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1168                        0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1169                        0x01,0x02,0x03,0x04,3,0,0,0,
1170                        0xef,0xdd,0x88,0xde,
1171                        7,
1172                        255,255,75,255,4,255,0};
1173
1174 /* packet that overspans over an entire page */
1175 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1176                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1177                        0x01,0x02,0x03,0x04,0,0,0,0,
1178                        0xff,0x7b,0x23,0x17,
1179                        1,
1180                        0};
1181
1182 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1183                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1184                        0x01,0x02,0x03,0x04,1,0,0,0,
1185                        0x3c,0xd9,0x4d,0x3f,
1186                        17,
1187                        100,255,255,255,255,255,255,255,255,
1188                        255,255,255,255,255,255,255,255};
1189
1190 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1191                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1192                        0x01,0x02,0x03,0x04,2,0,0,0,
1193                        0xd4,0xe0,0x60,0xe5,
1194                        1,0};
1195
1196 void test_pack(const int *pl, const int **headers){
1197   unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1198   long inptr=0;
1199   long outptr=0;
1200   long deptr=0;
1201   long depacket=0;
1202   long granule_pos=7,pageno=0;
1203   int i,j,packets,pageout=0;
1204   int eosflag=0;
1205   int bosflag=0;
1206
1207   ogg_stream_reset(&os_en);
1208   ogg_stream_reset(&os_de);
1209   ogg_sync_reset(&oy);
1210
1211   for(packets=0;;packets++)if(pl[packets]==-1)break;
1212
1213   for(i=0;i<packets;i++){
1214     /* construct a test packet */
1215     ogg_packet op;
1216     int len=pl[i];
1217     
1218     op.packet=data+inptr;
1219     op.bytes=len;
1220     op.e_o_s=(pl[i+1]<0?1:0);
1221     op.granulepos=granule_pos;
1222
1223     granule_pos+=1024;
1224
1225     for(j=0;j<len;j++)data[inptr++]=i+j;
1226
1227     /* submit the test packet */
1228     ogg_stream_packetin(&os_en,&op);
1229
1230     /* retrieve any finished pages */
1231     {
1232       ogg_page og;
1233       
1234       while(ogg_stream_pageout(&os_en,&og)){
1235         /* We have a page.  Check it carefully */
1236
1237         fprintf(stderr,"%ld, ",pageno);
1238
1239         if(headers[pageno]==NULL){
1240           fprintf(stderr,"coded too many pages!\n");
1241           exit(1);
1242         }
1243
1244         check_page(data+outptr,headers[pageno],&og);
1245
1246         outptr+=og.body_len;
1247         pageno++;
1248
1249         /* have a complete page; submit it to sync/decode */
1250
1251         {
1252           ogg_page og_de;
1253           ogg_packet op_de,op_de2;
1254           char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1255           memcpy(buf,og.header,og.header_len);
1256           memcpy(buf+og.header_len,og.body,og.body_len);
1257           ogg_sync_wrote(&oy,og.header_len+og.body_len);
1258
1259           while(ogg_sync_pageout(&oy,&og_de)>0){
1260             /* got a page.  Happy happy.  Verify that it's good. */
1261             
1262             check_page(data+deptr,headers[pageout],&og_de);
1263             deptr+=og_de.body_len;
1264             pageout++;
1265
1266             /* submit it to deconstitution */
1267             ogg_stream_pagein(&os_de,&og_de);
1268
1269             /* packets out? */
1270             while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1271               ogg_stream_packetpeek(&os_de,NULL);
1272               ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1273               
1274               /* verify peek and out match */
1275               if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1276                 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1277                         depacket);
1278                 exit(1);
1279               }
1280
1281               /* verify the packet! */
1282               /* check data */
1283               if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1284                 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1285                         depacket);
1286                 exit(1);
1287               }
1288               /* check bos flag */
1289               if(bosflag==0 && op_de.b_o_s==0){
1290                 fprintf(stderr,"b_o_s flag not set on packet!\n");
1291                 exit(1);
1292               }
1293               if(bosflag && op_de.b_o_s){
1294                 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1295                 exit(1);
1296               }
1297               bosflag=1;
1298               depacket+=op_de.bytes;
1299               
1300               /* check eos flag */
1301               if(eosflag){
1302                 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1303                 exit(1);
1304               }
1305
1306               if(op_de.e_o_s)eosflag=1;
1307
1308               /* check granulepos flag */
1309               if(op_de.granulepos!=-1){
1310                 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1311               }
1312             }
1313           }
1314         }
1315       }
1316     }
1317   }
1318   _ogg_free(data);
1319   if(headers[pageno]!=NULL){
1320     fprintf(stderr,"did not write last page!\n");
1321     exit(1);
1322   }
1323   if(headers[pageout]!=NULL){
1324     fprintf(stderr,"did not decode last page!\n");
1325     exit(1);
1326   }
1327   if(inptr!=outptr){
1328     fprintf(stderr,"encoded page data incomplete!\n");
1329     exit(1);
1330   }
1331   if(inptr!=deptr){
1332     fprintf(stderr,"decoded page data incomplete!\n");
1333     exit(1);
1334   }
1335   if(inptr!=depacket){
1336     fprintf(stderr,"decoded packet data incomplete!\n");
1337     exit(1);
1338   }
1339   if(!eosflag){
1340     fprintf(stderr,"Never got a packet with EOS set!\n");
1341     exit(1);
1342   }
1343   fprintf(stderr,"ok.\n");
1344 }
1345
1346 int main(void){
1347
1348   ogg_stream_init(&os_en,0x04030201);
1349   ogg_stream_init(&os_de,0x04030201);
1350   ogg_sync_init(&oy);
1351
1352   /* Exercise each code path in the framing code.  Also verify that
1353      the checksums are working.  */
1354
1355   {
1356     /* 17 only */
1357     const int packets[]={17, -1};
1358     const int *headret[]={head1_0,NULL};
1359     
1360     fprintf(stderr,"testing single page encoding... ");
1361     test_pack(packets,headret);
1362   }
1363
1364   {
1365     /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1366     const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1367     const int *headret[]={head1_1,head2_1,NULL};
1368     
1369     fprintf(stderr,"testing basic page encoding... ");
1370     test_pack(packets,headret);
1371   }
1372
1373   {
1374     /* nil packets; beginning,middle,end */
1375     const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1376     const int *headret[]={head1_2,head2_2,NULL};
1377     
1378     fprintf(stderr,"testing basic nil packets... ");
1379     test_pack(packets,headret);
1380   }
1381
1382   {
1383     /* large initial packet */
1384     const int packets[]={4345,259,255,-1};
1385     const int *headret[]={head1_3,head2_3,NULL};
1386     
1387     fprintf(stderr,"testing initial-packet lacing > 4k... ");
1388     test_pack(packets,headret);
1389   }
1390
1391   {
1392     /* continuing packet test */
1393     const int packets[]={0,4345,259,255,-1};
1394     const int *headret[]={head1_4,head2_4,head3_4,NULL};
1395     
1396     fprintf(stderr,"testing single packet page span... ");
1397     test_pack(packets,headret);
1398   }
1399
1400   /* page with the 255 segment limit */
1401   {
1402
1403     const int packets[]={0,10,10,10,10,10,10,10,10,
1404                    10,10,10,10,10,10,10,10,
1405                    10,10,10,10,10,10,10,10,
1406                    10,10,10,10,10,10,10,10,
1407                    10,10,10,10,10,10,10,10,
1408                    10,10,10,10,10,10,10,10,
1409                    10,10,10,10,10,10,10,10,
1410                    10,10,10,10,10,10,10,10,
1411                    10,10,10,10,10,10,10,10,
1412                    10,10,10,10,10,10,10,10,
1413                    10,10,10,10,10,10,10,10,
1414                    10,10,10,10,10,10,10,10,
1415                    10,10,10,10,10,10,10,10,
1416                    10,10,10,10,10,10,10,10,
1417                    10,10,10,10,10,10,10,10,
1418                    10,10,10,10,10,10,10,10,
1419                    10,10,10,10,10,10,10,10,
1420                    10,10,10,10,10,10,10,10,
1421                    10,10,10,10,10,10,10,10,
1422                    10,10,10,10,10,10,10,10,
1423                    10,10,10,10,10,10,10,10,
1424                    10,10,10,10,10,10,10,10,
1425                    10,10,10,10,10,10,10,10,
1426                    10,10,10,10,10,10,10,10,
1427                    10,10,10,10,10,10,10,10,
1428                    10,10,10,10,10,10,10,10,
1429                    10,10,10,10,10,10,10,10,
1430                    10,10,10,10,10,10,10,10,
1431                    10,10,10,10,10,10,10,10,
1432                    10,10,10,10,10,10,10,10,
1433                    10,10,10,10,10,10,10,10,
1434                    10,10,10,10,10,10,10,50,-1};
1435     const int *headret[]={head1_5,head2_5,head3_5,NULL};
1436     
1437     fprintf(stderr,"testing max packet segments... ");
1438     test_pack(packets,headret);
1439   }
1440
1441   {
1442     /* packet that overspans over an entire page */
1443     const int packets[]={0,100,9000,259,255,-1};
1444     const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1445     
1446     fprintf(stderr,"testing very large packets... ");
1447     test_pack(packets,headret);
1448   }
1449
1450   {
1451     /* term only page.  why not? */
1452     const int packets[]={0,100,4080,-1};
1453     const int *headret[]={head1_7,head2_7,head3_7,NULL};
1454     
1455     fprintf(stderr,"testing zero data page (1 nil packet)... ");
1456     test_pack(packets,headret);
1457   }
1458
1459
1460
1461   {
1462     /* build a bunch of pages for testing */
1463     unsigned char *data=_ogg_malloc(1024*1024);
1464     int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
1465     int inptr=0,i,j;
1466     ogg_page og[5];
1467     
1468     ogg_stream_reset(&os_en);
1469
1470     for(i=0;pl[i]!=-1;i++){
1471       ogg_packet op;
1472       int len=pl[i];
1473       
1474       op.packet=data+inptr;
1475       op.bytes=len;
1476       op.e_o_s=(pl[i+1]<0?1:0);
1477       op.granulepos=(i+1)*1000;
1478
1479       for(j=0;j<len;j++)data[inptr++]=i+j;
1480       ogg_stream_packetin(&os_en,&op);
1481     }
1482
1483     _ogg_free(data);
1484
1485     /* retrieve finished pages */
1486     for(i=0;i<5;i++){
1487       if(ogg_stream_pageout(&os_en,&og[i])==0){
1488         fprintf(stderr,"Too few pages output building sync tests!\n");
1489         exit(1);
1490       }
1491       copy_page(&og[i]);
1492     }
1493
1494     /* Test lost pages on pagein/packetout: no rollback */
1495     {
1496       ogg_page temp;
1497       ogg_packet test;
1498
1499       fprintf(stderr,"Testing loss of pages... ");
1500
1501       ogg_sync_reset(&oy);
1502       ogg_stream_reset(&os_de);
1503       for(i=0;i<5;i++){
1504         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1505                og[i].header_len);
1506         ogg_sync_wrote(&oy,og[i].header_len);
1507         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1508         ogg_sync_wrote(&oy,og[i].body_len);
1509       }
1510
1511       ogg_sync_pageout(&oy,&temp);
1512       ogg_stream_pagein(&os_de,&temp);
1513       ogg_sync_pageout(&oy,&temp);
1514       ogg_stream_pagein(&os_de,&temp);
1515       ogg_sync_pageout(&oy,&temp);
1516       /* skip */
1517       ogg_sync_pageout(&oy,&temp);
1518       ogg_stream_pagein(&os_de,&temp);
1519
1520       /* do we get the expected results/packets? */
1521       
1522       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1523       checkpacket(&test,0,0,0);
1524       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1525       checkpacket(&test,100,1,-1);
1526       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1527       checkpacket(&test,4079,2,3000);
1528       if(ogg_stream_packetout(&os_de,&test)!=-1){
1529         fprintf(stderr,"Error: loss of page did not return error\n");
1530         exit(1);
1531       }
1532       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1533       checkpacket(&test,76,5,-1);
1534       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1535       checkpacket(&test,34,6,-1);
1536       fprintf(stderr,"ok.\n");
1537     }
1538
1539     /* Test lost pages on pagein/packetout: rollback with continuation */
1540     {
1541       ogg_page temp;
1542       ogg_packet test;
1543
1544       fprintf(stderr,"Testing loss of pages (rollback required)... ");
1545
1546       ogg_sync_reset(&oy);
1547       ogg_stream_reset(&os_de);
1548       for(i=0;i<5;i++){
1549         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1550                og[i].header_len);
1551         ogg_sync_wrote(&oy,og[i].header_len);
1552         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1553         ogg_sync_wrote(&oy,og[i].body_len);
1554       }
1555
1556       ogg_sync_pageout(&oy,&temp);
1557       ogg_stream_pagein(&os_de,&temp);
1558       ogg_sync_pageout(&oy,&temp);
1559       ogg_stream_pagein(&os_de,&temp);
1560       ogg_sync_pageout(&oy,&temp);
1561       ogg_stream_pagein(&os_de,&temp);
1562       ogg_sync_pageout(&oy,&temp);
1563       /* skip */
1564       ogg_sync_pageout(&oy,&temp);
1565       ogg_stream_pagein(&os_de,&temp);
1566
1567       /* do we get the expected results/packets? */
1568       
1569       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1570       checkpacket(&test,0,0,0);
1571       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1572       checkpacket(&test,100,1,-1);
1573       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1574       checkpacket(&test,4079,2,3000);
1575       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1576       checkpacket(&test,2956,3,4000);
1577       if(ogg_stream_packetout(&os_de,&test)!=-1){
1578         fprintf(stderr,"Error: loss of page did not return error\n");
1579         exit(1);
1580       }
1581       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1582       checkpacket(&test,300,13,14000);
1583       fprintf(stderr,"ok.\n");
1584     }
1585     
1586     /* the rest only test sync */
1587     {
1588       ogg_page og_de;
1589       /* Test fractional page inputs: incomplete capture */
1590       fprintf(stderr,"Testing sync on partial inputs... ");
1591       ogg_sync_reset(&oy);
1592       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1593              3);
1594       ogg_sync_wrote(&oy,3);
1595       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1596       
1597       /* Test fractional page inputs: incomplete fixed header */
1598       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1599              20);
1600       ogg_sync_wrote(&oy,20);
1601       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1602       
1603       /* Test fractional page inputs: incomplete header */
1604       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1605              5);
1606       ogg_sync_wrote(&oy,5);
1607       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1608       
1609       /* Test fractional page inputs: incomplete body */
1610       
1611       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1612              og[1].header_len-28);
1613       ogg_sync_wrote(&oy,og[1].header_len-28);
1614       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1615       
1616       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1617       ogg_sync_wrote(&oy,1000);
1618       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1619       
1620       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1621              og[1].body_len-1000);
1622       ogg_sync_wrote(&oy,og[1].body_len-1000);
1623       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1624       
1625       fprintf(stderr,"ok.\n");
1626     }
1627
1628     /* Test fractional page inputs: page + incomplete capture */
1629     {
1630       ogg_page og_de;
1631       fprintf(stderr,"Testing sync on 1+partial inputs... ");
1632       ogg_sync_reset(&oy); 
1633
1634       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1635              og[1].header_len);
1636       ogg_sync_wrote(&oy,og[1].header_len);
1637
1638       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1639              og[1].body_len);
1640       ogg_sync_wrote(&oy,og[1].body_len);
1641
1642       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1643              20);
1644       ogg_sync_wrote(&oy,20);
1645       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1646       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1647
1648       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1649              og[1].header_len-20);
1650       ogg_sync_wrote(&oy,og[1].header_len-20);
1651       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1652              og[1].body_len);
1653       ogg_sync_wrote(&oy,og[1].body_len);
1654       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1655
1656       fprintf(stderr,"ok.\n");
1657     }
1658     
1659     /* Test recapture: garbage + page */
1660     {
1661       ogg_page og_de;
1662       fprintf(stderr,"Testing search for capture... ");
1663       ogg_sync_reset(&oy); 
1664       
1665       /* 'garbage' */
1666       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1667              og[1].body_len);
1668       ogg_sync_wrote(&oy,og[1].body_len);
1669
1670       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1671              og[1].header_len);
1672       ogg_sync_wrote(&oy,og[1].header_len);
1673
1674       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1675              og[1].body_len);
1676       ogg_sync_wrote(&oy,og[1].body_len);
1677
1678       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1679              20);
1680       ogg_sync_wrote(&oy,20);
1681       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1682       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1683       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1684
1685       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
1686              og[2].header_len-20);
1687       ogg_sync_wrote(&oy,og[2].header_len-20);
1688       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1689              og[2].body_len);
1690       ogg_sync_wrote(&oy,og[2].body_len);
1691       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1692
1693       fprintf(stderr,"ok.\n");
1694     }
1695
1696     /* Test recapture: page + garbage + page */
1697     {
1698       ogg_page og_de;
1699       fprintf(stderr,"Testing recapture... ");
1700       ogg_sync_reset(&oy); 
1701
1702       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1703              og[1].header_len);
1704       ogg_sync_wrote(&oy,og[1].header_len);
1705
1706       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1707              og[1].body_len);
1708       ogg_sync_wrote(&oy,og[1].body_len);
1709
1710       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1711              og[2].header_len);
1712       ogg_sync_wrote(&oy,og[2].header_len);
1713
1714       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1715              og[2].header_len);
1716       ogg_sync_wrote(&oy,og[2].header_len);
1717
1718       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1719
1720       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1721              og[2].body_len-5);
1722       ogg_sync_wrote(&oy,og[2].body_len-5);
1723
1724       memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
1725              og[3].header_len);
1726       ogg_sync_wrote(&oy,og[3].header_len);
1727
1728       memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
1729              og[3].body_len);
1730       ogg_sync_wrote(&oy,og[3].body_len);
1731
1732       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1733       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1734
1735       fprintf(stderr,"ok.\n");
1736     }
1737   }    
1738
1739   return(0);
1740 }
1741
1742 #endif
1743
1744
1745
1746