]> git.tdb.fi Git - ext/ogg.git/blob - src/framing.c
Add MSP build files
[ext/ogg.git] / src / framing.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE.              *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2018             *
9  * by the Xiph.Org Foundation http://www.xiph.org/                  *
10  *                                                                  *
11  ********************************************************************
12
13  function: code raw packets into framed OggSquish stream and
14            decode Ogg streams back into raw packets
15
16  note: The CRC code is directly derived from public domain code by
17  Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
18  for details.
19
20  ********************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdlib.h>
27 #include <limits.h>
28 #include <string.h>
29 #include <ogg/ogg.h>
30
31 /* A complete description of Ogg framing exists in docs/framing.html */
32
33 int ogg_page_version(const ogg_page *og){
34   return((int)(og->header[4]));
35 }
36
37 int ogg_page_continued(const ogg_page *og){
38   return((int)(og->header[5]&0x01));
39 }
40
41 int ogg_page_bos(const ogg_page *og){
42   return((int)(og->header[5]&0x02));
43 }
44
45 int ogg_page_eos(const ogg_page *og){
46   return((int)(og->header[5]&0x04));
47 }
48
49 ogg_int64_t ogg_page_granulepos(const ogg_page *og){
50   unsigned char *page=og->header;
51   ogg_uint64_t granulepos=page[13]&(0xff);
52   granulepos= (granulepos<<8)|(page[12]&0xff);
53   granulepos= (granulepos<<8)|(page[11]&0xff);
54   granulepos= (granulepos<<8)|(page[10]&0xff);
55   granulepos= (granulepos<<8)|(page[9]&0xff);
56   granulepos= (granulepos<<8)|(page[8]&0xff);
57   granulepos= (granulepos<<8)|(page[7]&0xff);
58   granulepos= (granulepos<<8)|(page[6]&0xff);
59   return((ogg_int64_t)granulepos);
60 }
61
62 int ogg_page_serialno(const ogg_page *og){
63   return((int)((ogg_uint32_t)og->header[14]) |
64               ((ogg_uint32_t)og->header[15]<<8) |
65               ((ogg_uint32_t)og->header[16]<<16) |
66               ((ogg_uint32_t)og->header[17]<<24));
67 }
68
69 long ogg_page_pageno(const ogg_page *og){
70   return((long)((ogg_uint32_t)og->header[18]) |
71                ((ogg_uint32_t)og->header[19]<<8) |
72                ((ogg_uint32_t)og->header[20]<<16) |
73                ((ogg_uint32_t)og->header[21]<<24));
74 }
75
76
77
78 /* returns the number of packets that are completed on this page (if
79    the leading packet is begun on a previous page, but ends on this
80    page, it's counted */
81
82 /* NOTE:
83    If a page consists of a packet begun on a previous page, and a new
84    packet begun (but not completed) on this page, the return will be:
85      ogg_page_packets(page)   ==1,
86      ogg_page_continued(page) !=0
87
88    If a page happens to be a single packet that was begun on a
89    previous page, and spans to the next page (in the case of a three or
90    more page packet), the return will be:
91      ogg_page_packets(page)   ==0,
92      ogg_page_continued(page) !=0
93 */
94
95 int ogg_page_packets(const ogg_page *og){
96   int i,n=og->header[26],count=0;
97   for(i=0;i<n;i++)
98     if(og->header[27+i]<255)count++;
99   return(count);
100 }
101
102
103 #if 0
104 /* helper to initialize lookup for direct-table CRC (illustrative; we
105    use the static init in crctable.h) */
106
107 static void _ogg_crc_init(){
108   int i, j;
109   ogg_uint32_t polynomial, crc;
110   polynomial = 0x04c11db7; /* The same as the ethernet generator
111                               polynomial, although we use an
112                               unreflected alg and an init/final
113                               of 0, not 0xffffffff */
114   for (i = 0; i <= 0xFF; i++){
115     crc = i << 24;
116
117     for (j = 0; j < 8; j++)
118       crc = (crc << 1) ^ (crc & (1 << 31) ? polynomial : 0);
119
120     crc_lookup[0][i] = crc;
121   }
122
123   for (i = 0; i <= 0xFF; i++)
124     for (j = 1; j < 8; j++)
125       crc_lookup[j][i] = crc_lookup[0][(crc_lookup[j - 1][i] >> 24) & 0xFF] ^ (crc_lookup[j - 1][i] << 8);
126 }
127 #endif
128
129 #include "crctable.h"
130
131 /* init the encode/decode logical stream state */
132
133 int ogg_stream_init(ogg_stream_state *os,int serialno){
134   if(os){
135     memset(os,0,sizeof(*os));
136     os->body_storage=16*1024;
137     os->lacing_storage=1024;
138
139     os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
140     os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
141     os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
142
143     if(!os->body_data || !os->lacing_vals || !os->granule_vals){
144       ogg_stream_clear(os);
145       return -1;
146     }
147
148     os->serialno=serialno;
149
150     return(0);
151   }
152   return(-1);
153 }
154
155 /* async/delayed error detection for the ogg_stream_state */
156 int ogg_stream_check(ogg_stream_state *os){
157   if(!os || !os->body_data) return -1;
158   return 0;
159 }
160
161 /* _clear does not free os, only the non-flat storage within */
162 int ogg_stream_clear(ogg_stream_state *os){
163   if(os){
164     if(os->body_data)_ogg_free(os->body_data);
165     if(os->lacing_vals)_ogg_free(os->lacing_vals);
166     if(os->granule_vals)_ogg_free(os->granule_vals);
167
168     memset(os,0,sizeof(*os));
169   }
170   return(0);
171 }
172
173 int ogg_stream_destroy(ogg_stream_state *os){
174   if(os){
175     ogg_stream_clear(os);
176     _ogg_free(os);
177   }
178   return(0);
179 }
180
181 /* Helpers for ogg_stream_encode; this keeps the structure and
182    what's happening fairly clear */
183
184 static int _os_body_expand(ogg_stream_state *os,long needed){
185   if(os->body_storage-needed<=os->body_fill){
186     long body_storage;
187     void *ret;
188     if(os->body_storage>LONG_MAX-needed){
189       ogg_stream_clear(os);
190       return -1;
191     }
192     body_storage=os->body_storage+needed;
193     if(body_storage<LONG_MAX-1024)body_storage+=1024;
194     ret=_ogg_realloc(os->body_data,body_storage*sizeof(*os->body_data));
195     if(!ret){
196       ogg_stream_clear(os);
197       return -1;
198     }
199     os->body_storage=body_storage;
200     os->body_data=ret;
201   }
202   return 0;
203 }
204
205 static int _os_lacing_expand(ogg_stream_state *os,long needed){
206   if(os->lacing_storage-needed<=os->lacing_fill){
207     long lacing_storage;
208     void *ret;
209     if(os->lacing_storage>LONG_MAX-needed){
210       ogg_stream_clear(os);
211       return -1;
212     }
213     lacing_storage=os->lacing_storage+needed;
214     if(lacing_storage<LONG_MAX-32)lacing_storage+=32;
215     ret=_ogg_realloc(os->lacing_vals,lacing_storage*sizeof(*os->lacing_vals));
216     if(!ret){
217       ogg_stream_clear(os);
218       return -1;
219     }
220     os->lacing_vals=ret;
221     ret=_ogg_realloc(os->granule_vals,lacing_storage*
222                      sizeof(*os->granule_vals));
223     if(!ret){
224       ogg_stream_clear(os);
225       return -1;
226     }
227     os->granule_vals=ret;
228     os->lacing_storage=lacing_storage;
229   }
230   return 0;
231 }
232
233 /* checksum the page */
234 /* Direct table CRC; note that this will be faster in the future if we
235    perform the checksum simultaneously with other copies */
236
237 static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsigned char *buffer, int size){
238   while (size>=8){
239     crc^=((ogg_uint32_t)buffer[0]<<24)|((ogg_uint32_t)buffer[1]<<16)|((ogg_uint32_t)buffer[2]<<8)|((ogg_uint32_t)buffer[3]);
240
241     crc=crc_lookup[7][ crc>>24      ]^crc_lookup[6][(crc>>16)&0xFF]^
242         crc_lookup[5][(crc>> 8)&0xFF]^crc_lookup[4][ crc     &0xFF]^
243         crc_lookup[3][buffer[4]     ]^crc_lookup[2][buffer[5]     ]^
244         crc_lookup[1][buffer[6]     ]^crc_lookup[0][buffer[7]     ];
245
246     buffer+=8;
247     size-=8;
248   }
249
250   while (size--)
251     crc=(crc<<8)^crc_lookup[0][((crc >> 24)&0xff)^*buffer++];
252   return crc;
253 }
254
255 void ogg_page_checksum_set(ogg_page *og){
256   if(og){
257     ogg_uint32_t crc_reg=0;
258
259     /* safety; needed for API behavior, but not framing code */
260     og->header[22]=0;
261     og->header[23]=0;
262     og->header[24]=0;
263     og->header[25]=0;
264
265     crc_reg=_os_update_crc(crc_reg,og->header,og->header_len);
266     crc_reg=_os_update_crc(crc_reg,og->body,og->body_len);
267
268     og->header[22]=(unsigned char)(crc_reg&0xff);
269     og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
270     og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
271     og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
272   }
273 }
274
275 /* submit data to the internal buffer of the framing engine */
276 int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
277                        long e_o_s, ogg_int64_t granulepos){
278
279   long bytes = 0, lacing_vals;
280   int i;
281
282   if(ogg_stream_check(os)) return -1;
283   if(!iov) return 0;
284
285   for (i = 0; i < count; ++i){
286     if(iov[i].iov_len>LONG_MAX) return -1;
287     if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1;
288     bytes += (long)iov[i].iov_len;
289   }
290   lacing_vals=bytes/255+1;
291
292   if(os->body_returned){
293     /* advance packet data according to the body_returned pointer. We
294        had to keep it around to return a pointer into the buffer last
295        call */
296
297     os->body_fill-=os->body_returned;
298     if(os->body_fill)
299       memmove(os->body_data,os->body_data+os->body_returned,
300               os->body_fill);
301     os->body_returned=0;
302   }
303
304   /* make sure we have the buffer storage */
305   if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
306     return -1;
307
308   /* Copy in the submitted packet.  Yes, the copy is a waste; this is
309      the liability of overly clean abstraction for the time being.  It
310      will actually be fairly easy to eliminate the extra copy in the
311      future */
312
313   for (i = 0; i < count; ++i) {
314     memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
315     os->body_fill += (int)iov[i].iov_len;
316   }
317
318   /* Store lacing vals for this packet */
319   for(i=0;i<lacing_vals-1;i++){
320     os->lacing_vals[os->lacing_fill+i]=255;
321     os->granule_vals[os->lacing_fill+i]=os->granulepos;
322   }
323   os->lacing_vals[os->lacing_fill+i]=bytes%255;
324   os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
325
326   /* flag the first segment as the beginning of the packet */
327   os->lacing_vals[os->lacing_fill]|= 0x100;
328
329   os->lacing_fill+=lacing_vals;
330
331   /* for the sake of completeness */
332   os->packetno++;
333
334   if(e_o_s)os->e_o_s=1;
335
336   return(0);
337 }
338
339 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
340   ogg_iovec_t iov;
341   iov.iov_base = op->packet;
342   iov.iov_len = op->bytes;
343   return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
344 }
345
346 /* Conditionally flush a page; force==0 will only flush nominal-size
347    pages, force==1 forces us to flush a page regardless of page size
348    so long as there's any data available at all. */
349 static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
350   int i;
351   int vals=0;
352   int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
353   int bytes=0;
354   long acc=0;
355   ogg_int64_t granule_pos=-1;
356
357   if(ogg_stream_check(os)) return(0);
358   if(maxvals==0) return(0);
359
360   /* construct a page */
361   /* decide how many segments to include */
362
363   /* If this is the initial header case, the first page must only include
364      the initial header packet */
365   if(os->b_o_s==0){  /* 'initial header page' case */
366     granule_pos=0;
367     for(vals=0;vals<maxvals;vals++){
368       if((os->lacing_vals[vals]&0x0ff)<255){
369         vals++;
370         break;
371       }
372     }
373   }else{
374
375     /* The extra packets_done, packet_just_done logic here attempts to do two things:
376        1) Don't unnecessarily span pages.
377        2) Unless necessary, don't flush pages if there are less than four packets on
378           them; this expands page size to reduce unnecessary overhead if incoming packets
379           are large.
380        These are not necessary behaviors, just 'always better than naive flushing'
381        without requiring an application to explicitly request a specific optimized
382        behavior. We'll want an explicit behavior setup pathway eventually as well. */
383
384     int packets_done=0;
385     int packet_just_done=0;
386     for(vals=0;vals<maxvals;vals++){
387       if(acc>nfill && packet_just_done>=4){
388         force=1;
389         break;
390       }
391       acc+=os->lacing_vals[vals]&0x0ff;
392       if((os->lacing_vals[vals]&0xff)<255){
393         granule_pos=os->granule_vals[vals];
394         packet_just_done=++packets_done;
395       }else
396         packet_just_done=0;
397     }
398     if(vals==255)force=1;
399   }
400
401   if(!force) return(0);
402
403   /* construct the header in temp storage */
404   memcpy(os->header,"OggS",4);
405
406   /* stream structure version */
407   os->header[4]=0x00;
408
409   /* continued packet flag? */
410   os->header[5]=0x00;
411   if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
412   /* first page flag? */
413   if(os->b_o_s==0)os->header[5]|=0x02;
414   /* last page flag? */
415   if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
416   os->b_o_s=1;
417
418   /* 64 bits of PCM position */
419   for(i=6;i<14;i++){
420     os->header[i]=(unsigned char)(granule_pos&0xff);
421     granule_pos>>=8;
422   }
423
424   /* 32 bits of stream serial number */
425   {
426     long serialno=os->serialno;
427     for(i=14;i<18;i++){
428       os->header[i]=(unsigned char)(serialno&0xff);
429       serialno>>=8;
430     }
431   }
432
433   /* 32 bits of page counter (we have both counter and page header
434      because this val can roll over) */
435   if(os->pageno==-1)os->pageno=0; /* because someone called
436                                      stream_reset; this would be a
437                                      strange thing to do in an
438                                      encode stream, but it has
439                                      plausible uses */
440   {
441     long pageno=os->pageno++;
442     for(i=18;i<22;i++){
443       os->header[i]=(unsigned char)(pageno&0xff);
444       pageno>>=8;
445     }
446   }
447
448   /* zero for computation; filled in later */
449   os->header[22]=0;
450   os->header[23]=0;
451   os->header[24]=0;
452   os->header[25]=0;
453
454   /* segment table */
455   os->header[26]=(unsigned char)(vals&0xff);
456   for(i=0;i<vals;i++)
457     bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
458
459   /* set pointers in the ogg_page struct */
460   og->header=os->header;
461   og->header_len=os->header_fill=vals+27;
462   og->body=os->body_data+os->body_returned;
463   og->body_len=bytes;
464
465   /* advance the lacing data and set the body_returned pointer */
466
467   os->lacing_fill-=vals;
468   memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
469   memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
470   os->body_returned+=bytes;
471
472   /* calculate the checksum */
473
474   ogg_page_checksum_set(og);
475
476   /* done */
477   return(1);
478 }
479
480 /* This will flush remaining packets into a page (returning nonzero),
481    even if there is not enough data to trigger a flush normally
482    (undersized page). If there are no packets or partial packets to
483    flush, ogg_stream_flush returns 0.  Note that ogg_stream_flush will
484    try to flush a normal sized page like ogg_stream_pageout; a call to
485    ogg_stream_flush does not guarantee that all packets have flushed.
486    Only a return value of 0 from ogg_stream_flush indicates all packet
487    data is flushed into pages.
488
489    since ogg_stream_flush will flush the last page in a stream even if
490    it's undersized, you almost certainly want to use ogg_stream_pageout
491    (and *not* ogg_stream_flush) unless you specifically need to flush
492    a page regardless of size in the middle of a stream. */
493
494 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
495   return ogg_stream_flush_i(os,og,1,4096);
496 }
497
498 /* Like the above, but an argument is provided to adjust the nominal
499    page size for applications which are smart enough to provide their
500    own delay based flushing */
501
502 int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
503   return ogg_stream_flush_i(os,og,1,nfill);
504 }
505
506 /* This constructs pages from buffered packet segments.  The pointers
507 returned are to static buffers; do not free. The returned buffers are
508 good only until the next call (using the same ogg_stream_state) */
509
510 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
511   int force=0;
512   if(ogg_stream_check(os)) return 0;
513
514   if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
515      (os->lacing_fill&&!os->b_o_s))           /* 'initial header page' case */
516     force=1;
517
518   return(ogg_stream_flush_i(os,og,force,4096));
519 }
520
521 /* Like the above, but an argument is provided to adjust the nominal
522 page size for applications which are smart enough to provide their
523 own delay based flushing */
524
525 int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
526   int force=0;
527   if(ogg_stream_check(os)) return 0;
528
529   if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
530      (os->lacing_fill&&!os->b_o_s))           /* 'initial header page' case */
531     force=1;
532
533   return(ogg_stream_flush_i(os,og,force,nfill));
534 }
535
536 int ogg_stream_eos(ogg_stream_state *os){
537   if(ogg_stream_check(os)) return 1;
538   return os->e_o_s;
539 }
540
541 /* DECODING PRIMITIVES: packet streaming layer **********************/
542
543 /* This has two layers to place more of the multi-serialno and paging
544    control in the application's hands.  First, we expose a data buffer
545    using ogg_sync_buffer().  The app either copies into the
546    buffer, or passes it directly to read(), etc.  We then call
547    ogg_sync_wrote() to tell how many bytes we just added.
548
549    Pages are returned (pointers into the buffer in ogg_sync_state)
550    by ogg_sync_pageout().  The page is then submitted to
551    ogg_stream_pagein() along with the appropriate
552    ogg_stream_state* (ie, matching serialno).  We then get raw
553    packets out calling ogg_stream_packetout() with a
554    ogg_stream_state. */
555
556 /* initialize the struct to a known state */
557 int ogg_sync_init(ogg_sync_state *oy){
558   if(oy){
559     oy->storage = -1; /* used as a readiness flag */
560     memset(oy,0,sizeof(*oy));
561   }
562   return(0);
563 }
564
565 /* clear non-flat storage within */
566 int ogg_sync_clear(ogg_sync_state *oy){
567   if(oy){
568     if(oy->data)_ogg_free(oy->data);
569     memset(oy,0,sizeof(*oy));
570   }
571   return(0);
572 }
573
574 int ogg_sync_destroy(ogg_sync_state *oy){
575   if(oy){
576     ogg_sync_clear(oy);
577     _ogg_free(oy);
578   }
579   return(0);
580 }
581
582 int ogg_sync_check(ogg_sync_state *oy){
583   if(oy->storage<0) return -1;
584   return 0;
585 }
586
587 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
588   if(ogg_sync_check(oy)) return NULL;
589
590   /* first, clear out any space that has been previously returned */
591   if(oy->returned){
592     oy->fill-=oy->returned;
593     if(oy->fill>0)
594       memmove(oy->data,oy->data+oy->returned,oy->fill);
595     oy->returned=0;
596   }
597
598   if(size>oy->storage-oy->fill){
599     /* We need to extend the internal buffer */
600     long newsize;
601     void *ret;
602
603     if(size>INT_MAX-4096-oy->fill){
604       ogg_sync_clear(oy);
605       return NULL;
606     }
607     newsize=size+oy->fill+4096; /* an extra page to be nice */
608     if(oy->data)
609       ret=_ogg_realloc(oy->data,newsize);
610     else
611       ret=_ogg_malloc(newsize);
612     if(!ret){
613       ogg_sync_clear(oy);
614       return NULL;
615     }
616     oy->data=ret;
617     oy->storage=newsize;
618   }
619
620   /* expose a segment at least as large as requested at the fill mark */
621   return((char *)oy->data+oy->fill);
622 }
623
624 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
625   if(ogg_sync_check(oy))return -1;
626   if(oy->fill+bytes>oy->storage)return -1;
627   oy->fill+=bytes;
628   return(0);
629 }
630
631 /* sync the stream.  This is meant to be useful for finding page
632    boundaries.
633
634    return values for this:
635   -n) skipped n bytes
636    0) page not ready; more data (no bytes skipped)
637    n) page synced at current location; page length n bytes
638
639 */
640
641 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
642   unsigned char *page=oy->data+oy->returned;
643   unsigned char *next;
644   long bytes=oy->fill-oy->returned;
645
646   if(ogg_sync_check(oy))return 0;
647
648   if(oy->headerbytes==0){
649     int headerbytes,i;
650     if(bytes<27)return(0); /* not enough for a header */
651
652     /* verify capture pattern */
653     if(memcmp(page,"OggS",4))goto sync_fail;
654
655     headerbytes=page[26]+27;
656     if(bytes<headerbytes)return(0); /* not enough for header + seg table */
657
658     /* count up body length in the segment table */
659
660     for(i=0;i<page[26];i++)
661       oy->bodybytes+=page[27+i];
662     oy->headerbytes=headerbytes;
663   }
664
665   if(oy->bodybytes+oy->headerbytes>bytes)return(0);
666
667   /* The whole test page is buffered.  Verify the checksum */
668   {
669     /* Grab the checksum bytes, set the header field to zero */
670     char chksum[4];
671     ogg_page log;
672
673     memcpy(chksum,page+22,4);
674     memset(page+22,0,4);
675
676     /* set up a temp page struct and recompute the checksum */
677     log.header=page;
678     log.header_len=oy->headerbytes;
679     log.body=page+oy->headerbytes;
680     log.body_len=oy->bodybytes;
681     ogg_page_checksum_set(&log);
682
683     /* Compare */
684     if(memcmp(chksum,page+22,4)){
685       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
686          at all) */
687       /* replace the computed checksum with the one actually read in */
688       memcpy(page+22,chksum,4);
689
690 #ifndef DISABLE_CRC
691       /* Bad checksum. Lose sync */
692       goto sync_fail;
693 #endif
694     }
695   }
696
697   /* yes, have a whole page all ready to go */
698   {
699     if(og){
700       og->header=page;
701       og->header_len=oy->headerbytes;
702       og->body=page+oy->headerbytes;
703       og->body_len=oy->bodybytes;
704     }
705
706     oy->unsynced=0;
707     oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
708     oy->headerbytes=0;
709     oy->bodybytes=0;
710     return(bytes);
711   }
712
713  sync_fail:
714
715   oy->headerbytes=0;
716   oy->bodybytes=0;
717
718   /* search for possible capture */
719   next=memchr(page+1,'O',bytes-1);
720   if(!next)
721     next=oy->data+oy->fill;
722
723   oy->returned=(int)(next-oy->data);
724   return((long)-(next-page));
725 }
726
727 /* sync the stream and get a page.  Keep trying until we find a page.
728    Suppress 'sync errors' after reporting the first.
729
730    return values:
731    -1) recapture (hole in data)
732     0) need more data
733     1) page returned
734
735    Returns pointers into buffered data; invalidated by next call to
736    _stream, _clear, _init, or _buffer */
737
738 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
739
740   if(ogg_sync_check(oy))return 0;
741
742   /* all we need to do is verify a page at the head of the stream
743      buffer.  If it doesn't verify, we look for the next potential
744      frame */
745
746   for(;;){
747     long ret=ogg_sync_pageseek(oy,og);
748     if(ret>0){
749       /* have a page */
750       return(1);
751     }
752     if(ret==0){
753       /* need more data */
754       return(0);
755     }
756
757     /* head did not start a synced page... skipped some bytes */
758     if(!oy->unsynced){
759       oy->unsynced=1;
760       return(-1);
761     }
762
763     /* loop. keep looking */
764
765   }
766 }
767
768 /* add the incoming page to the stream state; we decompose the page
769    into packet segments here as well. */
770
771 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
772   unsigned char *header=og->header;
773   unsigned char *body=og->body;
774   long           bodysize=og->body_len;
775   int            segptr=0;
776
777   int version=ogg_page_version(og);
778   int continued=ogg_page_continued(og);
779   int bos=ogg_page_bos(og);
780   int eos=ogg_page_eos(og);
781   ogg_int64_t granulepos=ogg_page_granulepos(og);
782   int serialno=ogg_page_serialno(og);
783   long pageno=ogg_page_pageno(og);
784   int segments=header[26];
785
786   if(ogg_stream_check(os)) return -1;
787
788   /* clean up 'returned data' */
789   {
790     long lr=os->lacing_returned;
791     long br=os->body_returned;
792
793     /* body data */
794     if(br){
795       os->body_fill-=br;
796       if(os->body_fill)
797         memmove(os->body_data,os->body_data+br,os->body_fill);
798       os->body_returned=0;
799     }
800
801     if(lr){
802       /* segment table */
803       if(os->lacing_fill-lr){
804         memmove(os->lacing_vals,os->lacing_vals+lr,
805                 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
806         memmove(os->granule_vals,os->granule_vals+lr,
807                 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
808       }
809       os->lacing_fill-=lr;
810       os->lacing_packet-=lr;
811       os->lacing_returned=0;
812     }
813   }
814
815   /* check the serial number */
816   if(serialno!=os->serialno)return(-1);
817   if(version>0)return(-1);
818
819   if(_os_lacing_expand(os,segments+1)) return -1;
820
821   /* are we in sequence? */
822   if(pageno!=os->pageno){
823     int i;
824
825     /* unroll previous partial packet (if any) */
826     for(i=os->lacing_packet;i<os->lacing_fill;i++)
827       os->body_fill-=os->lacing_vals[i]&0xff;
828     os->lacing_fill=os->lacing_packet;
829
830     /* make a note of dropped data in segment table */
831     if(os->pageno!=-1){
832       os->lacing_vals[os->lacing_fill++]=0x400;
833       os->lacing_packet++;
834     }
835   }
836
837   /* are we a 'continued packet' page?  If so, we may need to skip
838      some segments */
839   if(continued){
840     if(os->lacing_fill<1 ||
841        (os->lacing_vals[os->lacing_fill-1]&0xff)<255 ||
842        os->lacing_vals[os->lacing_fill-1]==0x400){
843       bos=0;
844       for(;segptr<segments;segptr++){
845         int val=header[27+segptr];
846         body+=val;
847         bodysize-=val;
848         if(val<255){
849           segptr++;
850           break;
851         }
852       }
853     }
854   }
855
856   if(bodysize){
857     if(_os_body_expand(os,bodysize)) return -1;
858     memcpy(os->body_data+os->body_fill,body,bodysize);
859     os->body_fill+=bodysize;
860   }
861
862   {
863     int saved=-1;
864     while(segptr<segments){
865       int val=header[27+segptr];
866       os->lacing_vals[os->lacing_fill]=val;
867       os->granule_vals[os->lacing_fill]=-1;
868
869       if(bos){
870         os->lacing_vals[os->lacing_fill]|=0x100;
871         bos=0;
872       }
873
874       if(val<255)saved=os->lacing_fill;
875
876       os->lacing_fill++;
877       segptr++;
878
879       if(val<255)os->lacing_packet=os->lacing_fill;
880     }
881
882     /* set the granulepos on the last granuleval of the last full packet */
883     if(saved!=-1){
884       os->granule_vals[saved]=granulepos;
885     }
886
887   }
888
889   if(eos){
890     os->e_o_s=1;
891     if(os->lacing_fill>0)
892       os->lacing_vals[os->lacing_fill-1]|=0x200;
893   }
894
895   os->pageno=pageno+1;
896
897   return(0);
898 }
899
900 /* clear things to an initial state.  Good to call, eg, before seeking */
901 int ogg_sync_reset(ogg_sync_state *oy){
902   if(ogg_sync_check(oy))return -1;
903
904   oy->fill=0;
905   oy->returned=0;
906   oy->unsynced=0;
907   oy->headerbytes=0;
908   oy->bodybytes=0;
909   return(0);
910 }
911
912 int ogg_stream_reset(ogg_stream_state *os){
913   if(ogg_stream_check(os)) return -1;
914
915   os->body_fill=0;
916   os->body_returned=0;
917
918   os->lacing_fill=0;
919   os->lacing_packet=0;
920   os->lacing_returned=0;
921
922   os->header_fill=0;
923
924   os->e_o_s=0;
925   os->b_o_s=0;
926   os->pageno=-1;
927   os->packetno=0;
928   os->granulepos=0;
929
930   return(0);
931 }
932
933 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
934   if(ogg_stream_check(os)) return -1;
935   ogg_stream_reset(os);
936   os->serialno=serialno;
937   return(0);
938 }
939
940 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
941
942   /* The last part of decode. We have the stream broken into packet
943      segments.  Now we need to group them into packets (or return the
944      out of sync markers) */
945
946   int ptr=os->lacing_returned;
947
948   if(os->lacing_packet<=ptr)return(0);
949
950   if(os->lacing_vals[ptr]&0x400){
951     /* we need to tell the codec there's a gap; it might need to
952        handle previous packet dependencies. */
953     os->lacing_returned++;
954     os->packetno++;
955     return(-1);
956   }
957
958   if(!op && !adv)return(1); /* just using peek as an inexpensive way
959                                to ask if there's a whole packet
960                                waiting */
961
962   /* Gather the whole packet. We'll have no holes or a partial packet */
963   {
964     int size=os->lacing_vals[ptr]&0xff;
965     long bytes=size;
966     int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
967     int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
968
969     while(size==255){
970       int val=os->lacing_vals[++ptr];
971       size=val&0xff;
972       if(val&0x200)eos=0x200;
973       bytes+=size;
974     }
975
976     if(op){
977       op->e_o_s=eos;
978       op->b_o_s=bos;
979       op->packet=os->body_data+os->body_returned;
980       op->packetno=os->packetno;
981       op->granulepos=os->granule_vals[ptr];
982       op->bytes=bytes;
983     }
984
985     if(adv){
986       os->body_returned+=bytes;
987       os->lacing_returned=ptr+1;
988       os->packetno++;
989     }
990   }
991   return(1);
992 }
993
994 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
995   if(ogg_stream_check(os)) return 0;
996   return _packetout(os,op,1);
997 }
998
999 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
1000   if(ogg_stream_check(os)) return 0;
1001   return _packetout(os,op,0);
1002 }
1003
1004 void ogg_packet_clear(ogg_packet *op) {
1005   _ogg_free(op->packet);
1006   memset(op, 0, sizeof(*op));
1007 }
1008
1009 #ifdef _V_SELFTEST
1010 #include <stdio.h>
1011
1012 ogg_stream_state os_en, os_de;
1013 ogg_sync_state oy;
1014
1015 void checkpacket(ogg_packet *op,long len, int no, long pos){
1016   long j;
1017   static int sequence=0;
1018   static int lastno=0;
1019
1020   if(op->bytes!=len){
1021     fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
1022     exit(1);
1023   }
1024   if(op->granulepos!=pos){
1025     fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1026     exit(1);
1027   }
1028
1029   /* packet number just follows sequence/gap; adjust the input number
1030      for that */
1031   if(no==0){
1032     sequence=0;
1033   }else{
1034     sequence++;
1035     if(no>lastno+1)
1036       sequence++;
1037   }
1038   lastno=no;
1039   if(op->packetno!=sequence){
1040     fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1041             (long)(op->packetno),sequence);
1042     exit(1);
1043   }
1044
1045   /* Test data */
1046   for(j=0;j<op->bytes;j++)
1047     if(op->packet[j]!=((j+no)&0xff)){
1048       fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1049               j,op->packet[j],(j+no)&0xff);
1050       exit(1);
1051     }
1052 }
1053
1054 void check_page(unsigned char *data,const int *header,ogg_page *og){
1055   long j;
1056   /* Test data */
1057   for(j=0;j<og->body_len;j++)
1058     if(og->body[j]!=data[j]){
1059       fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1060               j,data[j],og->body[j]);
1061       exit(1);
1062     }
1063
1064   /* Test header */
1065   for(j=0;j<og->header_len;j++){
1066     if(og->header[j]!=header[j]){
1067       fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1068       for(j=0;j<header[26]+27;j++)
1069         fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1070       fprintf(stderr,"\n");
1071       exit(1);
1072     }
1073   }
1074   if(og->header_len!=header[26]+27){
1075     fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1076             og->header_len,header[26]+27);
1077     exit(1);
1078   }
1079 }
1080
1081 void print_header(ogg_page *og){
1082   int j;
1083   fprintf(stderr,"\nHEADER:\n");
1084   fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
1085           og->header[0],og->header[1],og->header[2],og->header[3],
1086           (int)og->header[4],(int)og->header[5]);
1087
1088   fprintf(stderr,"  granulepos: %d  serialno: %d  pageno: %ld\n",
1089           (og->header[9]<<24)|(og->header[8]<<16)|
1090           (og->header[7]<<8)|og->header[6],
1091           (og->header[17]<<24)|(og->header[16]<<16)|
1092           (og->header[15]<<8)|og->header[14],
1093           ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1094           (og->header[19]<<8)|og->header[18]);
1095
1096   fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
1097           (int)og->header[22],(int)og->header[23],
1098           (int)og->header[24],(int)og->header[25],
1099           (int)og->header[26]);
1100
1101   for(j=27;j<og->header_len;j++)
1102     fprintf(stderr,"%d ",(int)og->header[j]);
1103   fprintf(stderr,")\n\n");
1104 }
1105
1106 void copy_page(ogg_page *og){
1107   unsigned char *temp=_ogg_malloc(og->header_len);
1108   memcpy(temp,og->header,og->header_len);
1109   og->header=temp;
1110
1111   temp=_ogg_malloc(og->body_len);
1112   memcpy(temp,og->body,og->body_len);
1113   og->body=temp;
1114 }
1115
1116 void free_page(ogg_page *og){
1117   _ogg_free (og->header);
1118   _ogg_free (og->body);
1119 }
1120
1121 void error(void){
1122   fprintf(stderr,"error!\n");
1123   exit(1);
1124 }
1125
1126 /* 17 only */
1127 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1128                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1129                        0x01,0x02,0x03,0x04,0,0,0,0,
1130                        0x15,0xed,0xec,0x91,
1131                        1,
1132                        17};
1133
1134 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1135 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1136                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1137                        0x01,0x02,0x03,0x04,0,0,0,0,
1138                        0x59,0x10,0x6c,0x2c,
1139                        1,
1140                        17};
1141 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1142                        0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1143                        0x01,0x02,0x03,0x04,1,0,0,0,
1144                        0x89,0x33,0x85,0xce,
1145                        13,
1146                        254,255,0,255,1,255,245,255,255,0,
1147                        255,255,90};
1148
1149 /* nil packets; beginning,middle,end */
1150 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1151                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1152                        0x01,0x02,0x03,0x04,0,0,0,0,
1153                        0xff,0x7b,0x23,0x17,
1154                        1,
1155                        0};
1156 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1157                        0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1158                        0x01,0x02,0x03,0x04,1,0,0,0,
1159                        0x5c,0x3f,0x66,0xcb,
1160                        17,
1161                        17,254,255,0,0,255,1,0,255,245,255,255,0,
1162                        255,255,90,0};
1163
1164 /* large initial packet */
1165 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1166                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1167                        0x01,0x02,0x03,0x04,0,0,0,0,
1168                        0x01,0x27,0x31,0xaa,
1169                        18,
1170                        255,255,255,255,255,255,255,255,
1171                        255,255,255,255,255,255,255,255,255,10};
1172
1173 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1174                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1175                        0x01,0x02,0x03,0x04,1,0,0,0,
1176                        0x7f,0x4e,0x8a,0xd2,
1177                        4,
1178                        255,4,255,0};
1179
1180
1181 /* continuing packet test */
1182 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1183                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1184                        0x01,0x02,0x03,0x04,0,0,0,0,
1185                        0xff,0x7b,0x23,0x17,
1186                        1,
1187                        0};
1188
1189 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1190                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1191                        0x01,0x02,0x03,0x04,1,0,0,0,
1192                        0xf8,0x3c,0x19,0x79,
1193                        255,
1194                        255,255,255,255,255,255,255,255,
1195                        255,255,255,255,255,255,255,255,
1196                        255,255,255,255,255,255,255,255,
1197                        255,255,255,255,255,255,255,255,
1198                        255,255,255,255,255,255,255,255,
1199                        255,255,255,255,255,255,255,255,
1200                        255,255,255,255,255,255,255,255,
1201                        255,255,255,255,255,255,255,255,
1202                        255,255,255,255,255,255,255,255,
1203                        255,255,255,255,255,255,255,255,
1204                        255,255,255,255,255,255,255,255,
1205                        255,255,255,255,255,255,255,255,
1206                        255,255,255,255,255,255,255,255,
1207                        255,255,255,255,255,255,255,255,
1208                        255,255,255,255,255,255,255,255,
1209                        255,255,255,255,255,255,255,255,
1210                        255,255,255,255,255,255,255,255,
1211                        255,255,255,255,255,255,255,255,
1212                        255,255,255,255,255,255,255,255,
1213                        255,255,255,255,255,255,255,255,
1214                        255,255,255,255,255,255,255,255,
1215                        255,255,255,255,255,255,255,255,
1216                        255,255,255,255,255,255,255,255,
1217                        255,255,255,255,255,255,255,255,
1218                        255,255,255,255,255,255,255,255,
1219                        255,255,255,255,255,255,255,255,
1220                        255,255,255,255,255,255,255,255,
1221                        255,255,255,255,255,255,255,255,
1222                        255,255,255,255,255,255,255,255,
1223                        255,255,255,255,255,255,255,255,
1224                        255,255,255,255,255,255,255,255,
1225                        255,255,255,255,255,255,255};
1226
1227 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1228                        0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1229                        0x01,0x02,0x03,0x04,2,0,0,0,
1230                        0x38,0xe6,0xb6,0x28,
1231                        6,
1232                        255,220,255,4,255,0};
1233
1234
1235 /* spill expansion test */
1236 const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1237                         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1238                         0x01,0x02,0x03,0x04,0,0,0,0,
1239                         0xff,0x7b,0x23,0x17,
1240                         1,
1241                         0};
1242
1243 const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1244                         0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1245                         0x01,0x02,0x03,0x04,1,0,0,0,
1246                         0xce,0x8f,0x17,0x1a,
1247                         23,
1248                         255,255,255,255,255,255,255,255,
1249                         255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1250
1251
1252 const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1253                         0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1254                         0x01,0x02,0x03,0x04,2,0,0,0,
1255                         0x9b,0xb2,0x50,0xa1,
1256                         1,
1257                         0};
1258
1259 /* page with the 255 segment limit */
1260 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1261                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1262                        0x01,0x02,0x03,0x04,0,0,0,0,
1263                        0xff,0x7b,0x23,0x17,
1264                        1,
1265                        0};
1266
1267 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1268                        0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1269                        0x01,0x02,0x03,0x04,1,0,0,0,
1270                        0xed,0x2a,0x2e,0xa7,
1271                        255,
1272                        10,10,10,10,10,10,10,10,
1273                        10,10,10,10,10,10,10,10,
1274                        10,10,10,10,10,10,10,10,
1275                        10,10,10,10,10,10,10,10,
1276                        10,10,10,10,10,10,10,10,
1277                        10,10,10,10,10,10,10,10,
1278                        10,10,10,10,10,10,10,10,
1279                        10,10,10,10,10,10,10,10,
1280                        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};
1304
1305 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1306                        0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1307                        0x01,0x02,0x03,0x04,2,0,0,0,
1308                        0x6c,0x3b,0x82,0x3d,
1309                        1,
1310                        50};
1311
1312
1313 /* packet that overspans over an entire page */
1314 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1315                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1316                        0x01,0x02,0x03,0x04,0,0,0,0,
1317                        0xff,0x7b,0x23,0x17,
1318                        1,
1319                        0};
1320
1321 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1322                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1323                        0x01,0x02,0x03,0x04,1,0,0,0,
1324                        0x68,0x22,0x7c,0x3d,
1325                        255,
1326                        100,
1327                        255,255,255,255,255,255,255,255,
1328                        255,255,255,255,255,255,255,255,
1329                        255,255,255,255,255,255,255,255,
1330                        255,255,255,255,255,255,255,255,
1331                        255,255,255,255,255,255,255,255,
1332                        255,255,255,255,255,255,255,255,
1333                        255,255,255,255,255,255,255,255,
1334                        255,255,255,255,255,255,255,255,
1335                        255,255,255,255,255,255,255,255,
1336                        255,255,255,255,255,255,255,255,
1337                        255,255,255,255,255,255,255,255,
1338                        255,255,255,255,255,255,255,255,
1339                        255,255,255,255,255,255,255,255,
1340                        255,255,255,255,255,255,255,255,
1341                        255,255,255,255,255,255,255,255,
1342                        255,255,255,255,255,255,255,255,
1343                        255,255,255,255,255,255,255,255,
1344                        255,255,255,255,255,255,255,255,
1345                        255,255,255,255,255,255,255,255,
1346                        255,255,255,255,255,255,255,255,
1347                        255,255,255,255,255,255,255,255,
1348                        255,255,255,255,255,255,255,255,
1349                        255,255,255,255,255,255,255,255,
1350                        255,255,255,255,255,255,255,255,
1351                        255,255,255,255,255,255,255,255,
1352                        255,255,255,255,255,255,255,255,
1353                        255,255,255,255,255,255,255,255,
1354                        255,255,255,255,255,255,255,255,
1355                        255,255,255,255,255,255,255,255,
1356                        255,255,255,255,255,255,255,255,
1357                        255,255,255,255,255,255,255,255,
1358                        255,255,255,255,255,255};
1359
1360 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1361                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1362                        0x01,0x02,0x03,0x04,2,0,0,0,
1363                        0xf4,0x87,0xba,0xf3,
1364                        255,
1365                        255,255,255,255,255,255,255,255,
1366                        255,255,255,255,255,255,255,255,
1367                        255,255,255,255,255,255,255,255,
1368                        255,255,255,255,255,255,255,255,
1369                        255,255,255,255,255,255,255,255,
1370                        255,255,255,255,255,255,255,255,
1371                        255,255,255,255,255,255,255,255,
1372                        255,255,255,255,255,255,255,255,
1373                        255,255,255,255,255,255,255,255,
1374                        255,255,255,255,255,255,255,255,
1375                        255,255,255,255,255,255,255,255,
1376                        255,255,255,255,255,255,255,255,
1377                        255,255,255,255,255,255,255,255,
1378                        255,255,255,255,255,255,255,255,
1379                        255,255,255,255,255,255,255,255,
1380                        255,255,255,255,255,255,255,255,
1381                        255,255,255,255,255,255,255,255,
1382                        255,255,255,255,255,255,255,255,
1383                        255,255,255,255,255,255,255,255,
1384                        255,255,255,255,255,255,255,255,
1385                        255,255,255,255,255,255,255,255,
1386                        255,255,255,255,255,255,255,255,
1387                        255,255,255,255,255,255,255,255,
1388                        255,255,255,255,255,255,255,255,
1389                        255,255,255,255,255,255,255,255,
1390                        255,255,255,255,255,255,255,255,
1391                        255,255,255,255,255,255,255,255,
1392                        255,255,255,255,255,255,255,255,
1393                        255,255,255,255,255,255,255,255,
1394                        255,255,255,255,255,255,255,255,
1395                        255,255,255,255,255,255,255,255,
1396                        255,255,255,255,255,255,255};
1397
1398 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1399                        0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1400                        0x01,0x02,0x03,0x04,3,0,0,0,
1401                        0xf7,0x2f,0x6c,0x60,
1402                        5,
1403                        254,255,4,255,0};
1404
1405 /* packet that overspans over an entire page */
1406 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1407                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1408                        0x01,0x02,0x03,0x04,0,0,0,0,
1409                        0xff,0x7b,0x23,0x17,
1410                        1,
1411                        0};
1412
1413 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1414                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1415                        0x01,0x02,0x03,0x04,1,0,0,0,
1416                        0x68,0x22,0x7c,0x3d,
1417                        255,
1418                        100,
1419                        255,255,255,255,255,255,255,255,
1420                        255,255,255,255,255,255,255,255,
1421                        255,255,255,255,255,255,255,255,
1422                        255,255,255,255,255,255,255,255,
1423                        255,255,255,255,255,255,255,255,
1424                        255,255,255,255,255,255,255,255,
1425                        255,255,255,255,255,255,255,255,
1426                        255,255,255,255,255,255,255,255,
1427                        255,255,255,255,255,255,255,255,
1428                        255,255,255,255,255,255,255,255,
1429                        255,255,255,255,255,255,255,255,
1430                        255,255,255,255,255,255,255,255,
1431                        255,255,255,255,255,255,255,255,
1432                        255,255,255,255,255,255,255,255,
1433                        255,255,255,255,255,255,255,255,
1434                        255,255,255,255,255,255,255,255,
1435                        255,255,255,255,255,255,255,255,
1436                        255,255,255,255,255,255,255,255,
1437                        255,255,255,255,255,255,255,255,
1438                        255,255,255,255,255,255,255,255,
1439                        255,255,255,255,255,255,255,255,
1440                        255,255,255,255,255,255,255,255,
1441                        255,255,255,255,255,255,255,255,
1442                        255,255,255,255,255,255,255,255,
1443                        255,255,255,255,255,255,255,255,
1444                        255,255,255,255,255,255,255,255,
1445                        255,255,255,255,255,255,255,255,
1446                        255,255,255,255,255,255,255,255,
1447                        255,255,255,255,255,255,255,255,
1448                        255,255,255,255,255,255,255,255,
1449                        255,255,255,255,255,255,255,255,
1450                        255,255,255,255,255,255};
1451
1452 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1453                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1454                        0x01,0x02,0x03,0x04,2,0,0,0,
1455                        0xd4,0xe0,0x60,0xe5,
1456                        1,
1457                        0};
1458
1459 int compare_packet(const ogg_packet *op1, const ogg_packet *op2){
1460   if(op1->packet!=op2->packet){
1461     fprintf(stderr,"op1->packet != op2->packet\n");
1462     return(1);
1463   }
1464   if(op1->bytes!=op2->bytes){
1465     fprintf(stderr,"op1->bytes != op2->bytes\n");
1466     return(1);
1467   }
1468   if(op1->b_o_s!=op2->b_o_s){
1469     fprintf(stderr,"op1->b_o_s != op2->b_o_s\n");
1470     return(1);
1471   }
1472   if(op1->e_o_s!=op2->e_o_s){
1473     fprintf(stderr,"op1->e_o_s != op2->e_o_s\n");
1474     return(1);
1475   }
1476   if(op1->granulepos!=op2->granulepos){
1477     fprintf(stderr,"op1->granulepos != op2->granulepos\n");
1478     return(1);
1479   }
1480   if(op1->packetno!=op2->packetno){
1481     fprintf(stderr,"op1->packetno != op2->packetno\n");
1482     return(1);
1483   }
1484   return(0);
1485 }
1486
1487 void test_pack(const int *pl, const int **headers, int byteskip,
1488                int pageskip, int packetskip){
1489   unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1490   long inptr=0;
1491   long outptr=0;
1492   long deptr=0;
1493   long depacket=0;
1494   long granule_pos=7,pageno=0;
1495   int i,j,packets,pageout=pageskip;
1496   int eosflag=0;
1497   int bosflag=0;
1498
1499   int byteskipcount=0;
1500
1501   ogg_stream_reset(&os_en);
1502   ogg_stream_reset(&os_de);
1503   ogg_sync_reset(&oy);
1504
1505   for(packets=0;packets<packetskip;packets++)
1506     depacket+=pl[packets];
1507
1508   for(packets=0;;packets++)if(pl[packets]==-1)break;
1509
1510   for(i=0;i<packets;i++){
1511     /* construct a test packet */
1512     ogg_packet op;
1513     int len=pl[i];
1514
1515     op.packet=data+inptr;
1516     op.bytes=len;
1517     op.e_o_s=(pl[i+1]<0?1:0);
1518     op.granulepos=granule_pos;
1519
1520     granule_pos+=1024;
1521
1522     for(j=0;j<len;j++)data[inptr++]=i+j;
1523
1524     /* submit the test packet */
1525     ogg_stream_packetin(&os_en,&op);
1526
1527     /* retrieve any finished pages */
1528     {
1529       ogg_page og;
1530
1531       while(ogg_stream_pageout(&os_en,&og)){
1532         /* We have a page.  Check it carefully */
1533
1534         fprintf(stderr,"%ld, ",pageno);
1535
1536         if(headers[pageno]==NULL){
1537           fprintf(stderr,"coded too many pages!\n");
1538           exit(1);
1539         }
1540
1541         check_page(data+outptr,headers[pageno],&og);
1542
1543         outptr+=og.body_len;
1544         pageno++;
1545         if(pageskip){
1546           bosflag=1;
1547           pageskip--;
1548           deptr+=og.body_len;
1549         }
1550
1551         /* have a complete page; submit it to sync/decode */
1552
1553         {
1554           ogg_page og_de;
1555           ogg_packet op_de,op_de2;
1556           char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1557           char *next=buf;
1558           byteskipcount+=og.header_len;
1559           if(byteskipcount>byteskip){
1560             memcpy(next,og.header,byteskipcount-byteskip);
1561             next+=byteskipcount-byteskip;
1562             byteskipcount=byteskip;
1563           }
1564
1565           byteskipcount+=og.body_len;
1566           if(byteskipcount>byteskip){
1567             memcpy(next,og.body,byteskipcount-byteskip);
1568             next+=byteskipcount-byteskip;
1569             byteskipcount=byteskip;
1570           }
1571
1572           ogg_sync_wrote(&oy,(long)(next-buf));
1573
1574           while(1){
1575             int ret=ogg_sync_pageout(&oy,&og_de);
1576             if(ret==0)break;
1577             if(ret<0)continue;
1578             /* got a page.  Happy happy.  Verify that it's good. */
1579
1580             fprintf(stderr,"(%d), ",pageout);
1581
1582             check_page(data+deptr,headers[pageout],&og_de);
1583             deptr+=og_de.body_len;
1584             pageout++;
1585
1586             /* submit it to deconstitution */
1587             ogg_stream_pagein(&os_de,&og_de);
1588
1589             /* packets out? */
1590             while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1591               ogg_stream_packetpeek(&os_de,NULL);
1592               ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1593
1594               /* verify peek and out match */
1595               if(compare_packet(&op_de,&op_de2)){
1596                 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1597                         depacket);
1598                 exit(1);
1599               }
1600
1601               /* verify the packet! */
1602               /* check data */
1603               if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1604                 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1605                         depacket);
1606                 exit(1);
1607               }
1608               /* check bos flag */
1609               if(bosflag==0 && op_de.b_o_s==0){
1610                 fprintf(stderr,"b_o_s flag not set on packet!\n");
1611                 exit(1);
1612               }
1613               if(bosflag && op_de.b_o_s){
1614                 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1615                 exit(1);
1616               }
1617               bosflag=1;
1618               depacket+=op_de.bytes;
1619
1620               /* check eos flag */
1621               if(eosflag){
1622                 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1623                 exit(1);
1624               }
1625
1626               if(op_de.e_o_s)eosflag=1;
1627
1628               /* check granulepos flag */
1629               if(op_de.granulepos!=-1){
1630                 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1631               }
1632             }
1633           }
1634         }
1635       }
1636     }
1637   }
1638   _ogg_free(data);
1639   if(headers[pageno]!=NULL){
1640     fprintf(stderr,"did not write last page!\n");
1641     exit(1);
1642   }
1643   if(headers[pageout]!=NULL){
1644     fprintf(stderr,"did not decode last page!\n");
1645     exit(1);
1646   }
1647   if(inptr!=outptr){
1648     fprintf(stderr,"encoded page data incomplete!\n");
1649     exit(1);
1650   }
1651   if(inptr!=deptr){
1652     fprintf(stderr,"decoded page data incomplete!\n");
1653     exit(1);
1654   }
1655   if(inptr!=depacket){
1656     fprintf(stderr,"decoded packet data incomplete!\n");
1657     exit(1);
1658   }
1659   if(!eosflag){
1660     fprintf(stderr,"Never got a packet with EOS set!\n");
1661     exit(1);
1662   }
1663   fprintf(stderr,"ok.\n");
1664 }
1665
1666 int main(void){
1667
1668   ogg_stream_init(&os_en,0x04030201);
1669   ogg_stream_init(&os_de,0x04030201);
1670   ogg_sync_init(&oy);
1671
1672   /* Exercise each code path in the framing code.  Also verify that
1673      the checksums are working.  */
1674
1675   {
1676     /* 17 only */
1677     const int packets[]={17, -1};
1678     const int *headret[]={head1_0,NULL};
1679
1680     fprintf(stderr,"testing single page encoding... ");
1681     test_pack(packets,headret,0,0,0);
1682   }
1683
1684   {
1685     /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1686     const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1687     const int *headret[]={head1_1,head2_1,NULL};
1688
1689     fprintf(stderr,"testing basic page encoding... ");
1690     test_pack(packets,headret,0,0,0);
1691   }
1692
1693   {
1694     /* nil packets; beginning,middle,end */
1695     const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1696     const int *headret[]={head1_2,head2_2,NULL};
1697
1698     fprintf(stderr,"testing basic nil packets... ");
1699     test_pack(packets,headret,0,0,0);
1700   }
1701
1702   {
1703     /* large initial packet */
1704     const int packets[]={4345,259,255,-1};
1705     const int *headret[]={head1_3,head2_3,NULL};
1706
1707     fprintf(stderr,"testing initial-packet lacing > 4k... ");
1708     test_pack(packets,headret,0,0,0);
1709   }
1710
1711   {
1712     /* continuing packet test; with page spill expansion, we have to
1713        overflow the lacing table. */
1714     const int packets[]={0,65500,259,255,-1};
1715     const int *headret[]={head1_4,head2_4,head3_4,NULL};
1716
1717     fprintf(stderr,"testing single packet page span... ");
1718     test_pack(packets,headret,0,0,0);
1719   }
1720
1721   {
1722     /* spill expand packet test */
1723     const int packets[]={0,4345,259,255,0,0,-1};
1724     const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1725
1726     fprintf(stderr,"testing page spill expansion... ");
1727     test_pack(packets,headret,0,0,0);
1728   }
1729
1730   /* page with the 255 segment limit */
1731   {
1732
1733     const int packets[]={0,10,10,10,10,10,10,10,10,
1734                    10,10,10,10,10,10,10,10,
1735                    10,10,10,10,10,10,10,10,
1736                    10,10,10,10,10,10,10,10,
1737                    10,10,10,10,10,10,10,10,
1738                    10,10,10,10,10,10,10,10,
1739                    10,10,10,10,10,10,10,10,
1740                    10,10,10,10,10,10,10,10,
1741                    10,10,10,10,10,10,10,10,
1742                    10,10,10,10,10,10,10,10,
1743                    10,10,10,10,10,10,10,10,
1744                    10,10,10,10,10,10,10,10,
1745                    10,10,10,10,10,10,10,10,
1746                    10,10,10,10,10,10,10,10,
1747                    10,10,10,10,10,10,10,10,
1748                    10,10,10,10,10,10,10,10,
1749                    10,10,10,10,10,10,10,10,
1750                    10,10,10,10,10,10,10,10,
1751                    10,10,10,10,10,10,10,10,
1752                    10,10,10,10,10,10,10,10,
1753                    10,10,10,10,10,10,10,10,
1754                    10,10,10,10,10,10,10,10,
1755                    10,10,10,10,10,10,10,10,
1756                    10,10,10,10,10,10,10,10,
1757                    10,10,10,10,10,10,10,10,
1758                    10,10,10,10,10,10,10,10,
1759                    10,10,10,10,10,10,10,10,
1760                    10,10,10,10,10,10,10,10,
1761                    10,10,10,10,10,10,10,10,
1762                    10,10,10,10,10,10,10,10,
1763                    10,10,10,10,10,10,10,10,
1764                    10,10,10,10,10,10,10,50,-1};
1765     const int *headret[]={head1_5,head2_5,head3_5,NULL};
1766
1767     fprintf(stderr,"testing max packet segments... ");
1768     test_pack(packets,headret,0,0,0);
1769   }
1770
1771   {
1772     /* packet that overspans over an entire page */
1773     const int packets[]={0,100,130049,259,255,-1};
1774     const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1775
1776     fprintf(stderr,"testing very large packets... ");
1777     test_pack(packets,headret,0,0,0);
1778   }
1779
1780 #ifndef DISABLE_CRC
1781   {
1782     /* test for the libogg 1.1.1 resync in large continuation bug
1783        found by Josh Coalson)  */
1784     const int packets[]={0,100,130049,259,255,-1};
1785     const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1786
1787     fprintf(stderr,"testing continuation resync in very large packets... ");
1788     test_pack(packets,headret,100,2,3);
1789   }
1790 #else
1791     fprintf(stderr,"Skipping continuation resync test due to --disable-crc\n");
1792 #endif
1793
1794   {
1795     /* term only page.  why not? */
1796     const int packets[]={0,100,64770,-1};
1797     const int *headret[]={head1_7,head2_7,head3_7,NULL};
1798
1799     fprintf(stderr,"testing zero data page (1 nil packet)... ");
1800     test_pack(packets,headret,0,0,0);
1801   }
1802
1803
1804
1805   {
1806     /* build a bunch of pages for testing */
1807     unsigned char *data=_ogg_malloc(1024*1024);
1808     int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1809     int inptr=0,i,j;
1810     ogg_page og[5];
1811
1812     ogg_stream_reset(&os_en);
1813
1814     for(i=0;pl[i]!=-1;i++){
1815       ogg_packet op;
1816       int len=pl[i];
1817
1818       op.packet=data+inptr;
1819       op.bytes=len;
1820       op.e_o_s=(pl[i+1]<0?1:0);
1821       op.granulepos=(i+1)*1000;
1822
1823       for(j=0;j<len;j++)data[inptr++]=i+j;
1824       ogg_stream_packetin(&os_en,&op);
1825     }
1826
1827     _ogg_free(data);
1828
1829     /* retrieve finished pages */
1830     for(i=0;i<5;i++){
1831       if(ogg_stream_pageout(&os_en,&og[i])==0){
1832         fprintf(stderr,"Too few pages output building sync tests!\n");
1833         exit(1);
1834       }
1835       copy_page(&og[i]);
1836     }
1837
1838     /* Test lost pages on pagein/packetout: no rollback */
1839     {
1840       ogg_page temp;
1841       ogg_packet test;
1842
1843       fprintf(stderr,"Testing loss of pages... ");
1844
1845       ogg_sync_reset(&oy);
1846       ogg_stream_reset(&os_de);
1847       for(i=0;i<5;i++){
1848         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1849                og[i].header_len);
1850         ogg_sync_wrote(&oy,og[i].header_len);
1851         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1852         ogg_sync_wrote(&oy,og[i].body_len);
1853       }
1854
1855       ogg_sync_pageout(&oy,&temp);
1856       ogg_stream_pagein(&os_de,&temp);
1857       ogg_sync_pageout(&oy,&temp);
1858       ogg_stream_pagein(&os_de,&temp);
1859       ogg_sync_pageout(&oy,&temp);
1860       /* skip */
1861       ogg_sync_pageout(&oy,&temp);
1862       ogg_stream_pagein(&os_de,&temp);
1863
1864       /* do we get the expected results/packets? */
1865
1866       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1867       checkpacket(&test,0,0,0);
1868       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1869       checkpacket(&test,1,1,-1);
1870       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1871       checkpacket(&test,1,2,-1);
1872       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1873       checkpacket(&test,98,3,-1);
1874       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1875       checkpacket(&test,4079,4,5000);
1876       if(ogg_stream_packetout(&os_de,&test)!=-1){
1877         fprintf(stderr,"Error: loss of page did not return error\n");
1878         exit(1);
1879       }
1880       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1881       checkpacket(&test,76,9,-1);
1882       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1883       checkpacket(&test,34,10,-1);
1884       fprintf(stderr,"ok.\n");
1885     }
1886
1887     /* Test lost pages on pagein/packetout: rollback with continuation */
1888     {
1889       ogg_page temp;
1890       ogg_packet test;
1891
1892       fprintf(stderr,"Testing loss of pages (rollback required)... ");
1893
1894       ogg_sync_reset(&oy);
1895       ogg_stream_reset(&os_de);
1896       for(i=0;i<5;i++){
1897         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1898                og[i].header_len);
1899         ogg_sync_wrote(&oy,og[i].header_len);
1900         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1901         ogg_sync_wrote(&oy,og[i].body_len);
1902       }
1903
1904       ogg_sync_pageout(&oy,&temp);
1905       ogg_stream_pagein(&os_de,&temp);
1906       ogg_sync_pageout(&oy,&temp);
1907       ogg_stream_pagein(&os_de,&temp);
1908       ogg_sync_pageout(&oy,&temp);
1909       ogg_stream_pagein(&os_de,&temp);
1910       ogg_sync_pageout(&oy,&temp);
1911       /* skip */
1912       ogg_sync_pageout(&oy,&temp);
1913       ogg_stream_pagein(&os_de,&temp);
1914
1915       /* do we get the expected results/packets? */
1916
1917       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1918       checkpacket(&test,0,0,0);
1919       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1920       checkpacket(&test,1,1,-1);
1921       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1922       checkpacket(&test,1,2,-1);
1923       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1924       checkpacket(&test,98,3,-1);
1925       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1926       checkpacket(&test,4079,4,5000);
1927       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1928       checkpacket(&test,1,5,-1);
1929       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1930       checkpacket(&test,1,6,-1);
1931       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1932       checkpacket(&test,2954,7,-1);
1933       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1934       checkpacket(&test,2057,8,9000);
1935       if(ogg_stream_packetout(&os_de,&test)!=-1){
1936         fprintf(stderr,"Error: loss of page did not return error\n");
1937         exit(1);
1938       }
1939       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1940       checkpacket(&test,300,17,18000);
1941       fprintf(stderr,"ok.\n");
1942     }
1943
1944     /* the rest only test sync */
1945     {
1946       ogg_page og_de;
1947       /* Test fractional page inputs: incomplete capture */
1948       fprintf(stderr,"Testing sync on partial inputs... ");
1949       ogg_sync_reset(&oy);
1950       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1951              3);
1952       ogg_sync_wrote(&oy,3);
1953       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1954
1955       /* Test fractional page inputs: incomplete fixed header */
1956       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1957              20);
1958       ogg_sync_wrote(&oy,20);
1959       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1960
1961       /* Test fractional page inputs: incomplete header */
1962       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1963              5);
1964       ogg_sync_wrote(&oy,5);
1965       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1966
1967       /* Test fractional page inputs: incomplete body */
1968
1969       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1970              og[1].header_len-28);
1971       ogg_sync_wrote(&oy,og[1].header_len-28);
1972       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1973
1974       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1975       ogg_sync_wrote(&oy,1000);
1976       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1977
1978       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1979              og[1].body_len-1000);
1980       ogg_sync_wrote(&oy,og[1].body_len-1000);
1981       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1982
1983       fprintf(stderr,"ok.\n");
1984     }
1985
1986     /* Test fractional page inputs: page + incomplete capture */
1987     {
1988       ogg_page og_de;
1989       fprintf(stderr,"Testing sync on 1+partial inputs... ");
1990       ogg_sync_reset(&oy);
1991
1992       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1993              og[1].header_len);
1994       ogg_sync_wrote(&oy,og[1].header_len);
1995
1996       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1997              og[1].body_len);
1998       ogg_sync_wrote(&oy,og[1].body_len);
1999
2000       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2001              20);
2002       ogg_sync_wrote(&oy,20);
2003       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2004       if(ogg_sync_pageout(&oy,&og_de)>0)error();
2005
2006       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
2007              og[1].header_len-20);
2008       ogg_sync_wrote(&oy,og[1].header_len-20);
2009       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2010              og[1].body_len);
2011       ogg_sync_wrote(&oy,og[1].body_len);
2012       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2013
2014       fprintf(stderr,"ok.\n");
2015     }
2016
2017     /* Test recapture: garbage + page */
2018     {
2019       ogg_page og_de;
2020       fprintf(stderr,"Testing search for capture... ");
2021       ogg_sync_reset(&oy);
2022
2023       /* 'garbage' */
2024       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2025              og[1].body_len);
2026       ogg_sync_wrote(&oy,og[1].body_len);
2027
2028       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2029              og[1].header_len);
2030       ogg_sync_wrote(&oy,og[1].header_len);
2031
2032       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2033              og[1].body_len);
2034       ogg_sync_wrote(&oy,og[1].body_len);
2035
2036       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2037              20);
2038       ogg_sync_wrote(&oy,20);
2039       if(ogg_sync_pageout(&oy,&og_de)>0)error();
2040       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2041       if(ogg_sync_pageout(&oy,&og_de)>0)error();
2042
2043       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2044              og[2].header_len-20);
2045       ogg_sync_wrote(&oy,og[2].header_len-20);
2046       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2047              og[2].body_len);
2048       ogg_sync_wrote(&oy,og[2].body_len);
2049       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2050
2051       fprintf(stderr,"ok.\n");
2052     }
2053
2054 #ifndef DISABLE_CRC
2055     /* Test recapture: page + garbage + page */
2056     {
2057       ogg_page og_de;
2058       fprintf(stderr,"Testing recapture... ");
2059       ogg_sync_reset(&oy);
2060
2061       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2062              og[1].header_len);
2063       ogg_sync_wrote(&oy,og[1].header_len);
2064
2065       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2066              og[1].body_len);
2067       ogg_sync_wrote(&oy,og[1].body_len);
2068
2069       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2070              og[2].header_len);
2071       ogg_sync_wrote(&oy,og[2].header_len);
2072
2073       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2074              og[2].header_len);
2075       ogg_sync_wrote(&oy,og[2].header_len);
2076
2077       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2078
2079       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2080              og[2].body_len-5);
2081       ogg_sync_wrote(&oy,og[2].body_len-5);
2082
2083       memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2084              og[3].header_len);
2085       ogg_sync_wrote(&oy,og[3].header_len);
2086
2087       memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2088              og[3].body_len);
2089       ogg_sync_wrote(&oy,og[3].body_len);
2090
2091       if(ogg_sync_pageout(&oy,&og_de)>0)error();
2092       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2093
2094       fprintf(stderr,"ok.\n");
2095     }
2096 #else
2097     fprintf(stderr,"Skipping recapture test due to --disable-crc\n");
2098 #endif
2099
2100     /* Free page data that was previously copied */
2101     {
2102       for(i=0;i<5;i++){
2103         free_page(&og[i]);
2104       }
2105     }
2106   }
2107   ogg_sync_clear(&oy);
2108   ogg_stream_clear(&os_en);
2109   ogg_stream_clear(&os_de);
2110
2111   return(0);
2112 }
2113
2114 #endif