Recognizes if input is ogg or not.
[xiph.git] / ogg2 / src / stream.c
blobbe5cfef5c08b7169af5bb467d93b1a171d6c8bff
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE Ogg Reference Library 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 Ogg Reference Library SOURCE CODE IS (C) COPYRIGHT 1994-2004 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
13 function: code raw packets into framed Ogg logical stream and
14 decode Ogg logical streams back into raw packets
15 last mod: $Id$
17 ********************************************************************/
19 #include <stdlib.h>
20 #include <string.h>
21 #include "ogginternal.h" /* proper way to suck in ogg/ogg.h from a
22 libogg compile */
24 /* A complete description of Ogg framing exists in docs/framing.html */
26 ogg2_stream_state *ogg2_stream_create(int serialno){
27 ogg2_stream_state *os=_ogg_calloc(1,sizeof(*os));
28 os->watermark=4096;
29 os->serialno=serialno;
30 os->bufferpool=ogg2_buffer_create();
31 return os;
34 int ogg2_stream_setdiscont(ogg2_stream_state *os){
35 /* Discont mode must be known and set before Page 1 is processed */
36 if(os->pageno==0||(os->pageno==1&&os->packets==0)){
37 os->discont=1;
38 return OGG2_SUCCESS;
40 return OGG2_EINVAL;
43 int ogg2_stream_setfill(ogg2_stream_state *os,int watermark){
44 if(os){
45 if(watermark>65535)watermark=65535;
46 os->watermark=watermark;
47 return watermark;
49 return OGG2_EINVAL;
52 /* _clear does not free os, only the non-flat storage within */
53 int ogg2_stream_destroy(ogg2_stream_state *os){
54 if(os){
56 ogg2_buffer_release(os->header_tail);
57 ogg2_buffer_release(os->body_tail);
58 ogg2byte_clear(&os->header_build);
59 ogg2_buffer_destroy(os->bufferpool);
60 memset(os,0,sizeof(*os));
63 return OGG2_SUCCESS;
66 /* finish building a header then flush the current page header and
67 body to the output buffer */
68 static void _packet_flush(ogg2_stream_state *os,int nextcomplete){
69 ogg2byte_buffer *obb=&os->header_build;
70 unsigned char ctemp;
72 if(os->lacing_fill){
73 /* build header */
74 ogg2byte_set1(obb,'O',0);
75 ogg2byte_set1(obb,'g',1);
76 ogg2byte_set1(obb,'g',2);
77 ogg2byte_set1(obb,'S',3);
79 ogg2byte_set1(obb,0x00,4); /* stream structure version */
81 ctemp=0x00;
82 if(os->continued)ctemp|=0x01; /* continued packet flag? */
83 os->continued=nextcomplete;
84 if(os->b_o_s==0)ctemp|=0x02; /* first page flag? */
85 if(os->e_o_s)ctemp|=0x04; /* last page flag? */
86 ogg2byte_set1(obb,ctemp,5);
88 /* 64 bits of granule position */
89 if(!os->b_o_s)
90 ogg2byte_set8(obb,0,6);
91 else
92 ogg2byte_set8(obb,os->granulepos,6);
93 os->b_o_s=1;
94 os->packets=0;
96 /* 32 bits of stream serial number */
97 ogg2byte_set4(obb,os->serialno,14);
99 /* 32 bits of page counter (we have both counter and page header
100 because this val can roll over) */
101 if(os->pageno==-1)os->pageno=0; /* because someone called
102 stream_reset; this would be a
103 strange thing to do in an
104 encode stream, but it has
105 plausible uses */
106 ogg2byte_set4(obb,os->pageno++,18);
108 /* CRC filled in later */
109 /* segment table size */
110 ogg2byte_set1(obb,os->lacing_fill,26);
112 /* toss the header on the fifo */
113 if(os->header_tail){
114 ogg2_reference *ret=ogg2byte_return_and_reset(&os->header_build);
115 os->header_head=ogg2_buffer_cat(os->header_head,ret);
116 if(nextcomplete)ogg2byte_init(&os->header_build,0,os->bufferpool);
117 }else{
118 os->header_tail=ogg2byte_return_and_reset(&os->header_build);
119 os->header_head=ogg2_buffer_walk(os->header_tail);
120 if(nextcomplete)ogg2byte_init(&os->header_build,0,os->bufferpool);
122 os->lacing_fill=0;
123 os->body_fill=0;
127 /* submit data to the internal buffer of the framing engine */
128 int ogg2_stream_packetin(ogg2_stream_state *os,ogg2_packet *op){
129 /* get sizing */
130 long bytes=ogg2_buffer_length(op->packet);
131 long lacing_vals=bytes/255+1;
132 int remainder=bytes%255;
133 int i;
135 if(os->e_o_s){
136 ogg2_packet_release(op);
137 return OGG2_EEOS;
140 if(!os->lacing_fill)
141 ogg2byte_init(&os->header_build, 0, os->bufferpool);
143 /* for discontinuous mode */
144 if(os->discont && !os->packets) os->granulepos=op->end_granule;
145 os->packets++;
147 /* concat packet data */
148 if(os->body_head)
149 os->body_head=ogg2_buffer_cat(os->body_head,op->packet);
150 else
151 os->body_tail=os->body_head=op->packet;
153 /* add lacing vals, but finish/flush packet first if we hit a
154 (watermark && not initial page) */
155 for(i=0;i<lacing_vals-1;i++){ /* handle the 255s first */
156 os->body_fill+=255;
157 ogg2byte_set1(&os->header_build,255,27+os->lacing_fill++);
159 if(os->body_fill>=os->watermark && os->b_o_s)_packet_flush(os,1);
160 if(os->lacing_fill==255)_packet_flush(os,1);
163 /* we know we'll finish this packet on this page; propogate
164 granulepos et al and then finish packet lacing */
166 os->body_fill+=remainder;
167 if (!os->discont) os->granulepos=op->end_granule;
168 os->packetno++; /* for the sake of completeness */
169 if(op->e_o_s)os->e_o_s=1;
170 ogg2byte_set1(&os->header_build,remainder,27+os->lacing_fill++);
172 if(os->e_o_s ||
173 os->body_fill>=os->watermark ||
174 !os->b_o_s ||
175 os->lacing_fill==255)_packet_flush(os,0);
177 memset(op,0,sizeof(*op));
178 return OGG2_SUCCESS;
181 /* This constructs pages from buffered packet segments. */
182 int ogg2_stream_pageout(ogg2_stream_state *os, ogg2_page *og){
183 ogg2byte_buffer ob;
184 long header_bytes;
185 long body_bytes=0;
186 int i;
188 /* if the incoming page is still valid (and thus unconsumed),
189 release it to prevent a leak */
190 ogg2_page_release(og);
192 /* is there a page waiting to come back? */
193 if(!os->header_tail) return 0;
195 /* get header and body sizes */
196 ogg2byte_init(&ob,os->header_tail,0);
197 header_bytes=ogg2byte_read1(&ob,26)+27;
198 for(i=27;i<header_bytes;i++)
199 body_bytes+=ogg2byte_read1(&ob,i);
201 /* split page references out of the fifos */
202 if(og){
203 og->header=ogg2_buffer_split(&os->header_tail,&os->header_head,header_bytes);
204 og->header_len=header_bytes;
205 og->body=ogg2_buffer_split(&os->body_tail,&os->body_head,body_bytes);
206 og->body_len=body_bytes;
208 /* checksum */
209 ogg2_page_checksum_set(og);
210 }else{
211 os->header_tail=ogg2_buffer_pretruncate(os->header_tail,header_bytes);
212 os->body_tail=ogg2_buffer_pretruncate(os->body_tail,body_bytes);
213 if(!os->header_tail)os->header_head=0;
214 if(!os->body_tail)os->body_head=0;
216 return 1;
219 /* This will flush remaining packets into a page (returning nonzero),
220 even if there is not enough data to trigger a flush normally
221 (undersized page). If there are no packets or partial packets to
222 flush, ogg2_stream_flush returns 0. Note that ogg2_stream_flush will
223 try to flush a normal sized page like ogg2_stream_pageout; a call to
224 ogg2_stream_flush does not guarantee that all packets have flushed.
225 Only a return value of 0 from ogg2_stream_flush indicates all packet
226 data is flushed into pages.
228 since ogg2_stream_flush will flush the last page in a stream even if
229 it's undersized, you almost certainly want to use ogg2_stream_pageout
230 (and *not* ogg2_stream_flush) unless you specifically need to flush
231 an page regardless of size in the middle of a stream. */
233 int ogg2_stream_flush(ogg2_stream_state *os,ogg2_page *og){
235 /* If there's no page already waiting for output, flush a partial
236 page... assuming we have one */
237 if(!os->header_tail)_packet_flush(os,0);
238 return ogg2_stream_pageout(os,og);
242 int ogg2_stream_eos(ogg2_stream_state *os){
243 return os->e_o_s;
246 /* DECODING PRIMITIVES: packet streaming layer **********************/
248 #define FINFLAG 0x80000000UL
249 #define FINMASK 0x7fffffffUL
251 static void _next_lace(ogg2byte_buffer *ob,ogg2_stream_state *os){
252 /* search ahead one lace */
253 os->body_fill_next=0;
254 while(os->laceptr<os->lacing_fill){
255 int val=ogg2byte_read1(ob,27+os->laceptr++);
256 os->body_fill_next+=val;
257 if(val<255){
258 os->body_fill_next|=FINFLAG;
259 os->clearflag=1;
260 break;
265 /* sync and reporting within a logical stream uses a flagging system
266 to improve the utility of the information coming back. There are
267 two basic problems a stream can run into; missing pages (a hole in
268 the page sequence numbering), and malformed pages such that
269 spanning isn't handled properly. Both need to be reported.
271 OGG_EHOLE happens when a page is out of sequence. However, this
272 can be a natural case after seeking or reset and we want to
273 suppress the error in this case. Nor shuld the error be reported
274 redundantly. We need to *set* the hole flag (see below), but we
275 don't want to report it. 0==unset. 1==set, 2==set and report.
277 OGG_ESPAN happens when packet span is indicated but there's no
278 spanning packet data, or there's spanning packet data and no
279 declared span. Naturally, this error should also not be
280 mistriggered due to seek or reset, or reported redundantly. */
282 static void _span_queued_page(ogg2_stream_state *os){
283 while( !(os->body_fill&FINFLAG) ){
285 if(!os->header_tail)break;
287 /* first flush out preceeding page header (if any). Body is
288 flushed as it's consumed, so that's not done here. */
290 if(os->lacing_fill>=0)
291 os->header_tail=ogg2_buffer_pretruncate(os->header_tail,
292 os->lacing_fill+27);
293 os->lacing_fill=0;
294 os->laceptr=0;
295 os->clearflag=0;
296 os->packets=0;
298 if(!os->header_tail){
299 os->header_head=0;
300 break;
301 }else{
303 /* process/prepare next page, if any */
305 ogg2_page og; /* only for parsing header values */
306 long pageno;
307 ogg2byte_buffer ob;
309 og.header=os->header_tail; /* only for parsing header values */
310 pageno=ogg2_page_pageno(&og);
312 ogg2byte_init(&ob,os->header_tail,0);
313 os->lacing_fill=ogg2byte_read1(&ob,26);
315 /* are we in sequence? */
316 if(pageno!=os->pageno){
317 if(os->pageno==-1) /* indicates seek or reset */
318 os->holeflag=1; /* set for internal use */
319 else
320 os->holeflag=2; /* set for external reporting */
322 os->body_tail=ogg2_buffer_pretruncate(os->body_tail,
323 os->body_fill);
324 if(os->body_tail==0)os->body_head=0;
325 os->body_fill=0;
329 if(ogg2_page_continued(&og)){
330 os->continued=1;
331 if(os->body_fill==0){
332 /* continued packet, but no preceeding data to continue */
333 /* dump the first partial packet on the page */
334 _next_lace(&ob,os);
335 os->body_tail=
336 ogg2_buffer_pretruncate(os->body_tail,os->body_fill_next&FINMASK);
337 if(os->body_tail==0)os->body_head=0;
338 /* set span flag */
339 if(!os->spanflag && !os->holeflag)os->spanflag=2;
341 }else{
342 os->continued=0;
343 if(os->body_fill>0){
344 /* preceeding data to continue, but not a continued page */
345 /* dump body_fill */
346 os->body_tail=ogg2_buffer_pretruncate(os->body_tail,
347 os->body_fill);
348 if(os->body_tail==0)os->body_head=0;
349 os->body_fill=0;
351 /* set espan flag */
352 if(!os->spanflag && !os->holeflag)os->spanflag=2;
356 if(os->laceptr<os->lacing_fill){
357 os->granulepos=ogg2_page_granulepos(&og);
359 /* get current packet size & flag */
360 _next_lace(&ob,os);
361 os->body_fill+=os->body_fill_next; /* addition handles the flag fine;
362 unsigned on purpose */
363 /* ...and next packet size & flag */
364 _next_lace(&ob,os);
368 os->pageno=pageno+1;
369 os->e_o_s=ogg2_page_eos(&og);
370 os->b_o_s=ogg2_page_bos(&og);
376 /* add the incoming page to the stream state; we decompose the page
377 into packet segments here as well. */
379 int ogg2_stream_pagein(ogg2_stream_state *os, ogg2_page *og){
381 int serialno=ogg2_page_serialno(og);
382 int version=ogg2_page_version(og);
384 /* check the serial number */
385 if(serialno!=os->serialno){
386 ogg2_page_release(og);
387 return OGG2_ESERIAL;
389 if(version>0){
390 ogg2_page_release(og);
391 return OGG2_EVERSION;
394 /* add to fifos */
395 if(!os->body_tail){
396 os->body_tail=og->body;
397 os->body_head=ogg2_buffer_walk(og->body);
398 }else{
399 os->body_head=ogg2_buffer_cat(os->body_head,og->body);
401 if(!os->header_tail){
402 os->header_tail=og->header;
403 os->header_head=ogg2_buffer_walk(og->header);
404 os->lacing_fill=-27;
405 }else{
406 os->header_head=ogg2_buffer_cat(os->header_head,og->header);
409 memset(og,0,sizeof(*og));
410 return OGG2_SUCCESS;
413 int ogg2_stream_reset(ogg2_stream_state *os){
415 ogg2_buffer_release(os->header_tail);
416 ogg2_buffer_release(os->body_tail);
417 os->header_tail=os->header_head=0;
418 os->body_tail=os->body_head=0;
420 os->e_o_s=0;
421 os->b_o_s=0;
422 os->pageno=-1;
423 os->packetno=0;
424 os->granulepos=0;
426 os->body_fill=0;
427 os->lacing_fill=0;
428 ogg2byte_clear(&os->header_build);
429 os->packets=0;
431 os->holeflag=0;
432 os->spanflag=0;
433 os->clearflag=0;
434 os->laceptr=0;
435 os->body_fill_next=0;
437 return OGG2_SUCCESS;
440 int ogg2_stream_reset_serialno(ogg2_stream_state *os,int serialno){
441 ogg2_stream_reset(os);
442 os->serialno=serialno;
443 return OGG2_SUCCESS;
446 static int _packetout(ogg2_stream_state *os,ogg2_packet *op,int adv){
448 /* if the incoming packet is a valid reference, release it such that
449 we don't leak the memory */
450 ogg2_packet_release(op);
452 /* buffer packets for return */
453 _span_queued_page(os);
455 if(os->holeflag){
456 int temp=os->holeflag;
457 if(os->clearflag)
458 os->holeflag=0;
459 else
460 os->holeflag=1;
461 if(temp==2){
462 os->packetno++;
463 return OGG2_HOLE;
466 if(os->spanflag){
467 int temp=os->spanflag;
468 if(os->clearflag)
469 os->spanflag=0;
470 else
471 os->spanflag=1;
472 if(temp==2){
473 os->packetno++;
474 return OGG2_SPAN;
478 if(!(os->body_fill&FINFLAG)) return 0;
479 if(!op && !adv)return 1; /* just using peek as an inexpensive way
480 to ask if there's a whole packet
481 waiting */
482 if(op){
483 op->b_o_s=os->b_o_s;
484 if(os->e_o_s && os->body_fill_next==0)
485 op->e_o_s=os->e_o_s;
486 else
487 op->e_o_s=0;
489 if (os->discont){
490 /* Discontinuous Mode */
491 if(!os->continued) {
492 if(os->packets==0)op->end_granule=os->granulepos;
493 else op->end_granule=-1;
494 }else{
495 if(os->packets==1)op->end_granule=os->granulepos;
496 else op->end_granule=-1;
498 }else{
499 /* Continuous Mode */
500 if( (os->body_fill&FINFLAG) && !(os->body_fill_next&FINFLAG) )
501 op->end_granule=os->granulepos;
502 else
503 op->end_granule=-1;
506 os->packets++;
507 op->packetno=os->packetno;
510 if(adv){
511 ogg2byte_buffer ob;
512 ogg2byte_init(&ob,os->header_tail,0);
514 /* split the body contents off */
515 if(op){
516 op->packet=ogg2_buffer_split(&os->body_tail,&os->body_head,os->body_fill&FINMASK);
517 op->bytes=os->body_fill&FINMASK;
518 }else{
519 os->body_tail=ogg2_buffer_pretruncate(os->body_tail,os->body_fill&FINMASK);
520 if(os->body_tail==0)os->body_head=0;
523 /* update lacing pointers */
524 os->body_fill=os->body_fill_next;
525 _next_lace(&ob,os);
526 }else{
527 if(op){
528 op->packet=ogg2_buffer_sub(os->body_tail,0,os->body_fill&FINMASK);
529 op->bytes=os->body_fill&FINMASK;
533 if(adv){
534 os->packetno++;
535 os->b_o_s=0;
538 return 1;
541 int ogg2_stream_packetout(ogg2_stream_state *os,ogg2_packet *op){
542 return _packetout(os,op,1);
545 int ogg2_stream_packetpeek(ogg2_stream_state *os,ogg2_packet *op){
546 return _packetout(os,op,0);
549 int ogg2_packet_release(ogg2_packet *op) {
550 if(op){
551 ogg2_buffer_release(op->packet);
552 memset(op, 0, sizeof(*op));
554 return OGG2_SUCCESS;
557 int ogg2_page_release(ogg2_page *og) {
558 if(og){
559 ogg2_buffer_release(og->header);
560 ogg2_buffer_release(og->body);
561 memset(og, 0, sizeof(*og));
563 return OGG2_SUCCESS;
566 #ifdef _V_SELFTEST2
567 #include <stdio.h>
569 ogg2_stream_state *os_en, *os_de;
570 ogg2_sync_state *oy;
571 ogg2_buffer_state *bs;
573 void checkpacket(ogg2_packet *op,int len, int no, int pos){
574 long j;
575 static int sequence=0;
576 static int lastno=0;
577 ogg2byte_buffer ob;
579 if(ogg2_buffer_length(op->packet)!=len){
580 fprintf(stderr,"incorrect packet length!\n");
581 exit(1);
583 if(op->end_granule!=pos){
584 fprintf(stderr,"incorrect packet position!\n");
585 exit(1);
588 /* packet number just follows sequence/gap; adjust the input number
589 for that */
590 if(no==0){
591 sequence=0;
592 }else{
593 sequence++;
594 if(no>lastno+1)
595 sequence++;
597 lastno=no;
598 if(op->packetno!=sequence){
599 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
600 (long)(op->packetno),sequence);
601 exit(1);
604 /* Test data */
605 ogg2byte_init(&ob,op->packet,0);
606 for(j=0;j<ogg2_buffer_length(op->packet);j++)
607 if(ogg2byte_read1(&ob,j)!=((j+no)&0xff)){
608 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
609 j,ogg2byte_read1(&ob,j),(j+no)&0xff);
610 exit(1);
614 void check_page(unsigned char *data,const int *header,ogg2_page *og){
615 long j;
616 ogg2byte_buffer ob;
618 /* test buffer lengths */
619 long header_len=header[26]+27;
620 long body_len=0;
622 for(j=27;j<header_len;j++)
623 body_len+=header[j];
625 if(header_len!=ogg2_buffer_length(og->header)){
626 fprintf(stderr,"page header length mismatch: %ld correct, buffer is %ld\n",
627 header_len,ogg2_buffer_length(og->header));
628 exit(1);
630 if(body_len!=ogg2_buffer_length(og->body)){
631 fprintf(stderr,"page body length mismatch: %ld correct, buffer is %ld\n",
632 body_len,ogg2_buffer_length(og->body));
633 exit(1);
636 /* Test data */
637 ogg2byte_init(&ob,og->body,0);
638 for(j=0;j<ogg2_buffer_length(og->body);j++)
639 if(ogg2byte_read1(&ob,j)!=data[j]){
640 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
641 j,data[j],ogg2byte_read1(&ob,j));
642 exit(1);
645 /* Test header */
646 ogg2byte_init(&ob,og->header,0);
647 for(j=0;j<ogg2_buffer_length(og->header);j++){
648 if(ogg2byte_read1(&ob,j)!=header[j]){
649 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
650 for(j=0;j<header[26]+27;j++)
651 fprintf(stderr," (%ld)%02x:%02x",j,header[j],ogg2byte_read1(&ob,j));
652 fprintf(stderr,"\n");
653 exit(1);
656 if(ogg2_buffer_length(og->header)!=header[26]+27){
657 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
658 ogg2_buffer_length(og->header),header[26]+27);
659 exit(1);
663 void print_header(ogg2_page *og){
664 int j;
665 ogg2byte_buffer ob;
666 ogg2byte_init(&ob,og->header,0);
668 fprintf(stderr,"\nHEADER:\n");
669 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
670 ogg2byte_read1(&ob,0),ogg2byte_read1(&ob,1),
671 ogg2byte_read1(&ob,2),ogg2byte_read1(&ob,3),
672 (int)ogg2byte_read1(&ob,4),(int)ogg2byte_read1(&ob,5));
674 fprintf(stderr," granulepos: %08x%08x serialno: %x pageno: %ld\n",
675 ogg2byte_read4(&ob,10),ogg2byte_read4(&ob,6),
676 ogg2byte_read4(&ob,14),
677 (long)ogg2byte_read4(&ob,18));
679 fprintf(stderr," checksum: %08x\n segments: %d (",
680 ogg2byte_read4(&ob,22),(int)ogg2byte_read1(&ob,26));
682 for(j=27;j<ogg2_buffer_length(og->header);j++)
683 fprintf(stderr,"%d ",(int)ogg2byte_read1(&ob,j));
684 fprintf(stderr,")\n\n");
687 void error(void){
688 fprintf(stderr,"error!\n");
689 exit(1);
692 /* 17 only */
693 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
694 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
695 0x01,0x02,0x03,0x04,0,0,0,0,
696 0x15,0xed,0xec,0x91,
698 17};
700 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
701 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
702 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
703 0x01,0x02,0x03,0x04,0,0,0,0,
704 0x59,0x10,0x6c,0x2c,
706 17};
707 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
708 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
709 0x01,0x02,0x03,0x04,1,0,0,0,
710 0x89,0x33,0x85,0xce,
712 254,255,0,255,1,255,245,255,255,0,
713 255,255,90};
715 /* nil packets; beginning,middle,end */
716 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
717 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
718 0x01,0x02,0x03,0x04,0,0,0,0,
719 0xff,0x7b,0x23,0x17,
722 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
723 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
724 0x01,0x02,0x03,0x04,1,0,0,0,
725 0x5c,0x3f,0x66,0xcb,
727 17,254,255,0,0,255,1,0,255,245,255,255,0,
728 255,255,90,0};
730 /* large initial packet */
731 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
732 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
733 0x01,0x02,0x03,0x04,0,0,0,0,
734 0x01,0x27,0x31,0xaa,
736 255,255,255,255,255,255,255,255,
737 255,255,255,255,255,255,255,255,255,10};
739 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
740 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
741 0x01,0x02,0x03,0x04,1,0,0,0,
742 0x7f,0x4e,0x8a,0xd2,
744 255,4,255,0};
747 /* continuing packet test */
748 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
749 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
750 0x01,0x02,0x03,0x04,0,0,0,0,
751 0xff,0x7b,0x23,0x17,
755 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
756 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
757 0x01,0x02,0x03,0x04,1,0,0,0,
758 0x34,0x24,0xd5,0x29,
760 255,255,255,255,255,255,255,255,
761 255,255,255,255,255,255,255,255,255};
763 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
764 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
765 0x01,0x02,0x03,0x04,2,0,0,0,
766 0xc8,0xc3,0xcb,0xed,
768 10,255,4,255,0};
771 /* page with the 255 segment limit */
772 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
773 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
774 0x01,0x02,0x03,0x04,0,0,0,0,
775 0xff,0x7b,0x23,0x17,
779 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
780 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
781 0x01,0x02,0x03,0x04,1,0,0,0,
782 0xed,0x2a,0x2e,0xa7,
783 255,
784 10,10,10,10,10,10,10,10,
785 10,10,10,10,10,10,10,10,
786 10,10,10,10,10,10,10,10,
787 10,10,10,10,10,10,10,10,
788 10,10,10,10,10,10,10,10,
789 10,10,10,10,10,10,10,10,
790 10,10,10,10,10,10,10,10,
791 10,10,10,10,10,10,10,10,
792 10,10,10,10,10,10,10,10,
793 10,10,10,10,10,10,10,10,
794 10,10,10,10,10,10,10,10,
795 10,10,10,10,10,10,10,10,
796 10,10,10,10,10,10,10,10,
797 10,10,10,10,10,10,10,10,
798 10,10,10,10,10,10,10,10,
799 10,10,10,10,10,10,10,10,
800 10,10,10,10,10,10,10,10,
801 10,10,10,10,10,10,10,10,
802 10,10,10,10,10,10,10,10,
803 10,10,10,10,10,10,10,10,
804 10,10,10,10,10,10,10,10,
805 10,10,10,10,10,10,10,10,
806 10,10,10,10,10,10,10,10,
807 10,10,10,10,10,10,10,10,
808 10,10,10,10,10,10,10,10,
809 10,10,10,10,10,10,10,10,
810 10,10,10,10,10,10,10,10,
811 10,10,10,10,10,10,10,10,
812 10,10,10,10,10,10,10,10,
813 10,10,10,10,10,10,10,10,
814 10,10,10,10,10,10,10,10,
815 10,10,10,10,10,10,10};
817 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
818 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
819 0x01,0x02,0x03,0x04,2,0,0,0,
820 0x6c,0x3b,0x82,0x3d,
822 50};
825 /* packet that overspans over an entire page */
826 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
827 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
828 0x01,0x02,0x03,0x04,0,0,0,0,
829 0xff,0x7b,0x23,0x17,
833 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
834 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
835 0x01,0x02,0x03,0x04,1,0,0,0,
836 0x3c,0xd9,0x4d,0x3f,
838 100,255,255,255,255,255,255,255,255,
839 255,255,255,255,255,255,255,255};
841 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
842 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
843 0x01,0x02,0x03,0x04,2,0,0,0,
844 0xbd,0xd5,0xb5,0x8b,
846 255,255,255,255,255,255,255,255,
847 255,255,255,255,255,255,255,255,255};
849 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
850 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
851 0x01,0x02,0x03,0x04,3,0,0,0,
852 0xef,0xdd,0x88,0xde,
854 255,255,75,255,4,255,0};
856 /* packet that overspans over an entire page */
857 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
858 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
859 0x01,0x02,0x03,0x04,0,0,0,0,
860 0xff,0x7b,0x23,0x17,
864 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
865 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
866 0x01,0x02,0x03,0x04,1,0,0,0,
867 0x3c,0xd9,0x4d,0x3f,
869 100,255,255,255,255,255,255,255,255,
870 255,255,255,255,255,255,255,255};
872 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
873 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
874 0x01,0x02,0x03,0x04,2,0,0,0,
875 0xd4,0xe0,0x60,0xe5,
876 1,0};
878 void bufcpy(void *data,ogg2_reference *or){
879 while(or){
880 memcpy(data,or->buffer->data+or->begin,or->length);
881 data+=or->length;
882 or=or->next;
886 void bufcpy2(void *data,ogg2_reference *or,int begin){
887 while(or){
888 if(or->length-begin>0){
889 memcpy(data,or->buffer->data+or->begin+begin,or->length-begin);
890 data+=or->length-begin;
891 }else
892 begin-=or->length;
893 or=or->next;
897 int bufcmp(void *data,ogg2_reference *or){
898 while(or){
899 int ret=memcmp(data,or->buffer->data+or->begin,or->length);
900 if(ret)return ret;
901 data+=or->length;
902 or=or->next;
904 return 0;
907 void test_pack(const int *pl, const int **headers){
908 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
909 long inptr=0;
910 long outptr=0;
911 long deptr=0;
912 long depacket=0;
913 long granulepos=7,pageno=0;
914 int i,j,packets,pageout=0;
915 int eosflag=0;
916 int bosflag=0;
918 for(packets=0;;packets++)if(pl[packets]==-1)break;
920 for(i=0;i<packets;i++){
921 /* construct a test packet */
922 ogg2_packet op={0,0,0,0,0,0};
923 int len=pl[i];
925 op.packet=ogg2_buffer_alloc(bs,len);
926 op.e_o_s=(pl[i+1]<0?1:0);
927 op.granulepos=granulepos;
929 granulepos+=1024;
931 for(j=0;j<len;j++)data[inptr+j]=i+j;
932 memcpy(op.packet->buffer->data,data+inptr,len);
933 op.packet->length=len;
935 inptr+=j;
936 /* submit the test packet */
937 ogg2_stream_packetin(os_en,&op);
939 /* retrieve any finished pages */
941 ogg2_page og={0,0,0,0};
943 while(ogg2_stream_pageout(os_en,&og)){
944 /* We have a page. Check it carefully */
946 fprintf(stderr,"%ld, ",pageno);
948 if(headers[pageno]==NULL){
949 fprintf(stderr,"coded too many pages!\n");
950 exit(1);
953 check_page(data+outptr,headers[pageno],&og);
955 outptr+=ogg2_buffer_length(og.body);
956 pageno++;
958 /* have a complete page; submit it to sync/decode */
961 ogg2_page og_de={0,0,0,0};
962 ogg2_packet op_de={0,0,0,0,0,0},op_de2={0,0,0,0,0,0};
963 int blen=ogg2_buffer_length(og.header)+ogg2_buffer_length(og.body);
964 char *buf=ogg2_sync_bufferin(oy,blen);
965 bufcpy(buf,og.header);
966 bufcpy(buf+ogg2_buffer_length(og.header),og.body);
967 ogg2_sync_wrote(oy,blen);
969 while(ogg2_sync_pageout(oy,&og_de)>0){
970 /* got a page. Happy happy. Verify that it's good. */
972 check_page(data+deptr,headers[pageout],&og_de);
973 deptr+=ogg2_buffer_length(og_de.body);
974 pageout++;
976 /* submit it to deconstitution */
977 ogg2_stream_pagein(os_de,&og_de);
979 /* packets out? */
980 while(ogg2_stream_packetpeek(os_de,NULL)>0){
981 ogg2_stream_packetpeek(os_de,&op_de2);
982 ogg2_stream_packetout(os_de,&op_de); /* just catching them all */
984 /* verify the packets! */
985 /* check data */
986 if(bufcmp(data+depacket,op_de.packet)){
987 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
988 depacket);
989 exit(1);
991 if(bufcmp(data+depacket,op_de2.packet)){
992 fprintf(stderr,"packet data mismatch in peek! pos=%ld\n",
993 depacket);
994 exit(1);
996 /* check bos flag */
997 if(bosflag==0 && op_de.b_o_s==0){
998 fprintf(stderr,"b_o_s flag not set on packet!\n");
999 exit(1);
1001 if(bosflag==0 && op_de2.b_o_s==0){
1002 fprintf(stderr,"b_o_s flag not set on peek!\n");
1003 exit(1);
1005 if(bosflag && op_de.b_o_s){
1006 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1007 exit(1);
1009 if(bosflag && op_de2.b_o_s){
1010 fprintf(stderr,"b_o_s flag incorrectly set on peek!\n");
1011 exit(1);
1013 bosflag=1;
1014 depacket+=ogg2_buffer_length(op_de.packet);
1016 /* check eos flag */
1017 if(eosflag){
1018 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1019 exit(1);
1022 if(op_de.e_o_s)eosflag=1;
1023 if(op_de.e_o_s!=op_de2.e_o_s){
1024 fprintf(stderr,"packet/peek eosflag mismatch!\n");
1025 exit(1);
1027 /* check granulepos flag */
1028 if(op_de.granulepos!=-1){
1029 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1031 if(op_de.granulepos!=op_de2.granulepos){
1032 fprintf(stderr,"packet/peek granpos mismatch!\n");
1033 exit(1);
1036 ogg2_packet_release(&op_de);
1037 ogg2_packet_release(&op_de2);
1041 ogg2_page_release(&og);
1045 _ogg_free(data);
1046 if(headers[pageno]!=NULL){
1047 fprintf(stderr,"did not write last page!\n");
1048 exit(1);
1050 if(headers[pageout]!=NULL){
1051 fprintf(stderr,"did not decode last page!\n");
1052 exit(1);
1054 if(inptr!=outptr){
1055 fprintf(stderr,"encoded page data incomplete!\n");
1056 exit(1);
1058 if(inptr!=deptr){
1059 fprintf(stderr,"decoded page data incomplete!\n");
1060 exit(1);
1062 if(inptr!=depacket){
1063 fprintf(stderr,"decoded packet data incomplete!\n");
1064 exit(1);
1066 if(!eosflag){
1067 fprintf(stderr,"Never got a packet with EOS set!\n");
1068 exit(1);
1070 fprintf(stderr,"ok.\n");
1072 ogg2_stream_reset(os_en);
1073 ogg2_stream_reset(os_de);
1074 ogg2_sync_reset(oy);
1078 int main(void){
1080 os_en=ogg2_stream_create(0x04030201);
1081 os_de=ogg2_stream_create(0x04030201);
1082 oy=ogg2_sync_create();
1083 bs=ogg2_buffer_create();
1085 /* Exercise each code path in the framing code. Also verify that
1086 the checksums are working. */
1089 /* 17 only */
1090 const int packets[]={17, -1};
1091 const int *headret[]={head1_0,NULL};
1093 fprintf(stderr,"testing single page encoding... ");
1094 test_pack(packets,headret);
1098 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1099 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1100 const int *headret[]={head1_1,head2_1,NULL};
1102 fprintf(stderr,"testing basic page encoding... ");
1103 test_pack(packets,headret);
1107 /* nil packets; beginning,middle,end */
1108 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1109 const int *headret[]={head1_2,head2_2,NULL};
1111 fprintf(stderr,"testing basic nil packets... ");
1112 test_pack(packets,headret);
1116 /* large initial packet */
1117 const int packets[]={4345,259,255,-1};
1118 const int *headret[]={head1_3,head2_3,NULL};
1120 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1121 test_pack(packets,headret);
1125 /* continuing packet test */
1126 const int packets[]={0,4345,259,255,-1};
1127 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1129 fprintf(stderr,"testing single packet page span... ");
1130 test_pack(packets,headret);
1133 /* page with the 255 segment limit */
1136 const int packets[]={0,10,10,10,10,10,10,10,10,
1137 10,10,10,10,10,10,10,10,
1138 10,10,10,10,10,10,10,10,
1139 10,10,10,10,10,10,10,10,
1140 10,10,10,10,10,10,10,10,
1141 10,10,10,10,10,10,10,10,
1142 10,10,10,10,10,10,10,10,
1143 10,10,10,10,10,10,10,10,
1144 10,10,10,10,10,10,10,10,
1145 10,10,10,10,10,10,10,10,
1146 10,10,10,10,10,10,10,10,
1147 10,10,10,10,10,10,10,10,
1148 10,10,10,10,10,10,10,10,
1149 10,10,10,10,10,10,10,10,
1150 10,10,10,10,10,10,10,10,
1151 10,10,10,10,10,10,10,10,
1152 10,10,10,10,10,10,10,10,
1153 10,10,10,10,10,10,10,10,
1154 10,10,10,10,10,10,10,10,
1155 10,10,10,10,10,10,10,10,
1156 10,10,10,10,10,10,10,10,
1157 10,10,10,10,10,10,10,10,
1158 10,10,10,10,10,10,10,10,
1159 10,10,10,10,10,10,10,10,
1160 10,10,10,10,10,10,10,10,
1161 10,10,10,10,10,10,10,10,
1162 10,10,10,10,10,10,10,10,
1163 10,10,10,10,10,10,10,10,
1164 10,10,10,10,10,10,10,10,
1165 10,10,10,10,10,10,10,10,
1166 10,10,10,10,10,10,10,10,
1167 10,10,10,10,10,10,10,50,-1};
1168 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1170 fprintf(stderr,"testing max packet segments... ");
1171 test_pack(packets,headret);
1175 /* packet that overspans over an entire page */
1176 const int packets[]={0,100,9000,259,255,-1};
1177 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1179 fprintf(stderr,"testing very large packets... ");
1180 test_pack(packets,headret);
1184 /* term only page. why not? */
1185 const int packets[]={0,100,4080,-1};
1186 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1188 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1189 test_pack(packets,headret);
1195 /* build a bunch of pages for testing */
1196 unsigned char *data=_ogg_malloc(1024*1024);
1197 int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
1198 int inptr=0,i,j;
1199 ogg2_page og[5];
1200 memset(og,0,sizeof(og));
1202 ogg2_stream_reset(os_en);
1204 for(i=0;pl[i]!=-1;i++){
1205 ogg2_packet op;
1206 int len=pl[i];
1208 op.packet=ogg2_buffer_alloc(bs,len);
1209 op.e_o_s=(pl[i+1]<0?1:0);
1210 op.granulepos=(i+1)*1000;
1212 for(j=0;j<len;j++)data[inptr+j]=i+j;
1213 memcpy(op.packet->buffer->data,data+inptr,len);
1214 op.packet->length=len;
1216 ogg2_stream_packetin(os_en,&op);
1217 inptr+=j;
1220 _ogg_free(data);
1222 /* retrieve finished pages */
1223 for(i=0;i<5;i++){
1224 if(ogg2_stream_pageout(os_en,&og[i])==0){
1225 fprintf(stderr,"Too few pages output building sync tests!\n");
1226 exit(1);
1230 ogg2_page temp;
1231 if(ogg2_stream_pageout(os_en,&temp)>0){
1232 fprintf(stderr,"Too many pages output building sync tests!\n");
1233 exit(1);
1237 /* Test lost pages on pagein/packetout: no rollback */
1239 ogg2_page temp={0,0,0,0};
1240 ogg2_packet test={0,0,0,0,0,0};
1242 fprintf(stderr,"Testing loss of pages... ");
1244 ogg2_sync_reset(oy);
1245 ogg2_stream_reset(os_de);
1246 for(i=0;i<5;i++){
1247 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[i].header)),
1248 og[i].header);
1249 ogg2_sync_wrote(oy,ogg2_buffer_length(og[i].header));
1250 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[i].body)),
1251 og[i].body);
1252 ogg2_sync_wrote(oy,ogg2_buffer_length(og[i].body));
1255 ogg2_sync_pageout(oy,&temp);
1256 ogg2_stream_pagein(os_de,&temp);
1257 ogg2_sync_pageout(oy,&temp);
1258 ogg2_stream_pagein(os_de,&temp);
1259 ogg2_sync_pageout(oy,&temp);
1260 ogg2_page_release(&temp);/* skip */
1261 ogg2_sync_pageout(oy,&temp);
1262 ogg2_stream_pagein(os_de,&temp);
1264 /* do we get the expected results/packets? */
1266 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1267 checkpacket(&test,0,0,0);
1268 ogg2_packet_release(&test);
1269 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1270 checkpacket(&test,100,1,-1);
1271 ogg2_packet_release(&test);
1272 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1273 checkpacket(&test,4079,2,3000);
1274 ogg2_packet_release(&test);
1275 if(ogg2_stream_packetout(os_de,&test)!=OGG2_HOLE){
1276 fprintf(stderr,"Error: loss of page did not return error\n");
1277 exit(1);
1279 ogg2_packet_release(&test);
1280 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1281 checkpacket(&test,76,5,-1);
1282 ogg2_packet_release(&test);
1283 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1284 checkpacket(&test,34,6,-1);
1285 ogg2_packet_release(&test);
1286 fprintf(stderr,"ok.\n");
1289 /* Test lost pages on pagein/packetout: rollback with continuation */
1291 ogg2_page temp={0,0,0,0};
1292 ogg2_packet test={0,0,0,0,0,0};
1294 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1296 ogg2_sync_reset(oy);
1297 ogg2_stream_reset(os_de);
1298 for(i=0;i<5;i++){
1299 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[i].header)),
1300 og[i].header);
1301 ogg2_sync_wrote(oy,ogg2_buffer_length(og[i].header));
1302 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[i].body)),
1303 og[i].body);
1304 ogg2_sync_wrote(oy,ogg2_buffer_length(og[i].body));
1307 ogg2_sync_pageout(oy,&temp);
1308 ogg2_stream_pagein(os_de,&temp);
1309 ogg2_sync_pageout(oy,&temp);
1310 ogg2_stream_pagein(os_de,&temp);
1311 ogg2_sync_pageout(oy,&temp);
1312 ogg2_stream_pagein(os_de,&temp);
1313 ogg2_sync_pageout(oy,&temp);
1314 ogg2_page_release(&temp);/* skip */
1315 ogg2_sync_pageout(oy,&temp);
1316 ogg2_stream_pagein(os_de,&temp);
1318 /* do we get the expected results/packets? */
1320 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1321 checkpacket(&test,0,0,0);
1322 ogg2_packet_release(&test);
1323 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1324 checkpacket(&test,100,1,-1);
1325 ogg2_packet_release(&test);
1326 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1327 checkpacket(&test,4079,2,3000);
1328 ogg2_packet_release(&test);
1329 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1330 checkpacket(&test,2956,3,4000);
1331 ogg2_packet_release(&test);
1332 if(ogg2_stream_packetout(os_de,&test)!=OGG2_HOLE){
1333 fprintf(stderr,"Error: loss of page did not return error\n");
1334 exit(1);
1336 ogg2_packet_release(&test);
1337 if(ogg2_stream_packetout(os_de,&test)!=1)error();
1338 checkpacket(&test,300,13,14000);
1339 ogg2_packet_release(&test);
1340 fprintf(stderr,"ok.\n");
1343 /* the rest only test sync */
1345 ogg2_page og_de={0,0,0,0};
1346 /* Test fractional page inputs: incomplete capture */
1347 fprintf(stderr,"Testing sync on partial inputs... ");
1348 ogg2_sync_reset(oy);
1349 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header);
1350 ogg2_sync_wrote(oy,3);
1351 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1352 ogg2_page_release(&og_de);
1354 /* Test fractional page inputs: incomplete fixed header */
1355 bufcpy2(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header,3);
1356 ogg2_sync_wrote(oy,20);
1357 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1358 ogg2_page_release(&og_de);
1360 /* Test fractional page inputs: incomplete header */
1361 bufcpy2(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header,23);
1362 ogg2_sync_wrote(oy,5);
1363 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1364 ogg2_page_release(&og_de);
1366 /* Test fractional page inputs: incomplete body */
1368 bufcpy2(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header,28);
1369 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].header)-28);
1370 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1371 ogg2_page_release(&og_de);
1373 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].body)),og[1].body);
1374 ogg2_sync_wrote(oy,1000);
1375 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1376 ogg2_page_release(&og_de);
1378 bufcpy2(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].body)),og[1].body,1000);
1379 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].body)-1000);
1380 if(ogg2_sync_pageout(oy,&og_de)<=0)error();
1381 ogg2_page_release(&og_de);
1383 fprintf(stderr,"ok.\n");
1386 /* Test fractional page inputs: page + incomplete capture */
1388 ogg2_page og_de={0,0,0,0};
1389 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1390 ogg2_sync_reset(oy);
1392 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header);
1393 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].header));
1395 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].body)),og[1].body);
1396 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].body));
1398 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header);
1399 ogg2_sync_wrote(oy,20);
1400 if(ogg2_sync_pageout(oy,&og_de)<=0)error();
1401 ogg2_page_release(&og_de);
1402 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1403 ogg2_page_release(&og_de);
1405 bufcpy2(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header,20);
1406 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].header)-20);
1408 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].body)),og[1].body);
1409 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].body));
1411 if(ogg2_sync_pageout(oy,&og_de)<=0)error();
1412 ogg2_page_release(&og_de);
1414 fprintf(stderr,"ok.\n");
1417 /* Test recapture: garbage + page */
1419 ogg2_page og_de={0,0,0,0};
1420 fprintf(stderr,"Testing search for capture... ");
1421 ogg2_sync_reset(oy);
1423 /* 'garbage' */
1424 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].body)),og[1].body);
1425 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].body));
1427 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header);
1428 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].header));
1430 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].body)),og[1].body);
1431 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].body));
1433 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[2].header)),og[2].header);
1434 ogg2_sync_wrote(oy,20);
1436 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1437 ogg2_page_release(&og_de);
1438 if(ogg2_sync_pageout(oy,&og_de)<=0)error();
1439 ogg2_page_release(&og_de);
1440 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1441 ogg2_page_release(&og_de);
1443 bufcpy2(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[2].header)),og[2].header,20);
1444 ogg2_sync_wrote(oy,ogg2_buffer_length(og[2].header)-20);
1446 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[2].body)),og[2].body);
1447 ogg2_sync_wrote(oy,ogg2_buffer_length(og[2].body));
1448 if(ogg2_sync_pageout(oy,&og_de)<=0)error();
1449 ogg2_page_release(&og_de);
1451 fprintf(stderr,"ok.\n");
1454 /* Test recapture: page + garbage + page */
1456 ogg2_page og_de={0,0,0,0};
1457 fprintf(stderr,"Testing recapture... ");
1458 ogg2_sync_reset(oy);
1460 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].header)),og[1].header);
1461 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].header));
1463 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[1].body)),og[1].body);
1464 ogg2_sync_wrote(oy,ogg2_buffer_length(og[1].body));
1466 /* garbage */
1468 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[2].header)),og[2].header);
1469 ogg2_sync_wrote(oy,ogg2_buffer_length(og[2].header));
1471 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[2].header)),og[2].header);
1472 ogg2_sync_wrote(oy,ogg2_buffer_length(og[2].header));
1474 if(ogg2_sync_pageout(oy,&og_de)<=0)error();
1475 ogg2_page_release(&og_de);
1477 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[2].body)),og[2].body);
1478 ogg2_sync_wrote(oy,ogg2_buffer_length(og[2].body)-5);
1480 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[3].header)),og[3].header);
1481 ogg2_sync_wrote(oy,ogg2_buffer_length(og[3].header));
1483 bufcpy(ogg2_sync_bufferin(oy,ogg2_buffer_length(og[3].body)),og[3].body);
1484 ogg2_sync_wrote(oy,ogg2_buffer_length(og[3].body));
1486 if(ogg2_sync_pageout(oy,&og_de)>0)error();
1487 ogg2_page_release(&og_de);
1488 if(ogg2_sync_pageout(oy,&og_de)<=0)error();
1489 ogg2_page_release(&og_de);
1491 fprintf(stderr,"ok.\n");
1493 ogg2_stream_destroy(os_en);
1494 for(i=0;i<5;i++)
1495 ogg2_page_release(&og[i]);
1498 ogg2_stream_destroy(os_de);
1499 ogg2_sync_destroy(oy);
1501 ogg2_buffer_destroy(bs);
1502 return 0;
1505 #endif