Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: src/libFLAC/metadata_iterators.c

Issue 1961133002: Update FLAC to 1.3.1 (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/flac.git@master
Patch Set: build config tweaks for Windows Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/libFLAC/memory.c ('k') | src/libFLAC/metadata_object.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* libFLAC - Free Lossless Audio Codec library
2 * Copyright (C) 2001-2009 Josh Coalson
3 * Copyright (C) 2011-2014 Xiph.Org Foundation
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * - Neither the name of the Xiph.org Foundation nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #ifdef HAVE_CONFIG_H
34 # include <config.h>
35 #endif
36
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdarg.h>
42
43 #include <sys/stat.h> /* for stat(), maybe chmod() */
44
45 #include "private/metadata.h"
46
47 #include "FLAC/assert.h"
48 #include "FLAC/stream_decoder.h"
49 #include "share/alloc.h"
50 #include "share/compat.h"
51 #include "share/macros.h"
52 #include "share/safe_str.h"
53 #include "private/macros.h"
54 #include "private/memory.h"
55
56 /* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). * /
57 #define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
58
59 /****************************************************************************
60 *
61 * Local function declarations
62 *
63 ***************************************************************************/
64
65 static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
66 static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
67 static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes);
68 static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes);
69 static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes);
70 static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes);
71
72 static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *ite rator);
73 static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *itera tor, FLAC__StreamMetadata *block);
74 static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IO Callback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned * length);
75 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IO Handle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLA C__StreamMetadata *block);
76 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_c b_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_St reamInfo *block);
77 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_( FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Paddi ng *block, unsigned block_length);
78 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_ cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_A pplication *block, unsigned block_length);
79 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb _(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_See kTable *block, unsigned block_length);
80 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comme nt_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamM etadata_VorbisComment_Entry *entry, unsigned max_length);
81 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comme nt_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Se ek seek_cb, FLAC__StreamMetadata_VorbisComment *block, unsigned block_length);
82 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_tra ck_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadat a_CueSheet_Track *track);
83 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_ (FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueS heet *block);
84 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_( FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Pictu re *block);
85 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_( FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unkno wn *block, unsigned block_length);
86
87 static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_Simple IteratorStatus *status, const FLAC__StreamMetadata *block);
88 static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIt eratorStatus *status, const FLAC__StreamMetadata *block);
89 static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__I OCallback_Write write_cb, const FLAC__StreamMetadata *block);
90 static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOC allback_Write write_cb, const FLAC__StreamMetadata *block);
91 static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle , FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block) ;
92 static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, F LAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsig ned block_length);
93 static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handl e, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *bloc k, unsigned block_length);
94 static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
95 static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle ha ndle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
96 static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
97 static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, F LAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block);
98 static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, F LAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsig ned block_length);
99
100 static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
101 static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_S impleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, F LAC__bool padding_is_last);
102 static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, F LAC__StreamMetadata *block, FLAC__bool append);
103
104 static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
105 static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
106
107 static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IO Callback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
108 static unsigned seek_to_first_metadata_block_(FILE *f);
109
110 static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterato r *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
111 static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterat or *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC __off_t fixup_is_last_flag_offset, FLAC__bool backup);
112
113 static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_ t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
114 static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCall back_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write _cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
115 static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FL AC__Metadata_SimpleIteratorStatus *status);
116 static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC __IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_hand le, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *s tatus);
117
118 static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path _prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStat us *status);
119 static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, cha r **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
120 static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
121
122 static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stat s);
123 static void set_file_stats_(const char *filename, struct flac_stat_s *stats);
124
125 static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence) ;
126 static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);
127
128 static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIt eratorStatus status);
129
130
131 #ifdef FLAC__VALGRIND_TESTING
132 static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *st ream)
133 {
134 size_t ret = fwrite(ptr, size, nmemb, stream);
135 if(!ferror(stream))
136 fflush(stream);
137 return ret;
138 }
139 #else
140 #define local__fwrite fwrite
141 #endif
142
143 /****************************************************************************
144 *
145 * Level 0 implementation
146 *
147 ***************************************************************************/
148
149 static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *cl ient_data);
150 static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__S treamMetadata *metadata, void *client_data);
151 static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDeco derErrorStatus status, void *client_data);
152
153 typedef struct {
154 FLAC__bool got_error;
155 FLAC__StreamMetadata *object;
156 } level0_client_data;
157
158 static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC_ _MetadataType type)
159 {
160 level0_client_data cd;
161 FLAC__StreamDecoder *decoder;
162
163 FLAC__ASSERT(0 != filename);
164
165 cd.got_error = false;
166 cd.object = 0;
167
168 decoder = FLAC__stream_decoder_new();
169
170 if(0 == decoder)
171 return 0;
172
173 FLAC__stream_decoder_set_md5_checking(decoder, false);
174 FLAC__stream_decoder_set_metadata_ignore_all(decoder);
175 FLAC__stream_decoder_set_metadata_respond(decoder, type);
176
177 if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, me tadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK | | cd.got_error) {
178 (void)FLAC__stream_decoder_finish(decoder);
179 FLAC__stream_decoder_delete(decoder);
180 return 0;
181 }
182
183 if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.go t_error) {
184 (void)FLAC__stream_decoder_finish(decoder);
185 FLAC__stream_decoder_delete(decoder);
186 if(0 != cd.object)
187 FLAC__metadata_object_delete(cd.object);
188 return 0;
189 }
190
191 (void)FLAC__stream_decoder_finish(decoder);
192 FLAC__stream_decoder_delete(decoder);
193
194 return cd.object;
195 }
196
197 FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__St reamMetadata *streaminfo)
198 {
199 FLAC__StreamMetadata *object;
200
201 FLAC__ASSERT(0 != filename);
202 FLAC__ASSERT(0 != streaminfo);
203
204 object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINF O);
205
206 if (object) {
207 /* can just copy the contents since STREAMINFO has no internal s tructure */
208 *streaminfo = *object;
209 FLAC__metadata_object_delete(object);
210 return true;
211 }
212 else {
213 return false;
214 }
215 }
216
217 FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMe tadata **tags)
218 {
219 FLAC__ASSERT(0 != filename);
220 FLAC__ASSERT(0 != tags);
221
222 *tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COM MENT);
223
224 return 0 != *tags;
225 }
226
227 FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__Stre amMetadata **cuesheet)
228 {
229 FLAC__ASSERT(0 != filename);
230 FLAC__ASSERT(0 != cuesheet);
231
232 *cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHE ET);
233
234 return 0 != *cuesheet;
235 }
236
237 FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decode r, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_da ta)
238 {
239 (void)decoder, (void)frame, (void)buffer, (void)client_data;
240
241 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
242 }
243
244 void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMe tadata *metadata, void *client_data)
245 {
246 level0_client_data *cd = (level0_client_data *)client_data;
247 (void)decoder;
248
249 /*
250 * we assume we only get here when the one metadata block we were
251 * looking for was passed to us
252 */
253 if(!cd->got_error && 0 == cd->object) {
254 if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
255 cd->got_error = true;
256 }
257 }
258
259 void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErro rStatus status, void *client_data)
260 {
261 level0_client_data *cd = (level0_client_data *)client_data;
262 (void)decoder;
263
264 if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
265 cd->got_error = true;
266 }
267
268 FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__Strea mMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_ty pe, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsi gned max_depth, unsigned max_colors)
269 {
270 FLAC__Metadata_SimpleIterator *it;
271 FLAC__uint64 max_area_seen = 0;
272 FLAC__uint64 max_depth_seen = 0;
273
274 FLAC__ASSERT(0 != filename);
275 FLAC__ASSERT(0 != picture);
276
277 *picture = 0;
278
279 it = FLAC__metadata_simple_iterator_new();
280 if(0 == it)
281 return false;
282 if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true , /*preserve_file_stats=*/true)) {
283 FLAC__metadata_simple_iterator_delete(it);
284 return false;
285 }
286 do {
287 if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__ME TADATA_TYPE_PICTURE) {
288 FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterat or_get_block(it);
289 FLAC__uint64 area = (FLAC__uint64)obj->data.picture.widt h * (FLAC__uint64)obj->data.picture.height;
290 /* check constraints */
291 if(
292 (type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&
293 (mime_type == 0 || !strcmp(mime_type, obj->data. picture.mime_type)) &&
294 (description == 0 || !strcmp((const char *)descr iption, (const char *)obj->data.picture.description)) &&
295 obj->data.picture.width <= max_width &&
296 obj->data.picture.height <= max_height &&
297 obj->data.picture.depth <= max_depth &&
298 obj->data.picture.colors <= max_colors &&
299 (area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))
300 ) {
301 if(*picture)
302 FLAC__metadata_object_delete(*picture);
303 *picture = obj;
304 max_area_seen = area;
305 max_depth_seen = obj->data.picture.depth;
306 }
307 else {
308 FLAC__metadata_object_delete(obj);
309 }
310 }
311 } while(FLAC__metadata_simple_iterator_next(it));
312
313 FLAC__metadata_simple_iterator_delete(it);
314
315 return (0 != *picture);
316 }
317
318
319 /****************************************************************************
320 *
321 * Level 1 implementation
322 *
323 ***************************************************************************/
324
325 #define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
326 /* 1 for initial offset, +4 for our own personal use */
327
328 struct FLAC__Metadata_SimpleIterator {
329 FILE *file;
330 char *filename, *tempfile_path_prefix;
331 struct flac_stat_s stats;
332 FLAC__bool has_stats;
333 FLAC__bool is_writable;
334 FLAC__Metadata_SimpleIteratorStatus status;
335 FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
336 FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */
337 unsigned depth;
338 /* this is the metadata block header of the current block we are pointin g to: */
339 FLAC__bool is_last;
340 FLAC__MetadataType type;
341 unsigned length;
342 };
343
344 FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
345 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
346 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
347 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
348 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
349 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
350 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
351 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
352 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
353 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
354 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
355 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
356 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
357 "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
358 };
359
360
361 FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
362 {
363 FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadat a_SimpleIterator));
364
365 if(0 != iterator) {
366 iterator->file = 0;
367 iterator->filename = 0;
368 iterator->tempfile_path_prefix = 0;
369 iterator->has_stats = false;
370 iterator->is_writable = false;
371 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
372 iterator->first_offset = iterator->offset[0] = -1;
373 iterator->depth = 0;
374 }
375
376 return iterator;
377 }
378
379 static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
380 {
381 FLAC__ASSERT(0 != iterator);
382
383 if(0 != iterator->file) {
384 fclose(iterator->file);
385 iterator->file = 0;
386 if(iterator->has_stats)
387 set_file_stats_(iterator->filename, &iterator->stats);
388 }
389 if(0 != iterator->filename) {
390 free(iterator->filename);
391 iterator->filename = 0;
392 }
393 if(0 != iterator->tempfile_path_prefix) {
394 free(iterator->tempfile_path_prefix);
395 iterator->tempfile_path_prefix = 0;
396 }
397 }
398
399 FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterato r *iterator)
400 {
401 FLAC__ASSERT(0 != iterator);
402
403 simple_iterator_free_guts_(iterator);
404 free(iterator);
405 }
406
407 FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_stat us(FLAC__Metadata_SimpleIterator *iterator)
408 {
409 FLAC__Metadata_SimpleIteratorStatus status;
410
411 FLAC__ASSERT(0 != iterator);
412
413 status = iterator->status;
414 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
415 return status;
416 }
417
418 static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *it erator, FLAC__bool read_only)
419 {
420 unsigned ret;
421
422 FLAC__ASSERT(0 != iterator);
423
424 if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r +b"))) {
425 iterator->is_writable = false;
426 if(read_only || errno == EACCES) {
427 if(0 == (iterator->file = flac_fopen(iterator->filename, "rb"))) {
428 iterator->status = FLAC__METADATA_SIMPLE_ITERATO R_STATUS_ERROR_OPENING_FILE;
429 return false;
430 }
431 }
432 else {
433 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _ERROR_OPENING_FILE;
434 return false;
435 }
436 }
437 else {
438 iterator->is_writable = true;
439 }
440
441 ret = seek_to_first_metadata_block_(iterator->file);
442 switch(ret) {
443 case 0:
444 iterator->depth = 0;
445 iterator->first_offset = iterator->offset[iterator->dept h] = ftello(iterator->file);
446 return read_metadata_block_header_(iterator);
447 case 1:
448 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _READ_ERROR;
449 return false;
450 case 2:
451 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _SEEK_ERROR;
452 return false;
453 case 3:
454 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _NOT_A_FLAC_FILE;
455 return false;
456 default:
457 FLAC__ASSERT(0);
458 return false;
459 }
460 }
461
462 #if 0
463 @@@ If we decide to finish implementing this, put this comment back in metadata. h
464 /*
465 * The 'tempfile_path_prefix' allows you to specify a directory where
466 * tempfiles should go. Remember that if your metadata edits cause the
467 * FLAC file to grow, the entire file will have to be rewritten. If
468 * 'tempfile_path_prefix' is NULL, the temp file will be written in the
469 * same directory as the original FLAC file. This makes replacing the
470 * original with the tempfile fast but requires extra space in the same
471 * partition for the tempfile. If space is a problem, you can pass a
472 * directory name belonging to a different partition in
473 * 'tempfile_path_prefix'. Note that you should use the forward slash
474 * '/' as the directory separator. A trailing slash is not needed; it
475 * will be added automatically.
476 */
477 FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *it erator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfi le_path_prefix);
478 #endif
479
480 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIte rator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve _file_stats)
481 {
482 const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'fl ac_rename(...)' for what it will take to finish implementing this */
483
484 FLAC__ASSERT(0 != iterator);
485 FLAC__ASSERT(0 != filename);
486
487 simple_iterator_free_guts_(iterator);
488
489 if(!read_only && preserve_file_stats)
490 iterator->has_stats = get_file_stats_(filename, &iterator->stats );
491
492 if(0 == (iterator->filename = strdup(filename))) {
493 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ ALLOCATION_ERROR;
494 return false;
495 }
496 if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = s trdup(tempfile_path_prefix))) {
497 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ ALLOCATION_ERROR;
498 return false;
499 }
500
501 return simple_iterator_prime_input_(iterator, read_only);
502 }
503
504 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metad ata_SimpleIterator *iterator)
505 {
506 FLAC__ASSERT(0 != iterator);
507 FLAC__ASSERT(0 != iterator->file);
508
509 return iterator->is_writable;
510 }
511
512 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIte rator *iterator)
513 {
514 FLAC__ASSERT(0 != iterator);
515 FLAC__ASSERT(0 != iterator->file);
516
517 if(iterator->is_last)
518 return false;
519
520 if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
521 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
522 return false;
523 }
524
525 iterator->offset[iterator->depth] = ftello(iterator->file);
526
527 return read_metadata_block_header_(iterator);
528 }
529
530 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIte rator *iterator)
531 {
532 FLAC__off_t this_offset;
533
534 FLAC__ASSERT(0 != iterator);
535 FLAC__ASSERT(0 != iterator->file);
536
537 if(iterator->offset[iterator->depth] == iterator->first_offset)
538 return false;
539
540 if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
541 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
542 return false;
543 }
544 this_offset = iterator->first_offset;
545 if(!read_metadata_block_header_(iterator))
546 return false;
547
548 /* we ignore any error from ftello() and catch it in fseeko() */
549 while(ftello(iterator->file) + (FLAC__off_t)iterator->length < iterator- >offset[iterator->depth]) {
550 if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
551 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _SEEK_ERROR;
552 return false;
553 }
554 this_offset = ftello(iterator->file);
555 if(!read_metadata_block_header_(iterator))
556 return false;
557 }
558
559 iterator->offset[iterator->depth] = this_offset;
560
561 return true;
562 }
563
564 /*@@@@add to tests*/
565 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_ SimpleIterator *iterator)
566 {
567 FLAC__ASSERT(0 != iterator);
568 FLAC__ASSERT(0 != iterator->file);
569
570 return iterator->is_last;
571 }
572
573 /*@@@@add to tests*/
574 FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metad ata_SimpleIterator *iterator)
575 {
576 FLAC__ASSERT(0 != iterator);
577 FLAC__ASSERT(0 != iterator->file);
578
579 return iterator->offset[iterator->depth];
580 }
581
582 FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
583 {
584 FLAC__ASSERT(0 != iterator);
585 FLAC__ASSERT(0 != iterator->file);
586
587 return iterator->type;
588 }
589
590 /*@@@@add to tests*/
591 FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Me tadata_SimpleIterator *iterator)
592 {
593 FLAC__ASSERT(0 != iterator);
594 FLAC__ASSERT(0 != iterator->file);
595
596 return iterator->length;
597 }
598
599 /*@@@@add to tests*/
600 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Meta data_SimpleIterator *iterator, FLAC__byte *id)
601 {
602 const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
603
604 FLAC__ASSERT(0 != iterator);
605 FLAC__ASSERT(0 != iterator->file);
606 FLAC__ASSERT(0 != id);
607
608 if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) {
609 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL _INPUT;
610 return false;
611 }
612
613 if(fread(id, 1, id_bytes, iterator->file) != id_bytes) {
614 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ER ROR;
615 return false;
616 }
617
618 /* back up */
619 if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) {
620 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
621 return false;
622 }
623
624 return true;
625 }
626
627 FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Me tadata_SimpleIterator *iterator)
628 {
629 FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
630
631 FLAC__ASSERT(0 != iterator);
632 FLAC__ASSERT(0 != iterator->file);
633
634 if(0 != block) {
635 block->is_last = iterator->is_last;
636 block->length = iterator->length;
637
638 if(!read_metadata_block_data_(iterator, block)) {
639 FLAC__metadata_object_delete(block);
640 return 0;
641 }
642
643 /* back up to the beginning of the block data to stay consistent */
644 if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) {
645 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _SEEK_ERROR;
646 FLAC__metadata_object_delete(block);
647 return 0;
648 }
649 }
650 else
651 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ ALLOCATION_ERROR;
652
653 return block;
654 }
655
656 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_Simp leIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
657 {
658 FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->off set[iterator->depth];)
659 FLAC__bool ret;
660
661 FLAC__ASSERT(0 != iterator);
662 FLAC__ASSERT(0 != iterator->file);
663 FLAC__ASSERT(0 != block);
664
665 if(!iterator->is_writable) {
666 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRI TABLE;
667 return false;
668 }
669
670 if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FL AC__METADATA_TYPE_STREAMINFO) {
671 if(iterator->type != block->type) {
672 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _ILLEGAL_INPUT;
673 return false;
674 }
675 }
676
677 block->is_last = iterator->is_last;
678
679 if(iterator->length == block->length)
680 return write_metadata_block_stationary_(iterator, block);
681 else if(iterator->length > block->length) {
682 if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEAD ER_LENGTH + block->length) {
683 ret = write_metadata_block_stationary_with_padding_(iter ator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->len gth, block->is_last);
684 FLAC__ASSERT(!ret || iterator->offset[iterator->depth] = = debug_target_offset);
685 FLAC__ASSERT(!ret || ftello(iterator->file) == debug_tar get_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
686 return ret;
687 }
688 else {
689 ret = rewrite_whole_file_(iterator, block, /*append=*/fa lse);
690 FLAC__ASSERT(!ret || iterator->offset[iterator->depth] = = debug_target_offset);
691 FLAC__ASSERT(!ret || ftello(iterator->file) == debug_tar get_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
692 return ret;
693 }
694 }
695 else /* iterator->length < block->length */ {
696 unsigned padding_leftover = 0;
697 FLAC__bool padding_is_last = false;
698 if(use_padding) {
699 /* first see if we can even use padding */
700 if(iterator->is_last) {
701 use_padding = false;
702 }
703 else {
704 const unsigned extra_padding_bytes_required = bl ock->length - iterator->length;
705 simple_iterator_push_(iterator);
706 if(!FLAC__metadata_simple_iterator_next(iterator )) {
707 (void)simple_iterator_pop_(iterator);
708 return false;
709 }
710 if(iterator->type != FLAC__METADATA_TYPE_PADDING ) {
711 use_padding = false;
712 }
713 else {
714 if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
715 padding_leftover = 0;
716 block->is_last = iterator->is_la st;
717 }
718 else if(iterator->length < extra_padding _bytes_required)
719 use_padding = false;
720 else {
721 padding_leftover = FLAC__STREAM_ METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
722 padding_is_last = iterator->is_l ast;
723 block->is_last = false;
724 }
725 }
726 if(!simple_iterator_pop_(iterator))
727 return false;
728 }
729 }
730 if(use_padding) {
731 if(padding_leftover == 0) {
732 ret = write_metadata_block_stationary_(iterator, block);
733 FLAC__ASSERT(!ret || iterator->offset[iterator-> depth] == debug_target_offset);
734 FLAC__ASSERT(!ret || ftello(iterator->file) == d ebug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
735 return ret;
736 }
737 else {
738 FLAC__ASSERT(padding_leftover >= FLAC__STREAM_ME TADATA_HEADER_LENGTH);
739 ret = write_metadata_block_stationary_with_paddi ng_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, pad ding_is_last);
740 FLAC__ASSERT(!ret || iterator->offset[iterator-> depth] == debug_target_offset);
741 FLAC__ASSERT(!ret || ftello(iterator->file) == d ebug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
742 return ret;
743 }
744 }
745 else {
746 ret = rewrite_whole_file_(iterator, block, /*append=*/fa lse);
747 FLAC__ASSERT(!ret || iterator->offset[iterator->depth] = = debug_target_offset);
748 FLAC__ASSERT(!ret || ftello(iterator->file) == debug_tar get_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
749 return ret;
750 }
751 }
752 }
753
754 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Meta data_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_paddi ng)
755 {
756 unsigned padding_leftover = 0;
757 FLAC__bool padding_is_last = false;
758
759 FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->off set[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;)
760 FLAC__bool ret;
761
762 FLAC__ASSERT(0 != iterator);
763 FLAC__ASSERT(0 != iterator->file);
764 FLAC__ASSERT(0 != block);
765
766 if(!iterator->is_writable) {
767 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRI TABLE;
768 return false;
769 }
770
771 if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
772 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL _INPUT;
773 return false;
774 }
775
776 block->is_last = iterator->is_last;
777
778 if(use_padding) {
779 /* first see if we can even use padding */
780 if(iterator->is_last) {
781 use_padding = false;
782 }
783 else {
784 simple_iterator_push_(iterator);
785 if(!FLAC__metadata_simple_iterator_next(iterator)) {
786 (void)simple_iterator_pop_(iterator);
787 return false;
788 }
789 if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
790 use_padding = false;
791 }
792 else {
793 if(iterator->length == block->length) {
794 padding_leftover = 0;
795 block->is_last = iterator->is_last;
796 }
797 else if(iterator->length < FLAC__STREAM_METADATA _HEADER_LENGTH + block->length)
798 use_padding = false;
799 else {
800 padding_leftover = iterator->length - bl ock->length;
801 padding_is_last = iterator->is_last;
802 block->is_last = false;
803 }
804 }
805 if(!simple_iterator_pop_(iterator))
806 return false;
807 }
808 }
809 if(use_padding) {
810 /* move to the next block, which is suitable padding */
811 if(!FLAC__metadata_simple_iterator_next(iterator))
812 return false;
813 if(padding_leftover == 0) {
814 ret = write_metadata_block_stationary_(iterator, block);
815 FLAC__ASSERT(iterator->offset[iterator->depth] == debug_ target_offset);
816 FLAC__ASSERT(ftello(iterator->file) == debug_target_offs et + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
817 return ret;
818 }
819 else {
820 FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_H EADER_LENGTH);
821 ret = write_metadata_block_stationary_with_padding_(iter ator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_ last);
822 FLAC__ASSERT(iterator->offset[iterator->depth] == debug_ target_offset);
823 FLAC__ASSERT(ftello(iterator->file) == debug_target_offs et + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
824 return ret;
825 }
826 }
827 else {
828 ret = rewrite_whole_file_(iterator, block, /*append=*/true);
829 FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_o ffset);
830 FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FL AC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
831 return ret;
832 }
833 }
834
835 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_S impleIterator *iterator, FLAC__bool use_padding)
836 {
837 FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->off set[iterator->depth];)
838 FLAC__bool ret;
839
840 if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
841 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL _INPUT;
842 return false;
843 }
844
845 if(use_padding) {
846 FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__ METADATA_TYPE_PADDING);
847 if(0 == padding) {
848 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _MEMORY_ALLOCATION_ERROR;
849 return false;
850 }
851 padding->length = iterator->length;
852 if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
853 FLAC__metadata_object_delete(padding);
854 return false;
855 }
856 FLAC__metadata_object_delete(padding);
857 if(!FLAC__metadata_simple_iterator_prev(iterator))
858 return false;
859 FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FL AC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_targe t_offset);
860 FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->len gth == debug_target_offset);
861 return true;
862 }
863 else {
864 ret = rewrite_whole_file_(iterator, 0, /*append=*/false);
865 FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FL AC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_targe t_offset);
866 FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->len gth == debug_target_offset);
867 return ret;
868 }
869 }
870
871
872
873 /****************************************************************************
874 *
875 * Level 2 implementation
876 *
877 ***************************************************************************/
878
879
880 typedef struct FLAC__Metadata_Node {
881 FLAC__StreamMetadata *data;
882 struct FLAC__Metadata_Node *prev, *next;
883 } FLAC__Metadata_Node;
884
885 struct FLAC__Metadata_Chain {
886 char *filename; /* will be NULL if using callbacks */
887 FLAC__bool is_ogg;
888 FLAC__Metadata_Node *head;
889 FLAC__Metadata_Node *tail;
890 unsigned nodes;
891 FLAC__Metadata_ChainStatus status;
892 FLAC__off_t first_offset, last_offset;
893 /*
894 * This is the length of the chain initially read from the FLAC file.
895 * it is used to compare against the current length to decide whether
896 * or not the whole file has to be rewritten.
897 */
898 FLAC__off_t initial_length;
899 /* @@@ hacky, these are currently only needed by ogg reader */
900 FLAC__IOHandle handle;
901 FLAC__IOCallback_Read read_cb;
902 };
903
904 struct FLAC__Metadata_Iterator {
905 FLAC__Metadata_Chain *chain;
906 FLAC__Metadata_Node *current;
907 };
908
909 FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
910 "FLAC__METADATA_CHAIN_STATUS_OK",
911 "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
912 "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
913 "FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
914 "FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
915 "FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
916 "FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
917 "FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
918 "FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
919 "FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
920 "FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
921 "FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
922 "FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
923 "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
924 "FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
925 "FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
926 };
927
928
929 static FLAC__Metadata_Node *node_new_(void)
930 {
931 return calloc(1, sizeof(FLAC__Metadata_Node));
932 }
933
934 static void node_delete_(FLAC__Metadata_Node *node)
935 {
936 FLAC__ASSERT(0 != node);
937 if(0 != node->data)
938 FLAC__metadata_object_delete(node->data);
939 free(node);
940 }
941
942 static void chain_init_(FLAC__Metadata_Chain *chain)
943 {
944 FLAC__ASSERT(0 != chain);
945
946 chain->filename = 0;
947 chain->is_ogg = false;
948 chain->head = chain->tail = 0;
949 chain->nodes = 0;
950 chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
951 chain->initial_length = 0;
952 chain->read_cb = 0;
953 }
954
955 static void chain_clear_(FLAC__Metadata_Chain *chain)
956 {
957 FLAC__Metadata_Node *node, *next;
958
959 FLAC__ASSERT(0 != chain);
960
961 for(node = chain->head; node; ) {
962 next = node->next;
963 node_delete_(node);
964 node = next;
965 }
966
967 if(0 != chain->filename)
968 free(chain->filename);
969
970 chain_init_(chain);
971 }
972
973 static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
974 {
975 FLAC__ASSERT(0 != chain);
976 FLAC__ASSERT(0 != node);
977 FLAC__ASSERT(0 != node->data);
978
979 node->next = node->prev = 0;
980 node->data->is_last = true;
981 if(0 != chain->tail)
982 chain->tail->data->is_last = false;
983
984 if(0 == chain->head)
985 chain->head = node;
986 else {
987 FLAC__ASSERT(0 != chain->tail);
988 chain->tail->next = node;
989 node->prev = chain->tail;
990 }
991 chain->tail = node;
992 chain->nodes++;
993 }
994
995 static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
996 {
997 FLAC__ASSERT(0 != chain);
998 FLAC__ASSERT(0 != node);
999
1000 if(node == chain->head)
1001 chain->head = node->next;
1002 else
1003 node->prev->next = node->next;
1004
1005 if(node == chain->tail)
1006 chain->tail = node->prev;
1007 else
1008 node->next->prev = node->prev;
1009
1010 if(0 != chain->tail)
1011 chain->tail->data->is_last = true;
1012
1013 chain->nodes--;
1014 }
1015
1016 static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
1017 {
1018 chain_remove_node_(chain, node);
1019 node_delete_(node);
1020 }
1021
1022 static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
1023 {
1024 const FLAC__Metadata_Node *node;
1025 FLAC__off_t length = 0;
1026 for(node = chain->head; node; node = node->next)
1027 length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->len gth);
1028 return length;
1029 }
1030
1031 static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metad ata_Node *node)
1032 {
1033 FLAC__ASSERT(0 != node);
1034 FLAC__ASSERT(0 != node->data);
1035 FLAC__ASSERT(0 != iterator);
1036 FLAC__ASSERT(0 != iterator->current);
1037 FLAC__ASSERT(0 != iterator->chain);
1038 FLAC__ASSERT(0 != iterator->chain->head);
1039 FLAC__ASSERT(0 != iterator->chain->tail);
1040
1041 node->data->is_last = false;
1042
1043 node->prev = iterator->current->prev;
1044 node->next = iterator->current;
1045
1046 if(0 == node->prev)
1047 iterator->chain->head = node;
1048 else
1049 node->prev->next = node;
1050
1051 iterator->current->prev = node;
1052
1053 iterator->chain->nodes++;
1054 }
1055
1056 static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC_ _Metadata_Node *node)
1057 {
1058 FLAC__ASSERT(0 != node);
1059 FLAC__ASSERT(0 != node->data);
1060 FLAC__ASSERT(0 != iterator);
1061 FLAC__ASSERT(0 != iterator->current);
1062 FLAC__ASSERT(0 != iterator->chain);
1063 FLAC__ASSERT(0 != iterator->chain->head);
1064 FLAC__ASSERT(0 != iterator->chain->tail);
1065
1066 iterator->current->data->is_last = false;
1067
1068 node->prev = iterator->current;
1069 node->next = iterator->current->next;
1070
1071 if(0 == node->next)
1072 iterator->chain->tail = node;
1073 else
1074 node->next->prev = node;
1075
1076 node->prev->next = node;
1077
1078 iterator->chain->tail->data->is_last = true;
1079
1080 iterator->chain->nodes++;
1081 }
1082
1083 /* return true iff node and node->next are both padding */
1084 static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLA C__Metadata_Node *node)
1085 {
1086 if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
1087 const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + no de->next->data->length;
1088 node->data->length += growth;
1089
1090 chain_delete_node_(chain, node->next);
1091 return true;
1092 }
1093 else
1094 return false;
1095 }
1096
1097 /* Returns the new length of the chain, or 0 if there was an error. */
1098 /* WATCHOUT: This can get called multiple times before a write, so
1099 * it should still work when this happens.
1100 */
1101 /* WATCHOUT: Make sure to also update the logic in
1102 * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
1103 */
1104 static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__b ool use_padding)
1105 {
1106 FLAC__off_t current_length = chain_calculate_length_(chain);
1107
1108 if(use_padding) {
1109 /* if the metadata shrank and the last block is padding, we just extend the last padding block */
1110 if(current_length < chain->initial_length && chain->tail->data-> type == FLAC__METADATA_TYPE_PADDING) {
1111 const FLAC__off_t delta = chain->initial_length - curren t_length;
1112 chain->tail->data->length += delta;
1113 current_length += delta;
1114 FLAC__ASSERT(current_length == chain->initial_length);
1115 }
1116 /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
1117 else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEAD ER_LENGTH <= chain->initial_length) {
1118 FLAC__StreamMetadata *padding;
1119 FLAC__Metadata_Node *node;
1120 if(0 == (padding = FLAC__metadata_object_new(FLAC__METAD ATA_TYPE_PADDING))) {
1121 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMO RY_ALLOCATION_ERROR;
1122 return 0;
1123 }
1124 padding->length = chain->initial_length - (FLAC__STREAM_ METADATA_HEADER_LENGTH + current_length);
1125 if(0 == (node = node_new_())) {
1126 FLAC__metadata_object_delete(padding);
1127 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMO RY_ALLOCATION_ERROR;
1128 return 0;
1129 }
1130 node->data = padding;
1131 chain_append_node_(chain, node);
1132 current_length = chain_calculate_length_(chain);
1133 FLAC__ASSERT(current_length == chain->initial_length);
1134 }
1135 /* if the metadata grew but the last block is padding, try cutti ng the padding to restore the original length so we don't have to rewrite the wh ole file */
1136 else if(current_length > chain->initial_length) {
1137 const FLAC__off_t delta = current_length - chain->initia l_length;
1138 if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDIN G) {
1139 /* if the delta is exactly the size of the last padding block, remove the padding block */
1140 if((FLAC__off_t)chain->tail->data->length + (FLA C__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
1141 chain_delete_node_(chain, chain->tail);
1142 current_length = chain_calculate_length_ (chain);
1143 FLAC__ASSERT(current_length == chain->in itial_length);
1144 }
1145 /* if there is at least 'delta' bytes of padding , trim the padding down */
1146 else if((FLAC__off_t)chain->tail->data->length > = delta) {
1147 chain->tail->data->length -= delta;
1148 current_length -= delta;
1149 FLAC__ASSERT(current_length == chain->in itial_length);
1150 }
1151 }
1152 }
1153 }
1154
1155 return current_length;
1156 }
1157
1158 static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle han dle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallb ack_Tell tell_cb)
1159 {
1160 FLAC__Metadata_Node *node;
1161
1162 FLAC__ASSERT(0 != chain);
1163
1164 /* we assume we're already at the beginning of the file */
1165
1166 switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
1167 case 0:
1168 break;
1169 case 1:
1170 chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
1171 return false;
1172 case 2:
1173 chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1174 return false;
1175 case 3:
1176 chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_F ILE;
1177 return false;
1178 default:
1179 FLAC__ASSERT(0);
1180 return false;
1181 }
1182
1183 {
1184 FLAC__int64 pos = tell_cb(handle);
1185 if(pos < 0) {
1186 chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
1187 return false;
1188 }
1189 chain->first_offset = (FLAC__off_t)pos;
1190 }
1191
1192 {
1193 FLAC__bool is_last;
1194 FLAC__MetadataType type;
1195 unsigned length;
1196
1197 do {
1198 node = node_new_();
1199 if(0 == node) {
1200 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMO RY_ALLOCATION_ERROR;
1201 return false;
1202 }
1203
1204 if(!read_metadata_block_header_cb_(handle, read_cb, &is_ last, &type, &length)) {
1205 node_delete_(node);
1206 chain->status = FLAC__METADATA_CHAIN_STATUS_READ _ERROR;
1207 return false;
1208 }
1209
1210 node->data = FLAC__metadata_object_new(type);
1211 if(0 == node->data) {
1212 node_delete_(node);
1213 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMO RY_ALLOCATION_ERROR;
1214 return false;
1215 }
1216
1217 node->data->is_last = is_last;
1218 node->data->length = length;
1219
1220 chain->status = get_equivalent_status_(read_metadata_blo ck_data_cb_(handle, read_cb, seek_cb, node->data));
1221 if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
1222 node_delete_(node);
1223 return false;
1224 }
1225 chain_append_node_(chain, node);
1226 } while(!is_last);
1227 }
1228
1229 {
1230 FLAC__int64 pos = tell_cb(handle);
1231 if(pos < 0) {
1232 chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
1233 return false;
1234 }
1235 chain->last_offset = (FLAC__off_t)pos;
1236 }
1237
1238 chain->initial_length = chain_calculate_length_(chain);
1239
1240 return true;
1241 }
1242
1243 static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamD ecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
1244 {
1245 FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
1246 (void)decoder;
1247 if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) {
1248 *bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chai n->handle);
1249 if(*bytes == 0)
1250 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
1251 else
1252 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
1253 }
1254 else
1255 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
1256 }
1257
1258 static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__Strea mDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
1259 {
1260 (void)decoder, (void)frame, (void)buffer, (void)client_data;
1261 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
1262 }
1263
1264 static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, cons t FLAC__StreamMetadata *metadata, void *client_data)
1265 {
1266 FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
1267 FLAC__Metadata_Node *node;
1268
1269 (void)decoder;
1270
1271 node = node_new_();
1272 if(0 == node) {
1273 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ER ROR;
1274 return;
1275 }
1276
1277 node->data = FLAC__metadata_object_clone(metadata);
1278 if(0 == node->data) {
1279 node_delete_(node);
1280 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ER ROR;
1281 return;
1282 }
1283
1284 chain_append_node_(chain, node);
1285 }
1286
1287 static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__S treamDecoderErrorStatus status, void *client_data)
1288 {
1289 FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
1290 (void)decoder, (void)status;
1291 chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
1292 }
1293
1294 static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb)
1295 {
1296 FLAC__StreamDecoder *decoder;
1297
1298 FLAC__ASSERT(0 != chain);
1299
1300 /* we assume we're already at the beginning of the file */
1301
1302 chain->handle = handle;
1303 chain->read_cb = read_cb;
1304 if(0 == (decoder = FLAC__stream_decoder_new())) {
1305 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ER ROR;
1306 return false;
1307 }
1308 FLAC__stream_decoder_set_metadata_respond_all(decoder);
1309 if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_ , /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callbac k=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_err or_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
1310 FLAC__stream_decoder_delete(decoder);
1311 chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@ @ maybe needs better error code */
1312 return false;
1313 }
1314
1315 chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to i mplement metadata writing for Ogg FLAC */
1316
1317 if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
1318 chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@ @ maybe needs better error code */
1319 if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
1320 FLAC__stream_decoder_delete(decoder);
1321 return false;
1322 }
1323
1324 FLAC__stream_decoder_delete(decoder);
1325
1326 chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to im plement metadata writing for Ogg FLAC */
1327
1328 chain->initial_length = chain_calculate_length_(chain);
1329
1330 return true;
1331 }
1332
1333 static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chai n, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb)
1334 {
1335 FLAC__Metadata_Node *node;
1336
1337 FLAC__ASSERT(0 != chain);
1338 FLAC__ASSERT(0 != chain->head);
1339
1340 if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
1341 chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1342 return false;
1343 }
1344
1345 for(node = chain->head; node; node = node->next) {
1346 if(!write_metadata_block_header_cb_(handle, write_cb, node->data )) {
1347 chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
1348 return false;
1349 }
1350 if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
1351 chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
1352 return false;
1353 }
1354 }
1355
1356 /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
1357
1358 chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
1359 return true;
1360 }
1361
1362 static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
1363 {
1364 FILE *file;
1365 FLAC__bool ret;
1366
1367 FLAC__ASSERT(0 != chain->filename);
1368
1369 if(0 == (file = flac_fopen(chain->filename, "r+b"))) {
1370 chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
1371 return false;
1372 }
1373
1374 /* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
1375 ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, ( FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
1376
1377 fclose(file);
1378
1379 return ret;
1380 }
1381
1382 static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *t empfile_path_prefix)
1383 {
1384 FILE *f, *tempfile = NULL;
1385 char *tempfilename;
1386 FLAC__Metadata_SimpleIteratorStatus status;
1387 const FLAC__Metadata_Node *node;
1388
1389 FLAC__ASSERT(0 != chain);
1390 FLAC__ASSERT(0 != chain->filename);
1391 FLAC__ASSERT(0 != chain->head);
1392
1393 /* copy the file prefix (data up to first metadata block */
1394 if(0 == (f = flac_fopen(chain->filename, "rb"))) {
1395 chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
1396 return false;
1397 }
1398 if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &te mpfilename, &status)) {
1399 chain->status = get_equivalent_status_(status);
1400 goto err;
1401 }
1402 if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
1403 chain->status = get_equivalent_status_(status);
1404 goto err;
1405 }
1406
1407 /* write the metadata */
1408 for(node = chain->head; node; node = node->next) {
1409 if(!write_metadata_block_header_(tempfile, &status, node->data)) {
1410 chain->status = get_equivalent_status_(status);
1411 goto err;
1412 }
1413 if(!write_metadata_block_data_(tempfile, &status, node->data)) {
1414 chain->status = get_equivalent_status_(status);
1415 goto err;
1416 }
1417 }
1418 /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
1419
1420 /* copy the file postfix (everything after the metadata) */
1421 if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
1422 chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1423 goto err;
1424 }
1425 if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
1426 chain->status = get_equivalent_status_(status);
1427 goto err;
1428 }
1429
1430 /* move the tempfile on top of the original */
1431 (void)fclose(f);
1432 if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &stat us))
1433 return false;
1434
1435 return true;
1436
1437 err:
1438 (void)fclose(f);
1439 cleanup_tempfile_(&tempfile, &tempfilename);
1440 return false;
1441 }
1442
1443 /* assumes 'handle' is already at beginning of file */
1444 static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHa ndle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC_ _IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_ write_cb)
1445 {
1446 FLAC__Metadata_SimpleIteratorStatus status;
1447 const FLAC__Metadata_Node *node;
1448
1449 FLAC__ASSERT(0 != chain);
1450 FLAC__ASSERT(0 == chain->filename);
1451 FLAC__ASSERT(0 != chain->head);
1452
1453 /* copy the file prefix (data up to first metadata block */
1454 if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_ cb, chain->first_offset, &status)) {
1455 chain->status = get_equivalent_status_(status);
1456 return false;
1457 }
1458
1459 /* write the metadata */
1460 for(node = chain->head; node; node = node->next) {
1461 if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
1462 chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
1463 return false;
1464 }
1465 if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, no de->data)) {
1466 chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
1467 return false;
1468 }
1469 }
1470 /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
1471
1472 /* copy the file postfix (everything after the metadata) */
1473 if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
1474 chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1475 return false;
1476 }
1477 if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_han dle, temp_write_cb, &status)) {
1478 chain->status = get_equivalent_status_(status);
1479 return false;
1480 }
1481
1482 return true;
1483 }
1484
1485 FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
1486 {
1487 FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain));
1488
1489 if(0 != chain)
1490 chain_init_(chain);
1491
1492 return chain;
1493 }
1494
1495 FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
1496 {
1497 FLAC__ASSERT(0 != chain);
1498
1499 chain_clear_(chain);
1500
1501 free(chain);
1502 }
1503
1504 FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_C hain *chain)
1505 {
1506 FLAC__Metadata_ChainStatus status;
1507
1508 FLAC__ASSERT(0 != chain);
1509
1510 status = chain->status;
1511 chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
1512 return status;
1513 }
1514
1515 static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
1516 {
1517 FILE *file;
1518 FLAC__bool ret;
1519
1520 FLAC__ASSERT(0 != chain);
1521 FLAC__ASSERT(0 != filename);
1522
1523 chain_clear_(chain);
1524
1525 if(0 == (chain->filename = strdup(filename))) {
1526 chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ER ROR;
1527 return false;
1528 }
1529
1530 chain->is_ogg = is_ogg;
1531
1532 if(0 == (file = flac_fopen(filename, "rb"))) {
1533 chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
1534 return false;
1535 }
1536
1537 /* the function also sets chain->status for us */
1538 ret = is_ogg?
1539 chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) :
1540 chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_ wrapper_, ftell_wrapper_)
1541 ;
1542
1543 fclose(file);
1544
1545 return ret;
1546 }
1547
1548 FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
1549 {
1550 return chain_read_(chain, filename, /*is_ogg=*/false);
1551 }
1552
1553 /*@@@@add to tests*/
1554 FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, c onst char *filename)
1555 {
1556 return chain_read_(chain, filename, /*is_ogg=*/true);
1557 }
1558
1559 static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__ IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg)
1560 {
1561 FLAC__bool ret;
1562
1563 FLAC__ASSERT(0 != chain);
1564
1565 chain_clear_(chain);
1566
1567 if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
1568 chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
1569 return false;
1570 }
1571
1572 chain->is_ogg = is_ogg;
1573
1574 /* rewind */
1575 if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
1576 chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1577 return false;
1578 }
1579
1580 /* the function also sets chain->status for us */
1581 ret = is_ogg?
1582 chain_read_ogg_cb_(chain, handle, callbacks.read) :
1583 chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, ca llbacks.tell)
1584 ;
1585
1586 return ret;
1587 }
1588
1589 FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chai n *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
1590 {
1591 return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/f alse);
1592 }
1593
1594 /*@@@@add to tests*/
1595 FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_ Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
1596 {
1597 return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/t rue);
1598 }
1599
1600 FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata _Chain *chain, FLAC__bool use_padding)
1601 {
1602 /* This does all the same checks that are in chain_prepare_for_write_()
1603 * but doesn't actually alter the chain. Make sure to update the logic
1604 * here if chain_prepare_for_write_() changes.
1605 */
1606 const FLAC__off_t current_length = chain_calculate_length_(chain);
1607
1608 FLAC__ASSERT(0 != chain);
1609
1610 if(use_padding) {
1611 /* if the metadata shrank and the last block is padding, we just extend the last padding block */
1612 if(current_length < chain->initial_length && chain->tail->data-> type == FLAC__METADATA_TYPE_PADDING)
1613 return false;
1614 /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
1615 else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEAD ER_LENGTH <= chain->initial_length)
1616 return false;
1617 /* if the metadata grew but the last block is padding, try cutti ng the padding to restore the original length so we don't have to rewrite the wh ole file */
1618 else if(current_length > chain->initial_length) {
1619 const FLAC__off_t delta = current_length - chain->initia l_length;
1620 if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDIN G) {
1621 /* if the delta is exactly the size of the last padding block, remove the padding block */
1622 if((FLAC__off_t)chain->tail->data->length + (FLA C__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta)
1623 return false;
1624 /* if there is at least 'delta' bytes of padding , trim the padding down */
1625 else if((FLAC__off_t)chain->tail->data->length > = delta)
1626 return false;
1627 }
1628 }
1629 }
1630
1631 return (current_length != chain->initial_length);
1632 }
1633
1634 FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC __bool use_padding, FLAC__bool preserve_file_stats)
1635 {
1636 struct flac_stat_s stats;
1637 const char *tempfile_path_prefix = 0;
1638 FLAC__off_t current_length;
1639
1640 FLAC__ASSERT(0 != chain);
1641
1642 if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
1643 chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
1644 return false;
1645 }
1646
1647 if (0 == chain->filename) {
1648 chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
1649 return false;
1650 }
1651
1652 current_length = chain_prepare_for_write_(chain, use_padding);
1653
1654 /* a return value of 0 means there was an error; chain->status is alread y set */
1655 if (0 == current_length)
1656 return false;
1657
1658 if(preserve_file_stats)
1659 get_file_stats_(chain->filename, &stats);
1660
1661 if(current_length == chain->initial_length) {
1662 if(!chain_rewrite_metadata_in_place_(chain))
1663 return false;
1664 }
1665 else {
1666 if(!chain_rewrite_file_(chain, tempfile_path_prefix))
1667 return false;
1668
1669 /* recompute lengths and offsets */
1670 {
1671 const FLAC__Metadata_Node *node;
1672 chain->initial_length = current_length;
1673 chain->last_offset = chain->first_offset;
1674 for(node = chain->head; node; node = node->next)
1675 chain->last_offset += (FLAC__STREAM_METADATA_HEA DER_LENGTH + node->data->length);
1676 }
1677 }
1678
1679 if(preserve_file_stats)
1680 set_file_stats_(chain->filename, &stats);
1681
1682 return true;
1683 }
1684
1685 FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Cha in *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks call backs)
1686 {
1687 FLAC__off_t current_length;
1688
1689 FLAC__ASSERT(0 != chain);
1690
1691 if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
1692 chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
1693 return false;
1694 }
1695
1696 if (0 != chain->filename) {
1697 chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
1698 return false;
1699 }
1700
1701 if (0 == callbacks.write || 0 == callbacks.seek) {
1702 chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
1703 return false;
1704 }
1705
1706 if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
1707 chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
1708 return false;
1709 }
1710
1711 current_length = chain_prepare_for_write_(chain, use_padding);
1712
1713 /* a return value of 0 means there was an error; chain->status is alread y set */
1714 if (0 == current_length)
1715 return false;
1716
1717 FLAC__ASSERT(current_length == chain->initial_length);
1718
1719 return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.writ e, callbacks.seek);
1720 }
1721
1722 FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC_ _Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOC allbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks )
1723 {
1724 FLAC__off_t current_length;
1725
1726 FLAC__ASSERT(0 != chain);
1727
1728 if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
1729 chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
1730 return false;
1731 }
1732
1733 if (0 != chain->filename) {
1734 chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
1735 return false;
1736 }
1737
1738 if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
1739 chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
1740 return false;
1741 }
1742 if (0 == temp_callbacks.write) {
1743 chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
1744 return false;
1745 }
1746
1747 if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
1748 chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
1749 return false;
1750 }
1751
1752 current_length = chain_prepare_for_write_(chain, use_padding);
1753
1754 /* a return value of 0 means there was an error; chain->status is alread y set */
1755 if (0 == current_length)
1756 return false;
1757
1758 FLAC__ASSERT(current_length != chain->initial_length);
1759
1760 /* rewind */
1761 if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
1762 chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1763 return false;
1764 }
1765
1766 if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek , callbacks.eof, temp_handle, temp_callbacks.write))
1767 return false;
1768
1769 /* recompute lengths and offsets */
1770 {
1771 const FLAC__Metadata_Node *node;
1772 chain->initial_length = current_length;
1773 chain->last_offset = chain->first_offset;
1774 for(node = chain->head; node; node = node->next)
1775 chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENG TH + node->data->length);
1776 }
1777
1778 return true;
1779 }
1780
1781 FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
1782 {
1783 FLAC__Metadata_Node *node;
1784
1785 FLAC__ASSERT(0 != chain);
1786
1787 for(node = chain->head; node; ) {
1788 if(!chain_merge_adjacent_padding_(chain, node))
1789 node = node->next;
1790 }
1791 }
1792
1793 FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
1794 {
1795 FLAC__Metadata_Node *node, *save;
1796 unsigned i;
1797
1798 FLAC__ASSERT(0 != chain);
1799
1800 /*
1801 * Don't try and be too smart... this simple algo is good enough for
1802 * the small number of nodes that we deal with.
1803 */
1804 for(i = 0, node = chain->head; i < chain->nodes; i++) {
1805 if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
1806 save = node->next;
1807 chain_remove_node_(chain, node);
1808 chain_append_node_(chain, node);
1809 node = save;
1810 }
1811 else {
1812 node = node->next;
1813 }
1814 }
1815
1816 FLAC__metadata_chain_merge_padding(chain);
1817 }
1818
1819
1820 FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
1821 {
1822 FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iter ator));
1823
1824 /* calloc() implies:
1825 iterator->current = 0;
1826 iterator->chain = 0;
1827 */
1828
1829 return iterator;
1830 }
1831
1832 FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
1833 {
1834 FLAC__ASSERT(0 != iterator);
1835
1836 free(iterator);
1837 }
1838
1839 FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FL AC__Metadata_Chain *chain)
1840 {
1841 FLAC__ASSERT(0 != iterator);
1842 FLAC__ASSERT(0 != chain);
1843 FLAC__ASSERT(0 != chain->head);
1844
1845 iterator->chain = chain;
1846 iterator->current = chain->head;
1847 }
1848
1849 FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterat or)
1850 {
1851 FLAC__ASSERT(0 != iterator);
1852
1853 if(0 == iterator->current || 0 == iterator->current->next)
1854 return false;
1855
1856 iterator->current = iterator->current->next;
1857 return true;
1858 }
1859
1860 FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterat or)
1861 {
1862 FLAC__ASSERT(0 != iterator);
1863
1864 if(0 == iterator->current || 0 == iterator->current->prev)
1865 return false;
1866
1867 iterator->current = iterator->current->prev;
1868 return true;
1869 }
1870
1871 FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__M etadata_Iterator *iterator)
1872 {
1873 FLAC__ASSERT(0 != iterator);
1874 FLAC__ASSERT(0 != iterator->current);
1875 FLAC__ASSERT(0 != iterator->current->data);
1876
1877 return iterator->current->data->type;
1878 }
1879
1880 FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_ Iterator *iterator)
1881 {
1882 FLAC__ASSERT(0 != iterator);
1883 FLAC__ASSERT(0 != iterator->current);
1884
1885 return iterator->current->data;
1886 }
1887
1888 FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *i terator, FLAC__StreamMetadata *block)
1889 {
1890 FLAC__ASSERT(0 != iterator);
1891 FLAC__ASSERT(0 != block);
1892 return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__me tadata_iterator_insert_block_after(iterator, block);
1893 }
1894
1895 FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
1896 {
1897 FLAC__Metadata_Node *save;
1898
1899 FLAC__ASSERT(0 != iterator);
1900 FLAC__ASSERT(0 != iterator->current);
1901
1902 if(0 == iterator->current->prev) {
1903 FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYP E_STREAMINFO);
1904 return false;
1905 }
1906
1907 save = iterator->current->prev;
1908
1909 if(replace_with_padding) {
1910 FLAC__metadata_object_delete_data(iterator->current->data);
1911 iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
1912 }
1913 else {
1914 chain_delete_node_(iterator->chain, iterator->current);
1915 }
1916
1917 iterator->current = save;
1918 return true;
1919 }
1920
1921 FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_I terator *iterator, FLAC__StreamMetadata *block)
1922 {
1923 FLAC__Metadata_Node *node;
1924
1925 FLAC__ASSERT(0 != iterator);
1926 FLAC__ASSERT(0 != iterator->current);
1927 FLAC__ASSERT(0 != block);
1928
1929 if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
1930 return false;
1931
1932 if(0 == iterator->current->prev) {
1933 FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYP E_STREAMINFO);
1934 return false;
1935 }
1936
1937 if(0 == (node = node_new_()))
1938 return false;
1939
1940 node->data = block;
1941 iterator_insert_node_(iterator, node);
1942 iterator->current = node;
1943 return true;
1944 }
1945
1946 FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_It erator *iterator, FLAC__StreamMetadata *block)
1947 {
1948 FLAC__Metadata_Node *node;
1949
1950 FLAC__ASSERT(0 != iterator);
1951 FLAC__ASSERT(0 != iterator->current);
1952 FLAC__ASSERT(0 != block);
1953
1954 if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
1955 return false;
1956
1957 if(0 == (node = node_new_()))
1958 return false;
1959
1960 node->data = block;
1961 iterator_insert_node_after_(iterator, node);
1962 iterator->current = node;
1963 return true;
1964 }
1965
1966
1967 /****************************************************************************
1968 *
1969 * Local function definitions
1970 *
1971 ***************************************************************************/
1972
1973 void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
1974 {
1975 unsigned i;
1976
1977 b += bytes;
1978
1979 for(i = 0; i < bytes; i++) {
1980 *(--b) = (FLAC__byte)(val & 0xff);
1981 val >>= 8;
1982 }
1983 }
1984
1985 void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
1986 {
1987 unsigned i;
1988
1989 for(i = 0; i < bytes; i++) {
1990 *(b++) = (FLAC__byte)(val & 0xff);
1991 val >>= 8;
1992 }
1993 }
1994
1995 void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes)
1996 {
1997 unsigned i;
1998
1999 b += bytes;
2000
2001 for(i = 0; i < bytes; i++) {
2002 *(--b) = (FLAC__byte)(val & 0xff);
2003 val >>= 8;
2004 }
2005 }
2006
2007 FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes)
2008 {
2009 FLAC__uint32 ret = 0;
2010 unsigned i;
2011
2012 for(i = 0; i < bytes; i++)
2013 ret = (ret << 8) | (FLAC__uint32)(*b++);
2014
2015 return ret;
2016 }
2017
2018 FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes)
2019 {
2020 FLAC__uint32 ret = 0;
2021 unsigned i;
2022
2023 b += bytes;
2024
2025 for(i = 0; i < bytes; i++)
2026 ret = (ret << 8) | (FLAC__uint32)(*--b);
2027
2028 return ret;
2029 }
2030
2031 FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes)
2032 {
2033 FLAC__uint64 ret = 0;
2034 unsigned i;
2035
2036 for(i = 0; i < bytes; i++)
2037 ret = (ret << 8) | (FLAC__uint64)(*b++);
2038
2039 return ret;
2040 }
2041
2042 FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
2043 {
2044 FLAC__ASSERT(0 != iterator);
2045 FLAC__ASSERT(0 != iterator->file);
2046
2047 if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC __IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length) ) {
2048 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ER ROR;
2049 return false;
2050 }
2051
2052 return true;
2053 }
2054
2055 FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FL AC__StreamMetadata *block)
2056 {
2057 FLAC__ASSERT(0 != iterator);
2058 FLAC__ASSERT(0 != iterator->file);
2059
2060 iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator ->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
2061
2062 return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
2063 }
2064
2065 FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallbac k_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length)
2066 {
2067 FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
2068
2069 if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) ! = FLAC__STREAM_METADATA_HEADER_LENGTH)
2070 return false;
2071
2072 *is_last = raw_header[0] & 0x80? true : false;
2073 *type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
2074 *length = unpack_uint32_(raw_header + 1, 3);
2075
2076 /* Note that we don't check:
2077 * if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
2078 * we just will read in an opaque block
2079 */
2080
2081 return true;
2082 }
2083
2084 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__Stre amMetadata *block)
2085 {
2086 switch(block->type) {
2087 case FLAC__METADATA_TYPE_STREAMINFO:
2088 return read_metadata_block_data_streaminfo_cb_(handle, r ead_cb, &block->data.stream_info);
2089 case FLAC__METADATA_TYPE_PADDING:
2090 return read_metadata_block_data_padding_cb_(handle, seek _cb, &block->data.padding, block->length);
2091 case FLAC__METADATA_TYPE_APPLICATION:
2092 return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
2093 case FLAC__METADATA_TYPE_SEEKTABLE:
2094 return read_metadata_block_data_seektable_cb_(handle, re ad_cb, &block->data.seek_table, block->length);
2095 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
2096 return read_metadata_block_data_vorbis_comment_cb_(handl e, read_cb, seek_cb, &block->data.vorbis_comment, block->length);
2097 case FLAC__METADATA_TYPE_CUESHEET:
2098 return read_metadata_block_data_cuesheet_cb_(handle, rea d_cb, &block->data.cue_sheet);
2099 case FLAC__METADATA_TYPE_PICTURE:
2100 return read_metadata_block_data_picture_cb_(handle, read _cb, &block->data.picture);
2101 default:
2102 return read_metadata_block_data_unknown_cb_(handle, read _cb, &block->data.unknown, block->length);
2103 }
2104 }
2105
2106 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC __IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInf o *block)
2107 {
2108 FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
2109
2110 if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) ! = FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
2111 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2112
2113 b = buffer;
2114
2115 /* we are using hardcoded numbers for simplicity but we should
2116 * probably eventually write a bit-level unpacker and use the
2117 * _STREAMINFO_ constants.
2118 */
2119 block->min_blocksize = unpack_uint32_(b, 2); b += 2;
2120 block->max_blocksize = unpack_uint32_(b, 2); b += 2;
2121 block->min_framesize = unpack_uint32_(b, 3); b += 3;
2122 block->max_framesize = unpack_uint32_(b, 3); b += 3;
2123 block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((unsigned)(b[2] & 0x f0) >> 4);
2124 block->channels = (unsigned)((b[2] & 0x0e) >> 1) + 1;
2125 block->bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 4) | (((unsigned )(b[3] & 0xf0)) >> 4)) + 1;
2126 block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_ui nt64_(b+4, 4);
2127 memcpy(block->md5sum, b+8, 16);
2128
2129 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2130 }
2131
2132 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__I OHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *blo ck, unsigned block_length)
2133 {
2134 (void)block; /* nothing to do; we don't care about reading the padding b ytes */
2135
2136 if(0 != seek_cb(handle, block_length, SEEK_CUR))
2137 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2138
2139 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2140 }
2141
2142 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLA C__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Applicat ion *block, unsigned block_length)
2143 {
2144 const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
2145
2146 if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
2147 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2148
2149 if(block_length < id_bytes)
2150 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2151
2152 block_length -= id_bytes;
2153
2154 if(block_length == 0) {
2155 block->data = 0;
2156 }
2157 else {
2158 if(0 == (block->data = malloc(block_length)))
2159 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLO CATION_ERROR;
2160
2161 if(read_cb(block->data, 1, block_length, handle) != block_length )
2162 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2163 }
2164
2165 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2166 }
2167
2168 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC_ _IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length)
2169 {
2170 unsigned i;
2171 FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
2172
2173 FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0) ;
2174
2175 block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGT H;
2176
2177 if(block->num_points == 0)
2178 block->points = 0;
2179 else if(0 == (block->points = safe_malloc_mul_2op_p(block->num_points, / *times*/sizeof(FLAC__StreamMetadata_SeekPoint))))
2180 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_E RROR;
2181
2182 for(i = 0; i < block->num_points; i++) {
2183 if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, ha ndle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
2184 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2185 /* some MAGIC NUMBERs here */
2186 block->points[i].sample_number = unpack_uint64_(buffer, 8);
2187 block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
2188 block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
2189 }
2190
2191 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2192 }
2193
2194 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entr y_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata _VorbisComment_Entry *entry, unsigned max_length)
2195 {
2196 const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_E NTRY_LENGTH_LEN / 8;
2197 FLAC__byte buffer[4]; /* magic number is asserted below */
2198
2199 FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 = = sizeof(buffer));
2200
2201 if(max_length < entry_length_len)
2202 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
2203
2204 max_length -= entry_length_len;
2205 if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
2206 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2207 entry->length = unpack_uint32_little_endian_(buffer, entry_length_len);
2208 if(max_length < entry->length) {
2209 entry->length = 0;
2210 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
2211 } else max_length -= entry->length;
2212
2213 if(0 != entry->entry)
2214 free(entry->entry);
2215
2216 if(entry->length == 0) {
2217 entry->entry = 0;
2218 }
2219 else {
2220 if(0 == (entry->entry = safe_malloc_add_2op_(entry->length, /*+* /1)))
2221 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLO CATION_ERROR;
2222
2223 if(read_cb(entry->entry, 1, entry->length, handle) != entry->len gth)
2224 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2225
2226 entry->entry[entry->length] = '\0';
2227 }
2228
2229 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2230 }
2231
2232 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_( FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek _cb, FLAC__StreamMetadata_VorbisComment *block, unsigned block_length)
2233 {
2234 unsigned i;
2235 FLAC__Metadata_SimpleIteratorStatus status;
2236 const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_N UM_COMMENTS_LEN / 8;
2237 FLAC__byte buffer[4]; /* magic number is asserted below */
2238
2239 FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 = = sizeof(buffer));
2240
2241 status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_ cb, &(block->vendor_string), block_length);
2242 if(block_length >= 4)
2243 block_length -= 4;
2244 if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA)
2245 goto skip;
2246 else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
2247 return status;
2248 block_length -= block->vendor_string.length;
2249
2250 if(block_length < num_comments_len) goto skip; else block_length -= num_ comments_len;
2251 if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
2252 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2253 block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_ len);
2254
2255 if(block->num_comments == 0) {
2256 block->comments = 0;
2257 }
2258 else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC_ _StreamMetadata_VorbisComment_Entry))))
2259 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_E RROR;
2260
2261 for(i = 0; i < block->num_comments; i++) {
2262 status = read_metadata_block_data_vorbis_comment_entry_cb_(handl e, read_cb, block->comments + i, block_length);
2263 if(block_length >= 4) block_length -= 4;
2264 if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) {
2265 block->num_comments = i;
2266 goto skip;
2267 }
2268 else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) retu rn status;
2269 block_length -= block->comments[i].length;
2270 }
2271
2272 skip:
2273 if(block_length > 0) {
2274 /* bad metadata */
2275 if(0 != seek_cb(handle, block_length, SEEK_CUR))
2276 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2277 }
2278
2279 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2280 }
2281
2282 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_( FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSh eet_Track *track)
2283 {
2284 unsigned i, len;
2285 FLAC__byte buffer[32]; /* asserted below that this is big enough */
2286
2287 FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
2288 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESE RVED_LEN/8);
2289 FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYP E_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_MET ADATA_CUESHEET_TRACK_RESERVED_LEN) / 8);
2290
2291 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
2292 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
2293 if(read_cb(buffer, 1, len, handle) != len)
2294 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2295 track->offset = unpack_uint64_(buffer, len);
2296
2297 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
2298 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
2299 if(read_cb(buffer, 1, len, handle) != len)
2300 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2301 track->number = (FLAC__byte)unpack_uint32_(buffer, len);
2302
2303 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
2304 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
2305 if(read_cb(track->isrc, 1, len, handle) != len)
2306 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2307
2308 FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STRE AM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRA CK_RESERVED_LEN) % 8 == 0);
2309 len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_META DATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESE RVED_LEN) / 8;
2310 if(read_cb(buffer, 1, len, handle) != len)
2311 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2312 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1);
2313 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1) ;
2314 track->type = buffer[0] >> 7;
2315 track->pre_emphasis = (buffer[0] >> 6) & 1;
2316
2317 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
2318 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
2319 if(read_cb(buffer, 1, len, handle) != len)
2320 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2321 track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
2322
2323 if(track->num_indices == 0) {
2324 track->indices = 0;
2325 }
2326 else if(0 == (track->indices = calloc(track->num_indices, sizeof(FLAC__S treamMetadata_CueSheet_Index))))
2327 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_E RROR;
2328
2329 for(i = 0; i < track->num_indices; i++) {
2330 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
2331 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
2332 if(read_cb(buffer, 1, len, handle) != len)
2333 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2334 track->indices[i].offset = unpack_uint64_(buffer, len);
2335
2336 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
2337 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
2338 if(read_cb(buffer, 1, len, handle) != len)
2339 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2340 track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, le n);
2341
2342 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
2343 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
2344 if(read_cb(buffer, 1, len, handle) != len)
2345 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2346 }
2347
2348 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2349 }
2350
2351 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__ IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *b lock)
2352 {
2353 unsigned i, len;
2354 FLAC__Metadata_SimpleIteratorStatus status;
2355 FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
2356
2357 FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_ME TADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer));
2358 FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer));
2359
2360 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
2361 len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
2362 if(read_cb(block->media_catalog_number, 1, len, handle) != len)
2363 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2364
2365 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
2366 len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
2367 if(read_cb(buffer, 1, len, handle) != len)
2368 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2369 block->lead_in = unpack_uint64_(buffer, len);
2370
2371 FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_ME TADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
2372 len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_ CUESHEET_RESERVED_LEN) / 8;
2373 if(read_cb(buffer, 1, len, handle) != len)
2374 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2375 block->is_cd = buffer[0]&0x80? true : false;
2376
2377 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
2378 len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
2379 if(read_cb(buffer, 1, len, handle) != len)
2380 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2381 block->num_tracks = unpack_uint32_(buffer, len);
2382
2383 if(block->num_tracks == 0) {
2384 block->tracks = 0;
2385 }
2386 else if(0 == (block->tracks = calloc(block->num_tracks, sizeof(FLAC__Str eamMetadata_CueSheet_Track))))
2387 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_E RROR;
2388
2389 for(i = 0; i < block->num_tracks; i++) {
2390 if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_me tadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
2391 return status;
2392 }
2393
2394 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2395 }
2396
2397 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstr ing_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len)
2398 {
2399 FLAC__byte buffer[sizeof(FLAC__uint32)];
2400
2401 FLAC__ASSERT(0 != data);
2402 FLAC__ASSERT(length_len%8 == 0);
2403
2404 length_len /= 8; /* convert to bytes */
2405
2406 FLAC__ASSERT(sizeof(buffer) >= length_len);
2407
2408 if(read_cb(buffer, 1, length_len, handle) != length_len)
2409 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2410 *length = unpack_uint32_(buffer, length_len);
2411
2412 if(0 != *data)
2413 free(*data);
2414
2415 if(0 == (*data = safe_malloc_add_2op_(*length, /*+*/1)))
2416 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_E RROR;
2417
2418 if(*length > 0) {
2419 if(read_cb(*data, 1, *length, handle) != *length)
2420 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2421 }
2422
2423 (*data)[*length] = '\0';
2424
2425 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2426 }
2427
2428 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__I OHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *blo ck)
2429 {
2430 FLAC__Metadata_SimpleIteratorStatus status;
2431 FLAC__byte buffer[4]; /* asserted below that this is big enough */
2432 FLAC__uint32 len;
2433
2434 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8) ;
2435 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8 );
2436 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/ 8);
2437 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8 );
2438 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/ 8);
2439
2440 FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0);
2441 len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8;
2442 if(read_cb(buffer, 1, len, handle) != len)
2443 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2444 block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len);
2445
2446 if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_c b, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME _TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
2447 return status;
2448
2449 if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_c b, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH _LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
2450 return status;
2451
2452 FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0);
2453 len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8;
2454 if(read_cb(buffer, 1, len, handle) != len)
2455 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2456 block->width = unpack_uint32_(buffer, len);
2457
2458 FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0);
2459 len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8;
2460 if(read_cb(buffer, 1, len, handle) != len)
2461 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2462 block->height = unpack_uint32_(buffer, len);
2463
2464 FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0);
2465 len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8;
2466 if(read_cb(buffer, 1, len, handle) != len)
2467 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2468 block->depth = unpack_uint32_(buffer, len);
2469
2470 FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_COLORS_LEN % 8 == 0);
2471 len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8;
2472 if(read_cb(buffer, 1, len, handle) != len)
2473 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2474 block->colors = unpack_uint32_(buffer, len);
2475
2476 /* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */
2477 if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_c b, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LEN GTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
2478 return status;
2479
2480 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2481 }
2482
2483 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__I OHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *blo ck, unsigned block_length)
2484 {
2485 if(block_length == 0) {
2486 block->data = 0;
2487 }
2488 else {
2489 if(0 == (block->data = malloc(block_length)))
2490 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLO CATION_ERROR;
2491
2492 if(read_cb(block->data, 1, block_length, handle) != block_length )
2493 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2494 }
2495
2496 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2497 }
2498
2499 FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIterato rStatus *status, const FLAC__StreamMetadata *block)
2500 {
2501 FLAC__ASSERT(0 != file);
2502 FLAC__ASSERT(0 != status);
2503
2504 if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallb ack_Write)fwrite, block)) {
2505 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
2506 return false;
2507 }
2508
2509 return true;
2510 }
2511
2512 FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorS tatus *status, const FLAC__StreamMetadata *block)
2513 {
2514 FLAC__ASSERT(0 != file);
2515 FLAC__ASSERT(0 != status);
2516
2517 if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallbac k_Write)fwrite, block)) {
2518 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2519 return true;
2520 }
2521 else {
2522 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
2523 return false;
2524 }
2525 }
2526
2527 FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallba ck_Write write_cb, const FLAC__StreamMetadata *block)
2528 {
2529 FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
2530
2531 FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
2532
2533 buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
2534 pack_uint32_(block->length, buffer + 1, 3);
2535
2536 if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != F LAC__STREAM_METADATA_HEADER_LENGTH)
2537 return false;
2538
2539 return true;
2540 }
2541
2542 FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback _Write write_cb, const FLAC__StreamMetadata *block)
2543 {
2544 FLAC__ASSERT(0 != block);
2545
2546 switch(block->type) {
2547 case FLAC__METADATA_TYPE_STREAMINFO:
2548 return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
2549 case FLAC__METADATA_TYPE_PADDING:
2550 return write_metadata_block_data_padding_cb_(handle, wri te_cb, &block->data.padding, block->length);
2551 case FLAC__METADATA_TYPE_APPLICATION:
2552 return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
2553 case FLAC__METADATA_TYPE_SEEKTABLE:
2554 return write_metadata_block_data_seektable_cb_(handle, w rite_cb, &block->data.seek_table);
2555 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
2556 return write_metadata_block_data_vorbis_comment_cb_(hand le, write_cb, &block->data.vorbis_comment);
2557 case FLAC__METADATA_TYPE_CUESHEET:
2558 return write_metadata_block_data_cuesheet_cb_(handle, wr ite_cb, &block->data.cue_sheet);
2559 case FLAC__METADATA_TYPE_PICTURE:
2560 return write_metadata_block_data_picture_cb_(handle, wri te_cb, &block->data.picture);
2561 default:
2562 return write_metadata_block_data_unknown_cb_(handle, wri te_cb, &block->data.unknown, block->length);
2563 }
2564 }
2565
2566 FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC_ _IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
2567 {
2568 FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
2569 const unsigned channels1 = block->channels - 1;
2570 const unsigned bps1 = block->bits_per_sample - 1;
2571
2572 /* we are using hardcoded numbers for simplicity but we should
2573 * probably eventually write a bit-level packer and use the
2574 * _STREAMINFO_ constants.
2575 */
2576 pack_uint32_(block->min_blocksize, buffer, 2);
2577 pack_uint32_(block->max_blocksize, buffer+2, 2);
2578 pack_uint32_(block->min_framesize, buffer+4, 3);
2579 pack_uint32_(block->max_framesize, buffer+7, 3);
2580 buffer[10] = (block->sample_rate >> 12) & 0xff;
2581 buffer[11] = (block->sample_rate >> 4) & 0xff;
2582 buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bp s1 >> 4);
2583 buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
2584 pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
2585 memcpy(buffer+18, block->md5sum, 16);
2586
2587 if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
2588 return false;
2589
2590 return true;
2591 }
2592
2593 FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IO Callback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned blo ck_length)
2594 {
2595 unsigned i, n = block_length;
2596 FLAC__byte buffer[1024];
2597
2598 (void)block;
2599
2600 memset(buffer, 0, 1024);
2601
2602 for(i = 0; i < n/1024; i++)
2603 if(write_cb(buffer, 1, 1024, handle) != 1024)
2604 return false;
2605
2606 n %= 1024;
2607
2608 if(write_cb(buffer, 1, n, handle) != n)
2609 return false;
2610
2611 return true;
2612 }
2613
2614 FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC __IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsi gned block_length)
2615 {
2616 const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
2617
2618 if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
2619 return false;
2620
2621 block_length -= id_bytes;
2622
2623 if(write_cb(block->data, 1, block_length, handle) != block_length)
2624 return false;
2625
2626 return true;
2627 }
2628
2629 FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__ IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
2630 {
2631 unsigned i;
2632 FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
2633
2634 for(i = 0; i < block->num_points; i++) {
2635 /* some MAGIC NUMBERs here */
2636 pack_uint64_(block->points[i].sample_number, buffer, 8);
2637 pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
2638 pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
2639 if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, h andle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
2640 return false;
2641 }
2642
2643 return true;
2644 }
2645
2646 FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, F LAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
2647 {
2648 unsigned i;
2649 const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_E NTRY_LENGTH_LEN / 8;
2650 const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_N UM_COMMENTS_LEN / 8;
2651 FLAC__byte buffer[4]; /* magic number is asserted below */
2652
2653 FLAC__ASSERT(flac_max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_ LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer ));
2654
2655 pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_le ngth_len);
2656 if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
2657 return false;
2658 if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
2659 return false;
2660
2661 pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len );
2662 if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
2663 return false;
2664
2665 for(i = 0; i < block->num_comments; i++) {
2666 pack_uint32_little_endian_(block->comments[i].length, buffer, en try_length_len);
2667 if(write_cb(buffer, 1, entry_length_len, handle) != entry_length _len)
2668 return false;
2669 if(write_cb(block->comments[i].entry, 1, block->comments[i].leng th, handle) != block->comments[i].length)
2670 return false;
2671 }
2672
2673 return true;
2674 }
2675
2676 FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__I OCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
2677 {
2678 unsigned i, j, len;
2679 FLAC__byte buffer[1024]; /* asserted below that this is big enough */
2680
2681 FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
2682 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_L EN/8);
2683 FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYP E_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_MET ADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8) ;
2684 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESE RVED_LEN/8);
2685
2686 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
2687 len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
2688 if(write_cb(block->media_catalog_number, 1, len, handle) != len)
2689 return false;
2690
2691 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
2692 len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
2693 pack_uint64_(block->lead_in, buffer, len);
2694 if(write_cb(buffer, 1, len, handle) != len)
2695 return false;
2696
2697 FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_ME TADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
2698 len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_ CUESHEET_RESERVED_LEN) / 8;
2699 memset(buffer, 0, len);
2700 if(block->is_cd)
2701 buffer[0] |= 0x80;
2702 if(write_cb(buffer, 1, len, handle) != len)
2703 return false;
2704
2705 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
2706 len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
2707 pack_uint32_(block->num_tracks, buffer, len);
2708 if(write_cb(buffer, 1, len, handle) != len)
2709 return false;
2710
2711 for(i = 0; i < block->num_tracks; i++) {
2712 FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
2713
2714 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
2715 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
2716 pack_uint64_(track->offset, buffer, len);
2717 if(write_cb(buffer, 1, len, handle) != len)
2718 return false;
2719
2720 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
2721 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
2722 pack_uint32_(track->number, buffer, len);
2723 if(write_cb(buffer, 1, len, handle) != len)
2724 return false;
2725
2726 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 = = 0);
2727 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
2728 if(write_cb(track->isrc, 1, len, handle) != len)
2729 return false;
2730
2731 FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FL AC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUES HEET_TRACK_RESERVED_LEN) % 8 == 0);
2732 len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STR EAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TR ACK_RESERVED_LEN) / 8;
2733 memset(buffer, 0, len);
2734 buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
2735 if(write_cb(buffer, 1, len, handle) != len)
2736 return false;
2737
2738 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LE N % 8 == 0);
2739 len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
2740 pack_uint32_(track->num_indices, buffer, len);
2741 if(write_cb(buffer, 1, len, handle) != len)
2742 return false;
2743
2744 for(j = 0; j < track->num_indices; j++) {
2745 FLAC__StreamMetadata_CueSheet_Index *indx = track->indic es + j;
2746
2747 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET _LEN % 8 == 0);
2748 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
2749 pack_uint64_(indx->offset, buffer, len);
2750 if(write_cb(buffer, 1, len, handle) != len)
2751 return false;
2752
2753 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER _LEN % 8 == 0);
2754 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
2755 pack_uint32_(indx->number, buffer, len);
2756 if(write_cb(buffer, 1, len, handle) != len)
2757 return false;
2758
2759 FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERV ED_LEN % 8 == 0);
2760 len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
2761 memset(buffer, 0, len);
2762 if(write_cb(buffer, 1, len, handle) != len)
2763 return false;
2764 }
2765 }
2766
2767 return true;
2768 }
2769
2770 FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IO Callback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
2771 {
2772 unsigned len;
2773 size_t slen;
2774 FLAC__byte buffer[4]; /* magic number is asserted below */
2775
2776 FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8);
2777 FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8);
2778 FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8 );
2779 FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8);
2780 FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8);
2781 FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8);
2782 FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_COLORS_LEN%8);
2783 FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8);
2784 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8) ;
2785 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_L ENGTH_LEN/8);
2786 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION _LENGTH_LEN/8);
2787 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8 );
2788 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/ 8);
2789 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8 );
2790 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/ 8);
2791 FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH _LEN/8);
2792
2793 len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8;
2794 pack_uint32_(block->type, buffer, len);
2795 if(write_cb(buffer, 1, len, handle) != len)
2796 return false;
2797
2798 len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8;
2799 slen = strlen(block->mime_type);
2800 pack_uint32_(slen, buffer, len);
2801 if(write_cb(buffer, 1, len, handle) != len)
2802 return false;
2803 if(write_cb(block->mime_type, 1, slen, handle) != slen)
2804 return false;
2805
2806 len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8;
2807 slen = strlen((const char *)block->description);
2808 pack_uint32_(slen, buffer, len);
2809 if(write_cb(buffer, 1, len, handle) != len)
2810 return false;
2811 if(write_cb(block->description, 1, slen, handle) != slen)
2812 return false;
2813
2814 len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8;
2815 pack_uint32_(block->width, buffer, len);
2816 if(write_cb(buffer, 1, len, handle) != len)
2817 return false;
2818
2819 len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8;
2820 pack_uint32_(block->height, buffer, len);
2821 if(write_cb(buffer, 1, len, handle) != len)
2822 return false;
2823
2824 len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8;
2825 pack_uint32_(block->depth, buffer, len);
2826 if(write_cb(buffer, 1, len, handle) != len)
2827 return false;
2828
2829 len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8;
2830 pack_uint32_(block->colors, buffer, len);
2831 if(write_cb(buffer, 1, len, handle) != len)
2832 return false;
2833
2834 len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8;
2835 pack_uint32_(block->data_length, buffer, len);
2836 if(write_cb(buffer, 1, len, handle) != len)
2837 return false;
2838 if(write_cb(block->data, 1, block->data_length, handle) != block->data_l ength)
2839 return false;
2840
2841 return true;
2842 }
2843
2844 FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IO Callback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned blo ck_length)
2845 {
2846 if(write_cb(block->data, 1, block_length, handle) != block_length)
2847 return false;
2848
2849 return true;
2850 }
2851
2852 FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *itera tor, const FLAC__StreamMetadata *block)
2853 {
2854 if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_S ET)) {
2855 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
2856 return false;
2857 }
2858
2859 if(!write_metadata_block_header_(iterator->file, &iterator->status, bloc k))
2860 return false;
2861
2862 if(!write_metadata_block_data_(iterator->file, &iterator->status, block) )
2863 return false;
2864
2865 if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_S ET)) {
2866 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
2867 return false;
2868 }
2869
2870 return read_metadata_block_header_(iterator);
2871 }
2872
2873 FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIt erator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bo ol padding_is_last)
2874 {
2875 FLAC__StreamMetadata *padding;
2876
2877 if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_S ET)) {
2878 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
2879 return false;
2880 }
2881
2882 block->is_last = false;
2883
2884 if(!write_metadata_block_header_(iterator->file, &iterator->status, bloc k))
2885 return false;
2886
2887 if(!write_metadata_block_data_(iterator->file, &iterator->status, block) )
2888 return false;
2889
2890 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING )))
2891 return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_E RROR;
2892
2893 padding->is_last = padding_is_last;
2894 padding->length = padding_length;
2895
2896 if(!write_metadata_block_header_(iterator->file, &iterator->status, padd ing)) {
2897 FLAC__metadata_object_delete(padding);
2898 return false;
2899 }
2900
2901 if(!write_metadata_block_data_(iterator->file, &iterator->status, paddin g)) {
2902 FLAC__metadata_object_delete(padding);
2903 return false;
2904 }
2905
2906 FLAC__metadata_object_delete(padding);
2907
2908 if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_S ET)) {
2909 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
2910 return false;
2911 }
2912
2913 return read_metadata_block_header_(iterator);
2914 }
2915
2916 FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__St reamMetadata *block, FLAC__bool append)
2917 {
2918 FILE *tempfile = NULL;
2919 char *tempfilename = NULL;
2920 int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
2921 FLAC__off_t fixup_is_last_flag_offset = -1;
2922
2923 FLAC__ASSERT(0 != block || append == false);
2924
2925 if(iterator->is_last) {
2926 if(append) {
2927 fixup_is_last_code = 1; /* 1 => clear the is_last flag a t the following offset */
2928 fixup_is_last_flag_offset = iterator->offset[iterator->d epth];
2929 }
2930 else if(0 == block) {
2931 simple_iterator_push_(iterator);
2932 if(!FLAC__metadata_simple_iterator_prev(iterator)) {
2933 (void)simple_iterator_pop_(iterator);
2934 return false;
2935 }
2936 fixup_is_last_code = -1; /* -1 => set the is_last the fl ag at the following offset */
2937 fixup_is_last_flag_offset = iterator->offset[iterator->d epth];
2938 if(!simple_iterator_pop_(iterator))
2939 return false;
2940 }
2941 }
2942
2943 if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename , append))
2944 return false;
2945
2946 if(0 != block) {
2947 if(!write_metadata_block_header_(tempfile, &iterator->status, bl ock)) {
2948 cleanup_tempfile_(&tempfile, &tempfilename);
2949 return false;
2950 }
2951
2952 if(!write_metadata_block_data_(tempfile, &iterator->status, bloc k)) {
2953 cleanup_tempfile_(&tempfile, &tempfilename);
2954 return false;
2955 }
2956 }
2957
2958 if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilenam e, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
2959 return false;
2960
2961 if(append)
2962 return FLAC__metadata_simple_iterator_next(iterator);
2963
2964 return true;
2965 }
2966
2967 void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
2968 {
2969 FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
2970 iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
2971 iterator->depth++;
2972 }
2973
2974 FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
2975 {
2976 FLAC__ASSERT(iterator->depth > 0);
2977 iterator->depth--;
2978 if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_S ET)) {
2979 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
2980 return false;
2981 }
2982
2983 return read_metadata_block_header_(iterator);
2984 }
2985
2986 /* return meanings:
2987 * 0: ok
2988 * 1: read error
2989 * 2: seek error
2990 * 3: not a FLAC file
2991 */
2992 unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallbac k_Read read_cb, FLAC__IOCallback_Seek seek_cb)
2993 {
2994 FLAC__byte buffer[4];
2995 size_t n;
2996 unsigned i;
2997
2998 FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer));
2999
3000 /* skip any id3v2 tag */
3001 errno = 0;
3002 n = read_cb(buffer, 1, 4, handle);
3003 if(errno)
3004 return 1;
3005 else if(n != 4)
3006 return 3;
3007 else if(0 == memcmp(buffer, "ID3", 3)) {
3008 unsigned tag_length = 0;
3009
3010 /* skip to the tag length */
3011 if(seek_cb(handle, 2, SEEK_CUR) < 0)
3012 return 2;
3013
3014 /* read the length */
3015 for(i = 0; i < 4; i++) {
3016 if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80 )
3017 return 1;
3018 tag_length <<= 7;
3019 tag_length |= (buffer[0] & 0x7f);
3020 }
3021
3022 /* skip the rest of the tag */
3023 if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
3024 return 2;
3025
3026 /* read the stream sync code */
3027 errno = 0;
3028 n = read_cb(buffer, 1, 4, handle);
3029 if(errno)
3030 return 1;
3031 else if(n != 4)
3032 return 3;
3033 }
3034
3035 /* check for the fLaC signature */
3036 if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGT H))
3037 return 0;
3038 else
3039 return 3;
3040 }
3041
3042 unsigned seek_to_first_metadata_block_(FILE *f)
3043 {
3044 return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCall back_Read)fread, fseek_wrapper_);
3045 }
3046
3047 FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iter ator, FILE **tempfile, char **tempfilename, FLAC__bool append)
3048 {
3049 const FLAC__off_t offset_end = append? iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->len gth : iterator->offset[iterator->depth];
3050
3051 if(0 != fseeko(iterator->file, 0, SEEK_SET)) {
3052 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
3053 return false;
3054 }
3055 if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, t empfile, tempfilename, &iterator->status)) {
3056 cleanup_tempfile_(tempfile, tempfilename);
3057 return false;
3058 }
3059 if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iter ator->status)) {
3060 cleanup_tempfile_(tempfile, tempfilename);
3061 return false;
3062 }
3063
3064 return true;
3065 }
3066
3067 FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *ite rator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup)
3068 {
3069 FLAC__off_t save_offset = iterator->offset[iterator->depth];
3070 FLAC__ASSERT(0 != *tempfile);
3071
3072 if(0 != fseeko(iterator->file, save_offset + (FLAC__off_t)FLAC__STREAM_M ETADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length, SEEK_SET)) {
3073 cleanup_tempfile_(tempfile, tempfilename);
3074 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ER ROR;
3075 return false;
3076 }
3077 if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator ->status)) {
3078 cleanup_tempfile_(tempfile, tempfilename);
3079 return false;
3080 }
3081
3082 if(fixup_is_last_code != 0) {
3083 /*
3084 * if code == 1, it means a block was appended to the end so
3085 * we have to clear the is_last flag of the previous block
3086 * if code == -1, it means the last block was deleted so
3087 * we have to set the is_last flag of the previous block
3088 */
3089 /* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
3090 FLAC__byte x;
3091 if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
3092 cleanup_tempfile_(tempfile, tempfilename);
3093 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _SEEK_ERROR;
3094 return false;
3095 }
3096 if(fread(&x, 1, 1, *tempfile) != 1) {
3097 cleanup_tempfile_(tempfile, tempfilename);
3098 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _READ_ERROR;
3099 return false;
3100 }
3101 if(fixup_is_last_code > 0) {
3102 FLAC__ASSERT(x & 0x80);
3103 x &= 0x7f;
3104 }
3105 else {
3106 FLAC__ASSERT(!(x & 0x80));
3107 x |= 0x80;
3108 }
3109 if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
3110 cleanup_tempfile_(tempfile, tempfilename);
3111 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _SEEK_ERROR;
3112 return false;
3113 }
3114 if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
3115 cleanup_tempfile_(tempfile, tempfilename);
3116 iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS _WRITE_ERROR;
3117 return false;
3118 }
3119 }
3120
3121 (void)fclose(iterator->file);
3122
3123 if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &ite rator->status))
3124 return false;
3125
3126 if(iterator->has_stats)
3127 set_file_stats_(iterator->filename, &iterator->stats);
3128
3129 if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
3130 return false;
3131 if(backup) {
3132 while(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STR EAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length < save_offset)
3133 if(!FLAC__metadata_simple_iterator_next(iterator))
3134 return false;
3135 return true;
3136 }
3137 else {
3138 /* move the iterator to it's original block faster by faking a p ush, then doing a pop_ */
3139 FLAC__ASSERT(iterator->depth == 0);
3140 iterator->offset[0] = save_offset;
3141 iterator->depth++;
3142 return simple_iterator_pop_(iterator);
3143 }
3144 }
3145
3146 FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes , FLAC__Metadata_SimpleIteratorStatus *status)
3147 {
3148 FLAC__byte buffer[8192];
3149 size_t n;
3150
3151 FLAC__ASSERT(bytes >= 0);
3152 while(bytes > 0) {
3153 n = flac_min(sizeof(buffer), (size_t)bytes);
3154 if(fread(buffer, 1, n, file) != n) {
3155 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERR OR;
3156 return false;
3157 }
3158 if(local__fwrite(buffer, 1, n, tempfile) != n) {
3159 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ER ROR;
3160 return false;
3161 }
3162 bytes -= n;
3163 }
3164
3165 return true;
3166 }
3167
3168 FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Re ad read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FL AC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
3169 {
3170 FLAC__byte buffer[8192];
3171 size_t n;
3172
3173 FLAC__ASSERT(bytes >= 0);
3174 while(bytes > 0) {
3175 n = flac_min(sizeof(buffer), (size_t)bytes);
3176 if(read_cb(buffer, 1, n, handle) != n) {
3177 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERR OR;
3178 return false;
3179 }
3180 if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
3181 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ER ROR;
3182 return false;
3183 }
3184 bytes -= n;
3185 }
3186
3187 return true;
3188 }
3189
3190 FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Met adata_SimpleIteratorStatus *status)
3191 {
3192 FLAC__byte buffer[8192];
3193 size_t n;
3194
3195 while(!feof(file)) {
3196 n = fread(buffer, 1, sizeof(buffer), file);
3197 if(n == 0 && !feof(file)) {
3198 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERR OR;
3199 return false;
3200 }
3201 if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
3202 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ER ROR;
3203 return false;
3204 }
3205 }
3206
3207 return true;
3208 }
3209
3210 FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCal lback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLA C__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
3211 {
3212 FLAC__byte buffer[8192];
3213 size_t n;
3214
3215 while(!eof_cb(handle)) {
3216 n = read_cb(buffer, 1, sizeof(buffer), handle);
3217 if(n == 0 && !eof_cb(handle)) {
3218 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERR OR;
3219 return false;
3220 }
3221 if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
3222 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ER ROR;
3223 return false;
3224 }
3225 }
3226
3227 return true;
3228 }
3229
3230 static int
3231 local_snprintf(char *str, size_t size, const char *fmt, ...)
3232 {
3233 va_list va;
3234 int rc;
3235
3236 va_start (va, fmt);
3237
3238 #if defined _MSC_VER
3239 if (size == 0)
3240 return 1024;
3241 rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
3242 if (rc < 0)
3243 rc = size - 1;
3244 #elif defined __MINGW32__
3245 rc = __mingw_vsnprintf (str, size, fmt, va);
3246 #else
3247 rc = vsnprintf (str, size, fmt, va);
3248 #endif
3249 va_end (va);
3250
3251 return rc;
3252 }
3253
3254 FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix , FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *sta tus)
3255 {
3256 static const char *tempfile_suffix = ".metadata_edit";
3257 if(0 == tempfile_path_prefix) {
3258 size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1 ;
3259 if(0 == (*tempfilename = safe_malloc_(dest_len))) {
3260 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_A LLOCATION_ERROR;
3261 return false;
3262 }
3263 local_snprintf(*tempfilename, dest_len, "%s%s", filename, tempfi le_suffix);
3264 }
3265 else {
3266 const char *p = strrchr(filename, '/');
3267 size_t dest_len;
3268 if(0 == p)
3269 p = filename;
3270 else
3271 p++;
3272
3273 dest_len = strlen(tempfile_path_prefix) + strlen(p) + strlen(tem pfile_suffix) + 2;
3274
3275 if(0 == (*tempfilename = safe_malloc_(dest_len))) {
3276 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_A LLOCATION_ERROR;
3277 return false;
3278 }
3279 local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path _prefix, p, tempfile_suffix);
3280 }
3281
3282 if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) {
3283 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FI LE;
3284 return false;
3285 }
3286
3287 return true;
3288 }
3289
3290 FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tem pfilename, FLAC__Metadata_SimpleIteratorStatus *status)
3291 {
3292 FLAC__ASSERT(0 != filename);
3293 FLAC__ASSERT(0 != tempfile);
3294 FLAC__ASSERT(0 != *tempfile);
3295 FLAC__ASSERT(0 != tempfilename);
3296 FLAC__ASSERT(0 != *tempfilename);
3297 FLAC__ASSERT(0 != status);
3298
3299 (void)fclose(*tempfile);
3300 *tempfile = 0;
3301
3302 #if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined _ _EMX__
3303 /* on some flavors of windows, flac_rename() will fail if the destinatio n already exists */
3304 if(flac_unlink(filename) < 0) {
3305 cleanup_tempfile_(tempfile, tempfilename);
3306 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
3307 return false;
3308 }
3309 #endif
3310
3311 /*@@@ to fully support the tempfile_path_prefix we need to update this p iece to actually copy across filesystems instead of just flac_rename(): */
3312 if(0 != flac_rename(*tempfilename, filename)) {
3313 cleanup_tempfile_(tempfile, tempfilename);
3314 *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
3315 return false;
3316 }
3317
3318 cleanup_tempfile_(tempfile, tempfilename);
3319
3320 return true;
3321 }
3322
3323 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
3324 {
3325 if(0 != *tempfile) {
3326 (void)fclose(*tempfile);
3327 *tempfile = 0;
3328 }
3329
3330 if(0 != *tempfilename) {
3331 (void)flac_unlink(*tempfilename);
3332 free(*tempfilename);
3333 *tempfilename = 0;
3334 }
3335 }
3336
3337 FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
3338 {
3339 FLAC__ASSERT(0 != filename);
3340 FLAC__ASSERT(0 != stats);
3341 return (0 == flac_stat(filename, stats));
3342 }
3343
3344 void set_file_stats_(const char *filename, struct flac_stat_s *stats)
3345 {
3346 struct utimbuf srctime;
3347
3348 FLAC__ASSERT(0 != filename);
3349 FLAC__ASSERT(0 != stats);
3350
3351 srctime.actime = stats->st_atime;
3352 srctime.modtime = stats->st_mtime;
3353 (void)flac_chmod(filename, stats->st_mode);
3354 (void)flac_utime(filename, &srctime);
3355 #if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__
3356 FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1));
3357 FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid));
3358 #endif
3359 }
3360
3361 int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
3362 {
3363 return fseeko((FILE*)handle, (FLAC__off_t)offset, whence);
3364 }
3365
3366 FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
3367 {
3368 return ftello((FILE*)handle);
3369 }
3370
3371 FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorS tatus status)
3372 {
3373 switch(status) {
3374 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
3375 return FLAC__METADATA_CHAIN_STATUS_OK;
3376 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
3377 return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
3378 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
3379 return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
3380 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
3381 return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
3382 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
3383 return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
3384 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
3385 return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
3386 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
3387 return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
3388 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
3389 return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
3390 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
3391 return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
3392 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
3393 return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
3394 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
3395 return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
3396 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERR OR:
3397 return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERR OR;
3398 case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
3399 default:
3400 return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
3401 }
3402 }
OLDNEW
« no previous file with comments | « src/libFLAC/memory.c ('k') | src/libFLAC/metadata_object.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698