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