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