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