Bug 436663. Work around ATSUI crasher caused by long Hebrew sequence. r=roc, sr=vlad
[wine-gecko.git] / media / libogg / src / framing.c
blobd9942d3ea4f91f925a30b859b3e8c47e71fba1a9
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
13 function: code raw [Vorbis] packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
15 last mod: $Id: framing.c 9601 2005-07-23 00:19:14Z giles $
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 <string.h>
25 #include <ogg/ogg.h>
27 /* A complete description of Ogg framing exists in docs/framing.html */
29 int ogg_page_version(ogg_page *og){
30 return((int)(og->header[4]));
33 int ogg_page_continued(ogg_page *og){
34 return((int)(og->header[5]&0x01));
37 int ogg_page_bos(ogg_page *og){
38 return((int)(og->header[5]&0x02));
41 int ogg_page_eos(ogg_page *og){
42 return((int)(og->header[5]&0x04));
45 ogg_int64_t ogg_page_granulepos(ogg_page *og){
46 unsigned char *page=og->header;
47 ogg_int64_t granulepos=page[13]&(0xff);
48 granulepos= (granulepos<<8)|(page[12]&0xff);
49 granulepos= (granulepos<<8)|(page[11]&0xff);
50 granulepos= (granulepos<<8)|(page[10]&0xff);
51 granulepos= (granulepos<<8)|(page[9]&0xff);
52 granulepos= (granulepos<<8)|(page[8]&0xff);
53 granulepos= (granulepos<<8)|(page[7]&0xff);
54 granulepos= (granulepos<<8)|(page[6]&0xff);
55 return(granulepos);
58 int ogg_page_serialno(ogg_page *og){
59 return(og->header[14] |
60 (og->header[15]<<8) |
61 (og->header[16]<<16) |
62 (og->header[17]<<24));
65 long ogg_page_pageno(ogg_page *og){
66 return(og->header[18] |
67 (og->header[19]<<8) |
68 (og->header[20]<<16) |
69 (og->header[21]<<24));
74 /* returns the number of packets that are completed on this page (if
75 the leading packet is begun on a previous page, but ends on this
76 page, it's counted */
78 /* NOTE:
79 If a page consists of a packet begun on a previous page, and a new
80 packet begun (but not completed) on this page, the return will be:
81 ogg_page_packets(page) ==1,
82 ogg_page_continued(page) !=0
84 If a page happens to be a single packet that was begun on a
85 previous page, and spans to the next page (in the case of a three or
86 more page packet), the return will be:
87 ogg_page_packets(page) ==0,
88 ogg_page_continued(page) !=0
91 int ogg_page_packets(ogg_page *og){
92 int i,n=og->header[26],count=0;
93 for(i=0;i<n;i++)
94 if(og->header[27+i]<255)count++;
95 return(count);
99 #if 0
100 /* helper to initialize lookup for direct-table CRC (illustrative; we
101 use the static init below) */
103 static ogg_uint32_t _ogg_crc_entry(unsigned long index){
104 int i;
105 unsigned long r;
107 r = index << 24;
108 for (i=0; i<8; i++)
109 if (r & 0x80000000UL)
110 r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
111 polynomial, although we use an
112 unreflected alg and an init/final
113 of 0, not 0xffffffff */
114 else
115 r<<=1;
116 return (r & 0xffffffffUL);
118 #endif
120 static const ogg_uint32_t crc_lookup[256]={
121 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
122 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
123 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
124 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
125 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
126 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
127 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
128 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
129 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
130 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
131 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
132 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
133 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
134 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
135 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
136 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
137 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
138 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
139 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
140 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
141 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
142 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
143 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
144 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
145 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
146 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
147 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
148 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
149 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
150 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
151 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
152 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
153 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
154 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
155 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
156 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
157 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
158 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
159 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
160 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
161 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
162 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
163 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
164 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
165 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
166 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
167 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
168 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
169 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
170 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
171 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
172 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
173 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
174 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
175 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
176 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
177 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
178 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
179 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
180 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
181 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
182 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
183 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
184 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
186 /* init the encode/decode logical stream state */
188 int ogg_stream_init(ogg_stream_state *os,int serialno){
189 if(os){
190 memset(os,0,sizeof(*os));
191 os->body_storage=16*1024;
192 os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
194 os->lacing_storage=1024;
195 os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
196 os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
198 os->serialno=serialno;
200 return(0);
202 return(-1);
205 /* _clear does not free os, only the non-flat storage within */
206 int ogg_stream_clear(ogg_stream_state *os){
207 if(os){
208 if(os->body_data)_ogg_free(os->body_data);
209 if(os->lacing_vals)_ogg_free(os->lacing_vals);
210 if(os->granule_vals)_ogg_free(os->granule_vals);
212 memset(os,0,sizeof(*os));
214 return(0);
217 int ogg_stream_destroy(ogg_stream_state *os){
218 if(os){
219 ogg_stream_clear(os);
220 _ogg_free(os);
222 return(0);
225 /* Helpers for ogg_stream_encode; this keeps the structure and
226 what's happening fairly clear */
228 static void _os_body_expand(ogg_stream_state *os,int needed){
229 if(os->body_storage<=os->body_fill+needed){
230 os->body_storage+=(needed+1024);
231 os->body_data=_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
235 static void _os_lacing_expand(ogg_stream_state *os,int needed){
236 if(os->lacing_storage<=os->lacing_fill+needed){
237 os->lacing_storage+=(needed+32);
238 os->lacing_vals=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
239 os->granule_vals=_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
243 /* checksum the page */
244 /* Direct table CRC; note that this will be faster in the future if we
245 perform the checksum silmultaneously with other copies */
247 void ogg_page_checksum_set(ogg_page *og){
248 if(og){
249 ogg_uint32_t crc_reg=0;
250 int i;
252 /* safety; needed for API behavior, but not framing code */
253 og->header[22]=0;
254 og->header[23]=0;
255 og->header[24]=0;
256 og->header[25]=0;
258 for(i=0;i<og->header_len;i++)
259 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
260 for(i=0;i<og->body_len;i++)
261 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
263 og->header[22]=(unsigned char)(crc_reg&0xff);
264 og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
265 og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
266 og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
270 /* submit data to the internal buffer of the framing engine */
271 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
272 int lacing_vals=op->bytes/255+1,i;
274 if(os->body_returned){
275 /* advance packet data according to the body_returned pointer. We
276 had to keep it around to return a pointer into the buffer last
277 call */
279 os->body_fill-=os->body_returned;
280 if(os->body_fill)
281 memmove(os->body_data,os->body_data+os->body_returned,
282 os->body_fill);
283 os->body_returned=0;
286 /* make sure we have the buffer storage */
287 _os_body_expand(os,op->bytes);
288 _os_lacing_expand(os,lacing_vals);
290 /* Copy in the submitted packet. Yes, the copy is a waste; this is
291 the liability of overly clean abstraction for the time being. It
292 will actually be fairly easy to eliminate the extra copy in the
293 future */
295 memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
296 os->body_fill+=op->bytes;
298 /* Store lacing vals for this packet */
299 for(i=0;i<lacing_vals-1;i++){
300 os->lacing_vals[os->lacing_fill+i]=255;
301 os->granule_vals[os->lacing_fill+i]=os->granulepos;
303 os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
304 os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos;
306 /* flag the first segment as the beginning of the packet */
307 os->lacing_vals[os->lacing_fill]|= 0x100;
309 os->lacing_fill+=lacing_vals;
311 /* for the sake of completeness */
312 os->packetno++;
314 if(op->e_o_s)os->e_o_s=1;
316 return(0);
319 /* This will flush remaining packets into a page (returning nonzero),
320 even if there is not enough data to trigger a flush normally
321 (undersized page). If there are no packets or partial packets to
322 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
323 try to flush a normal sized page like ogg_stream_pageout; a call to
324 ogg_stream_flush does not guarantee that all packets have flushed.
325 Only a return value of 0 from ogg_stream_flush indicates all packet
326 data is flushed into pages.
328 since ogg_stream_flush will flush the last page in a stream even if
329 it's undersized, you almost certainly want to use ogg_stream_pageout
330 (and *not* ogg_stream_flush) unless you specifically need to flush
331 an page regardless of size in the middle of a stream. */
333 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
334 int i;
335 int vals=0;
336 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
337 int bytes=0;
338 long acc=0;
339 ogg_int64_t granule_pos=-1;
341 if(maxvals==0)return(0);
343 /* construct a page */
344 /* decide how many segments to include */
346 /* If this is the initial header case, the first page must only include
347 the initial header packet */
348 if(os->b_o_s==0){ /* 'initial header page' case */
349 granule_pos=0;
350 for(vals=0;vals<maxvals;vals++){
351 if((os->lacing_vals[vals]&0x0ff)<255){
352 vals++;
353 break;
356 }else{
357 for(vals=0;vals<maxvals;vals++){
358 if(acc>4096)break;
359 acc+=os->lacing_vals[vals]&0x0ff;
360 if((os->lacing_vals[vals]&0xff)<255)
361 granule_pos=os->granule_vals[vals];
365 /* construct the header in temp storage */
366 memcpy(os->header,"OggS",4);
368 /* stream structure version */
369 os->header[4]=0x00;
371 /* continued packet flag? */
372 os->header[5]=0x00;
373 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
374 /* first page flag? */
375 if(os->b_o_s==0)os->header[5]|=0x02;
376 /* last page flag? */
377 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
378 os->b_o_s=1;
380 /* 64 bits of PCM position */
381 for(i=6;i<14;i++){
382 os->header[i]=(unsigned char)(granule_pos&0xff);
383 granule_pos>>=8;
386 /* 32 bits of stream serial number */
388 long serialno=os->serialno;
389 for(i=14;i<18;i++){
390 os->header[i]=(unsigned char)(serialno&0xff);
391 serialno>>=8;
395 /* 32 bits of page counter (we have both counter and page header
396 because this val can roll over) */
397 if(os->pageno==-1)os->pageno=0; /* because someone called
398 stream_reset; this would be a
399 strange thing to do in an
400 encode stream, but it has
401 plausible uses */
403 long pageno=os->pageno++;
404 for(i=18;i<22;i++){
405 os->header[i]=(unsigned char)(pageno&0xff);
406 pageno>>=8;
410 /* zero for computation; filled in later */
411 os->header[22]=0;
412 os->header[23]=0;
413 os->header[24]=0;
414 os->header[25]=0;
416 /* segment table */
417 os->header[26]=(unsigned char)(vals&0xff);
418 for(i=0;i<vals;i++)
419 bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
421 /* set pointers in the ogg_page struct */
422 og->header=os->header;
423 og->header_len=os->header_fill=vals+27;
424 og->body=os->body_data+os->body_returned;
425 og->body_len=bytes;
427 /* advance the lacing data and set the body_returned pointer */
429 os->lacing_fill-=vals;
430 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
431 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
432 os->body_returned+=bytes;
434 /* calculate the checksum */
436 ogg_page_checksum_set(og);
438 /* done */
439 return(1);
443 /* This constructs pages from buffered packet segments. The pointers
444 returned are to static buffers; do not free. The returned buffers are
445 good only until the next call (using the same ogg_stream_state) */
447 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
449 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
450 os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */
451 os->lacing_fill>=255 || /* 'segment table full' case */
452 (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */
454 return(ogg_stream_flush(os,og));
457 /* not enough data to construct a page and not end of stream */
458 return(0);
461 int ogg_stream_eos(ogg_stream_state *os){
462 return os->e_o_s;
465 /* DECODING PRIMITIVES: packet streaming layer **********************/
467 /* This has two layers to place more of the multi-serialno and paging
468 control in the application's hands. First, we expose a data buffer
469 using ogg_sync_buffer(). The app either copies into the
470 buffer, or passes it directly to read(), etc. We then call
471 ogg_sync_wrote() to tell how many bytes we just added.
473 Pages are returned (pointers into the buffer in ogg_sync_state)
474 by ogg_sync_pageout(). The page is then submitted to
475 ogg_stream_pagein() along with the appropriate
476 ogg_stream_state* (ie, matching serialno). We then get raw
477 packets out calling ogg_stream_packetout() with a
478 ogg_stream_state. */
480 /* initialize the struct to a known state */
481 int ogg_sync_init(ogg_sync_state *oy){
482 if(oy){
483 memset(oy,0,sizeof(*oy));
485 return(0);
488 /* clear non-flat storage within */
489 int ogg_sync_clear(ogg_sync_state *oy){
490 if(oy){
491 if(oy->data)_ogg_free(oy->data);
492 ogg_sync_init(oy);
494 return(0);
497 int ogg_sync_destroy(ogg_sync_state *oy){
498 if(oy){
499 ogg_sync_clear(oy);
500 _ogg_free(oy);
502 return(0);
505 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
507 /* first, clear out any space that has been previously returned */
508 if(oy->returned){
509 oy->fill-=oy->returned;
510 if(oy->fill>0)
511 memmove(oy->data,oy->data+oy->returned,oy->fill);
512 oy->returned=0;
515 if(size>oy->storage-oy->fill){
516 /* We need to extend the internal buffer */
517 long newsize=size+oy->fill+4096; /* an extra page to be nice */
519 if(oy->data)
520 oy->data=_ogg_realloc(oy->data,newsize);
521 else
522 oy->data=_ogg_malloc(newsize);
523 oy->storage=newsize;
526 /* expose a segment at least as large as requested at the fill mark */
527 return((char *)oy->data+oy->fill);
530 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
531 if(oy->fill+bytes>oy->storage)return(-1);
532 oy->fill+=bytes;
533 return(0);
536 /* sync the stream. This is meant to be useful for finding page
537 boundaries.
539 return values for this:
540 -n) skipped n bytes
541 0) page not ready; more data (no bytes skipped)
542 n) page synced at current location; page length n bytes
546 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
547 unsigned char *page=oy->data+oy->returned;
548 unsigned char *next;
549 long bytes=oy->fill-oy->returned;
551 if(oy->headerbytes==0){
552 int headerbytes,i;
553 if(bytes<27)return(0); /* not enough for a header */
555 /* verify capture pattern */
556 if(memcmp(page,"OggS",4))goto sync_fail;
558 headerbytes=page[26]+27;
559 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
561 /* count up body length in the segment table */
563 for(i=0;i<page[26];i++)
564 oy->bodybytes+=page[27+i];
565 oy->headerbytes=headerbytes;
568 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
570 /* The whole test page is buffered. Verify the checksum */
572 /* Grab the checksum bytes, set the header field to zero */
573 char chksum[4];
574 ogg_page log;
576 memcpy(chksum,page+22,4);
577 memset(page+22,0,4);
579 /* set up a temp page struct and recompute the checksum */
580 log.header=page;
581 log.header_len=oy->headerbytes;
582 log.body=page+oy->headerbytes;
583 log.body_len=oy->bodybytes;
584 ogg_page_checksum_set(&log);
586 /* Compare */
587 if(memcmp(chksum,page+22,4)){
588 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
589 at all) */
590 /* replace the computed checksum with the one actually read in */
591 memcpy(page+22,chksum,4);
593 /* Bad checksum. Lose sync */
594 goto sync_fail;
598 /* yes, have a whole page all ready to go */
600 unsigned char *page=oy->data+oy->returned;
601 long bytes;
603 if(og){
604 og->header=page;
605 og->header_len=oy->headerbytes;
606 og->body=page+oy->headerbytes;
607 og->body_len=oy->bodybytes;
610 oy->unsynced=0;
611 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
612 oy->headerbytes=0;
613 oy->bodybytes=0;
614 return(bytes);
617 sync_fail:
619 oy->headerbytes=0;
620 oy->bodybytes=0;
622 /* search for possible capture */
623 next=memchr(page+1,'O',bytes-1);
624 if(!next)
625 next=oy->data+oy->fill;
627 oy->returned=next-oy->data;
628 return(-(next-page));
631 /* sync the stream and get a page. Keep trying until we find a page.
632 Supress 'sync errors' after reporting the first.
634 return values:
635 -1) recapture (hole in data)
636 0) need more data
637 1) page returned
639 Returns pointers into buffered data; invalidated by next call to
640 _stream, _clear, _init, or _buffer */
642 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
644 /* all we need to do is verify a page at the head of the stream
645 buffer. If it doesn't verify, we look for the next potential
646 frame */
648 for(;;){
649 long ret=ogg_sync_pageseek(oy,og);
650 if(ret>0){
651 /* have a page */
652 return(1);
654 if(ret==0){
655 /* need more data */
656 return(0);
659 /* head did not start a synced page... skipped some bytes */
660 if(!oy->unsynced){
661 oy->unsynced=1;
662 return(-1);
665 /* loop. keep looking */
670 /* add the incoming page to the stream state; we decompose the page
671 into packet segments here as well. */
673 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
674 unsigned char *header=og->header;
675 unsigned char *body=og->body;
676 long bodysize=og->body_len;
677 int segptr=0;
679 int version=ogg_page_version(og);
680 int continued=ogg_page_continued(og);
681 int bos=ogg_page_bos(og);
682 int eos=ogg_page_eos(og);
683 ogg_int64_t granulepos=ogg_page_granulepos(og);
684 int serialno=ogg_page_serialno(og);
685 long pageno=ogg_page_pageno(og);
686 int segments=header[26];
688 /* clean up 'returned data' */
690 long lr=os->lacing_returned;
691 long br=os->body_returned;
693 /* body data */
694 if(br){
695 os->body_fill-=br;
696 if(os->body_fill)
697 memmove(os->body_data,os->body_data+br,os->body_fill);
698 os->body_returned=0;
701 if(lr){
702 /* segment table */
703 if(os->lacing_fill-lr){
704 memmove(os->lacing_vals,os->lacing_vals+lr,
705 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
706 memmove(os->granule_vals,os->granule_vals+lr,
707 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
709 os->lacing_fill-=lr;
710 os->lacing_packet-=lr;
711 os->lacing_returned=0;
715 /* check the serial number */
716 if(serialno!=os->serialno)return(-1);
717 if(version>0)return(-1);
719 _os_lacing_expand(os,segments+1);
721 /* are we in sequence? */
722 if(pageno!=os->pageno){
723 int i;
725 /* unroll previous partial packet (if any) */
726 for(i=os->lacing_packet;i<os->lacing_fill;i++)
727 os->body_fill-=os->lacing_vals[i]&0xff;
728 os->lacing_fill=os->lacing_packet;
730 /* make a note of dropped data in segment table */
731 if(os->pageno!=-1){
732 os->lacing_vals[os->lacing_fill++]=0x400;
733 os->lacing_packet++;
737 /* are we a 'continued packet' page? If so, we may need to skip
738 some segments */
739 if(continued){
740 if(os->lacing_fill<1 ||
741 os->lacing_vals[os->lacing_fill-1]==0x400){
742 bos=0;
743 for(;segptr<segments;segptr++){
744 int val=header[27+segptr];
745 body+=val;
746 bodysize-=val;
747 if(val<255){
748 segptr++;
749 break;
755 if(bodysize){
756 _os_body_expand(os,bodysize);
757 memcpy(os->body_data+os->body_fill,body,bodysize);
758 os->body_fill+=bodysize;
762 int saved=-1;
763 while(segptr<segments){
764 int val=header[27+segptr];
765 os->lacing_vals[os->lacing_fill]=val;
766 os->granule_vals[os->lacing_fill]=-1;
768 if(bos){
769 os->lacing_vals[os->lacing_fill]|=0x100;
770 bos=0;
773 if(val<255)saved=os->lacing_fill;
775 os->lacing_fill++;
776 segptr++;
778 if(val<255)os->lacing_packet=os->lacing_fill;
781 /* set the granulepos on the last granuleval of the last full packet */
782 if(saved!=-1){
783 os->granule_vals[saved]=granulepos;
788 if(eos){
789 os->e_o_s=1;
790 if(os->lacing_fill>0)
791 os->lacing_vals[os->lacing_fill-1]|=0x200;
794 os->pageno=pageno+1;
796 return(0);
799 /* clear things to an initial state. Good to call, eg, before seeking */
800 int ogg_sync_reset(ogg_sync_state *oy){
801 oy->fill=0;
802 oy->returned=0;
803 oy->unsynced=0;
804 oy->headerbytes=0;
805 oy->bodybytes=0;
806 return(0);
809 int ogg_stream_reset(ogg_stream_state *os){
810 os->body_fill=0;
811 os->body_returned=0;
813 os->lacing_fill=0;
814 os->lacing_packet=0;
815 os->lacing_returned=0;
817 os->header_fill=0;
819 os->e_o_s=0;
820 os->b_o_s=0;
821 os->pageno=-1;
822 os->packetno=0;
823 os->granulepos=0;
825 return(0);
828 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
829 ogg_stream_reset(os);
830 os->serialno=serialno;
831 return(0);
834 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
836 /* The last part of decode. We have the stream broken into packet
837 segments. Now we need to group them into packets (or return the
838 out of sync markers) */
840 int ptr=os->lacing_returned;
842 if(os->lacing_packet<=ptr)return(0);
844 if(os->lacing_vals[ptr]&0x400){
845 /* we need to tell the codec there's a gap; it might need to
846 handle previous packet dependencies. */
847 os->lacing_returned++;
848 os->packetno++;
849 return(-1);
852 if(!op && !adv)return(1); /* just using peek as an inexpensive way
853 to ask if there's a whole packet
854 waiting */
856 /* Gather the whole packet. We'll have no holes or a partial packet */
858 int size=os->lacing_vals[ptr]&0xff;
859 int bytes=size;
860 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
861 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
863 while(size==255){
864 int val=os->lacing_vals[++ptr];
865 size=val&0xff;
866 if(val&0x200)eos=0x200;
867 bytes+=size;
870 if(op){
871 op->e_o_s=eos;
872 op->b_o_s=bos;
873 op->packet=os->body_data+os->body_returned;
874 op->packetno=os->packetno;
875 op->granulepos=os->granule_vals[ptr];
876 op->bytes=bytes;
879 if(adv){
880 os->body_returned+=bytes;
881 os->lacing_returned=ptr+1;
882 os->packetno++;
885 return(1);
888 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
889 return _packetout(os,op,1);
892 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
893 return _packetout(os,op,0);
896 void ogg_packet_clear(ogg_packet *op) {
897 _ogg_free(op->packet);
898 memset(op, 0, sizeof(*op));
901 #ifdef _V_SELFTEST
902 #include <stdio.h>
904 ogg_stream_state os_en, os_de;
905 ogg_sync_state oy;
907 void checkpacket(ogg_packet *op,int len, int no, int pos){
908 long j;
909 static int sequence=0;
910 static int lastno=0;
912 if(op->bytes!=len){
913 fprintf(stderr,"incorrect packet length!\n");
914 exit(1);
916 if(op->granulepos!=pos){
917 fprintf(stderr,"incorrect packet position!\n");
918 exit(1);
921 /* packet number just follows sequence/gap; adjust the input number
922 for that */
923 if(no==0){
924 sequence=0;
925 }else{
926 sequence++;
927 if(no>lastno+1)
928 sequence++;
930 lastno=no;
931 if(op->packetno!=sequence){
932 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
933 (long)(op->packetno),sequence);
934 exit(1);
937 /* Test data */
938 for(j=0;j<op->bytes;j++)
939 if(op->packet[j]!=((j+no)&0xff)){
940 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
941 j,op->packet[j],(j+no)&0xff);
942 exit(1);
946 void check_page(unsigned char *data,const int *header,ogg_page *og){
947 long j;
948 /* Test data */
949 for(j=0;j<og->body_len;j++)
950 if(og->body[j]!=data[j]){
951 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
952 j,data[j],og->body[j]);
953 exit(1);
956 /* Test header */
957 for(j=0;j<og->header_len;j++){
958 if(og->header[j]!=header[j]){
959 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
960 for(j=0;j<header[26]+27;j++)
961 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
962 fprintf(stderr,"\n");
963 exit(1);
966 if(og->header_len!=header[26]+27){
967 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
968 og->header_len,header[26]+27);
969 exit(1);
973 void print_header(ogg_page *og){
974 int j;
975 fprintf(stderr,"\nHEADER:\n");
976 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
977 og->header[0],og->header[1],og->header[2],og->header[3],
978 (int)og->header[4],(int)og->header[5]);
980 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
981 (og->header[9]<<24)|(og->header[8]<<16)|
982 (og->header[7]<<8)|og->header[6],
983 (og->header[17]<<24)|(og->header[16]<<16)|
984 (og->header[15]<<8)|og->header[14],
985 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
986 (og->header[19]<<8)|og->header[18]);
988 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
989 (int)og->header[22],(int)og->header[23],
990 (int)og->header[24],(int)og->header[25],
991 (int)og->header[26]);
993 for(j=27;j<og->header_len;j++)
994 fprintf(stderr,"%d ",(int)og->header[j]);
995 fprintf(stderr,")\n\n");
998 void copy_page(ogg_page *og){
999 unsigned char *temp=_ogg_malloc(og->header_len);
1000 memcpy(temp,og->header,og->header_len);
1001 og->header=temp;
1003 temp=_ogg_malloc(og->body_len);
1004 memcpy(temp,og->body,og->body_len);
1005 og->body=temp;
1008 void free_page(ogg_page *og){
1009 _ogg_free (og->header);
1010 _ogg_free (og->body);
1013 void error(void){
1014 fprintf(stderr,"error!\n");
1015 exit(1);
1018 /* 17 only */
1019 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1020 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1021 0x01,0x02,0x03,0x04,0,0,0,0,
1022 0x15,0xed,0xec,0x91,
1024 17};
1026 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1027 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1028 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1029 0x01,0x02,0x03,0x04,0,0,0,0,
1030 0x59,0x10,0x6c,0x2c,
1032 17};
1033 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1034 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1035 0x01,0x02,0x03,0x04,1,0,0,0,
1036 0x89,0x33,0x85,0xce,
1038 254,255,0,255,1,255,245,255,255,0,
1039 255,255,90};
1041 /* nil packets; beginning,middle,end */
1042 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1043 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1044 0x01,0x02,0x03,0x04,0,0,0,0,
1045 0xff,0x7b,0x23,0x17,
1048 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1049 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1050 0x01,0x02,0x03,0x04,1,0,0,0,
1051 0x5c,0x3f,0x66,0xcb,
1053 17,254,255,0,0,255,1,0,255,245,255,255,0,
1054 255,255,90,0};
1056 /* large initial packet */
1057 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1058 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1059 0x01,0x02,0x03,0x04,0,0,0,0,
1060 0x01,0x27,0x31,0xaa,
1062 255,255,255,255,255,255,255,255,
1063 255,255,255,255,255,255,255,255,255,10};
1065 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1066 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1067 0x01,0x02,0x03,0x04,1,0,0,0,
1068 0x7f,0x4e,0x8a,0xd2,
1070 255,4,255,0};
1073 /* continuing packet test */
1074 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1075 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1076 0x01,0x02,0x03,0x04,0,0,0,0,
1077 0xff,0x7b,0x23,0x17,
1081 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1082 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1083 0x01,0x02,0x03,0x04,1,0,0,0,
1084 0x54,0x05,0x51,0xc8,
1086 255,255,255,255,255,255,255,255,
1087 255,255,255,255,255,255,255,255,255};
1089 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1090 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1091 0x01,0x02,0x03,0x04,2,0,0,0,
1092 0xc8,0xc3,0xcb,0xed,
1094 10,255,4,255,0};
1097 /* page with the 255 segment limit */
1098 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1099 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1100 0x01,0x02,0x03,0x04,0,0,0,0,
1101 0xff,0x7b,0x23,0x17,
1105 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1106 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1107 0x01,0x02,0x03,0x04,1,0,0,0,
1108 0xed,0x2a,0x2e,0xa7,
1109 255,
1110 10,10,10,10,10,10,10,10,
1111 10,10,10,10,10,10,10,10,
1112 10,10,10,10,10,10,10,10,
1113 10,10,10,10,10,10,10,10,
1114 10,10,10,10,10,10,10,10,
1115 10,10,10,10,10,10,10,10,
1116 10,10,10,10,10,10,10,10,
1117 10,10,10,10,10,10,10,10,
1118 10,10,10,10,10,10,10,10,
1119 10,10,10,10,10,10,10,10,
1120 10,10,10,10,10,10,10,10,
1121 10,10,10,10,10,10,10,10,
1122 10,10,10,10,10,10,10,10,
1123 10,10,10,10,10,10,10,10,
1124 10,10,10,10,10,10,10,10,
1125 10,10,10,10,10,10,10,10,
1126 10,10,10,10,10,10,10,10,
1127 10,10,10,10,10,10,10,10,
1128 10,10,10,10,10,10,10,10,
1129 10,10,10,10,10,10,10,10,
1130 10,10,10,10,10,10,10,10,
1131 10,10,10,10,10,10,10,10,
1132 10,10,10,10,10,10,10,10,
1133 10,10,10,10,10,10,10,10,
1134 10,10,10,10,10,10,10,10,
1135 10,10,10,10,10,10,10,10,
1136 10,10,10,10,10,10,10,10,
1137 10,10,10,10,10,10,10,10,
1138 10,10,10,10,10,10,10,10,
1139 10,10,10,10,10,10,10,10,
1140 10,10,10,10,10,10,10,10,
1141 10,10,10,10,10,10,10};
1143 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1144 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1145 0x01,0x02,0x03,0x04,2,0,0,0,
1146 0x6c,0x3b,0x82,0x3d,
1148 50};
1151 /* packet that overspans over an entire page */
1152 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1153 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1154 0x01,0x02,0x03,0x04,0,0,0,0,
1155 0xff,0x7b,0x23,0x17,
1159 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1160 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1161 0x01,0x02,0x03,0x04,1,0,0,0,
1162 0x3c,0xd9,0x4d,0x3f,
1164 100,255,255,255,255,255,255,255,255,
1165 255,255,255,255,255,255,255,255};
1167 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1168 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1169 0x01,0x02,0x03,0x04,2,0,0,0,
1170 0x01,0xd2,0xe5,0xe5,
1172 255,255,255,255,255,255,255,255,
1173 255,255,255,255,255,255,255,255,255};
1175 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1176 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1177 0x01,0x02,0x03,0x04,3,0,0,0,
1178 0xef,0xdd,0x88,0xde,
1180 255,255,75,255,4,255,0};
1182 /* packet that overspans over an entire page */
1183 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1184 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1185 0x01,0x02,0x03,0x04,0,0,0,0,
1186 0xff,0x7b,0x23,0x17,
1190 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1191 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1192 0x01,0x02,0x03,0x04,1,0,0,0,
1193 0x3c,0xd9,0x4d,0x3f,
1195 100,255,255,255,255,255,255,255,255,
1196 255,255,255,255,255,255,255,255};
1198 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1199 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1200 0x01,0x02,0x03,0x04,2,0,0,0,
1201 0xd4,0xe0,0x60,0xe5,
1202 1,0};
1204 void test_pack(const int *pl, const int **headers, int byteskip,
1205 int pageskip, int packetskip){
1206 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1207 long inptr=0;
1208 long outptr=0;
1209 long deptr=0;
1210 long depacket=0;
1211 long granule_pos=7,pageno=0;
1212 int i,j,packets,pageout=pageskip;
1213 int eosflag=0;
1214 int bosflag=0;
1216 int byteskipcount=0;
1218 ogg_stream_reset(&os_en);
1219 ogg_stream_reset(&os_de);
1220 ogg_sync_reset(&oy);
1222 for(packets=0;packets<packetskip;packets++)
1223 depacket+=pl[packets];
1225 for(packets=0;;packets++)if(pl[packets]==-1)break;
1227 for(i=0;i<packets;i++){
1228 /* construct a test packet */
1229 ogg_packet op;
1230 int len=pl[i];
1232 op.packet=data+inptr;
1233 op.bytes=len;
1234 op.e_o_s=(pl[i+1]<0?1:0);
1235 op.granulepos=granule_pos;
1237 granule_pos+=1024;
1239 for(j=0;j<len;j++)data[inptr++]=i+j;
1241 /* submit the test packet */
1242 ogg_stream_packetin(&os_en,&op);
1244 /* retrieve any finished pages */
1246 ogg_page og;
1248 while(ogg_stream_pageout(&os_en,&og)){
1249 /* We have a page. Check it carefully */
1251 fprintf(stderr,"%ld, ",pageno);
1253 if(headers[pageno]==NULL){
1254 fprintf(stderr,"coded too many pages!\n");
1255 exit(1);
1258 check_page(data+outptr,headers[pageno],&og);
1260 outptr+=og.body_len;
1261 pageno++;
1262 if(pageskip){
1263 bosflag=1;
1264 pageskip--;
1265 deptr+=og.body_len;
1268 /* have a complete page; submit it to sync/decode */
1271 ogg_page og_de;
1272 ogg_packet op_de,op_de2;
1273 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1274 char *next=buf;
1275 byteskipcount+=og.header_len;
1276 if(byteskipcount>byteskip){
1277 memcpy(next,og.header,byteskipcount-byteskip);
1278 next+=byteskipcount-byteskip;
1279 byteskipcount=byteskip;
1282 byteskipcount+=og.body_len;
1283 if(byteskipcount>byteskip){
1284 memcpy(next,og.body,byteskipcount-byteskip);
1285 next+=byteskipcount-byteskip;
1286 byteskipcount=byteskip;
1289 ogg_sync_wrote(&oy,next-buf);
1291 while(1){
1292 int ret=ogg_sync_pageout(&oy,&og_de);
1293 if(ret==0)break;
1294 if(ret<0)continue;
1295 /* got a page. Happy happy. Verify that it's good. */
1297 fprintf(stderr,"(%ld), ",pageout);
1299 check_page(data+deptr,headers[pageout],&og_de);
1300 deptr+=og_de.body_len;
1301 pageout++;
1303 /* submit it to deconstitution */
1304 ogg_stream_pagein(&os_de,&og_de);
1306 /* packets out? */
1307 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1308 ogg_stream_packetpeek(&os_de,NULL);
1309 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1311 /* verify peek and out match */
1312 if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1313 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1314 depacket);
1315 exit(1);
1318 /* verify the packet! */
1319 /* check data */
1320 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1321 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1322 depacket);
1323 exit(1);
1325 /* check bos flag */
1326 if(bosflag==0 && op_de.b_o_s==0){
1327 fprintf(stderr,"b_o_s flag not set on packet!\n");
1328 exit(1);
1330 if(bosflag && op_de.b_o_s){
1331 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1332 exit(1);
1334 bosflag=1;
1335 depacket+=op_de.bytes;
1337 /* check eos flag */
1338 if(eosflag){
1339 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1340 exit(1);
1343 if(op_de.e_o_s)eosflag=1;
1345 /* check granulepos flag */
1346 if(op_de.granulepos!=-1){
1347 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1355 _ogg_free(data);
1356 if(headers[pageno]!=NULL){
1357 fprintf(stderr,"did not write last page!\n");
1358 exit(1);
1360 if(headers[pageout]!=NULL){
1361 fprintf(stderr,"did not decode last page!\n");
1362 exit(1);
1364 if(inptr!=outptr){
1365 fprintf(stderr,"encoded page data incomplete!\n");
1366 exit(1);
1368 if(inptr!=deptr){
1369 fprintf(stderr,"decoded page data incomplete!\n");
1370 exit(1);
1372 if(inptr!=depacket){
1373 fprintf(stderr,"decoded packet data incomplete!\n");
1374 exit(1);
1376 if(!eosflag){
1377 fprintf(stderr,"Never got a packet with EOS set!\n");
1378 exit(1);
1380 fprintf(stderr,"ok.\n");
1383 int main(void){
1385 ogg_stream_init(&os_en,0x04030201);
1386 ogg_stream_init(&os_de,0x04030201);
1387 ogg_sync_init(&oy);
1389 /* Exercise each code path in the framing code. Also verify that
1390 the checksums are working. */
1393 /* 17 only */
1394 const int packets[]={17, -1};
1395 const int *headret[]={head1_0,NULL};
1397 fprintf(stderr,"testing single page encoding... ");
1398 test_pack(packets,headret,0,0,0);
1402 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1403 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1404 const int *headret[]={head1_1,head2_1,NULL};
1406 fprintf(stderr,"testing basic page encoding... ");
1407 test_pack(packets,headret,0,0,0);
1411 /* nil packets; beginning,middle,end */
1412 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1413 const int *headret[]={head1_2,head2_2,NULL};
1415 fprintf(stderr,"testing basic nil packets... ");
1416 test_pack(packets,headret,0,0,0);
1420 /* large initial packet */
1421 const int packets[]={4345,259,255,-1};
1422 const int *headret[]={head1_3,head2_3,NULL};
1424 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1425 test_pack(packets,headret,0,0,0);
1429 /* continuing packet test */
1430 const int packets[]={0,4345,259,255,-1};
1431 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1433 fprintf(stderr,"testing single packet page span... ");
1434 test_pack(packets,headret,0,0,0);
1437 /* page with the 255 segment limit */
1440 const int packets[]={0,10,10,10,10,10,10,10,10,
1441 10,10,10,10,10,10,10,10,
1442 10,10,10,10,10,10,10,10,
1443 10,10,10,10,10,10,10,10,
1444 10,10,10,10,10,10,10,10,
1445 10,10,10,10,10,10,10,10,
1446 10,10,10,10,10,10,10,10,
1447 10,10,10,10,10,10,10,10,
1448 10,10,10,10,10,10,10,10,
1449 10,10,10,10,10,10,10,10,
1450 10,10,10,10,10,10,10,10,
1451 10,10,10,10,10,10,10,10,
1452 10,10,10,10,10,10,10,10,
1453 10,10,10,10,10,10,10,10,
1454 10,10,10,10,10,10,10,10,
1455 10,10,10,10,10,10,10,10,
1456 10,10,10,10,10,10,10,10,
1457 10,10,10,10,10,10,10,10,
1458 10,10,10,10,10,10,10,10,
1459 10,10,10,10,10,10,10,10,
1460 10,10,10,10,10,10,10,10,
1461 10,10,10,10,10,10,10,10,
1462 10,10,10,10,10,10,10,10,
1463 10,10,10,10,10,10,10,10,
1464 10,10,10,10,10,10,10,10,
1465 10,10,10,10,10,10,10,10,
1466 10,10,10,10,10,10,10,10,
1467 10,10,10,10,10,10,10,10,
1468 10,10,10,10,10,10,10,10,
1469 10,10,10,10,10,10,10,10,
1470 10,10,10,10,10,10,10,10,
1471 10,10,10,10,10,10,10,50,-1};
1472 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1474 fprintf(stderr,"testing max packet segments... ");
1475 test_pack(packets,headret,0,0,0);
1479 /* packet that overspans over an entire page */
1480 const int packets[]={0,100,9000,259,255,-1};
1481 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1483 fprintf(stderr,"testing very large packets... ");
1484 test_pack(packets,headret,0,0,0);
1488 /* test for the libogg 1.1.1 resync in large continuation bug
1489 found by Josh Coalson) */
1490 const int packets[]={0,100,9000,259,255,-1};
1491 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1493 fprintf(stderr,"testing continuation resync in very large packets... ");
1494 test_pack(packets,headret,100,2,3);
1498 /* term only page. why not? */
1499 const int packets[]={0,100,4080,-1};
1500 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1502 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1503 test_pack(packets,headret,0,0,0);
1509 /* build a bunch of pages for testing */
1510 unsigned char *data=_ogg_malloc(1024*1024);
1511 int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
1512 int inptr=0,i,j;
1513 ogg_page og[5];
1515 ogg_stream_reset(&os_en);
1517 for(i=0;pl[i]!=-1;i++){
1518 ogg_packet op;
1519 int len=pl[i];
1521 op.packet=data+inptr;
1522 op.bytes=len;
1523 op.e_o_s=(pl[i+1]<0?1:0);
1524 op.granulepos=(i+1)*1000;
1526 for(j=0;j<len;j++)data[inptr++]=i+j;
1527 ogg_stream_packetin(&os_en,&op);
1530 _ogg_free(data);
1532 /* retrieve finished pages */
1533 for(i=0;i<5;i++){
1534 if(ogg_stream_pageout(&os_en,&og[i])==0){
1535 fprintf(stderr,"Too few pages output building sync tests!\n");
1536 exit(1);
1538 copy_page(&og[i]);
1541 /* Test lost pages on pagein/packetout: no rollback */
1543 ogg_page temp;
1544 ogg_packet test;
1546 fprintf(stderr,"Testing loss of pages... ");
1548 ogg_sync_reset(&oy);
1549 ogg_stream_reset(&os_de);
1550 for(i=0;i<5;i++){
1551 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1552 og[i].header_len);
1553 ogg_sync_wrote(&oy,og[i].header_len);
1554 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1555 ogg_sync_wrote(&oy,og[i].body_len);
1558 ogg_sync_pageout(&oy,&temp);
1559 ogg_stream_pagein(&os_de,&temp);
1560 ogg_sync_pageout(&oy,&temp);
1561 ogg_stream_pagein(&os_de,&temp);
1562 ogg_sync_pageout(&oy,&temp);
1563 /* skip */
1564 ogg_sync_pageout(&oy,&temp);
1565 ogg_stream_pagein(&os_de,&temp);
1567 /* do we get the expected results/packets? */
1569 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1570 checkpacket(&test,0,0,0);
1571 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1572 checkpacket(&test,100,1,-1);
1573 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1574 checkpacket(&test,4079,2,3000);
1575 if(ogg_stream_packetout(&os_de,&test)!=-1){
1576 fprintf(stderr,"Error: loss of page did not return error\n");
1577 exit(1);
1579 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1580 checkpacket(&test,76,5,-1);
1581 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1582 checkpacket(&test,34,6,-1);
1583 fprintf(stderr,"ok.\n");
1586 /* Test lost pages on pagein/packetout: rollback with continuation */
1588 ogg_page temp;
1589 ogg_packet test;
1591 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1593 ogg_sync_reset(&oy);
1594 ogg_stream_reset(&os_de);
1595 for(i=0;i<5;i++){
1596 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1597 og[i].header_len);
1598 ogg_sync_wrote(&oy,og[i].header_len);
1599 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1600 ogg_sync_wrote(&oy,og[i].body_len);
1603 ogg_sync_pageout(&oy,&temp);
1604 ogg_stream_pagein(&os_de,&temp);
1605 ogg_sync_pageout(&oy,&temp);
1606 ogg_stream_pagein(&os_de,&temp);
1607 ogg_sync_pageout(&oy,&temp);
1608 ogg_stream_pagein(&os_de,&temp);
1609 ogg_sync_pageout(&oy,&temp);
1610 /* skip */
1611 ogg_sync_pageout(&oy,&temp);
1612 ogg_stream_pagein(&os_de,&temp);
1614 /* do we get the expected results/packets? */
1616 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1617 checkpacket(&test,0,0,0);
1618 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1619 checkpacket(&test,100,1,-1);
1620 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1621 checkpacket(&test,4079,2,3000);
1622 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1623 checkpacket(&test,2956,3,4000);
1624 if(ogg_stream_packetout(&os_de,&test)!=-1){
1625 fprintf(stderr,"Error: loss of page did not return error\n");
1626 exit(1);
1628 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1629 checkpacket(&test,300,13,14000);
1630 fprintf(stderr,"ok.\n");
1633 /* the rest only test sync */
1635 ogg_page og_de;
1636 /* Test fractional page inputs: incomplete capture */
1637 fprintf(stderr,"Testing sync on partial inputs... ");
1638 ogg_sync_reset(&oy);
1639 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1641 ogg_sync_wrote(&oy,3);
1642 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1644 /* Test fractional page inputs: incomplete fixed header */
1645 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1646 20);
1647 ogg_sync_wrote(&oy,20);
1648 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1650 /* Test fractional page inputs: incomplete header */
1651 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1653 ogg_sync_wrote(&oy,5);
1654 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1656 /* Test fractional page inputs: incomplete body */
1658 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1659 og[1].header_len-28);
1660 ogg_sync_wrote(&oy,og[1].header_len-28);
1661 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1663 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1664 ogg_sync_wrote(&oy,1000);
1665 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1667 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1668 og[1].body_len-1000);
1669 ogg_sync_wrote(&oy,og[1].body_len-1000);
1670 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1672 fprintf(stderr,"ok.\n");
1675 /* Test fractional page inputs: page + incomplete capture */
1677 ogg_page og_de;
1678 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1679 ogg_sync_reset(&oy);
1681 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1682 og[1].header_len);
1683 ogg_sync_wrote(&oy,og[1].header_len);
1685 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1686 og[1].body_len);
1687 ogg_sync_wrote(&oy,og[1].body_len);
1689 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1690 20);
1691 ogg_sync_wrote(&oy,20);
1692 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1693 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1695 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1696 og[1].header_len-20);
1697 ogg_sync_wrote(&oy,og[1].header_len-20);
1698 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1699 og[1].body_len);
1700 ogg_sync_wrote(&oy,og[1].body_len);
1701 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1703 fprintf(stderr,"ok.\n");
1706 /* Test recapture: garbage + page */
1708 ogg_page og_de;
1709 fprintf(stderr,"Testing search for capture... ");
1710 ogg_sync_reset(&oy);
1712 /* 'garbage' */
1713 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1714 og[1].body_len);
1715 ogg_sync_wrote(&oy,og[1].body_len);
1717 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1718 og[1].header_len);
1719 ogg_sync_wrote(&oy,og[1].header_len);
1721 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1722 og[1].body_len);
1723 ogg_sync_wrote(&oy,og[1].body_len);
1725 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1726 20);
1727 ogg_sync_wrote(&oy,20);
1728 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1729 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1730 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1732 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
1733 og[2].header_len-20);
1734 ogg_sync_wrote(&oy,og[2].header_len-20);
1735 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1736 og[2].body_len);
1737 ogg_sync_wrote(&oy,og[2].body_len);
1738 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1740 fprintf(stderr,"ok.\n");
1743 /* Test recapture: page + garbage + page */
1745 ogg_page og_de;
1746 fprintf(stderr,"Testing recapture... ");
1747 ogg_sync_reset(&oy);
1749 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1750 og[1].header_len);
1751 ogg_sync_wrote(&oy,og[1].header_len);
1753 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1754 og[1].body_len);
1755 ogg_sync_wrote(&oy,og[1].body_len);
1757 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1758 og[2].header_len);
1759 ogg_sync_wrote(&oy,og[2].header_len);
1761 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1762 og[2].header_len);
1763 ogg_sync_wrote(&oy,og[2].header_len);
1765 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1767 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1768 og[2].body_len-5);
1769 ogg_sync_wrote(&oy,og[2].body_len-5);
1771 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
1772 og[3].header_len);
1773 ogg_sync_wrote(&oy,og[3].header_len);
1775 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
1776 og[3].body_len);
1777 ogg_sync_wrote(&oy,og[3].body_len);
1779 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1780 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1782 fprintf(stderr,"ok.\n");
1785 /* Free page data that was previously copied */
1787 for(i=0;i<5;i++){
1788 free_page(&og[i]);
1793 return(0);
1796 #endif