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