/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 | 107k | { |
69 | 107k | FLAC__ASSERT(to != NULL); |
70 | 107k | if (bytes > 0 && from != NULL) { |
71 | 82.6k | FLAC__byte *x; |
72 | 82.6k | if ((x = safe_malloc_(bytes)) == NULL) |
73 | 30 | return false; |
74 | 82.6k | memcpy(x, from, bytes); |
75 | 82.6k | *to = x; |
76 | 82.6k | } |
77 | 25.1k | else { |
78 | 25.1k | *to = 0; |
79 | 25.1k | } |
80 | 107k | return true; |
81 | 107k | } |
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 | 7.82k | { |
103 | 7.82k | FLAC__byte *x = safe_realloc_nofree_add_2op_(*entry, length, /*+*/1); |
104 | 7.82k | if (x != NULL) { |
105 | 7.81k | x[length] = '\0'; |
106 | 7.81k | *entry = x; |
107 | 7.81k | return true; |
108 | 7.81k | } |
109 | 8 | else |
110 | 8 | return false; |
111 | 7.82k | } |
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 | 97.6k | { |
119 | 97.6k | char *copy = strdup(from); |
120 | 97.6k | FLAC__ASSERT(to != NULL); |
121 | 97.6k | if (copy) { |
122 | 97.6k | free(*to); |
123 | 97.6k | *to = copy; |
124 | 97.6k | return true; |
125 | 97.6k | } |
126 | 0 | else |
127 | 0 | return false; |
128 | 97.6k | } |
129 | | |
130 | | static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from) |
131 | 1.26M | { |
132 | 1.26M | to->length = from->length; |
133 | 1.26M | 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.26M | else { |
140 | 1.26M | FLAC__byte *x; |
141 | 1.26M | if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL) |
142 | 26 | return false; |
143 | 1.26M | memcpy(x, from->entry, from->length); |
144 | 1.26M | x[from->length] = '\0'; |
145 | 1.26M | to->entry = x; |
146 | 1.26M | } |
147 | 1.26M | return true; |
148 | 1.26M | } |
149 | | |
150 | | static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from) |
151 | 76.5k | { |
152 | 76.5k | memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track)); |
153 | 76.5k | if (from->indices == 0) { |
154 | 53.4k | FLAC__ASSERT(from->num_indices == 0); |
155 | 53.4k | } |
156 | 23.0k | else { |
157 | 23.0k | FLAC__StreamMetadata_CueSheet_Index *x; |
158 | 23.0k | FLAC__ASSERT(from->num_indices > 0); |
159 | 23.0k | if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL) |
160 | 0 | return false; |
161 | 23.0k | memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); |
162 | 23.0k | to->indices = x; |
163 | 23.0k | } |
164 | 76.5k | return true; |
165 | 76.5k | } |
166 | | |
167 | | static void seektable_calculate_length_(FLAC__StreamMetadata *object) |
168 | 88.1k | { |
169 | 88.1k | FLAC__ASSERT(object != NULL); |
170 | 88.1k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
171 | | |
172 | 88.1k | object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; |
173 | 88.1k | } |
174 | | |
175 | | static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points) |
176 | 13.9k | { |
177 | 13.9k | FLAC__StreamMetadata_SeekPoint *object_array; |
178 | | |
179 | 13.9k | FLAC__ASSERT(num_points > 0); |
180 | | |
181 | 13.9k | object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)); |
182 | | |
183 | 13.9k | if (object_array != NULL) { |
184 | 13.9k | uint32_t i; |
185 | 165M | for (i = 0; i < num_points; i++) { |
186 | 165M | object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; |
187 | 165M | object_array[i].stream_offset = 0; |
188 | 165M | object_array[i].frame_samples = 0; |
189 | 165M | } |
190 | 13.9k | } |
191 | | |
192 | 13.9k | return object_array; |
193 | 13.9k | } |
194 | | |
195 | | static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object) |
196 | 147k | { |
197 | 147k | uint32_t i; |
198 | | |
199 | 147k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
200 | | |
201 | 147k | object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8; |
202 | 147k | object->length += object->data.vorbis_comment.vendor_string.length; |
203 | 147k | object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8; |
204 | 539M | for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { |
205 | 539M | object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8); |
206 | 539M | object->length += object->data.vorbis_comment.comments[i].length; |
207 | 539M | } |
208 | 147k | } |
209 | | |
210 | | static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments) |
211 | 7.16k | { |
212 | 7.16k | FLAC__ASSERT(num_comments > 0); |
213 | | |
214 | 7.16k | return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); |
215 | 7.16k | } |
216 | | |
217 | | static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) |
218 | 10.3k | { |
219 | 10.3k | uint32_t i; |
220 | | |
221 | 10.3k | FLAC__ASSERT(object_array != NULL); |
222 | | |
223 | 93.1M | for (i = 0; i < num_comments; i++) |
224 | 93.1M | free(object_array[i].entry); |
225 | | |
226 | 10.3k | free(object_array); |
227 | 10.3k | } |
228 | | |
229 | | static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) |
230 | 2.33k | { |
231 | 2.33k | FLAC__StreamMetadata_VorbisComment_Entry *return_array; |
232 | | |
233 | 2.33k | FLAC__ASSERT(object_array != NULL); |
234 | 2.33k | FLAC__ASSERT(num_comments > 0); |
235 | | |
236 | 2.33k | return_array = vorbiscomment_entry_array_new_(num_comments); |
237 | | |
238 | 2.33k | if (return_array != NULL) { |
239 | 2.33k | uint32_t i; |
240 | | |
241 | 1.22M | for (i = 0; i < num_comments; i++) { |
242 | 1.21M | if (!copy_vcentry_(return_array+i, object_array+i)) { |
243 | 9 | vorbiscomment_entry_array_delete_(return_array, num_comments); |
244 | 9 | return 0; |
245 | 9 | } |
246 | 1.21M | } |
247 | 2.33k | } |
248 | | |
249 | 2.33k | return return_array; |
250 | 2.33k | } |
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 | 45.4k | { |
254 | 45.4k | FLAC__byte *save; |
255 | | |
256 | 45.4k | FLAC__ASSERT(object != NULL); |
257 | 45.4k | FLAC__ASSERT(dest != NULL); |
258 | 45.4k | FLAC__ASSERT(src != NULL); |
259 | 45.4k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
260 | 45.4k | FLAC__ASSERT((src->entry != NULL && src->length > 0) || (src->entry == NULL && src->length == 0)); |
261 | | |
262 | 45.4k | save = dest->entry; |
263 | | |
264 | 45.4k | if (src->entry != NULL) { |
265 | 45.4k | if (copy) { |
266 | | /* do the copy first so that if we fail we leave the dest object untouched */ |
267 | 37.6k | if (!copy_vcentry_(dest, src)) |
268 | 15 | return false; |
269 | 37.6k | } |
270 | 7.82k | 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 | 7.82k | if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length)) |
282 | 8 | return false; |
283 | 7.81k | *dest = *src; |
284 | 7.81k | } |
285 | 45.4k | } |
286 | 0 | else { |
287 | | /* the src is null */ |
288 | 0 | *dest = *src; |
289 | 0 | } |
290 | | |
291 | 45.4k | free(save); |
292 | | |
293 | 45.4k | vorbiscomment_calculate_length_(object); |
294 | 45.4k | return true; |
295 | 45.4k | } |
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 | 12.8k | { |
299 | 12.8k | uint32_t i; |
300 | | |
301 | 12.8k | FLAC__ASSERT(object != NULL); |
302 | 12.8k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
303 | 12.8k | FLAC__ASSERT(field_name != NULL); |
304 | | |
305 | 288k | for (i = offset; i < object->data.vorbis_comment.num_comments; i++) { |
306 | 280k | if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) |
307 | 4.85k | return (int)i; |
308 | 280k | } |
309 | | |
310 | 7.98k | return -1; |
311 | 12.8k | } |
312 | | |
313 | | static void cuesheet_calculate_length_(FLAC__StreamMetadata *object) |
314 | 309k | { |
315 | 309k | uint32_t i; |
316 | | |
317 | 309k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
318 | | |
319 | 309k | object->length = ( |
320 | 309k | FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + |
321 | 309k | FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + |
322 | 309k | FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + |
323 | 309k | FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + |
324 | 309k | FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN |
325 | 309k | ) / 8; |
326 | | |
327 | 309k | object->length += object->data.cue_sheet.num_tracks * ( |
328 | 309k | FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + |
329 | 309k | FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + |
330 | 309k | FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + |
331 | 309k | FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + |
332 | 309k | FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + |
333 | 309k | FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + |
334 | 309k | FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN |
335 | 309k | ) / 8; |
336 | | |
337 | 564M | for (i = 0; i < object->data.cue_sheet.num_tracks; i++) { |
338 | 563M | object->length += object->data.cue_sheet.tracks[i].num_indices * ( |
339 | 563M | FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + |
340 | 563M | FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + |
341 | 563M | FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN |
342 | 563M | ) / 8; |
343 | 563M | } |
344 | 309k | } |
345 | | |
346 | | static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices) |
347 | 66.0k | { |
348 | 66.0k | FLAC__ASSERT(num_indices > 0); |
349 | | |
350 | 66.0k | return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)); |
351 | 66.0k | } |
352 | | |
353 | | static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks) |
354 | 11.9k | { |
355 | 11.9k | FLAC__ASSERT(num_tracks > 0); |
356 | | |
357 | 11.9k | return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)); |
358 | 11.9k | } |
359 | | |
360 | | static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) |
361 | 15.9k | { |
362 | 15.9k | uint32_t i; |
363 | | |
364 | 15.9k | FLAC__ASSERT(object_array != NULL && num_tracks > 0); |
365 | | |
366 | 330k | for (i = 0; i < num_tracks; i++) { |
367 | 314k | if (object_array[i].indices != 0) { |
368 | 110k | FLAC__ASSERT(object_array[i].num_indices > 0); |
369 | 110k | free(object_array[i].indices); |
370 | 110k | } |
371 | 314k | } |
372 | | |
373 | 15.9k | free(object_array); |
374 | 15.9k | } |
375 | | |
376 | | static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) |
377 | 6.08k | { |
378 | 6.08k | FLAC__StreamMetadata_CueSheet_Track *return_array; |
379 | | |
380 | 6.08k | FLAC__ASSERT(object_array != NULL); |
381 | 6.08k | FLAC__ASSERT(num_tracks > 0); |
382 | | |
383 | 6.08k | return_array = cuesheet_track_array_new_(num_tracks); |
384 | | |
385 | 6.08k | if (return_array != NULL) { |
386 | 6.08k | uint32_t i; |
387 | | |
388 | 81.8k | for (i = 0; i < num_tracks; i++) { |
389 | 75.8k | 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 | 75.8k | } |
394 | 6.08k | } |
395 | | |
396 | 6.08k | return return_array; |
397 | 6.08k | } |
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 | 67.7k | { |
401 | 67.7k | FLAC__StreamMetadata_CueSheet_Index *save; |
402 | | |
403 | 67.7k | FLAC__ASSERT(object != NULL); |
404 | 67.7k | FLAC__ASSERT(dest != NULL); |
405 | 67.7k | FLAC__ASSERT(src != NULL); |
406 | 67.7k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
407 | 67.7k | FLAC__ASSERT((src->indices != NULL && src->num_indices > 0) || (src->indices == NULL && src->num_indices == 0)); |
408 | | |
409 | 67.7k | save = dest->indices; |
410 | | |
411 | | /* do the copy first so that if we fail we leave the object untouched */ |
412 | 67.7k | if (copy) { |
413 | 98 | if (!copy_track_(dest, src)) |
414 | 0 | return false; |
415 | 98 | } |
416 | 67.6k | else { |
417 | 67.6k | *dest = *src; |
418 | 67.6k | } |
419 | | |
420 | 67.7k | free(save); |
421 | | |
422 | 67.7k | cuesheet_calculate_length_(object); |
423 | 67.7k | return true; |
424 | 67.7k | } |
425 | | |
426 | | |
427 | | /**************************************************************************** |
428 | | * |
429 | | * Metadata object routines |
430 | | * |
431 | | ***************************************************************************/ |
432 | | |
433 | | FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type) |
434 | 3.10M | { |
435 | 3.10M | FLAC__StreamMetadata *object; |
436 | | |
437 | 3.10M | if (type > FLAC__MAX_METADATA_TYPE) |
438 | 404 | return 0; |
439 | | |
440 | 3.10M | object = calloc(1, sizeof(FLAC__StreamMetadata)); |
441 | 3.10M | if (object != NULL) { |
442 | 3.10M | object->is_last = false; |
443 | 3.10M | object->type = type; |
444 | 3.10M | switch(type) { |
445 | 2.45M | case FLAC__METADATA_TYPE_STREAMINFO: |
446 | 2.45M | object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; |
447 | 2.45M | break; |
448 | 111k | case FLAC__METADATA_TYPE_PADDING: |
449 | | /* calloc() took care of this for us: |
450 | | object->length = 0; |
451 | | */ |
452 | 111k | break; |
453 | 26.8k | case FLAC__METADATA_TYPE_APPLICATION: |
454 | 26.8k | 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 | 26.8k | break; |
459 | 100k | 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 | 100k | break; |
466 | 54.9k | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
467 | 54.9k | object->data.vorbis_comment.vendor_string.length = (uint32_t)strlen(FLAC__VENDOR_STRING); |
468 | 54.9k | 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 | 3 | free(object); |
470 | 3 | return 0; |
471 | 3 | } |
472 | 54.9k | vorbiscomment_calculate_length_(object); |
473 | 54.9k | break; |
474 | 25.1k | case FLAC__METADATA_TYPE_CUESHEET: |
475 | 25.1k | cuesheet_calculate_length_(object); |
476 | 25.1k | break; |
477 | 35.7k | case FLAC__METADATA_TYPE_PICTURE: |
478 | 35.7k | object->length = ( |
479 | 35.7k | FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + |
480 | 35.7k | FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */ |
481 | 35.7k | FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */ |
482 | 35.7k | FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + |
483 | 35.7k | FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + |
484 | 35.7k | FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + |
485 | 35.7k | FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + |
486 | 35.7k | FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + |
487 | 35.7k | 0 /* no data */ |
488 | 35.7k | ) / 8; |
489 | 35.7k | object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; |
490 | 35.7k | object->data.picture.mime_type = 0; |
491 | 35.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 | 35.7k | if (!copy_cstring_(&object->data.picture.mime_type, "")) { |
502 | 0 | free(object); |
503 | 0 | return 0; |
504 | 0 | } |
505 | 35.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 | 35.7k | break; |
511 | 301k | default: |
512 | | /* calloc() took care of this for us: |
513 | | object->length = 0; |
514 | | object->data.unknown.data = 0; |
515 | | */ |
516 | 301k | break; |
517 | 3.10M | } |
518 | 3.10M | } |
519 | | |
520 | 3.10M | return object; |
521 | 3.10M | } |
522 | | |
523 | | FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object) |
524 | 130k | { |
525 | 130k | FLAC__StreamMetadata *to; |
526 | | |
527 | 130k | FLAC__ASSERT(object != NULL); |
528 | | |
529 | 130k | if ((to = FLAC__metadata_object_new(object->type)) != NULL) { |
530 | 130k | to->is_last = object->is_last; |
531 | 130k | to->type = object->type; |
532 | 130k | to->length = object->length; |
533 | 130k | switch(to->type) { |
534 | 30.6k | case FLAC__METADATA_TYPE_STREAMINFO: |
535 | 30.6k | memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo)); |
536 | 30.6k | break; |
537 | 34.6k | case FLAC__METADATA_TYPE_PADDING: |
538 | 34.6k | break; |
539 | 18.8k | case FLAC__METADATA_TYPE_APPLICATION: |
540 | 18.8k | 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 | 18.8k | memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8); |
545 | 18.8k | if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) { |
546 | 1 | FLAC__metadata_object_delete(to); |
547 | 1 | return 0; |
548 | 1 | } |
549 | 18.8k | break; |
550 | 18.8k | case FLAC__METADATA_TYPE_SEEKTABLE: |
551 | 7.88k | to->data.seek_table.num_points = object->data.seek_table.num_points; |
552 | 7.88k | 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 | 7.88k | 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 | 3 | FLAC__metadata_object_delete(to); |
558 | 3 | return 0; |
559 | 3 | } |
560 | 7.88k | break; |
561 | 8.03k | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
562 | 8.03k | if (to->data.vorbis_comment.vendor_string.entry != NULL) { |
563 | 8.03k | free(to->data.vorbis_comment.vendor_string.entry); |
564 | 8.03k | to->data.vorbis_comment.vendor_string.entry = 0; |
565 | 8.03k | } |
566 | 8.03k | if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) { |
567 | 2 | FLAC__metadata_object_delete(to); |
568 | 2 | return 0; |
569 | 2 | } |
570 | 8.03k | if (object->data.vorbis_comment.num_comments == 0) { |
571 | 5.69k | to->data.vorbis_comment.comments = 0; |
572 | 5.69k | } |
573 | 2.33k | else { |
574 | 2.33k | to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); |
575 | 2.33k | if (to->data.vorbis_comment.comments == NULL) { |
576 | 10 | to->data.vorbis_comment.num_comments = 0; |
577 | 10 | FLAC__metadata_object_delete(to); |
578 | 10 | return 0; |
579 | 10 | } |
580 | 2.33k | } |
581 | 8.02k | to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments; |
582 | 8.02k | break; |
583 | 6.11k | case FLAC__METADATA_TYPE_CUESHEET: |
584 | 6.11k | memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet)); |
585 | 6.11k | if (object->data.cue_sheet.num_tracks == 0) { |
586 | 26 | FLAC__ASSERT(object->data.cue_sheet.tracks == NULL); |
587 | 26 | } |
588 | 6.08k | else { |
589 | 6.08k | FLAC__ASSERT(object->data.cue_sheet.tracks != 0); |
590 | 6.08k | to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); |
591 | 6.08k | if (to->data.cue_sheet.tracks == NULL) { |
592 | 1 | FLAC__metadata_object_delete(to); |
593 | 1 | return 0; |
594 | 1 | } |
595 | 6.08k | } |
596 | 6.10k | break; |
597 | 13.1k | case FLAC__METADATA_TYPE_PICTURE: |
598 | 13.1k | to->data.picture.type = object->data.picture.type; |
599 | 13.1k | 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 | 13.1k | 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 | 13.1k | to->data.picture.width = object->data.picture.width; |
608 | 13.1k | to->data.picture.height = object->data.picture.height; |
609 | 13.1k | to->data.picture.depth = object->data.picture.depth; |
610 | 13.1k | to->data.picture.colors = object->data.picture.colors; |
611 | 13.1k | to->data.picture.data_length = object->data.picture.data_length; |
612 | 13.1k | if (!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) { |
613 | 10 | FLAC__metadata_object_delete(to); |
614 | 10 | return 0; |
615 | 10 | } |
616 | 13.1k | break; |
617 | 13.1k | default: |
618 | 10.9k | if (!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) { |
619 | 6 | FLAC__metadata_object_delete(to); |
620 | 6 | return 0; |
621 | 6 | } |
622 | 10.9k | break; |
623 | 130k | } |
624 | 130k | } |
625 | | |
626 | 130k | return to; |
627 | 130k | } |
628 | | |
629 | | void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object) |
630 | 3.20M | { |
631 | 3.20M | FLAC__ASSERT(object != NULL); |
632 | | |
633 | 3.20M | switch(object->type) { |
634 | 2.45M | case FLAC__METADATA_TYPE_STREAMINFO: |
635 | 2.66M | case FLAC__METADATA_TYPE_PADDING: |
636 | 2.66M | break; |
637 | 26.8k | case FLAC__METADATA_TYPE_APPLICATION: |
638 | 26.8k | if (object->data.application.data != NULL) { |
639 | 11.2k | free(object->data.application.data); |
640 | 11.2k | object->data.application.data = NULL; |
641 | 11.2k | } |
642 | 26.8k | break; |
643 | 100k | case FLAC__METADATA_TYPE_SEEKTABLE: |
644 | 100k | if (object->data.seek_table.points != NULL) { |
645 | 23.3k | free(object->data.seek_table.points); |
646 | 23.3k | object->data.seek_table.points = NULL; |
647 | 23.3k | } |
648 | 100k | break; |
649 | 54.9k | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
650 | 54.9k | if (object->data.vorbis_comment.vendor_string.entry != NULL) { |
651 | 54.9k | free(object->data.vorbis_comment.vendor_string.entry); |
652 | 54.9k | object->data.vorbis_comment.vendor_string.entry = 0; |
653 | 54.9k | } |
654 | 54.9k | if (object->data.vorbis_comment.comments != NULL) { |
655 | 10.3k | vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); |
656 | 10.3k | object->data.vorbis_comment.comments = NULL; |
657 | 10.3k | object->data.vorbis_comment.num_comments = 0; |
658 | 10.3k | } |
659 | 54.9k | break; |
660 | 25.1k | case FLAC__METADATA_TYPE_CUESHEET: |
661 | 25.1k | if (object->data.cue_sheet.tracks != NULL) { |
662 | 15.9k | FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); |
663 | 15.9k | cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); |
664 | 15.9k | object->data.cue_sheet.tracks = NULL; |
665 | 15.9k | object->data.cue_sheet.num_tracks = 0; |
666 | 15.9k | } |
667 | 25.1k | break; |
668 | 35.7k | case FLAC__METADATA_TYPE_PICTURE: |
669 | 35.7k | if (object->data.picture.mime_type != NULL) { |
670 | 35.7k | free(object->data.picture.mime_type); |
671 | 35.7k | object->data.picture.mime_type = NULL; |
672 | 35.7k | } |
673 | 35.7k | if (object->data.picture.description != NULL) { |
674 | 35.7k | free(object->data.picture.description); |
675 | 35.7k | object->data.picture.description = NULL; |
676 | 35.7k | } |
677 | 35.7k | if (object->data.picture.data != NULL) { |
678 | 18.9k | free(object->data.picture.data); |
679 | 18.9k | object->data.picture.data = NULL; |
680 | 18.9k | } |
681 | 35.7k | break; |
682 | 301k | default: |
683 | 301k | if (object->data.unknown.data != NULL) { |
684 | 16.1k | free(object->data.unknown.data); |
685 | 16.1k | object->data.unknown.data = NULL; |
686 | 16.1k | } |
687 | 301k | break; |
688 | 3.20M | } |
689 | 3.20M | } |
690 | | |
691 | | FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object) |
692 | 3.10M | { |
693 | 3.10M | FLAC__metadata_object_delete_data(object); |
694 | 3.10M | free(object); |
695 | 3.10M | } |
696 | | |
697 | | static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2) |
698 | 2.34k | { |
699 | 2.34k | if (block1->min_blocksize != block2->min_blocksize) |
700 | 0 | return false; |
701 | 2.34k | if (block1->max_blocksize != block2->max_blocksize) |
702 | 0 | return false; |
703 | 2.34k | if (block1->min_framesize != block2->min_framesize) |
704 | 0 | return false; |
705 | 2.34k | if (block1->max_framesize != block2->max_framesize) |
706 | 0 | return false; |
707 | 2.34k | if (block1->sample_rate != block2->sample_rate) |
708 | 0 | return false; |
709 | 2.34k | if (block1->channels != block2->channels) |
710 | 0 | return false; |
711 | 2.34k | if (block1->bits_per_sample != block2->bits_per_sample) |
712 | 0 | return false; |
713 | 2.34k | if (block1->total_samples != block2->total_samples) |
714 | 0 | return false; |
715 | 2.34k | if (memcmp(block1->md5sum, block2->md5sum, 16) != 0) |
716 | 0 | return false; |
717 | 2.34k | return true; |
718 | 2.34k | } |
719 | | |
720 | | static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, uint32_t block_length) |
721 | 3.27k | { |
722 | 3.27k | FLAC__ASSERT(block1 != NULL); |
723 | 3.27k | FLAC__ASSERT(block2 != NULL); |
724 | 3.27k | FLAC__ASSERT(block_length >= sizeof(block1->id)); |
725 | | |
726 | 3.27k | if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0) |
727 | 0 | return false; |
728 | 3.27k | if (block1->data != NULL && block2->data != NULL) |
729 | 2.01k | return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0; |
730 | 1.25k | else |
731 | 1.25k | return block1->data == block2->data; |
732 | 3.27k | } |
733 | | |
734 | | static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2) |
735 | 1.26k | { |
736 | 1.26k | uint32_t i; |
737 | | |
738 | 1.26k | FLAC__ASSERT(block1 != NULL); |
739 | 1.26k | FLAC__ASSERT(block2 != NULL); |
740 | | |
741 | 1.26k | if (block1->num_points != block2->num_points) |
742 | 0 | return false; |
743 | | |
744 | 1.26k | if (block1->points != NULL && block2->points != NULL) { |
745 | 764k | for (i = 0; i < block1->num_points; i++) { |
746 | 762k | if (block1->points[i].sample_number != block2->points[i].sample_number) |
747 | 0 | return false; |
748 | 762k | if (block1->points[i].stream_offset != block2->points[i].stream_offset) |
749 | 0 | return false; |
750 | 762k | if (block1->points[i].frame_samples != block2->points[i].frame_samples) |
751 | 0 | return false; |
752 | 762k | } |
753 | 1.24k | return true; |
754 | 1.24k | } |
755 | 11 | else |
756 | 11 | return block1->points == block2->points; |
757 | 1.26k | } |
758 | | |
759 | | static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2) |
760 | 1.74k | { |
761 | 1.74k | uint32_t i; |
762 | | |
763 | 1.74k | if (block1->vendor_string.length != block2->vendor_string.length) |
764 | 0 | return false; |
765 | | |
766 | 1.74k | if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) { |
767 | 1.74k | if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0) |
768 | 0 | return false; |
769 | 1.74k | } |
770 | 0 | else if (block1->vendor_string.entry != block2->vendor_string.entry) |
771 | 0 | return false; |
772 | | |
773 | 1.74k | if (block1->num_comments != block2->num_comments) |
774 | 0 | return false; |
775 | | |
776 | 331k | for (i = 0; i < block1->num_comments; i++) { |
777 | 329k | if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) { |
778 | 329k | if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0) |
779 | 0 | return false; |
780 | 329k | } |
781 | 0 | else if (block1->comments[i].entry != block2->comments[i].entry) |
782 | 0 | return false; |
783 | 329k | } |
784 | 1.74k | return true; |
785 | 1.74k | } |
786 | | |
787 | | static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2) |
788 | 5.11k | { |
789 | 5.11k | uint32_t i, j; |
790 | | |
791 | 5.11k | if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0) |
792 | 0 | return false; |
793 | | |
794 | 5.11k | if (block1->lead_in != block2->lead_in) |
795 | 0 | return false; |
796 | | |
797 | 5.11k | if (block1->is_cd != block2->is_cd) |
798 | 0 | return false; |
799 | | |
800 | 5.11k | if (block1->num_tracks != block2->num_tracks) |
801 | 0 | return false; |
802 | | |
803 | 5.11k | if (block1->tracks != NULL && block2->tracks != NULL) { |
804 | 5.10k | FLAC__ASSERT(block1->num_tracks > 0); |
805 | 39.8k | for (i = 0; i < block1->num_tracks; i++) { |
806 | 34.7k | if (block1->tracks[i].offset != block2->tracks[i].offset) |
807 | 0 | return false; |
808 | 34.7k | if (block1->tracks[i].number != block2->tracks[i].number) |
809 | 0 | return false; |
810 | 34.7k | if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0) |
811 | 0 | return false; |
812 | 34.7k | if (block1->tracks[i].type != block2->tracks[i].type) |
813 | 0 | return false; |
814 | 34.7k | if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis) |
815 | 0 | return false; |
816 | 34.7k | if (block1->tracks[i].num_indices != block2->tracks[i].num_indices) |
817 | 0 | return false; |
818 | 34.7k | if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) { |
819 | 15.8k | FLAC__ASSERT(block1->tracks[i].num_indices > 0); |
820 | 117k | for (j = 0; j < block1->tracks[i].num_indices; j++) { |
821 | 101k | if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset) |
822 | 0 | return false; |
823 | 101k | if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number) |
824 | 0 | return false; |
825 | 101k | } |
826 | 15.8k | } |
827 | 18.9k | else if (block1->tracks[i].indices != block2->tracks[i].indices) |
828 | 0 | return false; |
829 | 34.7k | } |
830 | 5.10k | } |
831 | 10 | else if (block1->tracks != block2->tracks) |
832 | 0 | return false; |
833 | 5.11k | return true; |
834 | 5.11k | } |
835 | | |
836 | | static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2) |
837 | 10.7k | { |
838 | 10.7k | if (block1->type != block2->type) |
839 | 0 | return false; |
840 | 10.7k | 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 | 10.7k | 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 | 10.7k | if (block1->width != block2->width) |
845 | 0 | return false; |
846 | 10.7k | if (block1->height != block2->height) |
847 | 0 | return false; |
848 | 10.7k | if (block1->depth != block2->depth) |
849 | 0 | return false; |
850 | 10.7k | if (block1->colors != block2->colors) |
851 | 0 | return false; |
852 | 10.7k | if (block1->data_length != block2->data_length) |
853 | 0 | return false; |
854 | 10.7k | if (block1->data != block2->data && (block1->data == NULL || block2->data == NULL || memcmp(block1->data, block2->data, block1->data_length))) |
855 | 226 | return false; |
856 | 10.5k | return true; |
857 | 10.7k | } |
858 | | |
859 | | static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, uint32_t block_length) |
860 | 24 | { |
861 | 24 | FLAC__ASSERT(block1 != NULL); |
862 | 24 | FLAC__ASSERT(block2 != NULL); |
863 | | |
864 | 24 | if (block1->data != NULL && block2->data != NULL) |
865 | 13 | return memcmp(block1->data, block2->data, block_length) == 0; |
866 | 11 | else |
867 | 11 | return block1->data == block2->data; |
868 | 24 | } |
869 | | |
870 | | FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2) |
871 | 25.2k | { |
872 | 25.2k | FLAC__ASSERT(block1 != NULL); |
873 | 25.2k | FLAC__ASSERT(block2 != NULL); |
874 | | |
875 | 25.2k | if (block1->type != block2->type) { |
876 | 0 | return false; |
877 | 0 | } |
878 | 25.2k | if (block1->is_last != block2->is_last) { |
879 | 0 | return false; |
880 | 0 | } |
881 | 25.2k | if (block1->length != block2->length) { |
882 | 0 | return false; |
883 | 0 | } |
884 | 25.2k | switch(block1->type) { |
885 | 2.34k | case FLAC__METADATA_TYPE_STREAMINFO: |
886 | 2.34k | return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info); |
887 | 716 | case FLAC__METADATA_TYPE_PADDING: |
888 | 716 | return true; /* we don't compare the padding guts */ |
889 | 3.27k | case FLAC__METADATA_TYPE_APPLICATION: |
890 | 3.27k | return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length); |
891 | 1.26k | case FLAC__METADATA_TYPE_SEEKTABLE: |
892 | 1.26k | return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table); |
893 | 1.74k | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
894 | 1.74k | return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment); |
895 | 5.11k | case FLAC__METADATA_TYPE_CUESHEET: |
896 | 5.11k | return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet); |
897 | 10.7k | case FLAC__METADATA_TYPE_PICTURE: |
898 | 10.7k | return compare_block_data_picture_(&block1->data.picture, &block2->data.picture); |
899 | 24 | default: |
900 | 24 | return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length); |
901 | 25.2k | } |
902 | 25.2k | } |
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 | 5.13k | { |
906 | 5.13k | FLAC__byte *save; |
907 | | |
908 | 5.13k | FLAC__ASSERT(object != NULL); |
909 | 5.13k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION); |
910 | 5.13k | FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false)); |
911 | | |
912 | 5.13k | save = object->data.application.data; |
913 | | |
914 | | /* do the copy first so that if we fail we leave the object untouched */ |
915 | 5.13k | if (copy) { |
916 | 0 | if (!copy_bytes_(&object->data.application.data, data, length)) |
917 | 0 | return false; |
918 | 0 | } |
919 | 5.13k | else { |
920 | 5.13k | object->data.application.data = data; |
921 | 5.13k | } |
922 | | |
923 | 5.13k | free(save); |
924 | | |
925 | 5.13k | object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length; |
926 | 5.13k | return true; |
927 | 5.13k | } |
928 | | |
929 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points) |
930 | 99.9k | { |
931 | 99.9k | FLAC__ASSERT(object != NULL); |
932 | 99.9k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
933 | | |
934 | 99.9k | if((FLAC__uint64)(new_num_points) * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) |
935 | 174 | return false; |
936 | | |
937 | 99.7k | if (object->data.seek_table.points == 0) { |
938 | 26.0k | FLAC__ASSERT(object->data.seek_table.num_points == 0); |
939 | 26.0k | if (new_num_points == 0) |
940 | 12.0k | return true; |
941 | 13.9k | else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0) |
942 | 0 | return false; |
943 | 26.0k | } |
944 | 73.7k | else { |
945 | 73.7k | const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint); |
946 | 73.7k | const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint); |
947 | | |
948 | | /* overflow check */ |
949 | 73.7k | if (new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) |
950 | 0 | return false; |
951 | | |
952 | 73.7k | FLAC__ASSERT(object->data.seek_table.num_points > 0); |
953 | | |
954 | 73.7k | if (new_size == 0) { |
955 | 11 | free(object->data.seek_table.points); |
956 | 11 | object->data.seek_table.points = 0; |
957 | 11 | } |
958 | 73.7k | else { |
959 | | /* Leave object->data.seek_table.points untouched if realloc fails */ |
960 | 73.7k | FLAC__StreamMetadata_SeekPoint *tmpptr; |
961 | 73.7k | if ((tmpptr = realloc(object->data.seek_table.points, new_size)) == NULL) |
962 | 0 | return false; |
963 | 73.7k | object->data.seek_table.points = tmpptr; |
964 | 73.7k | } |
965 | | |
966 | | /* if growing, set new elements to placeholders */ |
967 | 73.7k | if (new_size > old_size) { |
968 | 63.3k | uint32_t i; |
969 | 70.8M | for (i = object->data.seek_table.num_points; i < new_num_points; i++) { |
970 | 70.7M | object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; |
971 | 70.7M | object->data.seek_table.points[i].stream_offset = 0; |
972 | 70.7M | object->data.seek_table.points[i].frame_samples = 0; |
973 | 70.7M | } |
974 | 63.3k | } |
975 | 73.7k | } |
976 | | |
977 | 87.7k | object->data.seek_table.num_points = new_num_points; |
978 | | |
979 | 87.7k | seektable_calculate_length_(object); |
980 | 87.7k | return true; |
981 | 99.7k | } |
982 | | |
983 | | FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point) |
984 | 802 | { |
985 | 802 | FLAC__ASSERT(object != NULL); |
986 | 802 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
987 | 802 | FLAC__ASSERT(point_num < object->data.seek_table.num_points); |
988 | | |
989 | 802 | object->data.seek_table.points[point_num] = point; |
990 | 802 | } |
991 | | |
992 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point) |
993 | 401 | { |
994 | 401 | int i; |
995 | | |
996 | 401 | FLAC__ASSERT(object != NULL); |
997 | 401 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
998 | 401 | FLAC__ASSERT(point_num <= object->data.seek_table.num_points); |
999 | | |
1000 | 401 | 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 | 7.24M | for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--) |
1005 | 7.24M | object->data.seek_table.points[i] = object->data.seek_table.points[i-1]; |
1006 | | |
1007 | 401 | FLAC__metadata_object_seektable_set_point(object, point_num, point); |
1008 | 401 | seektable_calculate_length_(object); |
1009 | 401 | return true; |
1010 | 401 | } |
1011 | | |
1012 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num) |
1013 | 139 | { |
1014 | 139 | uint32_t i; |
1015 | | |
1016 | 139 | FLAC__ASSERT(object != NULL); |
1017 | 139 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1018 | 139 | FLAC__ASSERT(point_num < object->data.seek_table.num_points); |
1019 | | |
1020 | | /* move all points > point_num backward one space */ |
1021 | 3.83M | for (i = point_num; i < object->data.seek_table.num_points-1; i++) |
1022 | 3.83M | object->data.seek_table.points[i] = object->data.seek_table.points[i+1]; |
1023 | | |
1024 | 139 | return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1); |
1025 | 139 | } |
1026 | | |
1027 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object) |
1028 | 1.91k | { |
1029 | 1.91k | FLAC__ASSERT(object != NULL); |
1030 | 1.91k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1031 | | |
1032 | 1.91k | return FLAC__format_seektable_is_legal(&object->data.seek_table); |
1033 | 1.91k | } |
1034 | | |
1035 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num) |
1036 | 1.01k | { |
1037 | 1.01k | FLAC__ASSERT(object != NULL); |
1038 | 1.01k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1039 | | |
1040 | 1.01k | if (num > 0) |
1041 | | /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */ |
1042 | 1.01k | return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num); |
1043 | 0 | else |
1044 | 0 | return true; |
1045 | 1.01k | } |
1046 | | |
1047 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number) |
1048 | 55.9k | { |
1049 | 55.9k | FLAC__StreamMetadata_SeekTable *seek_table; |
1050 | | |
1051 | 55.9k | FLAC__ASSERT(object != NULL); |
1052 | 55.9k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1053 | | |
1054 | 55.9k | seek_table = &object->data.seek_table; |
1055 | | |
1056 | 55.9k | if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1)) |
1057 | 0 | return false; |
1058 | | |
1059 | 55.9k | seek_table->points[seek_table->num_points - 1].sample_number = sample_number; |
1060 | 55.9k | seek_table->points[seek_table->num_points - 1].stream_offset = 0; |
1061 | 55.9k | seek_table->points[seek_table->num_points - 1].frame_samples = 0; |
1062 | | |
1063 | 55.9k | return true; |
1064 | 55.9k | } |
1065 | | |
1066 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num) |
1067 | 514 | { |
1068 | 514 | FLAC__ASSERT(object != NULL); |
1069 | 514 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1070 | 514 | FLAC__ASSERT(sample_numbers != 0 || num == 0); |
1071 | | |
1072 | 514 | if (num > 0) { |
1073 | 514 | FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; |
1074 | 514 | uint32_t i, j; |
1075 | | |
1076 | 514 | i = seek_table->num_points; |
1077 | | |
1078 | 514 | if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) |
1079 | 0 | return false; |
1080 | | |
1081 | 2.05k | for (j = 0; j < num; i++, j++) { |
1082 | 1.54k | seek_table->points[i].sample_number = sample_numbers[j]; |
1083 | 1.54k | seek_table->points[i].stream_offset = 0; |
1084 | 1.54k | seek_table->points[i].frame_samples = 0; |
1085 | 1.54k | } |
1086 | 514 | } |
1087 | | |
1088 | 514 | return true; |
1089 | 514 | } |
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 | 2.26k | { |
1093 | 2.26k | FLAC__ASSERT(object != NULL); |
1094 | 2.26k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1095 | | |
1096 | 2.26k | if (num > 0 && total_samples > 0) { |
1097 | 2.14k | FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; |
1098 | 2.14k | uint32_t i, j; |
1099 | | |
1100 | 2.14k | i = seek_table->num_points; |
1101 | | |
1102 | 2.14k | if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) |
1103 | 169 | return false; |
1104 | | |
1105 | 1.97k | if(total_samples < UINT64_MAX / num) { |
1106 | | /* No risk of overflow */ |
1107 | 113M | for (j = 0; j < num; i++, j++) { |
1108 | 113M | seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num; |
1109 | 113M | seek_table->points[i].stream_offset = 0; |
1110 | 113M | seek_table->points[i].frame_samples = 0; |
1111 | 113M | } |
1112 | 1.40k | } |
1113 | 576 | else { |
1114 | | /* Less precise, but can handle total_samples near UINT64_MAX */ |
1115 | 3.19M | for (j = 0; j < num; i++, j++) { |
1116 | 3.19M | seek_table->points[i].sample_number = total_samples / (FLAC__uint64)num * (FLAC__uint64)j; |
1117 | 3.19M | seek_table->points[i].stream_offset = 0; |
1118 | 3.19M | seek_table->points[i].frame_samples = 0; |
1119 | 3.19M | } |
1120 | 576 | } |
1121 | 1.97k | } |
1122 | | |
1123 | 2.09k | return true; |
1124 | 2.26k | } |
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 | 18.8k | { |
1128 | 18.8k | FLAC__ASSERT(object != NULL); |
1129 | 18.8k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1130 | | |
1131 | 18.8k | if (samples > 0 && total_samples > 0) { |
1132 | 17.3k | FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; |
1133 | 17.3k | uint32_t i, j; |
1134 | 17.3k | FLAC__uint64 num, sample; |
1135 | | |
1136 | 17.3k | 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 | 17.3k | if (total_samples % samples == 0) |
1139 | 5.77k | num--; |
1140 | | |
1141 | | /* Put a strict upper bound on the number of allowed seek points. */ |
1142 | 17.3k | if (num > 32768) { |
1143 | | /* Set the bound and recalculate samples accordingly. */ |
1144 | 2.62k | num = 32768; |
1145 | 2.62k | samples = (uint32_t)(total_samples / num); |
1146 | 2.62k | } |
1147 | | |
1148 | 17.3k | i = seek_table->num_points; |
1149 | | |
1150 | 17.3k | if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (uint32_t)num)) |
1151 | 5 | return false; |
1152 | | |
1153 | 17.3k | sample = 0; |
1154 | 120M | for (j = 0; j < num; i++, j++, sample += samples) { |
1155 | 120M | seek_table->points[i].sample_number = sample; |
1156 | 120M | seek_table->points[i].stream_offset = 0; |
1157 | 120M | seek_table->points[i].frame_samples = 0; |
1158 | 120M | } |
1159 | 17.3k | } |
1160 | | |
1161 | 18.8k | return true; |
1162 | 18.8k | } |
1163 | | |
1164 | | FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact) |
1165 | 22.6k | { |
1166 | 22.6k | uint32_t unique; |
1167 | | |
1168 | 22.6k | FLAC__ASSERT(object != NULL); |
1169 | 22.6k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); |
1170 | | |
1171 | 22.6k | unique = FLAC__format_seektable_sort(&object->data.seek_table); |
1172 | | |
1173 | 22.6k | return !compact || FLAC__metadata_object_seektable_resize_points(object, unique); |
1174 | 22.6k | } |
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 | 47.0k | { |
1185 | 47.0k | FLAC__ASSERT(object != NULL); |
1186 | 47.0k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1187 | | |
1188 | 47.0k | if (object->data.vorbis_comment.comments == NULL) { |
1189 | 4.83k | FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0); |
1190 | 4.83k | if (new_num_comments == 0) |
1191 | 10 | return true; |
1192 | 4.82k | else { |
1193 | 4.82k | uint32_t i; |
1194 | 4.82k | if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL) |
1195 | 99 | return false; |
1196 | 10.0k | for (i = 0; i < new_num_comments; i++) { |
1197 | 5.31k | object->data.vorbis_comment.comments[i].length = 0; |
1198 | 5.31k | if ((object->data.vorbis_comment.comments[i].entry = safe_malloc_(1)) == NULL) { |
1199 | 13 | object->data.vorbis_comment.num_comments = i+1; |
1200 | 13 | return false; |
1201 | 13 | } |
1202 | 5.29k | object->data.vorbis_comment.comments[i].entry[0] = '\0'; |
1203 | 5.29k | } |
1204 | 4.72k | } |
1205 | 4.83k | } |
1206 | 42.2k | else { |
1207 | 42.2k | const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); |
1208 | 42.2k | const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); |
1209 | | |
1210 | | /* overflow check */ |
1211 | 42.2k | if (new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry)) |
1212 | 0 | return false; |
1213 | | |
1214 | 42.2k | FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0); |
1215 | | |
1216 | | /* if shrinking, free the truncated entries */ |
1217 | 42.2k | if (new_num_comments < object->data.vorbis_comment.num_comments) { |
1218 | 2.09k | uint32_t i; |
1219 | 122k | for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++) |
1220 | 120k | if (object->data.vorbis_comment.comments[i].entry != NULL) |
1221 | 118k | free(object->data.vorbis_comment.comments[i].entry); |
1222 | 2.09k | } |
1223 | | |
1224 | 42.2k | if (new_size == 0) { |
1225 | 188 | free(object->data.vorbis_comment.comments); |
1226 | 188 | object->data.vorbis_comment.comments = 0; |
1227 | 188 | } |
1228 | 42.0k | else { |
1229 | | /* Leave object->data.vorbis_comment.comments untouched if realloc fails */ |
1230 | 42.0k | FLAC__StreamMetadata_VorbisComment_Entry *tmpptr; |
1231 | 42.0k | if ((tmpptr = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) |
1232 | 0 | return false; |
1233 | 42.0k | object->data.vorbis_comment.comments = tmpptr; |
1234 | 42.0k | } |
1235 | | |
1236 | | /* if growing, zero all the length/pointers of new elements */ |
1237 | 42.2k | if (new_size > old_size) { |
1238 | 40.1k | uint32_t i; |
1239 | 80.6k | for (i = object->data.vorbis_comment.num_comments; i < new_num_comments; i++) { |
1240 | 40.5k | object->data.vorbis_comment.comments[i].length = 0; |
1241 | 40.5k | if ((object->data.vorbis_comment.comments[i].entry = safe_malloc_(1)) == NULL) { |
1242 | 94 | object->data.vorbis_comment.num_comments = i+1; |
1243 | 94 | return false; |
1244 | 94 | } |
1245 | 40.4k | object->data.vorbis_comment.comments[i].entry[0] = '\0'; |
1246 | 40.4k | } |
1247 | 40.1k | } |
1248 | 42.2k | } |
1249 | | |
1250 | 46.8k | object->data.vorbis_comment.num_comments = new_num_comments; |
1251 | | |
1252 | 46.8k | vorbiscomment_calculate_length_(object); |
1253 | 46.8k | return true; |
1254 | 47.0k | } |
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 | 45.4k | { |
1258 | 45.4k | FLAC__ASSERT(object != NULL); |
1259 | 45.4k | FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); |
1260 | | |
1261 | 45.4k | if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) |
1262 | 0 | return false; |
1263 | 45.4k | return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy); |
1264 | 45.4k | } |
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 | 44.7k | { |
1268 | 44.7k | FLAC__StreamMetadata_VorbisComment *vc; |
1269 | 44.7k | FLAC__StreamMetadata_VorbisComment_Entry temp; |
1270 | | |
1271 | 44.7k | FLAC__ASSERT(object != NULL); |
1272 | 44.7k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1273 | 44.7k | FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments); |
1274 | | |
1275 | 44.7k | if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) |
1276 | 0 | return false; |
1277 | | |
1278 | 44.7k | vc = &object->data.vorbis_comment; |
1279 | | |
1280 | 44.7k | if (!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1)) |
1281 | 206 | return false; |
1282 | | |
1283 | | /* move all comments >= comment_num forward one space */ |
1284 | | /* reuse newly added empty comment */ |
1285 | 44.5k | temp = vc->comments[vc->num_comments-1]; |
1286 | 44.5k | memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num)); |
1287 | 44.5k | vc->comments[comment_num] = temp; |
1288 | | |
1289 | 44.5k | return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy); |
1290 | 44.7k | } |
1291 | | |
1292 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) |
1293 | 40.6k | { |
1294 | 40.6k | FLAC__ASSERT(object != NULL); |
1295 | 40.6k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1296 | 40.6k | return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy); |
1297 | 40.6k | } |
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 | 447 | { |
1301 | 447 | FLAC__ASSERT(entry.entry != NULL); |
1302 | | |
1303 | 447 | if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) |
1304 | 0 | return false; |
1305 | | |
1306 | 447 | { |
1307 | 447 | int i; |
1308 | 447 | size_t field_name_length; |
1309 | 447 | const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); |
1310 | | |
1311 | 447 | if (eq == NULL) |
1312 | 0 | return false; /* double protection */ |
1313 | | |
1314 | 447 | field_name_length = eq-entry.entry; |
1315 | | |
1316 | 447 | i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length); |
1317 | 447 | if (i >= 0) { |
1318 | 447 | uint32_t indx = (uint32_t)i; |
1319 | 447 | if (!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy)) |
1320 | 0 | return false; |
1321 | 447 | entry = object->data.vorbis_comment.comments[indx]; |
1322 | 447 | indx++; /* skip over replaced comment */ |
1323 | 447 | if (all && indx < object->data.vorbis_comment.num_comments) { |
1324 | 229 | i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); |
1325 | 1.19k | while (i >= 0) { |
1326 | 964 | indx = (uint32_t)i; |
1327 | 964 | if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx)) |
1328 | 0 | return false; |
1329 | 964 | if (indx < object->data.vorbis_comment.num_comments) |
1330 | 826 | i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); |
1331 | 138 | else |
1332 | 138 | i = -1; |
1333 | 964 | } |
1334 | 229 | } |
1335 | 447 | return true; |
1336 | 447 | } |
1337 | 0 | else |
1338 | 0 | return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy); |
1339 | 447 | } |
1340 | 447 | } |
1341 | | |
1342 | | FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num) |
1343 | 2.04k | { |
1344 | 2.04k | FLAC__StreamMetadata_VorbisComment *vc; |
1345 | | |
1346 | 2.04k | FLAC__ASSERT(object != NULL); |
1347 | 2.04k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1348 | 2.04k | FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); |
1349 | | |
1350 | 2.04k | vc = &object->data.vorbis_comment; |
1351 | | |
1352 | | /* free the comment at comment_num */ |
1353 | 2.04k | free(vc->comments[comment_num].entry); |
1354 | | |
1355 | | /* move all comments > comment_num backward one space */ |
1356 | 2.04k | memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1)); |
1357 | 2.04k | vc->comments[vc->num_comments-1].length = 0; |
1358 | 2.04k | vc->comments[vc->num_comments-1].entry = 0; |
1359 | | |
1360 | 2.04k | return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1); |
1361 | 2.04k | } |
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 | 8.23k | { |
1365 | 8.23k | FLAC__ASSERT(entry != NULL); |
1366 | 8.23k | FLAC__ASSERT(field_name != NULL); |
1367 | 8.23k | FLAC__ASSERT(field_value != NULL); |
1368 | | |
1369 | 8.23k | if (!FLAC__format_vorbiscomment_entry_name_is_legal(field_name)) |
1370 | 0 | return false; |
1371 | 8.23k | if (!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (uint32_t)(-1))) |
1372 | 0 | return false; |
1373 | | |
1374 | 8.23k | { |
1375 | 8.23k | const size_t nn = strlen(field_name); |
1376 | 8.23k | const size_t nv = strlen(field_value); |
1377 | 8.23k | entry->length = nn + 1 /*=*/ + nv; |
1378 | 8.23k | if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL) |
1379 | 399 | return false; |
1380 | 7.83k | memcpy(entry->entry, field_name, nn); |
1381 | 7.83k | entry->entry[nn] = '='; |
1382 | 7.83k | memcpy(entry->entry+nn+1, field_value, nv); |
1383 | 7.83k | entry->entry[entry->length] = '\0'; |
1384 | 7.83k | } |
1385 | | |
1386 | 7.83k | return true; |
1387 | 8.23k | } |
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.22M | { |
1422 | 1.22M | FLAC__ASSERT(entry.entry != NULL); |
1423 | 1.22M | { |
1424 | 1.22M | const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); |
1425 | 1.22M | 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.22M | } |
1427 | 1.22M | } |
1428 | | |
1429 | | FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name) |
1430 | 11.3k | { |
1431 | 11.3k | FLAC__ASSERT(field_name != NULL); |
1432 | | |
1433 | 11.3k | return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name)); |
1434 | 11.3k | } |
1435 | | |
1436 | | FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name) |
1437 | 516 | { |
1438 | 516 | const uint32_t field_name_length = strlen(field_name); |
1439 | 516 | uint32_t i; |
1440 | | |
1441 | 516 | FLAC__ASSERT(object != NULL); |
1442 | 516 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); |
1443 | | |
1444 | 469k | for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { |
1445 | 469k | if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { |
1446 | 34 | if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i)) |
1447 | 0 | return -1; |
1448 | 34 | else |
1449 | 34 | return 1; |
1450 | 34 | } |
1451 | 469k | } |
1452 | | |
1453 | 482 | return 0; |
1454 | 516 | } |
1455 | | |
1456 | | FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name) |
1457 | 694 | { |
1458 | 694 | FLAC__bool ok = true; |
1459 | 694 | uint32_t matching = 0; |
1460 | 694 | const uint32_t field_name_length = strlen(field_name); |
1461 | 694 | int i; |
1462 | | |
1463 | 694 | FLAC__ASSERT(object != NULL); |
1464 | 694 | 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 | 474k | for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) { |
1468 | 474k | if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { |
1469 | 593 | matching++; |
1470 | 593 | ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (uint32_t)i); |
1471 | 593 | } |
1472 | 474k | } |
1473 | | |
1474 | 694 | return ok? (int)matching : -1; |
1475 | 694 | } |
1476 | | |
1477 | | FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void) |
1478 | 614 | { |
1479 | 614 | return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track)); |
1480 | 614 | } |
1481 | | |
1482 | | FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object) |
1483 | 614 | { |
1484 | 614 | FLAC__StreamMetadata_CueSheet_Track *to; |
1485 | | |
1486 | 614 | FLAC__ASSERT(object != NULL); |
1487 | | |
1488 | 614 | if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) { |
1489 | 614 | if (!copy_track_(to, object)) { |
1490 | 0 | FLAC__metadata_object_cuesheet_track_delete(to); |
1491 | 0 | return 0; |
1492 | 0 | } |
1493 | 614 | } |
1494 | | |
1495 | 614 | return to; |
1496 | 614 | } |
1497 | | |
1498 | | void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object) |
1499 | 614 | { |
1500 | 614 | FLAC__ASSERT(object != NULL); |
1501 | | |
1502 | 614 | if (object->indices != NULL) { |
1503 | 282 | FLAC__ASSERT(object->num_indices > 0); |
1504 | 282 | free(object->indices); |
1505 | 282 | } |
1506 | 614 | } |
1507 | | |
1508 | | FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object) |
1509 | 614 | { |
1510 | 614 | FLAC__metadata_object_cuesheet_track_delete_data(object); |
1511 | 614 | free(object); |
1512 | 614 | } |
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 | 74.3k | { |
1516 | 74.3k | FLAC__StreamMetadata_CueSheet_Track *track; |
1517 | 74.3k | FLAC__ASSERT(object != NULL); |
1518 | 74.3k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1519 | 74.3k | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1520 | | |
1521 | 74.3k | track = &object->data.cue_sheet.tracks[track_num]; |
1522 | | |
1523 | 74.3k | if (track->indices == NULL) { |
1524 | 66.0k | FLAC__ASSERT(track->num_indices == 0); |
1525 | 66.0k | if (new_num_indices == 0) |
1526 | 25 | return true; |
1527 | 66.0k | else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL) |
1528 | 2 | return false; |
1529 | 66.0k | } |
1530 | 8.25k | else { |
1531 | 8.25k | const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); |
1532 | 8.25k | const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); |
1533 | | |
1534 | | /* overflow check */ |
1535 | 8.25k | if (new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index)) |
1536 | 0 | return false; |
1537 | | |
1538 | 8.25k | FLAC__ASSERT(track->num_indices > 0); |
1539 | | |
1540 | 8.25k | if (new_size == 0) { |
1541 | 94 | free(track->indices); |
1542 | 94 | track->indices = 0; |
1543 | 94 | } |
1544 | 8.16k | else { |
1545 | | /* Leave track->indices untouched if realloc fails */ |
1546 | 8.16k | FLAC__StreamMetadata_CueSheet_Index *tmpptr; |
1547 | 8.16k | if ((tmpptr = realloc(track->indices, new_size)) == NULL) |
1548 | 0 | return false; |
1549 | 8.16k | track->indices = tmpptr; |
1550 | 8.16k | } |
1551 | | |
1552 | | /* if growing, zero all the lengths/pointers of new elements */ |
1553 | 8.25k | if (new_size > old_size) |
1554 | 8.15k | memset(track->indices + track->num_indices, 0, new_size - old_size); |
1555 | 8.25k | } |
1556 | | |
1557 | 74.3k | track->num_indices = new_num_indices; |
1558 | | |
1559 | 74.3k | cuesheet_calculate_length_(object); |
1560 | 74.3k | return true; |
1561 | 74.3k | } |
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 | 74.1k | { |
1565 | 74.1k | FLAC__StreamMetadata_CueSheet_Track *track; |
1566 | | |
1567 | 74.1k | FLAC__ASSERT(object != NULL); |
1568 | 74.1k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1569 | 74.1k | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1570 | 74.1k | FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices); |
1571 | | |
1572 | 74.1k | track = &object->data.cue_sheet.tracks[track_num]; |
1573 | | |
1574 | 74.1k | if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1)) |
1575 | 2 | return false; |
1576 | | |
1577 | | /* move all indices >= index_num forward one space */ |
1578 | 74.1k | memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num)); |
1579 | | |
1580 | 74.1k | track->indices[index_num] = indx; |
1581 | 74.1k | cuesheet_calculate_length_(object); |
1582 | 74.1k | return true; |
1583 | 74.1k | } |
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 | 74.0k | { |
1587 | 74.0k | FLAC__StreamMetadata_CueSheet_Index indx; |
1588 | 74.0k | memset(&indx, 0, sizeof(indx)); |
1589 | 74.0k | return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx); |
1590 | 74.0k | } |
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 | 50 | { |
1594 | 50 | FLAC__StreamMetadata_CueSheet_Track *track; |
1595 | | |
1596 | 50 | FLAC__ASSERT(object != NULL); |
1597 | 50 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1598 | 50 | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1599 | 50 | FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices); |
1600 | | |
1601 | 50 | track = &object->data.cue_sheet.tracks[track_num]; |
1602 | | |
1603 | | /* move all indices > index_num backward one space */ |
1604 | 50 | memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1)); |
1605 | | |
1606 | 50 | FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1); |
1607 | 50 | cuesheet_calculate_length_(object); |
1608 | 50 | return true; |
1609 | 50 | } |
1610 | | |
1611 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks) |
1612 | 67.9k | { |
1613 | 67.9k | FLAC__ASSERT(object != NULL); |
1614 | 67.9k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1615 | | |
1616 | 67.9k | if (object->data.cue_sheet.tracks == NULL) { |
1617 | 5.82k | FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0); |
1618 | 5.82k | if (new_num_tracks == 0) |
1619 | 0 | return true; |
1620 | 5.82k | else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL) |
1621 | 2 | return false; |
1622 | 5.82k | } |
1623 | 62.0k | else { |
1624 | 62.0k | const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); |
1625 | 62.0k | const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); |
1626 | | |
1627 | | /* overflow check */ |
1628 | 62.0k | if (new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track)) |
1629 | 0 | return false; |
1630 | | |
1631 | 62.0k | FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); |
1632 | | |
1633 | | /* if shrinking, free the truncated entries */ |
1634 | 62.0k | if (new_num_tracks < object->data.cue_sheet.num_tracks) { |
1635 | 87 | uint32_t i; |
1636 | 483 | for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++) |
1637 | 396 | free(object->data.cue_sheet.tracks[i].indices); |
1638 | 87 | } |
1639 | | |
1640 | 62.0k | if (new_size == 0) { |
1641 | 35 | free(object->data.cue_sheet.tracks); |
1642 | 35 | object->data.cue_sheet.tracks = 0; |
1643 | 35 | } |
1644 | 62.0k | else { |
1645 | | /* Leave object->data.cue_sheet.tracks untouched if realloc fails */ |
1646 | 62.0k | FLAC__StreamMetadata_CueSheet_Track *tmpptr; |
1647 | 62.0k | if ((tmpptr = realloc(object->data.cue_sheet.tracks, new_size)) == NULL) |
1648 | 0 | return false; |
1649 | 62.0k | object->data.cue_sheet.tracks = tmpptr; |
1650 | 62.0k | } |
1651 | | |
1652 | | /* if growing, zero all the lengths/pointers of new elements */ |
1653 | 62.0k | if (new_size > old_size) |
1654 | 62.0k | memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size); |
1655 | 62.0k | } |
1656 | | |
1657 | 67.9k | object->data.cue_sheet.num_tracks = new_num_tracks; |
1658 | | |
1659 | 67.9k | cuesheet_calculate_length_(object); |
1660 | 67.9k | return true; |
1661 | 67.9k | } |
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 | 67.7k | { |
1665 | 67.7k | FLAC__ASSERT(object != NULL); |
1666 | 67.7k | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1667 | | |
1668 | 67.7k | return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy); |
1669 | 67.7k | } |
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 | 67.7k | { |
1673 | 67.7k | FLAC__StreamMetadata_CueSheet *cs; |
1674 | | |
1675 | 67.7k | FLAC__ASSERT(object != NULL); |
1676 | 67.7k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1677 | 67.7k | FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks); |
1678 | | |
1679 | 67.7k | cs = &object->data.cue_sheet; |
1680 | | |
1681 | 67.7k | if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1)) |
1682 | 2 | return false; |
1683 | | |
1684 | | /* move all tracks >= track_num forward one space */ |
1685 | 67.7k | memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num)); |
1686 | 67.7k | cs->tracks[track_num].num_indices = 0; |
1687 | 67.7k | cs->tracks[track_num].indices = 0; |
1688 | | |
1689 | 67.7k | return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy); |
1690 | 67.7k | } |
1691 | | |
1692 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num) |
1693 | 67.6k | { |
1694 | 67.6k | FLAC__StreamMetadata_CueSheet_Track track; |
1695 | 67.6k | memset(&track, 0, sizeof(track)); |
1696 | 67.6k | return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false); |
1697 | 67.6k | } |
1698 | | |
1699 | | FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num) |
1700 | 78 | { |
1701 | 78 | FLAC__StreamMetadata_CueSheet *cs; |
1702 | | |
1703 | 78 | FLAC__ASSERT(object != NULL); |
1704 | 78 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1705 | 78 | FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); |
1706 | | |
1707 | 78 | cs = &object->data.cue_sheet; |
1708 | | |
1709 | | /* free the track at track_num */ |
1710 | 78 | free(cs->tracks[track_num].indices); |
1711 | | |
1712 | | /* move all tracks > track_num backward one space */ |
1713 | 78 | memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1)); |
1714 | 78 | cs->tracks[cs->num_tracks-1].num_indices = 0; |
1715 | 78 | cs->tracks[cs->num_tracks-1].indices = 0; |
1716 | | |
1717 | 78 | return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1); |
1718 | 78 | } |
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 | 6.36k | { |
1722 | 6.36k | FLAC__ASSERT(object != NULL); |
1723 | 6.36k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1724 | | |
1725 | 6.36k | return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation); |
1726 | 6.36k | } |
1727 | | |
1728 | | static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, uint32_t track) |
1729 | 2.77k | { |
1730 | 2.77k | if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1) |
1731 | 0 | return 0; |
1732 | 2.77k | else if (cs->tracks[track].indices[0].number == 1) |
1733 | 2.54k | return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in; |
1734 | 226 | else if (cs->tracks[track].num_indices < 2) |
1735 | 172 | return 0; |
1736 | 54 | else if (cs->tracks[track].indices[1].number == 1) |
1737 | 54 | return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in; |
1738 | 0 | else |
1739 | 0 | return 0; |
1740 | 2.77k | } |
1741 | | |
1742 | | static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x) |
1743 | 2.55k | { |
1744 | 2.55k | FLAC__uint32 n = 0; |
1745 | 25.5k | while (x) { |
1746 | 22.9k | n += (x%10); |
1747 | 22.9k | x /= 10; |
1748 | 22.9k | } |
1749 | 2.55k | return n; |
1750 | 2.55k | } |
1751 | | |
1752 | | /*@@@@add to tests*/ |
1753 | | FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object) |
1754 | 438 | { |
1755 | 438 | const FLAC__StreamMetadata_CueSheet *cs; |
1756 | | |
1757 | 438 | FLAC__ASSERT(object != NULL); |
1758 | 438 | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); |
1759 | | |
1760 | 438 | cs = &object->data.cue_sheet; |
1761 | | |
1762 | 438 | if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */ |
1763 | 225 | return 0; |
1764 | | |
1765 | 213 | { |
1766 | 213 | FLAC__uint32 i, length, sum = 0; |
1767 | 2.77k | for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */ |
1768 | 2.55k | sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100)); |
1769 | 213 | 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 | 213 | return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1); |
1772 | 438 | } |
1773 | 438 | } |
1774 | | |
1775 | | FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy) |
1776 | 2.74k | { |
1777 | 2.74k | char *old; |
1778 | 2.74k | size_t old_length, new_length; |
1779 | | |
1780 | 2.74k | FLAC__ASSERT(object != NULL); |
1781 | 2.74k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); |
1782 | 2.74k | FLAC__ASSERT(mime_type != NULL); |
1783 | | |
1784 | 2.74k | old = object->data.picture.mime_type; |
1785 | 2.74k | old_length = old? strlen(old) : 0; |
1786 | 2.74k | new_length = strlen(mime_type); |
1787 | | |
1788 | | /* do the copy first so that if we fail we leave the object untouched */ |
1789 | 2.74k | if (copy) { |
1790 | 345 | if (new_length >= SIZE_MAX) /* overflow check */ |
1791 | 0 | return false; |
1792 | 345 | if (!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1)) |
1793 | 1 | return false; |
1794 | 345 | } |
1795 | 2.40k | else { |
1796 | 2.40k | object->data.picture.mime_type = mime_type; |
1797 | 2.40k | } |
1798 | | |
1799 | 2.74k | free(old); |
1800 | | |
1801 | 2.74k | object->length -= old_length; |
1802 | 2.74k | object->length += new_length; |
1803 | 2.74k | return true; |
1804 | 2.74k | } |
1805 | | |
1806 | | FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy) |
1807 | 3.26k | { |
1808 | 3.26k | FLAC__byte *old; |
1809 | 3.26k | size_t old_length, new_length; |
1810 | | |
1811 | 3.26k | FLAC__ASSERT(object != NULL); |
1812 | 3.26k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); |
1813 | 3.26k | FLAC__ASSERT(description != NULL); |
1814 | | |
1815 | 3.26k | old = object->data.picture.description; |
1816 | 3.26k | old_length = old? strlen((const char *)old) : 0; |
1817 | 3.26k | new_length = strlen((const char *)description); |
1818 | | |
1819 | | /* do the copy first so that if we fail we leave the object untouched */ |
1820 | 3.26k | if (copy) { |
1821 | 103 | if (new_length >= SIZE_MAX) /* overflow check */ |
1822 | 0 | return false; |
1823 | 103 | if (!copy_bytes_(&object->data.picture.description, description, new_length+1)) |
1824 | 0 | return false; |
1825 | 103 | } |
1826 | 3.16k | else { |
1827 | 3.16k | object->data.picture.description = description; |
1828 | 3.16k | } |
1829 | | |
1830 | 3.26k | free(old); |
1831 | | |
1832 | 3.26k | object->length -= old_length; |
1833 | 3.26k | object->length += new_length; |
1834 | 3.26k | return true; |
1835 | 3.26k | } |
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 | 2.32k | { |
1839 | 2.32k | FLAC__byte *old; |
1840 | | |
1841 | 2.32k | FLAC__ASSERT(object != NULL); |
1842 | 2.32k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); |
1843 | 2.32k | FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false)); |
1844 | | |
1845 | 2.32k | old = object->data.picture.data; |
1846 | | |
1847 | | /* do the copy first so that if we fail we leave the object untouched */ |
1848 | 2.32k | if (copy) { |
1849 | 1.66k | if (!copy_bytes_(&object->data.picture.data, data, length)) |
1850 | 6 | return false; |
1851 | 1.66k | } |
1852 | 653 | else { |
1853 | 653 | object->data.picture.data = data; |
1854 | 653 | } |
1855 | | |
1856 | 2.31k | free(old); |
1857 | | |
1858 | 2.31k | object->length -= object->data.picture.data_length; |
1859 | 2.31k | object->data.picture.data_length = length; |
1860 | 2.31k | object->length += length; |
1861 | 2.31k | return true; |
1862 | 2.32k | } |
1863 | | |
1864 | | FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation) |
1865 | 10.7k | { |
1866 | 10.7k | FLAC__ASSERT(object != NULL); |
1867 | 10.7k | FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); |
1868 | | |
1869 | 10.7k | return FLAC__format_picture_is_legal(&object->data.picture, violation); |
1870 | 10.7k | } |
1871 | | |
1872 | | FLAC_API FLAC__byte * FLAC__metadata_object_get_raw(const FLAC__StreamMetadata *object) |
1873 | 2.46k | { |
1874 | 2.46k | FLAC__BitWriter *bw; |
1875 | 2.46k | const FLAC__byte * buffer; |
1876 | 2.46k | FLAC__byte * output; |
1877 | 2.46k | size_t bytes; |
1878 | | |
1879 | 2.46k | FLAC__ASSERT(object != NULL); |
1880 | | |
1881 | 2.46k | if((bw = FLAC__bitwriter_new()) == NULL) |
1882 | 0 | return 0; |
1883 | 2.46k | if(!FLAC__bitwriter_init(bw)) { |
1884 | 0 | FLAC__bitwriter_delete(bw); |
1885 | 0 | return 0; |
1886 | 0 | } |
1887 | 2.46k | if(!FLAC__add_metadata_block(object, bw, false)) { |
1888 | 187 | FLAC__bitwriter_delete(bw); |
1889 | 187 | return 0; |
1890 | 187 | } |
1891 | | |
1892 | 2.28k | 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 | 2.28k | if(bytes != (object->length+FLAC__STREAM_METADATA_HEADER_LENGTH)) { |
1899 | 0 | FLAC__bitwriter_delete(bw); |
1900 | 0 | return 0; |
1901 | 0 | } |
1902 | | |
1903 | 2.28k | output = safe_malloc_(bytes); |
1904 | 2.28k | if(output == 0) { |
1905 | 0 | FLAC__bitwriter_delete(bw); |
1906 | 0 | return 0; |
1907 | 0 | } |
1908 | | |
1909 | 2.28k | memcpy(output,buffer,bytes); |
1910 | 2.28k | FLAC__bitwriter_delete(bw); |
1911 | 2.28k | return output; |
1912 | 2.28k | } |
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 | 4.80k | { |
1931 | 4.80k | set_raw_client_data cd; |
1932 | 4.80k | FLAC__StreamDecoder * decoder; |
1933 | | |
1934 | 4.80k | cd.buffer = buffer; |
1935 | 4.80k | cd.length = length; |
1936 | 4.80k | cd.got_error = false; |
1937 | 4.80k | cd.object = 0; |
1938 | 4.80k | cd.tell = -4; |
1939 | | |
1940 | 4.80k | decoder = FLAC__stream_decoder_new(); |
1941 | | |
1942 | 4.80k | if(0 == decoder) |
1943 | 0 | return 0; |
1944 | | |
1945 | 4.80k | FLAC__stream_decoder_set_md5_checking(decoder, false); |
1946 | 4.80k | FLAC__stream_decoder_set_metadata_respond_all(decoder); |
1947 | | |
1948 | 4.80k | 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 | 4.80k | 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 | 244 | (void)FLAC__stream_decoder_finish(decoder); |
1956 | 244 | FLAC__stream_decoder_delete(decoder); |
1957 | 244 | if(0 != cd.object) |
1958 | 0 | FLAC__metadata_object_delete(cd.object); |
1959 | 244 | return 0; |
1960 | 244 | } |
1961 | | |
1962 | 4.56k | (void)FLAC__stream_decoder_finish(decoder); |
1963 | 4.56k | FLAC__stream_decoder_delete(decoder); |
1964 | | |
1965 | 4.56k | return cd.object; |
1966 | | |
1967 | 4.80k | } |
1968 | | |
1969 | | FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte *buffer, size_t *bytes, void *client_data) |
1970 | 13.7k | { |
1971 | 13.7k | set_raw_client_data *cd = (set_raw_client_data *)client_data; |
1972 | 13.7k | (void)decoder; |
1973 | | |
1974 | 13.7k | if(cd->tell == -4) { |
1975 | 4.80k | if(*bytes < 4) |
1976 | 0 | return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
1977 | 4.80k | buffer[0] = 'f'; |
1978 | 4.80k | buffer[1] = 'L'; |
1979 | 4.80k | buffer[2] = 'a'; |
1980 | 4.80k | buffer[3] = 'C'; |
1981 | 4.80k | *bytes = 4; |
1982 | 4.80k | cd->tell = 0; |
1983 | 4.80k | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
1984 | 4.80k | } |
1985 | 8.94k | else if(cd->tell < 0) |
1986 | 0 | return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
1987 | 8.94k | else if(cd->tell == cd->length) { |
1988 | 3.84k | *bytes = 0; |
1989 | 3.84k | return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; |
1990 | 3.84k | } |
1991 | 5.09k | else { |
1992 | 5.09k | if((FLAC__int32)(*bytes) > (cd->length - cd->tell)) |
1993 | 4.80k | *bytes = cd->length - cd->tell; |
1994 | 5.09k | memcpy(buffer, cd->buffer+cd->tell, *bytes); |
1995 | 5.09k | cd->tell += *bytes; |
1996 | 5.09k | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
1997 | 5.09k | } |
1998 | 13.7k | } |
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 | 4.55k | { |
2009 | 4.55k | set_raw_client_data *cd = (set_raw_client_data *)client_data; |
2010 | 4.55k | (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 | 4.55k | if(!cd->got_error && 0 == cd->object) { |
2017 | 4.55k | if(0 == (cd->object = FLAC__metadata_object_clone(metadata))) |
2018 | 7 | cd->got_error = true; |
2019 | 4.55k | } |
2020 | 4.55k | } |
2021 | | |
2022 | | void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) |
2023 | 235 | { |
2024 | 235 | set_raw_client_data *cd = (set_raw_client_data *)client_data; |
2025 | 235 | (void)decoder; |
2026 | | |
2027 | 235 | if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) |
2028 | 235 | cd->got_error = true; |
2029 | 235 | } |