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