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