/src/flac/src/share/grabbag/picture.c
Line | Count | Source |
1 | | /* grabbag - Convenience lib for various routines common to several tools |
2 | | * Copyright (C) 2006-2009 Josh Coalson |
3 | | * Copyright (C) 2011-2025 Xiph.Org Foundation |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or |
6 | | * modify it under the terms of the GNU General Public License |
7 | | * as published by the Free Software Foundation; either version 2 |
8 | | * of the License, or (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License along |
16 | | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | | */ |
19 | | |
20 | | #ifdef HAVE_CONFIG_H |
21 | | # include <config.h> |
22 | | #endif |
23 | | |
24 | | #include "share/alloc.h" |
25 | | #include "share/grabbag.h" |
26 | | #include "FLAC/assert.h" |
27 | | #include <stdio.h> |
28 | | #include <stdlib.h> |
29 | | #include <string.h> |
30 | | #include "share/compat.h" |
31 | | #include "share/safe_str.h" |
32 | | |
33 | | /* slightly different that strndup(): this always copies 'size' bytes starting from s into a NUL-terminated string. */ |
34 | | static char *local__strndup_(const char *s, size_t size) |
35 | 8.09k | { |
36 | 8.09k | char *x = safe_malloc_add_2op_(size, /*+*/1); |
37 | 8.09k | if(x) { |
38 | 7.87k | memcpy(x, s, size); |
39 | 7.87k | x[size] = '\0'; |
40 | 7.87k | } |
41 | 8.09k | return x; |
42 | 8.09k | } |
43 | | |
44 | | static FLAC__bool local__parse_type_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture) |
45 | 5.94k | { |
46 | 5.94k | size_t i; |
47 | 5.94k | FLAC__uint32 val = 0; |
48 | | |
49 | 5.94k | picture->type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; |
50 | | |
51 | 5.94k | if(len == 0) |
52 | 3.97k | return true; /* empty string implies default to 'front cover' */ |
53 | | |
54 | 6.90k | for(i = 0; i < len; i++) { |
55 | 5.15k | if(s[i] >= '0' && s[i] <= '9') |
56 | 4.93k | val = 10*val + (FLAC__uint32)(s[i] - '0'); |
57 | 218 | else |
58 | 218 | return false; |
59 | 5.15k | } |
60 | | |
61 | 1.75k | if(i == len) |
62 | 1.75k | picture->type = val; |
63 | 0 | else |
64 | 0 | return false; |
65 | | |
66 | 1.75k | return true; |
67 | 1.75k | } |
68 | | |
69 | | static FLAC__bool local__parse_resolution_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture) |
70 | 4.93k | { |
71 | 4.93k | int state = 0; |
72 | 4.93k | size_t i; |
73 | 4.93k | FLAC__uint32 val = 0; |
74 | | |
75 | 4.93k | picture->width = picture->height = picture->depth = picture->colors = 0; |
76 | | |
77 | 4.93k | if(len == 0) |
78 | 1.70k | return true; /* empty string implies client wants to get info from the file itself */ |
79 | | |
80 | 28.6k | for(i = 0; i < len; i++) { |
81 | 25.7k | if(s[i] == 'x') { |
82 | 5.94k | if(state == 0) |
83 | 2.97k | picture->width = val; |
84 | 2.96k | else if(state == 1) |
85 | 2.89k | picture->height = val; |
86 | 70 | else |
87 | 70 | return false; |
88 | 5.87k | state++; |
89 | 5.87k | val = 0; |
90 | 5.87k | } |
91 | 19.8k | else if(s[i] == '/') { |
92 | 347 | if(state == 2) |
93 | 246 | picture->depth = val; |
94 | 101 | else |
95 | 101 | return false; |
96 | 246 | state++; |
97 | 246 | val = 0; |
98 | 246 | } |
99 | 19.4k | else if(s[i] >= '0' && s[i] <= '9') |
100 | 19.2k | val = 10*val + (FLAC__uint32)(s[i] - '0'); |
101 | 198 | else |
102 | 198 | return false; |
103 | 25.7k | } |
104 | | |
105 | 2.86k | if(state < 2) |
106 | 89 | return false; |
107 | 2.77k | else if(state == 2) |
108 | 2.56k | picture->depth = val; |
109 | 206 | else if(state == 3) |
110 | 206 | picture->colors = val; |
111 | 0 | else |
112 | 0 | return false; |
113 | 2.77k | if(picture->depth < 32 && 1u<<picture->depth < picture->colors) |
114 | 143 | return false; |
115 | | |
116 | 2.62k | return true; |
117 | 2.77k | } |
118 | | |
119 | | static FLAC__bool local__extract_mime_type_(FLAC__StreamMetadata *obj) |
120 | 402 | { |
121 | 402 | if(obj->data.picture.data_length >= 8 && 0 == memcmp(obj->data.picture.data, "\x89PNG\x0d\x0a\x1a\x0a", 8)) |
122 | 109 | return FLAC__metadata_object_picture_set_mime_type(obj, "image/png", /*copy=*/true); |
123 | 293 | else if(obj->data.picture.data_length >= 6 && (0 == memcmp(obj->data.picture.data, "GIF87a", 6) || 0 == memcmp(obj->data.picture.data, "GIF89a", 6))) |
124 | 7 | return FLAC__metadata_object_picture_set_mime_type(obj, "image/gif", /*copy=*/true); |
125 | 286 | else if(obj->data.picture.data_length >= 2 && 0 == memcmp(obj->data.picture.data, "\xff\xd8", 2)) |
126 | 134 | return FLAC__metadata_object_picture_set_mime_type(obj, "image/jpeg", /*copy=*/true); |
127 | 152 | return false; |
128 | 402 | } |
129 | | |
130 | | static FLAC__bool local__extract_resolution_color_info_(FLAC__StreamMetadata_Picture *picture) |
131 | 874 | { |
132 | 874 | const FLAC__byte *data = picture->data; |
133 | 874 | FLAC__uint32 len = picture->data_length; |
134 | | |
135 | 874 | if(0 == strcmp(picture->mime_type, "image/png")) { |
136 | | /* c.f. http://www.w3.org/TR/PNG/ */ |
137 | 146 | FLAC__bool need_palette = false; /* if IHDR has color_type=3, we need to also read the PLTE chunk to get the #colors */ |
138 | 146 | if(len < 8 || memcmp(data, "\x89PNG\x0d\x0a\x1a\x0a", 8)) |
139 | 37 | return false; |
140 | | /* try to find IHDR chunk */ |
141 | 109 | data += 8; |
142 | 109 | len -= 8; |
143 | 618 | while(len > 12) { /* every PNG chunk must be at least 12 bytes long */ |
144 | 584 | const FLAC__uint32 clen = (FLAC__uint32)data[0] << 24 | (FLAC__uint32)data[1] << 16 | (FLAC__uint32)data[2] << 8 | (FLAC__uint32)data[3]; |
145 | | /* First check whether clen makes sense or causes overflow in this bit of code */ |
146 | 584 | if(clen + 12 <= clen || clen + 12 > len) |
147 | 63 | return false; |
148 | 521 | else if(0 == memcmp(data+4, "IHDR", 4) && clen == 13) { |
149 | 86 | uint32_t color_type = data[17]; |
150 | 86 | picture->width = (FLAC__uint32)data[8] << 24 | (FLAC__uint32)data[9] << 16 | (FLAC__uint32)data[10] << 8 | (FLAC__uint32)data[11]; |
151 | 86 | picture->height = (FLAC__uint32)data[12] << 24 | (FLAC__uint32)data[13] << 16 | (FLAC__uint32)data[14] << 8 | (FLAC__uint32)data[15]; |
152 | 86 | if(color_type == 3) { |
153 | | /* even though the bit depth for color_type==3 can be 1,2,4,or 8, |
154 | | * the spec in 11.2.2 of http://www.w3.org/TR/PNG/ says that the |
155 | | * sample depth is always 8 |
156 | | */ |
157 | 75 | picture->depth = 8 * 3u; |
158 | 75 | need_palette = true; |
159 | 75 | data += 12 + clen; |
160 | 75 | len -= 12 + clen; |
161 | 75 | } |
162 | 11 | else { |
163 | 11 | if(color_type == 0) /* greyscale, 1 sample per pixel */ |
164 | 1 | picture->depth = (FLAC__uint32)data[16]; |
165 | 11 | if(color_type == 2) /* truecolor, 3 samples per pixel */ |
166 | 1 | picture->depth = (FLAC__uint32)data[16] * 3u; |
167 | 11 | if(color_type == 4) /* greyscale+alpha, 2 samples per pixel */ |
168 | 1 | picture->depth = (FLAC__uint32)data[16] * 2u; |
169 | 11 | if(color_type == 6) /* truecolor+alpha, 4 samples per pixel */ |
170 | 1 | picture->depth = (FLAC__uint32)data[16] * 4u; |
171 | 11 | picture->colors = 0; |
172 | 11 | return true; |
173 | 11 | } |
174 | 86 | } |
175 | 435 | else if(need_palette && 0 == memcmp(data+4, "PLTE", 4)) { |
176 | 1 | picture->colors = clen / 3u; |
177 | 1 | return true; |
178 | 1 | } |
179 | 434 | else { |
180 | 434 | data += 12 + clen; |
181 | 434 | len -= 12 + clen; |
182 | 434 | } |
183 | 584 | } |
184 | 109 | } |
185 | 728 | else if(0 == strcmp(picture->mime_type, "image/jpeg")) { |
186 | | /* c.f. http://www.w3.org/Graphics/JPEG/itu-t81.pdf and Q22 of http://www.faqs.org/faqs/jpeg-faq/part1/ */ |
187 | 154 | if(len < 2 || memcmp(data, "\xff\xd8", 2)) |
188 | 21 | return false; |
189 | 133 | data += 2; |
190 | 133 | len -= 2; |
191 | 1.77k | while(1) { |
192 | | /* look for sync FF byte */ |
193 | 118k | for( ; len > 0; data++, len--) { |
194 | 118k | if(*data == 0xff) |
195 | 1.74k | break; |
196 | 118k | } |
197 | 1.77k | if(len == 0) |
198 | 30 | return false; |
199 | | /* eat any extra pad FF bytes before marker */ |
200 | 3.95k | for( ; len > 0; data++, len--) { |
201 | 3.95k | if(*data != 0xff) |
202 | 1.74k | break; |
203 | 3.95k | } |
204 | 1.74k | if(len == 0) |
205 | 4 | return false; |
206 | | /* if we hit SOS or EOI, bail */ |
207 | 1.74k | if(*data == 0xda || *data == 0xd9) |
208 | 3 | return false; |
209 | | /* looking for some SOFn */ |
210 | 1.73k | else if(memchr("\xc0\xc1\xc2\xc3\xc5\xc6\xc7\xc9\xca\xcb\xcd\xce\xcf", *data, 13)) { |
211 | 23 | data++; len--; /* skip marker byte */ |
212 | 23 | if(len < 2) |
213 | 3 | return false; |
214 | 20 | else { |
215 | 20 | const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1]; |
216 | 20 | if(clen < 8 || len < clen) |
217 | 16 | return false; |
218 | 4 | picture->width = (FLAC__uint32)data[5] << 8 | (FLAC__uint32)data[6]; |
219 | 4 | picture->height = (FLAC__uint32)data[3] << 8 | (FLAC__uint32)data[4]; |
220 | 4 | picture->depth = (FLAC__uint32)data[2] * (FLAC__uint32)data[7]; |
221 | 4 | picture->colors = 0; |
222 | 4 | return true; |
223 | 20 | } |
224 | 23 | } |
225 | | /* else skip it */ |
226 | 1.71k | else { |
227 | 1.71k | data++; len--; /* skip marker byte */ |
228 | 1.71k | if(len < 2) |
229 | 23 | return false; |
230 | 1.69k | else { |
231 | 1.69k | const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1]; |
232 | 1.69k | if(clen < 2 || len < clen) |
233 | 50 | return false; |
234 | 1.64k | data += clen; |
235 | 1.64k | len -= clen; |
236 | 1.64k | } |
237 | 1.71k | } |
238 | 1.74k | } |
239 | 133 | } |
240 | 574 | else if(0 == strcmp(picture->mime_type, "image/gif")) { |
241 | | /* c.f. http://www.w3.org/Graphics/GIF/spec-gif89a.txt */ |
242 | 44 | if(len < 14) |
243 | 3 | return false; |
244 | 41 | if(memcmp(data, "GIF87a", 6) && memcmp(data, "GIF89a", 6)) |
245 | 37 | return false; |
246 | | #if 0 |
247 | | /* according to the GIF spec, even if the GCTF is 0, the low 3 bits should still tell the total # colors used */ |
248 | | if(data[10] & 0x80 == 0) |
249 | | return false; |
250 | | #endif |
251 | 4 | picture->width = (FLAC__uint32)data[6] | ((FLAC__uint32)data[7] << 8); |
252 | 4 | picture->height = (FLAC__uint32)data[8] | ((FLAC__uint32)data[9] << 8); |
253 | | #if 0 |
254 | | /* this value doesn't seem to be reliable... */ |
255 | | picture->depth = (((FLAC__uint32)(data[10] & 0x70) >> 4) + 1) * 3u; |
256 | | #else |
257 | | /* ...just pessimistically assume it's 24-bit color without scanning all the color tables */ |
258 | 4 | picture->depth = 8u * 3u; |
259 | 4 | #endif |
260 | 4 | picture->colors = 1u << ((FLAC__uint32)(data[10] & 0x07) + 1u); |
261 | 4 | return true; |
262 | 41 | } |
263 | 564 | return false; |
264 | 874 | } |
265 | | |
266 | | static const char *error_messages[] = { |
267 | | "memory allocation error", |
268 | | "invalid picture specification", |
269 | | "invalid picture specification: can't parse resolution/color part", |
270 | | "unable to extract resolution and color info from URL, user must set explicitly", |
271 | | "unable to extract resolution and color info from file, user must set explicitly", |
272 | | "error opening picture file", |
273 | | "error reading picture file", |
274 | | "invalid picture type", |
275 | | "unable to guess MIME type from file, user must set explicitly", |
276 | | "type 1 icon must be a 32x32 pixel PNG", |
277 | | "file not found", /* currently unused */ |
278 | | "file is too large", |
279 | | "empty file" |
280 | | }; |
281 | | |
282 | | static const char * read_file (const char * filepath, FLAC__StreamMetadata * obj) |
283 | 2.35k | { |
284 | 2.35k | const FLAC__off_t size = grabbag__file_get_filesize(filepath); |
285 | 2.35k | FLAC__byte *buffer; |
286 | 2.35k | FILE *file; |
287 | 2.35k | const char *error_message=NULL; |
288 | | |
289 | 2.35k | if (size < 0) |
290 | 464 | return error_messages[5]; |
291 | | |
292 | 1.89k | if (size == 0) |
293 | 67 | return error_messages[12]; |
294 | | |
295 | 1.82k | if (size >= (FLAC__off_t)(1u << FLAC__STREAM_METADATA_LENGTH_LEN)) /* actual limit is less because of other fields in the PICTURE metadata block */ |
296 | 0 | return error_messages[11]; |
297 | | |
298 | 1.82k | if ((buffer = safe_malloc_(size)) == NULL) |
299 | 84 | return error_messages[0]; |
300 | | |
301 | 1.73k | if ((file = flac_fopen(filepath, "rb")) == NULL) { |
302 | 0 | free(buffer); |
303 | 0 | return error_messages[5]; |
304 | 0 | } |
305 | | |
306 | 1.73k | if (fread(buffer, 1, size, file) != (size_t) size) { |
307 | 207 | fclose(file); |
308 | 207 | free(buffer); |
309 | 207 | return error_messages[6]; |
310 | 207 | } |
311 | 1.53k | fclose(file); |
312 | | |
313 | 1.53k | if (!FLAC__metadata_object_picture_set_data(obj, buffer, (FLAC__uint32)size, /*copy=*/false)) |
314 | 0 | error_message = error_messages[6]; |
315 | | /* try to extract MIME type if user left it blank */ |
316 | 1.53k | else if (*obj->data.picture.mime_type == '\0' && !local__extract_mime_type_(obj)) |
317 | 153 | error_message = error_messages[8]; |
318 | | /* try to extract resolution/color info if user left it blank */ |
319 | 1.37k | else if ((obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) && !local__extract_resolution_color_info_(&obj->data.picture)) |
320 | 854 | error_message = error_messages[4]; |
321 | | /* check metadata block size */ |
322 | 525 | else if (obj->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) |
323 | 0 | error_message = error_messages[11]; |
324 | | |
325 | 1.53k | return error_message; |
326 | 1.73k | } |
327 | | |
328 | | FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message) |
329 | 5.94k | { |
330 | 5.94k | FLAC__StreamMetadata *obj; |
331 | 5.94k | int state = 0; |
332 | | |
333 | 5.94k | FLAC__ASSERT(0 != spec); |
334 | 5.94k | FLAC__ASSERT(0 != error_message); |
335 | | |
336 | | /* double protection */ |
337 | 5.94k | if(0 == spec) |
338 | 0 | return 0; |
339 | 5.94k | if(0 == error_message) |
340 | 0 | return 0; |
341 | | |
342 | 5.94k | *error_message = 0; |
343 | | |
344 | 5.94k | if(0 == (obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE))) { |
345 | 0 | *error_message = error_messages[0]; |
346 | 0 | return obj; |
347 | 0 | } |
348 | | |
349 | 5.94k | if(strchr(spec, '|')) { /* full format */ |
350 | 5.10k | const char *p; |
351 | 5.10k | char *q; |
352 | 9.02M | for(p = spec; *error_message==0 && *p; ) { |
353 | 9.02M | if(*p == '|') { |
354 | 18.5k | switch(state) { |
355 | 5.10k | case 0: /* type */ |
356 | 5.10k | if(!local__parse_type_(spec, p-spec, &obj->data.picture)) |
357 | 218 | *error_message = error_messages[7]; |
358 | 5.10k | break; |
359 | 4.80k | case 1: /* mime type */ |
360 | 4.80k | if(p-spec) { /* if blank, we'll try to guess later from the picture data */ |
361 | 3.69k | if(0 == (q = local__strndup_(spec, p-spec))) |
362 | 123 | *error_message = error_messages[0]; |
363 | 3.57k | else if(!FLAC__metadata_object_picture_set_mime_type(obj, q, /*copy=*/false)) |
364 | 0 | *error_message = error_messages[0]; |
365 | 3.69k | } |
366 | 4.80k | break; |
367 | 4.39k | case 2: /* description */ |
368 | 4.39k | if(0 == (q = local__strndup_(spec, p-spec))) |
369 | 99 | *error_message = error_messages[0]; |
370 | 4.29k | else if(!FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*)q, /*copy=*/false)) |
371 | 0 | *error_message = error_messages[0]; |
372 | 4.39k | break; |
373 | 4.09k | case 3: /* resolution/color (e.g. [300x300x16[/1234]] */ |
374 | 4.09k | if(!local__parse_resolution_(spec, p-spec, &obj->data.picture)) |
375 | 601 | *error_message = error_messages[2]; |
376 | 4.09k | break; |
377 | 120 | default: |
378 | 120 | *error_message = error_messages[1]; |
379 | 120 | break; |
380 | 18.5k | } |
381 | 18.5k | p++; |
382 | 18.5k | spec = p; |
383 | 18.5k | state++; |
384 | 18.5k | } |
385 | 9.00M | else |
386 | 9.00M | p++; |
387 | 9.02M | } |
388 | 5.10k | } |
389 | 839 | else { /* simple format, filename only, everything else guessed */ |
390 | 839 | if(!local__parse_type_("", 0, &obj->data.picture)) /* use default picture type */ |
391 | 0 | *error_message = error_messages[7]; |
392 | | /* leave MIME type to be filled in later */ |
393 | | /* leave description empty */ |
394 | | /* leave the rest to be filled in later: */ |
395 | 839 | else if(!local__parse_resolution_("", 0, &obj->data.picture)) |
396 | 0 | *error_message = error_messages[2]; |
397 | 839 | else |
398 | 839 | state = 4; |
399 | 839 | } |
400 | | |
401 | | /* parse filename, read file, try to extract resolution/color info if needed */ |
402 | 5.94k | if(*error_message == 0) { |
403 | 4.78k | if(state != 4) |
404 | 568 | *error_message = error_messages[1]; |
405 | 4.21k | else { /* 'spec' points to filename/URL */ |
406 | 4.21k | if(0 == strcmp(obj->data.picture.mime_type, "-->")) { /* magic MIME type means URL */ |
407 | 1.85k | if(strlen(spec) == 0) |
408 | 44 | *error_message = error_messages[1]; |
409 | 1.81k | else if(!FLAC__metadata_object_picture_set_data(obj, (FLAC__byte*)spec, strlen(spec), /*copy=*/true)) |
410 | 9 | *error_message = error_messages[0]; |
411 | 1.80k | else if(obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) |
412 | 512 | *error_message = error_messages[3]; |
413 | 1.85k | } |
414 | 2.35k | else { /* regular picture file */ |
415 | 2.35k | *error_message = read_file (spec, obj); |
416 | 2.35k | } |
417 | 4.21k | } |
418 | 4.78k | } |
419 | | |
420 | 5.94k | if(*error_message == 0) { |
421 | 1.81k | if( |
422 | 1.81k | obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && |
423 | 717 | ( |
424 | 717 | (strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) || |
425 | 427 | obj->data.picture.width != 32 || |
426 | 261 | obj->data.picture.height != 32 |
427 | 717 | ) |
428 | 1.81k | ) |
429 | 575 | *error_message = error_messages[9]; |
430 | 1.81k | } |
431 | | |
432 | 5.94k | if(*error_message && obj) { |
433 | 4.69k | FLAC__metadata_object_delete(obj); |
434 | 4.69k | obj = 0; |
435 | 4.69k | } |
436 | | |
437 | 5.94k | return obj; |
438 | 5.94k | } |
439 | | |
440 | | FLAC__StreamMetadata *grabbag__picture_from_specification(int type, const char *mime_type_in, const char * description, |
441 | | const PictureResolution * res, const char * filepath, const char **error_message) |
442 | 0 | { |
443 | |
|
444 | 0 | FLAC__StreamMetadata *obj; |
445 | 0 | char mime_type [64] ; |
446 | |
|
447 | 0 | if (error_message == 0) |
448 | 0 | return 0; |
449 | | |
450 | 0 | safe_strncpy(mime_type, mime_type_in, sizeof (mime_type)); |
451 | |
|
452 | 0 | *error_message = 0; |
453 | |
|
454 | 0 | if ((obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)) == 0) { |
455 | 0 | *error_message = error_messages[0]; |
456 | 0 | return obj; |
457 | 0 | } |
458 | | |
459 | | /* Picture type if known. */ |
460 | 0 | obj->data.picture.type = type >= 0 ? type : FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; |
461 | | |
462 | | /* Mime type if known. */ |
463 | 0 | if (mime_type_in && ! FLAC__metadata_object_picture_set_mime_type(obj, mime_type, /*copy=*/true)) { |
464 | 0 | *error_message = error_messages[0]; |
465 | 0 | return obj; |
466 | 0 | } |
467 | | |
468 | | /* Description if present. */ |
469 | 0 | if (description && ! FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*) description, /*copy=*/true)) { |
470 | 0 | *error_message = error_messages[0]; |
471 | 0 | return obj; |
472 | 0 | } |
473 | | |
474 | 0 | if (res == NULL) { |
475 | 0 | obj->data.picture.width = 0; |
476 | 0 | obj->data.picture.height = 0; |
477 | 0 | obj->data.picture.depth = 0; |
478 | 0 | obj->data.picture.colors = 0; |
479 | 0 | } |
480 | 0 | else { |
481 | 0 | obj->data.picture.width = res->width; |
482 | 0 | obj->data.picture.height = res->height; |
483 | 0 | obj->data.picture.depth = res->depth; |
484 | 0 | obj->data.picture.colors = res->colors; |
485 | 0 | } |
486 | |
|
487 | 0 | if (strcmp(obj->data.picture.mime_type, "-->") == 0) { /* magic MIME type means URL */ |
488 | 0 | if (!FLAC__metadata_object_picture_set_data(obj, (FLAC__byte*)filepath, strlen(filepath), /*copy=*/true)) |
489 | 0 | *error_message = error_messages[0]; |
490 | 0 | else if (obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) |
491 | 0 | *error_message = error_messages[3]; |
492 | 0 | } |
493 | 0 | else { |
494 | 0 | *error_message = read_file (filepath, obj); |
495 | 0 | } |
496 | |
|
497 | 0 | if (*error_message == NULL) { |
498 | 0 | if ( |
499 | 0 | obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && |
500 | 0 | ( |
501 | 0 | (strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) || |
502 | 0 | obj->data.picture.width != 32 || |
503 | 0 | obj->data.picture.height != 32 |
504 | 0 | ) |
505 | 0 | ) |
506 | 0 | *error_message = error_messages[9]; |
507 | 0 | } |
508 | |
|
509 | 0 | if (*error_message && obj) { |
510 | 0 | FLAC__metadata_object_delete(obj); |
511 | 0 | obj = 0; |
512 | 0 | } |
513 | |
|
514 | 0 | return obj; |
515 | 0 | } |