framing.c 64.5 KB
Newer Older
Jack Moffitt's avatar
Jack Moffitt committed
1 2
/********************************************************************
 *                                                                  *
Monty's avatar
Monty committed
3
 * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE.              *
Monty's avatar
 
Monty committed
4 5 6
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
Jack Moffitt's avatar
Jack Moffitt committed
7
 *                                                                  *
8
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2018             *
Monty's avatar
 
Monty committed
9
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
10
 *                                                                  *
Jack Moffitt's avatar
Jack Moffitt committed
11 12
 ********************************************************************

13
 function: code raw packets into framed OggSquish stream and
Jack Moffitt's avatar
Jack Moffitt committed
14 15 16 17 18 19 20 21
           decode Ogg streams back into raw packets

 note: The CRC code is directly derived from public domain code by
 Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
 for details.

 ********************************************************************/

22 23 24 25
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Jack Moffitt's avatar
Jack Moffitt committed
26
#include <stdlib.h>
27
#include <limits.h>
Jack Moffitt's avatar
Jack Moffitt committed
28 29 30 31 32
#include <string.h>
#include <ogg/ogg.h>

/* A complete description of Ogg framing exists in docs/framing.html */

erikd's avatar
erikd committed
33
int ogg_page_version(const ogg_page *og){
Jack Moffitt's avatar
Jack Moffitt committed
34 35 36
  return((int)(og->header[4]));
}

erikd's avatar
erikd committed
37
int ogg_page_continued(const ogg_page *og){
Jack Moffitt's avatar
Jack Moffitt committed
38 39 40
  return((int)(og->header[5]&0x01));
}

erikd's avatar
erikd committed
41
int ogg_page_bos(const ogg_page *og){
Jack Moffitt's avatar
Jack Moffitt committed
42 43 44
  return((int)(og->header[5]&0x02));
}

erikd's avatar
erikd committed
45
int ogg_page_eos(const ogg_page *og){
Jack Moffitt's avatar
Jack Moffitt committed
46 47 48
  return((int)(og->header[5]&0x04));
}

erikd's avatar
erikd committed
49
ogg_int64_t ogg_page_granulepos(const ogg_page *og){
Jack Moffitt's avatar
Jack Moffitt committed
50 51 52 53 54 55 56 57 58 59 60 61
  unsigned char *page=og->header;
  ogg_int64_t granulepos=page[13]&(0xff);
  granulepos= (granulepos<<8)|(page[12]&0xff);
  granulepos= (granulepos<<8)|(page[11]&0xff);
  granulepos= (granulepos<<8)|(page[10]&0xff);
  granulepos= (granulepos<<8)|(page[9]&0xff);
  granulepos= (granulepos<<8)|(page[8]&0xff);
  granulepos= (granulepos<<8)|(page[7]&0xff);
  granulepos= (granulepos<<8)|(page[6]&0xff);
  return(granulepos);
}

erikd's avatar
erikd committed
62
int ogg_page_serialno(const ogg_page *og){
Jack Moffitt's avatar
Jack Moffitt committed
63
  return(og->header[14] |
Monty's avatar
Monty committed
64 65 66
         (og->header[15]<<8) |
         (og->header[16]<<16) |
         (og->header[17]<<24));
Jack Moffitt's avatar
Jack Moffitt committed
67
}
Ralph Giles's avatar
Ralph Giles committed
68

erikd's avatar
erikd committed
69
long ogg_page_pageno(const ogg_page *og){
Jack Moffitt's avatar
Jack Moffitt committed
70
  return(og->header[18] |
Monty's avatar
Monty committed
71 72 73
         (og->header[19]<<8) |
         (og->header[20]<<16) |
         (og->header[21]<<24));
Jack Moffitt's avatar
Jack Moffitt committed
74 75
}

Monty's avatar
 
Monty committed
76 77 78 79 80 81 82


/* returns the number of packets that are completed on this page (if
   the leading packet is begun on a previous page, but ends on this
   page, it's counted */

/* NOTE:
Ralph Giles's avatar
Ralph Giles committed
83 84 85 86 87 88 89 90 91 92
   If a page consists of a packet begun on a previous page, and a new
   packet begun (but not completed) on this page, the return will be:
     ogg_page_packets(page)   ==1,
     ogg_page_continued(page) !=0

   If a page happens to be a single packet that was begun on a
   previous page, and spans to the next page (in the case of a three or
   more page packet), the return will be:
     ogg_page_packets(page)   ==0,
     ogg_page_continued(page) !=0
Monty's avatar
 
Monty committed
93 94
*/

erikd's avatar
erikd committed
95
int ogg_page_packets(const ogg_page *og){
Monty's avatar
 
Monty committed
96 97
  int i,n=og->header[26],count=0;
  for(i=0;i<n;i++)
Monty's avatar
 
Monty committed
98
    if(og->header[27+i]<255)count++;
Monty's avatar
 
Monty committed
99 100 101 102
  return(count);
}


Monty's avatar
 
Monty committed
103 104
#if 0
/* helper to initialize lookup for direct-table CRC (illustrative; we
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
   use the static init in crctable.h) */

static void _ogg_crc_init(){
  int i, j;
  ogg_uint32_t polynomial, crc;
  polynomial = 0x04c11db7; /* The same as the ethernet generator
                              polynomial, although we use an
                              unreflected alg and an init/final
                              of 0, not 0xffffffff */
  for (i = 0; i <= 0xFF; i++){
    crc = i << 24;

    for (j = 0; j < 8; j++)
      crc = (crc << 1) ^ (crc & (1 << 31) ? polynomial : 0);

    crc_lookup[0][i] = crc;
  }

  for (i = 0; i <= 0xFF; i++)
    for (j = 1; j < 8; j++)
      crc_lookup[j][i] = crc_lookup[0][(crc_lookup[j - 1][i] >> 24) & 0xFF] ^ (crc_lookup[j - 1][i] << 8);
Jack Moffitt's avatar
Jack Moffitt committed
126
}
Monty's avatar
 
Monty committed
127 128
#endif

129
#include "crctable.h"
Jack Moffitt's avatar
Jack Moffitt committed
130 131 132 133 134

/* init the encode/decode logical stream state */

int ogg_stream_init(ogg_stream_state *os,int serialno){
  if(os){
Segher Boessenkool's avatar
Segher Boessenkool committed
135
    memset(os,0,sizeof(*os));
Jack Moffitt's avatar
Jack Moffitt committed
136 137
    os->body_storage=16*1024;
    os->lacing_storage=1024;
138 139

    os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
Segher Boessenkool's avatar
Segher Boessenkool committed
140 141
    os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
    os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
Jack Moffitt's avatar
Jack Moffitt committed
142

143 144 145 146 147
    if(!os->body_data || !os->lacing_vals || !os->granule_vals){
      ogg_stream_clear(os);
      return -1;
    }

Jack Moffitt's avatar
Jack Moffitt committed
148 149 150 151 152
    os->serialno=serialno;

    return(0);
  }
  return(-1);
Ralph Giles's avatar
Ralph Giles committed
153
}
Jack Moffitt's avatar
Jack Moffitt committed
154

155 156 157 158 159 160
/* async/delayed error detection for the ogg_stream_state */
int ogg_stream_check(ogg_stream_state *os){
  if(!os || !os->body_data) return -1;
  return 0;
}

Jack Moffitt's avatar
Jack Moffitt committed
161 162 163
/* _clear does not free os, only the non-flat storage within */
int ogg_stream_clear(ogg_stream_state *os){
  if(os){
Monty's avatar
 
Monty committed
164 165 166
    if(os->body_data)_ogg_free(os->body_data);
    if(os->lacing_vals)_ogg_free(os->lacing_vals);
    if(os->granule_vals)_ogg_free(os->granule_vals);
Jack Moffitt's avatar
Jack Moffitt committed
167

Ralph Giles's avatar
Ralph Giles committed
168
    memset(os,0,sizeof(*os));
Jack Moffitt's avatar
Jack Moffitt committed
169 170
  }
  return(0);
Ralph Giles's avatar
Ralph Giles committed
171
}
Jack Moffitt's avatar
Jack Moffitt committed
172 173 174 175

int ogg_stream_destroy(ogg_stream_state *os){
  if(os){
    ogg_stream_clear(os);
Monty's avatar
 
Monty committed
176
    _ogg_free(os);
Jack Moffitt's avatar
Jack Moffitt committed
177 178
  }
  return(0);
Ralph Giles's avatar
Ralph Giles committed
179
}
Jack Moffitt's avatar
Jack Moffitt committed
180 181 182 183

/* Helpers for ogg_stream_encode; this keeps the structure and
   what's happening fairly clear */

184 185 186
static int _os_body_expand(ogg_stream_state *os,long needed){
  if(os->body_storage-needed<=os->body_fill){
    long body_storage;
187
    void *ret;
188 189 190 191 192 193 194
    if(os->body_storage>LONG_MAX-needed){
      ogg_stream_clear(os);
      return -1;
    }
    body_storage=os->body_storage+needed;
    if(body_storage<LONG_MAX-1024)body_storage+=1024;
    ret=_ogg_realloc(os->body_data,body_storage*sizeof(*os->body_data));
195 196 197 198
    if(!ret){
      ogg_stream_clear(os);
      return -1;
    }
199
    os->body_storage=body_storage;
200
    os->body_data=ret;
Jack Moffitt's avatar
Jack Moffitt committed
201
  }
202
  return 0;
Jack Moffitt's avatar
Jack Moffitt committed
203 204
}

205 206 207
static int _os_lacing_expand(ogg_stream_state *os,long needed){
  if(os->lacing_storage-needed<=os->lacing_fill){
    long lacing_storage;
208
    void *ret;
209 210 211 212 213 214 215
    if(os->lacing_storage>LONG_MAX-needed){
      ogg_stream_clear(os);
      return -1;
    }
    lacing_storage=os->lacing_storage+needed;
    if(lacing_storage<LONG_MAX-32)lacing_storage+=32;
    ret=_ogg_realloc(os->lacing_vals,lacing_storage*sizeof(*os->lacing_vals));
216 217 218 219
    if(!ret){
      ogg_stream_clear(os);
      return -1;
    }
220
    os->lacing_vals=ret;
221
    ret=_ogg_realloc(os->granule_vals,lacing_storage*
Monty's avatar
Monty committed
222
                     sizeof(*os->granule_vals));
223 224 225 226
    if(!ret){
      ogg_stream_clear(os);
      return -1;
    }
227
    os->granule_vals=ret;
228
    os->lacing_storage=lacing_storage;
Jack Moffitt's avatar
Jack Moffitt committed
229
  }
230
  return 0;
Jack Moffitt's avatar
Jack Moffitt committed
231 232 233 234
}

/* checksum the page */
/* Direct table CRC; note that this will be faster in the future if we
235
   perform the checksum simultaneously with other copies */
Jack Moffitt's avatar
Jack Moffitt committed
236

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsigned char *buffer, int size){
  while (size>=8){
    crc^=buffer[0]<<24|buffer[1]<<16|buffer[2]<<8|buffer[3];

    crc=crc_lookup[7][ crc>>24      ]^crc_lookup[6][(crc>>16)&0xFF]^
        crc_lookup[5][(crc>> 8)&0xFF]^crc_lookup[4][ crc     &0xFF]^
        crc_lookup[3][buffer[4]     ]^crc_lookup[2][buffer[5]     ]^
        crc_lookup[1][buffer[6]     ]^crc_lookup[0][buffer[7]     ];

    buffer+=8;
    size-=8;
  }

  while (size--)
    crc=(crc<<8)^crc_lookup[0][((crc >> 24)&0xff)^*buffer++];
  return crc;
}

Monty's avatar
 
Monty committed
255 256 257
void ogg_page_checksum_set(ogg_page *og){
  if(og){
    ogg_uint32_t crc_reg=0;
Jack Moffitt's avatar
Jack Moffitt committed
258

Monty's avatar
 
Monty committed
259 260 261 262 263
    /* safety; needed for API behavior, but not framing code */
    og->header[22]=0;
    og->header[23]=0;
    og->header[24]=0;
    og->header[25]=0;
Ralph Giles's avatar
Ralph Giles committed
264

265 266
    crc_reg=_os_update_crc(crc_reg,og->header,og->header_len);
    crc_reg=_os_update_crc(crc_reg,og->body,og->body_len);
Ralph Giles's avatar
Ralph Giles committed
267

Ralph Giles's avatar
Ralph Giles committed
268 269 270 271
    og->header[22]=(unsigned char)(crc_reg&0xff);
    og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
    og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
    og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
Monty's avatar
 
Monty committed
272
  }
Jack Moffitt's avatar
Jack Moffitt committed
273 274 275
}

/* submit data to the internal buffer of the framing engine */
276 277 278
int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
                       long e_o_s, ogg_int64_t granulepos){

279 280
  long bytes = 0, lacing_vals;
  int i;
281 282 283

  if(ogg_stream_check(os)) return -1;
  if(!iov) return 0;
Ralph Giles's avatar
Ralph Giles committed
284

285 286 287 288 289
  for (i = 0; i < count; ++i){
    if(iov[i].iov_len>LONG_MAX) return -1;
    if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1;
    bytes += (long)iov[i].iov_len;
  }
290
  lacing_vals=bytes/255+1;
Jack Moffitt's avatar
Jack Moffitt committed
291 292 293 294 295

  if(os->body_returned){
    /* advance packet data according to the body_returned pointer. We
       had to keep it around to return a pointer into the buffer last
       call */
Ralph Giles's avatar
Ralph Giles committed
296

Jack Moffitt's avatar
Jack Moffitt committed
297 298 299
    os->body_fill-=os->body_returned;
    if(os->body_fill)
      memmove(os->body_data,os->body_data+os->body_returned,
Monty's avatar
Monty committed
300
              os->body_fill);
Jack Moffitt's avatar
Jack Moffitt committed
301 302
    os->body_returned=0;
  }
Ralph Giles's avatar
Ralph Giles committed
303

Jack Moffitt's avatar
Jack Moffitt committed
304
  /* make sure we have the buffer storage */
305 306
  if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
    return -1;
Jack Moffitt's avatar
Jack Moffitt committed
307 308 309 310 311 312

  /* Copy in the submitted packet.  Yes, the copy is a waste; this is
     the liability of overly clean abstraction for the time being.  It
     will actually be fairly easy to eliminate the extra copy in the
     future */

313 314 315 316
  for (i = 0; i < count; ++i) {
    memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
    os->body_fill += (int)iov[i].iov_len;
  }
Jack Moffitt's avatar
Jack Moffitt committed
317 318 319 320 321 322

  /* Store lacing vals for this packet */
  for(i=0;i<lacing_vals-1;i++){
    os->lacing_vals[os->lacing_fill+i]=255;
    os->granule_vals[os->lacing_fill+i]=os->granulepos;
  }
323 324
  os->lacing_vals[os->lacing_fill+i]=bytes%255;
  os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
Jack Moffitt's avatar
Jack Moffitt committed
325 326 327 328 329 330 331 332 333

  /* flag the first segment as the beginning of the packet */
  os->lacing_vals[os->lacing_fill]|= 0x100;

  os->lacing_fill+=lacing_vals;

  /* for the sake of completeness */
  os->packetno++;

334
  if(e_o_s)os->e_o_s=1;
Jack Moffitt's avatar
Jack Moffitt committed
335 336 337 338

  return(0);
}

339 340 341 342 343 344 345
int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
  ogg_iovec_t iov;
  iov.iov_base = op->packet;
  iov.iov_len = op->bytes;
  return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
}

Monty's avatar
Monty committed
346 347 348
/* Conditionally flush a page; force==0 will only flush nominal-size
   pages, force==1 forces us to flush a page regardless of page size
   so long as there's any data available at all. */
349
static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
Jack Moffitt's avatar
Jack Moffitt committed
350 351 352 353 354
  int i;
  int vals=0;
  int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
  int bytes=0;
  long acc=0;
355
  ogg_int64_t granule_pos=-1;
Jack Moffitt's avatar
Jack Moffitt committed
356

Monty's avatar
Monty committed
357 358 359
  if(ogg_stream_check(os)) return(0);
  if(maxvals==0) return(0);

Jack Moffitt's avatar
Jack Moffitt committed
360 361
  /* construct a page */
  /* decide how many segments to include */
Monty's avatar
Monty committed
362

Jack Moffitt's avatar
Jack Moffitt committed
363 364 365 366 367 368
  /* If this is the initial header case, the first page must only include
     the initial header packet */
  if(os->b_o_s==0){  /* 'initial header page' case */
    granule_pos=0;
    for(vals=0;vals<maxvals;vals++){
      if((os->lacing_vals[vals]&0x0ff)<255){
Monty's avatar
Monty committed
369 370
        vals++;
        break;
Jack Moffitt's avatar
Jack Moffitt committed
371 372 373
      }
    }
  }else{
Monty's avatar
Monty committed
374 375 376 377 378 379 380 381 382 383 384 385

    /* The extra packets_done, packet_just_done logic here attempts to do two things:
       1) Don't unneccessarily span pages.
       2) Unless necessary, don't flush pages if there are less than four packets on
          them; this expands page size to reduce unneccessary overhead if incoming packets
          are large.
       These are not necessary behaviors, just 'always better than naive flushing'
       without requiring an application to explicitly request a specific optimized
       behavior. We'll want an explicit behavior setup pathway eventually as well. */

    int packets_done=0;
    int packet_just_done=0;
Jack Moffitt's avatar
Jack Moffitt committed
386
    for(vals=0;vals<maxvals;vals++){
387
      if(acc>nfill && packet_just_done>=4){
Monty's avatar
Monty committed
388 389 390
        force=1;
        break;
      }
Jack Moffitt's avatar
Jack Moffitt committed
391
      acc+=os->lacing_vals[vals]&0x0ff;
Monty's avatar
Monty committed
392
      if((os->lacing_vals[vals]&0xff)<255){
393
        granule_pos=os->granule_vals[vals];
Monty's avatar
Monty committed
394 395 396
        packet_just_done=++packets_done;
      }else
        packet_just_done=0;
Jack Moffitt's avatar
Jack Moffitt committed
397
    }
Monty's avatar
Monty committed
398
    if(vals==255)force=1;
Jack Moffitt's avatar
Jack Moffitt committed
399
  }
Monty's avatar
Monty committed
400 401 402

  if(!force) return(0);

Jack Moffitt's avatar
Jack Moffitt committed
403 404
  /* construct the header in temp storage */
  memcpy(os->header,"OggS",4);
Monty's avatar
Monty committed
405

Jack Moffitt's avatar
Jack Moffitt committed
406 407
  /* stream structure version */
  os->header[4]=0x00;
Monty's avatar
Monty committed
408

Jack Moffitt's avatar
Jack Moffitt committed
409 410 411 412 413 414 415 416 417 418 419
  /* continued packet flag? */
  os->header[5]=0x00;
  if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
  /* first page flag? */
  if(os->b_o_s==0)os->header[5]|=0x02;
  /* last page flag? */
  if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
  os->b_o_s=1;

  /* 64 bits of PCM position */
  for(i=6;i<14;i++){
Ralph Giles's avatar
Ralph Giles committed
420
    os->header[i]=(unsigned char)(granule_pos&0xff);
Jack Moffitt's avatar
Jack Moffitt committed
421 422 423 424 425 426 427
    granule_pos>>=8;
  }

  /* 32 bits of stream serial number */
  {
    long serialno=os->serialno;
    for(i=14;i<18;i++){
Ralph Giles's avatar
Ralph Giles committed
428
      os->header[i]=(unsigned char)(serialno&0xff);
Jack Moffitt's avatar
Jack Moffitt committed
429 430 431 432 433 434 435
      serialno>>=8;
    }
  }

  /* 32 bits of page counter (we have both counter and page header
     because this val can roll over) */
  if(os->pageno==-1)os->pageno=0; /* because someone called
Monty's avatar
Monty committed
436 437 438 439
                                     stream_reset; this would be a
                                     strange thing to do in an
                                     encode stream, but it has
                                     plausible uses */
Jack Moffitt's avatar
Jack Moffitt committed
440 441 442
  {
    long pageno=os->pageno++;
    for(i=18;i<22;i++){
Ralph Giles's avatar
Ralph Giles committed
443
      os->header[i]=(unsigned char)(pageno&0xff);
Jack Moffitt's avatar
Jack Moffitt committed
444 445 446
      pageno>>=8;
    }
  }
Ralph Giles's avatar
Ralph Giles committed
447

Jack Moffitt's avatar
Jack Moffitt committed
448 449 450 451 452
  /* zero for computation; filled in later */
  os->header[22]=0;
  os->header[23]=0;
  os->header[24]=0;
  os->header[25]=0;
Ralph Giles's avatar
Ralph Giles committed
453

Jack Moffitt's avatar
Jack Moffitt committed
454
  /* segment table */
Ralph Giles's avatar
Ralph Giles committed
455
  os->header[26]=(unsigned char)(vals&0xff);
Jack Moffitt's avatar
Jack Moffitt committed
456
  for(i=0;i<vals;i++)
Ralph Giles's avatar
Ralph Giles committed
457
    bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
Ralph Giles's avatar
Ralph Giles committed
458

Jack Moffitt's avatar
Jack Moffitt committed
459 460 461 462 463
  /* set pointers in the ogg_page struct */
  og->header=os->header;
  og->header_len=os->header_fill=vals+27;
  og->body=os->body_data+os->body_returned;
  og->body_len=bytes;
Ralph Giles's avatar
Ralph Giles committed
464

Jack Moffitt's avatar
Jack Moffitt committed
465
  /* advance the lacing data and set the body_returned pointer */
Ralph Giles's avatar
Ralph Giles committed
466

Jack Moffitt's avatar
Jack Moffitt committed
467
  os->lacing_fill-=vals;
Segher Boessenkool's avatar
Segher Boessenkool committed
468 469
  memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
  memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
Jack Moffitt's avatar
Jack Moffitt committed
470
  os->body_returned+=bytes;
Ralph Giles's avatar
Ralph Giles committed
471

Jack Moffitt's avatar
Jack Moffitt committed
472
  /* calculate the checksum */
Ralph Giles's avatar
Ralph Giles committed
473

Monty's avatar
 
Monty committed
474
  ogg_page_checksum_set(og);
Jack Moffitt's avatar
Jack Moffitt committed
475 476 477 478 479

  /* done */
  return(1);
}

Monty's avatar
Monty committed
480 481 482 483 484 485 486 487 488 489 490 491
/* This will flush remaining packets into a page (returning nonzero),
   even if there is not enough data to trigger a flush normally
   (undersized page). If there are no packets or partial packets to
   flush, ogg_stream_flush returns 0.  Note that ogg_stream_flush will
   try to flush a normal sized page like ogg_stream_pageout; a call to
   ogg_stream_flush does not guarantee that all packets have flushed.
   Only a return value of 0 from ogg_stream_flush indicates all packet
   data is flushed into pages.

   since ogg_stream_flush will flush the last page in a stream even if
   it's undersized, you almost certainly want to use ogg_stream_pageout
   (and *not* ogg_stream_flush) unless you specifically need to flush
Ralph Giles's avatar
Ralph Giles committed
492
   a page regardless of size in the middle of a stream. */
Monty's avatar
Monty committed
493 494

int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
495
  return ogg_stream_flush_i(os,og,1,4096);
Monty's avatar
Monty committed
496
}
Jack Moffitt's avatar
Jack Moffitt committed
497

Ralph Giles's avatar
Ralph Giles committed
498 499 500
/* Like the above, but an argument is provided to adjust the nominal
   page size for applications which are smart enough to provide their
   own delay based flushing */
501 502 503 504 505

int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
  return ogg_stream_flush_i(os,og,1,nfill);
}

Jack Moffitt's avatar
Jack Moffitt committed
506 507 508 509 510
/* This constructs pages from buffered packet segments.  The pointers
returned are to static buffers; do not free. The returned buffers are
good only until the next call (using the same ogg_stream_state) */

int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
Monty's avatar
Monty committed
511
  int force=0;
512
  if(ogg_stream_check(os)) return 0;
Jack Moffitt's avatar
Jack Moffitt committed
513 514

  if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
Monty's avatar
Monty committed
515 516 517
     (os->lacing_fill&&!os->b_o_s))           /* 'initial header page' case */
    force=1;

518 519 520
  return(ogg_stream_flush_i(os,og,force,4096));
}

Ralph Giles's avatar
Ralph Giles committed
521
/* Like the above, but an argument is provided to adjust the nominal
522 523
page size for applications which are smart enough to provide their
own delay based flushing */
Ralph Giles's avatar
Ralph Giles committed
524

525 526 527 528 529 530 531 532 533
int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
  int force=0;
  if(ogg_stream_check(os)) return 0;

  if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
     (os->lacing_fill&&!os->b_o_s))           /* 'initial header page' case */
    force=1;

  return(ogg_stream_flush_i(os,og,force,nfill));
Jack Moffitt's avatar
Jack Moffitt committed
534 535
}

536
int ogg_stream_eos(ogg_stream_state *os){
537
  if(ogg_stream_check(os)) return 1;
Jack Moffitt's avatar
Jack Moffitt committed
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
  return os->e_o_s;
}

/* DECODING PRIMITIVES: packet streaming layer **********************/

/* This has two layers to place more of the multi-serialno and paging
   control in the application's hands.  First, we expose a data buffer
   using ogg_sync_buffer().  The app either copies into the
   buffer, or passes it directly to read(), etc.  We then call
   ogg_sync_wrote() to tell how many bytes we just added.

   Pages are returned (pointers into the buffer in ogg_sync_state)
   by ogg_sync_pageout().  The page is then submitted to
   ogg_stream_pagein() along with the appropriate
   ogg_stream_state* (ie, matching serialno).  We then get raw
   packets out calling ogg_stream_packetout() with a
Ralph Giles's avatar
Ralph Giles committed
554
   ogg_stream_state. */
Jack Moffitt's avatar
Jack Moffitt committed
555 556 557 558

/* initialize the struct to a known state */
int ogg_sync_init(ogg_sync_state *oy){
  if(oy){
559
    oy->storage = -1; /* used as a readiness flag */
Segher Boessenkool's avatar
Segher Boessenkool committed
560
    memset(oy,0,sizeof(*oy));
Jack Moffitt's avatar
Jack Moffitt committed
561 562 563 564 565 566 567
  }
  return(0);
}

/* clear non-flat storage within */
int ogg_sync_clear(ogg_sync_state *oy){
  if(oy){
Monty's avatar
 
Monty committed
568
    if(oy->data)_ogg_free(oy->data);
569
    memset(oy,0,sizeof(*oy));
Jack Moffitt's avatar
Jack Moffitt committed
570 571 572 573
  }
  return(0);
}

574 575 576
int ogg_sync_destroy(ogg_sync_state *oy){
  if(oy){
    ogg_sync_clear(oy);
Monty's avatar
 
Monty committed
577
    _ogg_free(oy);
578 579 580 581
  }
  return(0);
}

582 583 584 585 586
int ogg_sync_check(ogg_sync_state *oy){
  if(oy->storage<0) return -1;
  return 0;
}

Jack Moffitt's avatar
Jack Moffitt committed
587
char *ogg_sync_buffer(ogg_sync_state *oy, long size){
588
  if(ogg_sync_check(oy)) return NULL;
Jack Moffitt's avatar
Jack Moffitt committed
589 590 591 592 593

  /* first, clear out any space that has been previously returned */
  if(oy->returned){
    oy->fill-=oy->returned;
    if(oy->fill>0)
Segher Boessenkool's avatar
Segher Boessenkool committed
594
      memmove(oy->data,oy->data+oy->returned,oy->fill);
Jack Moffitt's avatar
Jack Moffitt committed
595 596 597 598 599 600
    oy->returned=0;
  }

  if(size>oy->storage-oy->fill){
    /* We need to extend the internal buffer */
    long newsize=size+oy->fill+4096; /* an extra page to be nice */
601
    void *ret;
Jack Moffitt's avatar
Jack Moffitt committed
602 603

    if(oy->data)
604
      ret=_ogg_realloc(oy->data,newsize);
Jack Moffitt's avatar
Jack Moffitt committed
605
    else
606
      ret=_ogg_malloc(newsize);
607 608 609 610
    if(!ret){
      ogg_sync_clear(oy);
      return NULL;
    }
611
    oy->data=ret;
Jack Moffitt's avatar
Jack Moffitt committed
612 613 614 615 616 617 618 619
    oy->storage=newsize;
  }

  /* expose a segment at least as large as requested at the fill mark */
  return((char *)oy->data+oy->fill);
}

int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
620 621
  if(ogg_sync_check(oy))return -1;
  if(oy->fill+bytes>oy->storage)return -1;
Jack Moffitt's avatar
Jack Moffitt committed
622 623 624 625 626 627 628 629 630 631 632
  oy->fill+=bytes;
  return(0);
}

/* sync the stream.  This is meant to be useful for finding page
   boundaries.

   return values for this:
  -n) skipped n bytes
   0) page not ready; more data (no bytes skipped)
   n) page synced at current location; page length n bytes
Ralph Giles's avatar
Ralph Giles committed
633

Jack Moffitt's avatar
Jack Moffitt committed
634 635 636 637 638 639
*/

long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
  unsigned char *page=oy->data+oy->returned;
  unsigned char *next;
  long bytes=oy->fill-oy->returned;
640 641

  if(ogg_sync_check(oy))return 0;
Ralph Giles's avatar
Ralph Giles committed
642

Jack Moffitt's avatar
Jack Moffitt committed
643 644 645
  if(oy->headerbytes==0){
    int headerbytes,i;
    if(bytes<27)return(0); /* not enough for a header */
Ralph Giles's avatar
Ralph Giles committed
646

Jack Moffitt's avatar
Jack Moffitt committed
647 648
    /* verify capture pattern */
    if(memcmp(page,"OggS",4))goto sync_fail;
Ralph Giles's avatar
Ralph Giles committed
649

Jack Moffitt's avatar
Jack Moffitt committed
650 651
    headerbytes=page[26]+27;
    if(bytes<headerbytes)return(0); /* not enough for header + seg table */
Ralph Giles's avatar
Ralph Giles committed
652

Jack Moffitt's avatar
Jack Moffitt committed
653
    /* count up body length in the segment table */
Ralph Giles's avatar
Ralph Giles committed
654

Jack Moffitt's avatar
Jack Moffitt committed
655 656 657 658
    for(i=0;i<page[26];i++)
      oy->bodybytes+=page[27+i];
    oy->headerbytes=headerbytes;
  }
Ralph Giles's avatar
Ralph Giles committed
659

Jack Moffitt's avatar
Jack Moffitt committed
660
  if(oy->bodybytes+oy->headerbytes>bytes)return(0);
Ralph Giles's avatar
Ralph Giles committed
661

Jack Moffitt's avatar
Jack Moffitt committed
662 663 664 665 666
  /* The whole test page is buffered.  Verify the checksum */
  {
    /* Grab the checksum bytes, set the header field to zero */
    char chksum[4];
    ogg_page log;
Ralph Giles's avatar
Ralph Giles committed
667

Jack Moffitt's avatar
Jack Moffitt committed
668 669
    memcpy(chksum,page+22,4);
    memset(page+22,0,4);
Ralph Giles's avatar
Ralph Giles committed
670

Jack Moffitt's avatar
Jack Moffitt committed
671 672 673 674 675
    /* set up a temp page struct and recompute the checksum */
    log.header=page;
    log.header_len=oy->headerbytes;
    log.body=page+oy->headerbytes;
    log.body_len=oy->bodybytes;
Monty's avatar
 
Monty committed
676
    ogg_page_checksum_set(&log);
Ralph Giles's avatar
Ralph Giles committed
677

Jack Moffitt's avatar
Jack Moffitt committed
678 679 680
    /* Compare */
    if(memcmp(chksum,page+22,4)){
      /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
Monty's avatar
Monty committed
681
         at all) */
Jack Moffitt's avatar
Jack Moffitt committed
682 683
      /* replace the computed checksum with the one actually read in */
      memcpy(page+22,chksum,4);
Ralph Giles's avatar
Ralph Giles committed
684

685
#ifndef DISABLE_CRC
Jack Moffitt's avatar
Jack Moffitt committed
686 687
      /* Bad checksum. Lose sync */
      goto sync_fail;
688
#endif
Jack Moffitt's avatar
Jack Moffitt committed
689 690
    }
  }
Ralph Giles's avatar
Ralph Giles committed
691

Jack Moffitt's avatar
Jack Moffitt committed
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
  /* yes, have a whole page all ready to go */
  {
    unsigned char *page=oy->data+oy->returned;
    long bytes;

    if(og){
      og->header=page;
      og->header_len=oy->headerbytes;
      og->body=page+oy->headerbytes;
      og->body_len=oy->bodybytes;
    }

    oy->unsynced=0;
    oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
    oy->headerbytes=0;
    oy->bodybytes=0;
    return(bytes);
  }
Ralph Giles's avatar
Ralph Giles committed
710

Jack Moffitt's avatar
Jack Moffitt committed
711
 sync_fail:
Ralph Giles's avatar
Ralph Giles committed
712

Jack Moffitt's avatar
Jack Moffitt committed
713 714
  oy->headerbytes=0;
  oy->bodybytes=0;
Ralph Giles's avatar
Ralph Giles committed
715

Jack Moffitt's avatar
Jack Moffitt committed
716 717 718 719 720
  /* search for possible capture */
  next=memchr(page+1,'O',bytes-1);
  if(!next)
    next=oy->data+oy->fill;

721 722
  oy->returned=(int)(next-oy->data);
  return((long)-(next-page));
Jack Moffitt's avatar
Jack Moffitt committed
723 724 725
}

/* sync the stream and get a page.  Keep trying until we find a page.
726
   Suppress 'sync errors' after reporting the first.
Jack Moffitt's avatar
Jack Moffitt committed
727 728 729 730 731 732 733 734 735 736 737

   return values:
   -1) recapture (hole in data)
    0) need more data
    1) page returned

   Returns pointers into buffered data; invalidated by next call to
   _stream, _clear, _init, or _buffer */

int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){

738 739
  if(ogg_sync_check(oy))return 0;

Jack Moffitt's avatar
Jack Moffitt committed
740 741 742 743
  /* all we need to do is verify a page at the head of the stream
     buffer.  If it doesn't verify, we look for the next potential
     frame */

Ralph Giles's avatar
Ralph Giles committed
744
  for(;;){
Jack Moffitt's avatar
Jack Moffitt committed
745 746 747 748 749 750 751 752 753
    long ret=ogg_sync_pageseek(oy,og);
    if(ret>0){
      /* have a page */
      return(1);
    }
    if(ret==0){
      /* need more data */
      return(0);
    }
Ralph Giles's avatar
Ralph Giles committed
754

Jack Moffitt's avatar
Jack Moffitt committed
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
    /* head did not start a synced page... skipped some bytes */
    if(!oy->unsynced){
      oy->unsynced=1;
      return(-1);
    }

    /* loop. keep looking */

  }
}

/* add the incoming page to the stream state; we decompose the page
   into packet segments here as well. */

int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
  unsigned char *header=og->header;
  unsigned char *body=og->body;
  long           bodysize=og->body_len;
  int            segptr=0;

  int version=ogg_page_version(og);
  int continued=ogg_page_continued(og);
  int bos=ogg_page_bos(og);
  int eos=ogg_page_eos(og);
779
  ogg_int64_t granulepos=ogg_page_granulepos(og);
Jack Moffitt's avatar
Jack Moffitt committed
780
  int serialno=ogg_page_serialno(og);
Monty's avatar
 
Monty committed
781
  long pageno=ogg_page_pageno(og);
Jack Moffitt's avatar
Jack Moffitt committed
782
  int segments=header[26];
Ralph Giles's avatar
Ralph Giles committed
783

784 785
  if(ogg_stream_check(os)) return -1;

Jack Moffitt's avatar
Jack Moffitt committed
786 787 788 789 790 791 792 793 794
  /* clean up 'returned data' */
  {
    long lr=os->lacing_returned;
    long br=os->body_returned;

    /* body data */
    if(br){
      os->body_fill-=br;
      if(os->body_fill)
Monty's avatar
Monty committed
795
        memmove(os->body_data,os->body_data+br,os->body_fill);
Jack Moffitt's avatar
Jack Moffitt committed
796 797 798 799 800 801
      os->body_returned=0;
    }

    if(lr){
      /* segment table */
      if(os->lacing_fill-lr){
Monty's avatar
Monty committed
802 803 804 805
        memmove(os->lacing_vals,os->lacing_vals+lr,
                (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
        memmove(os->granule_vals,os->granule_vals+lr,
                (os->lacing_fill-lr)*sizeof(*os->granule_vals));
Jack Moffitt's avatar
Jack Moffitt committed
806 807 808 809 810 811 812 813 814 815 816
      }
      os->lacing_fill-=lr;
      os->lacing_packet-=lr;
      os->lacing_returned=0;
    }
  }

  /* check the serial number */
  if(serialno!=os->serialno)return(-1);
  if(version>0)return(-1);

817
  if(_os_lacing_expand(os,segments+1)) return -1;
Jack Moffitt's avatar
Jack Moffitt committed
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832

  /* are we in sequence? */
  if(pageno!=os->pageno){
    int i;

    /* unroll previous partial packet (if any) */
    for(i=os->lacing_packet;i<os->lacing_fill;i++)
      os->body_fill-=os->lacing_vals[i]&0xff;
    os->lacing_fill=os->lacing_packet;

    /* make a note of dropped data in segment table */
    if(os->pageno!=-1){
      os->lacing_vals[os->lacing_fill++]=0x400;
      os->lacing_packet++;
    }
833
  }
Jack Moffitt's avatar
Jack Moffitt committed
834

835 836 837
  /* are we a 'continued packet' page?  If so, we may need to skip
     some segments */
  if(continued){
Ralph Giles's avatar
Ralph Giles committed
838
    if(os->lacing_fill<1 ||
839
       (os->lacing_vals[os->lacing_fill-1]&0xff)<255 ||
840
       os->lacing_vals[os->lacing_fill-1]==0x400){
Jack Moffitt's avatar
Jack Moffitt committed
841 842
      bos=0;
      for(;segptr<segments;segptr++){
Monty's avatar
Monty committed
843 844 845 846 847 848 849
        int val=header[27+segptr];
        body+=val;
        bodysize-=val;
        if(val<255){
          segptr++;
          break;
        }
Jack Moffitt's avatar
Jack Moffitt committed
850 851 852
      }
    }
  }
Ralph Giles's avatar
Ralph Giles committed
853

Jack Moffitt's avatar
Jack Moffitt committed
854
  if(bodysize){
855
    if(_os_body_expand(os,bodysize)) return -1;
Jack Moffitt's avatar
Jack Moffitt committed
856 857 858 859 860 861 862 863 864 865
    memcpy(os->body_data+os->body_fill,body,bodysize);
    os->body_fill+=bodysize;
  }

  {
    int saved=-1;
    while(segptr<segments){
      int val=header[27+segptr];
      os->lacing_vals[os->lacing_fill]=val;
      os->granule_vals[os->lacing_fill]=-1;
Ralph Giles's avatar
Ralph Giles committed
866

Jack Moffitt's avatar
Jack Moffitt committed
867
      if(bos){
Monty's avatar
Monty committed
868 869
        os->lacing_vals[os->lacing_fill]|=0x100;
        bos=0;
Jack Moffitt's avatar
Jack Moffitt committed
870
      }
Ralph Giles's avatar
Ralph Giles committed
871

Jack Moffitt's avatar
Jack Moffitt committed
872
      if(val<255)saved=os->lacing_fill;
Ralph Giles's avatar
Ralph Giles committed
873

Jack Moffitt's avatar
Jack Moffitt committed
874 875
      os->lacing_fill++;
      segptr++;
Ralph Giles's avatar
Ralph Giles committed
876

Jack Moffitt's avatar
Jack Moffitt committed
877 878
      if(val<255)os->lacing_packet=os->lacing_fill;
    }
Ralph Giles's avatar
Ralph Giles committed
879

Jack Moffitt's avatar
Jack Moffitt committed
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
    /* set the granulepos on the last granuleval of the last full packet */
    if(saved!=-1){
      os->granule_vals[saved]=granulepos;
    }

  }

  if(eos){
    os->e_o_s=1;
    if(os->lacing_fill>0)
      os->lacing_vals[os->lacing_fill-1]|=0x200;
  }

  os->pageno=pageno+1;

  return(0);
}

/* clear things to an initial state.  Good to call, eg, before seeking */
int ogg_sync_reset(ogg_sync_state *oy){
900 901
  if(ogg_sync_check(oy))return -1;

Jack Moffitt's avatar
Jack Moffitt committed
902 903 904 905 906 907 908 909 910
  oy->fill=0;
  oy->returned=0;
  oy->unsynced=0;
  oy->headerbytes=0;
  oy->bodybytes=0;
  return(0);
}

int ogg_stream_reset(ogg_stream_state *os){
911 912
  if(ogg_stream_check(os)) return -1;

Jack Moffitt's avatar
Jack Moffitt committed
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930
  os->body_fill=0;
  os->body_returned=0;

  os->lacing_fill=0;
  os->lacing_packet=0;
  os->lacing_returned=0;

  os->header_fill=0;

  os->e_o_s=0;
  os->b_o_s=0;
  os->pageno=-1;
  os->packetno=0;
  os->granulepos=0;

  return(0);
}

Monty's avatar
 
Monty committed
931
int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
932
  if(ogg_stream_check(os)) return -1;
Monty's avatar
 
Monty committed
933 934 935 936 937
  ogg_stream_reset(os);
  os->serialno=serialno;
  return(0);
}

Monty's avatar
 
Monty committed
938
static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
Jack Moffitt's avatar
Jack Moffitt committed
939 940 941 942 943 944 945 946 947 948 949 950

  /* The last part of decode. We have the stream broken into packet
     segments.  Now we need to group them into packets (or return the
     out of sync markers) */

  int ptr=os->lacing_returned;

  if(os->lacing_packet<=ptr)return(0);

  if(os->lacing_vals[ptr]&0x400){
    /* we need to tell the codec there's a gap; it might need to
       handle previous packet dependencies. */
Monty's avatar
 
Monty committed
951 952
    os->lacing_returned++;
    os->packetno++;
Jack Moffitt's avatar
Jack Moffitt committed
953 954 955
    return(-1);
  }

Monty's avatar
 
Monty committed
956 957 958 959
  if(!op && !adv)return(1); /* just using peek as an inexpensive way
                               to ask if there's a whole packet
                               waiting */

Jack Moffitt's avatar
Jack Moffitt committed
960 961 962
  /* Gather the whole packet. We'll have no holes or a partial packet */
  {
    int size=os->lacing_vals[ptr]&0xff;
963
    long bytes=size;
Monty's avatar
 
Monty committed
964 965
    int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
    int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
Jack Moffitt's avatar
Jack Moffitt committed
966 967 968 969

    while(size==255){
      int val=os->lacing_vals[++ptr];
      size=val&0xff;
Monty's avatar
 
Monty committed
970
      if(val&0x200)eos=0x200;
Jack Moffitt's avatar
Jack Moffitt committed
971 972 973
      bytes+=size;
    }

Monty's avatar
 
Monty committed
974 975 976 977 978 979 980 981
    if(op){
      op->e_o_s=eos;
      op->b_o_s=bos;
      op->packet=os->body_data+os->body_returned;
      op->packetno=os->packetno;
      op->granulepos=os->granule_vals[ptr];
      op->bytes=bytes;
    }
Jack Moffitt's avatar
Jack Moffitt committed
982

Monty's avatar
 
Monty committed
983 984 985 986 987
    if(adv){
      os->body_returned+=bytes;
      os->lacing_returned=ptr+1;
      os->packetno++;
    }
Jack Moffitt's avatar
Jack Moffitt committed
988 989 990 991
  }
  return(1);
}

Monty's avatar
 
Monty committed
992
int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
993
  if(ogg_stream_check(os)) return 0;
Monty's avatar
 
Monty committed
994 995 996 997
  return _packetout(os,op,1);
}

int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
998
  if(ogg_stream_check(os)) return 0;
Monty's avatar
 
Monty committed
999 1000 1001
  return _packetout(os,op,0);
}

Michael Smith's avatar
 
Michael Smith committed
1002
void ogg_packet_clear(ogg_packet *op) {
1003
  _ogg_free(op->packet);
Segher Boessenkool's avatar
Segher Boessenkool committed
1004
  memset(op, 0, sizeof(*op));
Michael Smith's avatar
 
Michael Smith committed
1005 1006
}

Jack Moffitt's avatar
Jack Moffitt committed
1007 1008 1009 1010 1011 1012
#ifdef _V_SELFTEST
#include <stdio.h>

ogg_stream_state os_en, os_de;
ogg_sync_state oy;

1013
void checkpacket(ogg_packet *op,long len, int no, long pos){
Jack Moffitt's avatar
Jack Moffitt committed
1014 1015 1016 1017 1018
  long j;
  static int sequence=0;
  static int lastno=0;

  if(op->bytes!=len){
1019
    fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
Jack Moffitt's avatar
Jack Moffitt committed
1020 1021
    exit(1);
  }
1022
  if(op->granulepos!=pos){
1023
    fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
Jack Moffitt's avatar
Jack Moffitt committed
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
    exit(1);
  }

  /* packet number just follows sequence/gap; adjust the input number
     for that */
  if(no==0){
    sequence=0;
  }else{
    sequence++;
    if(no>lastno+1)
      sequence++;
  }
  lastno=no;
  if(op->packetno!=sequence){
    fprintf(stderr,"incorrect packet sequence %ld != %d\n",
Monty's avatar
Monty committed
1039
            (long)(op->packetno),sequence);
Jack Moffitt's avatar
Jack Moffitt committed
1040 1041 1042 1043 1044 1045 1046
    exit(1);
  }

  /* Test data */
  for(j=0;j<op->bytes;j++)
    if(op->packet[j]!=((j+no)&0xff)){
      fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
Monty's avatar
Monty committed
1047
              j,op->packet[j],(j+no)&0xff);
Jack Moffitt's avatar
Jack Moffitt committed
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
      exit(1);
    }
}

void check_page(unsigned char *data,const int *header,ogg_page *og){
  long j;
  /* Test data */
  for(j=0;j<og->body_len;j++)
    if(og->body[j]!=data[j]){
      fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
Monty's avatar
Monty committed
1058
              j,data[j],og->body[j]);
Jack Moffitt's avatar
Jack Moffitt committed
1059 1060 1061 1062 1063 1064 1065 1066
      exit(1);
    }

  /* Test header */
  for(j=0;j<og->header_len;j++){
    if(og->header[j]!=header[j]){
      fprintf(stderr,"header content mismatch at pos %ld:\n",j);
      for(j=0;j<header[26]+27;j++)
Monty's avatar
Monty committed
1067
        fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
Jack Moffitt's avatar
Jack Moffitt committed
1068 1069 1070 1071 1072 1073
      fprintf(stderr,"\n");
      exit(1);
    }
  }
  if(og->header_len!=header[26]+27){
    fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
Monty's avatar
Monty committed
1074
            og->header_len,header[26]+27);
Jack Moffitt's avatar
Jack Moffitt committed
1075 1076 1077 1078 1079 1080 1081 1082
    exit(1);
  }
}

void print_header(ogg_page *og){
  int j;
  fprintf(stderr,"\nHEADER:\n");
  fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
Monty's avatar
Monty committed
1083 1084
          og->header[0],og->header[1],og->header[2],og->header[3],
          (int)og->header[4],(int)og->header[5]);
Jack Moffitt's avatar
Jack Moffitt committed
1085

Monty's avatar
 
Monty committed
1086
  fprintf(stderr,"  granulepos: %d  serialno: %d  pageno: %ld\n",
Monty's avatar
Monty committed
1087 1088 1089 1090 1091 1092
          (og->header[9]<<24)|(og->header[8]<<16)|
          (og->header[7]<<8)|og->header[6],
          (og->header[17]<<24)|(og->header[16]<<16)|
          (og->header[15]<<8)|og->header[14],
          ((long)(og->header[21])<<24)|(og->header[20]<<16)|
          (og->header[19]<<8)|og->header[18]);
Jack Moffitt's avatar
Jack Moffitt committed
1093 1094

  fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
Monty's avatar
Monty committed
1095 1096 1097
          (int)og->header[22],(int)og->header[23],
          (int)og->header[24],(int)og->header[25],<