• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright (C) 2002-2019 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2007 John ffitch
4 ** Copyright (C) 2018 Arthur Taylor <art@ified.ca>
5 **
6 ** This program is free software ; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published by
8 ** the Free Software Foundation ; either version 2.1 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY ; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
14 ** GNU Lesser General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program ; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20 
21 /*
22 ** This file contains code based on OpusFile and Opus-Tools, both by
23 ** Xiph.Org. COPYING from each is identical and is as follows:
24 **
25 ** Copyright (c) 1994-2013 Xiph.Org Foundation and contributors
26 **
27 ** Redistribution and use in source and binary forms, with or without
28 ** modification, are permitted provided that the following conditions
29 ** are met:
30 **
31 ** - Redistributions of source code must retain the above copyright
32 ** notice, this list of conditions and the following disclaimer.
33 **
34 ** - Redistributions in binary form must reproduce the above copyright
35 ** notice, this list of conditions and the following disclaimer in the
36 ** documentation and/or other materials provided with the distribution.
37 **
38 ** - Neither the name of the Xiph.Org Foundation nor the names of its
39 ** contributors may be used to endorse or promote products derived from
40 ** this software without specific prior written permission.
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 ** ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 ** A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
46 ** OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54 
55 #include "sfconfig.h"
56 
57 #include <stdio.h>
58 #include <fcntl.h>
59 #include <string.h>
60 #include <ctype.h>
61 #include <time.h>
62 #include <math.h>
63 
64 #if HAVE_UNISTD_H
65 #include <unistd.h>
66 #else
67 #include "sf_unistd.h"
68 #endif
69 
70 #include "sndfile.h"
71 #include "sfendian.h"
72 #include "common.h"
73 
74 #if HAVE_EXTERNAL_XIPH_LIBS
75 
76 #include <ogg/ogg.h>
77 
78 #include "ogg.h"
79 
80 #define OGG_SYNC_READ_SIZE (2048)
81 #define OGG_PAGE_SIZE_MAX (65307)
82 #define OGG_CHUNK_SIZE (65536)
83 #define OGG_CHUNK_SIZE_MAX (1024*1024)
84 
85 /*
86  * The Ogg container may seem overly complicated, particularly when used for a
87  * on-disk audio file format. This is probably because Ogg is designed with
88  * streaming rather than storage as a priority, and can handle multiple codec
89  * payloads multiplexed together, then possibly chained on top of that.
90  * Ogg achieves its goals well, but it does lend to a bit of a learning curve,
91  * with many internal structures to push data around in compared to most sound
92  * file formats which only have a header and raw data.
93  *
94  * See
95  *  - [https://xiph.org/ogg/doc/oggstream.html]
96  *  - [https://xiph.org/ogg/doc/framing.html]
97  *
98  * libogg Memory Management
99  * ===========================================================================
100  *
101  * libOgg's memory management is documented in code, not in headers or external
102  * documentation. What follows is not an attempt to completely document it, but
103  * an explanation of the basics.
104  *
105  * libOgg has two data structures which allocate and manage data buffers: The
106  * ogg_sync_state structure and the ogg_stream_state structure. The remaining
107  * structures of ogg_page and ogg_packet are views into the buffers managed by
108  * the previous structures.
109  *
110  * ogg_sync_state is used for reading purposes. It takes a physical bitstream
111  * and searches for, validates, and returns complete Ogg Pages. The
112  * ogg_sync_state buffers the returned page data, holding at most one
113  * complete page at a time. A returned Ogg page remains valid until any
114  * operation other than ogg_sync_check() is called.
115  *
116  * ogg_stream_state is used for both reading and writing. For reading, the
117  * contents of an ogg_page is copied into the stream state. This data is
118  * buffered to be split or joined as necessary into complete ogg_packets. If,
119  * after copying an ogg_page into an ogg_stream_state, packets are available to
120  * be read, then all of those packets remain in memory and valid until either
121  * the ogg_stream_state is reset, destroyed, or a new ogg_page is read into it.
122  * As the maximum number of packets an Ogg Page may contain is 255, at most 255
123  * packets may be available from an ogg_stream_state at one time.
124  *
125  * For writing, the life cycle of a buffer pointed to by a ogg_packet is the
126  * responsibility of the caller. Packets written into an ogg_stream_state are
127  * buffered until a complete page is ready for writing. Pages for writing out
128  * remain in the ogg_stream_state's buffer and valid until either the
129  * ogg_stream_state is reset, cleared, destroyed. Writing another packet into
130  * the ogg_stream_state might also invalidate such pages, but writing in
131  * packets when a page is ready to be written out is a caller bug anyways.
132  */
133 
134 /*-----------------------------------------------------------------------------------------------
135 ** Private function prototypes.
136 */
137 
138 static int		ogg_close (SF_PRIVATE *psf) ;
139 static int		ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE * odata) ;
140 static int		ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og) ;
141 static uint64_t	ogg_page_search_do_rescale (uint64_t x, uint64_t from, uint64_t to) ;
142 static void		ogg_page_search_continued_data (OGG_PRIVATE *odata, ogg_page *page) ;
143 
144 /*-----------------------------------------------------------------------------------------------
145 ** Exported functions.
146 */
147 
148 int
ogg_read_first_page(SF_PRIVATE * psf,OGG_PRIVATE * odata)149 ogg_read_first_page (SF_PRIVATE *psf, OGG_PRIVATE *odata)
150 {	int ret ;
151 	char *buffer ;
152 
153 	/*
154 	** The ogg standard requires that the first pages of a physical ogg
155 	** bitstream be only the first pages of each logical bitstream. These
156 	** pages MUST have the Beginning-Of-Stream bit set, and must contain
157 	** only the stream's relevant header. Currently we only load the first
158 	** page and check that it contains a codec we support as supporting
159 	** multiplexed streams (video+audio(en)+audio(fs)+subtitles, etc) is
160 	** beyond the scope of this library.
161 	*/
162 
163 	ret = ogg_sync_fseek (psf, psf->header.indx, SEEK_SET) ;
164 	if (ret < 0)
165 		return SFE_NOT_SEEKABLE ;
166 
167 	buffer = ogg_sync_buffer (&odata->osync, psf->header.indx) ;
168 	if (buffer == NULL)
169 		return SFE_MALLOC_FAILED ;
170 	memcpy (buffer, psf->header.ptr, psf->header.indx) ;
171 	ogg_sync_wrote (&odata->osync, psf->header.indx) ;
172 
173 	ret = ogg_sync_next_page (psf, &odata->opage, SF_MAX ((sf_count_t) 0, 4096 - psf->header.indx), NULL) ;
174 
175 	/* Have we simply run out of data?  If so, we're done. */
176 	if (ret == 0)
177 		return 0 ;
178 	if (ret < 0)
179 		return psf->error ;
180 
181 	if (!ogg_page_bos (&odata->opage))
182 	{	/*
183 		** Error case. Either must not be an Ogg bitstream, or is in the
184 		** middle of a bitstream (live capture), or in the middle of a
185 		** bitstream and no complete page was in the buffer.
186 		*/
187 		psf_log_printf (psf, "Input does not appear to be the start of an Ogg bitstream.\n") ;
188 		return SFE_MALFORMED_FILE ;
189 		} ;
190 
191 	/*
192 	**	Get the serial number and set up the rest of decode.
193 	**	Serialno first ; use it to set up a logical stream.
194 	*/
195 	ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
196 
197 	if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
198 	{	/* Error ; stream version mismatch perhaps. */
199 		psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ;
200 		return SFE_MALFORMED_FILE ;
201 		} ;
202 
203 	if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1)
204 	{	/* No page? */
205 		psf_log_printf (psf, "Error reading initial header page packet.\n") ;
206 		return SFE_MALFORMED_FILE ;
207 		} ;
208 
209 	return 0 ;
210 } /* ogg_read_first_page */
211 
212 int
ogg_write_page(SF_PRIVATE * psf,ogg_page * page)213 ogg_write_page (SF_PRIVATE *psf, ogg_page *page)
214 {	int bytes ;
215 
216 	bytes = psf_fwrite (page->header, 1, page->header_len, psf) ;
217 	bytes += psf_fwrite (page->body, 1, page->body_len, psf) ;
218 
219 	return bytes == page->header_len + page->body_len ;
220 } /* ogg_write_page */
221 
222 sf_count_t
ogg_sync_ftell(SF_PRIVATE * psf)223 ogg_sync_ftell (SF_PRIVATE *psf)
224 {	OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
225 	sf_count_t position ;
226 
227 	position = psf_ftell (psf) ;
228 	if (position >= 0)
229 	{	/* success */
230 		if (position < odata->osync.fill)
231 		{	/* Really, this should be an assert. */
232 			psf->error = SFE_INTERNAL ;
233 			return -1 ;
234 			}
235 		position += (sf_count_t) (odata->osync.returned - odata->osync.fill) ;
236 		}
237 
238 	return position ;
239 } /* ogg_sync_ftell */
240 
241 sf_count_t
ogg_sync_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)242 ogg_sync_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
243 {	OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
244 	sf_count_t ret ;
245 
246 	ret = psf_fseek (psf, offset, whence) ;
247 	if (ret >= 0)
248 	{	/* success */
249 		odata->eos = 0 ;
250 		ogg_sync_reset (&odata->osync) ;
251 		}
252 
253 	return ret ;
254 } /* ogg_sync_fseek */
255 
256 int
ogg_sync_next_page(SF_PRIVATE * psf,ogg_page * og,sf_count_t readmax,sf_count_t * offset)257 ogg_sync_next_page (SF_PRIVATE * psf, ogg_page *og, sf_count_t readmax, sf_count_t *offset)
258 {	OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
259 	sf_count_t position, nb_read, read_ret ;
260 	unsigned char *buffer ;
261 	int synced ;
262 	int report_hole = 0 ;
263 
264 	for (position = 0 ; readmax <= 0 || readmax > position ; )
265 	{	synced = ogg_sync_pageseek (&odata->osync, og) ;
266 		if (synced < 0)
267 		{	/*
268 			** Skipped -synced bytes before finding the start of a page.
269 			** If seeking, we have just landed in the middle of a page.
270 			** Otherwise, warn about junk in the bitstream.
271 			** Page might not yet be ready, hence the continue.
272 			*/
273 			if (!offset)
274 				report_hole = 1 ;
275 			position -= synced ;
276 			continue ;
277 			} ;
278 
279 		if (report_hole)
280 		{	psf_log_printf (psf, "Ogg : Skipped %d bytes looking for the next page. Corrupted bitstream?!\n", position) ;
281 			report_hole = 0 ;
282 			} ;
283 
284 		if (synced > 0)
285 		{	/* Have a page */
286 			if (offset)
287 				*offset += position ;
288 			return og->header_len + og->body_len ;
289 			} ;
290 
291 		/*
292 		** Else readmax == 0, Out of data. Try to read more in without
293 		** invalidating our boundary (readmax) constraint.
294 		*/
295 		if (readmax == 0)
296 			return 0 ;
297 		if (readmax > 0)
298 			nb_read = SF_MIN ((sf_count_t) OGG_SYNC_READ_SIZE, readmax - position) ;
299 		else
300 			nb_read = OGG_SYNC_READ_SIZE ;
301 		buffer = (unsigned char *) ogg_sync_buffer (&odata->osync, nb_read) ;
302 		if (buffer == NULL)
303 		{	psf->error = SFE_MALLOC_FAILED ;
304 			return -1 ;
305 			}
306 		read_ret = psf_fread (buffer, 1, nb_read, psf) ;
307 		if (read_ret == 0)
308 			return psf->error ? -1 : 0 ;
309 		ogg_sync_wrote (&odata->osync, read_ret) ;
310 		} ;
311 	return 0 ;
312 } /* ogg_sync_next_page */
313 
314 int
ogg_stream_next_page(SF_PRIVATE * psf,OGG_PRIVATE * odata)315 ogg_stream_next_page (SF_PRIVATE *psf, OGG_PRIVATE *odata)
316 {	int nn ;
317 
318 	if (odata->eos)
319 		return 0 ;
320 
321 	for ( ; ; )
322 	{	nn = ogg_sync_next_page (psf, &odata->opage, -1, NULL) ;
323 		if (nn == 0)
324 		{	psf_log_printf (psf, "Ogg : File ended unexpectedly without an End-Of-Stream flag set.\n") ;
325 			odata->eos = 1 ;
326 			}
327 		if (nn <= 0)
328 			return nn ;
329 
330 		if (ogg_page_serialno (&odata->opage) == odata->ostream.serialno)
331 			break ;
332 		} ;
333 
334 	if (ogg_page_eos (&odata->opage))
335 		odata->eos = 1 ;
336 
337 	if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
338 	{	psf->error = SFE_INTERNAL ;
339 		return -1 ;
340 		}
341 
342 	return 1 ;
343 } /* ogg_stream_next_page */
344 
345 int
ogg_stream_unpack_page(SF_PRIVATE * psf,OGG_PRIVATE * odata)346 ogg_stream_unpack_page (SF_PRIVATE *psf, OGG_PRIVATE *odata)
347 {	int nn ;
348 	int i ;
349 	int found_hole = 0 ;
350 	ogg_packet *ppkt = odata->pkt ;
351 
352 	odata->pkt_indx = 0 ;
353 	nn = ogg_stream_packetout (&odata->ostream, ppkt) ;
354 	if (nn == 0)
355 	{	/*
356 		** Steam is out of packets. Read in more pages until there is one, or
357 		** the stream ends, or an error occurs.
358 		*/
359 		for ( ; nn == 0 ; nn = ogg_stream_packetout (&odata->ostream, ppkt))
360 		{	nn = ogg_stream_next_page (psf, odata) ;
361 			if (nn <= 0)
362 			{	odata->pkt_len = 0 ;
363 				return nn ;
364 				}
365 			}
366 		/*
367 		** In the case of the for loop exiting because
368 		** ogg_stream_packetout() == -1, fall-through.
369 		*/
370 		}
371 
372 	if (nn == -1)
373 	{	/*
374 		** libOgg found a hole. That is, the next packet found was out of
375 		** sequence. As such, "flush" the hole marker by removing the invalid
376 		** packet, as the valid packets are queued behind it.
377 		*/
378 		psf_log_printf (psf, "Ogg : Warning, libogg reports a hole at %d bytes.\n", ogg_sync_ftell (psf)) ;
379 		nn = ogg_stream_packetout (&odata->ostream, ppkt) ;
380 		found_hole = 1 ;
381 		}
382 
383 	/*
384 	** Unpack all the packets on the page. It is undocumented (like much of
385 	** libOgg behavior) but all packets from a page read into the stream are
386 	** guarenteed to remain valid in memory until a new page is read into the
387 	** stream.
388 	*/
389 	for (i = 1 ; ; i++)
390 	{	/* Not an off-by-one, there are 255 not 256 packets max. */
391 		if (i == 255)
392 		{	if (ogg_stream_packetpeek (&odata->ostream, NULL) == 1)
393 			{	psf->error = SFE_INTERNAL ;
394 				return -1 ;
395 				}
396 			break ;
397 			}
398 		if (ogg_stream_packetout (&odata->ostream, ++ ppkt) != 1)
399 			break ;
400 		}
401 	odata->pkt_len = i ;
402 
403 	/* 1 = ok, 2 = ok, and found a hole. */
404 	return 1 + found_hole ;
405 } /* ogg_stream_unpack_page */
406 
407 sf_count_t
ogg_sync_last_page_before(SF_PRIVATE * psf,OGG_PRIVATE * odata,uint64_t * gp_out,sf_count_t offset,int32_t serialno)408 ogg_sync_last_page_before (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t *gp_out, sf_count_t offset, int32_t serialno)
409 {	sf_count_t begin, end, original_end, chunk_size, ret ;
410 	sf_count_t position = 0 ;
411 	uint64_t gp = -1 ;
412 	int left_link ;
413 
414 	/* Based on code from Xiph.org's Opusfile */
415 
416 	original_end = end = begin = offset ;
417 	offset = -1 ;
418 	chunk_size = OGG_CHUNK_SIZE ;
419 	do
420 	{	begin = SF_MAX (begin - chunk_size, (sf_count_t) 0) ;
421 		position = ogg_sync_fseek (psf, begin, SEEK_SET) ;
422 		if (position < 0)
423 			return position ;
424 		left_link = 0 ;
425 		while (position < end)
426 		{	ret = ogg_sync_next_page (psf, &odata->opage, end - position, &position) ;
427 			if (ret <= 0)
428 				return -1 ;
429 			if (ogg_page_serialno (&odata->opage) == serialno)
430 			{	uint64_t page_gp = ogg_page_granulepos (&odata->opage) ;
431 				if (page_gp != (uint64_t) -1)
432 				{	offset = position ;
433 					gp = page_gp ;
434 					}
435 				}
436 			else
437 				left_link = 1 ;
438 			position += ret ;
439 			}
440 
441 		if ((left_link || !begin) && offset < 0)
442 		{	psf->error = SFE_MALFORMED_FILE ;
443 			return -1 ;
444 			}
445 
446 		chunk_size = SF_MIN (2 * chunk_size, (sf_count_t) OGG_CHUNK_SIZE_MAX) ;
447 		end = SF_MIN (begin + OGG_PAGE_SIZE_MAX - 1, original_end) ;
448 		}
449 	while (offset < 0) ;
450 
451 	*gp_out = gp ;
452 	return offset ;
453 } /* ogg_sync_last_page_before */
454 
455 int
ogg_stream_seek_page_search(SF_PRIVATE * psf,OGG_PRIVATE * odata,uint64_t target_gp,uint64_t pcm_start,uint64_t pcm_end,uint64_t * best_gp,sf_count_t begin,sf_count_t end,uint64_t gp_rate)456 ogg_stream_seek_page_search (SF_PRIVATE *psf, OGG_PRIVATE *odata,
457 	uint64_t target_gp, uint64_t pcm_start, uint64_t pcm_end, uint64_t *best_gp,
458 	sf_count_t begin, sf_count_t end, uint64_t gp_rate)
459 {	ogg_page page ;
460 	uint64_t gp ;
461 	sf_count_t d0, d1, d2 ;
462 	sf_count_t best ;
463 	sf_count_t best_start ;
464 	sf_count_t boundary ;
465 	sf_count_t next_boundary ;
466 	sf_count_t page_offset = -1 ;
467 	sf_count_t seek_pos = -1 ;
468 	sf_count_t bisect ;
469 	sf_count_t chunk_size ;
470 	int buffering = SF_FALSE ;
471 	int force_bisect = SF_FALSE ;
472 	int ret ;
473 	int has_packets ;
474 
475 	*best_gp = pcm_start ;
476 	best = best_start = begin ;
477 	boundary = end ;
478 
479 	ogg_stream_reset_serialno (&odata->ostream, odata->ostream.serialno) ;
480 
481 	/*
482 	** This code is based on op_pcm_seek_page() from Opusfile, which is in turn
483 	** based on "new search algorithm by Nicholas Vinen" from libvorbisfile.
484 	*/
485 
486 	d2 = d1 = d0 = end - begin ;
487 	while (begin < end)
488 	{	/*
489 		** Figure out if and where to try and seek in the file.
490 		*/
491 		if (end - begin < OGG_CHUNK_SIZE)
492 			bisect = begin ;
493 		else
494 		{	/* Update the interval size history */
495 			d0 = d1 >> 1 ;
496 			d1 = d2 >> 1 ;
497 			d2 = (end - begin) >> 1 ;
498 			if (force_bisect == SF_TRUE)
499 				bisect = begin + ((end - begin) >> 1) ;
500 			else
501 			{	/* Take a decent guess. */
502 				bisect = begin + ogg_page_search_do_rescale (target_gp - pcm_start, pcm_end - pcm_start, end - begin) ;
503 				}
504 			if (bisect - OGG_CHUNK_SIZE < begin)
505 				bisect = begin ;
506 			else
507 				bisect -= OGG_CHUNK_SIZE ;
508 			force_bisect = SF_FALSE ;
509 			}
510 
511 		/*
512 		** Avoid an actual fseek if we can (common for final iterations.)
513 		*/
514 		if (seek_pos != bisect)
515 		{	if (buffering == SF_TRUE)
516 				ogg_stream_reset (&odata->ostream) ;
517 			buffering = SF_FALSE ;
518 			page_offset = -1 ;
519 			seek_pos = ogg_sync_fseek (psf, bisect, SEEK_SET) ;
520 			if (seek_pos < 0)
521 				return seek_pos ;
522 			}
523 
524 		chunk_size = OGG_CHUNK_SIZE ;
525 		next_boundary = boundary ;
526 
527 		/*
528 		** Scan forward, figure out where we landed.
529 		** The ideal case is we see a page that ends before our target followed
530 		** by a page that ends after our target.
531 		** If we are too far before or after, breaking out will bisect what we
532 		** have found so far.
533 		*/
534 		while (begin < end)
535 		{	ret = ogg_sync_next_page (psf, &page, boundary - seek_pos, &seek_pos) ;
536 			if (ret <= 0)
537 				return ret ;
538 			page_offset = seek_pos ;
539 			if (ret == 0)
540 			{	/*
541 				** There are no more pages in this interval from our stream
542 				** with a granulepos less than our target.
543 				*/
544 				if (bisect <= begin + 1)
545 				{	/* Scanned the whole interval, so we are done. */
546 					end = begin ;
547 					}
548 				else
549 				{	/*
550 					** Otherwise, back up one chunk. First discard any data
551 					** from a continued packet.
552 					*/
553 					if (buffering)
554 						ogg_stream_reset (&odata->ostream) ;
555 					buffering = SF_FALSE ;
556 					bisect = SF_MAX (bisect - chunk_size, begin) ;
557 					seek_pos = ogg_sync_fseek (psf, bisect, SEEK_SET) ;
558 					if (seek_pos < 0)
559 						return seek_pos ;
560 					/* Bump up the chunk size. */
561 					chunk_size = SF_MIN (2 * chunk_size, (sf_count_t) OGG_CHUNK_SIZE_MAX) ;
562 					/*
563 					** If we did find a page from another stream or without a
564 					** timestamp, don't read past it.
565 					*/
566 					boundary = next_boundary ;
567 					}
568 				continue ;
569 				}
570 
571 			/* Found a page. Advance seek_pos past it */
572 			seek_pos += page.header_len + page.body_len ;
573 			/*
574 			** Save the offset of the first page we found after the seek,
575 			** regardless of the stream it came from or whether or not it has a
576 			** timestamp.
577 			*/
578 			next_boundary = SF_MIN (page_offset, next_boundary) ;
579 
580 			/* If not from our stream, continue. */
581 			if (odata->ostream.serialno != ogg_page_serialno (&page))
582 				continue ;
583 
584 			/*
585 			** The Ogg spec says that a page with a granule pos of -1 must not
586 			** contain and packets which complete, but the lack of biconditional
587 			** wording means that /technically/ a packet which does not complete
588 			** any packets can have a granule pos other than -1. To make matters
589 			** worse, older versions of libogg did just that.
590 			*/
591 			has_packets = ogg_page_packets (&page) > 0 ;
592 			gp = has_packets ? ogg_page_granulepos (&page) : -1 ;
593 			if (gp == (uint64_t) -1)
594 			{	if (buffering == SF_TRUE)
595 				{	if (!has_packets)
596 						ogg_stream_pagein (&odata->ostream, &page) ;
597 					else
598 					{	/*
599 						** If packets did end on this page, but we still didn't
600 						** have a valid granule position (in violation of the
601 						** spec!), stop buffering continued packet data.
602 						** Otherwise we might continue past the packet we
603 						** actually wanted.
604 						*/
605 						ogg_stream_reset (&odata->ostream) ;
606 						buffering = SF_FALSE ;
607 						}
608 					}
609 				continue ;
610 				}
611 
612 			if (gp < target_gp)
613 			{	/*
614 				** We found a page that ends before our target. Advance to
615 				** the raw offset of the next page.
616 				*/
617 				begin = seek_pos ;
618 				if (pcm_start > gp || pcm_end < gp)
619 					break ;
620 				/* Save the byte offset of after this page. */
621 				best = best_start = begin ;
622 				if (buffering)
623 					ogg_stream_reset (&odata->ostream) ;
624 				/* Check to see if the last packet continues. */
625 				if (ogg_page_continues (&page))
626 				{	ogg_page_search_continued_data (odata, &page) ;
627 					/*
628 					** If we have a continued packet, remember the offset of
629 					** this page's start, so that if we do wind up having to
630 					** seek back here later, we can prime the stream with the
631 					** continued packet data. With no continued packet, we
632 					** remember the end of the page.
633 					*/
634 					best_start = page_offset ;
635 					/*
636 					** Then force buffering on, so that if a packet starts (but
637 					** does not end) on the next page, we still avoid the extra
638 					** seek back.
639 					*/
640 					buffering = SF_TRUE ;
641 				} ;
642 				*best_gp = pcm_start = gp ;
643 				if (target_gp - gp > gp_rate)
644 				{	/* Out by over a second. Try another bisection. */
645 					break ;
646 					}
647 				/* Otherwise, keep scanning forward (do NOT use begin+1). */
648 				bisect = begin ;
649 				}
650 			else
651 			{	/*
652 				** Found a page that ends after our target. If we had just
653 				** scanned the whole interval before we found it, we're good.
654 				*/
655 				if (bisect <= begin + 1)
656 					end = begin ;
657 				else
658 				{	end = bisect ;
659 					/*
660 					** In later iterations, don't read past the first page we
661 					** found.
662 					*/
663 					boundary = next_boundary ;
664 					/*
665 					** If we're not making much progress shrinking the interval
666 					** size, start forcing straight bisection to limit the
667 					** worst case.
668 					*/
669 					force_bisect = end - begin > d0 * 2 ? SF_TRUE : SF_FALSE ;
670 					/*
671 					** Don't let pcm_end get out of range! That could happen
672 					** with an invalid timestamp.
673 					*/
674 					if (pcm_end > gp && pcm_start <= gp)
675 						pcm_end = gp ;
676 					}
677 				break ;
678 				}
679 			}
680 		}
681 
682 	/*
683 	** If we are buffering, the page we want is currently buffered in the
684 	** Ogg stream structure, or in the Ogg page which has not been submitted.
685 	** If not, we need to seek back and load it again.
686 	*/
687 	if (buffering == SF_FALSE)
688 	{	if (best_start != page_offset)
689 		{	page_offset = -1 ;
690 			seek_pos = ogg_sync_fseek (psf, best_start, SEEK_SET) ;
691 			if (seek_pos < 0)
692 				return seek_pos ;
693 			}
694 		if (best_start < best)
695 		{	if (page_offset < 0)
696 			{	ret = ogg_sync_next_page (psf, &page, -1, &seek_pos) ;
697 				if (seek_pos != best_start)
698 					return -1 ;
699 				}
700 			ogg_page_search_continued_data (odata, &page) ;
701 			page_offset = -1 ;
702 			}
703 		} ;
704 
705 	if (page_offset >= 0)
706 		ogg_stream_pagein (&odata->ostream, &page) ;
707 
708 	return 0 ;
709 } /* ogg_stream_seek_page_search */
710 
711 int
ogg_open(SF_PRIVATE * psf)712 ogg_open (SF_PRIVATE *psf)
713 {	OGG_PRIVATE* odata = calloc (1, sizeof (OGG_PRIVATE)) ;
714 	sf_count_t pos = psf_ftell (psf) ;
715 	int	error = 0 ;
716 
717 	psf->container_data = odata ;
718 	psf->container_close = ogg_close ;
719 
720 	if (psf->file.mode == SFM_RDWR)
721 		return SFE_BAD_MODE_RW ;
722 
723 	if (psf->file.mode == SFM_READ)
724 		if ((error = ogg_stream_classify (psf, odata)) != 0)
725 			return error ;
726 
727 	if (SF_ENDIAN (psf->sf.format) != 0)
728 		return SFE_BAD_ENDIAN ;
729 
730 	switch (psf->sf.format)
731 	{	case SF_FORMAT_OGG | SF_FORMAT_VORBIS :
732 			return ogg_vorbis_open (psf) ;
733 
734 		case SF_FORMAT_OGGFLAC :
735 			/* Reset everything to an initial state. */
736 			ogg_sync_clear (&odata->osync) ;
737 			ogg_stream_clear (&odata->ostream) ;
738 			psf_fseek (psf, pos, SEEK_SET) ;
739 			free (psf->container_data) ;
740 			psf->container_data = NULL ;
741 			psf->container_close = NULL ;
742 			return flac_open (psf) ;
743 
744 		case SF_FORMAT_OGG | SF_FORMAT_OPUS :
745 			return ogg_opus_open (psf) ;
746 
747 #if ENABLE_EXPERIMENTAL_CODE
748 		case SF_FORMAT_OGG | SF_FORMAT_SPEEX :
749 			return ogg_speex_open (psf) ;
750 
751 		case SF_FORMAT_OGG | SF_FORMAT_PCM_16 :
752 		case SF_FORMAT_OGG | SF_FORMAT_PCM_24 :
753 			return ogg_pcm_open (psf) ;
754 #endif
755 
756 		default :
757 			break ;
758 		} ;
759 
760 	psf_log_printf (psf, "%s : bad psf->sf.format 0x%x.\n", __func__, psf->sf.format) ;
761 	return SFE_INTERNAL ;
762 } /* ogg_open */
763 
764 /*==============================================================================
765 ** Private functions.
766 */
767 
768 static int
ogg_close(SF_PRIVATE * psf)769 ogg_close (SF_PRIVATE *psf)
770 {	OGG_PRIVATE* odata = psf->container_data ;
771 
772 	ogg_sync_clear (&odata->osync) ;
773 	ogg_stream_clear (&odata->ostream) ;
774 
775 	return 0 ;
776 } /* ogg_close */
777 
778 static int
ogg_stream_classify(SF_PRIVATE * psf,OGG_PRIVATE * odata)779 ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE* odata)
780 {	int error ;
781 
782 	/* Call this here so it only gets called once, so no memory is leaked. */
783 	ogg_sync_init (&odata->osync) ;
784 	ogg_stream_init (&odata->ostream, 0) ;
785 
786 	/* Load the first page in the physical bitstream. */
787 	if ((error = ogg_read_first_page (psf, odata)) != 0)
788 		return error ;
789 
790 	odata->codec = ogg_page_classify (psf, &odata->opage) ;
791 
792 	switch (odata->codec)
793 	{	case OGG_VORBIS :
794 			psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ;
795 			return 0 ;
796 
797 		case OGG_FLAC :
798 		case OGG_FLAC0 :
799 			psf->sf.format = SF_FORMAT_OGGFLAC ;
800 			return 0 ;
801 
802 		case OGG_SPEEX :
803 			psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ;
804 			return 0 ;
805 
806 		case OGG_OPUS :
807 			psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ;
808 			return 0 ;
809 
810 		case OGG_PCM :
811 			psf_log_printf (psf, "Detected Ogg/PCM data. This is not supported yet.\n") ;
812 			return SFE_UNIMPLEMENTED ;
813 
814 		default :
815 			break ;
816 		} ;
817 
818 	psf_log_printf (psf, "This Ogg bitstream contains some uknown data type.\n") ;
819 	return SFE_UNIMPLEMENTED ;
820 } /* ogg_stream_classify */
821 
822 /*==============================================================================
823 */
824 
825 static struct
826 {	const char *str, *name ;
827 	int len, codec ;
828 } codec_lookup [] =
829 {	{	"Annodex",		"Annodex",	8, OGG_ANNODEX },
830 	{	"AnxData",		"AnxData",	7, OGG_ANXDATA },
831 	{	"\177FLAC",		"Flac1",	5, OGG_FLAC },
832 	{	"fLaC",			"Flac0",	4, OGG_FLAC0 },
833 	{	"PCM     ",		"PCM",		8, OGG_PCM },
834 	{	"Speex",		"Speex",	5, OGG_SPEEX },
835 	{	"\001vorbis",	"Vorbis",	7, OGG_VORBIS },
836 	{	"OpusHead",		"Opus",		8, OGG_OPUS },
837 } ;
838 
839 static int
ogg_page_classify(SF_PRIVATE * psf,const ogg_page * og)840 ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og)
841 {	int k, len ;
842 
843 	for (k = 0 ; k < ARRAY_LEN (codec_lookup) ; k++)
844 	{	if (codec_lookup [k].len > og->body_len)
845 			continue ;
846 
847 		if (memcmp (og->body, codec_lookup [k].str, codec_lookup [k].len) == 0)
848 		{	psf_log_printf (psf, "Ogg stream data : %s\n", codec_lookup [k].name) ;
849 			psf_log_printf (psf, "Stream serialno : %u\n", (uint32_t) ogg_page_serialno (og)) ;
850 			return codec_lookup [k].codec ;
851 			} ;
852 		} ;
853 
854 	len = og->body_len < 8 ? og->body_len : 8 ;
855 
856 	psf_log_printf (psf, "Ogg_stream data : '") ;
857 	for (k = 0 ; k < len ; k++)
858 		psf_log_printf (psf, "%c", isprint (og->body [k]) ? og->body [k] : '.') ;
859 	psf_log_printf (psf, "'     ") ;
860 	for (k = 0 ; k < len ; k++)
861 		psf_log_printf (psf, " %02x", og->body [k] & 0xff) ;
862 	psf_log_printf (psf, "\n") ;
863 
864 	return 0 ;
865 } /* ogg_page_classify */
866 
867 /*
868 ** Scale x from the range [0, from] to the range [0, to]
869 */
870 static uint64_t
ogg_page_search_do_rescale(uint64_t x,uint64_t from,uint64_t to)871 ogg_page_search_do_rescale (uint64_t x, uint64_t from, uint64_t to)
872 {	uint64_t frac ;
873 	uint64_t ret ;
874 	int i ;
875 
876 	/* I should have paid more attention in CSc 349A: Numerical Analysis */
877 	if (x >= from)
878 		return to ;
879 	if (x == 0)
880 		return 0 ;
881 	frac = 0 ;
882 	for (i = 0 ; i < 63 ; i++)
883 	{	frac <<= 1 ;
884 		if (x >= from >> 1)
885 		{	x -= from - x ;
886 			frac |= 1 ;
887 			}
888 		else
889 			x <<= 1 ;
890 		}
891 	ret = 0 ;
892 	for (i = 0 ; i < 63 ; i++)
893 	{	if (frac & 1)
894 			ret = (ret & to & 1) + (ret >> 1) + (to >> 1) ;
895 		else
896 			ret >>= 1 ;
897 		frac >>= 1 ;
898 		}
899 	return ret ;
900 } /* ogg_page_search_do_rescale */
901 
902 static void
ogg_page_search_continued_data(OGG_PRIVATE * odata,ogg_page * page)903 ogg_page_search_continued_data (OGG_PRIVATE *odata, ogg_page *page)
904 {	ogg_stream_pagein (&odata->ostream, page) ;
905 	while (ogg_stream_packetout (&odata->ostream, &odata->opacket)) ;
906 } /* ogg_page_search_continued_data */
907 
908 #else /* HAVE_EXTERNAL_XIPH_LIBS */
909 
910 int
ogg_open(SF_PRIVATE * psf)911 ogg_open	(SF_PRIVATE *psf)
912 {
913 	psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ;
914 	return SFE_UNIMPLEMENTED ;
915 } /* ogg_open */
916 
917 #endif
918