[sane-devel] [PATCH 1/3] Separate ICC profile loading into a separate file.

Aaron Muir Hamilton aaron at correspondwith.me
Mon Apr 17 12:07:38 UTC 2017


  This cuts out some duplicate code, and enables us to reuse this
  logic for PNG, JPEG, and any other future output format.
  sanei_load_icc_profile also allows us to know that an ICC profile
  file is not long enough before we start to write it to the output;
  this should prevent poorly-written software from overflowing into
  image data when they read the bad profile based on its length.
---
 frontend/Makefile.am |  2 +-
 frontend/Makefile.in |  5 +--
 frontend/sicc.c      | 65 ++++++++++++++++++++++++++++++++++
 frontend/sicc.h      | 19 ++++++++++
 frontend/stiff.c     | 99 +++++++++++++---------------------------------------
 5 files changed, 113 insertions(+), 77 deletions(-)
 create mode 100644 frontend/sicc.c
 create mode 100644 frontend/sicc.h

diff --git a/frontend/Makefile.am b/frontend/Makefile.am
index 892b32ae..1b234dbc 100644
--- a/frontend/Makefile.am
+++ b/frontend/Makefile.am
@@ -16,7 +16,7 @@ endif
 
 AM_CPPFLAGS += -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include
 
-scanimage_SOURCES = scanimage.c stiff.c stiff.h
+scanimage_SOURCES = scanimage.c sicc.c sicc.h stiff.c stiff.h
 scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \
                   $(PNG_LIBS) $(JPEG_LIBS)
 
diff --git a/frontend/Makefile.in b/frontend/Makefile.in
index e944a9cb..6571ba3a 100644
--- a/frontend/Makefile.in
+++ b/frontend/Makefile.in
@@ -114,7 +114,7 @@ AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-am_scanimage_OBJECTS = scanimage.$(OBJEXT) stiff.$(OBJEXT)
+am_scanimage_OBJECTS = scanimage.$(OBJEXT) sicc.$(OBJEXT) stiff.$(OBJEXT)
 scanimage_OBJECTS = $(am_scanimage_OBJECTS)
 scanimage_DEPENDENCIES = ../backend/libsane.la ../sanei/libsanei.la \
 	../lib/liblib.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -381,7 +381,7 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-scanimage_SOURCES = scanimage.c stiff.c stiff.h
+scanimage_SOURCES = scanimage.c sicc.c sicc.h stiff.c stiff.h
 scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \
                   $(PNG_LIBS) $(JPEG_LIBS)
 
@@ -550,6 +550,7 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/saned.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/scanimage.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sicc.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stiff.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tstbackend.Po at am__quote@
diff --git a/frontend/sicc.c b/frontend/sicc.c
new file mode 100644
index 00000000..21d600d1
--- /dev/null
+++ b/frontend/sicc.c
@@ -0,0 +1,65 @@
+/* Load an ICC profile for embedding in an output file
+   Copyright (C) 2017 Aaron Muir Hamilton <aaron at correspondwith.me>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+void *
+sanei_load_icc_profile (const char *path, size_t *size)
+{
+  FILE *fd = NULL;
+  size_t stated_size = 0;
+  void *profile = NULL;
+  struct stat s;
+
+  fd = fopen(path, "r");
+
+  if (!fd)
+  {
+    fprintf(stderr, "Could not open ICC profile %s\n", path);
+  }
+  else
+  {
+    fstat(fileno(fd), &s);
+    stated_size = 16777216 * fgetc(fd) + 65536 * fgetc(fd) + 256 * fgetc(fd) + fgetc(fd);
+    rewind(fd);
+
+    if (stated_size > (size_t) s.st_size)
+    {
+      fprintf(stderr, "Ignoring ICC profile because file %s is shorter than the profile\n", path);
+    }
+    else
+    {
+      profile = malloc(stated_size);
+
+      if (fread(profile, stated_size, 1, fd) != 1)
+      {
+        fprintf(stderr, "Error reading ICC profile %s\n", path);
+        free(profile);
+      }
+      else
+      {
+        fclose(fd);
+        *size = stated_size;
+        return profile;
+      }
+    }
+    fclose(fd);
+  }
+  return NULL;
+}
diff --git a/frontend/sicc.h b/frontend/sicc.h
new file mode 100644
index 00000000..5c225dad
--- /dev/null
+++ b/frontend/sicc.h
@@ -0,0 +1,19 @@
+/* Load an ICC profile for embedding in an output file
+   Copyright (C) 2017 Aaron Muir Hamilton <aaron at correspondwith.me>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+void *
+sanei_load_icc_profile (const char *path, size_t *size);
diff --git a/frontend/stiff.c b/frontend/stiff.c
index 01d845bf..c9153e59 100644
--- a/frontend/stiff.c
+++ b/frontend/stiff.c
@@ -1,6 +1,7 @@
 /* Create SANE/tiff headers TIFF interfacing routines for SANE
    Copyright (C) 2000 Peter Kirchgessner
    Copyright (C) 2002 Oliver Rauch: added tiff ICC profile
+   Copyright (C) 2017 Aaron Muir Hamilton <aaron at correspondwith.me>
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -20,6 +21,7 @@
    2000-11-19, PK: Color TIFF-header: write 3 values for bits per sample
    2001-12-16, PK: Write fill order tag for b/w-images
    2002-08-27, OR: Added tiff tag for ICC profile
+   2017-04-16, AMH: Separate ICC profile loading into a separate file
 */
 #ifdef _AIX
 # include "../include/lalloca.h"	/* MUST come first for AIX! */
@@ -31,6 +33,7 @@
 #include "../include/sane/config.h"
 #include "../include/sane/sane.h"
 
+#include "sicc.h"
 #include "stiff.h"
 
 typedef struct {
@@ -269,22 +272,12 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,
     int strip_bytecount;
     int ntags;
     int motorola, bps, maxsamplevalue;
-    FILE *icc_file = 0;
-    int icc_len = -1;
+    void *icc_buffer = NULL;
+    size_t icc_size = 0;
 
     if (icc_profile)
     {
-      icc_file = fopen(icc_profile, "r");
-
-      if (!icc_file)
-      {
-        fprintf(stderr, "Could not open ICC profile %s\n", icc_profile);
-      }
-      else
-      {
-        icc_len = 16777216 * fgetc(icc_file) + 65536 * fgetc(icc_file) + 256 * fgetc(icc_file) + fgetc(icc_file);
-        rewind(icc_file);
-      }
+      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
     }
 
     ifd = create_ifd ();
@@ -302,10 +295,10 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,
         data_size += 2*4 + 2*4;
     }
 
-    if (icc_len > 0) /* if icc profile exists add memory for tag */
+    if (icc_size > 0) /* if icc profile exists add memory for tag */
     {
         ntags += 1;
-        data_size += icc_len;
+        data_size += icc_size;
     }
 
     ifd_size = 2 + ntags*12 + 4;
@@ -355,10 +348,10 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,
         add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2);
     }
 
-    if (icc_len > 0) /* add ICC-profile TAG */
+    if (icc_size > 0) /* add ICC-profile TAG */
     {
-      add_ifd_entry(ifd, 34675, 7, icc_len, data_offset);
-      data_offset += icc_len;
+      add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset);
+      data_offset += icc_size;
     }
 
     /* I prefer motorola format. Its human readable. But for 16 bit, */
@@ -383,33 +376,16 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,
         write_i4 (fptr, 1, motorola);
     }
 
-    /* Write ICC profile */
-    if (icc_len > 0)
+    if (icc_size > 0)
     {
-      int i;
-      for (i=0; i<icc_len; i++)
-      {
-        if (!feof(icc_file))
-        {
-          fputc(fgetc(icc_file), fptr);
-        }
-        else
-        {
-          fprintf(stderr, "ICC profile %s is too short\n", icc_profile);
-          break;
-        }
-      }
+      fwrite(icc_buffer, icc_size, 1, fptr);
     }
 
-    if (icc_file)
-    {
-      fclose(icc_file);
-    }
+    free(icc_buffer);
 
     free_ifd (ifd);
 }
 
-
 static void
 write_tiff_color_header (FILE *fptr, int width, int height, int depth,
                          int resolution, const char *icc_profile)
@@ -419,22 +395,12 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,
     int strip_bytecount;
     int ntags;
     int motorola, bps, maxsamplevalue;
-    FILE *icc_file = 0;
-    int icc_len = -1;
+    void *icc_buffer = NULL;
+    size_t icc_size = 0;
 
     if (icc_profile)
     {
-      icc_file = fopen(icc_profile, "r");
-
-      if (!icc_file)
-      {
-        fprintf(stderr, "Could not open ICC profile %s\n", icc_profile);
-      }
-      else
-      {
-        icc_len = 16777216 * fgetc(icc_file) + 65536 * fgetc(icc_file) + 256 * fgetc(icc_file) + fgetc(icc_file);
-        rewind(icc_file);
-      }
+      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
     }
 
 
@@ -454,10 +420,10 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,
         data_size += 2*4 + 2*4;
     }
 
-    if (icc_len > 0) /* if icc profile exists add memory for tag */
+    if (icc_size > 0) /* if icc profile exists add memory for tag */
     {
         ntags += 1;
-        data_size += icc_len;
+        data_size += icc_size;
     }
 
 
@@ -513,10 +479,10 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,
         add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2);
     }
 
-    if (icc_len > 0) /* add ICC-profile TAG */
+    if (icc_size > 0) /* add ICC-profile TAG */
     {
-      add_ifd_entry(ifd, 34675, 7, icc_len, data_offset);
-      data_offset += icc_len;
+      add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset);
+      data_offset += icc_size;
     }
 
 
@@ -558,27 +524,12 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,
     }
 
     /* Write ICC profile */
-    if (icc_len > 0)
+    if (icc_size > 0)
     {
-      int i;
-      for (i=0; i<icc_len; i++)
-      {
-        if (!feof(icc_file))
-        {
-          fputc(fgetc(icc_file), fptr);
-        }
-        else
-        {
-          fprintf(stderr, "ICC profile %s is too short\n", icc_profile);
-          break;
-        }
-      }
+      fwrite(icc_buffer, icc_size, 1, fptr);
     }
 
-    if (icc_file)
-    {
-      fclose(icc_file);
-    }
+    free(icc_buffer);
 
     free_ifd (ifd);
 }
-- 
2.12.2




More information about the sane-devel mailing list