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