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