tweaks to the MD5 routines; they need to be exported when building a windows DLL...
[platform/upstream/flac.git] / src / libOggFLAC / seekable_stream_decoder.c
1 /* libOggFLAC - Free Lossless Audio Codec + Ogg library
2  * Copyright (C) 2002,2003,2004  Josh Coalson
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * - Neither the name of the Xiph.org Foundation nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h> /* for calloc() */
34 #include <string.h> /* for memcpy()/memcmp() */
35 #include "FLAC/assert.h"
36 #include "protected/seekable_stream_decoder.h"
37 #include "protected/stream_decoder.h"
38 #include "../libFLAC/include/private/md5.h" /* @@@@@@ ugly hack, but how else to do?  we need to reuse the md5 code but don't want to expose it */
39
40 /***********************************************************************
41  *
42  * Private class method prototypes
43  *
44  ***********************************************************************/
45
46 static void set_defaults_(OggFLAC__SeekableStreamDecoder *decoder);
47 static FLAC__StreamDecoderReadStatus read_callback_(const OggFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
48 static FLAC__StreamDecoderWriteStatus write_callback_(const OggFLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
49 static void metadata_callback_(const OggFLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
50 static void error_callback_(const OggFLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
51 static FLAC__bool seek_to_absolute_sample_(OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
52
53 /***********************************************************************
54  *
55  * Private class data
56  *
57  ***********************************************************************/
58
59 typedef struct OggFLAC__SeekableStreamDecoderPrivate {
60         OggFLAC__SeekableStreamDecoderReadCallback read_callback;
61         OggFLAC__SeekableStreamDecoderSeekCallback seek_callback;
62         OggFLAC__SeekableStreamDecoderTellCallback tell_callback;
63         OggFLAC__SeekableStreamDecoderLengthCallback length_callback;
64         OggFLAC__SeekableStreamDecoderEofCallback eof_callback;
65         OggFLAC__SeekableStreamDecoderWriteCallback write_callback;
66         OggFLAC__SeekableStreamDecoderMetadataCallback metadata_callback;
67         OggFLAC__SeekableStreamDecoderErrorCallback error_callback;
68         void *client_data;
69         OggFLAC__StreamDecoder *stream_decoder;
70         FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek */
71         struct FLAC__MD5Context md5context;
72         FLAC__byte stored_md5sum[16]; /* this is what is stored in the metadata */
73         FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */
74         /* the rest of these are only used for seeking: */
75         FLAC__StreamMetadata_StreamInfo stream_info; /* we keep this around so we can figure out how to seek quickly */
76         const FLAC__StreamMetadata_SeekTable *seek_table; /* we hold a pointer to the stream decoder's seek table for the same reason */
77         /* Since we always want to see the STREAMINFO and SEEK_TABLE blocks at this level, we need some extra flags to keep track of whether they should be passed on up through the metadata_callback */
78         FLAC__bool ignore_stream_info_block;
79         FLAC__bool ignore_seek_table_block;
80         FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */
81         FLAC__uint64 target_sample;
82 } OggFLAC__SeekableStreamDecoderPrivate;
83
84 /***********************************************************************
85  *
86  * Public static class data
87  *
88  ***********************************************************************/
89
90 OggFLAC_API const char * const OggFLAC__SeekableStreamDecoderStateString[] = {
91         "OggFLAC__SEEKABLE_STREAM_DECODER_OK",
92         "OggFLAC__SEEKABLE_STREAM_DECODER_SEEKING",
93         "OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM",
94         "OggFLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
95         "OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR",
96         "OggFLAC__SEEKABLE_STREAM_DECODER_READ_ERROR",
97         "OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR",
98         "OggFLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED",
99         "OggFLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK",
100         "OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED"
101 };
102
103 OggFLAC_API const char * const OggFLAC__SeekableStreamDecoderReadStatusString[] = {
104         "OggFLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK",
105         "OggFLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR"
106 };
107
108 OggFLAC_API const char * const OggFLAC__SeekableStreamDecoderSeekStatusString[] = {
109         "OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK",
110         "OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR"
111 };
112
113 OggFLAC_API const char * const OggFLAC__SeekableStreamDecoderTellStatusString[] = {
114         "OggFLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK",
115         "OggFLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR"
116 };
117
118 OggFLAC_API const char * const OggFLAC__SeekableStreamDecoderLengthStatusString[] = {
119         "OggFLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK",
120         "OggFLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR"
121 };
122
123
124 /***********************************************************************
125  *
126  * Class constructor/destructor
127  *
128  ***********************************************************************/
129
130 OggFLAC_API OggFLAC__SeekableStreamDecoder *OggFLAC__seekable_stream_decoder_new()
131 {
132         OggFLAC__SeekableStreamDecoder *decoder;
133
134         FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
135
136         decoder = (OggFLAC__SeekableStreamDecoder*)calloc(1, sizeof(OggFLAC__SeekableStreamDecoder));
137         if(decoder == 0) {
138                 return 0;
139         }
140
141         decoder->protected_ = (OggFLAC__SeekableStreamDecoderProtected*)calloc(1, sizeof(OggFLAC__SeekableStreamDecoderProtected));
142         if(decoder->protected_ == 0) {
143                 free(decoder);
144                 return 0;
145         }
146
147         decoder->private_ = (OggFLAC__SeekableStreamDecoderPrivate*)calloc(1, sizeof(OggFLAC__SeekableStreamDecoderPrivate));
148         if(decoder->private_ == 0) {
149                 free(decoder->protected_);
150                 free(decoder);
151                 return 0;
152         }
153
154         decoder->private_->stream_decoder = OggFLAC__stream_decoder_new();
155         if(0 == decoder->private_->stream_decoder) {
156                 free(decoder->private_);
157                 free(decoder->protected_);
158                 free(decoder);
159                 return 0;
160         }
161
162         set_defaults_(decoder);
163
164         decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED;
165
166         return decoder;
167 }
168
169 OggFLAC_API void OggFLAC__seekable_stream_decoder_delete(OggFLAC__SeekableStreamDecoder *decoder)
170 {
171         FLAC__ASSERT(0 != decoder);
172         FLAC__ASSERT(0 != decoder->protected_);
173         FLAC__ASSERT(0 != decoder->private_);
174         FLAC__ASSERT(0 != decoder->private_->stream_decoder);
175
176         (void)OggFLAC__seekable_stream_decoder_finish(decoder);
177
178         OggFLAC__stream_decoder_delete(decoder->private_->stream_decoder);
179
180         free(decoder->private_);
181         free(decoder->protected_);
182         free(decoder);
183 }
184
185 /***********************************************************************
186  *
187  * Public class methods
188  *
189  ***********************************************************************/
190
191 OggFLAC_API OggFLAC__SeekableStreamDecoderState OggFLAC__seekable_stream_decoder_init(OggFLAC__SeekableStreamDecoder *decoder)
192 {
193         FLAC__ASSERT(0 != decoder);
194
195         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
196                 return decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED;
197
198         if(0 == decoder->private_->read_callback || 0 == decoder->private_->seek_callback || 0 == decoder->private_->tell_callback || 0 == decoder->private_->length_callback || 0 == decoder->private_->eof_callback)
199                 return decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK;
200
201         if(0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback)
202                 return decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK;
203
204         decoder->private_->seek_table = 0;
205
206         decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
207
208         /* We initialize the FLAC__MD5Context even though we may never use it.  This
209          * is because md5 checking may be turned on to start and then turned off if
210          * a seek occurs.  So we always init the context here and finalize it in
211          * OggFLAC__seekable_stream_decoder_finish() to make sure things are always
212          * cleaned up properly.
213          */
214         FLAC__MD5Init(&decoder->private_->md5context);
215
216         OggFLAC__stream_decoder_set_read_callback(decoder->private_->stream_decoder, read_callback_);
217         OggFLAC__stream_decoder_set_write_callback(decoder->private_->stream_decoder, write_callback_);
218         OggFLAC__stream_decoder_set_metadata_callback(decoder->private_->stream_decoder, metadata_callback_);
219         OggFLAC__stream_decoder_set_error_callback(decoder->private_->stream_decoder, error_callback_);
220         OggFLAC__stream_decoder_set_client_data(decoder->private_->stream_decoder, decoder);
221
222         /* We always want to see these blocks.  Whether or not we pass them up
223          * through the metadata callback will be determined by flags set in our
224          * implementation of ..._set_metadata_respond/ignore...()
225          */
226         OggFLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_STREAMINFO);
227         OggFLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_SEEKTABLE);
228
229         if(OggFLAC__stream_decoder_init(decoder->private_->stream_decoder) != OggFLAC__STREAM_DECODER_OK)
230                 return decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
231
232         return decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_OK;
233 }
234
235 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_finish(OggFLAC__SeekableStreamDecoder *decoder)
236 {
237         FLAC__bool md5_failed = false;
238
239         FLAC__ASSERT(0 != decoder);
240         FLAC__ASSERT(0 != decoder->private_);
241         FLAC__ASSERT(0 != decoder->protected_);
242
243         if(decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
244                 return true;
245
246         FLAC__ASSERT(0 != decoder->private_->stream_decoder);
247
248         /* see the comment in OggFLAC__seekable_stream_decoder_init() as to why we
249          * always call FLAC__MD5Final()
250          */
251         FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
252
253         OggFLAC__stream_decoder_finish(decoder->private_->stream_decoder);
254
255         if(decoder->private_->do_md5_checking) {
256                 if(memcmp(decoder->private_->stored_md5sum, decoder->private_->computed_md5sum, 16))
257                         md5_failed = true;
258         }
259
260         set_defaults_(decoder);
261
262         decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED;
263
264         return !md5_failed;
265 }
266
267 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_md5_checking(OggFLAC__SeekableStreamDecoder *decoder, FLAC__bool value)
268 {
269         FLAC__ASSERT(0 != decoder);
270         FLAC__ASSERT(0 != decoder->protected_);
271         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
272                 return false;
273         decoder->protected_->md5_checking = value;
274         return true;
275 }
276
277 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_read_callback(OggFLAC__SeekableStreamDecoder *decoder, OggFLAC__SeekableStreamDecoderReadCallback value)
278 {
279         FLAC__ASSERT(0 != decoder);
280         FLAC__ASSERT(0 != decoder->private_);
281         FLAC__ASSERT(0 != decoder->protected_);
282         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
283                 return false;
284         decoder->private_->read_callback = value;
285         return true;
286 }
287
288 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_seek_callback(OggFLAC__SeekableStreamDecoder *decoder, OggFLAC__SeekableStreamDecoderSeekCallback value)
289 {
290         FLAC__ASSERT(0 != decoder);
291         FLAC__ASSERT(0 != decoder->private_);
292         FLAC__ASSERT(0 != decoder->protected_);
293         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
294                 return false;
295         decoder->private_->seek_callback = value;
296         return true;
297 }
298
299 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_tell_callback(OggFLAC__SeekableStreamDecoder *decoder, OggFLAC__SeekableStreamDecoderTellCallback value)
300 {
301         FLAC__ASSERT(0 != decoder);
302         FLAC__ASSERT(0 != decoder->private_);
303         FLAC__ASSERT(0 != decoder->protected_);
304         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
305                 return false;
306         decoder->private_->tell_callback = value;
307         return true;
308 }
309
310 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_length_callback(OggFLAC__SeekableStreamDecoder *decoder, OggFLAC__SeekableStreamDecoderLengthCallback value)
311 {
312         FLAC__ASSERT(0 != decoder);
313         FLAC__ASSERT(0 != decoder->private_);
314         FLAC__ASSERT(0 != decoder->protected_);
315         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
316                 return false;
317         decoder->private_->length_callback = value;
318         return true;
319 }
320
321 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_eof_callback(OggFLAC__SeekableStreamDecoder *decoder, OggFLAC__SeekableStreamDecoderEofCallback value)
322 {
323         FLAC__ASSERT(0 != decoder);
324         FLAC__ASSERT(0 != decoder->private_);
325         FLAC__ASSERT(0 != decoder->protected_);
326         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
327                 return false;
328         decoder->private_->eof_callback = value;
329         return true;
330 }
331
332 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_write_callback(OggFLAC__SeekableStreamDecoder *decoder, OggFLAC__SeekableStreamDecoderWriteCallback value)
333 {
334         FLAC__ASSERT(0 != decoder);
335         FLAC__ASSERT(0 != decoder->private_);
336         FLAC__ASSERT(0 != decoder->protected_);
337         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
338                 return false;
339         decoder->private_->write_callback = value;
340         return true;
341 }
342
343 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_metadata_callback(OggFLAC__SeekableStreamDecoder *decoder, OggFLAC__SeekableStreamDecoderMetadataCallback value)
344 {
345         FLAC__ASSERT(0 != decoder);
346         FLAC__ASSERT(0 != decoder->private_);
347         FLAC__ASSERT(0 != decoder->protected_);
348         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
349                 return false;
350         decoder->private_->metadata_callback = value;
351         return true;
352 }
353
354 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_error_callback(OggFLAC__SeekableStreamDecoder *decoder, OggFLAC__SeekableStreamDecoderErrorCallback value)
355 {
356         FLAC__ASSERT(0 != decoder);
357         FLAC__ASSERT(0 != decoder->private_);
358         FLAC__ASSERT(0 != decoder->protected_);
359         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
360                 return false;
361         decoder->private_->error_callback = value;
362         return true;
363 }
364
365 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_client_data(OggFLAC__SeekableStreamDecoder *decoder, void *value)
366 {
367         FLAC__ASSERT(0 != decoder);
368         FLAC__ASSERT(0 != decoder->private_);
369         FLAC__ASSERT(0 != decoder->protected_);
370         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
371                 return false;
372         decoder->private_->client_data = value;
373         return true;
374 }
375
376 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_serial_number(OggFLAC__SeekableStreamDecoder *decoder, long value)
377 {
378         FLAC__ASSERT(0 != decoder);
379         FLAC__ASSERT(0 != decoder->private_);
380         FLAC__ASSERT(0 != decoder->protected_);
381         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
382                 return false;
383         OggFLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value);
384         return true;
385 }
386
387 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_metadata_respond(OggFLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type)
388 {
389         FLAC__ASSERT(0 != decoder);
390         FLAC__ASSERT(0 != decoder->private_);
391         FLAC__ASSERT(0 != decoder->protected_);
392         FLAC__ASSERT(0 != decoder->private_->stream_decoder);
393         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
394                 return false;
395         if(type == FLAC__METADATA_TYPE_STREAMINFO)
396                 decoder->private_->ignore_stream_info_block = false;
397         else if(type == FLAC__METADATA_TYPE_SEEKTABLE)
398                 decoder->private_->ignore_seek_table_block = false;
399         return OggFLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, type);
400 }
401
402 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_metadata_respond_application(OggFLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4])
403 {
404         FLAC__ASSERT(0 != decoder);
405         FLAC__ASSERT(0 != decoder->private_);
406         FLAC__ASSERT(0 != decoder->protected_);
407         FLAC__ASSERT(0 != decoder->private_->stream_decoder);
408         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
409                 return false;
410         return OggFLAC__stream_decoder_set_metadata_respond_application(decoder->private_->stream_decoder, id);
411 }
412
413 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_metadata_respond_all(OggFLAC__SeekableStreamDecoder *decoder)
414 {
415         FLAC__ASSERT(0 != decoder);
416         FLAC__ASSERT(0 != decoder->private_);
417         FLAC__ASSERT(0 != decoder->protected_);
418         FLAC__ASSERT(0 != decoder->private_->stream_decoder);
419         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
420                 return false;
421         decoder->private_->ignore_stream_info_block = false;
422         decoder->private_->ignore_seek_table_block = false;
423         return OggFLAC__stream_decoder_set_metadata_respond_all(decoder->private_->stream_decoder);
424 }
425
426 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_metadata_ignore(OggFLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type)
427 {
428         FLAC__ASSERT(0 != decoder);
429         FLAC__ASSERT(0 != decoder->private_);
430         FLAC__ASSERT(0 != decoder->protected_);
431         FLAC__ASSERT(0 != decoder->private_->stream_decoder);
432         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
433                 return false;
434         if(type == FLAC__METADATA_TYPE_STREAMINFO) {
435                 decoder->private_->ignore_stream_info_block = true;
436                 return true;
437         }
438         else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
439                 decoder->private_->ignore_seek_table_block = true;
440                 return true;
441         }
442         else
443                 return OggFLAC__stream_decoder_set_metadata_ignore(decoder->private_->stream_decoder, type);
444 }
445
446 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(OggFLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4])
447 {
448         FLAC__ASSERT(0 != decoder);
449         FLAC__ASSERT(0 != decoder->private_);
450         FLAC__ASSERT(0 != decoder->protected_);
451         FLAC__ASSERT(0 != decoder->private_->stream_decoder);
452         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
453                 return false;
454         return OggFLAC__stream_decoder_set_metadata_ignore_application(decoder->private_->stream_decoder, id);
455 }
456
457 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_set_metadata_ignore_all(OggFLAC__SeekableStreamDecoder *decoder)
458 {
459         FLAC__ASSERT(0 != decoder);
460         FLAC__ASSERT(0 != decoder->private_);
461         FLAC__ASSERT(0 != decoder->protected_);
462         FLAC__ASSERT(0 != decoder->private_->stream_decoder);
463         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
464                 return false;
465         decoder->private_->ignore_stream_info_block = true;
466         decoder->private_->ignore_seek_table_block = true;
467         return
468                 OggFLAC__stream_decoder_set_metadata_ignore_all(decoder->private_->stream_decoder) &&
469                 OggFLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_STREAMINFO) &&
470                 OggFLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_SEEKTABLE);
471 }
472
473 OggFLAC_API OggFLAC__SeekableStreamDecoderState OggFLAC__seekable_stream_decoder_get_state(const OggFLAC__SeekableStreamDecoder *decoder)
474 {
475         FLAC__ASSERT(0 != decoder);
476         FLAC__ASSERT(0 != decoder->protected_);
477         return decoder->protected_->state;
478 }
479
480 OggFLAC_API OggFLAC__StreamDecoderState OggFLAC__seekable_stream_decoder_get_stream_decoder_state(const OggFLAC__SeekableStreamDecoder *decoder)
481 {
482         FLAC__ASSERT(0 != decoder);
483         FLAC__ASSERT(0 != decoder->private_);
484         return OggFLAC__stream_decoder_get_state(decoder->private_->stream_decoder);
485 }
486
487 OggFLAC_API FLAC__StreamDecoderState OggFLAC__seekable_stream_decoder_get_FLAC_stream_decoder_state(const OggFLAC__SeekableStreamDecoder *decoder)
488 {
489         FLAC__ASSERT(0 != decoder);
490         FLAC__ASSERT(0 != decoder->private_);
491         return OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder->private_->stream_decoder);
492 }
493
494 OggFLAC_API const char *OggFLAC__seekable_stream_decoder_get_resolved_state_string(const OggFLAC__SeekableStreamDecoder *decoder)
495 {
496         if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR)
497                 return OggFLAC__SeekableStreamDecoderStateString[decoder->protected_->state];
498         else
499                 return OggFLAC__stream_decoder_get_resolved_state_string(decoder->private_->stream_decoder);
500 }
501
502 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_get_md5_checking(const OggFLAC__SeekableStreamDecoder *decoder)
503 {
504         FLAC__ASSERT(0 != decoder);
505         FLAC__ASSERT(0 != decoder->protected_);
506         return decoder->protected_->md5_checking;
507 }
508
509 OggFLAC_API unsigned OggFLAC__seekable_stream_decoder_get_channels(const OggFLAC__SeekableStreamDecoder *decoder)
510 {
511         FLAC__ASSERT(0 != decoder);
512         FLAC__ASSERT(0 != decoder->private_);
513         return OggFLAC__stream_decoder_get_channels(decoder->private_->stream_decoder);
514 }
515
516 OggFLAC_API FLAC__ChannelAssignment OggFLAC__seekable_stream_decoder_get_channel_assignment(const OggFLAC__SeekableStreamDecoder *decoder)
517 {
518         FLAC__ASSERT(0 != decoder);
519         FLAC__ASSERT(0 != decoder->private_);
520         return OggFLAC__stream_decoder_get_channel_assignment(decoder->private_->stream_decoder);
521 }
522
523 OggFLAC_API unsigned OggFLAC__seekable_stream_decoder_get_bits_per_sample(const OggFLAC__SeekableStreamDecoder *decoder)
524 {
525         FLAC__ASSERT(0 != decoder);
526         FLAC__ASSERT(0 != decoder->private_);
527         return OggFLAC__stream_decoder_get_bits_per_sample(decoder->private_->stream_decoder);
528 }
529
530 OggFLAC_API unsigned OggFLAC__seekable_stream_decoder_get_sample_rate(const OggFLAC__SeekableStreamDecoder *decoder)
531 {
532         FLAC__ASSERT(0 != decoder);
533         FLAC__ASSERT(0 != decoder->private_);
534         return OggFLAC__stream_decoder_get_sample_rate(decoder->private_->stream_decoder);
535 }
536
537 OggFLAC_API unsigned OggFLAC__seekable_stream_decoder_get_blocksize(const OggFLAC__SeekableStreamDecoder *decoder)
538 {
539         FLAC__ASSERT(0 != decoder);
540         FLAC__ASSERT(0 != decoder->private_);
541         return OggFLAC__stream_decoder_get_blocksize(decoder->private_->stream_decoder);
542 }
543
544 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_flush(OggFLAC__SeekableStreamDecoder *decoder)
545 {
546         FLAC__ASSERT(0 != decoder);
547         FLAC__ASSERT(0 != decoder->private_);
548         FLAC__ASSERT(0 != decoder->protected_);
549
550         decoder->private_->do_md5_checking = false;
551
552         if(!OggFLAC__stream_decoder_flush(decoder->private_->stream_decoder)) {
553                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
554                 return false;
555         }
556
557         decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_OK;
558
559         return true;
560 }
561
562 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_reset(OggFLAC__SeekableStreamDecoder *decoder)
563 {
564         FLAC__ASSERT(0 != decoder);
565         FLAC__ASSERT(0 != decoder->private_);
566         FLAC__ASSERT(0 != decoder->protected_);
567
568         if(!OggFLAC__seekable_stream_decoder_flush(decoder)) {
569                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
570                 return false;
571         }
572
573         if(!OggFLAC__stream_decoder_reset(decoder->private_->stream_decoder)) {
574                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
575                 return false;
576         }
577
578         decoder->private_->seek_table = 0;
579
580         decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
581
582         /* We initialize the FLAC__MD5Context even though we may never use it.  This
583          * is because md5 checking may be turned on to start and then turned off if
584          * a seek occurs.  So we always init the context here and finalize it in
585          * OggFLAC__seekable_stream_decoder_finish() to make sure things are always
586          * cleaned up properly.
587          */
588         FLAC__MD5Init(&decoder->private_->md5context);
589
590         decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_OK;
591
592         return true;
593 }
594
595 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_process_single(OggFLAC__SeekableStreamDecoder *decoder)
596 {
597         FLAC__bool ret;
598         FLAC__ASSERT(0 != decoder);
599
600         if(decoder->private_->stream_decoder->protected_->state == OggFLAC__STREAM_DECODER_END_OF_STREAM)
601                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
602
603         if(decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
604                 return true;
605
606         FLAC__ASSERT(decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_OK);
607
608         ret = OggFLAC__stream_decoder_process_single(decoder->private_->stream_decoder);
609         if(!ret)
610                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
611
612         return ret;
613 }
614
615 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_process_until_end_of_metadata(OggFLAC__SeekableStreamDecoder *decoder)
616 {
617         FLAC__bool ret;
618         FLAC__ASSERT(0 != decoder);
619
620         if(decoder->private_->stream_decoder->protected_->state == OggFLAC__STREAM_DECODER_END_OF_STREAM)
621                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
622
623         if(decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
624                 return true;
625
626         FLAC__ASSERT(decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_OK);
627
628         ret = OggFLAC__stream_decoder_process_until_end_of_metadata(decoder->private_->stream_decoder);
629         if(!ret)
630                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
631
632         return ret;
633 }
634
635 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_process_until_end_of_stream(OggFLAC__SeekableStreamDecoder *decoder)
636 {
637         FLAC__bool ret;
638         FLAC__ASSERT(0 != decoder);
639
640         if(decoder->private_->stream_decoder->protected_->state == OggFLAC__STREAM_DECODER_END_OF_STREAM)
641                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
642
643         if(decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
644                 return true;
645
646         FLAC__ASSERT(decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_OK);
647
648         ret = OggFLAC__stream_decoder_process_until_end_of_stream(decoder->private_->stream_decoder);
649         if(!ret)
650                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
651
652         return ret;
653 }
654
655 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_decoder_seek_absolute(OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample)
656 {
657         FLAC__uint64 length;
658
659         FLAC__ASSERT(0 != decoder);
660         FLAC__ASSERT(decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_OK || decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM);
661
662         decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_SEEKING;
663
664         /* turn off md5 checking if a seek is attempted */
665         decoder->private_->do_md5_checking = false;
666
667         if(!OggFLAC__stream_decoder_reset(decoder->private_->stream_decoder)) {
668                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
669                 return false;
670         }
671         /* get the file length */
672         if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != OggFLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK) {
673                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
674                 return false;
675         }
676         /* rewind */
677         if(decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) != OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) {
678                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
679                 return false;
680         }
681         if(!OggFLAC__stream_decoder_process_until_end_of_metadata(decoder->private_->stream_decoder)) {
682                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
683                 return false;
684         }
685         if(decoder->private_->stream_info.total_samples > 0 && sample >= decoder->private_->stream_info.total_samples) {
686                 decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
687                 return false;
688         }
689
690         return seek_to_absolute_sample_(decoder, length, sample);
691 }
692
693 /***********************************************************************
694  *
695  * Private class methods
696  *
697  ***********************************************************************/
698
699 void set_defaults_(OggFLAC__SeekableStreamDecoder *decoder)
700 {
701         decoder->private_->read_callback = 0;
702         decoder->private_->seek_callback = 0;
703         decoder->private_->tell_callback = 0;
704         decoder->private_->length_callback = 0;
705         decoder->private_->eof_callback = 0;
706         decoder->private_->write_callback = 0;
707         decoder->private_->metadata_callback = 0;
708         decoder->private_->error_callback = 0;
709         decoder->private_->client_data = 0;
710         /* WATCHOUT: these should match the default behavior of OggFLAC__StreamDecoder */
711         decoder->private_->ignore_stream_info_block = false;
712         decoder->private_->ignore_seek_table_block = true;
713
714         decoder->protected_->md5_checking = false;
715 }
716
717 FLAC__StreamDecoderReadStatus read_callback_(const OggFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
718 {
719         OggFLAC__SeekableStreamDecoder *seekable_stream_decoder = (OggFLAC__SeekableStreamDecoder *)client_data;
720         (void)decoder;
721         if(seekable_stream_decoder->private_->eof_callback(seekable_stream_decoder, seekable_stream_decoder->private_->client_data)) {
722                 *bytes = 0;
723 #if 0
724 @@@@@@ verify that this is not needed:
725                 seekable_stream_decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
726 #endif
727                 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
728         }
729         else if(*bytes > 0) {
730                 if(seekable_stream_decoder->private_->read_callback(seekable_stream_decoder, buffer, bytes, seekable_stream_decoder->private_->client_data) != OggFLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK) {
731                         seekable_stream_decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_READ_ERROR;
732                         return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
733                 }
734                 if(*bytes == 0) {
735                         if(seekable_stream_decoder->private_->eof_callback(seekable_stream_decoder, seekable_stream_decoder->private_->client_data)) {
736 #if 0
737 @@@@@@ verify that this is not needed:
738                                 seekable_stream_decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
739 #endif
740                                 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
741                         }
742                         else
743                                 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
744                 }
745                 else {
746                         return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
747                 }
748         }
749         else
750                 return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
751 }
752
753 FLAC__StreamDecoderWriteStatus write_callback_(const OggFLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
754 {
755         OggFLAC__SeekableStreamDecoder *seekable_stream_decoder = (OggFLAC__SeekableStreamDecoder *)client_data;
756         (void)decoder;
757
758         if(seekable_stream_decoder->protected_->state == OggFLAC__SEEKABLE_STREAM_DECODER_SEEKING) {
759                 FLAC__uint64 this_frame_sample = frame->header.number.sample_number;
760                 FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize;
761                 FLAC__uint64 target_sample = seekable_stream_decoder->private_->target_sample;
762
763                 FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
764
765                 seekable_stream_decoder->private_->last_frame = *frame; /* save the frame */
766                 if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */
767                         unsigned delta = (unsigned)(target_sample - this_frame_sample);
768                         /* kick out of seek mode */
769                         seekable_stream_decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_OK;
770                         /* shift out the samples before target_sample */
771                         if(delta > 0) {
772                                 unsigned channel;
773                                 const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS];
774                                 for(channel = 0; channel < frame->header.channels; channel++)
775                                         newbuffer[channel] = buffer[channel] + delta;
776                                 seekable_stream_decoder->private_->last_frame.header.blocksize -= delta;
777                                 seekable_stream_decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta;
778                                 /* write the relevant samples */
779                                 return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, &seekable_stream_decoder->private_->last_frame, newbuffer, seekable_stream_decoder->private_->client_data);
780                         }
781                         else {
782                                 /* write the relevant samples */
783                                 return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, frame, buffer, seekable_stream_decoder->private_->client_data);
784                         }
785                 }
786                 else {
787                         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
788                 }
789         }
790         else {
791                 if(seekable_stream_decoder->private_->do_md5_checking) {
792                         if(!FLAC__MD5Accumulate(&seekable_stream_decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8))
793                                 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
794                 }
795                 return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, frame, buffer, seekable_stream_decoder->private_->client_data);
796         }
797 }
798
799 void metadata_callback_(const OggFLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
800 {
801         OggFLAC__SeekableStreamDecoder *seekable_stream_decoder = (OggFLAC__SeekableStreamDecoder *)client_data;
802         (void)decoder;
803
804         if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
805                 seekable_stream_decoder->private_->stream_info = metadata->data.stream_info;
806                 /* save the MD5 signature for comparison later */
807                 memcpy(seekable_stream_decoder->private_->stored_md5sum, metadata->data.stream_info.md5sum, 16);
808                 if(0 == memcmp(seekable_stream_decoder->private_->stored_md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
809                         seekable_stream_decoder->private_->do_md5_checking = false;
810         }
811         else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE) {
812                 seekable_stream_decoder->private_->seek_table = &metadata->data.seek_table;
813         }
814
815         if(seekable_stream_decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_SEEKING) {
816                 FLAC__bool ignore_block = false;
817                 if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && seekable_stream_decoder->private_->ignore_stream_info_block)
818                         ignore_block = true;
819                 else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE && seekable_stream_decoder->private_->ignore_seek_table_block)
820                         ignore_block = true;
821                 if(!ignore_block)
822                         seekable_stream_decoder->private_->metadata_callback(seekable_stream_decoder, metadata, seekable_stream_decoder->private_->client_data);
823         }
824 }
825
826 void error_callback_(const OggFLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
827 {
828         OggFLAC__SeekableStreamDecoder *seekable_stream_decoder = (OggFLAC__SeekableStreamDecoder *)client_data;
829         (void)decoder;
830
831         if(seekable_stream_decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_SEEKING)
832                 seekable_stream_decoder->private_->error_callback(seekable_stream_decoder, status, seekable_stream_decoder->private_->client_data);
833 }
834
835 FLAC__bool seek_to_absolute_sample_(OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
836 {
837         FLAC__uint64 left_pos = 0, right_pos = stream_length;
838         FLAC__uint64 left_sample = 0, right_sample = decoder->private_->stream_info.total_samples;
839         unsigned iteration = 0;
840
841         /* In the first iterations, we will calculate the target byte position 
842          * by the distance from the target sample to left_sample and
843          * right_sample.  After that, we will switch to binary search.
844          */
845         static const unsigned BINARY_SEARCH_AFTER_ITERATION = 2;
846
847         /* We will switch to a linear search once our current sample is less
848          * that this number of samples ahead of the target sample
849          */
850         static const FLAC__uint64 LINEAR_SEARCH_WITHIN_SAMPLES = FLAC__MAX_BLOCK_SIZE * 2;
851
852         /* If the total number of samples is unknown, use a large value and
853          * increase 'iteration' to force binary search immediately.
854          */
855         if(right_sample == 0) {
856                 right_sample = (FLAC__uint64)(-1);
857                 iteration = BINARY_SEARCH_AFTER_ITERATION;
858         }
859
860         decoder->private_->target_sample = target_sample;
861         for( ; ; iteration++) {
862                 if(!OggFLAC__stream_decoder_process_single(decoder->private_->stream_decoder)) {
863                         decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
864                         return false;
865                 }
866                 /* our write callback will change the state when it gets to the target frame */
867                 if(decoder->protected_->state != OggFLAC__SEEKABLE_STREAM_DECODER_SEEKING) {
868                         break;
869                 }
870                 else {
871                         const FLAC__uint64 this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
872                         FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
873
874                         if (this_frame_sample > target_sample || target_sample - this_frame_sample > LINEAR_SEARCH_WITHIN_SAMPLES) {
875                                 FLAC__uint64 pos;
876
877                                 if (iteration >= BINARY_SEARCH_AFTER_ITERATION)
878                                         pos = (right_pos + left_pos) / 2;
879                                 else
880 #if defined _MSC_VER || defined __MINGW32__
881                                         /* with VC++ you have to spoon feed it the casting */
882                                         pos = (FLAC__uint64)((double)(FLAC__int64)(target_sample - left_sample) / (double)(FLAC__int64)(right_pos - left_pos));
883 #else
884                                         pos = (FLAC__uint64)((double)(target_sample - left_sample) / (double)(right_pos - left_pos));
885 #endif
886
887                                 if (this_frame_sample <= target_sample) {
888                                         /* The 'equal' case should not happen, since
889                                          * OggFLAC__stream_decoder_process_single()
890                                          * should recognize that it has hit the
891                                          * target sample and we would exit through
892                                          * the 'break' above.
893                                          */
894                                         FLAC__ASSERT(this_frame_sample != target_sample);
895
896                                         left_sample = this_frame_sample;
897                                         left_pos = pos;
898                                 }
899                                 else if(this_frame_sample > target_sample) {
900                                         right_sample = this_frame_sample;
901                                         right_pos = pos;
902                                 }
903
904                                 /* physical seek */
905                                 if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) {
906                                         decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
907                                         return false;
908                                 }
909                                 if(!OggFLAC__stream_decoder_flush(decoder->private_->stream_decoder)) {
910                                         decoder->protected_->state = OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
911                                         return false;
912                                 }
913                         }
914                 }
915         }
916
917         return true;
918 }