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