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