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