• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
4  *                                                                  *
5  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
6  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
7  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
8  *                                                                  *
9  * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
10  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
11  *                                                                  *
12  ********************************************************************
13 
14  function: decode Ogg streams back into raw packets
15 
16  note: The CRC code is directly derived from public domain code by
17  Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
18  for details.
19 
20  ********************************************************************/
21 
22 #include <stdlib.h>
23 #include <string.h>
24 #include "ogg.h"
25 #include "misc.h"
26 
27 
28 /* A complete description of Ogg framing exists in docs/framing.html */
29 
30 /* basic, centralized Ogg memory management based on linked lists of
31    references to refcounted memory buffers.  References and buffers
32    are both recycled.  Buffers are passed around and consumed in
33    reference form. */
34 
ogg_buffer_create(void)35 static ogg_buffer_state *ogg_buffer_create(void){
36   ogg_buffer_state *bs=_ogg_calloc(1,sizeof(*bs));
37   return bs;
38 }
39 
40 /* destruction is 'lazy'; there may be memory references outstanding,
41    and yanking the buffer state out from underneath would be
42    antisocial.  Dealloc what is currently unused and have
43    _release_one watch for the stragglers to come in.  When they do,
44    finish destruction. */
45 
46 /* call the helper while holding lock */
_ogg_buffer_destroy(ogg_buffer_state * bs)47 static void _ogg_buffer_destroy(ogg_buffer_state *bs){
48   ogg_buffer *bt;
49   ogg_reference *rt;
50 
51   if(bs->shutdown){
52 
53     bt=bs->unused_buffers;
54     rt=bs->unused_references;
55 
56     while(bt){
57       ogg_buffer *b=bt;
58       bt=b->ptr.next;
59       if(b->data)_ogg_free(b->data);
60       _ogg_free(b);
61     }
62     bs->unused_buffers=0;
63     while(rt){
64       ogg_reference *r=rt;
65       rt=r->next;
66       _ogg_free(r);
67     }
68     bs->unused_references=0;
69 
70     if(!bs->outstanding)
71       _ogg_free(bs);
72 
73   }
74 }
75 
ogg_buffer_destroy(ogg_buffer_state * bs)76 static void ogg_buffer_destroy(ogg_buffer_state *bs){
77   bs->shutdown=1;
78   _ogg_buffer_destroy(bs);
79 }
80 
_fetch_buffer(ogg_buffer_state * bs,long bytes)81 static ogg_buffer *_fetch_buffer(ogg_buffer_state *bs,long bytes){
82   ogg_buffer    *ob;
83   bs->outstanding++;
84 
85   /* do we have an unused buffer sitting in the pool? */
86   if(bs->unused_buffers){
87     ob=bs->unused_buffers;
88     bs->unused_buffers=ob->ptr.next;
89 
90     /* if the unused buffer is too small, grow it */
91     if(ob->size<bytes){
92       ob->data=_ogg_realloc(ob->data,bytes);
93       ob->size=bytes;
94     }
95   }else{
96     /* allocate a new buffer */
97     ob=_ogg_malloc(sizeof(*ob));
98     ob->data=_ogg_malloc(bytes<16?16:bytes);
99     ob->size=bytes;
100   }
101 
102   ob->refcount=1;
103   ob->ptr.owner=bs;
104   return ob;
105 }
106 
_fetch_ref(ogg_buffer_state * bs)107 static ogg_reference *_fetch_ref(ogg_buffer_state *bs){
108   ogg_reference *or;
109   bs->outstanding++;
110 
111   /* do we have an unused reference sitting in the pool? */
112   if(bs->unused_references){
113     or=bs->unused_references;
114     bs->unused_references=or->next;
115   }else{
116     /* allocate a new reference */
117     or=_ogg_malloc(sizeof(*or));
118   }
119 
120   or->begin=0;
121   or->length=0;
122   or->next=0;
123   return or;
124 }
125 
126 /* fetch a reference pointing to a fresh, initially continguous buffer
127    of at least [bytes] length */
ogg_buffer_alloc(ogg_buffer_state * bs,long bytes)128 static ogg_reference *ogg_buffer_alloc(ogg_buffer_state *bs,long bytes){
129   ogg_buffer    *ob=_fetch_buffer(bs,bytes);
130   ogg_reference *or=_fetch_ref(bs);
131   or->buffer=ob;
132   return or;
133 }
134 
135 /* enlarge the data buffer in the current link */
ogg_buffer_realloc(ogg_reference * or,long bytes)136 static void ogg_buffer_realloc(ogg_reference *or,long bytes){
137   ogg_buffer    *ob=or->buffer;
138 
139   /* if the unused buffer is too small, grow it */
140   if(ob->size<bytes){
141     ob->data=_ogg_realloc(ob->data,bytes);
142     ob->size=bytes;
143   }
144 }
145 
_ogg_buffer_mark_one(ogg_reference * or)146 static void _ogg_buffer_mark_one(ogg_reference *or){
147   or->buffer->refcount++;
148 }
149 
150 /* increase the refcount of the buffers to which the reference points */
ogg_buffer_mark(ogg_reference * or)151 static void ogg_buffer_mark(ogg_reference *or){
152   while(or){
153     _ogg_buffer_mark_one(or);
154     or=or->next;
155   }
156 }
157 
158 /* duplicate a reference (pointing to the same actual buffer memory)
159    and increment buffer refcount.  If the desired segment is zero
160    length, a zero length ref is returned. */
ogg_buffer_sub(ogg_reference * or,long length)161 static ogg_reference *ogg_buffer_sub(ogg_reference *or,long length){
162   ogg_reference *ret=0,*head=0;
163 
164   /* duplicate the reference chain; increment refcounts */
165   while(or && length){
166     ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner);
167     if(head)
168       head->next=temp;
169     else
170       ret=temp;
171     head=temp;
172     head->buffer=or->buffer;
173     head->begin=or->begin;
174     head->length=length;
175     if(head->length>or->length)
176       head->length=or->length;
177 
178     length-=head->length;
179     or=or->next;
180   }
181 
182   ogg_buffer_mark(ret);
183   return ret;
184 }
185 
ogg_buffer_dup(ogg_reference * or)186 ogg_reference *ogg_buffer_dup(ogg_reference *or){
187   ogg_reference *ret=0,*head=0;
188   /* duplicate the reference chain; increment refcounts */
189   while(or){
190     ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner);
191     if(head)
192       head->next=temp;
193     else
194       ret=temp;
195     head=temp;
196     head->buffer=or->buffer;
197     head->begin=or->begin;
198     head->length=or->length;
199     or=or->next;
200   }
201 
202   ogg_buffer_mark(ret);
203   return ret;
204 }
205 
206 /* split a reference into two references; 'return' is a reference to
207    the buffer preceeding pos and 'head'/'tail' are the buffer past the
208    split.  If pos is at or past the end of the passed in segment,
209    'head/tail' are NULL */
ogg_buffer_split(ogg_reference ** tail,ogg_reference ** head,long pos)210 static ogg_reference *ogg_buffer_split(ogg_reference **tail,
211                                 ogg_reference **head,long pos){
212 
213   /* walk past any preceeding fragments to one of:
214      a) the exact boundary that seps two fragments
215      b) the fragment that needs split somewhere in the middle */
216   ogg_reference *ret=*tail;
217   ogg_reference *or=*tail;
218 
219   while(or && pos>or->length){
220     pos-=or->length;
221     or=or->next;
222   }
223 
224   if(!or || pos==0){
225 
226     return 0;
227 
228   }else{
229 
230     if(pos>=or->length){
231       /* exact split, or off the end? */
232       if(or->next){
233 
234         /* a split */
235         *tail=or->next;
236         or->next=0;
237 
238       }else{
239 
240         /* off or at the end */
241         *tail=*head=0;
242 
243       }
244     }else{
245 
246       /* split within a fragment */
247       long lengthA=pos;
248       long beginB=or->begin+pos;
249       long lengthB=or->length-pos;
250 
251       /* make a new reference to tail the second piece */
252       *tail=_fetch_ref(or->buffer->ptr.owner);
253 
254       (*tail)->buffer=or->buffer;
255       (*tail)->begin=beginB;
256       (*tail)->length=lengthB;
257       (*tail)->next=or->next;
258       _ogg_buffer_mark_one(*tail);
259       if(head && or==*head)*head=*tail;
260 
261       /* update the first piece */
262       or->next=0;
263       or->length=lengthA;
264 
265     }
266   }
267   return ret;
268 }
269 
ogg_buffer_release_one(ogg_reference * or)270 static void ogg_buffer_release_one(ogg_reference *or){
271   ogg_buffer *ob=or->buffer;
272   ogg_buffer_state *bs=ob->ptr.owner;
273 
274   ob->refcount--;
275   if(ob->refcount==0){
276     bs->outstanding--; /* for the returned buffer */
277     ob->ptr.next=bs->unused_buffers;
278     bs->unused_buffers=ob;
279   }
280 
281   bs->outstanding--; /* for the returned reference */
282   or->next=bs->unused_references;
283   bs->unused_references=or;
284 
285   _ogg_buffer_destroy(bs); /* lazy cleanup (if needed) */
286 
287 }
288 
289 /* release the references, decrease the refcounts of buffers to which
290    they point, release any buffers with a refcount that drops to zero */
ogg_buffer_release(ogg_reference * or)291 static void ogg_buffer_release(ogg_reference *or){
292   while(or){
293     ogg_reference *next=or->next;
294     ogg_buffer_release_one(or);
295     or=next;
296   }
297 }
298 
ogg_buffer_pretruncate(ogg_reference * or,long pos)299 static ogg_reference *ogg_buffer_pretruncate(ogg_reference *or,long pos){
300   /* release preceeding fragments we don't want */
301   while(or && pos>=or->length){
302     ogg_reference *next=or->next;
303     pos-=or->length;
304     ogg_buffer_release_one(or);
305     or=next;
306   }
307   if (or) {
308     or->begin+=pos;
309     or->length-=pos;
310   }
311   return or;
312 }
313 
ogg_buffer_walk(ogg_reference * or)314 static ogg_reference *ogg_buffer_walk(ogg_reference *or){
315   if(!or)return NULL;
316   while(or->next){
317     or=or->next;
318   }
319   return(or);
320 }
321 
322 /* *head is appended to the front end (head) of *tail; both continue to
323    be valid pointers, with *tail at the tail and *head at the head */
ogg_buffer_cat(ogg_reference * tail,ogg_reference * head)324 static ogg_reference *ogg_buffer_cat(ogg_reference *tail, ogg_reference *head){
325   if(!tail)return head;
326 
327   while(tail->next){
328     tail=tail->next;
329   }
330   tail->next=head;
331   return ogg_buffer_walk(head);
332 }
333 
_positionB(oggbyte_buffer * b,int pos)334 static void _positionB(oggbyte_buffer *b,int pos){
335   if(pos<b->pos){
336     /* start at beginning, scan forward */
337     b->ref=b->baseref;
338     b->pos=0;
339     b->end=b->pos+b->ref->length;
340     b->ptr=b->ref->buffer->data+b->ref->begin;
341   }
342 }
343 
_positionF(oggbyte_buffer * b,int pos)344 static void _positionF(oggbyte_buffer *b,int pos){
345   /* scan forward for position */
346   while(pos>=b->end){
347     /* just seek forward */
348     b->pos+=b->ref->length;
349     b->ref=b->ref->next;
350     b->end=b->ref->length+b->pos;
351     b->ptr=b->ref->buffer->data+b->ref->begin;
352   }
353 }
354 
oggbyte_init(oggbyte_buffer * b,ogg_reference * or)355 static int oggbyte_init(oggbyte_buffer *b,ogg_reference *or){
356   memset(b,0,sizeof(*b));
357   if(or){
358     b->ref=b->baseref=or;
359     b->pos=0;
360     b->end=b->ref->length;
361     b->ptr=b->ref->buffer->data+b->ref->begin;
362     return 0;
363   }else
364     return -1;
365 }
366 
oggbyte_set4(oggbyte_buffer * b,ogg_uint32_t val,int pos)367 static void oggbyte_set4(oggbyte_buffer *b,ogg_uint32_t val,int pos){
368   int i;
369   _positionB(b,pos);
370   for(i=0;i<4;i++){
371     _positionF(b,pos);
372     b->ptr[pos-b->pos]=val;
373     val>>=8;
374     ++pos;
375   }
376 }
377 
oggbyte_read1(oggbyte_buffer * b,int pos)378 static unsigned char oggbyte_read1(oggbyte_buffer *b,int pos){
379   _positionB(b,pos);
380   _positionF(b,pos);
381   return b->ptr[pos-b->pos];
382 }
383 
oggbyte_read4(oggbyte_buffer * b,int pos)384 static ogg_uint32_t oggbyte_read4(oggbyte_buffer *b,int pos){
385   ogg_uint32_t ret;
386   _positionB(b,pos);
387   _positionF(b,pos);
388   ret=b->ptr[pos-b->pos];
389   _positionF(b,++pos);
390   ret|=b->ptr[pos-b->pos]<<8;
391   _positionF(b,++pos);
392   ret|=b->ptr[pos-b->pos]<<16;
393   _positionF(b,++pos);
394   ret|=b->ptr[pos-b->pos]<<24;
395   return ret;
396 }
397 
oggbyte_read8(oggbyte_buffer * b,int pos)398 static ogg_int64_t oggbyte_read8(oggbyte_buffer *b,int pos){
399   ogg_int64_t ret;
400   unsigned char t[7];
401   int i;
402   _positionB(b,pos);
403   for(i=0;i<7;i++){
404     _positionF(b,pos);
405     t[i]=b->ptr[pos++ -b->pos];
406   }
407 
408   _positionF(b,pos);
409   ret=b->ptr[pos-b->pos];
410 
411   for(i=6;i>=0;--i)
412     ret= ret<<8 | t[i];
413 
414   return ret;
415 }
416 
417 /* Now we get to the actual framing code */
418 
ogg_page_version(ogg_page * og)419 int ogg_page_version(ogg_page *og){
420   oggbyte_buffer ob;
421   if(oggbyte_init(&ob,og->header))return -1;
422   return oggbyte_read1(&ob,4);
423 }
424 
ogg_page_continued(ogg_page * og)425 int ogg_page_continued(ogg_page *og){
426   oggbyte_buffer ob;
427   if(oggbyte_init(&ob,og->header))return -1;
428   return oggbyte_read1(&ob,5)&0x01;
429 }
430 
ogg_page_bos(ogg_page * og)431 int ogg_page_bos(ogg_page *og){
432   oggbyte_buffer ob;
433   if(oggbyte_init(&ob,og->header))return -1;
434   return oggbyte_read1(&ob,5)&0x02;
435 }
436 
ogg_page_eos(ogg_page * og)437 int ogg_page_eos(ogg_page *og){
438   oggbyte_buffer ob;
439   if(oggbyte_init(&ob,og->header))return -1;
440   return oggbyte_read1(&ob,5)&0x04;
441 }
442 
ogg_page_granulepos(ogg_page * og)443 ogg_int64_t ogg_page_granulepos(ogg_page *og){
444   oggbyte_buffer ob;
445   if(oggbyte_init(&ob,og->header))return -1;
446   return oggbyte_read8(&ob,6);
447 }
448 
ogg_page_serialno(ogg_page * og)449 ogg_uint32_t ogg_page_serialno(ogg_page *og){
450   oggbyte_buffer ob;
451   if(oggbyte_init(&ob,og->header)) return 0xffffffffUL;
452   return oggbyte_read4(&ob,14);
453 }
454 
ogg_page_pageno(ogg_page * og)455 ogg_uint32_t ogg_page_pageno(ogg_page *og){
456   oggbyte_buffer ob;
457   if(oggbyte_init(&ob,og->header))return 0xffffffffUL;
458   return oggbyte_read4(&ob,18);
459 }
460 
461 /* returns the number of packets that are completed on this page (if
462    the leading packet is begun on a previous page, but ends on this
463    page, it's counted */
464 
465 /* NOTE:
466 If a page consists of a packet begun on a previous page, and a new
467 packet begun (but not completed) on this page, the return will be:
468   ogg_page_packets(page)   ==1,
469   ogg_page_continued(page) !=0
470 
471 If a page happens to be a single packet that was begun on a
472 previous page, and spans to the next page (in the case of a three or
473 more page packet), the return will be:
474   ogg_page_packets(page)   ==0,
475   ogg_page_continued(page) !=0
476 */
477 
ogg_page_packets(ogg_page * og)478 int ogg_page_packets(ogg_page *og){
479   int i;
480   int n;
481   int count=0;
482   oggbyte_buffer ob;
483   oggbyte_init(&ob,og->header);
484 
485   n=oggbyte_read1(&ob,26);
486   for(i=0;i<n;i++)
487     if(oggbyte_read1(&ob,27+i)<255)count++;
488   return(count);
489 }
490 
491 /* Static CRC calculation table.  See older code in CVS for dead
492    run-time initialization code. */
493 
494 static ogg_uint32_t crc_lookup[256]={
495   0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
496   0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
497   0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
498   0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
499   0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
500   0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
501   0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
502   0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
503   0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
504   0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
505   0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
506   0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
507   0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
508   0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
509   0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
510   0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
511   0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
512   0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
513   0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
514   0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
515   0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
516   0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
517   0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
518   0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
519   0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
520   0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
521   0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
522   0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
523   0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
524   0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
525   0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
526   0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
527   0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
528   0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
529   0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
530   0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
531   0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
532   0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
533   0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
534   0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
535   0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
536   0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
537   0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
538   0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
539   0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
540   0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
541   0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
542   0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
543   0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
544   0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
545   0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
546   0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
547   0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
548   0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
549   0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
550   0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
551   0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
552   0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
553   0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
554   0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
555   0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
556   0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
557   0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
558   0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
559 
ogg_sync_create(void)560 ogg_sync_state *ogg_sync_create(void){
561   ogg_sync_state *oy=_ogg_calloc(1,sizeof(*oy));
562   memset(oy,0,sizeof(*oy));
563   oy->bufferpool=ogg_buffer_create();
564   return oy;
565 }
566 
ogg_sync_destroy(ogg_sync_state * oy)567 int ogg_sync_destroy(ogg_sync_state *oy){
568   if(oy){
569     ogg_sync_reset(oy);
570     ogg_buffer_destroy(oy->bufferpool);
571     memset(oy,0,sizeof(*oy));
572     _ogg_free(oy);
573   }
574   return OGG_SUCCESS;
575 }
576 
ogg_sync_bufferin(ogg_sync_state * oy,long bytes)577 unsigned char *ogg_sync_bufferin(ogg_sync_state *oy, long bytes){
578 
579   /* [allocate and] expose a buffer for data submission.
580 
581      If there is no head fragment
582        allocate one and expose it
583      else
584        if the current head fragment has sufficient unused space
585          expose it
586        else
587          if the current head fragment is unused
588            resize and expose it
589          else
590            allocate new fragment and expose it
591   */
592 
593   /* base case; fifo uninitialized */
594   if(!oy->fifo_head){
595     oy->fifo_head=oy->fifo_tail=ogg_buffer_alloc(oy->bufferpool,bytes);
596     return oy->fifo_head->buffer->data;
597   }
598 
599   /* space left in current fragment case */
600   if(oy->fifo_head->buffer->size-
601      oy->fifo_head->length-
602      oy->fifo_head->begin >= bytes)
603     return oy->fifo_head->buffer->data+
604       oy->fifo_head->length+oy->fifo_head->begin;
605 
606   /* current fragment is unused, but too small */
607   if(!oy->fifo_head->length){
608     ogg_buffer_realloc(oy->fifo_head,bytes);
609     return oy->fifo_head->buffer->data+oy->fifo_head->begin;
610   }
611 
612   /* current fragment used/full; get new fragment */
613   {
614     ogg_reference *new=ogg_buffer_alloc(oy->bufferpool,bytes);
615     oy->fifo_head->next=new;
616     oy->fifo_head=new;
617   }
618   return oy->fifo_head->buffer->data;
619 }
620 
ogg_sync_wrote(ogg_sync_state * oy,long bytes)621 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
622   if(!oy->fifo_head)return OGG_EINVAL;
623   if(oy->fifo_head->buffer->size-oy->fifo_head->length-oy->fifo_head->begin <
624      bytes)return OGG_EINVAL;
625   oy->fifo_head->length+=bytes;
626   oy->fifo_fill+=bytes;
627   return OGG_SUCCESS;
628 }
629 
_checksum(ogg_reference * or,int bytes)630 static ogg_uint32_t _checksum(ogg_reference *or, int bytes){
631   ogg_uint32_t crc_reg=0;
632   int j,post;
633 
634   while(or){
635     unsigned char *data=or->buffer->data+or->begin;
636     post=(bytes<or->length?bytes:or->length);
637     for(j=0;j<post;++j)
638       crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^data[j]];
639     bytes-=j;
640     or=or->next;
641   }
642 
643   return crc_reg;
644 }
645 
646 
647 /* sync the stream.  This is meant to be useful for finding page
648    boundaries.
649 
650    return values for this:
651   -n) skipped n bytes
652    0) page not ready; more data (no bytes skipped)
653    n) page synced at current location; page length n bytes
654 
655 */
656 
ogg_sync_pageseek(ogg_sync_state * oy,ogg_page * og)657 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
658   oggbyte_buffer page;
659   long           bytes,ret=0;
660 
661   ogg_page_release(og);
662 
663   bytes=oy->fifo_fill;
664   oggbyte_init(&page,oy->fifo_tail);
665 
666   if(oy->headerbytes==0){
667     if(bytes<27)goto sync_out; /* not enough for even a minimal header */
668 
669     /* verify capture pattern */
670     if(oggbyte_read1(&page,0)!=(int)'O' ||
671        oggbyte_read1(&page,1)!=(int)'g' ||
672        oggbyte_read1(&page,2)!=(int)'g' ||
673        oggbyte_read1(&page,3)!=(int)'S'    ) goto sync_fail;
674 
675     oy->headerbytes=oggbyte_read1(&page,26)+27;
676   }
677   if(bytes<oy->headerbytes)goto sync_out; /* not enough for header +
678                                              seg table */
679   if(oy->bodybytes==0){
680     int i;
681     /* count up body length in the segment table */
682     for(i=0;i<oy->headerbytes-27;i++)
683       oy->bodybytes+=oggbyte_read1(&page,27+i);
684   }
685 
686   if(oy->bodybytes+oy->headerbytes>bytes)goto sync_out;
687 
688   /* we have what appears to be a complete page; last test: verify
689      checksum */
690   {
691     ogg_uint32_t chksum=oggbyte_read4(&page,22);
692     oggbyte_set4(&page,0,22);
693 
694     /* Compare checksums; memory continues to be common access */
695     if(chksum!=_checksum(oy->fifo_tail,oy->bodybytes+oy->headerbytes)){
696 
697       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
698          at all). replace the computed checksum with the one actually
699          read in; remember all the memory is common access */
700 
701       oggbyte_set4(&page,chksum,22);
702       goto sync_fail;
703     }
704     oggbyte_set4(&page,chksum,22);
705   }
706 
707   /* We have a page.  Set up page return. */
708   if(og){
709     /* set up page output */
710     og->header=ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->headerbytes);
711     og->header_len=oy->headerbytes;
712     og->body=ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->bodybytes);
713     og->body_len=oy->bodybytes;
714   }else{
715     /* simply advance */
716     oy->fifo_tail=
717       ogg_buffer_pretruncate(oy->fifo_tail,oy->headerbytes+oy->bodybytes);
718     if(!oy->fifo_tail)oy->fifo_head=0;
719   }
720 
721   ret=oy->headerbytes+oy->bodybytes;
722   oy->unsynced=0;
723   oy->headerbytes=0;
724   oy->bodybytes=0;
725   oy->fifo_fill-=ret;
726 
727   return ret;
728 
729  sync_fail:
730 
731   oy->headerbytes=0;
732   oy->bodybytes=0;
733   oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,1);
734   ret--;
735 
736   /* search forward through fragments for possible capture */
737   while(oy->fifo_tail){
738     /* invariant: fifo_cursor points to a position in fifo_tail */
739     unsigned char *now=oy->fifo_tail->buffer->data+oy->fifo_tail->begin;
740     unsigned char *next=memchr(now, 'O', oy->fifo_tail->length);
741 
742     if(next){
743       /* possible capture in this segment */
744       long bytes=next-now;
745       oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,bytes);
746       ret-=bytes;
747       break;
748     }else{
749       /* no capture.  advance to next segment */
750       long bytes=oy->fifo_tail->length;
751       ret-=bytes;
752       oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,bytes);
753     }
754   }
755   if(!oy->fifo_tail)oy->fifo_head=0;
756   oy->fifo_fill+=ret;
757 
758  sync_out:
759   return ret;
760 }
761 
762 /* sync the stream and get a page.  Keep trying until we find a page.
763    Supress 'sync errors' after reporting the first.
764 
765    return values:
766    OGG_HOLE) recapture (hole in data)
767           0) need more data
768           1) page returned
769 
770    Returns pointers into buffered data; invalidated by next call to
771    _stream, _clear, _init, or _buffer */
772 
ogg_sync_pageout(ogg_sync_state * oy,ogg_page * og)773 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
774 
775   /* all we need to do is verify a page at the head of the stream
776      buffer.  If it doesn't verify, we look for the next potential
777      frame */
778 
779   while(1){
780     long ret=ogg_sync_pageseek(oy,og);
781     if(ret>0){
782       /* have a page */
783       return 1;
784     }
785     if(ret==0){
786       /* need more data */
787       return 0;
788     }
789 
790     /* head did not start a synced page... skipped some bytes */
791     if(!oy->unsynced){
792       oy->unsynced=1;
793       return OGG_HOLE;
794     }
795 
796     /* loop. keep looking */
797 
798   }
799 }
800 
801 /* clear things to an initial state.  Good to call, eg, before seeking */
ogg_sync_reset(ogg_sync_state * oy)802 int ogg_sync_reset(ogg_sync_state *oy){
803 
804   ogg_buffer_release(oy->fifo_tail);
805   oy->fifo_tail=0;
806   oy->fifo_head=0;
807   oy->fifo_fill=0;
808 
809   oy->unsynced=0;
810   oy->headerbytes=0;
811   oy->bodybytes=0;
812   return OGG_SUCCESS;
813 }
814 
ogg_stream_create(int serialno)815 ogg_stream_state *ogg_stream_create(int serialno){
816   ogg_stream_state *os=_ogg_calloc(1,sizeof(*os));
817   os->serialno=serialno;
818   os->pageno=-1;
819   return os;
820 }
821 
ogg_stream_destroy(ogg_stream_state * os)822 int ogg_stream_destroy(ogg_stream_state *os){
823   if(os){
824     ogg_buffer_release(os->header_tail);
825     ogg_buffer_release(os->body_tail);
826     memset(os,0,sizeof(*os));
827     _ogg_free(os);
828   }
829   return OGG_SUCCESS;
830 }
831 
832 
833 #define FINFLAG 0x80000000UL
834 #define FINMASK 0x7fffffffUL
835 
_next_lace(oggbyte_buffer * ob,ogg_stream_state * os)836 static void _next_lace(oggbyte_buffer *ob,ogg_stream_state *os){
837   /* search ahead one lace */
838   os->body_fill_next=0;
839   while(os->laceptr<os->lacing_fill){
840     int val=oggbyte_read1(ob,27+os->laceptr++);
841     os->body_fill_next+=val;
842     if(val<255){
843       os->body_fill_next|=FINFLAG;
844       os->clearflag=1;
845       break;
846     }
847   }
848 }
849 
_span_queued_page(ogg_stream_state * os)850 static void _span_queued_page(ogg_stream_state *os){
851   while( !(os->body_fill&FINFLAG) ){
852 
853     if(!os->header_tail)break;
854 
855     /* first flush out preceeding page header (if any).  Body is
856        flushed as it's consumed, so that's not done here. */
857 
858     if(os->lacing_fill>=0)
859       os->header_tail=ogg_buffer_pretruncate(os->header_tail,
860                                              os->lacing_fill+27);
861     os->lacing_fill=0;
862     os->laceptr=0;
863     os->clearflag=0;
864 
865     if(!os->header_tail){
866       os->header_head=0;
867       break;
868     }else{
869 
870       /* process/prepare next page, if any */
871 
872       long pageno;
873       oggbyte_buffer ob;
874       ogg_page og;               /* only for parsing header values */
875       og.header=os->header_tail; /* only for parsing header values */
876       pageno=ogg_page_pageno(&og);
877 
878       oggbyte_init(&ob,os->header_tail);
879       os->lacing_fill=oggbyte_read1(&ob,26);
880 
881       /* are we in sequence? */
882       if(pageno!=os->pageno){
883         if(os->pageno==-1) /* indicates seek or reset */
884           os->holeflag=1;  /* set for internal use */
885         else
886           os->holeflag=2;  /* set for external reporting */
887 
888         os->body_tail=ogg_buffer_pretruncate(os->body_tail,
889                                              os->body_fill);
890         if(os->body_tail==0)os->body_head=0;
891         os->body_fill=0;
892 
893       }
894 
895       if(ogg_page_continued(&og)){
896         if(os->body_fill==0){
897           /* continued packet, but no preceeding data to continue */
898           /* dump the first partial packet on the page */
899           _next_lace(&ob,os);
900           os->body_tail=
901             ogg_buffer_pretruncate(os->body_tail,os->body_fill_next&FINMASK);
902           if(os->body_tail==0)os->body_head=0;
903           /* set span flag */
904           if(!os->spanflag && !os->holeflag)os->spanflag=2;
905         }
906       }else{
907         if(os->body_fill>0){
908           /* preceeding data to continue, but not a continued page */
909           /* dump body_fill */
910           os->body_tail=ogg_buffer_pretruncate(os->body_tail,
911                                                os->body_fill);
912           if(os->body_tail==0)os->body_head=0;
913           os->body_fill=0;
914 
915           /* set espan flag */
916           if(!os->spanflag && !os->holeflag)os->spanflag=2;
917         }
918       }
919 
920       if(os->laceptr<os->lacing_fill){
921         os->granulepos=ogg_page_granulepos(&og);
922 
923         /* get current packet size & flag */
924         _next_lace(&ob,os);
925         os->body_fill+=os->body_fill_next; /* addition handles the flag fine;
926                                              unsigned on purpose */
927         /* ...and next packet size & flag */
928         _next_lace(&ob,os);
929 
930       }
931 
932       os->pageno=pageno+1;
933       os->e_o_s=ogg_page_eos(&og);
934       os->b_o_s=ogg_page_bos(&og);
935 
936     }
937   }
938 }
939 
940 /* add the incoming page to the stream state; we decompose the page
941    into packet segments here as well. */
942 
ogg_stream_pagein(ogg_stream_state * os,ogg_page * og)943 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
944 
945   int serialno=ogg_page_serialno(og);
946   int version=ogg_page_version(og);
947 
948   /* check the serial number */
949   if(serialno!=os->serialno){
950     ogg_page_release(og);
951     return OGG_ESERIAL;
952   }
953   if(version>0){
954     ogg_page_release(og);
955     return OGG_EVERSION;
956   }
957 
958   /* add to fifos */
959   if(!os->body_tail){
960     os->body_tail=og->body;
961     os->body_head=ogg_buffer_walk(og->body);
962   }else{
963     os->body_head=ogg_buffer_cat(os->body_head,og->body);
964   }
965   if(!os->header_tail){
966     os->header_tail=og->header;
967     os->header_head=ogg_buffer_walk(og->header);
968     os->lacing_fill=-27;
969   }else{
970     os->header_head=ogg_buffer_cat(os->header_head,og->header);
971   }
972 
973   memset(og,0,sizeof(*og));
974   return OGG_SUCCESS;
975 }
976 
ogg_stream_reset(ogg_stream_state * os)977 int ogg_stream_reset(ogg_stream_state *os){
978 
979   ogg_buffer_release(os->header_tail);
980   ogg_buffer_release(os->body_tail);
981   os->header_tail=os->header_head=0;
982   os->body_tail=os->body_head=0;
983 
984   os->e_o_s=0;
985   os->b_o_s=0;
986   os->pageno=-1;
987   os->packetno=0;
988   os->granulepos=0;
989 
990   os->body_fill=0;
991   os->lacing_fill=0;
992 
993   os->holeflag=0;
994   os->spanflag=0;
995   os->clearflag=0;
996   os->laceptr=0;
997   os->body_fill_next=0;
998 
999   return OGG_SUCCESS;
1000 }
1001 
ogg_stream_reset_serialno(ogg_stream_state * os,int serialno)1002 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
1003   ogg_stream_reset(os);
1004   os->serialno=serialno;
1005   return OGG_SUCCESS;
1006 }
1007 
_packetout(ogg_stream_state * os,ogg_packet * op,int adv)1008 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
1009 
1010   ogg_packet_release(op);
1011   _span_queued_page(os);
1012 
1013   if(os->holeflag){
1014     int temp=os->holeflag;
1015     if(os->clearflag)
1016       os->holeflag=0;
1017     else
1018       os->holeflag=1;
1019     if(temp==2){
1020       os->packetno++;
1021       return OGG_HOLE;
1022     }
1023   }
1024   if(os->spanflag){
1025     int temp=os->spanflag;
1026     if(os->clearflag)
1027       os->spanflag=0;
1028     else
1029       os->spanflag=1;
1030     if(temp==2){
1031       os->packetno++;
1032       return OGG_SPAN;
1033     }
1034   }
1035 
1036   if(!(os->body_fill&FINFLAG)) return 0;
1037   if(!op && !adv)return 1; /* just using peek as an inexpensive way
1038                                to ask if there's a whole packet
1039                                waiting */
1040   if(op){
1041     op->b_o_s=os->b_o_s;
1042     if(os->e_o_s && os->body_fill_next==0)
1043       op->e_o_s=os->e_o_s;
1044     else
1045       op->e_o_s=0;
1046     if( (os->body_fill&FINFLAG) && !(os->body_fill_next&FINFLAG) )
1047       op->granulepos=os->granulepos;
1048     else
1049       op->granulepos=-1;
1050     op->packetno=os->packetno;
1051   }
1052 
1053   if(adv){
1054     oggbyte_buffer ob;
1055     oggbyte_init(&ob,os->header_tail);
1056 
1057     /* split the body contents off */
1058     if(op){
1059       op->packet=ogg_buffer_split(&os->body_tail,&os->body_head,
1060 				  os->body_fill&FINMASK);
1061       op->bytes=os->body_fill&FINMASK;
1062     }else{
1063       os->body_tail=ogg_buffer_pretruncate(os->body_tail,
1064 					   os->body_fill&FINMASK);
1065       if(os->body_tail==0)os->body_head=0;
1066     }
1067 
1068     /* update lacing pointers */
1069     os->body_fill=os->body_fill_next;
1070     _next_lace(&ob,os);
1071   }else{
1072     if(op){
1073       op->packet=ogg_buffer_sub(os->body_tail,os->body_fill&FINMASK);
1074       op->bytes=os->body_fill&FINMASK;
1075     }
1076   }
1077 
1078   if(adv){
1079     os->packetno++;
1080     os->b_o_s=0;
1081   }
1082 
1083   return 1;
1084 }
1085 
ogg_stream_packetout(ogg_stream_state * os,ogg_packet * op)1086 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
1087   return _packetout(os,op,1);
1088 }
1089 
ogg_stream_packetpeek(ogg_stream_state * os,ogg_packet * op)1090 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
1091   return _packetout(os,op,0);
1092 }
1093 
ogg_packet_release(ogg_packet * op)1094 int ogg_packet_release(ogg_packet *op) {
1095   if(op){
1096     ogg_buffer_release(op->packet);
1097     memset(op, 0, sizeof(*op));
1098   }
1099   return OGG_SUCCESS;
1100 }
1101 
ogg_page_release(ogg_page * og)1102 int ogg_page_release(ogg_page *og) {
1103   if(og){
1104     ogg_buffer_release(og->header);
1105     ogg_buffer_release(og->body);
1106     memset(og, 0, sizeof(*og));
1107   }
1108   return OGG_SUCCESS;
1109 }
1110 
ogg_page_dup(ogg_page * dup,ogg_page * orig)1111 void ogg_page_dup(ogg_page *dup,ogg_page *orig){
1112   dup->header_len=orig->header_len;
1113   dup->body_len=orig->body_len;
1114   dup->header=ogg_buffer_dup(orig->header);
1115   dup->body=ogg_buffer_dup(orig->body);
1116 }
1117 
1118