xref: /aosp_15_r20/external/flac/src/share/grabbag/picture.c (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
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