Update encoder and decoder examples. One inch away from everything
[platform/upstream/libvorbis.git] / lib / framing.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE.  *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5  * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE.    *
6  * PLEASE READ THESE TERMS DISTRIBUTING.                            *
7  *                                                                  *
8  * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000             *
9  * by Monty <monty@xiph.org> and the XIPHOPHORUS Company            *
10  * http://www.xiph.org/                                             *
11  *                                                                  *
12  ********************************************************************
13
14  function: code raw [Vorbis] packets into framed OggSquish stream and
15            decode Ogg streams back into raw packets
16  last mod: $Id: framing.c,v 1.14 2000/01/12 11:34:40 xiphmont Exp $
17
18  note: The CRC code is directly derived from public domain code by
19  Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
20  for details.
21
22  ********************************************************************/
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include "vorbis/codec.h"
27
28 /* A complete description of Ogg framing exists in docs/framing.html */
29
30 int ogg_page_version(ogg_page *og){
31   return((int)(og->header[4]));
32 }
33
34 int ogg_page_continued(ogg_page *og){
35   return((int)(og->header[5]&0x01));
36 }
37
38 int ogg_page_bos(ogg_page *og){
39   return((int)(og->header[5]&0x02));
40 }
41
42 int ogg_page_eos(ogg_page *og){
43   return((int)(og->header[5]&0x04));
44 }
45
46 int64_t ogg_page_frameno(ogg_page *og){
47   unsigned char *page=og->header;
48   int64_t pcmpos=page[13]&(0xff);
49   pcmpos= (pcmpos<<8)|(page[12]&0xff);
50   pcmpos= (pcmpos<<8)|(page[11]&0xff);
51   pcmpos= (pcmpos<<8)|(page[10]&0xff);
52   pcmpos= (pcmpos<<8)|(page[9]&0xff);
53   pcmpos= (pcmpos<<8)|(page[8]&0xff);
54   pcmpos= (pcmpos<<8)|(page[7]&0xff);
55   pcmpos= (pcmpos<<8)|(page[6]&0xff);
56   return(pcmpos);
57 }
58
59 int ogg_page_serialno(ogg_page *og){
60   return(og->header[14] |
61          (og->header[15]<<8) |
62          (og->header[16]<<16) |
63          (og->header[17]<<24));
64 }
65  
66 int ogg_page_pageno(ogg_page *og){
67   return(og->header[18] |
68          (og->header[19]<<8) |
69          (og->header[20]<<16) |
70          (og->header[21]<<24));
71 }
72
73 /* helper to initialize lookup for direct-table CRC */
74
75 static u_int32_t crc_lookup[256];
76 static int crc_ready=0;
77
78 static u_int32_t _ogg_crc_entry(unsigned long index){
79   int           i;
80   unsigned long r;
81
82   r = index << 24;
83   for (i=0; i<8; i++)
84     if (r & 0x80000000UL)
85       r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
86                                     polynomial, although we use an
87                                     unreflected alg and an init/final
88                                     of 0, not 0xffffffff */
89     else
90        r<<=1;
91  return (r & 0xffffffffUL);
92 }
93
94 /* mind this in threaded code; sync_init and stream_init call it.
95    It's thread safe only after the first time it returns */
96
97 static void _ogg_crc_init(void){
98   if(!crc_ready){
99     /* initialize the crc_lookup table */
100     int i;
101     for (i=0;i<256;i++)
102       crc_lookup[i]=_ogg_crc_entry((unsigned long)i);
103     crc_ready=0;
104   }
105 }
106
107 /* init the encode/decode logical stream state */
108
109 int ogg_stream_init(ogg_stream_state *os,int serialno){
110   if(os){
111     memset(os,0,sizeof(ogg_stream_state));
112     os->body_storage=16*1024;
113     os->body_data=malloc(os->body_storage*sizeof(char));
114
115     os->lacing_storage=1024;
116     os->lacing_vals=malloc(os->lacing_storage*sizeof(int));
117     os->pcm_vals=malloc(os->lacing_storage*sizeof(int64_t));
118
119     /* initialize the crc_lookup table if not done */
120     _ogg_crc_init();
121
122     os->serialno=serialno;
123
124     return(0);
125   }
126   return(-1);
127
128
129 /* _clear does not free os, only the non-flat storage within */
130 int ogg_stream_clear(ogg_stream_state *os){
131   if(os){
132     if(os->body_data)free(os->body_data);
133     if(os->lacing_vals)free(os->lacing_vals);
134     if(os->pcm_vals)free(os->pcm_vals);
135
136     memset(os,0,sizeof(ogg_stream_state));    
137   }
138   return(0);
139
140
141 int ogg_stream_destroy(ogg_stream_state *os){
142   if(os){
143     ogg_stream_clear(os);
144     free(os);
145   }
146   return(0);
147
148
149 /* Helpers for ogg_stream_encode; this keeps the structure and
150    what's happening fairly clear */
151
152 static void _os_body_expand(ogg_stream_state *os,int needed){
153   if(os->body_storage<=os->body_fill+needed){
154     os->body_storage+=(needed+1024);
155     os->body_data=realloc(os->body_data,os->body_storage);
156   }
157 }
158
159 static void _os_lacing_expand(ogg_stream_state *os,int needed){
160   if(os->lacing_storage<=os->lacing_fill+needed){
161     os->lacing_storage+=(needed+32);
162     os->lacing_vals=realloc(os->lacing_vals,os->lacing_storage*sizeof(int));
163     os->pcm_vals=realloc(os->pcm_vals,os->lacing_storage*sizeof(int64_t));
164   }
165 }
166
167 /* checksum the page */
168 /* Direct table CRC; note that this will be faster in the future if we
169    perform the checksum silmultaneously with other copies */
170
171 static void _os_checksum(ogg_page *og){
172   u_int32_t crc_reg=0;
173   int i;
174
175   for(i=0;i<og->header_len;i++)
176     crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
177   for(i=0;i<og->body_len;i++)
178     crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
179   
180   og->header[22]=crc_reg&0xff;
181   og->header[23]=(crc_reg>>8)&0xff;
182   og->header[24]=(crc_reg>>16)&0xff;
183   og->header[25]=(crc_reg>>24)&0xff;
184 }
185
186 /* submit data to the internal buffer of the framing engine */
187 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
188   int lacing_vals=op->bytes/255+1,i;
189
190   /* make sure we have the buffer storage */
191   _os_body_expand(os,op->bytes);
192   _os_lacing_expand(os,lacing_vals);
193
194   /* Copy in the submitted packet.  Yes, the copy is a waste; this is
195      the liability of overly clean abstraction for the time being.  It
196      will actually be fairly easy to eliminate the extra copy in the
197      future */
198
199   memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
200   os->body_fill+=op->bytes;
201
202   /* Store lacing vals for this packet */
203   for(i=0;i<lacing_vals-1;i++){
204     os->lacing_vals[os->lacing_fill+i]=255;
205     os->pcm_vals[os->lacing_fill+i]=os->pcmpos;
206   }
207   os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
208   os->pcmpos=os->pcm_vals[os->lacing_fill+i]=op->frameno;
209
210   /* flag the first segment as the beginning of the packet */
211   os->lacing_vals[os->lacing_fill]|= 0x100;
212
213   os->lacing_fill+=lacing_vals;
214
215   /* for the sake of completeness */
216   os->packetno++;
217
218   if(op->e_o_s)os->e_o_s=1;
219
220   return(0);
221 }
222
223 /* This constructs pages from buffered packet segments.  The pointers
224 returned are to static buffers; do not free. The returned buffers are
225 good only until the next call (using the same ogg_stream_state) */
226
227 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
228   int i;
229
230   if(os->body_returned){
231     /* advance packet data according to the body_returned pointer. We
232        had to keep it around to return a pointer into the buffer last
233        call */
234
235     os->body_fill-=os->body_returned;
236     if(os->body_fill)
237       memmove(os->body_data,os->body_data+os->body_returned,
238               os->body_fill*sizeof(char));
239     os->body_returned=0;
240   }
241
242   if((os->e_o_s&&os->lacing_fill) ||  /* 'were done, now flush' case */
243      os->body_fill > 4096 ||          /* 'page nominal size' case */
244      os->lacing_fill>=255 ||          /* 'segment table full' case */
245      (os->lacing_fill&&!os->b_o_s)){  /* 'initial header page' case */
246
247     int vals=0,bytes=0;
248     int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
249     long acc=0;
250     int64_t pcm_pos=os->pcm_vals[0];
251
252     /* construct a page */
253     /* decide how many segments to include */
254
255     /* If this is the initial header case, the first page must only include
256        the initial header packet */
257     if(os->b_o_s==0){  /* 'initial header page' case */
258       pcm_pos=0;
259       for(vals=0;vals<maxvals;vals++){
260         if((os->lacing_vals[vals]&0x0ff)<255){
261           vals++;
262           break;
263         }
264       }
265     }else{
266       for(vals=0;vals<maxvals;vals++){
267         if(acc>4096)break;
268         acc+=os->lacing_vals[vals]&0x0ff;
269         pcm_pos=os->pcm_vals[vals];
270       }
271     }
272
273     /* construct the header in temp storage */
274     memcpy(os->header,"OggS",4);
275
276     /* stream structure version */
277     os->header[4]=0x00;
278     
279     /* continued packet flag? */
280     os->header[5]=0x00;
281     if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
282     /* first page flag? */
283     if(os->b_o_s==0)os->header[5]|=0x02;
284     /* last page flag? */
285     if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
286     os->b_o_s=1;
287
288     /* 64 bits of PCM position */
289     for(i=6;i<14;i++){
290       os->header[i]=(pcm_pos&0xff);
291       pcm_pos>>=8;
292     }
293
294     /* 32 bits of stream serial number */
295     {
296       long serialno=os->serialno;
297       for(i=14;i<18;i++){
298         os->header[i]=(serialno&0xff);
299         serialno>>=8;
300       }
301     }
302
303     /* 32 bits of page counter (we have both counter and page header
304        because this val can roll over) */
305     {
306       long pageno=os->pageno++;
307       for(i=18;i<22;i++){
308         os->header[i]=(pageno&0xff);
309         pageno>>=8;
310       }
311     }
312
313     /* zero for computation; filled in later */
314     os->header[22]=0;
315     os->header[23]=0;
316     os->header[24]=0;
317     os->header[25]=0;
318
319     /* segment table */
320     os->header[26]=vals&0xff;
321     for(i=0;i<vals;i++)
322       bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
323       
324     /* advance the lacing data and set the body_returned pointer */
325
326     os->lacing_fill-=vals;
327     memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(int));
328     memmove(os->pcm_vals,os->pcm_vals+vals,os->lacing_fill*sizeof(int64_t));
329     os->body_returned=bytes;
330
331     /* set pointers in the ogg_page struct */
332     og->header=os->header;
333     og->header_len=os->header_fill=vals+27;
334     og->body=os->body_data;
335     og->body_len=bytes;
336
337     /* calculate the checksum */
338
339     _os_checksum(og);
340
341     return(1);
342   }
343
344   /* not enough data to construct a page and not end of stream */
345   return(0);
346 }
347
348 int ogg_stream_eof(ogg_stream_state *os){
349   return os->e_o_s;
350 }
351
352 /* DECODING PRIMITIVES: packet streaming layer **********************/
353
354 /* This has two layers to place more of the multi-serialno and paging
355    control in the application's hands.  First, we expose a data buffer
356    using ogg_decode_buffer().  The app either copies into the
357    buffer, or passes it directly to read(), etc.  We then call
358    ogg_decode_wrote() to tell how many bytes we just added.
359
360    Pages are returned (pointers into the buffer in ogg_sync_state)
361    by ogg_decode_stream().  The page is then submitted to
362    ogg_decode_page() along with the appropriate
363    ogg_stream_state* (ie, matching serialno).  We then get raw
364    packets out calling ogg_stream_packet() with a
365    ogg_stream_state.  See the 'frame-prog.txt' docs for details and
366    example code. */
367
368 /* initialize the struct to a known state */
369 int ogg_sync_init(ogg_sync_state *oy){
370   if(oy){
371     memset(oy,0,sizeof(ogg_sync_state));
372     _ogg_crc_init();
373   }
374   return(0);
375 }
376
377 /* clear non-flat storage within */
378 int ogg_sync_clear(ogg_sync_state *oy){
379   if(oy){
380     if(oy->data)free(oy->data);
381     ogg_sync_init(oy);
382   }
383   return(0);
384 }
385
386 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
387
388   /* first, clear out any space that has been previously returned */
389   if(oy->returned){
390     oy->fill-=oy->returned;
391     if(oy->fill>0)
392       memmove(oy->data,oy->data+oy->returned,
393               (oy->fill)*sizeof(char));
394     oy->returned=0;
395   }
396
397   if(size>oy->storage-oy->fill){
398     /* We need to extend the internal buffer */
399     long newsize=size+oy->fill+4096; /* an extra page to be nice */
400
401     if(oy->data)
402       oy->data=realloc(oy->data,newsize);
403     else
404       oy->data=malloc(newsize);
405     oy->storage=newsize;
406   }
407
408   /* expose a segment at least as large as requested at the fill mark */
409   return((char *)oy->data+oy->fill);
410 }
411
412 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
413   if(oy->fill+bytes>oy->storage)return(-1);
414   oy->fill+=bytes;
415   return(0);
416 }
417
418 /* sync the stream.  This is meant to be useful for finding page
419    boundaries.
420
421    return values for this:
422   -n) skipped n bytes
423    0) page not ready; more data (no bytes skipped)
424    n) page synced at current location; page length n bytes
425    
426 */
427
428 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
429   unsigned char *page=oy->data+oy->returned;
430   unsigned char *next;
431   long bytes=oy->fill-oy->returned;
432   
433   if(oy->headerbytes==0){
434     int headerbytes,i;
435     if(bytes<27)return(0); /* not enough for a header */
436     
437     /* verify capture pattern */
438     if(memcmp(page,"OggS",4))goto sync_fail;
439     
440     headerbytes=page[26]+27;
441     if(bytes<headerbytes)return(0); /* not enough for header + seg table */
442     
443     /* count up body length in the segment table */
444     
445     for(i=0;i<page[26];i++)
446       oy->bodybytes+=page[27+i];
447     oy->headerbytes=headerbytes;
448   }
449   
450   if(oy->bodybytes+oy->headerbytes>bytes)return(0);
451   
452   /* The whole test page is buffered.  Verify the checksum */
453   {
454     /* Grab the checksum bytes, set the header field to zero */
455     char chksum[4];
456     ogg_page log;
457     
458     memcpy(chksum,page+22,4);
459     memset(page+22,0,4);
460     
461     /* set up a temp page struct and recompute the checksum */
462     log.header=page;
463     log.header_len=oy->headerbytes;
464     log.body=page+oy->headerbytes;
465     log.body_len=oy->bodybytes;
466     _os_checksum(&log);
467     
468     /* Compare */
469     if(memcmp(chksum,page+22,4)){
470       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
471          at all) */
472       /* replace the computed checksum with the one actually read in */
473       memcpy(page+22,chksum,4);
474       
475       /* Bad checksum. Lose sync */
476       goto sync_fail;
477     }
478   }
479   
480   /* yes, have a whole page all ready to go */
481   {
482     unsigned char *page=oy->data+oy->returned;
483     long bytes;
484
485     if(og){
486       og->header=page;
487       og->header_len=oy->headerbytes;
488       og->body=page+oy->headerbytes;
489       og->body_len=oy->bodybytes;
490     }
491
492     oy->unsynced=0;
493     oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
494     oy->headerbytes=0;
495     oy->bodybytes=0;
496     return(bytes);
497   }
498   
499  sync_fail:
500   
501   oy->headerbytes=0;
502   oy->bodybytes=0;
503   
504   /* search for possible capture */
505   next=memchr(page+1,'O',bytes-1);
506   if(!next)
507     next=oy->data+oy->fill;
508
509   oy->returned=next-oy->data;
510   return(-(next-page));
511 }
512
513 /* sync the stream and get a page.  Keep trying until we find a page.
514    Supress 'sync errors' after reporting the first.
515
516    return values:
517    -1) recapture (hole in data)
518     0) need more data
519     1) page returned
520
521    Returns pointers into buffered data; invalidated by next call to
522    _stream, _clear, _init, or _buffer */
523
524 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
525
526   /* all we need to do is verify a page at the head of the stream
527      buffer.  If it doesn't verify, we look for the next potential
528      frame */
529
530   while(1){
531     long ret=ogg_sync_pageseek(oy,og);
532     if(ret>0){
533       /* have a page */
534       return(1);
535     }
536     if(ret==0){
537       /* need more data */
538       return(0);
539     }
540     
541     /* head did not start a synced page... skipped some bytes */
542     if(!oy->unsynced){
543       oy->unsynced=1;
544       return(-1);
545     }
546
547     /* loop. keep looking */
548
549   }
550 }
551
552 /* add the incoming page to the stream state; we decompose the page
553    into packet segments here as well. */
554
555 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
556   unsigned char *header=og->header;
557   unsigned char *body=og->body;
558   long           bodysize=og->body_len;
559   int            segptr=0;
560
561   int version=ogg_page_version(og);
562   int continued=ogg_page_continued(og);
563   int bos=ogg_page_bos(og);
564   int eos=ogg_page_eos(og);
565   int64_t pcmpos=ogg_page_frameno(og);
566   int serialno=ogg_page_serialno(og);
567   int pageno=ogg_page_pageno(og);
568   int segments=header[26];
569   
570   /* clean up 'returned data' */
571   {
572     long lr=os->lacing_returned;
573     long br=os->body_returned;
574
575     /* body data */
576     if(br){
577       os->body_fill-=br;
578       if(os->body_fill)
579         memmove(os->body_data,os->body_data+br,os->body_fill);
580       os->body_returned=0;
581     }
582
583     if(lr){
584       /* segment table */
585       if(os->lacing_fill-lr){
586         memmove(os->lacing_vals,os->lacing_vals+lr,
587                 (os->lacing_fill-lr)*sizeof(int));
588         memmove(os->pcm_vals,os->pcm_vals+lr,
589                 (os->lacing_fill-lr)*sizeof(int64_t));
590       }
591       os->lacing_fill-=lr;
592       os->lacing_packet-=lr;
593       os->lacing_returned=0;
594     }
595   }
596
597   /* check the serial number */
598   if(serialno!=os->serialno)return(-1);
599   if(version>0)return(-1);
600
601   _os_lacing_expand(os,segments+1);
602
603   /* are we in sequence? */
604   if(pageno!=os->pageno){
605     int i;
606
607     /* unroll previous partial packet (if any) */
608     for(i=os->lacing_packet;i<os->lacing_fill;i++)
609       os->body_fill-=os->lacing_vals[i]&0xff;
610     os->lacing_fill=os->lacing_packet;
611
612     /* make a note of dropped data in segment table */
613     os->lacing_vals[os->lacing_fill++]=0x400;
614     os->lacing_packet++;
615
616     /* are we a 'continued packet' page?  If so, we'll need to skip
617        some segments */
618     if(continued){
619       bos=0;
620       for(;segptr<segments;segptr++){
621         int val=header[27+segptr];
622         body+=val;
623         bodysize-=val;
624         if(val<255){
625           segptr++;
626           break;
627         }
628       }
629     }
630   }
631   
632   if(bodysize){
633     _os_body_expand(os,bodysize);
634     memcpy(os->body_data+os->body_fill,body,bodysize);
635     os->body_fill+=bodysize;
636   }
637
638   {
639     int saved=-1;
640     while(segptr<segments){
641       int val=header[27+segptr];
642       os->lacing_vals[os->lacing_fill]=val;
643       os->pcm_vals[os->lacing_fill]=-1;
644       
645       if(bos){
646         os->lacing_vals[os->lacing_fill]|=0x100;
647         bos=0;
648       }
649       
650       if(val<255)saved=os->lacing_fill;
651       
652       os->lacing_fill++;
653       segptr++;
654       
655       if(val<255)os->lacing_packet=os->lacing_fill;
656     }
657   
658     /* set the pcmpos on the last pcmval of the last full packet */
659     if(saved!=-1){
660       os->pcm_vals[saved]=pcmpos;
661     }
662
663   }
664
665   if(eos){
666     os->e_o_s=1;
667     if(os->lacing_fill>0)
668       os->lacing_vals[os->lacing_fill-1]|=0x200;
669   }
670
671   os->pageno=pageno+1;
672
673   return(0);
674 }
675
676 /* clear things to an initial state.  Good to call, eg, before seeking */
677 int ogg_sync_reset(ogg_sync_state *oy){
678   oy->fill=0;
679   oy->returned=0;
680   oy->unsynced=0;
681   oy->headerbytes=0;
682   oy->bodybytes=0;
683   return(0);
684 }
685
686 int ogg_stream_reset(ogg_stream_state *os,long expected_pageno){
687   os->body_fill=0;
688   os->body_returned=0;
689
690   os->lacing_fill=0;
691   os->lacing_packet=0;
692   os->lacing_returned=0;
693
694   os->header_fill=0;
695
696   os->e_o_s=0;
697   os->b_o_s=0;
698   os->pageno=expected_pageno;
699   os->packetno=0;
700   os->pcmpos=0;
701
702   return(0);
703 }
704
705 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
706
707   /* The last part of decode. We have the stream broken into packet
708      segments.  Now we need to group them into packets (or return the
709      out of sync markers) */
710
711   int ptr=os->lacing_returned;
712
713   if(os->lacing_packet<=ptr)return(0);
714
715   if(os->lacing_vals[ptr]&0x400){
716     /* We lost sync here; let the app know */
717     os->lacing_returned++;
718
719     /* we need to tell the codec there's a gap; it might need to
720        handle previous packet dependencies. */
721     os->packetno++;
722     return(-1);
723   }
724
725   /* Gather the whole packet. We'll have no holes or a partial packet */
726   {
727     int size=os->lacing_vals[ptr]&0xff;
728     int bytes=0;
729
730     op->packet=os->body_data+os->body_returned;
731     op->e_o_s=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
732     op->b_o_s=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
733     bytes+=size;
734
735     while(size==255){
736       int val=os->lacing_vals[++ptr];
737       size=val&0xff;
738       if(val&0x200)op->e_o_s=0x200;
739       bytes+=size;
740     }
741
742     op->packetno=os->packetno;
743     op->frameno=os->pcm_vals[ptr];
744     op->bytes=bytes;
745
746     os->body_returned+=bytes;
747     os->lacing_returned=ptr+1;
748   }
749   os->packetno++;
750   return(1);
751 }
752
753 #ifdef _V_SELFTEST
754 #include <stdio.h>
755
756 ogg_stream_state os_en, os_de;
757 ogg_sync_state oy;
758
759 void checkpacket(ogg_packet *op,int len, int no, int pos){
760   long j;
761   static int sequence=0;
762   static int lastno=0;
763
764   if(op->bytes!=len){
765     fprintf(stderr,"incorrect packet length!\n");
766     exit(1);
767   }
768   if(op->frameno!=pos){
769     fprintf(stderr,"incorrect packet position!\n");
770     exit(1);
771   }
772
773   /* packet number just follows sequence/gap; adjust the input number
774      for that */
775   if(no==0){
776     sequence=0;
777   }else{
778     sequence++;
779     if(no>lastno+1)
780       sequence++;
781   }
782   lastno=no;
783   if(op->packetno!=sequence){
784     fprintf(stderr,"incorrect packet sequence %ld != %d\n",op->packetno,sequence);
785     exit(1);
786   }
787
788   /* Test data */
789   for(j=0;j<op->bytes;j++)
790     if(op->packet[j]!=((j+no)&0xff)){
791       fprintf(stderr,"body data mismatch at pos %ld: %x!=%lx!\n\n",
792               j,op->packet[j],(j+no)&0xff);
793       exit(1);
794     }
795 }
796
797 void check_page(unsigned char *data,int *header,ogg_page *og){
798   long j;
799   /* Test data */
800   for(j=0;j<og->body_len;j++)
801     if(og->body[j]!=data[j]){
802       fprintf(stderr,"body data mismatch at pos %ld: %x!=%x!\n\n",
803               j,data[j],og->body[j]);
804       exit(1);
805     }
806
807   /* Test header */
808   for(j=0;j<og->header_len;j++){
809     if(og->header[j]!=header[j]){
810       fprintf(stderr,"header content mismatch at pos %ld:\n",j);
811       for(j=0;j<header[26]+27;j++)
812         fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
813       fprintf(stderr,"\n");
814       exit(1);
815     }
816   }
817   if(og->header_len!=header[26]+27){
818     fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
819             og->header_len,header[26]+27);
820     exit(1);
821   }
822 }
823
824 void print_header(ogg_page *og){
825   int j;
826   fprintf(stderr,"\nHEADER:\n");
827   fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
828           og->header[0],og->header[1],og->header[2],og->header[3],
829           (int)og->header[4],(int)og->header[5]);
830
831   fprintf(stderr,"  pcmpos: %d  serialno: %d  pageno: %d\n",
832           (og->header[9]<<24)|(og->header[8]<<16)|
833           (og->header[7]<<8)|og->header[6],
834           (og->header[17]<<24)|(og->header[16]<<16)|
835           (og->header[15]<<8)|og->header[14],
836           (og->header[21]<<24)|(og->header[20]<<16)|
837           (og->header[19]<<8)|og->header[18]);
838
839   fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
840           (int)og->header[22],(int)og->header[23],
841           (int)og->header[24],(int)og->header[25],
842           (int)og->header[26]);
843
844   for(j=27;j<og->header_len;j++)
845     fprintf(stderr,"%d ",(int)og->header[j]);
846   fprintf(stderr,")\n\n");
847 }
848
849 void copy_page(ogg_page *og){
850   char *temp=malloc(og->header_len);
851   memcpy(temp,og->header,og->header_len);
852   og->header=temp;
853
854   temp=malloc(og->body_len);
855   memcpy(temp,og->body,og->body_len);
856   og->body=temp;
857 }
858
859 void error(void){
860   fprintf(stderr,"error!\n");
861   exit(1);
862 }
863
864 void test_pack(int *pl, int **headers){
865   unsigned char *data=malloc(1024*1024); /* for scripted test cases only */
866   long inptr=0;
867   long outptr=0;
868   long deptr=0;
869   long depacket=0;
870   long pcm_pos=7;
871   int i,j,packets,pageno=0,pageout=0;
872   int eosflag=0;
873   int bosflag=0;
874
875   ogg_stream_reset(&os_en,0);
876   ogg_stream_reset(&os_de,0);
877   ogg_sync_reset(&oy);
878
879   for(packets=0;;packets++)if(pl[packets]==-1)break;
880
881   for(i=0;i<packets;i++){
882     /* construct a test packet */
883     ogg_packet op;
884     int len=pl[i];
885     
886     op.packet=data+inptr;
887     op.bytes=len;
888     op.e_o_s=(pl[i+1]<0?1:0);
889     op.frameno=pcm_pos;
890
891     pcm_pos+=1024;
892
893     for(j=0;j<len;j++)data[inptr++]=i+j;
894
895     /* submit the test packet */
896     ogg_stream_packetin(&os_en,&op);
897
898     /* retrieve any finished pages */
899     {
900       ogg_page og;
901       
902       while(ogg_stream_pageout(&os_en,&og)){
903         /* We have a page.  Check it carefully */
904
905         fprintf(stderr,"%d, ",pageno);
906
907         if(headers[pageno]==NULL){
908           fprintf(stderr,"coded too many pages!\n");
909           exit(1);
910         }
911
912         check_page(data+outptr,headers[pageno],&og);
913
914         outptr+=og.body_len;
915         pageno++;
916
917         /* have a complete page; submit it to sync/decode */
918
919         {
920           ogg_page og_de;
921           ogg_packet op_de;
922           char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
923           memcpy(buf,og.header,og.header_len);
924           memcpy(buf+og.header_len,og.body,og.body_len);
925           ogg_sync_wrote(&oy,og.header_len+og.body_len);
926
927           while(ogg_sync_pageout(&oy,&og_de)>0){
928             /* got a page.  Happy happy.  Verify that it's good. */
929             
930             check_page(data+deptr,headers[pageout],&og_de);
931             deptr+=og_de.body_len;
932             pageout++;
933
934             /* submit it to deconstitution */
935             ogg_stream_pagein(&os_de,&og_de);
936
937             /* packets out? */
938             while(ogg_stream_packetout(&os_de,&op_de)>0){
939               
940               /* verify the packet! */
941               /* check data */
942               if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
943                 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
944                         depacket);
945                 exit(1);
946               }
947               /* check bos flag */
948               if(bosflag==0 && op_de.b_o_s==0){
949                 fprintf(stderr,"b_o_s flag not set on packet!\n");
950                 exit(1);
951               }
952               if(bosflag && op_de.b_o_s){
953                 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
954                 exit(1);
955               }
956               bosflag=1;
957               depacket+=op_de.bytes;
958               
959               /* check eos flag */
960               if(eosflag){
961                 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
962                 exit(1);
963               }
964
965               if(op_de.e_o_s)eosflag=1;
966
967               /* check pcmpos flag */
968               if(op_de.frameno!=-1){
969                 fprintf(stderr," pcm:%ld ",(long)op_de.frameno);
970               }
971             }
972           }
973         }
974       }
975     }
976   }
977   free(data);
978   if(headers[pageno]!=NULL){
979     fprintf(stderr,"did not write last page!\n");
980     exit(1);
981   }
982   if(headers[pageout]!=NULL){
983     fprintf(stderr,"did not decode last page!\n");
984     exit(1);
985   }
986   if(inptr!=outptr){
987     fprintf(stderr,"encoded page data incomplete!\n");
988     exit(1);
989   }
990   if(inptr!=deptr){
991     fprintf(stderr,"decoded page data incomplete!\n");
992     exit(1);
993   }
994   if(inptr!=depacket){
995     fprintf(stderr,"decoded packet data incomplete!\n");
996     exit(1);
997   }
998   if(!eosflag){
999     fprintf(stderr,"Never got a packet with EOS set!\n");
1000     exit(1);
1001   }
1002   fprintf(stderr,"ok.\n");
1003 }
1004
1005 int main(void){
1006
1007   ogg_stream_init(&os_en,0x04030201);
1008   ogg_stream_init(&os_de,0x04030201);
1009   ogg_sync_init(&oy);
1010
1011   /* Exercise each code path in the framing code.  Also verify that
1012      the checksums are working.  */
1013
1014   {
1015     /* 17 only */
1016     int packets[]={17, -1};
1017     int head1[] = {0x4f,0x67,0x67,0x53,0,0x06,
1018                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1019                    0x01,0x02,0x03,0x04,0,0,0,0,
1020                    0x15,0xed,0xec,0x91,
1021                    1,
1022                    17};
1023     int *headret[]={head1,NULL};
1024     
1025     fprintf(stderr,"testing single page encoding... ");
1026     test_pack(packets,headret);
1027   }
1028
1029   {
1030     /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1031     int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1032     int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1033                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1034                    0x01,0x02,0x03,0x04,0,0,0,0,
1035                    0x59,0x10,0x6c,0x2c,
1036                    1,
1037                    17};
1038     int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1039                    0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1040                    0x01,0x02,0x03,0x04,1,0,0,0,
1041                    0x89,0x33,0x85,0xce,
1042                    13,
1043                    254,255,0,255,1,255,245,255,255,0,
1044                    255,255,90};
1045     int *headret[]={head1,head2,NULL};
1046     
1047     fprintf(stderr,"testing basic page encoding... ");
1048     test_pack(packets,headret);
1049   }
1050
1051   {
1052     /* nil packets; beginning,middle,end */
1053     int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1054
1055     int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1056                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1057                    0x01,0x02,0x03,0x04,0,0,0,0,
1058                    0xff,0x7b,0x23,0x17,
1059                    1,
1060                    0};
1061     int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1062                    0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1063                    0x01,0x02,0x03,0x04,1,0,0,0,
1064                    0x5c,0x3f,0x66,0xcb,
1065                    17,
1066                    17,254,255,0,0,255,1,0,255,245,255,255,0,
1067                    255,255,90,0};
1068     int *headret[]={head1,head2,NULL};
1069     
1070     fprintf(stderr,"testing basic nil packets... ");
1071     test_pack(packets,headret);
1072   }
1073
1074   {
1075     /* large initial packet */
1076     int packets[]={4345,259,255,-1};
1077
1078     int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1079                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1080                    0x01,0x02,0x03,0x04,0,0,0,0,
1081                    0x01,0x27,0x31,0xaa,
1082                    18,
1083                    255,255,255,255,255,255,255,255,
1084                    255,255,255,255,255,255,255,255,255,10};
1085
1086     int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1087                    0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1088                    0x01,0x02,0x03,0x04,1,0,0,0,
1089                    0x7f,0x4e,0x8a,0xd2,
1090                    4,
1091                    255,4,255,0};
1092     int *headret[]={head1,head2,NULL};
1093     
1094     fprintf(stderr,"testing initial-packet lacing > 4k... ");
1095     test_pack(packets,headret);
1096   }
1097
1098   {
1099     /* continuing packet test */
1100     int packets[]={0,4345,259,255,-1};
1101
1102     int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1103                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1104                    0x01,0x02,0x03,0x04,0,0,0,0,
1105                    0xff,0x7b,0x23,0x17,
1106                    1,
1107                    0};
1108
1109     int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1110                    0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1111                    0x01,0x02,0x03,0x04,1,0,0,0,
1112                    0x34,0x24,0xd5,0x29,
1113                    17,
1114                    255,255,255,255,255,255,255,255,
1115                    255,255,255,255,255,255,255,255,255};
1116
1117     int head3[] = {0x4f,0x67,0x67,0x53,0,0x05,
1118                    0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1119                    0x01,0x02,0x03,0x04,2,0,0,0,
1120                    0xc8,0xc3,0xcb,0xed,
1121                    5,
1122                    10,255,4,255,0};
1123     int *headret[]={head1,head2,head3,NULL};
1124     
1125     fprintf(stderr,"testing single packet page span... ");
1126     test_pack(packets,headret);
1127   }
1128
1129   /* page with the 255 segment limit */
1130   {
1131
1132     int packets[]={0,10,10,10,10,10,10,10,10,
1133                    10,10,10,10,10,10,10,10,
1134                    10,10,10,10,10,10,10,10,
1135                    10,10,10,10,10,10,10,10,
1136                    10,10,10,10,10,10,10,10,
1137                    10,10,10,10,10,10,10,10,
1138                    10,10,10,10,10,10,10,10,
1139                    10,10,10,10,10,10,10,10,
1140                    10,10,10,10,10,10,10,10,
1141                    10,10,10,10,10,10,10,10,
1142                    10,10,10,10,10,10,10,10,
1143                    10,10,10,10,10,10,10,10,
1144                    10,10,10,10,10,10,10,10,
1145                    10,10,10,10,10,10,10,10,
1146                    10,10,10,10,10,10,10,10,
1147                    10,10,10,10,10,10,10,10,
1148                    10,10,10,10,10,10,10,10,
1149                    10,10,10,10,10,10,10,10,
1150                    10,10,10,10,10,10,10,10,
1151                    10,10,10,10,10,10,10,10,
1152                    10,10,10,10,10,10,10,10,
1153                    10,10,10,10,10,10,10,10,
1154                    10,10,10,10,10,10,10,10,
1155                    10,10,10,10,10,10,10,10,
1156                    10,10,10,10,10,10,10,10,
1157                    10,10,10,10,10,10,10,10,
1158                    10,10,10,10,10,10,10,10,
1159                    10,10,10,10,10,10,10,10,
1160                    10,10,10,10,10,10,10,10,
1161                    10,10,10,10,10,10,10,10,
1162                    10,10,10,10,10,10,10,10,
1163                    10,10,10,10,10,10,10,50,-1};
1164
1165     int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1166                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1167                    0x01,0x02,0x03,0x04,0,0,0,0,
1168                    0xff,0x7b,0x23,0x17,
1169                    1,
1170                    0};
1171
1172     int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1173                    0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1174                    0x01,0x02,0x03,0x04,1,0,0,0,
1175                    0xed,0x2a,0x2e,0xa7,
1176                    255,
1177                    10,10,10,10,10,10,10,10,
1178                    10,10,10,10,10,10,10,10,
1179                    10,10,10,10,10,10,10,10,
1180                    10,10,10,10,10,10,10,10,
1181                    10,10,10,10,10,10,10,10,
1182                    10,10,10,10,10,10,10,10,
1183                    10,10,10,10,10,10,10,10,
1184                    10,10,10,10,10,10,10,10,
1185                    10,10,10,10,10,10,10,10,
1186                    10,10,10,10,10,10,10,10,
1187                    10,10,10,10,10,10,10,10,
1188                    10,10,10,10,10,10,10,10,
1189                    10,10,10,10,10,10,10,10,
1190                    10,10,10,10,10,10,10,10,
1191                    10,10,10,10,10,10,10,10,
1192                    10,10,10,10,10,10,10,10,
1193                    10,10,10,10,10,10,10,10,
1194                    10,10,10,10,10,10,10,10,
1195                    10,10,10,10,10,10,10,10,
1196                    10,10,10,10,10,10,10,10,
1197                    10,10,10,10,10,10,10,10,
1198                    10,10,10,10,10,10,10,10,
1199                    10,10,10,10,10,10,10,10,
1200                    10,10,10,10,10,10,10,10,
1201                    10,10,10,10,10,10,10,10,
1202                    10,10,10,10,10,10,10,10,
1203                    10,10,10,10,10,10,10,10,
1204                    10,10,10,10,10,10,10,10,
1205                    10,10,10,10,10,10,10,10,
1206                    10,10,10,10,10,10,10,10,
1207                    10,10,10,10,10,10,10,10,
1208                    10,10,10,10,10,10,10};
1209
1210     int head3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1211                    0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1212                    0x01,0x02,0x03,0x04,2,0,0,0,
1213                    0x6c,0x3b,0x82,0x3d,
1214                    1,
1215                    50};
1216     int *headret[]={head1,head2,head3,NULL};
1217     
1218     fprintf(stderr,"testing max packet segments... ");
1219     test_pack(packets,headret);
1220   }
1221
1222   {
1223     /* packet that overspans over an entire page */
1224
1225     int packets[]={0,100,9000,259,255,-1};
1226
1227     int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1228                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1229                    0x01,0x02,0x03,0x04,0,0,0,0,
1230                    0xff,0x7b,0x23,0x17,
1231                    1,
1232                    0};
1233
1234     int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1235                    0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1236                    0x01,0x02,0x03,0x04,1,0,0,0,
1237                    0x3c,0xd9,0x4d,0x3f,
1238                    17,
1239                    100,255,255,255,255,255,255,255,255,
1240                    255,255,255,255,255,255,255,255};
1241
1242     int head3[] = {0x4f,0x67,0x67,0x53,0,0x01,
1243                    0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1244                    0x01,0x02,0x03,0x04,2,0,0,0,
1245                    0xbd,0xd5,0xb5,0x8b,
1246                    17,
1247                    255,255,255,255,255,255,255,255,
1248                    255,255,255,255,255,255,255,255,255};
1249
1250     int head4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1251                    0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1252                    0x01,0x02,0x03,0x04,3,0,0,0,
1253                    0xef,0xdd,0x88,0xde,
1254                    7,
1255                    255,255,75,255,4,255,0};
1256     int *headret[]={head1,head2,head3,head4,NULL};
1257     
1258     fprintf(stderr,"testing very large packets... ");
1259     test_pack(packets,headret);
1260   }
1261
1262   {
1263     /* term only page.  why not? */
1264
1265     int packets[]={0,100,4080,-1};
1266
1267     int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1268                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1269                    0x01,0x02,0x03,0x04,0,0,0,0,
1270                    0xff,0x7b,0x23,0x17,
1271                    1,
1272                    0};
1273
1274     int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1275                    0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1276                    0x01,0x02,0x03,0x04,1,0,0,0,
1277                    0x3c,0xd9,0x4d,0x3f,
1278                    17,
1279                    100,255,255,255,255,255,255,255,255,
1280                    255,255,255,255,255,255,255,255};
1281
1282     int head3[] = {0x4f,0x67,0x67,0x53,0,0x05,
1283                    0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1284                    0x01,0x02,0x03,0x04,2,0,0,0,
1285                    0xd4,0xe0,0x60,0xe5,
1286                    1,0};
1287
1288     int *headret[]={head1,head2,head3,NULL};
1289     
1290     fprintf(stderr,"testing zero data page (1 nil packet)... ");
1291     test_pack(packets,headret);
1292   }
1293
1294
1295
1296   {
1297     /* build a bunch of pages for testing */
1298     unsigned char *data=malloc(1024*1024);
1299     int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
1300     int inptr=0,i,j;
1301     ogg_page og[5];
1302     
1303     ogg_stream_reset(&os_en,0);
1304
1305     for(i=0;pl[i]!=-1;i++){
1306       ogg_packet op;
1307       int len=pl[i];
1308       
1309       op.packet=data+inptr;
1310       op.bytes=len;
1311       op.e_o_s=(pl[i+1]<0?1:0);
1312       op.frameno=(i+1)*1000;
1313
1314       for(j=0;j<len;j++)data[inptr++]=i+j;
1315       ogg_stream_packetin(&os_en,&op);
1316     }
1317
1318     free(data);
1319
1320     /* retrieve finished pages */
1321     for(i=0;i<5;i++){
1322       if(ogg_stream_pageout(&os_en,&og[i])==0){
1323         fprintf(stderr,"Too few pages output building sync tests!\n");
1324         exit(1);
1325       }
1326       copy_page(&og[i]);
1327     }
1328
1329     /* Test lost pages on pagein/packetout: no rollback */
1330     {
1331       ogg_page temp;
1332       ogg_packet test;
1333
1334       fprintf(stderr,"Testing loss of pages... ");
1335
1336       ogg_sync_reset(&oy);
1337       ogg_stream_reset(&os_de,0);
1338       for(i=0;i<5;i++){
1339         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1340                og[i].header_len);
1341         ogg_sync_wrote(&oy,og[i].header_len);
1342         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1343         ogg_sync_wrote(&oy,og[i].body_len);
1344       }
1345
1346       ogg_sync_pageout(&oy,&temp);
1347       ogg_stream_pagein(&os_de,&temp);
1348       ogg_sync_pageout(&oy,&temp);
1349       ogg_stream_pagein(&os_de,&temp);
1350       ogg_sync_pageout(&oy,&temp);
1351       /* skip */
1352       ogg_sync_pageout(&oy,&temp);
1353       ogg_stream_pagein(&os_de,&temp);
1354
1355       /* do we get the expected results/packets? */
1356       
1357       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1358       checkpacket(&test,0,0,0);
1359       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1360       checkpacket(&test,100,1,-1);
1361       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1362       checkpacket(&test,4079,2,3000);
1363       if(ogg_stream_packetout(&os_de,&test)!=-1){
1364         fprintf(stderr,"Error: loss of page did not return error\n");
1365         exit(1);
1366       }
1367       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1368       checkpacket(&test,76,5,-1);
1369       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1370       checkpacket(&test,34,6,-1);
1371       fprintf(stderr,"ok.\n");
1372     }
1373
1374     /* Test lost pages on pagein/packetout: rollback with continuation */
1375     {
1376       ogg_page temp;
1377       ogg_packet test;
1378
1379       fprintf(stderr,"Testing loss of pages (rollback required)... ");
1380
1381       ogg_sync_reset(&oy);
1382       ogg_stream_reset(&os_de,0);
1383       for(i=0;i<5;i++){
1384         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1385                og[i].header_len);
1386         ogg_sync_wrote(&oy,og[i].header_len);
1387         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1388         ogg_sync_wrote(&oy,og[i].body_len);
1389       }
1390
1391       ogg_sync_pageout(&oy,&temp);
1392       ogg_stream_pagein(&os_de,&temp);
1393       ogg_sync_pageout(&oy,&temp);
1394       ogg_stream_pagein(&os_de,&temp);
1395       ogg_sync_pageout(&oy,&temp);
1396       ogg_stream_pagein(&os_de,&temp);
1397       ogg_sync_pageout(&oy,&temp);
1398       /* skip */
1399       ogg_sync_pageout(&oy,&temp);
1400       ogg_stream_pagein(&os_de,&temp);
1401
1402       /* do we get the expected results/packets? */
1403       
1404       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1405       checkpacket(&test,0,0,0);
1406       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1407       checkpacket(&test,100,1,-1);
1408       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1409       checkpacket(&test,4079,2,3000);
1410       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1411       checkpacket(&test,2956,3,4000);
1412       if(ogg_stream_packetout(&os_de,&test)!=-1){
1413         fprintf(stderr,"Error: loss of page did not return error\n");
1414         exit(1);
1415       }
1416       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1417       checkpacket(&test,300,13,14000);
1418       fprintf(stderr,"ok.\n");
1419     }
1420     
1421     /* the rest only test sync */
1422     {
1423       ogg_page og_de;
1424       /* Test fractional page inputs: incomplete capture */
1425       fprintf(stderr,"Testing sync on partial inputs... ");
1426       ogg_sync_reset(&oy);
1427       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1428              3);
1429       ogg_sync_wrote(&oy,3);
1430       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1431       
1432       /* Test fractional page inputs: incomplete fixed header */
1433       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1434              20);
1435       ogg_sync_wrote(&oy,20);
1436       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1437       
1438       /* Test fractional page inputs: incomplete header */
1439       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1440              5);
1441       ogg_sync_wrote(&oy,5);
1442       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1443       
1444       /* Test fractional page inputs: incomplete body */
1445       
1446       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1447              og[1].header_len-28);
1448       ogg_sync_wrote(&oy,og[1].header_len-28);
1449       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1450       
1451       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1452       ogg_sync_wrote(&oy,1000);
1453       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1454       
1455       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1456              og[1].body_len-1000);
1457       ogg_sync_wrote(&oy,og[1].body_len-1000);
1458       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1459       
1460       fprintf(stderr,"ok.\n");
1461     }
1462
1463     /* Test fractional page inputs: page + incomplete capture */
1464     {
1465       ogg_page og_de;
1466       fprintf(stderr,"Testing sync on 1+partial inputs... ");
1467       ogg_sync_reset(&oy); 
1468
1469       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1470              og[1].header_len);
1471       ogg_sync_wrote(&oy,og[1].header_len);
1472
1473       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1474              og[1].body_len);
1475       ogg_sync_wrote(&oy,og[1].body_len);
1476
1477       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1478              20);
1479       ogg_sync_wrote(&oy,20);
1480       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1481       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1482
1483       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1484              og[1].header_len-20);
1485       ogg_sync_wrote(&oy,og[1].header_len-20);
1486       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1487              og[1].body_len);
1488       ogg_sync_wrote(&oy,og[1].body_len);
1489       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1490
1491       fprintf(stderr,"ok.\n");
1492     }
1493     
1494     /* Test recapture: garbage + page */
1495     {
1496       ogg_page og_de;
1497       fprintf(stderr,"Testing search for capture... ");
1498       ogg_sync_reset(&oy); 
1499       
1500       /* 'garbage' */
1501       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1502              og[1].body_len);
1503       ogg_sync_wrote(&oy,og[1].body_len);
1504
1505       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1506              og[1].header_len);
1507       ogg_sync_wrote(&oy,og[1].header_len);
1508
1509       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1510              og[1].body_len);
1511       ogg_sync_wrote(&oy,og[1].body_len);
1512
1513       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1514              20);
1515       ogg_sync_wrote(&oy,20);
1516       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1517       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1518       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1519
1520       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
1521              og[2].header_len-20);
1522       ogg_sync_wrote(&oy,og[2].header_len-20);
1523       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1524              og[2].body_len);
1525       ogg_sync_wrote(&oy,og[2].body_len);
1526       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1527
1528       fprintf(stderr,"ok.\n");
1529     }
1530
1531     /* Test recapture: page + garbage + page */
1532     {
1533       ogg_page og_de;
1534       fprintf(stderr,"Testing recapture... ");
1535       ogg_sync_reset(&oy); 
1536
1537       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1538              og[1].header_len);
1539       ogg_sync_wrote(&oy,og[1].header_len);
1540
1541       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1542              og[1].body_len);
1543       ogg_sync_wrote(&oy,og[1].body_len);
1544
1545       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1546              og[2].header_len);
1547       ogg_sync_wrote(&oy,og[2].header_len);
1548
1549       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1550              og[2].header_len);
1551       ogg_sync_wrote(&oy,og[2].header_len);
1552
1553       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1554
1555       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1556              og[2].body_len-5);
1557       ogg_sync_wrote(&oy,og[2].body_len-5);
1558
1559       memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
1560              og[3].header_len);
1561       ogg_sync_wrote(&oy,og[3].header_len);
1562
1563       memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
1564              og[3].body_len);
1565       ogg_sync_wrote(&oy,og[3].body_len);
1566
1567       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1568       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1569
1570       fprintf(stderr,"ok.\n");
1571     }
1572   }    
1573
1574   return(0);
1575 }
1576
1577 #endif
1578
1579
1580
1581