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