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 17592 2010-11-01 20:27: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 simultaneously 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,int nfill)372 static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
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>nfill && 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,4096);
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,4096));
534 }
535
536 /* Like the above, but an argument is provided to adjust the nominal
537 page size for applications which are smart enough to provide their
538 own delay based flushing */
539
ogg_stream_pageout_fill(ogg_stream_state * os,ogg_page * og,int nfill)540 int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
541 int force=0;
542 if(ogg_stream_check(os)) return 0;
543
544 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
545 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
546 force=1;
547
548 return(ogg_stream_flush_i(os,og,force,nfill));
549 }
550
ogg_stream_eos(ogg_stream_state * os)551 int ogg_stream_eos(ogg_stream_state *os){
552 if(ogg_stream_check(os)) return 1;
553 return os->e_o_s;
554 }
555
556 /* DECODING PRIMITIVES: packet streaming layer **********************/
557
558 /* This has two layers to place more of the multi-serialno and paging
559 control in the application's hands. First, we expose a data buffer
560 using ogg_sync_buffer(). The app either copies into the
561 buffer, or passes it directly to read(), etc. We then call
562 ogg_sync_wrote() to tell how many bytes we just added.
563
564 Pages are returned (pointers into the buffer in ogg_sync_state)
565 by ogg_sync_pageout(). The page is then submitted to
566 ogg_stream_pagein() along with the appropriate
567 ogg_stream_state* (ie, matching serialno). We then get raw
568 packets out calling ogg_stream_packetout() with a
569 ogg_stream_state. */
570
571 /* initialize the struct to a known state */
ogg_sync_init(ogg_sync_state * oy)572 int ogg_sync_init(ogg_sync_state *oy){
573 if(oy){
574 oy->storage = -1; /* used as a readiness flag */
575 memset(oy,0,sizeof(*oy));
576 }
577 return(0);
578 }
579
580 /* clear non-flat storage within */
ogg_sync_clear(ogg_sync_state * oy)581 int ogg_sync_clear(ogg_sync_state *oy){
582 if(oy){
583 if(oy->data)_ogg_free(oy->data);
584 memset(oy,0,sizeof(*oy));
585 }
586 return(0);
587 }
588
ogg_sync_destroy(ogg_sync_state * oy)589 int ogg_sync_destroy(ogg_sync_state *oy){
590 if(oy){
591 ogg_sync_clear(oy);
592 _ogg_free(oy);
593 }
594 return(0);
595 }
596
ogg_sync_check(ogg_sync_state * oy)597 int ogg_sync_check(ogg_sync_state *oy){
598 if(oy->storage<0) return -1;
599 return 0;
600 }
601
ogg_sync_buffer(ogg_sync_state * oy,long size)602 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
603 if(ogg_sync_check(oy)) return NULL;
604
605 /* first, clear out any space that has been previously returned */
606 if(oy->returned){
607 oy->fill-=oy->returned;
608 if(oy->fill>0)
609 memmove(oy->data,oy->data+oy->returned,oy->fill);
610 oy->returned=0;
611 }
612
613 if(size>oy->storage-oy->fill){
614 /* We need to extend the internal buffer */
615 long newsize=size+oy->fill+4096; /* an extra page to be nice */
616 void *ret;
617
618 if(oy->data)
619 ret=_ogg_realloc(oy->data,newsize);
620 else
621 ret=_ogg_malloc(newsize);
622 if(!ret){
623 ogg_sync_clear(oy);
624 return NULL;
625 }
626 oy->data=ret;
627 oy->storage=newsize;
628 }
629
630 /* expose a segment at least as large as requested at the fill mark */
631 return((char *)oy->data+oy->fill);
632 }
633
ogg_sync_wrote(ogg_sync_state * oy,long bytes)634 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
635 if(ogg_sync_check(oy))return -1;
636 if(oy->fill+bytes>oy->storage)return -1;
637 oy->fill+=bytes;
638 return(0);
639 }
640
641 /* sync the stream. This is meant to be useful for finding page
642 boundaries.
643
644 return values for this:
645 -n) skipped n bytes
646 0) page not ready; more data (no bytes skipped)
647 n) page synced at current location; page length n bytes
648
649 */
650
ogg_sync_pageseek(ogg_sync_state * oy,ogg_page * og)651 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
652 unsigned char *page=oy->data+oy->returned;
653 unsigned char *next;
654 long bytes=oy->fill-oy->returned;
655
656 if(ogg_sync_check(oy))return 0;
657
658 if(oy->headerbytes==0){
659 int headerbytes,i;
660 if(bytes<27)return(0); /* not enough for a header */
661
662 /* verify capture pattern */
663 if(memcmp(page,"OggS",4))goto sync_fail;
664
665 headerbytes=page[26]+27;
666 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
667
668 /* count up body length in the segment table */
669
670 for(i=0;i<page[26];i++)
671 oy->bodybytes+=page[27+i];
672 oy->headerbytes=headerbytes;
673 }
674
675 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
676
677 /* The whole test page is buffered. Verify the checksum */
678 {
679 /* Grab the checksum bytes, set the header field to zero */
680 char chksum[4];
681 ogg_page log;
682
683 memcpy(chksum,page+22,4);
684 memset(page+22,0,4);
685
686 /* set up a temp page struct and recompute the checksum */
687 log.header=page;
688 log.header_len=oy->headerbytes;
689 log.body=page+oy->headerbytes;
690 log.body_len=oy->bodybytes;
691 ogg_page_checksum_set(&log);
692
693 /* Compare */
694 if(memcmp(chksum,page+22,4)){
695 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
696 at all) */
697 /* replace the computed checksum with the one actually read in */
698 memcpy(page+22,chksum,4);
699
700 /* Bad checksum. Lose sync */
701 goto sync_fail;
702 }
703 }
704
705 /* yes, have a whole page all ready to go */
706 {
707 unsigned char *page=oy->data+oy->returned;
708 long bytes;
709
710 if(og){
711 og->header=page;
712 og->header_len=oy->headerbytes;
713 og->body=page+oy->headerbytes;
714 og->body_len=oy->bodybytes;
715 }
716
717 oy->unsynced=0;
718 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
719 oy->headerbytes=0;
720 oy->bodybytes=0;
721 return(bytes);
722 }
723
724 sync_fail:
725
726 oy->headerbytes=0;
727 oy->bodybytes=0;
728
729 /* search for possible capture */
730 next=memchr(page+1,'O',bytes-1);
731 if(!next)
732 next=oy->data+oy->fill;
733
734 oy->returned=(int)(next-oy->data);
735 return((long)-(next-page));
736 }
737
738 /* sync the stream and get a page. Keep trying until we find a page.
739 Suppress 'sync errors' after reporting the first.
740
741 return values:
742 -1) recapture (hole in data)
743 0) need more data
744 1) page returned
745
746 Returns pointers into buffered data; invalidated by next call to
747 _stream, _clear, _init, or _buffer */
748
ogg_sync_pageout(ogg_sync_state * oy,ogg_page * og)749 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
750
751 if(ogg_sync_check(oy))return 0;
752
753 /* all we need to do is verify a page at the head of the stream
754 buffer. If it doesn't verify, we look for the next potential
755 frame */
756
757 for(;;){
758 long ret=ogg_sync_pageseek(oy,og);
759 if(ret>0){
760 /* have a page */
761 return(1);
762 }
763 if(ret==0){
764 /* need more data */
765 return(0);
766 }
767
768 /* head did not start a synced page... skipped some bytes */
769 if(!oy->unsynced){
770 oy->unsynced=1;
771 return(-1);
772 }
773
774 /* loop. keep looking */
775
776 }
777 }
778
779 /* add the incoming page to the stream state; we decompose the page
780 into packet segments here as well. */
781
ogg_stream_pagein(ogg_stream_state * os,ogg_page * og)782 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
783 unsigned char *header=og->header;
784 unsigned char *body=og->body;
785 long bodysize=og->body_len;
786 int segptr=0;
787
788 int version=ogg_page_version(og);
789 int continued=ogg_page_continued(og);
790 int bos=ogg_page_bos(og);
791 int eos=ogg_page_eos(og);
792 ogg_int64_t granulepos=ogg_page_granulepos(og);
793 int serialno=ogg_page_serialno(og);
794 long pageno=ogg_page_pageno(og);
795 int segments=header[26];
796
797 if(ogg_stream_check(os)) return -1;
798
799 /* clean up 'returned data' */
800 {
801 long lr=os->lacing_returned;
802 long br=os->body_returned;
803
804 /* body data */
805 if(br){
806 os->body_fill-=br;
807 if(os->body_fill)
808 memmove(os->body_data,os->body_data+br,os->body_fill);
809 os->body_returned=0;
810 }
811
812 if(lr){
813 /* segment table */
814 if(os->lacing_fill-lr){
815 memmove(os->lacing_vals,os->lacing_vals+lr,
816 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
817 memmove(os->granule_vals,os->granule_vals+lr,
818 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
819 }
820 os->lacing_fill-=lr;
821 os->lacing_packet-=lr;
822 os->lacing_returned=0;
823 }
824 }
825
826 /* check the serial number */
827 if(serialno!=os->serialno)return(-1);
828 if(version>0)return(-1);
829
830 if(_os_lacing_expand(os,segments+1)) return -1;
831
832 /* are we in sequence? */
833 if(pageno!=os->pageno){
834 int i;
835
836 /* unroll previous partial packet (if any) */
837 for(i=os->lacing_packet;i<os->lacing_fill;i++)
838 os->body_fill-=os->lacing_vals[i]&0xff;
839 os->lacing_fill=os->lacing_packet;
840
841 /* make a note of dropped data in segment table */
842 if(os->pageno!=-1){
843 os->lacing_vals[os->lacing_fill++]=0x400;
844 os->lacing_packet++;
845 }
846 }
847
848 /* are we a 'continued packet' page? If so, we may need to skip
849 some segments */
850 if(continued){
851 if(os->lacing_fill<1 ||
852 os->lacing_vals[os->lacing_fill-1]==0x400){
853 bos=0;
854 for(;segptr<segments;segptr++){
855 int val=header[27+segptr];
856 body+=val;
857 bodysize-=val;
858 if(val<255){
859 segptr++;
860 break;
861 }
862 }
863 }
864 }
865
866 if(bodysize){
867 if(_os_body_expand(os,bodysize)) return -1;
868 memcpy(os->body_data+os->body_fill,body,bodysize);
869 os->body_fill+=bodysize;
870 }
871
872 {
873 int saved=-1;
874 while(segptr<segments){
875 int val=header[27+segptr];
876 os->lacing_vals[os->lacing_fill]=val;
877 os->granule_vals[os->lacing_fill]=-1;
878
879 if(bos){
880 os->lacing_vals[os->lacing_fill]|=0x100;
881 bos=0;
882 }
883
884 if(val<255)saved=os->lacing_fill;
885
886 os->lacing_fill++;
887 segptr++;
888
889 if(val<255)os->lacing_packet=os->lacing_fill;
890 }
891
892 /* set the granulepos on the last granuleval of the last full packet */
893 if(saved!=-1){
894 os->granule_vals[saved]=granulepos;
895 }
896
897 }
898
899 if(eos){
900 os->e_o_s=1;
901 if(os->lacing_fill>0)
902 os->lacing_vals[os->lacing_fill-1]|=0x200;
903 }
904
905 os->pageno=pageno+1;
906
907 return(0);
908 }
909
910 /* clear things to an initial state. Good to call, eg, before seeking */
ogg_sync_reset(ogg_sync_state * oy)911 int ogg_sync_reset(ogg_sync_state *oy){
912 if(ogg_sync_check(oy))return -1;
913
914 oy->fill=0;
915 oy->returned=0;
916 oy->unsynced=0;
917 oy->headerbytes=0;
918 oy->bodybytes=0;
919 return(0);
920 }
921
ogg_stream_reset(ogg_stream_state * os)922 int ogg_stream_reset(ogg_stream_state *os){
923 if(ogg_stream_check(os)) return -1;
924
925 os->body_fill=0;
926 os->body_returned=0;
927
928 os->lacing_fill=0;
929 os->lacing_packet=0;
930 os->lacing_returned=0;
931
932 os->header_fill=0;
933
934 os->e_o_s=0;
935 os->b_o_s=0;
936 os->pageno=-1;
937 os->packetno=0;
938 os->granulepos=0;
939
940 return(0);
941 }
942
ogg_stream_reset_serialno(ogg_stream_state * os,int serialno)943 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
944 if(ogg_stream_check(os)) return -1;
945 ogg_stream_reset(os);
946 os->serialno=serialno;
947 return(0);
948 }
949
_packetout(ogg_stream_state * os,ogg_packet * op,int adv)950 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
951
952 /* The last part of decode. We have the stream broken into packet
953 segments. Now we need to group them into packets (or return the
954 out of sync markers) */
955
956 int ptr=os->lacing_returned;
957
958 if(os->lacing_packet<=ptr)return(0);
959
960 if(os->lacing_vals[ptr]&0x400){
961 /* we need to tell the codec there's a gap; it might need to
962 handle previous packet dependencies. */
963 os->lacing_returned++;
964 os->packetno++;
965 return(-1);
966 }
967
968 if(!op && !adv)return(1); /* just using peek as an inexpensive way
969 to ask if there's a whole packet
970 waiting */
971
972 /* Gather the whole packet. We'll have no holes or a partial packet */
973 {
974 int size=os->lacing_vals[ptr]&0xff;
975 long bytes=size;
976 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
977 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
978
979 while(size==255){
980 int val=os->lacing_vals[++ptr];
981 size=val&0xff;
982 if(val&0x200)eos=0x200;
983 bytes+=size;
984 }
985
986 if(op){
987 op->e_o_s=eos;
988 op->b_o_s=bos;
989 op->packet=os->body_data+os->body_returned;
990 op->packetno=os->packetno;
991 op->granulepos=os->granule_vals[ptr];
992 op->bytes=bytes;
993 }
994
995 if(adv){
996 os->body_returned+=bytes;
997 os->lacing_returned=ptr+1;
998 os->packetno++;
999 }
1000 }
1001 return(1);
1002 }
1003
ogg_stream_packetout(ogg_stream_state * os,ogg_packet * op)1004 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
1005 if(ogg_stream_check(os)) return 0;
1006 return _packetout(os,op,1);
1007 }
1008
ogg_stream_packetpeek(ogg_stream_state * os,ogg_packet * op)1009 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
1010 if(ogg_stream_check(os)) return 0;
1011 return _packetout(os,op,0);
1012 }
1013
ogg_packet_clear(ogg_packet * op)1014 void ogg_packet_clear(ogg_packet *op) {
1015 _ogg_free(op->packet);
1016 memset(op, 0, sizeof(*op));
1017 }
1018
1019 #ifdef _V_SELFTEST
1020 #include <stdio.h>
1021
1022 ogg_stream_state os_en, os_de;
1023 ogg_sync_state oy;
1024
checkpacket(ogg_packet * op,long len,int no,long pos)1025 void checkpacket(ogg_packet *op,long len, int no, long pos){
1026 long j;
1027 static int sequence=0;
1028 static int lastno=0;
1029
1030 if(op->bytes!=len){
1031 fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
1032 exit(1);
1033 }
1034 if(op->granulepos!=pos){
1035 fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1036 exit(1);
1037 }
1038
1039 /* packet number just follows sequence/gap; adjust the input number
1040 for that */
1041 if(no==0){
1042 sequence=0;
1043 }else{
1044 sequence++;
1045 if(no>lastno+1)
1046 sequence++;
1047 }
1048 lastno=no;
1049 if(op->packetno!=sequence){
1050 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1051 (long)(op->packetno),sequence);
1052 exit(1);
1053 }
1054
1055 /* Test data */
1056 for(j=0;j<op->bytes;j++)
1057 if(op->packet[j]!=((j+no)&0xff)){
1058 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1059 j,op->packet[j],(j+no)&0xff);
1060 exit(1);
1061 }
1062 }
1063
check_page(unsigned char * data,const int * header,ogg_page * og)1064 void check_page(unsigned char *data,const int *header,ogg_page *og){
1065 long j;
1066 /* Test data */
1067 for(j=0;j<og->body_len;j++)
1068 if(og->body[j]!=data[j]){
1069 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1070 j,data[j],og->body[j]);
1071 exit(1);
1072 }
1073
1074 /* Test header */
1075 for(j=0;j<og->header_len;j++){
1076 if(og->header[j]!=header[j]){
1077 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1078 for(j=0;j<header[26]+27;j++)
1079 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1080 fprintf(stderr,"\n");
1081 exit(1);
1082 }
1083 }
1084 if(og->header_len!=header[26]+27){
1085 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1086 og->header_len,header[26]+27);
1087 exit(1);
1088 }
1089 }
1090
print_header(ogg_page * og)1091 void print_header(ogg_page *og){
1092 int j;
1093 fprintf(stderr,"\nHEADER:\n");
1094 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
1095 og->header[0],og->header[1],og->header[2],og->header[3],
1096 (int)og->header[4],(int)og->header[5]);
1097
1098 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
1099 (og->header[9]<<24)|(og->header[8]<<16)|
1100 (og->header[7]<<8)|og->header[6],
1101 (og->header[17]<<24)|(og->header[16]<<16)|
1102 (og->header[15]<<8)|og->header[14],
1103 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1104 (og->header[19]<<8)|og->header[18]);
1105
1106 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
1107 (int)og->header[22],(int)og->header[23],
1108 (int)og->header[24],(int)og->header[25],
1109 (int)og->header[26]);
1110
1111 for(j=27;j<og->header_len;j++)
1112 fprintf(stderr,"%d ",(int)og->header[j]);
1113 fprintf(stderr,")\n\n");
1114 }
1115
copy_page(ogg_page * og)1116 void copy_page(ogg_page *og){
1117 unsigned char *temp=_ogg_malloc(og->header_len);
1118 memcpy(temp,og->header,og->header_len);
1119 og->header=temp;
1120
1121 temp=_ogg_malloc(og->body_len);
1122 memcpy(temp,og->body,og->body_len);
1123 og->body=temp;
1124 }
1125
free_page(ogg_page * og)1126 void free_page(ogg_page *og){
1127 _ogg_free (og->header);
1128 _ogg_free (og->body);
1129 }
1130
error(void)1131 void error(void){
1132 fprintf(stderr,"error!\n");
1133 exit(1);
1134 }
1135
1136 /* 17 only */
1137 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1138 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1139 0x01,0x02,0x03,0x04,0,0,0,0,
1140 0x15,0xed,0xec,0x91,
1141 1,
1142 17};
1143
1144 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1145 const int head1_1[] = {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 0x59,0x10,0x6c,0x2c,
1149 1,
1150 17};
1151 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1152 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1153 0x01,0x02,0x03,0x04,1,0,0,0,
1154 0x89,0x33,0x85,0xce,
1155 13,
1156 254,255,0,255,1,255,245,255,255,0,
1157 255,255,90};
1158
1159 /* nil packets; beginning,middle,end */
1160 const int head1_2[] = {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 0xff,0x7b,0x23,0x17,
1164 1,
1165 0};
1166 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1167 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1168 0x01,0x02,0x03,0x04,1,0,0,0,
1169 0x5c,0x3f,0x66,0xcb,
1170 17,
1171 17,254,255,0,0,255,1,0,255,245,255,255,0,
1172 255,255,90,0};
1173
1174 /* large initial packet */
1175 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1176 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1177 0x01,0x02,0x03,0x04,0,0,0,0,
1178 0x01,0x27,0x31,0xaa,
1179 18,
1180 255,255,255,255,255,255,255,255,
1181 255,255,255,255,255,255,255,255,255,10};
1182
1183 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1184 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1185 0x01,0x02,0x03,0x04,1,0,0,0,
1186 0x7f,0x4e,0x8a,0xd2,
1187 4,
1188 255,4,255,0};
1189
1190
1191 /* continuing packet test */
1192 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1193 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1194 0x01,0x02,0x03,0x04,0,0,0,0,
1195 0xff,0x7b,0x23,0x17,
1196 1,
1197 0};
1198
1199 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1200 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1201 0x01,0x02,0x03,0x04,1,0,0,0,
1202 0xf8,0x3c,0x19,0x79,
1203 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,255,
1221 255,255,255,255,255,255,255,255,
1222 255,255,255,255,255,255,255,255,
1223 255,255,255,255,255,255,255,255,
1224 255,255,255,255,255,255,255,255,
1225 255,255,255,255,255,255,255,255,
1226 255,255,255,255,255,255,255,255,
1227 255,255,255,255,255,255,255,255,
1228 255,255,255,255,255,255,255,255,
1229 255,255,255,255,255,255,255,255,
1230 255,255,255,255,255,255,255,255,
1231 255,255,255,255,255,255,255,255,
1232 255,255,255,255,255,255,255,255,
1233 255,255,255,255,255,255,255,255,
1234 255,255,255,255,255,255,255,255,
1235 255,255,255,255,255,255,255};
1236
1237 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1238 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1239 0x01,0x02,0x03,0x04,2,0,0,0,
1240 0x38,0xe6,0xb6,0x28,
1241 6,
1242 255,220,255,4,255,0};
1243
1244
1245 /* spill expansion test */
1246 const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1247 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1248 0x01,0x02,0x03,0x04,0,0,0,0,
1249 0xff,0x7b,0x23,0x17,
1250 1,
1251 0};
1252
1253 const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1254 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1255 0x01,0x02,0x03,0x04,1,0,0,0,
1256 0xce,0x8f,0x17,0x1a,
1257 23,
1258 255,255,255,255,255,255,255,255,
1259 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1260
1261
1262 const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1263 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1264 0x01,0x02,0x03,0x04,2,0,0,0,
1265 0x9b,0xb2,0x50,0xa1,
1266 1,
1267 0};
1268
1269 /* page with the 255 segment limit */
1270 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1271 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1272 0x01,0x02,0x03,0x04,0,0,0,0,
1273 0xff,0x7b,0x23,0x17,
1274 1,
1275 0};
1276
1277 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1278 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1279 0x01,0x02,0x03,0x04,1,0,0,0,
1280 0xed,0x2a,0x2e,0xa7,
1281 255,
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,10,
1299 10,10,10,10,10,10,10,10,
1300 10,10,10,10,10,10,10,10,
1301 10,10,10,10,10,10,10,10,
1302 10,10,10,10,10,10,10,10,
1303 10,10,10,10,10,10,10,10,
1304 10,10,10,10,10,10,10,10,
1305 10,10,10,10,10,10,10,10,
1306 10,10,10,10,10,10,10,10,
1307 10,10,10,10,10,10,10,10,
1308 10,10,10,10,10,10,10,10,
1309 10,10,10,10,10,10,10,10,
1310 10,10,10,10,10,10,10,10,
1311 10,10,10,10,10,10,10,10,
1312 10,10,10,10,10,10,10,10,
1313 10,10,10,10,10,10,10};
1314
1315 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1316 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1317 0x01,0x02,0x03,0x04,2,0,0,0,
1318 0x6c,0x3b,0x82,0x3d,
1319 1,
1320 50};
1321
1322
1323 /* packet that overspans over an entire page */
1324 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1325 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1326 0x01,0x02,0x03,0x04,0,0,0,0,
1327 0xff,0x7b,0x23,0x17,
1328 1,
1329 0};
1330
1331 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1332 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1333 0x01,0x02,0x03,0x04,1,0,0,0,
1334 0x68,0x22,0x7c,0x3d,
1335 255,
1336 100,
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,255,255,
1354 255,255,255,255,255,255,255,255,
1355 255,255,255,255,255,255,255,255,
1356 255,255,255,255,255,255,255,255,
1357 255,255,255,255,255,255,255,255,
1358 255,255,255,255,255,255,255,255,
1359 255,255,255,255,255,255,255,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};
1369
1370 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1371 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1372 0x01,0x02,0x03,0x04,2,0,0,0,
1373 0xf4,0x87,0xba,0xf3,
1374 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,255,
1392 255,255,255,255,255,255,255,255,
1393 255,255,255,255,255,255,255,255,
1394 255,255,255,255,255,255,255,255,
1395 255,255,255,255,255,255,255,255,
1396 255,255,255,255,255,255,255,255,
1397 255,255,255,255,255,255,255,255,
1398 255,255,255,255,255,255,255,255,
1399 255,255,255,255,255,255,255,255,
1400 255,255,255,255,255,255,255,255,
1401 255,255,255,255,255,255,255,255,
1402 255,255,255,255,255,255,255,255,
1403 255,255,255,255,255,255,255,255,
1404 255,255,255,255,255,255,255,255,
1405 255,255,255,255,255,255,255,255,
1406 255,255,255,255,255,255,255};
1407
1408 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1409 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1410 0x01,0x02,0x03,0x04,3,0,0,0,
1411 0xf7,0x2f,0x6c,0x60,
1412 5,
1413 254,255,4,255,0};
1414
1415 /* packet that overspans over an entire page */
1416 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1417 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1418 0x01,0x02,0x03,0x04,0,0,0,0,
1419 0xff,0x7b,0x23,0x17,
1420 1,
1421 0};
1422
1423 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1424 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1425 0x01,0x02,0x03,0x04,1,0,0,0,
1426 0x68,0x22,0x7c,0x3d,
1427 255,
1428 100,
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,255,255,
1446 255,255,255,255,255,255,255,255,
1447 255,255,255,255,255,255,255,255,
1448 255,255,255,255,255,255,255,255,
1449 255,255,255,255,255,255,255,255,
1450 255,255,255,255,255,255,255,255,
1451 255,255,255,255,255,255,255,255,
1452 255,255,255,255,255,255,255,255,
1453 255,255,255,255,255,255,255,255,
1454 255,255,255,255,255,255,255,255,
1455 255,255,255,255,255,255,255,255,
1456 255,255,255,255,255,255,255,255,
1457 255,255,255,255,255,255,255,255,
1458 255,255,255,255,255,255,255,255,
1459 255,255,255,255,255,255,255,255,
1460 255,255,255,255,255,255};
1461
1462 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1463 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1464 0x01,0x02,0x03,0x04,2,0,0,0,
1465 0xd4,0xe0,0x60,0xe5,
1466 1,
1467 0};
1468
test_pack(const int * pl,const int ** headers,int byteskip,int pageskip,int packetskip)1469 void test_pack(const int *pl, const int **headers, int byteskip,
1470 int pageskip, int packetskip){
1471 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1472 long inptr=0;
1473 long outptr=0;
1474 long deptr=0;
1475 long depacket=0;
1476 long granule_pos=7,pageno=0;
1477 int i,j,packets,pageout=pageskip;
1478 int eosflag=0;
1479 int bosflag=0;
1480
1481 int byteskipcount=0;
1482
1483 ogg_stream_reset(&os_en);
1484 ogg_stream_reset(&os_de);
1485 ogg_sync_reset(&oy);
1486
1487 for(packets=0;packets<packetskip;packets++)
1488 depacket+=pl[packets];
1489
1490 for(packets=0;;packets++)if(pl[packets]==-1)break;
1491
1492 for(i=0;i<packets;i++){
1493 /* construct a test packet */
1494 ogg_packet op;
1495 int len=pl[i];
1496
1497 op.packet=data+inptr;
1498 op.bytes=len;
1499 op.e_o_s=(pl[i+1]<0?1:0);
1500 op.granulepos=granule_pos;
1501
1502 granule_pos+=1024;
1503
1504 for(j=0;j<len;j++)data[inptr++]=i+j;
1505
1506 /* submit the test packet */
1507 ogg_stream_packetin(&os_en,&op);
1508
1509 /* retrieve any finished pages */
1510 {
1511 ogg_page og;
1512
1513 while(ogg_stream_pageout(&os_en,&og)){
1514 /* We have a page. Check it carefully */
1515
1516 fprintf(stderr,"%ld, ",pageno);
1517
1518 if(headers[pageno]==NULL){
1519 fprintf(stderr,"coded too many pages!\n");
1520 exit(1);
1521 }
1522
1523 check_page(data+outptr,headers[pageno],&og);
1524
1525 outptr+=og.body_len;
1526 pageno++;
1527 if(pageskip){
1528 bosflag=1;
1529 pageskip--;
1530 deptr+=og.body_len;
1531 }
1532
1533 /* have a complete page; submit it to sync/decode */
1534
1535 {
1536 ogg_page og_de;
1537 ogg_packet op_de,op_de2;
1538 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1539 char *next=buf;
1540 byteskipcount+=og.header_len;
1541 if(byteskipcount>byteskip){
1542 memcpy(next,og.header,byteskipcount-byteskip);
1543 next+=byteskipcount-byteskip;
1544 byteskipcount=byteskip;
1545 }
1546
1547 byteskipcount+=og.body_len;
1548 if(byteskipcount>byteskip){
1549 memcpy(next,og.body,byteskipcount-byteskip);
1550 next+=byteskipcount-byteskip;
1551 byteskipcount=byteskip;
1552 }
1553
1554 ogg_sync_wrote(&oy,next-buf);
1555
1556 while(1){
1557 int ret=ogg_sync_pageout(&oy,&og_de);
1558 if(ret==0)break;
1559 if(ret<0)continue;
1560 /* got a page. Happy happy. Verify that it's good. */
1561
1562 fprintf(stderr,"(%d), ",pageout);
1563
1564 check_page(data+deptr,headers[pageout],&og_de);
1565 deptr+=og_de.body_len;
1566 pageout++;
1567
1568 /* submit it to deconstitution */
1569 ogg_stream_pagein(&os_de,&og_de);
1570
1571 /* packets out? */
1572 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1573 ogg_stream_packetpeek(&os_de,NULL);
1574 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1575
1576 /* verify peek and out match */
1577 if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1578 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1579 depacket);
1580 exit(1);
1581 }
1582
1583 /* verify the packet! */
1584 /* check data */
1585 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1586 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1587 depacket);
1588 exit(1);
1589 }
1590 /* check bos flag */
1591 if(bosflag==0 && op_de.b_o_s==0){
1592 fprintf(stderr,"b_o_s flag not set on packet!\n");
1593 exit(1);
1594 }
1595 if(bosflag && op_de.b_o_s){
1596 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1597 exit(1);
1598 }
1599 bosflag=1;
1600 depacket+=op_de.bytes;
1601
1602 /* check eos flag */
1603 if(eosflag){
1604 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1605 exit(1);
1606 }
1607
1608 if(op_de.e_o_s)eosflag=1;
1609
1610 /* check granulepos flag */
1611 if(op_de.granulepos!=-1){
1612 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1613 }
1614 }
1615 }
1616 }
1617 }
1618 }
1619 }
1620 _ogg_free(data);
1621 if(headers[pageno]!=NULL){
1622 fprintf(stderr,"did not write last page!\n");
1623 exit(1);
1624 }
1625 if(headers[pageout]!=NULL){
1626 fprintf(stderr,"did not decode last page!\n");
1627 exit(1);
1628 }
1629 if(inptr!=outptr){
1630 fprintf(stderr,"encoded page data incomplete!\n");
1631 exit(1);
1632 }
1633 if(inptr!=deptr){
1634 fprintf(stderr,"decoded page data incomplete!\n");
1635 exit(1);
1636 }
1637 if(inptr!=depacket){
1638 fprintf(stderr,"decoded packet data incomplete!\n");
1639 exit(1);
1640 }
1641 if(!eosflag){
1642 fprintf(stderr,"Never got a packet with EOS set!\n");
1643 exit(1);
1644 }
1645 fprintf(stderr,"ok.\n");
1646 }
1647
main(void)1648 int main(void){
1649
1650 ogg_stream_init(&os_en,0x04030201);
1651 ogg_stream_init(&os_de,0x04030201);
1652 ogg_sync_init(&oy);
1653
1654 /* Exercise each code path in the framing code. Also verify that
1655 the checksums are working. */
1656
1657 {
1658 /* 17 only */
1659 const int packets[]={17, -1};
1660 const int *headret[]={head1_0,NULL};
1661
1662 fprintf(stderr,"testing single page encoding... ");
1663 test_pack(packets,headret,0,0,0);
1664 }
1665
1666 {
1667 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1668 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1669 const int *headret[]={head1_1,head2_1,NULL};
1670
1671 fprintf(stderr,"testing basic page encoding... ");
1672 test_pack(packets,headret,0,0,0);
1673 }
1674
1675 {
1676 /* nil packets; beginning,middle,end */
1677 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1678 const int *headret[]={head1_2,head2_2,NULL};
1679
1680 fprintf(stderr,"testing basic nil packets... ");
1681 test_pack(packets,headret,0,0,0);
1682 }
1683
1684 {
1685 /* large initial packet */
1686 const int packets[]={4345,259,255,-1};
1687 const int *headret[]={head1_3,head2_3,NULL};
1688
1689 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1690 test_pack(packets,headret,0,0,0);
1691 }
1692
1693 {
1694 /* continuing packet test; with page spill expansion, we have to
1695 overflow the lacing table. */
1696 const int packets[]={0,65500,259,255,-1};
1697 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1698
1699 fprintf(stderr,"testing single packet page span... ");
1700 test_pack(packets,headret,0,0,0);
1701 }
1702
1703 {
1704 /* spill expand packet test */
1705 const int packets[]={0,4345,259,255,0,0,-1};
1706 const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1707
1708 fprintf(stderr,"testing page spill expansion... ");
1709 test_pack(packets,headret,0,0,0);
1710 }
1711
1712 /* page with the 255 segment limit */
1713 {
1714
1715 const int packets[]={0,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,10,
1732 10,10,10,10,10,10,10,10,
1733 10,10,10,10,10,10,10,10,
1734 10,10,10,10,10,10,10,10,
1735 10,10,10,10,10,10,10,10,
1736 10,10,10,10,10,10,10,10,
1737 10,10,10,10,10,10,10,10,
1738 10,10,10,10,10,10,10,10,
1739 10,10,10,10,10,10,10,10,
1740 10,10,10,10,10,10,10,10,
1741 10,10,10,10,10,10,10,10,
1742 10,10,10,10,10,10,10,10,
1743 10,10,10,10,10,10,10,10,
1744 10,10,10,10,10,10,10,10,
1745 10,10,10,10,10,10,10,10,
1746 10,10,10,10,10,10,10,50,-1};
1747 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1748
1749 fprintf(stderr,"testing max packet segments... ");
1750 test_pack(packets,headret,0,0,0);
1751 }
1752
1753 {
1754 /* packet that overspans over an entire page */
1755 const int packets[]={0,100,130049,259,255,-1};
1756 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1757
1758 fprintf(stderr,"testing very large packets... ");
1759 test_pack(packets,headret,0,0,0);
1760 }
1761
1762 {
1763 /* test for the libogg 1.1.1 resync in large continuation bug
1764 found by Josh Coalson) */
1765 const int packets[]={0,100,130049,259,255,-1};
1766 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1767
1768 fprintf(stderr,"testing continuation resync in very large packets... ");
1769 test_pack(packets,headret,100,2,3);
1770 }
1771
1772 {
1773 /* term only page. why not? */
1774 const int packets[]={0,100,64770,-1};
1775 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1776
1777 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1778 test_pack(packets,headret,0,0,0);
1779 }
1780
1781
1782
1783 {
1784 /* build a bunch of pages for testing */
1785 unsigned char *data=_ogg_malloc(1024*1024);
1786 int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1787 int inptr=0,i,j;
1788 ogg_page og[5];
1789
1790 ogg_stream_reset(&os_en);
1791
1792 for(i=0;pl[i]!=-1;i++){
1793 ogg_packet op;
1794 int len=pl[i];
1795
1796 op.packet=data+inptr;
1797 op.bytes=len;
1798 op.e_o_s=(pl[i+1]<0?1:0);
1799 op.granulepos=(i+1)*1000;
1800
1801 for(j=0;j<len;j++)data[inptr++]=i+j;
1802 ogg_stream_packetin(&os_en,&op);
1803 }
1804
1805 _ogg_free(data);
1806
1807 /* retrieve finished pages */
1808 for(i=0;i<5;i++){
1809 if(ogg_stream_pageout(&os_en,&og[i])==0){
1810 fprintf(stderr,"Too few pages output building sync tests!\n");
1811 exit(1);
1812 }
1813 copy_page(&og[i]);
1814 }
1815
1816 /* Test lost pages on pagein/packetout: no rollback */
1817 {
1818 ogg_page temp;
1819 ogg_packet test;
1820
1821 fprintf(stderr,"Testing loss of pages... ");
1822
1823 ogg_sync_reset(&oy);
1824 ogg_stream_reset(&os_de);
1825 for(i=0;i<5;i++){
1826 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1827 og[i].header_len);
1828 ogg_sync_wrote(&oy,og[i].header_len);
1829 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1830 ogg_sync_wrote(&oy,og[i].body_len);
1831 }
1832
1833 ogg_sync_pageout(&oy,&temp);
1834 ogg_stream_pagein(&os_de,&temp);
1835 ogg_sync_pageout(&oy,&temp);
1836 ogg_stream_pagein(&os_de,&temp);
1837 ogg_sync_pageout(&oy,&temp);
1838 /* skip */
1839 ogg_sync_pageout(&oy,&temp);
1840 ogg_stream_pagein(&os_de,&temp);
1841
1842 /* do we get the expected results/packets? */
1843
1844 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1845 checkpacket(&test,0,0,0);
1846 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1847 checkpacket(&test,1,1,-1);
1848 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1849 checkpacket(&test,1,2,-1);
1850 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1851 checkpacket(&test,98,3,-1);
1852 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1853 checkpacket(&test,4079,4,5000);
1854 if(ogg_stream_packetout(&os_de,&test)!=-1){
1855 fprintf(stderr,"Error: loss of page did not return error\n");
1856 exit(1);
1857 }
1858 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1859 checkpacket(&test,76,9,-1);
1860 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1861 checkpacket(&test,34,10,-1);
1862 fprintf(stderr,"ok.\n");
1863 }
1864
1865 /* Test lost pages on pagein/packetout: rollback with continuation */
1866 {
1867 ogg_page temp;
1868 ogg_packet test;
1869
1870 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1871
1872 ogg_sync_reset(&oy);
1873 ogg_stream_reset(&os_de);
1874 for(i=0;i<5;i++){
1875 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1876 og[i].header_len);
1877 ogg_sync_wrote(&oy,og[i].header_len);
1878 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1879 ogg_sync_wrote(&oy,og[i].body_len);
1880 }
1881
1882 ogg_sync_pageout(&oy,&temp);
1883 ogg_stream_pagein(&os_de,&temp);
1884 ogg_sync_pageout(&oy,&temp);
1885 ogg_stream_pagein(&os_de,&temp);
1886 ogg_sync_pageout(&oy,&temp);
1887 ogg_stream_pagein(&os_de,&temp);
1888 ogg_sync_pageout(&oy,&temp);
1889 /* skip */
1890 ogg_sync_pageout(&oy,&temp);
1891 ogg_stream_pagein(&os_de,&temp);
1892
1893 /* do we get the expected results/packets? */
1894
1895 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1896 checkpacket(&test,0,0,0);
1897 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1898 checkpacket(&test,1,1,-1);
1899 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1900 checkpacket(&test,1,2,-1);
1901 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1902 checkpacket(&test,98,3,-1);
1903 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1904 checkpacket(&test,4079,4,5000);
1905 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1906 checkpacket(&test,1,5,-1);
1907 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1908 checkpacket(&test,1,6,-1);
1909 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1910 checkpacket(&test,2954,7,-1);
1911 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1912 checkpacket(&test,2057,8,9000);
1913 if(ogg_stream_packetout(&os_de,&test)!=-1){
1914 fprintf(stderr,"Error: loss of page did not return error\n");
1915 exit(1);
1916 }
1917 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1918 checkpacket(&test,300,17,18000);
1919 fprintf(stderr,"ok.\n");
1920 }
1921
1922 /* the rest only test sync */
1923 {
1924 ogg_page og_de;
1925 /* Test fractional page inputs: incomplete capture */
1926 fprintf(stderr,"Testing sync on partial inputs... ");
1927 ogg_sync_reset(&oy);
1928 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1929 3);
1930 ogg_sync_wrote(&oy,3);
1931 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1932
1933 /* Test fractional page inputs: incomplete fixed header */
1934 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1935 20);
1936 ogg_sync_wrote(&oy,20);
1937 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1938
1939 /* Test fractional page inputs: incomplete header */
1940 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1941 5);
1942 ogg_sync_wrote(&oy,5);
1943 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1944
1945 /* Test fractional page inputs: incomplete body */
1946
1947 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1948 og[1].header_len-28);
1949 ogg_sync_wrote(&oy,og[1].header_len-28);
1950 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1951
1952 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1953 ogg_sync_wrote(&oy,1000);
1954 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1955
1956 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1957 og[1].body_len-1000);
1958 ogg_sync_wrote(&oy,og[1].body_len-1000);
1959 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1960
1961 fprintf(stderr,"ok.\n");
1962 }
1963
1964 /* Test fractional page inputs: page + incomplete capture */
1965 {
1966 ogg_page og_de;
1967 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1968 ogg_sync_reset(&oy);
1969
1970 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1971 og[1].header_len);
1972 ogg_sync_wrote(&oy,og[1].header_len);
1973
1974 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1975 og[1].body_len);
1976 ogg_sync_wrote(&oy,og[1].body_len);
1977
1978 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1979 20);
1980 ogg_sync_wrote(&oy,20);
1981 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1982 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1983
1984 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1985 og[1].header_len-20);
1986 ogg_sync_wrote(&oy,og[1].header_len-20);
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 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1991
1992 fprintf(stderr,"ok.\n");
1993 }
1994
1995 /* Test recapture: garbage + page */
1996 {
1997 ogg_page og_de;
1998 fprintf(stderr,"Testing search for capture... ");
1999 ogg_sync_reset(&oy);
2000
2001 /* 'garbage' */
2002 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2003 og[1].body_len);
2004 ogg_sync_wrote(&oy,og[1].body_len);
2005
2006 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2007 og[1].header_len);
2008 ogg_sync_wrote(&oy,og[1].header_len);
2009
2010 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2011 og[1].body_len);
2012 ogg_sync_wrote(&oy,og[1].body_len);
2013
2014 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2015 20);
2016 ogg_sync_wrote(&oy,20);
2017 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2018 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2019 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2020
2021 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2022 og[2].header_len-20);
2023 ogg_sync_wrote(&oy,og[2].header_len-20);
2024 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2025 og[2].body_len);
2026 ogg_sync_wrote(&oy,og[2].body_len);
2027 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2028
2029 fprintf(stderr,"ok.\n");
2030 }
2031
2032 /* Test recapture: page + garbage + page */
2033 {
2034 ogg_page og_de;
2035 fprintf(stderr,"Testing recapture... ");
2036 ogg_sync_reset(&oy);
2037
2038 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2039 og[1].header_len);
2040 ogg_sync_wrote(&oy,og[1].header_len);
2041
2042 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2043 og[1].body_len);
2044 ogg_sync_wrote(&oy,og[1].body_len);
2045
2046 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2047 og[2].header_len);
2048 ogg_sync_wrote(&oy,og[2].header_len);
2049
2050 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2051 og[2].header_len);
2052 ogg_sync_wrote(&oy,og[2].header_len);
2053
2054 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2055
2056 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2057 og[2].body_len-5);
2058 ogg_sync_wrote(&oy,og[2].body_len-5);
2059
2060 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2061 og[3].header_len);
2062 ogg_sync_wrote(&oy,og[3].header_len);
2063
2064 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2065 og[3].body_len);
2066 ogg_sync_wrote(&oy,og[3].body_len);
2067
2068 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2069 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2070
2071 fprintf(stderr,"ok.\n");
2072 }
2073
2074 /* Free page data that was previously copied */
2075 {
2076 for(i=0;i<5;i++){
2077 free_page(&og[i]);
2078 }
2079 }
2080 }
2081
2082 return(0);
2083 }
2084
2085 #endif
2086
2087
2088
2089
2090