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