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