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