X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/e4bf9335cc2b884d905065b18d37f2014035ae4c..748bfdfc4d4f60631ff5d06f2f954a36f2ea8ee5:/imexif.c?ds=sidebyside diff --git a/imexif.c b/imexif.c index 9e562f7f..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 } @@ -264,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. @@ -277,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")); @@ -704,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; @@ -917,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; } @@ -926,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; } @@ -942,6 +938,7 @@ tiff_load_ifd(imtiff *tiff, unsigned long offset) { 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; } @@ -1015,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) { - i_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; @@ -1079,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) { - i_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; @@ -1110,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) { - i_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) { - i_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; @@ -1165,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) { - i_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; @@ -1206,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; } } @@ -1257,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; } } @@ -1289,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)) { - i_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)) { - i_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; } @@ -1352,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; } @@ -1384,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) - i_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]; @@ -1403,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) - i_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] @@ -1452,8 +1486,11 @@ static int tiff_get16s(imtiff *tiff, unsigned long offset) { int result; - if (offset + 2 > tiff->size) - i_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]; @@ -1478,8 +1515,11 @@ static int tiff_get32s(imtiff *tiff, unsigned long offset) { unsigned work; - if (offset + 4 > tiff->size) - i_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] @@ -1506,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) - i_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); @@ -1530,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) - i_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); @@ -1554,7 +1600,7 @@ http://www.exif.org/ =head1 AUTHOR -Tony Cook +Tony Cook =head1 REVISION