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