From 68cc564c9bd327743896cded4a49aad7af0b1d37 Mon Sep 17 00:00:00 2001 From: Teruaki Kawashima Date: Sat, 22 Jan 2011 13:41:53 +0000 Subject: FS#11819: image viewer: use magick number in file to determine image type. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29110 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/imageviewer/image_decoder.c | 68 +++++++++++++++++++++++++++----- apps/plugins/imageviewer/image_decoder.h | 5 ++- apps/plugins/imageviewer/imageviewer.c | 14 +++++-- 3 files changed, 72 insertions(+), 15 deletions(-) diff --git a/apps/plugins/imageviewer/image_decoder.c b/apps/plugins/imageviewer/image_decoder.c index 553632e559..0088eb4873 100644 --- a/apps/plugins/imageviewer/image_decoder.c +++ b/apps/plugins/imageviewer/image_decoder.c @@ -32,8 +32,14 @@ static const char *decoder_names[MAX_IMAGE_TYPES] = { #endif }; -/* check file type by extention */ -enum image_type get_image_type(const char *name) +/* Check file type by magic number or file extension + * + * If the file contains magic number, use it to determine image type. + * Otherwise use file extension to determine image type. + * If the file contains magic number and file extension is not correct, + * informs user that something is wrong. + */ +enum image_type get_image_type(const char *name, bool quiet) { static const struct { char *ext; @@ -48,18 +54,60 @@ enum image_type get_image_type(const char *name) { ".ppm", IMAGE_PPM }, #endif }; + static const struct { + char *magic; /* magic number */ + int length; /* length of the magic number */ + enum image_type type; + } magic_list[] = { + { "BM", 2, IMAGE_BMP }, + { "\xff\xd8\xff\xe0", 4, IMAGE_JPEG }, + { "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8, IMAGE_PNG }, +#ifdef HAVE_LCD_COLOR + { "P3", 2, IMAGE_PPM }, + { "P6", 2, IMAGE_PPM }, +#endif + }; + enum image_type type = IMAGE_UNKNOWN; const char *ext = rb->strrchr(name, '.'); - int i; - if (!ext) - return IMAGE_UNKNOWN; + int i, fd; + char buf[12]; + + /* check file extention */ + if (ext) + { + for (i = 0; i < (int)ARRAYLEN(ext_list); i++) + { + if (!rb->strcasecmp(ext, ext_list[i].ext)) + { + type = ext_list[i].type; + break; + } + } + } - for (i = 0; i < (int)ARRAYLEN(ext_list); i++) + /* check magic value in the file */ + fd = rb->open(name, O_RDONLY); + if (fd >= 0) { - if (!rb->strcasecmp(ext, ext_list[i].ext)) - return ext_list[i].type; + rb->memset(buf, 0, sizeof buf); + rb->read(fd, buf, sizeof buf); + rb->close(fd); + for (i = 0; i < (int)ARRAYLEN(magic_list); i++) + { + if (!rb->memcmp(buf, magic_list[i].magic, magic_list[i].length)) + { + if (!quiet && type != magic_list[i].type) + { + /* file extension is wrong. */ + rb->splashf(HZ*1, "Note: File extension is not correct"); + } + type = magic_list[i].type; + break; + } + } } - return IMAGE_UNKNOWN; + return type; } static void *decoder_handle = NULL; @@ -79,7 +127,7 @@ const struct image_decoder *load_decoder(struct loader_info *loader_info) release_decoder(); name = decoder_names[loader_info->type]; - rb->snprintf(filename, MAX_PATH, VIEWERS_DIR "/%s.ovl", name); + rb->snprintf(filename, MAX_PATH, "/rockbox/rocks/viewers" "/%s.ovl", name); /* load decoder to the buffer. */ decoder_handle = rb->lc_open(filename, loader_info->buffer, loader_info->size); diff --git a/apps/plugins/imageviewer/image_decoder.h b/apps/plugins/imageviewer/image_decoder.h index 1ccf9cabf2..3267d2af6e 100644 --- a/apps/plugins/imageviewer/image_decoder.h +++ b/apps/plugins/imageviewer/image_decoder.h @@ -42,8 +42,11 @@ struct loader_info { size_t size; }; -enum image_type get_image_type(const char *name); +/* Check file type by magic number or file extension */ +enum image_type get_image_type(const char *name, bool quiet); +/* Load image decoder */ const struct image_decoder *load_decoder(struct loader_info *loader_info); +/* Release the loaded decoder */ void release_decoder(void); #endif /* _IMAGE_DECODER_H */ diff --git a/apps/plugins/imageviewer/imageviewer.c b/apps/plugins/imageviewer/imageviewer.c index 37610b7bf6..6cc2192cb9 100644 --- a/apps/plugins/imageviewer/imageviewer.c +++ b/apps/plugins/imageviewer/imageviewer.c @@ -148,8 +148,8 @@ static void get_pic_list(void) for (i = 0; i < tree->filesindir && buf_size > sizeof(char**); i++) { - if (!(dircache[i].attr & ATTR_DIRECTORY) - && get_image_type(dircache[i].name) != IMAGE_UNKNOWN) + /* Add all files. Non-image files will be filtered out while loading. */ + if (!(dircache[i].attr & ATTR_DIRECTORY)) { file_pt[entries] = dircache[i].name; /* Set Selected File. */ @@ -742,7 +742,13 @@ static int load_and_show(char* filename, struct image_info *info) rb->lcd_clear_display(); - status = get_image_type(filename); + /* suppress warning while running slideshow */ + status = get_image_type(filename, iv_api.running_slideshow); + if (status == IMAGE_UNKNOWN) { + /* file isn't supported image file, skip this. */ + file_pt[curfile] = NULL; + return change_filename(direction); + } if (image_type != status) /* type of image is changed, load decoder. */ { struct loader_info loader_info = { @@ -914,7 +920,7 @@ enum plugin_status plugin_start(const void* parameter) if(!parameter) return PLUGIN_ERROR; rb->strcpy(np_file, parameter); - if (get_image_type(np_file) == IMAGE_UNKNOWN) + if (get_image_type(np_file, false) == IMAGE_UNKNOWN) { rb->splash(HZ*2, "Unsupported file"); return PLUGIN_ERROR; -- cgit v1.2.3