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