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