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/ogg.h>
30
31/* A complete description of Ogg framing exists in docs/framing.html */
32
33int ogg_page_version(const ogg_page *og){
34 return((int)(og->header[4]));
35}
36
37int ogg_page_continued(const ogg_page *og){
38 return((int)(og->header[5]&0x01));
39}
40
41int ogg_page_bos(const ogg_page *og){
42 return((int)(og->header[5]&0x02));
43}
44
45int ogg_page_eos(const ogg_page *og){
46 return((int)(og->header[5]&0x04));
47}
48
49ogg_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
62int 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
69long 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
95int 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
107static 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
133int 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=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
140 os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
141 os->granule_vals=_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 */
156int 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 */
162int 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
173int 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
184static 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=ret;
201 }
202 return 0;
203}
204
205static 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=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=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
237static 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
255void 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 */
276int 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
339int 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. */
349static 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
494int 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
502int 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
507returned are to static buffers; do not free. The returned buffers are
508good only until the next call (using the same ogg_stream_state) */
509
510int 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
522page size for applications which are smart enough to provide their
523own delay based flushing */
524
525int 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
536int 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 */
557int 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 */
566int 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
574int 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
582int ogg_sync_check(ogg_sync_state *oy){
583 if(oy->storage<0) return -1;
584 return 0;
585}
586
587char *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;
601 void *ret;
602
603 if(size>INT_MAX-4096-oy->fill){
604 ogg_sync_clear(oy);
605 return NULL;
606 }
607 newsize=size+oy->fill+4096; /* an extra page to be nice */
608 if(oy->data)
609 ret=_ogg_realloc(oy->data,newsize);
610 else
611 ret=_ogg_malloc(newsize);
612 if(!ret){
613 ogg_sync_clear(oy);
614 return NULL;
615 }
616 oy->data=ret;
617 oy->storage=newsize;
618 }
619
620 /* expose a segment at least as large as requested at the fill mark */
621 return((char *)oy->data+oy->fill);
622}
623
624int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
625 if(ogg_sync_check(oy))return -1;
626 if(oy->fill+bytes>oy->storage)return -1;
627 oy->fill+=bytes;
628 return(0);
629}
630
631/* sync the stream. This is meant to be useful for finding page
632 boundaries.
633
634 return values for this:
635 -n) skipped n bytes
636 0) page not ready; more data (no bytes skipped)
637 n) page synced at current location; page length n bytes
638
639*/
640
641long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
642 unsigned char *page=oy->data+oy->returned;
643 unsigned char *next;
644 long bytes=oy->fill-oy->returned;
645
646 if(ogg_sync_check(oy))return 0;
647
648 if(oy->headerbytes==0){
649 int headerbytes,i;
650 if(bytes<27)return(0); /* not enough for a header */
651
652 /* verify capture pattern */
653 if(memcmp(page,"OggS",4))goto sync_fail;
654
655 headerbytes=page[26]+27;
656 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
657
658 /* count up body length in the segment table */
659
660 for(i=0;i<page[26];i++)
661 oy->bodybytes+=page[27+i];
662 oy->headerbytes=headerbytes;
663 }
664
665 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
666
667 /* The whole test page is buffered. Verify the checksum */
668 {
669 /* Grab the checksum bytes, set the header field to zero */
670 char chksum[4];
671 ogg_page log;
672
673 memcpy(chksum,page+22,4);
674 memset(page+22,0,4);
675
676 /* set up a temp page struct and recompute the checksum */
677 log.header=page;
678 log.header_len=oy->headerbytes;
679 log.body=page+oy->headerbytes;
680 log.body_len=oy->bodybytes;
681 ogg_page_checksum_set(&log);
682
683 /* Compare */
684 if(memcmp(chksum,page+22,4)){
685 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
686 at all) */
687 /* replace the computed checksum with the one actually read in */
688 memcpy(page+22,chksum,4);
689
690#ifndef DISABLE_CRC
691 /* Bad checksum. Lose sync */
692 goto sync_fail;
693#endif
694 }
695 }
696
697 /* yes, have a whole page all ready to go */
698 {
699 if(og){
700 og->header=page;
701 og->header_len=oy->headerbytes;
702 og->body=page+oy->headerbytes;
703 og->body_len=oy->bodybytes;
704 }
705
706 oy->unsynced=0;
707 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
708 oy->headerbytes=0;
709 oy->bodybytes=0;
710 return(bytes);
711 }
712
713 sync_fail:
714
715 oy->headerbytes=0;
716 oy->bodybytes=0;
717
718 /* search for possible capture */
719 next=memchr(page+1,'O',bytes-1);
720 if(!next)
721 next=oy->data+oy->fill;
722
723 oy->returned=(int)(next-oy->data);
724 return((long)-(next-page));
725}
726
727/* sync the stream and get a page. Keep trying until we find a page.
728 Suppress 'sync errors' after reporting the first.
729
730 return values:
731 -1) recapture (hole in data)
732 0) need more data
733 1) page returned
734
735 Returns pointers into buffered data; invalidated by next call to
736 _stream, _clear, _init, or _buffer */
737
738int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
739
740 if(ogg_sync_check(oy))return 0;
741
742 /* all we need to do is verify a page at the head of the stream
743 buffer. If it doesn't verify, we look for the next potential
744 frame */
745
746 for(;;){
747 long ret=ogg_sync_pageseek(oy,og);
748 if(ret>0){
749 /* have a page */
750 return(1);
751 }
752 if(ret==0){
753 /* need more data */
754 return(0);
755 }
756
757 /* head did not start a synced page... skipped some bytes */
758 if(!oy->unsynced){
759 oy->unsynced=1;
760 return(-1);
761 }
762
763 /* loop. keep looking */
764
765 }
766}
767
768/* add the incoming page to the stream state; we decompose the page
769 into packet segments here as well. */
770
771int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
772 unsigned char *header=og->header;
773 unsigned char *body=og->body;
774 long bodysize=og->body_len;
775 int segptr=0;
776
777 int version=ogg_page_version(og);
778 int continued=ogg_page_continued(og);
779 int bos=ogg_page_bos(og);
780 int eos=ogg_page_eos(og);
781 ogg_int64_t granulepos=ogg_page_granulepos(og);
782 int serialno=ogg_page_serialno(og);
783 long pageno=ogg_page_pageno(og);
784 int segments=header[26];
785
786 if(ogg_stream_check(os)) return -1;
787
788 /* clean up 'returned data' */
789 {
790 long lr=os->lacing_returned;
791 long br=os->body_returned;
792
793 /* body data */
794 if(br){
795 os->body_fill-=br;
796 if(os->body_fill)
797 memmove(os->body_data,os->body_data+br,os->body_fill);
798 os->body_returned=0;
799 }
800
801 if(lr){
802 /* segment table */
803 if(os->lacing_fill-lr){
804 memmove(os->lacing_vals,os->lacing_vals+lr,
805 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
806 memmove(os->granule_vals,os->granule_vals+lr,
807 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
808 }
809 os->lacing_fill-=lr;
810 os->lacing_packet-=lr;
811 os->lacing_returned=0;
812 }
813 }
814
815 /* check the serial number */
816 if(serialno!=os->serialno)return(-1);
817 if(version>0)return(-1);
818
819 if(_os_lacing_expand(os,segments+1)) return -1;
820
821 /* are we in sequence? */
822 if(pageno!=os->pageno){
823 int i;
824
825 /* unroll previous partial packet (if any) */
826 for(i=os->lacing_packet;i<os->lacing_fill;i++)
827 os->body_fill-=os->lacing_vals[i]&0xff;
828 os->lacing_fill=os->lacing_packet;
829
830 /* make a note of dropped data in segment table */
831 if(os->pageno!=-1){
832 os->lacing_vals[os->lacing_fill++]=0x400;
833 os->lacing_packet++;
834 }
835 }
836
837 /* are we a 'continued packet' page? If so, we may need to skip
838 some segments */
839 if(continued){
840 if(os->lacing_fill<1 ||
841 (os->lacing_vals[os->lacing_fill-1]&0xff)<255 ||
842 os->lacing_vals[os->lacing_fill-1]==0x400){
843 bos=0;
844 for(;segptr<segments;segptr++){
845 int val=header[27+segptr];
846 body+=val;
847 bodysize-=val;
848 if(val<255){
849 segptr++;
850 break;
851 }
852 }
853 }
854 }
855
856 if(bodysize){
857 if(_os_body_expand(os,bodysize)) return -1;
858 memcpy(os->body_data+os->body_fill,body,bodysize);
859 os->body_fill+=bodysize;
860 }
861
862 {
863 int saved=-1;
864 while(segptr<segments){
865 int val=header[27+segptr];
866 os->lacing_vals[os->lacing_fill]=val;
867 os->granule_vals[os->lacing_fill]=-1;
868
869 if(bos){
870 os->lacing_vals[os->lacing_fill]|=0x100;
871 bos=0;
872 }
873
874 if(val<255)saved=os->lacing_fill;
875
876 os->lacing_fill++;
877 segptr++;
878
879 if(val<255)os->lacing_packet=os->lacing_fill;
880 }
881
882 /* set the granulepos on the last granuleval of the last full packet */
883 if(saved!=-1){
884 os->granule_vals[saved]=granulepos;
885 }
886
887 }
888
889 if(eos){
890 os->e_o_s=1;
891 if(os->lacing_fill>0)
892 os->lacing_vals[os->lacing_fill-1]|=0x200;
893 }
894
895 os->pageno=pageno+1;
896
897 return(0);
898}
899
900/* clear things to an initial state. Good to call, eg, before seeking */
901int ogg_sync_reset(ogg_sync_state *oy){
902 if(ogg_sync_check(oy))return -1;
903
904 oy->fill=0;
905 oy->returned=0;
906 oy->unsynced=0;
907 oy->headerbytes=0;
908 oy->bodybytes=0;
909 return(0);
910}
911
912int ogg_stream_reset(ogg_stream_state *os){
913 if(ogg_stream_check(os)) return -1;
914
915 os->body_fill=0;
916 os->body_returned=0;
917
918 os->lacing_fill=0;
919 os->lacing_packet=0;
920 os->lacing_returned=0;
921
922 os->header_fill=0;
923
924 os->e_o_s=0;
925 os->b_o_s=0;
926 os->pageno=-1;
927 os->packetno=0;
928 os->granulepos=0;
929
930 return(0);
931}
932
933int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
934 if(ogg_stream_check(os)) return -1;
935 ogg_stream_reset(os);
936 os->serialno=serialno;
937 return(0);
938}
939
940static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
941
942 /* The last part of decode. We have the stream broken into packet
943 segments. Now we need to group them into packets (or return the
944 out of sync markers) */
945
946 int ptr=os->lacing_returned;
947
948 if(os->lacing_packet<=ptr)return(0);
949
950 if(os->lacing_vals[ptr]&0x400){
951 /* we need to tell the codec there's a gap; it might need to
952 handle previous packet dependencies. */
953 os->lacing_returned++;
954 os->packetno++;
955 return(-1);
956 }
957
958 if(!op && !adv)return(1); /* just using peek as an inexpensive way
959 to ask if there's a whole packet
960 waiting */
961
962 /* Gather the whole packet. We'll have no holes or a partial packet */
963 {
964 int size=os->lacing_vals[ptr]&0xff;
965 long bytes=size;
966 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
967 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
968
969 while(size==255){
970 int val=os->lacing_vals[++ptr];
971 size=val&0xff;
972 if(val&0x200)eos=0x200;
973 bytes+=size;
974 }
975
976 if(op){
977 op->e_o_s=eos;
978 op->b_o_s=bos;
979 op->packet=os->body_data+os->body_returned;
980 op->packetno=os->packetno;
981 op->granulepos=os->granule_vals[ptr];
982 op->bytes=bytes;
983 }
984
985 if(adv){
986 os->body_returned+=bytes;
987 os->lacing_returned=ptr+1;
988 os->packetno++;
989 }
990 }
991 return(1);
992}
993
994int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
995 if(ogg_stream_check(os)) return 0;
996 return _packetout(os,op,1);
997}
998
999int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
1000 if(ogg_stream_check(os)) return 0;
1001 return _packetout(os,op,0);
1002}
1003
1004void ogg_packet_clear(ogg_packet *op) {
1005 _ogg_free(op->packet);
1006 memset(op, 0, sizeof(*op));
1007}
1008
1009#ifdef _V_SELFTEST
1010#include <stdio.h>
1011
1012ogg_stream_state os_en, os_de;
1013ogg_sync_state oy;
1014
1015void checkpacket(ogg_packet *op,long len, int no, long pos){
1016 long j;
1017 static int sequence=0;
1018 static int lastno=0;
1019
1020 if(op->bytes!=len){
1021 fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
1022 exit(1);
1023 }
1024 if(op->granulepos!=pos){
1025 fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1026 exit(1);
1027 }
1028
1029 /* packet number just follows sequence/gap; adjust the input number
1030 for that */
1031 if(no==0){
1032 sequence=0;
1033 }else{
1034 sequence++;
1035 if(no>lastno+1)
1036 sequence++;
1037 }
1038 lastno=no;
1039 if(op->packetno!=sequence){
1040 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1041 (long)(op->packetno),sequence);
1042 exit(1);
1043 }
1044
1045 /* Test data */
1046 for(j=0;j<op->bytes;j++)
1047 if(op->packet[j]!=((j+no)&0xff)){
1048 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1049 j,op->packet[j],(j+no)&0xff);
1050 exit(1);
1051 }
1052}
1053
1054void check_page(unsigned char *data,const int *header,ogg_page *og){
1055 long j;
1056 /* Test data */
1057 for(j=0;j<og->body_len;j++)
1058 if(og->body[j]!=data[j]){
1059 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1060 j,data[j],og->body[j]);
1061 exit(1);
1062 }
1063
1064 /* Test header */
1065 for(j=0;j<og->header_len;j++){
1066 if(og->header[j]!=header[j]){
1067 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1068 for(j=0;j<header[26]+27;j++)
1069 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1070 fprintf(stderr,"\n");
1071 exit(1);
1072 }
1073 }
1074 if(og->header_len!=header[26]+27){
1075 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1076 og->header_len,header[26]+27);
1077 exit(1);
1078 }
1079}
1080
1081void print_header(ogg_page *og){
1082 int j;
1083 fprintf(stderr,"\nHEADER:\n");
1084 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
1085 og->header[0],og->header[1],og->header[2],og->header[3],
1086 (int)og->header[4],(int)og->header[5]);
1087
1088 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
1089 (og->header[9]<<24)|(og->header[8]<<16)|
1090 (og->header[7]<<8)|og->header[6],
1091 (og->header[17]<<24)|(og->header[16]<<16)|
1092 (og->header[15]<<8)|og->header[14],
1093 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1094 (og->header[19]<<8)|og->header[18]);
1095
1096 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
1097 (int)og->header[22],(int)og->header[23],
1098 (int)og->header[24],(int)og->header[25],
1099 (int)og->header[26]);
1100
1101 for(j=27;j<og->header_len;j++)
1102 fprintf(stderr,"%d ",(int)og->header[j]);
1103 fprintf(stderr,")\n\n");
1104}
1105
1106void copy_page(ogg_page *og){
1107 unsigned char *temp=_ogg_malloc(og->header_len);
1108 memcpy(temp,og->header,og->header_len);
1109 og->header=temp;
1110
1111 temp=_ogg_malloc(og->body_len);
1112 memcpy(temp,og->body,og->body_len);
1113 og->body=temp;
1114}
1115
1116void free_page(ogg_page *og){
1117 _ogg_free (og->header);
1118 _ogg_free (og->body);
1119}
1120
1121void error(void){
1122 fprintf(stderr,"error!\n");
1123 exit(1);
1124}
1125
1126/* 17 only */
1127const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1128 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1129 0x01,0x02,0x03,0x04,0,0,0,0,
1130 0x15,0xed,0xec,0x91,
1131 1,
1132 17};
1133
1134/* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1135const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1136 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1137 0x01,0x02,0x03,0x04,0,0,0,0,
1138 0x59,0x10,0x6c,0x2c,
1139 1,
1140 17};
1141const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1142 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1143 0x01,0x02,0x03,0x04,1,0,0,0,
1144 0x89,0x33,0x85,0xce,
1145 13,
1146 254,255,0,255,1,255,245,255,255,0,
1147 255,255,90};
1148
1149/* nil packets; beginning,middle,end */
1150const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1151 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1152 0x01,0x02,0x03,0x04,0,0,0,0,
1153 0xff,0x7b,0x23,0x17,
1154 1,
1155 0};
1156const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1157 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1158 0x01,0x02,0x03,0x04,1,0,0,0,
1159 0x5c,0x3f,0x66,0xcb,
1160 17,
1161 17,254,255,0,0,255,1,0,255,245,255,255,0,
1162 255,255,90,0};
1163
1164/* large initial packet */
1165const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1166 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1167 0x01,0x02,0x03,0x04,0,0,0,0,
1168 0x01,0x27,0x31,0xaa,
1169 18,
1170 255,255,255,255,255,255,255,255,
1171 255,255,255,255,255,255,255,255,255,10};
1172
1173const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1174 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1175 0x01,0x02,0x03,0x04,1,0,0,0,
1176 0x7f,0x4e,0x8a,0xd2,
1177 4,
1178 255,4,255,0};
1179
1180
1181/* continuing packet test */
1182const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1183 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1184 0x01,0x02,0x03,0x04,0,0,0,0,
1185 0xff,0x7b,0x23,0x17,
1186 1,
1187 0};
1188
1189const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1190 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1191 0x01,0x02,0x03,0x04,1,0,0,0,
1192 0xf8,0x3c,0x19,0x79,
1193 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,255,
1221 255,255,255,255,255,255,255,255,
1222 255,255,255,255,255,255,255,255,
1223 255,255,255,255,255,255,255,255,
1224 255,255,255,255,255,255,255,255,
1225 255,255,255,255,255,255,255};
1226
1227const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1228 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1229 0x01,0x02,0x03,0x04,2,0,0,0,
1230 0x38,0xe6,0xb6,0x28,
1231 6,
1232 255,220,255,4,255,0};
1233
1234
1235/* spill expansion test */
1236const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1237 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1238 0x01,0x02,0x03,0x04,0,0,0,0,
1239 0xff,0x7b,0x23,0x17,
1240 1,
1241 0};
1242
1243const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1244 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1245 0x01,0x02,0x03,0x04,1,0,0,0,
1246 0xce,0x8f,0x17,0x1a,
1247 23,
1248 255,255,255,255,255,255,255,255,
1249 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1250
1251
1252const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1253 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1254 0x01,0x02,0x03,0x04,2,0,0,0,
1255 0x9b,0xb2,0x50,0xa1,
1256 1,
1257 0};
1258
1259/* page with the 255 segment limit */
1260const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1261 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1262 0x01,0x02,0x03,0x04,0,0,0,0,
1263 0xff,0x7b,0x23,0x17,
1264 1,
1265 0};
1266
1267const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1268 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1269 0x01,0x02,0x03,0x04,1,0,0,0,
1270 0xed,0x2a,0x2e,0xa7,
1271 255,
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,10,
1299 10,10,10,10,10,10,10,10,
1300 10,10,10,10,10,10,10,10,
1301 10,10,10,10,10,10,10,10,
1302 10,10,10,10,10,10,10,10,
1303 10,10,10,10,10,10,10};
1304
1305const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1306 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1307 0x01,0x02,0x03,0x04,2,0,0,0,
1308 0x6c,0x3b,0x82,0x3d,
1309 1,
1310 50};
1311
1312
1313/* packet that overspans over an entire page */
1314const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1315 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1316 0x01,0x02,0x03,0x04,0,0,0,0,
1317 0xff,0x7b,0x23,0x17,
1318 1,
1319 0};
1320
1321const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1322 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1323 0x01,0x02,0x03,0x04,1,0,0,0,
1324 0x68,0x22,0x7c,0x3d,
1325 255,
1326 100,
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,255,255,
1354 255,255,255,255,255,255,255,255,
1355 255,255,255,255,255,255,255,255,
1356 255,255,255,255,255,255,255,255,
1357 255,255,255,255,255,255,255,255,
1358 255,255,255,255,255,255};
1359
1360const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1361 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1362 0x01,0x02,0x03,0x04,2,0,0,0,
1363 0xf4,0x87,0xba,0xf3,
1364 255,
1365 255,255,255,255,255,255,255,255,
1366 255,255,255,255,255,255,255,255,
1367 255,255,255,255,255,255,255,255,
1368 255,255,255,255,255,255,255,255,
1369 255,255,255,255,255,255,255,255,
1370 255,255,255,255,255,255,255,255,
1371 255,255,255,255,255,255,255,255,
1372 255,255,255,255,255,255,255,255,
1373 255,255,255,255,255,255,255,255,
1374 255,255,255,255,255,255,255,255,
1375 255,255,255,255,255,255,255,255,
1376 255,255,255,255,255,255,255,255,
1377 255,255,255,255,255,255,255,255,
1378 255,255,255,255,255,255,255,255,
1379 255,255,255,255,255,255,255,255,
1380 255,255,255,255,255,255,255,255,
1381 255,255,255,255,255,255,255,255,
1382 255,255,255,255,255,255,255,255,
1383 255,255,255,255,255,255,255,255,
1384 255,255,255,255,255,255,255,255,
1385 255,255,255,255,255,255,255,255,
1386 255,255,255,255,255,255,255,255,
1387 255,255,255,255,255,255,255,255,
1388 255,255,255,255,255,255,255,255,
1389 255,255,255,255,255,255,255,255,
1390 255,255,255,255,255,255,255,255,
1391 255,255,255,255,255,255,255,255,
1392 255,255,255,255,255,255,255,255,
1393 255,255,255,255,255,255,255,255,
1394 255,255,255,255,255,255,255,255,
1395 255,255,255,255,255,255,255,255,
1396 255,255,255,255,255,255,255};
1397
1398const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1399 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1400 0x01,0x02,0x03,0x04,3,0,0,0,
1401 0xf7,0x2f,0x6c,0x60,
1402 5,
1403 254,255,4,255,0};
1404
1405/* packet that overspans over an entire page */
1406const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1407 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1408 0x01,0x02,0x03,0x04,0,0,0,0,
1409 0xff,0x7b,0x23,0x17,
1410 1,
1411 0};
1412
1413const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1414 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1415 0x01,0x02,0x03,0x04,1,0,0,0,
1416 0x68,0x22,0x7c,0x3d,
1417 255,
1418 100,
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,255,255,
1446 255,255,255,255,255,255,255,255,
1447 255,255,255,255,255,255,255,255,
1448 255,255,255,255,255,255,255,255,
1449 255,255,255,255,255,255,255,255,
1450 255,255,255,255,255,255};
1451
1452const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1453 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1454 0x01,0x02,0x03,0x04,2,0,0,0,
1455 0xd4,0xe0,0x60,0xe5,
1456 1,
1457 0};
1458
1459int compare_packet(const ogg_packet *op1, const ogg_packet *op2){
1460 if(op1->packet!=op2->packet){
1461 fprintf(stderr,"op1->packet != op2->packet\n");
1462 return(1);
1463 }
1464 if(op1->bytes!=op2->bytes){
1465 fprintf(stderr,"op1->bytes != op2->bytes\n");
1466 return(1);
1467 }
1468 if(op1->b_o_s!=op2->b_o_s){
1469 fprintf(stderr,"op1->b_o_s != op2->b_o_s\n");
1470 return(1);
1471 }
1472 if(op1->e_o_s!=op2->e_o_s){
1473 fprintf(stderr,"op1->e_o_s != op2->e_o_s\n");
1474 return(1);
1475 }
1476 if(op1->granulepos!=op2->granulepos){
1477 fprintf(stderr,"op1->granulepos != op2->granulepos\n");
1478 return(1);
1479 }
1480 if(op1->packetno!=op2->packetno){
1481 fprintf(stderr,"op1->packetno != op2->packetno\n");
1482 return(1);
1483 }
1484 return(0);
1485}
1486
1487void test_pack(const int *pl, const int **headers, int byteskip,
1488 int pageskip, int packetskip){
1489 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1490 long inptr=0;
1491 long outptr=0;
1492 long deptr=0;
1493 long depacket=0;
1494 long granule_pos=7,pageno=0;
1495 int i,j,packets,pageout=pageskip;
1496 int eosflag=0;
1497 int bosflag=0;
1498
1499 int byteskipcount=0;
1500
1501 ogg_stream_reset(&os_en);
1502 ogg_stream_reset(&os_de);
1503 ogg_sync_reset(&oy);
1504
1505 for(packets=0;packets<packetskip;packets++)
1506 depacket+=pl[packets];
1507
1508 for(packets=0;;packets++)if(pl[packets]==-1)break;
1509
1510 for(i=0;i<packets;i++){
1511 /* construct a test packet */
1512 ogg_packet op;
1513 int len=pl[i];
1514
1515 op.packet=data+inptr;
1516 op.bytes=len;
1517 op.e_o_s=(pl[i+1]<0?1:0);
1518 op.granulepos=granule_pos;
1519
1520 granule_pos+=1024;
1521
1522 for(j=0;j<len;j++)data[inptr++]=i+j;
1523
1524 /* submit the test packet */
1525 ogg_stream_packetin(&os_en,&op);
1526
1527 /* retrieve any finished pages */
1528 {
1529 ogg_page og;
1530
1531 while(ogg_stream_pageout(&os_en,&og)){
1532 /* We have a page. Check it carefully */
1533
1534 fprintf(stderr,"%ld, ",pageno);
1535
1536 if(headers[pageno]==NULL){
1537 fprintf(stderr,"coded too many pages!\n");
1538 exit(1);
1539 }
1540
1541 check_page(data+outptr,headers[pageno],&og);
1542
1543 outptr+=og.body_len;
1544 pageno++;
1545 if(pageskip){
1546 bosflag=1;
1547 pageskip--;
1548 deptr+=og.body_len;
1549 }
1550
1551 /* have a complete page; submit it to sync/decode */
1552
1553 {
1554 ogg_page og_de;
1555 ogg_packet op_de,op_de2;
1556 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1557 char *next=buf;
1558 byteskipcount+=og.header_len;
1559 if(byteskipcount>byteskip){
1560 memcpy(next,og.header,byteskipcount-byteskip);
1561 next+=byteskipcount-byteskip;
1562 byteskipcount=byteskip;
1563 }
1564
1565 byteskipcount+=og.body_len;
1566 if(byteskipcount>byteskip){
1567 memcpy(next,og.body,byteskipcount-byteskip);
1568 next+=byteskipcount-byteskip;
1569 byteskipcount=byteskip;
1570 }
1571
1572 ogg_sync_wrote(&oy,(long)(next-buf));
1573
1574 while(1){
1575 int ret=ogg_sync_pageout(&oy,&og_de);
1576 if(ret==0)break;
1577 if(ret<0)continue;
1578 /* got a page. Happy happy. Verify that it's good. */
1579
1580 fprintf(stderr,"(%d), ",pageout);
1581
1582 check_page(data+deptr,headers[pageout],&og_de);
1583 deptr+=og_de.body_len;
1584 pageout++;
1585
1586 /* submit it to deconstitution */
1587 ogg_stream_pagein(&os_de,&og_de);
1588
1589 /* packets out? */
1590 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1591 ogg_stream_packetpeek(&os_de,NULL);
1592 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1593
1594 /* verify peek and out match */
1595 if(compare_packet(&op_de,&op_de2)){
1596 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1597 depacket);
1598 exit(1);
1599 }
1600
1601 /* verify the packet! */
1602 /* check data */
1603 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1604 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1605 depacket);
1606 exit(1);
1607 }
1608 /* check bos flag */
1609 if(bosflag==0 && op_de.b_o_s==0){
1610 fprintf(stderr,"b_o_s flag not set on packet!\n");
1611 exit(1);
1612 }
1613 if(bosflag && op_de.b_o_s){
1614 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1615 exit(1);
1616 }
1617 bosflag=1;
1618 depacket+=op_de.bytes;
1619
1620 /* check eos flag */
1621 if(eosflag){
1622 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1623 exit(1);
1624 }
1625
1626 if(op_de.e_o_s)eosflag=1;
1627
1628 /* check granulepos flag */
1629 if(op_de.granulepos!=-1){
1630 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1631 }
1632 }
1633 }
1634 }
1635 }
1636 }
1637 }
1638 _ogg_free(data);
1639 if(headers[pageno]!=NULL){
1640 fprintf(stderr,"did not write last page!\n");
1641 exit(1);
1642 }
1643 if(headers[pageout]!=NULL){
1644 fprintf(stderr,"did not decode last page!\n");
1645 exit(1);
1646 }
1647 if(inptr!=outptr){
1648 fprintf(stderr,"encoded page data incomplete!\n");
1649 exit(1);
1650 }
1651 if(inptr!=deptr){
1652 fprintf(stderr,"decoded page data incomplete!\n");
1653 exit(1);
1654 }
1655 if(inptr!=depacket){
1656 fprintf(stderr,"decoded packet data incomplete!\n");
1657 exit(1);
1658 }
1659 if(!eosflag){
1660 fprintf(stderr,"Never got a packet with EOS set!\n");
1661 exit(1);
1662 }
1663 fprintf(stderr,"ok.\n");
1664}
1665
1666int main(void){
1667
1668 ogg_stream_init(&os_en,0x04030201);
1669 ogg_stream_init(&os_de,0x04030201);
1670 ogg_sync_init(&oy);
1671
1672 /* Exercise each code path in the framing code. Also verify that
1673 the checksums are working. */
1674
1675 {
1676 /* 17 only */
1677 const int packets[]={17, -1};
1678 const int *headret[]={head1_0,NULL};
1679
1680 fprintf(stderr,"testing single page encoding... ");
1681 test_pack(packets,headret,0,0,0);
1682 }
1683
1684 {
1685 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1686 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1687 const int *headret[]={head1_1,head2_1,NULL};
1688
1689 fprintf(stderr,"testing basic page encoding... ");
1690 test_pack(packets,headret,0,0,0);
1691 }
1692
1693 {
1694 /* nil packets; beginning,middle,end */
1695 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1696 const int *headret[]={head1_2,head2_2,NULL};
1697
1698 fprintf(stderr,"testing basic nil packets... ");
1699 test_pack(packets,headret,0,0,0);
1700 }
1701
1702 {
1703 /* large initial packet */
1704 const int packets[]={4345,259,255,-1};
1705 const int *headret[]={head1_3,head2_3,NULL};
1706
1707 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1708 test_pack(packets,headret,0,0,0);
1709 }
1710
1711 {
1712 /* continuing packet test; with page spill expansion, we have to
1713 overflow the lacing table. */
1714 const int packets[]={0,65500,259,255,-1};
1715 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1716
1717 fprintf(stderr,"testing single packet page span... ");
1718 test_pack(packets,headret,0,0,0);
1719 }
1720
1721 {
1722 /* spill expand packet test */
1723 const int packets[]={0,4345,259,255,0,0,-1};
1724 const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1725
1726 fprintf(stderr,"testing page spill expansion... ");
1727 test_pack(packets,headret,0,0,0);
1728 }
1729
1730 /* page with the 255 segment limit */
1731 {
1732
1733 const int packets[]={0,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,10,
1760 10,10,10,10,10,10,10,10,
1761 10,10,10,10,10,10,10,10,
1762 10,10,10,10,10,10,10,10,
1763 10,10,10,10,10,10,10,10,
1764 10,10,10,10,10,10,10,50,-1};
1765 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1766
1767 fprintf(stderr,"testing max packet segments... ");
1768 test_pack(packets,headret,0,0,0);
1769 }
1770
1771 {
1772 /* packet that overspans over an entire page */
1773 const int packets[]={0,100,130049,259,255,-1};
1774 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1775
1776 fprintf(stderr,"testing very large packets... ");
1777 test_pack(packets,headret,0,0,0);
1778 }
1779
1780#ifndef DISABLE_CRC
1781 {
1782 /* test for the libogg 1.1.1 resync in large continuation bug
1783 found by Josh Coalson) */
1784 const int packets[]={0,100,130049,259,255,-1};
1785 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1786
1787 fprintf(stderr,"testing continuation resync in very large packets... ");
1788 test_pack(packets,headret,100,2,3);
1789 }
1790#else
1791 fprintf(stderr,"Skipping continuation resync test due to --disable-crc\n");
1792#endif
1793
1794 {
1795 /* term only page. why not? */
1796 const int packets[]={0,100,64770,-1};
1797 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1798
1799 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1800 test_pack(packets,headret,0,0,0);
1801 }
1802
1803
1804
1805 {
1806 /* build a bunch of pages for testing */
1807 unsigned char *data=_ogg_malloc(1024*1024);
1808 int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1809 int inptr=0,i,j;
1810 ogg_page og[5];
1811
1812 ogg_stream_reset(&os_en);
1813
1814 for(i=0;pl[i]!=-1;i++){
1815 ogg_packet op;
1816 int len=pl[i];
1817
1818 op.packet=data+inptr;
1819 op.bytes=len;
1820 op.e_o_s=(pl[i+1]<0?1:0);
1821 op.granulepos=(i+1)*1000;
1822
1823 for(j=0;j<len;j++)data[inptr++]=i+j;
1824 ogg_stream_packetin(&os_en,&op);
1825 }
1826
1827 _ogg_free(data);
1828
1829 /* retrieve finished pages */
1830 for(i=0;i<5;i++){
1831 if(ogg_stream_pageout(&os_en,&og[i])==0){
1832 fprintf(stderr,"Too few pages output building sync tests!\n");
1833 exit(1);
1834 }
1835 copy_page(&og[i]);
1836 }
1837
1838 /* Test lost pages on pagein/packetout: no rollback */
1839 {
1840 ogg_page temp;
1841 ogg_packet test;
1842
1843 fprintf(stderr,"Testing loss of pages... ");
1844
1845 ogg_sync_reset(&oy);
1846 ogg_stream_reset(&os_de);
1847 for(i=0;i<5;i++){
1848 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1849 og[i].header_len);
1850 ogg_sync_wrote(&oy,og[i].header_len);
1851 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1852 ogg_sync_wrote(&oy,og[i].body_len);
1853 }
1854
1855 ogg_sync_pageout(&oy,&temp);
1856 ogg_stream_pagein(&os_de,&temp);
1857 ogg_sync_pageout(&oy,&temp);
1858 ogg_stream_pagein(&os_de,&temp);
1859 ogg_sync_pageout(&oy,&temp);
1860 /* skip */
1861 ogg_sync_pageout(&oy,&temp);
1862 ogg_stream_pagein(&os_de,&temp);
1863
1864 /* do we get the expected results/packets? */
1865
1866 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1867 checkpacket(&test,0,0,0);
1868 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1869 checkpacket(&test,1,1,-1);
1870 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1871 checkpacket(&test,1,2,-1);
1872 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1873 checkpacket(&test,98,3,-1);
1874 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1875 checkpacket(&test,4079,4,5000);
1876 if(ogg_stream_packetout(&os_de,&test)!=-1){
1877 fprintf(stderr,"Error: loss of page did not return error\n");
1878 exit(1);
1879 }
1880 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1881 checkpacket(&test,76,9,-1);
1882 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1883 checkpacket(&test,34,10,-1);
1884 fprintf(stderr,"ok.\n");
1885 }
1886
1887 /* Test lost pages on pagein/packetout: rollback with continuation */
1888 {
1889 ogg_page temp;
1890 ogg_packet test;
1891
1892 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1893
1894 ogg_sync_reset(&oy);
1895 ogg_stream_reset(&os_de);
1896 for(i=0;i<5;i++){
1897 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1898 og[i].header_len);
1899 ogg_sync_wrote(&oy,og[i].header_len);
1900 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1901 ogg_sync_wrote(&oy,og[i].body_len);
1902 }
1903
1904 ogg_sync_pageout(&oy,&temp);
1905 ogg_stream_pagein(&os_de,&temp);
1906 ogg_sync_pageout(&oy,&temp);
1907 ogg_stream_pagein(&os_de,&temp);
1908 ogg_sync_pageout(&oy,&temp);
1909 ogg_stream_pagein(&os_de,&temp);
1910 ogg_sync_pageout(&oy,&temp);
1911 /* skip */
1912 ogg_sync_pageout(&oy,&temp);
1913 ogg_stream_pagein(&os_de,&temp);
1914
1915 /* do we get the expected results/packets? */
1916
1917 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1918 checkpacket(&test,0,0,0);
1919 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1920 checkpacket(&test,1,1,-1);
1921 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1922 checkpacket(&test,1,2,-1);
1923 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1924 checkpacket(&test,98,3,-1);
1925 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1926 checkpacket(&test,4079,4,5000);
1927 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1928 checkpacket(&test,1,5,-1);
1929 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1930 checkpacket(&test,1,6,-1);
1931 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1932 checkpacket(&test,2954,7,-1);
1933 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1934 checkpacket(&test,2057,8,9000);
1935 if(ogg_stream_packetout(&os_de,&test)!=-1){
1936 fprintf(stderr,"Error: loss of page did not return error\n");
1937 exit(1);
1938 }
1939 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1940 checkpacket(&test,300,17,18000);
1941 fprintf(stderr,"ok.\n");
1942 }
1943
1944 /* the rest only test sync */
1945 {
1946 ogg_page og_de;
1947 /* Test fractional page inputs: incomplete capture */
1948 fprintf(stderr,"Testing sync on partial inputs... ");
1949 ogg_sync_reset(&oy);
1950 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1951 3);
1952 ogg_sync_wrote(&oy,3);
1953 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1954
1955 /* Test fractional page inputs: incomplete fixed header */
1956 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1957 20);
1958 ogg_sync_wrote(&oy,20);
1959 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1960
1961 /* Test fractional page inputs: incomplete header */
1962 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1963 5);
1964 ogg_sync_wrote(&oy,5);
1965 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1966
1967 /* Test fractional page inputs: incomplete body */
1968
1969 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1970 og[1].header_len-28);
1971 ogg_sync_wrote(&oy,og[1].header_len-28);
1972 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1973
1974 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1975 ogg_sync_wrote(&oy,1000);
1976 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1977
1978 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1979 og[1].body_len-1000);
1980 ogg_sync_wrote(&oy,og[1].body_len-1000);
1981 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1982
1983 fprintf(stderr,"ok.\n");
1984 }
1985
1986 /* Test fractional page inputs: page + incomplete capture */
1987 {
1988 ogg_page og_de;
1989 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1990 ogg_sync_reset(&oy);
1991
1992 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1993 og[1].header_len);
1994 ogg_sync_wrote(&oy,og[1].header_len);
1995
1996 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1997 og[1].body_len);
1998 ogg_sync_wrote(&oy,og[1].body_len);
1999
2000 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2001 20);
2002 ogg_sync_wrote(&oy,20);
2003 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2004 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2005
2006 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
2007 og[1].header_len-20);
2008 ogg_sync_wrote(&oy,og[1].header_len-20);
2009 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2010 og[1].body_len);
2011 ogg_sync_wrote(&oy,og[1].body_len);
2012 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2013
2014 fprintf(stderr,"ok.\n");
2015 }
2016
2017 /* Test recapture: garbage + page */
2018 {
2019 ogg_page og_de;
2020 fprintf(stderr,"Testing search for capture... ");
2021 ogg_sync_reset(&oy);
2022
2023 /* 'garbage' */
2024 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2025 og[1].body_len);
2026 ogg_sync_wrote(&oy,og[1].body_len);
2027
2028 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2029 og[1].header_len);
2030 ogg_sync_wrote(&oy,og[1].header_len);
2031
2032 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2033 og[1].body_len);
2034 ogg_sync_wrote(&oy,og[1].body_len);
2035
2036 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2037 20);
2038 ogg_sync_wrote(&oy,20);
2039 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2040 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2041 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2042
2043 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2044 og[2].header_len-20);
2045 ogg_sync_wrote(&oy,og[2].header_len-20);
2046 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2047 og[2].body_len);
2048 ogg_sync_wrote(&oy,og[2].body_len);
2049 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2050
2051 fprintf(stderr,"ok.\n");
2052 }
2053
2054#ifndef DISABLE_CRC
2055 /* Test recapture: page + garbage + page */
2056 {
2057 ogg_page og_de;
2058 fprintf(stderr,"Testing recapture... ");
2059 ogg_sync_reset(&oy);
2060
2061 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2062 og[1].header_len);
2063 ogg_sync_wrote(&oy,og[1].header_len);
2064
2065 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2066 og[1].body_len);
2067 ogg_sync_wrote(&oy,og[1].body_len);
2068
2069 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2070 og[2].header_len);
2071 ogg_sync_wrote(&oy,og[2].header_len);
2072
2073 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2074 og[2].header_len);
2075 ogg_sync_wrote(&oy,og[2].header_len);
2076
2077 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2078
2079 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2080 og[2].body_len-5);
2081 ogg_sync_wrote(&oy,og[2].body_len-5);
2082
2083 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2084 og[3].header_len);
2085 ogg_sync_wrote(&oy,og[3].header_len);
2086
2087 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2088 og[3].body_len);
2089 ogg_sync_wrote(&oy,og[3].body_len);
2090
2091 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2092 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2093
2094 fprintf(stderr,"ok.\n");
2095 }
2096#else
2097 fprintf(stderr,"Skipping recapture test due to --disable-crc\n");
2098#endif
2099
2100 /* Free page data that was previously copied */
2101 {
2102 for(i=0;i<5;i++){
2103 free_page(&og[i]);
2104 }
2105 }
2106 }
2107 ogg_sync_clear(&oy);
2108 ogg_stream_clear(&os_en);
2109 ogg_stream_clear(&os_de);
2110
2111 return(0);
2112}
2113
2114#endif
2115