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_@AM_V@) am__v_lt_ = $(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@ @am__quote@./$(DEPDIR)/saned.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scanimage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sicc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stiff.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tstbackend.Po@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 <aa...@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 <aa...@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 <aa...@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 -- sane-devel mailing list: sane-devel@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-requ...@lists.alioth.debian.org