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