• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 17039 2010-03-26 00:34:54Z xiphmont $
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/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 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 
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 #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 
ogg_stream_init(ogg_stream_state * os,int serialno)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 */
ogg_stream_check(ogg_stream_state * os)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 */
ogg_stream_clear(ogg_stream_state * os)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 
ogg_stream_destroy(ogg_stream_state * os)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 
_os_body_expand(ogg_stream_state * os,int needed)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 
_os_lacing_expand(ogg_stream_state * os,int needed)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 silmultaneously with other copies */
279 
ogg_page_checksum_set(ogg_page * og)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 */
ogg_stream_iovecin(ogg_stream_state * os,ogg_iovec_t * iov,int count,long e_o_s,ogg_int64_t granulepos)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 
ogg_stream_packetin(ogg_stream_state * os,ogg_packet * op)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. */
ogg_stream_flush_i(ogg_stream_state * os,ogg_page * og,int force)372 static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force){
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>4096 && 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    an page regardless of size in the middle of a stream. */
516 
ogg_stream_flush(ogg_stream_state * os,ogg_page * og)517 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
518   return ogg_stream_flush_i(os,og,1);
519 }
520 
521 /* This constructs pages from buffered packet segments.  The pointers
522 returned are to static buffers; do not free. The returned buffers are
523 good only until the next call (using the same ogg_stream_state) */
524 
ogg_stream_pageout(ogg_stream_state * os,ogg_page * og)525 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
526   int force=0;
527   if(ogg_stream_check(os)) return 0;
528 
529   if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
530      (os->lacing_fill&&!os->b_o_s))           /* 'initial header page' case */
531     force=1;
532 
533   return(ogg_stream_flush_i(os,og,force));
534 }
535 
ogg_stream_eos(ogg_stream_state * os)536 int ogg_stream_eos(ogg_stream_state *os){
537   if(ogg_stream_check(os)) return 1;
538   return os->e_o_s;
539 }
540 
541 /* DECODING PRIMITIVES: packet streaming layer **********************/
542 
543 /* This has two layers to place more of the multi-serialno and paging
544    control in the application's hands.  First, we expose a data buffer
545    using ogg_sync_buffer().  The app either copies into the
546    buffer, or passes it directly to read(), etc.  We then call
547    ogg_sync_wrote() to tell how many bytes we just added.
548 
549    Pages are returned (pointers into the buffer in ogg_sync_state)
550    by ogg_sync_pageout().  The page is then submitted to
551    ogg_stream_pagein() along with the appropriate
552    ogg_stream_state* (ie, matching serialno).  We then get raw
553    packets out calling ogg_stream_packetout() with a
554    ogg_stream_state. */
555 
556 /* initialize the struct to a known state */
ogg_sync_init(ogg_sync_state * oy)557 int ogg_sync_init(ogg_sync_state *oy){
558   if(oy){
559     oy->storage = -1; /* used as a readiness flag */
560     memset(oy,0,sizeof(*oy));
561   }
562   return(0);
563 }
564 
565 /* clear non-flat storage within */
ogg_sync_clear(ogg_sync_state * oy)566 int ogg_sync_clear(ogg_sync_state *oy){
567   if(oy){
568     if(oy->data)_ogg_free(oy->data);
569     memset(oy,0,sizeof(*oy));
570   }
571   return(0);
572 }
573 
ogg_sync_destroy(ogg_sync_state * oy)574 int ogg_sync_destroy(ogg_sync_state *oy){
575   if(oy){
576     ogg_sync_clear(oy);
577     _ogg_free(oy);
578   }
579   return(0);
580 }
581 
ogg_sync_check(ogg_sync_state * oy)582 int ogg_sync_check(ogg_sync_state *oy){
583   if(oy->storage<0) return -1;
584   return 0;
585 }
586 
ogg_sync_buffer(ogg_sync_state * oy,long size)587 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
588   if(ogg_sync_check(oy)) return NULL;
589 
590   /* first, clear out any space that has been previously returned */
591   if(oy->returned){
592     oy->fill-=oy->returned;
593     if(oy->fill>0)
594       memmove(oy->data,oy->data+oy->returned,oy->fill);
595     oy->returned=0;
596   }
597 
598   if(size>oy->storage-oy->fill){
599     /* We need to extend the internal buffer */
600     long newsize=size+oy->fill+4096; /* an extra page to be nice */
601     void *ret;
602 
603     if(oy->data)
604       ret=_ogg_realloc(oy->data,newsize);
605     else
606       ret=_ogg_malloc(newsize);
607     if(!ret){
608       ogg_sync_clear(oy);
609       return NULL;
610     }
611     oy->data=ret;
612     oy->storage=newsize;
613   }
614 
615   /* expose a segment at least as large as requested at the fill mark */
616   return((char *)oy->data+oy->fill);
617 }
618 
ogg_sync_wrote(ogg_sync_state * oy,long bytes)619 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
620   if(ogg_sync_check(oy))return -1;
621   if(oy->fill+bytes>oy->storage)return -1;
622   oy->fill+=bytes;
623   return(0);
624 }
625 
626 /* sync the stream.  This is meant to be useful for finding page
627    boundaries.
628 
629    return values for this:
630   -n) skipped n bytes
631    0) page not ready; more data (no bytes skipped)
632    n) page synced at current location; page length n bytes
633 
634 */
635 
ogg_sync_pageseek(ogg_sync_state * oy,ogg_page * og)636 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
637   unsigned char *page=oy->data+oy->returned;
638   unsigned char *next;
639   long bytes=oy->fill-oy->returned;
640 
641   if(ogg_sync_check(oy))return 0;
642 
643   if(oy->headerbytes==0){
644     int headerbytes,i;
645     if(bytes<27)return(0); /* not enough for a header */
646 
647     /* verify capture pattern */
648     if(memcmp(page,"OggS",4))goto sync_fail;
649 
650     headerbytes=page[26]+27;
651     if(bytes<headerbytes)return(0); /* not enough for header + seg table */
652 
653     /* count up body length in the segment table */
654 
655     for(i=0;i<page[26];i++)
656       oy->bodybytes+=page[27+i];
657     oy->headerbytes=headerbytes;
658   }
659 
660   if(oy->bodybytes+oy->headerbytes>bytes)return(0);
661 
662   /* The whole test page is buffered.  Verify the checksum */
663   {
664     /* Grab the checksum bytes, set the header field to zero */
665     char chksum[4];
666     ogg_page log;
667 
668     memcpy(chksum,page+22,4);
669     memset(page+22,0,4);
670 
671     /* set up a temp page struct and recompute the checksum */
672     log.header=page;
673     log.header_len=oy->headerbytes;
674     log.body=page+oy->headerbytes;
675     log.body_len=oy->bodybytes;
676     ogg_page_checksum_set(&log);
677 
678     /* Compare */
679     if(memcmp(chksum,page+22,4)){
680       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
681          at all) */
682       /* replace the computed checksum with the one actually read in */
683       memcpy(page+22,chksum,4);
684 
685       /* Bad checksum. Lose sync */
686       goto sync_fail;
687     }
688   }
689 
690   /* yes, have a whole page all ready to go */
691   {
692     unsigned char *page=oy->data+oy->returned;
693     long bytes;
694 
695     if(og){
696       og->header=page;
697       og->header_len=oy->headerbytes;
698       og->body=page+oy->headerbytes;
699       og->body_len=oy->bodybytes;
700     }
701 
702     oy->unsynced=0;
703     oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
704     oy->headerbytes=0;
705     oy->bodybytes=0;
706     return(bytes);
707   }
708 
709  sync_fail:
710 
711   oy->headerbytes=0;
712   oy->bodybytes=0;
713 
714   /* search for possible capture */
715   next=memchr(page+1,'O',bytes-1);
716   if(!next)
717     next=oy->data+oy->fill;
718 
719   oy->returned=(int)(next-oy->data);
720   return((long)-(next-page));
721 }
722 
723 /* sync the stream and get a page.  Keep trying until we find a page.
724    Supress 'sync errors' after reporting the first.
725 
726    return values:
727    -1) recapture (hole in data)
728     0) need more data
729     1) page returned
730 
731    Returns pointers into buffered data; invalidated by next call to
732    _stream, _clear, _init, or _buffer */
733 
ogg_sync_pageout(ogg_sync_state * oy,ogg_page * og)734 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
735 
736   if(ogg_sync_check(oy))return 0;
737 
738   /* all we need to do is verify a page at the head of the stream
739      buffer.  If it doesn't verify, we look for the next potential
740      frame */
741 
742   for(;;){
743     long ret=ogg_sync_pageseek(oy,og);
744     if(ret>0){
745       /* have a page */
746       return(1);
747     }
748     if(ret==0){
749       /* need more data */
750       return(0);
751     }
752 
753     /* head did not start a synced page... skipped some bytes */
754     if(!oy->unsynced){
755       oy->unsynced=1;
756       return(-1);
757     }
758 
759     /* loop. keep looking */
760 
761   }
762 }
763 
764 /* add the incoming page to the stream state; we decompose the page
765    into packet segments here as well. */
766 
ogg_stream_pagein(ogg_stream_state * os,ogg_page * og)767 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
768   unsigned char *header=og->header;
769   unsigned char *body=og->body;
770   long           bodysize=og->body_len;
771   int            segptr=0;
772 
773   int version=ogg_page_version(og);
774   int continued=ogg_page_continued(og);
775   int bos=ogg_page_bos(og);
776   int eos=ogg_page_eos(og);
777   ogg_int64_t granulepos=ogg_page_granulepos(og);
778   int serialno=ogg_page_serialno(og);
779   long pageno=ogg_page_pageno(og);
780   int segments=header[26];
781 
782   if(ogg_stream_check(os)) return -1;
783 
784   /* clean up 'returned data' */
785   {
786     long lr=os->lacing_returned;
787     long br=os->body_returned;
788 
789     /* body data */
790     if(br){
791       os->body_fill-=br;
792       if(os->body_fill)
793         memmove(os->body_data,os->body_data+br,os->body_fill);
794       os->body_returned=0;
795     }
796 
797     if(lr){
798       /* segment table */
799       if(os->lacing_fill-lr){
800         memmove(os->lacing_vals,os->lacing_vals+lr,
801                 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
802         memmove(os->granule_vals,os->granule_vals+lr,
803                 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
804       }
805       os->lacing_fill-=lr;
806       os->lacing_packet-=lr;
807       os->lacing_returned=0;
808     }
809   }
810 
811   /* check the serial number */
812   if(serialno!=os->serialno)return(-1);
813   if(version>0)return(-1);
814 
815   if(_os_lacing_expand(os,segments+1)) return -1;
816 
817   /* are we in sequence? */
818   if(pageno!=os->pageno){
819     int i;
820 
821     /* unroll previous partial packet (if any) */
822     for(i=os->lacing_packet;i<os->lacing_fill;i++)
823       os->body_fill-=os->lacing_vals[i]&0xff;
824     os->lacing_fill=os->lacing_packet;
825 
826     /* make a note of dropped data in segment table */
827     if(os->pageno!=-1){
828       os->lacing_vals[os->lacing_fill++]=0x400;
829       os->lacing_packet++;
830     }
831   }
832 
833   /* are we a 'continued packet' page?  If so, we may need to skip
834      some segments */
835   if(continued){
836     if(os->lacing_fill<1 ||
837        os->lacing_vals[os->lacing_fill-1]==0x400){
838       bos=0;
839       for(;segptr<segments;segptr++){
840         int val=header[27+segptr];
841         body+=val;
842         bodysize-=val;
843         if(val<255){
844           segptr++;
845           break;
846         }
847       }
848     }
849   }
850 
851   if(bodysize){
852     if(_os_body_expand(os,bodysize)) return -1;
853     memcpy(os->body_data+os->body_fill,body,bodysize);
854     os->body_fill+=bodysize;
855   }
856 
857   {
858     int saved=-1;
859     while(segptr<segments){
860       int val=header[27+segptr];
861       os->lacing_vals[os->lacing_fill]=val;
862       os->granule_vals[os->lacing_fill]=-1;
863 
864       if(bos){
865         os->lacing_vals[os->lacing_fill]|=0x100;
866         bos=0;
867       }
868 
869       if(val<255)saved=os->lacing_fill;
870 
871       os->lacing_fill++;
872       segptr++;
873 
874       if(val<255)os->lacing_packet=os->lacing_fill;
875     }
876 
877     /* set the granulepos on the last granuleval of the last full packet */
878     if(saved!=-1){
879       os->granule_vals[saved]=granulepos;
880     }
881 
882   }
883 
884   if(eos){
885     os->e_o_s=1;
886     if(os->lacing_fill>0)
887       os->lacing_vals[os->lacing_fill-1]|=0x200;
888   }
889 
890   os->pageno=pageno+1;
891 
892   return(0);
893 }
894 
895 /* clear things to an initial state.  Good to call, eg, before seeking */
ogg_sync_reset(ogg_sync_state * oy)896 int ogg_sync_reset(ogg_sync_state *oy){
897   if(ogg_sync_check(oy))return -1;
898 
899   oy->fill=0;
900   oy->returned=0;
901   oy->unsynced=0;
902   oy->headerbytes=0;
903   oy->bodybytes=0;
904   return(0);
905 }
906 
ogg_stream_reset(ogg_stream_state * os)907 int ogg_stream_reset(ogg_stream_state *os){
908   if(ogg_stream_check(os)) return -1;
909 
910   os->body_fill=0;
911   os->body_returned=0;
912 
913   os->lacing_fill=0;
914   os->lacing_packet=0;
915   os->lacing_returned=0;
916 
917   os->header_fill=0;
918 
919   os->e_o_s=0;
920   os->b_o_s=0;
921   os->pageno=-1;
922   os->packetno=0;
923   os->granulepos=0;
924 
925   return(0);
926 }
927 
ogg_stream_reset_serialno(ogg_stream_state * os,int serialno)928 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
929   if(ogg_stream_check(os)) return -1;
930   ogg_stream_reset(os);
931   os->serialno=serialno;
932   return(0);
933 }
934 
_packetout(ogg_stream_state * os,ogg_packet * op,int adv)935 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
936 
937   /* The last part of decode. We have the stream broken into packet
938      segments.  Now we need to group them into packets (or return the
939      out of sync markers) */
940 
941   int ptr=os->lacing_returned;
942 
943   if(os->lacing_packet<=ptr)return(0);
944 
945   if(os->lacing_vals[ptr]&0x400){
946     /* we need to tell the codec there's a gap; it might need to
947        handle previous packet dependencies. */
948     os->lacing_returned++;
949     os->packetno++;
950     return(-1);
951   }
952 
953   if(!op && !adv)return(1); /* just using peek as an inexpensive way
954                                to ask if there's a whole packet
955                                waiting */
956 
957   /* Gather the whole packet. We'll have no holes or a partial packet */
958   {
959     int size=os->lacing_vals[ptr]&0xff;
960     int bytes=size;
961     int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
962     int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
963 
964     while(size==255){
965       int val=os->lacing_vals[++ptr];
966       size=val&0xff;
967       if(val&0x200)eos=0x200;
968       bytes+=size;
969     }
970 
971     if(op){
972       op->e_o_s=eos;
973       op->b_o_s=bos;
974       op->packet=os->body_data+os->body_returned;
975       op->packetno=os->packetno;
976       op->granulepos=os->granule_vals[ptr];
977       op->bytes=bytes;
978     }
979 
980     if(adv){
981       os->body_returned+=bytes;
982       os->lacing_returned=ptr+1;
983       os->packetno++;
984     }
985   }
986   return(1);
987 }
988 
ogg_stream_packetout(ogg_stream_state * os,ogg_packet * op)989 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
990   if(ogg_stream_check(os)) return 0;
991   return _packetout(os,op,1);
992 }
993 
ogg_stream_packetpeek(ogg_stream_state * os,ogg_packet * op)994 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
995   if(ogg_stream_check(os)) return 0;
996   return _packetout(os,op,0);
997 }
998 
ogg_packet_clear(ogg_packet * op)999 void ogg_packet_clear(ogg_packet *op) {
1000   _ogg_free(op->packet);
1001   memset(op, 0, sizeof(*op));
1002 }
1003 
1004 #ifdef _V_SELFTEST
1005 #include <stdio.h>
1006 
1007 ogg_stream_state os_en, os_de;
1008 ogg_sync_state oy;
1009 
checkpacket(ogg_packet * op,int len,int no,int pos)1010 void checkpacket(ogg_packet *op,int len, int no, int pos){
1011   long j;
1012   static int sequence=0;
1013   static int lastno=0;
1014 
1015   if(op->bytes!=len){
1016     fprintf(stderr,"incorrect packet length (%d != %d)!\n",op->bytes,len);
1017     exit(1);
1018   }
1019   if(op->granulepos!=pos){
1020     fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1021     exit(1);
1022   }
1023 
1024   /* packet number just follows sequence/gap; adjust the input number
1025      for that */
1026   if(no==0){
1027     sequence=0;
1028   }else{
1029     sequence++;
1030     if(no>lastno+1)
1031       sequence++;
1032   }
1033   lastno=no;
1034   if(op->packetno!=sequence){
1035     fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1036             (long)(op->packetno),sequence);
1037     exit(1);
1038   }
1039 
1040   /* Test data */
1041   for(j=0;j<op->bytes;j++)
1042     if(op->packet[j]!=((j+no)&0xff)){
1043       fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1044               j,op->packet[j],(j+no)&0xff);
1045       exit(1);
1046     }
1047 }
1048 
check_page(unsigned char * data,const int * header,ogg_page * og)1049 void check_page(unsigned char *data,const int *header,ogg_page *og){
1050   long j;
1051   /* Test data */
1052   for(j=0;j<og->body_len;j++)
1053     if(og->body[j]!=data[j]){
1054       fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1055               j,data[j],og->body[j]);
1056       exit(1);
1057     }
1058 
1059   /* Test header */
1060   for(j=0;j<og->header_len;j++){
1061     if(og->header[j]!=header[j]){
1062       fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1063       for(j=0;j<header[26]+27;j++)
1064         fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1065       fprintf(stderr,"\n");
1066       exit(1);
1067     }
1068   }
1069   if(og->header_len!=header[26]+27){
1070     fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1071             og->header_len,header[26]+27);
1072     exit(1);
1073   }
1074 }
1075 
print_header(ogg_page * og)1076 void print_header(ogg_page *og){
1077   int j;
1078   fprintf(stderr,"\nHEADER:\n");
1079   fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
1080           og->header[0],og->header[1],og->header[2],og->header[3],
1081           (int)og->header[4],(int)og->header[5]);
1082 
1083   fprintf(stderr,"  granulepos: %d  serialno: %d  pageno: %ld\n",
1084           (og->header[9]<<24)|(og->header[8]<<16)|
1085           (og->header[7]<<8)|og->header[6],
1086           (og->header[17]<<24)|(og->header[16]<<16)|
1087           (og->header[15]<<8)|og->header[14],
1088           ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1089           (og->header[19]<<8)|og->header[18]);
1090 
1091   fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
1092           (int)og->header[22],(int)og->header[23],
1093           (int)og->header[24],(int)og->header[25],
1094           (int)og->header[26]);
1095 
1096   for(j=27;j<og->header_len;j++)
1097     fprintf(stderr,"%d ",(int)og->header[j]);
1098   fprintf(stderr,")\n\n");
1099 }
1100 
copy_page(ogg_page * og)1101 void copy_page(ogg_page *og){
1102   unsigned char *temp=_ogg_malloc(og->header_len);
1103   memcpy(temp,og->header,og->header_len);
1104   og->header=temp;
1105 
1106   temp=_ogg_malloc(og->body_len);
1107   memcpy(temp,og->body,og->body_len);
1108   og->body=temp;
1109 }
1110 
free_page(ogg_page * og)1111 void free_page(ogg_page *og){
1112   _ogg_free (og->header);
1113   _ogg_free (og->body);
1114 }
1115 
error(void)1116 void error(void){
1117   fprintf(stderr,"error!\n");
1118   exit(1);
1119 }
1120 
1121 /* 17 only */
1122 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1123                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1124                        0x01,0x02,0x03,0x04,0,0,0,0,
1125                        0x15,0xed,0xec,0x91,
1126                        1,
1127                        17};
1128 
1129 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1130 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1131                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1132                        0x01,0x02,0x03,0x04,0,0,0,0,
1133                        0x59,0x10,0x6c,0x2c,
1134                        1,
1135                        17};
1136 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1137                        0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1138                        0x01,0x02,0x03,0x04,1,0,0,0,
1139                        0x89,0x33,0x85,0xce,
1140                        13,
1141                        254,255,0,255,1,255,245,255,255,0,
1142                        255,255,90};
1143 
1144 /* nil packets; beginning,middle,end */
1145 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1146                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1147                        0x01,0x02,0x03,0x04,0,0,0,0,
1148                        0xff,0x7b,0x23,0x17,
1149                        1,
1150                        0};
1151 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1152                        0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1153                        0x01,0x02,0x03,0x04,1,0,0,0,
1154                        0x5c,0x3f,0x66,0xcb,
1155                        17,
1156                        17,254,255,0,0,255,1,0,255,245,255,255,0,
1157                        255,255,90,0};
1158 
1159 /* large initial packet */
1160 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1161                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1162                        0x01,0x02,0x03,0x04,0,0,0,0,
1163                        0x01,0x27,0x31,0xaa,
1164                        18,
1165                        255,255,255,255,255,255,255,255,
1166                        255,255,255,255,255,255,255,255,255,10};
1167 
1168 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1169                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1170                        0x01,0x02,0x03,0x04,1,0,0,0,
1171                        0x7f,0x4e,0x8a,0xd2,
1172                        4,
1173                        255,4,255,0};
1174 
1175 
1176 /* continuing packet test */
1177 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1178                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1179                        0x01,0x02,0x03,0x04,0,0,0,0,
1180                        0xff,0x7b,0x23,0x17,
1181                        1,
1182                        0};
1183 
1184 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1185                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1186                        0x01,0x02,0x03,0x04,1,0,0,0,
1187                        0xf8,0x3c,0x19,0x79,
1188                        255,
1189                        255,255,255,255,255,255,255,255,
1190                        255,255,255,255,255,255,255,255,
1191                        255,255,255,255,255,255,255,255,
1192                        255,255,255,255,255,255,255,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};
1221 
1222 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1223                        0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1224                        0x01,0x02,0x03,0x04,2,0,0,0,
1225                        0x38,0xe6,0xb6,0x28,
1226                        6,
1227                        255,220,255,4,255,0};
1228 
1229 
1230 /* spill expansion test */
1231 const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1232                         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1233                         0x01,0x02,0x03,0x04,0,0,0,0,
1234                         0xff,0x7b,0x23,0x17,
1235                         1,
1236                         0};
1237 
1238 const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1239                         0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1240                         0x01,0x02,0x03,0x04,1,0,0,0,
1241                         0xce,0x8f,0x17,0x1a,
1242                         23,
1243                         255,255,255,255,255,255,255,255,
1244                         255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1245 
1246 
1247 const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1248                         0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1249                         0x01,0x02,0x03,0x04,2,0,0,0,
1250                         0x9b,0xb2,0x50,0xa1,
1251                         1,
1252                         0};
1253 
1254 /* page with the 255 segment limit */
1255 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1256                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1257                        0x01,0x02,0x03,0x04,0,0,0,0,
1258                        0xff,0x7b,0x23,0x17,
1259                        1,
1260                        0};
1261 
1262 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1263                        0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1264                        0x01,0x02,0x03,0x04,1,0,0,0,
1265                        0xed,0x2a,0x2e,0xa7,
1266                        255,
1267                        10,10,10,10,10,10,10,10,
1268                        10,10,10,10,10,10,10,10,
1269                        10,10,10,10,10,10,10,10,
1270                        10,10,10,10,10,10,10,10,
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};
1299 
1300 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1301                        0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1302                        0x01,0x02,0x03,0x04,2,0,0,0,
1303                        0x6c,0x3b,0x82,0x3d,
1304                        1,
1305                        50};
1306 
1307 
1308 /* packet that overspans over an entire page */
1309 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1310                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1311                        0x01,0x02,0x03,0x04,0,0,0,0,
1312                        0xff,0x7b,0x23,0x17,
1313                        1,
1314                        0};
1315 
1316 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1317                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1318                        0x01,0x02,0x03,0x04,1,0,0,0,
1319                        0x68,0x22,0x7c,0x3d,
1320                        255,
1321                        100,
1322                        255,255,255,255,255,255,255,255,
1323                        255,255,255,255,255,255,255,255,
1324                        255,255,255,255,255,255,255,255,
1325                        255,255,255,255,255,255,255,255,
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};
1354 
1355 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1356                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1357                        0x01,0x02,0x03,0x04,2,0,0,0,
1358                        0xf4,0x87,0xba,0xf3,
1359                        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,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};
1392 
1393 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1394                        0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1395                        0x01,0x02,0x03,0x04,3,0,0,0,
1396                        0xf7,0x2f,0x6c,0x60,
1397                        5,
1398                        254,255,4,255,0};
1399 
1400 /* packet that overspans over an entire page */
1401 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1402                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1403                        0x01,0x02,0x03,0x04,0,0,0,0,
1404                        0xff,0x7b,0x23,0x17,
1405                        1,
1406                        0};
1407 
1408 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1409                        0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1410                        0x01,0x02,0x03,0x04,1,0,0,0,
1411                        0x68,0x22,0x7c,0x3d,
1412                        255,
1413                        100,
1414                        255,255,255,255,255,255,255,255,
1415                        255,255,255,255,255,255,255,255,
1416                        255,255,255,255,255,255,255,255,
1417                        255,255,255,255,255,255,255,255,
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};
1446 
1447 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1448                        0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1449                        0x01,0x02,0x03,0x04,2,0,0,0,
1450                        0xd4,0xe0,0x60,0xe5,
1451                        1,
1452                        0};
1453 
test_pack(const int * pl,const int ** headers,int byteskip,int pageskip,int packetskip)1454 void test_pack(const int *pl, const int **headers, int byteskip,
1455                int pageskip, int packetskip){
1456   unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1457   long inptr=0;
1458   long outptr=0;
1459   long deptr=0;
1460   long depacket=0;
1461   long granule_pos=7,pageno=0;
1462   int i,j,packets,pageout=pageskip;
1463   int eosflag=0;
1464   int bosflag=0;
1465 
1466   int byteskipcount=0;
1467 
1468   ogg_stream_reset(&os_en);
1469   ogg_stream_reset(&os_de);
1470   ogg_sync_reset(&oy);
1471 
1472   for(packets=0;packets<packetskip;packets++)
1473     depacket+=pl[packets];
1474 
1475   for(packets=0;;packets++)if(pl[packets]==-1)break;
1476 
1477   for(i=0;i<packets;i++){
1478     /* construct a test packet */
1479     ogg_packet op;
1480     int len=pl[i];
1481 
1482     op.packet=data+inptr;
1483     op.bytes=len;
1484     op.e_o_s=(pl[i+1]<0?1:0);
1485     op.granulepos=granule_pos;
1486 
1487     granule_pos+=1024;
1488 
1489     for(j=0;j<len;j++)data[inptr++]=i+j;
1490 
1491     /* submit the test packet */
1492     ogg_stream_packetin(&os_en,&op);
1493 
1494     /* retrieve any finished pages */
1495     {
1496       ogg_page og;
1497 
1498       while(ogg_stream_pageout(&os_en,&og)){
1499         /* We have a page.  Check it carefully */
1500 
1501         fprintf(stderr,"%ld, ",pageno);
1502 
1503         if(headers[pageno]==NULL){
1504           fprintf(stderr,"coded too many pages!\n");
1505           exit(1);
1506         }
1507 
1508         check_page(data+outptr,headers[pageno],&og);
1509 
1510         outptr+=og.body_len;
1511         pageno++;
1512         if(pageskip){
1513           bosflag=1;
1514           pageskip--;
1515           deptr+=og.body_len;
1516         }
1517 
1518         /* have a complete page; submit it to sync/decode */
1519 
1520         {
1521           ogg_page og_de;
1522           ogg_packet op_de,op_de2;
1523           char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1524           char *next=buf;
1525           byteskipcount+=og.header_len;
1526           if(byteskipcount>byteskip){
1527             memcpy(next,og.header,byteskipcount-byteskip);
1528             next+=byteskipcount-byteskip;
1529             byteskipcount=byteskip;
1530           }
1531 
1532           byteskipcount+=og.body_len;
1533           if(byteskipcount>byteskip){
1534             memcpy(next,og.body,byteskipcount-byteskip);
1535             next+=byteskipcount-byteskip;
1536             byteskipcount=byteskip;
1537           }
1538 
1539           ogg_sync_wrote(&oy,next-buf);
1540 
1541           while(1){
1542             int ret=ogg_sync_pageout(&oy,&og_de);
1543             if(ret==0)break;
1544             if(ret<0)continue;
1545             /* got a page.  Happy happy.  Verify that it's good. */
1546 
1547             fprintf(stderr,"(%ld), ",pageout);
1548 
1549             check_page(data+deptr,headers[pageout],&og_de);
1550             deptr+=og_de.body_len;
1551             pageout++;
1552 
1553             /* submit it to deconstitution */
1554             ogg_stream_pagein(&os_de,&og_de);
1555 
1556             /* packets out? */
1557             while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1558               ogg_stream_packetpeek(&os_de,NULL);
1559               ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1560 
1561               /* verify peek and out match */
1562               if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1563                 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1564                         depacket);
1565                 exit(1);
1566               }
1567 
1568               /* verify the packet! */
1569               /* check data */
1570               if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1571                 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1572                         depacket);
1573                 exit(1);
1574               }
1575               /* check bos flag */
1576               if(bosflag==0 && op_de.b_o_s==0){
1577                 fprintf(stderr,"b_o_s flag not set on packet!\n");
1578                 exit(1);
1579               }
1580               if(bosflag && op_de.b_o_s){
1581                 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1582                 exit(1);
1583               }
1584               bosflag=1;
1585               depacket+=op_de.bytes;
1586 
1587               /* check eos flag */
1588               if(eosflag){
1589                 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1590                 exit(1);
1591               }
1592 
1593               if(op_de.e_o_s)eosflag=1;
1594 
1595               /* check granulepos flag */
1596               if(op_de.granulepos!=-1){
1597                 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1598               }
1599             }
1600           }
1601         }
1602       }
1603     }
1604   }
1605   _ogg_free(data);
1606   if(headers[pageno]!=NULL){
1607     fprintf(stderr,"did not write last page!\n");
1608     exit(1);
1609   }
1610   if(headers[pageout]!=NULL){
1611     fprintf(stderr,"did not decode last page!\n");
1612     exit(1);
1613   }
1614   if(inptr!=outptr){
1615     fprintf(stderr,"encoded page data incomplete!\n");
1616     exit(1);
1617   }
1618   if(inptr!=deptr){
1619     fprintf(stderr,"decoded page data incomplete!\n");
1620     exit(1);
1621   }
1622   if(inptr!=depacket){
1623     fprintf(stderr,"decoded packet data incomplete!\n");
1624     exit(1);
1625   }
1626   if(!eosflag){
1627     fprintf(stderr,"Never got a packet with EOS set!\n");
1628     exit(1);
1629   }
1630   fprintf(stderr,"ok.\n");
1631 }
1632 
main(void)1633 int main(void){
1634 
1635   ogg_stream_init(&os_en,0x04030201);
1636   ogg_stream_init(&os_de,0x04030201);
1637   ogg_sync_init(&oy);
1638 
1639   /* Exercise each code path in the framing code.  Also verify that
1640      the checksums are working.  */
1641 
1642   {
1643     /* 17 only */
1644     const int packets[]={17, -1};
1645     const int *headret[]={head1_0,NULL};
1646 
1647     fprintf(stderr,"testing single page encoding... ");
1648     test_pack(packets,headret,0,0,0);
1649   }
1650 
1651   {
1652     /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1653     const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1654     const int *headret[]={head1_1,head2_1,NULL};
1655 
1656     fprintf(stderr,"testing basic page encoding... ");
1657     test_pack(packets,headret,0,0,0);
1658   }
1659 
1660   {
1661     /* nil packets; beginning,middle,end */
1662     const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1663     const int *headret[]={head1_2,head2_2,NULL};
1664 
1665     fprintf(stderr,"testing basic nil packets... ");
1666     test_pack(packets,headret,0,0,0);
1667   }
1668 
1669   {
1670     /* large initial packet */
1671     const int packets[]={4345,259,255,-1};
1672     const int *headret[]={head1_3,head2_3,NULL};
1673 
1674     fprintf(stderr,"testing initial-packet lacing > 4k... ");
1675     test_pack(packets,headret,0,0,0);
1676   }
1677 
1678   {
1679     /* continuing packet test; with page spill expansion, we have to
1680        overflow the lacing table. */
1681     const int packets[]={0,65500,259,255,-1};
1682     const int *headret[]={head1_4,head2_4,head3_4,NULL};
1683 
1684     fprintf(stderr,"testing single packet page span... ");
1685     test_pack(packets,headret,0,0,0);
1686   }
1687 
1688   {
1689     /* spill expand packet test */
1690     const int packets[]={0,4345,259,255,0,0,-1};
1691     const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1692 
1693     fprintf(stderr,"testing page spill expansion... ");
1694     test_pack(packets,headret,0,0,0);
1695   }
1696 
1697   /* page with the 255 segment limit */
1698   {
1699 
1700     const int packets[]={0,10,10,10,10,10,10,10,10,
1701                    10,10,10,10,10,10,10,10,
1702                    10,10,10,10,10,10,10,10,
1703                    10,10,10,10,10,10,10,10,
1704                    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,50,-1};
1732     const int *headret[]={head1_5,head2_5,head3_5,NULL};
1733 
1734     fprintf(stderr,"testing max packet segments... ");
1735     test_pack(packets,headret,0,0,0);
1736   }
1737 
1738   {
1739     /* packet that overspans over an entire page */
1740     const int packets[]={0,100,130049,259,255,-1};
1741     const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1742 
1743     fprintf(stderr,"testing very large packets... ");
1744     test_pack(packets,headret,0,0,0);
1745   }
1746 
1747   {
1748     /* test for the libogg 1.1.1 resync in large continuation bug
1749        found by Josh Coalson)  */
1750     const int packets[]={0,100,130049,259,255,-1};
1751     const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1752 
1753     fprintf(stderr,"testing continuation resync in very large packets... ");
1754     test_pack(packets,headret,100,2,3);
1755   }
1756 
1757   {
1758     /* term only page.  why not? */
1759     const int packets[]={0,100,64770,-1};
1760     const int *headret[]={head1_7,head2_7,head3_7,NULL};
1761 
1762     fprintf(stderr,"testing zero data page (1 nil packet)... ");
1763     test_pack(packets,headret,0,0,0);
1764   }
1765 
1766 
1767 
1768   {
1769     /* build a bunch of pages for testing */
1770     unsigned char *data=_ogg_malloc(1024*1024);
1771     int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1772     int inptr=0,i,j;
1773     ogg_page og[5];
1774 
1775     ogg_stream_reset(&os_en);
1776 
1777     for(i=0;pl[i]!=-1;i++){
1778       ogg_packet op;
1779       int len=pl[i];
1780 
1781       op.packet=data+inptr;
1782       op.bytes=len;
1783       op.e_o_s=(pl[i+1]<0?1:0);
1784       op.granulepos=(i+1)*1000;
1785 
1786       for(j=0;j<len;j++)data[inptr++]=i+j;
1787       ogg_stream_packetin(&os_en,&op);
1788     }
1789 
1790     _ogg_free(data);
1791 
1792     /* retrieve finished pages */
1793     for(i=0;i<5;i++){
1794       if(ogg_stream_pageout(&os_en,&og[i])==0){
1795         fprintf(stderr,"Too few pages output building sync tests!\n");
1796         exit(1);
1797       }
1798       copy_page(&og[i]);
1799     }
1800 
1801     /* Test lost pages on pagein/packetout: no rollback */
1802     {
1803       ogg_page temp;
1804       ogg_packet test;
1805 
1806       fprintf(stderr,"Testing loss of pages... ");
1807 
1808       ogg_sync_reset(&oy);
1809       ogg_stream_reset(&os_de);
1810       for(i=0;i<5;i++){
1811         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1812                og[i].header_len);
1813         ogg_sync_wrote(&oy,og[i].header_len);
1814         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1815         ogg_sync_wrote(&oy,og[i].body_len);
1816       }
1817 
1818       ogg_sync_pageout(&oy,&temp);
1819       ogg_stream_pagein(&os_de,&temp);
1820       ogg_sync_pageout(&oy,&temp);
1821       ogg_stream_pagein(&os_de,&temp);
1822       ogg_sync_pageout(&oy,&temp);
1823       /* skip */
1824       ogg_sync_pageout(&oy,&temp);
1825       ogg_stream_pagein(&os_de,&temp);
1826 
1827       /* do we get the expected results/packets? */
1828 
1829       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1830       checkpacket(&test,0,0,0);
1831       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1832       checkpacket(&test,1,1,-1);
1833       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1834       checkpacket(&test,1,2,-1);
1835       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1836       checkpacket(&test,98,3,-1);
1837       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1838       checkpacket(&test,4079,4,5000);
1839       if(ogg_stream_packetout(&os_de,&test)!=-1){
1840         fprintf(stderr,"Error: loss of page did not return error\n");
1841         exit(1);
1842       }
1843       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1844       checkpacket(&test,76,9,-1);
1845       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1846       checkpacket(&test,34,10,-1);
1847       fprintf(stderr,"ok.\n");
1848     }
1849 
1850     /* Test lost pages on pagein/packetout: rollback with continuation */
1851     {
1852       ogg_page temp;
1853       ogg_packet test;
1854 
1855       fprintf(stderr,"Testing loss of pages (rollback required)... ");
1856 
1857       ogg_sync_reset(&oy);
1858       ogg_stream_reset(&os_de);
1859       for(i=0;i<5;i++){
1860         memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1861                og[i].header_len);
1862         ogg_sync_wrote(&oy,og[i].header_len);
1863         memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1864         ogg_sync_wrote(&oy,og[i].body_len);
1865       }
1866 
1867       ogg_sync_pageout(&oy,&temp);
1868       ogg_stream_pagein(&os_de,&temp);
1869       ogg_sync_pageout(&oy,&temp);
1870       ogg_stream_pagein(&os_de,&temp);
1871       ogg_sync_pageout(&oy,&temp);
1872       ogg_stream_pagein(&os_de,&temp);
1873       ogg_sync_pageout(&oy,&temp);
1874       /* skip */
1875       ogg_sync_pageout(&oy,&temp);
1876       ogg_stream_pagein(&os_de,&temp);
1877 
1878       /* do we get the expected results/packets? */
1879 
1880       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1881       checkpacket(&test,0,0,0);
1882       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1883       checkpacket(&test,1,1,-1);
1884       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1885       checkpacket(&test,1,2,-1);
1886       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1887       checkpacket(&test,98,3,-1);
1888       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1889       checkpacket(&test,4079,4,5000);
1890       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1891       checkpacket(&test,1,5,-1);
1892       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1893       checkpacket(&test,1,6,-1);
1894       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1895       checkpacket(&test,2954,7,-1);
1896       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1897       checkpacket(&test,2057,8,9000);
1898       if(ogg_stream_packetout(&os_de,&test)!=-1){
1899         fprintf(stderr,"Error: loss of page did not return error\n");
1900         exit(1);
1901       }
1902       if(ogg_stream_packetout(&os_de,&test)!=1)error();
1903       checkpacket(&test,300,17,18000);
1904       fprintf(stderr,"ok.\n");
1905     }
1906 
1907     /* the rest only test sync */
1908     {
1909       ogg_page og_de;
1910       /* Test fractional page inputs: incomplete capture */
1911       fprintf(stderr,"Testing sync on partial inputs... ");
1912       ogg_sync_reset(&oy);
1913       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1914              3);
1915       ogg_sync_wrote(&oy,3);
1916       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1917 
1918       /* Test fractional page inputs: incomplete fixed header */
1919       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1920              20);
1921       ogg_sync_wrote(&oy,20);
1922       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1923 
1924       /* Test fractional page inputs: incomplete header */
1925       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1926              5);
1927       ogg_sync_wrote(&oy,5);
1928       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1929 
1930       /* Test fractional page inputs: incomplete body */
1931 
1932       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1933              og[1].header_len-28);
1934       ogg_sync_wrote(&oy,og[1].header_len-28);
1935       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1936 
1937       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1938       ogg_sync_wrote(&oy,1000);
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              og[1].body_len-1000);
1943       ogg_sync_wrote(&oy,og[1].body_len-1000);
1944       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1945 
1946       fprintf(stderr,"ok.\n");
1947     }
1948 
1949     /* Test fractional page inputs: page + incomplete capture */
1950     {
1951       ogg_page og_de;
1952       fprintf(stderr,"Testing sync on 1+partial inputs... ");
1953       ogg_sync_reset(&oy);
1954 
1955       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1956              og[1].header_len);
1957       ogg_sync_wrote(&oy,og[1].header_len);
1958 
1959       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1960              og[1].body_len);
1961       ogg_sync_wrote(&oy,og[1].body_len);
1962 
1963       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1964              20);
1965       ogg_sync_wrote(&oy,20);
1966       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1967       if(ogg_sync_pageout(&oy,&og_de)>0)error();
1968 
1969       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1970              og[1].header_len-20);
1971       ogg_sync_wrote(&oy,og[1].header_len-20);
1972       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1973              og[1].body_len);
1974       ogg_sync_wrote(&oy,og[1].body_len);
1975       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1976 
1977       fprintf(stderr,"ok.\n");
1978     }
1979 
1980     /* Test recapture: garbage + page */
1981     {
1982       ogg_page og_de;
1983       fprintf(stderr,"Testing search for capture... ");
1984       ogg_sync_reset(&oy);
1985 
1986       /* 'garbage' */
1987       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1988              og[1].body_len);
1989       ogg_sync_wrote(&oy,og[1].body_len);
1990 
1991       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1992              og[1].header_len);
1993       ogg_sync_wrote(&oy,og[1].header_len);
1994 
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 
1999       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2000              20);
2001       ogg_sync_wrote(&oy,20);
2002       if(ogg_sync_pageout(&oy,&og_de)>0)error();
2003       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2004       if(ogg_sync_pageout(&oy,&og_de)>0)error();
2005 
2006       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2007              og[2].header_len-20);
2008       ogg_sync_wrote(&oy,og[2].header_len-20);
2009       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2010              og[2].body_len);
2011       ogg_sync_wrote(&oy,og[2].body_len);
2012       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2013 
2014       fprintf(stderr,"ok.\n");
2015     }
2016 
2017     /* Test recapture: page + garbage + page */
2018     {
2019       ogg_page og_de;
2020       fprintf(stderr,"Testing recapture... ");
2021       ogg_sync_reset(&oy);
2022 
2023       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2024              og[1].header_len);
2025       ogg_sync_wrote(&oy,og[1].header_len);
2026 
2027       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2028              og[1].body_len);
2029       ogg_sync_wrote(&oy,og[1].body_len);
2030 
2031       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2032              og[2].header_len);
2033       ogg_sync_wrote(&oy,og[2].header_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       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2040 
2041       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2042              og[2].body_len-5);
2043       ogg_sync_wrote(&oy,og[2].body_len-5);
2044 
2045       memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2046              og[3].header_len);
2047       ogg_sync_wrote(&oy,og[3].header_len);
2048 
2049       memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2050              og[3].body_len);
2051       ogg_sync_wrote(&oy,og[3].body_len);
2052 
2053       if(ogg_sync_pageout(&oy,&og_de)>0)error();
2054       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2055 
2056       fprintf(stderr,"ok.\n");
2057     }
2058 
2059     /* Free page data that was previously copied */
2060     {
2061       for(i=0;i<5;i++){
2062         free_page(&og[i]);
2063       }
2064     }
2065   }
2066 
2067   return(0);
2068 }
2069 
2070 #endif
2071 
2072 
2073 
2074 
2075