Discussion:
[PATCH 1/2] Separate ICC profile loading into a separate file.
Add Reply
Aaron Muir Hamilton
2017-04-16 14:59:29 UTC
Reply
Permalink
Raw Message
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 892b32a..1b234db 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 e944a9c..6571ba3 100644
--- a/frontend/Makefile.in
+++ b/frontend/Makefile.in
@@ -114,7 +114,7 @@ AM_V_lt = $(***@AM_V@)
am__v_lt_ = $(***@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@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
+@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
diff --git a/frontend/sicc.c b/frontend/sicc.c
new file mode 100644
index 0000000..21d600d
--- /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 <***@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 0000000..5c225da
--- /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 <***@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 01d845b..c9153e5 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 <***@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);
}
--
1.8.3.1
--
sane-devel mailing list: sane-***@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/sane-devel
Unsubscribe: Send mail with subject "unsubscribe your_password"
to sane-devel-***@lists.alioth.debian.org
Aaron Muir Hamilton
2017-04-16 14:59:30 UTC
Reply
Permalink
Raw Message
---
frontend/scanimage.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/frontend/scanimage.c b/frontend/scanimage.c
index 77c2288..0f71422 100644
--- a/frontend/scanimage.c
+++ b/frontend/scanimage.c
@@ -56,6 +56,7 @@
#include "../include/sane/sanei.h"
#include "../include/sane/saneopts.h"

+#include "sicc.h"
#include "stiff.h"

#include "../include/md5.h"
@@ -1165,9 +1166,11 @@ write_pnm_header (SANE_Frame format, int width, int height, int depth, FILE *ofp

#ifdef HAVE_LIBPNG
static void
-write_png_header (SANE_Frame format, int width, int height, int depth, FILE *ofp, png_structp* png_ptr, png_infop* info_ptr)
+write_png_header (SANE_Frame format, int width, int height, int depth, const char * icc_profile, FILE *ofp, png_structp* png_ptr, png_infop* info_ptr)
{
int color_type;
+ size_t icc_size = 0;
+ void *icc_buffer;

*png_ptr = png_create_write_struct
(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
@@ -1200,6 +1203,16 @@ write_png_header (SANE_Frame format, int width, int height, int depth, FILE *ofp
depth, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

+ if (icc_profile)
+ {
+ icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
+ if (icc_size > 0)
+ {
+ png_set_iCCP(*png_ptr, *info_ptr, basename(icc_profile), PNG_COMPRESSION_TYPE_BASE, icc_buffer, icc_size);
+ free(icc_buffer);
+ }
+ }
+
png_write_info(*png_ptr, *info_ptr);
}
#endif
@@ -1379,7 +1392,8 @@ scan_it (FILE *ofp)
#ifdef HAVE_LIBPNG
case OUTPUT_PNG:
write_png_header (parm.format, parm.pixels_per_line,
- parm.lines, parm.depth, ofp, &png_ptr, &info_ptr);
+ parm.lines, parm.depth, icc_profile,
+ ofp, &png_ptr, &info_ptr);
break;
#endif
#ifdef HAVE_LIBJPEG
@@ -1635,7 +1649,8 @@ scan_it (FILE *ofp)
#ifdef HAVE_LIBPNG
case OUTPUT_PNG:
write_png_header (parm.format, parm.pixels_per_line,
- image.height, parm.depth, ofp, &png_ptr, &info_ptr);
+ image.height, parm.depth, icc_profile,
+ ofp, &png_ptr, &info_ptr);
break;
#endif
#ifdef HAVE_LIBJPEG
--
1.8.3.1
--
sane-devel mailing list: sane-***@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/sane-devel
Unsubscribe: Send mail with subject "unsubscribe your_password"
to sane-devel-***@lists.alioth.debian.org
Aaron Muir Hamilton
2017-04-16 15:13:07 UTC
Reply
Permalink
Raw Message
---
frontend/scanimage.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/frontend/scanimage.c b/frontend/scanimage.c
index 77c2288..0f71422 100644
--- a/frontend/scanimage.c
+++ b/frontend/scanimage.c
@@ -56,6 +56,7 @@
#include "../include/sane/sanei.h"
#include "../include/sane/saneopts.h"

+#include "sicc.h"
#include "stiff.h"

#include "../include/md5.h"
@@ -1165,9 +1166,11 @@ write_pnm_header (SANE_Frame format, int width, int height, int depth, FILE *ofp

#ifdef HAVE_LIBPNG
static void
-write_png_header (SANE_Frame format, int width, int height, int depth, FILE *ofp, png_structp* png_ptr, png_infop* info_ptr)
+write_png_header (SANE_Frame format, int width, int height, int depth, const char * icc_profile, FILE *ofp, png_structp* png_ptr, png_infop* info_ptr)
{
int color_type;
+ size_t icc_size = 0;
+ void *icc_buffer;

*png_ptr = png_create_write_struct
(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
@@ -1200,6 +1203,16 @@ write_png_header (SANE_Frame format, int width, int height, int depth, FILE *ofp
depth, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

+ if (icc_profile)
+ {
+ icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
+ if (icc_size > 0)
+ {
+ png_set_iCCP(*png_ptr, *info_ptr, basename(icc_profile), PNG_COMPRESSION_TYPE_BASE, icc_buffer, icc_size);
+ free(icc_buffer);
+ }
+ }
+
png_write_info(*png_ptr, *info_ptr);
}
#endif
@@ -1379,7 +1392,8 @@ scan_it (FILE *ofp)
#ifdef HAVE_LIBPNG
case OUTPUT_PNG:
write_png_header (parm.format, parm.pixels_per_line,
- parm.lines, parm.depth, ofp, &png_ptr, &info_ptr);
+ parm.lines, parm.depth, icc_profile,
+ ofp, &png_ptr, &info_ptr);
break;
#endif
#ifdef HAVE_LIBJPEG
@@ -1635,7 +1649,8 @@ scan_it (FILE *ofp)
#ifdef HAVE_LIBPNG
case OUTPUT_PNG:
write_png_header (parm.format, parm.pixels_per_line,
- image.height, parm.depth, ofp, &png_ptr, &info_ptr);
+ image.height, parm.depth, icc_profile,
+ ofp, &png_ptr, &info_ptr);
break;
#endif
#ifdef HAVE_LIBJPEG
--
1.8.3.1
--
sane-devel mailing list: sane-***@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/sane-devel
Unsubscribe: Send mail with subject "unsubscribe your_password"
to sane-devel-***@lists.alioth.debian.org
Loading...