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