1c74663799493f2b1e6123c18def94295d0afab7Kenny Root/* libFLAC - Free Lossless Audio Codec
2c74663799493f2b1e6123c18def94295d0afab7Kenny Root * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
3c74663799493f2b1e6123c18def94295d0afab7Kenny Root *
4c74663799493f2b1e6123c18def94295d0afab7Kenny Root * Redistribution and use in source and binary forms, with or without
5c74663799493f2b1e6123c18def94295d0afab7Kenny Root * modification, are permitted provided that the following conditions
6c74663799493f2b1e6123c18def94295d0afab7Kenny Root * are met:
7c74663799493f2b1e6123c18def94295d0afab7Kenny Root *
8c74663799493f2b1e6123c18def94295d0afab7Kenny Root * - Redistributions of source code must retain the above copyright
9c74663799493f2b1e6123c18def94295d0afab7Kenny Root * notice, this list of conditions and the following disclaimer.
10c74663799493f2b1e6123c18def94295d0afab7Kenny Root *
11c74663799493f2b1e6123c18def94295d0afab7Kenny Root * - Redistributions in binary form must reproduce the above copyright
12c74663799493f2b1e6123c18def94295d0afab7Kenny Root * notice, this list of conditions and the following disclaimer in the
13c74663799493f2b1e6123c18def94295d0afab7Kenny Root * documentation and/or other materials provided with the distribution.
14c74663799493f2b1e6123c18def94295d0afab7Kenny Root *
15c74663799493f2b1e6123c18def94295d0afab7Kenny Root * - Neither the name of the Xiph.org Foundation nor the names of its
16c74663799493f2b1e6123c18def94295d0afab7Kenny Root * contributors may be used to endorse or promote products derived from
17c74663799493f2b1e6123c18def94295d0afab7Kenny Root * this software without specific prior written permission.
18c74663799493f2b1e6123c18def94295d0afab7Kenny Root *
19c74663799493f2b1e6123c18def94295d0afab7Kenny Root * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20c74663799493f2b1e6123c18def94295d0afab7Kenny Root * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21c74663799493f2b1e6123c18def94295d0afab7Kenny Root * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22c74663799493f2b1e6123c18def94295d0afab7Kenny Root * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23c74663799493f2b1e6123c18def94295d0afab7Kenny Root * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24c74663799493f2b1e6123c18def94295d0afab7Kenny Root * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25c74663799493f2b1e6123c18def94295d0afab7Kenny Root * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26c74663799493f2b1e6123c18def94295d0afab7Kenny Root * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27c74663799493f2b1e6123c18def94295d0afab7Kenny Root * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28c74663799493f2b1e6123c18def94295d0afab7Kenny Root * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29c74663799493f2b1e6123c18def94295d0afab7Kenny Root * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30c74663799493f2b1e6123c18def94295d0afab7Kenny Root */
31c74663799493f2b1e6123c18def94295d0afab7Kenny Root
32c74663799493f2b1e6123c18def94295d0afab7Kenny Root#if HAVE_CONFIG_H
33c74663799493f2b1e6123c18def94295d0afab7Kenny Root#  include <config.h>
34c74663799493f2b1e6123c18def94295d0afab7Kenny Root#endif
35c74663799493f2b1e6123c18def94295d0afab7Kenny Root
36c74663799493f2b1e6123c18def94295d0afab7Kenny Root#include <string.h> /* for memcpy() */
37c74663799493f2b1e6123c18def94295d0afab7Kenny Root#include "FLAC/assert.h"
38c74663799493f2b1e6123c18def94295d0afab7Kenny Root#include "private/ogg_decoder_aspect.h"
39c74663799493f2b1e6123c18def94295d0afab7Kenny Root#include "private/ogg_mapping.h"
40c74663799493f2b1e6123c18def94295d0afab7Kenny Root
41c74663799493f2b1e6123c18def94295d0afab7Kenny Root#ifdef max
42c74663799493f2b1e6123c18def94295d0afab7Kenny Root#undef max
43c74663799493f2b1e6123c18def94295d0afab7Kenny Root#endif
44c74663799493f2b1e6123c18def94295d0afab7Kenny Root#define max(x,y) ((x)>(y)?(x):(y))
45c74663799493f2b1e6123c18def94295d0afab7Kenny Root
46c74663799493f2b1e6123c18def94295d0afab7Kenny Root/***********************************************************************
47c74663799493f2b1e6123c18def94295d0afab7Kenny Root *
48c74663799493f2b1e6123c18def94295d0afab7Kenny Root * Public class methods
49c74663799493f2b1e6123c18def94295d0afab7Kenny Root *
50c74663799493f2b1e6123c18def94295d0afab7Kenny Root ***********************************************************************/
51c74663799493f2b1e6123c18def94295d0afab7Kenny Root
52c74663799493f2b1e6123c18def94295d0afab7Kenny RootFLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect)
53c74663799493f2b1e6123c18def94295d0afab7Kenny Root{
54c74663799493f2b1e6123c18def94295d0afab7Kenny Root	/* we will determine the serial number later if necessary */
55c74663799493f2b1e6123c18def94295d0afab7Kenny Root	if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
56c74663799493f2b1e6123c18def94295d0afab7Kenny Root		return false;
57c74663799493f2b1e6123c18def94295d0afab7Kenny Root
58c74663799493f2b1e6123c18def94295d0afab7Kenny Root	if(ogg_sync_init(&aspect->sync_state) != 0)
59c74663799493f2b1e6123c18def94295d0afab7Kenny Root		return false;
60c74663799493f2b1e6123c18def94295d0afab7Kenny Root
61c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->version_major = ~(0u);
62c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->version_minor = ~(0u);
63c74663799493f2b1e6123c18def94295d0afab7Kenny Root
64c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->need_serial_number = aspect->use_first_serial_number;
65c74663799493f2b1e6123c18def94295d0afab7Kenny Root
66c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->end_of_stream = false;
67c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->have_working_page = false;
68c74663799493f2b1e6123c18def94295d0afab7Kenny Root
69c74663799493f2b1e6123c18def94295d0afab7Kenny Root	return true;
70c74663799493f2b1e6123c18def94295d0afab7Kenny Root}
71c74663799493f2b1e6123c18def94295d0afab7Kenny Root
72c74663799493f2b1e6123c18def94295d0afab7Kenny Rootvoid FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect)
73c74663799493f2b1e6123c18def94295d0afab7Kenny Root{
74c74663799493f2b1e6123c18def94295d0afab7Kenny Root	(void)ogg_sync_clear(&aspect->sync_state);
75c74663799493f2b1e6123c18def94295d0afab7Kenny Root	(void)ogg_stream_clear(&aspect->stream_state);
76c74663799493f2b1e6123c18def94295d0afab7Kenny Root}
77c74663799493f2b1e6123c18def94295d0afab7Kenny Root
78c74663799493f2b1e6123c18def94295d0afab7Kenny Rootvoid FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value)
79c74663799493f2b1e6123c18def94295d0afab7Kenny Root{
80c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->use_first_serial_number = false;
81c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->serial_number = value;
82c74663799493f2b1e6123c18def94295d0afab7Kenny Root}
83c74663799493f2b1e6123c18def94295d0afab7Kenny Root
84c74663799493f2b1e6123c18def94295d0afab7Kenny Rootvoid FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect)
85c74663799493f2b1e6123c18def94295d0afab7Kenny Root{
86c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->use_first_serial_number = true;
87c74663799493f2b1e6123c18def94295d0afab7Kenny Root}
88c74663799493f2b1e6123c18def94295d0afab7Kenny Root
89c74663799493f2b1e6123c18def94295d0afab7Kenny Rootvoid FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect)
90c74663799493f2b1e6123c18def94295d0afab7Kenny Root{
91c74663799493f2b1e6123c18def94295d0afab7Kenny Root	(void)ogg_stream_reset(&aspect->stream_state);
92c74663799493f2b1e6123c18def94295d0afab7Kenny Root	(void)ogg_sync_reset(&aspect->sync_state);
93c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->end_of_stream = false;
94c74663799493f2b1e6123c18def94295d0afab7Kenny Root	aspect->have_working_page = false;
95c74663799493f2b1e6123c18def94295d0afab7Kenny Root}
96c74663799493f2b1e6123c18def94295d0afab7Kenny Root
97c74663799493f2b1e6123c18def94295d0afab7Kenny Rootvoid FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect)
98c74663799493f2b1e6123c18def94295d0afab7Kenny Root{
99c74663799493f2b1e6123c18def94295d0afab7Kenny Root	FLAC__ogg_decoder_aspect_flush(aspect);
100c74663799493f2b1e6123c18def94295d0afab7Kenny Root
101c74663799493f2b1e6123c18def94295d0afab7Kenny Root	if(aspect->use_first_serial_number)
102c74663799493f2b1e6123c18def94295d0afab7Kenny Root		aspect->need_serial_number = true;
103c74663799493f2b1e6123c18def94295d0afab7Kenny Root}
104c74663799493f2b1e6123c18def94295d0afab7Kenny Root
105c74663799493f2b1e6123c18def94295d0afab7Kenny RootFLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data)
106c74663799493f2b1e6123c18def94295d0afab7Kenny Root{
107c74663799493f2b1e6123c18def94295d0afab7Kenny Root	static const size_t OGG_BYTES_CHUNK = 8192;
108c74663799493f2b1e6123c18def94295d0afab7Kenny Root	const size_t bytes_requested = *bytes;
109c74663799493f2b1e6123c18def94295d0afab7Kenny Root
110c74663799493f2b1e6123c18def94295d0afab7Kenny Root	/*
111c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * The FLAC decoding API uses pull-based reads, whereas Ogg decoding
112c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * is push-based.  In libFLAC, when you ask to decode a frame, the
113c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * decoder will eventually call the read callback to supply some data,
114c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * but how much it asks for depends on how much free space it has in
115c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * its internal buffer.  It does not try to grow its internal buffer
116c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * to accomodate a whole frame because then the internal buffer size
117c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * could not be limited, which is necessary in embedded applications.
118c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 *
119c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * Ogg however grows its internal buffer until a whole page is present;
120c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * only then can you get decoded data out.  So we can't just ask for
121c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * the same number of bytes from Ogg, then pass what's decoded down to
122c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * libFLAC.  If what libFLAC is asking for will not contain a whole
123c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * page, then we will get no data from ogg_sync_pageout(), and at the
124c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * same time cannot just read more data from the client for the purpose
125c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * of getting a whole decoded page because the decoded size might be
126c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * larger than libFLAC's internal buffer.
127c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 *
128c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * Instead, whenever this read callback wrapper is called, we will
129c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * continually request data from the client until we have at least one
130c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * page, and manage pages internally so that we can send pieces of
131c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * pages down to libFLAC in such a way that we obey its size
132c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * requirement.  To limit the amount of callbacks, we will always try
133c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * to read in enough pages to return the full number of bytes
134c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 * requested.
135c74663799493f2b1e6123c18def94295d0afab7Kenny Root	 */
136c74663799493f2b1e6123c18def94295d0afab7Kenny Root	*bytes = 0;
137c74663799493f2b1e6123c18def94295d0afab7Kenny Root	while (*bytes < bytes_requested && !aspect->end_of_stream) {
138c74663799493f2b1e6123c18def94295d0afab7Kenny Root		if (aspect->have_working_page) {
139c74663799493f2b1e6123c18def94295d0afab7Kenny Root			if (aspect->have_working_packet) {
140c74663799493f2b1e6123c18def94295d0afab7Kenny Root				size_t n = bytes_requested - *bytes;
141c74663799493f2b1e6123c18def94295d0afab7Kenny Root				if ((size_t)aspect->working_packet.bytes <= n) {
142c74663799493f2b1e6123c18def94295d0afab7Kenny Root					/* the rest of the packet will fit in the buffer */
143c74663799493f2b1e6123c18def94295d0afab7Kenny Root					n = aspect->working_packet.bytes;
144c74663799493f2b1e6123c18def94295d0afab7Kenny Root					memcpy(buffer, aspect->working_packet.packet, n);
145c74663799493f2b1e6123c18def94295d0afab7Kenny Root					*bytes += n;
146c74663799493f2b1e6123c18def94295d0afab7Kenny Root					buffer += n;
147c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->have_working_packet = false;
148c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
149c74663799493f2b1e6123c18def94295d0afab7Kenny Root				else {
150c74663799493f2b1e6123c18def94295d0afab7Kenny Root					/* only n bytes of the packet will fit in the buffer */
151c74663799493f2b1e6123c18def94295d0afab7Kenny Root					memcpy(buffer, aspect->working_packet.packet, n);
152c74663799493f2b1e6123c18def94295d0afab7Kenny Root					*bytes += n;
153c74663799493f2b1e6123c18def94295d0afab7Kenny Root					buffer += n;
154c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->working_packet.packet += n;
155c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->working_packet.bytes -= n;
156c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
157c74663799493f2b1e6123c18def94295d0afab7Kenny Root			}
158c74663799493f2b1e6123c18def94295d0afab7Kenny Root			else {
159c74663799493f2b1e6123c18def94295d0afab7Kenny Root				/* try and get another packet */
160c74663799493f2b1e6123c18def94295d0afab7Kenny Root				const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
161c74663799493f2b1e6123c18def94295d0afab7Kenny Root				if (ret > 0) {
162c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->have_working_packet = true;
163c74663799493f2b1e6123c18def94295d0afab7Kenny Root					/* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */
164c74663799493f2b1e6123c18def94295d0afab7Kenny Root					if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) {
165c74663799493f2b1e6123c18def94295d0afab7Kenny Root						const FLAC__byte *b = aspect->working_packet.packet;
166c74663799493f2b1e6123c18def94295d0afab7Kenny Root						const unsigned header_length =
167c74663799493f2b1e6123c18def94295d0afab7Kenny Root							FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
168c74663799493f2b1e6123c18def94295d0afab7Kenny Root							FLAC__OGG_MAPPING_MAGIC_LENGTH +
169c74663799493f2b1e6123c18def94295d0afab7Kenny Root							FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
170c74663799493f2b1e6123c18def94295d0afab7Kenny Root							FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
171c74663799493f2b1e6123c18def94295d0afab7Kenny Root							FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH;
172c74663799493f2b1e6123c18def94295d0afab7Kenny Root						if (aspect->working_packet.bytes < (long)header_length)
173c74663799493f2b1e6123c18def94295d0afab7Kenny Root							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
174c74663799493f2b1e6123c18def94295d0afab7Kenny Root						b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
175c74663799493f2b1e6123c18def94295d0afab7Kenny Root						if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH))
176c74663799493f2b1e6123c18def94295d0afab7Kenny Root							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
177c74663799493f2b1e6123c18def94295d0afab7Kenny Root						b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
178c74663799493f2b1e6123c18def94295d0afab7Kenny Root						aspect->version_major = (unsigned)(*b);
179c74663799493f2b1e6123c18def94295d0afab7Kenny Root						b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
180c74663799493f2b1e6123c18def94295d0afab7Kenny Root						aspect->version_minor = (unsigned)(*b);
181c74663799493f2b1e6123c18def94295d0afab7Kenny Root						if (aspect->version_major != 1)
182c74663799493f2b1e6123c18def94295d0afab7Kenny Root							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
183c74663799493f2b1e6123c18def94295d0afab7Kenny Root						aspect->working_packet.packet += header_length;
184c74663799493f2b1e6123c18def94295d0afab7Kenny Root						aspect->working_packet.bytes -= header_length;
185c74663799493f2b1e6123c18def94295d0afab7Kenny Root					}
186c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
187c74663799493f2b1e6123c18def94295d0afab7Kenny Root				else if (ret == 0) {
188c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->have_working_page = false;
189c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
190c74663799493f2b1e6123c18def94295d0afab7Kenny Root				else { /* ret < 0 */
191c74663799493f2b1e6123c18def94295d0afab7Kenny Root					/* lost sync, we'll leave the working page for the next call */
192c74663799493f2b1e6123c18def94295d0afab7Kenny Root					return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
193c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
194c74663799493f2b1e6123c18def94295d0afab7Kenny Root			}
195c74663799493f2b1e6123c18def94295d0afab7Kenny Root		}
196c74663799493f2b1e6123c18def94295d0afab7Kenny Root		else {
197c74663799493f2b1e6123c18def94295d0afab7Kenny Root			/* try and get another page */
198c74663799493f2b1e6123c18def94295d0afab7Kenny Root			const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
199c74663799493f2b1e6123c18def94295d0afab7Kenny Root			if (ret > 0) {
200c74663799493f2b1e6123c18def94295d0afab7Kenny Root				/* got a page, grab the serial number if necessary */
201c74663799493f2b1e6123c18def94295d0afab7Kenny Root				if(aspect->need_serial_number) {
202c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page);
203c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->need_serial_number = false;
204c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
205c74663799493f2b1e6123c18def94295d0afab7Kenny Root				if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
206c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->have_working_page = true;
207c74663799493f2b1e6123c18def94295d0afab7Kenny Root					aspect->have_working_packet = false;
208c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
209c74663799493f2b1e6123c18def94295d0afab7Kenny Root				/* else do nothing, could be a page from another stream */
210c74663799493f2b1e6123c18def94295d0afab7Kenny Root			}
211c74663799493f2b1e6123c18def94295d0afab7Kenny Root			else if (ret == 0) {
212c74663799493f2b1e6123c18def94295d0afab7Kenny Root				/* need more data */
213c74663799493f2b1e6123c18def94295d0afab7Kenny Root				const size_t ogg_bytes_to_read = max(bytes_requested - *bytes, OGG_BYTES_CHUNK);
214c74663799493f2b1e6123c18def94295d0afab7Kenny Root				char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);
215c74663799493f2b1e6123c18def94295d0afab7Kenny Root
216c74663799493f2b1e6123c18def94295d0afab7Kenny Root				if(0 == oggbuf) {
217c74663799493f2b1e6123c18def94295d0afab7Kenny Root					return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
218c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
219c74663799493f2b1e6123c18def94295d0afab7Kenny Root				else {
220c74663799493f2b1e6123c18def94295d0afab7Kenny Root					size_t ogg_bytes_read = ogg_bytes_to_read;
221c74663799493f2b1e6123c18def94295d0afab7Kenny Root
222c74663799493f2b1e6123c18def94295d0afab7Kenny Root					switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
223c74663799493f2b1e6123c18def94295d0afab7Kenny Root						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
224c74663799493f2b1e6123c18def94295d0afab7Kenny Root							break;
225c74663799493f2b1e6123c18def94295d0afab7Kenny Root						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
226c74663799493f2b1e6123c18def94295d0afab7Kenny Root							aspect->end_of_stream = true;
227c74663799493f2b1e6123c18def94295d0afab7Kenny Root							break;
228c74663799493f2b1e6123c18def94295d0afab7Kenny Root						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
229c74663799493f2b1e6123c18def94295d0afab7Kenny Root							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
230c74663799493f2b1e6123c18def94295d0afab7Kenny Root						default:
231c74663799493f2b1e6123c18def94295d0afab7Kenny Root							FLAC__ASSERT(0);
232c74663799493f2b1e6123c18def94295d0afab7Kenny Root					}
233c74663799493f2b1e6123c18def94295d0afab7Kenny Root
234c74663799493f2b1e6123c18def94295d0afab7Kenny Root					if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) {
235c74663799493f2b1e6123c18def94295d0afab7Kenny Root						/* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */
236c74663799493f2b1e6123c18def94295d0afab7Kenny Root						FLAC__ASSERT(0);
237c74663799493f2b1e6123c18def94295d0afab7Kenny Root						return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
238c74663799493f2b1e6123c18def94295d0afab7Kenny Root					}
239c74663799493f2b1e6123c18def94295d0afab7Kenny Root				}
240c74663799493f2b1e6123c18def94295d0afab7Kenny Root			}
241c74663799493f2b1e6123c18def94295d0afab7Kenny Root			else { /* ret < 0 */
242c74663799493f2b1e6123c18def94295d0afab7Kenny Root				/* lost sync, bail out */
243c74663799493f2b1e6123c18def94295d0afab7Kenny Root				return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
244c74663799493f2b1e6123c18def94295d0afab7Kenny Root			}
245c74663799493f2b1e6123c18def94295d0afab7Kenny Root		}
246c74663799493f2b1e6123c18def94295d0afab7Kenny Root	}
247c74663799493f2b1e6123c18def94295d0afab7Kenny Root
248c74663799493f2b1e6123c18def94295d0afab7Kenny Root	if (aspect->end_of_stream && *bytes == 0) {
249c74663799493f2b1e6123c18def94295d0afab7Kenny Root		return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
250c74663799493f2b1e6123c18def94295d0afab7Kenny Root	}
251c74663799493f2b1e6123c18def94295d0afab7Kenny Root
252c74663799493f2b1e6123c18def94295d0afab7Kenny Root	return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
253c74663799493f2b1e6123c18def94295d0afab7Kenny Root}
254