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