1 | /******************************************************************** |
---|
2 | * * |
---|
3 | * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC 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-2002 * |
---|
9 | * by the Xiph.Org Foundation http://www.xiph.org/ * |
---|
10 | * * |
---|
11 | ******************************************************************** |
---|
12 | |
---|
13 | function: code raw [Vorbis] packets into framed OggSquish stream and |
---|
14 | decode Ogg streams back into raw packets |
---|
15 | last mod: $Id: framing.c 9601 2005-07-23 00:19:14Z 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 | int ogg_page_version(ogg_page *og){ |
---|
30 | return((int)(og->header[4])); |
---|
31 | } |
---|
32 | |
---|
33 | int ogg_page_continued(ogg_page *og){ |
---|
34 | return((int)(og->header[5]&0x01)); |
---|
35 | } |
---|
36 | |
---|
37 | int ogg_page_bos(ogg_page *og){ |
---|
38 | return((int)(og->header[5]&0x02)); |
---|
39 | } |
---|
40 | |
---|
41 | int ogg_page_eos(ogg_page *og){ |
---|
42 | return((int)(og->header[5]&0x04)); |
---|
43 | } |
---|
44 | |
---|
45 | ogg_int64_t ogg_page_granulepos(ogg_page *og){ |
---|
46 | unsigned char *page=og->header; |
---|
47 | ogg_int64_t granulepos=page[13]&(0xff); |
---|
48 | granulepos= (granulepos<<8)|(page[12]&0xff); |
---|
49 | granulepos= (granulepos<<8)|(page[11]&0xff); |
---|
50 | granulepos= (granulepos<<8)|(page[10]&0xff); |
---|
51 | granulepos= (granulepos<<8)|(page[9]&0xff); |
---|
52 | granulepos= (granulepos<<8)|(page[8]&0xff); |
---|
53 | granulepos= (granulepos<<8)|(page[7]&0xff); |
---|
54 | granulepos= (granulepos<<8)|(page[6]&0xff); |
---|
55 | return(granulepos); |
---|
56 | } |
---|
57 | |
---|
58 | int ogg_page_serialno(ogg_page *og){ |
---|
59 | return(og->header[14] | |
---|
60 | (og->header[15]<<8) | |
---|
61 | (og->header[16]<<16) | |
---|
62 | (og->header[17]<<24)); |
---|
63 | } |
---|
64 | |
---|
65 | long ogg_page_pageno(ogg_page *og){ |
---|
66 | return(og->header[18] | |
---|
67 | (og->header[19]<<8) | |
---|
68 | (og->header[20]<<16) | |
---|
69 | (og->header[21]<<24)); |
---|
70 | } |
---|
71 | |
---|
72 | |
---|
73 | |
---|
74 | /* returns the number of packets that are completed on this page (if |
---|
75 | the leading packet is begun on a previous page, but ends on this |
---|
76 | page, it's counted */ |
---|
77 | |
---|
78 | /* NOTE: |
---|
79 | If a page consists of a packet begun on a previous page, and a new |
---|
80 | packet begun (but not completed) on this page, the return will be: |
---|
81 | ogg_page_packets(page) ==1, |
---|
82 | ogg_page_continued(page) !=0 |
---|
83 | |
---|
84 | If a page happens to be a single packet that was begun on a |
---|
85 | previous page, and spans to the next page (in the case of a three or |
---|
86 | more page packet), the return will be: |
---|
87 | ogg_page_packets(page) ==0, |
---|
88 | ogg_page_continued(page) !=0 |
---|
89 | */ |
---|
90 | |
---|
91 | int ogg_page_packets(ogg_page *og){ |
---|
92 | int i,n=og->header[26],count=0; |
---|
93 | for(i=0;i<n;i++) |
---|
94 | if(og->header[27+i]<255)count++; |
---|
95 | return(count); |
---|
96 | } |
---|
97 | |
---|
98 | |
---|
99 | #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 | int ogg_stream_init(ogg_stream_state *os,int serialno){ |
---|
189 | if(os){ |
---|
190 | memset(os,0,sizeof(*os)); |
---|
191 | os->body_storage=16*1024; |
---|
192 | os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); |
---|
193 | |
---|
194 | os->lacing_storage=1024; |
---|
195 | os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); |
---|
196 | os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); |
---|
197 | |
---|
198 | os->serialno=serialno; |
---|
199 | |
---|
200 | return(0); |
---|
201 | } |
---|
202 | return(-1); |
---|
203 | } |
---|
204 | |
---|
205 | /* _clear does not free os, only the non-flat storage within */ |
---|
206 | int ogg_stream_clear(ogg_stream_state *os){ |
---|
207 | if(os){ |
---|
208 | if(os->body_data)_ogg_free(os->body_data); |
---|
209 | if(os->lacing_vals)_ogg_free(os->lacing_vals); |
---|
210 | if(os->granule_vals)_ogg_free(os->granule_vals); |
---|
211 | |
---|
212 | memset(os,0,sizeof(*os)); |
---|
213 | } |
---|
214 | return(0); |
---|
215 | } |
---|
216 | |
---|
217 | int ogg_stream_destroy(ogg_stream_state *os){ |
---|
218 | if(os){ |
---|
219 | ogg_stream_clear(os); |
---|
220 | _ogg_free(os); |
---|
221 | } |
---|
222 | return(0); |
---|
223 | } |
---|
224 | |
---|
225 | /* Helpers for ogg_stream_encode; this keeps the structure and |
---|
226 | what's happening fairly clear */ |
---|
227 | |
---|
228 | static void _os_body_expand(ogg_stream_state *os,int needed){ |
---|
229 | if(os->body_storage<=os->body_fill+needed){ |
---|
230 | os->body_storage+=(needed+1024); |
---|
231 | os->body_data=_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data)); |
---|
232 | } |
---|
233 | } |
---|
234 | |
---|
235 | static void _os_lacing_expand(ogg_stream_state *os,int needed){ |
---|
236 | if(os->lacing_storage<=os->lacing_fill+needed){ |
---|
237 | os->lacing_storage+=(needed+32); |
---|
238 | os->lacing_vals=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals)); |
---|
239 | os->granule_vals=_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals)); |
---|
240 | } |
---|
241 | } |
---|
242 | |
---|
243 | /* checksum the page */ |
---|
244 | /* Direct table CRC; note that this will be faster in the future if we |
---|
245 | perform the checksum silmultaneously with other copies */ |
---|
246 | |
---|
247 | void ogg_page_checksum_set(ogg_page *og){ |
---|
248 | if(og){ |
---|
249 | ogg_uint32_t crc_reg=0; |
---|
250 | int i; |
---|
251 | |
---|
252 | /* safety; needed for API behavior, but not framing code */ |
---|
253 | og->header[22]=0; |
---|
254 | og->header[23]=0; |
---|
255 | og->header[24]=0; |
---|
256 | og->header[25]=0; |
---|
257 | |
---|
258 | for(i=0;i<og->header_len;i++) |
---|
259 | crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; |
---|
260 | for(i=0;i<og->body_len;i++) |
---|
261 | crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]]; |
---|
262 | |
---|
263 | og->header[22]=(unsigned char)(crc_reg&0xff); |
---|
264 | og->header[23]=(unsigned char)((crc_reg>>8)&0xff); |
---|
265 | og->header[24]=(unsigned char)((crc_reg>>16)&0xff); |
---|
266 | og->header[25]=(unsigned char)((crc_reg>>24)&0xff); |
---|
267 | } |
---|
268 | } |
---|
269 | |
---|
270 | /* submit data to the internal buffer of the framing engine */ |
---|
271 | int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ |
---|
272 | int lacing_vals=op->bytes/255+1,i; |
---|
273 | |
---|
274 | if(os->body_returned){ |
---|
275 | /* advance packet data according to the body_returned pointer. We |
---|
276 | had to keep it around to return a pointer into the buffer last |
---|
277 | call */ |
---|
278 | |
---|
279 | os->body_fill-=os->body_returned; |
---|
280 | if(os->body_fill) |
---|
281 | memmove(os->body_data,os->body_data+os->body_returned, |
---|
282 | os->body_fill); |
---|
283 | os->body_returned=0; |
---|
284 | } |
---|
285 | |
---|
286 | /* make sure we have the buffer storage */ |
---|
287 | _os_body_expand(os,op->bytes); |
---|
288 | _os_lacing_expand(os,lacing_vals); |
---|
289 | |
---|
290 | /* Copy in the submitted packet. Yes, the copy is a waste; this is |
---|
291 | the liability of overly clean abstraction for the time being. It |
---|
292 | will actually be fairly easy to eliminate the extra copy in the |
---|
293 | future */ |
---|
294 | |
---|
295 | memcpy(os->body_data+os->body_fill,op->packet,op->bytes); |
---|
296 | os->body_fill+=op->bytes; |
---|
297 | |
---|
298 | /* Store lacing vals for this packet */ |
---|
299 | for(i=0;i<lacing_vals-1;i++){ |
---|
300 | os->lacing_vals[os->lacing_fill+i]=255; |
---|
301 | os->granule_vals[os->lacing_fill+i]=os->granulepos; |
---|
302 | } |
---|
303 | os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255; |
---|
304 | os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos; |
---|
305 | |
---|
306 | /* flag the first segment as the beginning of the packet */ |
---|
307 | os->lacing_vals[os->lacing_fill]|= 0x100; |
---|
308 | |
---|
309 | os->lacing_fill+=lacing_vals; |
---|
310 | |
---|
311 | /* for the sake of completeness */ |
---|
312 | os->packetno++; |
---|
313 | |
---|
314 | if(op->e_o_s)os->e_o_s=1; |
---|
315 | |
---|
316 | return(0); |
---|
317 | } |
---|
318 | |
---|
319 | /* This will flush remaining packets into a page (returning nonzero), |
---|
320 | even if there is not enough data to trigger a flush normally |
---|
321 | (undersized page). If there are no packets or partial packets to |
---|
322 | flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will |
---|
323 | try to flush a normal sized page like ogg_stream_pageout; a call to |
---|
324 | ogg_stream_flush does not guarantee that all packets have flushed. |
---|
325 | Only a return value of 0 from ogg_stream_flush indicates all packet |
---|
326 | data is flushed into pages. |
---|
327 | |
---|
328 | since ogg_stream_flush will flush the last page in a stream even if |
---|
329 | it's undersized, you almost certainly want to use ogg_stream_pageout |
---|
330 | (and *not* ogg_stream_flush) unless you specifically need to flush |
---|
331 | an page regardless of size in the middle of a stream. */ |
---|
332 | |
---|
333 | int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ |
---|
334 | int i; |
---|
335 | int vals=0; |
---|
336 | int maxvals=(os->lacing_fill>255?255:os->lacing_fill); |
---|
337 | int bytes=0; |
---|
338 | long acc=0; |
---|
339 | ogg_int64_t granule_pos=-1; |
---|
340 | |
---|
341 | if(maxvals==0)return(0); |
---|
342 | |
---|
343 | /* construct a page */ |
---|
344 | /* decide how many segments to include */ |
---|
345 | |
---|
346 | /* If this is the initial header case, the first page must only include |
---|
347 | the initial header packet */ |
---|
348 | if(os->b_o_s==0){ /* 'initial header page' case */ |
---|
349 | granule_pos=0; |
---|
350 | for(vals=0;vals<maxvals;vals++){ |
---|
351 | if((os->lacing_vals[vals]&0x0ff)<255){ |
---|
352 | vals++; |
---|
353 | break; |
---|
354 | } |
---|
355 | } |
---|
356 | }else{ |
---|
357 | for(vals=0;vals<maxvals;vals++){ |
---|
358 | if(acc>4096)break; |
---|
359 | acc+=os->lacing_vals[vals]&0x0ff; |
---|
360 | if((os->lacing_vals[vals]&0xff)<255) |
---|
361 | granule_pos=os->granule_vals[vals]; |
---|
362 | } |
---|
363 | } |
---|
364 | |
---|
365 | /* construct the header in temp storage */ |
---|
366 | memcpy(os->header,"OggS",4); |
---|
367 | |
---|
368 | /* stream structure version */ |
---|
369 | os->header[4]=0x00; |
---|
370 | |
---|
371 | /* continued packet flag? */ |
---|
372 | os->header[5]=0x00; |
---|
373 | if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; |
---|
374 | /* first page flag? */ |
---|
375 | if(os->b_o_s==0)os->header[5]|=0x02; |
---|
376 | /* last page flag? */ |
---|
377 | if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; |
---|
378 | os->b_o_s=1; |
---|
379 | |
---|
380 | /* 64 bits of PCM position */ |
---|
381 | for(i=6;i<14;i++){ |
---|
382 | os->header[i]=(unsigned char)(granule_pos&0xff); |
---|
383 | granule_pos>>=8; |
---|
384 | } |
---|
385 | |
---|
386 | /* 32 bits of stream serial number */ |
---|
387 | { |
---|
388 | long serialno=os->serialno; |
---|
389 | for(i=14;i<18;i++){ |
---|
390 | os->header[i]=(unsigned char)(serialno&0xff); |
---|
391 | serialno>>=8; |
---|
392 | } |
---|
393 | } |
---|
394 | |
---|
395 | /* 32 bits of page counter (we have both counter and page header |
---|
396 | because this val can roll over) */ |
---|
397 | if(os->pageno==-1)os->pageno=0; /* because someone called |
---|
398 | stream_reset; this would be a |
---|
399 | strange thing to do in an |
---|
400 | encode stream, but it has |
---|
401 | plausible uses */ |
---|
402 | { |
---|
403 | long pageno=os->pageno++; |
---|
404 | for(i=18;i<22;i++){ |
---|
405 | os->header[i]=(unsigned char)(pageno&0xff); |
---|
406 | pageno>>=8; |
---|
407 | } |
---|
408 | } |
---|
409 | |
---|
410 | /* zero for computation; filled in later */ |
---|
411 | os->header[22]=0; |
---|
412 | os->header[23]=0; |
---|
413 | os->header[24]=0; |
---|
414 | os->header[25]=0; |
---|
415 | |
---|
416 | /* segment table */ |
---|
417 | os->header[26]=(unsigned char)(vals&0xff); |
---|
418 | for(i=0;i<vals;i++) |
---|
419 | bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); |
---|
420 | |
---|
421 | /* set pointers in the ogg_page struct */ |
---|
422 | og->header=os->header; |
---|
423 | og->header_len=os->header_fill=vals+27; |
---|
424 | og->body=os->body_data+os->body_returned; |
---|
425 | og->body_len=bytes; |
---|
426 | |
---|
427 | /* advance the lacing data and set the body_returned pointer */ |
---|
428 | |
---|
429 | os->lacing_fill-=vals; |
---|
430 | memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); |
---|
431 | memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); |
---|
432 | os->body_returned+=bytes; |
---|
433 | |
---|
434 | /* calculate the checksum */ |
---|
435 | |
---|
436 | ogg_page_checksum_set(og); |
---|
437 | |
---|
438 | /* done */ |
---|
439 | return(1); |
---|
440 | } |
---|
441 | |
---|
442 | |
---|
443 | /* This constructs pages from buffered packet segments. The pointers |
---|
444 | returned are to static buffers; do not free. The returned buffers are |
---|
445 | good only until the next call (using the same ogg_stream_state) */ |
---|
446 | |
---|
447 | int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ |
---|
448 | |
---|
449 | if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ |
---|
450 | os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */ |
---|
451 | os->lacing_fill>=255 || /* 'segment table full' case */ |
---|
452 | (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */ |
---|
453 | |
---|
454 | return(ogg_stream_flush(os,og)); |
---|
455 | } |
---|
456 | |
---|
457 | /* not enough data to construct a page and not end of stream */ |
---|
458 | return(0); |
---|
459 | } |
---|
460 | |
---|
461 | int ogg_stream_eos(ogg_stream_state *os){ |
---|
462 | return os->e_o_s; |
---|
463 | } |
---|
464 | |
---|
465 | /* DECODING PRIMITIVES: packet streaming layer **********************/ |
---|
466 | |
---|
467 | /* This has two layers to place more of the multi-serialno and paging |
---|
468 | control in the application's hands. First, we expose a data buffer |
---|
469 | using ogg_sync_buffer(). The app either copies into the |
---|
470 | buffer, or passes it directly to read(), etc. We then call |
---|
471 | ogg_sync_wrote() to tell how many bytes we just added. |
---|
472 | |
---|
473 | Pages are returned (pointers into the buffer in ogg_sync_state) |
---|
474 | by ogg_sync_pageout(). The page is then submitted to |
---|
475 | ogg_stream_pagein() along with the appropriate |
---|
476 | ogg_stream_state* (ie, matching serialno). We then get raw |
---|
477 | packets out calling ogg_stream_packetout() with a |
---|
478 | ogg_stream_state. */ |
---|
479 | |
---|
480 | /* initialize the struct to a known state */ |
---|
481 | int ogg_sync_init(ogg_sync_state *oy){ |
---|
482 | if(oy){ |
---|
483 | memset(oy,0,sizeof(*oy)); |
---|
484 | } |
---|
485 | return(0); |
---|
486 | } |
---|
487 | |
---|
488 | /* clear non-flat storage within */ |
---|
489 | int ogg_sync_clear(ogg_sync_state *oy){ |
---|
490 | if(oy){ |
---|
491 | if(oy->data)_ogg_free(oy->data); |
---|
492 | ogg_sync_init(oy); |
---|
493 | } |
---|
494 | return(0); |
---|
495 | } |
---|
496 | |
---|
497 | int ogg_sync_destroy(ogg_sync_state *oy){ |
---|
498 | if(oy){ |
---|
499 | ogg_sync_clear(oy); |
---|
500 | _ogg_free(oy); |
---|
501 | } |
---|
502 | return(0); |
---|
503 | } |
---|
504 | |
---|
505 | char *ogg_sync_buffer(ogg_sync_state *oy, long size){ |
---|
506 | |
---|
507 | /* first, clear out any space that has been previously returned */ |
---|
508 | if(oy->returned){ |
---|
509 | oy->fill-=oy->returned; |
---|
510 | if(oy->fill>0) |
---|
511 | memmove(oy->data,oy->data+oy->returned,oy->fill); |
---|
512 | oy->returned=0; |
---|
513 | } |
---|
514 | |
---|
515 | if(size>oy->storage-oy->fill){ |
---|
516 | /* We need to extend the internal buffer */ |
---|
517 | long newsize=size+oy->fill+4096; /* an extra page to be nice */ |
---|
518 | |
---|
519 | if(oy->data) |
---|
520 | oy->data=_ogg_realloc(oy->data,newsize); |
---|
521 | else |
---|
522 | oy->data=_ogg_malloc(newsize); |
---|
523 | oy->storage=newsize; |
---|
524 | } |
---|
525 | |
---|
526 | /* expose a segment at least as large as requested at the fill mark */ |
---|
527 | return((char *)oy->data+oy->fill); |
---|
528 | } |
---|
529 | |
---|
530 | int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ |
---|
531 | if(oy->fill+bytes>oy->storage)return(-1); |
---|
532 | oy->fill+=bytes; |
---|
533 | return(0); |
---|
534 | } |
---|
535 | |
---|
536 | /* sync the stream. This is meant to be useful for finding page |
---|
537 | boundaries. |
---|
538 | |
---|
539 | return values for this: |
---|
540 | -n) skipped n bytes |
---|
541 | 0) page not ready; more data (no bytes skipped) |
---|
542 | n) page synced at current location; page length n bytes |
---|
543 | |
---|
544 | */ |
---|
545 | |
---|
546 | long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ |
---|
547 | unsigned char *page=oy->data+oy->returned; |
---|
548 | unsigned char *next; |
---|
549 | long bytes=oy->fill-oy->returned; |
---|
550 | |
---|
551 | if(oy->headerbytes==0){ |
---|
552 | int headerbytes,i; |
---|
553 | if(bytes<27)return(0); /* not enough for a header */ |
---|
554 | |
---|
555 | /* verify capture pattern */ |
---|
556 | if(memcmp(page,"OggS",4))goto sync_fail; |
---|
557 | |
---|
558 | headerbytes=page[26]+27; |
---|
559 | if(bytes<headerbytes)return(0); /* not enough for header + seg table */ |
---|
560 | |
---|
561 | /* count up body length in the segment table */ |
---|
562 | |
---|
563 | for(i=0;i<page[26];i++) |
---|
564 | oy->bodybytes+=page[27+i]; |
---|
565 | oy->headerbytes=headerbytes; |
---|
566 | } |
---|
567 | |
---|
568 | if(oy->bodybytes+oy->headerbytes>bytes)return(0); |
---|
569 | |
---|
570 | /* The whole test page is buffered. Verify the checksum */ |
---|
571 | { |
---|
572 | /* Grab the checksum bytes, set the header field to zero */ |
---|
573 | char chksum[4]; |
---|
574 | ogg_page log; |
---|
575 | |
---|
576 | memcpy(chksum,page+22,4); |
---|
577 | memset(page+22,0,4); |
---|
578 | |
---|
579 | /* set up a temp page struct and recompute the checksum */ |
---|
580 | log.header=page; |
---|
581 | log.header_len=oy->headerbytes; |
---|
582 | log.body=page+oy->headerbytes; |
---|
583 | log.body_len=oy->bodybytes; |
---|
584 | ogg_page_checksum_set(&log); |
---|
585 | |
---|
586 | /* Compare */ |
---|
587 | if(memcmp(chksum,page+22,4)){ |
---|
588 | /* D'oh. Mismatch! Corrupt page (or miscapture and not a page |
---|
589 | at all) */ |
---|
590 | /* replace the computed checksum with the one actually read in */ |
---|
591 | memcpy(page+22,chksum,4); |
---|
592 | |
---|
593 | /* Bad checksum. Lose sync */ |
---|
594 | goto sync_fail; |
---|
595 | } |
---|
596 | } |
---|
597 | |
---|
598 | /* yes, have a whole page all ready to go */ |
---|
599 | { |
---|
600 | unsigned char *page=oy->data+oy->returned; |
---|
601 | long bytes; |
---|
602 | |
---|
603 | if(og){ |
---|
604 | og->header=page; |
---|
605 | og->header_len=oy->headerbytes; |
---|
606 | og->body=page+oy->headerbytes; |
---|
607 | og->body_len=oy->bodybytes; |
---|
608 | } |
---|
609 | |
---|
610 | oy->unsynced=0; |
---|
611 | oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); |
---|
612 | oy->headerbytes=0; |
---|
613 | oy->bodybytes=0; |
---|
614 | return(bytes); |
---|
615 | } |
---|
616 | |
---|
617 | sync_fail: |
---|
618 | |
---|
619 | oy->headerbytes=0; |
---|
620 | oy->bodybytes=0; |
---|
621 | |
---|
622 | /* search for possible capture */ |
---|
623 | next=memchr(page+1,'O',bytes-1); |
---|
624 | if(!next) |
---|
625 | next=oy->data+oy->fill; |
---|
626 | |
---|
627 | oy->returned=next-oy->data; |
---|
628 | return(-(next-page)); |
---|
629 | } |
---|
630 | |
---|
631 | /* sync the stream and get a page. Keep trying until we find a page. |
---|
632 | Supress 'sync errors' after reporting the first. |
---|
633 | |
---|
634 | return values: |
---|
635 | -1) recapture (hole in data) |
---|
636 | 0) need more data |
---|
637 | 1) page returned |
---|
638 | |
---|
639 | Returns pointers into buffered data; invalidated by next call to |
---|
640 | _stream, _clear, _init, or _buffer */ |
---|
641 | |
---|
642 | int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ |
---|
643 | |
---|
644 | /* all we need to do is verify a page at the head of the stream |
---|
645 | buffer. If it doesn't verify, we look for the next potential |
---|
646 | frame */ |
---|
647 | |
---|
648 | for(;;){ |
---|
649 | long ret=ogg_sync_pageseek(oy,og); |
---|
650 | if(ret>0){ |
---|
651 | /* have a page */ |
---|
652 | return(1); |
---|
653 | } |
---|
654 | if(ret==0){ |
---|
655 | /* need more data */ |
---|
656 | return(0); |
---|
657 | } |
---|
658 | |
---|
659 | /* head did not start a synced page... skipped some bytes */ |
---|
660 | if(!oy->unsynced){ |
---|
661 | oy->unsynced=1; |
---|
662 | return(-1); |
---|
663 | } |
---|
664 | |
---|
665 | /* loop. keep looking */ |
---|
666 | |
---|
667 | } |
---|
668 | } |
---|
669 | |
---|
670 | /* add the incoming page to the stream state; we decompose the page |
---|
671 | into packet segments here as well. */ |
---|
672 | |
---|
673 | int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ |
---|
674 | unsigned char *header=og->header; |
---|
675 | unsigned char *body=og->body; |
---|
676 | long bodysize=og->body_len; |
---|
677 | int segptr=0; |
---|
678 | |
---|
679 | int version=ogg_page_version(og); |
---|
680 | int continued=ogg_page_continued(og); |
---|
681 | int bos=ogg_page_bos(og); |
---|
682 | int eos=ogg_page_eos(og); |
---|
683 | ogg_int64_t granulepos=ogg_page_granulepos(og); |
---|
684 | int serialno=ogg_page_serialno(og); |
---|
685 | long pageno=ogg_page_pageno(og); |
---|
686 | int segments=header[26]; |
---|
687 | |
---|
688 | /* clean up 'returned data' */ |
---|
689 | { |
---|
690 | long lr=os->lacing_returned; |
---|
691 | long br=os->body_returned; |
---|
692 | |
---|
693 | /* body data */ |
---|
694 | if(br){ |
---|
695 | os->body_fill-=br; |
---|
696 | if(os->body_fill) |
---|
697 | memmove(os->body_data,os->body_data+br,os->body_fill); |
---|
698 | os->body_returned=0; |
---|
699 | } |
---|
700 | |
---|
701 | if(lr){ |
---|
702 | /* segment table */ |
---|
703 | if(os->lacing_fill-lr){ |
---|
704 | memmove(os->lacing_vals,os->lacing_vals+lr, |
---|
705 | (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); |
---|
706 | memmove(os->granule_vals,os->granule_vals+lr, |
---|
707 | (os->lacing_fill-lr)*sizeof(*os->granule_vals)); |
---|
708 | } |
---|
709 | os->lacing_fill-=lr; |
---|
710 | os->lacing_packet-=lr; |
---|
711 | os->lacing_returned=0; |
---|
712 | } |
---|
713 | } |
---|
714 | |
---|
715 | /* check the serial number */ |
---|
716 | if(serialno!=os->serialno)return(-1); |
---|
717 | if(version>0)return(-1); |
---|
718 | |
---|
719 | _os_lacing_expand(os,segments+1); |
---|
720 | |
---|
721 | /* are we in sequence? */ |
---|
722 | if(pageno!=os->pageno){ |
---|
723 | int i; |
---|
724 | |
---|
725 | /* unroll previous partial packet (if any) */ |
---|
726 | for(i=os->lacing_packet;i<os->lacing_fill;i++) |
---|
727 | os->body_fill-=os->lacing_vals[i]&0xff; |
---|
728 | os->lacing_fill=os->lacing_packet; |
---|
729 | |
---|
730 | /* make a note of dropped data in segment table */ |
---|
731 | if(os->pageno!=-1){ |
---|
732 | os->lacing_vals[os->lacing_fill++]=0x400; |
---|
733 | os->lacing_packet++; |
---|
734 | } |
---|
735 | } |
---|
736 | |
---|
737 | /* are we a 'continued packet' page? If so, we may need to skip |
---|
738 | some segments */ |
---|
739 | if(continued){ |
---|
740 | if(os->lacing_fill<1 || |
---|
741 | os->lacing_vals[os->lacing_fill-1]==0x400){ |
---|
742 | bos=0; |
---|
743 | for(;segptr<segments;segptr++){ |
---|
744 | int val=header[27+segptr]; |
---|
745 | body+=val; |
---|
746 | bodysize-=val; |
---|
747 | if(val<255){ |
---|
748 | segptr++; |
---|
749 | break; |
---|
750 | } |
---|
751 | } |
---|
752 | } |
---|
753 | } |
---|
754 | |
---|
755 | if(bodysize){ |
---|
756 | _os_body_expand(os,bodysize); |
---|
757 | memcpy(os->body_data+os->body_fill,body,bodysize); |
---|
758 | os->body_fill+=bodysize; |
---|
759 | } |
---|
760 | |
---|
761 | { |
---|
762 | int saved=-1; |
---|
763 | while(segptr<segments){ |
---|
764 | int val=header[27+segptr]; |
---|
765 | os->lacing_vals[os->lacing_fill]=val; |
---|
766 | os->granule_vals[os->lacing_fill]=-1; |
---|
767 | |
---|
768 | if(bos){ |
---|
769 | os->lacing_vals[os->lacing_fill]|=0x100; |
---|
770 | bos=0; |
---|
771 | } |
---|
772 | |
---|
773 | if(val<255)saved=os->lacing_fill; |
---|
774 | |
---|
775 | os->lacing_fill++; |
---|
776 | segptr++; |
---|
777 | |
---|
778 | if(val<255)os->lacing_packet=os->lacing_fill; |
---|
779 | } |
---|
780 | |
---|
781 | /* set the granulepos on the last granuleval of the last full packet */ |
---|
782 | if(saved!=-1){ |
---|
783 | os->granule_vals[saved]=granulepos; |
---|
784 | } |
---|
785 | |
---|
786 | } |
---|
787 | |
---|
788 | if(eos){ |
---|
789 | os->e_o_s=1; |
---|
790 | if(os->lacing_fill>0) |
---|
791 | os->lacing_vals[os->lacing_fill-1]|=0x200; |
---|
792 | } |
---|
793 | |
---|
794 | os->pageno=pageno+1; |
---|
795 | |
---|
796 | return(0); |
---|
797 | } |
---|
798 | |
---|
799 | /* clear things to an initial state. Good to call, eg, before seeking */ |
---|
800 | int ogg_sync_reset(ogg_sync_state *oy){ |
---|
801 | oy->fill=0; |
---|
802 | oy->returned=0; |
---|
803 | oy->unsynced=0; |
---|
804 | oy->headerbytes=0; |
---|
805 | oy->bodybytes=0; |
---|
806 | return(0); |
---|
807 | } |
---|
808 | |
---|
809 | int ogg_stream_reset(ogg_stream_state *os){ |
---|
810 | os->body_fill=0; |
---|
811 | os->body_returned=0; |
---|
812 | |
---|
813 | os->lacing_fill=0; |
---|
814 | os->lacing_packet=0; |
---|
815 | os->lacing_returned=0; |
---|
816 | |
---|
817 | os->header_fill=0; |
---|
818 | |
---|
819 | os->e_o_s=0; |
---|
820 | os->b_o_s=0; |
---|
821 | os->pageno=-1; |
---|
822 | os->packetno=0; |
---|
823 | os->granulepos=0; |
---|
824 | |
---|
825 | return(0); |
---|
826 | } |
---|
827 | |
---|
828 | int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ |
---|
829 | ogg_stream_reset(os); |
---|
830 | os->serialno=serialno; |
---|
831 | return(0); |
---|
832 | } |
---|
833 | |
---|
834 | static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ |
---|
835 | |
---|
836 | /* The last part of decode. We have the stream broken into packet |
---|
837 | segments. Now we need to group them into packets (or return the |
---|
838 | out of sync markers) */ |
---|
839 | |
---|
840 | int ptr=os->lacing_returned; |
---|
841 | |
---|
842 | if(os->lacing_packet<=ptr)return(0); |
---|
843 | |
---|
844 | if(os->lacing_vals[ptr]&0x400){ |
---|
845 | /* we need to tell the codec there's a gap; it might need to |
---|
846 | handle previous packet dependencies. */ |
---|
847 | os->lacing_returned++; |
---|
848 | os->packetno++; |
---|
849 | return(-1); |
---|
850 | } |
---|
851 | |
---|
852 | if(!op && !adv)return(1); /* just using peek as an inexpensive way |
---|
853 | to ask if there's a whole packet |
---|
854 | waiting */ |
---|
855 | |
---|
856 | /* Gather the whole packet. We'll have no holes or a partial packet */ |
---|
857 | { |
---|
858 | int size=os->lacing_vals[ptr]&0xff; |
---|
859 | int bytes=size; |
---|
860 | int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ |
---|
861 | int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ |
---|
862 | |
---|
863 | while(size==255){ |
---|
864 | int val=os->lacing_vals[++ptr]; |
---|
865 | size=val&0xff; |
---|
866 | if(val&0x200)eos=0x200; |
---|
867 | bytes+=size; |
---|
868 | } |
---|
869 | |
---|
870 | if(op){ |
---|
871 | op->e_o_s=eos; |
---|
872 | op->b_o_s=bos; |
---|
873 | op->packet=os->body_data+os->body_returned; |
---|
874 | op->packetno=os->packetno; |
---|
875 | op->granulepos=os->granule_vals[ptr]; |
---|
876 | op->bytes=bytes; |
---|
877 | } |
---|
878 | |
---|
879 | if(adv){ |
---|
880 | os->body_returned+=bytes; |
---|
881 | os->lacing_returned=ptr+1; |
---|
882 | os->packetno++; |
---|
883 | } |
---|
884 | } |
---|
885 | return(1); |
---|
886 | } |
---|
887 | |
---|
888 | int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ |
---|
889 | return _packetout(os,op,1); |
---|
890 | } |
---|
891 | |
---|
892 | int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ |
---|
893 | return _packetout(os,op,0); |
---|
894 | } |
---|
895 | |
---|
896 | void ogg_packet_clear(ogg_packet *op) { |
---|
897 | _ogg_free(op->packet); |
---|
898 | memset(op, 0, sizeof(*op)); |
---|
899 | } |
---|
900 | |
---|
901 | #ifdef _V_SELFTEST |
---|
902 | #include <stdio.h> |
---|
903 | |
---|
904 | ogg_stream_state os_en, os_de; |
---|
905 | ogg_sync_state oy; |
---|
906 | |
---|
907 | void checkpacket(ogg_packet *op,int len, int no, int pos){ |
---|
908 | long j; |
---|
909 | static int sequence=0; |
---|
910 | static int lastno=0; |
---|
911 | |
---|
912 | if(op->bytes!=len){ |
---|
913 | fprintf(stderr,"incorrect packet length!\n"); |
---|
914 | exit(1); |
---|
915 | } |
---|
916 | if(op->granulepos!=pos){ |
---|
917 | fprintf(stderr,"incorrect packet position!\n"); |
---|
918 | exit(1); |
---|
919 | } |
---|
920 | |
---|
921 | /* packet number just follows sequence/gap; adjust the input number |
---|
922 | for that */ |
---|
923 | if(no==0){ |
---|
924 | sequence=0; |
---|
925 | }else{ |
---|
926 | sequence++; |
---|
927 | if(no>lastno+1) |
---|
928 | sequence++; |
---|
929 | } |
---|
930 | lastno=no; |
---|
931 | if(op->packetno!=sequence){ |
---|
932 | fprintf(stderr,"incorrect packet sequence %ld != %d\n", |
---|
933 | (long)(op->packetno),sequence); |
---|
934 | exit(1); |
---|
935 | } |
---|
936 | |
---|
937 | /* Test data */ |
---|
938 | for(j=0;j<op->bytes;j++) |
---|
939 | if(op->packet[j]!=((j+no)&0xff)){ |
---|
940 | fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", |
---|
941 | j,op->packet[j],(j+no)&0xff); |
---|
942 | exit(1); |
---|
943 | } |
---|
944 | } |
---|
945 | |
---|
946 | void check_page(unsigned char *data,const int *header,ogg_page *og){ |
---|
947 | long j; |
---|
948 | /* Test data */ |
---|
949 | for(j=0;j<og->body_len;j++) |
---|
950 | if(og->body[j]!=data[j]){ |
---|
951 | fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", |
---|
952 | j,data[j],og->body[j]); |
---|
953 | exit(1); |
---|
954 | } |
---|
955 | |
---|
956 | /* Test header */ |
---|
957 | for(j=0;j<og->header_len;j++){ |
---|
958 | if(og->header[j]!=header[j]){ |
---|
959 | fprintf(stderr,"header content mismatch at pos %ld:\n",j); |
---|
960 | for(j=0;j<header[26]+27;j++) |
---|
961 | fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]); |
---|
962 | fprintf(stderr,"\n"); |
---|
963 | exit(1); |
---|
964 | } |
---|
965 | } |
---|
966 | if(og->header_len!=header[26]+27){ |
---|
967 | fprintf(stderr,"header length incorrect! (%ld!=%d)\n", |
---|
968 | og->header_len,header[26]+27); |
---|
969 | exit(1); |
---|
970 | } |
---|
971 | } |
---|
972 | |
---|
973 | void print_header(ogg_page *og){ |
---|
974 | int j; |
---|
975 | fprintf(stderr,"\nHEADER:\n"); |
---|
976 | fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", |
---|
977 | og->header[0],og->header[1],og->header[2],og->header[3], |
---|
978 | (int)og->header[4],(int)og->header[5]); |
---|
979 | |
---|
980 | fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", |
---|
981 | (og->header[9]<<24)|(og->header[8]<<16)| |
---|
982 | (og->header[7]<<8)|og->header[6], |
---|
983 | (og->header[17]<<24)|(og->header[16]<<16)| |
---|
984 | (og->header[15]<<8)|og->header[14], |
---|
985 | ((long)(og->header[21])<<24)|(og->header[20]<<16)| |
---|
986 | (og->header[19]<<8)|og->header[18]); |
---|
987 | |
---|
988 | fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", |
---|
989 | (int)og->header[22],(int)og->header[23], |
---|
990 | (int)og->header[24],(int)og->header[25], |
---|
991 | (int)og->header[26]); |
---|
992 | |
---|
993 | for(j=27;j<og->header_len;j++) |
---|
994 | fprintf(stderr,"%d ",(int)og->header[j]); |
---|
995 | fprintf(stderr,")\n\n"); |
---|
996 | } |
---|
997 | |
---|
998 | void copy_page(ogg_page *og){ |
---|
999 | unsigned char *temp=_ogg_malloc(og->header_len); |
---|
1000 | memcpy(temp,og->header,og->header_len); |
---|
1001 | og->header=temp; |
---|
1002 | |
---|
1003 | temp=_ogg_malloc(og->body_len); |
---|
1004 | memcpy(temp,og->body,og->body_len); |
---|
1005 | og->body=temp; |
---|
1006 | } |
---|
1007 | |
---|
1008 | void free_page(ogg_page *og){ |
---|
1009 | _ogg_free (og->header); |
---|
1010 | _ogg_free (og->body); |
---|
1011 | } |
---|
1012 | |
---|
1013 | void error(void){ |
---|
1014 | fprintf(stderr,"error!\n"); |
---|
1015 | exit(1); |
---|
1016 | } |
---|
1017 | |
---|
1018 | /* 17 only */ |
---|
1019 | const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, |
---|
1020 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1021 | 0x01,0x02,0x03,0x04,0,0,0,0, |
---|
1022 | 0x15,0xed,0xec,0x91, |
---|
1023 | 1, |
---|
1024 | 17}; |
---|
1025 | |
---|
1026 | /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ |
---|
1027 | const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, |
---|
1028 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1029 | 0x01,0x02,0x03,0x04,0,0,0,0, |
---|
1030 | 0x59,0x10,0x6c,0x2c, |
---|
1031 | 1, |
---|
1032 | 17}; |
---|
1033 | const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, |
---|
1034 | 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1035 | 0x01,0x02,0x03,0x04,1,0,0,0, |
---|
1036 | 0x89,0x33,0x85,0xce, |
---|
1037 | 13, |
---|
1038 | 254,255,0,255,1,255,245,255,255,0, |
---|
1039 | 255,255,90}; |
---|
1040 | |
---|
1041 | /* nil packets; beginning,middle,end */ |
---|
1042 | const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, |
---|
1043 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1044 | 0x01,0x02,0x03,0x04,0,0,0,0, |
---|
1045 | 0xff,0x7b,0x23,0x17, |
---|
1046 | 1, |
---|
1047 | 0}; |
---|
1048 | const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, |
---|
1049 | 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1050 | 0x01,0x02,0x03,0x04,1,0,0,0, |
---|
1051 | 0x5c,0x3f,0x66,0xcb, |
---|
1052 | 17, |
---|
1053 | 17,254,255,0,0,255,1,0,255,245,255,255,0, |
---|
1054 | 255,255,90,0}; |
---|
1055 | |
---|
1056 | /* large initial packet */ |
---|
1057 | const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, |
---|
1058 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1059 | 0x01,0x02,0x03,0x04,0,0,0,0, |
---|
1060 | 0x01,0x27,0x31,0xaa, |
---|
1061 | 18, |
---|
1062 | 255,255,255,255,255,255,255,255, |
---|
1063 | 255,255,255,255,255,255,255,255,255,10}; |
---|
1064 | |
---|
1065 | const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, |
---|
1066 | 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1067 | 0x01,0x02,0x03,0x04,1,0,0,0, |
---|
1068 | 0x7f,0x4e,0x8a,0xd2, |
---|
1069 | 4, |
---|
1070 | 255,4,255,0}; |
---|
1071 | |
---|
1072 | |
---|
1073 | /* continuing packet test */ |
---|
1074 | const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, |
---|
1075 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1076 | 0x01,0x02,0x03,0x04,0,0,0,0, |
---|
1077 | 0xff,0x7b,0x23,0x17, |
---|
1078 | 1, |
---|
1079 | 0}; |
---|
1080 | |
---|
1081 | const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, |
---|
1082 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, |
---|
1083 | 0x01,0x02,0x03,0x04,1,0,0,0, |
---|
1084 | 0x54,0x05,0x51,0xc8, |
---|
1085 | 17, |
---|
1086 | 255,255,255,255,255,255,255,255, |
---|
1087 | 255,255,255,255,255,255,255,255,255}; |
---|
1088 | |
---|
1089 | const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, |
---|
1090 | 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1091 | 0x01,0x02,0x03,0x04,2,0,0,0, |
---|
1092 | 0xc8,0xc3,0xcb,0xed, |
---|
1093 | 5, |
---|
1094 | 10,255,4,255,0}; |
---|
1095 | |
---|
1096 | |
---|
1097 | /* page with the 255 segment limit */ |
---|
1098 | const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, |
---|
1099 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1100 | 0x01,0x02,0x03,0x04,0,0,0,0, |
---|
1101 | 0xff,0x7b,0x23,0x17, |
---|
1102 | 1, |
---|
1103 | 0}; |
---|
1104 | |
---|
1105 | const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, |
---|
1106 | 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, |
---|
1107 | 0x01,0x02,0x03,0x04,1,0,0,0, |
---|
1108 | 0xed,0x2a,0x2e,0xa7, |
---|
1109 | 255, |
---|
1110 | 10,10,10,10,10,10,10,10, |
---|
1111 | 10,10,10,10,10,10,10,10, |
---|
1112 | 10,10,10,10,10,10,10,10, |
---|
1113 | 10,10,10,10,10,10,10,10, |
---|
1114 | 10,10,10,10,10,10,10,10, |
---|
1115 | 10,10,10,10,10,10,10,10, |
---|
1116 | 10,10,10,10,10,10,10,10, |
---|
1117 | 10,10,10,10,10,10,10,10, |
---|
1118 | 10,10,10,10,10,10,10,10, |
---|
1119 | 10,10,10,10,10,10,10,10, |
---|
1120 | 10,10,10,10,10,10,10,10, |
---|
1121 | 10,10,10,10,10,10,10,10, |
---|
1122 | 10,10,10,10,10,10,10,10, |
---|
1123 | 10,10,10,10,10,10,10,10, |
---|
1124 | 10,10,10,10,10,10,10,10, |
---|
1125 | 10,10,10,10,10,10,10,10, |
---|
1126 | 10,10,10,10,10,10,10,10, |
---|
1127 | 10,10,10,10,10,10,10,10, |
---|
1128 | 10,10,10,10,10,10,10,10, |
---|
1129 | 10,10,10,10,10,10,10,10, |
---|
1130 | 10,10,10,10,10,10,10,10, |
---|
1131 | 10,10,10,10,10,10,10,10, |
---|
1132 | 10,10,10,10,10,10,10,10, |
---|
1133 | 10,10,10,10,10,10,10,10, |
---|
1134 | 10,10,10,10,10,10,10,10, |
---|
1135 | 10,10,10,10,10,10,10,10, |
---|
1136 | 10,10,10,10,10,10,10,10, |
---|
1137 | 10,10,10,10,10,10,10,10, |
---|
1138 | 10,10,10,10,10,10,10,10, |
---|
1139 | 10,10,10,10,10,10,10,10, |
---|
1140 | 10,10,10,10,10,10,10,10, |
---|
1141 | 10,10,10,10,10,10,10}; |
---|
1142 | |
---|
1143 | const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, |
---|
1144 | 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, |
---|
1145 | 0x01,0x02,0x03,0x04,2,0,0,0, |
---|
1146 | 0x6c,0x3b,0x82,0x3d, |
---|
1147 | 1, |
---|
1148 | 50}; |
---|
1149 | |
---|
1150 | |
---|
1151 | /* packet that overspans over an entire page */ |
---|
1152 | const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, |
---|
1153 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1154 | 0x01,0x02,0x03,0x04,0,0,0,0, |
---|
1155 | 0xff,0x7b,0x23,0x17, |
---|
1156 | 1, |
---|
1157 | 0}; |
---|
1158 | |
---|
1159 | const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, |
---|
1160 | 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1161 | 0x01,0x02,0x03,0x04,1,0,0,0, |
---|
1162 | 0x3c,0xd9,0x4d,0x3f, |
---|
1163 | 17, |
---|
1164 | 100,255,255,255,255,255,255,255,255, |
---|
1165 | 255,255,255,255,255,255,255,255}; |
---|
1166 | |
---|
1167 | const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, |
---|
1168 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, |
---|
1169 | 0x01,0x02,0x03,0x04,2,0,0,0, |
---|
1170 | 0x01,0xd2,0xe5,0xe5, |
---|
1171 | 17, |
---|
1172 | 255,255,255,255,255,255,255,255, |
---|
1173 | 255,255,255,255,255,255,255,255,255}; |
---|
1174 | |
---|
1175 | const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, |
---|
1176 | 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1177 | 0x01,0x02,0x03,0x04,3,0,0,0, |
---|
1178 | 0xef,0xdd,0x88,0xde, |
---|
1179 | 7, |
---|
1180 | 255,255,75,255,4,255,0}; |
---|
1181 | |
---|
1182 | /* packet that overspans over an entire page */ |
---|
1183 | const int head1_7[] = {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 | 0xff,0x7b,0x23,0x17, |
---|
1187 | 1, |
---|
1188 | 0}; |
---|
1189 | |
---|
1190 | const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, |
---|
1191 | 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1192 | 0x01,0x02,0x03,0x04,1,0,0,0, |
---|
1193 | 0x3c,0xd9,0x4d,0x3f, |
---|
1194 | 17, |
---|
1195 | 100,255,255,255,255,255,255,255,255, |
---|
1196 | 255,255,255,255,255,255,255,255}; |
---|
1197 | |
---|
1198 | const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, |
---|
1199 | 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, |
---|
1200 | 0x01,0x02,0x03,0x04,2,0,0,0, |
---|
1201 | 0xd4,0xe0,0x60,0xe5, |
---|
1202 | 1,0}; |
---|
1203 | |
---|
1204 | void test_pack(const int *pl, const int **headers, int byteskip, |
---|
1205 | int pageskip, int packetskip){ |
---|
1206 | unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ |
---|
1207 | long inptr=0; |
---|
1208 | long outptr=0; |
---|
1209 | long deptr=0; |
---|
1210 | long depacket=0; |
---|
1211 | long granule_pos=7,pageno=0; |
---|
1212 | int i,j,packets,pageout=pageskip; |
---|
1213 | int eosflag=0; |
---|
1214 | int bosflag=0; |
---|
1215 | |
---|
1216 | int byteskipcount=0; |
---|
1217 | |
---|
1218 | ogg_stream_reset(&os_en); |
---|
1219 | ogg_stream_reset(&os_de); |
---|
1220 | ogg_sync_reset(&oy); |
---|
1221 | |
---|
1222 | for(packets=0;packets<packetskip;packets++) |
---|
1223 | depacket+=pl[packets]; |
---|
1224 | |
---|
1225 | for(packets=0;;packets++)if(pl[packets]==-1)break; |
---|
1226 | |
---|
1227 | for(i=0;i<packets;i++){ |
---|
1228 | /* construct a test packet */ |
---|
1229 | ogg_packet op; |
---|
1230 | int len=pl[i]; |
---|
1231 | |
---|
1232 | op.packet=data+inptr; |
---|
1233 | op.bytes=len; |
---|
1234 | op.e_o_s=(pl[i+1]<0?1:0); |
---|
1235 | op.granulepos=granule_pos; |
---|
1236 | |
---|
1237 | granule_pos+=1024; |
---|
1238 | |
---|
1239 | for(j=0;j<len;j++)data[inptr++]=i+j; |
---|
1240 | |
---|
1241 | /* submit the test packet */ |
---|
1242 | ogg_stream_packetin(&os_en,&op); |
---|
1243 | |
---|
1244 | /* retrieve any finished pages */ |
---|
1245 | { |
---|
1246 | ogg_page og; |
---|
1247 | |
---|
1248 | while(ogg_stream_pageout(&os_en,&og)){ |
---|
1249 | /* We have a page. Check it carefully */ |
---|
1250 | |
---|
1251 | fprintf(stderr,"%ld, ",pageno); |
---|
1252 | |
---|
1253 | if(headers[pageno]==NULL){ |
---|
1254 | fprintf(stderr,"coded too many pages!\n"); |
---|
1255 | exit(1); |
---|
1256 | } |
---|
1257 | |
---|
1258 | check_page(data+outptr,headers[pageno],&og); |
---|
1259 | |
---|
1260 | outptr+=og.body_len; |
---|
1261 | pageno++; |
---|
1262 | if(pageskip){ |
---|
1263 | bosflag=1; |
---|
1264 | pageskip--; |
---|
1265 | deptr+=og.body_len; |
---|
1266 | } |
---|
1267 | |
---|
1268 | /* have a complete page; submit it to sync/decode */ |
---|
1269 | |
---|
1270 | { |
---|
1271 | ogg_page og_de; |
---|
1272 | ogg_packet op_de,op_de2; |
---|
1273 | char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len); |
---|
1274 | char *next=buf; |
---|
1275 | byteskipcount+=og.header_len; |
---|
1276 | if(byteskipcount>byteskip){ |
---|
1277 | memcpy(next,og.header,byteskipcount-byteskip); |
---|
1278 | next+=byteskipcount-byteskip; |
---|
1279 | byteskipcount=byteskip; |
---|
1280 | } |
---|
1281 | |
---|
1282 | byteskipcount+=og.body_len; |
---|
1283 | if(byteskipcount>byteskip){ |
---|
1284 | memcpy(next,og.body,byteskipcount-byteskip); |
---|
1285 | next+=byteskipcount-byteskip; |
---|
1286 | byteskipcount=byteskip; |
---|
1287 | } |
---|
1288 | |
---|
1289 | ogg_sync_wrote(&oy,next-buf); |
---|
1290 | |
---|
1291 | while(1){ |
---|
1292 | int ret=ogg_sync_pageout(&oy,&og_de); |
---|
1293 | if(ret==0)break; |
---|
1294 | if(ret<0)continue; |
---|
1295 | /* got a page. Happy happy. Verify that it's good. */ |
---|
1296 | |
---|
1297 | fprintf(stderr,"(%ld), ",pageout); |
---|
1298 | |
---|
1299 | check_page(data+deptr,headers[pageout],&og_de); |
---|
1300 | deptr+=og_de.body_len; |
---|
1301 | pageout++; |
---|
1302 | |
---|
1303 | /* submit it to deconstitution */ |
---|
1304 | ogg_stream_pagein(&os_de,&og_de); |
---|
1305 | |
---|
1306 | /* packets out? */ |
---|
1307 | while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ |
---|
1308 | ogg_stream_packetpeek(&os_de,NULL); |
---|
1309 | ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ |
---|
1310 | |
---|
1311 | /* verify peek and out match */ |
---|
1312 | if(memcmp(&op_de,&op_de2,sizeof(op_de))){ |
---|
1313 | fprintf(stderr,"packetout != packetpeek! pos=%ld\n", |
---|
1314 | depacket); |
---|
1315 | exit(1); |
---|
1316 | } |
---|
1317 | |
---|
1318 | /* verify the packet! */ |
---|
1319 | /* check data */ |
---|
1320 | if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ |
---|
1321 | fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", |
---|
1322 | depacket); |
---|
1323 | exit(1); |
---|
1324 | } |
---|
1325 | /* check bos flag */ |
---|
1326 | if(bosflag==0 && op_de.b_o_s==0){ |
---|
1327 | fprintf(stderr,"b_o_s flag not set on packet!\n"); |
---|
1328 | exit(1); |
---|
1329 | } |
---|
1330 | if(bosflag && op_de.b_o_s){ |
---|
1331 | fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); |
---|
1332 | exit(1); |
---|
1333 | } |
---|
1334 | bosflag=1; |
---|
1335 | depacket+=op_de.bytes; |
---|
1336 | |
---|
1337 | /* check eos flag */ |
---|
1338 | if(eosflag){ |
---|
1339 | fprintf(stderr,"Multiple decoded packets with eos flag!\n"); |
---|
1340 | exit(1); |
---|
1341 | } |
---|
1342 | |
---|
1343 | if(op_de.e_o_s)eosflag=1; |
---|
1344 | |
---|
1345 | /* check granulepos flag */ |
---|
1346 | if(op_de.granulepos!=-1){ |
---|
1347 | fprintf(stderr," granule:%ld ",(long)op_de.granulepos); |
---|
1348 | } |
---|
1349 | } |
---|
1350 | } |
---|
1351 | } |
---|
1352 | } |
---|
1353 | } |
---|
1354 | } |
---|
1355 | _ogg_free(data); |
---|
1356 | if(headers[pageno]!=NULL){ |
---|
1357 | fprintf(stderr,"did not write last page!\n"); |
---|
1358 | exit(1); |
---|
1359 | } |
---|
1360 | if(headers[pageout]!=NULL){ |
---|
1361 | fprintf(stderr,"did not decode last page!\n"); |
---|
1362 | exit(1); |
---|
1363 | } |
---|
1364 | if(inptr!=outptr){ |
---|
1365 | fprintf(stderr,"encoded page data incomplete!\n"); |
---|
1366 | exit(1); |
---|
1367 | } |
---|
1368 | if(inptr!=deptr){ |
---|
1369 | fprintf(stderr,"decoded page data incomplete!\n"); |
---|
1370 | exit(1); |
---|
1371 | } |
---|
1372 | if(inptr!=depacket){ |
---|
1373 | fprintf(stderr,"decoded packet data incomplete!\n"); |
---|
1374 | exit(1); |
---|
1375 | } |
---|
1376 | if(!eosflag){ |
---|
1377 | fprintf(stderr,"Never got a packet with EOS set!\n"); |
---|
1378 | exit(1); |
---|
1379 | } |
---|
1380 | fprintf(stderr,"ok.\n"); |
---|
1381 | } |
---|
1382 | |
---|
1383 | int main(void){ |
---|
1384 | |
---|
1385 | ogg_stream_init(&os_en,0x04030201); |
---|
1386 | ogg_stream_init(&os_de,0x04030201); |
---|
1387 | ogg_sync_init(&oy); |
---|
1388 | |
---|
1389 | /* Exercise each code path in the framing code. Also verify that |
---|
1390 | the checksums are working. */ |
---|
1391 | |
---|
1392 | { |
---|
1393 | /* 17 only */ |
---|
1394 | const int packets[]={17, -1}; |
---|
1395 | const int *headret[]={head1_0,NULL}; |
---|
1396 | |
---|
1397 | fprintf(stderr,"testing single page encoding... "); |
---|
1398 | test_pack(packets,headret,0,0,0); |
---|
1399 | } |
---|
1400 | |
---|
1401 | { |
---|
1402 | /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ |
---|
1403 | const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; |
---|
1404 | const int *headret[]={head1_1,head2_1,NULL}; |
---|
1405 | |
---|
1406 | fprintf(stderr,"testing basic page encoding... "); |
---|
1407 | test_pack(packets,headret,0,0,0); |
---|
1408 | } |
---|
1409 | |
---|
1410 | { |
---|
1411 | /* nil packets; beginning,middle,end */ |
---|
1412 | const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; |
---|
1413 | const int *headret[]={head1_2,head2_2,NULL}; |
---|
1414 | |
---|
1415 | fprintf(stderr,"testing basic nil packets... "); |
---|
1416 | test_pack(packets,headret,0,0,0); |
---|
1417 | } |
---|
1418 | |
---|
1419 | { |
---|
1420 | /* large initial packet */ |
---|
1421 | const int packets[]={4345,259,255,-1}; |
---|
1422 | const int *headret[]={head1_3,head2_3,NULL}; |
---|
1423 | |
---|
1424 | fprintf(stderr,"testing initial-packet lacing > 4k... "); |
---|
1425 | test_pack(packets,headret,0,0,0); |
---|
1426 | } |
---|
1427 | |
---|
1428 | { |
---|
1429 | /* continuing packet test */ |
---|
1430 | const int packets[]={0,4345,259,255,-1}; |
---|
1431 | const int *headret[]={head1_4,head2_4,head3_4,NULL}; |
---|
1432 | |
---|
1433 | fprintf(stderr,"testing single packet page span... "); |
---|
1434 | test_pack(packets,headret,0,0,0); |
---|
1435 | } |
---|
1436 | |
---|
1437 | /* page with the 255 segment limit */ |
---|
1438 | { |
---|
1439 | |
---|
1440 | const int packets[]={0,10,10,10,10,10,10,10,10, |
---|
1441 | 10,10,10,10,10,10,10,10, |
---|
1442 | 10,10,10,10,10,10,10,10, |
---|
1443 | 10,10,10,10,10,10,10,10, |
---|
1444 | 10,10,10,10,10,10,10,10, |
---|
1445 | 10,10,10,10,10,10,10,10, |
---|
1446 | 10,10,10,10,10,10,10,10, |
---|
1447 | 10,10,10,10,10,10,10,10, |
---|
1448 | 10,10,10,10,10,10,10,10, |
---|
1449 | 10,10,10,10,10,10,10,10, |
---|
1450 | 10,10,10,10,10,10,10,10, |
---|
1451 | 10,10,10,10,10,10,10,10, |
---|
1452 | 10,10,10,10,10,10,10,10, |
---|
1453 | 10,10,10,10,10,10,10,10, |
---|
1454 | 10,10,10,10,10,10,10,10, |
---|
1455 | 10,10,10,10,10,10,10,10, |
---|
1456 | 10,10,10,10,10,10,10,10, |
---|
1457 | 10,10,10,10,10,10,10,10, |
---|
1458 | 10,10,10,10,10,10,10,10, |
---|
1459 | 10,10,10,10,10,10,10,10, |
---|
1460 | 10,10,10,10,10,10,10,10, |
---|
1461 | 10,10,10,10,10,10,10,10, |
---|
1462 | 10,10,10,10,10,10,10,10, |
---|
1463 | 10,10,10,10,10,10,10,10, |
---|
1464 | 10,10,10,10,10,10,10,10, |
---|
1465 | 10,10,10,10,10,10,10,10, |
---|
1466 | 10,10,10,10,10,10,10,10, |
---|
1467 | 10,10,10,10,10,10,10,10, |
---|
1468 | 10,10,10,10,10,10,10,10, |
---|
1469 | 10,10,10,10,10,10,10,10, |
---|
1470 | 10,10,10,10,10,10,10,10, |
---|
1471 | 10,10,10,10,10,10,10,50,-1}; |
---|
1472 | const int *headret[]={head1_5,head2_5,head3_5,NULL}; |
---|
1473 | |
---|
1474 | fprintf(stderr,"testing max packet segments... "); |
---|
1475 | test_pack(packets,headret,0,0,0); |
---|
1476 | } |
---|
1477 | |
---|
1478 | { |
---|
1479 | /* packet that overspans over an entire page */ |
---|
1480 | const int packets[]={0,100,9000,259,255,-1}; |
---|
1481 | const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; |
---|
1482 | |
---|
1483 | fprintf(stderr,"testing very large packets... "); |
---|
1484 | test_pack(packets,headret,0,0,0); |
---|
1485 | } |
---|
1486 | |
---|
1487 | { |
---|
1488 | /* test for the libogg 1.1.1 resync in large continuation bug |
---|
1489 | found by Josh Coalson) */ |
---|
1490 | const int packets[]={0,100,9000,259,255,-1}; |
---|
1491 | const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; |
---|
1492 | |
---|
1493 | fprintf(stderr,"testing continuation resync in very large packets... "); |
---|
1494 | test_pack(packets,headret,100,2,3); |
---|
1495 | } |
---|
1496 | |
---|
1497 | { |
---|
1498 | /* term only page. why not? */ |
---|
1499 | const int packets[]={0,100,4080,-1}; |
---|
1500 | const int *headret[]={head1_7,head2_7,head3_7,NULL}; |
---|
1501 | |
---|
1502 | fprintf(stderr,"testing zero data page (1 nil packet)... "); |
---|
1503 | test_pack(packets,headret,0,0,0); |
---|
1504 | } |
---|
1505 | |
---|
1506 | |
---|
1507 | |
---|
1508 | { |
---|
1509 | /* build a bunch of pages for testing */ |
---|
1510 | unsigned char *data=_ogg_malloc(1024*1024); |
---|
1511 | int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1}; |
---|
1512 | int inptr=0,i,j; |
---|
1513 | ogg_page og[5]; |
---|
1514 | |
---|
1515 | ogg_stream_reset(&os_en); |
---|
1516 | |
---|
1517 | for(i=0;pl[i]!=-1;i++){ |
---|
1518 | ogg_packet op; |
---|
1519 | int len=pl[i]; |
---|
1520 | |
---|
1521 | op.packet=data+inptr; |
---|
1522 | op.bytes=len; |
---|
1523 | op.e_o_s=(pl[i+1]<0?1:0); |
---|
1524 | op.granulepos=(i+1)*1000; |
---|
1525 | |
---|
1526 | for(j=0;j<len;j++)data[inptr++]=i+j; |
---|
1527 | ogg_stream_packetin(&os_en,&op); |
---|
1528 | } |
---|
1529 | |
---|
1530 | _ogg_free(data); |
---|
1531 | |
---|
1532 | /* retrieve finished pages */ |
---|
1533 | for(i=0;i<5;i++){ |
---|
1534 | if(ogg_stream_pageout(&os_en,&og[i])==0){ |
---|
1535 | fprintf(stderr,"Too few pages output building sync tests!\n"); |
---|
1536 | exit(1); |
---|
1537 | } |
---|
1538 | copy_page(&og[i]); |
---|
1539 | } |
---|
1540 | |
---|
1541 | /* Test lost pages on pagein/packetout: no rollback */ |
---|
1542 | { |
---|
1543 | ogg_page temp; |
---|
1544 | ogg_packet test; |
---|
1545 | |
---|
1546 | fprintf(stderr,"Testing loss of pages... "); |
---|
1547 | |
---|
1548 | ogg_sync_reset(&oy); |
---|
1549 | ogg_stream_reset(&os_de); |
---|
1550 | for(i=0;i<5;i++){ |
---|
1551 | memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, |
---|
1552 | og[i].header_len); |
---|
1553 | ogg_sync_wrote(&oy,og[i].header_len); |
---|
1554 | memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); |
---|
1555 | ogg_sync_wrote(&oy,og[i].body_len); |
---|
1556 | } |
---|
1557 | |
---|
1558 | ogg_sync_pageout(&oy,&temp); |
---|
1559 | ogg_stream_pagein(&os_de,&temp); |
---|
1560 | ogg_sync_pageout(&oy,&temp); |
---|
1561 | ogg_stream_pagein(&os_de,&temp); |
---|
1562 | ogg_sync_pageout(&oy,&temp); |
---|
1563 | /* skip */ |
---|
1564 | ogg_sync_pageout(&oy,&temp); |
---|
1565 | ogg_stream_pagein(&os_de,&temp); |
---|
1566 | |
---|
1567 | /* do we get the expected results/packets? */ |
---|
1568 | |
---|
1569 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1570 | checkpacket(&test,0,0,0); |
---|
1571 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1572 | checkpacket(&test,100,1,-1); |
---|
1573 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1574 | checkpacket(&test,4079,2,3000); |
---|
1575 | if(ogg_stream_packetout(&os_de,&test)!=-1){ |
---|
1576 | fprintf(stderr,"Error: loss of page did not return error\n"); |
---|
1577 | exit(1); |
---|
1578 | } |
---|
1579 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1580 | checkpacket(&test,76,5,-1); |
---|
1581 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1582 | checkpacket(&test,34,6,-1); |
---|
1583 | fprintf(stderr,"ok.\n"); |
---|
1584 | } |
---|
1585 | |
---|
1586 | /* Test lost pages on pagein/packetout: rollback with continuation */ |
---|
1587 | { |
---|
1588 | ogg_page temp; |
---|
1589 | ogg_packet test; |
---|
1590 | |
---|
1591 | fprintf(stderr,"Testing loss of pages (rollback required)... "); |
---|
1592 | |
---|
1593 | ogg_sync_reset(&oy); |
---|
1594 | ogg_stream_reset(&os_de); |
---|
1595 | for(i=0;i<5;i++){ |
---|
1596 | memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, |
---|
1597 | og[i].header_len); |
---|
1598 | ogg_sync_wrote(&oy,og[i].header_len); |
---|
1599 | memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); |
---|
1600 | ogg_sync_wrote(&oy,og[i].body_len); |
---|
1601 | } |
---|
1602 | |
---|
1603 | ogg_sync_pageout(&oy,&temp); |
---|
1604 | ogg_stream_pagein(&os_de,&temp); |
---|
1605 | ogg_sync_pageout(&oy,&temp); |
---|
1606 | ogg_stream_pagein(&os_de,&temp); |
---|
1607 | ogg_sync_pageout(&oy,&temp); |
---|
1608 | ogg_stream_pagein(&os_de,&temp); |
---|
1609 | ogg_sync_pageout(&oy,&temp); |
---|
1610 | /* skip */ |
---|
1611 | ogg_sync_pageout(&oy,&temp); |
---|
1612 | ogg_stream_pagein(&os_de,&temp); |
---|
1613 | |
---|
1614 | /* do we get the expected results/packets? */ |
---|
1615 | |
---|
1616 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1617 | checkpacket(&test,0,0,0); |
---|
1618 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1619 | checkpacket(&test,100,1,-1); |
---|
1620 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1621 | checkpacket(&test,4079,2,3000); |
---|
1622 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1623 | checkpacket(&test,2956,3,4000); |
---|
1624 | if(ogg_stream_packetout(&os_de,&test)!=-1){ |
---|
1625 | fprintf(stderr,"Error: loss of page did not return error\n"); |
---|
1626 | exit(1); |
---|
1627 | } |
---|
1628 | if(ogg_stream_packetout(&os_de,&test)!=1)error(); |
---|
1629 | checkpacket(&test,300,13,14000); |
---|
1630 | fprintf(stderr,"ok.\n"); |
---|
1631 | } |
---|
1632 | |
---|
1633 | /* the rest only test sync */ |
---|
1634 | { |
---|
1635 | ogg_page og_de; |
---|
1636 | /* Test fractional page inputs: incomplete capture */ |
---|
1637 | fprintf(stderr,"Testing sync on partial inputs... "); |
---|
1638 | ogg_sync_reset(&oy); |
---|
1639 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, |
---|
1640 | 3); |
---|
1641 | ogg_sync_wrote(&oy,3); |
---|
1642 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1643 | |
---|
1644 | /* Test fractional page inputs: incomplete fixed header */ |
---|
1645 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, |
---|
1646 | 20); |
---|
1647 | ogg_sync_wrote(&oy,20); |
---|
1648 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1649 | |
---|
1650 | /* Test fractional page inputs: incomplete header */ |
---|
1651 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, |
---|
1652 | 5); |
---|
1653 | ogg_sync_wrote(&oy,5); |
---|
1654 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1655 | |
---|
1656 | /* Test fractional page inputs: incomplete body */ |
---|
1657 | |
---|
1658 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, |
---|
1659 | og[1].header_len-28); |
---|
1660 | ogg_sync_wrote(&oy,og[1].header_len-28); |
---|
1661 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1662 | |
---|
1663 | memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); |
---|
1664 | ogg_sync_wrote(&oy,1000); |
---|
1665 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1666 | |
---|
1667 | memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, |
---|
1668 | og[1].body_len-1000); |
---|
1669 | ogg_sync_wrote(&oy,og[1].body_len-1000); |
---|
1670 | if(ogg_sync_pageout(&oy,&og_de)<=0)error(); |
---|
1671 | |
---|
1672 | fprintf(stderr,"ok.\n"); |
---|
1673 | } |
---|
1674 | |
---|
1675 | /* Test fractional page inputs: page + incomplete capture */ |
---|
1676 | { |
---|
1677 | ogg_page og_de; |
---|
1678 | fprintf(stderr,"Testing sync on 1+partial inputs... "); |
---|
1679 | ogg_sync_reset(&oy); |
---|
1680 | |
---|
1681 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, |
---|
1682 | og[1].header_len); |
---|
1683 | ogg_sync_wrote(&oy,og[1].header_len); |
---|
1684 | |
---|
1685 | memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, |
---|
1686 | og[1].body_len); |
---|
1687 | ogg_sync_wrote(&oy,og[1].body_len); |
---|
1688 | |
---|
1689 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, |
---|
1690 | 20); |
---|
1691 | ogg_sync_wrote(&oy,20); |
---|
1692 | if(ogg_sync_pageout(&oy,&og_de)<=0)error(); |
---|
1693 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1694 | |
---|
1695 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, |
---|
1696 | og[1].header_len-20); |
---|
1697 | ogg_sync_wrote(&oy,og[1].header_len-20); |
---|
1698 | memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, |
---|
1699 | og[1].body_len); |
---|
1700 | ogg_sync_wrote(&oy,og[1].body_len); |
---|
1701 | if(ogg_sync_pageout(&oy,&og_de)<=0)error(); |
---|
1702 | |
---|
1703 | fprintf(stderr,"ok.\n"); |
---|
1704 | } |
---|
1705 | |
---|
1706 | /* Test recapture: garbage + page */ |
---|
1707 | { |
---|
1708 | ogg_page og_de; |
---|
1709 | fprintf(stderr,"Testing search for capture... "); |
---|
1710 | ogg_sync_reset(&oy); |
---|
1711 | |
---|
1712 | /* 'garbage' */ |
---|
1713 | memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, |
---|
1714 | og[1].body_len); |
---|
1715 | ogg_sync_wrote(&oy,og[1].body_len); |
---|
1716 | |
---|
1717 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, |
---|
1718 | og[1].header_len); |
---|
1719 | ogg_sync_wrote(&oy,og[1].header_len); |
---|
1720 | |
---|
1721 | memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, |
---|
1722 | og[1].body_len); |
---|
1723 | ogg_sync_wrote(&oy,og[1].body_len); |
---|
1724 | |
---|
1725 | memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, |
---|
1726 | 20); |
---|
1727 | ogg_sync_wrote(&oy,20); |
---|
1728 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1729 | if(ogg_sync_pageout(&oy,&og_de)<=0)error(); |
---|
1730 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1731 | |
---|
1732 | memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, |
---|
1733 | og[2].header_len-20); |
---|
1734 | ogg_sync_wrote(&oy,og[2].header_len-20); |
---|
1735 | memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, |
---|
1736 | og[2].body_len); |
---|
1737 | ogg_sync_wrote(&oy,og[2].body_len); |
---|
1738 | if(ogg_sync_pageout(&oy,&og_de)<=0)error(); |
---|
1739 | |
---|
1740 | fprintf(stderr,"ok.\n"); |
---|
1741 | } |
---|
1742 | |
---|
1743 | /* Test recapture: page + garbage + page */ |
---|
1744 | { |
---|
1745 | ogg_page og_de; |
---|
1746 | fprintf(stderr,"Testing recapture... "); |
---|
1747 | ogg_sync_reset(&oy); |
---|
1748 | |
---|
1749 | memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, |
---|
1750 | og[1].header_len); |
---|
1751 | ogg_sync_wrote(&oy,og[1].header_len); |
---|
1752 | |
---|
1753 | memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, |
---|
1754 | og[1].body_len); |
---|
1755 | ogg_sync_wrote(&oy,og[1].body_len); |
---|
1756 | |
---|
1757 | memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, |
---|
1758 | og[2].header_len); |
---|
1759 | ogg_sync_wrote(&oy,og[2].header_len); |
---|
1760 | |
---|
1761 | memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, |
---|
1762 | og[2].header_len); |
---|
1763 | ogg_sync_wrote(&oy,og[2].header_len); |
---|
1764 | |
---|
1765 | if(ogg_sync_pageout(&oy,&og_de)<=0)error(); |
---|
1766 | |
---|
1767 | memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, |
---|
1768 | og[2].body_len-5); |
---|
1769 | ogg_sync_wrote(&oy,og[2].body_len-5); |
---|
1770 | |
---|
1771 | memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, |
---|
1772 | og[3].header_len); |
---|
1773 | ogg_sync_wrote(&oy,og[3].header_len); |
---|
1774 | |
---|
1775 | memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, |
---|
1776 | og[3].body_len); |
---|
1777 | ogg_sync_wrote(&oy,og[3].body_len); |
---|
1778 | |
---|
1779 | if(ogg_sync_pageout(&oy,&og_de)>0)error(); |
---|
1780 | if(ogg_sync_pageout(&oy,&og_de)<=0)error(); |
---|
1781 | |
---|
1782 | fprintf(stderr,"ok.\n"); |
---|
1783 | } |
---|
1784 | |
---|
1785 | /* Free page data that was previously copied */ |
---|
1786 | { |
---|
1787 | for(i=0;i<5;i++){ |
---|
1788 | free_page(&og[i]); |
---|
1789 | } |
---|
1790 | } |
---|
1791 | } |
---|
1792 | |
---|
1793 | return(0); |
---|
1794 | } |
---|
1795 | |
---|
1796 | #endif |
---|
1797 | |
---|
1798 | |
---|
1799 | |
---|
1800 | |
---|