vrshoot

view libs/ogg/framing.c @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
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-2010 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
13 function: code raw packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
15 last mod: $Id: framing.c 18758 2013-01-08 16:29:56Z tterribe $
17 note: The CRC code is directly derived from public domain code by
18 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
19 for details.
21 ********************************************************************/
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <string.h>
26 #include <ogg/ogg.h>
28 /* A complete description of Ogg framing exists in docs/framing.html */
30 int ogg_page_version(const ogg_page *og){
31 return((int)(og->header[4]));
32 }
34 int ogg_page_continued(const ogg_page *og){
35 return((int)(og->header[5]&0x01));
36 }
38 int ogg_page_bos(const ogg_page *og){
39 return((int)(og->header[5]&0x02));
40 }
42 int ogg_page_eos(const ogg_page *og){
43 return((int)(og->header[5]&0x04));
44 }
46 ogg_int64_t ogg_page_granulepos(const ogg_page *og){
47 unsigned char *page=og->header;
48 ogg_int64_t granulepos=page[13]&(0xff);
49 granulepos= (granulepos<<8)|(page[12]&0xff);
50 granulepos= (granulepos<<8)|(page[11]&0xff);
51 granulepos= (granulepos<<8)|(page[10]&0xff);
52 granulepos= (granulepos<<8)|(page[9]&0xff);
53 granulepos= (granulepos<<8)|(page[8]&0xff);
54 granulepos= (granulepos<<8)|(page[7]&0xff);
55 granulepos= (granulepos<<8)|(page[6]&0xff);
56 return(granulepos);
57 }
59 int ogg_page_serialno(const ogg_page *og){
60 return(og->header[14] |
61 (og->header[15]<<8) |
62 (og->header[16]<<16) |
63 (og->header[17]<<24));
64 }
66 long ogg_page_pageno(const ogg_page *og){
67 return(og->header[18] |
68 (og->header[19]<<8) |
69 (og->header[20]<<16) |
70 (og->header[21]<<24));
71 }
75 /* returns the number of packets that are completed on this page (if
76 the leading packet is begun on a previous page, but ends on this
77 page, it's counted */
79 /* NOTE:
80 If a page consists of a packet begun on a previous page, and a new
81 packet begun (but not completed) on this page, the return will be:
82 ogg_page_packets(page) ==1,
83 ogg_page_continued(page) !=0
85 If a page happens to be a single packet that was begun on a
86 previous page, and spans to the next page (in the case of a three or
87 more page packet), the return will be:
88 ogg_page_packets(page) ==0,
89 ogg_page_continued(page) !=0
90 */
92 int ogg_page_packets(const ogg_page *og){
93 int i,n=og->header[26],count=0;
94 for(i=0;i<n;i++)
95 if(og->header[27+i]<255)count++;
96 return(count);
97 }
100 #if 0
101 /* helper to initialize lookup for direct-table CRC (illustrative; we
102 use the static init below) */
104 static ogg_uint32_t _ogg_crc_entry(unsigned long index){
105 int i;
106 unsigned long r;
108 r = index << 24;
109 for (i=0; i<8; i++)
110 if (r & 0x80000000UL)
111 r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
112 polynomial, although we use an
113 unreflected alg and an init/final
114 of 0, not 0xffffffff */
115 else
116 r<<=1;
117 return (r & 0xffffffffUL);
118 }
119 #endif
121 static const ogg_uint32_t crc_lookup[256]={
122 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
123 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
124 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
125 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
126 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
127 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
128 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
129 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
130 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
131 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
132 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
133 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
134 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
135 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
136 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
137 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
138 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
139 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
140 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
141 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
142 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
143 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
144 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
145 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
146 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
147 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
148 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
149 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
150 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
151 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
152 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
153 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
154 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
155 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
156 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
157 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
158 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
159 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
160 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
161 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
162 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
163 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
164 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
165 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
166 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
167 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
168 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
169 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
170 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
171 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
172 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
173 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
174 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
175 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
176 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
177 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
178 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
179 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
180 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
181 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
182 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
183 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
184 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
185 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
187 /* init the encode/decode logical stream state */
189 int ogg_stream_init(ogg_stream_state *os,int serialno){
190 if(os){
191 memset(os,0,sizeof(*os));
192 os->body_storage=16*1024;
193 os->lacing_storage=1024;
195 os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
196 os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
197 os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
199 if(!os->body_data || !os->lacing_vals || !os->granule_vals){
200 ogg_stream_clear(os);
201 return -1;
202 }
204 os->serialno=serialno;
206 return(0);
207 }
208 return(-1);
209 }
211 /* async/delayed error detection for the ogg_stream_state */
212 int ogg_stream_check(ogg_stream_state *os){
213 if(!os || !os->body_data) return -1;
214 return 0;
215 }
217 /* _clear does not free os, only the non-flat storage within */
218 int ogg_stream_clear(ogg_stream_state *os){
219 if(os){
220 if(os->body_data)_ogg_free(os->body_data);
221 if(os->lacing_vals)_ogg_free(os->lacing_vals);
222 if(os->granule_vals)_ogg_free(os->granule_vals);
224 memset(os,0,sizeof(*os));
225 }
226 return(0);
227 }
229 int ogg_stream_destroy(ogg_stream_state *os){
230 if(os){
231 ogg_stream_clear(os);
232 _ogg_free(os);
233 }
234 return(0);
235 }
237 /* Helpers for ogg_stream_encode; this keeps the structure and
238 what's happening fairly clear */
240 static int _os_body_expand(ogg_stream_state *os,long needed){
241 if(os->body_storage-needed<=os->body_fill){
242 long body_storage;
243 void *ret;
244 if(os->body_storage>LONG_MAX-needed){
245 ogg_stream_clear(os);
246 return -1;
247 }
248 body_storage=os->body_storage+needed;
249 if(body_storage<LONG_MAX-1024)body_storage+=1024;
250 ret=_ogg_realloc(os->body_data,body_storage*sizeof(*os->body_data));
251 if(!ret){
252 ogg_stream_clear(os);
253 return -1;
254 }
255 os->body_storage=body_storage;
256 os->body_data=ret;
257 }
258 return 0;
259 }
261 static int _os_lacing_expand(ogg_stream_state *os,long needed){
262 if(os->lacing_storage-needed<=os->lacing_fill){
263 long lacing_storage;
264 void *ret;
265 if(os->lacing_storage>LONG_MAX-needed){
266 ogg_stream_clear(os);
267 return -1;
268 }
269 lacing_storage=os->lacing_storage+needed;
270 if(lacing_storage<LONG_MAX-32)lacing_storage+=32;
271 ret=_ogg_realloc(os->lacing_vals,lacing_storage*sizeof(*os->lacing_vals));
272 if(!ret){
273 ogg_stream_clear(os);
274 return -1;
275 }
276 os->lacing_vals=ret;
277 ret=_ogg_realloc(os->granule_vals,lacing_storage*
278 sizeof(*os->granule_vals));
279 if(!ret){
280 ogg_stream_clear(os);
281 return -1;
282 }
283 os->granule_vals=ret;
284 os->lacing_storage=lacing_storage;
285 }
286 return 0;
287 }
289 /* checksum the page */
290 /* Direct table CRC; note that this will be faster in the future if we
291 perform the checksum simultaneously with other copies */
293 void ogg_page_checksum_set(ogg_page *og){
294 if(og){
295 ogg_uint32_t crc_reg=0;
296 int i;
298 /* safety; needed for API behavior, but not framing code */
299 og->header[22]=0;
300 og->header[23]=0;
301 og->header[24]=0;
302 og->header[25]=0;
304 for(i=0;i<og->header_len;i++)
305 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
306 for(i=0;i<og->body_len;i++)
307 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
309 og->header[22]=(unsigned char)(crc_reg&0xff);
310 og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
311 og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
312 og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
313 }
314 }
316 /* submit data to the internal buffer of the framing engine */
317 int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
318 long e_o_s, ogg_int64_t granulepos){
320 long bytes = 0, lacing_vals;
321 int i;
323 if(ogg_stream_check(os)) return -1;
324 if(!iov) return 0;
326 for (i = 0; i < count; ++i){
327 if(iov[i].iov_len>LONG_MAX) return -1;
328 if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1;
329 bytes += (long)iov[i].iov_len;
330 }
331 lacing_vals=bytes/255+1;
333 if(os->body_returned){
334 /* advance packet data according to the body_returned pointer. We
335 had to keep it around to return a pointer into the buffer last
336 call */
338 os->body_fill-=os->body_returned;
339 if(os->body_fill)
340 memmove(os->body_data,os->body_data+os->body_returned,
341 os->body_fill);
342 os->body_returned=0;
343 }
345 /* make sure we have the buffer storage */
346 if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
347 return -1;
349 /* Copy in the submitted packet. Yes, the copy is a waste; this is
350 the liability of overly clean abstraction for the time being. It
351 will actually be fairly easy to eliminate the extra copy in the
352 future */
354 for (i = 0; i < count; ++i) {
355 memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
356 os->body_fill += (int)iov[i].iov_len;
357 }
359 /* Store lacing vals for this packet */
360 for(i=0;i<lacing_vals-1;i++){
361 os->lacing_vals[os->lacing_fill+i]=255;
362 os->granule_vals[os->lacing_fill+i]=os->granulepos;
363 }
364 os->lacing_vals[os->lacing_fill+i]=bytes%255;
365 os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
367 /* flag the first segment as the beginning of the packet */
368 os->lacing_vals[os->lacing_fill]|= 0x100;
370 os->lacing_fill+=lacing_vals;
372 /* for the sake of completeness */
373 os->packetno++;
375 if(e_o_s)os->e_o_s=1;
377 return(0);
378 }
380 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
381 ogg_iovec_t iov;
382 iov.iov_base = op->packet;
383 iov.iov_len = op->bytes;
384 return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
385 }
387 /* Conditionally flush a page; force==0 will only flush nominal-size
388 pages, force==1 forces us to flush a page regardless of page size
389 so long as there's any data available at all. */
390 static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
391 int i;
392 int vals=0;
393 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
394 int bytes=0;
395 long acc=0;
396 ogg_int64_t granule_pos=-1;
398 if(ogg_stream_check(os)) return(0);
399 if(maxvals==0) return(0);
401 /* construct a page */
402 /* decide how many segments to include */
404 /* If this is the initial header case, the first page must only include
405 the initial header packet */
406 if(os->b_o_s==0){ /* 'initial header page' case */
407 granule_pos=0;
408 for(vals=0;vals<maxvals;vals++){
409 if((os->lacing_vals[vals]&0x0ff)<255){
410 vals++;
411 break;
412 }
413 }
414 }else{
416 /* The extra packets_done, packet_just_done logic here attempts to do two things:
417 1) Don't unneccessarily span pages.
418 2) Unless necessary, don't flush pages if there are less than four packets on
419 them; this expands page size to reduce unneccessary overhead if incoming packets
420 are large.
421 These are not necessary behaviors, just 'always better than naive flushing'
422 without requiring an application to explicitly request a specific optimized
423 behavior. We'll want an explicit behavior setup pathway eventually as well. */
425 int packets_done=0;
426 int packet_just_done=0;
427 for(vals=0;vals<maxvals;vals++){
428 if(acc>nfill && packet_just_done>=4){
429 force=1;
430 break;
431 }
432 acc+=os->lacing_vals[vals]&0x0ff;
433 if((os->lacing_vals[vals]&0xff)<255){
434 granule_pos=os->granule_vals[vals];
435 packet_just_done=++packets_done;
436 }else
437 packet_just_done=0;
438 }
439 if(vals==255)force=1;
440 }
442 if(!force) return(0);
444 /* construct the header in temp storage */
445 memcpy(os->header,"OggS",4);
447 /* stream structure version */
448 os->header[4]=0x00;
450 /* continued packet flag? */
451 os->header[5]=0x00;
452 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
453 /* first page flag? */
454 if(os->b_o_s==0)os->header[5]|=0x02;
455 /* last page flag? */
456 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
457 os->b_o_s=1;
459 /* 64 bits of PCM position */
460 for(i=6;i<14;i++){
461 os->header[i]=(unsigned char)(granule_pos&0xff);
462 granule_pos>>=8;
463 }
465 /* 32 bits of stream serial number */
466 {
467 long serialno=os->serialno;
468 for(i=14;i<18;i++){
469 os->header[i]=(unsigned char)(serialno&0xff);
470 serialno>>=8;
471 }
472 }
474 /* 32 bits of page counter (we have both counter and page header
475 because this val can roll over) */
476 if(os->pageno==-1)os->pageno=0; /* because someone called
477 stream_reset; this would be a
478 strange thing to do in an
479 encode stream, but it has
480 plausible uses */
481 {
482 long pageno=os->pageno++;
483 for(i=18;i<22;i++){
484 os->header[i]=(unsigned char)(pageno&0xff);
485 pageno>>=8;
486 }
487 }
489 /* zero for computation; filled in later */
490 os->header[22]=0;
491 os->header[23]=0;
492 os->header[24]=0;
493 os->header[25]=0;
495 /* segment table */
496 os->header[26]=(unsigned char)(vals&0xff);
497 for(i=0;i<vals;i++)
498 bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
500 /* set pointers in the ogg_page struct */
501 og->header=os->header;
502 og->header_len=os->header_fill=vals+27;
503 og->body=os->body_data+os->body_returned;
504 og->body_len=bytes;
506 /* advance the lacing data and set the body_returned pointer */
508 os->lacing_fill-=vals;
509 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
510 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
511 os->body_returned+=bytes;
513 /* calculate the checksum */
515 ogg_page_checksum_set(og);
517 /* done */
518 return(1);
519 }
521 /* This will flush remaining packets into a page (returning nonzero),
522 even if there is not enough data to trigger a flush normally
523 (undersized page). If there are no packets or partial packets to
524 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
525 try to flush a normal sized page like ogg_stream_pageout; a call to
526 ogg_stream_flush does not guarantee that all packets have flushed.
527 Only a return value of 0 from ogg_stream_flush indicates all packet
528 data is flushed into pages.
530 since ogg_stream_flush will flush the last page in a stream even if
531 it's undersized, you almost certainly want to use ogg_stream_pageout
532 (and *not* ogg_stream_flush) unless you specifically need to flush
533 a page regardless of size in the middle of a stream. */
535 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
536 return ogg_stream_flush_i(os,og,1,4096);
537 }
539 /* Like the above, but an argument is provided to adjust the nominal
540 page size for applications which are smart enough to provide their
541 own delay based flushing */
543 int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
544 return ogg_stream_flush_i(os,og,1,nfill);
545 }
547 /* This constructs pages from buffered packet segments. The pointers
548 returned are to static buffers; do not free. The returned buffers are
549 good only until the next call (using the same ogg_stream_state) */
551 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
552 int force=0;
553 if(ogg_stream_check(os)) return 0;
555 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
556 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
557 force=1;
559 return(ogg_stream_flush_i(os,og,force,4096));
560 }
562 /* Like the above, but an argument is provided to adjust the nominal
563 page size for applications which are smart enough to provide their
564 own delay based flushing */
566 int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
567 int force=0;
568 if(ogg_stream_check(os)) return 0;
570 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
571 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
572 force=1;
574 return(ogg_stream_flush_i(os,og,force,nfill));
575 }
577 int ogg_stream_eos(ogg_stream_state *os){
578 if(ogg_stream_check(os)) return 1;
579 return os->e_o_s;
580 }
582 /* DECODING PRIMITIVES: packet streaming layer **********************/
584 /* This has two layers to place more of the multi-serialno and paging
585 control in the application's hands. First, we expose a data buffer
586 using ogg_sync_buffer(). The app either copies into the
587 buffer, or passes it directly to read(), etc. We then call
588 ogg_sync_wrote() to tell how many bytes we just added.
590 Pages are returned (pointers into the buffer in ogg_sync_state)
591 by ogg_sync_pageout(). The page is then submitted to
592 ogg_stream_pagein() along with the appropriate
593 ogg_stream_state* (ie, matching serialno). We then get raw
594 packets out calling ogg_stream_packetout() with a
595 ogg_stream_state. */
597 /* initialize the struct to a known state */
598 int ogg_sync_init(ogg_sync_state *oy){
599 if(oy){
600 oy->storage = -1; /* used as a readiness flag */
601 memset(oy,0,sizeof(*oy));
602 }
603 return(0);
604 }
606 /* clear non-flat storage within */
607 int ogg_sync_clear(ogg_sync_state *oy){
608 if(oy){
609 if(oy->data)_ogg_free(oy->data);
610 memset(oy,0,sizeof(*oy));
611 }
612 return(0);
613 }
615 int ogg_sync_destroy(ogg_sync_state *oy){
616 if(oy){
617 ogg_sync_clear(oy);
618 _ogg_free(oy);
619 }
620 return(0);
621 }
623 int ogg_sync_check(ogg_sync_state *oy){
624 if(oy->storage<0) return -1;
625 return 0;
626 }
628 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
629 if(ogg_sync_check(oy)) return NULL;
631 /* first, clear out any space that has been previously returned */
632 if(oy->returned){
633 oy->fill-=oy->returned;
634 if(oy->fill>0)
635 memmove(oy->data,oy->data+oy->returned,oy->fill);
636 oy->returned=0;
637 }
639 if(size>oy->storage-oy->fill){
640 /* We need to extend the internal buffer */
641 long newsize=size+oy->fill+4096; /* an extra page to be nice */
642 void *ret;
644 if(oy->data)
645 ret=_ogg_realloc(oy->data,newsize);
646 else
647 ret=_ogg_malloc(newsize);
648 if(!ret){
649 ogg_sync_clear(oy);
650 return NULL;
651 }
652 oy->data=ret;
653 oy->storage=newsize;
654 }
656 /* expose a segment at least as large as requested at the fill mark */
657 return((char *)oy->data+oy->fill);
658 }
660 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
661 if(ogg_sync_check(oy))return -1;
662 if(oy->fill+bytes>oy->storage)return -1;
663 oy->fill+=bytes;
664 return(0);
665 }
667 /* sync the stream. This is meant to be useful for finding page
668 boundaries.
670 return values for this:
671 -n) skipped n bytes
672 0) page not ready; more data (no bytes skipped)
673 n) page synced at current location; page length n bytes
675 */
677 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
678 unsigned char *page=oy->data+oy->returned;
679 unsigned char *next;
680 long bytes=oy->fill-oy->returned;
682 if(ogg_sync_check(oy))return 0;
684 if(oy->headerbytes==0){
685 int headerbytes,i;
686 if(bytes<27)return(0); /* not enough for a header */
688 /* verify capture pattern */
689 if(memcmp(page,"OggS",4))goto sync_fail;
691 headerbytes=page[26]+27;
692 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
694 /* count up body length in the segment table */
696 for(i=0;i<page[26];i++)
697 oy->bodybytes+=page[27+i];
698 oy->headerbytes=headerbytes;
699 }
701 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
703 /* The whole test page is buffered. Verify the checksum */
704 {
705 /* Grab the checksum bytes, set the header field to zero */
706 char chksum[4];
707 ogg_page log;
709 memcpy(chksum,page+22,4);
710 memset(page+22,0,4);
712 /* set up a temp page struct and recompute the checksum */
713 log.header=page;
714 log.header_len=oy->headerbytes;
715 log.body=page+oy->headerbytes;
716 log.body_len=oy->bodybytes;
717 ogg_page_checksum_set(&log);
719 /* Compare */
720 if(memcmp(chksum,page+22,4)){
721 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
722 at all) */
723 /* replace the computed checksum with the one actually read in */
724 memcpy(page+22,chksum,4);
726 /* Bad checksum. Lose sync */
727 goto sync_fail;
728 }
729 }
731 /* yes, have a whole page all ready to go */
732 {
733 unsigned char *page=oy->data+oy->returned;
734 long bytes;
736 if(og){
737 og->header=page;
738 og->header_len=oy->headerbytes;
739 og->body=page+oy->headerbytes;
740 og->body_len=oy->bodybytes;
741 }
743 oy->unsynced=0;
744 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
745 oy->headerbytes=0;
746 oy->bodybytes=0;
747 return(bytes);
748 }
750 sync_fail:
752 oy->headerbytes=0;
753 oy->bodybytes=0;
755 /* search for possible capture */
756 next=memchr(page+1,'O',bytes-1);
757 if(!next)
758 next=oy->data+oy->fill;
760 oy->returned=(int)(next-oy->data);
761 return((long)-(next-page));
762 }
764 /* sync the stream and get a page. Keep trying until we find a page.
765 Suppress 'sync errors' after reporting the first.
767 return values:
768 -1) recapture (hole in data)
769 0) need more data
770 1) page returned
772 Returns pointers into buffered data; invalidated by next call to
773 _stream, _clear, _init, or _buffer */
775 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
777 if(ogg_sync_check(oy))return 0;
779 /* all we need to do is verify a page at the head of the stream
780 buffer. If it doesn't verify, we look for the next potential
781 frame */
783 for(;;){
784 long ret=ogg_sync_pageseek(oy,og);
785 if(ret>0){
786 /* have a page */
787 return(1);
788 }
789 if(ret==0){
790 /* need more data */
791 return(0);
792 }
794 /* head did not start a synced page... skipped some bytes */
795 if(!oy->unsynced){
796 oy->unsynced=1;
797 return(-1);
798 }
800 /* loop. keep looking */
802 }
803 }
805 /* add the incoming page to the stream state; we decompose the page
806 into packet segments here as well. */
808 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
809 unsigned char *header=og->header;
810 unsigned char *body=og->body;
811 long bodysize=og->body_len;
812 int segptr=0;
814 int version=ogg_page_version(og);
815 int continued=ogg_page_continued(og);
816 int bos=ogg_page_bos(og);
817 int eos=ogg_page_eos(og);
818 ogg_int64_t granulepos=ogg_page_granulepos(og);
819 int serialno=ogg_page_serialno(og);
820 long pageno=ogg_page_pageno(og);
821 int segments=header[26];
823 if(ogg_stream_check(os)) return -1;
825 /* clean up 'returned data' */
826 {
827 long lr=os->lacing_returned;
828 long br=os->body_returned;
830 /* body data */
831 if(br){
832 os->body_fill-=br;
833 if(os->body_fill)
834 memmove(os->body_data,os->body_data+br,os->body_fill);
835 os->body_returned=0;
836 }
838 if(lr){
839 /* segment table */
840 if(os->lacing_fill-lr){
841 memmove(os->lacing_vals,os->lacing_vals+lr,
842 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
843 memmove(os->granule_vals,os->granule_vals+lr,
844 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
845 }
846 os->lacing_fill-=lr;
847 os->lacing_packet-=lr;
848 os->lacing_returned=0;
849 }
850 }
852 /* check the serial number */
853 if(serialno!=os->serialno)return(-1);
854 if(version>0)return(-1);
856 if(_os_lacing_expand(os,segments+1)) return -1;
858 /* are we in sequence? */
859 if(pageno!=os->pageno){
860 int i;
862 /* unroll previous partial packet (if any) */
863 for(i=os->lacing_packet;i<os->lacing_fill;i++)
864 os->body_fill-=os->lacing_vals[i]&0xff;
865 os->lacing_fill=os->lacing_packet;
867 /* make a note of dropped data in segment table */
868 if(os->pageno!=-1){
869 os->lacing_vals[os->lacing_fill++]=0x400;
870 os->lacing_packet++;
871 }
872 }
874 /* are we a 'continued packet' page? If so, we may need to skip
875 some segments */
876 if(continued){
877 if(os->lacing_fill<1 ||
878 os->lacing_vals[os->lacing_fill-1]==0x400){
879 bos=0;
880 for(;segptr<segments;segptr++){
881 int val=header[27+segptr];
882 body+=val;
883 bodysize-=val;
884 if(val<255){
885 segptr++;
886 break;
887 }
888 }
889 }
890 }
892 if(bodysize){
893 if(_os_body_expand(os,bodysize)) return -1;
894 memcpy(os->body_data+os->body_fill,body,bodysize);
895 os->body_fill+=bodysize;
896 }
898 {
899 int saved=-1;
900 while(segptr<segments){
901 int val=header[27+segptr];
902 os->lacing_vals[os->lacing_fill]=val;
903 os->granule_vals[os->lacing_fill]=-1;
905 if(bos){
906 os->lacing_vals[os->lacing_fill]|=0x100;
907 bos=0;
908 }
910 if(val<255)saved=os->lacing_fill;
912 os->lacing_fill++;
913 segptr++;
915 if(val<255)os->lacing_packet=os->lacing_fill;
916 }
918 /* set the granulepos on the last granuleval of the last full packet */
919 if(saved!=-1){
920 os->granule_vals[saved]=granulepos;
921 }
923 }
925 if(eos){
926 os->e_o_s=1;
927 if(os->lacing_fill>0)
928 os->lacing_vals[os->lacing_fill-1]|=0x200;
929 }
931 os->pageno=pageno+1;
933 return(0);
934 }
936 /* clear things to an initial state. Good to call, eg, before seeking */
937 int ogg_sync_reset(ogg_sync_state *oy){
938 if(ogg_sync_check(oy))return -1;
940 oy->fill=0;
941 oy->returned=0;
942 oy->unsynced=0;
943 oy->headerbytes=0;
944 oy->bodybytes=0;
945 return(0);
946 }
948 int ogg_stream_reset(ogg_stream_state *os){
949 if(ogg_stream_check(os)) return -1;
951 os->body_fill=0;
952 os->body_returned=0;
954 os->lacing_fill=0;
955 os->lacing_packet=0;
956 os->lacing_returned=0;
958 os->header_fill=0;
960 os->e_o_s=0;
961 os->b_o_s=0;
962 os->pageno=-1;
963 os->packetno=0;
964 os->granulepos=0;
966 return(0);
967 }
969 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
970 if(ogg_stream_check(os)) return -1;
971 ogg_stream_reset(os);
972 os->serialno=serialno;
973 return(0);
974 }
976 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
978 /* The last part of decode. We have the stream broken into packet
979 segments. Now we need to group them into packets (or return the
980 out of sync markers) */
982 int ptr=os->lacing_returned;
984 if(os->lacing_packet<=ptr)return(0);
986 if(os->lacing_vals[ptr]&0x400){
987 /* we need to tell the codec there's a gap; it might need to
988 handle previous packet dependencies. */
989 os->lacing_returned++;
990 os->packetno++;
991 return(-1);
992 }
994 if(!op && !adv)return(1); /* just using peek as an inexpensive way
995 to ask if there's a whole packet
996 waiting */
998 /* Gather the whole packet. We'll have no holes or a partial packet */
999 {
1000 int size=os->lacing_vals[ptr]&0xff;
1001 long bytes=size;
1002 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
1003 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
1005 while(size==255){
1006 int val=os->lacing_vals[++ptr];
1007 size=val&0xff;
1008 if(val&0x200)eos=0x200;
1009 bytes+=size;
1012 if(op){
1013 op->e_o_s=eos;
1014 op->b_o_s=bos;
1015 op->packet=os->body_data+os->body_returned;
1016 op->packetno=os->packetno;
1017 op->granulepos=os->granule_vals[ptr];
1018 op->bytes=bytes;
1021 if(adv){
1022 os->body_returned+=bytes;
1023 os->lacing_returned=ptr+1;
1024 os->packetno++;
1027 return(1);
1030 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
1031 if(ogg_stream_check(os)) return 0;
1032 return _packetout(os,op,1);
1035 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
1036 if(ogg_stream_check(os)) return 0;
1037 return _packetout(os,op,0);
1040 void ogg_packet_clear(ogg_packet *op) {
1041 _ogg_free(op->packet);
1042 memset(op, 0, sizeof(*op));
1045 #ifdef _V_SELFTEST
1046 #include <stdio.h>
1048 ogg_stream_state os_en, os_de;
1049 ogg_sync_state oy;
1051 void checkpacket(ogg_packet *op,long len, int no, long pos){
1052 long j;
1053 static int sequence=0;
1054 static int lastno=0;
1056 if(op->bytes!=len){
1057 fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
1058 exit(1);
1060 if(op->granulepos!=pos){
1061 fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1062 exit(1);
1065 /* packet number just follows sequence/gap; adjust the input number
1066 for that */
1067 if(no==0){
1068 sequence=0;
1069 }else{
1070 sequence++;
1071 if(no>lastno+1)
1072 sequence++;
1074 lastno=no;
1075 if(op->packetno!=sequence){
1076 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1077 (long)(op->packetno),sequence);
1078 exit(1);
1081 /* Test data */
1082 for(j=0;j<op->bytes;j++)
1083 if(op->packet[j]!=((j+no)&0xff)){
1084 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1085 j,op->packet[j],(j+no)&0xff);
1086 exit(1);
1090 void check_page(unsigned char *data,const int *header,ogg_page *og){
1091 long j;
1092 /* Test data */
1093 for(j=0;j<og->body_len;j++)
1094 if(og->body[j]!=data[j]){
1095 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1096 j,data[j],og->body[j]);
1097 exit(1);
1100 /* Test header */
1101 for(j=0;j<og->header_len;j++){
1102 if(og->header[j]!=header[j]){
1103 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1104 for(j=0;j<header[26]+27;j++)
1105 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1106 fprintf(stderr,"\n");
1107 exit(1);
1110 if(og->header_len!=header[26]+27){
1111 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1112 og->header_len,header[26]+27);
1113 exit(1);
1117 void print_header(ogg_page *og){
1118 int j;
1119 fprintf(stderr,"\nHEADER:\n");
1120 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
1121 og->header[0],og->header[1],og->header[2],og->header[3],
1122 (int)og->header[4],(int)og->header[5]);
1124 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
1125 (og->header[9]<<24)|(og->header[8]<<16)|
1126 (og->header[7]<<8)|og->header[6],
1127 (og->header[17]<<24)|(og->header[16]<<16)|
1128 (og->header[15]<<8)|og->header[14],
1129 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1130 (og->header[19]<<8)|og->header[18]);
1132 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
1133 (int)og->header[22],(int)og->header[23],
1134 (int)og->header[24],(int)og->header[25],
1135 (int)og->header[26]);
1137 for(j=27;j<og->header_len;j++)
1138 fprintf(stderr,"%d ",(int)og->header[j]);
1139 fprintf(stderr,")\n\n");
1142 void copy_page(ogg_page *og){
1143 unsigned char *temp=_ogg_malloc(og->header_len);
1144 memcpy(temp,og->header,og->header_len);
1145 og->header=temp;
1147 temp=_ogg_malloc(og->body_len);
1148 memcpy(temp,og->body,og->body_len);
1149 og->body=temp;
1152 void free_page(ogg_page *og){
1153 _ogg_free (og->header);
1154 _ogg_free (og->body);
1157 void error(void){
1158 fprintf(stderr,"error!\n");
1159 exit(1);
1162 /* 17 only */
1163 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1164 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1165 0x01,0x02,0x03,0x04,0,0,0,0,
1166 0x15,0xed,0xec,0x91,
1167 1,
1168 17};
1170 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1171 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1172 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1173 0x01,0x02,0x03,0x04,0,0,0,0,
1174 0x59,0x10,0x6c,0x2c,
1175 1,
1176 17};
1177 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1178 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1179 0x01,0x02,0x03,0x04,1,0,0,0,
1180 0x89,0x33,0x85,0xce,
1181 13,
1182 254,255,0,255,1,255,245,255,255,0,
1183 255,255,90};
1185 /* nil packets; beginning,middle,end */
1186 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1187 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1188 0x01,0x02,0x03,0x04,0,0,0,0,
1189 0xff,0x7b,0x23,0x17,
1190 1,
1191 0};
1192 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1193 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1194 0x01,0x02,0x03,0x04,1,0,0,0,
1195 0x5c,0x3f,0x66,0xcb,
1196 17,
1197 17,254,255,0,0,255,1,0,255,245,255,255,0,
1198 255,255,90,0};
1200 /* large initial packet */
1201 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1202 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1203 0x01,0x02,0x03,0x04,0,0,0,0,
1204 0x01,0x27,0x31,0xaa,
1205 18,
1206 255,255,255,255,255,255,255,255,
1207 255,255,255,255,255,255,255,255,255,10};
1209 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1210 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1211 0x01,0x02,0x03,0x04,1,0,0,0,
1212 0x7f,0x4e,0x8a,0xd2,
1213 4,
1214 255,4,255,0};
1217 /* continuing packet test */
1218 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1219 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1220 0x01,0x02,0x03,0x04,0,0,0,0,
1221 0xff,0x7b,0x23,0x17,
1222 1,
1223 0};
1225 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1226 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1227 0x01,0x02,0x03,0x04,1,0,0,0,
1228 0xf8,0x3c,0x19,0x79,
1229 255,
1230 255,255,255,255,255,255,255,255,
1231 255,255,255,255,255,255,255,255,
1232 255,255,255,255,255,255,255,255,
1233 255,255,255,255,255,255,255,255,
1234 255,255,255,255,255,255,255,255,
1235 255,255,255,255,255,255,255,255,
1236 255,255,255,255,255,255,255,255,
1237 255,255,255,255,255,255,255,255,
1238 255,255,255,255,255,255,255,255,
1239 255,255,255,255,255,255,255,255,
1240 255,255,255,255,255,255,255,255,
1241 255,255,255,255,255,255,255,255,
1242 255,255,255,255,255,255,255,255,
1243 255,255,255,255,255,255,255,255,
1244 255,255,255,255,255,255,255,255,
1245 255,255,255,255,255,255,255,255,
1246 255,255,255,255,255,255,255,255,
1247 255,255,255,255,255,255,255,255,
1248 255,255,255,255,255,255,255,255,
1249 255,255,255,255,255,255,255,255,
1250 255,255,255,255,255,255,255,255,
1251 255,255,255,255,255,255,255,255,
1252 255,255,255,255,255,255,255,255,
1253 255,255,255,255,255,255,255,255,
1254 255,255,255,255,255,255,255,255,
1255 255,255,255,255,255,255,255,255,
1256 255,255,255,255,255,255,255,255,
1257 255,255,255,255,255,255,255,255,
1258 255,255,255,255,255,255,255,255,
1259 255,255,255,255,255,255,255,255,
1260 255,255,255,255,255,255,255,255,
1261 255,255,255,255,255,255,255};
1263 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1264 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1265 0x01,0x02,0x03,0x04,2,0,0,0,
1266 0x38,0xe6,0xb6,0x28,
1267 6,
1268 255,220,255,4,255,0};
1271 /* spill expansion test */
1272 const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1273 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1274 0x01,0x02,0x03,0x04,0,0,0,0,
1275 0xff,0x7b,0x23,0x17,
1276 1,
1277 0};
1279 const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1280 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1281 0x01,0x02,0x03,0x04,1,0,0,0,
1282 0xce,0x8f,0x17,0x1a,
1283 23,
1284 255,255,255,255,255,255,255,255,
1285 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1288 const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1289 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1290 0x01,0x02,0x03,0x04,2,0,0,0,
1291 0x9b,0xb2,0x50,0xa1,
1292 1,
1293 0};
1295 /* page with the 255 segment limit */
1296 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1297 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1298 0x01,0x02,0x03,0x04,0,0,0,0,
1299 0xff,0x7b,0x23,0x17,
1300 1,
1301 0};
1303 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1304 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1305 0x01,0x02,0x03,0x04,1,0,0,0,
1306 0xed,0x2a,0x2e,0xa7,
1307 255,
1308 10,10,10,10,10,10,10,10,
1309 10,10,10,10,10,10,10,10,
1310 10,10,10,10,10,10,10,10,
1311 10,10,10,10,10,10,10,10,
1312 10,10,10,10,10,10,10,10,
1313 10,10,10,10,10,10,10,10,
1314 10,10,10,10,10,10,10,10,
1315 10,10,10,10,10,10,10,10,
1316 10,10,10,10,10,10,10,10,
1317 10,10,10,10,10,10,10,10,
1318 10,10,10,10,10,10,10,10,
1319 10,10,10,10,10,10,10,10,
1320 10,10,10,10,10,10,10,10,
1321 10,10,10,10,10,10,10,10,
1322 10,10,10,10,10,10,10,10,
1323 10,10,10,10,10,10,10,10,
1324 10,10,10,10,10,10,10,10,
1325 10,10,10,10,10,10,10,10,
1326 10,10,10,10,10,10,10,10,
1327 10,10,10,10,10,10,10,10,
1328 10,10,10,10,10,10,10,10,
1329 10,10,10,10,10,10,10,10,
1330 10,10,10,10,10,10,10,10,
1331 10,10,10,10,10,10,10,10,
1332 10,10,10,10,10,10,10,10,
1333 10,10,10,10,10,10,10,10,
1334 10,10,10,10,10,10,10,10,
1335 10,10,10,10,10,10,10,10,
1336 10,10,10,10,10,10,10,10,
1337 10,10,10,10,10,10,10,10,
1338 10,10,10,10,10,10,10,10,
1339 10,10,10,10,10,10,10};
1341 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1342 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1343 0x01,0x02,0x03,0x04,2,0,0,0,
1344 0x6c,0x3b,0x82,0x3d,
1345 1,
1346 50};
1349 /* packet that overspans over an entire page */
1350 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1351 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1352 0x01,0x02,0x03,0x04,0,0,0,0,
1353 0xff,0x7b,0x23,0x17,
1354 1,
1355 0};
1357 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1358 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1359 0x01,0x02,0x03,0x04,1,0,0,0,
1360 0x68,0x22,0x7c,0x3d,
1361 255,
1362 100,
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,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};
1396 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1397 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1398 0x01,0x02,0x03,0x04,2,0,0,0,
1399 0xf4,0x87,0xba,0xf3,
1400 255,
1401 255,255,255,255,255,255,255,255,
1402 255,255,255,255,255,255,255,255,
1403 255,255,255,255,255,255,255,255,
1404 255,255,255,255,255,255,255,255,
1405 255,255,255,255,255,255,255,255,
1406 255,255,255,255,255,255,255,255,
1407 255,255,255,255,255,255,255,255,
1408 255,255,255,255,255,255,255,255,
1409 255,255,255,255,255,255,255,255,
1410 255,255,255,255,255,255,255,255,
1411 255,255,255,255,255,255,255,255,
1412 255,255,255,255,255,255,255,255,
1413 255,255,255,255,255,255,255,255,
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};
1434 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1435 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1436 0x01,0x02,0x03,0x04,3,0,0,0,
1437 0xf7,0x2f,0x6c,0x60,
1438 5,
1439 254,255,4,255,0};
1441 /* packet that overspans over an entire page */
1442 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1443 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1444 0x01,0x02,0x03,0x04,0,0,0,0,
1445 0xff,0x7b,0x23,0x17,
1446 1,
1447 0};
1449 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1450 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1451 0x01,0x02,0x03,0x04,1,0,0,0,
1452 0x68,0x22,0x7c,0x3d,
1453 255,
1454 100,
1455 255,255,255,255,255,255,255,255,
1456 255,255,255,255,255,255,255,255,
1457 255,255,255,255,255,255,255,255,
1458 255,255,255,255,255,255,255,255,
1459 255,255,255,255,255,255,255,255,
1460 255,255,255,255,255,255,255,255,
1461 255,255,255,255,255,255,255,255,
1462 255,255,255,255,255,255,255,255,
1463 255,255,255,255,255,255,255,255,
1464 255,255,255,255,255,255,255,255,
1465 255,255,255,255,255,255,255,255,
1466 255,255,255,255,255,255,255,255,
1467 255,255,255,255,255,255,255,255,
1468 255,255,255,255,255,255,255,255,
1469 255,255,255,255,255,255,255,255,
1470 255,255,255,255,255,255,255,255,
1471 255,255,255,255,255,255,255,255,
1472 255,255,255,255,255,255,255,255,
1473 255,255,255,255,255,255,255,255,
1474 255,255,255,255,255,255,255,255,
1475 255,255,255,255,255,255,255,255,
1476 255,255,255,255,255,255,255,255,
1477 255,255,255,255,255,255,255,255,
1478 255,255,255,255,255,255,255,255,
1479 255,255,255,255,255,255,255,255,
1480 255,255,255,255,255,255,255,255,
1481 255,255,255,255,255,255,255,255,
1482 255,255,255,255,255,255,255,255,
1483 255,255,255,255,255,255,255,255,
1484 255,255,255,255,255,255,255,255,
1485 255,255,255,255,255,255,255,255,
1486 255,255,255,255,255,255};
1488 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1489 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1490 0x01,0x02,0x03,0x04,2,0,0,0,
1491 0xd4,0xe0,0x60,0xe5,
1492 1,
1493 0};
1495 void test_pack(const int *pl, const int **headers, int byteskip,
1496 int pageskip, int packetskip){
1497 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1498 long inptr=0;
1499 long outptr=0;
1500 long deptr=0;
1501 long depacket=0;
1502 long granule_pos=7,pageno=0;
1503 int i,j,packets,pageout=pageskip;
1504 int eosflag=0;
1505 int bosflag=0;
1507 int byteskipcount=0;
1509 ogg_stream_reset(&os_en);
1510 ogg_stream_reset(&os_de);
1511 ogg_sync_reset(&oy);
1513 for(packets=0;packets<packetskip;packets++)
1514 depacket+=pl[packets];
1516 for(packets=0;;packets++)if(pl[packets]==-1)break;
1518 for(i=0;i<packets;i++){
1519 /* construct a test packet */
1520 ogg_packet op;
1521 int len=pl[i];
1523 op.packet=data+inptr;
1524 op.bytes=len;
1525 op.e_o_s=(pl[i+1]<0?1:0);
1526 op.granulepos=granule_pos;
1528 granule_pos+=1024;
1530 for(j=0;j<len;j++)data[inptr++]=i+j;
1532 /* submit the test packet */
1533 ogg_stream_packetin(&os_en,&op);
1535 /* retrieve any finished pages */
1537 ogg_page og;
1539 while(ogg_stream_pageout(&os_en,&og)){
1540 /* We have a page. Check it carefully */
1542 fprintf(stderr,"%ld, ",pageno);
1544 if(headers[pageno]==NULL){
1545 fprintf(stderr,"coded too many pages!\n");
1546 exit(1);
1549 check_page(data+outptr,headers[pageno],&og);
1551 outptr+=og.body_len;
1552 pageno++;
1553 if(pageskip){
1554 bosflag=1;
1555 pageskip--;
1556 deptr+=og.body_len;
1559 /* have a complete page; submit it to sync/decode */
1562 ogg_page og_de;
1563 ogg_packet op_de,op_de2;
1564 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1565 char *next=buf;
1566 byteskipcount+=og.header_len;
1567 if(byteskipcount>byteskip){
1568 memcpy(next,og.header,byteskipcount-byteskip);
1569 next+=byteskipcount-byteskip;
1570 byteskipcount=byteskip;
1573 byteskipcount+=og.body_len;
1574 if(byteskipcount>byteskip){
1575 memcpy(next,og.body,byteskipcount-byteskip);
1576 next+=byteskipcount-byteskip;
1577 byteskipcount=byteskip;
1580 ogg_sync_wrote(&oy,next-buf);
1582 while(1){
1583 int ret=ogg_sync_pageout(&oy,&og_de);
1584 if(ret==0)break;
1585 if(ret<0)continue;
1586 /* got a page. Happy happy. Verify that it's good. */
1588 fprintf(stderr,"(%d), ",pageout);
1590 check_page(data+deptr,headers[pageout],&og_de);
1591 deptr+=og_de.body_len;
1592 pageout++;
1594 /* submit it to deconstitution */
1595 ogg_stream_pagein(&os_de,&og_de);
1597 /* packets out? */
1598 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1599 ogg_stream_packetpeek(&os_de,NULL);
1600 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1602 /* verify peek and out match */
1603 if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1604 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1605 depacket);
1606 exit(1);
1609 /* verify the packet! */
1610 /* check data */
1611 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1612 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1613 depacket);
1614 exit(1);
1616 /* check bos flag */
1617 if(bosflag==0 && op_de.b_o_s==0){
1618 fprintf(stderr,"b_o_s flag not set on packet!\n");
1619 exit(1);
1621 if(bosflag && op_de.b_o_s){
1622 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1623 exit(1);
1625 bosflag=1;
1626 depacket+=op_de.bytes;
1628 /* check eos flag */
1629 if(eosflag){
1630 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1631 exit(1);
1634 if(op_de.e_o_s)eosflag=1;
1636 /* check granulepos flag */
1637 if(op_de.granulepos!=-1){
1638 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1646 _ogg_free(data);
1647 if(headers[pageno]!=NULL){
1648 fprintf(stderr,"did not write last page!\n");
1649 exit(1);
1651 if(headers[pageout]!=NULL){
1652 fprintf(stderr,"did not decode last page!\n");
1653 exit(1);
1655 if(inptr!=outptr){
1656 fprintf(stderr,"encoded page data incomplete!\n");
1657 exit(1);
1659 if(inptr!=deptr){
1660 fprintf(stderr,"decoded page data incomplete!\n");
1661 exit(1);
1663 if(inptr!=depacket){
1664 fprintf(stderr,"decoded packet data incomplete!\n");
1665 exit(1);
1667 if(!eosflag){
1668 fprintf(stderr,"Never got a packet with EOS set!\n");
1669 exit(1);
1671 fprintf(stderr,"ok.\n");
1674 int main(void){
1676 ogg_stream_init(&os_en,0x04030201);
1677 ogg_stream_init(&os_de,0x04030201);
1678 ogg_sync_init(&oy);
1680 /* Exercise each code path in the framing code. Also verify that
1681 the checksums are working. */
1684 /* 17 only */
1685 const int packets[]={17, -1};
1686 const int *headret[]={head1_0,NULL};
1688 fprintf(stderr,"testing single page encoding... ");
1689 test_pack(packets,headret,0,0,0);
1693 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1694 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1695 const int *headret[]={head1_1,head2_1,NULL};
1697 fprintf(stderr,"testing basic page encoding... ");
1698 test_pack(packets,headret,0,0,0);
1702 /* nil packets; beginning,middle,end */
1703 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1704 const int *headret[]={head1_2,head2_2,NULL};
1706 fprintf(stderr,"testing basic nil packets... ");
1707 test_pack(packets,headret,0,0,0);
1711 /* large initial packet */
1712 const int packets[]={4345,259,255,-1};
1713 const int *headret[]={head1_3,head2_3,NULL};
1715 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1716 test_pack(packets,headret,0,0,0);
1720 /* continuing packet test; with page spill expansion, we have to
1721 overflow the lacing table. */
1722 const int packets[]={0,65500,259,255,-1};
1723 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1725 fprintf(stderr,"testing single packet page span... ");
1726 test_pack(packets,headret,0,0,0);
1730 /* spill expand packet test */
1731 const int packets[]={0,4345,259,255,0,0,-1};
1732 const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1734 fprintf(stderr,"testing page spill expansion... ");
1735 test_pack(packets,headret,0,0,0);
1738 /* page with the 255 segment limit */
1741 const int packets[]={0,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,10,
1765 10,10,10,10,10,10,10,10,
1766 10,10,10,10,10,10,10,10,
1767 10,10,10,10,10,10,10,10,
1768 10,10,10,10,10,10,10,10,
1769 10,10,10,10,10,10,10,10,
1770 10,10,10,10,10,10,10,10,
1771 10,10,10,10,10,10,10,10,
1772 10,10,10,10,10,10,10,50,-1};
1773 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1775 fprintf(stderr,"testing max packet segments... ");
1776 test_pack(packets,headret,0,0,0);
1780 /* packet that overspans over an entire page */
1781 const int packets[]={0,100,130049,259,255,-1};
1782 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1784 fprintf(stderr,"testing very large packets... ");
1785 test_pack(packets,headret,0,0,0);
1789 /* test for the libogg 1.1.1 resync in large continuation bug
1790 found by Josh Coalson) */
1791 const int packets[]={0,100,130049,259,255,-1};
1792 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1794 fprintf(stderr,"testing continuation resync in very large packets... ");
1795 test_pack(packets,headret,100,2,3);
1799 /* term only page. why not? */
1800 const int packets[]={0,100,64770,-1};
1801 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1803 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1804 test_pack(packets,headret,0,0,0);
1810 /* build a bunch of pages for testing */
1811 unsigned char *data=_ogg_malloc(1024*1024);
1812 int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1813 int inptr=0,i,j;
1814 ogg_page og[5];
1816 ogg_stream_reset(&os_en);
1818 for(i=0;pl[i]!=-1;i++){
1819 ogg_packet op;
1820 int len=pl[i];
1822 op.packet=data+inptr;
1823 op.bytes=len;
1824 op.e_o_s=(pl[i+1]<0?1:0);
1825 op.granulepos=(i+1)*1000;
1827 for(j=0;j<len;j++)data[inptr++]=i+j;
1828 ogg_stream_packetin(&os_en,&op);
1831 _ogg_free(data);
1833 /* retrieve finished pages */
1834 for(i=0;i<5;i++){
1835 if(ogg_stream_pageout(&os_en,&og[i])==0){
1836 fprintf(stderr,"Too few pages output building sync tests!\n");
1837 exit(1);
1839 copy_page(&og[i]);
1842 /* Test lost pages on pagein/packetout: no rollback */
1844 ogg_page temp;
1845 ogg_packet test;
1847 fprintf(stderr,"Testing loss of pages... ");
1849 ogg_sync_reset(&oy);
1850 ogg_stream_reset(&os_de);
1851 for(i=0;i<5;i++){
1852 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1853 og[i].header_len);
1854 ogg_sync_wrote(&oy,og[i].header_len);
1855 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1856 ogg_sync_wrote(&oy,og[i].body_len);
1859 ogg_sync_pageout(&oy,&temp);
1860 ogg_stream_pagein(&os_de,&temp);
1861 ogg_sync_pageout(&oy,&temp);
1862 ogg_stream_pagein(&os_de,&temp);
1863 ogg_sync_pageout(&oy,&temp);
1864 /* skip */
1865 ogg_sync_pageout(&oy,&temp);
1866 ogg_stream_pagein(&os_de,&temp);
1868 /* do we get the expected results/packets? */
1870 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1871 checkpacket(&test,0,0,0);
1872 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1873 checkpacket(&test,1,1,-1);
1874 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1875 checkpacket(&test,1,2,-1);
1876 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1877 checkpacket(&test,98,3,-1);
1878 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1879 checkpacket(&test,4079,4,5000);
1880 if(ogg_stream_packetout(&os_de,&test)!=-1){
1881 fprintf(stderr,"Error: loss of page did not return error\n");
1882 exit(1);
1884 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1885 checkpacket(&test,76,9,-1);
1886 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1887 checkpacket(&test,34,10,-1);
1888 fprintf(stderr,"ok.\n");
1891 /* Test lost pages on pagein/packetout: rollback with continuation */
1893 ogg_page temp;
1894 ogg_packet test;
1896 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1898 ogg_sync_reset(&oy);
1899 ogg_stream_reset(&os_de);
1900 for(i=0;i<5;i++){
1901 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1902 og[i].header_len);
1903 ogg_sync_wrote(&oy,og[i].header_len);
1904 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1905 ogg_sync_wrote(&oy,og[i].body_len);
1908 ogg_sync_pageout(&oy,&temp);
1909 ogg_stream_pagein(&os_de,&temp);
1910 ogg_sync_pageout(&oy,&temp);
1911 ogg_stream_pagein(&os_de,&temp);
1912 ogg_sync_pageout(&oy,&temp);
1913 ogg_stream_pagein(&os_de,&temp);
1914 ogg_sync_pageout(&oy,&temp);
1915 /* skip */
1916 ogg_sync_pageout(&oy,&temp);
1917 ogg_stream_pagein(&os_de,&temp);
1919 /* do we get the expected results/packets? */
1921 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1922 checkpacket(&test,0,0,0);
1923 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1924 checkpacket(&test,1,1,-1);
1925 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1926 checkpacket(&test,1,2,-1);
1927 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1928 checkpacket(&test,98,3,-1);
1929 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1930 checkpacket(&test,4079,4,5000);
1931 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1932 checkpacket(&test,1,5,-1);
1933 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1934 checkpacket(&test,1,6,-1);
1935 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1936 checkpacket(&test,2954,7,-1);
1937 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1938 checkpacket(&test,2057,8,9000);
1939 if(ogg_stream_packetout(&os_de,&test)!=-1){
1940 fprintf(stderr,"Error: loss of page did not return error\n");
1941 exit(1);
1943 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1944 checkpacket(&test,300,17,18000);
1945 fprintf(stderr,"ok.\n");
1948 /* the rest only test sync */
1950 ogg_page og_de;
1951 /* Test fractional page inputs: incomplete capture */
1952 fprintf(stderr,"Testing sync on partial inputs... ");
1953 ogg_sync_reset(&oy);
1954 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1955 3);
1956 ogg_sync_wrote(&oy,3);
1957 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1959 /* Test fractional page inputs: incomplete fixed header */
1960 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1961 20);
1962 ogg_sync_wrote(&oy,20);
1963 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1965 /* Test fractional page inputs: incomplete header */
1966 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1967 5);
1968 ogg_sync_wrote(&oy,5);
1969 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1971 /* Test fractional page inputs: incomplete body */
1973 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1974 og[1].header_len-28);
1975 ogg_sync_wrote(&oy,og[1].header_len-28);
1976 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1978 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1979 ogg_sync_wrote(&oy,1000);
1980 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1982 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1983 og[1].body_len-1000);
1984 ogg_sync_wrote(&oy,og[1].body_len-1000);
1985 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1987 fprintf(stderr,"ok.\n");
1990 /* Test fractional page inputs: page + incomplete capture */
1992 ogg_page og_de;
1993 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1994 ogg_sync_reset(&oy);
1996 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1997 og[1].header_len);
1998 ogg_sync_wrote(&oy,og[1].header_len);
2000 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2001 og[1].body_len);
2002 ogg_sync_wrote(&oy,og[1].body_len);
2004 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2005 20);
2006 ogg_sync_wrote(&oy,20);
2007 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2008 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2010 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
2011 og[1].header_len-20);
2012 ogg_sync_wrote(&oy,og[1].header_len-20);
2013 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2014 og[1].body_len);
2015 ogg_sync_wrote(&oy,og[1].body_len);
2016 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2018 fprintf(stderr,"ok.\n");
2021 /* Test recapture: garbage + page */
2023 ogg_page og_de;
2024 fprintf(stderr,"Testing search for capture... ");
2025 ogg_sync_reset(&oy);
2027 /* 'garbage' */
2028 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2029 og[1].body_len);
2030 ogg_sync_wrote(&oy,og[1].body_len);
2032 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2033 og[1].header_len);
2034 ogg_sync_wrote(&oy,og[1].header_len);
2036 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2037 og[1].body_len);
2038 ogg_sync_wrote(&oy,og[1].body_len);
2040 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2041 20);
2042 ogg_sync_wrote(&oy,20);
2043 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2044 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2045 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2047 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2048 og[2].header_len-20);
2049 ogg_sync_wrote(&oy,og[2].header_len-20);
2050 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2051 og[2].body_len);
2052 ogg_sync_wrote(&oy,og[2].body_len);
2053 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2055 fprintf(stderr,"ok.\n");
2058 /* Test recapture: page + garbage + page */
2060 ogg_page og_de;
2061 fprintf(stderr,"Testing recapture... ");
2062 ogg_sync_reset(&oy);
2064 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2065 og[1].header_len);
2066 ogg_sync_wrote(&oy,og[1].header_len);
2068 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2069 og[1].body_len);
2070 ogg_sync_wrote(&oy,og[1].body_len);
2072 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2073 og[2].header_len);
2074 ogg_sync_wrote(&oy,og[2].header_len);
2076 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2077 og[2].header_len);
2078 ogg_sync_wrote(&oy,og[2].header_len);
2080 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2082 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2083 og[2].body_len-5);
2084 ogg_sync_wrote(&oy,og[2].body_len-5);
2086 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2087 og[3].header_len);
2088 ogg_sync_wrote(&oy,og[3].header_len);
2090 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2091 og[3].body_len);
2092 ogg_sync_wrote(&oy,og[3].body_len);
2094 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2095 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2097 fprintf(stderr,"ok.\n");
2100 /* Free page data that was previously copied */
2102 for(i=0;i<5;i++){
2103 free_page(&og[i]);
2108 return(0);
2111 #endif