]> git.imager.perl.org - imager.git/blobdiff - imexif.c
on't check if the unsigned size supplied to im_set_image_file_limits() is negative
[imager.git] / imexif.c
index 9e562f7f4f84ca07cef41bd9a26f8d7729a1eb1d..4bdf386aa2a677bcdbef60c19a2a5cd23c8def6d 100644 (file)
--- a/imexif.c
+++ b/imexif.c
@@ -1,6 +1,9 @@
+#include "imager.h"
 #include "imexif.h"
 #include <stdlib.h>
 #include <float.h>
 #include "imexif.h"
 #include <stdlib.h>
 #include <float.h>
+#include <string.h>
+#include <stdio.h>
 
 /*
 =head1 NAME
 
 /*
 =head1 NAME
@@ -9,7 +12,7 @@ imexif.c - EXIF support for Imager
 
 =head1 SYNOPSIS
 
 
 =head1 SYNOPSIS
 
-  if (i_int_decode_exif(im, app1data, app1datasize)) {
+  if (im_decode_exif(im, app1data, app1datasize)) {
     // exif block seen
   }
 
     // exif block seen
   }
 
@@ -264,12 +267,12 @@ intended to be called from outside of Imager.
 
 =over
 
 
 =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<data_base> for C<data_size> bytes will be scanned for
+EXIF data.
 
 Any data found will be used to set tags in the supplied image.
 
 
 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.
 
 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
 */
 
 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;
   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"));
 
   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;
       /* 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;
 
       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) {
 
   /* 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;
   }
 
     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) {
   /* 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;
   }
 
     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) {
       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;
       }
        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) {
   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;
   }
   
   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) {
 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;
   }
   
   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) {
   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) {
   }
   
   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;
   }
 
   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) {
 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;
   }
 
   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)) {
       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;
       }
     }
        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;
     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;
       }
     }
        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];
        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)) {
          *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, " ");
              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];
        }
        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)) {
          *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, " ");
              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;
       }
        }
        break;
       }
@@ -1352,7 +1380,7 @@ copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count) {
          }
        }
        if (found) {
          }
        }
        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;
       }
        }
        break;
       }
@@ -1384,8 +1412,11 @@ Retrieve a 16 bit unsigned integer from offset.
 
 static unsigned
 tiff_get16(imtiff *tiff, unsigned long 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];
 
   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) {
 
 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] 
 
   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;
 
 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];
 
   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;
 
 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] 
 
   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;
 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);
 
   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;
 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);
 
   numer = tiff_get32s(tiff, offset);
   denom = tiff_get32s(tiff, offset+4);
@@ -1554,7 +1600,7 @@ http://www.exif.org/
 
 =head1 AUTHOR
 
 
 =head1 AUTHOR
 
-Tony Cook <tony@imager.perl.org>
+Tony Cook <tonyc@cpan.org>
 
 =head1 REVISION
 
 
 =head1 REVISION