1 /********************************************************************
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. *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
11 ********************************************************************
13 function: code raw packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
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
21 ********************************************************************/
27 /* A complete description of Ogg framing exists in docs/framing.html */
29 int ogg_page_version(const ogg_page
*og
){
30 return((int)(og
->header
[4]));
33 int ogg_page_continued(const ogg_page
*og
){
34 return((int)(og
->header
[5]&0x01));
37 int ogg_page_bos(const ogg_page
*og
){
38 return((int)(og
->header
[5]&0x02));
41 int ogg_page_eos(const ogg_page
*og
){
42 return((int)(og
->header
[5]&0x04));
45 ogg_int64_t
ogg_page_granulepos(const 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);
58 ogg_uint32_t
ogg_page_serialno(const ogg_page
*og
){
59 return(og
->header
[14] |
61 (og
->header
[16]<<16) |
62 (og
->header
[17]<<24));
65 long ogg_page_pageno(const ogg_page
*og
){
66 return(og
->header
[18] |
68 (og
->header
[20]<<16) |
69 (og
->header
[21]<<24));
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
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
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
91 int ogg_page_packets(const ogg_page
*og
){
92 int i
,n
=og
->header
[26],count
=0;
94 if(og
->header
[27+i
]<255)count
++;
100 /* helper to initialize lookup for direct-table CRC (illustrative; we
101 use the static init below) */
103 static ogg_uint32_t
_ogg_crc_entry(unsigned long index
){
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 */
116 return (r
& 0xffffffffUL
);
120 static const ogg_uint32_t crc_lookup
[256] ICONST_ATTR
= {
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};
186 /* init the encode/decode logical stream state */
188 int ogg_stream_init(ogg_stream_state
*os
,int serialno
){
190 memset(os
,0,sizeof(*os
));
191 os
->body_storage
=16*1024;
192 os
->lacing_storage
=1024;
194 os
->body_data
=_ogg_malloc(os
->body_storage
*sizeof(*os
->body_data
));
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
));
198 if(!os
->body_data
|| !os
->lacing_vals
|| !os
->granule_vals
){
199 ogg_stream_clear(os
);
203 os
->serialno
=serialno
;
210 /* async/delayed error detection for the ogg_stream_state */
211 int ogg_stream_check(ogg_stream_state
*os
){
212 if(!os
|| !os
->body_data
) return -1;
216 /* _clear does not free os, only the non-flat storage within */
217 int ogg_stream_clear(ogg_stream_state
*os
){
219 if(os
->body_data
)_ogg_free(os
->body_data
);
220 if(os
->lacing_vals
)_ogg_free(os
->lacing_vals
);
221 if(os
->granule_vals
)_ogg_free(os
->granule_vals
);
223 memset(os
,0,sizeof(*os
));
228 int ogg_stream_destroy(ogg_stream_state
*os
){
230 ogg_stream_clear(os
);
236 /* Helpers for ogg_stream_encode; this keeps the structure and
237 what's happening fairly clear */
239 static int _os_body_expand(ogg_stream_state
*os
,int needed
){
240 if(os
->body_storage
<=os
->body_fill
+needed
){
242 ret
=_ogg_realloc(os
->body_data
,(os
->body_storage
+needed
+1024)*
243 sizeof(*os
->body_data
));
245 ogg_stream_clear(os
);
248 os
->body_storage
+=(needed
+1024);
254 static int _os_lacing_expand(ogg_stream_state
*os
,int needed
){
255 if(os
->lacing_storage
<=os
->lacing_fill
+needed
){
257 ret
=_ogg_realloc(os
->lacing_vals
,(os
->lacing_storage
+needed
+32)*
258 sizeof(*os
->lacing_vals
));
260 ogg_stream_clear(os
);
264 ret
=_ogg_realloc(os
->granule_vals
,(os
->lacing_storage
+needed
+32)*
265 sizeof(*os
->granule_vals
));
267 ogg_stream_clear(os
);
270 os
->granule_vals
=ret
;
271 os
->lacing_storage
+=(needed
+32);
276 /* checksum the page */
277 /* Direct table CRC; note that this will be faster in the future if we
278 perform the checksum simultaneously with other copies */
280 void ogg_page_checksum_set(ogg_page
*og
){
282 ogg_uint32_t crc_reg
=0;
285 /* safety; needed for API behavior, but not framing code */
291 for(i
=0;i
<og
->header_len
;i
++)
292 crc_reg
=(crc_reg
<<8)^crc_lookup
[((crc_reg
>> 24)&0xff)^og
->header
[i
]];
293 for(i
=0;i
<og
->body_len
;i
++)
294 crc_reg
=(crc_reg
<<8)^crc_lookup
[((crc_reg
>> 24)&0xff)^og
->body
[i
]];
296 og
->header
[22]=(unsigned char)(crc_reg
&0xff);
297 og
->header
[23]=(unsigned char)((crc_reg
>>8)&0xff);
298 og
->header
[24]=(unsigned char)((crc_reg
>>16)&0xff);
299 og
->header
[25]=(unsigned char)((crc_reg
>>24)&0xff);
304 /* submit data to the internal buffer of the framing engine */
305 int ogg_stream_iovecin(ogg_stream_state
*os
, ogg_iovec_t
*iov
, int count
,
306 long e_o_s
, ogg_int64_t granulepos
){
308 int bytes
= 0, lacing_vals
, i
;
310 if(ogg_stream_check(os
)) return -1;
313 for (i
= 0; i
< count
; ++i
) bytes
+= (int)iov
[i
].iov_len
;
314 lacing_vals
=bytes
/255+1;
316 if(os
->body_returned
){
317 /* advance packet data according to the body_returned pointer. We
318 had to keep it around to return a pointer into the buffer last
321 os
->body_fill
-=os
->body_returned
;
323 memmove(os
->body_data
,os
->body_data
+os
->body_returned
,
328 /* make sure we have the buffer storage */
329 if(_os_body_expand(os
,bytes
) || _os_lacing_expand(os
,lacing_vals
))
332 /* Copy in the submitted packet. Yes, the copy is a waste; this is
333 the liability of overly clean abstraction for the time being. It
334 will actually be fairly easy to eliminate the extra copy in the
337 for (i
= 0; i
< count
; ++i
) {
338 memcpy(os
->body_data
+os
->body_fill
, iov
[i
].iov_base
, iov
[i
].iov_len
);
339 os
->body_fill
+= (int)iov
[i
].iov_len
;
342 /* Store lacing vals for this packet */
343 for(i
=0;i
<lacing_vals
-1;i
++){
344 os
->lacing_vals
[os
->lacing_fill
+i
]=255;
345 os
->granule_vals
[os
->lacing_fill
+i
]=os
->granulepos
;
347 os
->lacing_vals
[os
->lacing_fill
+i
]=bytes
%255;
348 os
->granulepos
=os
->granule_vals
[os
->lacing_fill
+i
]=granulepos
;
350 /* flag the first segment as the beginning of the packet */
351 os
->lacing_vals
[os
->lacing_fill
]|= 0x100;
353 os
->lacing_fill
+=lacing_vals
;
355 /* for the sake of completeness */
358 if(e_o_s
)os
->e_o_s
=1;
363 int ogg_stream_packetin(ogg_stream_state
*os
,ogg_packet
*op
){
365 iov
.iov_base
= op
->packet
;
366 iov
.iov_len
= op
->bytes
;
367 return ogg_stream_iovecin(os
, &iov
, 1, op
->e_o_s
, op
->granulepos
);
371 /* Conditionally flush a page; force==0 will only flush nominal-size
372 pages, force==1 forces us to flush a page regardless of page size
373 so long as there's any data available at all. */
374 static int ogg_stream_flush_i(ogg_stream_state
*os
,ogg_page
*og
, int force
, int nfill
){
377 int maxvals
=(os
->lacing_fill
>255?255:os
->lacing_fill
);
380 ogg_int64_t granule_pos
=-1;
382 if(ogg_stream_check(os
)) return(0);
383 if(maxvals
==0) return(0);
385 /* construct a page */
386 /* decide how many segments to include */
388 /* If this is the initial header case, the first page must only include
389 the initial header packet */
390 if(os
->b_o_s
==0){ /* 'initial header page' case */
392 for(vals
=0;vals
<maxvals
;vals
++){
393 if((os
->lacing_vals
[vals
]&0x0ff)<255){
400 /* The extra packets_done, packet_just_done logic here attempts to do two things:
401 1) Don't unneccessarily span pages.
402 2) Unless necessary, don't flush pages if there are less than four packets on
403 them; this expands page size to reduce unneccessary overhead if incoming packets
405 These are not necessary behaviors, just 'always better than naive flushing'
406 without requiring an application to explicitly request a specific optimized
407 behavior. We'll want an explicit behavior setup pathway eventually as well. */
410 int packet_just_done
=0;
411 for(vals
=0;vals
<maxvals
;vals
++){
412 if(acc
>nfill
&& packet_just_done
>=4){
416 acc
+=os
->lacing_vals
[vals
]&0x0ff;
417 if((os
->lacing_vals
[vals
]&0xff)<255){
418 granule_pos
=os
->granule_vals
[vals
];
419 packet_just_done
=++packets_done
;
423 if(vals
==255)force
=1;
426 if(!force
) return(0);
428 /* construct the header in temp storage */
429 memcpy(os
->header
,"OggS",4);
431 /* stream structure version */
434 /* continued packet flag? */
436 if((os
->lacing_vals
[0]&0x100)==0)os
->header
[5]|=0x01;
437 /* first page flag? */
438 if(os
->b_o_s
==0)os
->header
[5]|=0x02;
439 /* last page flag? */
440 if(os
->e_o_s
&& os
->lacing_fill
==vals
)os
->header
[5]|=0x04;
443 /* 64 bits of PCM position */
445 os
->header
[i
]=(unsigned char)(granule_pos
&0xff);
449 /* 32 bits of stream serial number */
451 long serialno
=os
->serialno
;
453 os
->header
[i
]=(unsigned char)(serialno
&0xff);
458 /* 32 bits of page counter (we have both counter and page header
459 because this val can roll over) */
460 if(os
->pageno
==-1)os
->pageno
=0; /* because someone called
461 stream_reset; this would be a
462 strange thing to do in an
463 encode stream, but it has
466 long pageno
=os
->pageno
++;
468 os
->header
[i
]=(unsigned char)(pageno
&0xff);
473 /* zero for computation; filled in later */
480 os
->header
[26]=(unsigned char)(vals
&0xff);
482 bytes
+=os
->header
[i
+27]=(unsigned char)(os
->lacing_vals
[i
]&0xff);
484 /* set pointers in the ogg_page struct */
485 og
->header
=os
->header
;
486 og
->header_len
=os
->header_fill
=vals
+27;
487 og
->body
=os
->body_data
+os
->body_returned
;
490 /* advance the lacing data and set the body_returned pointer */
492 os
->lacing_fill
-=vals
;
493 memmove(os
->lacing_vals
,os
->lacing_vals
+vals
,os
->lacing_fill
*sizeof(*os
->lacing_vals
));
494 memmove(os
->granule_vals
,os
->granule_vals
+vals
,os
->lacing_fill
*sizeof(*os
->granule_vals
));
495 os
->body_returned
+=bytes
;
497 /* calculate the checksum */
499 ogg_page_checksum_set(og
);
505 /* This will flush remaining packets into a page (returning nonzero),
506 even if there is not enough data to trigger a flush normally
507 (undersized page). If there are no packets or partial packets to
508 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
509 try to flush a normal sized page like ogg_stream_pageout; a call to
510 ogg_stream_flush does not guarantee that all packets have flushed.
511 Only a return value of 0 from ogg_stream_flush indicates all packet
512 data is flushed into pages.
514 since ogg_stream_flush will flush the last page in a stream even if
515 it's undersized, you almost certainly want to use ogg_stream_pageout
516 (and *not* ogg_stream_flush) unless you specifically need to flush
517 an page regardless of size in the middle of a stream. */
519 int ogg_stream_flush(ogg_stream_state
*os
,ogg_page
*og
){
520 return ogg_stream_flush_i(os
,og
,1,4096);
523 /* This constructs pages from buffered packet segments. The pointers
524 returned are to static buffers; do not free. The returned buffers are
525 good only until the next call (using the same ogg_stream_state) */
527 int ogg_stream_pageout(ogg_stream_state
*os
, ogg_page
*og
){
529 if(ogg_stream_check(os
)) return 0;
531 if((os
->e_o_s
&&os
->lacing_fill
) || /* 'were done, now flush' case */
532 (os
->lacing_fill
&&!os
->b_o_s
)) /* 'initial header page' case */
535 return(ogg_stream_flush_i(os
,og
,force
,4096));
538 /* Like the above, but an argument is provided to adjust the nominal
539 page size for applications which are smart enough to provide their
540 own delay based flushing */
542 int ogg_stream_pageout_fill(ogg_stream_state
*os
, ogg_page
*og
, int nfill
){
544 if(ogg_stream_check(os
)) return 0;
546 if((os
->e_o_s
&&os
->lacing_fill
) || /* 'were done, now flush' case */
547 (os
->lacing_fill
&&!os
->b_o_s
)) /* 'initial header page' case */
550 return(ogg_stream_flush_i(os
,og
,force
,nfill
));
553 int ogg_stream_eos(ogg_stream_state
*os
){
554 if(ogg_stream_check(os
)) return 1;
558 /* DECODING PRIMITIVES: packet streaming layer **********************/
560 /* This has two layers to place more of the multi-serialno and paging
561 control in the application's hands. First, we expose a data buffer
562 using ogg_sync_buffer(). The app either copies into the
563 buffer, or passes it directly to read(), etc. We then call
564 ogg_sync_wrote() to tell how many bytes we just added.
566 Pages are returned (pointers into the buffer in ogg_sync_state)
567 by ogg_sync_pageout(). The page is then submitted to
568 ogg_stream_pagein() along with the appropriate
569 ogg_stream_state* (ie, matching serialno). We then get raw
570 packets out calling ogg_stream_packetout() with a
573 /* initialize the struct to a known state */
574 int ogg_sync_init(ogg_sync_state
*oy
){
576 oy
->storage
= -1; /* used as a readiness flag */
577 memset(oy
,0,sizeof(*oy
));
582 /* clear non-flat storage within */
583 int ogg_sync_clear(ogg_sync_state
*oy
){
585 if(oy
->data
)_ogg_free(oy
->data
);
586 memset(oy
,0,sizeof(*oy
));
591 int ogg_sync_destroy(ogg_sync_state
*oy
){
599 int ogg_sync_check(ogg_sync_state
*oy
){
600 if(oy
->storage
<0) return -1;
604 char *ogg_sync_buffer(ogg_sync_state
*oy
, long size
){
605 if(ogg_sync_check(oy
)) return NULL
;
607 /* first, clear out any space that has been previously returned */
609 oy
->fill
-=oy
->returned
;
611 memmove(oy
->data
,oy
->data
+oy
->returned
,oy
->fill
);
615 if(size
>oy
->storage
-oy
->fill
){
616 /* We need to extend the internal buffer */
617 long newsize
=size
+oy
->fill
+4096; /* an extra page to be nice */
621 ret
=_ogg_realloc(oy
->data
,newsize
);
623 ret
=_ogg_malloc(newsize
);
632 /* expose a segment at least as large as requested at the fill mark */
633 return((char *)oy
->data
+oy
->fill
);
636 int ogg_sync_wrote(ogg_sync_state
*oy
, long bytes
){
637 if(ogg_sync_check(oy
))return -1;
638 if(oy
->fill
+bytes
>oy
->storage
)return -1;
643 /* sync the stream. This is meant to be useful for finding page
646 return values for this:
648 0) page not ready; more data (no bytes skipped)
649 n) page synced at current location; page length n bytes
653 long ogg_sync_pageseek(ogg_sync_state
*oy
,ogg_page
*og
){
654 unsigned char *page
=oy
->data
+oy
->returned
;
656 long bytes
=oy
->fill
-oy
->returned
;
658 if(ogg_sync_check(oy
))return 0;
660 if(oy
->headerbytes
==0){
662 if(bytes
<27)return(0); /* not enough for a header */
664 /* verify capture pattern */
665 if(memcmp(page
,"OggS",4))goto sync_fail
;
667 headerbytes
=page
[26]+27;
668 if(bytes
<headerbytes
)return(0); /* not enough for header + seg table */
670 /* count up body length in the segment table */
672 for(i
=0;i
<page
[26];i
++)
673 oy
->bodybytes
+=page
[27+i
];
674 oy
->headerbytes
=headerbytes
;
677 if(oy
->bodybytes
+oy
->headerbytes
>bytes
)return(0);
679 /* The whole test page is buffered. Verify the checksum */
681 /* Grab the checksum bytes, set the header field to zero */
685 memcpy(chksum
,page
+22,4);
688 /* set up a temp page struct and recompute the checksum */
690 log
.header_len
=oy
->headerbytes
;
691 log
.body
=page
+oy
->headerbytes
;
692 log
.body_len
=oy
->bodybytes
;
693 ogg_page_checksum_set(&log
);
696 if(memcmp(chksum
,page
+22,4)){
697 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
699 /* replace the computed checksum with the one actually read in */
700 memcpy(page
+22,chksum
,4);
702 /* Bad checksum. Lose sync */
707 /* yes, have a whole page all ready to go */
709 unsigned char *page
=oy
->data
+oy
->returned
;
714 og
->header_len
=oy
->headerbytes
;
715 og
->body
=page
+oy
->headerbytes
;
716 og
->body_len
=oy
->bodybytes
;
720 oy
->returned
+=(bytes
=oy
->headerbytes
+oy
->bodybytes
);
731 /* search for possible capture */
732 next
=memchr(page
+1,'O',bytes
-1);
734 next
=oy
->data
+oy
->fill
;
736 oy
->returned
=(int)(next
-oy
->data
);
737 return((long)-(next
-page
));
740 /* sync the stream and get a page. Keep trying until we find a page.
741 Suppress 'sync errors' after reporting the first.
744 -1) recapture (hole in data)
748 Returns pointers into buffered data; invalidated by next call to
749 _stream, _clear, _init, or _buffer */
751 int ogg_sync_pageout(ogg_sync_state
*oy
, ogg_page
*og
){
753 if(ogg_sync_check(oy
))return 0;
755 /* all we need to do is verify a page at the head of the stream
756 buffer. If it doesn't verify, we look for the next potential
760 long ret
=ogg_sync_pageseek(oy
,og
);
770 /* head did not start a synced page... skipped some bytes */
776 /* loop. keep looking */
781 /* add the incoming page to the stream state; we decompose the page
782 into packet segments here as well. */
784 int ogg_stream_pagein(ogg_stream_state
*os
, ogg_page
*og
){
785 unsigned char *header
=og
->header
;
786 unsigned char *body
=og
->body
;
787 long bodysize
=og
->body_len
;
790 int version
=ogg_page_version(og
);
791 int continued
=ogg_page_continued(og
);
792 int bos
=ogg_page_bos(og
);
793 int eos
=ogg_page_eos(og
);
794 ogg_int64_t granulepos
=ogg_page_granulepos(og
);
795 ogg_uint32_t serialno
=ogg_page_serialno(og
);
796 long pageno
=ogg_page_pageno(og
);
797 int segments
=header
[26];
799 if(ogg_stream_check(os
)) return -1;
801 /* clean up 'returned data' */
803 long lr
=os
->lacing_returned
;
804 long br
=os
->body_returned
;
810 memmove(os
->body_data
,os
->body_data
+br
,os
->body_fill
);
816 if(os
->lacing_fill
-lr
){
817 memmove(os
->lacing_vals
,os
->lacing_vals
+lr
,
818 (os
->lacing_fill
-lr
)*sizeof(*os
->lacing_vals
));
819 memmove(os
->granule_vals
,os
->granule_vals
+lr
,
820 (os
->lacing_fill
-lr
)*sizeof(*os
->granule_vals
));
823 os
->lacing_packet
-=lr
;
824 os
->lacing_returned
=0;
828 /* check the serial number */
829 if(serialno
!=os
->serialno
)return(-1);
830 if(version
>0)return(-1);
832 if(_os_lacing_expand(os
,segments
+1)) return -1;
834 /* are we in sequence? */
835 if(pageno
!=os
->pageno
){
838 /* unroll previous partial packet (if any) */
839 for(i
=os
->lacing_packet
;i
<os
->lacing_fill
;i
++)
840 os
->body_fill
-=os
->lacing_vals
[i
]&0xff;
841 os
->lacing_fill
=os
->lacing_packet
;
843 /* make a note of dropped data in segment table */
845 os
->lacing_vals
[os
->lacing_fill
++]=0x400;
850 /* are we a 'continued packet' page? If so, we may need to skip
853 if(os
->lacing_fill
<1 ||
854 os
->lacing_vals
[os
->lacing_fill
-1]==0x400){
856 for(;segptr
<segments
;segptr
++){
857 int val
=header
[27+segptr
];
869 if(_os_body_expand(os
,bodysize
)) return -1;
870 memcpy(os
->body_data
+os
->body_fill
,body
,bodysize
);
871 os
->body_fill
+=bodysize
;
876 while(segptr
<segments
){
877 int val
=header
[27+segptr
];
878 os
->lacing_vals
[os
->lacing_fill
]=val
;
879 os
->granule_vals
[os
->lacing_fill
]=-1;
882 os
->lacing_vals
[os
->lacing_fill
]|=0x100;
886 if(val
<255)saved
=os
->lacing_fill
;
891 if(val
<255)os
->lacing_packet
=os
->lacing_fill
;
894 /* set the granulepos on the last granuleval of the last full packet */
896 os
->granule_vals
[saved
]=granulepos
;
903 if(os
->lacing_fill
>0)
904 os
->lacing_vals
[os
->lacing_fill
-1]|=0x200;
912 /* clear things to an initial state. Good to call, eg, before seeking */
913 int ogg_sync_reset(ogg_sync_state
*oy
){
914 if(ogg_sync_check(oy
))return -1;
924 int ogg_stream_reset(ogg_stream_state
*os
){
925 if(ogg_stream_check(os
)) return -1;
932 os
->lacing_returned
=0;
934 /* os->header_fill=0; */
945 int ogg_stream_reset_serialno(ogg_stream_state
*os
,int serialno
){
946 if(ogg_stream_check(os
)) return -1;
947 ogg_stream_reset(os
);
948 os
->serialno
=serialno
;
952 static int _packetout(ogg_stream_state
*os
,ogg_packet
*op
,int adv
)
953 ICODE_ATTR_TREMOR_NOT_MDCT
;
954 static int _packetout(ogg_stream_state
*os
,ogg_packet
*op
,int adv
){
956 /* The last part of decode. We have the stream broken into packet
957 segments. Now we need to group them into packets (or return the
958 out of sync markers) */
960 int ptr
=os
->lacing_returned
;
962 if(os
->lacing_packet
<=ptr
)return(0);
964 if(os
->lacing_vals
[ptr
]&0x400){
965 /* we need to tell the codec there's a gap; it might need to
966 handle previous packet dependencies. */
967 os
->lacing_returned
++;
972 if(!op
&& !adv
)return(1); /* just using peek as an inexpensive way
973 to ask if there's a whole packet
976 /* Gather the whole packet. We'll have no holes or a partial packet */
978 int size
=os
->lacing_vals
[ptr
]&0xff;
980 int eos
=os
->lacing_vals
[ptr
]&0x200; /* last packet of the stream? */
981 int bos
=os
->lacing_vals
[ptr
]&0x100; /* first packet of the stream? */
984 int val
=os
->lacing_vals
[++ptr
];
986 if(val
&0x200)eos
=0x200;
993 op
->packet
=os
->body_data
+os
->body_returned
;
994 op
->packetno
=os
->packetno
;
995 op
->granulepos
=os
->granule_vals
[ptr
];
1000 os
->body_returned
+=bytes
;
1001 os
->lacing_returned
=ptr
+1;
1008 int ogg_stream_packetout(ogg_stream_state
*os
,ogg_packet
*op
)
1009 ICODE_ATTR_TREMOR_NOT_MDCT
;
1010 int ogg_stream_packetout(ogg_stream_state
*os
,ogg_packet
*op
){
1011 if(ogg_stream_check(os
)) return 0;
1012 return _packetout(os
,op
,1);
1015 int ogg_stream_packetpeek(ogg_stream_state
*os
,ogg_packet
*op
)
1016 ICODE_ATTR_TREMOR_NOT_MDCT
;
1017 int ogg_stream_packetpeek(ogg_stream_state
*os
,ogg_packet
*op
){
1018 if(ogg_stream_check(os
)) return 0;
1019 return _packetout(os
,op
,0);
1022 void ogg_packet_clear(ogg_packet
*op
) {
1023 _ogg_free(op
->packet
);
1024 memset(op
, 0, sizeof(*op
));
1030 ogg_stream_state os_en
, os_de
;
1033 void checkpacket(ogg_packet
*op
,long len
, int no
, long pos
){
1035 static int sequence
=0;
1036 static int lastno
=0;
1039 fprintf(stderr
,"incorrect packet length (%ld != %ld)!\n",op
->bytes
,len
);
1042 if(op
->granulepos
!=pos
){
1043 fprintf(stderr
,"incorrect packet granpos (%ld != %ld)!\n",(long)op
->granulepos
,pos
);
1047 /* packet number just follows sequence/gap; adjust the input number
1057 if(op
->packetno
!=sequence
){
1058 fprintf(stderr
,"incorrect packet sequence %ld != %d\n",
1059 (long)(op
->packetno
),sequence
);
1064 for(j
=0;j
<op
->bytes
;j
++)
1065 if(op
->packet
[j
]!=((j
+no
)&0xff)){
1066 fprintf(stderr
,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1067 j
,op
->packet
[j
],(j
+no
)&0xff);
1072 void check_page(unsigned char *data
,const int *header
,ogg_page
*og
){
1075 for(j
=0;j
<og
->body_len
;j
++)
1076 if(og
->body
[j
]!=data
[j
]){
1077 fprintf(stderr
,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1078 j
,data
[j
],og
->body
[j
]);
1083 for(j
=0;j
<og
->header_len
;j
++){
1084 if(og
->header
[j
]!=header
[j
]){
1085 fprintf(stderr
,"header content mismatch at pos %ld:\n",j
);
1086 for(j
=0;j
<header
[26]+27;j
++)
1087 fprintf(stderr
," (%ld)%02x:%02x",j
,header
[j
],og
->header
[j
]);
1088 fprintf(stderr
,"\n");
1092 if(og
->header_len
!=header
[26]+27){
1093 fprintf(stderr
,"header length incorrect! (%ld!=%d)\n",
1094 og
->header_len
,header
[26]+27);
1099 void print_header(ogg_page
*og
){
1101 fprintf(stderr
,"\nHEADER:\n");
1102 fprintf(stderr
," capture: %c %c %c %c version: %d flags: %x\n",
1103 og
->header
[0],og
->header
[1],og
->header
[2],og
->header
[3],
1104 (int)og
->header
[4],(int)og
->header
[5]);
1106 fprintf(stderr
," granulepos: %d serialno: %d pageno: %ld\n",
1107 (og
->header
[9]<<24)|(og
->header
[8]<<16)|
1108 (og
->header
[7]<<8)|og
->header
[6],
1109 (og
->header
[17]<<24)|(og
->header
[16]<<16)|
1110 (og
->header
[15]<<8)|og
->header
[14],
1111 ((long)(og
->header
[21])<<24)|(og
->header
[20]<<16)|
1112 (og
->header
[19]<<8)|og
->header
[18]);
1114 fprintf(stderr
," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
1115 (int)og
->header
[22],(int)og
->header
[23],
1116 (int)og
->header
[24],(int)og
->header
[25],
1117 (int)og
->header
[26]);
1119 for(j
=27;j
<og
->header_len
;j
++)
1120 fprintf(stderr
,"%d ",(int)og
->header
[j
]);
1121 fprintf(stderr
,")\n\n");
1124 void copy_page(ogg_page
*og
){
1125 unsigned char *temp
=_ogg_malloc(og
->header_len
);
1126 memcpy(temp
,og
->header
,og
->header_len
);
1129 temp
=_ogg_malloc(og
->body_len
);
1130 memcpy(temp
,og
->body
,og
->body_len
);
1134 void free_page(ogg_page
*og
){
1135 _ogg_free (og
->header
);
1136 _ogg_free (og
->body
);
1140 fprintf(stderr
,"error!\n");
1145 const int head1_0
[] = {0x4f,0x67,0x67,0x53,0,0x06,
1146 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1147 0x01,0x02,0x03,0x04,0,0,0,0,
1148 0x15,0xed,0xec,0x91,
1152 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1153 const int head1_1
[] = {0x4f,0x67,0x67,0x53,0,0x02,
1154 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1155 0x01,0x02,0x03,0x04,0,0,0,0,
1156 0x59,0x10,0x6c,0x2c,
1159 const int head2_1
[] = {0x4f,0x67,0x67,0x53,0,0x04,
1160 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1161 0x01,0x02,0x03,0x04,1,0,0,0,
1162 0x89,0x33,0x85,0xce,
1164 254,255,0,255,1,255,245,255,255,0,
1167 /* nil packets; beginning,middle,end */
1168 const int head1_2
[] = {0x4f,0x67,0x67,0x53,0,0x02,
1169 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1170 0x01,0x02,0x03,0x04,0,0,0,0,
1171 0xff,0x7b,0x23,0x17,
1174 const int head2_2
[] = {0x4f,0x67,0x67,0x53,0,0x04,
1175 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1176 0x01,0x02,0x03,0x04,1,0,0,0,
1177 0x5c,0x3f,0x66,0xcb,
1179 17,254,255,0,0,255,1,0,255,245,255,255,0,
1182 /* large initial packet */
1183 const int head1_3
[] = {0x4f,0x67,0x67,0x53,0,0x02,
1184 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1185 0x01,0x02,0x03,0x04,0,0,0,0,
1186 0x01,0x27,0x31,0xaa,
1188 255,255,255,255,255,255,255,255,
1189 255,255,255,255,255,255,255,255,255,10};
1191 const int head2_3
[] = {0x4f,0x67,0x67,0x53,0,0x04,
1192 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1193 0x01,0x02,0x03,0x04,1,0,0,0,
1194 0x7f,0x4e,0x8a,0xd2,
1199 /* continuing packet test */
1200 const int head1_4
[] = {0x4f,0x67,0x67,0x53,0,0x02,
1201 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1202 0x01,0x02,0x03,0x04,0,0,0,0,
1203 0xff,0x7b,0x23,0x17,
1207 const int head2_4
[] = {0x4f,0x67,0x67,0x53,0,0x00,
1208 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1209 0x01,0x02,0x03,0x04,1,0,0,0,
1210 0xf8,0x3c,0x19,0x79,
1212 255,255,255,255,255,255,255,255,
1213 255,255,255,255,255,255,255,255,
1214 255,255,255,255,255,255,255,255,
1215 255,255,255,255,255,255,255,255,
1216 255,255,255,255,255,255,255,255,
1217 255,255,255,255,255,255,255,255,
1218 255,255,255,255,255,255,255,255,
1219 255,255,255,255,255,255,255,255,
1220 255,255,255,255,255,255,255,255,
1221 255,255,255,255,255,255,255,255,
1222 255,255,255,255,255,255,255,255,
1223 255,255,255,255,255,255,255,255,
1224 255,255,255,255,255,255,255,255,
1225 255,255,255,255,255,255,255,255,
1226 255,255,255,255,255,255,255,255,
1227 255,255,255,255,255,255,255,255,
1228 255,255,255,255,255,255,255,255,
1229 255,255,255,255,255,255,255,255,
1230 255,255,255,255,255,255,255,255,
1231 255,255,255,255,255,255,255,255,
1232 255,255,255,255,255,255,255,255,
1233 255,255,255,255,255,255,255,255,
1234 255,255,255,255,255,255,255,255,
1235 255,255,255,255,255,255,255,255,
1236 255,255,255,255,255,255,255,255,
1237 255,255,255,255,255,255,255,255,
1238 255,255,255,255,255,255,255,255,
1239 255,255,255,255,255,255,255,255,
1240 255,255,255,255,255,255,255,255,
1241 255,255,255,255,255,255,255,255,
1242 255,255,255,255,255,255,255,255,
1243 255,255,255,255,255,255,255};
1245 const int head3_4
[] = {0x4f,0x67,0x67,0x53,0,0x05,
1246 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1247 0x01,0x02,0x03,0x04,2,0,0,0,
1248 0x38,0xe6,0xb6,0x28,
1250 255,220,255,4,255,0};
1253 /* spill expansion test */
1254 const int head1_4b
[] = {0x4f,0x67,0x67,0x53,0,0x02,
1255 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1256 0x01,0x02,0x03,0x04,0,0,0,0,
1257 0xff,0x7b,0x23,0x17,
1261 const int head2_4b
[] = {0x4f,0x67,0x67,0x53,0,0x00,
1262 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1263 0x01,0x02,0x03,0x04,1,0,0,0,
1264 0xce,0x8f,0x17,0x1a,
1266 255,255,255,255,255,255,255,255,
1267 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1270 const int head3_4b
[] = {0x4f,0x67,0x67,0x53,0,0x04,
1271 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1272 0x01,0x02,0x03,0x04,2,0,0,0,
1273 0x9b,0xb2,0x50,0xa1,
1277 /* page with the 255 segment limit */
1278 const int head1_5
[] = {0x4f,0x67,0x67,0x53,0,0x02,
1279 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1280 0x01,0x02,0x03,0x04,0,0,0,0,
1281 0xff,0x7b,0x23,0x17,
1285 const int head2_5
[] = {0x4f,0x67,0x67,0x53,0,0x00,
1286 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1287 0x01,0x02,0x03,0x04,1,0,0,0,
1288 0xed,0x2a,0x2e,0xa7,
1290 10,10,10,10,10,10,10,10,
1291 10,10,10,10,10,10,10,10,
1292 10,10,10,10,10,10,10,10,
1293 10,10,10,10,10,10,10,10,
1294 10,10,10,10,10,10,10,10,
1295 10,10,10,10,10,10,10,10,
1296 10,10,10,10,10,10,10,10,
1297 10,10,10,10,10,10,10,10,
1298 10,10,10,10,10,10,10,10,
1299 10,10,10,10,10,10,10,10,
1300 10,10,10,10,10,10,10,10,
1301 10,10,10,10,10,10,10,10,
1302 10,10,10,10,10,10,10,10,
1303 10,10,10,10,10,10,10,10,
1304 10,10,10,10,10,10,10,10,
1305 10,10,10,10,10,10,10,10,
1306 10,10,10,10,10,10,10,10,
1307 10,10,10,10,10,10,10,10,
1308 10,10,10,10,10,10,10,10,
1309 10,10,10,10,10,10,10,10,
1310 10,10,10,10,10,10,10,10,
1311 10,10,10,10,10,10,10,10,
1312 10,10,10,10,10,10,10,10,
1313 10,10,10,10,10,10,10,10,
1314 10,10,10,10,10,10,10,10,
1315 10,10,10,10,10,10,10,10,
1316 10,10,10,10,10,10,10,10,
1317 10,10,10,10,10,10,10,10,
1318 10,10,10,10,10,10,10,10,
1319 10,10,10,10,10,10,10,10,
1320 10,10,10,10,10,10,10,10,
1321 10,10,10,10,10,10,10};
1323 const int head3_5
[] = {0x4f,0x67,0x67,0x53,0,0x04,
1324 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1325 0x01,0x02,0x03,0x04,2,0,0,0,
1326 0x6c,0x3b,0x82,0x3d,
1331 /* packet that overspans over an entire page */
1332 const int head1_6
[] = {0x4f,0x67,0x67,0x53,0,0x02,
1333 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1334 0x01,0x02,0x03,0x04,0,0,0,0,
1335 0xff,0x7b,0x23,0x17,
1339 const int head2_6
[] = {0x4f,0x67,0x67,0x53,0,0x00,
1340 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1341 0x01,0x02,0x03,0x04,1,0,0,0,
1342 0x68,0x22,0x7c,0x3d,
1345 255,255,255,255,255,255,255,255,
1346 255,255,255,255,255,255,255,255,
1347 255,255,255,255,255,255,255,255,
1348 255,255,255,255,255,255,255,255,
1349 255,255,255,255,255,255,255,255,
1350 255,255,255,255,255,255,255,255,
1351 255,255,255,255,255,255,255,255,
1352 255,255,255,255,255,255,255,255,
1353 255,255,255,255,255,255,255,255,
1354 255,255,255,255,255,255,255,255,
1355 255,255,255,255,255,255,255,255,
1356 255,255,255,255,255,255,255,255,
1357 255,255,255,255,255,255,255,255,
1358 255,255,255,255,255,255,255,255,
1359 255,255,255,255,255,255,255,255,
1360 255,255,255,255,255,255,255,255,
1361 255,255,255,255,255,255,255,255,
1362 255,255,255,255,255,255,255,255,
1363 255,255,255,255,255,255,255,255,
1364 255,255,255,255,255,255,255,255,
1365 255,255,255,255,255,255,255,255,
1366 255,255,255,255,255,255,255,255,
1367 255,255,255,255,255,255,255,255,
1368 255,255,255,255,255,255,255,255,
1369 255,255,255,255,255,255,255,255,
1370 255,255,255,255,255,255,255,255,
1371 255,255,255,255,255,255,255,255,
1372 255,255,255,255,255,255,255,255,
1373 255,255,255,255,255,255,255,255,
1374 255,255,255,255,255,255,255,255,
1375 255,255,255,255,255,255,255,255,
1376 255,255,255,255,255,255};
1378 const int head3_6
[] = {0x4f,0x67,0x67,0x53,0,0x01,
1379 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1380 0x01,0x02,0x03,0x04,2,0,0,0,
1381 0xf4,0x87,0xba,0xf3,
1383 255,255,255,255,255,255,255,255,
1384 255,255,255,255,255,255,255,255,
1385 255,255,255,255,255,255,255,255,
1386 255,255,255,255,255,255,255,255,
1387 255,255,255,255,255,255,255,255,
1388 255,255,255,255,255,255,255,255,
1389 255,255,255,255,255,255,255,255,
1390 255,255,255,255,255,255,255,255,
1391 255,255,255,255,255,255,255,255,
1392 255,255,255,255,255,255,255,255,
1393 255,255,255,255,255,255,255,255,
1394 255,255,255,255,255,255,255,255,
1395 255,255,255,255,255,255,255,255,
1396 255,255,255,255,255,255,255,255,
1397 255,255,255,255,255,255,255,255,
1398 255,255,255,255,255,255,255,255,
1399 255,255,255,255,255,255,255,255,
1400 255,255,255,255,255,255,255,255,
1401 255,255,255,255,255,255,255,255,
1402 255,255,255,255,255,255,255,255,
1403 255,255,255,255,255,255,255,255,
1404 255,255,255,255,255,255,255,255,
1405 255,255,255,255,255,255,255,255,
1406 255,255,255,255,255,255,255,255,
1407 255,255,255,255,255,255,255,255,
1408 255,255,255,255,255,255,255,255,
1409 255,255,255,255,255,255,255,255,
1410 255,255,255,255,255,255,255,255,
1411 255,255,255,255,255,255,255,255,
1412 255,255,255,255,255,255,255,255,
1413 255,255,255,255,255,255,255,255,
1414 255,255,255,255,255,255,255};
1416 const int head4_6
[] = {0x4f,0x67,0x67,0x53,0,0x05,
1417 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1418 0x01,0x02,0x03,0x04,3,0,0,0,
1419 0xf7,0x2f,0x6c,0x60,
1423 /* packet that overspans over an entire page */
1424 const int head1_7
[] = {0x4f,0x67,0x67,0x53,0,0x02,
1425 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1426 0x01,0x02,0x03,0x04,0,0,0,0,
1427 0xff,0x7b,0x23,0x17,
1431 const int head2_7
[] = {0x4f,0x67,0x67,0x53,0,0x00,
1432 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1433 0x01,0x02,0x03,0x04,1,0,0,0,
1434 0x68,0x22,0x7c,0x3d,
1437 255,255,255,255,255,255,255,255,
1438 255,255,255,255,255,255,255,255,
1439 255,255,255,255,255,255,255,255,
1440 255,255,255,255,255,255,255,255,
1441 255,255,255,255,255,255,255,255,
1442 255,255,255,255,255,255,255,255,
1443 255,255,255,255,255,255,255,255,
1444 255,255,255,255,255,255,255,255,
1445 255,255,255,255,255,255,255,255,
1446 255,255,255,255,255,255,255,255,
1447 255,255,255,255,255,255,255,255,
1448 255,255,255,255,255,255,255,255,
1449 255,255,255,255,255,255,255,255,
1450 255,255,255,255,255,255,255,255,
1451 255,255,255,255,255,255,255,255,
1452 255,255,255,255,255,255,255,255,
1453 255,255,255,255,255,255,255,255,
1454 255,255,255,255,255,255,255,255,
1455 255,255,255,255,255,255,255,255,
1456 255,255,255,255,255,255,255,255,
1457 255,255,255,255,255,255,255,255,
1458 255,255,255,255,255,255,255,255,
1459 255,255,255,255,255,255,255,255,
1460 255,255,255,255,255,255,255,255,
1461 255,255,255,255,255,255,255,255,
1462 255,255,255,255,255,255,255,255,
1463 255,255,255,255,255,255,255,255,
1464 255,255,255,255,255,255,255,255,
1465 255,255,255,255,255,255,255,255,
1466 255,255,255,255,255,255,255,255,
1467 255,255,255,255,255,255,255,255,
1468 255,255,255,255,255,255};
1470 const int head3_7
[] = {0x4f,0x67,0x67,0x53,0,0x05,
1471 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1472 0x01,0x02,0x03,0x04,2,0,0,0,
1473 0xd4,0xe0,0x60,0xe5,
1477 void test_pack(const int *pl
, const int **headers
, int byteskip
,
1478 int pageskip
, int packetskip
){
1479 unsigned char *data
=_ogg_malloc(1024*1024); /* for scripted test cases only */
1484 long granule_pos
=7,pageno
=0;
1485 int i
,j
,packets
,pageout
=pageskip
;
1489 int byteskipcount
=0;
1491 ogg_stream_reset(&os_en
);
1492 ogg_stream_reset(&os_de
);
1493 ogg_sync_reset(&oy
);
1495 for(packets
=0;packets
<packetskip
;packets
++)
1496 depacket
+=pl
[packets
];
1498 for(packets
=0;;packets
++)if(pl
[packets
]==-1)break;
1500 for(i
=0;i
<packets
;i
++){
1501 /* construct a test packet */
1505 op
.packet
=data
+inptr
;
1507 op
.e_o_s
=(pl
[i
+1]<0?1:0);
1508 op
.granulepos
=granule_pos
;
1512 for(j
=0;j
<len
;j
++)data
[inptr
++]=i
+j
;
1514 /* submit the test packet */
1515 ogg_stream_packetin(&os_en
,&op
);
1517 /* retrieve any finished pages */
1521 while(ogg_stream_pageout(&os_en
,&og
)){
1522 /* We have a page. Check it carefully */
1524 fprintf(stderr
,"%ld, ",pageno
);
1526 if(headers
[pageno
]==NULL
){
1527 fprintf(stderr
,"coded too many pages!\n");
1531 check_page(data
+outptr
,headers
[pageno
],&og
);
1533 outptr
+=og
.body_len
;
1541 /* have a complete page; submit it to sync/decode */
1545 ogg_packet op_de
,op_de2
;
1546 char *buf
=ogg_sync_buffer(&oy
,og
.header_len
+og
.body_len
);
1548 byteskipcount
+=og
.header_len
;
1549 if(byteskipcount
>byteskip
){
1550 memcpy(next
,og
.header
,byteskipcount
-byteskip
);
1551 next
+=byteskipcount
-byteskip
;
1552 byteskipcount
=byteskip
;
1555 byteskipcount
+=og
.body_len
;
1556 if(byteskipcount
>byteskip
){
1557 memcpy(next
,og
.body
,byteskipcount
-byteskip
);
1558 next
+=byteskipcount
-byteskip
;
1559 byteskipcount
=byteskip
;
1562 ogg_sync_wrote(&oy
,next
-buf
);
1565 int ret
=ogg_sync_pageout(&oy
,&og_de
);
1568 /* got a page. Happy happy. Verify that it's good. */
1570 fprintf(stderr
,"(%d), ",pageout
);
1572 check_page(data
+deptr
,headers
[pageout
],&og_de
);
1573 deptr
+=og_de
.body_len
;
1576 /* submit it to deconstitution */
1577 ogg_stream_pagein(&os_de
,&og_de
);
1580 while(ogg_stream_packetpeek(&os_de
,&op_de2
)>0){
1581 ogg_stream_packetpeek(&os_de
,NULL
);
1582 ogg_stream_packetout(&os_de
,&op_de
); /* just catching them all */
1584 /* verify peek and out match */
1585 if(memcmp(&op_de
,&op_de2
,sizeof(op_de
))){
1586 fprintf(stderr
,"packetout != packetpeek! pos=%ld\n",
1591 /* verify the packet! */
1593 if(memcmp(data
+depacket
,op_de
.packet
,op_de
.bytes
)){
1594 fprintf(stderr
,"packet data mismatch in decode! pos=%ld\n",
1598 /* check bos flag */
1599 if(bosflag
==0 && op_de
.b_o_s
==0){
1600 fprintf(stderr
,"b_o_s flag not set on packet!\n");
1603 if(bosflag
&& op_de
.b_o_s
){
1604 fprintf(stderr
,"b_o_s flag incorrectly set on packet!\n");
1608 depacket
+=op_de
.bytes
;
1610 /* check eos flag */
1612 fprintf(stderr
,"Multiple decoded packets with eos flag!\n");
1616 if(op_de
.e_o_s
)eosflag
=1;
1618 /* check granulepos flag */
1619 if(op_de
.granulepos
!=-1){
1620 fprintf(stderr
," granule:%ld ",(long)op_de
.granulepos
);
1629 if(headers
[pageno
]!=NULL
){
1630 fprintf(stderr
,"did not write last page!\n");
1633 if(headers
[pageout
]!=NULL
){
1634 fprintf(stderr
,"did not decode last page!\n");
1638 fprintf(stderr
,"encoded page data incomplete!\n");
1642 fprintf(stderr
,"decoded page data incomplete!\n");
1645 if(inptr
!=depacket
){
1646 fprintf(stderr
,"decoded packet data incomplete!\n");
1650 fprintf(stderr
,"Never got a packet with EOS set!\n");
1653 fprintf(stderr
,"ok.\n");
1658 ogg_stream_init(&os_en
,0x04030201);
1659 ogg_stream_init(&os_de
,0x04030201);
1662 /* Exercise each code path in the framing code. Also verify that
1663 the checksums are working. */
1667 const int packets
[]={17, -1};
1668 const int *headret
[]={head1_0
,NULL
};
1670 fprintf(stderr
,"testing single page encoding... ");
1671 test_pack(packets
,headret
,0,0,0);
1675 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1676 const int packets
[]={17, 254, 255, 256, 500, 510, 600, -1};
1677 const int *headret
[]={head1_1
,head2_1
,NULL
};
1679 fprintf(stderr
,"testing basic page encoding... ");
1680 test_pack(packets
,headret
,0,0,0);
1684 /* nil packets; beginning,middle,end */
1685 const int packets
[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1686 const int *headret
[]={head1_2
,head2_2
,NULL
};
1688 fprintf(stderr
,"testing basic nil packets... ");
1689 test_pack(packets
,headret
,0,0,0);
1693 /* large initial packet */
1694 const int packets
[]={4345,259,255,-1};
1695 const int *headret
[]={head1_3
,head2_3
,NULL
};
1697 fprintf(stderr
,"testing initial-packet lacing > 4k... ");
1698 test_pack(packets
,headret
,0,0,0);
1702 /* continuing packet test; with page spill expansion, we have to
1703 overflow the lacing table. */
1704 const int packets
[]={0,65500,259,255,-1};
1705 const int *headret
[]={head1_4
,head2_4
,head3_4
,NULL
};
1707 fprintf(stderr
,"testing single packet page span... ");
1708 test_pack(packets
,headret
,0,0,0);
1712 /* spill expand packet test */
1713 const int packets
[]={0,4345,259,255,0,0,-1};
1714 const int *headret
[]={head1_4b
,head2_4b
,head3_4b
,NULL
};
1716 fprintf(stderr
,"testing page spill expansion... ");
1717 test_pack(packets
,headret
,0,0,0);
1720 /* page with the 255 segment limit */
1723 const int packets
[]={0,10,10,10,10,10,10,10,10,
1724 10,10,10,10,10,10,10,10,
1725 10,10,10,10,10,10,10,10,
1726 10,10,10,10,10,10,10,10,
1727 10,10,10,10,10,10,10,10,
1728 10,10,10,10,10,10,10,10,
1729 10,10,10,10,10,10,10,10,
1730 10,10,10,10,10,10,10,10,
1731 10,10,10,10,10,10,10,10,
1732 10,10,10,10,10,10,10,10,
1733 10,10,10,10,10,10,10,10,
1734 10,10,10,10,10,10,10,10,
1735 10,10,10,10,10,10,10,10,
1736 10,10,10,10,10,10,10,10,
1737 10,10,10,10,10,10,10,10,
1738 10,10,10,10,10,10,10,10,
1739 10,10,10,10,10,10,10,10,
1740 10,10,10,10,10,10,10,10,
1741 10,10,10,10,10,10,10,10,
1742 10,10,10,10,10,10,10,10,
1743 10,10,10,10,10,10,10,10,
1744 10,10,10,10,10,10,10,10,
1745 10,10,10,10,10,10,10,10,
1746 10,10,10,10,10,10,10,10,
1747 10,10,10,10,10,10,10,10,
1748 10,10,10,10,10,10,10,10,
1749 10,10,10,10,10,10,10,10,
1750 10,10,10,10,10,10,10,10,
1751 10,10,10,10,10,10,10,10,
1752 10,10,10,10,10,10,10,10,
1753 10,10,10,10,10,10,10,10,
1754 10,10,10,10,10,10,10,50,-1};
1755 const int *headret
[]={head1_5
,head2_5
,head3_5
,NULL
};
1757 fprintf(stderr
,"testing max packet segments... ");
1758 test_pack(packets
,headret
,0,0,0);
1762 /* packet that overspans over an entire page */
1763 const int packets
[]={0,100,130049,259,255,-1};
1764 const int *headret
[]={head1_6
,head2_6
,head3_6
,head4_6
,NULL
};
1766 fprintf(stderr
,"testing very large packets... ");
1767 test_pack(packets
,headret
,0,0,0);
1771 /* test for the libogg 1.1.1 resync in large continuation bug
1772 found by Josh Coalson) */
1773 const int packets
[]={0,100,130049,259,255,-1};
1774 const int *headret
[]={head1_6
,head2_6
,head3_6
,head4_6
,NULL
};
1776 fprintf(stderr
,"testing continuation resync in very large packets... ");
1777 test_pack(packets
,headret
,100,2,3);
1781 /* term only page. why not? */
1782 const int packets
[]={0,100,64770,-1};
1783 const int *headret
[]={head1_7
,head2_7
,head3_7
,NULL
};
1785 fprintf(stderr
,"testing zero data page (1 nil packet)... ");
1786 test_pack(packets
,headret
,0,0,0);
1792 /* build a bunch of pages for testing */
1793 unsigned char *data
=_ogg_malloc(1024*1024);
1794 int pl
[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1798 ogg_stream_reset(&os_en
);
1800 for(i
=0;pl
[i
]!=-1;i
++){
1804 op
.packet
=data
+inptr
;
1806 op
.e_o_s
=(pl
[i
+1]<0?1:0);
1807 op
.granulepos
=(i
+1)*1000;
1809 for(j
=0;j
<len
;j
++)data
[inptr
++]=i
+j
;
1810 ogg_stream_packetin(&os_en
,&op
);
1815 /* retrieve finished pages */
1817 if(ogg_stream_pageout(&os_en
,&og
[i
])==0){
1818 fprintf(stderr
,"Too few pages output building sync tests!\n");
1824 /* Test lost pages on pagein/packetout: no rollback */
1829 fprintf(stderr
,"Testing loss of pages... ");
1831 ogg_sync_reset(&oy
);
1832 ogg_stream_reset(&os_de
);
1834 memcpy(ogg_sync_buffer(&oy
,og
[i
].header_len
),og
[i
].header
,
1836 ogg_sync_wrote(&oy
,og
[i
].header_len
);
1837 memcpy(ogg_sync_buffer(&oy
,og
[i
].body_len
),og
[i
].body
,og
[i
].body_len
);
1838 ogg_sync_wrote(&oy
,og
[i
].body_len
);
1841 ogg_sync_pageout(&oy
,&temp
);
1842 ogg_stream_pagein(&os_de
,&temp
);
1843 ogg_sync_pageout(&oy
,&temp
);
1844 ogg_stream_pagein(&os_de
,&temp
);
1845 ogg_sync_pageout(&oy
,&temp
);
1847 ogg_sync_pageout(&oy
,&temp
);
1848 ogg_stream_pagein(&os_de
,&temp
);
1850 /* do we get the expected results/packets? */
1852 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1853 checkpacket(&test
,0,0,0);
1854 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1855 checkpacket(&test
,1,1,-1);
1856 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1857 checkpacket(&test
,1,2,-1);
1858 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1859 checkpacket(&test
,98,3,-1);
1860 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1861 checkpacket(&test
,4079,4,5000);
1862 if(ogg_stream_packetout(&os_de
,&test
)!=-1){
1863 fprintf(stderr
,"Error: loss of page did not return error\n");
1866 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1867 checkpacket(&test
,76,9,-1);
1868 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1869 checkpacket(&test
,34,10,-1);
1870 fprintf(stderr
,"ok.\n");
1873 /* Test lost pages on pagein/packetout: rollback with continuation */
1878 fprintf(stderr
,"Testing loss of pages (rollback required)... ");
1880 ogg_sync_reset(&oy
);
1881 ogg_stream_reset(&os_de
);
1883 memcpy(ogg_sync_buffer(&oy
,og
[i
].header_len
),og
[i
].header
,
1885 ogg_sync_wrote(&oy
,og
[i
].header_len
);
1886 memcpy(ogg_sync_buffer(&oy
,og
[i
].body_len
),og
[i
].body
,og
[i
].body_len
);
1887 ogg_sync_wrote(&oy
,og
[i
].body_len
);
1890 ogg_sync_pageout(&oy
,&temp
);
1891 ogg_stream_pagein(&os_de
,&temp
);
1892 ogg_sync_pageout(&oy
,&temp
);
1893 ogg_stream_pagein(&os_de
,&temp
);
1894 ogg_sync_pageout(&oy
,&temp
);
1895 ogg_stream_pagein(&os_de
,&temp
);
1896 ogg_sync_pageout(&oy
,&temp
);
1898 ogg_sync_pageout(&oy
,&temp
);
1899 ogg_stream_pagein(&os_de
,&temp
);
1901 /* do we get the expected results/packets? */
1903 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1904 checkpacket(&test
,0,0,0);
1905 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1906 checkpacket(&test
,1,1,-1);
1907 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1908 checkpacket(&test
,1,2,-1);
1909 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1910 checkpacket(&test
,98,3,-1);
1911 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1912 checkpacket(&test
,4079,4,5000);
1913 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1914 checkpacket(&test
,1,5,-1);
1915 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1916 checkpacket(&test
,1,6,-1);
1917 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1918 checkpacket(&test
,2954,7,-1);
1919 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1920 checkpacket(&test
,2057,8,9000);
1921 if(ogg_stream_packetout(&os_de
,&test
)!=-1){
1922 fprintf(stderr
,"Error: loss of page did not return error\n");
1925 if(ogg_stream_packetout(&os_de
,&test
)!=1)error();
1926 checkpacket(&test
,300,17,18000);
1927 fprintf(stderr
,"ok.\n");
1930 /* the rest only test sync */
1933 /* Test fractional page inputs: incomplete capture */
1934 fprintf(stderr
,"Testing sync on partial inputs... ");
1935 ogg_sync_reset(&oy
);
1936 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
,
1938 ogg_sync_wrote(&oy
,3);
1939 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
1941 /* Test fractional page inputs: incomplete fixed header */
1942 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
+3,
1944 ogg_sync_wrote(&oy
,20);
1945 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
1947 /* Test fractional page inputs: incomplete header */
1948 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
+23,
1950 ogg_sync_wrote(&oy
,5);
1951 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
1953 /* Test fractional page inputs: incomplete body */
1955 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
+28,
1956 og
[1].header_len
-28);
1957 ogg_sync_wrote(&oy
,og
[1].header_len
-28);
1958 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
1960 memcpy(ogg_sync_buffer(&oy
,og
[1].body_len
),og
[1].body
,1000);
1961 ogg_sync_wrote(&oy
,1000);
1962 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
1964 memcpy(ogg_sync_buffer(&oy
,og
[1].body_len
),og
[1].body
+1000,
1965 og
[1].body_len
-1000);
1966 ogg_sync_wrote(&oy
,og
[1].body_len
-1000);
1967 if(ogg_sync_pageout(&oy
,&og_de
)<=0)error();
1969 fprintf(stderr
,"ok.\n");
1972 /* Test fractional page inputs: page + incomplete capture */
1975 fprintf(stderr
,"Testing sync on 1+partial inputs... ");
1976 ogg_sync_reset(&oy
);
1978 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
,
1980 ogg_sync_wrote(&oy
,og
[1].header_len
);
1982 memcpy(ogg_sync_buffer(&oy
,og
[1].body_len
),og
[1].body
,
1984 ogg_sync_wrote(&oy
,og
[1].body_len
);
1986 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
,
1988 ogg_sync_wrote(&oy
,20);
1989 if(ogg_sync_pageout(&oy
,&og_de
)<=0)error();
1990 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
1992 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
+20,
1993 og
[1].header_len
-20);
1994 ogg_sync_wrote(&oy
,og
[1].header_len
-20);
1995 memcpy(ogg_sync_buffer(&oy
,og
[1].body_len
),og
[1].body
,
1997 ogg_sync_wrote(&oy
,og
[1].body_len
);
1998 if(ogg_sync_pageout(&oy
,&og_de
)<=0)error();
2000 fprintf(stderr
,"ok.\n");
2003 /* Test recapture: garbage + page */
2006 fprintf(stderr
,"Testing search for capture... ");
2007 ogg_sync_reset(&oy
);
2010 memcpy(ogg_sync_buffer(&oy
,og
[1].body_len
),og
[1].body
,
2012 ogg_sync_wrote(&oy
,og
[1].body_len
);
2014 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
,
2016 ogg_sync_wrote(&oy
,og
[1].header_len
);
2018 memcpy(ogg_sync_buffer(&oy
,og
[1].body_len
),og
[1].body
,
2020 ogg_sync_wrote(&oy
,og
[1].body_len
);
2022 memcpy(ogg_sync_buffer(&oy
,og
[2].header_len
),og
[2].header
,
2024 ogg_sync_wrote(&oy
,20);
2025 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
2026 if(ogg_sync_pageout(&oy
,&og_de
)<=0)error();
2027 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
2029 memcpy(ogg_sync_buffer(&oy
,og
[2].header_len
),og
[2].header
+20,
2030 og
[2].header_len
-20);
2031 ogg_sync_wrote(&oy
,og
[2].header_len
-20);
2032 memcpy(ogg_sync_buffer(&oy
,og
[2].body_len
),og
[2].body
,
2034 ogg_sync_wrote(&oy
,og
[2].body_len
);
2035 if(ogg_sync_pageout(&oy
,&og_de
)<=0)error();
2037 fprintf(stderr
,"ok.\n");
2040 /* Test recapture: page + garbage + page */
2043 fprintf(stderr
,"Testing recapture... ");
2044 ogg_sync_reset(&oy
);
2046 memcpy(ogg_sync_buffer(&oy
,og
[1].header_len
),og
[1].header
,
2048 ogg_sync_wrote(&oy
,og
[1].header_len
);
2050 memcpy(ogg_sync_buffer(&oy
,og
[1].body_len
),og
[1].body
,
2052 ogg_sync_wrote(&oy
,og
[1].body_len
);
2054 memcpy(ogg_sync_buffer(&oy
,og
[2].header_len
),og
[2].header
,
2056 ogg_sync_wrote(&oy
,og
[2].header_len
);
2058 memcpy(ogg_sync_buffer(&oy
,og
[2].header_len
),og
[2].header
,
2060 ogg_sync_wrote(&oy
,og
[2].header_len
);
2062 if(ogg_sync_pageout(&oy
,&og_de
)<=0)error();
2064 memcpy(ogg_sync_buffer(&oy
,og
[2].body_len
),og
[2].body
,
2066 ogg_sync_wrote(&oy
,og
[2].body_len
-5);
2068 memcpy(ogg_sync_buffer(&oy
,og
[3].header_len
),og
[3].header
,
2070 ogg_sync_wrote(&oy
,og
[3].header_len
);
2072 memcpy(ogg_sync_buffer(&oy
,og
[3].body_len
),og
[3].body
,
2074 ogg_sync_wrote(&oy
,og
[3].body_len
);
2076 if(ogg_sync_pageout(&oy
,&og_de
)>0)error();
2077 if(ogg_sync_pageout(&oy
,&og_de
)<=0)error();
2079 fprintf(stderr
,"ok.\n");
2082 /* Free page data that was previously copied */