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 ogg_uint32_t crc_reg=0;
296 int i;
297
298 /* safety; needed for API behavior, but not framing code */
299 og->header[22]=0;
300 og->header[23]=0;
301 og->header[24]=0;
302 og->header[25]=0;
303
304 for(i=0;i<og->header_len;i++)
305 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
306 for(i=0;i<og->body_len;i++)
307 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
308
309 og->header[22]=(unsigned char)(crc_reg&0xff);
310 og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
311 og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
312 og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
313 }
314 }
315
316 /* 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)317 int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
318 long e_o_s, ogg_int64_t granulepos){
319
320 long bytes = 0, lacing_vals;
321 int i;
322
323 if(ogg_stream_check(os)) return -1;
324 if(!iov) return 0;
325
326 for (i = 0; i < count; ++i){
327 if(iov[i].iov_len>LONG_MAX) return -1;
328 if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1;
329 bytes += (long)iov[i].iov_len;
330 }
331 lacing_vals=bytes/255+1;
332
333 if(os->body_returned){
334 /* advance packet data according to the body_returned pointer. We
335 had to keep it around to return a pointer into the buffer last
336 call */
337
338 os->body_fill-=os->body_returned;
339 if(os->body_fill)
340 memmove(os->body_data,os->body_data+os->body_returned,
341 os->body_fill);
342 os->body_returned=0;
343 }
344
345 /* make sure we have the buffer storage */
346 if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
347 return -1;
348
349 /* Copy in the submitted packet. Yes, the copy is a waste; this is
350 the liability of overly clean abstraction for the time being. It
351 will actually be fairly easy to eliminate the extra copy in the
352 future */
353
354 for (i = 0; i < count; ++i) {
355 memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
356 os->body_fill += (int)iov[i].iov_len;
357 }
358
359 /* Store lacing vals for this packet */
360 for(i=0;i<lacing_vals-1;i++){
361 os->lacing_vals[os->lacing_fill+i]=255;
362 os->granule_vals[os->lacing_fill+i]=os->granulepos;
363 }
364 os->lacing_vals[os->lacing_fill+i]=bytes%255;
365 os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
366
367 /* flag the first segment as the beginning of the packet */
368 os->lacing_vals[os->lacing_fill]|= 0x100;
369
370 os->lacing_fill+=lacing_vals;
371
372 /* for the sake of completeness */
373 os->packetno++;
374
375 if(e_o_s)os->e_o_s=1;
376
377 return(0);
378 }
379
ogg_stream_packetin(ogg_stream_state * os,ogg_packet * op)380 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
381 ogg_iovec_t iov;
382 iov.iov_base = op->packet;
383 iov.iov_len = op->bytes;
384 return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
385 }
386
387 /* Conditionally flush a page; force==0 will only flush nominal-size
388 pages, force==1 forces us to flush a page regardless of page size
389 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)390 static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
391 int i;
392 int vals=0;
393 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
394 int bytes=0;
395 long acc=0;
396 ogg_int64_t granule_pos=-1;
397
398 if(ogg_stream_check(os)) return(0);
399 if(maxvals==0) return(0);
400
401 /* construct a page */
402 /* decide how many segments to include */
403
404 /* If this is the initial header case, the first page must only include
405 the initial header packet */
406 if(os->b_o_s==0){ /* 'initial header page' case */
407 granule_pos=0;
408 for(vals=0;vals<maxvals;vals++){
409 if((os->lacing_vals[vals]&0x0ff)<255){
410 vals++;
411 break;
412 }
413 }
414 }else{
415
416 /* The extra packets_done, packet_just_done logic here attempts to do two things:
417 1) Don't unneccessarily span pages.
418 2) Unless necessary, don't flush pages if there are less than four packets on
419 them; this expands page size to reduce unneccessary overhead if incoming packets
420 are large.
421 These are not necessary behaviors, just 'always better than naive flushing'
422 without requiring an application to explicitly request a specific optimized
423 behavior. We'll want an explicit behavior setup pathway eventually as well. */
424
425 int packets_done=0;
426 int packet_just_done=0;
427 for(vals=0;vals<maxvals;vals++){
428 if(acc>nfill && packet_just_done>=4){
429 force=1;
430 break;
431 }
432 acc+=os->lacing_vals[vals]&0x0ff;
433 if((os->lacing_vals[vals]&0xff)<255){
434 granule_pos=os->granule_vals[vals];
435 packet_just_done=++packets_done;
436 }else
437 packet_just_done=0;
438 }
439 if(vals==255)force=1;
440 }
441
442 if(!force) return(0);
443
444 /* construct the header in temp storage */
445 memcpy(os->header,"OggS",4);
446
447 /* stream structure version */
448 os->header[4]=0x00;
449
450 /* continued packet flag? */
451 os->header[5]=0x00;
452 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
453 /* first page flag? */
454 if(os->b_o_s==0)os->header[5]|=0x02;
455 /* last page flag? */
456 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
457 os->b_o_s=1;
458
459 /* 64 bits of PCM position */
460 for(i=6;i<14;i++){
461 os->header[i]=(unsigned char)(granule_pos&0xff);
462 granule_pos>>=8;
463 }
464
465 /* 32 bits of stream serial number */
466 {
467 long serialno=os->serialno;
468 for(i=14;i<18;i++){
469 os->header[i]=(unsigned char)(serialno&0xff);
470 serialno>>=8;
471 }
472 }
473
474 /* 32 bits of page counter (we have both counter and page header
475 because this val can roll over) */
476 if(os->pageno==-1)os->pageno=0; /* because someone called
477 stream_reset; this would be a
478 strange thing to do in an
479 encode stream, but it has
480 plausible uses */
481 {
482 long pageno=os->pageno++;
483 for(i=18;i<22;i++){
484 os->header[i]=(unsigned char)(pageno&0xff);
485 pageno>>=8;
486 }
487 }
488
489 /* zero for computation; filled in later */
490 os->header[22]=0;
491 os->header[23]=0;
492 os->header[24]=0;
493 os->header[25]=0;
494
495 /* segment table */
496 os->header[26]=(unsigned char)(vals&0xff);
497 for(i=0;i<vals;i++)
498 bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
499
500 /* set pointers in the ogg_page struct */
501 og->header=os->header;
502 og->header_len=os->header_fill=vals+27;
503 og->body=os->body_data+os->body_returned;
504 og->body_len=bytes;
505
506 /* advance the lacing data and set the body_returned pointer */
507
508 os->lacing_fill-=vals;
509 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
510 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
511 os->body_returned+=bytes;
512
513 /* calculate the checksum */
514
515 ogg_page_checksum_set(og);
516
517 /* done */
518 return(1);
519 }
520
521 /* This will flush remaining packets into a page (returning nonzero),
522 even if there is not enough data to trigger a flush normally
523 (undersized page). If there are no packets or partial packets to
524 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
525 try to flush a normal sized page like ogg_stream_pageout; a call to
526 ogg_stream_flush does not guarantee that all packets have flushed.
527 Only a return value of 0 from ogg_stream_flush indicates all packet
528 data is flushed into pages.
529
530 since ogg_stream_flush will flush the last page in a stream even if
531 it's undersized, you almost certainly want to use ogg_stream_pageout
532 (and *not* ogg_stream_flush) unless you specifically need to flush
533 a page regardless of size in the middle of a stream. */
534
ogg_stream_flush(ogg_stream_state * os,ogg_page * og)535 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
536 return ogg_stream_flush_i(os,og,1,4096);
537 }
538
539 /* Like the above, but an argument is provided to adjust the nominal
540 page size for applications which are smart enough to provide their
541 own delay based flushing */
542
ogg_stream_flush_fill(ogg_stream_state * os,ogg_page * og,int nfill)543 int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
544 return ogg_stream_flush_i(os,og,1,nfill);
545 }
546
547 /* This constructs pages from buffered packet segments. The pointers
548 returned are to static buffers; do not free. The returned buffers are
549 good only until the next call (using the same ogg_stream_state) */
550
ogg_stream_pageout(ogg_stream_state * os,ogg_page * og)551 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
552 int force=0;
553 if(ogg_stream_check(os)) return 0;
554
555 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
556 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
557 force=1;
558
559 return(ogg_stream_flush_i(os,og,force,4096));
560 }
561
562 /* Like the above, but an argument is provided to adjust the nominal
563 page size for applications which are smart enough to provide their
564 own delay based flushing */
565
ogg_stream_pageout_fill(ogg_stream_state * os,ogg_page * og,int nfill)566 int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
567 int force=0;
568 if(ogg_stream_check(os)) return 0;
569
570 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
571 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
572 force=1;
573
574 return(ogg_stream_flush_i(os,og,force,nfill));
575 }
576
ogg_stream_eos(ogg_stream_state * os)577 int ogg_stream_eos(ogg_stream_state *os){
578 if(ogg_stream_check(os)) return 1;
579 return os->e_o_s;
580 }
581
582 /* DECODING PRIMITIVES: packet streaming layer **********************/
583
584 /* This has two layers to place more of the multi-serialno and paging
585 control in the application's hands. First, we expose a data buffer
586 using ogg_sync_buffer(). The app either copies into the
587 buffer, or passes it directly to read(), etc. We then call
588 ogg_sync_wrote() to tell how many bytes we just added.
589
590 Pages are returned (pointers into the buffer in ogg_sync_state)
591 by ogg_sync_pageout(). The page is then submitted to
592 ogg_stream_pagein() along with the appropriate
593 ogg_stream_state* (ie, matching serialno). We then get raw
594 packets out calling ogg_stream_packetout() with a
595 ogg_stream_state. */
596
597 /* initialize the struct to a known state */
ogg_sync_init(ogg_sync_state * oy)598 int ogg_sync_init(ogg_sync_state *oy){
599 if(oy){
600 oy->storage = -1; /* used as a readiness flag */
601 memset(oy,0,sizeof(*oy));
602 }
603 return(0);
604 }
605
606 /* clear non-flat storage within */
ogg_sync_clear(ogg_sync_state * oy)607 int ogg_sync_clear(ogg_sync_state *oy){
608 if(oy){
609 if(oy->data)_ogg_free(oy->data);
610 memset(oy,0,sizeof(*oy));
611 }
612 return(0);
613 }
614
ogg_sync_destroy(ogg_sync_state * oy)615 int ogg_sync_destroy(ogg_sync_state *oy){
616 if(oy){
617 ogg_sync_clear(oy);
618 _ogg_free(oy);
619 }
620 return(0);
621 }
622
ogg_sync_check(ogg_sync_state * oy)623 int ogg_sync_check(ogg_sync_state *oy){
624 if(oy->storage<0) return -1;
625 return 0;
626 }
627
ogg_sync_buffer(ogg_sync_state * oy,long size)628 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
629 if(ogg_sync_check(oy)) return NULL;
630
631 /* first, clear out any space that has been previously returned */
632 if(oy->returned){
633 oy->fill-=oy->returned;
634 if(oy->fill>0)
635 memmove(oy->data,oy->data+oy->returned,oy->fill);
636 oy->returned=0;
637 }
638
639 if(size>oy->storage-oy->fill){
640 /* We need to extend the internal buffer */
641 long newsize=size+oy->fill+4096; /* an extra page to be nice */
642 void *ret;
643
644 if(oy->data)
645 ret=_ogg_realloc(oy->data,newsize);
646 else
647 ret=_ogg_malloc(newsize);
648 if(!ret){
649 ogg_sync_clear(oy);
650 return NULL;
651 }
652 oy->data=ret;
653 oy->storage=newsize;
654 }
655
656 /* expose a segment at least as large as requested at the fill mark */
657 return((char *)oy->data+oy->fill);
658 }
659
ogg_sync_wrote(ogg_sync_state * oy,long bytes)660 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
661 if(ogg_sync_check(oy))return -1;
662 if(oy->fill+bytes>oy->storage)return -1;
663 oy->fill+=bytes;
664 return(0);
665 }
666
667 /* sync the stream. This is meant to be useful for finding page
668 boundaries.
669
670 return values for this:
671 -n) skipped n bytes
672 0) page not ready; more data (no bytes skipped)
673 n) page synced at current location; page length n bytes
674
675 */
676
ogg_sync_pageseek(ogg_sync_state * oy,ogg_page * og)677 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
678 unsigned char *page=oy->data+oy->returned;
679 unsigned char *next;
680 long bytes=oy->fill-oy->returned;
681
682 if(ogg_sync_check(oy))return 0;
683
684 if(oy->headerbytes==0){
685 int headerbytes,i;
686 if(bytes<27)return(0); /* not enough for a header */
687
688 /* verify capture pattern */
689 if(memcmp(page,"OggS",4))goto sync_fail;
690
691 headerbytes=page[26]+27;
692 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
693
694 /* count up body length in the segment table */
695
696 for(i=0;i<page[26];i++)
697 oy->bodybytes+=page[27+i];
698 oy->headerbytes=headerbytes;
699 }
700
701 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
702
703 /* The whole test page is buffered. Verify the checksum */
704 {
705 /* Grab the checksum bytes, set the header field to zero */
706 char chksum[4];
707 ogg_page log;
708
709 memcpy(chksum,page+22,4);
710 memset(page+22,0,4);
711
712 /* set up a temp page struct and recompute the checksum */
713 log.header=page;
714 log.header_len=oy->headerbytes;
715 log.body=page+oy->headerbytes;
716 log.body_len=oy->bodybytes;
717 ogg_page_checksum_set(&log);
718
719 /* Compare */
720 if(memcmp(chksum,page+22,4)){
721 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
722 at all) */
723 /* replace the computed checksum with the one actually read in */
724 memcpy(page+22,chksum,4);
725
726 /* Bad checksum. Lose sync */
727 goto sync_fail;
728 }
729 }
730
731 /* yes, have a whole page all ready to go */
732 {
733 unsigned char *page=oy->data+oy->returned;
734 long bytes;
735
736 if(og){
737 og->header=page;
738 og->header_len=oy->headerbytes;
739 og->body=page+oy->headerbytes;
740 og->body_len=oy->bodybytes;
741 }
742
743 oy->unsynced=0;
744 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
745 oy->headerbytes=0;
746 oy->bodybytes=0;
747 return(bytes);
748 }
749
750 sync_fail:
751
752 oy->headerbytes=0;
753 oy->bodybytes=0;
754
755 /* search for possible capture */
756 next=memchr(page+1,'O',bytes-1);
757 if(!next)
758 next=oy->data+oy->fill;
759
760 oy->returned=(int)(next-oy->data);
761 return((long)-(next-page));
762 }
763
764 /* sync the stream and get a page. Keep trying until we find a page.
765 Suppress 'sync errors' after reporting the first.
766
767 return values:
768 -1) recapture (hole in data)
769 0) need more data
770 1) page returned
771
772 Returns pointers into buffered data; invalidated by next call to
773 _stream, _clear, _init, or _buffer */
774
ogg_sync_pageout(ogg_sync_state * oy,ogg_page * og)775 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
776
777 if(ogg_sync_check(oy))return 0;
778
779 /* all we need to do is verify a page at the head of the stream
780 buffer. If it doesn't verify, we look for the next potential
781 frame */
782
783 for(;;){
784 long ret=ogg_sync_pageseek(oy,og);
785 if(ret>0){
786 /* have a page */
787 return(1);
788 }
789 if(ret==0){
790 /* need more data */
791 return(0);
792 }
793
794 /* head did not start a synced page... skipped some bytes */
795 if(!oy->unsynced){
796 oy->unsynced=1;
797 return(-1);
798 }
799
800 /* loop. keep looking */
801
802 }
803 }
804
805 /* add the incoming page to the stream state; we decompose the page
806 into packet segments here as well. */
807
ogg_stream_pagein(ogg_stream_state * os,ogg_page * og)808 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
809 unsigned char *header=og->header;
810 unsigned char *body=og->body;
811 long bodysize=og->body_len;
812 int segptr=0;
813
814 int version=ogg_page_version(og);
815 int continued=ogg_page_continued(og);
816 int bos=ogg_page_bos(og);
817 int eos=ogg_page_eos(og);
818 ogg_int64_t granulepos=ogg_page_granulepos(og);
819 int serialno=ogg_page_serialno(og);
820 long pageno=ogg_page_pageno(og);
821 int segments=header[26];
822
823 if(ogg_stream_check(os)) return -1;
824
825 /* clean up 'returned data' */
826 {
827 long lr=os->lacing_returned;
828 long br=os->body_returned;
829
830 /* body data */
831 if(br){
832 os->body_fill-=br;
833 if(os->body_fill)
834 memmove(os->body_data,os->body_data+br,os->body_fill);
835 os->body_returned=0;
836 }
837
838 if(lr){
839 /* segment table */
840 if(os->lacing_fill-lr){
841 memmove(os->lacing_vals,os->lacing_vals+lr,
842 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
843 memmove(os->granule_vals,os->granule_vals+lr,
844 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
845 }
846 os->lacing_fill-=lr;
847 os->lacing_packet-=lr;
848 os->lacing_returned=0;
849 }
850 }
851
852 /* check the serial number */
853 if(serialno!=os->serialno)return(-1);
854 if(version>0)return(-1);
855
856 if(_os_lacing_expand(os,segments+1)) return -1;
857
858 /* are we in sequence? */
859 if(pageno!=os->pageno){
860 int i;
861
862 /* unroll previous partial packet (if any) */
863 for(i=os->lacing_packet;i<os->lacing_fill;i++)
864 os->body_fill-=os->lacing_vals[i]&0xff;
865 os->lacing_fill=os->lacing_packet;
866
867 /* make a note of dropped data in segment table */
868 if(os->pageno!=-1){
869 os->lacing_vals[os->lacing_fill++]=0x400;
870 os->lacing_packet++;
871 }
872 }
873
874 /* are we a 'continued packet' page? If so, we may need to skip
875 some segments */
876 if(continued){
877 if(os->lacing_fill<1 ||
878 (os->lacing_vals[os->lacing_fill-1]&0xff)<255 ||
879 os->lacing_vals[os->lacing_fill-1]==0x400){
880 bos=0;
881 for(;segptr<segments;segptr++){
882 int val=header[27+segptr];
883 body+=val;
884 bodysize-=val;
885 if(val<255){
886 segptr++;
887 break;
888 }
889 }
890 }
891 }
892
893 if(bodysize){
894 if(_os_body_expand(os,bodysize)) return -1;
895 memcpy(os->body_data+os->body_fill,body,bodysize);
896 os->body_fill+=bodysize;
897 }
898
899 {
900 int saved=-1;
901 while(segptr<segments){
902 int val=header[27+segptr];
903 os->lacing_vals[os->lacing_fill]=val;
904 os->granule_vals[os->lacing_fill]=-1;
905
906 if(bos){
907 os->lacing_vals[os->lacing_fill]|=0x100;
908 bos=0;
909 }
910
911 if(val<255)saved=os->lacing_fill;
912
913 os->lacing_fill++;
914 segptr++;
915
916 if(val<255)os->lacing_packet=os->lacing_fill;
917 }
918
919 /* set the granulepos on the last granuleval of the last full packet */
920 if(saved!=-1){
921 os->granule_vals[saved]=granulepos;
922 }
923
924 }
925
926 if(eos){
927 os->e_o_s=1;
928 if(os->lacing_fill>0)
929 os->lacing_vals[os->lacing_fill-1]|=0x200;
930 }
931
932 os->pageno=pageno+1;
933
934 return(0);
935 }
936
937 /* clear things to an initial state. Good to call, eg, before seeking */
ogg_sync_reset(ogg_sync_state * oy)938 int ogg_sync_reset(ogg_sync_state *oy){
939 if(ogg_sync_check(oy))return -1;
940
941 oy->fill=0;
942 oy->returned=0;
943 oy->unsynced=0;
944 oy->headerbytes=0;
945 oy->bodybytes=0;
946 return(0);
947 }
948
ogg_stream_reset(ogg_stream_state * os)949 int ogg_stream_reset(ogg_stream_state *os){
950 if(ogg_stream_check(os)) return -1;
951
952 os->body_fill=0;
953 os->body_returned=0;
954
955 os->lacing_fill=0;
956 os->lacing_packet=0;
957 os->lacing_returned=0;
958
959 os->header_fill=0;
960
961 os->e_o_s=0;
962 os->b_o_s=0;
963 os->pageno=-1;
964 os->packetno=0;
965 os->granulepos=0;
966
967 return(0);
968 }
969
ogg_stream_reset_serialno(ogg_stream_state * os,int serialno)970 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
971 if(ogg_stream_check(os)) return -1;
972 ogg_stream_reset(os);
973 os->serialno=serialno;
974 return(0);
975 }
976
_packetout(ogg_stream_state * os,ogg_packet * op,int adv)977 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
978
979 /* The last part of decode. We have the stream broken into packet
980 segments. Now we need to group them into packets (or return the
981 out of sync markers) */
982
983 int ptr=os->lacing_returned;
984
985 if(os->lacing_packet<=ptr)return(0);
986
987 if(os->lacing_vals[ptr]&0x400){
988 /* we need to tell the codec there's a gap; it might need to
989 handle previous packet dependencies. */
990 os->lacing_returned++;
991 os->packetno++;
992 return(-1);
993 }
994
995 if(!op && !adv)return(1); /* just using peek as an inexpensive way
996 to ask if there's a whole packet
997 waiting */
998
999 /* Gather the whole packet. We'll have no holes or a partial packet */
1000 {
1001 int size=os->lacing_vals[ptr]&0xff;
1002 long bytes=size;
1003 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
1004 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
1005
1006 while(size==255){
1007 int val=os->lacing_vals[++ptr];
1008 size=val&0xff;
1009 if(val&0x200)eos=0x200;
1010 bytes+=size;
1011 }
1012
1013 if(op){
1014 op->e_o_s=eos;
1015 op->b_o_s=bos;
1016 op->packet=os->body_data+os->body_returned;
1017 op->packetno=os->packetno;
1018 op->granulepos=os->granule_vals[ptr];
1019 op->bytes=bytes;
1020 }
1021
1022 if(adv){
1023 os->body_returned+=bytes;
1024 os->lacing_returned=ptr+1;
1025 os->packetno++;
1026 }
1027 }
1028 return(1);
1029 }
1030
ogg_stream_packetout(ogg_stream_state * os,ogg_packet * op)1031 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
1032 if(ogg_stream_check(os)) return 0;
1033 return _packetout(os,op,1);
1034 }
1035
ogg_stream_packetpeek(ogg_stream_state * os,ogg_packet * op)1036 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
1037 if(ogg_stream_check(os)) return 0;
1038 return _packetout(os,op,0);
1039 }
1040
ogg_packet_clear(ogg_packet * op)1041 void ogg_packet_clear(ogg_packet *op) {
1042 _ogg_free(op->packet);
1043 memset(op, 0, sizeof(*op));
1044 }
1045
1046 #ifdef _V_SELFTEST
1047 #include <stdio.h>
1048
1049 ogg_stream_state os_en, os_de;
1050 ogg_sync_state oy;
1051
checkpacket(ogg_packet * op,long len,int no,long pos)1052 void checkpacket(ogg_packet *op,long len, int no, long pos){
1053 long j;
1054 static int sequence=0;
1055 static int lastno=0;
1056
1057 if(op->bytes!=len){
1058 fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
1059 exit(1);
1060 }
1061 if(op->granulepos!=pos){
1062 fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1063 exit(1);
1064 }
1065
1066 /* packet number just follows sequence/gap; adjust the input number
1067 for that */
1068 if(no==0){
1069 sequence=0;
1070 }else{
1071 sequence++;
1072 if(no>lastno+1)
1073 sequence++;
1074 }
1075 lastno=no;
1076 if(op->packetno!=sequence){
1077 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1078 (long)(op->packetno),sequence);
1079 exit(1);
1080 }
1081
1082 /* Test data */
1083 for(j=0;j<op->bytes;j++)
1084 if(op->packet[j]!=((j+no)&0xff)){
1085 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1086 j,op->packet[j],(j+no)&0xff);
1087 exit(1);
1088 }
1089 }
1090
check_page(unsigned char * data,const int * header,ogg_page * og)1091 void check_page(unsigned char *data,const int *header,ogg_page *og){
1092 long j;
1093 /* Test data */
1094 for(j=0;j<og->body_len;j++)
1095 if(og->body[j]!=data[j]){
1096 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1097 j,data[j],og->body[j]);
1098 exit(1);
1099 }
1100
1101 /* Test header */
1102 for(j=0;j<og->header_len;j++){
1103 if(og->header[j]!=header[j]){
1104 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1105 for(j=0;j<header[26]+27;j++)
1106 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1107 fprintf(stderr,"\n");
1108 exit(1);
1109 }
1110 }
1111 if(og->header_len!=header[26]+27){
1112 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1113 og->header_len,header[26]+27);
1114 exit(1);
1115 }
1116 }
1117
print_header(ogg_page * og)1118 void print_header(ogg_page *og){
1119 int j;
1120 fprintf(stderr,"\nHEADER:\n");
1121 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
1122 og->header[0],og->header[1],og->header[2],og->header[3],
1123 (int)og->header[4],(int)og->header[5]);
1124
1125 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
1126 (og->header[9]<<24)|(og->header[8]<<16)|
1127 (og->header[7]<<8)|og->header[6],
1128 (og->header[17]<<24)|(og->header[16]<<16)|
1129 (og->header[15]<<8)|og->header[14],
1130 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1131 (og->header[19]<<8)|og->header[18]);
1132
1133 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
1134 (int)og->header[22],(int)og->header[23],
1135 (int)og->header[24],(int)og->header[25],
1136 (int)og->header[26]);
1137
1138 for(j=27;j<og->header_len;j++)
1139 fprintf(stderr,"%d ",(int)og->header[j]);
1140 fprintf(stderr,")\n\n");
1141 }
1142
copy_page(ogg_page * og)1143 void copy_page(ogg_page *og){
1144 unsigned char *temp=_ogg_malloc(og->header_len);
1145 memcpy(temp,og->header,og->header_len);
1146 og->header=temp;
1147
1148 temp=_ogg_malloc(og->body_len);
1149 memcpy(temp,og->body,og->body_len);
1150 og->body=temp;
1151 }
1152
free_page(ogg_page * og)1153 void free_page(ogg_page *og){
1154 _ogg_free (og->header);
1155 _ogg_free (og->body);
1156 }
1157
error(void)1158 void error(void){
1159 fprintf(stderr,"error!\n");
1160 exit(1);
1161 }
1162
1163 /* 17 only */
1164 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1165 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1166 0x01,0x02,0x03,0x04,0,0,0,0,
1167 0x15,0xed,0xec,0x91,
1168 1,
1169 17};
1170
1171 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1172 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1173 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1174 0x01,0x02,0x03,0x04,0,0,0,0,
1175 0x59,0x10,0x6c,0x2c,
1176 1,
1177 17};
1178 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1179 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1180 0x01,0x02,0x03,0x04,1,0,0,0,
1181 0x89,0x33,0x85,0xce,
1182 13,
1183 254,255,0,255,1,255,245,255,255,0,
1184 255,255,90};
1185
1186 /* nil packets; beginning,middle,end */
1187 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1188 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1189 0x01,0x02,0x03,0x04,0,0,0,0,
1190 0xff,0x7b,0x23,0x17,
1191 1,
1192 0};
1193 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1194 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1195 0x01,0x02,0x03,0x04,1,0,0,0,
1196 0x5c,0x3f,0x66,0xcb,
1197 17,
1198 17,254,255,0,0,255,1,0,255,245,255,255,0,
1199 255,255,90,0};
1200
1201 /* large initial packet */
1202 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1203 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1204 0x01,0x02,0x03,0x04,0,0,0,0,
1205 0x01,0x27,0x31,0xaa,
1206 18,
1207 255,255,255,255,255,255,255,255,
1208 255,255,255,255,255,255,255,255,255,10};
1209
1210 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1211 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1212 0x01,0x02,0x03,0x04,1,0,0,0,
1213 0x7f,0x4e,0x8a,0xd2,
1214 4,
1215 255,4,255,0};
1216
1217
1218 /* continuing packet test */
1219 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1220 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1221 0x01,0x02,0x03,0x04,0,0,0,0,
1222 0xff,0x7b,0x23,0x17,
1223 1,
1224 0};
1225
1226 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1227 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1228 0x01,0x02,0x03,0x04,1,0,0,0,
1229 0xf8,0x3c,0x19,0x79,
1230 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,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};
1263
1264 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1265 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1266 0x01,0x02,0x03,0x04,2,0,0,0,
1267 0x38,0xe6,0xb6,0x28,
1268 6,
1269 255,220,255,4,255,0};
1270
1271
1272 /* spill expansion test */
1273 const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1274 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1275 0x01,0x02,0x03,0x04,0,0,0,0,
1276 0xff,0x7b,0x23,0x17,
1277 1,
1278 0};
1279
1280 const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1281 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1282 0x01,0x02,0x03,0x04,1,0,0,0,
1283 0xce,0x8f,0x17,0x1a,
1284 23,
1285 255,255,255,255,255,255,255,255,
1286 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1287
1288
1289 const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1290 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1291 0x01,0x02,0x03,0x04,2,0,0,0,
1292 0x9b,0xb2,0x50,0xa1,
1293 1,
1294 0};
1295
1296 /* page with the 255 segment limit */
1297 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1298 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1299 0x01,0x02,0x03,0x04,0,0,0,0,
1300 0xff,0x7b,0x23,0x17,
1301 1,
1302 0};
1303
1304 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1305 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1306 0x01,0x02,0x03,0x04,1,0,0,0,
1307 0xed,0x2a,0x2e,0xa7,
1308 255,
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,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};
1341
1342 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1343 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1344 0x01,0x02,0x03,0x04,2,0,0,0,
1345 0x6c,0x3b,0x82,0x3d,
1346 1,
1347 50};
1348
1349
1350 /* packet that overspans over an entire page */
1351 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1352 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1353 0x01,0x02,0x03,0x04,0,0,0,0,
1354 0xff,0x7b,0x23,0x17,
1355 1,
1356 0};
1357
1358 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1359 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1360 0x01,0x02,0x03,0x04,1,0,0,0,
1361 0x68,0x22,0x7c,0x3d,
1362 255,
1363 100,
1364 255,255,255,255,255,255,255,255,
1365 255,255,255,255,255,255,255,255,
1366 255,255,255,255,255,255,255,255,
1367 255,255,255,255,255,255,255,255,
1368 255,255,255,255,255,255,255,255,
1369 255,255,255,255,255,255,255,255,
1370 255,255,255,255,255,255,255,255,
1371 255,255,255,255,255,255,255,255,
1372 255,255,255,255,255,255,255,255,
1373 255,255,255,255,255,255,255,255,
1374 255,255,255,255,255,255,255,255,
1375 255,255,255,255,255,255,255,255,
1376 255,255,255,255,255,255,255,255,
1377 255,255,255,255,255,255,255,255,
1378 255,255,255,255,255,255,255,255,
1379 255,255,255,255,255,255,255,255,
1380 255,255,255,255,255,255,255,255,
1381 255,255,255,255,255,255,255,255,
1382 255,255,255,255,255,255,255,255,
1383 255,255,255,255,255,255,255,255,
1384 255,255,255,255,255,255,255,255,
1385 255,255,255,255,255,255,255,255,
1386 255,255,255,255,255,255,255,255,
1387 255,255,255,255,255,255,255,255,
1388 255,255,255,255,255,255,255,255,
1389 255,255,255,255,255,255,255,255,
1390 255,255,255,255,255,255,255,255,
1391 255,255,255,255,255,255,255,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};
1396
1397 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1398 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1399 0x01,0x02,0x03,0x04,2,0,0,0,
1400 0xf4,0x87,0xba,0xf3,
1401 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,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};
1434
1435 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1436 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1437 0x01,0x02,0x03,0x04,3,0,0,0,
1438 0xf7,0x2f,0x6c,0x60,
1439 5,
1440 254,255,4,255,0};
1441
1442 /* packet that overspans over an entire page */
1443 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1444 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1445 0x01,0x02,0x03,0x04,0,0,0,0,
1446 0xff,0x7b,0x23,0x17,
1447 1,
1448 0};
1449
1450 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1451 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1452 0x01,0x02,0x03,0x04,1,0,0,0,
1453 0x68,0x22,0x7c,0x3d,
1454 255,
1455 100,
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,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};
1488
1489 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1490 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1491 0x01,0x02,0x03,0x04,2,0,0,0,
1492 0xd4,0xe0,0x60,0xe5,
1493 1,
1494 0};
1495
compare_packet(const ogg_packet * op1,const ogg_packet * op2)1496 int compare_packet(const ogg_packet *op1, const ogg_packet *op2){
1497 if(op1->packet!=op2->packet){
1498 fprintf(stderr,"op1->packet != op2->packet\n");
1499 return(1);
1500 }
1501 if(op1->bytes!=op2->bytes){
1502 fprintf(stderr,"op1->bytes != op2->bytes\n");
1503 return(1);
1504 }
1505 if(op1->b_o_s!=op2->b_o_s){
1506 fprintf(stderr,"op1->b_o_s != op2->b_o_s\n");
1507 return(1);
1508 }
1509 if(op1->e_o_s!=op2->e_o_s){
1510 fprintf(stderr,"op1->e_o_s != op2->e_o_s\n");
1511 return(1);
1512 }
1513 if(op1->granulepos!=op2->granulepos){
1514 fprintf(stderr,"op1->granulepos != op2->granulepos\n");
1515 return(1);
1516 }
1517 if(op1->packetno!=op2->packetno){
1518 fprintf(stderr,"op1->packetno != op2->packetno\n");
1519 return(1);
1520 }
1521 return(0);
1522 }
1523
test_pack(const int * pl,const int ** headers,int byteskip,int pageskip,int packetskip)1524 void test_pack(const int *pl, const int **headers, int byteskip,
1525 int pageskip, int packetskip){
1526 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1527 long inptr=0;
1528 long outptr=0;
1529 long deptr=0;
1530 long depacket=0;
1531 long granule_pos=7,pageno=0;
1532 int i,j,packets,pageout=pageskip;
1533 int eosflag=0;
1534 int bosflag=0;
1535
1536 int byteskipcount=0;
1537
1538 ogg_stream_reset(&os_en);
1539 ogg_stream_reset(&os_de);
1540 ogg_sync_reset(&oy);
1541
1542 for(packets=0;packets<packetskip;packets++)
1543 depacket+=pl[packets];
1544
1545 for(packets=0;;packets++)if(pl[packets]==-1)break;
1546
1547 for(i=0;i<packets;i++){
1548 /* construct a test packet */
1549 ogg_packet op;
1550 int len=pl[i];
1551
1552 op.packet=data+inptr;
1553 op.bytes=len;
1554 op.e_o_s=(pl[i+1]<0?1:0);
1555 op.granulepos=granule_pos;
1556
1557 granule_pos+=1024;
1558
1559 for(j=0;j<len;j++)data[inptr++]=i+j;
1560
1561 /* submit the test packet */
1562 ogg_stream_packetin(&os_en,&op);
1563
1564 /* retrieve any finished pages */
1565 {
1566 ogg_page og;
1567
1568 while(ogg_stream_pageout(&os_en,&og)){
1569 /* We have a page. Check it carefully */
1570
1571 fprintf(stderr,"%ld, ",pageno);
1572
1573 if(headers[pageno]==NULL){
1574 fprintf(stderr,"coded too many pages!\n");
1575 exit(1);
1576 }
1577
1578 check_page(data+outptr,headers[pageno],&og);
1579
1580 outptr+=og.body_len;
1581 pageno++;
1582 if(pageskip){
1583 bosflag=1;
1584 pageskip--;
1585 deptr+=og.body_len;
1586 }
1587
1588 /* have a complete page; submit it to sync/decode */
1589
1590 {
1591 ogg_page og_de;
1592 ogg_packet op_de,op_de2;
1593 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1594 char *next=buf;
1595 byteskipcount+=og.header_len;
1596 if(byteskipcount>byteskip){
1597 memcpy(next,og.header,byteskipcount-byteskip);
1598 next+=byteskipcount-byteskip;
1599 byteskipcount=byteskip;
1600 }
1601
1602 byteskipcount+=og.body_len;
1603 if(byteskipcount>byteskip){
1604 memcpy(next,og.body,byteskipcount-byteskip);
1605 next+=byteskipcount-byteskip;
1606 byteskipcount=byteskip;
1607 }
1608
1609 ogg_sync_wrote(&oy,next-buf);
1610
1611 while(1){
1612 int ret=ogg_sync_pageout(&oy,&og_de);
1613 if(ret==0)break;
1614 if(ret<0)continue;
1615 /* got a page. Happy happy. Verify that it's good. */
1616
1617 fprintf(stderr,"(%d), ",pageout);
1618
1619 check_page(data+deptr,headers[pageout],&og_de);
1620 deptr+=og_de.body_len;
1621 pageout++;
1622
1623 /* submit it to deconstitution */
1624 ogg_stream_pagein(&os_de,&og_de);
1625
1626 /* packets out? */
1627 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1628 ogg_stream_packetpeek(&os_de,NULL);
1629 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1630
1631 /* verify peek and out match */
1632 if(compare_packet(&op_de,&op_de2)){
1633 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1634 depacket);
1635 exit(1);
1636 }
1637
1638 /* verify the packet! */
1639 /* check data */
1640 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1641 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1642 depacket);
1643 exit(1);
1644 }
1645 /* check bos flag */
1646 if(bosflag==0 && op_de.b_o_s==0){
1647 fprintf(stderr,"b_o_s flag not set on packet!\n");
1648 exit(1);
1649 }
1650 if(bosflag && op_de.b_o_s){
1651 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1652 exit(1);
1653 }
1654 bosflag=1;
1655 depacket+=op_de.bytes;
1656
1657 /* check eos flag */
1658 if(eosflag){
1659 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1660 exit(1);
1661 }
1662
1663 if(op_de.e_o_s)eosflag=1;
1664
1665 /* check granulepos flag */
1666 if(op_de.granulepos!=-1){
1667 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1668 }
1669 }
1670 }
1671 }
1672 }
1673 }
1674 }
1675 _ogg_free(data);
1676 if(headers[pageno]!=NULL){
1677 fprintf(stderr,"did not write last page!\n");
1678 exit(1);
1679 }
1680 if(headers[pageout]!=NULL){
1681 fprintf(stderr,"did not decode last page!\n");
1682 exit(1);
1683 }
1684 if(inptr!=outptr){
1685 fprintf(stderr,"encoded page data incomplete!\n");
1686 exit(1);
1687 }
1688 if(inptr!=deptr){
1689 fprintf(stderr,"decoded page data incomplete!\n");
1690 exit(1);
1691 }
1692 if(inptr!=depacket){
1693 fprintf(stderr,"decoded packet data incomplete!\n");
1694 exit(1);
1695 }
1696 if(!eosflag){
1697 fprintf(stderr,"Never got a packet with EOS set!\n");
1698 exit(1);
1699 }
1700 fprintf(stderr,"ok.\n");
1701 }
1702
main(void)1703 int main(void){
1704
1705 ogg_stream_init(&os_en,0x04030201);
1706 ogg_stream_init(&os_de,0x04030201);
1707 ogg_sync_init(&oy);
1708
1709 /* Exercise each code path in the framing code. Also verify that
1710 the checksums are working. */
1711
1712 {
1713 /* 17 only */
1714 const int packets[]={17, -1};
1715 const int *headret[]={head1_0,NULL};
1716
1717 fprintf(stderr,"testing single page encoding... ");
1718 test_pack(packets,headret,0,0,0);
1719 }
1720
1721 {
1722 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1723 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1724 const int *headret[]={head1_1,head2_1,NULL};
1725
1726 fprintf(stderr,"testing basic page encoding... ");
1727 test_pack(packets,headret,0,0,0);
1728 }
1729
1730 {
1731 /* nil packets; beginning,middle,end */
1732 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1733 const int *headret[]={head1_2,head2_2,NULL};
1734
1735 fprintf(stderr,"testing basic nil packets... ");
1736 test_pack(packets,headret,0,0,0);
1737 }
1738
1739 {
1740 /* large initial packet */
1741 const int packets[]={4345,259,255,-1};
1742 const int *headret[]={head1_3,head2_3,NULL};
1743
1744 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1745 test_pack(packets,headret,0,0,0);
1746 }
1747
1748 {
1749 /* continuing packet test; with page spill expansion, we have to
1750 overflow the lacing table. */
1751 const int packets[]={0,65500,259,255,-1};
1752 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1753
1754 fprintf(stderr,"testing single packet page span... ");
1755 test_pack(packets,headret,0,0,0);
1756 }
1757
1758 {
1759 /* spill expand packet test */
1760 const int packets[]={0,4345,259,255,0,0,-1};
1761 const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1762
1763 fprintf(stderr,"testing page spill expansion... ");
1764 test_pack(packets,headret,0,0,0);
1765 }
1766
1767 /* page with the 255 segment limit */
1768 {
1769
1770 const int packets[]={0,10,10,10,10,10,10,10,10,
1771 10,10,10,10,10,10,10,10,
1772 10,10,10,10,10,10,10,10,
1773 10,10,10,10,10,10,10,10,
1774 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,50,-1};
1802 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1803
1804 fprintf(stderr,"testing max packet segments... ");
1805 test_pack(packets,headret,0,0,0);
1806 }
1807
1808 {
1809 /* packet that overspans over an entire page */
1810 const int packets[]={0,100,130049,259,255,-1};
1811 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1812
1813 fprintf(stderr,"testing very large packets... ");
1814 test_pack(packets,headret,0,0,0);
1815 }
1816
1817 {
1818 /* test for the libogg 1.1.1 resync in large continuation bug
1819 found by Josh Coalson) */
1820 const int packets[]={0,100,130049,259,255,-1};
1821 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1822
1823 fprintf(stderr,"testing continuation resync in very large packets... ");
1824 test_pack(packets,headret,100,2,3);
1825 }
1826
1827 {
1828 /* term only page. why not? */
1829 const int packets[]={0,100,64770,-1};
1830 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1831
1832 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1833 test_pack(packets,headret,0,0,0);
1834 }
1835
1836
1837
1838 {
1839 /* build a bunch of pages for testing */
1840 unsigned char *data=_ogg_malloc(1024*1024);
1841 int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1842 int inptr=0,i,j;
1843 ogg_page og[5];
1844
1845 ogg_stream_reset(&os_en);
1846
1847 for(i=0;pl[i]!=-1;i++){
1848 ogg_packet op;
1849 int len=pl[i];
1850
1851 op.packet=data+inptr;
1852 op.bytes=len;
1853 op.e_o_s=(pl[i+1]<0?1:0);
1854 op.granulepos=(i+1)*1000;
1855
1856 for(j=0;j<len;j++)data[inptr++]=i+j;
1857 ogg_stream_packetin(&os_en,&op);
1858 }
1859
1860 _ogg_free(data);
1861
1862 /* retrieve finished pages */
1863 for(i=0;i<5;i++){
1864 if(ogg_stream_pageout(&os_en,&og[i])==0){
1865 fprintf(stderr,"Too few pages output building sync tests!\n");
1866 exit(1);
1867 }
1868 copy_page(&og[i]);
1869 }
1870
1871 /* Test lost pages on pagein/packetout: no rollback */
1872 {
1873 ogg_page temp;
1874 ogg_packet test;
1875
1876 fprintf(stderr,"Testing loss of pages... ");
1877
1878 ogg_sync_reset(&oy);
1879 ogg_stream_reset(&os_de);
1880 for(i=0;i<5;i++){
1881 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1882 og[i].header_len);
1883 ogg_sync_wrote(&oy,og[i].header_len);
1884 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1885 ogg_sync_wrote(&oy,og[i].body_len);
1886 }
1887
1888 ogg_sync_pageout(&oy,&temp);
1889 ogg_stream_pagein(&os_de,&temp);
1890 ogg_sync_pageout(&oy,&temp);
1891 ogg_stream_pagein(&os_de,&temp);
1892 ogg_sync_pageout(&oy,&temp);
1893 /* skip */
1894 ogg_sync_pageout(&oy,&temp);
1895 ogg_stream_pagein(&os_de,&temp);
1896
1897 /* do we get the expected results/packets? */
1898
1899 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1900 checkpacket(&test,0,0,0);
1901 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1902 checkpacket(&test,1,1,-1);
1903 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1904 checkpacket(&test,1,2,-1);
1905 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1906 checkpacket(&test,98,3,-1);
1907 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1908 checkpacket(&test,4079,4,5000);
1909 if(ogg_stream_packetout(&os_de,&test)!=-1){
1910 fprintf(stderr,"Error: loss of page did not return error\n");
1911 exit(1);
1912 }
1913 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1914 checkpacket(&test,76,9,-1);
1915 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1916 checkpacket(&test,34,10,-1);
1917 fprintf(stderr,"ok.\n");
1918 }
1919
1920 /* Test lost pages on pagein/packetout: rollback with continuation */
1921 {
1922 ogg_page temp;
1923 ogg_packet test;
1924
1925 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1926
1927 ogg_sync_reset(&oy);
1928 ogg_stream_reset(&os_de);
1929 for(i=0;i<5;i++){
1930 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1931 og[i].header_len);
1932 ogg_sync_wrote(&oy,og[i].header_len);
1933 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1934 ogg_sync_wrote(&oy,og[i].body_len);
1935 }
1936
1937 ogg_sync_pageout(&oy,&temp);
1938 ogg_stream_pagein(&os_de,&temp);
1939 ogg_sync_pageout(&oy,&temp);
1940 ogg_stream_pagein(&os_de,&temp);
1941 ogg_sync_pageout(&oy,&temp);
1942 ogg_stream_pagein(&os_de,&temp);
1943 ogg_sync_pageout(&oy,&temp);
1944 /* skip */
1945 ogg_sync_pageout(&oy,&temp);
1946 ogg_stream_pagein(&os_de,&temp);
1947
1948 /* do we get the expected results/packets? */
1949
1950 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1951 checkpacket(&test,0,0,0);
1952 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1953 checkpacket(&test,1,1,-1);
1954 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1955 checkpacket(&test,1,2,-1);
1956 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1957 checkpacket(&test,98,3,-1);
1958 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1959 checkpacket(&test,4079,4,5000);
1960 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1961 checkpacket(&test,1,5,-1);
1962 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1963 checkpacket(&test,1,6,-1);
1964 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1965 checkpacket(&test,2954,7,-1);
1966 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1967 checkpacket(&test,2057,8,9000);
1968 if(ogg_stream_packetout(&os_de,&test)!=-1){
1969 fprintf(stderr,"Error: loss of page did not return error\n");
1970 exit(1);
1971 }
1972 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1973 checkpacket(&test,300,17,18000);
1974 fprintf(stderr,"ok.\n");
1975 }
1976
1977 /* the rest only test sync */
1978 {
1979 ogg_page og_de;
1980 /* Test fractional page inputs: incomplete capture */
1981 fprintf(stderr,"Testing sync on partial inputs... ");
1982 ogg_sync_reset(&oy);
1983 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1984 3);
1985 ogg_sync_wrote(&oy,3);
1986 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1987
1988 /* Test fractional page inputs: incomplete fixed header */
1989 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1990 20);
1991 ogg_sync_wrote(&oy,20);
1992 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1993
1994 /* Test fractional page inputs: incomplete header */
1995 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1996 5);
1997 ogg_sync_wrote(&oy,5);
1998 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1999
2000 /* Test fractional page inputs: incomplete body */
2001
2002 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
2003 og[1].header_len-28);
2004 ogg_sync_wrote(&oy,og[1].header_len-28);
2005 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2006
2007 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
2008 ogg_sync_wrote(&oy,1000);
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 og[1].body_len-1000);
2013 ogg_sync_wrote(&oy,og[1].body_len-1000);
2014 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2015
2016 fprintf(stderr,"ok.\n");
2017 }
2018
2019 /* Test fractional page inputs: page + incomplete capture */
2020 {
2021 ogg_page og_de;
2022 fprintf(stderr,"Testing sync on 1+partial inputs... ");
2023 ogg_sync_reset(&oy);
2024
2025 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2026 og[1].header_len);
2027 ogg_sync_wrote(&oy,og[1].header_len);
2028
2029 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2030 og[1].body_len);
2031 ogg_sync_wrote(&oy,og[1].body_len);
2032
2033 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2034 20);
2035 ogg_sync_wrote(&oy,20);
2036 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2037 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2038
2039 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
2040 og[1].header_len-20);
2041 ogg_sync_wrote(&oy,og[1].header_len-20);
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 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2046
2047 fprintf(stderr,"ok.\n");
2048 }
2049
2050 /* Test recapture: garbage + page */
2051 {
2052 ogg_page og_de;
2053 fprintf(stderr,"Testing search for capture... ");
2054 ogg_sync_reset(&oy);
2055
2056 /* 'garbage' */
2057 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2058 og[1].body_len);
2059 ogg_sync_wrote(&oy,og[1].body_len);
2060
2061 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2062 og[1].header_len);
2063 ogg_sync_wrote(&oy,og[1].header_len);
2064
2065 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2066 og[1].body_len);
2067 ogg_sync_wrote(&oy,og[1].body_len);
2068
2069 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2070 20);
2071 ogg_sync_wrote(&oy,20);
2072 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2073 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2074 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2075
2076 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2077 og[2].header_len-20);
2078 ogg_sync_wrote(&oy,og[2].header_len-20);
2079 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2080 og[2].body_len);
2081 ogg_sync_wrote(&oy,og[2].body_len);
2082 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2083
2084 fprintf(stderr,"ok.\n");
2085 }
2086
2087 /* Test recapture: page + garbage + page */
2088 {
2089 ogg_page og_de;
2090 fprintf(stderr,"Testing recapture... ");
2091 ogg_sync_reset(&oy);
2092
2093 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2094 og[1].header_len);
2095 ogg_sync_wrote(&oy,og[1].header_len);
2096
2097 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2098 og[1].body_len);
2099 ogg_sync_wrote(&oy,og[1].body_len);
2100
2101 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2102 og[2].header_len);
2103 ogg_sync_wrote(&oy,og[2].header_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 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2110
2111 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2112 og[2].body_len-5);
2113 ogg_sync_wrote(&oy,og[2].body_len-5);
2114
2115 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2116 og[3].header_len);
2117 ogg_sync_wrote(&oy,og[3].header_len);
2118
2119 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2120 og[3].body_len);
2121 ogg_sync_wrote(&oy,og[3].body_len);
2122
2123 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2124 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2125
2126 fprintf(stderr,"ok.\n");
2127 }
2128
2129 /* Free page data that was previously copied */
2130 {
2131 for(i=0;i<5;i++){
2132 free_page(&og[i]);
2133 }
2134 }
2135 }
2136
2137 return(0);
2138 }
2139
2140 #endif
2141