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