]> git.imager.perl.org - imager.git/blobdiff - png.c
the image data offset wasn't validated when reading a 240bit bmp
[imager.git] / png.c
diff --git a/png.c b/png.c
index 83cea1bced1c0e308ab349212952cf50e60ceec6..5ea25ce08c047fd10c9e252cd0c5f316ec6eba2e 100644 (file)
--- a/png.c
+++ b/png.c
@@ -1,5 +1,5 @@
 #include "iolayer.h"
-#include "image.h"
+#include "imageri.h"
 #include "png.h"
 
 /* Check to see if a file is a PNG file using png_sig_cmp().  png_sig_cmp()
 /* this is a way to get number of channels from color space 
  * Color code to channel number */
 
-int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA];
+static int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA];
 
 #define PNG_BYTES_TO_CHECK 4
  
 
 
-
-
-
-
-
-
-/*
-  png_set_read_fn(png_structp read_ptr, voidp read_io_ptr, png_rw_ptr read_data_fn)
-  png_set_write_fn(png_structp write_ptr, voidp write_io_ptr, png_rw_ptr write_data_fn,
-  png_flush_ptr output_flush_fn);
-  voidp read_io_ptr = png_get_io_ptr(read_ptr);
-  voidp write_io_ptr = png_get_io_ptr(write_ptr);
-*/
-
-
-
-
 static void
 wiol_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
   io_glue *ig = (io_glue *)png_ptr->io_ptr;
@@ -70,165 +53,25 @@ wiol_flush_data(png_structp png_ptr) {
 }
 
 
+/* Check function demo 
+
 int
 check_if_png(char *file_name, FILE **fp) {
   char buf[PNG_BYTES_TO_CHECK];
-   
-  /* Open the prospective PNG file. */
   if ((*fp = fopen(file_name, "rb")) != NULL) return 0;
-   
-  /* Read in some of the signature bytes */
   if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) return 0;
-
-  /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
-     Return nonzero (true) if they match */
-
   return(!png_sig_cmp((png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
 }
-
-
-
-undef_int
-i_writepng(i_img *im, int fd) {
-  FILE *fp;
-  png_structp png_ptr;
-  png_infop info_ptr;
-  int width,height,y;
-  volatile int cspace,channels;
-  double xres, yres;
-  int aspect_only, have_res;
-  double offx, offy;
-  char offunit[20] = "pixel";
-
-  mm_log((1,"i_writepng(0x%x,fd %d)\n",im,fd));
-  
-  if ((fp = fdopen(fd,"w")) == NULL) {
-    mm_log((1,"can't fdopen.\n"));
-    exit(1);
-  }
-
-  height=im->ysize;
-  width=im->xsize;
-
-  channels=im->channels;
-
-  if (channels>2) { cspace=PNG_COLOR_TYPE_RGB; channels-=3; }
-  else { cspace=PNG_COLOR_TYPE_GRAY; channels--; }
-  
-  if (channels) cspace|=PNG_COLOR_MASK_ALPHA;
-  mm_log((1,"cspace=%d\n",cspace));
-
-  channels=im->channels;
-
-  /* Create and initialize the png_struct with the desired error handler
-   * functions.  If you want to use the default stderr and longjump method,
-   * you can supply NULL for the last three parameters.  We also check that
-   * the library version is compatible with the one used at compile time,
-   * in case we are using dynamically linked libraries.  REQUIRED.
-   */
-  
-  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
-  
-  if (png_ptr == NULL) {
-    fclose(fp);
-    return 0;
-  }
-  
-  /* Allocate/initialize the image information data.  REQUIRED */
-  info_ptr = png_create_info_struct(png_ptr);
-
-  if (info_ptr == NULL) {
-    fclose(fp);
-    png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
-    return(0);
-  }
-  
-  /* Set error handling.  REQUIRED if you aren't supplying your own
-   * error hadnling functions in the png_create_write_struct() call.
-   */
-  if (setjmp(png_ptr->jmpbuf)) {
-    /* If we get here, we had a problem reading the file */
-    fclose(fp);
-    png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
-    return(0);
-  }
-  
-  png_init_io(png_ptr, fp);
-
-  /* Set the image information here.  Width and height are up to 2^31,
-   * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
-   * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
-   * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
-   * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
-   * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
-   * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
-   */
-
-  png_set_IHDR(png_ptr, info_ptr, width, height, 8, cspace,
-              PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
-  have_res = 1;
-  if (i_tags_get_float(&im->tags, "i_xres", 0, &xres)) {
-    if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
-      ; /* nothing to do */
-    else
-      yres = xres;
-  }
-  else {
-    if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
-      xres = yres;
-    else
-      have_res = 0;
-  }
-  if (have_res) {
-    aspect_only = 0;
-    i_tags_get_int(&im->tags, "i_aspect_only", 0, &aspect_only);
-    xres /= 0.0254;
-    yres /= 0.0254;
-    png_set_pHYs(png_ptr, info_ptr, xres + 0.5, yres + 0.5, 
-                 aspect_only ? PNG_RESOLUTION_UNKNOWN : PNG_RESOLUTION_METER);
-  }
-
-  png_write_info(png_ptr, info_ptr);
-  if (!im->virtual && im->type == i_direct_type && im->bits == i_8_bits) {
-    for (y = 0; y < height; y++) 
-      png_write_row(png_ptr, (png_bytep) &(im->idata[channels*width*y]));
-  }
-  else {
-    unsigned char *data = mymalloc(im->xsize * im->channels);
-    if (data) {
-      for (y = 0; y < height; y++) {
-        i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
-        png_write_row(png_ptr, (png_bytep)data);
-      }
-      myfree(data);
-    }
-    else {
-      fclose(fp);
-      png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
-      return 0;
-    }
-  }
-  png_write_end(png_ptr, info_ptr);
-  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
-
-  fclose(fp);
-  return(1);
-}
-
-
+*/
 
 undef_int
 i_writepng_wiol(i_img *im, io_glue *ig) {
-  FILE *fp;
   png_structp png_ptr;
-  png_infop info_ptr;
+  png_infop info_ptr = NULL;
   int width,height,y;
   volatile int cspace,channels;
   double xres, yres;
   int aspect_only, have_res;
-  double offx, offy;
-  char offunit[20] = "pixel";
 
   io_glue_commit_types(ig);
   mm_log((1,"i_writepng(im %p ,ig %p)\n", im, ig));
@@ -262,7 +105,7 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
   info_ptr = png_create_info_struct(png_ptr);
 
   if (info_ptr == NULL) {
-    png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
     return 0;
   }
   
@@ -270,7 +113,7 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
    * error hadnling functions in the png_create_write_struct() call.
    */
   if (setjmp(png_ptr->jmpbuf)) {
-    png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
     return(0);
   }
   
@@ -319,23 +162,18 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
   }
   else {
     unsigned char *data = mymalloc(im->xsize * im->channels);
-    if (data) {
-      for (y = 0; y < height; y++) {
-        i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
-        png_write_row(png_ptr, (png_bytep)data);
-      }
-      myfree(data);
-    }
-    else {
-      fclose(fp);
-      png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
-      return 0;
+    for (y = 0; y < height; y++) {
+      i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
+      png_write_row(png_ptr, (png_bytep)data);
     }
+    myfree(data);
   }
 
   png_write_end(png_ptr, info_ptr);
 
-  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+  png_destroy_write_struct(&png_ptr, &info_ptr);
+
+  ig->closecb(ig);
 
   return(1);
 }
@@ -393,6 +231,12 @@ i_readpng_wiol(io_glue *ig, int length) {
 
   mm_log((1,"i_readpng_wiol: channels %d\n",channels));
 
+  if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
+    mm_log((1, "i_readpnm: image size exceeds limits\n"));
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    return NULL;
+  }
+
   png_set_strip_16(png_ptr);
   png_set_packing(png_ptr);
   if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
@@ -409,6 +253,10 @@ i_readpng_wiol(io_glue *ig, int length) {
   png_read_update_info(png_ptr, info_ptr);
   
   im = i_img_empty_ch(NULL,width,height,channels);
+  if (!im) {
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    return NULL;
+  }
 
   for (pass = 0; pass < number_passes; pass++)
     for (y = 0; y < height; y++) { png_read_row(png_ptr,(png_bytep) &(im->idata[channels*width*y]), NULL); }
@@ -427,11 +275,13 @@ i_readpng_wiol(io_glue *ig, int length) {
 static void get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr) {
   png_uint_32 xres, yres;
   int unit_type;
+
+  i_tags_add(&im->tags, "i_format", 0, "png", -1, 0);
   if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) {
     mm_log((1,"pHYs (%d, %d) %d\n", xres, yres, unit_type));
     if (unit_type == PNG_RESOLUTION_METER) {
-      i_tags_set_float(&im->tags, "i_xres", 0, xres * 0.0254);
-      i_tags_set_float(&im->tags, "i_yres", 0, xres * 0.0254);
+      i_tags_set_float2(&im->tags, "i_xres", 0, xres * 0.0254, 5);
+      i_tags_set_float2(&im->tags, "i_yres", 0, yres * 0.0254, 5);
     }
     else {
       i_tags_addn(&im->tags, "i_xres", 0, xres);