1 /********************************************************************
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC 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. *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
11 ********************************************************************
13 function: code raw [Vorbis] packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
15 last mod: $Id: framing.c,v 1.22 2002/07/11 09:09:08 xiphmont Exp $
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
21 ********************************************************************/
27 /* A complete description of Ogg framing exists in docs/framing.html */
29 int ogg_page_version(ogg_page *og){
30 return((int)(og->header[4]));
33 int ogg_page_continued(ogg_page *og){
34 return((int)(og->header[5]&0x01));
37 int ogg_page_bos(ogg_page *og){
38 return((int)(og->header[5]&0x02));
41 int ogg_page_eos(ogg_page *og){
42 return((int)(og->header[5]&0x04));
45 ogg_int64_t ogg_page_granulepos(ogg_page *og){
46 unsigned char *page=og->header;
47 ogg_int64_t granulepos=page[13]&(0xff);
48 granulepos= (granulepos<<8)|(page[12]&0xff);
49 granulepos= (granulepos<<8)|(page[11]&0xff);
50 granulepos= (granulepos<<8)|(page[10]&0xff);
51 granulepos= (granulepos<<8)|(page[9]&0xff);
52 granulepos= (granulepos<<8)|(page[8]&0xff);
53 granulepos= (granulepos<<8)|(page[7]&0xff);
54 granulepos= (granulepos<<8)|(page[6]&0xff);
58 int ogg_page_serialno(ogg_page *og){
59 return(og->header[14] |
61 (og->header[16]<<16) |
62 (og->header[17]<<24));
65 long ogg_page_pageno(ogg_page *og){
66 return(og->header[18] |
68 (og->header[20]<<16) |
69 (og->header[21]<<24));
74 /* returns the number of packets that are completed on this page (if
75 the leading packet is begun on a previous page, but ends on this
79 If a page consists of a packet begun on a previous page, and a new
80 packet begun (but not completed) on this page, the return will be:
81 ogg_page_packets(page) ==1,
82 ogg_page_continued(page) !=0
84 If a page happens to be a single packet that was begun on a
85 previous page, and spans to the next page (in the case of a three or
86 more page packet), the return will be:
87 ogg_page_packets(page) ==0,
88 ogg_page_continued(page) !=0
91 int ogg_page_packets(ogg_page *og){
92 int i,n=og->header[26],count=0;
94 if(og->header[27+i]<255)count++;
100 /* helper to initialize lookup for direct-table CRC (illustrative; we
101 use the static init below) */
103 static ogg_uint32_t _ogg_crc_entry(unsigned long index){
109 if (r & 0x80000000UL)
110 r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
111 polynomial, although we use an
112 unreflected alg and an init/final
113 of 0, not 0xffffffff */
116 return (r & 0xffffffffUL);
120 static ogg_uint32_t crc_lookup[256]={
121 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
122 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
123 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
124 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
125 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
126 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
127 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
128 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
129 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
130 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
131 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
132 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
133 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
134 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
135 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
136 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
137 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
138 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
139 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
140 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
141 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
142 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
143 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
144 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
145 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
146 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
147 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
148 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
149 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
150 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
151 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
152 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
153 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
154 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
155 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
156 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
157 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
158 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
159 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
160 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
161 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
162 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
163 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
164 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
165 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
166 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
167 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
168 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
169 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
170 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
171 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
172 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
173 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
174 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
175 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
176 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
177 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
178 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
179 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
180 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
181 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
182 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
183 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
184 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
186 /* init the encode/decode logical stream state */
188 int ogg_stream_init(ogg_stream_state *os,int serialno){
190 memset(os,0,sizeof(*os));
191 os->body_storage=16*1024;
192 os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
194 os->lacing_storage=1024;
195 os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
196 os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
198 os->serialno=serialno;
205 /* _clear does not free os, only the non-flat storage within */
206 int ogg_stream_clear(ogg_stream_state *os){
208 if(os->body_data)_ogg_free(os->body_data);
209 if(os->lacing_vals)_ogg_free(os->lacing_vals);
210 if(os->granule_vals)_ogg_free(os->granule_vals);
212 memset(os,0,sizeof(*os));
217 int ogg_stream_destroy(ogg_stream_state *os){
219 ogg_stream_clear(os);
225 /* Helpers for ogg_stream_encode; this keeps the structure and
226 what's happening fairly clear */
228 static void _os_body_expand(ogg_stream_state *os,int needed){
229 if(os->body_storage<=os->body_fill+needed){
230 os->body_storage+=(needed+1024);
231 os->body_data=_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
235 static void _os_lacing_expand(ogg_stream_state *os,int needed){
236 if(os->lacing_storage<=os->lacing_fill+needed){
237 os->lacing_storage+=(needed+32);
238 os->lacing_vals=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
239 os->granule_vals=_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
243 /* checksum the page */
244 /* Direct table CRC; note that this will be faster in the future if we
245 perform the checksum silmultaneously with other copies */
247 void ogg_page_checksum_set(ogg_page *og){
249 ogg_uint32_t crc_reg=0;
252 /* safety; needed for API behavior, but not framing code */
258 for(i=0;i<og->header_len;i++)
259 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
260 for(i=0;i<og->body_len;i++)
261 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
263 og->header[22]=crc_reg&0xff;
264 og->header[23]=(crc_reg>>8)&0xff;
265 og->header[24]=(crc_reg>>16)&0xff;
266 og->header[25]=(crc_reg>>24)&0xff;
270 /* submit data to the internal buffer of the framing engine */
271 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
272 int lacing_vals=op->bytes/255+1,i;
274 if(os->body_returned){
275 /* advance packet data according to the body_returned pointer. We
276 had to keep it around to return a pointer into the buffer last
279 os->body_fill-=os->body_returned;
281 memmove(os->body_data,os->body_data+os->body_returned,
286 /* make sure we have the buffer storage */
287 _os_body_expand(os,op->bytes);
288 _os_lacing_expand(os,lacing_vals);
290 /* Copy in the submitted packet. Yes, the copy is a waste; this is
291 the liability of overly clean abstraction for the time being. It
292 will actually be fairly easy to eliminate the extra copy in the
295 memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
296 os->body_fill+=op->bytes;
298 /* Store lacing vals for this packet */
299 for(i=0;i<lacing_vals-1;i++){
300 os->lacing_vals[os->lacing_fill+i]=255;
301 os->granule_vals[os->lacing_fill+i]=os->granulepos;
303 os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
304 os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos;
306 /* flag the first segment as the beginning of the packet */
307 os->lacing_vals[os->lacing_fill]|= 0x100;
309 os->lacing_fill+=lacing_vals;
311 /* for the sake of completeness */
314 if(op->e_o_s)os->e_o_s=1;
319 /* This will flush remaining packets into a page (returning nonzero),
320 even if there is not enough data to trigger a flush normally
321 (undersized page). If there are no packets or partial packets to
322 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
323 try to flush a normal sized page like ogg_stream_pageout; a call to
324 ogg_stream_flush does not gurantee that all packets have flushed.
325 Only a return value of 0 from ogg_stream_flush indicates all packet
326 data is flushed into pages.
328 ogg_stream_page will flush the last page in a stream even if it's
329 undersized; you almost certainly want to use ogg_stream_pageout
330 (and *not* ogg_stream_flush) unless you need to flush an undersized
331 page in the middle of a stream for some reason. */
333 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
336 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
339 ogg_int64_t granule_pos=os->granule_vals[0];
341 if(maxvals==0)return(0);
343 /* construct a page */
344 /* decide how many segments to include */
346 /* If this is the initial header case, the first page must only include
347 the initial header packet */
348 if(os->b_o_s==0){ /* 'initial header page' case */
350 for(vals=0;vals<maxvals;vals++){
351 if((os->lacing_vals[vals]&0x0ff)<255){
357 for(vals=0;vals<maxvals;vals++){
359 acc+=os->lacing_vals[vals]&0x0ff;
360 granule_pos=os->granule_vals[vals];
364 /* construct the header in temp storage */
365 memcpy(os->header,"OggS",4);
367 /* stream structure version */
370 /* continued packet flag? */
372 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
373 /* first page flag? */
374 if(os->b_o_s==0)os->header[5]|=0x02;
375 /* last page flag? */
376 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
379 /* 64 bits of PCM position */
381 os->header[i]=(granule_pos&0xff);
385 /* 32 bits of stream serial number */
387 long serialno=os->serialno;
389 os->header[i]=(serialno&0xff);
394 /* 32 bits of page counter (we have both counter and page header
395 because this val can roll over) */
396 if(os->pageno==-1)os->pageno=0; /* because someone called
397 stream_reset; this would be a
398 strange thing to do in an
399 encode stream, but it has
402 long pageno=os->pageno++;
404 os->header[i]=(pageno&0xff);
409 /* zero for computation; filled in later */
416 os->header[26]=vals&0xff;
418 bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
420 /* set pointers in the ogg_page struct */
421 og->header=os->header;
422 og->header_len=os->header_fill=vals+27;
423 og->body=os->body_data+os->body_returned;
426 /* advance the lacing data and set the body_returned pointer */
428 os->lacing_fill-=vals;
429 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
430 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
431 os->body_returned+=bytes;
433 /* calculate the checksum */
435 ogg_page_checksum_set(og);
442 /* This constructs pages from buffered packet segments. The pointers
443 returned are to static buffers; do not free. The returned buffers are
444 good only until the next call (using the same ogg_stream_state) */
446 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
448 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
449 os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */
450 os->lacing_fill>=255 || /* 'segment table full' case */
451 (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */
453 return(ogg_stream_flush(os,og));
456 /* not enough data to construct a page and not end of stream */
460 int ogg_stream_eos(ogg_stream_state *os){
464 /* DECODING PRIMITIVES: packet streaming layer **********************/
466 /* This has two layers to place more of the multi-serialno and paging
467 control in the application's hands. First, we expose a data buffer
468 using ogg_sync_buffer(). The app either copies into the
469 buffer, or passes it directly to read(), etc. We then call
470 ogg_sync_wrote() to tell how many bytes we just added.
472 Pages are returned (pointers into the buffer in ogg_sync_state)
473 by ogg_sync_pageout(). The page is then submitted to
474 ogg_stream_pagein() along with the appropriate
475 ogg_stream_state* (ie, matching serialno). We then get raw
476 packets out calling ogg_stream_packetout() with a
477 ogg_stream_state. See the 'frame-prog.txt' docs for details and
480 /* initialize the struct to a known state */
481 int ogg_sync_init(ogg_sync_state *oy){
483 memset(oy,0,sizeof(*oy));
488 /* clear non-flat storage within */
489 int ogg_sync_clear(ogg_sync_state *oy){
491 if(oy->data)_ogg_free(oy->data);
497 int ogg_sync_destroy(ogg_sync_state *oy){
505 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
507 /* first, clear out any space that has been previously returned */
509 oy->fill-=oy->returned;
511 memmove(oy->data,oy->data+oy->returned,oy->fill);
515 if(size>oy->storage-oy->fill){
516 /* We need to extend the internal buffer */
517 long newsize=size+oy->fill+4096; /* an extra page to be nice */
520 oy->data=_ogg_realloc(oy->data,newsize);
522 oy->data=_ogg_malloc(newsize);
526 /* expose a segment at least as large as requested at the fill mark */
527 return((char *)oy->data+oy->fill);
530 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
531 if(oy->fill+bytes>oy->storage)return(-1);
536 /* sync the stream. This is meant to be useful for finding page
539 return values for this:
541 0) page not ready; more data (no bytes skipped)
542 n) page synced at current location; page length n bytes
546 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
547 unsigned char *page=oy->data+oy->returned;
549 long bytes=oy->fill-oy->returned;
551 if(oy->headerbytes==0){
553 if(bytes<27)return(0); /* not enough for a header */
555 /* verify capture pattern */
556 if(memcmp(page,"OggS",4))goto sync_fail;
558 headerbytes=page[26]+27;
559 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
561 /* count up body length in the segment table */
563 for(i=0;i<page[26];i++)
564 oy->bodybytes+=page[27+i];
565 oy->headerbytes=headerbytes;
568 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
570 /* The whole test page is buffered. Verify the checksum */
572 /* Grab the checksum bytes, set the header field to zero */
576 memcpy(chksum,page+22,4);
579 /* set up a temp page struct and recompute the checksum */
581 log.header_len=oy->headerbytes;
582 log.body=page+oy->headerbytes;
583 log.body_len=oy->bodybytes;
584 ogg_page_checksum_set(&log);
587 if(memcmp(chksum,page+22,4)){
588 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
590 /* replace the computed checksum with the one actually read in */
591 memcpy(page+22,chksum,4);
593 /* Bad checksum. Lose sync */
598 /* yes, have a whole page all ready to go */
600 unsigned char *page=oy->data+oy->returned;
605 og->header_len=oy->headerbytes;
606 og->body=page+oy->headerbytes;
607 og->body_len=oy->bodybytes;
611 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
622 /* search for possible capture */
623 next=memchr(page+1,'O',bytes-1);
625 next=oy->data+oy->fill;
627 oy->returned=next-oy->data;
628 return(-(next-page));
631 /* sync the stream and get a page. Keep trying until we find a page.
632 Supress 'sync errors' after reporting the first.
635 -1) recapture (hole in data)
639 Returns pointers into buffered data; invalidated by next call to
640 _stream, _clear, _init, or _buffer */
642 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
644 /* all we need to do is verify a page at the head of the stream
645 buffer. If it doesn't verify, we look for the next potential
649 long ret=ogg_sync_pageseek(oy,og);
659 /* head did not start a synced page... skipped some bytes */
665 /* loop. keep looking */
670 /* add the incoming page to the stream state; we decompose the page
671 into packet segments here as well. */
673 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
674 unsigned char *header=og->header;
675 unsigned char *body=og->body;
676 long bodysize=og->body_len;
679 int version=ogg_page_version(og);
680 int continued=ogg_page_continued(og);
681 int bos=ogg_page_bos(og);
682 int eos=ogg_page_eos(og);
683 ogg_int64_t granulepos=ogg_page_granulepos(og);
684 int serialno=ogg_page_serialno(og);
685 long pageno=ogg_page_pageno(og);
686 int segments=header[26];
688 /* clean up 'returned data' */
690 long lr=os->lacing_returned;
691 long br=os->body_returned;
697 memmove(os->body_data,os->body_data+br,os->body_fill);
703 if(os->lacing_fill-lr){
704 memmove(os->lacing_vals,os->lacing_vals+lr,
705 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
706 memmove(os->granule_vals,os->granule_vals+lr,
707 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
710 os->lacing_packet-=lr;
711 os->lacing_returned=0;
715 /* check the serial number */
716 if(serialno!=os->serialno)return(-1);
717 if(version>0)return(-1);
719 _os_lacing_expand(os,segments+1);
721 /* are we in sequence? */
722 if(pageno!=os->pageno){
725 /* unroll previous partial packet (if any) */
726 for(i=os->lacing_packet;i<os->lacing_fill;i++)
727 os->body_fill-=os->lacing_vals[i]&0xff;
728 os->lacing_fill=os->lacing_packet;
730 /* make a note of dropped data in segment table */
732 os->lacing_vals[os->lacing_fill++]=0x400;
736 /* are we a 'continued packet' page? If so, we'll need to skip
740 for(;segptr<segments;segptr++){
741 int val=header[27+segptr];
753 _os_body_expand(os,bodysize);
754 memcpy(os->body_data+os->body_fill,body,bodysize);
755 os->body_fill+=bodysize;
760 while(segptr<segments){
761 int val=header[27+segptr];
762 os->lacing_vals[os->lacing_fill]=val;
763 os->granule_vals[os->lacing_fill]=-1;
766 os->lacing_vals[os->lacing_fill]|=0x100;
770 if(val<255)saved=os->lacing_fill;
775 if(val<255)os->lacing_packet=os->lacing_fill;
778 /* set the granulepos on the last granuleval of the last full packet */
780 os->granule_vals[saved]=granulepos;
787 if(os->lacing_fill>0)
788 os->lacing_vals[os->lacing_fill-1]|=0x200;
796 /* clear things to an initial state. Good to call, eg, before seeking */
797 int ogg_sync_reset(ogg_sync_state *oy){
806 int ogg_stream_reset(ogg_stream_state *os){
812 os->lacing_returned=0;
825 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
826 ogg_stream_reset(os);
827 os->serialno=serialno;
831 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
833 /* The last part of decode. We have the stream broken into packet
834 segments. Now we need to group them into packets (or return the
835 out of sync markers) */
837 int ptr=os->lacing_returned;
839 if(os->lacing_packet<=ptr)return(0);
841 if(os->lacing_vals[ptr]&0x400){
842 /* we need to tell the codec there's a gap; it might need to
843 handle previous packet dependencies. */
844 os->lacing_returned++;
849 if(!op && !adv)return(1); /* just using peek as an inexpensive way
850 to ask if there's a whole packet
853 /* Gather the whole packet. We'll have no holes or a partial packet */
855 int size=os->lacing_vals[ptr]&0xff;
857 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
858 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
861 int val=os->lacing_vals[++ptr];
863 if(val&0x200)eos=0x200;
870 op->packet=os->body_data+os->body_returned;
871 op->packetno=os->packetno;
872 op->granulepos=os->granule_vals[ptr];
877 os->body_returned+=bytes;
878 os->lacing_returned=ptr+1;
885 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
886 return _packetout(os,op,1);
889 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
890 return _packetout(os,op,0);
893 void ogg_packet_clear(ogg_packet *op) {
894 _ogg_free(op->packet);
895 memset(op, 0, sizeof(*op));
901 ogg_stream_state os_en, os_de;
904 void checkpacket(ogg_packet *op,int len, int no, int pos){
906 static int sequence=0;
910 fprintf(stderr,"incorrect packet length!\n");
913 if(op->granulepos!=pos){
914 fprintf(stderr,"incorrect packet position!\n");
918 /* packet number just follows sequence/gap; adjust the input number
928 if(op->packetno!=sequence){
929 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
930 (long)(op->packetno),sequence);
935 for(j=0;j<op->bytes;j++)
936 if(op->packet[j]!=((j+no)&0xff)){
937 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
938 j,op->packet[j],(j+no)&0xff);
943 void check_page(unsigned char *data,const int *header,ogg_page *og){
946 for(j=0;j<og->body_len;j++)
947 if(og->body[j]!=data[j]){
948 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
949 j,data[j],og->body[j]);
954 for(j=0;j<og->header_len;j++){
955 if(og->header[j]!=header[j]){
956 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
957 for(j=0;j<header[26]+27;j++)
958 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
959 fprintf(stderr,"\n");
963 if(og->header_len!=header[26]+27){
964 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
965 og->header_len,header[26]+27);
970 void print_header(ogg_page *og){
972 fprintf(stderr,"\nHEADER:\n");
973 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
974 og->header[0],og->header[1],og->header[2],og->header[3],
975 (int)og->header[4],(int)og->header[5]);
977 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
978 (og->header[9]<<24)|(og->header[8]<<16)|
979 (og->header[7]<<8)|og->header[6],
980 (og->header[17]<<24)|(og->header[16]<<16)|
981 (og->header[15]<<8)|og->header[14],
982 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
983 (og->header[19]<<8)|og->header[18]);
985 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
986 (int)og->header[22],(int)og->header[23],
987 (int)og->header[24],(int)og->header[25],
988 (int)og->header[26]);
990 for(j=27;j<og->header_len;j++)
991 fprintf(stderr,"%d ",(int)og->header[j]);
992 fprintf(stderr,")\n\n");
995 void copy_page(ogg_page *og){
996 unsigned char *temp=_ogg_malloc(og->header_len);
997 memcpy(temp,og->header,og->header_len);
1000 temp=_ogg_malloc(og->body_len);
1001 memcpy(temp,og->body,og->body_len);
1006 fprintf(stderr,"error!\n");
1011 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1012 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1013 0x01,0x02,0x03,0x04,0,0,0,0,
1014 0x15,0xed,0xec,0x91,
1018 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1019 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1020 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1021 0x01,0x02,0x03,0x04,0,0,0,0,
1022 0x59,0x10,0x6c,0x2c,
1025 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1026 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1027 0x01,0x02,0x03,0x04,1,0,0,0,
1028 0x89,0x33,0x85,0xce,
1030 254,255,0,255,1,255,245,255,255,0,
1033 /* nil packets; beginning,middle,end */
1034 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1035 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1036 0x01,0x02,0x03,0x04,0,0,0,0,
1037 0xff,0x7b,0x23,0x17,
1040 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1041 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1042 0x01,0x02,0x03,0x04,1,0,0,0,
1043 0x5c,0x3f,0x66,0xcb,
1045 17,254,255,0,0,255,1,0,255,245,255,255,0,
1048 /* large initial packet */
1049 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1050 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1051 0x01,0x02,0x03,0x04,0,0,0,0,
1052 0x01,0x27,0x31,0xaa,
1054 255,255,255,255,255,255,255,255,
1055 255,255,255,255,255,255,255,255,255,10};
1057 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1058 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1059 0x01,0x02,0x03,0x04,1,0,0,0,
1060 0x7f,0x4e,0x8a,0xd2,
1065 /* continuing packet test */
1066 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1067 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1068 0x01,0x02,0x03,0x04,0,0,0,0,
1069 0xff,0x7b,0x23,0x17,
1073 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1074 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1075 0x01,0x02,0x03,0x04,1,0,0,0,
1076 0x34,0x24,0xd5,0x29,
1078 255,255,255,255,255,255,255,255,
1079 255,255,255,255,255,255,255,255,255};
1081 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1082 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1083 0x01,0x02,0x03,0x04,2,0,0,0,
1084 0xc8,0xc3,0xcb,0xed,
1089 /* page with the 255 segment limit */
1090 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1091 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1092 0x01,0x02,0x03,0x04,0,0,0,0,
1093 0xff,0x7b,0x23,0x17,
1097 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1098 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1099 0x01,0x02,0x03,0x04,1,0,0,0,
1100 0xed,0x2a,0x2e,0xa7,
1102 10,10,10,10,10,10,10,10,
1103 10,10,10,10,10,10,10,10,
1104 10,10,10,10,10,10,10,10,
1105 10,10,10,10,10,10,10,10,
1106 10,10,10,10,10,10,10,10,
1107 10,10,10,10,10,10,10,10,
1108 10,10,10,10,10,10,10,10,
1109 10,10,10,10,10,10,10,10,
1110 10,10,10,10,10,10,10,10,
1111 10,10,10,10,10,10,10,10,
1112 10,10,10,10,10,10,10,10,
1113 10,10,10,10,10,10,10,10,
1114 10,10,10,10,10,10,10,10,
1115 10,10,10,10,10,10,10,10,
1116 10,10,10,10,10,10,10,10,
1117 10,10,10,10,10,10,10,10,
1118 10,10,10,10,10,10,10,10,
1119 10,10,10,10,10,10,10,10,
1120 10,10,10,10,10,10,10,10,
1121 10,10,10,10,10,10,10,10,
1122 10,10,10,10,10,10,10,10,
1123 10,10,10,10,10,10,10,10,
1124 10,10,10,10,10,10,10,10,
1125 10,10,10,10,10,10,10,10,
1126 10,10,10,10,10,10,10,10,
1127 10,10,10,10,10,10,10,10,
1128 10,10,10,10,10,10,10,10,
1129 10,10,10,10,10,10,10,10,
1130 10,10,10,10,10,10,10,10,
1131 10,10,10,10,10,10,10,10,
1132 10,10,10,10,10,10,10,10,
1133 10,10,10,10,10,10,10};
1135 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1136 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1137 0x01,0x02,0x03,0x04,2,0,0,0,
1138 0x6c,0x3b,0x82,0x3d,
1143 /* packet that overspans over an entire page */
1144 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1145 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1146 0x01,0x02,0x03,0x04,0,0,0,0,
1147 0xff,0x7b,0x23,0x17,
1151 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1152 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1153 0x01,0x02,0x03,0x04,1,0,0,0,
1154 0x3c,0xd9,0x4d,0x3f,
1156 100,255,255,255,255,255,255,255,255,
1157 255,255,255,255,255,255,255,255};
1159 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1160 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1161 0x01,0x02,0x03,0x04,2,0,0,0,
1162 0xbd,0xd5,0xb5,0x8b,
1164 255,255,255,255,255,255,255,255,
1165 255,255,255,255,255,255,255,255,255};
1167 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1168 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1169 0x01,0x02,0x03,0x04,3,0,0,0,
1170 0xef,0xdd,0x88,0xde,
1172 255,255,75,255,4,255,0};
1174 /* packet that overspans over an entire page */
1175 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1176 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1177 0x01,0x02,0x03,0x04,0,0,0,0,
1178 0xff,0x7b,0x23,0x17,
1182 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1183 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1184 0x01,0x02,0x03,0x04,1,0,0,0,
1185 0x3c,0xd9,0x4d,0x3f,
1187 100,255,255,255,255,255,255,255,255,
1188 255,255,255,255,255,255,255,255};
1190 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1191 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1192 0x01,0x02,0x03,0x04,2,0,0,0,
1193 0xd4,0xe0,0x60,0xe5,
1196 void test_pack(const int *pl, const int **headers){
1197 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1202 long granule_pos=7,pageno=0;
1203 int i,j,packets,pageout=0;
1207 ogg_stream_reset(&os_en);
1208 ogg_stream_reset(&os_de);
1209 ogg_sync_reset(&oy);
1211 for(packets=0;;packets++)if(pl[packets]==-1)break;
1213 for(i=0;i<packets;i++){
1214 /* construct a test packet */
1218 op.packet=data+inptr;
1220 op.e_o_s=(pl[i+1]<0?1:0);
1221 op.granulepos=granule_pos;
1225 for(j=0;j<len;j++)data[inptr++]=i+j;
1227 /* submit the test packet */
1228 ogg_stream_packetin(&os_en,&op);
1230 /* retrieve any finished pages */
1234 while(ogg_stream_pageout(&os_en,&og)){
1235 /* We have a page. Check it carefully */
1237 fprintf(stderr,"%ld, ",pageno);
1239 if(headers[pageno]==NULL){
1240 fprintf(stderr,"coded too many pages!\n");
1244 check_page(data+outptr,headers[pageno],&og);
1246 outptr+=og.body_len;
1249 /* have a complete page; submit it to sync/decode */
1253 ogg_packet op_de,op_de2;
1254 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1255 memcpy(buf,og.header,og.header_len);
1256 memcpy(buf+og.header_len,og.body,og.body_len);
1257 ogg_sync_wrote(&oy,og.header_len+og.body_len);
1259 while(ogg_sync_pageout(&oy,&og_de)>0){
1260 /* got a page. Happy happy. Verify that it's good. */
1262 check_page(data+deptr,headers[pageout],&og_de);
1263 deptr+=og_de.body_len;
1266 /* submit it to deconstitution */
1267 ogg_stream_pagein(&os_de,&og_de);
1270 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1271 ogg_stream_packetpeek(&os_de,NULL);
1272 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1274 /* verify peek and out match */
1275 if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1276 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1281 /* verify the packet! */
1283 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1284 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1288 /* check bos flag */
1289 if(bosflag==0 && op_de.b_o_s==0){
1290 fprintf(stderr,"b_o_s flag not set on packet!\n");
1293 if(bosflag && op_de.b_o_s){
1294 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1298 depacket+=op_de.bytes;
1300 /* check eos flag */
1302 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1306 if(op_de.e_o_s)eosflag=1;
1308 /* check granulepos flag */
1309 if(op_de.granulepos!=-1){
1310 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1319 if(headers[pageno]!=NULL){
1320 fprintf(stderr,"did not write last page!\n");
1323 if(headers[pageout]!=NULL){
1324 fprintf(stderr,"did not decode last page!\n");
1328 fprintf(stderr,"encoded page data incomplete!\n");
1332 fprintf(stderr,"decoded page data incomplete!\n");
1335 if(inptr!=depacket){
1336 fprintf(stderr,"decoded packet data incomplete!\n");
1340 fprintf(stderr,"Never got a packet with EOS set!\n");
1343 fprintf(stderr,"ok.\n");
1348 ogg_stream_init(&os_en,0x04030201);
1349 ogg_stream_init(&os_de,0x04030201);
1352 /* Exercise each code path in the framing code. Also verify that
1353 the checksums are working. */
1357 const int packets[]={17, -1};
1358 const int *headret[]={head1_0,NULL};
1360 fprintf(stderr,"testing single page encoding... ");
1361 test_pack(packets,headret);
1365 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1366 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1367 const int *headret[]={head1_1,head2_1,NULL};
1369 fprintf(stderr,"testing basic page encoding... ");
1370 test_pack(packets,headret);
1374 /* nil packets; beginning,middle,end */
1375 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1376 const int *headret[]={head1_2,head2_2,NULL};
1378 fprintf(stderr,"testing basic nil packets... ");
1379 test_pack(packets,headret);
1383 /* large initial packet */
1384 const int packets[]={4345,259,255,-1};
1385 const int *headret[]={head1_3,head2_3,NULL};
1387 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1388 test_pack(packets,headret);
1392 /* continuing packet test */
1393 const int packets[]={0,4345,259,255,-1};
1394 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1396 fprintf(stderr,"testing single packet page span... ");
1397 test_pack(packets,headret);
1400 /* page with the 255 segment limit */
1403 const int packets[]={0,10,10,10,10,10,10,10,10,
1404 10,10,10,10,10,10,10,10,
1405 10,10,10,10,10,10,10,10,
1406 10,10,10,10,10,10,10,10,
1407 10,10,10,10,10,10,10,10,
1408 10,10,10,10,10,10,10,10,
1409 10,10,10,10,10,10,10,10,
1410 10,10,10,10,10,10,10,10,
1411 10,10,10,10,10,10,10,10,
1412 10,10,10,10,10,10,10,10,
1413 10,10,10,10,10,10,10,10,
1414 10,10,10,10,10,10,10,10,
1415 10,10,10,10,10,10,10,10,
1416 10,10,10,10,10,10,10,10,
1417 10,10,10,10,10,10,10,10,
1418 10,10,10,10,10,10,10,10,
1419 10,10,10,10,10,10,10,10,
1420 10,10,10,10,10,10,10,10,
1421 10,10,10,10,10,10,10,10,
1422 10,10,10,10,10,10,10,10,
1423 10,10,10,10,10,10,10,10,
1424 10,10,10,10,10,10,10,10,
1425 10,10,10,10,10,10,10,10,
1426 10,10,10,10,10,10,10,10,
1427 10,10,10,10,10,10,10,10,
1428 10,10,10,10,10,10,10,10,
1429 10,10,10,10,10,10,10,10,
1430 10,10,10,10,10,10,10,10,
1431 10,10,10,10,10,10,10,10,
1432 10,10,10,10,10,10,10,10,
1433 10,10,10,10,10,10,10,10,
1434 10,10,10,10,10,10,10,50,-1};
1435 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1437 fprintf(stderr,"testing max packet segments... ");
1438 test_pack(packets,headret);
1442 /* packet that overspans over an entire page */
1443 const int packets[]={0,100,9000,259,255,-1};
1444 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1446 fprintf(stderr,"testing very large packets... ");
1447 test_pack(packets,headret);
1451 /* term only page. why not? */
1452 const int packets[]={0,100,4080,-1};
1453 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1455 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1456 test_pack(packets,headret);
1462 /* build a bunch of pages for testing */
1463 unsigned char *data=_ogg_malloc(1024*1024);
1464 int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
1468 ogg_stream_reset(&os_en);
1470 for(i=0;pl[i]!=-1;i++){
1474 op.packet=data+inptr;
1476 op.e_o_s=(pl[i+1]<0?1:0);
1477 op.granulepos=(i+1)*1000;
1479 for(j=0;j<len;j++)data[inptr++]=i+j;
1480 ogg_stream_packetin(&os_en,&op);
1485 /* retrieve finished pages */
1487 if(ogg_stream_pageout(&os_en,&og[i])==0){
1488 fprintf(stderr,"Too few pages output building sync tests!\n");
1494 /* Test lost pages on pagein/packetout: no rollback */
1499 fprintf(stderr,"Testing loss of pages... ");
1501 ogg_sync_reset(&oy);
1502 ogg_stream_reset(&os_de);
1504 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1506 ogg_sync_wrote(&oy,og[i].header_len);
1507 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1508 ogg_sync_wrote(&oy,og[i].body_len);
1511 ogg_sync_pageout(&oy,&temp);
1512 ogg_stream_pagein(&os_de,&temp);
1513 ogg_sync_pageout(&oy,&temp);
1514 ogg_stream_pagein(&os_de,&temp);
1515 ogg_sync_pageout(&oy,&temp);
1517 ogg_sync_pageout(&oy,&temp);
1518 ogg_stream_pagein(&os_de,&temp);
1520 /* do we get the expected results/packets? */
1522 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1523 checkpacket(&test,0,0,0);
1524 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1525 checkpacket(&test,100,1,-1);
1526 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1527 checkpacket(&test,4079,2,3000);
1528 if(ogg_stream_packetout(&os_de,&test)!=-1){
1529 fprintf(stderr,"Error: loss of page did not return error\n");
1532 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1533 checkpacket(&test,76,5,-1);
1534 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1535 checkpacket(&test,34,6,-1);
1536 fprintf(stderr,"ok.\n");
1539 /* Test lost pages on pagein/packetout: rollback with continuation */
1544 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1546 ogg_sync_reset(&oy);
1547 ogg_stream_reset(&os_de);
1549 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1551 ogg_sync_wrote(&oy,og[i].header_len);
1552 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1553 ogg_sync_wrote(&oy,og[i].body_len);
1556 ogg_sync_pageout(&oy,&temp);
1557 ogg_stream_pagein(&os_de,&temp);
1558 ogg_sync_pageout(&oy,&temp);
1559 ogg_stream_pagein(&os_de,&temp);
1560 ogg_sync_pageout(&oy,&temp);
1561 ogg_stream_pagein(&os_de,&temp);
1562 ogg_sync_pageout(&oy,&temp);
1564 ogg_sync_pageout(&oy,&temp);
1565 ogg_stream_pagein(&os_de,&temp);
1567 /* do we get the expected results/packets? */
1569 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1570 checkpacket(&test,0,0,0);
1571 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1572 checkpacket(&test,100,1,-1);
1573 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1574 checkpacket(&test,4079,2,3000);
1575 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1576 checkpacket(&test,2956,3,4000);
1577 if(ogg_stream_packetout(&os_de,&test)!=-1){
1578 fprintf(stderr,"Error: loss of page did not return error\n");
1581 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1582 checkpacket(&test,300,13,14000);
1583 fprintf(stderr,"ok.\n");
1586 /* the rest only test sync */
1589 /* Test fractional page inputs: incomplete capture */
1590 fprintf(stderr,"Testing sync on partial inputs... ");
1591 ogg_sync_reset(&oy);
1592 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1594 ogg_sync_wrote(&oy,3);
1595 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1597 /* Test fractional page inputs: incomplete fixed header */
1598 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1600 ogg_sync_wrote(&oy,20);
1601 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1603 /* Test fractional page inputs: incomplete header */
1604 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1606 ogg_sync_wrote(&oy,5);
1607 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1609 /* Test fractional page inputs: incomplete body */
1611 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1612 og[1].header_len-28);
1613 ogg_sync_wrote(&oy,og[1].header_len-28);
1614 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1616 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1617 ogg_sync_wrote(&oy,1000);
1618 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1620 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1621 og[1].body_len-1000);
1622 ogg_sync_wrote(&oy,og[1].body_len-1000);
1623 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1625 fprintf(stderr,"ok.\n");
1628 /* Test fractional page inputs: page + incomplete capture */
1631 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1632 ogg_sync_reset(&oy);
1634 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1636 ogg_sync_wrote(&oy,og[1].header_len);
1638 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1640 ogg_sync_wrote(&oy,og[1].body_len);
1642 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1644 ogg_sync_wrote(&oy,20);
1645 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1646 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1648 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1649 og[1].header_len-20);
1650 ogg_sync_wrote(&oy,og[1].header_len-20);
1651 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1653 ogg_sync_wrote(&oy,og[1].body_len);
1654 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1656 fprintf(stderr,"ok.\n");
1659 /* Test recapture: garbage + page */
1662 fprintf(stderr,"Testing search for capture... ");
1663 ogg_sync_reset(&oy);
1666 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1668 ogg_sync_wrote(&oy,og[1].body_len);
1670 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1672 ogg_sync_wrote(&oy,og[1].header_len);
1674 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1676 ogg_sync_wrote(&oy,og[1].body_len);
1678 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1680 ogg_sync_wrote(&oy,20);
1681 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1682 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1683 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1685 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
1686 og[2].header_len-20);
1687 ogg_sync_wrote(&oy,og[2].header_len-20);
1688 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1690 ogg_sync_wrote(&oy,og[2].body_len);
1691 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1693 fprintf(stderr,"ok.\n");
1696 /* Test recapture: page + garbage + page */
1699 fprintf(stderr,"Testing recapture... ");
1700 ogg_sync_reset(&oy);
1702 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1704 ogg_sync_wrote(&oy,og[1].header_len);
1706 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1708 ogg_sync_wrote(&oy,og[1].body_len);
1710 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1712 ogg_sync_wrote(&oy,og[2].header_len);
1714 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1716 ogg_sync_wrote(&oy,og[2].header_len);
1718 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1720 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1722 ogg_sync_wrote(&oy,og[2].body_len-5);
1724 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
1726 ogg_sync_wrote(&oy,og[3].header_len);
1728 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
1730 ogg_sync_wrote(&oy,og[3].body_len);
1732 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1733 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1735 fprintf(stderr,"ok.\n");