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