1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: code raw packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
15 last mod: $Id: framing.c 18758 2013-01-08 16:29:56Z tterribe $
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]==0x400){
879 bos=0;
880 for(;segptr<segments;segptr++){
881 int val=header[27+segptr];
882 body+=val;
883 bodysize-=val;
884 if(val<255){
885 segptr++;
886 break;
887 }
888 }
889 }
890 }
891
892 if(bodysize){
893 if(_os_body_expand(os,bodysize)) return -1;
894 memcpy(os->body_data+os->body_fill,body,bodysize);
895 os->body_fill+=bodysize;
896 }
897
898 {
899 int saved=-1;
900 while(segptr<segments){
901 int val=header[27+segptr];
902 os->lacing_vals[os->lacing_fill]=val;
903 os->granule_vals[os->lacing_fill]=-1;
904
905 if(bos){
906 os->lacing_vals[os->lacing_fill]|=0x100;
907 bos=0;
908 }
909
910 if(val<255)saved=os->lacing_fill;
911
912 os->lacing_fill++;
913 segptr++;
914
915 if(val<255)os->lacing_packet=os->lacing_fill;
916 }
917
918 /* set the granulepos on the last granuleval of the last full packet */
919 if(saved!=-1){
920 os->granule_vals[saved]=granulepos;
921 }
922
923 }
924
925 if(eos){
926 os->e_o_s=1;
927 if(os->lacing_fill>0)
928 os->lacing_vals[os->lacing_fill-1]|=0x200;
929 }
930
931 os->pageno=pageno+1;
932
933 return(0);
934 }
935
936 /* clear things to an initial state. Good to call, eg, before seeking */
ogg_sync_reset(ogg_sync_state * oy)937 int ogg_sync_reset(ogg_sync_state *oy){
938 if(ogg_sync_check(oy))return -1;
939
940 oy->fill=0;
941 oy->returned=0;
942 oy->unsynced=0;
943 oy->headerbytes=0;
944 oy->bodybytes=0;
945 return(0);
946 }
947
ogg_stream_reset(ogg_stream_state * os)948 int ogg_stream_reset(ogg_stream_state *os){
949 if(ogg_stream_check(os)) return -1;
950
951 os->body_fill=0;
952 os->body_returned=0;
953
954 os->lacing_fill=0;
955 os->lacing_packet=0;
956 os->lacing_returned=0;
957
958 os->header_fill=0;
959
960 os->e_o_s=0;
961 os->b_o_s=0;
962 os->pageno=-1;
963 os->packetno=0;
964 os->granulepos=0;
965
966 return(0);
967 }
968
ogg_stream_reset_serialno(ogg_stream_state * os,int serialno)969 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
970 if(ogg_stream_check(os)) return -1;
971 ogg_stream_reset(os);
972 os->serialno=serialno;
973 return(0);
974 }
975
_packetout(ogg_stream_state * os,ogg_packet * op,int adv)976 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
977
978 /* The last part of decode. We have the stream broken into packet
979 segments. Now we need to group them into packets (or return the
980 out of sync markers) */
981
982 int ptr=os->lacing_returned;
983
984 if(os->lacing_packet<=ptr)return(0);
985
986 if(os->lacing_vals[ptr]&0x400){
987 /* we need to tell the codec there's a gap; it might need to
988 handle previous packet dependencies. */
989 os->lacing_returned++;
990 os->packetno++;
991 return(-1);
992 }
993
994 if(!op && !adv)return(1); /* just using peek as an inexpensive way
995 to ask if there's a whole packet
996 waiting */
997
998 /* Gather the whole packet. We'll have no holes or a partial packet */
999 {
1000 int size=os->lacing_vals[ptr]&0xff;
1001 long bytes=size;
1002 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
1003 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
1004
1005 while(size==255){
1006 int val=os->lacing_vals[++ptr];
1007 size=val&0xff;
1008 if(val&0x200)eos=0x200;
1009 bytes+=size;
1010 }
1011
1012 if(op){
1013 op->e_o_s=eos;
1014 op->b_o_s=bos;
1015 op->packet=os->body_data+os->body_returned;
1016 op->packetno=os->packetno;
1017 op->granulepos=os->granule_vals[ptr];
1018 op->bytes=bytes;
1019 }
1020
1021 if(adv){
1022 os->body_returned+=bytes;
1023 os->lacing_returned=ptr+1;
1024 os->packetno++;
1025 }
1026 }
1027 return(1);
1028 }
1029
ogg_stream_packetout(ogg_stream_state * os,ogg_packet * op)1030 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
1031 if(ogg_stream_check(os)) return 0;
1032 return _packetout(os,op,1);
1033 }
1034
ogg_stream_packetpeek(ogg_stream_state * os,ogg_packet * op)1035 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
1036 if(ogg_stream_check(os)) return 0;
1037 return _packetout(os,op,0);
1038 }
1039
ogg_packet_clear(ogg_packet * op)1040 void ogg_packet_clear(ogg_packet *op) {
1041 _ogg_free(op->packet);
1042 memset(op, 0, sizeof(*op));
1043 }
1044
1045 #ifdef _V_SELFTEST
1046 #include <stdio.h>
1047
1048 ogg_stream_state os_en, os_de;
1049 ogg_sync_state oy;
1050
checkpacket(ogg_packet * op,long len,int no,long pos)1051 void checkpacket(ogg_packet *op,long len, int no, long pos){
1052 long j;
1053 static int sequence=0;
1054 static int lastno=0;
1055
1056 if(op->bytes!=len){
1057 fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
1058 exit(1);
1059 }
1060 if(op->granulepos!=pos){
1061 fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1062 exit(1);
1063 }
1064
1065 /* packet number just follows sequence/gap; adjust the input number
1066 for that */
1067 if(no==0){
1068 sequence=0;
1069 }else{
1070 sequence++;
1071 if(no>lastno+1)
1072 sequence++;
1073 }
1074 lastno=no;
1075 if(op->packetno!=sequence){
1076 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1077 (long)(op->packetno),sequence);
1078 exit(1);
1079 }
1080
1081 /* Test data */
1082 for(j=0;j<op->bytes;j++)
1083 if(op->packet[j]!=((j+no)&0xff)){
1084 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1085 j,op->packet[j],(j+no)&0xff);
1086 exit(1);
1087 }
1088 }
1089
check_page(unsigned char * data,const int * header,ogg_page * og)1090 void check_page(unsigned char *data,const int *header,ogg_page *og){
1091 long j;
1092 /* Test data */
1093 for(j=0;j<og->body_len;j++)
1094 if(og->body[j]!=data[j]){
1095 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1096 j,data[j],og->body[j]);
1097 exit(1);
1098 }
1099
1100 /* Test header */
1101 for(j=0;j<og->header_len;j++){
1102 if(og->header[j]!=header[j]){
1103 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1104 for(j=0;j<header[26]+27;j++)
1105 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1106 fprintf(stderr,"\n");
1107 exit(1);
1108 }
1109 }
1110 if(og->header_len!=header[26]+27){
1111 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1112 og->header_len,header[26]+27);
1113 exit(1);
1114 }
1115 }
1116
print_header(ogg_page * og)1117 void print_header(ogg_page *og){
1118 int j;
1119 fprintf(stderr,"\nHEADER:\n");
1120 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
1121 og->header[0],og->header[1],og->header[2],og->header[3],
1122 (int)og->header[4],(int)og->header[5]);
1123
1124 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
1125 (og->header[9]<<24)|(og->header[8]<<16)|
1126 (og->header[7]<<8)|og->header[6],
1127 (og->header[17]<<24)|(og->header[16]<<16)|
1128 (og->header[15]<<8)|og->header[14],
1129 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1130 (og->header[19]<<8)|og->header[18]);
1131
1132 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
1133 (int)og->header[22],(int)og->header[23],
1134 (int)og->header[24],(int)og->header[25],
1135 (int)og->header[26]);
1136
1137 for(j=27;j<og->header_len;j++)
1138 fprintf(stderr,"%d ",(int)og->header[j]);
1139 fprintf(stderr,")\n\n");
1140 }
1141
copy_page(ogg_page * og)1142 void copy_page(ogg_page *og){
1143 unsigned char *temp=_ogg_malloc(og->header_len);
1144 memcpy(temp,og->header,og->header_len);
1145 og->header=temp;
1146
1147 temp=_ogg_malloc(og->body_len);
1148 memcpy(temp,og->body,og->body_len);
1149 og->body=temp;
1150 }
1151
free_page(ogg_page * og)1152 void free_page(ogg_page *og){
1153 _ogg_free (og->header);
1154 _ogg_free (og->body);
1155 }
1156
error(void)1157 void error(void){
1158 fprintf(stderr,"error!\n");
1159 exit(1);
1160 }
1161
1162 /* 17 only */
1163 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1164 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1165 0x01,0x02,0x03,0x04,0,0,0,0,
1166 0x15,0xed,0xec,0x91,
1167 1,
1168 17};
1169
1170 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1171 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1172 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1173 0x01,0x02,0x03,0x04,0,0,0,0,
1174 0x59,0x10,0x6c,0x2c,
1175 1,
1176 17};
1177 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1178 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1179 0x01,0x02,0x03,0x04,1,0,0,0,
1180 0x89,0x33,0x85,0xce,
1181 13,
1182 254,255,0,255,1,255,245,255,255,0,
1183 255,255,90};
1184
1185 /* nil packets; beginning,middle,end */
1186 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1187 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1188 0x01,0x02,0x03,0x04,0,0,0,0,
1189 0xff,0x7b,0x23,0x17,
1190 1,
1191 0};
1192 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1193 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1194 0x01,0x02,0x03,0x04,1,0,0,0,
1195 0x5c,0x3f,0x66,0xcb,
1196 17,
1197 17,254,255,0,0,255,1,0,255,245,255,255,0,
1198 255,255,90,0};
1199
1200 /* large initial packet */
1201 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1202 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1203 0x01,0x02,0x03,0x04,0,0,0,0,
1204 0x01,0x27,0x31,0xaa,
1205 18,
1206 255,255,255,255,255,255,255,255,
1207 255,255,255,255,255,255,255,255,255,10};
1208
1209 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1210 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1211 0x01,0x02,0x03,0x04,1,0,0,0,
1212 0x7f,0x4e,0x8a,0xd2,
1213 4,
1214 255,4,255,0};
1215
1216
1217 /* continuing packet test */
1218 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1219 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1220 0x01,0x02,0x03,0x04,0,0,0,0,
1221 0xff,0x7b,0x23,0x17,
1222 1,
1223 0};
1224
1225 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1226 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1227 0x01,0x02,0x03,0x04,1,0,0,0,
1228 0xf8,0x3c,0x19,0x79,
1229 255,
1230 255,255,255,255,255,255,255,255,
1231 255,255,255,255,255,255,255,255,
1232 255,255,255,255,255,255,255,255,
1233 255,255,255,255,255,255,255,255,
1234 255,255,255,255,255,255,255,255,
1235 255,255,255,255,255,255,255,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};
1262
1263 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1264 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1265 0x01,0x02,0x03,0x04,2,0,0,0,
1266 0x38,0xe6,0xb6,0x28,
1267 6,
1268 255,220,255,4,255,0};
1269
1270
1271 /* spill expansion test */
1272 const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1273 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1274 0x01,0x02,0x03,0x04,0,0,0,0,
1275 0xff,0x7b,0x23,0x17,
1276 1,
1277 0};
1278
1279 const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1280 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1281 0x01,0x02,0x03,0x04,1,0,0,0,
1282 0xce,0x8f,0x17,0x1a,
1283 23,
1284 255,255,255,255,255,255,255,255,
1285 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1286
1287
1288 const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1289 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1290 0x01,0x02,0x03,0x04,2,0,0,0,
1291 0x9b,0xb2,0x50,0xa1,
1292 1,
1293 0};
1294
1295 /* page with the 255 segment limit */
1296 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1297 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1298 0x01,0x02,0x03,0x04,0,0,0,0,
1299 0xff,0x7b,0x23,0x17,
1300 1,
1301 0};
1302
1303 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1304 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1305 0x01,0x02,0x03,0x04,1,0,0,0,
1306 0xed,0x2a,0x2e,0xa7,
1307 255,
1308 10,10,10,10,10,10,10,10,
1309 10,10,10,10,10,10,10,10,
1310 10,10,10,10,10,10,10,10,
1311 10,10,10,10,10,10,10,10,
1312 10,10,10,10,10,10,10,10,
1313 10,10,10,10,10,10,10,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};
1340
1341 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1342 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1343 0x01,0x02,0x03,0x04,2,0,0,0,
1344 0x6c,0x3b,0x82,0x3d,
1345 1,
1346 50};
1347
1348
1349 /* packet that overspans over an entire page */
1350 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1351 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1352 0x01,0x02,0x03,0x04,0,0,0,0,
1353 0xff,0x7b,0x23,0x17,
1354 1,
1355 0};
1356
1357 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1358 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1359 0x01,0x02,0x03,0x04,1,0,0,0,
1360 0x68,0x22,0x7c,0x3d,
1361 255,
1362 100,
1363 255,255,255,255,255,255,255,255,
1364 255,255,255,255,255,255,255,255,
1365 255,255,255,255,255,255,255,255,
1366 255,255,255,255,255,255,255,255,
1367 255,255,255,255,255,255,255,255,
1368 255,255,255,255,255,255,255,255,
1369 255,255,255,255,255,255,255,255,
1370 255,255,255,255,255,255,255,255,
1371 255,255,255,255,255,255,255,255,
1372 255,255,255,255,255,255,255,255,
1373 255,255,255,255,255,255,255,255,
1374 255,255,255,255,255,255,255,255,
1375 255,255,255,255,255,255,255,255,
1376 255,255,255,255,255,255,255,255,
1377 255,255,255,255,255,255,255,255,
1378 255,255,255,255,255,255,255,255,
1379 255,255,255,255,255,255,255,255,
1380 255,255,255,255,255,255,255,255,
1381 255,255,255,255,255,255,255,255,
1382 255,255,255,255,255,255,255,255,
1383 255,255,255,255,255,255,255,255,
1384 255,255,255,255,255,255,255,255,
1385 255,255,255,255,255,255,255,255,
1386 255,255,255,255,255,255,255,255,
1387 255,255,255,255,255,255,255,255,
1388 255,255,255,255,255,255,255,255,
1389 255,255,255,255,255,255,255,255,
1390 255,255,255,255,255,255,255,255,
1391 255,255,255,255,255,255,255,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};
1395
1396 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1397 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1398 0x01,0x02,0x03,0x04,2,0,0,0,
1399 0xf4,0x87,0xba,0xf3,
1400 255,
1401 255,255,255,255,255,255,255,255,
1402 255,255,255,255,255,255,255,255,
1403 255,255,255,255,255,255,255,255,
1404 255,255,255,255,255,255,255,255,
1405 255,255,255,255,255,255,255,255,
1406 255,255,255,255,255,255,255,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};
1433
1434 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1435 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1436 0x01,0x02,0x03,0x04,3,0,0,0,
1437 0xf7,0x2f,0x6c,0x60,
1438 5,
1439 254,255,4,255,0};
1440
1441 /* packet that overspans over an entire page */
1442 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1443 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1444 0x01,0x02,0x03,0x04,0,0,0,0,
1445 0xff,0x7b,0x23,0x17,
1446 1,
1447 0};
1448
1449 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1450 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1451 0x01,0x02,0x03,0x04,1,0,0,0,
1452 0x68,0x22,0x7c,0x3d,
1453 255,
1454 100,
1455 255,255,255,255,255,255,255,255,
1456 255,255,255,255,255,255,255,255,
1457 255,255,255,255,255,255,255,255,
1458 255,255,255,255,255,255,255,255,
1459 255,255,255,255,255,255,255,255,
1460 255,255,255,255,255,255,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};
1487
1488 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1489 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1490 0x01,0x02,0x03,0x04,2,0,0,0,
1491 0xd4,0xe0,0x60,0xe5,
1492 1,
1493 0};
1494
test_pack(const int * pl,const int ** headers,int byteskip,int pageskip,int packetskip)1495 void test_pack(const int *pl, const int **headers, int byteskip,
1496 int pageskip, int packetskip){
1497 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1498 long inptr=0;
1499 long outptr=0;
1500 long deptr=0;
1501 long depacket=0;
1502 long granule_pos=7,pageno=0;
1503 int i,j,packets,pageout=pageskip;
1504 int eosflag=0;
1505 int bosflag=0;
1506
1507 int byteskipcount=0;
1508
1509 ogg_stream_reset(&os_en);
1510 ogg_stream_reset(&os_de);
1511 ogg_sync_reset(&oy);
1512
1513 for(packets=0;packets<packetskip;packets++)
1514 depacket+=pl[packets];
1515
1516 for(packets=0;;packets++)if(pl[packets]==-1)break;
1517
1518 for(i=0;i<packets;i++){
1519 /* construct a test packet */
1520 ogg_packet op;
1521 int len=pl[i];
1522
1523 op.packet=data+inptr;
1524 op.bytes=len;
1525 op.e_o_s=(pl[i+1]<0?1:0);
1526 op.granulepos=granule_pos;
1527
1528 granule_pos+=1024;
1529
1530 for(j=0;j<len;j++)data[inptr++]=i+j;
1531
1532 /* submit the test packet */
1533 ogg_stream_packetin(&os_en,&op);
1534
1535 /* retrieve any finished pages */
1536 {
1537 ogg_page og;
1538
1539 while(ogg_stream_pageout(&os_en,&og)){
1540 /* We have a page. Check it carefully */
1541
1542 fprintf(stderr,"%ld, ",pageno);
1543
1544 if(headers[pageno]==NULL){
1545 fprintf(stderr,"coded too many pages!\n");
1546 exit(1);
1547 }
1548
1549 check_page(data+outptr,headers[pageno],&og);
1550
1551 outptr+=og.body_len;
1552 pageno++;
1553 if(pageskip){
1554 bosflag=1;
1555 pageskip--;
1556 deptr+=og.body_len;
1557 }
1558
1559 /* have a complete page; submit it to sync/decode */
1560
1561 {
1562 ogg_page og_de;
1563 ogg_packet op_de,op_de2;
1564 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1565 char *next=buf;
1566 byteskipcount+=og.header_len;
1567 if(byteskipcount>byteskip){
1568 memcpy(next,og.header,byteskipcount-byteskip);
1569 next+=byteskipcount-byteskip;
1570 byteskipcount=byteskip;
1571 }
1572
1573 byteskipcount+=og.body_len;
1574 if(byteskipcount>byteskip){
1575 memcpy(next,og.body,byteskipcount-byteskip);
1576 next+=byteskipcount-byteskip;
1577 byteskipcount=byteskip;
1578 }
1579
1580 ogg_sync_wrote(&oy,next-buf);
1581
1582 while(1){
1583 int ret=ogg_sync_pageout(&oy,&og_de);
1584 if(ret==0)break;
1585 if(ret<0)continue;
1586 /* got a page. Happy happy. Verify that it's good. */
1587
1588 fprintf(stderr,"(%d), ",pageout);
1589
1590 check_page(data+deptr,headers[pageout],&og_de);
1591 deptr+=og_de.body_len;
1592 pageout++;
1593
1594 /* submit it to deconstitution */
1595 ogg_stream_pagein(&os_de,&og_de);
1596
1597 /* packets out? */
1598 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1599 ogg_stream_packetpeek(&os_de,NULL);
1600 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1601
1602 /* verify peek and out match */
1603 if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1604 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1605 depacket);
1606 exit(1);
1607 }
1608
1609 /* verify the packet! */
1610 /* check data */
1611 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1612 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1613 depacket);
1614 exit(1);
1615 }
1616 /* check bos flag */
1617 if(bosflag==0 && op_de.b_o_s==0){
1618 fprintf(stderr,"b_o_s flag not set on packet!\n");
1619 exit(1);
1620 }
1621 if(bosflag && op_de.b_o_s){
1622 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1623 exit(1);
1624 }
1625 bosflag=1;
1626 depacket+=op_de.bytes;
1627
1628 /* check eos flag */
1629 if(eosflag){
1630 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1631 exit(1);
1632 }
1633
1634 if(op_de.e_o_s)eosflag=1;
1635
1636 /* check granulepos flag */
1637 if(op_de.granulepos!=-1){
1638 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1639 }
1640 }
1641 }
1642 }
1643 }
1644 }
1645 }
1646 _ogg_free(data);
1647 if(headers[pageno]!=NULL){
1648 fprintf(stderr,"did not write last page!\n");
1649 exit(1);
1650 }
1651 if(headers[pageout]!=NULL){
1652 fprintf(stderr,"did not decode last page!\n");
1653 exit(1);
1654 }
1655 if(inptr!=outptr){
1656 fprintf(stderr,"encoded page data incomplete!\n");
1657 exit(1);
1658 }
1659 if(inptr!=deptr){
1660 fprintf(stderr,"decoded page data incomplete!\n");
1661 exit(1);
1662 }
1663 if(inptr!=depacket){
1664 fprintf(stderr,"decoded packet data incomplete!\n");
1665 exit(1);
1666 }
1667 if(!eosflag){
1668 fprintf(stderr,"Never got a packet with EOS set!\n");
1669 exit(1);
1670 }
1671 fprintf(stderr,"ok.\n");
1672 }
1673
main(void)1674 int main(void){
1675
1676 ogg_stream_init(&os_en,0x04030201);
1677 ogg_stream_init(&os_de,0x04030201);
1678 ogg_sync_init(&oy);
1679
1680 /* Exercise each code path in the framing code. Also verify that
1681 the checksums are working. */
1682
1683 {
1684 /* 17 only */
1685 const int packets[]={17, -1};
1686 const int *headret[]={head1_0,NULL};
1687
1688 fprintf(stderr,"testing single page encoding... ");
1689 test_pack(packets,headret,0,0,0);
1690 }
1691
1692 {
1693 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1694 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1695 const int *headret[]={head1_1,head2_1,NULL};
1696
1697 fprintf(stderr,"testing basic page encoding... ");
1698 test_pack(packets,headret,0,0,0);
1699 }
1700
1701 {
1702 /* nil packets; beginning,middle,end */
1703 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1704 const int *headret[]={head1_2,head2_2,NULL};
1705
1706 fprintf(stderr,"testing basic nil packets... ");
1707 test_pack(packets,headret,0,0,0);
1708 }
1709
1710 {
1711 /* large initial packet */
1712 const int packets[]={4345,259,255,-1};
1713 const int *headret[]={head1_3,head2_3,NULL};
1714
1715 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1716 test_pack(packets,headret,0,0,0);
1717 }
1718
1719 {
1720 /* continuing packet test; with page spill expansion, we have to
1721 overflow the lacing table. */
1722 const int packets[]={0,65500,259,255,-1};
1723 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1724
1725 fprintf(stderr,"testing single packet page span... ");
1726 test_pack(packets,headret,0,0,0);
1727 }
1728
1729 {
1730 /* spill expand packet test */
1731 const int packets[]={0,4345,259,255,0,0,-1};
1732 const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1733
1734 fprintf(stderr,"testing page spill expansion... ");
1735 test_pack(packets,headret,0,0,0);
1736 }
1737
1738 /* page with the 255 segment limit */
1739 {
1740
1741 const int packets[]={0,10,10,10,10,10,10,10,10,
1742 10,10,10,10,10,10,10,10,
1743 10,10,10,10,10,10,10,10,
1744 10,10,10,10,10,10,10,10,
1745 10,10,10,10,10,10,10,10,
1746 10,10,10,10,10,10,10,10,
1747 10,10,10,10,10,10,10,10,
1748 10,10,10,10,10,10,10,10,
1749 10,10,10,10,10,10,10,10,
1750 10,10,10,10,10,10,10,10,
1751 10,10,10,10,10,10,10,10,
1752 10,10,10,10,10,10,10,10,
1753 10,10,10,10,10,10,10,10,
1754 10,10,10,10,10,10,10,10,
1755 10,10,10,10,10,10,10,10,
1756 10,10,10,10,10,10,10,10,
1757 10,10,10,10,10,10,10,10,
1758 10,10,10,10,10,10,10,10,
1759 10,10,10,10,10,10,10,10,
1760 10,10,10,10,10,10,10,10,
1761 10,10,10,10,10,10,10,10,
1762 10,10,10,10,10,10,10,10,
1763 10,10,10,10,10,10,10,10,
1764 10,10,10,10,10,10,10,10,
1765 10,10,10,10,10,10,10,10,
1766 10,10,10,10,10,10,10,10,
1767 10,10,10,10,10,10,10,10,
1768 10,10,10,10,10,10,10,10,
1769 10,10,10,10,10,10,10,10,
1770 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,50,-1};
1773 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1774
1775 fprintf(stderr,"testing max packet segments... ");
1776 test_pack(packets,headret,0,0,0);
1777 }
1778
1779 {
1780 /* packet that overspans over an entire page */
1781 const int packets[]={0,100,130049,259,255,-1};
1782 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1783
1784 fprintf(stderr,"testing very large packets... ");
1785 test_pack(packets,headret,0,0,0);
1786 }
1787
1788 {
1789 /* test for the libogg 1.1.1 resync in large continuation bug
1790 found by Josh Coalson) */
1791 const int packets[]={0,100,130049,259,255,-1};
1792 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1793
1794 fprintf(stderr,"testing continuation resync in very large packets... ");
1795 test_pack(packets,headret,100,2,3);
1796 }
1797
1798 {
1799 /* term only page. why not? */
1800 const int packets[]={0,100,64770,-1};
1801 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1802
1803 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1804 test_pack(packets,headret,0,0,0);
1805 }
1806
1807
1808
1809 {
1810 /* build a bunch of pages for testing */
1811 unsigned char *data=_ogg_malloc(1024*1024);
1812 int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1813 int inptr=0,i,j;
1814 ogg_page og[5];
1815
1816 ogg_stream_reset(&os_en);
1817
1818 for(i=0;pl[i]!=-1;i++){
1819 ogg_packet op;
1820 int len=pl[i];
1821
1822 op.packet=data+inptr;
1823 op.bytes=len;
1824 op.e_o_s=(pl[i+1]<0?1:0);
1825 op.granulepos=(i+1)*1000;
1826
1827 for(j=0;j<len;j++)data[inptr++]=i+j;
1828 ogg_stream_packetin(&os_en,&op);
1829 }
1830
1831 _ogg_free(data);
1832
1833 /* retrieve finished pages */
1834 for(i=0;i<5;i++){
1835 if(ogg_stream_pageout(&os_en,&og[i])==0){
1836 fprintf(stderr,"Too few pages output building sync tests!\n");
1837 exit(1);
1838 }
1839 copy_page(&og[i]);
1840 }
1841
1842 /* Test lost pages on pagein/packetout: no rollback */
1843 {
1844 ogg_page temp;
1845 ogg_packet test;
1846
1847 fprintf(stderr,"Testing loss of pages... ");
1848
1849 ogg_sync_reset(&oy);
1850 ogg_stream_reset(&os_de);
1851 for(i=0;i<5;i++){
1852 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1853 og[i].header_len);
1854 ogg_sync_wrote(&oy,og[i].header_len);
1855 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1856 ogg_sync_wrote(&oy,og[i].body_len);
1857 }
1858
1859 ogg_sync_pageout(&oy,&temp);
1860 ogg_stream_pagein(&os_de,&temp);
1861 ogg_sync_pageout(&oy,&temp);
1862 ogg_stream_pagein(&os_de,&temp);
1863 ogg_sync_pageout(&oy,&temp);
1864 /* skip */
1865 ogg_sync_pageout(&oy,&temp);
1866 ogg_stream_pagein(&os_de,&temp);
1867
1868 /* do we get the expected results/packets? */
1869
1870 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1871 checkpacket(&test,0,0,0);
1872 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1873 checkpacket(&test,1,1,-1);
1874 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1875 checkpacket(&test,1,2,-1);
1876 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1877 checkpacket(&test,98,3,-1);
1878 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1879 checkpacket(&test,4079,4,5000);
1880 if(ogg_stream_packetout(&os_de,&test)!=-1){
1881 fprintf(stderr,"Error: loss of page did not return error\n");
1882 exit(1);
1883 }
1884 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1885 checkpacket(&test,76,9,-1);
1886 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1887 checkpacket(&test,34,10,-1);
1888 fprintf(stderr,"ok.\n");
1889 }
1890
1891 /* Test lost pages on pagein/packetout: rollback with continuation */
1892 {
1893 ogg_page temp;
1894 ogg_packet test;
1895
1896 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1897
1898 ogg_sync_reset(&oy);
1899 ogg_stream_reset(&os_de);
1900 for(i=0;i<5;i++){
1901 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1902 og[i].header_len);
1903 ogg_sync_wrote(&oy,og[i].header_len);
1904 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1905 ogg_sync_wrote(&oy,og[i].body_len);
1906 }
1907
1908 ogg_sync_pageout(&oy,&temp);
1909 ogg_stream_pagein(&os_de,&temp);
1910 ogg_sync_pageout(&oy,&temp);
1911 ogg_stream_pagein(&os_de,&temp);
1912 ogg_sync_pageout(&oy,&temp);
1913 ogg_stream_pagein(&os_de,&temp);
1914 ogg_sync_pageout(&oy,&temp);
1915 /* skip */
1916 ogg_sync_pageout(&oy,&temp);
1917 ogg_stream_pagein(&os_de,&temp);
1918
1919 /* do we get the expected results/packets? */
1920
1921 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1922 checkpacket(&test,0,0,0);
1923 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1924 checkpacket(&test,1,1,-1);
1925 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1926 checkpacket(&test,1,2,-1);
1927 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1928 checkpacket(&test,98,3,-1);
1929 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1930 checkpacket(&test,4079,4,5000);
1931 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1932 checkpacket(&test,1,5,-1);
1933 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1934 checkpacket(&test,1,6,-1);
1935 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1936 checkpacket(&test,2954,7,-1);
1937 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1938 checkpacket(&test,2057,8,9000);
1939 if(ogg_stream_packetout(&os_de,&test)!=-1){
1940 fprintf(stderr,"Error: loss of page did not return error\n");
1941 exit(1);
1942 }
1943 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1944 checkpacket(&test,300,17,18000);
1945 fprintf(stderr,"ok.\n");
1946 }
1947
1948 /* the rest only test sync */
1949 {
1950 ogg_page og_de;
1951 /* Test fractional page inputs: incomplete capture */
1952 fprintf(stderr,"Testing sync on partial inputs... ");
1953 ogg_sync_reset(&oy);
1954 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1955 3);
1956 ogg_sync_wrote(&oy,3);
1957 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1958
1959 /* Test fractional page inputs: incomplete fixed header */
1960 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1961 20);
1962 ogg_sync_wrote(&oy,20);
1963 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1964
1965 /* Test fractional page inputs: incomplete header */
1966 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1967 5);
1968 ogg_sync_wrote(&oy,5);
1969 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1970
1971 /* Test fractional page inputs: incomplete body */
1972
1973 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1974 og[1].header_len-28);
1975 ogg_sync_wrote(&oy,og[1].header_len-28);
1976 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1977
1978 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1979 ogg_sync_wrote(&oy,1000);
1980 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1981
1982 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1983 og[1].body_len-1000);
1984 ogg_sync_wrote(&oy,og[1].body_len-1000);
1985 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1986
1987 fprintf(stderr,"ok.\n");
1988 }
1989
1990 /* Test fractional page inputs: page + incomplete capture */
1991 {
1992 ogg_page og_de;
1993 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1994 ogg_sync_reset(&oy);
1995
1996 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1997 og[1].header_len);
1998 ogg_sync_wrote(&oy,og[1].header_len);
1999
2000 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2001 og[1].body_len);
2002 ogg_sync_wrote(&oy,og[1].body_len);
2003
2004 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2005 20);
2006 ogg_sync_wrote(&oy,20);
2007 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2008 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2009
2010 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
2011 og[1].header_len-20);
2012 ogg_sync_wrote(&oy,og[1].header_len-20);
2013 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2014 og[1].body_len);
2015 ogg_sync_wrote(&oy,og[1].body_len);
2016 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2017
2018 fprintf(stderr,"ok.\n");
2019 }
2020
2021 /* Test recapture: garbage + page */
2022 {
2023 ogg_page og_de;
2024 fprintf(stderr,"Testing search for capture... ");
2025 ogg_sync_reset(&oy);
2026
2027 /* 'garbage' */
2028 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2029 og[1].body_len);
2030 ogg_sync_wrote(&oy,og[1].body_len);
2031
2032 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2033 og[1].header_len);
2034 ogg_sync_wrote(&oy,og[1].header_len);
2035
2036 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2037 og[1].body_len);
2038 ogg_sync_wrote(&oy,og[1].body_len);
2039
2040 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2041 20);
2042 ogg_sync_wrote(&oy,20);
2043 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2044 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2045 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2046
2047 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2048 og[2].header_len-20);
2049 ogg_sync_wrote(&oy,og[2].header_len-20);
2050 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2051 og[2].body_len);
2052 ogg_sync_wrote(&oy,og[2].body_len);
2053 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2054
2055 fprintf(stderr,"ok.\n");
2056 }
2057
2058 /* Test recapture: page + garbage + page */
2059 {
2060 ogg_page og_de;
2061 fprintf(stderr,"Testing recapture... ");
2062 ogg_sync_reset(&oy);
2063
2064 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2065 og[1].header_len);
2066 ogg_sync_wrote(&oy,og[1].header_len);
2067
2068 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2069 og[1].body_len);
2070 ogg_sync_wrote(&oy,og[1].body_len);
2071
2072 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2073 og[2].header_len);
2074 ogg_sync_wrote(&oy,og[2].header_len);
2075
2076 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2077 og[2].header_len);
2078 ogg_sync_wrote(&oy,og[2].header_len);
2079
2080 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2081
2082 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2083 og[2].body_len-5);
2084 ogg_sync_wrote(&oy,og[2].body_len-5);
2085
2086 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2087 og[3].header_len);
2088 ogg_sync_wrote(&oy,og[3].header_len);
2089
2090 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2091 og[3].body_len);
2092 ogg_sync_wrote(&oy,og[3].body_len);
2093
2094 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2095 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2096
2097 fprintf(stderr,"ok.\n");
2098 }
2099
2100 /* Free page data that was previously copied */
2101 {
2102 for(i=0;i<5;i++){
2103 free_page(&og[i]);
2104 }
2105 }
2106 }
2107
2108 return(0);
2109 }
2110
2111 #endif
2112