Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/libogg-1.1.3/src/framing.c @ 52

Last change on this file since 52 was 15, checked in by landauf, 17 years ago

added libogg

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