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