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