minor formatting
[flac.git] / src / libFLAC / metadata_iterators.c
1 /* libFLAC - Free Lossless Audio Codec library
2  * Copyright (C) 2001,2002,2003  Josh Coalson
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA  02111-1307, USA.
18  */
19
20 #if !defined _MSC_VER && !defined __MINGW32__
21 /*@@@ don't know how to resolve errno without using LIBC.LIB; must use MSVCRT.LIB only for plugins */
22 #include <errno.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #if defined _MSC_VER || defined __MINGW32__
29 #include <sys/utime.h> /* for utime() */
30 #include <io.h> /* for chmod() */
31 #else
32 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
33 #include <utime.h> /* for utime() */
34 #include <unistd.h> /* for chown(), unlink() */
35 #endif
36 #include <sys/stat.h> /* for stat(), maybe chmod() */
37
38 #include "private/metadata.h"
39
40 #include "FLAC/assert.h"
41 #include "FLAC/file_decoder.h"
42
43 #ifdef max
44 #undef max
45 #endif
46 #define max(a,b) ((a)>(b)?(a):(b))
47 #ifdef min
48 #undef min
49 #endif
50 #define min(a,b) ((a)<(b)?(a):(b))
51
52
53 /****************************************************************************
54  *
55  * Local function declarations
56  *
57  ***************************************************************************/
58
59 static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
60 static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
61 static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes);
62 static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes);
63 static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes);
64 static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes);
65
66 static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
67 static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
68 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_(FILE *file, FLAC__StreamMetadata_StreamInfo *block);
69 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_(FILE *file, FLAC__StreamMetadata_Padding *block, unsigned block_length);
70 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_(FILE *file, FLAC__StreamMetadata_Application *block, unsigned block_length);
71 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_(FILE *file, FLAC__StreamMetadata_SeekTable *block, unsigned block_length);
72 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_(FILE *file, FLAC__StreamMetadata_VorbisComment_Entry *entry);
73 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_(FILE *file, FLAC__StreamMetadata_VorbisComment *block);
74 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_(FILE *file, FLAC__StreamMetadata_CueSheet_Track *track);
75 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_(FILE *file, FLAC__StreamMetadata_CueSheet *block);
76 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_(FILE *file, FLAC__StreamMetadata_Unknown *block, unsigned block_length);
77
78 static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
79 static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
80 static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_streaminfo_(FILE *file, const FLAC__StreamMetadata_StreamInfo *block);
81 static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_padding_(FILE *file, const FLAC__StreamMetadata_Padding *block, unsigned block_length);
82 static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_application_(FILE *file, const FLAC__StreamMetadata_Application *block, unsigned block_length);
83 static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_seektable_(FILE *file, const FLAC__StreamMetadata_SeekTable *block);
84 static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_vorbis_comment_(FILE *file, const FLAC__StreamMetadata_VorbisComment *block);
85 static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_cuesheet_(FILE *file, const FLAC__StreamMetadata_CueSheet *block);
86 static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_unknown_(FILE *file, const FLAC__StreamMetadata_Unknown *block, unsigned block_length);
87 static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
88 static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last);
89 static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
90
91 static FLAC__bool chain_rewrite_chain_(FLAC__Metadata_Chain *chain);
92 static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix);
93
94 static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
95 static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
96
97 /* return 0 if OK, 1 if read error, 2 if not a FLAC file */
98 static unsigned seek_to_first_metadata_block_(FILE *f);
99
100 static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
101 static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, long fixup_is_last_flag_offset, FLAC__bool backup);
102
103 static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status);
104 static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status);
105
106 static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
107 static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
108 static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
109
110 static FLAC__bool get_file_stats_(const char *filename, struct stat *stats);
111 static void set_file_stats_(const char *filename, struct stat *stats);
112
113 static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
114
115
116 #ifdef FLAC__VALGRIND_TESTING
117 static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
118 {
119         size_t ret = fwrite(ptr, size, nmemb, stream);
120         if(!ferror(stream))
121                 fflush(stream);
122         return ret;
123 }
124 #else
125 #define local__fwrite fwrite
126 #endif
127
128 /****************************************************************************
129  *
130  * Level 0 implementation
131  *
132  ***************************************************************************/
133
134 static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
135 static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
136 static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
137
138 typedef struct {
139         FLAC__bool got_error;
140         FLAC__bool got_streaminfo;
141         FLAC__StreamMetadata *streaminfo;
142 } level0_client_data;
143
144 FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
145 {
146         level0_client_data cd;
147         FLAC__FileDecoder *decoder;
148
149         FLAC__ASSERT(0 != filename);
150         FLAC__ASSERT(0 != streaminfo);
151
152         decoder = FLAC__file_decoder_new();
153
154         if(0 == decoder)
155                 return false;
156
157         cd.got_error = false;
158         cd.got_streaminfo = false;
159         cd.streaminfo = streaminfo;
160
161         FLAC__file_decoder_set_md5_checking(decoder, false);
162         FLAC__file_decoder_set_filename(decoder, filename);
163         FLAC__file_decoder_set_metadata_ignore_all(decoder);
164         FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
165         FLAC__file_decoder_set_write_callback(decoder, write_callback_);
166         FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
167         FLAC__file_decoder_set_error_callback(decoder, error_callback_);
168         FLAC__file_decoder_set_client_data(decoder, &cd);
169
170         if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK || cd.got_error) {
171                 FLAC__file_decoder_finish(decoder);
172                 FLAC__file_decoder_delete(decoder);
173                 return false;
174         }
175
176         /* the first thing decoded must be the STREAMINFO block: */
177         if(!FLAC__file_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
178                 FLAC__file_decoder_finish(decoder);
179                 FLAC__file_decoder_delete(decoder);
180                 return false;
181         }
182
183         FLAC__file_decoder_finish(decoder);
184         FLAC__file_decoder_delete(decoder);
185
186         return !cd.got_error && cd.got_streaminfo;
187 }
188
189 FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
190 {
191         (void)decoder, (void)frame, (void)buffer, (void)client_data;
192
193         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
194 }
195
196 void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
197 {
198         level0_client_data *cd = (level0_client_data *)client_data;
199         (void)decoder;
200
201         if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && 0 != cd->streaminfo) {
202                 *(cd->streaminfo) = *metadata;
203                 cd->got_streaminfo = true;
204         }
205 }
206
207 void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
208 {
209         level0_client_data *cd = (level0_client_data *)client_data;
210         (void)decoder;
211
212         if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
213                 cd->got_error = true;
214 }
215
216
217 /****************************************************************************
218  *
219  * Level 1 implementation
220  *
221  ***************************************************************************/
222
223 #define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
224 /* 1 for initial offset, +4 for our own personal use */
225
226 struct FLAC__Metadata_SimpleIterator {
227         FILE *file;
228         char *filename, *tempfile_path_prefix;
229         struct stat stats;
230         FLAC__bool has_stats;
231         FLAC__bool is_writable;
232         FLAC__Metadata_SimpleIteratorStatus status;
233         /*@@@ 2G limits here because of the offset type: */
234         long offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
235         long first_offset; /* this is the offset to the STREAMINFO block */
236         unsigned depth;
237         /* this is the metadata block header of the current block we are pointing to: */
238         FLAC__bool is_last;
239         FLAC__MetadataType type;
240         unsigned length;
241 };
242
243 FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
244         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
245         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
246         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
247         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
248         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
249         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
250         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
251         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
252         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
253         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
254         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
255         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
256         "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
257 };
258
259
260 FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new()
261 {
262         FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
263
264         if(0 != iterator) {
265                 iterator->file = 0;
266                 iterator->filename = 0;
267                 iterator->tempfile_path_prefix = 0;
268                 iterator->has_stats = false;
269                 iterator->is_writable = false;
270                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
271                 iterator->first_offset = iterator->offset[0] = -1;
272                 iterator->depth = 0;
273         }
274
275         return iterator;
276 }
277
278 static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
279 {
280         FLAC__ASSERT(0 != iterator);
281
282         if(0 != iterator->file) {
283                 fclose(iterator->file);
284                 iterator->file = 0;
285                 if(iterator->has_stats)
286                         set_file_stats_(iterator->filename, &iterator->stats);
287         }
288         if(0 != iterator->filename) {
289                 free(iterator->filename);
290                 iterator->filename = 0;
291         }
292         if(0 != iterator->tempfile_path_prefix) {
293                 free(iterator->tempfile_path_prefix);
294                 iterator->tempfile_path_prefix = 0;
295         }
296 }
297
298 FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
299 {
300         FLAC__ASSERT(0 != iterator);
301
302         simple_iterator_free_guts_(iterator);
303         free(iterator);
304 }
305
306 FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
307 {
308         FLAC__Metadata_SimpleIteratorStatus status;
309
310         FLAC__ASSERT(0 != iterator);
311
312         status = iterator->status;
313         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
314         return status;
315 }
316
317 static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
318 {
319         unsigned ret;
320
321         FLAC__ASSERT(0 != iterator);
322
323         if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) {
324                 iterator->is_writable = false;
325 #if !defined _MSC_VER && !defined __MINGW32__
326 /*@@@ don't know how to resolve errno without using LIBC.LIB; must use MSVCRT.LIB only for plugins */
327                 if(read_only || errno == EACCES) {
328 #endif
329                         if(0 == (iterator->file = fopen(iterator->filename, "rb"))) {
330                                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
331                                 return false;
332                         }
333 #if !defined _MSC_VER && !defined __MINGW32__
334                 }
335                 else {
336                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
337                         return false;
338                 }
339 #endif
340         }
341         else {
342                 iterator->is_writable = true;
343         }
344
345         ret = seek_to_first_metadata_block_(iterator->file);
346         switch(ret) {
347                 case 0:
348                         iterator->depth = 0;
349                         iterator->first_offset = iterator->offset[iterator->depth] = ftell(iterator->file);
350                         return read_metadata_block_header_(iterator);
351                 case 1:
352                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
353                         return false;
354                 case 2:
355                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
356                         return false;
357                 default:
358                         FLAC__ASSERT(0);
359                         return false;
360         }
361 }
362
363 #if 0
364 @@@ If we decide to finish implementing this, put this comment back in metadata.h
365 /*
366  * The 'tempfile_path_prefix' allows you to specify a directory where
367  * tempfiles should go.  Remember that if your metadata edits cause the
368  * FLAC file to grow, the entire file will have to be rewritten.  If
369  * 'tempfile_path_prefix' is NULL, the temp file will be written in the
370  * same directory as the original FLAC file.  This makes replacing the
371  * original with the tempfile fast but requires extra space in the same
372  * partition for the tempfile.  If space is a problem, you can pass a
373  * directory name belonging to a different partition in
374  * 'tempfile_path_prefix'.  Note that you should use the forward slash
375  * '/' as the directory separator.  A trailing slash is not needed; it
376  * will be added automatically.
377  */
378 FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix);
379 #endif
380
381 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
382 {
383         const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'rename(...)' for what it will take to finish implementing this */
384
385         FLAC__ASSERT(0 != iterator);
386         FLAC__ASSERT(0 != filename);
387
388         simple_iterator_free_guts_(iterator);
389
390         if(!read_only && preserve_file_stats)
391                 iterator->has_stats = get_file_stats_(filename, &iterator->stats);
392
393         if(0 == (iterator->filename = strdup(filename))) {
394                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
395                 return false;
396         }
397         if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
398                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
399                 return false;
400         }
401
402         return simple_iterator_prime_input_(iterator, read_only);
403 }
404
405 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
406 {
407         FLAC__ASSERT(0 != iterator);
408         FLAC__ASSERT(0 != iterator->file);
409
410         return iterator->is_writable;
411 }
412
413 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
414 {
415         FLAC__ASSERT(0 != iterator);
416         FLAC__ASSERT(0 != iterator->file);
417
418         if(iterator->is_last)
419                 return false;
420
421         if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) {
422                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
423                 return false;
424         }
425
426         iterator->offset[iterator->depth] = ftell(iterator->file);
427
428         return read_metadata_block_header_(iterator);
429 }
430
431 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
432 {
433         long this_offset;
434
435         FLAC__ASSERT(0 != iterator);
436         FLAC__ASSERT(0 != iterator->file);
437
438         if(iterator->offset[iterator->depth] == iterator->first_offset)
439                 return false;
440
441         if(0 != fseek(iterator->file, iterator->first_offset, SEEK_SET)) {
442                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
443                 return false;
444         }
445         this_offset = iterator->first_offset;
446         if(!read_metadata_block_header_(iterator))
447                 return false;
448
449         /* we ignore any error from ftell() and catch it in fseek() */
450         while(ftell(iterator->file) + (long)iterator->length < iterator->offset[iterator->depth]) {
451                 if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) {
452                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
453                         return false;
454                 }
455                 this_offset = ftell(iterator->file);
456                 if(!read_metadata_block_header_(iterator))
457                         return false;
458         }
459
460         iterator->offset[iterator->depth] = this_offset;
461
462         return true;
463 }
464
465 FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
466 {
467         FLAC__ASSERT(0 != iterator);
468         FLAC__ASSERT(0 != iterator->file);
469
470         return iterator->type;
471 }
472
473 FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator)
474 {
475         FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
476
477         FLAC__ASSERT(0 != iterator);
478         FLAC__ASSERT(0 != iterator->file);
479
480         if(0 != block) {
481                 block->is_last = iterator->is_last;
482                 block->length = iterator->length;
483
484                 if(!read_metadata_block_data_(iterator, block)) {
485                         FLAC__metadata_object_delete(block);
486                         return 0;
487                 }
488
489                 /* back up to the beginning of the block data to stay consistent */
490                 if(0 != fseek(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) {
491                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
492                         FLAC__metadata_object_delete(block);
493                         return 0;
494                 }
495         }
496         else
497                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
498
499         return block;
500 }
501
502 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
503 {
504         FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth];)
505         FLAC__bool ret;
506
507         FLAC__ASSERT(0 != iterator);
508         FLAC__ASSERT(0 != iterator->file);
509         FLAC__ASSERT(0 != block);
510
511         if(!iterator->is_writable) {
512                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
513                 return false;
514         }
515
516         if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
517                 if(iterator->type != block->type) {
518                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
519                         return false;
520                 }
521         }
522
523         block->is_last = iterator->is_last;
524
525         if(iterator->length == block->length)
526                 return write_metadata_block_stationary_(iterator, block);
527         else if(iterator->length > block->length) {
528                 if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
529                         ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
530                         FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
531                         FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
532                         return ret;
533                 }
534                 else {
535                         ret = rewrite_whole_file_(iterator, block, /*append=*/false);
536                         FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
537                         FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
538                         return ret;
539                 }
540         }
541         else /* iterator->length < block->length */ {
542                 unsigned padding_leftover = 0;
543                 FLAC__bool padding_is_last = false;
544                 if(use_padding) {
545                         /* first see if we can even use padding */
546                         if(iterator->is_last) {
547                                 use_padding = false;
548                         }
549                         else {
550                                 const unsigned extra_padding_bytes_required = block->length - iterator->length;
551                                 simple_iterator_push_(iterator);
552                                 if(!FLAC__metadata_simple_iterator_next(iterator)) {
553                                         (void)simple_iterator_pop_(iterator);
554                                         return false;
555                                 }
556                                 if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
557                                         use_padding = false;
558                                 }
559                                 else {
560                                         if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
561                                                 padding_leftover = 0;
562                                                 block->is_last = iterator->is_last;
563                                         }
564                                         else if(iterator->length < extra_padding_bytes_required)
565                                                 use_padding = false;
566                                         else {
567                                                 padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
568                                                 padding_is_last = iterator->is_last;
569                                                 block->is_last = false;
570                                         }
571                                 }
572                                 if(!simple_iterator_pop_(iterator))
573                                         return false;
574                         }
575                 }
576                 if(use_padding) {
577                         if(padding_leftover == 0) {
578                                 ret = write_metadata_block_stationary_(iterator, block);
579                                 FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
580                                 FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
581                                 return ret;
582                         }
583                         else {
584                                 FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
585                                 ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
586                                 FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
587                                 FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
588                                 return ret;
589                         }
590                 }
591                 else {
592                         ret = rewrite_whole_file_(iterator, block, /*append=*/false);
593                         FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
594                         FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
595                         return ret;
596                 }
597         }
598 }
599
600 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
601 {
602         unsigned padding_leftover = 0;
603         FLAC__bool padding_is_last = false;
604
605         FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;)
606         FLAC__bool ret;
607
608         FLAC__ASSERT(0 != iterator);
609         FLAC__ASSERT(0 != iterator->file);
610         FLAC__ASSERT(0 != block);
611
612         if(!iterator->is_writable)
613                 return false;
614
615         if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
616                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
617                 return false;
618         }
619
620         block->is_last = iterator->is_last;
621
622         if(use_padding) {
623                 /* first see if we can even use padding */
624                 if(iterator->is_last) {
625                         use_padding = false;
626                 }
627                 else {
628                         simple_iterator_push_(iterator);
629                         if(!FLAC__metadata_simple_iterator_next(iterator)) {
630                                 (void)simple_iterator_pop_(iterator);
631                                 return false;
632                         }
633                         if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
634                                 use_padding = false;
635                         }
636                         else {
637                                 if(iterator->length == block->length) {
638                                         padding_leftover = 0;
639                                         block->is_last = iterator->is_last;
640                                 }
641                                 else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
642                                         use_padding = false;
643                                 else {
644                                         padding_leftover = iterator->length - block->length;
645                                         padding_is_last = iterator->is_last;
646                                         block->is_last = false;
647                                 }
648                         }
649                         if(!simple_iterator_pop_(iterator))
650                                 return false;
651                 }
652         }
653         if(use_padding) {
654                 /* move to the next block, which is suitable padding */
655                 if(!FLAC__metadata_simple_iterator_next(iterator))
656                         return false;
657                 if(padding_leftover == 0) {
658                         ret = write_metadata_block_stationary_(iterator, block);
659                         FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
660                         FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
661                         return ret;
662                 }
663                 else {
664                         FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
665                         ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
666                         FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
667                         FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
668                         return ret;
669                 }
670         }
671         else {
672                 ret = rewrite_whole_file_(iterator, block, /*append=*/true);
673                 FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
674                 FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
675                 return ret;
676         }
677 }
678
679 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
680 {
681         FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth];)
682         FLAC__bool ret;
683
684         if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
685                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
686                 return false;
687         }
688
689         if(use_padding) {
690                 FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
691                 if(0 == padding) {
692                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
693                         return false;
694                 }
695                 padding->length = iterator->length;
696                 if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
697                         FLAC__metadata_object_delete(padding);
698                         return false;
699                 }
700                 FLAC__metadata_object_delete(padding);
701                 if(!FLAC__metadata_simple_iterator_prev(iterator))
702                         return false;
703                 FLAC__ASSERT(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length == debug_target_offset);
704                 FLAC__ASSERT(ftell(iterator->file) + (long)iterator->length == debug_target_offset);
705                 return true;
706         }
707         else {
708                 ret = rewrite_whole_file_(iterator, 0, /*append=*/false);
709                 FLAC__ASSERT(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length == debug_target_offset);
710                 FLAC__ASSERT(ftell(iterator->file) + (long)iterator->length == debug_target_offset);
711                 return ret;
712         }
713 }
714
715
716
717 /****************************************************************************
718  *
719  * Level 2 implementation
720  *
721  ***************************************************************************/
722
723
724 typedef struct FLAC__Metadata_Node {
725         FLAC__StreamMetadata *data;
726         struct FLAC__Metadata_Node *prev, *next;
727 } FLAC__Metadata_Node;
728
729 struct FLAC__Metadata_Chain {
730         char *filename;
731         FLAC__Metadata_Node *head;
732         FLAC__Metadata_Node *tail;
733         unsigned nodes;
734         FLAC__Metadata_ChainStatus status;
735         long first_offset, last_offset; /*@@@ 2G limit */
736         /*
737          * This is the length of the chain initially read from the FLAC file.
738          * it is used to compare against the current length to decide whether
739          * or not the whole file has to be rewritten.
740          */
741         unsigned initial_length; /*@@@ 4G limit */
742 };
743
744 struct FLAC__Metadata_Iterator {
745         FLAC__Metadata_Chain *chain;
746         FLAC__Metadata_Node *current;
747 };
748
749 FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
750         "FLAC__METADATA_CHAIN_STATUS_OK",
751         "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
752         "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
753         "FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
754         "FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
755         "FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
756         "FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
757         "FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
758         "FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
759         "FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
760         "FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
761         "FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
762         "FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR"
763 };
764
765
766 static FLAC__Metadata_Node *node_new_()
767 {
768         return (FLAC__Metadata_Node*)calloc(1, sizeof(FLAC__Metadata_Node));
769 }
770
771 static void node_delete_(FLAC__Metadata_Node *node)
772 {
773         FLAC__ASSERT(0 != node);
774         if(0 != node->data)
775                 FLAC__metadata_object_delete(node->data);
776         free(node);
777 }
778
779 static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
780 {
781         FLAC__ASSERT(0 != chain);
782         FLAC__ASSERT(0 != node);
783         FLAC__ASSERT(0 != node->data);
784
785         node->next = node->prev = 0;
786         node->data->is_last = true;
787         if(0 != chain->tail)
788                 chain->tail->data->is_last = false;
789
790         if(0 == chain->head)
791                 chain->head = node;
792         else {
793                 FLAC__ASSERT(0 != chain->tail);
794                 chain->tail->next = node;
795                 node->prev = chain->tail;
796         }
797         chain->tail = node;
798         chain->nodes++;
799 }
800
801 static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
802 {
803         FLAC__ASSERT(0 != chain);
804         FLAC__ASSERT(0 != node);
805
806         if(node == chain->head)
807                 chain->head = node->next;
808         else
809                 node->prev->next = node->next;
810
811         if(node == chain->tail)
812                 chain->tail = node->prev;
813         else
814                 node->next->prev = node->prev;
815
816         if(0 != chain->tail)
817                 chain->tail->data->is_last = true;
818
819         chain->nodes--;
820 }
821
822 static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
823 {
824         chain_remove_node_(chain, node);
825         node_delete_(node);
826 }
827
828 static unsigned chain_calculate_length_(FLAC__Metadata_Chain *chain)
829 {
830         const FLAC__Metadata_Node *node;
831         unsigned length = 0;
832         for(node = chain->head; node; node = node->next)
833                 length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
834         return length;
835 }
836
837 static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
838 {
839         FLAC__ASSERT(0 != node);
840         FLAC__ASSERT(0 != node->data);
841         FLAC__ASSERT(0 != iterator);
842         FLAC__ASSERT(0 != iterator->current);
843         FLAC__ASSERT(0 != iterator->chain);
844         FLAC__ASSERT(0 != iterator->chain->head);
845         FLAC__ASSERT(0 != iterator->chain->tail);
846
847         node->data->is_last = false;
848
849         node->prev = iterator->current->prev;
850         node->next = iterator->current;
851
852         if(0 == node->prev)
853                 iterator->chain->head = node;
854         else
855                 node->prev->next = node;
856
857         iterator->current->prev = node;
858
859         iterator->chain->nodes++;
860 }
861
862 static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
863 {
864         FLAC__ASSERT(0 != node);
865         FLAC__ASSERT(0 != node->data);
866         FLAC__ASSERT(0 != iterator);
867         FLAC__ASSERT(0 != iterator->current);
868         FLAC__ASSERT(0 != iterator->chain);
869         FLAC__ASSERT(0 != iterator->chain->head);
870         FLAC__ASSERT(0 != iterator->chain->tail);
871
872         iterator->current->data->is_last = false;
873
874         node->prev = iterator->current;
875         node->next = iterator->current->next;
876
877         if(0 == node->next)
878                 iterator->chain->tail = node;
879         else
880                 node->next->prev = node;
881
882         node->prev->next = node;
883
884         iterator->chain->tail->data->is_last = true;
885
886         iterator->chain->nodes++;
887 }
888
889 /* return true iff node and node->next are both padding */
890 static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
891 {
892         if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
893                 const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
894                 node->data->length += growth;
895
896                 chain_delete_node_(chain, node->next);
897                 return true;
898         }
899         else
900                 return false;
901 }
902
903 FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new()
904 {
905         FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain));
906
907         if(0 != chain) {
908                 chain->filename = 0;
909                 chain->head = chain->tail = 0;
910                 chain->nodes = 0;
911                 chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
912                 chain->initial_length = 0;
913         }
914
915         return chain;
916 }
917
918 FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
919 {
920         FLAC__Metadata_Node *node, *next;
921
922         FLAC__ASSERT(0 != chain);
923
924         for(node = chain->head; node; ) {
925                 next = node->next;
926                 node_delete_(node);
927                 node = next;
928         }
929
930         if(0 != chain->filename)
931                 free(chain->filename);
932
933         free(chain);
934 }
935
936 FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
937 {
938         FLAC__Metadata_ChainStatus status;
939
940         FLAC__ASSERT(0 != chain);
941
942         status = chain->status;
943         chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
944         return status;
945 }
946
947 FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
948 {
949         FLAC__Metadata_SimpleIterator *iterator;
950         FLAC__Metadata_Node *node;
951
952         FLAC__ASSERT(0 != chain);
953         FLAC__ASSERT(0 != filename);
954
955         if(0 == (chain->filename = strdup(filename))) {
956                 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
957                 return false;
958         }
959
960         if(0 == (iterator = FLAC__metadata_simple_iterator_new())) {
961                 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
962                 return false;
963         }
964
965         if(!FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
966                 chain->status = get_equivalent_status_(iterator->status);
967                 return false;
968         }
969
970         chain->first_offset = iterator->offset[iterator->depth];
971
972         do {
973                 node = node_new_();
974                 if(0 == node) {
975                         chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
976                         return false;
977                 }
978                 node->data = FLAC__metadata_simple_iterator_get_block(iterator);
979                 if(0 == node->data) {
980                         node_delete_(node);
981                         chain->status = get_equivalent_status_(iterator->status);
982                         return false;
983                 }
984                 chain_append_node_(chain, node);
985         } while(FLAC__metadata_simple_iterator_next(iterator));
986
987         if(!iterator->is_last || iterator->status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) {
988                 chain->status = get_equivalent_status_(iterator->status);
989                 return false;
990         }
991
992         chain->last_offset = ftell(iterator->file) + iterator->length;
993         FLAC__metadata_simple_iterator_delete(iterator);
994
995         chain->initial_length = chain_calculate_length_(chain);
996         return true;
997 }
998
999 FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
1000 {
1001         struct stat stats;
1002         const char *tempfile_path_prefix = 0;
1003         unsigned current_length;
1004
1005         FLAC__ASSERT(0 != chain);
1006
1007         current_length = chain_calculate_length_(chain);
1008
1009         if(use_padding) {
1010                 if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
1011                         const unsigned delta = chain->initial_length - current_length;
1012                         chain->tail->data->length += delta;
1013                         current_length += delta;
1014                         FLAC__ASSERT(current_length == chain->initial_length);
1015                 }
1016                 else if(current_length + FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
1017                         FLAC__StreamMetadata *padding;
1018                         FLAC__Metadata_Node *node;
1019                         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) {
1020                                 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1021                                 return false;
1022                         }
1023                         padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length);
1024                         if(0 == (node = node_new_())) {
1025                                 FLAC__metadata_object_delete(padding);
1026                                 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1027                                 return false;
1028                         }
1029                         node->data = padding;
1030                         chain_append_node_(chain, node);
1031                         current_length = chain_calculate_length_(chain);
1032                         FLAC__ASSERT(current_length == chain->initial_length);
1033                 }
1034                 else if(current_length > chain->initial_length) {
1035                         const unsigned delta = current_length - chain->initial_length;
1036                         if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
1037                                 if(chain->tail->data->length + FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
1038                                         chain_delete_node_(chain, chain->tail);
1039                                         current_length = chain_calculate_length_(chain);
1040                                         FLAC__ASSERT(current_length == chain->initial_length);
1041                                 }
1042                                 else if(chain->tail->data->length >= delta) {
1043                                         chain->tail->data->length -= delta;
1044                                         current_length -= delta;
1045                                         FLAC__ASSERT(current_length == chain->initial_length);
1046                                 }
1047                         }
1048                 }
1049         }
1050
1051         if(preserve_file_stats)
1052                 get_file_stats_(chain->filename, &stats);
1053
1054         if(current_length == chain->initial_length) {
1055                 if(!chain_rewrite_chain_(chain))
1056                         return false;
1057         }
1058         else {
1059                 if(!chain_rewrite_file_(chain, tempfile_path_prefix))
1060                         return false;
1061         }
1062
1063         if(preserve_file_stats)
1064                 set_file_stats_(chain->filename, &stats);
1065
1066         /* recompute lengths and offsets if necessary */
1067         if(chain->initial_length != current_length) {
1068                 const FLAC__Metadata_Node *node;
1069                 chain->initial_length = current_length;
1070                 chain->last_offset = chain->first_offset;
1071                 for(node = chain->head; node; node = node->next)
1072                         chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
1073         }
1074
1075         return true;
1076 }
1077
1078 FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
1079 {
1080         FLAC__Metadata_Node *node;
1081
1082         FLAC__ASSERT(0 != chain);
1083
1084         for(node = chain->head; node; ) {
1085                 if(!chain_merge_adjacent_padding_(chain, node))
1086                         node = node->next;
1087         }
1088 }
1089
1090 FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
1091 {
1092         FLAC__Metadata_Node *node, *save;
1093         unsigned i;
1094
1095         FLAC__ASSERT(0 != chain);
1096
1097         /*
1098          * Don't try and be too smart... this simple algo is good enough for
1099          * the small number of nodes that we deal with.
1100          */
1101         for(i = 0, node = chain->head; i < chain->nodes; i++) {
1102                 if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
1103                         save = node->next;
1104                         chain_remove_node_(chain, node);
1105                         chain_append_node_(chain, node);
1106                         node = save;
1107                 }
1108                 else {
1109                         node = node->next;
1110                 }
1111         }
1112
1113         FLAC__metadata_chain_merge_padding(chain);
1114 }
1115
1116
1117 FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new()
1118 {
1119         FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator));
1120
1121         /* calloc() implies:
1122                 iterator->current = 0;
1123                 iterator->chain = 0;
1124         */
1125
1126         return iterator;
1127 }
1128
1129 FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
1130 {
1131         FLAC__ASSERT(0 != iterator);
1132
1133         free(iterator);
1134 }
1135
1136 FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
1137 {
1138         FLAC__ASSERT(0 != iterator);
1139         FLAC__ASSERT(0 != chain);
1140         FLAC__ASSERT(0 != chain->head);
1141
1142         iterator->chain = chain;
1143         iterator->current = chain->head;
1144 }
1145
1146 FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
1147 {
1148         FLAC__ASSERT(0 != iterator);
1149
1150         if(0 == iterator->current || 0 == iterator->current->next)
1151                 return false;
1152
1153         iterator->current = iterator->current->next;
1154         return true;
1155 }
1156
1157 FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
1158 {
1159         FLAC__ASSERT(0 != iterator);
1160
1161         if(0 == iterator->current || 0 == iterator->current->prev)
1162                 return false;
1163
1164         iterator->current = iterator->current->prev;
1165         return true;
1166 }
1167
1168 FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
1169 {
1170         FLAC__ASSERT(0 != iterator);
1171         FLAC__ASSERT(0 != iterator->current);
1172         FLAC__ASSERT(0 != iterator->current->data);
1173
1174         return iterator->current->data->type;
1175 }
1176
1177 FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
1178 {
1179         FLAC__ASSERT(0 != iterator);
1180         FLAC__ASSERT(0 != iterator->current);
1181
1182         return iterator->current->data;
1183 }
1184
1185 FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
1186 {
1187         FLAC__ASSERT(0 != iterator);
1188         FLAC__ASSERT(0 != block);
1189         return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
1190 }
1191
1192 FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
1193 {
1194         FLAC__Metadata_Node *save;
1195
1196         FLAC__ASSERT(0 != iterator);
1197         FLAC__ASSERT(0 != iterator->current);
1198
1199         if(0 == iterator->current->prev) {
1200                 FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
1201                 return false;
1202         }
1203
1204         save = iterator->current->prev;
1205
1206         if(replace_with_padding) {
1207                 FLAC__metadata_object_delete_data(iterator->current->data);
1208                 iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
1209         }
1210         else {
1211                 chain_delete_node_(iterator->chain, iterator->current);
1212         }
1213
1214         iterator->current = save;
1215         return true;
1216 }
1217
1218 FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
1219 {
1220         FLAC__Metadata_Node *node;
1221
1222         FLAC__ASSERT(0 != iterator);
1223         FLAC__ASSERT(0 != iterator->current);
1224         FLAC__ASSERT(0 != block);
1225
1226         if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
1227                 return false;
1228
1229         if(0 == iterator->current->prev) {
1230                 FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
1231                 return false;
1232         }
1233
1234         if(0 == (node = node_new_()))
1235                 return false;
1236
1237         node->data = block;
1238         iterator_insert_node_(iterator, node);
1239         iterator->current = node;
1240         return true;
1241 }
1242
1243 FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
1244 {
1245         FLAC__Metadata_Node *node;
1246
1247         FLAC__ASSERT(0 != iterator);
1248         FLAC__ASSERT(0 != iterator->current);
1249         FLAC__ASSERT(0 != block);
1250
1251         if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
1252                 return false;
1253
1254         if(0 == (node = node_new_()))
1255                 return false;
1256
1257         node->data = block;
1258         iterator_insert_node_after_(iterator, node);
1259         iterator->current = node;
1260         return true;
1261 }
1262
1263
1264 /****************************************************************************
1265  *
1266  * Local function definitions
1267  *
1268  ***************************************************************************/
1269
1270 void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
1271 {
1272         unsigned i;
1273
1274         b += bytes;
1275
1276         for(i = 0; i < bytes; i++) {
1277                 *(--b) = (FLAC__byte)(val & 0xff);
1278                 val >>= 8;
1279         }
1280 }
1281
1282 void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
1283 {
1284         unsigned i;
1285
1286         for(i = 0; i < bytes; i++) {
1287                 *(b++) = (FLAC__byte)(val & 0xff);
1288                 val >>= 8;
1289         }
1290 }
1291
1292 void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes)
1293 {
1294         unsigned i;
1295
1296         b += bytes;
1297
1298         for(i = 0; i < bytes; i++) {
1299                 *(--b) = (FLAC__byte)(val & 0xff);
1300                 val >>= 8;
1301         }
1302 }
1303
1304 FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes)
1305 {
1306         FLAC__uint32 ret = 0;
1307         unsigned i;
1308
1309         for(i = 0; i < bytes; i++)
1310                 ret = (ret << 8) | (FLAC__uint32)(*b++);
1311
1312         return ret;
1313 }
1314
1315 FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes)
1316 {
1317         FLAC__uint32 ret = 0;
1318         unsigned i;
1319
1320         b += bytes;
1321
1322         for(i = 0; i < bytes; i++)
1323                 ret = (ret << 8) | (FLAC__uint32)(*--b);
1324
1325         return ret;
1326 }
1327
1328 FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes)
1329 {
1330         FLAC__uint64 ret = 0;
1331         unsigned i;
1332
1333         for(i = 0; i < bytes; i++)
1334                 ret = (ret << 8) | (FLAC__uint64)(*b++);
1335
1336         return ret;
1337 }
1338
1339 FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
1340 {
1341         FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
1342
1343         FLAC__ASSERT(0 != iterator);
1344         FLAC__ASSERT(0 != iterator->file);
1345
1346         if(fread(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, iterator->file) != FLAC__STREAM_METADATA_HEADER_LENGTH) {
1347                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1348                 return false;
1349         }
1350
1351         iterator->is_last = raw_header[0] & 0x80? true : false;
1352         iterator->type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
1353         iterator->length = unpack_uint32_(raw_header + 1, 3);
1354
1355         /* Note that we don't check:
1356          *    if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
1357          * we just will read in an opaque block
1358          */
1359
1360         return true;
1361 }
1362
1363 FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
1364 {
1365         FLAC__ASSERT(0 != iterator);
1366         FLAC__ASSERT(0 != iterator->file);
1367
1368         switch(block->type) {
1369                 case FLAC__METADATA_TYPE_STREAMINFO:
1370                         iterator->status = read_metadata_block_data_streaminfo_(iterator->file, &block->data.stream_info);
1371                         break;
1372                 case FLAC__METADATA_TYPE_PADDING:
1373                         iterator->status = read_metadata_block_data_padding_(iterator->file, &block->data.padding, block->length);
1374                         break;
1375                 case FLAC__METADATA_TYPE_APPLICATION:
1376                         iterator->status = read_metadata_block_data_application_(iterator->file, &block->data.application, block->length);
1377                         break;
1378                 case FLAC__METADATA_TYPE_SEEKTABLE:
1379                         iterator->status = read_metadata_block_data_seektable_(iterator->file, &block->data.seek_table, block->length);
1380                         break;
1381                 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
1382                         iterator->status = read_metadata_block_data_vorbis_comment_(iterator->file, &block->data.vorbis_comment);
1383                         break;
1384                 case FLAC__METADATA_TYPE_CUESHEET:
1385                         iterator->status = read_metadata_block_data_cuesheet_(iterator->file, &block->data.cue_sheet);
1386                         break;
1387                 default:
1388                         iterator->status = read_metadata_block_data_unknown_(iterator->file, &block->data.unknown, block->length);
1389                         break;
1390         }
1391
1392         return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
1393 }
1394
1395 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_(FILE *file, FLAC__StreamMetadata_StreamInfo *block)
1396 {
1397         FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
1398
1399         FLAC__ASSERT(0 != file);
1400
1401         if(fread(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, file) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
1402                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1403
1404         b = buffer;
1405
1406         /* @@@ we are using hardcoded numbers for simplicity but we should
1407          * probably eventually write a bit-level unpacker and use the
1408          * _STREAMINFO_ constants.
1409          */
1410         block->min_blocksize = unpack_uint32_(b, 2); b += 2;
1411         block->max_blocksize = unpack_uint32_(b, 2); b += 2;
1412         block->min_framesize = unpack_uint32_(b, 3); b += 3;
1413         block->max_framesize = unpack_uint32_(b, 3); b += 3;
1414         block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((unsigned)(b[2] & 0xf0) >> 4);
1415         block->channels = (unsigned)((b[2] & 0x0e) >> 1) + 1;
1416         block->bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 4) | (((unsigned)(b[3] & 0xf0)) >> 4)) + 1;
1417         block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
1418         memcpy(block->md5sum, b+8, 16);
1419
1420         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1421 }
1422
1423
1424 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_(FILE *file, FLAC__StreamMetadata_Padding *block, unsigned block_length)
1425 {
1426         FLAC__ASSERT(0 != file);
1427
1428         (void)block; /* nothing to do; we don't care about reading the padding bytes */
1429
1430         if(0 != fseek(file, block_length, SEEK_CUR))
1431                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
1432
1433         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1434 }
1435
1436 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_(FILE *file, FLAC__StreamMetadata_Application *block, unsigned block_length)
1437 {
1438         const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
1439
1440         FLAC__ASSERT(0 != file);
1441
1442         if(fread(block->id, 1, id_bytes, file) != id_bytes)
1443                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1444
1445         block_length -= id_bytes;
1446
1447         if(block_length == 0) {
1448                 block->data = 0;
1449         }
1450         else {
1451                 if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
1452                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
1453
1454                 if(fread(block->data, 1, block_length, file) != block_length)
1455                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1456         }
1457
1458         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1459 }
1460
1461 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_(FILE *file, FLAC__StreamMetadata_SeekTable *block, unsigned block_length)
1462 {
1463         unsigned i;
1464         FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
1465
1466         FLAC__ASSERT(0 != file);
1467         FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0);
1468
1469         block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
1470
1471         if(block->num_points == 0)
1472                 block->points = 0;
1473         else if(0 == (block->points = (FLAC__StreamMetadata_SeekPoint*)malloc(block->num_points * sizeof(FLAC__StreamMetadata_SeekPoint))))
1474                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
1475
1476         for(i = 0; i < block->num_points; i++) {
1477                 if(fread(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, file) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
1478                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1479                 /*@@@ some MAGIC NUMBERs here */
1480                 block->points[i].sample_number = unpack_uint64_(buffer, 8);
1481                 block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
1482                 block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
1483         }
1484
1485         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1486 }
1487
1488 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_(FILE *file, FLAC__StreamMetadata_VorbisComment_Entry *entry)
1489 {
1490         const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
1491         FLAC__byte buffer[4]; /* magic number is asserted below */
1492
1493         FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == 4);
1494         FLAC__ASSERT(0 != file);
1495
1496         if(fread(buffer, 1, entry_length_len, file) != entry_length_len)
1497                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1498         entry->length = unpack_uint32_little_endian_(buffer, entry_length_len);
1499
1500         if(0 != entry->entry)
1501                 free(entry->entry);
1502
1503         if(entry->length == 0) {
1504                 entry->entry = 0;
1505         }
1506         else {
1507                 if(0 == (entry->entry = (FLAC__byte*)malloc(entry->length)))
1508                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
1509
1510                 if(fread(entry->entry, 1, entry->length, file) != entry->length)
1511                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1512         }
1513
1514         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1515 }
1516
1517 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_(FILE *file, FLAC__StreamMetadata_VorbisComment *block)
1518 {
1519         unsigned i;
1520         FLAC__Metadata_SimpleIteratorStatus status;
1521         const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
1522         FLAC__byte buffer[4]; /* magic number is asserted below */
1523
1524         FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == 4);
1525         FLAC__ASSERT(0 != file);
1526
1527         if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_(file, &(block->vendor_string))))
1528                 return status;
1529
1530         if(fread(buffer, 1, num_comments_len, file) != num_comments_len)
1531                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1532         block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len);
1533
1534         if(block->num_comments == 0) {
1535                 block->comments = 0;
1536         }
1537         else if(0 == (block->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry))))
1538                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
1539
1540         for(i = 0; i < block->num_comments; i++) {
1541                 if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_(file, block->comments + i)))
1542                         return status;
1543         }
1544
1545         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1546 }
1547
1548 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_(FILE *file, FLAC__StreamMetadata_CueSheet_Track *track)
1549 {
1550         unsigned i, len;
1551         FLAC__byte buffer[32]; /* asserted below that this is big enough */
1552
1553         FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
1554         FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
1555         FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8);
1556
1557         FLAC__ASSERT(0 != file);
1558
1559         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
1560         len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
1561         if(fread(buffer, 1, len, file) != len)
1562                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1563         track->offset = unpack_uint64_(buffer, len);
1564
1565         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
1566         len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
1567         if(fread(buffer, 1, len, file) != len)
1568                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1569         track->number = (FLAC__byte)unpack_uint32_(buffer, len);
1570
1571         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
1572         len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
1573         if(fread(track->isrc, 1, len, file) != len)
1574                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1575
1576         FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
1577         len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
1578         if(fread(buffer, 1, len, file) != len)
1579                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1580         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1);
1581         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1);
1582         track->type = buffer[0] >> 7;
1583         track->pre_emphasis = (buffer[0] >> 6) & 1;
1584
1585         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
1586         len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
1587         if(fread(buffer, 1, len, file) != len)
1588                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1589         track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
1590
1591         if(track->num_indices == 0) {
1592                 track->indices = 0;
1593         }
1594         else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
1595                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
1596
1597         for(i = 0; i < track->num_indices; i++) {
1598                 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
1599                 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
1600                 if(fread(buffer, 1, len, file) != len)
1601                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1602                 track->indices[i].offset = unpack_uint64_(buffer, len);
1603
1604                 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
1605                 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
1606                 if(fread(buffer, 1, len, file) != len)
1607                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1608                 track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
1609
1610                 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
1611                 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
1612                 if(fread(buffer, 1, len, file) != len)
1613                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1614         }
1615
1616         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1617 }
1618
1619 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_(FILE *file, FLAC__StreamMetadata_CueSheet *block)
1620 {
1621         unsigned i, len;
1622         FLAC__Metadata_SimpleIteratorStatus status;
1623         FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
1624
1625         FLAC__ASSERT(0 != file);
1626         FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer));
1627         FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer));
1628
1629         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
1630         len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
1631         if(fread(block->media_catalog_number, 1, len, file) != len)
1632                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1633
1634         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
1635         len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
1636         if(fread(buffer, 1, len, file) != len)
1637                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1638         block->lead_in = unpack_uint64_(buffer, len);
1639
1640         FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
1641         len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
1642         if(fread(buffer, 1, len, file) != len)
1643                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1644         block->is_cd = buffer[0]&0x80? true : false;
1645
1646         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
1647         len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
1648         if(fread(buffer, 1, len, file) != len)
1649                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1650         block->num_tracks = unpack_uint32_(buffer, len);
1651
1652         if(block->num_tracks == 0) {
1653                 block->tracks = 0;
1654         }
1655         else if(0 == (block->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
1656                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
1657
1658         for(i = 0; i < block->num_tracks; i++) {
1659                 if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_(file, block->tracks + i)))
1660                         return status;
1661         }
1662
1663         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1664 }
1665
1666 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_(FILE *file, FLAC__StreamMetadata_Unknown *block, unsigned block_length)
1667 {
1668         FLAC__ASSERT(0 != file);
1669
1670         if(block_length == 0) {
1671                 block->data = 0;
1672         }
1673         else {
1674                 if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
1675                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
1676
1677                 if(fread(block->data, 1, block_length, file) != block_length)
1678                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
1679         }
1680
1681         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1682 }
1683
1684 FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
1685 {
1686         FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
1687
1688         FLAC__ASSERT(0 != file);
1689         FLAC__ASSERT(0 != status);
1690         FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
1691
1692         buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
1693         pack_uint32_(block->length, buffer + 1, 3);
1694
1695         if(local__fwrite(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, file) != FLAC__STREAM_METADATA_HEADER_LENGTH) {
1696                 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1697                 return false;
1698         }
1699
1700         return true;
1701 }
1702
1703 FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
1704 {
1705         FLAC__ASSERT(0 != file);
1706         FLAC__ASSERT(0 != status);
1707
1708         switch(block->type) {
1709                 case FLAC__METADATA_TYPE_STREAMINFO:
1710                         *status = write_metadata_block_data_streaminfo_(file, &block->data.stream_info);
1711                         break;
1712                 case FLAC__METADATA_TYPE_PADDING:
1713                         *status = write_metadata_block_data_padding_(file, &block->data.padding, block->length);
1714                         break;
1715                 case FLAC__METADATA_TYPE_APPLICATION:
1716                         *status = write_metadata_block_data_application_(file, &block->data.application, block->length);
1717                         break;
1718                 case FLAC__METADATA_TYPE_SEEKTABLE:
1719                         *status = write_metadata_block_data_seektable_(file, &block->data.seek_table);
1720                         break;
1721                 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
1722                         *status = write_metadata_block_data_vorbis_comment_(file, &block->data.vorbis_comment);
1723                         break;
1724                 case FLAC__METADATA_TYPE_CUESHEET:
1725                         *status = write_metadata_block_data_cuesheet_(file, &block->data.cue_sheet);
1726                         break;
1727                 default:
1728                         *status = write_metadata_block_data_unknown_(file, &block->data.unknown, block->length);
1729                         break;
1730         }
1731         return (*status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
1732 }
1733
1734 FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_streaminfo_(FILE *file, const FLAC__StreamMetadata_StreamInfo *block)
1735 {
1736         FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
1737         const unsigned channels1 = block->channels - 1;
1738         const unsigned bps1 = block->bits_per_sample - 1;
1739
1740         FLAC__ASSERT(0 != file);
1741
1742         /* @@@ we are using hardcoded numbers for simplicity but we should
1743          * probably eventually write a bit-level packer and use the
1744          * _STREAMINFO_ constants.
1745          */
1746         pack_uint32_(block->min_blocksize, buffer, 2);
1747         pack_uint32_(block->max_blocksize, buffer+2, 2);
1748         pack_uint32_(block->min_framesize, buffer+4, 3);
1749         pack_uint32_(block->max_framesize, buffer+7, 3);
1750         buffer[10] = (block->sample_rate >> 12) & 0xff;
1751         buffer[11] = (block->sample_rate >> 4) & 0xff;
1752         buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4);
1753         buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
1754         pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
1755         memcpy(buffer+18, block->md5sum, 16);
1756
1757         if(local__fwrite(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, file) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
1758                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1759
1760         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1761 }
1762
1763 FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_padding_(FILE *file, const FLAC__StreamMetadata_Padding *block, unsigned block_length)
1764 {
1765         unsigned i, n = block_length;
1766         FLAC__byte buffer[1024];
1767
1768         FLAC__ASSERT(0 != file);
1769
1770         (void)block;
1771
1772         memset(buffer, 0, 1024);
1773
1774         for(i = 0; i < n/1024; i++)
1775                 if(local__fwrite(buffer, 1, 1024, file) != 1024)
1776                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1777
1778         n %= 1024;
1779
1780         if(local__fwrite(buffer, 1, n, file) != n)
1781                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1782
1783         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1784 }
1785
1786 FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_application_(FILE *file, const FLAC__StreamMetadata_Application *block, unsigned block_length)
1787 {
1788         const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
1789
1790         FLAC__ASSERT(0 != file);
1791
1792         if(local__fwrite(block->id, 1, id_bytes, file) != id_bytes)
1793                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1794
1795         block_length -= id_bytes;
1796
1797         if(local__fwrite(block->data, 1, block_length, file) != block_length)
1798                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1799
1800         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1801 }
1802
1803 FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_seektable_(FILE *file, const FLAC__StreamMetadata_SeekTable *block)
1804 {
1805         unsigned i;
1806         FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
1807
1808         FLAC__ASSERT(0 != file);
1809
1810         for(i = 0; i < block->num_points; i++) {
1811                 /*@@@ some MAGIC NUMBERs here */
1812                 pack_uint64_(block->points[i].sample_number, buffer, 8);
1813                 pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
1814                 pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
1815                 if(local__fwrite(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, file) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
1816                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1817         }
1818
1819         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1820 }
1821
1822 FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_vorbis_comment_(FILE *file, const FLAC__StreamMetadata_VorbisComment *block)
1823 {
1824         unsigned i;
1825         const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
1826         const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
1827         FLAC__byte buffer[4]; /* magic number is asserted below */
1828
1829         FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == 4);
1830         FLAC__ASSERT(0 != file);
1831
1832         pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
1833         if(local__fwrite(buffer, 1, entry_length_len, file) != entry_length_len)
1834                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1835         if(local__fwrite(block->vendor_string.entry, 1, block->vendor_string.length, file) != block->vendor_string.length)
1836                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1837
1838         pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
1839         if(local__fwrite(buffer, 1, num_comments_len, file) != num_comments_len)
1840                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1841
1842         for(i = 0; i < block->num_comments; i++) {
1843                 pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
1844                 if(local__fwrite(buffer, 1, entry_length_len, file) != entry_length_len)
1845                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1846                 if(local__fwrite(block->comments[i].entry, 1, block->comments[i].length, file) != block->comments[i].length)
1847                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1848         }
1849
1850         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1851 }
1852
1853 FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_cuesheet_(FILE *file, const FLAC__StreamMetadata_CueSheet *block)
1854 {
1855         unsigned i, j, len;
1856         FLAC__byte buffer[1024]; /* asserted below that this is big enough */
1857
1858         FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
1859         FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8);
1860         FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8);
1861         FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
1862
1863         FLAC__ASSERT(0 != file);
1864
1865         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
1866         len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
1867         if(local__fwrite(block->media_catalog_number, 1, len, file) != len)
1868                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1869
1870         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
1871         len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
1872         pack_uint64_(block->lead_in, buffer, len);
1873         if(local__fwrite(buffer, 1, len, file) != len)
1874                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1875
1876         FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
1877         len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
1878         memset(buffer, 0, len);
1879         if(block->is_cd)
1880                 buffer[0] |= 0x80;
1881         if(local__fwrite(buffer, 1, len, file) != len)
1882                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1883
1884         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
1885         len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
1886         pack_uint32_(block->num_tracks, buffer, len);
1887         if(local__fwrite(buffer, 1, len, file) != len)
1888                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1889
1890         for(i = 0; i < block->num_tracks; i++) {
1891                 FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
1892
1893                 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
1894                 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
1895                 pack_uint64_(track->offset, buffer, len);
1896                 if(local__fwrite(buffer, 1, len, file) != len)
1897                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1898
1899                 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
1900                 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
1901                 pack_uint32_(track->number, buffer, len);
1902                 if(local__fwrite(buffer, 1, len, file) != len)
1903                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1904
1905                 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
1906                 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
1907                 if(local__fwrite(track->isrc, 1, len, file) != len)
1908                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1909
1910                 FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
1911                 len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
1912                 memset(buffer, 0, len);
1913                 buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
1914                 if(local__fwrite(buffer, 1, len, file) != len)
1915                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1916
1917                 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
1918                 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
1919                 pack_uint32_(track->num_indices, buffer, len);
1920                 if(local__fwrite(buffer, 1, len, file) != len)
1921                         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1922
1923                 for(j = 0; j < track->num_indices; j++) {
1924                         FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
1925
1926                         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
1927                         len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
1928                         pack_uint64_(index->offset, buffer, len);
1929                         if(local__fwrite(buffer, 1, len, file) != len)
1930                                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1931
1932                         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
1933                         len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
1934                         pack_uint32_(index->number, buffer, len);
1935                         if(local__fwrite(buffer, 1, len, file) != len)
1936                                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1937
1938                         FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
1939                         len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
1940                         memset(buffer, 0, len);
1941                         if(local__fwrite(buffer, 1, len, file) != len)
1942                                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1943                 }
1944         }
1945
1946         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1947 }
1948
1949 FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_unknown_(FILE *file, const FLAC__StreamMetadata_Unknown *block, unsigned block_length)
1950 {
1951         FLAC__ASSERT(0 != file);
1952
1953         if(local__fwrite(block->data, 1, block_length, file) != block_length)
1954                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
1955
1956         return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
1957 }
1958
1959 FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
1960 {
1961         if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
1962                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
1963                 return false;
1964         }
1965
1966         if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
1967                 return false;
1968
1969         if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
1970                 return false;
1971
1972         if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
1973                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
1974                 return false;
1975         }
1976
1977         return read_metadata_block_header_(iterator);
1978 }
1979
1980 FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last)
1981 {
1982         FLAC__StreamMetadata *padding;
1983
1984         if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
1985                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
1986                 return false;
1987         }
1988
1989         block->is_last = false;
1990
1991         if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
1992                 return false;
1993
1994         if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
1995                 return false;
1996
1997         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1998                 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
1999
2000         padding->is_last = padding_is_last;
2001         padding->length = padding_length;
2002
2003         if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
2004                 FLAC__metadata_object_delete(padding);
2005                 return false;
2006         }
2007
2008         if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
2009                 FLAC__metadata_object_delete(padding);
2010                 return false;
2011         }
2012
2013         FLAC__metadata_object_delete(padding);
2014
2015         if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
2016                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2017                 return false;
2018         }
2019
2020         return read_metadata_block_header_(iterator);
2021 }
2022
2023 FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
2024 {
2025         FILE *tempfile;
2026         char *tempfilename;
2027         int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
2028         long fixup_is_last_flag_offset = -1;
2029
2030         FLAC__ASSERT(0 != block || append == false);
2031
2032         if(iterator->is_last) {
2033                 if(append) {
2034                         fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
2035                         fixup_is_last_flag_offset = iterator->offset[iterator->depth];
2036                 }
2037                 else if(0 == block) {
2038                         simple_iterator_push_(iterator);
2039                         if(!FLAC__metadata_simple_iterator_prev(iterator)) {
2040                                 (void)simple_iterator_pop_(iterator);
2041                                 return false;
2042                         }
2043                         fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
2044                         fixup_is_last_flag_offset = iterator->offset[iterator->depth];
2045                         if(!simple_iterator_pop_(iterator))
2046                                 return false;
2047                 }
2048         }
2049
2050         if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
2051                 return false;
2052
2053         if(0 != block) {
2054                 if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
2055                         cleanup_tempfile_(&tempfile, &tempfilename);
2056                         return false;
2057                 }
2058
2059                 if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
2060                         cleanup_tempfile_(&tempfile, &tempfilename);
2061                         return false;
2062                 }
2063         }
2064
2065         if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
2066                 return false;
2067
2068         if(append)
2069                 return FLAC__metadata_simple_iterator_next(iterator);
2070
2071         return true;
2072 }
2073
2074 FLAC__bool chain_rewrite_chain_(FLAC__Metadata_Chain *chain)
2075 {
2076         FILE *f;
2077         FLAC__Metadata_Node *node;
2078         FLAC__Metadata_SimpleIteratorStatus status;
2079
2080         FLAC__ASSERT(0 != chain);
2081         FLAC__ASSERT(0 != chain->filename);
2082         FLAC__ASSERT(0 != chain->head);
2083
2084         if(0 == (f = fopen(chain->filename, "r+b"))) {
2085                 chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
2086                 return false;
2087         }
2088         if(0 != fseek(f, chain->first_offset, SEEK_SET)) {
2089                 chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
2090                 return false;
2091         }
2092
2093         for(node = chain->head; node; node = node->next) {
2094                 if(!write_metadata_block_header_(f, &status, node->data)) {
2095                         chain->status = get_equivalent_status_(status);
2096                         return false;
2097                 }
2098                 if(!write_metadata_block_data_(f, &status, node->data)) {
2099                         chain->status = get_equivalent_status_(status);
2100                         return false;
2101                 }
2102         }
2103
2104         /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
2105
2106         (void)fclose(f);
2107
2108         return true;
2109 }
2110
2111 FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
2112 {
2113         FILE *f, *tempfile;
2114         char *tempfilename;
2115         FLAC__Metadata_SimpleIteratorStatus status;
2116         const FLAC__Metadata_Node *node;
2117
2118         FLAC__ASSERT(0 != chain);
2119         FLAC__ASSERT(0 != chain->filename);
2120         FLAC__ASSERT(0 != chain->head);
2121
2122         /* copy the file prefix (data up to first metadata block */
2123         if(0 == (f = fopen(chain->filename, "rb"))) {
2124                 chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
2125                 return false;
2126         }
2127         if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) {
2128                 chain->status = get_equivalent_status_(status);
2129                 cleanup_tempfile_(&tempfile, &tempfilename);
2130                 return false;
2131         }
2132         if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
2133                 chain->status = get_equivalent_status_(status);
2134                 cleanup_tempfile_(&tempfile, &tempfilename);
2135                 return false;
2136         }
2137
2138         /* write the metadata */
2139         for(node = chain->head; node; node = node->next) {
2140                 if(!write_metadata_block_header_(tempfile, &status, node->data)) {
2141                         chain->status = get_equivalent_status_(status);
2142                         return false;
2143                 }
2144                 if(!write_metadata_block_data_(tempfile, &status, node->data)) {
2145                         chain->status = get_equivalent_status_(status);
2146                         return false;
2147                 }
2148         }
2149         /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
2150
2151         /* copy the file postfix (everything after the metadata) */
2152         if(0 != fseek(f, chain->last_offset, SEEK_SET)) {
2153                 cleanup_tempfile_(&tempfile, &tempfilename);
2154                 chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
2155                 return false;
2156         }
2157         if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
2158                 cleanup_tempfile_(&tempfile, &tempfilename);
2159                 chain->status = get_equivalent_status_(status);
2160                 return false;
2161         }
2162
2163         /* move the tempfile on top of the original */
2164         (void)fclose(f);
2165         if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
2166                 return false;
2167
2168         return true;
2169 }
2170
2171 void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
2172 {
2173         FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
2174         iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
2175         iterator->depth++;
2176 }
2177
2178 FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
2179 {
2180         FLAC__ASSERT(iterator->depth > 0);
2181         iterator->depth--;
2182         if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
2183                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2184                 return false;
2185         }
2186
2187         return read_metadata_block_header_(iterator);
2188 }
2189
2190 unsigned seek_to_first_metadata_block_(FILE *f)
2191 {
2192         FLAC__byte buffer[4];
2193         size_t n;
2194         unsigned i;
2195
2196         FLAC__ASSERT(0 != f);
2197         FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == 4);
2198
2199         /* skip any id3v2 tag */
2200 #if !defined _MSC_VER && !defined __MINGW32__
2201 /*@@@ don't know how to resolve errno without using LIBC.LIB; must use MSVCRT.LIB only for plugins */
2202         errno = 0;
2203 #endif
2204         n = fread(buffer, 1, 4, f);
2205 #if !defined _MSC_VER && !defined __MINGW32__
2206 /*@@@ don't know how to resolve errno without using LIBC.LIB; must use MSVCRT.LIB only for plugins */
2207         if(errno)
2208                 return 1;
2209         else
2210 #endif
2211         if(n != 4)
2212                 return 2;
2213         else if(0 == memcmp(buffer, "ID3", 3)) {
2214                 unsigned tag_length = 0;
2215
2216                 /* skip to the tag length */
2217                 if(fseek(f, 2, SEEK_CUR) < 0)
2218                         return 1;
2219
2220                 /* read the length */
2221                 for(i = 0; i < 4; i++) {
2222                         if(fread(buffer, 1, 1, f) < 1 || buffer[0] & 0x80)
2223                                 return 1;
2224                         tag_length <<= 7;
2225                         tag_length |= (buffer[0] & 0x7f);
2226                 }
2227
2228                 /* skip the rest of the tag */
2229                 if(fseek(f, tag_length, SEEK_CUR) < 0)
2230                         return 1;
2231
2232                 /* read the stream sync code */
2233 #if !defined _MSC_VER && !defined __MINGW32__
2234 /*@@@ don't know how to resolve errno without using LIBC.LIB; must use MSVCRT.LIB only for plugins */
2235                 errno = 0;
2236 #endif
2237                 n = fread(buffer, 1, 4, f);
2238 #if !defined _MSC_VER && !defined __MINGW32__
2239 /*@@@ don't know how to resolve errno without using LIBC.LIB; must use MSVCRT.LIB only for plugins */
2240                 if(errno)
2241                         return 1;
2242                 else
2243 #endif
2244                 if(n != 4)
2245                         return 2;
2246         }
2247
2248         /* check for the fLaC signature */
2249         if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
2250                 return 0;
2251         else
2252                 return 2;
2253 }
2254
2255 FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
2256 {
2257         const long offset_end = append? iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length : iterator->offset[iterator->depth];
2258
2259         if(0 != fseek(iterator->file, 0, SEEK_SET)) {
2260                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2261                 return false;
2262         }
2263         if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
2264                 cleanup_tempfile_(tempfile, tempfilename);
2265                 return false;
2266         }
2267         if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
2268                 cleanup_tempfile_(tempfile, tempfilename);
2269                 return false;
2270         }
2271
2272         return true;
2273 }
2274
2275 FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, long fixup_is_last_flag_offset, FLAC__bool backup)
2276 {
2277         long save_offset = iterator->offset[iterator->depth]; /*@@@ 2G limit */
2278         FLAC__ASSERT(0 != *tempfile);
2279
2280         if(0 != fseek(iterator->file, save_offset + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length, SEEK_SET)) {
2281                 cleanup_tempfile_(tempfile, tempfilename);
2282                 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2283                 return false;
2284         }
2285         if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
2286                 cleanup_tempfile_(tempfile, tempfilename);
2287                 return false;
2288         }
2289
2290         if(fixup_is_last_code != 0) {
2291                 /*
2292                  * if code == 1, it means a block was appended to the end so
2293                  *   we have to clear the is_last flag of the previous block
2294                  * if code == -1, it means the last block was deleted so
2295                  *   we have to set the is_last flag of the previous block
2296                  */
2297                 /*@@@ MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
2298                 FLAC__byte x;
2299                 if(0 != fseek(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
2300                         cleanup_tempfile_(tempfile, tempfilename);
2301                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2302                         return false;
2303                 }
2304                 if(fread(&x, 1, 1, *tempfile) != 1) {
2305                         cleanup_tempfile_(tempfile, tempfilename);
2306                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2307                         return false;
2308                 }
2309                 if(fixup_is_last_code > 0) {
2310                         FLAC__ASSERT(x & 0x80);
2311                         x &= 0x7f;
2312                 }
2313                 else {
2314                         FLAC__ASSERT(!(x & 0x80));
2315                         x |= 0x80;
2316                 }
2317                 if(0 != fseek(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
2318                         cleanup_tempfile_(tempfile, tempfilename);
2319                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2320                         return false;
2321                 }
2322                 if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
2323                         cleanup_tempfile_(tempfile, tempfilename);
2324                         iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
2325                         return false;
2326                 }
2327         }
2328
2329         (void)fclose(iterator->file);
2330
2331         if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
2332                 return false;
2333
2334         if(iterator->has_stats)
2335                 set_file_stats_(iterator->filename, &iterator->stats);
2336
2337         if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
2338                 return false;
2339         if(backup) {
2340                 while(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length < save_offset)
2341                         if(!FLAC__metadata_simple_iterator_next(iterator))
2342                                 return false;
2343                 return true;
2344         }
2345         else {
2346                 /* move the iterator to it's original block faster by faking a push, then doing a pop_ */
2347                 FLAC__ASSERT(iterator->depth == 0);
2348                 iterator->offset[0] = save_offset;
2349                 iterator->depth++;
2350                 return simple_iterator_pop_(iterator);
2351         }
2352 }
2353
2354 FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status)
2355 {
2356         FLAC__byte buffer[8192];
2357         unsigned n;
2358
2359         while(bytes > 0) {
2360                 n = min(sizeof(buffer), bytes);
2361                 if(fread(buffer, 1, n, file) != n) {
2362                         *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2363                         return false;
2364                 }
2365                 if(local__fwrite(buffer, 1, n, tempfile) != n) {
2366                         *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
2367                         return false;
2368                 }
2369                 bytes -= n;
2370         }
2371
2372         return true;
2373 }
2374
2375 FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
2376 {
2377         FLAC__byte buffer[8192];
2378         size_t n;
2379
2380         while(!feof(file)) {
2381                 n = fread(buffer, 1, sizeof(buffer), file);
2382                 if(n == 0 && !feof(file)) {
2383                         *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2384                         return false;
2385                 }
2386                 if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
2387                         *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
2388                         return false;
2389                 }
2390         }
2391
2392         return true;
2393 }
2394
2395 FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
2396 {
2397         static const char *tempfile_suffix = ".metadata_edit";
2398         if(0 == tempfile_path_prefix) {
2399                 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1))) {
2400                         *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2401                         return false;
2402                 }
2403                 strcpy(*tempfilename, filename);
2404                 strcat(*tempfilename, tempfile_suffix);
2405         }
2406         else {
2407                 const char *p = strrchr(filename, '/');
2408                 if(0 == p)
2409                         p = filename;
2410                 else
2411                         p++;
2412
2413                 if(0 == (*tempfilename = (char*)malloc(strlen(tempfile_path_prefix) + 1 + strlen(p) + strlen(tempfile_suffix) + 1))) {
2414                         *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2415                         return false;
2416                 }
2417                 strcpy(*tempfilename, tempfile_path_prefix);
2418                 strcat(*tempfilename, "/");
2419                 strcat(*tempfilename, p);
2420                 strcat(*tempfilename, tempfile_suffix);
2421         }
2422
2423         if(0 == (*tempfile = fopen(*tempfilename, "w+b"))) {
2424                 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
2425                 return false;
2426         }
2427
2428         return true;
2429 }
2430
2431 FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
2432 {
2433         FLAC__ASSERT(0 != filename);
2434         FLAC__ASSERT(0 != tempfile);
2435         FLAC__ASSERT(0 != *tempfile);
2436         FLAC__ASSERT(0 != tempfilename);
2437         FLAC__ASSERT(0 != *tempfilename);
2438         FLAC__ASSERT(0 != status);
2439
2440         (void)fclose(*tempfile);
2441         *tempfile = 0;
2442
2443 #if defined _MSC_VER || defined __MINGW32__
2444         if(unlink(filename) < 0) {
2445                 cleanup_tempfile_(tempfile, tempfilename);
2446                 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
2447                 return false;
2448         }
2449 #endif
2450
2451         /*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just rename(): */
2452         if(0 != rename(*tempfilename, filename)) {
2453                 cleanup_tempfile_(tempfile, tempfilename);
2454                 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
2455                 return false;
2456         }
2457
2458         cleanup_tempfile_(tempfile, tempfilename);
2459
2460         return true;
2461 }
2462
2463 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
2464 {
2465         if(0 != *tempfile) {
2466                 (void)fclose(*tempfile);
2467                 *tempfile = 0;
2468         }
2469
2470         if(0 != *tempfilename) {
2471                 (void)unlink(*tempfilename);
2472                 free(*tempfilename);
2473                 *tempfilename = 0;
2474         }
2475 }
2476
2477 FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
2478 {
2479         FLAC__ASSERT(0 != filename);
2480         FLAC__ASSERT(0 != stats);
2481         return (0 == stat(filename, stats));
2482 }
2483
2484 void set_file_stats_(const char *filename, struct stat *stats)
2485 {
2486         struct utimbuf srctime;
2487
2488         FLAC__ASSERT(0 != filename);
2489         FLAC__ASSERT(0 != stats);
2490
2491         srctime.actime = stats->st_atime;
2492         srctime.modtime = stats->st_mtime;
2493         (void)chmod(filename, stats->st_mode);
2494         (void)utime(filename, &srctime);
2495 #if !defined _MSC_VER && !defined __MINGW32__
2496         (void)chown(filename, stats->st_uid, -1);
2497         (void)chown(filename, -1, stats->st_gid);
2498 #endif
2499 }
2500
2501 FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
2502 {
2503         switch(status) {
2504                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
2505                         return FLAC__METADATA_CHAIN_STATUS_OK;
2506                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
2507                         return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
2508                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
2509                         return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
2510                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
2511                         return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
2512                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
2513                         return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
2514                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
2515                         return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
2516                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
2517                         return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
2518                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
2519                         return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
2520                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
2521                         return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
2522                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
2523                         return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
2524                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
2525                         return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
2526                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
2527                         return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
2528                 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
2529                 default:
2530                         return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
2531         }
2532 }