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