/src/flac/src/libFLAC/metadata_object.c
Line | Count | Source |
1 | | /* libFLAC - Free Lossless Audio Codec library |
2 | | * Copyright (C) 2001-2009 Josh Coalson |
3 | | * Copyright (C) 2011-2025 Xiph.Org Foundation |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * |
9 | | * - Redistributions of source code must retain the above copyright |
10 | | * notice, this list of conditions and the following disclaimer. |
11 | | * |
12 | | * - Redistributions in binary form must reproduce the above copyright |
13 | | * notice, this list of conditions and the following disclaimer in the |
14 | | * documentation and/or other materials provided with the distribution. |
15 | | * |
16 | | * - Neither the name of the Xiph.org Foundation nor the names of its |
17 | | * contributors may be used to endorse or promote products derived from |
18 | | * this software without specific prior written permission. |
19 | | * |
20 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
23 | | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
24 | | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
25 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
26 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
27 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
28 | | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
29 | | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
30 | | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | | */ |
32 | | |
33 | | #ifdef HAVE_CONFIG_H |
34 | | # include <config.h> |
35 | | #endif |
36 | | |
37 | | #include <stdlib.h> |
38 | | #include <string.h> |
39 | | |
40 | | #include "private/metadata.h" |
41 | | #include "private/memory.h" |
42 | | #include "private/stream_encoder_framing.h" |
43 | | |
44 | | #include "FLAC/assert.h" |
45 | | #include "FLAC/stream_decoder.h" |
46 | | #include "share/alloc.h" |
47 | | #include "share/compat.h" |
48 | | |
49 | | /* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */ |
50 | | #define safe_malloc_mul_2op_ safe_malloc_mul_2op_p |
51 | | |
52 | | |
53 | | /**************************************************************************** |
54 | | * |
55 | | * Local routines |
56 | | * |
57 | | ***************************************************************************/ |
58 | | |
59 | | /* copy bytes: |
60 | | * from = NULL && bytes = 0 |
61 | | * to <- NULL |
62 | | * from != NULL && bytes > 0 |
63 | | * to <- copy of from |
64 | | * else ASSERT |
65 | | * malloc error leaves 'to' unchanged |
66 | | */ |
67 | | static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes) |
68 | 17.9k | { |
69 | 17.9k | FLAC__ASSERT(to != NULL); |
70 | 17.9k | if (bytes > 0 && from != NULL) { |
71 | 15.5k | FLAC__byte *x; |
72 | 15.5k | if ((x = safe_malloc_(bytes)) == NULL) |
73 | 0 | return false; |
74 | 15.5k | memcpy(x, from, bytes); |
75 | 15.5k | *to = x; |
76 | 15.5k | } |
77 | 2.38k | else { |
78 | 2.38k | *to = 0; |
79 | 2.38k | } |
80 | 17.9k | return true; |
81 | 17.9k | } |
82 | | |
83 | | #if 0 /* UNUSED */ |
84 | | /* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */ |
85 | | static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes) |
86 | | { |
87 | | FLAC__byte *copy; |
88 | | FLAC__ASSERT(to != NULL); |
89 | | if (copy_bytes_(©, from, bytes)) { |
90 | | free(*to); |
91 | | *to = copy; |
92 | | return true; |
93 | | } |
94 | | else |
95 | | return false; |
96 | | } |
97 | | #endif |
98 | | |
99 | | /* reallocate entry to 1 byte larger and add a terminating NUL */ |
100 | | /* realloc() failure leaves entry unchanged */ |
101 | | static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, uint32_t length) |
102 | 0 | { |
103 | 0 | FLAC__byte *x = safe_realloc_nofree_add_2op_(*entry, length, /*+*/1); |
104 | 0 | if (x != NULL) { |
105 | 0 | x[length] = '\0'; |
106 | 0 | *entry = x; |
107 | 0 | return true; |
108 | 0 | } |
109 | 0 | else |
110 | 0 | return false; |
111 | 0 | } |
112 | | |
113 | | /* copies the NUL-terminated C-string 'from' to '*to', leaving '*to' |
114 | | * unchanged if malloc fails, free()ing the original '*to' if it |
115 | | * succeeds and the original '*to' was not NULL |
116 | | */ |
117 | | static FLAC__bool copy_cstring_(char **to, const char *from) |
118 | 30.1k | { |
119 | 30.1k | char *copy = strdup(from); |
120 | 30.1k | FLAC__ASSERT(to != NULL); |
121 | 30.1k | if (copy) { |
122 | 30.1k | free(*to); |
123 | 30.1k | *to = copy; |
124 | 30.1k | return true; |
125 | 30.1k | } |
126 | 0 | else |
127 | 0 | return false; |
128 | 30.1k | } |
129 | | |
130 | | static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from) |
131 | 1.42M | { |
132 | 1.42M | to->length = from->length; |
133 | 1.42M | if (from->entry == 0) { |
134 | 0 | FLAC__ASSERT(from->length == 0); |
135 | 0 | if ((to->entry = safe_malloc_(1)) == NULL) |
136 | 0 | return false; |
137 | 0 | to->entry[0] = '\0'; |
138 | 0 | } |
139 | 1.42M | else { |
140 | 1.42M | FLAC__byte *x; |
141 | 1.42M | if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL) |
142 | 0 | return false; |
143 | 1.42M | memcpy(x, from->entry, from->length); |
144 | 1.42M | x[from->length] = '\0'; |
145 | 1.42M | to->entry = x; |
146 | 1.42M | } |
147 | 1.42M | return true; |
148 | 1.42M | } |
149 | | |
150 | | static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from) |
151 | 71.4k | { |
152 | 71.4k | memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track)); |
153 | 71.4k | if (from->indices == 0) { |
154 | 59.5k | FLAC__ASSERT(from->num_indices == 0); |
155 | 59.5k | } |
156 | 11.9k | else { |
157 | 11.9k | FLAC__StreamMetadata_CueSheet_Index *x; |
158 | 11.9k | FLAC__ASSERT(from->num_indices > 0); |
159 | 11.9k | if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL) |
160 | 0 | return false; |
161 | 11.9k | memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); |
162 | 11.9k | to->indices = x; |
163 | 11.9k | } |
164 | 71.4k | return true; |
165 | 71.4k | } |
166 | | |
167 | | static void seektable_calculate_length_(FLAC__StreamMetadata *object) |
168 | 3.69k | { |
169 | 3.69k | FLAC__ASSERT(object != NULL); |
170 | 3.69k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
171 | | |
172 | 3.69k | object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; |
173 | 3.69k | } |
174 | | |
175 | | static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points) |
176 | 198 | { |
177 | 198 | FLAC__StreamMetadata_SeekPoint *object_array; |
178 | | |
179 | 198 | FLAC__ASSERT(num_points > 0); |
180 | | |
181 | 198 | object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)); |
182 | | |
183 | 198 | if (object_array != NULL) { |
184 | 198 | uint32_t i; |
185 | 1.24k | for (i = 0; i < num_points; i++) { |
186 | 1.05k | object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; |
187 | 1.05k | object_array[i].stream_offset = 0; |
188 | 1.05k | object_array[i].frame_samples = 0; |
189 | 1.05k | } |
190 | 198 | } |
191 | | |
192 | 198 | return object_array; |
193 | 198 | } |
194 | | |
195 | | static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object) |
196 | 17.8k | { |
197 | 17.8k | uint32_t i; |
198 | | |
199 | 17.8k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
200 | | |
201 | 17.8k | object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8; |
202 | 17.8k | object->length += object->data.vorbis_comment.vendor_string.length; |
203 | 17.8k | object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8; |
204 | 2.45M | for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { |
205 | 2.44M | object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8); |
206 | 2.44M | object->length += object->data.vorbis_comment.comments[i].length; |
207 | 2.44M | } |
208 | 17.8k | } |
209 | | |
210 | | static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments) |
211 | 1.28k | { |
212 | 1.28k | FLAC__ASSERT(num_comments > 0); |
213 | | |
214 | 1.28k | return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); |
215 | 1.28k | } |
216 | | |
217 | | static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) |
218 | 2.71k | { |
219 | 2.71k | uint32_t i; |
220 | | |
221 | 2.71k | FLAC__ASSERT(object_array != NULL); |
222 | | |
223 | 53.2M | for (i = 0; i < num_comments; i++) |
224 | 53.2M | free(object_array[i].entry); |
225 | | |
226 | 2.71k | free(object_array); |
227 | 2.71k | } |
228 | | |
229 | | static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) |
230 | 1.19k | { |
231 | 1.19k | FLAC__StreamMetadata_VorbisComment_Entry *return_array; |
232 | | |
233 | 1.19k | FLAC__ASSERT(object_array != NULL); |
234 | 1.19k | FLAC__ASSERT(num_comments > 0); |
235 | | |
236 | 1.19k | return_array = vorbiscomment_entry_array_new_(num_comments); |
237 | | |
238 | 1.19k | if (return_array != NULL) { |
239 | 1.19k | uint32_t i; |
240 | | |
241 | 1.42M | for (i = 0; i < num_comments; i++) { |
242 | 1.42M | if (!copy_vcentry_(return_array+i, object_array+i)) { |
243 | 0 | vorbiscomment_entry_array_delete_(return_array, num_comments); |
244 | 0 | return 0; |
245 | 0 | } |
246 | 1.42M | } |
247 | 1.19k | } |
248 | | |
249 | 1.19k | return return_array; |
250 | 1.19k | } |
251 | | |
252 | | static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy) |
253 | 1.84k | { |
254 | 1.84k | FLAC__byte *save; |
255 | | |
256 | 1.84k | FLAC__ASSERT(object != NULL); |
257 | 1.84k | FLAC__ASSERT(dest != NULL); |
258 | 1.84k | FLAC__ASSERT(src != NULL); |
259 | 1.84k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
260 | 1.84k | FLAC__ASSERT((src->entry != NULL && src->length > 0) || (src->entry == NULL && src->length == 0)); |
261 | | |
262 | 1.84k | save = dest->entry; |
263 | | |
264 | 1.84k | if (src->entry != NULL) { |
265 | 1.84k | if (copy) { |
266 | | /* do the copy first so that if we fail we leave the dest object untouched */ |
267 | 1.84k | if (!copy_vcentry_(dest, src)) |
268 | 0 | return false; |
269 | 1.84k | } |
270 | 0 | else { |
271 | | /* we have to make sure that the string we're taking over is null-terminated */ |
272 | | |
273 | | /* |
274 | | * Stripping the const from src->entry is OK since we're taking |
275 | | * ownership of the pointer. This is a hack around a deficiency |
276 | | * in the API where the same function is used for 'copy' and |
277 | | * 'own', but the source entry is a const pointer. If we were |
278 | | * precise, the 'own' flavor would be a separate function with a |
279 | | * non-const source pointer. But it's not, so we hack away. |
280 | | */ |
281 | 0 | if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length)) |
282 | 0 | return false; |
283 | 0 | *dest = *src; |
284 | 0 | } |
285 | 1.84k | } |
286 | 0 | else { |
287 | | /* the src is null */ |
288 | 0 | *dest = *src; |
289 | 0 | } |
290 | | |
291 | 1.84k | free(save); |
292 | | |
293 | 1.84k | vorbiscomment_calculate_length_(object); |
294 | 1.84k | return true; |
295 | 1.84k | } |
296 | | |
297 | | static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length) |
298 | 1.78k | { |
299 | 1.78k | uint32_t i; |
300 | | |
301 | 1.78k | FLAC__ASSERT(object != NULL); |
302 | 1.78k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
303 | 1.78k | FLAC__ASSERT(field_name != NULL); |
304 | | |
305 | 288k | for (i = offset; i < object->data.vorbis_comment.num_comments; i++) { |
306 | 287k | if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) |
307 | 1.52k | return (int)i; |
308 | 287k | } |
309 | | |
310 | 259 | return -1; |
311 | 1.78k | } |
312 | | |
313 | | static void cuesheet_calculate_length_(FLAC__StreamMetadata *object) |
314 | 11.3k | { |
315 | 11.3k | uint32_t i; |
316 | | |
317 | 11.3k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
318 | | |
319 | 11.3k | object->length = ( |
320 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + |
321 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + |
322 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + |
323 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + |
324 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN |
325 | 11.3k | ) / 8; |
326 | | |
327 | 11.3k | object->length += object->data.cue_sheet.num_tracks * ( |
328 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + |
329 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + |
330 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + |
331 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + |
332 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + |
333 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + |
334 | 11.3k | FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN |
335 | 11.3k | ) / 8; |
336 | | |
337 | 176k | for (i = 0; i < object->data.cue_sheet.num_tracks; i++) { |
338 | 165k | object->length += object->data.cue_sheet.tracks[i].num_indices * ( |
339 | 165k | FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + |
340 | 165k | FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + |
341 | 165k | FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN |
342 | 165k | ) / 8; |
343 | 165k | } |
344 | 11.3k | } |
345 | | |
346 | | static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices) |
347 | 70 | { |
348 | 70 | FLAC__ASSERT(num_indices > 0); |
349 | | |
350 | 70 | return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)); |
351 | 70 | } |
352 | | |
353 | | static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks) |
354 | 833 | { |
355 | 833 | FLAC__ASSERT(num_tracks > 0); |
356 | | |
357 | 833 | return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)); |
358 | 833 | } |
359 | | |
360 | | static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) |
361 | 2.90k | { |
362 | 2.90k | uint32_t i; |
363 | | |
364 | 2.90k | FLAC__ASSERT(object_array != NULL && num_tracks > 0); |
365 | | |
366 | 241k | for (i = 0; i < num_tracks; i++) { |
367 | 238k | if (object_array[i].indices != 0) { |
368 | 23.0k | FLAC__ASSERT(object_array[i].num_indices > 0); |
369 | 23.0k | free(object_array[i].indices); |
370 | 23.0k | } |
371 | 238k | } |
372 | | |
373 | 2.90k | free(object_array); |
374 | 2.90k | } |
375 | | |
376 | | static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) |
377 | 833 | { |
378 | 833 | FLAC__StreamMetadata_CueSheet_Track *return_array; |
379 | | |
380 | 833 | FLAC__ASSERT(object_array != NULL); |
381 | 833 | FLAC__ASSERT(num_tracks > 0); |
382 | | |
383 | 833 | return_array = cuesheet_track_array_new_(num_tracks); |
384 | | |
385 | 833 | if (return_array != NULL) { |
386 | 833 | uint32_t i; |
387 | | |
388 | 71.5k | for (i = 0; i < num_tracks; i++) { |
389 | 70.7k | if (!copy_track_(return_array+i, object_array+i)) { |
390 | 0 | cuesheet_track_array_delete_(return_array, num_tracks); |
391 | 0 | return 0; |
392 | 0 | } |
393 | 70.7k | } |
394 | 833 | } |
395 | | |
396 | 833 | return return_array; |
397 | 833 | } |
398 | | |
399 | | static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy) |
400 | 222 | { |
401 | 222 | FLAC__StreamMetadata_CueSheet_Index *save; |
402 | | |
403 | 222 | FLAC__ASSERT(object != NULL); |
404 | 222 | FLAC__ASSERT(dest != NULL); |
405 | 222 | FLAC__ASSERT(src != NULL); |
406 | 222 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
407 | 222 | FLAC__ASSERT((src->indices != NULL && src->num_indices > 0) || (src->indices == NULL && src->num_indices == 0)); |
408 | | |
409 | 222 | save = dest->indices; |
410 | | |
411 | | /* do the copy first so that if we fail we leave the object untouched */ |
412 | 222 | if (copy) { |
413 | 111 | if (!copy_track_(dest, src)) |
414 | 0 | return false; |
415 | 111 | } |
416 | 111 | else { |
417 | 111 | *dest = *src; |
418 | 111 | } |
419 | | |
420 | 222 | free(save); |
421 | | |
422 | 222 | cuesheet_calculate_length_(object); |
423 | 222 | return true; |
424 | 222 | } |
425 | | |
426 | | |
427 | | /**************************************************************************** |
428 | | * |
429 | | * Metadata object routines |
430 | | * |
431 | | ***************************************************************************/ |
432 | | |
433 | | FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type) |
434 | 351k | { |
435 | 351k | FLAC__StreamMetadata *object; |
436 | | |
437 | 351k | if (type > FLAC__MAX_METADATA_TYPE) |
438 | 245 | return 0; |
439 | | |
440 | 351k | object = calloc(1, sizeof(FLAC__StreamMetadata)); |
441 | 351k | if (object != NULL) { |
442 | 351k | object->is_last = false; |
443 | 351k | object->type = type; |
444 | 351k | switch(type) { |
445 | 54.4k | case FLAC__METADATA_TYPE_STREAMINFO: |
446 | 54.4k | object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; |
447 | 54.4k | break; |
448 | 5.99k | case FLAC__METADATA_TYPE_PADDING: |
449 | | /* calloc() took care of this for us: |
450 | | object->length = 0; |
451 | | */ |
452 | 5.99k | break; |
453 | 1.93k | case FLAC__METADATA_TYPE_APPLICATION: |
454 | 1.93k | object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; |
455 | | /* calloc() took care of this for us: |
456 | | object->data.application.data = 0; |
457 | | */ |
458 | 1.93k | break; |
459 | 3.22k | case FLAC__METADATA_TYPE_SEEKTABLE: |
460 | | /* calloc() took care of this for us: |
461 | | object->length = 0; |
462 | | object->data.seek_table.num_points = 0; |
463 | | object->data.seek_table.points = 0; |
464 | | */ |
465 | 3.22k | break; |
466 | 13.3k | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
467 | 13.3k | object->data.vorbis_comment.vendor_string.length = (uint32_t)strlen(FLAC__VENDOR_STRING); |
468 | 13.3k | if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) { |
469 | 0 | free(object); |
470 | 0 | return 0; |
471 | 0 | } |
472 | 13.3k | vorbiscomment_calculate_length_(object); |
473 | 13.3k | break; |
474 | 10.1k | case FLAC__METADATA_TYPE_CUESHEET: |
475 | 10.1k | cuesheet_calculate_length_(object); |
476 | 10.1k | break; |
477 | 13.7k | case FLAC__METADATA_TYPE_PICTURE: |
478 | 13.7k | object->length = ( |
479 | 13.7k | FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + |
480 | 13.7k | FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */ |
481 | 13.7k | FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */ |
482 | 13.7k | FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + |
483 | 13.7k | FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + |
484 | 13.7k | FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + |
485 | 13.7k | FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + |
486 | 13.7k | FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + |
487 | 13.7k | 0 /* no data */ |
488 | 13.7k | ) / 8; |
489 | 13.7k | object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; |
490 | 13.7k | object->data.picture.mime_type = 0; |
491 | 13.7k | object->data.picture.description = 0; |
492 | | /* calloc() took care of this for us: |
493 | | object->data.picture.width = 0; |
494 | | object->data.picture.height = 0; |
495 | | object->data.picture.depth = 0; |
496 | | object->data.picture.colors = 0; |
497 | | object->data.picture.data_length = 0; |
498 | | object->data.picture.data = 0; |
499 | | */ |
500 | | /* now initialize mime_type and description with empty strings to make things easier on the client */ |
501 | 13.7k | if (!copy_cstring_(&object->data.picture.mime_type, "")) { |
502 | 0 | free(object); |
503 | 0 | return 0; |
504 | 0 | } |
505 | 13.7k | if (!copy_cstring_((char**)(&object->data.picture.description), "")) { |
506 | 0 | free(object->data.picture.mime_type); |
507 | 0 | free(object); |
508 | 0 | return 0; |
509 | 0 | } |
510 | 13.7k | break; |
511 | 248k | default: |
512 | | /* calloc() took care of this for us: |
513 | | object->length = 0; |
514 | | object->data.unknown.data = 0; |
515 | | */ |
516 | 248k | break; |
517 | 351k | } |
518 | 351k | } |
519 | | |
520 | 351k | return object; |
521 | 351k | } |
522 | | |
523 | | FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object) |
524 | 9.38k | { |
525 | 9.38k | FLAC__StreamMetadata *to; |
526 | | |
527 | 9.38k | FLAC__ASSERT(object != NULL); |
528 | | |
529 | 9.38k | if ((to = FLAC__metadata_object_new(object->type)) != NULL) { |
530 | 9.16k | to->is_last = object->is_last; |
531 | 9.16k | to->type = object->type; |
532 | 9.16k | to->length = object->length; |
533 | 9.16k | switch(to->type) { |
534 | 1.42k | case FLAC__METADATA_TYPE_STREAMINFO: |
535 | 1.42k | memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo)); |
536 | 1.42k | break; |
537 | 663 | case FLAC__METADATA_TYPE_PADDING: |
538 | 663 | break; |
539 | 757 | case FLAC__METADATA_TYPE_APPLICATION: |
540 | 757 | if (to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */ |
541 | 0 | FLAC__metadata_object_delete(to); |
542 | 0 | return 0; |
543 | 0 | } |
544 | 757 | memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8); |
545 | 757 | if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) { |
546 | 0 | FLAC__metadata_object_delete(to); |
547 | 0 | return 0; |
548 | 0 | } |
549 | 757 | break; |
550 | 790 | case FLAC__METADATA_TYPE_SEEKTABLE: |
551 | 790 | to->data.seek_table.num_points = object->data.seek_table.num_points; |
552 | 790 | if (to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */ |
553 | 0 | FLAC__metadata_object_delete(to); |
554 | 0 | return 0; |
555 | 0 | } |
556 | 790 | if (!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) { |
557 | 0 | FLAC__metadata_object_delete(to); |
558 | 0 | return 0; |
559 | 0 | } |
560 | 790 | break; |
561 | 1.89k | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
562 | 1.89k | if (to->data.vorbis_comment.vendor_string.entry != NULL) { |
563 | 1.89k | free(to->data.vorbis_comment.vendor_string.entry); |
564 | 1.89k | to->data.vorbis_comment.vendor_string.entry = 0; |
565 | 1.89k | } |
566 | 1.89k | if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) { |
567 | 0 | FLAC__metadata_object_delete(to); |
568 | 0 | return 0; |
569 | 0 | } |
570 | 1.89k | if (object->data.vorbis_comment.num_comments == 0) { |
571 | 701 | to->data.vorbis_comment.comments = 0; |
572 | 701 | } |
573 | 1.19k | else { |
574 | 1.19k | to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); |
575 | 1.19k | if (to->data.vorbis_comment.comments == NULL) { |
576 | 0 | to->data.vorbis_comment.num_comments = 0; |
577 | 0 | FLAC__metadata_object_delete(to); |
578 | 0 | return 0; |
579 | 0 | } |
580 | 1.19k | } |
581 | 1.89k | to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments; |
582 | 1.89k | break; |
583 | 857 | case FLAC__METADATA_TYPE_CUESHEET: |
584 | 857 | memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet)); |
585 | 857 | if (object->data.cue_sheet.num_tracks == 0) { |
586 | 24 | FLAC__ASSERT(object->data.cue_sheet.tracks == NULL); |
587 | 24 | } |
588 | 833 | else { |
589 | 833 | FLAC__ASSERT(object->data.cue_sheet.tracks != 0); |
590 | 833 | to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); |
591 | 833 | if (to->data.cue_sheet.tracks == NULL) { |
592 | 0 | FLAC__metadata_object_delete(to); |
593 | 0 | return 0; |
594 | 0 | } |
595 | 833 | } |
596 | 857 | break; |
597 | 1.37k | case FLAC__METADATA_TYPE_PICTURE: |
598 | 1.37k | to->data.picture.type = object->data.picture.type; |
599 | 1.37k | if (!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) { |
600 | 0 | FLAC__metadata_object_delete(to); |
601 | 0 | return 0; |
602 | 0 | } |
603 | 1.37k | if (!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) { |
604 | 0 | FLAC__metadata_object_delete(to); |
605 | 0 | return 0; |
606 | 0 | } |
607 | 1.37k | to->data.picture.width = object->data.picture.width; |
608 | 1.37k | to->data.picture.height = object->data.picture.height; |
609 | 1.37k | to->data.picture.depth = object->data.picture.depth; |
610 | 1.37k | to->data.picture.colors = object->data.picture.colors; |
611 | 1.37k | to->data.picture.data_length = object->data.picture.data_length; |
612 | 1.37k | if (!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) { |
613 | 0 | FLAC__metadata_object_delete(to); |
614 | 0 | return 0; |
615 | 0 | } |
616 | 1.37k | break; |
617 | 1.41k | default: |
618 | 1.41k | if (!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) { |
619 | 0 | FLAC__metadata_object_delete(to); |
620 | 0 | return 0; |
621 | 0 | } |
622 | 1.41k | break; |
623 | 9.16k | } |
624 | 9.16k | } |
625 | | |
626 | 9.38k | return to; |
627 | 9.38k | } |
628 | | |
629 | | void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object) |
630 | 351k | { |
631 | 351k | FLAC__ASSERT(object != NULL); |
632 | | |
633 | 351k | switch(object->type) { |
634 | 54.4k | case FLAC__METADATA_TYPE_STREAMINFO: |
635 | 60.5k | case FLAC__METADATA_TYPE_PADDING: |
636 | 60.5k | break; |
637 | 1.93k | case FLAC__METADATA_TYPE_APPLICATION: |
638 | 1.93k | if (object->data.application.data != NULL) { |
639 | 670 | free(object->data.application.data); |
640 | 670 | object->data.application.data = NULL; |
641 | 670 | } |
642 | 1.93k | break; |
643 | 3.22k | case FLAC__METADATA_TYPE_SEEKTABLE: |
644 | 3.22k | if (object->data.seek_table.points != NULL) { |
645 | 1.86k | free(object->data.seek_table.points); |
646 | 1.86k | object->data.seek_table.points = NULL; |
647 | 1.86k | } |
648 | 3.22k | break; |
649 | 13.3k | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
650 | 13.3k | if (object->data.vorbis_comment.vendor_string.entry != NULL) { |
651 | 13.3k | free(object->data.vorbis_comment.vendor_string.entry); |
652 | 13.3k | object->data.vorbis_comment.vendor_string.entry = 0; |
653 | 13.3k | } |
654 | 13.3k | if (object->data.vorbis_comment.comments != NULL) { |
655 | 2.71k | vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); |
656 | 2.71k | object->data.vorbis_comment.comments = NULL; |
657 | 2.71k | object->data.vorbis_comment.num_comments = 0; |
658 | 2.71k | } |
659 | 13.3k | break; |
660 | 10.1k | case FLAC__METADATA_TYPE_CUESHEET: |
661 | 10.1k | if (object->data.cue_sheet.tracks != NULL) { |
662 | 2.90k | FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); |
663 | 2.90k | cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); |
664 | 2.90k | object->data.cue_sheet.tracks = NULL; |
665 | 2.90k | object->data.cue_sheet.num_tracks = 0; |
666 | 2.90k | } |
667 | 10.1k | break; |
668 | 13.7k | case FLAC__METADATA_TYPE_PICTURE: |
669 | 13.7k | if (object->data.picture.mime_type != NULL) { |
670 | 13.7k | free(object->data.picture.mime_type); |
671 | 13.7k | object->data.picture.mime_type = NULL; |
672 | 13.7k | } |
673 | 13.7k | if (object->data.picture.description != NULL) { |
674 | 13.7k | free(object->data.picture.description); |
675 | 13.7k | object->data.picture.description = NULL; |
676 | 13.7k | } |
677 | 13.7k | if (object->data.picture.data != NULL) { |
678 | 5.03k | free(object->data.picture.data); |
679 | 5.03k | object->data.picture.data = NULL; |
680 | 5.03k | } |
681 | 13.7k | break; |
682 | 248k | default: |
683 | 248k | if (object->data.unknown.data != NULL) { |
684 | 2.94k | free(object->data.unknown.data); |
685 | 2.94k | object->data.unknown.data = NULL; |
686 | 2.94k | } |
687 | 248k | break; |
688 | 351k | } |
689 | 351k | } |
690 | | |
691 | | FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object) |
692 | 351k | { |
693 | 351k | FLAC__metadata_object_delete_data(object); |
694 | 351k | free(object); |
695 | 351k | } |
696 | | |
697 | | static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2) |
698 | 16 | { |
699 | 16 | if (block1->min_blocksize != block2->min_blocksize) |
700 | 0 | return false; |
701 | 16 | if (block1->max_blocksize != block2->max_blocksize) |
702 | 0 | return false; |
703 | 16 | if (block1->min_framesize != block2->min_framesize) |
704 | 0 | return false; |
705 | 16 | if (block1->max_framesize != block2->max_framesize) |
706 | 0 | return false; |
707 | 16 | if (block1->sample_rate != block2->sample_rate) |
708 | 0 | return false; |
709 | 16 | if (block1->channels != block2->channels) |
710 | 0 | return false; |
711 | 16 | if (block1->bits_per_sample != block2->bits_per_sample) |
712 | 0 | return false; |
713 | 16 | if (block1->total_samples != block2->total_samples) |
714 | 0 | return false; |
715 | 16 | if (memcmp(block1->md5sum, block2->md5sum, 16) != 0) |
716 | 0 | return false; |
717 | 16 | return true; |
718 | 16 | } |
719 | | |
720 | | static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, uint32_t block_length) |
721 | 51 | { |
722 | 51 | FLAC__ASSERT(block1 != NULL); |
723 | 51 | FLAC__ASSERT(block2 != NULL); |
724 | 51 | FLAC__ASSERT(block_length >= sizeof(block1->id)); |
725 | | |
726 | 51 | if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0) |
727 | 0 | return false; |
728 | 51 | if (block1->data != NULL && block2->data != NULL) |
729 | 37 | return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0; |
730 | 14 | else |
731 | 14 | return block1->data == block2->data; |
732 | 51 | } |
733 | | |
734 | | static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2) |
735 | 35 | { |
736 | 35 | uint32_t i; |
737 | | |
738 | 35 | FLAC__ASSERT(block1 != NULL); |
739 | 35 | FLAC__ASSERT(block2 != NULL); |
740 | | |
741 | 35 | if (block1->num_points != block2->num_points) |
742 | 0 | return false; |
743 | | |
744 | 35 | if (block1->points != NULL && block2->points != NULL) { |
745 | 597k | for (i = 0; i < block1->num_points; i++) { |
746 | 597k | if (block1->points[i].sample_number != block2->points[i].sample_number) |
747 | 0 | return false; |
748 | 597k | if (block1->points[i].stream_offset != block2->points[i].stream_offset) |
749 | 0 | return false; |
750 | 597k | if (block1->points[i].frame_samples != block2->points[i].frame_samples) |
751 | 0 | return false; |
752 | 597k | } |
753 | 25 | return true; |
754 | 25 | } |
755 | 10 | else |
756 | 10 | return block1->points == block2->points; |
757 | 35 | } |
758 | | |
759 | | static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2) |
760 | 73 | { |
761 | 73 | uint32_t i; |
762 | | |
763 | 73 | if (block1->vendor_string.length != block2->vendor_string.length) |
764 | 0 | return false; |
765 | | |
766 | 73 | if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) { |
767 | 73 | if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0) |
768 | 0 | return false; |
769 | 73 | } |
770 | 0 | else if (block1->vendor_string.entry != block2->vendor_string.entry) |
771 | 0 | return false; |
772 | | |
773 | 73 | if (block1->num_comments != block2->num_comments) |
774 | 0 | return false; |
775 | | |
776 | 537k | for (i = 0; i < block1->num_comments; i++) { |
777 | 537k | if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) { |
778 | 537k | if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0) |
779 | 0 | return false; |
780 | 537k | } |
781 | 0 | else if (block1->comments[i].entry != block2->comments[i].entry) |
782 | 0 | return false; |
783 | 537k | } |
784 | 73 | return true; |
785 | 73 | } |
786 | | |
787 | | static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2) |
788 | 109 | { |
789 | 109 | uint32_t i, j; |
790 | | |
791 | 109 | if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0) |
792 | 0 | return false; |
793 | | |
794 | 109 | if (block1->lead_in != block2->lead_in) |
795 | 0 | return false; |
796 | | |
797 | 109 | if (block1->is_cd != block2->is_cd) |
798 | 0 | return false; |
799 | | |
800 | 109 | if (block1->num_tracks != block2->num_tracks) |
801 | 0 | return false; |
802 | | |
803 | 109 | if (block1->tracks != NULL && block2->tracks != NULL) { |
804 | 98 | FLAC__ASSERT(block1->num_tracks > 0); |
805 | 21.7k | for (i = 0; i < block1->num_tracks; i++) { |
806 | 21.6k | if (block1->tracks[i].offset != block2->tracks[i].offset) |
807 | 0 | return false; |
808 | 21.6k | if (block1->tracks[i].number != block2->tracks[i].number) |
809 | 0 | return false; |
810 | 21.6k | if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0) |
811 | 0 | return false; |
812 | 21.6k | if (block1->tracks[i].type != block2->tracks[i].type) |
813 | 0 | return false; |
814 | 21.6k | if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis) |
815 | 0 | return false; |
816 | 21.6k | if (block1->tracks[i].num_indices != block2->tracks[i].num_indices) |
817 | 0 | return false; |
818 | 21.6k | if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) { |
819 | 3.19k | FLAC__ASSERT(block1->tracks[i].num_indices > 0); |
820 | 6.84k | for (j = 0; j < block1->tracks[i].num_indices; j++) { |
821 | 3.65k | if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset) |
822 | 0 | return false; |
823 | 3.65k | if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number) |
824 | 0 | return false; |
825 | 3.65k | } |
826 | 3.19k | } |
827 | 18.4k | else if (block1->tracks[i].indices != block2->tracks[i].indices) |
828 | 0 | return false; |
829 | 21.6k | } |
830 | 98 | } |
831 | 11 | else if (block1->tracks != block2->tracks) |
832 | 0 | return false; |
833 | 109 | return true; |
834 | 109 | } |
835 | | |
836 | | static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2) |
837 | 44 | { |
838 | 44 | if (block1->type != block2->type) |
839 | 0 | return false; |
840 | 44 | if (block1->mime_type != block2->mime_type && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type))) |
841 | 0 | return false; |
842 | 44 | if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || strcmp((const char *)block1->description, (const char *)block2->description))) |
843 | 0 | return false; |
844 | 44 | if (block1->width != block2->width) |
845 | 0 | return false; |
846 | 44 | if (block1->height != block2->height) |
847 | 0 | return false; |
848 | 44 | if (block1->depth != block2->depth) |
849 | 0 | return false; |
850 | 44 | if (block1->colors != block2->colors) |
851 | 0 | return false; |
852 | 44 | if (block1->data_length != block2->data_length) |
853 | 0 | return false; |
854 | 44 | if (block1->data != block2->data && (block1->data == NULL || block2->data == NULL || memcmp(block1->data, block2->data, block1->data_length))) |
855 | 0 | return false; |
856 | 44 | return true; |
857 | 44 | } |
858 | | |
859 | | static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, uint32_t block_length) |
860 | 22 | { |
861 | 22 | FLAC__ASSERT(block1 != NULL); |
862 | 22 | FLAC__ASSERT(block2 != NULL); |
863 | | |
864 | 22 | if (block1->data != NULL && block2->data != NULL) |
865 | 11 | return memcmp(block1->data, block2->data, block_length) == 0; |
866 | 11 | else |
867 | 11 | return block1->data == block2->data; |
868 | 22 | } |
869 | | |
870 | | FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2) |
871 | 360 | { |
872 | 360 | FLAC__ASSERT(block1 != NULL); |
873 | 360 | FLAC__ASSERT(block2 != NULL); |
874 | | |
875 | 360 | if (block1->type != block2->type) { |
876 | 0 | return false; |
877 | 0 | } |
878 | 360 | if (block1->is_last != block2->is_last) { |
879 | 0 | return false; |
880 | 0 | } |
881 | 360 | if (block1->length != block2->length) { |
882 | 0 | return false; |
883 | 0 | } |
884 | 360 | switch(block1->type) { |
885 | 16 | case FLAC__METADATA_TYPE_STREAMINFO: |
886 | 16 | return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info); |
887 | 10 | case FLAC__METADATA_TYPE_PADDING: |
888 | 10 | return true; /* we don't compare the padding guts */ |
889 | 51 | case FLAC__METADATA_TYPE_APPLICATION: |
890 | 51 | return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length); |
891 | 35 | case FLAC__METADATA_TYPE_SEEKTABLE: |
892 | 35 | return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table); |
893 | 73 | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
894 | 73 | return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment); |
895 | 109 | case FLAC__METADATA_TYPE_CUESHEET: |
896 | 109 | return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet); |
897 | 44 | case FLAC__METADATA_TYPE_PICTURE: |
898 | 44 | return compare_block_data_picture_(&block1->data.picture, &block2->data.picture); |
899 | 22 | default: |
900 | 22 | return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length); |
901 | 360 | } |
902 | 360 | } |
903 | | |
904 | | FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy) |
905 | 0 | { |
906 | 0 | FLAC__byte *save; |
907 | |
|
908 | 0 | FLAC__ASSERT(object != NULL); |
909 | 0 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION); |
910 | 0 | FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false)); |
911 | |
|
912 | 0 | save = object->data.application.data; |
913 | | |
914 | | /* do the copy first so that if we fail we leave the object untouched */ |
915 | 0 | if (copy) { |
916 | 0 | if (!copy_bytes_(&object->data.application.data, data, length)) |
917 | 0 | return false; |
918 | 0 | } |
919 | 0 | else { |
920 | 0 | object->data.application.data = data; |
921 | 0 | } |
922 | | |
923 | 0 | free(save); |
924 | |
|
925 | 0 | object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length; |
926 | 0 | return true; |
927 | 0 | } |
928 | | |
929 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points) |
930 | 3.29k | { |
931 | 3.29k | FLAC__ASSERT(object != NULL); |
932 | 3.29k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
933 | | |
934 | 3.29k | if((FLAC__uint64)(new_num_points) * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) |
935 | 0 | return false; |
936 | | |
937 | 3.29k | if (object->data.seek_table.points == 0) { |
938 | 208 | FLAC__ASSERT(object->data.seek_table.num_points == 0); |
939 | 208 | if (new_num_points == 0) |
940 | 10 | return true; |
941 | 198 | else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0) |
942 | 0 | return false; |
943 | 208 | } |
944 | 3.09k | else { |
945 | 3.09k | const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint); |
946 | 3.09k | const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint); |
947 | | |
948 | | /* overflow check */ |
949 | 3.09k | if (new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) |
950 | 0 | return false; |
951 | | |
952 | 3.09k | FLAC__ASSERT(object->data.seek_table.num_points > 0); |
953 | | |
954 | 3.09k | if (new_size == 0) { |
955 | 12 | free(object->data.seek_table.points); |
956 | 12 | object->data.seek_table.points = 0; |
957 | 12 | } |
958 | 3.07k | else { |
959 | | /* Leave object->data.seek_table.points untouched if realloc fails */ |
960 | 3.07k | FLAC__StreamMetadata_SeekPoint *tmpptr; |
961 | 3.07k | if ((tmpptr = realloc(object->data.seek_table.points, new_size)) == NULL) |
962 | 0 | return false; |
963 | 3.07k | object->data.seek_table.points = tmpptr; |
964 | 3.07k | } |
965 | | |
966 | | /* if growing, set new elements to placeholders */ |
967 | 3.09k | if (new_size > old_size) { |
968 | 2.76k | uint32_t i; |
969 | 14.3M | for (i = object->data.seek_table.num_points; i < new_num_points; i++) { |
970 | 14.3M | object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; |
971 | 14.3M | object->data.seek_table.points[i].stream_offset = 0; |
972 | 14.3M | object->data.seek_table.points[i].frame_samples = 0; |
973 | 14.3M | } |
974 | 2.76k | } |
975 | 3.09k | } |
976 | | |
977 | 3.28k | object->data.seek_table.num_points = new_num_points; |
978 | | |
979 | 3.28k | seektable_calculate_length_(object); |
980 | 3.28k | return true; |
981 | 3.29k | } |
982 | | |
983 | | FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point) |
984 | 808 | { |
985 | 808 | FLAC__ASSERT(object != NULL); |
986 | 808 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
987 | 808 | FLAC__ASSERT(point_num < object->data.seek_table.num_points); |
988 | | |
989 | 808 | object->data.seek_table.points[point_num] = point; |
990 | 808 | } |
991 | | |
992 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point) |
993 | 404 | { |
994 | 404 | int i; |
995 | | |
996 | 404 | FLAC__ASSERT(object != NULL); |
997 | 404 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
998 | 404 | FLAC__ASSERT(point_num <= object->data.seek_table.num_points); |
999 | | |
1000 | 404 | if (!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1)) |
1001 | 0 | return false; |
1002 | | |
1003 | | /* move all points >= point_num forward one space */ |
1004 | 6.49M | for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--) |
1005 | 6.49M | object->data.seek_table.points[i] = object->data.seek_table.points[i-1]; |
1006 | | |
1007 | 404 | FLAC__metadata_object_seektable_set_point(object, point_num, point); |
1008 | 404 | seektable_calculate_length_(object); |
1009 | 404 | return true; |
1010 | 404 | } |
1011 | | |
1012 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num) |
1013 | 128 | { |
1014 | 128 | uint32_t i; |
1015 | | |
1016 | 128 | FLAC__ASSERT(object != NULL); |
1017 | 128 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1018 | 128 | FLAC__ASSERT(point_num < object->data.seek_table.num_points); |
1019 | | |
1020 | | /* move all points > point_num backward one space */ |
1021 | 3.21M | for (i = point_num; i < object->data.seek_table.num_points-1; i++) |
1022 | 3.21M | object->data.seek_table.points[i] = object->data.seek_table.points[i+1]; |
1023 | | |
1024 | 128 | return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1); |
1025 | 128 | } |
1026 | | |
1027 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object) |
1028 | 701 | { |
1029 | 701 | FLAC__ASSERT(object != NULL); |
1030 | 701 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1031 | | |
1032 | 701 | return FLAC__format_seektable_is_legal(&object->data.seek_table); |
1033 | 701 | } |
1034 | | |
1035 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num) |
1036 | 536 | { |
1037 | 536 | FLAC__ASSERT(object != NULL); |
1038 | 536 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1039 | | |
1040 | 536 | if (num > 0) |
1041 | | /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */ |
1042 | 536 | return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num); |
1043 | 0 | else |
1044 | 0 | return true; |
1045 | 536 | } |
1046 | | |
1047 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number) |
1048 | 536 | { |
1049 | 536 | FLAC__StreamMetadata_SeekTable *seek_table; |
1050 | | |
1051 | 536 | FLAC__ASSERT(object != NULL); |
1052 | 536 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1053 | | |
1054 | 536 | seek_table = &object->data.seek_table; |
1055 | | |
1056 | 536 | if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1)) |
1057 | 0 | return false; |
1058 | | |
1059 | 536 | seek_table->points[seek_table->num_points - 1].sample_number = sample_number; |
1060 | 536 | seek_table->points[seek_table->num_points - 1].stream_offset = 0; |
1061 | 536 | seek_table->points[seek_table->num_points - 1].frame_samples = 0; |
1062 | | |
1063 | 536 | return true; |
1064 | 536 | } |
1065 | | |
1066 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num) |
1067 | 536 | { |
1068 | 536 | FLAC__ASSERT(object != NULL); |
1069 | 536 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1070 | 536 | FLAC__ASSERT(sample_numbers != 0 || num == 0); |
1071 | | |
1072 | 536 | if (num > 0) { |
1073 | 536 | FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; |
1074 | 536 | uint32_t i, j; |
1075 | | |
1076 | 536 | i = seek_table->num_points; |
1077 | | |
1078 | 536 | if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) |
1079 | 0 | return false; |
1080 | | |
1081 | 2.14k | for (j = 0; j < num; i++, j++) { |
1082 | 1.60k | seek_table->points[i].sample_number = sample_numbers[j]; |
1083 | 1.60k | seek_table->points[i].stream_offset = 0; |
1084 | 1.60k | seek_table->points[i].frame_samples = 0; |
1085 | 1.60k | } |
1086 | 536 | } |
1087 | | |
1088 | 536 | return true; |
1089 | 536 | } |
1090 | | |
1091 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples) |
1092 | 536 | { |
1093 | 536 | FLAC__ASSERT(object != NULL); |
1094 | 536 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1095 | | |
1096 | 536 | if (num > 0 && total_samples > 0) { |
1097 | 437 | FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; |
1098 | 437 | uint32_t i, j; |
1099 | | |
1100 | 437 | i = seek_table->num_points; |
1101 | | |
1102 | 437 | if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) |
1103 | 0 | return false; |
1104 | | |
1105 | 437 | if(total_samples < UINT64_MAX / num) { |
1106 | | /* No risk of overflow */ |
1107 | 2.25k | for (j = 0; j < num; i++, j++) { |
1108 | 1.81k | seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num; |
1109 | 1.81k | seek_table->points[i].stream_offset = 0; |
1110 | 1.81k | seek_table->points[i].frame_samples = 0; |
1111 | 1.81k | } |
1112 | 437 | } |
1113 | 0 | else { |
1114 | | /* Less precise, but can handle total_samples near UINT64_MAX */ |
1115 | 0 | for (j = 0; j < num; i++, j++) { |
1116 | 0 | seek_table->points[i].sample_number = total_samples / (FLAC__uint64)num * (FLAC__uint64)j; |
1117 | 0 | seek_table->points[i].stream_offset = 0; |
1118 | 0 | seek_table->points[i].frame_samples = 0; |
1119 | 0 | } |
1120 | 0 | } |
1121 | 437 | } |
1122 | | |
1123 | 536 | return true; |
1124 | 536 | } |
1125 | | |
1126 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples) |
1127 | 536 | { |
1128 | 536 | FLAC__ASSERT(object != NULL); |
1129 | 536 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1130 | | |
1131 | 536 | if (samples > 0 && total_samples > 0) { |
1132 | 437 | FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; |
1133 | 437 | uint32_t i, j; |
1134 | 437 | FLAC__uint64 num, sample; |
1135 | | |
1136 | 437 | num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */ |
1137 | | /* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */ |
1138 | 437 | if (total_samples % samples == 0) |
1139 | 231 | num--; |
1140 | | |
1141 | | /* Put a strict upper bound on the number of allowed seek points. */ |
1142 | 437 | if (num > 32768) { |
1143 | | /* Set the bound and recalculate samples accordingly. */ |
1144 | 437 | num = 32768; |
1145 | 437 | samples = (uint32_t)(total_samples / num); |
1146 | 437 | } |
1147 | | |
1148 | 437 | i = seek_table->num_points; |
1149 | | |
1150 | 437 | if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (uint32_t)num)) |
1151 | 0 | return false; |
1152 | | |
1153 | 437 | sample = 0; |
1154 | 14.3M | for (j = 0; j < num; i++, j++, sample += samples) { |
1155 | 14.3M | seek_table->points[i].sample_number = sample; |
1156 | 14.3M | seek_table->points[i].stream_offset = 0; |
1157 | 14.3M | seek_table->points[i].frame_samples = 0; |
1158 | 14.3M | } |
1159 | 437 | } |
1160 | | |
1161 | 536 | return true; |
1162 | 536 | } |
1163 | | |
1164 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact) |
1165 | 536 | { |
1166 | 536 | uint32_t unique; |
1167 | | |
1168 | 536 | FLAC__ASSERT(object != NULL); |
1169 | 536 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1170 | | |
1171 | 536 | unique = FLAC__format_seektable_sort(&object->data.seek_table); |
1172 | | |
1173 | 536 | return !compact || FLAC__metadata_object_seektable_resize_points(object, unique); |
1174 | 536 | } |
1175 | | |
1176 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) |
1177 | 0 | { |
1178 | 0 | if (!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length)) |
1179 | 0 | return false; |
1180 | 0 | return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy); |
1181 | 0 | } |
1182 | | |
1183 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments) |
1184 | 2.73k | { |
1185 | 2.73k | FLAC__ASSERT(object != NULL); |
1186 | 2.73k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1187 | | |
1188 | 2.73k | if (object->data.vorbis_comment.comments == NULL) { |
1189 | 103 | FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0); |
1190 | 103 | if (new_num_comments == 0) |
1191 | 11 | return true; |
1192 | 92 | else { |
1193 | 92 | uint32_t i; |
1194 | 92 | if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL) |
1195 | 0 | return false; |
1196 | 749 | for (i = 0; i < new_num_comments; i++) { |
1197 | 657 | object->data.vorbis_comment.comments[i].length = 0; |
1198 | 657 | if ((object->data.vorbis_comment.comments[i].entry = safe_malloc_(1)) == NULL) { |
1199 | 0 | object->data.vorbis_comment.num_comments = i+1; |
1200 | 0 | return false; |
1201 | 0 | } |
1202 | 657 | object->data.vorbis_comment.comments[i].entry[0] = '\0'; |
1203 | 657 | } |
1204 | 92 | } |
1205 | 103 | } |
1206 | 2.63k | else { |
1207 | 2.63k | const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); |
1208 | 2.63k | const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); |
1209 | | |
1210 | | /* overflow check */ |
1211 | 2.63k | if (new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry)) |
1212 | 0 | return false; |
1213 | | |
1214 | 2.63k | FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0); |
1215 | | |
1216 | | /* if shrinking, free the truncated entries */ |
1217 | 2.63k | if (new_num_comments < object->data.vorbis_comment.num_comments) { |
1218 | 1.62k | uint32_t i; |
1219 | 175k | for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++) |
1220 | 173k | if (object->data.vorbis_comment.comments[i].entry != NULL) |
1221 | 172k | free(object->data.vorbis_comment.comments[i].entry); |
1222 | 1.62k | } |
1223 | | |
1224 | 2.63k | if (new_size == 0) { |
1225 | 33 | free(object->data.vorbis_comment.comments); |
1226 | 33 | object->data.vorbis_comment.comments = 0; |
1227 | 33 | } |
1228 | 2.60k | else { |
1229 | | /* Leave object->data.vorbis_comment.comments untouched if realloc fails */ |
1230 | 2.60k | FLAC__StreamMetadata_VorbisComment_Entry *tmpptr; |
1231 | 2.60k | if ((tmpptr = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) |
1232 | 0 | return false; |
1233 | 2.60k | object->data.vorbis_comment.comments = tmpptr; |
1234 | 2.60k | } |
1235 | | |
1236 | | /* if growing, zero all the length/pointers of new elements */ |
1237 | 2.63k | if (new_size > old_size) { |
1238 | 1.00k | uint32_t i; |
1239 | 2.51k | for (i = object->data.vorbis_comment.num_comments; i < new_num_comments; i++) { |
1240 | 1.51k | object->data.vorbis_comment.comments[i].length = 0; |
1241 | 1.51k | if ((object->data.vorbis_comment.comments[i].entry = safe_malloc_(1)) == NULL) { |
1242 | 0 | object->data.vorbis_comment.num_comments = i+1; |
1243 | 0 | return false; |
1244 | 0 | } |
1245 | 1.51k | object->data.vorbis_comment.comments[i].entry[0] = '\0'; |
1246 | 1.51k | } |
1247 | 1.00k | } |
1248 | 2.63k | } |
1249 | | |
1250 | 2.72k | object->data.vorbis_comment.num_comments = new_num_comments; |
1251 | | |
1252 | 2.72k | vorbiscomment_calculate_length_(object); |
1253 | 2.72k | return true; |
1254 | 2.73k | } |
1255 | | |
1256 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) |
1257 | 1.84k | { |
1258 | 1.84k | FLAC__ASSERT(object != NULL); |
1259 | 1.84k | FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); |
1260 | | |
1261 | 1.84k | if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) |
1262 | 0 | return false; |
1263 | 1.84k | return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy); |
1264 | 1.84k | } |
1265 | | |
1266 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) |
1267 | 924 | { |
1268 | 924 | FLAC__StreamMetadata_VorbisComment *vc; |
1269 | 924 | FLAC__StreamMetadata_VorbisComment_Entry temp; |
1270 | | |
1271 | 924 | FLAC__ASSERT(object != NULL); |
1272 | 924 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1273 | 924 | FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments); |
1274 | | |
1275 | 924 | if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) |
1276 | 0 | return false; |
1277 | | |
1278 | 924 | vc = &object->data.vorbis_comment; |
1279 | | |
1280 | 924 | if (!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1)) |
1281 | 0 | return false; |
1282 | | |
1283 | | /* move all comments >= comment_num forward one space */ |
1284 | | /* reuse newly added empty comment */ |
1285 | 924 | temp = vc->comments[vc->num_comments-1]; |
1286 | 924 | memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num)); |
1287 | 924 | vc->comments[comment_num] = temp; |
1288 | | |
1289 | 924 | return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy); |
1290 | 924 | } |
1291 | | |
1292 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) |
1293 | 462 | { |
1294 | 462 | FLAC__ASSERT(object != NULL); |
1295 | 462 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1296 | 462 | return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy); |
1297 | 462 | } |
1298 | | |
1299 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy) |
1300 | 462 | { |
1301 | 462 | FLAC__ASSERT(entry.entry != NULL); |
1302 | | |
1303 | 462 | if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) |
1304 | 0 | return false; |
1305 | | |
1306 | 462 | { |
1307 | 462 | int i; |
1308 | 462 | size_t field_name_length; |
1309 | 462 | const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); |
1310 | | |
1311 | 462 | if (eq == NULL) |
1312 | 0 | return false; /* double protection */ |
1313 | | |
1314 | 462 | field_name_length = eq-entry.entry; |
1315 | | |
1316 | 462 | i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length); |
1317 | 462 | if (i >= 0) { |
1318 | 462 | uint32_t indx = (uint32_t)i; |
1319 | 462 | if (!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy)) |
1320 | 0 | return false; |
1321 | 462 | entry = object->data.vorbis_comment.comments[indx]; |
1322 | 462 | indx++; /* skip over replaced comment */ |
1323 | 462 | if (all && indx < object->data.vorbis_comment.num_comments) { |
1324 | 217 | i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); |
1325 | 1.28k | while (i >= 0) { |
1326 | 1.06k | indx = (uint32_t)i; |
1327 | 1.06k | if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx)) |
1328 | 0 | return false; |
1329 | 1.06k | if (indx < object->data.vorbis_comment.num_comments) |
1330 | 955 | i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); |
1331 | 108 | else |
1332 | 108 | i = -1; |
1333 | 1.06k | } |
1334 | 217 | } |
1335 | 462 | return true; |
1336 | 462 | } |
1337 | 0 | else |
1338 | 0 | return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy); |
1339 | 462 | } |
1340 | 462 | } |
1341 | | |
1342 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num) |
1343 | 1.59k | { |
1344 | 1.59k | FLAC__StreamMetadata_VorbisComment *vc; |
1345 | | |
1346 | 1.59k | FLAC__ASSERT(object != NULL); |
1347 | 1.59k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1348 | 1.59k | FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); |
1349 | | |
1350 | 1.59k | vc = &object->data.vorbis_comment; |
1351 | | |
1352 | | /* free the comment at comment_num */ |
1353 | 1.59k | free(vc->comments[comment_num].entry); |
1354 | | |
1355 | | /* move all comments > comment_num backward one space */ |
1356 | 1.59k | memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1)); |
1357 | 1.59k | vc->comments[vc->num_comments-1].length = 0; |
1358 | 1.59k | vc->comments[vc->num_comments-1].entry = 0; |
1359 | | |
1360 | 1.59k | return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1); |
1361 | 1.59k | } |
1362 | | |
1363 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value) |
1364 | 0 | { |
1365 | 0 | FLAC__ASSERT(entry != NULL); |
1366 | 0 | FLAC__ASSERT(field_name != NULL); |
1367 | 0 | FLAC__ASSERT(field_value != NULL); |
1368 | |
|
1369 | 0 | if (!FLAC__format_vorbiscomment_entry_name_is_legal(field_name)) |
1370 | 0 | return false; |
1371 | 0 | if (!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (uint32_t)(-1))) |
1372 | 0 | return false; |
1373 | | |
1374 | 0 | { |
1375 | 0 | const size_t nn = strlen(field_name); |
1376 | 0 | const size_t nv = strlen(field_value); |
1377 | 0 | entry->length = nn + 1 /*=*/ + nv; |
1378 | 0 | if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL) |
1379 | 0 | return false; |
1380 | 0 | memcpy(entry->entry, field_name, nn); |
1381 | 0 | entry->entry[nn] = '='; |
1382 | 0 | memcpy(entry->entry+nn+1, field_value, nv); |
1383 | 0 | entry->entry[entry->length] = '\0'; |
1384 | 0 | } |
1385 | | |
1386 | 0 | return true; |
1387 | 0 | } |
1388 | | |
1389 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value) |
1390 | 0 | { |
1391 | 0 | FLAC__ASSERT(entry.entry != NULL); |
1392 | 0 | FLAC__ASSERT(field_name != NULL); |
1393 | 0 | FLAC__ASSERT(field_value != NULL); |
1394 | |
|
1395 | 0 | if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) |
1396 | 0 | return false; |
1397 | | |
1398 | 0 | { |
1399 | 0 | const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); |
1400 | 0 | const size_t nn = eq-entry.entry; |
1401 | 0 | const size_t nv = entry.length-nn-1; /* -1 for the '=' */ |
1402 | |
|
1403 | 0 | if (eq == NULL) |
1404 | 0 | return false; /* double protection */ |
1405 | 0 | if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL) |
1406 | 0 | return false; |
1407 | 0 | if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) { |
1408 | 0 | free(*field_name); |
1409 | 0 | return false; |
1410 | 0 | } |
1411 | 0 | memcpy(*field_name, entry.entry, nn); |
1412 | 0 | memcpy(*field_value, entry.entry+nn+1, nv); |
1413 | 0 | (*field_name)[nn] = '\0'; |
1414 | 0 | (*field_value)[nv] = '\0'; |
1415 | 0 | } |
1416 | | |
1417 | 0 | return true; |
1418 | 0 | } |
1419 | | |
1420 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length) |
1421 | 1.42M | { |
1422 | 1.42M | FLAC__ASSERT(entry.entry != NULL); |
1423 | 1.42M | { |
1424 | 1.42M | const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); |
1425 | 1.42M | return (eq != NULL && (uint32_t)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0); |
1426 | 1.42M | } |
1427 | 1.42M | } |
1428 | | |
1429 | | FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name) |
1430 | 151 | { |
1431 | 151 | FLAC__ASSERT(field_name != NULL); |
1432 | | |
1433 | 151 | return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name)); |
1434 | 151 | } |
1435 | | |
1436 | | FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name) |
1437 | 283 | { |
1438 | 283 | const uint32_t field_name_length = strlen(field_name); |
1439 | 283 | uint32_t i; |
1440 | | |
1441 | 283 | FLAC__ASSERT(object != NULL); |
1442 | 283 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1443 | | |
1444 | 566k | for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { |
1445 | 566k | if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { |
1446 | 22 | if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i)) |
1447 | 0 | return -1; |
1448 | 22 | else |
1449 | 22 | return 1; |
1450 | 22 | } |
1451 | 566k | } |
1452 | | |
1453 | 261 | return 0; |
1454 | 283 | } |
1455 | | |
1456 | | FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name) |
1457 | 283 | { |
1458 | 283 | FLAC__bool ok = true; |
1459 | 283 | uint32_t matching = 0; |
1460 | 283 | const uint32_t field_name_length = strlen(field_name); |
1461 | 283 | int i; |
1462 | | |
1463 | 283 | FLAC__ASSERT(object != NULL); |
1464 | 283 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1465 | | |
1466 | | /* must delete from end to start otherwise it will interfere with our iteration */ |
1467 | 568k | for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) { |
1468 | 568k | if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { |
1469 | 239 | matching++; |
1470 | 239 | ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (uint32_t)i); |
1471 | 239 | } |
1472 | 568k | } |
1473 | | |
1474 | 283 | return ok? (int)matching : -1; |
1475 | 283 | } |
1476 | | |
1477 | | FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void) |
1478 | 642 | { |
1479 | 642 | return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track)); |
1480 | 642 | } |
1481 | | |
1482 | | FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object) |
1483 | 642 | { |
1484 | 642 | FLAC__StreamMetadata_CueSheet_Track *to; |
1485 | | |
1486 | 642 | FLAC__ASSERT(object != NULL); |
1487 | | |
1488 | 642 | if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) { |
1489 | 642 | if (!copy_track_(to, object)) { |
1490 | 0 | FLAC__metadata_object_cuesheet_track_delete(to); |
1491 | 0 | return 0; |
1492 | 0 | } |
1493 | 642 | } |
1494 | | |
1495 | 642 | return to; |
1496 | 642 | } |
1497 | | |
1498 | | void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object) |
1499 | 642 | { |
1500 | 642 | FLAC__ASSERT(object != NULL); |
1501 | | |
1502 | 642 | if (object->indices != NULL) { |
1503 | 283 | FLAC__ASSERT(object->num_indices > 0); |
1504 | 283 | free(object->indices); |
1505 | 283 | } |
1506 | 642 | } |
1507 | | |
1508 | | FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object) |
1509 | 642 | { |
1510 | 642 | FLAC__metadata_object_cuesheet_track_delete_data(object); |
1511 | 642 | free(object); |
1512 | 642 | } |
1513 | | |
1514 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices) |
1515 | 408 | { |
1516 | 408 | FLAC__StreamMetadata_CueSheet_Track *track; |
1517 | 408 | FLAC__ASSERT(object != NULL); |
1518 | 408 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1519 | 408 | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1520 | | |
1521 | 408 | track = &object->data.cue_sheet.tracks[track_num]; |
1522 | | |
1523 | 408 | if (track->indices == NULL) { |
1524 | 90 | FLAC__ASSERT(track->num_indices == 0); |
1525 | 90 | if (new_num_indices == 0) |
1526 | 20 | return true; |
1527 | 70 | else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL) |
1528 | 0 | return false; |
1529 | 90 | } |
1530 | 318 | else { |
1531 | 318 | const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); |
1532 | 318 | const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); |
1533 | | |
1534 | | /* overflow check */ |
1535 | 318 | if (new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index)) |
1536 | 0 | return false; |
1537 | | |
1538 | 318 | FLAC__ASSERT(track->num_indices > 0); |
1539 | | |
1540 | 318 | if (new_size == 0) { |
1541 | 123 | free(track->indices); |
1542 | 123 | track->indices = 0; |
1543 | 123 | } |
1544 | 195 | else { |
1545 | | /* Leave track->indices untouched if realloc fails */ |
1546 | 195 | FLAC__StreamMetadata_CueSheet_Index *tmpptr; |
1547 | 195 | if ((tmpptr = realloc(track->indices, new_size)) == NULL) |
1548 | 0 | return false; |
1549 | 195 | track->indices = tmpptr; |
1550 | 195 | } |
1551 | | |
1552 | | /* if growing, zero all the lengths/pointers of new elements */ |
1553 | 318 | if (new_size > old_size) |
1554 | 184 | memset(track->indices + track->num_indices, 0, new_size - old_size); |
1555 | 318 | } |
1556 | | |
1557 | 388 | track->num_indices = new_num_indices; |
1558 | | |
1559 | 388 | cuesheet_calculate_length_(object); |
1560 | 388 | return true; |
1561 | 408 | } |
1562 | | |
1563 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index indx) |
1564 | 128 | { |
1565 | 128 | FLAC__StreamMetadata_CueSheet_Track *track; |
1566 | | |
1567 | 128 | FLAC__ASSERT(object != NULL); |
1568 | 128 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1569 | 128 | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1570 | 128 | FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices); |
1571 | | |
1572 | 128 | track = &object->data.cue_sheet.tracks[track_num]; |
1573 | | |
1574 | 128 | if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1)) |
1575 | 0 | return false; |
1576 | | |
1577 | | /* move all indices >= index_num forward one space */ |
1578 | 128 | memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num)); |
1579 | | |
1580 | 128 | track->indices[index_num] = indx; |
1581 | 128 | cuesheet_calculate_length_(object); |
1582 | 128 | return true; |
1583 | 128 | } |
1584 | | |
1585 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num) |
1586 | 64 | { |
1587 | 64 | FLAC__StreamMetadata_CueSheet_Index indx; |
1588 | 64 | memset(&indx, 0, sizeof(indx)); |
1589 | 64 | return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx); |
1590 | 64 | } |
1591 | | |
1592 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num) |
1593 | 66 | { |
1594 | 66 | FLAC__StreamMetadata_CueSheet_Track *track; |
1595 | | |
1596 | 66 | FLAC__ASSERT(object != NULL); |
1597 | 66 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1598 | 66 | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1599 | 66 | FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices); |
1600 | | |
1601 | 66 | track = &object->data.cue_sheet.tracks[track_num]; |
1602 | | |
1603 | | /* move all indices > index_num backward one space */ |
1604 | 66 | memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1)); |
1605 | | |
1606 | 66 | FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1); |
1607 | 66 | cuesheet_calculate_length_(object); |
1608 | 66 | return true; |
1609 | 66 | } |
1610 | | |
1611 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks) |
1612 | 425 | { |
1613 | 425 | FLAC__ASSERT(object != NULL); |
1614 | 425 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1615 | | |
1616 | 425 | if (object->data.cue_sheet.tracks == NULL) { |
1617 | 0 | FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0); |
1618 | 0 | if (new_num_tracks == 0) |
1619 | 0 | return true; |
1620 | 0 | else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL) |
1621 | 0 | return false; |
1622 | 0 | } |
1623 | 425 | else { |
1624 | 425 | const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); |
1625 | 425 | const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); |
1626 | | |
1627 | | /* overflow check */ |
1628 | 425 | if (new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track)) |
1629 | 0 | return false; |
1630 | | |
1631 | 425 | FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); |
1632 | | |
1633 | | /* if shrinking, free the truncated entries */ |
1634 | 425 | if (new_num_tracks < object->data.cue_sheet.num_tracks) { |
1635 | 111 | uint32_t i; |
1636 | 644 | for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++) |
1637 | 533 | free(object->data.cue_sheet.tracks[i].indices); |
1638 | 111 | } |
1639 | | |
1640 | 425 | if (new_size == 0) { |
1641 | 38 | free(object->data.cue_sheet.tracks); |
1642 | 38 | object->data.cue_sheet.tracks = 0; |
1643 | 38 | } |
1644 | 387 | else { |
1645 | | /* Leave object->data.cue_sheet.tracks untouched if realloc fails */ |
1646 | 387 | FLAC__StreamMetadata_CueSheet_Track *tmpptr; |
1647 | 387 | if ((tmpptr = realloc(object->data.cue_sheet.tracks, new_size)) == NULL) |
1648 | 0 | return false; |
1649 | 387 | object->data.cue_sheet.tracks = tmpptr; |
1650 | 387 | } |
1651 | | |
1652 | | /* if growing, zero all the lengths/pointers of new elements */ |
1653 | 425 | if (new_size > old_size) |
1654 | 314 | memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size); |
1655 | 425 | } |
1656 | | |
1657 | 425 | object->data.cue_sheet.num_tracks = new_num_tracks; |
1658 | | |
1659 | 425 | cuesheet_calculate_length_(object); |
1660 | 425 | return true; |
1661 | 425 | } |
1662 | | |
1663 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy) |
1664 | 222 | { |
1665 | 222 | FLAC__ASSERT(object != NULL); |
1666 | 222 | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1667 | | |
1668 | 222 | return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy); |
1669 | 222 | } |
1670 | | |
1671 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy) |
1672 | 222 | { |
1673 | 222 | FLAC__StreamMetadata_CueSheet *cs; |
1674 | | |
1675 | 222 | FLAC__ASSERT(object != NULL); |
1676 | 222 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1677 | 222 | FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks); |
1678 | | |
1679 | 222 | cs = &object->data.cue_sheet; |
1680 | | |
1681 | 222 | if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1)) |
1682 | 0 | return false; |
1683 | | |
1684 | | /* move all tracks >= track_num forward one space */ |
1685 | 222 | memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num)); |
1686 | 222 | cs->tracks[track_num].num_indices = 0; |
1687 | 222 | cs->tracks[track_num].indices = 0; |
1688 | | |
1689 | 222 | return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy); |
1690 | 222 | } |
1691 | | |
1692 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num) |
1693 | 111 | { |
1694 | 111 | FLAC__StreamMetadata_CueSheet_Track track; |
1695 | 111 | memset(&track, 0, sizeof(track)); |
1696 | 111 | return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false); |
1697 | 111 | } |
1698 | | |
1699 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num) |
1700 | 100 | { |
1701 | 100 | FLAC__StreamMetadata_CueSheet *cs; |
1702 | | |
1703 | 100 | FLAC__ASSERT(object != NULL); |
1704 | 100 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1705 | 100 | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1706 | | |
1707 | 100 | cs = &object->data.cue_sheet; |
1708 | | |
1709 | | /* free the track at track_num */ |
1710 | 100 | free(cs->tracks[track_num].indices); |
1711 | | |
1712 | | /* move all tracks > track_num backward one space */ |
1713 | 100 | memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1)); |
1714 | 100 | cs->tracks[cs->num_tracks-1].num_indices = 0; |
1715 | 100 | cs->tracks[cs->num_tracks-1].indices = 0; |
1716 | | |
1717 | 100 | return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1); |
1718 | 100 | } |
1719 | | |
1720 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation) |
1721 | 1.39k | { |
1722 | 1.39k | FLAC__ASSERT(object != NULL); |
1723 | 1.39k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1724 | | |
1725 | 1.39k | return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation); |
1726 | 1.39k | } |
1727 | | |
1728 | | static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, uint32_t track) |
1729 | 3.58k | { |
1730 | 3.58k | if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1) |
1731 | 0 | return 0; |
1732 | 3.58k | else if (cs->tracks[track].indices[0].number == 1) |
1733 | 3.30k | return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in; |
1734 | 282 | else if (cs->tracks[track].num_indices < 2) |
1735 | 216 | return 0; |
1736 | 66 | else if (cs->tracks[track].indices[1].number == 1) |
1737 | 66 | return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in; |
1738 | 0 | else |
1739 | 0 | return 0; |
1740 | 3.58k | } |
1741 | | |
1742 | | static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x) |
1743 | 3.35k | { |
1744 | 3.35k | FLAC__uint32 n = 0; |
1745 | 33.3k | while (x) { |
1746 | 30.0k | n += (x%10); |
1747 | 30.0k | x /= 10; |
1748 | 30.0k | } |
1749 | 3.35k | return n; |
1750 | 3.35k | } |
1751 | | |
1752 | | /*@@@@add to tests*/ |
1753 | | FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object) |
1754 | 431 | { |
1755 | 431 | const FLAC__StreamMetadata_CueSheet *cs; |
1756 | | |
1757 | 431 | FLAC__ASSERT(object != NULL); |
1758 | 431 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1759 | | |
1760 | 431 | cs = &object->data.cue_sheet; |
1761 | | |
1762 | 431 | if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */ |
1763 | 201 | return 0; |
1764 | | |
1765 | 230 | { |
1766 | 230 | FLAC__uint32 i, length, sum = 0; |
1767 | 3.58k | for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */ |
1768 | 3.35k | sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100)); |
1769 | 230 | length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100); |
1770 | | |
1771 | 230 | return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1); |
1772 | 431 | } |
1773 | 431 | } |
1774 | | |
1775 | | FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy) |
1776 | 95 | { |
1777 | 95 | char *old; |
1778 | 95 | size_t old_length, new_length; |
1779 | | |
1780 | 95 | FLAC__ASSERT(object != NULL); |
1781 | 95 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); |
1782 | 95 | FLAC__ASSERT(mime_type != NULL); |
1783 | | |
1784 | 95 | old = object->data.picture.mime_type; |
1785 | 95 | old_length = old? strlen(old) : 0; |
1786 | 95 | new_length = strlen(mime_type); |
1787 | | |
1788 | | /* do the copy first so that if we fail we leave the object untouched */ |
1789 | 95 | if (copy) { |
1790 | 95 | if (new_length >= SIZE_MAX) /* overflow check */ |
1791 | 0 | return false; |
1792 | 95 | if (!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1)) |
1793 | 0 | return false; |
1794 | 95 | } |
1795 | 0 | else { |
1796 | 0 | object->data.picture.mime_type = mime_type; |
1797 | 0 | } |
1798 | | |
1799 | 95 | free(old); |
1800 | | |
1801 | 95 | object->length -= old_length; |
1802 | 95 | object->length += new_length; |
1803 | 95 | return true; |
1804 | 95 | } |
1805 | | |
1806 | | FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy) |
1807 | 95 | { |
1808 | 95 | FLAC__byte *old; |
1809 | 95 | size_t old_length, new_length; |
1810 | | |
1811 | 95 | FLAC__ASSERT(object != NULL); |
1812 | 95 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); |
1813 | 95 | FLAC__ASSERT(description != NULL); |
1814 | | |
1815 | 95 | old = object->data.picture.description; |
1816 | 95 | old_length = old? strlen((const char *)old) : 0; |
1817 | 95 | new_length = strlen((const char *)description); |
1818 | | |
1819 | | /* do the copy first so that if we fail we leave the object untouched */ |
1820 | 95 | if (copy) { |
1821 | 95 | if (new_length >= SIZE_MAX) /* overflow check */ |
1822 | 0 | return false; |
1823 | 95 | if (!copy_bytes_(&object->data.picture.description, description, new_length+1)) |
1824 | 0 | return false; |
1825 | 95 | } |
1826 | 0 | else { |
1827 | 0 | object->data.picture.description = description; |
1828 | 0 | } |
1829 | | |
1830 | 95 | free(old); |
1831 | | |
1832 | 95 | object->length -= old_length; |
1833 | 95 | object->length += new_length; |
1834 | 95 | return true; |
1835 | 95 | } |
1836 | | |
1837 | | FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy) |
1838 | 95 | { |
1839 | 95 | FLAC__byte *old; |
1840 | | |
1841 | 95 | FLAC__ASSERT(object != NULL); |
1842 | 95 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); |
1843 | 95 | FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false)); |
1844 | | |
1845 | 95 | old = object->data.picture.data; |
1846 | | |
1847 | | /* do the copy first so that if we fail we leave the object untouched */ |
1848 | 95 | if (copy) { |
1849 | 95 | if (!copy_bytes_(&object->data.picture.data, data, length)) |
1850 | 0 | return false; |
1851 | 95 | } |
1852 | 0 | else { |
1853 | 0 | object->data.picture.data = data; |
1854 | 0 | } |
1855 | | |
1856 | 95 | free(old); |
1857 | | |
1858 | 95 | object->length -= object->data.picture.data_length; |
1859 | 95 | object->data.picture.data_length = length; |
1860 | 95 | object->length += length; |
1861 | 95 | return true; |
1862 | 95 | } |
1863 | | |
1864 | | FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation) |
1865 | 213 | { |
1866 | 213 | FLAC__ASSERT(object != NULL); |
1867 | 213 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); |
1868 | | |
1869 | 213 | return FLAC__format_picture_is_legal(&object->data.picture, violation); |
1870 | 213 | } |
1871 | | |
1872 | | FLAC_API FLAC__byte * FLAC__metadata_object_get_raw(const FLAC__StreamMetadata *object) |
1873 | 0 | { |
1874 | 0 | FLAC__BitWriter *bw; |
1875 | 0 | const FLAC__byte * buffer; |
1876 | 0 | FLAC__byte * output; |
1877 | 0 | size_t bytes; |
1878 | |
|
1879 | 0 | FLAC__ASSERT(object != NULL); |
1880 | |
|
1881 | 0 | if((bw = FLAC__bitwriter_new()) == NULL) |
1882 | 0 | return 0; |
1883 | 0 | if(!FLAC__bitwriter_init(bw)) { |
1884 | 0 | FLAC__bitwriter_delete(bw); |
1885 | 0 | return 0; |
1886 | 0 | } |
1887 | 0 | if(!FLAC__add_metadata_block(object, bw, false)) { |
1888 | 0 | FLAC__bitwriter_delete(bw); |
1889 | 0 | return 0; |
1890 | 0 | } |
1891 | | |
1892 | 0 | if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) { |
1893 | 0 | FLAC__bitwriter_delete(bw); |
1894 | 0 | return 0; |
1895 | 0 | } |
1896 | | |
1897 | | /* Extra check whether length of bitwriter agrees with length of metadata block */ |
1898 | 0 | if(bytes != (object->length+FLAC__STREAM_METADATA_HEADER_LENGTH)) { |
1899 | 0 | FLAC__bitwriter_delete(bw); |
1900 | 0 | return 0; |
1901 | 0 | } |
1902 | | |
1903 | 0 | output = safe_malloc_(bytes); |
1904 | 0 | if(output == 0) { |
1905 | 0 | FLAC__bitwriter_delete(bw); |
1906 | 0 | return 0; |
1907 | 0 | } |
1908 | | |
1909 | 0 | memcpy(output,buffer,bytes); |
1910 | 0 | FLAC__bitwriter_delete(bw); |
1911 | 0 | return output; |
1912 | 0 | } |
1913 | | |
1914 | | /* The following callbacks are for FLAC__metadata_object_set_raw */ |
1915 | | |
1916 | | static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte *buffer, size_t *bytes, void *client_data); |
1917 | | static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); |
1918 | | static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); |
1919 | | static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); |
1920 | | |
1921 | | typedef struct { |
1922 | | FLAC__StreamMetadata *object; |
1923 | | FLAC__bool got_error; |
1924 | | FLAC__byte *buffer; |
1925 | | FLAC__int32 length; |
1926 | | FLAC__int32 tell; |
1927 | | } set_raw_client_data; |
1928 | | |
1929 | | FLAC_API FLAC__StreamMetadata * FLAC__metadata_object_set_raw(FLAC__byte *buffer, FLAC__uint32 length) |
1930 | 0 | { |
1931 | 0 | set_raw_client_data cd; |
1932 | 0 | FLAC__StreamDecoder * decoder; |
1933 | |
|
1934 | 0 | cd.buffer = buffer; |
1935 | 0 | cd.length = length; |
1936 | 0 | cd.got_error = false; |
1937 | 0 | cd.object = 0; |
1938 | 0 | cd.tell = -4; |
1939 | |
|
1940 | 0 | decoder = FLAC__stream_decoder_new(); |
1941 | |
|
1942 | 0 | if(0 == decoder) |
1943 | 0 | return 0; |
1944 | | |
1945 | 0 | FLAC__stream_decoder_set_md5_checking(decoder, false); |
1946 | 0 | FLAC__stream_decoder_set_metadata_respond_all(decoder); |
1947 | |
|
1948 | 0 | if(FLAC__stream_decoder_init_stream(decoder, read_callback_, NULL, NULL, NULL, NULL, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) { |
1949 | 0 | (void)FLAC__stream_decoder_finish(decoder); |
1950 | 0 | FLAC__stream_decoder_delete(decoder); |
1951 | 0 | return 0; |
1952 | 0 | } |
1953 | | |
1954 | 0 | if((!FLAC__stream_decoder_process_until_end_of_metadata(decoder) && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM) || cd.got_error) { |
1955 | 0 | (void)FLAC__stream_decoder_finish(decoder); |
1956 | 0 | FLAC__stream_decoder_delete(decoder); |
1957 | 0 | if(0 != cd.object) |
1958 | 0 | FLAC__metadata_object_delete(cd.object); |
1959 | 0 | return 0; |
1960 | 0 | } |
1961 | | |
1962 | 0 | (void)FLAC__stream_decoder_finish(decoder); |
1963 | 0 | FLAC__stream_decoder_delete(decoder); |
1964 | |
|
1965 | 0 | return cd.object; |
1966 | |
|
1967 | 0 | } |
1968 | | |
1969 | | FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte *buffer, size_t *bytes, void *client_data) |
1970 | 0 | { |
1971 | 0 | set_raw_client_data *cd = (set_raw_client_data *)client_data; |
1972 | 0 | (void)decoder; |
1973 | |
|
1974 | 0 | if(cd->tell == -4) { |
1975 | 0 | if(*bytes < 4) |
1976 | 0 | return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
1977 | 0 | buffer[0] = 'f'; |
1978 | 0 | buffer[1] = 'L'; |
1979 | 0 | buffer[2] = 'a'; |
1980 | 0 | buffer[3] = 'C'; |
1981 | 0 | *bytes = 4; |
1982 | 0 | cd->tell = 0; |
1983 | 0 | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
1984 | 0 | } |
1985 | 0 | else if(cd->tell < 0) |
1986 | 0 | return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
1987 | 0 | else if(cd->tell == cd->length) { |
1988 | 0 | *bytes = 0; |
1989 | 0 | return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; |
1990 | 0 | } |
1991 | 0 | else { |
1992 | 0 | if((FLAC__int32)(*bytes) > (cd->length - cd->tell)) |
1993 | 0 | *bytes = cd->length - cd->tell; |
1994 | 0 | memcpy(buffer, cd->buffer+cd->tell, *bytes); |
1995 | 0 | cd->tell += *bytes; |
1996 | 0 | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
1997 | 0 | } |
1998 | 0 | } |
1999 | | |
2000 | | FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) |
2001 | 0 | { |
2002 | 0 | (void)decoder, (void)frame, (void)buffer, (void)client_data; |
2003 | |
|
2004 | 0 | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; |
2005 | 0 | } |
2006 | | |
2007 | | void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) |
2008 | 0 | { |
2009 | 0 | set_raw_client_data *cd = (set_raw_client_data *)client_data; |
2010 | 0 | (void)decoder; |
2011 | | |
2012 | | /* |
2013 | | * we assume we only get here when the one metadata block we were |
2014 | | * looking for was passed to us |
2015 | | */ |
2016 | 0 | if(!cd->got_error && 0 == cd->object) { |
2017 | 0 | if(0 == (cd->object = FLAC__metadata_object_clone(metadata))) |
2018 | 0 | cd->got_error = true; |
2019 | 0 | } |
2020 | 0 | } |
2021 | | |
2022 | | void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) |
2023 | 0 | { |
2024 | 0 | set_raw_client_data *cd = (set_raw_client_data *)client_data; |
2025 | 0 | (void)decoder; |
2026 | |
|
2027 | 0 | if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) |
2028 | 0 | cd->got_error = true; |
2029 | 0 | } |