framing.c (49564B)
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 ******************************************************************** 12 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 1919 2005-07-24 14:18:04Z baford $ 16 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. 20 21 ********************************************************************/ 22 23 #include <stdlib.h> 24 #include <string.h> 25 #include <ogg/ogg.h> 26 27 /* A complete description of Ogg framing exists in docs/framing.html */ 28 29 int ogg_page_version(ogg_page *og){ 30 return((int)(og->header[4])); 31 } 32 33 int ogg_page_continued(ogg_page *og){ 34 return((int)(og->header[5]&0x01)); 35 } 36 37 int ogg_page_bos(ogg_page *og){ 38 return((int)(og->header[5]&0x02)); 39 } 40 41 int ogg_page_eos(ogg_page *og){ 42 return((int)(og->header[5]&0x04)); 43 } 44 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); 56 } 57 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)); 63 } 64 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)); 70 } 71 72 73 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 */ 77 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 83 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 89 */ 90 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); 96 } 97 98 99 #if 0 100 /* helper to initialize lookup for direct-table CRC (illustrative; we 101 use the static init below) */ 102 103 static ogg_uint32_t _ogg_crc_entry(unsigned long index){ 104 int i; 105 unsigned long r; 106 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); 117 } 118 #endif 119 120 static 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}; 185 186 /* init the encode/decode logical stream state */ 187 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)); 193 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)); 197 198 os->serialno=serialno; 199 200 return(0); 201 } 202 return(-1); 203 } 204 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); 211 212 memset(os,0,sizeof(*os)); 213 } 214 return(0); 215 } 216 217 int ogg_stream_destroy(ogg_stream_state *os){ 218 if(os){ 219 ogg_stream_clear(os); 220 _ogg_free(os); 221 } 222 return(0); 223 } 224 225 /* Helpers for ogg_stream_encode; this keeps the structure and 226 what's happening fairly clear */ 227 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)); 232 } 233 } 234 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)); 240 } 241 } 242 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 */ 246 247 void ogg_page_checksum_set(ogg_page *og){ 248 if(og){ 249 ogg_uint32_t crc_reg=0; 250 int i; 251 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; 257 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]]; 262 263 og->header[22]=crc_reg&0xff; 264 og->header[23]=(crc_reg>>8)&0xff; 265 og->header[24]=(crc_reg>>16)&0xff; 266 og->header[25]=(crc_reg>>24)&0xff; 267 } 268 } 269 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; 273 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 */ 278 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; 284 } 285 286 /* make sure we have the buffer storage */ 287 _os_body_expand(os,op->bytes); 288 _os_lacing_expand(os,lacing_vals); 289 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 */ 294 295 memcpy(os->body_data+os->body_fill,op->packet,op->bytes); 296 os->body_fill+=op->bytes; 297 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; 302 } 303 os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255; 304 os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos; 305 306 /* flag the first segment as the beginning of the packet */ 307 os->lacing_vals[os->lacing_fill]|= 0x100; 308 309 os->lacing_fill+=lacing_vals; 310 311 /* for the sake of completeness */ 312 os->packetno++; 313 314 if(op->e_o_s)os->e_o_s=1; 315 316 return(0); 317 } 318 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. 327 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. */ 332 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=os->granule_vals[0]; 340 341 if(maxvals==0)return(0); 342 343 /* construct a page */ 344 /* decide how many segments to include */ 345 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; 354 } 355 } 356 }else{ 357 for(vals=0;vals<maxvals;vals++){ 358 if(acc>4096)break; 359 acc+=os->lacing_vals[vals]&0x0ff; 360 granule_pos=os->granule_vals[vals]; 361 } 362 } 363 364 /* construct the header in temp storage */ 365 memcpy(os->header,"OggS",4); 366 367 /* stream structure version */ 368 os->header[4]=0x00; 369 370 /* continued packet flag? */ 371 os->header[5]=0x00; 372 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; 373 /* first page flag? */ 374 if(os->b_o_s==0)os->header[5]|=0x02; 375 /* last page flag? */ 376 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; 377 os->b_o_s=1; 378 379 /* 64 bits of PCM position */ 380 for(i=6;i<14;i++){ 381 os->header[i]=(granule_pos&0xff); 382 granule_pos>>=8; 383 } 384 385 /* 32 bits of stream serial number */ 386 { 387 long serialno=os->serialno; 388 for(i=14;i<18;i++){ 389 os->header[i]=(serialno&0xff); 390 serialno>>=8; 391 } 392 } 393 394 /* 32 bits of page counter (we have both counter and page header 395 because this val can roll over) */ 396 if(os->pageno==-1)os->pageno=0; /* because someone called 397 stream_reset; this would be a 398 strange thing to do in an 399 encode stream, but it has 400 plausible uses */ 401 { 402 long pageno=os->pageno++; 403 for(i=18;i<22;i++){ 404 os->header[i]=(pageno&0xff); 405 pageno>>=8; 406 } 407 } 408 409 /* zero for computation; filled in later */ 410 os->header[22]=0; 411 os->header[23]=0; 412 os->header[24]=0; 413 os->header[25]=0; 414 415 /* segment table */ 416 os->header[26]=vals&0xff; 417 for(i=0;i<vals;i++) 418 bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff); 419 420 /* set pointers in the ogg_page struct */ 421 og->header=os->header; 422 og->header_len=os->header_fill=vals+27; 423 og->body=os->body_data+os->body_returned; 424 og->body_len=bytes; 425 426 /* advance the lacing data and set the body_returned pointer */ 427 428 os->lacing_fill-=vals; 429 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); 430 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); 431 os->body_returned+=bytes; 432 433 /* calculate the checksum */ 434 435 ogg_page_checksum_set(og); 436 437 /* done */ 438 return(1); 439 } 440 441 442 /* This constructs pages from buffered packet segments. The pointers 443 returned are to static buffers; do not free. The returned buffers are 444 good only until the next call (using the same ogg_stream_state) */ 445 446 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ 447 448 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ 449 os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */ 450 os->lacing_fill>=255 || /* 'segment table full' case */ 451 (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */ 452 453 return(ogg_stream_flush(os,og)); 454 } 455 456 /* not enough data to construct a page and not end of stream */ 457 return(0); 458 } 459 460 int ogg_stream_eos(ogg_stream_state *os){ 461 return os->e_o_s; 462 } 463 464 /* DECODING PRIMITIVES: packet streaming layer **********************/ 465 466 /* This has two layers to place more of the multi-serialno and paging 467 control in the application's hands. First, we expose a data buffer 468 using ogg_sync_buffer(). The app either copies into the 469 buffer, or passes it directly to read(), etc. We then call 470 ogg_sync_wrote() to tell how many bytes we just added. 471 472 Pages are returned (pointers into the buffer in ogg_sync_state) 473 by ogg_sync_pageout(). The page is then submitted to 474 ogg_stream_pagein() along with the appropriate 475 ogg_stream_state* (ie, matching serialno). We then get raw 476 packets out calling ogg_stream_packetout() with a 477 ogg_stream_state. See the 'frame-prog.txt' docs for details and 478 example code. */ 479 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)); 484 } 485 return(0); 486 } 487 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); 493 } 494 return(0); 495 } 496 497 int ogg_sync_destroy(ogg_sync_state *oy){ 498 if(oy){ 499 ogg_sync_clear(oy); 500 _ogg_free(oy); 501 } 502 return(0); 503 } 504 505 char *ogg_sync_buffer(ogg_sync_state *oy, long size){ 506 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; 513 } 514 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 */ 518 519 if(oy->data) 520 oy->data=_ogg_realloc(oy->data,newsize); 521 else 522 oy->data=_ogg_malloc(newsize); 523 oy->storage=newsize; 524 } 525 526 /* expose a segment at least as large as requested at the fill mark */ 527 return((char *)oy->data+oy->fill); 528 } 529 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); 534 } 535 536 /* sync the stream. This is meant to be useful for finding page 537 boundaries. 538 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 543 544 */ 545 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; 550 551 if(oy->headerbytes==0){ 552 int headerbytes,i; 553 if(bytes<27)return(0); /* not enough for a header */ 554 555 /* verify capture pattern */ 556 if(memcmp(page,"OggS",4))goto sync_fail; 557 558 headerbytes=page[26]+27; 559 if(bytes<headerbytes)return(0); /* not enough for header + seg table */ 560 561 /* count up body length in the segment table */ 562 563 for(i=0;i<page[26];i++) 564 oy->bodybytes+=page[27+i]; 565 oy->headerbytes=headerbytes; 566 } 567 568 if(oy->bodybytes+oy->headerbytes>bytes)return(0); 569 570 /* The whole test page is buffered. Verify the checksum */ 571 { 572 /* Grab the checksum bytes, set the header field to zero */ 573 char chksum[4]; 574 ogg_page log; 575 576 memcpy(chksum,page+22,4); 577 memset(page+22,0,4); 578 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); 585 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); 592 593 /* Bad checksum. Lose sync */ 594 goto sync_fail; 595 } 596 } 597 598 /* yes, have a whole page all ready to go */ 599 { 600 unsigned char *page=oy->data+oy->returned; 601 long bytes; 602 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; 608 } 609 610 oy->unsynced=0; 611 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); 612 oy->headerbytes=0; 613 oy->bodybytes=0; 614 return(bytes); 615 } 616 617 sync_fail: 618 619 oy->headerbytes=0; 620 oy->bodybytes=0; 621 622 /* search for possible capture */ 623 next=memchr(page+1,'O',bytes-1); 624 if(!next) 625 next=oy->data+oy->fill; 626 627 oy->returned=next-oy->data; 628 return(-(next-page)); 629 } 630 631 /* sync the stream and get a page. Keep trying until we find a page. 632 Supress 'sync errors' after reporting the first. 633 634 return values: 635 -1) recapture (hole in data) 636 0) need more data 637 1) page returned 638 639 Returns pointers into buffered data; invalidated by next call to 640 _stream, _clear, _init, or _buffer */ 641 642 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ 643 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 */ 647 648 while(1){ 649 long ret=ogg_sync_pageseek(oy,og); 650 if(ret>0){ 651 /* have a page */ 652 return(1); 653 } 654 if(ret==0){ 655 /* need more data */ 656 return(0); 657 } 658 659 /* head did not start a synced page... skipped some bytes */ 660 if(!oy->unsynced){ 661 oy->unsynced=1; 662 return(-1); 663 } 664 665 /* loop. keep looking */ 666 667 } 668 } 669 670 /* add the incoming page to the stream state; we decompose the page 671 into packet segments here as well. */ 672 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; 678 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]; 687 688 /* clean up 'returned data' */ 689 { 690 long lr=os->lacing_returned; 691 long br=os->body_returned; 692 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; 699 } 700 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)); 708 } 709 os->lacing_fill-=lr; 710 os->lacing_packet-=lr; 711 os->lacing_returned=0; 712 } 713 } 714 715 /* check the serial number */ 716 if(serialno!=os->serialno)return(-1); 717 if(version>0)return(-1); 718 719 _os_lacing_expand(os,segments+1); 720 721 /* are we in sequence? */ 722 if(pageno!=os->pageno){ 723 int i; 724 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; 729 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++; 734 } 735 736 /* are we a 'continued packet' page? If so, we'll need to skip 737 some segments */ 738 if(continued){ 739 bos=0; 740 for(;segptr<segments;segptr++){ 741 int val=header[27+segptr]; 742 body+=val; 743 bodysize-=val; 744 if(val<255){ 745 segptr++; 746 break; 747 } 748 } 749 } 750 } 751 752 if(bodysize){ 753 _os_body_expand(os,bodysize); 754 memcpy(os->body_data+os->body_fill,body,bodysize); 755 os->body_fill+=bodysize; 756 } 757 758 { 759 int saved=-1; 760 while(segptr<segments){ 761 int val=header[27+segptr]; 762 os->lacing_vals[os->lacing_fill]=val; 763 os->granule_vals[os->lacing_fill]=-1; 764 765 if(bos){ 766 os->lacing_vals[os->lacing_fill]|=0x100; 767 bos=0; 768 } 769 770 if(val<255)saved=os->lacing_fill; 771 772 os->lacing_fill++; 773 segptr++; 774 775 if(val<255)os->lacing_packet=os->lacing_fill; 776 } 777 778 /* set the granulepos on the last granuleval of the last full packet */ 779 if(saved!=-1){ 780 os->granule_vals[saved]=granulepos; 781 } 782 783 } 784 785 if(eos){ 786 os->e_o_s=1; 787 if(os->lacing_fill>0) 788 os->lacing_vals[os->lacing_fill-1]|=0x200; 789 } 790 791 os->pageno=pageno+1; 792 793 return(0); 794 } 795 796 /* clear things to an initial state. Good to call, eg, before seeking */ 797 int ogg_sync_reset(ogg_sync_state *oy){ 798 oy->fill=0; 799 oy->returned=0; 800 oy->unsynced=0; 801 oy->headerbytes=0; 802 oy->bodybytes=0; 803 return(0); 804 } 805 806 int ogg_stream_reset(ogg_stream_state *os){ 807 os->body_fill=0; 808 os->body_returned=0; 809 810 os->lacing_fill=0; 811 os->lacing_packet=0; 812 os->lacing_returned=0; 813 814 os->header_fill=0; 815 816 os->e_o_s=0; 817 os->b_o_s=0; 818 os->pageno=-1; 819 os->packetno=0; 820 os->granulepos=0; 821 822 return(0); 823 } 824 825 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ 826 ogg_stream_reset(os); 827 os->serialno=serialno; 828 return(0); 829 } 830 831 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ 832 833 /* The last part of decode. We have the stream broken into packet 834 segments. Now we need to group them into packets (or return the 835 out of sync markers) */ 836 837 int ptr=os->lacing_returned; 838 839 if(os->lacing_packet<=ptr)return(0); 840 841 if(os->lacing_vals[ptr]&0x400){ 842 /* we need to tell the codec there's a gap; it might need to 843 handle previous packet dependencies. */ 844 os->lacing_returned++; 845 os->packetno++; 846 return(-1); 847 } 848 849 if(!op && !adv)return(1); /* just using peek as an inexpensive way 850 to ask if there's a whole packet 851 waiting */ 852 853 /* Gather the whole packet. We'll have no holes or a partial packet */ 854 { 855 int size=os->lacing_vals[ptr]&0xff; 856 int bytes=size; 857 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ 858 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ 859 860 while(size==255){ 861 int val=os->lacing_vals[++ptr]; 862 size=val&0xff; 863 if(val&0x200)eos=0x200; 864 bytes+=size; 865 } 866 867 if(op){ 868 op->e_o_s=eos; 869 op->b_o_s=bos; 870 op->packet=os->body_data+os->body_returned; 871 op->packetno=os->packetno; 872 op->granulepos=os->granule_vals[ptr]; 873 op->bytes=bytes; 874 } 875 876 if(adv){ 877 os->body_returned+=bytes; 878 os->lacing_returned=ptr+1; 879 os->packetno++; 880 } 881 } 882 return(1); 883 } 884 885 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ 886 return _packetout(os,op,1); 887 } 888 889 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ 890 return _packetout(os,op,0); 891 } 892 893 void ogg_packet_clear(ogg_packet *op) { 894 _ogg_free(op->packet); 895 memset(op, 0, sizeof(*op)); 896 } 897 898 #ifdef _V_SELFTEST 899 #include <stdio.h> 900 901 ogg_stream_state os_en, os_de; 902 ogg_sync_state oy; 903 904 void checkpacket(ogg_packet *op,int len, int no, int pos){ 905 long j; 906 static int sequence=0; 907 static int lastno=0; 908 909 if(op->bytes!=len){ 910 fprintf(stderr,"incorrect packet length!\n"); 911 exit(1); 912 } 913 if(op->granulepos!=pos){ 914 fprintf(stderr,"incorrect packet position!\n"); 915 exit(1); 916 } 917 918 /* packet number just follows sequence/gap; adjust the input number 919 for that */ 920 if(no==0){ 921 sequence=0; 922 }else{ 923 sequence++; 924 if(no>lastno+1) 925 sequence++; 926 } 927 lastno=no; 928 if(op->packetno!=sequence){ 929 fprintf(stderr,"incorrect packet sequence %ld != %d\n", 930 (long)(op->packetno),sequence); 931 exit(1); 932 } 933 934 /* Test data */ 935 for(j=0;j<op->bytes;j++) 936 if(op->packet[j]!=((j+no)&0xff)){ 937 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", 938 j,op->packet[j],(j+no)&0xff); 939 exit(1); 940 } 941 } 942 943 void check_page(unsigned char *data,const int *header,ogg_page *og){ 944 long j; 945 /* Test data */ 946 for(j=0;j<og->body_len;j++) 947 if(og->body[j]!=data[j]){ 948 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", 949 j,data[j],og->body[j]); 950 exit(1); 951 } 952 953 /* Test header */ 954 for(j=0;j<og->header_len;j++){ 955 if(og->header[j]!=header[j]){ 956 fprintf(stderr,"header content mismatch at pos %ld:\n",j); 957 for(j=0;j<header[26]+27;j++) 958 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]); 959 fprintf(stderr,"\n"); 960 exit(1); 961 } 962 } 963 if(og->header_len!=header[26]+27){ 964 fprintf(stderr,"header length incorrect! (%ld!=%d)\n", 965 og->header_len,header[26]+27); 966 exit(1); 967 } 968 } 969 970 void print_header(ogg_page *og){ 971 int j; 972 fprintf(stderr,"\nHEADER:\n"); 973 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", 974 og->header[0],og->header[1],og->header[2],og->header[3], 975 (int)og->header[4],(int)og->header[5]); 976 977 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", 978 (og->header[9]<<24)|(og->header[8]<<16)| 979 (og->header[7]<<8)|og->header[6], 980 (og->header[17]<<24)|(og->header[16]<<16)| 981 (og->header[15]<<8)|og->header[14], 982 ((long)(og->header[21])<<24)|(og->header[20]<<16)| 983 (og->header[19]<<8)|og->header[18]); 984 985 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", 986 (int)og->header[22],(int)og->header[23], 987 (int)og->header[24],(int)og->header[25], 988 (int)og->header[26]); 989 990 for(j=27;j<og->header_len;j++) 991 fprintf(stderr,"%d ",(int)og->header[j]); 992 fprintf(stderr,")\n\n"); 993 } 994 995 void copy_page(ogg_page *og){ 996 unsigned char *temp=_ogg_malloc(og->header_len); 997 memcpy(temp,og->header,og->header_len); 998 og->header=temp; 999 1000 temp=_ogg_malloc(og->body_len); 1001 memcpy(temp,og->body,og->body_len); 1002 og->body=temp; 1003 } 1004 1005 void error(void){ 1006 fprintf(stderr,"error!\n"); 1007 exit(1); 1008 } 1009 1010 /* 17 only */ 1011 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, 1012 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1013 0x01,0x02,0x03,0x04,0,0,0,0, 1014 0x15,0xed,0xec,0x91, 1015 1, 1016 17}; 1017 1018 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ 1019 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, 1020 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1021 0x01,0x02,0x03,0x04,0,0,0,0, 1022 0x59,0x10,0x6c,0x2c, 1023 1, 1024 17}; 1025 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, 1026 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 1027 0x01,0x02,0x03,0x04,1,0,0,0, 1028 0x89,0x33,0x85,0xce, 1029 13, 1030 254,255,0,255,1,255,245,255,255,0, 1031 255,255,90}; 1032 1033 /* nil packets; beginning,middle,end */ 1034 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, 1035 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1036 0x01,0x02,0x03,0x04,0,0,0,0, 1037 0xff,0x7b,0x23,0x17, 1038 1, 1039 0}; 1040 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, 1041 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, 1042 0x01,0x02,0x03,0x04,1,0,0,0, 1043 0x5c,0x3f,0x66,0xcb, 1044 17, 1045 17,254,255,0,0,255,1,0,255,245,255,255,0, 1046 255,255,90,0}; 1047 1048 /* large initial packet */ 1049 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, 1050 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1051 0x01,0x02,0x03,0x04,0,0,0,0, 1052 0x01,0x27,0x31,0xaa, 1053 18, 1054 255,255,255,255,255,255,255,255, 1055 255,255,255,255,255,255,255,255,255,10}; 1056 1057 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, 1058 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, 1059 0x01,0x02,0x03,0x04,1,0,0,0, 1060 0x7f,0x4e,0x8a,0xd2, 1061 4, 1062 255,4,255,0}; 1063 1064 1065 /* continuing packet test */ 1066 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, 1067 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1068 0x01,0x02,0x03,0x04,0,0,0,0, 1069 0xff,0x7b,0x23,0x17, 1070 1, 1071 0}; 1072 1073 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, 1074 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1075 0x01,0x02,0x03,0x04,1,0,0,0, 1076 0x34,0x24,0xd5,0x29, 1077 17, 1078 255,255,255,255,255,255,255,255, 1079 255,255,255,255,255,255,255,255,255}; 1080 1081 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, 1082 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, 1083 0x01,0x02,0x03,0x04,2,0,0,0, 1084 0xc8,0xc3,0xcb,0xed, 1085 5, 1086 10,255,4,255,0}; 1087 1088 1089 /* page with the 255 segment limit */ 1090 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, 1091 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1092 0x01,0x02,0x03,0x04,0,0,0,0, 1093 0xff,0x7b,0x23,0x17, 1094 1, 1095 0}; 1096 1097 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, 1098 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, 1099 0x01,0x02,0x03,0x04,1,0,0,0, 1100 0xed,0x2a,0x2e,0xa7, 1101 255, 1102 10,10,10,10,10,10,10,10, 1103 10,10,10,10,10,10,10,10, 1104 10,10,10,10,10,10,10,10, 1105 10,10,10,10,10,10,10,10, 1106 10,10,10,10,10,10,10,10, 1107 10,10,10,10,10,10,10,10, 1108 10,10,10,10,10,10,10,10, 1109 10,10,10,10,10,10,10,10, 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}; 1134 1135 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, 1136 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, 1137 0x01,0x02,0x03,0x04,2,0,0,0, 1138 0x6c,0x3b,0x82,0x3d, 1139 1, 1140 50}; 1141 1142 1143 /* packet that overspans over an entire page */ 1144 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, 1145 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1146 0x01,0x02,0x03,0x04,0,0,0,0, 1147 0xff,0x7b,0x23,0x17, 1148 1, 1149 0}; 1150 1151 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, 1152 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 1153 0x01,0x02,0x03,0x04,1,0,0,0, 1154 0x3c,0xd9,0x4d,0x3f, 1155 17, 1156 100,255,255,255,255,255,255,255,255, 1157 255,255,255,255,255,255,255,255}; 1158 1159 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, 1160 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 1161 0x01,0x02,0x03,0x04,2,0,0,0, 1162 0xbd,0xd5,0xb5,0x8b, 1163 17, 1164 255,255,255,255,255,255,255,255, 1165 255,255,255,255,255,255,255,255,255}; 1166 1167 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, 1168 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, 1169 0x01,0x02,0x03,0x04,3,0,0,0, 1170 0xef,0xdd,0x88,0xde, 1171 7, 1172 255,255,75,255,4,255,0}; 1173 1174 /* packet that overspans over an entire page */ 1175 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, 1176 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1177 0x01,0x02,0x03,0x04,0,0,0,0, 1178 0xff,0x7b,0x23,0x17, 1179 1, 1180 0}; 1181 1182 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, 1183 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 1184 0x01,0x02,0x03,0x04,1,0,0,0, 1185 0x3c,0xd9,0x4d,0x3f, 1186 17, 1187 100,255,255,255,255,255,255,255,255, 1188 255,255,255,255,255,255,255,255}; 1189 1190 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, 1191 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, 1192 0x01,0x02,0x03,0x04,2,0,0,0, 1193 0xd4,0xe0,0x60,0xe5, 1194 1,0}; 1195 1196 void test_pack(const int *pl, const int **headers){ 1197 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ 1198 long inptr=0; 1199 long outptr=0; 1200 long deptr=0; 1201 long depacket=0; 1202 long granule_pos=7,pageno=0; 1203 int i,j,packets,pageout=0; 1204 int eosflag=0; 1205 int bosflag=0; 1206 1207 ogg_stream_reset(&os_en); 1208 ogg_stream_reset(&os_de); 1209 ogg_sync_reset(&oy); 1210 1211 for(packets=0;;packets++)if(pl[packets]==-1)break; 1212 1213 for(i=0;i<packets;i++){ 1214 /* construct a test packet */ 1215 ogg_packet op; 1216 int len=pl[i]; 1217 1218 op.packet=data+inptr; 1219 op.bytes=len; 1220 op.e_o_s=(pl[i+1]<0?1:0); 1221 op.granulepos=granule_pos; 1222 1223 granule_pos+=1024; 1224 1225 for(j=0;j<len;j++)data[inptr++]=i+j; 1226 1227 /* submit the test packet */ 1228 ogg_stream_packetin(&os_en,&op); 1229 1230 /* retrieve any finished pages */ 1231 { 1232 ogg_page og; 1233 1234 while(ogg_stream_pageout(&os_en,&og)){ 1235 /* We have a page. Check it carefully */ 1236 1237 fprintf(stderr,"%ld, ",pageno); 1238 1239 if(headers[pageno]==NULL){ 1240 fprintf(stderr,"coded too many pages!\n"); 1241 exit(1); 1242 } 1243 1244 check_page(data+outptr,headers[pageno],&og); 1245 1246 outptr+=og.body_len; 1247 pageno++; 1248 1249 /* have a complete page; submit it to sync/decode */ 1250 1251 { 1252 ogg_page og_de; 1253 ogg_packet op_de,op_de2; 1254 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len); 1255 memcpy(buf,og.header,og.header_len); 1256 memcpy(buf+og.header_len,og.body,og.body_len); 1257 ogg_sync_wrote(&oy,og.header_len+og.body_len); 1258 1259 while(ogg_sync_pageout(&oy,&og_de)>0){ 1260 /* got a page. Happy happy. Verify that it's good. */ 1261 1262 check_page(data+deptr,headers[pageout],&og_de); 1263 deptr+=og_de.body_len; 1264 pageout++; 1265 1266 /* submit it to deconstitution */ 1267 ogg_stream_pagein(&os_de,&og_de); 1268 1269 /* packets out? */ 1270 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ 1271 ogg_stream_packetpeek(&os_de,NULL); 1272 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ 1273 1274 /* verify peek and out match */ 1275 if(memcmp(&op_de,&op_de2,sizeof(op_de))){ 1276 fprintf(stderr,"packetout != packetpeek! pos=%ld\n", 1277 depacket); 1278 exit(1); 1279 } 1280 1281 /* verify the packet! */ 1282 /* check data */ 1283 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ 1284 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", 1285 depacket); 1286 exit(1); 1287 } 1288 /* check bos flag */ 1289 if(bosflag==0 && op_de.b_o_s==0){ 1290 fprintf(stderr,"b_o_s flag not set on packet!\n"); 1291 exit(1); 1292 } 1293 if(bosflag && op_de.b_o_s){ 1294 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); 1295 exit(1); 1296 } 1297 bosflag=1; 1298 depacket+=op_de.bytes; 1299 1300 /* check eos flag */ 1301 if(eosflag){ 1302 fprintf(stderr,"Multiple decoded packets with eos flag!\n"); 1303 exit(1); 1304 } 1305 1306 if(op_de.e_o_s)eosflag=1; 1307 1308 /* check granulepos flag */ 1309 if(op_de.granulepos!=-1){ 1310 fprintf(stderr," granule:%ld ",(long)op_de.granulepos); 1311 } 1312 } 1313 } 1314 } 1315 } 1316 } 1317 } 1318 _ogg_free(data); 1319 if(headers[pageno]!=NULL){ 1320 fprintf(stderr,"did not write last page!\n"); 1321 exit(1); 1322 } 1323 if(headers[pageout]!=NULL){ 1324 fprintf(stderr,"did not decode last page!\n"); 1325 exit(1); 1326 } 1327 if(inptr!=outptr){ 1328 fprintf(stderr,"encoded page data incomplete!\n"); 1329 exit(1); 1330 } 1331 if(inptr!=deptr){ 1332 fprintf(stderr,"decoded page data incomplete!\n"); 1333 exit(1); 1334 } 1335 if(inptr!=depacket){ 1336 fprintf(stderr,"decoded packet data incomplete!\n"); 1337 exit(1); 1338 } 1339 if(!eosflag){ 1340 fprintf(stderr,"Never got a packet with EOS set!\n"); 1341 exit(1); 1342 } 1343 fprintf(stderr,"ok.\n"); 1344 } 1345 1346 int main(void){ 1347 1348 ogg_stream_init(&os_en,0x04030201); 1349 ogg_stream_init(&os_de,0x04030201); 1350 ogg_sync_init(&oy); 1351 1352 /* Exercise each code path in the framing code. Also verify that 1353 the checksums are working. */ 1354 1355 { 1356 /* 17 only */ 1357 const int packets[]={17, -1}; 1358 const int *headret[]={head1_0,NULL}; 1359 1360 fprintf(stderr,"testing single page encoding... "); 1361 test_pack(packets,headret); 1362 } 1363 1364 { 1365 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ 1366 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; 1367 const int *headret[]={head1_1,head2_1,NULL}; 1368 1369 fprintf(stderr,"testing basic page encoding... "); 1370 test_pack(packets,headret); 1371 } 1372 1373 { 1374 /* nil packets; beginning,middle,end */ 1375 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; 1376 const int *headret[]={head1_2,head2_2,NULL}; 1377 1378 fprintf(stderr,"testing basic nil packets... "); 1379 test_pack(packets,headret); 1380 } 1381 1382 { 1383 /* large initial packet */ 1384 const int packets[]={4345,259,255,-1}; 1385 const int *headret[]={head1_3,head2_3,NULL}; 1386 1387 fprintf(stderr,"testing initial-packet lacing > 4k... "); 1388 test_pack(packets,headret); 1389 } 1390 1391 { 1392 /* continuing packet test */ 1393 const int packets[]={0,4345,259,255,-1}; 1394 const int *headret[]={head1_4,head2_4,head3_4,NULL}; 1395 1396 fprintf(stderr,"testing single packet page span... "); 1397 test_pack(packets,headret); 1398 } 1399 1400 /* page with the 255 segment limit */ 1401 { 1402 1403 const int packets[]={0,10,10,10,10,10,10,10,10, 1404 10,10,10,10,10,10,10,10, 1405 10,10,10,10,10,10,10,10, 1406 10,10,10,10,10,10,10,10, 1407 10,10,10,10,10,10,10,10, 1408 10,10,10,10,10,10,10,10, 1409 10,10,10,10,10,10,10,10, 1410 10,10,10,10,10,10,10,10, 1411 10,10,10,10,10,10,10,10, 1412 10,10,10,10,10,10,10,10, 1413 10,10,10,10,10,10,10,10, 1414 10,10,10,10,10,10,10,10, 1415 10,10,10,10,10,10,10,10, 1416 10,10,10,10,10,10,10,10, 1417 10,10,10,10,10,10,10,10, 1418 10,10,10,10,10,10,10,10, 1419 10,10,10,10,10,10,10,10, 1420 10,10,10,10,10,10,10,10, 1421 10,10,10,10,10,10,10,10, 1422 10,10,10,10,10,10,10,10, 1423 10,10,10,10,10,10,10,10, 1424 10,10,10,10,10,10,10,10, 1425 10,10,10,10,10,10,10,10, 1426 10,10,10,10,10,10,10,10, 1427 10,10,10,10,10,10,10,10, 1428 10,10,10,10,10,10,10,10, 1429 10,10,10,10,10,10,10,10, 1430 10,10,10,10,10,10,10,10, 1431 10,10,10,10,10,10,10,10, 1432 10,10,10,10,10,10,10,10, 1433 10,10,10,10,10,10,10,10, 1434 10,10,10,10,10,10,10,50,-1}; 1435 const int *headret[]={head1_5,head2_5,head3_5,NULL}; 1436 1437 fprintf(stderr,"testing max packet segments... "); 1438 test_pack(packets,headret); 1439 } 1440 1441 { 1442 /* packet that overspans over an entire page */ 1443 const int packets[]={0,100,9000,259,255,-1}; 1444 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; 1445 1446 fprintf(stderr,"testing very large packets... "); 1447 test_pack(packets,headret); 1448 } 1449 1450 { 1451 /* term only page. why not? */ 1452 const int packets[]={0,100,4080,-1}; 1453 const int *headret[]={head1_7,head2_7,head3_7,NULL}; 1454 1455 fprintf(stderr,"testing zero data page (1 nil packet)... "); 1456 test_pack(packets,headret); 1457 } 1458 1459 1460 1461 { 1462 /* build a bunch of pages for testing */ 1463 unsigned char *data=_ogg_malloc(1024*1024); 1464 int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1}; 1465 int inptr=0,i,j; 1466 ogg_page og[5]; 1467 1468 ogg_stream_reset(&os_en); 1469 1470 for(i=0;pl[i]!=-1;i++){ 1471 ogg_packet op; 1472 int len=pl[i]; 1473 1474 op.packet=data+inptr; 1475 op.bytes=len; 1476 op.e_o_s=(pl[i+1]<0?1:0); 1477 op.granulepos=(i+1)*1000; 1478 1479 for(j=0;j<len;j++)data[inptr++]=i+j; 1480 ogg_stream_packetin(&os_en,&op); 1481 } 1482 1483 _ogg_free(data); 1484 1485 /* retrieve finished pages */ 1486 for(i=0;i<5;i++){ 1487 if(ogg_stream_pageout(&os_en,&og[i])==0){ 1488 fprintf(stderr,"Too few pages output building sync tests!\n"); 1489 exit(1); 1490 } 1491 copy_page(&og[i]); 1492 } 1493 1494 /* Test lost pages on pagein/packetout: no rollback */ 1495 { 1496 ogg_page temp; 1497 ogg_packet test; 1498 1499 fprintf(stderr,"Testing loss of pages... "); 1500 1501 ogg_sync_reset(&oy); 1502 ogg_stream_reset(&os_de); 1503 for(i=0;i<5;i++){ 1504 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, 1505 og[i].header_len); 1506 ogg_sync_wrote(&oy,og[i].header_len); 1507 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); 1508 ogg_sync_wrote(&oy,og[i].body_len); 1509 } 1510 1511 ogg_sync_pageout(&oy,&temp); 1512 ogg_stream_pagein(&os_de,&temp); 1513 ogg_sync_pageout(&oy,&temp); 1514 ogg_stream_pagein(&os_de,&temp); 1515 ogg_sync_pageout(&oy,&temp); 1516 /* skip */ 1517 ogg_sync_pageout(&oy,&temp); 1518 ogg_stream_pagein(&os_de,&temp); 1519 1520 /* do we get the expected results/packets? */ 1521 1522 if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1523 checkpacket(&test,0,0,0); 1524 if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1525 checkpacket(&test,100,1,-1); 1526 if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1527 checkpacket(&test,4079,2,3000); 1528 if(ogg_stream_packetout(&os_de,&test)!=-1){ 1529 fprintf(stderr,"Error: loss of page did not return error\n"); 1530 exit(1); 1531 } 1532 if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1533 checkpacket(&test,76,5,-1); 1534 if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1535 checkpacket(&test,34,6,-1); 1536 fprintf(stderr,"ok.\n"); 1537 } 1538 1539 /* Test lost pages on pagein/packetout: rollback with continuation */ 1540 { 1541 ogg_page temp; 1542 ogg_packet test; 1543 1544 fprintf(stderr,"Testing loss of pages (rollback required)... "); 1545 1546 ogg_sync_reset(&oy); 1547 ogg_stream_reset(&os_de); 1548 for(i=0;i<5;i++){ 1549 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, 1550 og[i].header_len); 1551 ogg_sync_wrote(&oy,og[i].header_len); 1552 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); 1553 ogg_sync_wrote(&oy,og[i].body_len); 1554 } 1555 1556 ogg_sync_pageout(&oy,&temp); 1557 ogg_stream_pagein(&os_de,&temp); 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); 1566 1567 /* do we get the expected results/packets? */ 1568 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)error(); 1576 checkpacket(&test,2956,3,4000); 1577 if(ogg_stream_packetout(&os_de,&test)!=-1){ 1578 fprintf(stderr,"Error: loss of page did not return error\n"); 1579 exit(1); 1580 } 1581 if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1582 checkpacket(&test,300,13,14000); 1583 fprintf(stderr,"ok.\n"); 1584 } 1585 1586 /* the rest only test sync */ 1587 { 1588 ogg_page og_de; 1589 /* Test fractional page inputs: incomplete capture */ 1590 fprintf(stderr,"Testing sync on partial inputs... "); 1591 ogg_sync_reset(&oy); 1592 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1593 3); 1594 ogg_sync_wrote(&oy,3); 1595 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1596 1597 /* Test fractional page inputs: incomplete fixed header */ 1598 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, 1599 20); 1600 ogg_sync_wrote(&oy,20); 1601 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1602 1603 /* Test fractional page inputs: incomplete header */ 1604 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, 1605 5); 1606 ogg_sync_wrote(&oy,5); 1607 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1608 1609 /* Test fractional page inputs: incomplete body */ 1610 1611 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, 1612 og[1].header_len-28); 1613 ogg_sync_wrote(&oy,og[1].header_len-28); 1614 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1615 1616 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); 1617 ogg_sync_wrote(&oy,1000); 1618 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1619 1620 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, 1621 og[1].body_len-1000); 1622 ogg_sync_wrote(&oy,og[1].body_len-1000); 1623 if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1624 1625 fprintf(stderr,"ok.\n"); 1626 } 1627 1628 /* Test fractional page inputs: page + incomplete capture */ 1629 { 1630 ogg_page og_de; 1631 fprintf(stderr,"Testing sync on 1+partial inputs... "); 1632 ogg_sync_reset(&oy); 1633 1634 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1635 og[1].header_len); 1636 ogg_sync_wrote(&oy,og[1].header_len); 1637 1638 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1639 og[1].body_len); 1640 ogg_sync_wrote(&oy,og[1].body_len); 1641 1642 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1643 20); 1644 ogg_sync_wrote(&oy,20); 1645 if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1646 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1647 1648 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, 1649 og[1].header_len-20); 1650 ogg_sync_wrote(&oy,og[1].header_len-20); 1651 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1652 og[1].body_len); 1653 ogg_sync_wrote(&oy,og[1].body_len); 1654 if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1655 1656 fprintf(stderr,"ok.\n"); 1657 } 1658 1659 /* Test recapture: garbage + page */ 1660 { 1661 ogg_page og_de; 1662 fprintf(stderr,"Testing search for capture... "); 1663 ogg_sync_reset(&oy); 1664 1665 /* 'garbage' */ 1666 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1667 og[1].body_len); 1668 ogg_sync_wrote(&oy,og[1].body_len); 1669 1670 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1671 og[1].header_len); 1672 ogg_sync_wrote(&oy,og[1].header_len); 1673 1674 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1675 og[1].body_len); 1676 ogg_sync_wrote(&oy,og[1].body_len); 1677 1678 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 1679 20); 1680 ogg_sync_wrote(&oy,20); 1681 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1682 if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1683 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1684 1685 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, 1686 og[2].header_len-20); 1687 ogg_sync_wrote(&oy,og[2].header_len-20); 1688 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, 1689 og[2].body_len); 1690 ogg_sync_wrote(&oy,og[2].body_len); 1691 if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1692 1693 fprintf(stderr,"ok.\n"); 1694 } 1695 1696 /* Test recapture: page + garbage + page */ 1697 { 1698 ogg_page og_de; 1699 fprintf(stderr,"Testing recapture... "); 1700 ogg_sync_reset(&oy); 1701 1702 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1703 og[1].header_len); 1704 ogg_sync_wrote(&oy,og[1].header_len); 1705 1706 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1707 og[1].body_len); 1708 ogg_sync_wrote(&oy,og[1].body_len); 1709 1710 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 1711 og[2].header_len); 1712 ogg_sync_wrote(&oy,og[2].header_len); 1713 1714 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 1715 og[2].header_len); 1716 ogg_sync_wrote(&oy,og[2].header_len); 1717 1718 if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1719 1720 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, 1721 og[2].body_len-5); 1722 ogg_sync_wrote(&oy,og[2].body_len-5); 1723 1724 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, 1725 og[3].header_len); 1726 ogg_sync_wrote(&oy,og[3].header_len); 1727 1728 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, 1729 og[3].body_len); 1730 ogg_sync_wrote(&oy,og[3].body_len); 1731 1732 if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1733 if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1734 1735 fprintf(stderr,"ok.\n"); 1736 } 1737 } 1738 1739 return(0); 1740 } 1741 1742 #endif 1743 1744 1745 1746