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