mirror of https://github.com/xiph/flac
add parsing of picture type from spec; add check that type 1 picture is 32x32 PNG
This commit is contained in:
parent
63da21f4f9
commit
6e94c90e60
|
@ -27,7 +27,16 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* spec and error_message must not be NULL */
|
/* spec should be of the form "[TYPE]|MIME_TYPE|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE", e.g.
|
||||||
|
* "|image/jpeg|||cover.jpg"
|
||||||
|
* "4|image/jpeg||300x300x24|backcover.jpg"
|
||||||
|
* "|image/png|description|300x300x24/71|cover.png"
|
||||||
|
* "-->|image/gif||300x300x24/71|http://blah.blah.blah/cover.gif"
|
||||||
|
*
|
||||||
|
* empty type means default to FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER
|
||||||
|
* empty resolution spec means to get from the file (cannot get used with "-->" linked images)
|
||||||
|
* spec and error_message must not be NULL
|
||||||
|
*/
|
||||||
FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message);
|
FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -37,6 +37,31 @@ static char *local__strndup_(const char *s, size_t size)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FLAC__bool local__parse_type_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
FLAC__uint32 val = 0;
|
||||||
|
|
||||||
|
picture->type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;;
|
||||||
|
|
||||||
|
if(len == 0)
|
||||||
|
return true; /* empty string implies default to 'front cover' */
|
||||||
|
|
||||||
|
for(i = 0; i < len; i++) {
|
||||||
|
if(s[i] >= '0' && s[i] <= '9')
|
||||||
|
val = 10*val + (FLAC__uint32)(s[i] - '0');
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i == len)
|
||||||
|
picture->type = val;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static FLAC__bool local__parse_resolution_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
|
static FLAC__bool local__parse_resolution_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
|
||||||
{
|
{
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
@ -236,7 +261,9 @@ FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, con
|
||||||
"unable to extract resolution and color info from file, user must set explicitly",
|
"unable to extract resolution and color info from file, user must set explicitly",
|
||||||
"error opening picture file",
|
"error opening picture file",
|
||||||
"error reading picture file",
|
"error reading picture file",
|
||||||
"invalid MIME type"
|
"invalid picture type",
|
||||||
|
"invalid MIME type",
|
||||||
|
"type 1 icon must be a 32x32 pixel PNG"
|
||||||
};
|
};
|
||||||
|
|
||||||
FLAC__ASSERT(0 != spec);
|
FLAC__ASSERT(0 != spec);
|
||||||
|
@ -256,21 +283,25 @@ FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, con
|
||||||
for(p = spec; *error_message==0 && *p; ) {
|
for(p = spec; *error_message==0 && *p; ) {
|
||||||
if(*p == '|') {
|
if(*p == '|') {
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case 0: /* mime type */
|
case 0: /* type */
|
||||||
if(p-spec == 0)
|
if(!local__parse_type_(spec, p-spec, &obj->data.picture))
|
||||||
*error_message = error_messages[7];
|
*error_message = error_messages[7];
|
||||||
|
break;
|
||||||
|
case 1: /* mime type */
|
||||||
|
if(p-spec == 0)
|
||||||
|
*error_message = error_messages[8];
|
||||||
else if(0 == (q = local__strndup_(spec, p-spec)))
|
else if(0 == (q = local__strndup_(spec, p-spec)))
|
||||||
*error_message = error_messages[0];
|
*error_message = error_messages[0];
|
||||||
else if(!FLAC__metadata_object_picture_set_mime_type(obj, q, /*copy=*/false))
|
else if(!FLAC__metadata_object_picture_set_mime_type(obj, q, /*copy=*/false))
|
||||||
*error_message = error_messages[0];
|
*error_message = error_messages[0];
|
||||||
break;
|
break;
|
||||||
case 1: /* description */
|
case 2: /* description */
|
||||||
if(0 == (q = local__strndup_(spec, p-spec)))
|
if(0 == (q = local__strndup_(spec, p-spec)))
|
||||||
*error_message = error_messages[0];
|
*error_message = error_messages[0];
|
||||||
else if(!FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*)q, /*copy=*/false))
|
else if(!FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*)q, /*copy=*/false))
|
||||||
*error_message = error_messages[0];
|
*error_message = error_messages[0];
|
||||||
break;
|
break;
|
||||||
case 2: /* resolution/color (e.g. [300x300x16[/1234]] */
|
case 3: /* resolution/color (e.g. [300x300x16[/1234]] */
|
||||||
if(!local__parse_resolution_(spec, p-spec, &obj->data.picture))
|
if(!local__parse_resolution_(spec, p-spec, &obj->data.picture))
|
||||||
*error_message = error_messages[2];
|
*error_message = error_messages[2];
|
||||||
break;
|
break;
|
||||||
|
@ -287,7 +318,7 @@ FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, con
|
||||||
}
|
}
|
||||||
/* parse filename, read file, try to extract resolution/color info if needed */
|
/* parse filename, read file, try to extract resolution/color info if needed */
|
||||||
if(*error_message == 0) {
|
if(*error_message == 0) {
|
||||||
if(state != 3)
|
if(state != 4)
|
||||||
*error_message = error_messages[1];
|
*error_message = error_messages[1];
|
||||||
else { /* 'spec' points to filename/URL */
|
else { /* 'spec' points to filename/URL */
|
||||||
if(0 == strcmp(obj->data.picture.mime_type, "-->")) { /* magic MIME type means URL */
|
if(0 == strcmp(obj->data.picture.mime_type, "-->")) { /* magic MIME type means URL */
|
||||||
|
@ -328,6 +359,18 @@ FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(*error_message == 0) {
|
||||||
|
if(
|
||||||
|
obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD &&
|
||||||
|
(
|
||||||
|
(strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) ||
|
||||||
|
obj->data.picture.width != 32 ||
|
||||||
|
obj->data.picture.height != 32
|
||||||
|
)
|
||||||
|
)
|
||||||
|
*error_message = error_messages[9];
|
||||||
|
}
|
||||||
|
|
||||||
if(*error_message && obj) {
|
if(*error_message && obj) {
|
||||||
FLAC__metadata_object_delete(obj);
|
FLAC__metadata_object_delete(obj);
|
||||||
obj = 0;
|
obj = 0;
|
||||||
|
|
|
@ -32,23 +32,24 @@ typedef struct {
|
||||||
FLAC__uint32 height;
|
FLAC__uint32 height;
|
||||||
FLAC__uint32 depth;
|
FLAC__uint32 depth;
|
||||||
FLAC__uint32 colors;
|
FLAC__uint32 colors;
|
||||||
|
FLAC__StreamMetadata_Picture_Type type;
|
||||||
} PictureFile;
|
} PictureFile;
|
||||||
|
|
||||||
PictureFile picturefiles[] = {
|
PictureFile picturefiles[] = {
|
||||||
{ "0.gif", "image/gif" , "", 24, 24, 24, 2 },
|
{ "0.gif", "image/gif" , "", 24, 24, 24, 2, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "1.gif", "image/gif" , "", 12, 8, 24, 256 },
|
{ "1.gif", "image/gif" , "", 12, 8, 24, 256, FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER },
|
||||||
{ "2.gif", "image/gif" , "", 16, 14, 24, 128 },
|
{ "2.gif", "image/gif" , "", 16, 14, 24, 128, FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER },
|
||||||
{ "0.jpg", "image/jpeg", "", 30, 20, 8, 0 },
|
{ "0.jpg", "image/jpeg", "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "4.jpg", "image/jpeg", "", 31, 47, 24, 0 },
|
{ "4.jpg", "image/jpeg", "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "0.png", "image/png" , "", 30, 20, 8, 0 },
|
{ "0.png", "image/png" , "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "1.png", "image/png" , "", 30, 20, 8, 0 },
|
{ "1.png", "image/png" , "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "2.png", "image/png" , "", 30, 20, 24, 7 },
|
{ "2.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "3.png", "image/png" , "", 30, 20, 24, 7 },
|
{ "3.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "4.png", "image/png" , "", 31, 47, 24, 0 },
|
{ "4.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "5.png", "image/png" , "", 31, 47, 24, 0 },
|
{ "5.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "6.png", "image/png" , "", 31, 47, 24, 23 },
|
{ "6.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "7.png", "image/png" , "", 31, 47, 24, 23 },
|
{ "7.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
|
||||||
{ "8.png", "image/png" , "", 32, 32, 32, 0 }
|
{ "8.png", "image/png" , "", 32, 32, 32, 0, 999 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static FLAC__bool debug_ = false;
|
static FLAC__bool debug_ = false;
|
||||||
|
@ -68,13 +69,16 @@ static FLAC__bool test_one_picture(const char *prefix, const PictureFile *pf, co
|
||||||
FLAC__StreamMetadata *obj;
|
FLAC__StreamMetadata *obj;
|
||||||
const char *error;
|
const char *error;
|
||||||
char s[4096];
|
char s[4096];
|
||||||
snprintf(s, sizeof(s)-1, "%s|%s|%s|%s/%s", pf->mime_type, pf->description, res, prefix, pf->path);
|
snprintf(s, sizeof(s)-1, "%u|%s|%s|%s|%s/%s", (unsigned)pf->type, pf->mime_type, pf->description, res, prefix, pf->path);
|
||||||
|
|
||||||
printf("testing grabbag__picture_parse_specification(\"%s\")... ", s);
|
printf("testing grabbag__picture_parse_specification(\"%s\")... ", s);
|
||||||
if(0 == (obj = grabbag__picture_parse_specification(s, &error)))
|
if(0 == (obj = grabbag__picture_parse_specification(s, &error)))
|
||||||
return failed_(error);
|
return failed_(error);
|
||||||
if(debug_) {
|
if(debug_) {
|
||||||
printf("\nmime_type=%s\ndescription=%s\nwidth=%u\nheight=%u\ndepth=%u\ncolors=%u\ndata_length=%u\n",
|
printf("\ntype=%u (%s)\nmime_type=%s\ndescription=%s\nwidth=%u\nheight=%u\ndepth=%u\ncolors=%u\ndata_length=%u\n",
|
||||||
|
obj->data.picture.type,
|
||||||
|
obj->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED?
|
||||||
|
FLAC__StreamMetadata_Picture_TypeString[obj->data.picture.type] : "UNDEFINED",
|
||||||
obj->data.picture.mime_type,
|
obj->data.picture.mime_type,
|
||||||
obj->data.picture.description,
|
obj->data.picture.description,
|
||||||
obj->data.picture.width,
|
obj->data.picture.width,
|
||||||
|
@ -84,6 +88,8 @@ static FLAC__bool test_one_picture(const char *prefix, const PictureFile *pf, co
|
||||||
obj->data.picture.data_length
|
obj->data.picture.data_length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if(obj->data.picture.type != pf->type)
|
||||||
|
return failed_("picture type mismatch");
|
||||||
if(strcmp(obj->data.picture.mime_type, pf->mime_type))
|
if(strcmp(obj->data.picture.mime_type, pf->mime_type))
|
||||||
return failed_("picture MIME type mismatch");
|
return failed_("picture MIME type mismatch");
|
||||||
if(strcmp((const char *)obj->data.picture.description, (const char *)pf->description))
|
if(strcmp((const char *)obj->data.picture.description, (const char *)pf->description))
|
||||||
|
@ -116,49 +122,55 @@ static FLAC__bool do_picture(const char *prefix)
|
||||||
printf("OK (failed as expected, error: %s)\n", error);
|
printf("OK (failed as expected, error: %s)\n", error);
|
||||||
|
|
||||||
/* invalid spec: no filename */
|
/* invalid spec: no filename */
|
||||||
printf("testing grabbag__picture_parse_specification(\"|||\")... ");
|
printf("testing grabbag__picture_parse_specification(\"||||\")... ");
|
||||||
if(0 != (obj = grabbag__picture_parse_specification("|||", &error)))
|
if(0 != (obj = grabbag__picture_parse_specification("||||", &error)))
|
||||||
return failed_("expected error, got object");
|
return failed_("expected error, got object");
|
||||||
printf("OK (failed as expected: %s)\n", error);
|
printf("OK (failed as expected: %s)\n", error);
|
||||||
|
|
||||||
/* invalid spec: no filename */
|
/* invalid spec: no filename */
|
||||||
printf("testing grabbag__picture_parse_specification(\"image/gif|||\")... ");
|
printf("testing grabbag__picture_parse_specification(\"|image/gif|||\")... ");
|
||||||
if(0 != (obj = grabbag__picture_parse_specification("image/gif|||", &error)))
|
if(0 != (obj = grabbag__picture_parse_specification("|image/gif|||", &error)))
|
||||||
return failed_("expected error, got object");
|
return failed_("expected error, got object");
|
||||||
printf("OK (failed as expected: %s)\n", error);
|
printf("OK (failed as expected: %s)\n", error);
|
||||||
|
|
||||||
/* invalid spec: bad resolution */
|
/* invalid spec: bad resolution */
|
||||||
printf("testing grabbag__picture_parse_specification(\"image/gif|desc|320|0.gif\")... ");
|
printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320|0.gif\")... ");
|
||||||
if(0 != (obj = grabbag__picture_parse_specification("image/gif|desc|320|0.gif", &error)))
|
if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320|0.gif", &error)))
|
||||||
return failed_("expected error, got object");
|
return failed_("expected error, got object");
|
||||||
printf("OK (failed as expected: %s)\n", error);
|
printf("OK (failed as expected: %s)\n", error);
|
||||||
|
|
||||||
/* invalid spec: bad resolution */
|
/* invalid spec: bad resolution */
|
||||||
printf("testing grabbag__picture_parse_specification(\"image/gif|desc|320x240|0.gif\")... ");
|
printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240|0.gif\")... ");
|
||||||
if(0 != (obj = grabbag__picture_parse_specification("image/gif|desc|320x240|0.gif", &error)))
|
if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240|0.gif", &error)))
|
||||||
return failed_("expected error, got object");
|
return failed_("expected error, got object");
|
||||||
printf("OK (failed as expected: %s)\n", error);
|
printf("OK (failed as expected: %s)\n", error);
|
||||||
|
|
||||||
/* invalid spec: no filename */
|
/* invalid spec: no filename */
|
||||||
printf("testing grabbag__picture_parse_specification(\"image/gif|desc|320x240x9|\")... ");
|
printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9|\")... ");
|
||||||
if(0 != (obj = grabbag__picture_parse_specification("image/gif|desc|320x240x9|", &error)))
|
if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9|", &error)))
|
||||||
return failed_("expected error, got object");
|
return failed_("expected error, got object");
|
||||||
printf("OK (failed as expected: %s)\n", error);
|
printf("OK (failed as expected: %s)\n", error);
|
||||||
|
|
||||||
/* invalid spec: #colors exceeds color depth */
|
/* invalid spec: #colors exceeds color depth */
|
||||||
printf("testing grabbag__picture_parse_specification(\"image/gif|desc|320x240x9/2345|0.gif\")... ");
|
printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9/2345|0.gif\")... ");
|
||||||
if(0 != (obj = grabbag__picture_parse_specification("image/gif|desc|320x240x9/2345|0.gif", &error)))
|
if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9/2345|0.gif", &error)))
|
||||||
|
return failed_("expected error, got object");
|
||||||
|
printf("OK (failed as expected: %s)\n", error);
|
||||||
|
|
||||||
|
/* invalid spec: standard icon has to be 32x32 PNG */
|
||||||
|
printf("testing grabbag__picture_parse_specification(\"1|-->|desc|32x24x9|0.gif\")... ");
|
||||||
|
if(0 != (obj = grabbag__picture_parse_specification("1|-->|desc|32x24x9|0.gif", &error)))
|
||||||
return failed_("expected error, got object");
|
return failed_("expected error, got object");
|
||||||
printf("OK (failed as expected: %s)\n", error);
|
printf("OK (failed as expected: %s)\n", error);
|
||||||
|
|
||||||
/* invalid spec: need resolution for linked URL */
|
/* invalid spec: need resolution for linked URL */
|
||||||
printf("testing grabbag__picture_parse_specification(\"-->|desc||http://blah.blah.blah/z.gif\")... ");
|
printf("testing grabbag__picture_parse_specification(\"|-->|desc||http://blah.blah.blah/z.gif\")... ");
|
||||||
if(0 != (obj = grabbag__picture_parse_specification("-->|desc||http://blah.blah.blah/z.gif", &error)))
|
if(0 != (obj = grabbag__picture_parse_specification("|-->|desc||http://blah.blah.blah/z.gif", &error)))
|
||||||
return failed_("expected error, got object");
|
return failed_("expected error, got object");
|
||||||
printf("OK (failed as expected: %s)\n", error);
|
printf("OK (failed as expected: %s)\n", error);
|
||||||
|
|
||||||
printf("testing grabbag__picture_parse_specification(\"-->|desc|320x240x9|http://blah.blah.blah/z.gif\")... ");
|
printf("testing grabbag__picture_parse_specification(\"|-->|desc|320x240x9|http://blah.blah.blah/z.gif\")... ");
|
||||||
if(0 == (obj = grabbag__picture_parse_specification("-->|desc|320x240x9|http://blah.blah.blah/z.gif", &error)))
|
if(0 == (obj = grabbag__picture_parse_specification("|-->|desc|320x240x9|http://blah.blah.blah/z.gif", &error)))
|
||||||
return failed_(error);
|
return failed_(error);
|
||||||
printf("OK\n");
|
printf("OK\n");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue