X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/41cdb34705baec32fa41aad3d6d2c69d0fb7ea8a..e1c0692925:/imexif.c diff --git a/imexif.c b/imexif.c index e3950948..4bdf386a 100644 --- a/imexif.c +++ b/imexif.c @@ -1,6 +1,9 @@ +#include "imager.h" #include "imexif.h" #include #include +#include +#include /* =head1 NAME @@ -9,7 +12,7 @@ imexif.c - EXIF support for Imager =head1 SYNOPSIS - if (i_int_decode_exif(im, app1data, app1datasize)) { + if (im_decode_exif(im, app1data, app1datasize)) { // exif block seen } @@ -229,8 +232,10 @@ static int tiff_init(imtiff *tiff, unsigned char *base, size_t length); static int tiff_load_ifd(imtiff *tiff, unsigned long offset); static void tiff_final(imtiff *tiff); static void tiff_clear_ifd(imtiff *tiff); +#if 0 /* currently unused, but that may change */ static int tiff_get_bytes(imtiff *tiff, unsigned char *to, size_t offset, size_t count); +#endif static int tiff_get_tag_double(imtiff *, int index, double *result); static int tiff_get_tag_int(imtiff *, int index, int *result); static unsigned tiff_get16(imtiff *, unsigned long offset); @@ -262,12 +267,12 @@ intended to be called from outside of Imager. =over -=item i_int_decode_exit +=item im_decode_exif -i_int_decode_exif(im, data_base, data_size); +im_decode_exif(im, data_base, data_size); -The data from data_base for data_size bytes will be scanned for EXIF -data. +The data from C for C bytes will be scanned for +EXIF data. Any data found will be used to set tags in the supplied image. @@ -275,23 +280,16 @@ The intent is that invalid EXIF data will simply fail to set tags, and write to the log. In no case should this code exit when supplied invalid data. -Returns true if an Exif header was seen. +Returns true if an EXIF header was seen. +=cut */ int -i_int_decode_exif(i_img *im, unsigned char *data, size_t length) { +im_decode_exif(i_img *im, unsigned char *data, size_t length) { imtiff tiff; unsigned long exif_ifd_offset = 0; unsigned long gps_ifd_offset = 0; - /* basic checks - must start with "Exif\0\0" */ - - if (length < 6 || memcmp(data, "Exif\0\0", 6) != 0) { - return 0; - } - - data += 6; - length -= 6; if (!tiff_init(&tiff, data, length)) { mm_log((2, "Exif header found, but no valid TIFF header\n")); @@ -702,7 +700,7 @@ save_exif_ifd_tags(i_img *im, imtiff *tiff) { /* find the actual end of the string */ while (i < entry->size && user_comment[i]) ++i; - i_tags_add(&im->tags, "exif_user_comment", 0, user_comment, i, 0); + i_tags_set(&im->tags, "exif_user_comment", user_comment, i); myfree(user_comment); break; @@ -915,7 +913,7 @@ tiff_load_ifd(imtiff *tiff, unsigned long offset) { /* rough check count + 1 entry + next offset */ if (offset + (2+12+4) > tiff->size) { - mm_log((2, "offset %uld beyond end off Exif block")); + mm_log((2, "offset %lu beyond end off Exif block", offset)); return 0; } @@ -924,7 +922,7 @@ tiff_load_ifd(imtiff *tiff, unsigned long offset) { /* check we can fit the whole thing */ ifd_size = 2 + count * 12 + 4; /* count + count entries + next offset */ if (offset + ifd_size > tiff->size) { - mm_log((2, "offset %uld beyond end off Exif block")); + mm_log((2, "offset %lu beyond end off Exif block", offset)); return 0; } @@ -936,10 +934,11 @@ tiff_load_ifd(imtiff *tiff, unsigned long offset) { entry->tag = tiff_get16(tiff, base); entry->type = tiff_get16(tiff, base+2); entry->count = tiff_get32(tiff, base+4); - if (entry->type >= 1 || entry->type <= ift_last) { + if (entry->type >= 1 && entry->type <= ift_last) { entry->item_size = type_sizes[entry->type]; entry->size = entry->item_size * entry->count; if (entry->size / entry->item_size != entry->count) { + myfree(entries); mm_log((1, "Integer overflow calculating tag data size processing EXIF block\n")); return 0; } @@ -1013,7 +1012,8 @@ tiff_get_tag_double_array(imtiff *tiff, int index, double *result, ifd_entry *entry; unsigned long offset; if (index < 0 || index >= tiff->ifd_size) { - m_fatal(3, "tiff_get_tag_double_array() tag index out of range"); + mm_log((3, "tiff_get_tag_double_array() tag index out of range")); + return 0; } entry = tiff->ifd + index; @@ -1077,7 +1077,8 @@ static int tiff_get_tag_double(imtiff *tiff, int index, double *result) { ifd_entry *entry; if (index < 0 || index >= tiff->ifd_size) { - m_fatal(3, "tiff_get_tag_double() index out of range"); + mm_log((3, "tiff_get_tag_double() index out of range")); + return 0; } entry = tiff->ifd + index; @@ -1108,12 +1109,14 @@ tiff_get_tag_int_array(imtiff *tiff, int index, int *result, int array_index) { ifd_entry *entry; unsigned long offset; if (index < 0 || index >= tiff->ifd_size) { - m_fatal(3, "tiff_get_tag_int_array() tag index out of range"); + mm_log((3, "tiff_get_tag_int_array() tag index out of range")); + return 0; } entry = tiff->ifd + index; if (array_index < 0 || array_index >= entry->count) { - m_fatal(3, "tiff_get_tag_int_array() array index out of range"); + mm_log((3, "tiff_get_tag_int_array() array index out of range")); + return 0; } offset = entry->offset + array_index * entry->item_size; @@ -1163,7 +1166,8 @@ static int tiff_get_tag_int(imtiff *tiff, int index, int *result) { ifd_entry *entry; if (index < 0 || index >= tiff->ifd_size) { - m_fatal(3, "tiff_get_tag_int() index out of range"); + mm_log((3, "tiff_get_tag_int() index out of range")); + return 0; } entry = tiff->ifd + index; @@ -1204,7 +1208,7 @@ copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) { int value; if (map[i].tag == entry->tag && tiff_get_tag_int(tiff, tag_index, &value)) { - i_tags_addn(&im->tags, map[i].name, 0, value); + i_tags_setn(&im->tags, map[i].name, value); break; } } @@ -1255,8 +1259,8 @@ copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) { for (i = 0; i < map_count; ++i) { if (map[i].tag == entry->tag) { int len = entry->type == ift_ascii ? entry->size - 1 : entry->size; - i_tags_add(&im->tags, map[i].name, 0, - (char const *)(tiff->base + entry->offset), len, 0); + i_tags_set(&im->tags, map[i].name, + (char const *)(tiff->base + entry->offset), len); break; } } @@ -1287,32 +1291,58 @@ copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) { if (entry->type == ift_rational || entry->type == ift_srational) { double value; char workstr[MAX_ARRAY_STRING]; + size_t len = 0, item_len; *workstr = '\0'; for (j = 0; j < entry->count; ++j) { if (!tiff_get_tag_double_array(tiff, tag_index, &value, j)) { - m_fatal(3, "unexpected failure from tiff_get_tag_double_array(..., %d, ..., %d)\n", tag_index, j); + mm_log((3, "unexpected failure from tiff_get_tag_double_array(..., %d, ..., %d)\n", tag_index, j)); + return; + } + if (len >= sizeof(workstr) - 1) { + mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag)); + return; } - if (j) + if (j) { strcat(workstr, " "); - sprintf(workstr + strlen(workstr), "%.6g", value); + ++len; + } +#ifdef IMAGER_SNPRINTF + item_len = snprintf(workstr + len, sizeof(workstr)-len, "%.6g", value); +#else + item_len = sprintf(workstr + len, "%.6g", value); +#endif + len += item_len; } - i_tags_add(&im->tags, map[i].name, 0, workstr, -1, 0); + i_tags_set(&im->tags, map[i].name, workstr, -1); } else if (entry->type == ift_short || entry->type == ift_long || entry->type == ift_sshort || entry->type == ift_slong || entry->type == ift_byte) { int value; char workstr[MAX_ARRAY_STRING]; + size_t len = 0, item_len; *workstr = '\0'; for (j = 0; j < entry->count; ++j) { if (!tiff_get_tag_int_array(tiff, tag_index, &value, j)) { - m_fatal(3, "unexpected failure from tiff_get_tag_int_array(..., %d, ..., %d)\n", tag_index, j); + mm_log((3, "unexpected failure from tiff_get_tag_int_array(..., %d, ..., %d)\n", tag_index, j)); + return; + } + if (len >= sizeof(workstr) - 1) { + mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag)); + return; } - if (j) + if (j) { strcat(workstr, " "); - sprintf(workstr + strlen(workstr), "%d", value); + ++len; + } +#ifdef IMAGER_SNPRINTF + item_len = snprintf(workstr + len, sizeof(workstr) - len, "%d", value); +#else + item_len = sprintf(workstr + len, "%d", value); +#endif + len += item_len; } - i_tags_add(&im->tags, map[i].name, 0, workstr, -1, 0); + i_tags_set(&im->tags, map[i].name, workstr, -1); } break; } @@ -1350,7 +1380,7 @@ copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count) { } } if (found) { - i_tags_add(&im->tags, map[i].name, 0, found->name, -1, 0); + i_tags_set(&im->tags, map[i].name, found->name, -1); } break; } @@ -1382,8 +1412,11 @@ Retrieve a 16 bit unsigned integer from offset. static unsigned tiff_get16(imtiff *tiff, unsigned long offset) { - if (offset + 2 > tiff->size) - m_fatal(3, "attempt to get16 at %uld in %uld image", offset, tiff->size); + if (offset + 2 > tiff->size) { + mm_log((3, "attempt to get16 at %lu in %lu image", offset, + (unsigned long)tiff->size)); + return 0; + } if (tiff->type == tt_intel) return tiff->base[offset] + 0x100 * tiff->base[offset+1]; @@ -1401,8 +1434,11 @@ Retrieve a 32-bit unsigned integer from offset. static unsigned tiff_get32(imtiff *tiff, unsigned long offset) { - if (offset + 4 > tiff->size) - m_fatal(3, "attempt to get16 at %uld in %uld image", offset, tiff->size); + if (offset + 4 > tiff->size) { + mm_log((3, "attempt to get16 at %lu in %lu image", offset, + (unsigned long)tiff->size)); + return 0; + } if (tiff->type == tt_intel) return tiff->base[offset] + 0x100 * tiff->base[offset+1] @@ -1412,6 +1448,8 @@ tiff_get32(imtiff *tiff, unsigned long offset) { + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset]; } +#if 0 /* currently unused, but that may change */ + /* =item tiff_get_bytes @@ -1434,6 +1472,8 @@ tiff_get_bytes(imtiff *tiff, unsigned char *data, size_t offset, return 1; } +#endif + /* =item tiff_get16s @@ -1446,8 +1486,11 @@ static int tiff_get16s(imtiff *tiff, unsigned long offset) { int result; - if (offset + 2 > tiff->size) - m_fatal(3, "attempt to get16 at %uld in %uld image", offset, tiff->size); + if (offset + 2 > tiff->size) { + mm_log((3, "attempt to get16 at %lu in %lu image", offset, + (unsigned long)tiff->size)); + return 0; + } if (tiff->type == tt_intel) result = tiff->base[offset] + 0x100 * tiff->base[offset+1]; @@ -1472,8 +1515,11 @@ static int tiff_get32s(imtiff *tiff, unsigned long offset) { unsigned work; - if (offset + 4 > tiff->size) - m_fatal(3, "attempt to get16 at %uld in %uld image", offset, tiff->size); + if (offset + 4 > tiff->size) { + mm_log((3, "attempt to get16 at %lu in %lu image", offset, + (unsigned long)tiff->size)); + return 0; + } if (tiff->type == tt_intel) work = tiff->base[offset] + 0x100 * tiff->base[offset+1] @@ -1500,8 +1546,11 @@ Retrieve an unsigned rational from offset. static double tiff_get_rat(imtiff *tiff, unsigned long offset) { unsigned long numer, denom; - if (offset + 8 > tiff->size) - m_fatal(3, "attempt to get_rat at %lu in %lu image", offset, tiff->size); + if (offset + 8 > tiff->size) { + mm_log((3, "attempt to get_rat at %lu in %lu image", offset, + (unsigned long)tiff->size)); + return 0; + } numer = tiff_get32(tiff, offset); denom = tiff_get32(tiff, offset+4); @@ -1524,8 +1573,11 @@ Retrieve an signed rational from offset. static double tiff_get_rats(imtiff *tiff, unsigned long offset) { long numer, denom; - if (offset + 8 > tiff->size) - m_fatal(3, "attempt to get_rat at %lu in %lu image", offset, tiff->size); + if (offset + 8 > tiff->size) { + mm_log((3, "attempt to get_rat at %lu in %lu image", offset, + (unsigned long)tiff->size)); + return 0; + } numer = tiff_get32s(tiff, offset); denom = tiff_get32s(tiff, offset+4); @@ -1548,7 +1600,7 @@ http://www.exif.org/ =head1 AUTHOR -Tony Cook +Tony Cook =head1 REVISION