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