fix bug in file closing logic in _finish()
[flac.git] / src / libOggFLAC / stream_encoder.c
1 /* libOggFLAC - Free Lossless Audio Codec + Ogg library
2  * Copyright (C) 2002,2003,2004,2005,2006  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 #if HAVE_CONFIG_H
33 #  include <config.h>
34 #endif
35
36 #if defined _MSC_VER || defined __MINGW32__
37 #include <io.h> /* for _setmode() */
38 #include <fcntl.h> /* for _O_BINARY */
39 #endif
40 #if defined __CYGWIN__ || defined __EMX__
41 #include <io.h> /* for setmode(), O_BINARY */
42 #include <fcntl.h> /* for _O_BINARY */
43 #endif
44 #include <stdio.h>
45 #include <stdlib.h> /* for calloc() */
46 #include <string.h> /* for memcpy() */
47 #include <sys/types.h> /* for off_t */
48 #if defined _MSC_VER || defined __MINGW32__
49 /*@@@ [2G limit] hacks for MSVC6 */
50 #define fseeko fseek
51 #define ftello ftell
52 #endif
53 #include "FLAC/assert.h"
54 #include "OggFLAC/stream_encoder.h"
55 #include "protected/stream_encoder.h"
56 #include "private/ogg_helper.h"
57
58 #ifdef max
59 #undef max
60 #endif
61 #define max(a,b) ((a)>(b)?(a):(b))
62
63 /***********************************************************************
64  *
65  * Private class method prototypes
66  *
67  ***********************************************************************/
68
69 /* unpublished debug routines */
70 extern FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
71 extern FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
72 extern FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
73
74 static void set_defaults_(OggFLAC__StreamEncoder *encoder);
75 static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
76 static void metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
77 static OggFLAC__StreamEncoderReadStatus file_read_callback_(const OggFLAC__StreamEncoder *encoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
78 static FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
79 static FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
80 static FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
81 static FILE *get_binary_stdout_();
82
83
84 /***********************************************************************
85  *
86  * Private class data
87  *
88  ***********************************************************************/
89
90 typedef struct OggFLAC__StreamEncoderPrivate {
91         OggFLAC__StreamEncoderReadCallback read_callback;
92         FLAC__StreamEncoderWriteCallback write_callback;
93         FLAC__StreamEncoderSeekCallback seek_callback;
94         FLAC__StreamEncoderTellCallback tell_callback;
95         FLAC__StreamEncoderMetadataCallback metadata_callback;
96         FLAC__StreamEncoderProgressCallback progress_callback;
97         void *client_data;
98 #if 0 //@@@@@@
99         FLAC__StreamEncoder *FLAC_stream_encoder;
100 #endif
101         FLAC__StreamMetadata_SeekTable *seek_table;
102         /* internal vars (all the above are class settings) */
103         unsigned first_seekpoint_to_check;
104         FILE *file;                            /* only used when encoding to a file */
105         FLAC__uint64 bytes_written;
106         FLAC__uint64 samples_written;
107         unsigned frames_written;
108         unsigned total_frames_estimate;
109 } OggFLAC__StreamEncoderPrivate;
110
111
112 /***********************************************************************
113  *
114  * Public static class data
115  *
116  ***********************************************************************/
117
118 OggFLAC_API const char * const OggFLAC__StreamEncoderStateString[] = {
119         "OggFLAC__STREAM_ENCODER_OK",
120         "OggFLAC__STREAM_ENCODER_UNINITIALIZED",
121         "OggFLAC__STREAM_ENCODER_OGG_ERROR",
122         "OggFLAC__STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR",
123         "OggFLAC__STREAM_ENCODER_CLIENT_ERROR",
124         "OggFLAC__STREAM_ENCODER_IO_ERROR",
125         "OggFLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR"
126 };
127
128 OggFLAC_API const char * const OggFLAC__treamEncoderReadStatusString[] = {
129         "OggFLAC__STREAM_ENCODER_READ_STATUS_CONTINUE",
130         "OggFLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM",
131         "OggFLAC__STREAM_ENCODER_READ_STATUS_ABORT",
132         "OggFLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED"
133 };
134
135
136 /***********************************************************************
137  *
138  * Class constructor/destructor
139  *
140  */
141 OggFLAC_API OggFLAC__StreamEncoder *OggFLAC__stream_encoder_new()
142 {
143         OggFLAC__StreamEncoder *encoder;
144         FLAC__StreamEncoder *parent;
145
146         FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
147
148         encoder = (OggFLAC__StreamEncoder*)calloc(1, sizeof(OggFLAC__StreamEncoder));
149         if(encoder == 0) {
150                 return 0;
151         }
152
153         encoder->protected_ = (OggFLAC__StreamEncoderProtected*)calloc(1, sizeof(OggFLAC__StreamEncoderProtected));
154         if(encoder->protected_ == 0) {
155                 free(encoder);
156                 return 0;
157         }
158
159         encoder->private_ = (OggFLAC__StreamEncoderPrivate*)calloc(1, sizeof(OggFLAC__StreamEncoderPrivate));
160         if(encoder->private_ == 0) {
161                 free(encoder->protected_);
162                 free(encoder);
163                 return 0;
164         }
165
166         parent = FLAC__stream_encoder_new();
167         if(0 == parent) {
168                 free(encoder->private_);
169                 free(encoder->protected_);
170                 free(encoder);
171                 return 0;
172         }
173         encoder->super_ = *parent;
174
175         encoder->private_->file = 0;
176
177         set_defaults_(encoder);
178
179         encoder->protected_->state = OggFLAC__STREAM_ENCODER_UNINITIALIZED;
180
181         return encoder;
182 }
183
184 OggFLAC_API void OggFLAC__stream_encoder_delete(OggFLAC__StreamEncoder *encoder)
185 {
186         FLAC__ASSERT(0 != encoder);
187         FLAC__ASSERT(0 != encoder->protected_);
188         FLAC__ASSERT(0 != encoder->private_);
189
190         (void)OggFLAC__stream_encoder_finish(encoder);
191
192         free(encoder->private_);
193         free(encoder->protected_);
194         /* don't free(encoder) because FLAC__stream_encoder_delete() will do it */
195
196         /* call superclass destructor last */
197         FLAC__stream_encoder_delete((FLAC__StreamEncoder*)encoder);
198 }
199
200
201 /***********************************************************************
202  *
203  * Public class methods
204  *
205  ***********************************************************************/
206
207 OggFLAC_API FLAC__StreamEncoderInitStatus OggFLAC__stream_encoder_init_stream(OggFLAC__StreamEncoder *encoder, OggFLAC__StreamEncoderReadCallback read_callback, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data)
208 {
209         FLAC__ASSERT(0 != encoder);
210
211         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
212                 return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
213
214         if(0 == write_callback || (seek_callback && (0 == read_callback || 0 == tell_callback)))
215                 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS;
216
217         /* check seek table before FLAC__stream_encoder_init_stream() does, just to avoid messing up the encoder state for a trivial error */
218         if(0 != encoder->private_->seek_table && !FLAC__format_seektable_is_legal(encoder->private_->seek_table))
219                 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
220
221         /* set state to OK; from here on, errors are fatal and we'll override the state then */
222         encoder->protected_->state = OggFLAC__STREAM_ENCODER_OK;
223
224         if(!OggFLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect)) {
225                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_OGG_ERROR;
226                 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
227         }
228
229         encoder->private_->read_callback = read_callback;
230         encoder->private_->write_callback = write_callback;
231         encoder->private_->seek_callback = seek_callback;
232         encoder->private_->tell_callback = tell_callback;
233         encoder->private_->metadata_callback = metadata_callback;
234         encoder->private_->client_data = client_data;
235
236         /*
237          * These must be done before we init the stream encoder because that
238          * calls the write_callback, which uses these values.
239          */
240         encoder->private_->first_seekpoint_to_check = 0;
241         encoder->private_->samples_written = 0;
242         encoder->protected_->streaminfo_offset = 0;
243         encoder->protected_->seektable_offset = 0;
244         encoder->protected_->audio_offset = 0;
245
246         /* we do our own special metadata updating inside Ogg here, so we don't pass in our seek/tell callbacks */
247         if(FLAC__stream_encoder_init_stream((FLAC__StreamEncoder*)encoder, write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, metadata_callback_, /*client_data=*/encoder) != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
248                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR;
249                 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
250         }
251
252         /*
253          * Initializing the stream encoder writes all the metadata, so we
254          * save the stream offset now.
255          */
256         if(encoder->private_->tell_callback && encoder->private_->tell_callback((FLAC__StreamEncoder*)encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
257                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_CLIENT_ERROR;
258                 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
259         }
260
261         return FLAC__STREAM_ENCODER_INIT_STATUS_OK;
262 }
263
264 OggFLAC_API FLAC__StreamEncoderInitStatus OggFLAC__stream_encoder_init_FILE(OggFLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data)
265 {
266         FLAC__StreamEncoderInitStatus init_status;
267
268         FLAC__ASSERT(0 != encoder);
269         FLAC__ASSERT(0 != file);
270
271         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
272                 return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
273
274         /*
275          * To make sure that our file does not go unclosed after an error, we
276          * must assign the FILE pointer before any further error can occur in
277          * this routine.
278          */
279         if(file == stdout)
280                 file = get_binary_stdout_(); /* just to be safe */
281
282         encoder->private_->file = file;
283
284         encoder->private_->progress_callback = progress_callback;
285         encoder->private_->bytes_written = 0;
286         encoder->private_->samples_written = 0;
287         encoder->private_->frames_written = 0;
288
289         init_status = OggFLAC__stream_encoder_init_stream(encoder, file_read_callback_, file_write_callback_, file_seek_callback_, file_tell_callback_, /*metadata_callback=*/0, client_data);
290         if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
291                 /* the above function sets the state for us in case of an error */
292                 return init_status;
293         }
294
295         {
296                 unsigned blocksize = OggFLAC__stream_encoder_get_blocksize(encoder);
297
298                 FLAC__ASSERT(blocksize != 0);
299                 encoder->private_->total_frames_estimate = (unsigned)((OggFLAC__stream_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize);
300         }
301
302         return init_status;
303 }
304
305 OggFLAC_API FLAC__StreamEncoderInitStatus OggFLAC__stream_encoder_init_file(OggFLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data)
306 {
307         FILE *file;
308
309         FLAC__ASSERT(0 != encoder);
310
311         /*
312          * To make sure that our file does not go unclosed after an error, we
313          * have to do the same entrance checks here that are later performed
314          * in FLAC__stream_encoder_init_FILE() before the FILE* is assigned.
315          */
316         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
317                 return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
318
319         file = filename? fopen(filename, "w+b") : stdout;
320
321         if(file == 0) {
322                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_IO_ERROR;
323                 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
324         }
325
326         return OggFLAC__stream_encoder_init_FILE(encoder, file, progress_callback, client_data);
327 }
328
329 OggFLAC_API void OggFLAC__stream_encoder_finish(OggFLAC__StreamEncoder *encoder)
330 {
331         FLAC__ASSERT(0 != encoder);
332         FLAC__ASSERT(0 != encoder->private_);
333         FLAC__ASSERT(0 != encoder->protected_);
334
335         if(encoder->protected_->state == OggFLAC__STREAM_ENCODER_UNINITIALIZED)
336                 return;
337
338         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
339
340         FLAC__stream_encoder_finish((FLAC__StreamEncoder*)encoder);
341
342         OggFLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect);
343
344         if(0 != encoder->private_->file) {
345                 if(encoder->private_->file != stdout)
346                         fclose(encoder->private_->file);
347                 encoder->private_->file = 0;
348         }
349
350         set_defaults_(encoder);
351
352         encoder->protected_->state = OggFLAC__STREAM_ENCODER_UNINITIALIZED;
353 }
354
355 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_serial_number(OggFLAC__StreamEncoder *encoder, long value)
356 {
357         FLAC__ASSERT(0 != encoder);
358         FLAC__ASSERT(0 != encoder->private_);
359         FLAC__ASSERT(0 != encoder->protected_);
360         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
361         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
362                 return false;
363         OggFLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value);
364         return true;
365 }
366
367 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_verify(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
368 {
369         FLAC__ASSERT(0 != encoder);
370         FLAC__ASSERT(0 != encoder->private_);
371         FLAC__ASSERT(0 != encoder->protected_);
372         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
373         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
374                 return false;
375         return FLAC__stream_encoder_set_verify((FLAC__StreamEncoder*)encoder, value);
376 }
377
378 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_streamable_subset(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
379 {
380         FLAC__ASSERT(0 != encoder);
381         FLAC__ASSERT(0 != encoder->private_);
382         FLAC__ASSERT(0 != encoder->protected_);
383         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
384         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
385                 return false;
386         return FLAC__stream_encoder_set_streamable_subset((FLAC__StreamEncoder*)encoder, value);
387 }
388
389 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_do_mid_side_stereo(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
390 {
391         FLAC__ASSERT(0 != encoder);
392         FLAC__ASSERT(0 != encoder->private_);
393         FLAC__ASSERT(0 != encoder->protected_);
394         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
395         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
396                 return false;
397         return FLAC__stream_encoder_set_do_mid_side_stereo((FLAC__StreamEncoder*)encoder, value);
398 }
399
400 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_loose_mid_side_stereo(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
401 {
402         FLAC__ASSERT(0 != encoder);
403         FLAC__ASSERT(0 != encoder->private_);
404         FLAC__ASSERT(0 != encoder->protected_);
405         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
406         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
407                 return false;
408         return FLAC__stream_encoder_set_loose_mid_side_stereo((FLAC__StreamEncoder*)encoder, value);
409 }
410
411 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_channels(OggFLAC__StreamEncoder *encoder, unsigned value)
412 {
413         FLAC__ASSERT(0 != encoder);
414         FLAC__ASSERT(0 != encoder->private_);
415         FLAC__ASSERT(0 != encoder->protected_);
416         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
417         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
418                 return false;
419         return FLAC__stream_encoder_set_channels((FLAC__StreamEncoder*)encoder, value);
420 }
421
422 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_bits_per_sample(OggFLAC__StreamEncoder *encoder, unsigned value)
423 {
424         FLAC__ASSERT(0 != encoder);
425         FLAC__ASSERT(0 != encoder->private_);
426         FLAC__ASSERT(0 != encoder->protected_);
427         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
428         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
429                 return false;
430         return FLAC__stream_encoder_set_bits_per_sample((FLAC__StreamEncoder*)encoder, value);
431 }
432
433 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_sample_rate(OggFLAC__StreamEncoder *encoder, unsigned value)
434 {
435         FLAC__ASSERT(0 != encoder);
436         FLAC__ASSERT(0 != encoder->private_);
437         FLAC__ASSERT(0 != encoder->protected_);
438         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
439         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
440                 return false;
441         return FLAC__stream_encoder_set_sample_rate((FLAC__StreamEncoder*)encoder, value);
442 }
443
444 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_blocksize(OggFLAC__StreamEncoder *encoder, unsigned value)
445 {
446         FLAC__ASSERT(0 != encoder);
447         FLAC__ASSERT(0 != encoder->private_);
448         FLAC__ASSERT(0 != encoder->protected_);
449         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
450         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
451                 return false;
452         return FLAC__stream_encoder_set_blocksize((FLAC__StreamEncoder*)encoder, value);
453 }
454
455 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_apodization(OggFLAC__StreamEncoder *encoder, const char *specification)
456 {
457         FLAC__ASSERT(0 != encoder);
458         FLAC__ASSERT(0 != encoder->private_);
459         FLAC__ASSERT(0 != encoder->protected_);
460         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
461         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
462                 return false;
463         return FLAC__stream_encoder_set_apodization((FLAC__StreamEncoder*)encoder, specification);
464 }
465
466 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_max_lpc_order(OggFLAC__StreamEncoder *encoder, unsigned value)
467 {
468         FLAC__ASSERT(0 != encoder);
469         FLAC__ASSERT(0 != encoder->private_);
470         FLAC__ASSERT(0 != encoder->protected_);
471         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
472         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
473                 return false;
474         return FLAC__stream_encoder_set_max_lpc_order((FLAC__StreamEncoder*)encoder, value);
475 }
476
477 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_qlp_coeff_precision(OggFLAC__StreamEncoder *encoder, unsigned value)
478 {
479         FLAC__ASSERT(0 != encoder);
480         FLAC__ASSERT(0 != encoder->private_);
481         FLAC__ASSERT(0 != encoder->protected_);
482         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
483         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
484                 return false;
485         return FLAC__stream_encoder_set_qlp_coeff_precision((FLAC__StreamEncoder*)encoder, value);
486 }
487
488 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_do_qlp_coeff_prec_search(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
489 {
490         FLAC__ASSERT(0 != encoder);
491         FLAC__ASSERT(0 != encoder->private_);
492         FLAC__ASSERT(0 != encoder->protected_);
493         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
494         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
495                 return false;
496         return FLAC__stream_encoder_set_do_qlp_coeff_prec_search((FLAC__StreamEncoder*)encoder, value);
497 }
498
499 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_do_escape_coding(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
500 {
501         FLAC__ASSERT(0 != encoder);
502         FLAC__ASSERT(0 != encoder->private_);
503         FLAC__ASSERT(0 != encoder->protected_);
504         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
505         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
506                 return false;
507         return FLAC__stream_encoder_set_do_escape_coding((FLAC__StreamEncoder*)encoder, value);
508 }
509
510 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_do_exhaustive_model_search(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
511 {
512         FLAC__ASSERT(0 != encoder);
513         FLAC__ASSERT(0 != encoder->private_);
514         FLAC__ASSERT(0 != encoder->protected_);
515         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
516         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
517                 return false;
518         return FLAC__stream_encoder_set_do_exhaustive_model_search((FLAC__StreamEncoder*)encoder, value);
519 }
520
521 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_min_residual_partition_order(OggFLAC__StreamEncoder *encoder, unsigned value)
522 {
523         FLAC__ASSERT(0 != encoder);
524         FLAC__ASSERT(0 != encoder->private_);
525         FLAC__ASSERT(0 != encoder->protected_);
526         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
527         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
528                 return false;
529         return FLAC__stream_encoder_set_min_residual_partition_order((FLAC__StreamEncoder*)encoder, value);
530 }
531
532 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_max_residual_partition_order(OggFLAC__StreamEncoder *encoder, unsigned value)
533 {
534         FLAC__ASSERT(0 != encoder);
535         FLAC__ASSERT(0 != encoder->private_);
536         FLAC__ASSERT(0 != encoder->protected_);
537         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
538         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
539                 return false;
540         return FLAC__stream_encoder_set_max_residual_partition_order((FLAC__StreamEncoder*)encoder, value);
541 }
542
543 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_rice_parameter_search_dist(OggFLAC__StreamEncoder *encoder, unsigned value)
544 {
545         FLAC__ASSERT(0 != encoder);
546         FLAC__ASSERT(0 != encoder->private_);
547         FLAC__ASSERT(0 != encoder->protected_);
548         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
549         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
550                 return false;
551         return FLAC__stream_encoder_set_rice_parameter_search_dist((FLAC__StreamEncoder*)encoder, value);
552 }
553
554 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_total_samples_estimate(OggFLAC__StreamEncoder *encoder, FLAC__uint64 value)
555 {
556         FLAC__ASSERT(0 != encoder);
557         FLAC__ASSERT(0 != encoder->private_);
558         FLAC__ASSERT(0 != encoder->protected_);
559         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
560         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
561                 return false;
562         return FLAC__stream_encoder_set_total_samples_estimate((FLAC__StreamEncoder*)encoder, value);
563 }
564
565 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_metadata(OggFLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
566 {
567         FLAC__ASSERT(0 != encoder);
568         FLAC__ASSERT(0 != encoder->private_);
569         FLAC__ASSERT(0 != encoder->protected_);
570         //@@@@@@superclass;FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
571         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
572                 return false;
573         /* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */
574         if(0 != metadata && num_blocks > 1) {
575                 unsigned i;
576                 for(i = 1; i < num_blocks; i++) {
577                         if(0 != metadata[i] && metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
578                                 FLAC__StreamMetadata *vc = metadata[i];
579                                 for( ; i > 0; i--)
580                                         metadata[i] = metadata[i-1];
581                                 metadata[0] = vc;
582                                 break;
583                         }
584                 }
585         }
586         if(0 != metadata && num_blocks > 0) {
587                 unsigned i;
588                 for(i = 0; i < num_blocks; i++) {
589                         /* keep track of any SEEKTABLE block */
590                         if(0 != metadata[i] && metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
591                                 encoder->private_->seek_table = &metadata[i]->data.seek_table;
592                                 break; /* take only the first one */
593                         }
594                 }
595         }
596         if(!OggFLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks))
597                 return false;
598         return FLAC__stream_encoder_set_metadata((FLAC__StreamEncoder*)encoder, metadata, num_blocks);
599 }
600
601 /*
602  * These three functions are not static, but not publically exposed in
603  * include/OggFLAC/ either.  They are used by the test suite.
604  */
605 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_disable_constant_subframes(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
606 {
607         FLAC__ASSERT(0 != encoder);
608         FLAC__ASSERT(0 != encoder->private_);
609         FLAC__ASSERT(0 != encoder->protected_);
610         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
611                 return false;
612         return FLAC__stream_encoder_disable_constant_subframes((FLAC__StreamEncoder*)encoder, value);
613 }
614
615 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_disable_fixed_subframes(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
616 {
617         FLAC__ASSERT(0 != encoder);
618         FLAC__ASSERT(0 != encoder->private_);
619         FLAC__ASSERT(0 != encoder->protected_);
620         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
621                 return false;
622         return FLAC__stream_encoder_disable_fixed_subframes((FLAC__StreamEncoder*)encoder, value);
623 }
624
625 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_disable_verbatim_subframes(OggFLAC__StreamEncoder *encoder, FLAC__bool value)
626 {
627         FLAC__ASSERT(0 != encoder);
628         FLAC__ASSERT(0 != encoder->private_);
629         FLAC__ASSERT(0 != encoder->protected_);
630         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED)
631                 return false;
632         return FLAC__stream_encoder_disable_verbatim_subframes((FLAC__StreamEncoder*)encoder, value);
633 }
634
635 OggFLAC_API OggFLAC__StreamEncoderState OggFLAC__stream_encoder_get_state(const OggFLAC__StreamEncoder *encoder)
636 {
637         FLAC__ASSERT(0 != encoder);
638         FLAC__ASSERT(0 != encoder->private_);
639         FLAC__ASSERT(0 != encoder->protected_);
640         return encoder->protected_->state;
641 }
642
643 OggFLAC_API FLAC__StreamEncoderState OggFLAC__stream_encoder_get_FLAC_stream_encoder_state(const OggFLAC__StreamEncoder *encoder)
644 {
645         FLAC__ASSERT(0 != encoder);
646         FLAC__ASSERT(0 != encoder->private_);
647         FLAC__ASSERT(0 != encoder->protected_);
648         return FLAC__stream_encoder_get_state((FLAC__StreamEncoder*)encoder);
649 }
650
651 OggFLAC_API FLAC__StreamDecoderState OggFLAC__stream_encoder_get_verify_decoder_state(const OggFLAC__StreamEncoder *encoder)
652 {
653         FLAC__ASSERT(0 != encoder);
654         FLAC__ASSERT(0 != encoder->private_);
655         FLAC__ASSERT(0 != encoder->protected_);
656         return FLAC__stream_encoder_get_verify_decoder_state((FLAC__StreamEncoder*)encoder);
657 }
658
659 OggFLAC_API const char *OggFLAC__stream_encoder_get_resolved_state_string(const OggFLAC__StreamEncoder *encoder)
660 {
661         if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR)
662                 return OggFLAC__StreamEncoderStateString[encoder->protected_->state];
663         else
664                 return FLAC__stream_encoder_get_resolved_state_string((FLAC__StreamEncoder*)encoder);
665 }
666
667 OggFLAC_API void OggFLAC__stream_encoder_get_verify_decoder_error_stats(const OggFLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
668 {
669         FLAC__ASSERT(0 != encoder);
670         FLAC__ASSERT(0 != encoder->private_);
671         FLAC__stream_encoder_get_verify_decoder_error_stats((FLAC__StreamEncoder*)encoder, absolute_sample, frame_number, channel, sample, expected, got);
672 }
673
674 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_get_verify(const OggFLAC__StreamEncoder *encoder)
675 {
676         FLAC__ASSERT(0 != encoder);
677         FLAC__ASSERT(0 != encoder->private_);
678         FLAC__ASSERT(0 != encoder->protected_);
679         return FLAC__stream_encoder_get_verify((FLAC__StreamEncoder*)encoder);
680 }
681
682 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_get_streamable_subset(const OggFLAC__StreamEncoder *encoder)
683 {
684         FLAC__ASSERT(0 != encoder);
685         FLAC__ASSERT(0 != encoder->private_);
686         FLAC__ASSERT(0 != encoder->protected_);
687         return FLAC__stream_encoder_get_streamable_subset((FLAC__StreamEncoder*)encoder);
688 }
689
690 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_get_do_mid_side_stereo(const OggFLAC__StreamEncoder *encoder)
691 {
692         FLAC__ASSERT(0 != encoder);
693         FLAC__ASSERT(0 != encoder->private_);
694         FLAC__ASSERT(0 != encoder->protected_);
695         return FLAC__stream_encoder_get_do_mid_side_stereo((FLAC__StreamEncoder*)encoder);
696 }
697
698 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_get_loose_mid_side_stereo(const OggFLAC__StreamEncoder *encoder)
699 {
700         FLAC__ASSERT(0 != encoder);
701         FLAC__ASSERT(0 != encoder->private_);
702         FLAC__ASSERT(0 != encoder->protected_);
703         return FLAC__stream_encoder_get_loose_mid_side_stereo((FLAC__StreamEncoder*)encoder);
704 }
705
706 OggFLAC_API unsigned OggFLAC__stream_encoder_get_channels(const OggFLAC__StreamEncoder *encoder)
707 {
708         FLAC__ASSERT(0 != encoder);
709         FLAC__ASSERT(0 != encoder->private_);
710         FLAC__ASSERT(0 != encoder->protected_);
711         return FLAC__stream_encoder_get_channels((FLAC__StreamEncoder*)encoder);
712 }
713
714 OggFLAC_API unsigned OggFLAC__stream_encoder_get_bits_per_sample(const OggFLAC__StreamEncoder *encoder)
715 {
716         FLAC__ASSERT(0 != encoder);
717         FLAC__ASSERT(0 != encoder->private_);
718         FLAC__ASSERT(0 != encoder->protected_);
719         return FLAC__stream_encoder_get_bits_per_sample((FLAC__StreamEncoder*)encoder);
720 }
721
722 OggFLAC_API unsigned OggFLAC__stream_encoder_get_sample_rate(const OggFLAC__StreamEncoder *encoder)
723 {
724         FLAC__ASSERT(0 != encoder);
725         FLAC__ASSERT(0 != encoder->private_);
726         FLAC__ASSERT(0 != encoder->protected_);
727         return FLAC__stream_encoder_get_sample_rate((FLAC__StreamEncoder*)encoder);
728 }
729
730 OggFLAC_API unsigned OggFLAC__stream_encoder_get_blocksize(const OggFLAC__StreamEncoder *encoder)
731 {
732         FLAC__ASSERT(0 != encoder);
733         FLAC__ASSERT(0 != encoder->private_);
734         FLAC__ASSERT(0 != encoder->protected_);
735         return FLAC__stream_encoder_get_blocksize((FLAC__StreamEncoder*)encoder);
736 }
737
738 OggFLAC_API unsigned OggFLAC__stream_encoder_get_max_lpc_order(const OggFLAC__StreamEncoder *encoder)
739 {
740         FLAC__ASSERT(0 != encoder);
741         FLAC__ASSERT(0 != encoder->private_);
742         FLAC__ASSERT(0 != encoder->protected_);
743         return FLAC__stream_encoder_get_max_lpc_order((FLAC__StreamEncoder*)encoder);
744 }
745
746 OggFLAC_API unsigned OggFLAC__stream_encoder_get_qlp_coeff_precision(const OggFLAC__StreamEncoder *encoder)
747 {
748         FLAC__ASSERT(0 != encoder);
749         FLAC__ASSERT(0 != encoder->private_);
750         FLAC__ASSERT(0 != encoder->protected_);
751         return FLAC__stream_encoder_get_qlp_coeff_precision((FLAC__StreamEncoder*)encoder);
752 }
753
754 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_get_do_qlp_coeff_prec_search(const OggFLAC__StreamEncoder *encoder)
755 {
756         FLAC__ASSERT(0 != encoder);
757         FLAC__ASSERT(0 != encoder->private_);
758         FLAC__ASSERT(0 != encoder->protected_);
759         return FLAC__stream_encoder_get_do_qlp_coeff_prec_search((FLAC__StreamEncoder*)encoder);
760 }
761
762 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_get_do_escape_coding(const OggFLAC__StreamEncoder *encoder)
763 {
764         FLAC__ASSERT(0 != encoder);
765         FLAC__ASSERT(0 != encoder->private_);
766         FLAC__ASSERT(0 != encoder->protected_);
767         return FLAC__stream_encoder_get_do_escape_coding((FLAC__StreamEncoder*)encoder);
768 }
769
770 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_get_do_exhaustive_model_search(const OggFLAC__StreamEncoder *encoder)
771 {
772         FLAC__ASSERT(0 != encoder);
773         FLAC__ASSERT(0 != encoder->private_);
774         FLAC__ASSERT(0 != encoder->protected_);
775         return FLAC__stream_encoder_get_do_exhaustive_model_search((FLAC__StreamEncoder*)encoder);
776 }
777
778 OggFLAC_API unsigned OggFLAC__stream_encoder_get_min_residual_partition_order(const OggFLAC__StreamEncoder *encoder)
779 {
780         FLAC__ASSERT(0 != encoder);
781         FLAC__ASSERT(0 != encoder->private_);
782         FLAC__ASSERT(0 != encoder->protected_);
783         return FLAC__stream_encoder_get_min_residual_partition_order((FLAC__StreamEncoder*)encoder);
784 }
785
786 OggFLAC_API unsigned OggFLAC__stream_encoder_get_max_residual_partition_order(const OggFLAC__StreamEncoder *encoder)
787 {
788         FLAC__ASSERT(0 != encoder);
789         FLAC__ASSERT(0 != encoder->private_);
790         FLAC__ASSERT(0 != encoder->protected_);
791         return FLAC__stream_encoder_get_max_residual_partition_order((FLAC__StreamEncoder*)encoder);
792 }
793
794 OggFLAC_API unsigned OggFLAC__stream_encoder_get_rice_parameter_search_dist(const OggFLAC__StreamEncoder *encoder)
795 {
796         FLAC__ASSERT(0 != encoder);
797         FLAC__ASSERT(0 != encoder->private_);
798         FLAC__ASSERT(0 != encoder->protected_);
799         return FLAC__stream_encoder_get_rice_parameter_search_dist((FLAC__StreamEncoder*)encoder);
800 }
801
802 OggFLAC_API FLAC__uint64 OggFLAC__stream_encoder_get_total_samples_estimate(const OggFLAC__StreamEncoder *encoder)
803 {
804         FLAC__ASSERT(0 != encoder);
805         FLAC__ASSERT(0 != encoder->private_);
806         FLAC__ASSERT(0 != encoder->protected_);
807         return FLAC__stream_encoder_get_total_samples_estimate((FLAC__StreamEncoder*)encoder);
808 }
809
810 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_process(OggFLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
811 {
812         FLAC__ASSERT(0 != encoder);
813         FLAC__ASSERT(0 != encoder->private_);
814         FLAC__ASSERT(0 != encoder->protected_);
815         if(!FLAC__stream_encoder_process((FLAC__StreamEncoder*)encoder, buffer, samples)) {
816                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR;
817                 return false;
818         }
819         else
820                 return true;
821 }
822
823 OggFLAC_API FLAC__bool OggFLAC__stream_encoder_process_interleaved(OggFLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
824 {
825         FLAC__ASSERT(0 != encoder);
826         FLAC__ASSERT(0 != encoder->private_);
827         FLAC__ASSERT(0 != encoder->protected_);
828         if(!FLAC__stream_encoder_process_interleaved((FLAC__StreamEncoder*)encoder, buffer, samples)) {
829                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR;
830                 return false;
831         }
832         else
833                 return true;
834 }
835
836 /***********************************************************************
837  *
838  * Private class methods
839  *
840  ***********************************************************************/
841
842 void set_defaults_(OggFLAC__StreamEncoder *encoder)
843 {
844         FLAC__ASSERT(0 != encoder);
845         FLAC__ASSERT(0 != encoder->private_);
846         FLAC__ASSERT(0 != encoder->protected_);
847
848         encoder->private_->read_callback = 0;
849         encoder->private_->write_callback = 0;
850         encoder->private_->seek_callback = 0;
851         encoder->private_->tell_callback = 0;
852         encoder->private_->metadata_callback = 0;
853         encoder->private_->progress_callback = 0;
854         encoder->private_->client_data = 0;
855
856         encoder->private_->seek_table = 0;
857
858         OggFLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect);
859 }
860
861 FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *super, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
862 {
863         OggFLAC__StreamEncoder *encoder = (OggFLAC__StreamEncoder*)super;
864         FLAC__StreamEncoderWriteStatus status;
865         FLAC__uint64 output_position;
866
867         (void)client_data; /* silence compiler warning about unused parameter */
868
869         /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
870         if(encoder->private_->tell_callback && encoder->private_->tell_callback((FLAC__StreamEncoder*)encoder, &output_position, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) {
871                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_CLIENT_ERROR;
872                 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
873         }
874
875         /*
876          * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets.
877          */
878         if(samples == 0) {
879                 FLAC__MetadataType type = (buffer[0] & 0x7f);
880                 if(type == FLAC__METADATA_TYPE_STREAMINFO)
881                         encoder->protected_->streaminfo_offset = output_position;
882                 else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0)
883                         encoder->protected_->seektable_offset = output_position;
884         }
885
886         /*
887          * Mark the current seek point if hit (if audio_offset == 0 that
888          * means we're still writing metadata and haven't hit the first
889          * frame yet)
890          */
891         if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) {
892                 const unsigned blocksize = FLAC__stream_encoder_get_blocksize((FLAC__StreamEncoder*)encoder);
893                 const FLAC__uint64 frame_first_sample = encoder->private_->samples_written;
894                 const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
895                 FLAC__uint64 test_sample;
896                 unsigned i;
897                 for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) {
898                         test_sample = encoder->private_->seek_table->points[i].sample_number;
899                         if(test_sample > frame_last_sample) {
900                                 break;
901                         }
902                         else if(test_sample >= frame_first_sample) {
903                                 encoder->private_->seek_table->points[i].sample_number = frame_first_sample;
904                                 encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset;
905                                 encoder->private_->seek_table->points[i].frame_samples = blocksize;
906                                 encoder->private_->first_seekpoint_to_check++;
907                                 /* DO NOT: "break;" and here's why:
908                                  * The seektable template may contain more than one target
909                                  * sample for any given frame; we will keep looping, generating
910                                  * duplicate seekpoints for them, and we'll clean it up later,
911                                  * just before writing the seektable back to the metadata.
912                                  */
913                         }
914                         else {
915                                 encoder->private_->first_seekpoint_to_check++;
916                         }
917                 }
918         }
919
920         status = OggFLAC__ogg_encoder_aspect_write_callback_wrapper(&encoder->protected_->ogg_encoder_aspect, FLAC__stream_encoder_get_total_samples_estimate((FLAC__StreamEncoder*)encoder), buffer, bytes, samples, current_frame, (OggFLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback, encoder, encoder->private_->client_data);
921
922         if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
923                 encoder->private_->samples_written += samples;
924         else
925                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_CLIENT_ERROR;
926
927         return status;
928 }
929
930 void metadata_callback_(const FLAC__StreamEncoder *super, const FLAC__StreamMetadata *metadata, void *client_data)
931 {
932         OggFLAC__StreamEncoder *encoder = (OggFLAC__StreamEncoder*)super;
933         FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
934         const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
935         const unsigned min_framesize = metadata->data.stream_info.min_framesize;
936         const unsigned max_framesize = metadata->data.stream_info.max_framesize;
937         ogg_page page;
938
939         FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
940
941         /* We get called by the stream encoder when the encoding process
942          * has finished so that we can update the STREAMINFO and SEEKTABLE
943          * blocks.
944          */
945
946         (void)client_data; /* silence compiler warning about unused parameter */
947
948         /* All this is based on intimate knowledge of the stream header
949          * layout, but a change to the header format that would break this
950          * would also break all streams encoded in the previous format.
951          */
952
953         /**
954          ** Write STREAMINFO stats
955          **/
956         simple_ogg_page__init(&page);
957         if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
958                 simple_ogg_page__clear(&page);
959                 return; /* state already set */
960         }
961
962         /*
963          * Write MD5 signature
964          */
965         {
966                 const unsigned md5_offset =
967                         FLAC__STREAM_METADATA_HEADER_LENGTH +
968                         (
969                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
970                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
971                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
972                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
973                                 FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
974                                 FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
975                                 FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
976                                 FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
977                         ) / 8;
978
979                 if(md5_offset + 16 > (unsigned)page.body_len) {
980                         encoder->protected_->state = OggFLAC__STREAM_ENCODER_OGG_ERROR;
981                         simple_ogg_page__clear(&page);
982                         return;
983                 }
984                 memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16);
985         }
986
987         /*
988          * Write total samples
989          */
990         {
991                 const unsigned total_samples_byte_offset =
992                         FLAC__STREAM_METADATA_HEADER_LENGTH +
993                         (
994                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
995                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
996                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
997                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
998                                 FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
999                                 FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
1000                                 FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
1001                                 - 4
1002                         ) / 8;
1003
1004                 if(total_samples_byte_offset + 5 > (unsigned)page.body_len) {
1005                         encoder->protected_->state = OggFLAC__STREAM_ENCODER_OGG_ERROR;
1006                         simple_ogg_page__clear(&page);
1007                         return;
1008                 }
1009                 b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0;
1010                 b[0] |= (FLAC__byte)((samples >> 32) & 0x0F);
1011                 b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
1012                 b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
1013                 b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
1014                 b[4] = (FLAC__byte)(samples & 0xFF);
1015                 memcpy(page.body + total_samples_byte_offset, b, 5);
1016         }
1017
1018         /*
1019          * Write min/max framesize
1020          */
1021         {
1022                 const unsigned min_framesize_offset =
1023                         FLAC__STREAM_METADATA_HEADER_LENGTH +
1024                         (
1025                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
1026                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
1027                         ) / 8;
1028
1029                 if(min_framesize_offset + 6 > (unsigned)page.body_len) {
1030                         encoder->protected_->state = OggFLAC__STREAM_ENCODER_OGG_ERROR;
1031                         simple_ogg_page__clear(&page);
1032                         return;
1033                 }
1034                 b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
1035                 b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
1036                 b[2] = (FLAC__byte)(min_framesize & 0xFF);
1037                 b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
1038                 b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
1039                 b[5] = (FLAC__byte)(max_framesize & 0xFF);
1040                 memcpy(page.body + min_framesize_offset, b, 6);
1041         }
1042         if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
1043                 simple_ogg_page__clear(&page);
1044                 return; /* state already set */
1045         }
1046         simple_ogg_page__clear(&page);
1047
1048         /*
1049          * Write seektable
1050          */
1051         if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
1052                 unsigned i;
1053                 FLAC__byte *p;
1054
1055                 FLAC__format_seektable_sort(encoder->private_->seek_table);
1056
1057                 FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
1058
1059                 simple_ogg_page__init(&page);
1060                 if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
1061                         simple_ogg_page__clear(&page);
1062                         return; /* state already set */
1063                 }
1064
1065                 if(FLAC__STREAM_METADATA_HEADER_LENGTH + (18*encoder->private_->seek_table->num_points) > (unsigned)page.body_len) {
1066                         encoder->protected_->state = OggFLAC__STREAM_ENCODER_OGG_ERROR;
1067                         simple_ogg_page__clear(&page);
1068                         return;
1069                 }
1070
1071                 for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) {
1072                         FLAC__uint64 xx;
1073                         unsigned x;
1074                         xx = encoder->private_->seek_table->points[i].sample_number;
1075                         b[7] = (FLAC__byte)xx; xx >>= 8;
1076                         b[6] = (FLAC__byte)xx; xx >>= 8;
1077                         b[5] = (FLAC__byte)xx; xx >>= 8;
1078                         b[4] = (FLAC__byte)xx; xx >>= 8;
1079                         b[3] = (FLAC__byte)xx; xx >>= 8;
1080                         b[2] = (FLAC__byte)xx; xx >>= 8;
1081                         b[1] = (FLAC__byte)xx; xx >>= 8;
1082                         b[0] = (FLAC__byte)xx; xx >>= 8;
1083                         xx = encoder->private_->seek_table->points[i].stream_offset;
1084                         b[15] = (FLAC__byte)xx; xx >>= 8;
1085                         b[14] = (FLAC__byte)xx; xx >>= 8;
1086                         b[13] = (FLAC__byte)xx; xx >>= 8;
1087                         b[12] = (FLAC__byte)xx; xx >>= 8;
1088                         b[11] = (FLAC__byte)xx; xx >>= 8;
1089                         b[10] = (FLAC__byte)xx; xx >>= 8;
1090                         b[9] = (FLAC__byte)xx; xx >>= 8;
1091                         b[8] = (FLAC__byte)xx; xx >>= 8;
1092                         x = encoder->private_->seek_table->points[i].frame_samples;
1093                         b[17] = (FLAC__byte)x; x >>= 8;
1094                         b[16] = (FLAC__byte)x; x >>= 8;
1095                         if(encoder->private_->write_callback((FLAC__StreamEncoder*)encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
1096                                 encoder->protected_->state = OggFLAC__STREAM_ENCODER_CLIENT_ERROR;
1097                                 simple_ogg_page__clear(&page);
1098                                 return;
1099                         }
1100                         memcpy(p, b, 18);
1101                 }
1102
1103                 if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
1104                         simple_ogg_page__clear(&page);
1105                         return; /* state already set */
1106                 }
1107                 simple_ogg_page__clear(&page);
1108         }
1109
1110         if(encoder->private_->metadata_callback)
1111                 encoder->private_->metadata_callback((FLAC__StreamEncoder*)encoder, metadata, client_data);
1112 }
1113
1114 OggFLAC__StreamEncoderReadStatus file_read_callback_(const OggFLAC__StreamEncoder *encoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
1115 {
1116         (void)client_data;
1117
1118         *bytes = (unsigned)fread(buffer, 1, *bytes, encoder->private_->file);
1119         if (*bytes == 0) {
1120                 if (feof(encoder->private_->file))
1121                         return OggFLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
1122                 else if (ferror(encoder->private_->file))
1123                         return OggFLAC__STREAM_ENCODER_READ_STATUS_ABORT;
1124         }
1125         return OggFLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
1126 }
1127
1128 FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *super, FLAC__uint64 absolute_byte_offset, void *client_data)
1129 {
1130         OggFLAC__StreamEncoder *encoder = (OggFLAC__StreamEncoder*)super;
1131
1132         (void)client_data;
1133
1134         if(fseeko(encoder->private_->file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
1135                 return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
1136         else
1137                 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
1138 }
1139
1140 FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *super, FLAC__uint64 *absolute_byte_offset, void *client_data)
1141 {
1142         OggFLAC__StreamEncoder *encoder = (OggFLAC__StreamEncoder*)super;
1143         off_t offset;
1144
1145         (void)client_data;
1146
1147         offset = ftello(encoder->private_->file);
1148
1149         if(offset < 0) {
1150                 return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
1151         }
1152         else {
1153                 *absolute_byte_offset = (FLAC__uint64)offset;
1154                 return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
1155         }
1156 }
1157
1158 #ifdef FLAC__VALGRIND_TESTING
1159 static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
1160 {
1161         size_t ret = fwrite(ptr, size, nmemb, stream);
1162         if(!ferror(stream))
1163                 fflush(stream);
1164         return ret;
1165 }
1166 #else
1167 #define local__fwrite fwrite
1168 #endif
1169
1170 FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *super, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
1171 {
1172         OggFLAC__StreamEncoder *encoder = (OggFLAC__StreamEncoder*)super;
1173
1174         (void)client_data;
1175
1176         if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, encoder->private_->file) == bytes) {
1177                 encoder->private_->bytes_written += bytes;
1178                 encoder->private_->samples_written += samples;
1179                 /* we keep a high watermark on the number of frames written because
1180                  * when the encoder goes back to write metadata, 'current_frame'
1181                  * will drop back to 0.
1182                  */
1183                 encoder->private_->frames_written = max(encoder->private_->frames_written, current_frame+1);
1184                 /*@@@ We would like to add an '&& samples > 0' to the if
1185                  * clause here but currently because of the nature of our Ogg
1186                  * writing implementation, 'samples' is always 0 (see
1187                  * ogg_encoder_aspect.c).  The downside is extra progress
1188                  * callbacks.
1189                  */
1190                 if(0 != encoder->private_->progress_callback /*@@@ && samples > 0 */)
1191                         encoder->private_->progress_callback((FLAC__StreamEncoder*)encoder, encoder->private_->bytes_written, encoder->private_->samples_written, encoder->private_->frames_written, encoder->private_->total_frames_estimate, encoder->private_->client_data);
1192                 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
1193         }
1194         else
1195                 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
1196 }
1197
1198 /*
1199  * This will forcibly set stdout to binary mode (for OSes that require it)
1200  */
1201 FILE *get_binary_stdout_()
1202 {
1203         /* if something breaks here it is probably due to the presence or
1204          * absence of an underscore before the identifiers 'setmode',
1205          * 'fileno', and/or 'O_BINARY'; check your system header files.
1206          */
1207 #if defined _MSC_VER || defined __MINGW32__
1208         _setmode(_fileno(stdout), _O_BINARY);
1209 #elif defined __CYGWIN__
1210         /* almost certainly not needed for any modern Cygwin, but let's be safe... */
1211         setmode(_fileno(stdout), _O_BINARY);
1212 #elif defined __EMX__
1213         setmode(fileno(stdout), O_BINARY);
1214 #endif
1215
1216         return stdout;
1217 }