1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: code raw packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
15 last mod: $Id: framing.c 17039 2010-03-26 00:34:54Z xiphmont $
16
17 note: The CRC code is directly derived from public domain code by
18 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
19 for details.
20
21 ********************************************************************/
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ogg/ogg.h>
26
27 /* A complete description of Ogg framing exists in docs/framing.html */
28
ogg_page_version(const ogg_page * og)29 int ogg_page_version(const ogg_page *og){
30 return((int)(og->header[4]));
31 }
32
ogg_page_continued(const ogg_page * og)33 int ogg_page_continued(const ogg_page *og){
34 return((int)(og->header[5]&0x01));
35 }
36
ogg_page_bos(const ogg_page * og)37 int ogg_page_bos(const ogg_page *og){
38 return((int)(og->header[5]&0x02));
39 }
40
ogg_page_eos(const ogg_page * og)41 int ogg_page_eos(const ogg_page *og){
42 return((int)(og->header[5]&0x04));
43 }
44
ogg_page_granulepos(const ogg_page * og)45 ogg_int64_t ogg_page_granulepos(const ogg_page *og){
46 unsigned char *page=og->header;
47 ogg_int64_t granulepos=page[13]&(0xff);
48 granulepos= (granulepos<<8)|(page[12]&0xff);
49 granulepos= (granulepos<<8)|(page[11]&0xff);
50 granulepos= (granulepos<<8)|(page[10]&0xff);
51 granulepos= (granulepos<<8)|(page[9]&0xff);
52 granulepos= (granulepos<<8)|(page[8]&0xff);
53 granulepos= (granulepos<<8)|(page[7]&0xff);
54 granulepos= (granulepos<<8)|(page[6]&0xff);
55 return(granulepos);
56 }
57
ogg_page_serialno(const ogg_page * og)58 int ogg_page_serialno(const ogg_page *og){
59 return(og->header[14] |
60 (og->header[15]<<8) |
61 (og->header[16]<<16) |
62 (og->header[17]<<24));
63 }
64
ogg_page_pageno(const ogg_page * og)65 long ogg_page_pageno(const ogg_page *og){
66 return(og->header[18] |
67 (og->header[19]<<8) |
68 (og->header[20]<<16) |
69 (og->header[21]<<24));
70 }
71
72
73
74 /* returns the number of packets that are completed on this page (if
75 the leading packet is begun on a previous page, but ends on this
76 page, it's counted */
77
78 /* NOTE:
79 If a page consists of a packet begun on a previous page, and a new
80 packet begun (but not completed) on this page, the return will be:
81 ogg_page_packets(page) ==1,
82 ogg_page_continued(page) !=0
83
84 If a page happens to be a single packet that was begun on a
85 previous page, and spans to the next page (in the case of a three or
86 more page packet), the return will be:
87 ogg_page_packets(page) ==0,
88 ogg_page_continued(page) !=0
89 */
90
ogg_page_packets(const ogg_page * og)91 int ogg_page_packets(const ogg_page *og){
92 int i,n=og->header[26],count=0;
93 for(i=0;i<n;i++)
94 if(og->header[27+i]<255)count++;
95 return(count);
96 }
97
98
99 #if 0
100 /* helper to initialize lookup for direct-table CRC (illustrative; we
101 use the static init below) */
102
103 static ogg_uint32_t _ogg_crc_entry(unsigned long index){
104 int i;
105 unsigned long r;
106
107 r = index << 24;
108 for (i=0; i<8; i++)
109 if (r & 0x80000000UL)
110 r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
111 polynomial, although we use an
112 unreflected alg and an init/final
113 of 0, not 0xffffffff */
114 else
115 r<<=1;
116 return (r & 0xffffffffUL);
117 }
118 #endif
119
120 static const ogg_uint32_t crc_lookup[256]={
121 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
122 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
123 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
124 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
125 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
126 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
127 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
128 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
129 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
130 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
131 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
132 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
133 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
134 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
135 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
136 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
137 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
138 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
139 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
140 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
141 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
142 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
143 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
144 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
145 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
146 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
147 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
148 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
149 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
150 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
151 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
152 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
153 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
154 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
155 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
156 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
157 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
158 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
159 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
160 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
161 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
162 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
163 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
164 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
165 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
166 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
167 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
168 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
169 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
170 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
171 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
172 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
173 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
174 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
175 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
176 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
177 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
178 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
179 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
180 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
181 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
182 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
183 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
184 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
185
186 /* init the encode/decode logical stream state */
187
ogg_stream_init(ogg_stream_state * os,int serialno)188 int ogg_stream_init(ogg_stream_state *os,int serialno){
189 if(os){
190 memset(os,0,sizeof(*os));
191 os->body_storage=16*1024;
192 os->lacing_storage=1024;
193
194 os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
195 os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
196 os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
197
198 if(!os->body_data || !os->lacing_vals || !os->granule_vals){
199 ogg_stream_clear(os);
200 return -1;
201 }
202
203 os->serialno=serialno;
204
205 return(0);
206 }
207 return(-1);
208 }
209
210 /* async/delayed error detection for the ogg_stream_state */
ogg_stream_check(ogg_stream_state * os)211 int ogg_stream_check(ogg_stream_state *os){
212 if(!os || !os->body_data) return -1;
213 return 0;
214 }
215
216 /* _clear does not free os, only the non-flat storage within */
ogg_stream_clear(ogg_stream_state * os)217 int ogg_stream_clear(ogg_stream_state *os){
218 if(os){
219 if(os->body_data)_ogg_free(os->body_data);
220 if(os->lacing_vals)_ogg_free(os->lacing_vals);
221 if(os->granule_vals)_ogg_free(os->granule_vals);
222
223 memset(os,0,sizeof(*os));
224 }
225 return(0);
226 }
227
ogg_stream_destroy(ogg_stream_state * os)228 int ogg_stream_destroy(ogg_stream_state *os){
229 if(os){
230 ogg_stream_clear(os);
231 _ogg_free(os);
232 }
233 return(0);
234 }
235
236 /* Helpers for ogg_stream_encode; this keeps the structure and
237 what's happening fairly clear */
238
_os_body_expand(ogg_stream_state * os,int needed)239 static int _os_body_expand(ogg_stream_state *os,int needed){
240 if(os->body_storage<=os->body_fill+needed){
241 void *ret;
242 ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)*
243 sizeof(*os->body_data));
244 if(!ret){
245 ogg_stream_clear(os);
246 return -1;
247 }
248 os->body_storage+=(needed+1024);
249 os->body_data=ret;
250 }
251 return 0;
252 }
253
_os_lacing_expand(ogg_stream_state * os,int needed)254 static int _os_lacing_expand(ogg_stream_state *os,int needed){
255 if(os->lacing_storage<=os->lacing_fill+needed){
256 void *ret;
257 ret=_ogg_realloc(os->lacing_vals,(os->lacing_storage+needed+32)*
258 sizeof(*os->lacing_vals));
259 if(!ret){
260 ogg_stream_clear(os);
261 return -1;
262 }
263 os->lacing_vals=ret;
264 ret=_ogg_realloc(os->granule_vals,(os->lacing_storage+needed+32)*
265 sizeof(*os->granule_vals));
266 if(!ret){
267 ogg_stream_clear(os);
268 return -1;
269 }
270 os->granule_vals=ret;
271 os->lacing_storage+=(needed+32);
272 }
273 return 0;
274 }
275
276 /* checksum the page */
277 /* Direct table CRC; note that this will be faster in the future if we
278 perform the checksum silmultaneously with other copies */
279
ogg_page_checksum_set(ogg_page * og)280 void ogg_page_checksum_set(ogg_page *og){
281 if(og){
282 ogg_uint32_t crc_reg=0;
283 int i;
284
285 /* safety; needed for API behavior, but not framing code */
286 og->header[22]=0;
287 og->header[23]=0;
288 og->header[24]=0;
289 og->header[25]=0;
290
291 for(i=0;i<og->header_len;i++)
292 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
293 for(i=0;i<og->body_len;i++)
294 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
295
296 og->header[22]=(unsigned char)(crc_reg&0xff);
297 og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
298 og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
299 og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
300 }
301 }
302
303 /* submit data to the internal buffer of the framing engine */
ogg_stream_iovecin(ogg_stream_state * os,ogg_iovec_t * iov,int count,long e_o_s,ogg_int64_t granulepos)304 int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
305 long e_o_s, ogg_int64_t granulepos){
306
307 int bytes = 0, lacing_vals, i;
308
309 if(ogg_stream_check(os)) return -1;
310 if(!iov) return 0;
311
312 for (i = 0; i < count; ++i) bytes += (int)iov[i].iov_len;
313 lacing_vals=bytes/255+1;
314
315 if(os->body_returned){
316 /* advance packet data according to the body_returned pointer. We
317 had to keep it around to return a pointer into the buffer last
318 call */
319
320 os->body_fill-=os->body_returned;
321 if(os->body_fill)
322 memmove(os->body_data,os->body_data+os->body_returned,
323 os->body_fill);
324 os->body_returned=0;
325 }
326
327 /* make sure we have the buffer storage */
328 if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
329 return -1;
330
331 /* Copy in the submitted packet. Yes, the copy is a waste; this is
332 the liability of overly clean abstraction for the time being. It
333 will actually be fairly easy to eliminate the extra copy in the
334 future */
335
336 for (i = 0; i < count; ++i) {
337 memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
338 os->body_fill += (int)iov[i].iov_len;
339 }
340
341 /* Store lacing vals for this packet */
342 for(i=0;i<lacing_vals-1;i++){
343 os->lacing_vals[os->lacing_fill+i]=255;
344 os->granule_vals[os->lacing_fill+i]=os->granulepos;
345 }
346 os->lacing_vals[os->lacing_fill+i]=bytes%255;
347 os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
348
349 /* flag the first segment as the beginning of the packet */
350 os->lacing_vals[os->lacing_fill]|= 0x100;
351
352 os->lacing_fill+=lacing_vals;
353
354 /* for the sake of completeness */
355 os->packetno++;
356
357 if(e_o_s)os->e_o_s=1;
358
359 return(0);
360 }
361
ogg_stream_packetin(ogg_stream_state * os,ogg_packet * op)362 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
363 ogg_iovec_t iov;
364 iov.iov_base = op->packet;
365 iov.iov_len = op->bytes;
366 return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
367 }
368
369 /* Conditionally flush a page; force==0 will only flush nominal-size
370 pages, force==1 forces us to flush a page regardless of page size
371 so long as there's any data available at all. */
ogg_stream_flush_i(ogg_stream_state * os,ogg_page * og,int force)372 static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force){
373 int i;
374 int vals=0;
375 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
376 int bytes=0;
377 long acc=0;
378 ogg_int64_t granule_pos=-1;
379
380 if(ogg_stream_check(os)) return(0);
381 if(maxvals==0) return(0);
382
383 /* construct a page */
384 /* decide how many segments to include */
385
386 /* If this is the initial header case, the first page must only include
387 the initial header packet */
388 if(os->b_o_s==0){ /* 'initial header page' case */
389 granule_pos=0;
390 for(vals=0;vals<maxvals;vals++){
391 if((os->lacing_vals[vals]&0x0ff)<255){
392 vals++;
393 break;
394 }
395 }
396 }else{
397
398 /* The extra packets_done, packet_just_done logic here attempts to do two things:
399 1) Don't unneccessarily span pages.
400 2) Unless necessary, don't flush pages if there are less than four packets on
401 them; this expands page size to reduce unneccessary overhead if incoming packets
402 are large.
403 These are not necessary behaviors, just 'always better than naive flushing'
404 without requiring an application to explicitly request a specific optimized
405 behavior. We'll want an explicit behavior setup pathway eventually as well. */
406
407 int packets_done=0;
408 int packet_just_done=0;
409 for(vals=0;vals<maxvals;vals++){
410 if(acc>4096 && packet_just_done>=4){
411 force=1;
412 break;
413 }
414 acc+=os->lacing_vals[vals]&0x0ff;
415 if((os->lacing_vals[vals]&0xff)<255){
416 granule_pos=os->granule_vals[vals];
417 packet_just_done=++packets_done;
418 }else
419 packet_just_done=0;
420 }
421 if(vals==255)force=1;
422 }
423
424 if(!force) return(0);
425
426 /* construct the header in temp storage */
427 memcpy(os->header,"OggS",4);
428
429 /* stream structure version */
430 os->header[4]=0x00;
431
432 /* continued packet flag? */
433 os->header[5]=0x00;
434 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
435 /* first page flag? */
436 if(os->b_o_s==0)os->header[5]|=0x02;
437 /* last page flag? */
438 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
439 os->b_o_s=1;
440
441 /* 64 bits of PCM position */
442 for(i=6;i<14;i++){
443 os->header[i]=(unsigned char)(granule_pos&0xff);
444 granule_pos>>=8;
445 }
446
447 /* 32 bits of stream serial number */
448 {
449 long serialno=os->serialno;
450 for(i=14;i<18;i++){
451 os->header[i]=(unsigned char)(serialno&0xff);
452 serialno>>=8;
453 }
454 }
455
456 /* 32 bits of page counter (we have both counter and page header
457 because this val can roll over) */
458 if(os->pageno==-1)os->pageno=0; /* because someone called
459 stream_reset; this would be a
460 strange thing to do in an
461 encode stream, but it has
462 plausible uses */
463 {
464 long pageno=os->pageno++;
465 for(i=18;i<22;i++){
466 os->header[i]=(unsigned char)(pageno&0xff);
467 pageno>>=8;
468 }
469 }
470
471 /* zero for computation; filled in later */
472 os->header[22]=0;
473 os->header[23]=0;
474 os->header[24]=0;
475 os->header[25]=0;
476
477 /* segment table */
478 os->header[26]=(unsigned char)(vals&0xff);
479 for(i=0;i<vals;i++)
480 bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
481
482 /* set pointers in the ogg_page struct */
483 og->header=os->header;
484 og->header_len=os->header_fill=vals+27;
485 og->body=os->body_data+os->body_returned;
486 og->body_len=bytes;
487
488 /* advance the lacing data and set the body_returned pointer */
489
490 os->lacing_fill-=vals;
491 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
492 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
493 os->body_returned+=bytes;
494
495 /* calculate the checksum */
496
497 ogg_page_checksum_set(og);
498
499 /* done */
500 return(1);
501 }
502
503 /* This will flush remaining packets into a page (returning nonzero),
504 even if there is not enough data to trigger a flush normally
505 (undersized page). If there are no packets or partial packets to
506 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
507 try to flush a normal sized page like ogg_stream_pageout; a call to
508 ogg_stream_flush does not guarantee that all packets have flushed.
509 Only a return value of 0 from ogg_stream_flush indicates all packet
510 data is flushed into pages.
511
512 since ogg_stream_flush will flush the last page in a stream even if
513 it's undersized, you almost certainly want to use ogg_stream_pageout
514 (and *not* ogg_stream_flush) unless you specifically need to flush
515 an page regardless of size in the middle of a stream. */
516
ogg_stream_flush(ogg_stream_state * os,ogg_page * og)517 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
518 return ogg_stream_flush_i(os,og,1);
519 }
520
521 /* This constructs pages from buffered packet segments. The pointers
522 returned are to static buffers; do not free. The returned buffers are
523 good only until the next call (using the same ogg_stream_state) */
524
ogg_stream_pageout(ogg_stream_state * os,ogg_page * og)525 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
526 int force=0;
527 if(ogg_stream_check(os)) return 0;
528
529 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
530 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
531 force=1;
532
533 return(ogg_stream_flush_i(os,og,force));
534 }
535
ogg_stream_eos(ogg_stream_state * os)536 int ogg_stream_eos(ogg_stream_state *os){
537 if(ogg_stream_check(os)) return 1;
538 return os->e_o_s;
539 }
540
541 /* DECODING PRIMITIVES: packet streaming layer **********************/
542
543 /* This has two layers to place more of the multi-serialno and paging
544 control in the application's hands. First, we expose a data buffer
545 using ogg_sync_buffer(). The app either copies into the
546 buffer, or passes it directly to read(), etc. We then call
547 ogg_sync_wrote() to tell how many bytes we just added.
548
549 Pages are returned (pointers into the buffer in ogg_sync_state)
550 by ogg_sync_pageout(). The page is then submitted to
551 ogg_stream_pagein() along with the appropriate
552 ogg_stream_state* (ie, matching serialno). We then get raw
553 packets out calling ogg_stream_packetout() with a
554 ogg_stream_state. */
555
556 /* initialize the struct to a known state */
ogg_sync_init(ogg_sync_state * oy)557 int ogg_sync_init(ogg_sync_state *oy){
558 if(oy){
559 oy->storage = -1; /* used as a readiness flag */
560 memset(oy,0,sizeof(*oy));
561 }
562 return(0);
563 }
564
565 /* clear non-flat storage within */
ogg_sync_clear(ogg_sync_state * oy)566 int ogg_sync_clear(ogg_sync_state *oy){
567 if(oy){
568 if(oy->data)_ogg_free(oy->data);
569 memset(oy,0,sizeof(*oy));
570 }
571 return(0);
572 }
573
ogg_sync_destroy(ogg_sync_state * oy)574 int ogg_sync_destroy(ogg_sync_state *oy){
575 if(oy){
576 ogg_sync_clear(oy);
577 _ogg_free(oy);
578 }
579 return(0);
580 }
581
ogg_sync_check(ogg_sync_state * oy)582 int ogg_sync_check(ogg_sync_state *oy){
583 if(oy->storage<0) return -1;
584 return 0;
585 }
586
ogg_sync_buffer(ogg_sync_state * oy,long size)587 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
588 if(ogg_sync_check(oy)) return NULL;
589
590 /* first, clear out any space that has been previously returned */
591 if(oy->returned){
592 oy->fill-=oy->returned;
593 if(oy->fill>0)
594 memmove(oy->data,oy->data+oy->returned,oy->fill);
595 oy->returned=0;
596 }
597
598 if(size>oy->storage-oy->fill){
599 /* We need to extend the internal buffer */
600 long newsize=size+oy->fill+4096; /* an extra page to be nice */
601 void *ret;
602
603 if(oy->data)
604 ret=_ogg_realloc(oy->data,newsize);
605 else
606 ret=_ogg_malloc(newsize);
607 if(!ret){
608 ogg_sync_clear(oy);
609 return NULL;
610 }
611 oy->data=ret;
612 oy->storage=newsize;
613 }
614
615 /* expose a segment at least as large as requested at the fill mark */
616 return((char *)oy->data+oy->fill);
617 }
618
ogg_sync_wrote(ogg_sync_state * oy,long bytes)619 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
620 if(ogg_sync_check(oy))return -1;
621 if(oy->fill+bytes>oy->storage)return -1;
622 oy->fill+=bytes;
623 return(0);
624 }
625
626 /* sync the stream. This is meant to be useful for finding page
627 boundaries.
628
629 return values for this:
630 -n) skipped n bytes
631 0) page not ready; more data (no bytes skipped)
632 n) page synced at current location; page length n bytes
633
634 */
635
ogg_sync_pageseek(ogg_sync_state * oy,ogg_page * og)636 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
637 unsigned char *page=oy->data+oy->returned;
638 unsigned char *next;
639 long bytes=oy->fill-oy->returned;
640
641 if(ogg_sync_check(oy))return 0;
642
643 if(oy->headerbytes==0){
644 int headerbytes,i;
645 if(bytes<27)return(0); /* not enough for a header */
646
647 /* verify capture pattern */
648 if(memcmp(page,"OggS",4))goto sync_fail;
649
650 headerbytes=page[26]+27;
651 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
652
653 /* count up body length in the segment table */
654
655 for(i=0;i<page[26];i++)
656 oy->bodybytes+=page[27+i];
657 oy->headerbytes=headerbytes;
658 }
659
660 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
661
662 /* The whole test page is buffered. Verify the checksum */
663 {
664 /* Grab the checksum bytes, set the header field to zero */
665 char chksum[4];
666 ogg_page log;
667
668 memcpy(chksum,page+22,4);
669 memset(page+22,0,4);
670
671 /* set up a temp page struct and recompute the checksum */
672 log.header=page;
673 log.header_len=oy->headerbytes;
674 log.body=page+oy->headerbytes;
675 log.body_len=oy->bodybytes;
676 ogg_page_checksum_set(&log);
677
678 /* Compare */
679 if(memcmp(chksum,page+22,4)){
680 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
681 at all) */
682 /* replace the computed checksum with the one actually read in */
683 memcpy(page+22,chksum,4);
684
685 /* Bad checksum. Lose sync */
686 goto sync_fail;
687 }
688 }
689
690 /* yes, have a whole page all ready to go */
691 {
692 unsigned char *page=oy->data+oy->returned;
693 long bytes;
694
695 if(og){
696 og->header=page;
697 og->header_len=oy->headerbytes;
698 og->body=page+oy->headerbytes;
699 og->body_len=oy->bodybytes;
700 }
701
702 oy->unsynced=0;
703 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
704 oy->headerbytes=0;
705 oy->bodybytes=0;
706 return(bytes);
707 }
708
709 sync_fail:
710
711 oy->headerbytes=0;
712 oy->bodybytes=0;
713
714 /* search for possible capture */
715 next=memchr(page+1,'O',bytes-1);
716 if(!next)
717 next=oy->data+oy->fill;
718
719 oy->returned=(int)(next-oy->data);
720 return((long)-(next-page));
721 }
722
723 /* sync the stream and get a page. Keep trying until we find a page.
724 Supress 'sync errors' after reporting the first.
725
726 return values:
727 -1) recapture (hole in data)
728 0) need more data
729 1) page returned
730
731 Returns pointers into buffered data; invalidated by next call to
732 _stream, _clear, _init, or _buffer */
733
ogg_sync_pageout(ogg_sync_state * oy,ogg_page * og)734 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
735
736 if(ogg_sync_check(oy))return 0;
737
738 /* all we need to do is verify a page at the head of the stream
739 buffer. If it doesn't verify, we look for the next potential
740 frame */
741
742 for(;;){
743 long ret=ogg_sync_pageseek(oy,og);
744 if(ret>0){
745 /* have a page */
746 return(1);
747 }
748 if(ret==0){
749 /* need more data */
750 return(0);
751 }
752
753 /* head did not start a synced page... skipped some bytes */
754 if(!oy->unsynced){
755 oy->unsynced=1;
756 return(-1);
757 }
758
759 /* loop. keep looking */
760
761 }
762 }
763
764 /* add the incoming page to the stream state; we decompose the page
765 into packet segments here as well. */
766
ogg_stream_pagein(ogg_stream_state * os,ogg_page * og)767 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
768 unsigned char *header=og->header;
769 unsigned char *body=og->body;
770 long bodysize=og->body_len;
771 int segptr=0;
772
773 int version=ogg_page_version(og);
774 int continued=ogg_page_continued(og);
775 int bos=ogg_page_bos(og);
776 int eos=ogg_page_eos(og);
777 ogg_int64_t granulepos=ogg_page_granulepos(og);
778 int serialno=ogg_page_serialno(og);
779 long pageno=ogg_page_pageno(og);
780 int segments=header[26];
781
782 if(ogg_stream_check(os)) return -1;
783
784 /* clean up 'returned data' */
785 {
786 long lr=os->lacing_returned;
787 long br=os->body_returned;
788
789 /* body data */
790 if(br){
791 os->body_fill-=br;
792 if(os->body_fill)
793 memmove(os->body_data,os->body_data+br,os->body_fill);
794 os->body_returned=0;
795 }
796
797 if(lr){
798 /* segment table */
799 if(os->lacing_fill-lr){
800 memmove(os->lacing_vals,os->lacing_vals+lr,
801 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
802 memmove(os->granule_vals,os->granule_vals+lr,
803 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
804 }
805 os->lacing_fill-=lr;
806 os->lacing_packet-=lr;
807 os->lacing_returned=0;
808 }
809 }
810
811 /* check the serial number */
812 if(serialno!=os->serialno)return(-1);
813 if(version>0)return(-1);
814
815 if(_os_lacing_expand(os,segments+1)) return -1;
816
817 /* are we in sequence? */
818 if(pageno!=os->pageno){
819 int i;
820
821 /* unroll previous partial packet (if any) */
822 for(i=os->lacing_packet;i<os->lacing_fill;i++)
823 os->body_fill-=os->lacing_vals[i]&0xff;
824 os->lacing_fill=os->lacing_packet;
825
826 /* make a note of dropped data in segment table */
827 if(os->pageno!=-1){
828 os->lacing_vals[os->lacing_fill++]=0x400;
829 os->lacing_packet++;
830 }
831 }
832
833 /* are we a 'continued packet' page? If so, we may need to skip
834 some segments */
835 if(continued){
836 if(os->lacing_fill<1 ||
837 os->lacing_vals[os->lacing_fill-1]==0x400){
838 bos=0;
839 for(;segptr<segments;segptr++){
840 int val=header[27+segptr];
841 body+=val;
842 bodysize-=val;
843 if(val<255){
844 segptr++;
845 break;
846 }
847 }
848 }
849 }
850
851 if(bodysize){
852 if(_os_body_expand(os,bodysize)) return -1;
853 memcpy(os->body_data+os->body_fill,body,bodysize);
854 os->body_fill+=bodysize;
855 }
856
857 {
858 int saved=-1;
859 while(segptr<segments){
860 int val=header[27+segptr];
861 os->lacing_vals[os->lacing_fill]=val;
862 os->granule_vals[os->lacing_fill]=-1;
863
864 if(bos){
865 os->lacing_vals[os->lacing_fill]|=0x100;
866 bos=0;
867 }
868
869 if(val<255)saved=os->lacing_fill;
870
871 os->lacing_fill++;
872 segptr++;
873
874 if(val<255)os->lacing_packet=os->lacing_fill;
875 }
876
877 /* set the granulepos on the last granuleval of the last full packet */
878 if(saved!=-1){
879 os->granule_vals[saved]=granulepos;
880 }
881
882 }
883
884 if(eos){
885 os->e_o_s=1;
886 if(os->lacing_fill>0)
887 os->lacing_vals[os->lacing_fill-1]|=0x200;
888 }
889
890 os->pageno=pageno+1;
891
892 return(0);
893 }
894
895 /* clear things to an initial state. Good to call, eg, before seeking */
ogg_sync_reset(ogg_sync_state * oy)896 int ogg_sync_reset(ogg_sync_state *oy){
897 if(ogg_sync_check(oy))return -1;
898
899 oy->fill=0;
900 oy->returned=0;
901 oy->unsynced=0;
902 oy->headerbytes=0;
903 oy->bodybytes=0;
904 return(0);
905 }
906
ogg_stream_reset(ogg_stream_state * os)907 int ogg_stream_reset(ogg_stream_state *os){
908 if(ogg_stream_check(os)) return -1;
909
910 os->body_fill=0;
911 os->body_returned=0;
912
913 os->lacing_fill=0;
914 os->lacing_packet=0;
915 os->lacing_returned=0;
916
917 os->header_fill=0;
918
919 os->e_o_s=0;
920 os->b_o_s=0;
921 os->pageno=-1;
922 os->packetno=0;
923 os->granulepos=0;
924
925 return(0);
926 }
927
ogg_stream_reset_serialno(ogg_stream_state * os,int serialno)928 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
929 if(ogg_stream_check(os)) return -1;
930 ogg_stream_reset(os);
931 os->serialno=serialno;
932 return(0);
933 }
934
_packetout(ogg_stream_state * os,ogg_packet * op,int adv)935 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
936
937 /* The last part of decode. We have the stream broken into packet
938 segments. Now we need to group them into packets (or return the
939 out of sync markers) */
940
941 int ptr=os->lacing_returned;
942
943 if(os->lacing_packet<=ptr)return(0);
944
945 if(os->lacing_vals[ptr]&0x400){
946 /* we need to tell the codec there's a gap; it might need to
947 handle previous packet dependencies. */
948 os->lacing_returned++;
949 os->packetno++;
950 return(-1);
951 }
952
953 if(!op && !adv)return(1); /* just using peek as an inexpensive way
954 to ask if there's a whole packet
955 waiting */
956
957 /* Gather the whole packet. We'll have no holes or a partial packet */
958 {
959 int size=os->lacing_vals[ptr]&0xff;
960 int bytes=size;
961 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
962 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
963
964 while(size==255){
965 int val=os->lacing_vals[++ptr];
966 size=val&0xff;
967 if(val&0x200)eos=0x200;
968 bytes+=size;
969 }
970
971 if(op){
972 op->e_o_s=eos;
973 op->b_o_s=bos;
974 op->packet=os->body_data+os->body_returned;
975 op->packetno=os->packetno;
976 op->granulepos=os->granule_vals[ptr];
977 op->bytes=bytes;
978 }
979
980 if(adv){
981 os->body_returned+=bytes;
982 os->lacing_returned=ptr+1;
983 os->packetno++;
984 }
985 }
986 return(1);
987 }
988
ogg_stream_packetout(ogg_stream_state * os,ogg_packet * op)989 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
990 if(ogg_stream_check(os)) return 0;
991 return _packetout(os,op,1);
992 }
993
ogg_stream_packetpeek(ogg_stream_state * os,ogg_packet * op)994 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
995 if(ogg_stream_check(os)) return 0;
996 return _packetout(os,op,0);
997 }
998
ogg_packet_clear(ogg_packet * op)999 void ogg_packet_clear(ogg_packet *op) {
1000 _ogg_free(op->packet);
1001 memset(op, 0, sizeof(*op));
1002 }
1003
1004 #ifdef _V_SELFTEST
1005 #include <stdio.h>
1006
1007 ogg_stream_state os_en, os_de;
1008 ogg_sync_state oy;
1009
checkpacket(ogg_packet * op,int len,int no,int pos)1010 void checkpacket(ogg_packet *op,int len, int no, int pos){
1011 long j;
1012 static int sequence=0;
1013 static int lastno=0;
1014
1015 if(op->bytes!=len){
1016 fprintf(stderr,"incorrect packet length (%d != %d)!\n",op->bytes,len);
1017 exit(1);
1018 }
1019 if(op->granulepos!=pos){
1020 fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1021 exit(1);
1022 }
1023
1024 /* packet number just follows sequence/gap; adjust the input number
1025 for that */
1026 if(no==0){
1027 sequence=0;
1028 }else{
1029 sequence++;
1030 if(no>lastno+1)
1031 sequence++;
1032 }
1033 lastno=no;
1034 if(op->packetno!=sequence){
1035 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1036 (long)(op->packetno),sequence);
1037 exit(1);
1038 }
1039
1040 /* Test data */
1041 for(j=0;j<op->bytes;j++)
1042 if(op->packet[j]!=((j+no)&0xff)){
1043 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1044 j,op->packet[j],(j+no)&0xff);
1045 exit(1);
1046 }
1047 }
1048
check_page(unsigned char * data,const int * header,ogg_page * og)1049 void check_page(unsigned char *data,const int *header,ogg_page *og){
1050 long j;
1051 /* Test data */
1052 for(j=0;j<og->body_len;j++)
1053 if(og->body[j]!=data[j]){
1054 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1055 j,data[j],og->body[j]);
1056 exit(1);
1057 }
1058
1059 /* Test header */
1060 for(j=0;j<og->header_len;j++){
1061 if(og->header[j]!=header[j]){
1062 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1063 for(j=0;j<header[26]+27;j++)
1064 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1065 fprintf(stderr,"\n");
1066 exit(1);
1067 }
1068 }
1069 if(og->header_len!=header[26]+27){
1070 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1071 og->header_len,header[26]+27);
1072 exit(1);
1073 }
1074 }
1075
print_header(ogg_page * og)1076 void print_header(ogg_page *og){
1077 int j;
1078 fprintf(stderr,"\nHEADER:\n");
1079 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
1080 og->header[0],og->header[1],og->header[2],og->header[3],
1081 (int)og->header[4],(int)og->header[5]);
1082
1083 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
1084 (og->header[9]<<24)|(og->header[8]<<16)|
1085 (og->header[7]<<8)|og->header[6],
1086 (og->header[17]<<24)|(og->header[16]<<16)|
1087 (og->header[15]<<8)|og->header[14],
1088 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1089 (og->header[19]<<8)|og->header[18]);
1090
1091 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
1092 (int)og->header[22],(int)og->header[23],
1093 (int)og->header[24],(int)og->header[25],
1094 (int)og->header[26]);
1095
1096 for(j=27;j<og->header_len;j++)
1097 fprintf(stderr,"%d ",(int)og->header[j]);
1098 fprintf(stderr,")\n\n");
1099 }
1100
copy_page(ogg_page * og)1101 void copy_page(ogg_page *og){
1102 unsigned char *temp=_ogg_malloc(og->header_len);
1103 memcpy(temp,og->header,og->header_len);
1104 og->header=temp;
1105
1106 temp=_ogg_malloc(og->body_len);
1107 memcpy(temp,og->body,og->body_len);
1108 og->body=temp;
1109 }
1110
free_page(ogg_page * og)1111 void free_page(ogg_page *og){
1112 _ogg_free (og->header);
1113 _ogg_free (og->body);
1114 }
1115
error(void)1116 void error(void){
1117 fprintf(stderr,"error!\n");
1118 exit(1);
1119 }
1120
1121 /* 17 only */
1122 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1123 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1124 0x01,0x02,0x03,0x04,0,0,0,0,
1125 0x15,0xed,0xec,0x91,
1126 1,
1127 17};
1128
1129 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1130 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1131 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1132 0x01,0x02,0x03,0x04,0,0,0,0,
1133 0x59,0x10,0x6c,0x2c,
1134 1,
1135 17};
1136 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1137 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1138 0x01,0x02,0x03,0x04,1,0,0,0,
1139 0x89,0x33,0x85,0xce,
1140 13,
1141 254,255,0,255,1,255,245,255,255,0,
1142 255,255,90};
1143
1144 /* nil packets; beginning,middle,end */
1145 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1146 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1147 0x01,0x02,0x03,0x04,0,0,0,0,
1148 0xff,0x7b,0x23,0x17,
1149 1,
1150 0};
1151 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1152 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1153 0x01,0x02,0x03,0x04,1,0,0,0,
1154 0x5c,0x3f,0x66,0xcb,
1155 17,
1156 17,254,255,0,0,255,1,0,255,245,255,255,0,
1157 255,255,90,0};
1158
1159 /* large initial packet */
1160 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1161 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1162 0x01,0x02,0x03,0x04,0,0,0,0,
1163 0x01,0x27,0x31,0xaa,
1164 18,
1165 255,255,255,255,255,255,255,255,
1166 255,255,255,255,255,255,255,255,255,10};
1167
1168 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1169 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1170 0x01,0x02,0x03,0x04,1,0,0,0,
1171 0x7f,0x4e,0x8a,0xd2,
1172 4,
1173 255,4,255,0};
1174
1175
1176 /* continuing packet test */
1177 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1178 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1179 0x01,0x02,0x03,0x04,0,0,0,0,
1180 0xff,0x7b,0x23,0x17,
1181 1,
1182 0};
1183
1184 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1185 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1186 0x01,0x02,0x03,0x04,1,0,0,0,
1187 0xf8,0x3c,0x19,0x79,
1188 255,
1189 255,255,255,255,255,255,255,255,
1190 255,255,255,255,255,255,255,255,
1191 255,255,255,255,255,255,255,255,
1192 255,255,255,255,255,255,255,255,
1193 255,255,255,255,255,255,255,255,
1194 255,255,255,255,255,255,255,255,
1195 255,255,255,255,255,255,255,255,
1196 255,255,255,255,255,255,255,255,
1197 255,255,255,255,255,255,255,255,
1198 255,255,255,255,255,255,255,255,
1199 255,255,255,255,255,255,255,255,
1200 255,255,255,255,255,255,255,255,
1201 255,255,255,255,255,255,255,255,
1202 255,255,255,255,255,255,255,255,
1203 255,255,255,255,255,255,255,255,
1204 255,255,255,255,255,255,255,255,
1205 255,255,255,255,255,255,255,255,
1206 255,255,255,255,255,255,255,255,
1207 255,255,255,255,255,255,255,255,
1208 255,255,255,255,255,255,255,255,
1209 255,255,255,255,255,255,255,255,
1210 255,255,255,255,255,255,255,255,
1211 255,255,255,255,255,255,255,255,
1212 255,255,255,255,255,255,255,255,
1213 255,255,255,255,255,255,255,255,
1214 255,255,255,255,255,255,255,255,
1215 255,255,255,255,255,255,255,255,
1216 255,255,255,255,255,255,255,255,
1217 255,255,255,255,255,255,255,255,
1218 255,255,255,255,255,255,255,255,
1219 255,255,255,255,255,255,255,255,
1220 255,255,255,255,255,255,255};
1221
1222 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1223 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1224 0x01,0x02,0x03,0x04,2,0,0,0,
1225 0x38,0xe6,0xb6,0x28,
1226 6,
1227 255,220,255,4,255,0};
1228
1229
1230 /* spill expansion test */
1231 const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1232 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1233 0x01,0x02,0x03,0x04,0,0,0,0,
1234 0xff,0x7b,0x23,0x17,
1235 1,
1236 0};
1237
1238 const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1239 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1240 0x01,0x02,0x03,0x04,1,0,0,0,
1241 0xce,0x8f,0x17,0x1a,
1242 23,
1243 255,255,255,255,255,255,255,255,
1244 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1245
1246
1247 const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1248 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1249 0x01,0x02,0x03,0x04,2,0,0,0,
1250 0x9b,0xb2,0x50,0xa1,
1251 1,
1252 0};
1253
1254 /* page with the 255 segment limit */
1255 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1256 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1257 0x01,0x02,0x03,0x04,0,0,0,0,
1258 0xff,0x7b,0x23,0x17,
1259 1,
1260 0};
1261
1262 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1263 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1264 0x01,0x02,0x03,0x04,1,0,0,0,
1265 0xed,0x2a,0x2e,0xa7,
1266 255,
1267 10,10,10,10,10,10,10,10,
1268 10,10,10,10,10,10,10,10,
1269 10,10,10,10,10,10,10,10,
1270 10,10,10,10,10,10,10,10,
1271 10,10,10,10,10,10,10,10,
1272 10,10,10,10,10,10,10,10,
1273 10,10,10,10,10,10,10,10,
1274 10,10,10,10,10,10,10,10,
1275 10,10,10,10,10,10,10,10,
1276 10,10,10,10,10,10,10,10,
1277 10,10,10,10,10,10,10,10,
1278 10,10,10,10,10,10,10,10,
1279 10,10,10,10,10,10,10,10,
1280 10,10,10,10,10,10,10,10,
1281 10,10,10,10,10,10,10,10,
1282 10,10,10,10,10,10,10,10,
1283 10,10,10,10,10,10,10,10,
1284 10,10,10,10,10,10,10,10,
1285 10,10,10,10,10,10,10,10,
1286 10,10,10,10,10,10,10,10,
1287 10,10,10,10,10,10,10,10,
1288 10,10,10,10,10,10,10,10,
1289 10,10,10,10,10,10,10,10,
1290 10,10,10,10,10,10,10,10,
1291 10,10,10,10,10,10,10,10,
1292 10,10,10,10,10,10,10,10,
1293 10,10,10,10,10,10,10,10,
1294 10,10,10,10,10,10,10,10,
1295 10,10,10,10,10,10,10,10,
1296 10,10,10,10,10,10,10,10,
1297 10,10,10,10,10,10,10,10,
1298 10,10,10,10,10,10,10};
1299
1300 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1301 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1302 0x01,0x02,0x03,0x04,2,0,0,0,
1303 0x6c,0x3b,0x82,0x3d,
1304 1,
1305 50};
1306
1307
1308 /* packet that overspans over an entire page */
1309 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1310 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1311 0x01,0x02,0x03,0x04,0,0,0,0,
1312 0xff,0x7b,0x23,0x17,
1313 1,
1314 0};
1315
1316 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1317 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1318 0x01,0x02,0x03,0x04,1,0,0,0,
1319 0x68,0x22,0x7c,0x3d,
1320 255,
1321 100,
1322 255,255,255,255,255,255,255,255,
1323 255,255,255,255,255,255,255,255,
1324 255,255,255,255,255,255,255,255,
1325 255,255,255,255,255,255,255,255,
1326 255,255,255,255,255,255,255,255,
1327 255,255,255,255,255,255,255,255,
1328 255,255,255,255,255,255,255,255,
1329 255,255,255,255,255,255,255,255,
1330 255,255,255,255,255,255,255,255,
1331 255,255,255,255,255,255,255,255,
1332 255,255,255,255,255,255,255,255,
1333 255,255,255,255,255,255,255,255,
1334 255,255,255,255,255,255,255,255,
1335 255,255,255,255,255,255,255,255,
1336 255,255,255,255,255,255,255,255,
1337 255,255,255,255,255,255,255,255,
1338 255,255,255,255,255,255,255,255,
1339 255,255,255,255,255,255,255,255,
1340 255,255,255,255,255,255,255,255,
1341 255,255,255,255,255,255,255,255,
1342 255,255,255,255,255,255,255,255,
1343 255,255,255,255,255,255,255,255,
1344 255,255,255,255,255,255,255,255,
1345 255,255,255,255,255,255,255,255,
1346 255,255,255,255,255,255,255,255,
1347 255,255,255,255,255,255,255,255,
1348 255,255,255,255,255,255,255,255,
1349 255,255,255,255,255,255,255,255,
1350 255,255,255,255,255,255,255,255,
1351 255,255,255,255,255,255,255,255,
1352 255,255,255,255,255,255,255,255,
1353 255,255,255,255,255,255};
1354
1355 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1356 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1357 0x01,0x02,0x03,0x04,2,0,0,0,
1358 0xf4,0x87,0xba,0xf3,
1359 255,
1360 255,255,255,255,255,255,255,255,
1361 255,255,255,255,255,255,255,255,
1362 255,255,255,255,255,255,255,255,
1363 255,255,255,255,255,255,255,255,
1364 255,255,255,255,255,255,255,255,
1365 255,255,255,255,255,255,255,255,
1366 255,255,255,255,255,255,255,255,
1367 255,255,255,255,255,255,255,255,
1368 255,255,255,255,255,255,255,255,
1369 255,255,255,255,255,255,255,255,
1370 255,255,255,255,255,255,255,255,
1371 255,255,255,255,255,255,255,255,
1372 255,255,255,255,255,255,255,255,
1373 255,255,255,255,255,255,255,255,
1374 255,255,255,255,255,255,255,255,
1375 255,255,255,255,255,255,255,255,
1376 255,255,255,255,255,255,255,255,
1377 255,255,255,255,255,255,255,255,
1378 255,255,255,255,255,255,255,255,
1379 255,255,255,255,255,255,255,255,
1380 255,255,255,255,255,255,255,255,
1381 255,255,255,255,255,255,255,255,
1382 255,255,255,255,255,255,255,255,
1383 255,255,255,255,255,255,255,255,
1384 255,255,255,255,255,255,255,255,
1385 255,255,255,255,255,255,255,255,
1386 255,255,255,255,255,255,255,255,
1387 255,255,255,255,255,255,255,255,
1388 255,255,255,255,255,255,255,255,
1389 255,255,255,255,255,255,255,255,
1390 255,255,255,255,255,255,255,255,
1391 255,255,255,255,255,255,255};
1392
1393 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1394 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1395 0x01,0x02,0x03,0x04,3,0,0,0,
1396 0xf7,0x2f,0x6c,0x60,
1397 5,
1398 254,255,4,255,0};
1399
1400 /* packet that overspans over an entire page */
1401 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1402 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1403 0x01,0x02,0x03,0x04,0,0,0,0,
1404 0xff,0x7b,0x23,0x17,
1405 1,
1406 0};
1407
1408 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1409 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1410 0x01,0x02,0x03,0x04,1,0,0,0,
1411 0x68,0x22,0x7c,0x3d,
1412 255,
1413 100,
1414 255,255,255,255,255,255,255,255,
1415 255,255,255,255,255,255,255,255,
1416 255,255,255,255,255,255,255,255,
1417 255,255,255,255,255,255,255,255,
1418 255,255,255,255,255,255,255,255,
1419 255,255,255,255,255,255,255,255,
1420 255,255,255,255,255,255,255,255,
1421 255,255,255,255,255,255,255,255,
1422 255,255,255,255,255,255,255,255,
1423 255,255,255,255,255,255,255,255,
1424 255,255,255,255,255,255,255,255,
1425 255,255,255,255,255,255,255,255,
1426 255,255,255,255,255,255,255,255,
1427 255,255,255,255,255,255,255,255,
1428 255,255,255,255,255,255,255,255,
1429 255,255,255,255,255,255,255,255,
1430 255,255,255,255,255,255,255,255,
1431 255,255,255,255,255,255,255,255,
1432 255,255,255,255,255,255,255,255,
1433 255,255,255,255,255,255,255,255,
1434 255,255,255,255,255,255,255,255,
1435 255,255,255,255,255,255,255,255,
1436 255,255,255,255,255,255,255,255,
1437 255,255,255,255,255,255,255,255,
1438 255,255,255,255,255,255,255,255,
1439 255,255,255,255,255,255,255,255,
1440 255,255,255,255,255,255,255,255,
1441 255,255,255,255,255,255,255,255,
1442 255,255,255,255,255,255,255,255,
1443 255,255,255,255,255,255,255,255,
1444 255,255,255,255,255,255,255,255,
1445 255,255,255,255,255,255};
1446
1447 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1448 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1449 0x01,0x02,0x03,0x04,2,0,0,0,
1450 0xd4,0xe0,0x60,0xe5,
1451 1,
1452 0};
1453
test_pack(const int * pl,const int ** headers,int byteskip,int pageskip,int packetskip)1454 void test_pack(const int *pl, const int **headers, int byteskip,
1455 int pageskip, int packetskip){
1456 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1457 long inptr=0;
1458 long outptr=0;
1459 long deptr=0;
1460 long depacket=0;
1461 long granule_pos=7,pageno=0;
1462 int i,j,packets,pageout=pageskip;
1463 int eosflag=0;
1464 int bosflag=0;
1465
1466 int byteskipcount=0;
1467
1468 ogg_stream_reset(&os_en);
1469 ogg_stream_reset(&os_de);
1470 ogg_sync_reset(&oy);
1471
1472 for(packets=0;packets<packetskip;packets++)
1473 depacket+=pl[packets];
1474
1475 for(packets=0;;packets++)if(pl[packets]==-1)break;
1476
1477 for(i=0;i<packets;i++){
1478 /* construct a test packet */
1479 ogg_packet op;
1480 int len=pl[i];
1481
1482 op.packet=data+inptr;
1483 op.bytes=len;
1484 op.e_o_s=(pl[i+1]<0?1:0);
1485 op.granulepos=granule_pos;
1486
1487 granule_pos+=1024;
1488
1489 for(j=0;j<len;j++)data[inptr++]=i+j;
1490
1491 /* submit the test packet */
1492 ogg_stream_packetin(&os_en,&op);
1493
1494 /* retrieve any finished pages */
1495 {
1496 ogg_page og;
1497
1498 while(ogg_stream_pageout(&os_en,&og)){
1499 /* We have a page. Check it carefully */
1500
1501 fprintf(stderr,"%ld, ",pageno);
1502
1503 if(headers[pageno]==NULL){
1504 fprintf(stderr,"coded too many pages!\n");
1505 exit(1);
1506 }
1507
1508 check_page(data+outptr,headers[pageno],&og);
1509
1510 outptr+=og.body_len;
1511 pageno++;
1512 if(pageskip){
1513 bosflag=1;
1514 pageskip--;
1515 deptr+=og.body_len;
1516 }
1517
1518 /* have a complete page; submit it to sync/decode */
1519
1520 {
1521 ogg_page og_de;
1522 ogg_packet op_de,op_de2;
1523 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1524 char *next=buf;
1525 byteskipcount+=og.header_len;
1526 if(byteskipcount>byteskip){
1527 memcpy(next,og.header,byteskipcount-byteskip);
1528 next+=byteskipcount-byteskip;
1529 byteskipcount=byteskip;
1530 }
1531
1532 byteskipcount+=og.body_len;
1533 if(byteskipcount>byteskip){
1534 memcpy(next,og.body,byteskipcount-byteskip);
1535 next+=byteskipcount-byteskip;
1536 byteskipcount=byteskip;
1537 }
1538
1539 ogg_sync_wrote(&oy,next-buf);
1540
1541 while(1){
1542 int ret=ogg_sync_pageout(&oy,&og_de);
1543 if(ret==0)break;
1544 if(ret<0)continue;
1545 /* got a page. Happy happy. Verify that it's good. */
1546
1547 fprintf(stderr,"(%ld), ",pageout);
1548
1549 check_page(data+deptr,headers[pageout],&og_de);
1550 deptr+=og_de.body_len;
1551 pageout++;
1552
1553 /* submit it to deconstitution */
1554 ogg_stream_pagein(&os_de,&og_de);
1555
1556 /* packets out? */
1557 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1558 ogg_stream_packetpeek(&os_de,NULL);
1559 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1560
1561 /* verify peek and out match */
1562 if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1563 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1564 depacket);
1565 exit(1);
1566 }
1567
1568 /* verify the packet! */
1569 /* check data */
1570 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1571 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1572 depacket);
1573 exit(1);
1574 }
1575 /* check bos flag */
1576 if(bosflag==0 && op_de.b_o_s==0){
1577 fprintf(stderr,"b_o_s flag not set on packet!\n");
1578 exit(1);
1579 }
1580 if(bosflag && op_de.b_o_s){
1581 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1582 exit(1);
1583 }
1584 bosflag=1;
1585 depacket+=op_de.bytes;
1586
1587 /* check eos flag */
1588 if(eosflag){
1589 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1590 exit(1);
1591 }
1592
1593 if(op_de.e_o_s)eosflag=1;
1594
1595 /* check granulepos flag */
1596 if(op_de.granulepos!=-1){
1597 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1598 }
1599 }
1600 }
1601 }
1602 }
1603 }
1604 }
1605 _ogg_free(data);
1606 if(headers[pageno]!=NULL){
1607 fprintf(stderr,"did not write last page!\n");
1608 exit(1);
1609 }
1610 if(headers[pageout]!=NULL){
1611 fprintf(stderr,"did not decode last page!\n");
1612 exit(1);
1613 }
1614 if(inptr!=outptr){
1615 fprintf(stderr,"encoded page data incomplete!\n");
1616 exit(1);
1617 }
1618 if(inptr!=deptr){
1619 fprintf(stderr,"decoded page data incomplete!\n");
1620 exit(1);
1621 }
1622 if(inptr!=depacket){
1623 fprintf(stderr,"decoded packet data incomplete!\n");
1624 exit(1);
1625 }
1626 if(!eosflag){
1627 fprintf(stderr,"Never got a packet with EOS set!\n");
1628 exit(1);
1629 }
1630 fprintf(stderr,"ok.\n");
1631 }
1632
main(void)1633 int main(void){
1634
1635 ogg_stream_init(&os_en,0x04030201);
1636 ogg_stream_init(&os_de,0x04030201);
1637 ogg_sync_init(&oy);
1638
1639 /* Exercise each code path in the framing code. Also verify that
1640 the checksums are working. */
1641
1642 {
1643 /* 17 only */
1644 const int packets[]={17, -1};
1645 const int *headret[]={head1_0,NULL};
1646
1647 fprintf(stderr,"testing single page encoding... ");
1648 test_pack(packets,headret,0,0,0);
1649 }
1650
1651 {
1652 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1653 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1654 const int *headret[]={head1_1,head2_1,NULL};
1655
1656 fprintf(stderr,"testing basic page encoding... ");
1657 test_pack(packets,headret,0,0,0);
1658 }
1659
1660 {
1661 /* nil packets; beginning,middle,end */
1662 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1663 const int *headret[]={head1_2,head2_2,NULL};
1664
1665 fprintf(stderr,"testing basic nil packets... ");
1666 test_pack(packets,headret,0,0,0);
1667 }
1668
1669 {
1670 /* large initial packet */
1671 const int packets[]={4345,259,255,-1};
1672 const int *headret[]={head1_3,head2_3,NULL};
1673
1674 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1675 test_pack(packets,headret,0,0,0);
1676 }
1677
1678 {
1679 /* continuing packet test; with page spill expansion, we have to
1680 overflow the lacing table. */
1681 const int packets[]={0,65500,259,255,-1};
1682 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1683
1684 fprintf(stderr,"testing single packet page span... ");
1685 test_pack(packets,headret,0,0,0);
1686 }
1687
1688 {
1689 /* spill expand packet test */
1690 const int packets[]={0,4345,259,255,0,0,-1};
1691 const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1692
1693 fprintf(stderr,"testing page spill expansion... ");
1694 test_pack(packets,headret,0,0,0);
1695 }
1696
1697 /* page with the 255 segment limit */
1698 {
1699
1700 const int packets[]={0,10,10,10,10,10,10,10,10,
1701 10,10,10,10,10,10,10,10,
1702 10,10,10,10,10,10,10,10,
1703 10,10,10,10,10,10,10,10,
1704 10,10,10,10,10,10,10,10,
1705 10,10,10,10,10,10,10,10,
1706 10,10,10,10,10,10,10,10,
1707 10,10,10,10,10,10,10,10,
1708 10,10,10,10,10,10,10,10,
1709 10,10,10,10,10,10,10,10,
1710 10,10,10,10,10,10,10,10,
1711 10,10,10,10,10,10,10,10,
1712 10,10,10,10,10,10,10,10,
1713 10,10,10,10,10,10,10,10,
1714 10,10,10,10,10,10,10,10,
1715 10,10,10,10,10,10,10,10,
1716 10,10,10,10,10,10,10,10,
1717 10,10,10,10,10,10,10,10,
1718 10,10,10,10,10,10,10,10,
1719 10,10,10,10,10,10,10,10,
1720 10,10,10,10,10,10,10,10,
1721 10,10,10,10,10,10,10,10,
1722 10,10,10,10,10,10,10,10,
1723 10,10,10,10,10,10,10,10,
1724 10,10,10,10,10,10,10,10,
1725 10,10,10,10,10,10,10,10,
1726 10,10,10,10,10,10,10,10,
1727 10,10,10,10,10,10,10,10,
1728 10,10,10,10,10,10,10,10,
1729 10,10,10,10,10,10,10,10,
1730 10,10,10,10,10,10,10,10,
1731 10,10,10,10,10,10,10,50,-1};
1732 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1733
1734 fprintf(stderr,"testing max packet segments... ");
1735 test_pack(packets,headret,0,0,0);
1736 }
1737
1738 {
1739 /* packet that overspans over an entire page */
1740 const int packets[]={0,100,130049,259,255,-1};
1741 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1742
1743 fprintf(stderr,"testing very large packets... ");
1744 test_pack(packets,headret,0,0,0);
1745 }
1746
1747 {
1748 /* test for the libogg 1.1.1 resync in large continuation bug
1749 found by Josh Coalson) */
1750 const int packets[]={0,100,130049,259,255,-1};
1751 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1752
1753 fprintf(stderr,"testing continuation resync in very large packets... ");
1754 test_pack(packets,headret,100,2,3);
1755 }
1756
1757 {
1758 /* term only page. why not? */
1759 const int packets[]={0,100,64770,-1};
1760 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1761
1762 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1763 test_pack(packets,headret,0,0,0);
1764 }
1765
1766
1767
1768 {
1769 /* build a bunch of pages for testing */
1770 unsigned char *data=_ogg_malloc(1024*1024);
1771 int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1772 int inptr=0,i,j;
1773 ogg_page og[5];
1774
1775 ogg_stream_reset(&os_en);
1776
1777 for(i=0;pl[i]!=-1;i++){
1778 ogg_packet op;
1779 int len=pl[i];
1780
1781 op.packet=data+inptr;
1782 op.bytes=len;
1783 op.e_o_s=(pl[i+1]<0?1:0);
1784 op.granulepos=(i+1)*1000;
1785
1786 for(j=0;j<len;j++)data[inptr++]=i+j;
1787 ogg_stream_packetin(&os_en,&op);
1788 }
1789
1790 _ogg_free(data);
1791
1792 /* retrieve finished pages */
1793 for(i=0;i<5;i++){
1794 if(ogg_stream_pageout(&os_en,&og[i])==0){
1795 fprintf(stderr,"Too few pages output building sync tests!\n");
1796 exit(1);
1797 }
1798 copy_page(&og[i]);
1799 }
1800
1801 /* Test lost pages on pagein/packetout: no rollback */
1802 {
1803 ogg_page temp;
1804 ogg_packet test;
1805
1806 fprintf(stderr,"Testing loss of pages... ");
1807
1808 ogg_sync_reset(&oy);
1809 ogg_stream_reset(&os_de);
1810 for(i=0;i<5;i++){
1811 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1812 og[i].header_len);
1813 ogg_sync_wrote(&oy,og[i].header_len);
1814 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1815 ogg_sync_wrote(&oy,og[i].body_len);
1816 }
1817
1818 ogg_sync_pageout(&oy,&temp);
1819 ogg_stream_pagein(&os_de,&temp);
1820 ogg_sync_pageout(&oy,&temp);
1821 ogg_stream_pagein(&os_de,&temp);
1822 ogg_sync_pageout(&oy,&temp);
1823 /* skip */
1824 ogg_sync_pageout(&oy,&temp);
1825 ogg_stream_pagein(&os_de,&temp);
1826
1827 /* do we get the expected results/packets? */
1828
1829 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1830 checkpacket(&test,0,0,0);
1831 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1832 checkpacket(&test,1,1,-1);
1833 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1834 checkpacket(&test,1,2,-1);
1835 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1836 checkpacket(&test,98,3,-1);
1837 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1838 checkpacket(&test,4079,4,5000);
1839 if(ogg_stream_packetout(&os_de,&test)!=-1){
1840 fprintf(stderr,"Error: loss of page did not return error\n");
1841 exit(1);
1842 }
1843 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1844 checkpacket(&test,76,9,-1);
1845 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1846 checkpacket(&test,34,10,-1);
1847 fprintf(stderr,"ok.\n");
1848 }
1849
1850 /* Test lost pages on pagein/packetout: rollback with continuation */
1851 {
1852 ogg_page temp;
1853 ogg_packet test;
1854
1855 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1856
1857 ogg_sync_reset(&oy);
1858 ogg_stream_reset(&os_de);
1859 for(i=0;i<5;i++){
1860 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1861 og[i].header_len);
1862 ogg_sync_wrote(&oy,og[i].header_len);
1863 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1864 ogg_sync_wrote(&oy,og[i].body_len);
1865 }
1866
1867 ogg_sync_pageout(&oy,&temp);
1868 ogg_stream_pagein(&os_de,&temp);
1869 ogg_sync_pageout(&oy,&temp);
1870 ogg_stream_pagein(&os_de,&temp);
1871 ogg_sync_pageout(&oy,&temp);
1872 ogg_stream_pagein(&os_de,&temp);
1873 ogg_sync_pageout(&oy,&temp);
1874 /* skip */
1875 ogg_sync_pageout(&oy,&temp);
1876 ogg_stream_pagein(&os_de,&temp);
1877
1878 /* do we get the expected results/packets? */
1879
1880 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1881 checkpacket(&test,0,0,0);
1882 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1883 checkpacket(&test,1,1,-1);
1884 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1885 checkpacket(&test,1,2,-1);
1886 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1887 checkpacket(&test,98,3,-1);
1888 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1889 checkpacket(&test,4079,4,5000);
1890 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1891 checkpacket(&test,1,5,-1);
1892 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1893 checkpacket(&test,1,6,-1);
1894 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1895 checkpacket(&test,2954,7,-1);
1896 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1897 checkpacket(&test,2057,8,9000);
1898 if(ogg_stream_packetout(&os_de,&test)!=-1){
1899 fprintf(stderr,"Error: loss of page did not return error\n");
1900 exit(1);
1901 }
1902 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1903 checkpacket(&test,300,17,18000);
1904 fprintf(stderr,"ok.\n");
1905 }
1906
1907 /* the rest only test sync */
1908 {
1909 ogg_page og_de;
1910 /* Test fractional page inputs: incomplete capture */
1911 fprintf(stderr,"Testing sync on partial inputs... ");
1912 ogg_sync_reset(&oy);
1913 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1914 3);
1915 ogg_sync_wrote(&oy,3);
1916 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1917
1918 /* Test fractional page inputs: incomplete fixed header */
1919 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1920 20);
1921 ogg_sync_wrote(&oy,20);
1922 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1923
1924 /* Test fractional page inputs: incomplete header */
1925 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1926 5);
1927 ogg_sync_wrote(&oy,5);
1928 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1929
1930 /* Test fractional page inputs: incomplete body */
1931
1932 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1933 og[1].header_len-28);
1934 ogg_sync_wrote(&oy,og[1].header_len-28);
1935 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1936
1937 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1938 ogg_sync_wrote(&oy,1000);
1939 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1940
1941 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1942 og[1].body_len-1000);
1943 ogg_sync_wrote(&oy,og[1].body_len-1000);
1944 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1945
1946 fprintf(stderr,"ok.\n");
1947 }
1948
1949 /* Test fractional page inputs: page + incomplete capture */
1950 {
1951 ogg_page og_de;
1952 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1953 ogg_sync_reset(&oy);
1954
1955 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1956 og[1].header_len);
1957 ogg_sync_wrote(&oy,og[1].header_len);
1958
1959 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1960 og[1].body_len);
1961 ogg_sync_wrote(&oy,og[1].body_len);
1962
1963 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1964 20);
1965 ogg_sync_wrote(&oy,20);
1966 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1967 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1968
1969 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1970 og[1].header_len-20);
1971 ogg_sync_wrote(&oy,og[1].header_len-20);
1972 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1973 og[1].body_len);
1974 ogg_sync_wrote(&oy,og[1].body_len);
1975 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1976
1977 fprintf(stderr,"ok.\n");
1978 }
1979
1980 /* Test recapture: garbage + page */
1981 {
1982 ogg_page og_de;
1983 fprintf(stderr,"Testing search for capture... ");
1984 ogg_sync_reset(&oy);
1985
1986 /* 'garbage' */
1987 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1988 og[1].body_len);
1989 ogg_sync_wrote(&oy,og[1].body_len);
1990
1991 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1992 og[1].header_len);
1993 ogg_sync_wrote(&oy,og[1].header_len);
1994
1995 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1996 og[1].body_len);
1997 ogg_sync_wrote(&oy,og[1].body_len);
1998
1999 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2000 20);
2001 ogg_sync_wrote(&oy,20);
2002 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2003 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2004 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2005
2006 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2007 og[2].header_len-20);
2008 ogg_sync_wrote(&oy,og[2].header_len-20);
2009 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2010 og[2].body_len);
2011 ogg_sync_wrote(&oy,og[2].body_len);
2012 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2013
2014 fprintf(stderr,"ok.\n");
2015 }
2016
2017 /* Test recapture: page + garbage + page */
2018 {
2019 ogg_page og_de;
2020 fprintf(stderr,"Testing recapture... ");
2021 ogg_sync_reset(&oy);
2022
2023 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2024 og[1].header_len);
2025 ogg_sync_wrote(&oy,og[1].header_len);
2026
2027 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2028 og[1].body_len);
2029 ogg_sync_wrote(&oy,og[1].body_len);
2030
2031 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2032 og[2].header_len);
2033 ogg_sync_wrote(&oy,og[2].header_len);
2034
2035 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2036 og[2].header_len);
2037 ogg_sync_wrote(&oy,og[2].header_len);
2038
2039 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2040
2041 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2042 og[2].body_len-5);
2043 ogg_sync_wrote(&oy,og[2].body_len-5);
2044
2045 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2046 og[3].header_len);
2047 ogg_sync_wrote(&oy,og[3].header_len);
2048
2049 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2050 og[3].body_len);
2051 ogg_sync_wrote(&oy,og[3].body_len);
2052
2053 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2054 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2055
2056 fprintf(stderr,"ok.\n");
2057 }
2058
2059 /* Free page data that was previously copied */
2060 {
2061 for(i=0;i<5;i++){
2062 free_page(&og[i]);
2063 }
2064 }
2065 }
2066
2067 return(0);
2068 }
2069
2070 #endif
2071
2072
2073
2074
2075