vrshoot
diff libs/ogg/framing.c @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/ogg/framing.c Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,2111 @@ 1.4 +/******************************************************************** 1.5 + * * 1.6 + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * 1.7 + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * 1.8 + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * 1.9 + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * 1.10 + * * 1.11 + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * 1.12 + * by the Xiph.Org Foundation http://www.xiph.org/ * 1.13 + * * 1.14 + ******************************************************************** 1.15 + 1.16 + function: code raw packets into framed OggSquish stream and 1.17 + decode Ogg streams back into raw packets 1.18 + last mod: $Id: framing.c 18758 2013-01-08 16:29:56Z tterribe $ 1.19 + 1.20 + note: The CRC code is directly derived from public domain code by 1.21 + Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html 1.22 + for details. 1.23 + 1.24 + ********************************************************************/ 1.25 + 1.26 +#include <stdlib.h> 1.27 +#include <limits.h> 1.28 +#include <string.h> 1.29 +#include <ogg/ogg.h> 1.30 + 1.31 +/* A complete description of Ogg framing exists in docs/framing.html */ 1.32 + 1.33 +int ogg_page_version(const ogg_page *og){ 1.34 + return((int)(og->header[4])); 1.35 +} 1.36 + 1.37 +int ogg_page_continued(const ogg_page *og){ 1.38 + return((int)(og->header[5]&0x01)); 1.39 +} 1.40 + 1.41 +int ogg_page_bos(const ogg_page *og){ 1.42 + return((int)(og->header[5]&0x02)); 1.43 +} 1.44 + 1.45 +int ogg_page_eos(const ogg_page *og){ 1.46 + return((int)(og->header[5]&0x04)); 1.47 +} 1.48 + 1.49 +ogg_int64_t ogg_page_granulepos(const ogg_page *og){ 1.50 + unsigned char *page=og->header; 1.51 + ogg_int64_t granulepos=page[13]&(0xff); 1.52 + granulepos= (granulepos<<8)|(page[12]&0xff); 1.53 + granulepos= (granulepos<<8)|(page[11]&0xff); 1.54 + granulepos= (granulepos<<8)|(page[10]&0xff); 1.55 + granulepos= (granulepos<<8)|(page[9]&0xff); 1.56 + granulepos= (granulepos<<8)|(page[8]&0xff); 1.57 + granulepos= (granulepos<<8)|(page[7]&0xff); 1.58 + granulepos= (granulepos<<8)|(page[6]&0xff); 1.59 + return(granulepos); 1.60 +} 1.61 + 1.62 +int ogg_page_serialno(const ogg_page *og){ 1.63 + return(og->header[14] | 1.64 + (og->header[15]<<8) | 1.65 + (og->header[16]<<16) | 1.66 + (og->header[17]<<24)); 1.67 +} 1.68 + 1.69 +long ogg_page_pageno(const ogg_page *og){ 1.70 + return(og->header[18] | 1.71 + (og->header[19]<<8) | 1.72 + (og->header[20]<<16) | 1.73 + (og->header[21]<<24)); 1.74 +} 1.75 + 1.76 + 1.77 + 1.78 +/* returns the number of packets that are completed on this page (if 1.79 + the leading packet is begun on a previous page, but ends on this 1.80 + page, it's counted */ 1.81 + 1.82 +/* NOTE: 1.83 + If a page consists of a packet begun on a previous page, and a new 1.84 + packet begun (but not completed) on this page, the return will be: 1.85 + ogg_page_packets(page) ==1, 1.86 + ogg_page_continued(page) !=0 1.87 + 1.88 + If a page happens to be a single packet that was begun on a 1.89 + previous page, and spans to the next page (in the case of a three or 1.90 + more page packet), the return will be: 1.91 + ogg_page_packets(page) ==0, 1.92 + ogg_page_continued(page) !=0 1.93 +*/ 1.94 + 1.95 +int ogg_page_packets(const ogg_page *og){ 1.96 + int i,n=og->header[26],count=0; 1.97 + for(i=0;i<n;i++) 1.98 + if(og->header[27+i]<255)count++; 1.99 + return(count); 1.100 +} 1.101 + 1.102 + 1.103 +#if 0 1.104 +/* helper to initialize lookup for direct-table CRC (illustrative; we 1.105 + use the static init below) */ 1.106 + 1.107 +static ogg_uint32_t _ogg_crc_entry(unsigned long index){ 1.108 + int i; 1.109 + unsigned long r; 1.110 + 1.111 + r = index << 24; 1.112 + for (i=0; i<8; i++) 1.113 + if (r & 0x80000000UL) 1.114 + r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator 1.115 + polynomial, although we use an 1.116 + unreflected alg and an init/final 1.117 + of 0, not 0xffffffff */ 1.118 + else 1.119 + r<<=1; 1.120 + return (r & 0xffffffffUL); 1.121 +} 1.122 +#endif 1.123 + 1.124 +static const ogg_uint32_t crc_lookup[256]={ 1.125 + 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9, 1.126 + 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, 1.127 + 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61, 1.128 + 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, 1.129 + 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9, 1.130 + 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, 1.131 + 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011, 1.132 + 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, 1.133 + 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039, 1.134 + 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, 1.135 + 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81, 1.136 + 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, 1.137 + 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49, 1.138 + 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, 1.139 + 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1, 1.140 + 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, 1.141 + 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae, 1.142 + 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, 1.143 + 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16, 1.144 + 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, 1.145 + 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde, 1.146 + 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, 1.147 + 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066, 1.148 + 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, 1.149 + 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e, 1.150 + 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, 1.151 + 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6, 1.152 + 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, 1.153 + 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e, 1.154 + 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, 1.155 + 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686, 1.156 + 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, 1.157 + 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637, 1.158 + 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, 1.159 + 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f, 1.160 + 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, 1.161 + 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47, 1.162 + 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, 1.163 + 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff, 1.164 + 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, 1.165 + 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7, 1.166 + 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, 1.167 + 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f, 1.168 + 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, 1.169 + 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7, 1.170 + 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, 1.171 + 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f, 1.172 + 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, 1.173 + 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640, 1.174 + 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, 1.175 + 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8, 1.176 + 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, 1.177 + 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30, 1.178 + 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, 1.179 + 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088, 1.180 + 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, 1.181 + 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0, 1.182 + 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, 1.183 + 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18, 1.184 + 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, 1.185 + 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0, 1.186 + 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, 1.187 + 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668, 1.188 + 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}; 1.189 + 1.190 +/* init the encode/decode logical stream state */ 1.191 + 1.192 +int ogg_stream_init(ogg_stream_state *os,int serialno){ 1.193 + if(os){ 1.194 + memset(os,0,sizeof(*os)); 1.195 + os->body_storage=16*1024; 1.196 + os->lacing_storage=1024; 1.197 + 1.198 + os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); 1.199 + os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); 1.200 + os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); 1.201 + 1.202 + if(!os->body_data || !os->lacing_vals || !os->granule_vals){ 1.203 + ogg_stream_clear(os); 1.204 + return -1; 1.205 + } 1.206 + 1.207 + os->serialno=serialno; 1.208 + 1.209 + return(0); 1.210 + } 1.211 + return(-1); 1.212 +} 1.213 + 1.214 +/* async/delayed error detection for the ogg_stream_state */ 1.215 +int ogg_stream_check(ogg_stream_state *os){ 1.216 + if(!os || !os->body_data) return -1; 1.217 + return 0; 1.218 +} 1.219 + 1.220 +/* _clear does not free os, only the non-flat storage within */ 1.221 +int ogg_stream_clear(ogg_stream_state *os){ 1.222 + if(os){ 1.223 + if(os->body_data)_ogg_free(os->body_data); 1.224 + if(os->lacing_vals)_ogg_free(os->lacing_vals); 1.225 + if(os->granule_vals)_ogg_free(os->granule_vals); 1.226 + 1.227 + memset(os,0,sizeof(*os)); 1.228 + } 1.229 + return(0); 1.230 +} 1.231 + 1.232 +int ogg_stream_destroy(ogg_stream_state *os){ 1.233 + if(os){ 1.234 + ogg_stream_clear(os); 1.235 + _ogg_free(os); 1.236 + } 1.237 + return(0); 1.238 +} 1.239 + 1.240 +/* Helpers for ogg_stream_encode; this keeps the structure and 1.241 + what's happening fairly clear */ 1.242 + 1.243 +static int _os_body_expand(ogg_stream_state *os,long needed){ 1.244 + if(os->body_storage-needed<=os->body_fill){ 1.245 + long body_storage; 1.246 + void *ret; 1.247 + if(os->body_storage>LONG_MAX-needed){ 1.248 + ogg_stream_clear(os); 1.249 + return -1; 1.250 + } 1.251 + body_storage=os->body_storage+needed; 1.252 + if(body_storage<LONG_MAX-1024)body_storage+=1024; 1.253 + ret=_ogg_realloc(os->body_data,body_storage*sizeof(*os->body_data)); 1.254 + if(!ret){ 1.255 + ogg_stream_clear(os); 1.256 + return -1; 1.257 + } 1.258 + os->body_storage=body_storage; 1.259 + os->body_data=ret; 1.260 + } 1.261 + return 0; 1.262 +} 1.263 + 1.264 +static int _os_lacing_expand(ogg_stream_state *os,long needed){ 1.265 + if(os->lacing_storage-needed<=os->lacing_fill){ 1.266 + long lacing_storage; 1.267 + void *ret; 1.268 + if(os->lacing_storage>LONG_MAX-needed){ 1.269 + ogg_stream_clear(os); 1.270 + return -1; 1.271 + } 1.272 + lacing_storage=os->lacing_storage+needed; 1.273 + if(lacing_storage<LONG_MAX-32)lacing_storage+=32; 1.274 + ret=_ogg_realloc(os->lacing_vals,lacing_storage*sizeof(*os->lacing_vals)); 1.275 + if(!ret){ 1.276 + ogg_stream_clear(os); 1.277 + return -1; 1.278 + } 1.279 + os->lacing_vals=ret; 1.280 + ret=_ogg_realloc(os->granule_vals,lacing_storage* 1.281 + sizeof(*os->granule_vals)); 1.282 + if(!ret){ 1.283 + ogg_stream_clear(os); 1.284 + return -1; 1.285 + } 1.286 + os->granule_vals=ret; 1.287 + os->lacing_storage=lacing_storage; 1.288 + } 1.289 + return 0; 1.290 +} 1.291 + 1.292 +/* checksum the page */ 1.293 +/* Direct table CRC; note that this will be faster in the future if we 1.294 + perform the checksum simultaneously with other copies */ 1.295 + 1.296 +void ogg_page_checksum_set(ogg_page *og){ 1.297 + if(og){ 1.298 + ogg_uint32_t crc_reg=0; 1.299 + int i; 1.300 + 1.301 + /* safety; needed for API behavior, but not framing code */ 1.302 + og->header[22]=0; 1.303 + og->header[23]=0; 1.304 + og->header[24]=0; 1.305 + og->header[25]=0; 1.306 + 1.307 + for(i=0;i<og->header_len;i++) 1.308 + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; 1.309 + for(i=0;i<og->body_len;i++) 1.310 + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]]; 1.311 + 1.312 + og->header[22]=(unsigned char)(crc_reg&0xff); 1.313 + og->header[23]=(unsigned char)((crc_reg>>8)&0xff); 1.314 + og->header[24]=(unsigned char)((crc_reg>>16)&0xff); 1.315 + og->header[25]=(unsigned char)((crc_reg>>24)&0xff); 1.316 + } 1.317 +} 1.318 + 1.319 +/* submit data to the internal buffer of the framing engine */ 1.320 +int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, 1.321 + long e_o_s, ogg_int64_t granulepos){ 1.322 + 1.323 + long bytes = 0, lacing_vals; 1.324 + int i; 1.325 + 1.326 + if(ogg_stream_check(os)) return -1; 1.327 + if(!iov) return 0; 1.328 + 1.329 + for (i = 0; i < count; ++i){ 1.330 + if(iov[i].iov_len>LONG_MAX) return -1; 1.331 + if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1; 1.332 + bytes += (long)iov[i].iov_len; 1.333 + } 1.334 + lacing_vals=bytes/255+1; 1.335 + 1.336 + if(os->body_returned){ 1.337 + /* advance packet data according to the body_returned pointer. We 1.338 + had to keep it around to return a pointer into the buffer last 1.339 + call */ 1.340 + 1.341 + os->body_fill-=os->body_returned; 1.342 + if(os->body_fill) 1.343 + memmove(os->body_data,os->body_data+os->body_returned, 1.344 + os->body_fill); 1.345 + os->body_returned=0; 1.346 + } 1.347 + 1.348 + /* make sure we have the buffer storage */ 1.349 + if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals)) 1.350 + return -1; 1.351 + 1.352 + /* Copy in the submitted packet. Yes, the copy is a waste; this is 1.353 + the liability of overly clean abstraction for the time being. It 1.354 + will actually be fairly easy to eliminate the extra copy in the 1.355 + future */ 1.356 + 1.357 + for (i = 0; i < count; ++i) { 1.358 + memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len); 1.359 + os->body_fill += (int)iov[i].iov_len; 1.360 + } 1.361 + 1.362 + /* Store lacing vals for this packet */ 1.363 + for(i=0;i<lacing_vals-1;i++){ 1.364 + os->lacing_vals[os->lacing_fill+i]=255; 1.365 + os->granule_vals[os->lacing_fill+i]=os->granulepos; 1.366 + } 1.367 + os->lacing_vals[os->lacing_fill+i]=bytes%255; 1.368 + os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos; 1.369 + 1.370 + /* flag the first segment as the beginning of the packet */ 1.371 + os->lacing_vals[os->lacing_fill]|= 0x100; 1.372 + 1.373 + os->lacing_fill+=lacing_vals; 1.374 + 1.375 + /* for the sake of completeness */ 1.376 + os->packetno++; 1.377 + 1.378 + if(e_o_s)os->e_o_s=1; 1.379 + 1.380 + return(0); 1.381 +} 1.382 + 1.383 +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ 1.384 + ogg_iovec_t iov; 1.385 + iov.iov_base = op->packet; 1.386 + iov.iov_len = op->bytes; 1.387 + return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos); 1.388 +} 1.389 + 1.390 +/* Conditionally flush a page; force==0 will only flush nominal-size 1.391 + pages, force==1 forces us to flush a page regardless of page size 1.392 + so long as there's any data available at all. */ 1.393 +static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){ 1.394 + int i; 1.395 + int vals=0; 1.396 + int maxvals=(os->lacing_fill>255?255:os->lacing_fill); 1.397 + int bytes=0; 1.398 + long acc=0; 1.399 + ogg_int64_t granule_pos=-1; 1.400 + 1.401 + if(ogg_stream_check(os)) return(0); 1.402 + if(maxvals==0) return(0); 1.403 + 1.404 + /* construct a page */ 1.405 + /* decide how many segments to include */ 1.406 + 1.407 + /* If this is the initial header case, the first page must only include 1.408 + the initial header packet */ 1.409 + if(os->b_o_s==0){ /* 'initial header page' case */ 1.410 + granule_pos=0; 1.411 + for(vals=0;vals<maxvals;vals++){ 1.412 + if((os->lacing_vals[vals]&0x0ff)<255){ 1.413 + vals++; 1.414 + break; 1.415 + } 1.416 + } 1.417 + }else{ 1.418 + 1.419 + /* The extra packets_done, packet_just_done logic here attempts to do two things: 1.420 + 1) Don't unneccessarily span pages. 1.421 + 2) Unless necessary, don't flush pages if there are less than four packets on 1.422 + them; this expands page size to reduce unneccessary overhead if incoming packets 1.423 + are large. 1.424 + These are not necessary behaviors, just 'always better than naive flushing' 1.425 + without requiring an application to explicitly request a specific optimized 1.426 + behavior. We'll want an explicit behavior setup pathway eventually as well. */ 1.427 + 1.428 + int packets_done=0; 1.429 + int packet_just_done=0; 1.430 + for(vals=0;vals<maxvals;vals++){ 1.431 + if(acc>nfill && packet_just_done>=4){ 1.432 + force=1; 1.433 + break; 1.434 + } 1.435 + acc+=os->lacing_vals[vals]&0x0ff; 1.436 + if((os->lacing_vals[vals]&0xff)<255){ 1.437 + granule_pos=os->granule_vals[vals]; 1.438 + packet_just_done=++packets_done; 1.439 + }else 1.440 + packet_just_done=0; 1.441 + } 1.442 + if(vals==255)force=1; 1.443 + } 1.444 + 1.445 + if(!force) return(0); 1.446 + 1.447 + /* construct the header in temp storage */ 1.448 + memcpy(os->header,"OggS",4); 1.449 + 1.450 + /* stream structure version */ 1.451 + os->header[4]=0x00; 1.452 + 1.453 + /* continued packet flag? */ 1.454 + os->header[5]=0x00; 1.455 + if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; 1.456 + /* first page flag? */ 1.457 + if(os->b_o_s==0)os->header[5]|=0x02; 1.458 + /* last page flag? */ 1.459 + if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; 1.460 + os->b_o_s=1; 1.461 + 1.462 + /* 64 bits of PCM position */ 1.463 + for(i=6;i<14;i++){ 1.464 + os->header[i]=(unsigned char)(granule_pos&0xff); 1.465 + granule_pos>>=8; 1.466 + } 1.467 + 1.468 + /* 32 bits of stream serial number */ 1.469 + { 1.470 + long serialno=os->serialno; 1.471 + for(i=14;i<18;i++){ 1.472 + os->header[i]=(unsigned char)(serialno&0xff); 1.473 + serialno>>=8; 1.474 + } 1.475 + } 1.476 + 1.477 + /* 32 bits of page counter (we have both counter and page header 1.478 + because this val can roll over) */ 1.479 + if(os->pageno==-1)os->pageno=0; /* because someone called 1.480 + stream_reset; this would be a 1.481 + strange thing to do in an 1.482 + encode stream, but it has 1.483 + plausible uses */ 1.484 + { 1.485 + long pageno=os->pageno++; 1.486 + for(i=18;i<22;i++){ 1.487 + os->header[i]=(unsigned char)(pageno&0xff); 1.488 + pageno>>=8; 1.489 + } 1.490 + } 1.491 + 1.492 + /* zero for computation; filled in later */ 1.493 + os->header[22]=0; 1.494 + os->header[23]=0; 1.495 + os->header[24]=0; 1.496 + os->header[25]=0; 1.497 + 1.498 + /* segment table */ 1.499 + os->header[26]=(unsigned char)(vals&0xff); 1.500 + for(i=0;i<vals;i++) 1.501 + bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); 1.502 + 1.503 + /* set pointers in the ogg_page struct */ 1.504 + og->header=os->header; 1.505 + og->header_len=os->header_fill=vals+27; 1.506 + og->body=os->body_data+os->body_returned; 1.507 + og->body_len=bytes; 1.508 + 1.509 + /* advance the lacing data and set the body_returned pointer */ 1.510 + 1.511 + os->lacing_fill-=vals; 1.512 + memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); 1.513 + memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); 1.514 + os->body_returned+=bytes; 1.515 + 1.516 + /* calculate the checksum */ 1.517 + 1.518 + ogg_page_checksum_set(og); 1.519 + 1.520 + /* done */ 1.521 + return(1); 1.522 +} 1.523 + 1.524 +/* This will flush remaining packets into a page (returning nonzero), 1.525 + even if there is not enough data to trigger a flush normally 1.526 + (undersized page). If there are no packets or partial packets to 1.527 + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will 1.528 + try to flush a normal sized page like ogg_stream_pageout; a call to 1.529 + ogg_stream_flush does not guarantee that all packets have flushed. 1.530 + Only a return value of 0 from ogg_stream_flush indicates all packet 1.531 + data is flushed into pages. 1.532 + 1.533 + since ogg_stream_flush will flush the last page in a stream even if 1.534 + it's undersized, you almost certainly want to use ogg_stream_pageout 1.535 + (and *not* ogg_stream_flush) unless you specifically need to flush 1.536 + a page regardless of size in the middle of a stream. */ 1.537 + 1.538 +int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ 1.539 + return ogg_stream_flush_i(os,og,1,4096); 1.540 +} 1.541 + 1.542 +/* Like the above, but an argument is provided to adjust the nominal 1.543 + page size for applications which are smart enough to provide their 1.544 + own delay based flushing */ 1.545 + 1.546 +int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){ 1.547 + return ogg_stream_flush_i(os,og,1,nfill); 1.548 +} 1.549 + 1.550 +/* This constructs pages from buffered packet segments. The pointers 1.551 +returned are to static buffers; do not free. The returned buffers are 1.552 +good only until the next call (using the same ogg_stream_state) */ 1.553 + 1.554 +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ 1.555 + int force=0; 1.556 + if(ogg_stream_check(os)) return 0; 1.557 + 1.558 + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ 1.559 + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ 1.560 + force=1; 1.561 + 1.562 + return(ogg_stream_flush_i(os,og,force,4096)); 1.563 +} 1.564 + 1.565 +/* Like the above, but an argument is provided to adjust the nominal 1.566 +page size for applications which are smart enough to provide their 1.567 +own delay based flushing */ 1.568 + 1.569 +int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){ 1.570 + int force=0; 1.571 + if(ogg_stream_check(os)) return 0; 1.572 + 1.573 + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ 1.574 + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ 1.575 + force=1; 1.576 + 1.577 + return(ogg_stream_flush_i(os,og,force,nfill)); 1.578 +} 1.579 + 1.580 +int ogg_stream_eos(ogg_stream_state *os){ 1.581 + if(ogg_stream_check(os)) return 1; 1.582 + return os->e_o_s; 1.583 +} 1.584 + 1.585 +/* DECODING PRIMITIVES: packet streaming layer **********************/ 1.586 + 1.587 +/* This has two layers to place more of the multi-serialno and paging 1.588 + control in the application's hands. First, we expose a data buffer 1.589 + using ogg_sync_buffer(). The app either copies into the 1.590 + buffer, or passes it directly to read(), etc. We then call 1.591 + ogg_sync_wrote() to tell how many bytes we just added. 1.592 + 1.593 + Pages are returned (pointers into the buffer in ogg_sync_state) 1.594 + by ogg_sync_pageout(). The page is then submitted to 1.595 + ogg_stream_pagein() along with the appropriate 1.596 + ogg_stream_state* (ie, matching serialno). We then get raw 1.597 + packets out calling ogg_stream_packetout() with a 1.598 + ogg_stream_state. */ 1.599 + 1.600 +/* initialize the struct to a known state */ 1.601 +int ogg_sync_init(ogg_sync_state *oy){ 1.602 + if(oy){ 1.603 + oy->storage = -1; /* used as a readiness flag */ 1.604 + memset(oy,0,sizeof(*oy)); 1.605 + } 1.606 + return(0); 1.607 +} 1.608 + 1.609 +/* clear non-flat storage within */ 1.610 +int ogg_sync_clear(ogg_sync_state *oy){ 1.611 + if(oy){ 1.612 + if(oy->data)_ogg_free(oy->data); 1.613 + memset(oy,0,sizeof(*oy)); 1.614 + } 1.615 + return(0); 1.616 +} 1.617 + 1.618 +int ogg_sync_destroy(ogg_sync_state *oy){ 1.619 + if(oy){ 1.620 + ogg_sync_clear(oy); 1.621 + _ogg_free(oy); 1.622 + } 1.623 + return(0); 1.624 +} 1.625 + 1.626 +int ogg_sync_check(ogg_sync_state *oy){ 1.627 + if(oy->storage<0) return -1; 1.628 + return 0; 1.629 +} 1.630 + 1.631 +char *ogg_sync_buffer(ogg_sync_state *oy, long size){ 1.632 + if(ogg_sync_check(oy)) return NULL; 1.633 + 1.634 + /* first, clear out any space that has been previously returned */ 1.635 + if(oy->returned){ 1.636 + oy->fill-=oy->returned; 1.637 + if(oy->fill>0) 1.638 + memmove(oy->data,oy->data+oy->returned,oy->fill); 1.639 + oy->returned=0; 1.640 + } 1.641 + 1.642 + if(size>oy->storage-oy->fill){ 1.643 + /* We need to extend the internal buffer */ 1.644 + long newsize=size+oy->fill+4096; /* an extra page to be nice */ 1.645 + void *ret; 1.646 + 1.647 + if(oy->data) 1.648 + ret=_ogg_realloc(oy->data,newsize); 1.649 + else 1.650 + ret=_ogg_malloc(newsize); 1.651 + if(!ret){ 1.652 + ogg_sync_clear(oy); 1.653 + return NULL; 1.654 + } 1.655 + oy->data=ret; 1.656 + oy->storage=newsize; 1.657 + } 1.658 + 1.659 + /* expose a segment at least as large as requested at the fill mark */ 1.660 + return((char *)oy->data+oy->fill); 1.661 +} 1.662 + 1.663 +int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ 1.664 + if(ogg_sync_check(oy))return -1; 1.665 + if(oy->fill+bytes>oy->storage)return -1; 1.666 + oy->fill+=bytes; 1.667 + return(0); 1.668 +} 1.669 + 1.670 +/* sync the stream. This is meant to be useful for finding page 1.671 + boundaries. 1.672 + 1.673 + return values for this: 1.674 + -n) skipped n bytes 1.675 + 0) page not ready; more data (no bytes skipped) 1.676 + n) page synced at current location; page length n bytes 1.677 + 1.678 +*/ 1.679 + 1.680 +long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ 1.681 + unsigned char *page=oy->data+oy->returned; 1.682 + unsigned char *next; 1.683 + long bytes=oy->fill-oy->returned; 1.684 + 1.685 + if(ogg_sync_check(oy))return 0; 1.686 + 1.687 + if(oy->headerbytes==0){ 1.688 + int headerbytes,i; 1.689 + if(bytes<27)return(0); /* not enough for a header */ 1.690 + 1.691 + /* verify capture pattern */ 1.692 + if(memcmp(page,"OggS",4))goto sync_fail; 1.693 + 1.694 + headerbytes=page[26]+27; 1.695 + if(bytes<headerbytes)return(0); /* not enough for header + seg table */ 1.696 + 1.697 + /* count up body length in the segment table */ 1.698 + 1.699 + for(i=0;i<page[26];i++) 1.700 + oy->bodybytes+=page[27+i]; 1.701 + oy->headerbytes=headerbytes; 1.702 + } 1.703 + 1.704 + if(oy->bodybytes+oy->headerbytes>bytes)return(0); 1.705 + 1.706 + /* The whole test page is buffered. Verify the checksum */ 1.707 + { 1.708 + /* Grab the checksum bytes, set the header field to zero */ 1.709 + char chksum[4]; 1.710 + ogg_page log; 1.711 + 1.712 + memcpy(chksum,page+22,4); 1.713 + memset(page+22,0,4); 1.714 + 1.715 + /* set up a temp page struct and recompute the checksum */ 1.716 + log.header=page; 1.717 + log.header_len=oy->headerbytes; 1.718 + log.body=page+oy->headerbytes; 1.719 + log.body_len=oy->bodybytes; 1.720 + ogg_page_checksum_set(&log); 1.721 + 1.722 + /* Compare */ 1.723 + if(memcmp(chksum,page+22,4)){ 1.724 + /* D'oh. Mismatch! Corrupt page (or miscapture and not a page 1.725 + at all) */ 1.726 + /* replace the computed checksum with the one actually read in */ 1.727 + memcpy(page+22,chksum,4); 1.728 + 1.729 + /* Bad checksum. Lose sync */ 1.730 + goto sync_fail; 1.731 + } 1.732 + } 1.733 + 1.734 + /* yes, have a whole page all ready to go */ 1.735 + { 1.736 + unsigned char *page=oy->data+oy->returned; 1.737 + long bytes; 1.738 + 1.739 + if(og){ 1.740 + og->header=page; 1.741 + og->header_len=oy->headerbytes; 1.742 + og->body=page+oy->headerbytes; 1.743 + og->body_len=oy->bodybytes; 1.744 + } 1.745 + 1.746 + oy->unsynced=0; 1.747 + oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); 1.748 + oy->headerbytes=0; 1.749 + oy->bodybytes=0; 1.750 + return(bytes); 1.751 + } 1.752 + 1.753 + sync_fail: 1.754 + 1.755 + oy->headerbytes=0; 1.756 + oy->bodybytes=0; 1.757 + 1.758 + /* search for possible capture */ 1.759 + next=memchr(page+1,'O',bytes-1); 1.760 + if(!next) 1.761 + next=oy->data+oy->fill; 1.762 + 1.763 + oy->returned=(int)(next-oy->data); 1.764 + return((long)-(next-page)); 1.765 +} 1.766 + 1.767 +/* sync the stream and get a page. Keep trying until we find a page. 1.768 + Suppress 'sync errors' after reporting the first. 1.769 + 1.770 + return values: 1.771 + -1) recapture (hole in data) 1.772 + 0) need more data 1.773 + 1) page returned 1.774 + 1.775 + Returns pointers into buffered data; invalidated by next call to 1.776 + _stream, _clear, _init, or _buffer */ 1.777 + 1.778 +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ 1.779 + 1.780 + if(ogg_sync_check(oy))return 0; 1.781 + 1.782 + /* all we need to do is verify a page at the head of the stream 1.783 + buffer. If it doesn't verify, we look for the next potential 1.784 + frame */ 1.785 + 1.786 + for(;;){ 1.787 + long ret=ogg_sync_pageseek(oy,og); 1.788 + if(ret>0){ 1.789 + /* have a page */ 1.790 + return(1); 1.791 + } 1.792 + if(ret==0){ 1.793 + /* need more data */ 1.794 + return(0); 1.795 + } 1.796 + 1.797 + /* head did not start a synced page... skipped some bytes */ 1.798 + if(!oy->unsynced){ 1.799 + oy->unsynced=1; 1.800 + return(-1); 1.801 + } 1.802 + 1.803 + /* loop. keep looking */ 1.804 + 1.805 + } 1.806 +} 1.807 + 1.808 +/* add the incoming page to the stream state; we decompose the page 1.809 + into packet segments here as well. */ 1.810 + 1.811 +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ 1.812 + unsigned char *header=og->header; 1.813 + unsigned char *body=og->body; 1.814 + long bodysize=og->body_len; 1.815 + int segptr=0; 1.816 + 1.817 + int version=ogg_page_version(og); 1.818 + int continued=ogg_page_continued(og); 1.819 + int bos=ogg_page_bos(og); 1.820 + int eos=ogg_page_eos(og); 1.821 + ogg_int64_t granulepos=ogg_page_granulepos(og); 1.822 + int serialno=ogg_page_serialno(og); 1.823 + long pageno=ogg_page_pageno(og); 1.824 + int segments=header[26]; 1.825 + 1.826 + if(ogg_stream_check(os)) return -1; 1.827 + 1.828 + /* clean up 'returned data' */ 1.829 + { 1.830 + long lr=os->lacing_returned; 1.831 + long br=os->body_returned; 1.832 + 1.833 + /* body data */ 1.834 + if(br){ 1.835 + os->body_fill-=br; 1.836 + if(os->body_fill) 1.837 + memmove(os->body_data,os->body_data+br,os->body_fill); 1.838 + os->body_returned=0; 1.839 + } 1.840 + 1.841 + if(lr){ 1.842 + /* segment table */ 1.843 + if(os->lacing_fill-lr){ 1.844 + memmove(os->lacing_vals,os->lacing_vals+lr, 1.845 + (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); 1.846 + memmove(os->granule_vals,os->granule_vals+lr, 1.847 + (os->lacing_fill-lr)*sizeof(*os->granule_vals)); 1.848 + } 1.849 + os->lacing_fill-=lr; 1.850 + os->lacing_packet-=lr; 1.851 + os->lacing_returned=0; 1.852 + } 1.853 + } 1.854 + 1.855 + /* check the serial number */ 1.856 + if(serialno!=os->serialno)return(-1); 1.857 + if(version>0)return(-1); 1.858 + 1.859 + if(_os_lacing_expand(os,segments+1)) return -1; 1.860 + 1.861 + /* are we in sequence? */ 1.862 + if(pageno!=os->pageno){ 1.863 + int i; 1.864 + 1.865 + /* unroll previous partial packet (if any) */ 1.866 + for(i=os->lacing_packet;i<os->lacing_fill;i++) 1.867 + os->body_fill-=os->lacing_vals[i]&0xff; 1.868 + os->lacing_fill=os->lacing_packet; 1.869 + 1.870 + /* make a note of dropped data in segment table */ 1.871 + if(os->pageno!=-1){ 1.872 + os->lacing_vals[os->lacing_fill++]=0x400; 1.873 + os->lacing_packet++; 1.874 + } 1.875 + } 1.876 + 1.877 + /* are we a 'continued packet' page? If so, we may need to skip 1.878 + some segments */ 1.879 + if(continued){ 1.880 + if(os->lacing_fill<1 || 1.881 + os->lacing_vals[os->lacing_fill-1]==0x400){ 1.882 + bos=0; 1.883 + for(;segptr<segments;segptr++){ 1.884 + int val=header[27+segptr]; 1.885 + body+=val; 1.886 + bodysize-=val; 1.887 + if(val<255){ 1.888 + segptr++; 1.889 + break; 1.890 + } 1.891 + } 1.892 + } 1.893 + } 1.894 + 1.895 + if(bodysize){ 1.896 + if(_os_body_expand(os,bodysize)) return -1; 1.897 + memcpy(os->body_data+os->body_fill,body,bodysize); 1.898 + os->body_fill+=bodysize; 1.899 + } 1.900 + 1.901 + { 1.902 + int saved=-1; 1.903 + while(segptr<segments){ 1.904 + int val=header[27+segptr]; 1.905 + os->lacing_vals[os->lacing_fill]=val; 1.906 + os->granule_vals[os->lacing_fill]=-1; 1.907 + 1.908 + if(bos){ 1.909 + os->lacing_vals[os->lacing_fill]|=0x100; 1.910 + bos=0; 1.911 + } 1.912 + 1.913 + if(val<255)saved=os->lacing_fill; 1.914 + 1.915 + os->lacing_fill++; 1.916 + segptr++; 1.917 + 1.918 + if(val<255)os->lacing_packet=os->lacing_fill; 1.919 + } 1.920 + 1.921 + /* set the granulepos on the last granuleval of the last full packet */ 1.922 + if(saved!=-1){ 1.923 + os->granule_vals[saved]=granulepos; 1.924 + } 1.925 + 1.926 + } 1.927 + 1.928 + if(eos){ 1.929 + os->e_o_s=1; 1.930 + if(os->lacing_fill>0) 1.931 + os->lacing_vals[os->lacing_fill-1]|=0x200; 1.932 + } 1.933 + 1.934 + os->pageno=pageno+1; 1.935 + 1.936 + return(0); 1.937 +} 1.938 + 1.939 +/* clear things to an initial state. Good to call, eg, before seeking */ 1.940 +int ogg_sync_reset(ogg_sync_state *oy){ 1.941 + if(ogg_sync_check(oy))return -1; 1.942 + 1.943 + oy->fill=0; 1.944 + oy->returned=0; 1.945 + oy->unsynced=0; 1.946 + oy->headerbytes=0; 1.947 + oy->bodybytes=0; 1.948 + return(0); 1.949 +} 1.950 + 1.951 +int ogg_stream_reset(ogg_stream_state *os){ 1.952 + if(ogg_stream_check(os)) return -1; 1.953 + 1.954 + os->body_fill=0; 1.955 + os->body_returned=0; 1.956 + 1.957 + os->lacing_fill=0; 1.958 + os->lacing_packet=0; 1.959 + os->lacing_returned=0; 1.960 + 1.961 + os->header_fill=0; 1.962 + 1.963 + os->e_o_s=0; 1.964 + os->b_o_s=0; 1.965 + os->pageno=-1; 1.966 + os->packetno=0; 1.967 + os->granulepos=0; 1.968 + 1.969 + return(0); 1.970 +} 1.971 + 1.972 +int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ 1.973 + if(ogg_stream_check(os)) return -1; 1.974 + ogg_stream_reset(os); 1.975 + os->serialno=serialno; 1.976 + return(0); 1.977 +} 1.978 + 1.979 +static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ 1.980 + 1.981 + /* The last part of decode. We have the stream broken into packet 1.982 + segments. Now we need to group them into packets (or return the 1.983 + out of sync markers) */ 1.984 + 1.985 + int ptr=os->lacing_returned; 1.986 + 1.987 + if(os->lacing_packet<=ptr)return(0); 1.988 + 1.989 + if(os->lacing_vals[ptr]&0x400){ 1.990 + /* we need to tell the codec there's a gap; it might need to 1.991 + handle previous packet dependencies. */ 1.992 + os->lacing_returned++; 1.993 + os->packetno++; 1.994 + return(-1); 1.995 + } 1.996 + 1.997 + if(!op && !adv)return(1); /* just using peek as an inexpensive way 1.998 + to ask if there's a whole packet 1.999 + waiting */ 1.1000 + 1.1001 + /* Gather the whole packet. We'll have no holes or a partial packet */ 1.1002 + { 1.1003 + int size=os->lacing_vals[ptr]&0xff; 1.1004 + long bytes=size; 1.1005 + int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ 1.1006 + int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ 1.1007 + 1.1008 + while(size==255){ 1.1009 + int val=os->lacing_vals[++ptr]; 1.1010 + size=val&0xff; 1.1011 + if(val&0x200)eos=0x200; 1.1012 + bytes+=size; 1.1013 + } 1.1014 + 1.1015 + if(op){ 1.1016 + op->e_o_s=eos; 1.1017 + op->b_o_s=bos; 1.1018 + op->packet=os->body_data+os->body_returned; 1.1019 + op->packetno=os->packetno; 1.1020 + op->granulepos=os->granule_vals[ptr]; 1.1021 + op->bytes=bytes; 1.1022 + } 1.1023 + 1.1024 + if(adv){ 1.1025 + os->body_returned+=bytes; 1.1026 + os->lacing_returned=ptr+1; 1.1027 + os->packetno++; 1.1028 + } 1.1029 + } 1.1030 + return(1); 1.1031 +} 1.1032 + 1.1033 +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ 1.1034 + if(ogg_stream_check(os)) return 0; 1.1035 + return _packetout(os,op,1); 1.1036 +} 1.1037 + 1.1038 +int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ 1.1039 + if(ogg_stream_check(os)) return 0; 1.1040 + return _packetout(os,op,0); 1.1041 +} 1.1042 + 1.1043 +void ogg_packet_clear(ogg_packet *op) { 1.1044 + _ogg_free(op->packet); 1.1045 + memset(op, 0, sizeof(*op)); 1.1046 +} 1.1047 + 1.1048 +#ifdef _V_SELFTEST 1.1049 +#include <stdio.h> 1.1050 + 1.1051 +ogg_stream_state os_en, os_de; 1.1052 +ogg_sync_state oy; 1.1053 + 1.1054 +void checkpacket(ogg_packet *op,long len, int no, long pos){ 1.1055 + long j; 1.1056 + static int sequence=0; 1.1057 + static int lastno=0; 1.1058 + 1.1059 + if(op->bytes!=len){ 1.1060 + fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len); 1.1061 + exit(1); 1.1062 + } 1.1063 + if(op->granulepos!=pos){ 1.1064 + fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos); 1.1065 + exit(1); 1.1066 + } 1.1067 + 1.1068 + /* packet number just follows sequence/gap; adjust the input number 1.1069 + for that */ 1.1070 + if(no==0){ 1.1071 + sequence=0; 1.1072 + }else{ 1.1073 + sequence++; 1.1074 + if(no>lastno+1) 1.1075 + sequence++; 1.1076 + } 1.1077 + lastno=no; 1.1078 + if(op->packetno!=sequence){ 1.1079 + fprintf(stderr,"incorrect packet sequence %ld != %d\n", 1.1080 + (long)(op->packetno),sequence); 1.1081 + exit(1); 1.1082 + } 1.1083 + 1.1084 + /* Test data */ 1.1085 + for(j=0;j<op->bytes;j++) 1.1086 + if(op->packet[j]!=((j+no)&0xff)){ 1.1087 + fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", 1.1088 + j,op->packet[j],(j+no)&0xff); 1.1089 + exit(1); 1.1090 + } 1.1091 +} 1.1092 + 1.1093 +void check_page(unsigned char *data,const int *header,ogg_page *og){ 1.1094 + long j; 1.1095 + /* Test data */ 1.1096 + for(j=0;j<og->body_len;j++) 1.1097 + if(og->body[j]!=data[j]){ 1.1098 + fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", 1.1099 + j,data[j],og->body[j]); 1.1100 + exit(1); 1.1101 + } 1.1102 + 1.1103 + /* Test header */ 1.1104 + for(j=0;j<og->header_len;j++){ 1.1105 + if(og->header[j]!=header[j]){ 1.1106 + fprintf(stderr,"header content mismatch at pos %ld:\n",j); 1.1107 + for(j=0;j<header[26]+27;j++) 1.1108 + fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]); 1.1109 + fprintf(stderr,"\n"); 1.1110 + exit(1); 1.1111 + } 1.1112 + } 1.1113 + if(og->header_len!=header[26]+27){ 1.1114 + fprintf(stderr,"header length incorrect! (%ld!=%d)\n", 1.1115 + og->header_len,header[26]+27); 1.1116 + exit(1); 1.1117 + } 1.1118 +} 1.1119 + 1.1120 +void print_header(ogg_page *og){ 1.1121 + int j; 1.1122 + fprintf(stderr,"\nHEADER:\n"); 1.1123 + fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", 1.1124 + og->header[0],og->header[1],og->header[2],og->header[3], 1.1125 + (int)og->header[4],(int)og->header[5]); 1.1126 + 1.1127 + fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", 1.1128 + (og->header[9]<<24)|(og->header[8]<<16)| 1.1129 + (og->header[7]<<8)|og->header[6], 1.1130 + (og->header[17]<<24)|(og->header[16]<<16)| 1.1131 + (og->header[15]<<8)|og->header[14], 1.1132 + ((long)(og->header[21])<<24)|(og->header[20]<<16)| 1.1133 + (og->header[19]<<8)|og->header[18]); 1.1134 + 1.1135 + fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", 1.1136 + (int)og->header[22],(int)og->header[23], 1.1137 + (int)og->header[24],(int)og->header[25], 1.1138 + (int)og->header[26]); 1.1139 + 1.1140 + for(j=27;j<og->header_len;j++) 1.1141 + fprintf(stderr,"%d ",(int)og->header[j]); 1.1142 + fprintf(stderr,")\n\n"); 1.1143 +} 1.1144 + 1.1145 +void copy_page(ogg_page *og){ 1.1146 + unsigned char *temp=_ogg_malloc(og->header_len); 1.1147 + memcpy(temp,og->header,og->header_len); 1.1148 + og->header=temp; 1.1149 + 1.1150 + temp=_ogg_malloc(og->body_len); 1.1151 + memcpy(temp,og->body,og->body_len); 1.1152 + og->body=temp; 1.1153 +} 1.1154 + 1.1155 +void free_page(ogg_page *og){ 1.1156 + _ogg_free (og->header); 1.1157 + _ogg_free (og->body); 1.1158 +} 1.1159 + 1.1160 +void error(void){ 1.1161 + fprintf(stderr,"error!\n"); 1.1162 + exit(1); 1.1163 +} 1.1164 + 1.1165 +/* 17 only */ 1.1166 +const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, 1.1167 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1168 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1169 + 0x15,0xed,0xec,0x91, 1.1170 + 1, 1.1171 + 17}; 1.1172 + 1.1173 +/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ 1.1174 +const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, 1.1175 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1176 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1177 + 0x59,0x10,0x6c,0x2c, 1.1178 + 1, 1.1179 + 17}; 1.1180 +const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, 1.1181 + 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 1.1182 + 0x01,0x02,0x03,0x04,1,0,0,0, 1.1183 + 0x89,0x33,0x85,0xce, 1.1184 + 13, 1.1185 + 254,255,0,255,1,255,245,255,255,0, 1.1186 + 255,255,90}; 1.1187 + 1.1188 +/* nil packets; beginning,middle,end */ 1.1189 +const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, 1.1190 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1191 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1192 + 0xff,0x7b,0x23,0x17, 1.1193 + 1, 1.1194 + 0}; 1.1195 +const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, 1.1196 + 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, 1.1197 + 0x01,0x02,0x03,0x04,1,0,0,0, 1.1198 + 0x5c,0x3f,0x66,0xcb, 1.1199 + 17, 1.1200 + 17,254,255,0,0,255,1,0,255,245,255,255,0, 1.1201 + 255,255,90,0}; 1.1202 + 1.1203 +/* large initial packet */ 1.1204 +const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, 1.1205 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1206 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1207 + 0x01,0x27,0x31,0xaa, 1.1208 + 18, 1.1209 + 255,255,255,255,255,255,255,255, 1.1210 + 255,255,255,255,255,255,255,255,255,10}; 1.1211 + 1.1212 +const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, 1.1213 + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, 1.1214 + 0x01,0x02,0x03,0x04,1,0,0,0, 1.1215 + 0x7f,0x4e,0x8a,0xd2, 1.1216 + 4, 1.1217 + 255,4,255,0}; 1.1218 + 1.1219 + 1.1220 +/* continuing packet test */ 1.1221 +const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, 1.1222 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1223 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1224 + 0xff,0x7b,0x23,0x17, 1.1225 + 1, 1.1226 + 0}; 1.1227 + 1.1228 +const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, 1.1229 + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 1.1230 + 0x01,0x02,0x03,0x04,1,0,0,0, 1.1231 + 0xf8,0x3c,0x19,0x79, 1.1232 + 255, 1.1233 + 255,255,255,255,255,255,255,255, 1.1234 + 255,255,255,255,255,255,255,255, 1.1235 + 255,255,255,255,255,255,255,255, 1.1236 + 255,255,255,255,255,255,255,255, 1.1237 + 255,255,255,255,255,255,255,255, 1.1238 + 255,255,255,255,255,255,255,255, 1.1239 + 255,255,255,255,255,255,255,255, 1.1240 + 255,255,255,255,255,255,255,255, 1.1241 + 255,255,255,255,255,255,255,255, 1.1242 + 255,255,255,255,255,255,255,255, 1.1243 + 255,255,255,255,255,255,255,255, 1.1244 + 255,255,255,255,255,255,255,255, 1.1245 + 255,255,255,255,255,255,255,255, 1.1246 + 255,255,255,255,255,255,255,255, 1.1247 + 255,255,255,255,255,255,255,255, 1.1248 + 255,255,255,255,255,255,255,255, 1.1249 + 255,255,255,255,255,255,255,255, 1.1250 + 255,255,255,255,255,255,255,255, 1.1251 + 255,255,255,255,255,255,255,255, 1.1252 + 255,255,255,255,255,255,255,255, 1.1253 + 255,255,255,255,255,255,255,255, 1.1254 + 255,255,255,255,255,255,255,255, 1.1255 + 255,255,255,255,255,255,255,255, 1.1256 + 255,255,255,255,255,255,255,255, 1.1257 + 255,255,255,255,255,255,255,255, 1.1258 + 255,255,255,255,255,255,255,255, 1.1259 + 255,255,255,255,255,255,255,255, 1.1260 + 255,255,255,255,255,255,255,255, 1.1261 + 255,255,255,255,255,255,255,255, 1.1262 + 255,255,255,255,255,255,255,255, 1.1263 + 255,255,255,255,255,255,255,255, 1.1264 + 255,255,255,255,255,255,255}; 1.1265 + 1.1266 +const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, 1.1267 + 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, 1.1268 + 0x01,0x02,0x03,0x04,2,0,0,0, 1.1269 + 0x38,0xe6,0xb6,0x28, 1.1270 + 6, 1.1271 + 255,220,255,4,255,0}; 1.1272 + 1.1273 + 1.1274 +/* spill expansion test */ 1.1275 +const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02, 1.1276 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1277 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1278 + 0xff,0x7b,0x23,0x17, 1.1279 + 1, 1.1280 + 0}; 1.1281 + 1.1282 +const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00, 1.1283 + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, 1.1284 + 0x01,0x02,0x03,0x04,1,0,0,0, 1.1285 + 0xce,0x8f,0x17,0x1a, 1.1286 + 23, 1.1287 + 255,255,255,255,255,255,255,255, 1.1288 + 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0}; 1.1289 + 1.1290 + 1.1291 +const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04, 1.1292 + 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00, 1.1293 + 0x01,0x02,0x03,0x04,2,0,0,0, 1.1294 + 0x9b,0xb2,0x50,0xa1, 1.1295 + 1, 1.1296 + 0}; 1.1297 + 1.1298 +/* page with the 255 segment limit */ 1.1299 +const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, 1.1300 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1301 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1302 + 0xff,0x7b,0x23,0x17, 1.1303 + 1, 1.1304 + 0}; 1.1305 + 1.1306 +const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, 1.1307 + 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, 1.1308 + 0x01,0x02,0x03,0x04,1,0,0,0, 1.1309 + 0xed,0x2a,0x2e,0xa7, 1.1310 + 255, 1.1311 + 10,10,10,10,10,10,10,10, 1.1312 + 10,10,10,10,10,10,10,10, 1.1313 + 10,10,10,10,10,10,10,10, 1.1314 + 10,10,10,10,10,10,10,10, 1.1315 + 10,10,10,10,10,10,10,10, 1.1316 + 10,10,10,10,10,10,10,10, 1.1317 + 10,10,10,10,10,10,10,10, 1.1318 + 10,10,10,10,10,10,10,10, 1.1319 + 10,10,10,10,10,10,10,10, 1.1320 + 10,10,10,10,10,10,10,10, 1.1321 + 10,10,10,10,10,10,10,10, 1.1322 + 10,10,10,10,10,10,10,10, 1.1323 + 10,10,10,10,10,10,10,10, 1.1324 + 10,10,10,10,10,10,10,10, 1.1325 + 10,10,10,10,10,10,10,10, 1.1326 + 10,10,10,10,10,10,10,10, 1.1327 + 10,10,10,10,10,10,10,10, 1.1328 + 10,10,10,10,10,10,10,10, 1.1329 + 10,10,10,10,10,10,10,10, 1.1330 + 10,10,10,10,10,10,10,10, 1.1331 + 10,10,10,10,10,10,10,10, 1.1332 + 10,10,10,10,10,10,10,10, 1.1333 + 10,10,10,10,10,10,10,10, 1.1334 + 10,10,10,10,10,10,10,10, 1.1335 + 10,10,10,10,10,10,10,10, 1.1336 + 10,10,10,10,10,10,10,10, 1.1337 + 10,10,10,10,10,10,10,10, 1.1338 + 10,10,10,10,10,10,10,10, 1.1339 + 10,10,10,10,10,10,10,10, 1.1340 + 10,10,10,10,10,10,10,10, 1.1341 + 10,10,10,10,10,10,10,10, 1.1342 + 10,10,10,10,10,10,10}; 1.1343 + 1.1344 +const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, 1.1345 + 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, 1.1346 + 0x01,0x02,0x03,0x04,2,0,0,0, 1.1347 + 0x6c,0x3b,0x82,0x3d, 1.1348 + 1, 1.1349 + 50}; 1.1350 + 1.1351 + 1.1352 +/* packet that overspans over an entire page */ 1.1353 +const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, 1.1354 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1355 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1356 + 0xff,0x7b,0x23,0x17, 1.1357 + 1, 1.1358 + 0}; 1.1359 + 1.1360 +const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, 1.1361 + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 1.1362 + 0x01,0x02,0x03,0x04,1,0,0,0, 1.1363 + 0x68,0x22,0x7c,0x3d, 1.1364 + 255, 1.1365 + 100, 1.1366 + 255,255,255,255,255,255,255,255, 1.1367 + 255,255,255,255,255,255,255,255, 1.1368 + 255,255,255,255,255,255,255,255, 1.1369 + 255,255,255,255,255,255,255,255, 1.1370 + 255,255,255,255,255,255,255,255, 1.1371 + 255,255,255,255,255,255,255,255, 1.1372 + 255,255,255,255,255,255,255,255, 1.1373 + 255,255,255,255,255,255,255,255, 1.1374 + 255,255,255,255,255,255,255,255, 1.1375 + 255,255,255,255,255,255,255,255, 1.1376 + 255,255,255,255,255,255,255,255, 1.1377 + 255,255,255,255,255,255,255,255, 1.1378 + 255,255,255,255,255,255,255,255, 1.1379 + 255,255,255,255,255,255,255,255, 1.1380 + 255,255,255,255,255,255,255,255, 1.1381 + 255,255,255,255,255,255,255,255, 1.1382 + 255,255,255,255,255,255,255,255, 1.1383 + 255,255,255,255,255,255,255,255, 1.1384 + 255,255,255,255,255,255,255,255, 1.1385 + 255,255,255,255,255,255,255,255, 1.1386 + 255,255,255,255,255,255,255,255, 1.1387 + 255,255,255,255,255,255,255,255, 1.1388 + 255,255,255,255,255,255,255,255, 1.1389 + 255,255,255,255,255,255,255,255, 1.1390 + 255,255,255,255,255,255,255,255, 1.1391 + 255,255,255,255,255,255,255,255, 1.1392 + 255,255,255,255,255,255,255,255, 1.1393 + 255,255,255,255,255,255,255,255, 1.1394 + 255,255,255,255,255,255,255,255, 1.1395 + 255,255,255,255,255,255,255,255, 1.1396 + 255,255,255,255,255,255,255,255, 1.1397 + 255,255,255,255,255,255}; 1.1398 + 1.1399 +const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, 1.1400 + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 1.1401 + 0x01,0x02,0x03,0x04,2,0,0,0, 1.1402 + 0xf4,0x87,0xba,0xf3, 1.1403 + 255, 1.1404 + 255,255,255,255,255,255,255,255, 1.1405 + 255,255,255,255,255,255,255,255, 1.1406 + 255,255,255,255,255,255,255,255, 1.1407 + 255,255,255,255,255,255,255,255, 1.1408 + 255,255,255,255,255,255,255,255, 1.1409 + 255,255,255,255,255,255,255,255, 1.1410 + 255,255,255,255,255,255,255,255, 1.1411 + 255,255,255,255,255,255,255,255, 1.1412 + 255,255,255,255,255,255,255,255, 1.1413 + 255,255,255,255,255,255,255,255, 1.1414 + 255,255,255,255,255,255,255,255, 1.1415 + 255,255,255,255,255,255,255,255, 1.1416 + 255,255,255,255,255,255,255,255, 1.1417 + 255,255,255,255,255,255,255,255, 1.1418 + 255,255,255,255,255,255,255,255, 1.1419 + 255,255,255,255,255,255,255,255, 1.1420 + 255,255,255,255,255,255,255,255, 1.1421 + 255,255,255,255,255,255,255,255, 1.1422 + 255,255,255,255,255,255,255,255, 1.1423 + 255,255,255,255,255,255,255,255, 1.1424 + 255,255,255,255,255,255,255,255, 1.1425 + 255,255,255,255,255,255,255,255, 1.1426 + 255,255,255,255,255,255,255,255, 1.1427 + 255,255,255,255,255,255,255,255, 1.1428 + 255,255,255,255,255,255,255,255, 1.1429 + 255,255,255,255,255,255,255,255, 1.1430 + 255,255,255,255,255,255,255,255, 1.1431 + 255,255,255,255,255,255,255,255, 1.1432 + 255,255,255,255,255,255,255,255, 1.1433 + 255,255,255,255,255,255,255,255, 1.1434 + 255,255,255,255,255,255,255,255, 1.1435 + 255,255,255,255,255,255,255}; 1.1436 + 1.1437 +const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, 1.1438 + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, 1.1439 + 0x01,0x02,0x03,0x04,3,0,0,0, 1.1440 + 0xf7,0x2f,0x6c,0x60, 1.1441 + 5, 1.1442 + 254,255,4,255,0}; 1.1443 + 1.1444 +/* packet that overspans over an entire page */ 1.1445 +const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, 1.1446 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1.1447 + 0x01,0x02,0x03,0x04,0,0,0,0, 1.1448 + 0xff,0x7b,0x23,0x17, 1.1449 + 1, 1.1450 + 0}; 1.1451 + 1.1452 +const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, 1.1453 + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 1.1454 + 0x01,0x02,0x03,0x04,1,0,0,0, 1.1455 + 0x68,0x22,0x7c,0x3d, 1.1456 + 255, 1.1457 + 100, 1.1458 + 255,255,255,255,255,255,255,255, 1.1459 + 255,255,255,255,255,255,255,255, 1.1460 + 255,255,255,255,255,255,255,255, 1.1461 + 255,255,255,255,255,255,255,255, 1.1462 + 255,255,255,255,255,255,255,255, 1.1463 + 255,255,255,255,255,255,255,255, 1.1464 + 255,255,255,255,255,255,255,255, 1.1465 + 255,255,255,255,255,255,255,255, 1.1466 + 255,255,255,255,255,255,255,255, 1.1467 + 255,255,255,255,255,255,255,255, 1.1468 + 255,255,255,255,255,255,255,255, 1.1469 + 255,255,255,255,255,255,255,255, 1.1470 + 255,255,255,255,255,255,255,255, 1.1471 + 255,255,255,255,255,255,255,255, 1.1472 + 255,255,255,255,255,255,255,255, 1.1473 + 255,255,255,255,255,255,255,255, 1.1474 + 255,255,255,255,255,255,255,255, 1.1475 + 255,255,255,255,255,255,255,255, 1.1476 + 255,255,255,255,255,255,255,255, 1.1477 + 255,255,255,255,255,255,255,255, 1.1478 + 255,255,255,255,255,255,255,255, 1.1479 + 255,255,255,255,255,255,255,255, 1.1480 + 255,255,255,255,255,255,255,255, 1.1481 + 255,255,255,255,255,255,255,255, 1.1482 + 255,255,255,255,255,255,255,255, 1.1483 + 255,255,255,255,255,255,255,255, 1.1484 + 255,255,255,255,255,255,255,255, 1.1485 + 255,255,255,255,255,255,255,255, 1.1486 + 255,255,255,255,255,255,255,255, 1.1487 + 255,255,255,255,255,255,255,255, 1.1488 + 255,255,255,255,255,255,255,255, 1.1489 + 255,255,255,255,255,255}; 1.1490 + 1.1491 +const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, 1.1492 + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, 1.1493 + 0x01,0x02,0x03,0x04,2,0,0,0, 1.1494 + 0xd4,0xe0,0x60,0xe5, 1.1495 + 1, 1.1496 + 0}; 1.1497 + 1.1498 +void test_pack(const int *pl, const int **headers, int byteskip, 1.1499 + int pageskip, int packetskip){ 1.1500 + unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ 1.1501 + long inptr=0; 1.1502 + long outptr=0; 1.1503 + long deptr=0; 1.1504 + long depacket=0; 1.1505 + long granule_pos=7,pageno=0; 1.1506 + int i,j,packets,pageout=pageskip; 1.1507 + int eosflag=0; 1.1508 + int bosflag=0; 1.1509 + 1.1510 + int byteskipcount=0; 1.1511 + 1.1512 + ogg_stream_reset(&os_en); 1.1513 + ogg_stream_reset(&os_de); 1.1514 + ogg_sync_reset(&oy); 1.1515 + 1.1516 + for(packets=0;packets<packetskip;packets++) 1.1517 + depacket+=pl[packets]; 1.1518 + 1.1519 + for(packets=0;;packets++)if(pl[packets]==-1)break; 1.1520 + 1.1521 + for(i=0;i<packets;i++){ 1.1522 + /* construct a test packet */ 1.1523 + ogg_packet op; 1.1524 + int len=pl[i]; 1.1525 + 1.1526 + op.packet=data+inptr; 1.1527 + op.bytes=len; 1.1528 + op.e_o_s=(pl[i+1]<0?1:0); 1.1529 + op.granulepos=granule_pos; 1.1530 + 1.1531 + granule_pos+=1024; 1.1532 + 1.1533 + for(j=0;j<len;j++)data[inptr++]=i+j; 1.1534 + 1.1535 + /* submit the test packet */ 1.1536 + ogg_stream_packetin(&os_en,&op); 1.1537 + 1.1538 + /* retrieve any finished pages */ 1.1539 + { 1.1540 + ogg_page og; 1.1541 + 1.1542 + while(ogg_stream_pageout(&os_en,&og)){ 1.1543 + /* We have a page. Check it carefully */ 1.1544 + 1.1545 + fprintf(stderr,"%ld, ",pageno); 1.1546 + 1.1547 + if(headers[pageno]==NULL){ 1.1548 + fprintf(stderr,"coded too many pages!\n"); 1.1549 + exit(1); 1.1550 + } 1.1551 + 1.1552 + check_page(data+outptr,headers[pageno],&og); 1.1553 + 1.1554 + outptr+=og.body_len; 1.1555 + pageno++; 1.1556 + if(pageskip){ 1.1557 + bosflag=1; 1.1558 + pageskip--; 1.1559 + deptr+=og.body_len; 1.1560 + } 1.1561 + 1.1562 + /* have a complete page; submit it to sync/decode */ 1.1563 + 1.1564 + { 1.1565 + ogg_page og_de; 1.1566 + ogg_packet op_de,op_de2; 1.1567 + char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len); 1.1568 + char *next=buf; 1.1569 + byteskipcount+=og.header_len; 1.1570 + if(byteskipcount>byteskip){ 1.1571 + memcpy(next,og.header,byteskipcount-byteskip); 1.1572 + next+=byteskipcount-byteskip; 1.1573 + byteskipcount=byteskip; 1.1574 + } 1.1575 + 1.1576 + byteskipcount+=og.body_len; 1.1577 + if(byteskipcount>byteskip){ 1.1578 + memcpy(next,og.body,byteskipcount-byteskip); 1.1579 + next+=byteskipcount-byteskip; 1.1580 + byteskipcount=byteskip; 1.1581 + } 1.1582 + 1.1583 + ogg_sync_wrote(&oy,next-buf); 1.1584 + 1.1585 + while(1){ 1.1586 + int ret=ogg_sync_pageout(&oy,&og_de); 1.1587 + if(ret==0)break; 1.1588 + if(ret<0)continue; 1.1589 + /* got a page. Happy happy. Verify that it's good. */ 1.1590 + 1.1591 + fprintf(stderr,"(%d), ",pageout); 1.1592 + 1.1593 + check_page(data+deptr,headers[pageout],&og_de); 1.1594 + deptr+=og_de.body_len; 1.1595 + pageout++; 1.1596 + 1.1597 + /* submit it to deconstitution */ 1.1598 + ogg_stream_pagein(&os_de,&og_de); 1.1599 + 1.1600 + /* packets out? */ 1.1601 + while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ 1.1602 + ogg_stream_packetpeek(&os_de,NULL); 1.1603 + ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ 1.1604 + 1.1605 + /* verify peek and out match */ 1.1606 + if(memcmp(&op_de,&op_de2,sizeof(op_de))){ 1.1607 + fprintf(stderr,"packetout != packetpeek! pos=%ld\n", 1.1608 + depacket); 1.1609 + exit(1); 1.1610 + } 1.1611 + 1.1612 + /* verify the packet! */ 1.1613 + /* check data */ 1.1614 + if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ 1.1615 + fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", 1.1616 + depacket); 1.1617 + exit(1); 1.1618 + } 1.1619 + /* check bos flag */ 1.1620 + if(bosflag==0 && op_de.b_o_s==0){ 1.1621 + fprintf(stderr,"b_o_s flag not set on packet!\n"); 1.1622 + exit(1); 1.1623 + } 1.1624 + if(bosflag && op_de.b_o_s){ 1.1625 + fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); 1.1626 + exit(1); 1.1627 + } 1.1628 + bosflag=1; 1.1629 + depacket+=op_de.bytes; 1.1630 + 1.1631 + /* check eos flag */ 1.1632 + if(eosflag){ 1.1633 + fprintf(stderr,"Multiple decoded packets with eos flag!\n"); 1.1634 + exit(1); 1.1635 + } 1.1636 + 1.1637 + if(op_de.e_o_s)eosflag=1; 1.1638 + 1.1639 + /* check granulepos flag */ 1.1640 + if(op_de.granulepos!=-1){ 1.1641 + fprintf(stderr," granule:%ld ",(long)op_de.granulepos); 1.1642 + } 1.1643 + } 1.1644 + } 1.1645 + } 1.1646 + } 1.1647 + } 1.1648 + } 1.1649 + _ogg_free(data); 1.1650 + if(headers[pageno]!=NULL){ 1.1651 + fprintf(stderr,"did not write last page!\n"); 1.1652 + exit(1); 1.1653 + } 1.1654 + if(headers[pageout]!=NULL){ 1.1655 + fprintf(stderr,"did not decode last page!\n"); 1.1656 + exit(1); 1.1657 + } 1.1658 + if(inptr!=outptr){ 1.1659 + fprintf(stderr,"encoded page data incomplete!\n"); 1.1660 + exit(1); 1.1661 + } 1.1662 + if(inptr!=deptr){ 1.1663 + fprintf(stderr,"decoded page data incomplete!\n"); 1.1664 + exit(1); 1.1665 + } 1.1666 + if(inptr!=depacket){ 1.1667 + fprintf(stderr,"decoded packet data incomplete!\n"); 1.1668 + exit(1); 1.1669 + } 1.1670 + if(!eosflag){ 1.1671 + fprintf(stderr,"Never got a packet with EOS set!\n"); 1.1672 + exit(1); 1.1673 + } 1.1674 + fprintf(stderr,"ok.\n"); 1.1675 +} 1.1676 + 1.1677 +int main(void){ 1.1678 + 1.1679 + ogg_stream_init(&os_en,0x04030201); 1.1680 + ogg_stream_init(&os_de,0x04030201); 1.1681 + ogg_sync_init(&oy); 1.1682 + 1.1683 + /* Exercise each code path in the framing code. Also verify that 1.1684 + the checksums are working. */ 1.1685 + 1.1686 + { 1.1687 + /* 17 only */ 1.1688 + const int packets[]={17, -1}; 1.1689 + const int *headret[]={head1_0,NULL}; 1.1690 + 1.1691 + fprintf(stderr,"testing single page encoding... "); 1.1692 + test_pack(packets,headret,0,0,0); 1.1693 + } 1.1694 + 1.1695 + { 1.1696 + /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ 1.1697 + const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; 1.1698 + const int *headret[]={head1_1,head2_1,NULL}; 1.1699 + 1.1700 + fprintf(stderr,"testing basic page encoding... "); 1.1701 + test_pack(packets,headret,0,0,0); 1.1702 + } 1.1703 + 1.1704 + { 1.1705 + /* nil packets; beginning,middle,end */ 1.1706 + const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; 1.1707 + const int *headret[]={head1_2,head2_2,NULL}; 1.1708 + 1.1709 + fprintf(stderr,"testing basic nil packets... "); 1.1710 + test_pack(packets,headret,0,0,0); 1.1711 + } 1.1712 + 1.1713 + { 1.1714 + /* large initial packet */ 1.1715 + const int packets[]={4345,259,255,-1}; 1.1716 + const int *headret[]={head1_3,head2_3,NULL}; 1.1717 + 1.1718 + fprintf(stderr,"testing initial-packet lacing > 4k... "); 1.1719 + test_pack(packets,headret,0,0,0); 1.1720 + } 1.1721 + 1.1722 + { 1.1723 + /* continuing packet test; with page spill expansion, we have to 1.1724 + overflow the lacing table. */ 1.1725 + const int packets[]={0,65500,259,255,-1}; 1.1726 + const int *headret[]={head1_4,head2_4,head3_4,NULL}; 1.1727 + 1.1728 + fprintf(stderr,"testing single packet page span... "); 1.1729 + test_pack(packets,headret,0,0,0); 1.1730 + } 1.1731 + 1.1732 + { 1.1733 + /* spill expand packet test */ 1.1734 + const int packets[]={0,4345,259,255,0,0,-1}; 1.1735 + const int *headret[]={head1_4b,head2_4b,head3_4b,NULL}; 1.1736 + 1.1737 + fprintf(stderr,"testing page spill expansion... "); 1.1738 + test_pack(packets,headret,0,0,0); 1.1739 + } 1.1740 + 1.1741 + /* page with the 255 segment limit */ 1.1742 + { 1.1743 + 1.1744 + const int packets[]={0,10,10,10,10,10,10,10,10, 1.1745 + 10,10,10,10,10,10,10,10, 1.1746 + 10,10,10,10,10,10,10,10, 1.1747 + 10,10,10,10,10,10,10,10, 1.1748 + 10,10,10,10,10,10,10,10, 1.1749 + 10,10,10,10,10,10,10,10, 1.1750 + 10,10,10,10,10,10,10,10, 1.1751 + 10,10,10,10,10,10,10,10, 1.1752 + 10,10,10,10,10,10,10,10, 1.1753 + 10,10,10,10,10,10,10,10, 1.1754 + 10,10,10,10,10,10,10,10, 1.1755 + 10,10,10,10,10,10,10,10, 1.1756 + 10,10,10,10,10,10,10,10, 1.1757 + 10,10,10,10,10,10,10,10, 1.1758 + 10,10,10,10,10,10,10,10, 1.1759 + 10,10,10,10,10,10,10,10, 1.1760 + 10,10,10,10,10,10,10,10, 1.1761 + 10,10,10,10,10,10,10,10, 1.1762 + 10,10,10,10,10,10,10,10, 1.1763 + 10,10,10,10,10,10,10,10, 1.1764 + 10,10,10,10,10,10,10,10, 1.1765 + 10,10,10,10,10,10,10,10, 1.1766 + 10,10,10,10,10,10,10,10, 1.1767 + 10,10,10,10,10,10,10,10, 1.1768 + 10,10,10,10,10,10,10,10, 1.1769 + 10,10,10,10,10,10,10,10, 1.1770 + 10,10,10,10,10,10,10,10, 1.1771 + 10,10,10,10,10,10,10,10, 1.1772 + 10,10,10,10,10,10,10,10, 1.1773 + 10,10,10,10,10,10,10,10, 1.1774 + 10,10,10,10,10,10,10,10, 1.1775 + 10,10,10,10,10,10,10,50,-1}; 1.1776 + const int *headret[]={head1_5,head2_5,head3_5,NULL}; 1.1777 + 1.1778 + fprintf(stderr,"testing max packet segments... "); 1.1779 + test_pack(packets,headret,0,0,0); 1.1780 + } 1.1781 + 1.1782 + { 1.1783 + /* packet that overspans over an entire page */ 1.1784 + const int packets[]={0,100,130049,259,255,-1}; 1.1785 + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; 1.1786 + 1.1787 + fprintf(stderr,"testing very large packets... "); 1.1788 + test_pack(packets,headret,0,0,0); 1.1789 + } 1.1790 + 1.1791 + { 1.1792 + /* test for the libogg 1.1.1 resync in large continuation bug 1.1793 + found by Josh Coalson) */ 1.1794 + const int packets[]={0,100,130049,259,255,-1}; 1.1795 + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; 1.1796 + 1.1797 + fprintf(stderr,"testing continuation resync in very large packets... "); 1.1798 + test_pack(packets,headret,100,2,3); 1.1799 + } 1.1800 + 1.1801 + { 1.1802 + /* term only page. why not? */ 1.1803 + const int packets[]={0,100,64770,-1}; 1.1804 + const int *headret[]={head1_7,head2_7,head3_7,NULL}; 1.1805 + 1.1806 + fprintf(stderr,"testing zero data page (1 nil packet)... "); 1.1807 + test_pack(packets,headret,0,0,0); 1.1808 + } 1.1809 + 1.1810 + 1.1811 + 1.1812 + { 1.1813 + /* build a bunch of pages for testing */ 1.1814 + unsigned char *data=_ogg_malloc(1024*1024); 1.1815 + int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1}; 1.1816 + int inptr=0,i,j; 1.1817 + ogg_page og[5]; 1.1818 + 1.1819 + ogg_stream_reset(&os_en); 1.1820 + 1.1821 + for(i=0;pl[i]!=-1;i++){ 1.1822 + ogg_packet op; 1.1823 + int len=pl[i]; 1.1824 + 1.1825 + op.packet=data+inptr; 1.1826 + op.bytes=len; 1.1827 + op.e_o_s=(pl[i+1]<0?1:0); 1.1828 + op.granulepos=(i+1)*1000; 1.1829 + 1.1830 + for(j=0;j<len;j++)data[inptr++]=i+j; 1.1831 + ogg_stream_packetin(&os_en,&op); 1.1832 + } 1.1833 + 1.1834 + _ogg_free(data); 1.1835 + 1.1836 + /* retrieve finished pages */ 1.1837 + for(i=0;i<5;i++){ 1.1838 + if(ogg_stream_pageout(&os_en,&og[i])==0){ 1.1839 + fprintf(stderr,"Too few pages output building sync tests!\n"); 1.1840 + exit(1); 1.1841 + } 1.1842 + copy_page(&og[i]); 1.1843 + } 1.1844 + 1.1845 + /* Test lost pages on pagein/packetout: no rollback */ 1.1846 + { 1.1847 + ogg_page temp; 1.1848 + ogg_packet test; 1.1849 + 1.1850 + fprintf(stderr,"Testing loss of pages... "); 1.1851 + 1.1852 + ogg_sync_reset(&oy); 1.1853 + ogg_stream_reset(&os_de); 1.1854 + for(i=0;i<5;i++){ 1.1855 + memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, 1.1856 + og[i].header_len); 1.1857 + ogg_sync_wrote(&oy,og[i].header_len); 1.1858 + memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); 1.1859 + ogg_sync_wrote(&oy,og[i].body_len); 1.1860 + } 1.1861 + 1.1862 + ogg_sync_pageout(&oy,&temp); 1.1863 + ogg_stream_pagein(&os_de,&temp); 1.1864 + ogg_sync_pageout(&oy,&temp); 1.1865 + ogg_stream_pagein(&os_de,&temp); 1.1866 + ogg_sync_pageout(&oy,&temp); 1.1867 + /* skip */ 1.1868 + ogg_sync_pageout(&oy,&temp); 1.1869 + ogg_stream_pagein(&os_de,&temp); 1.1870 + 1.1871 + /* do we get the expected results/packets? */ 1.1872 + 1.1873 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1874 + checkpacket(&test,0,0,0); 1.1875 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1876 + checkpacket(&test,1,1,-1); 1.1877 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1878 + checkpacket(&test,1,2,-1); 1.1879 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1880 + checkpacket(&test,98,3,-1); 1.1881 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1882 + checkpacket(&test,4079,4,5000); 1.1883 + if(ogg_stream_packetout(&os_de,&test)!=-1){ 1.1884 + fprintf(stderr,"Error: loss of page did not return error\n"); 1.1885 + exit(1); 1.1886 + } 1.1887 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1888 + checkpacket(&test,76,9,-1); 1.1889 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1890 + checkpacket(&test,34,10,-1); 1.1891 + fprintf(stderr,"ok.\n"); 1.1892 + } 1.1893 + 1.1894 + /* Test lost pages on pagein/packetout: rollback with continuation */ 1.1895 + { 1.1896 + ogg_page temp; 1.1897 + ogg_packet test; 1.1898 + 1.1899 + fprintf(stderr,"Testing loss of pages (rollback required)... "); 1.1900 + 1.1901 + ogg_sync_reset(&oy); 1.1902 + ogg_stream_reset(&os_de); 1.1903 + for(i=0;i<5;i++){ 1.1904 + memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, 1.1905 + og[i].header_len); 1.1906 + ogg_sync_wrote(&oy,og[i].header_len); 1.1907 + memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); 1.1908 + ogg_sync_wrote(&oy,og[i].body_len); 1.1909 + } 1.1910 + 1.1911 + ogg_sync_pageout(&oy,&temp); 1.1912 + ogg_stream_pagein(&os_de,&temp); 1.1913 + ogg_sync_pageout(&oy,&temp); 1.1914 + ogg_stream_pagein(&os_de,&temp); 1.1915 + ogg_sync_pageout(&oy,&temp); 1.1916 + ogg_stream_pagein(&os_de,&temp); 1.1917 + ogg_sync_pageout(&oy,&temp); 1.1918 + /* skip */ 1.1919 + ogg_sync_pageout(&oy,&temp); 1.1920 + ogg_stream_pagein(&os_de,&temp); 1.1921 + 1.1922 + /* do we get the expected results/packets? */ 1.1923 + 1.1924 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1925 + checkpacket(&test,0,0,0); 1.1926 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1927 + checkpacket(&test,1,1,-1); 1.1928 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1929 + checkpacket(&test,1,2,-1); 1.1930 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1931 + checkpacket(&test,98,3,-1); 1.1932 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1933 + checkpacket(&test,4079,4,5000); 1.1934 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1935 + checkpacket(&test,1,5,-1); 1.1936 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1937 + checkpacket(&test,1,6,-1); 1.1938 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1939 + checkpacket(&test,2954,7,-1); 1.1940 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1941 + checkpacket(&test,2057,8,9000); 1.1942 + if(ogg_stream_packetout(&os_de,&test)!=-1){ 1.1943 + fprintf(stderr,"Error: loss of page did not return error\n"); 1.1944 + exit(1); 1.1945 + } 1.1946 + if(ogg_stream_packetout(&os_de,&test)!=1)error(); 1.1947 + checkpacket(&test,300,17,18000); 1.1948 + fprintf(stderr,"ok.\n"); 1.1949 + } 1.1950 + 1.1951 + /* the rest only test sync */ 1.1952 + { 1.1953 + ogg_page og_de; 1.1954 + /* Test fractional page inputs: incomplete capture */ 1.1955 + fprintf(stderr,"Testing sync on partial inputs... "); 1.1956 + ogg_sync_reset(&oy); 1.1957 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1.1958 + 3); 1.1959 + ogg_sync_wrote(&oy,3); 1.1960 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.1961 + 1.1962 + /* Test fractional page inputs: incomplete fixed header */ 1.1963 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, 1.1964 + 20); 1.1965 + ogg_sync_wrote(&oy,20); 1.1966 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.1967 + 1.1968 + /* Test fractional page inputs: incomplete header */ 1.1969 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, 1.1970 + 5); 1.1971 + ogg_sync_wrote(&oy,5); 1.1972 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.1973 + 1.1974 + /* Test fractional page inputs: incomplete body */ 1.1975 + 1.1976 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, 1.1977 + og[1].header_len-28); 1.1978 + ogg_sync_wrote(&oy,og[1].header_len-28); 1.1979 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.1980 + 1.1981 + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); 1.1982 + ogg_sync_wrote(&oy,1000); 1.1983 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.1984 + 1.1985 + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, 1.1986 + og[1].body_len-1000); 1.1987 + ogg_sync_wrote(&oy,og[1].body_len-1000); 1.1988 + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1.1989 + 1.1990 + fprintf(stderr,"ok.\n"); 1.1991 + } 1.1992 + 1.1993 + /* Test fractional page inputs: page + incomplete capture */ 1.1994 + { 1.1995 + ogg_page og_de; 1.1996 + fprintf(stderr,"Testing sync on 1+partial inputs... "); 1.1997 + ogg_sync_reset(&oy); 1.1998 + 1.1999 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1.2000 + og[1].header_len); 1.2001 + ogg_sync_wrote(&oy,og[1].header_len); 1.2002 + 1.2003 + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1.2004 + og[1].body_len); 1.2005 + ogg_sync_wrote(&oy,og[1].body_len); 1.2006 + 1.2007 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1.2008 + 20); 1.2009 + ogg_sync_wrote(&oy,20); 1.2010 + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1.2011 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.2012 + 1.2013 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, 1.2014 + og[1].header_len-20); 1.2015 + ogg_sync_wrote(&oy,og[1].header_len-20); 1.2016 + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1.2017 + og[1].body_len); 1.2018 + ogg_sync_wrote(&oy,og[1].body_len); 1.2019 + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1.2020 + 1.2021 + fprintf(stderr,"ok.\n"); 1.2022 + } 1.2023 + 1.2024 + /* Test recapture: garbage + page */ 1.2025 + { 1.2026 + ogg_page og_de; 1.2027 + fprintf(stderr,"Testing search for capture... "); 1.2028 + ogg_sync_reset(&oy); 1.2029 + 1.2030 + /* 'garbage' */ 1.2031 + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1.2032 + og[1].body_len); 1.2033 + ogg_sync_wrote(&oy,og[1].body_len); 1.2034 + 1.2035 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1.2036 + og[1].header_len); 1.2037 + ogg_sync_wrote(&oy,og[1].header_len); 1.2038 + 1.2039 + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1.2040 + og[1].body_len); 1.2041 + ogg_sync_wrote(&oy,og[1].body_len); 1.2042 + 1.2043 + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 1.2044 + 20); 1.2045 + ogg_sync_wrote(&oy,20); 1.2046 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.2047 + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1.2048 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.2049 + 1.2050 + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, 1.2051 + og[2].header_len-20); 1.2052 + ogg_sync_wrote(&oy,og[2].header_len-20); 1.2053 + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, 1.2054 + og[2].body_len); 1.2055 + ogg_sync_wrote(&oy,og[2].body_len); 1.2056 + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1.2057 + 1.2058 + fprintf(stderr,"ok.\n"); 1.2059 + } 1.2060 + 1.2061 + /* Test recapture: page + garbage + page */ 1.2062 + { 1.2063 + ogg_page og_de; 1.2064 + fprintf(stderr,"Testing recapture... "); 1.2065 + ogg_sync_reset(&oy); 1.2066 + 1.2067 + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 1.2068 + og[1].header_len); 1.2069 + ogg_sync_wrote(&oy,og[1].header_len); 1.2070 + 1.2071 + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, 1.2072 + og[1].body_len); 1.2073 + ogg_sync_wrote(&oy,og[1].body_len); 1.2074 + 1.2075 + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 1.2076 + og[2].header_len); 1.2077 + ogg_sync_wrote(&oy,og[2].header_len); 1.2078 + 1.2079 + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 1.2080 + og[2].header_len); 1.2081 + ogg_sync_wrote(&oy,og[2].header_len); 1.2082 + 1.2083 + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1.2084 + 1.2085 + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, 1.2086 + og[2].body_len-5); 1.2087 + ogg_sync_wrote(&oy,og[2].body_len-5); 1.2088 + 1.2089 + memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, 1.2090 + og[3].header_len); 1.2091 + ogg_sync_wrote(&oy,og[3].header_len); 1.2092 + 1.2093 + memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, 1.2094 + og[3].body_len); 1.2095 + ogg_sync_wrote(&oy,og[3].body_len); 1.2096 + 1.2097 + if(ogg_sync_pageout(&oy,&og_de)>0)error(); 1.2098 + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); 1.2099 + 1.2100 + fprintf(stderr,"ok.\n"); 1.2101 + } 1.2102 + 1.2103 + /* Free page data that was previously copied */ 1.2104 + { 1.2105 + for(i=0;i<5;i++){ 1.2106 + free_page(&og[i]); 1.2107 + } 1.2108 + } 1.2109 + } 1.2110 + 1.2111 + return(0); 1.2112 +} 1.2113 + 1.2114 +#endif