Commit 2c653a92 authored by Aaron Muir Hamilton's avatar Aaron Muir Hamilton Committed by Olaf Meeuwissen

Separate ICC profile loading into a separate file.

  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.
parent 5fa4be5a
...@@ -16,7 +16,7 @@ endif ...@@ -16,7 +16,7 @@ endif
AM_CPPFLAGS += -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include 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 \ scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \
$(PNG_LIBS) $(JPEG_LIBS) $(PNG_LIBS) $(JPEG_LIBS)
......
...@@ -114,7 +114,7 @@ AM_V_lt = $(am__v_lt_@AM_V@) ...@@ -114,7 +114,7 @@ AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent am__v_lt_0 = --silent
am__v_lt_1 = 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_OBJECTS = $(am_scanimage_OBJECTS)
scanimage_DEPENDENCIES = ../backend/libsane.la ../sanei/libsanei.la \ scanimage_DEPENDENCIES = ../backend/libsane.la ../sanei/libsanei.la \
../lib/liblib.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) ../lib/liblib.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
...@@ -381,7 +381,7 @@ target_alias = @target_alias@ ...@@ -381,7 +381,7 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ 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 \ scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \
$(PNG_LIBS) $(JPEG_LIBS) $(PNG_LIBS) $(JPEG_LIBS)
...@@ -550,6 +550,7 @@ distclean-compile: ...@@ -550,6 +550,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/saned.Po@am__quote@ @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)/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)/stiff.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tstbackend.Po@am__quote@
......
/* Load an ICC profile for embedding in an output file
Copyright (C) 2017 Aaron Muir Hamilton <aaron@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;
}
/* Load an ICC profile for embedding in an output file
Copyright (C) 2017 Aaron Muir Hamilton <aaron@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);
/* Create SANE/tiff headers TIFF interfacing routines for SANE /* Create SANE/tiff headers TIFF interfacing routines for SANE
Copyright (C) 2000 Peter Kirchgessner Copyright (C) 2000 Peter Kirchgessner
Copyright (C) 2002 Oliver Rauch: added tiff ICC profile Copyright (C) 2002 Oliver Rauch: added tiff ICC profile
Copyright (C) 2017 Aaron Muir Hamilton <aaron@correspondwith.me>
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
2000-11-19, PK: Color TIFF-header: write 3 values for bits per sample 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 2001-12-16, PK: Write fill order tag for b/w-images
2002-08-27, OR: Added tiff tag for ICC profile 2002-08-27, OR: Added tiff tag for ICC profile
2017-04-16, AMH: Separate ICC profile loading into a separate file
*/ */
#ifdef _AIX #ifdef _AIX
# include "../include/lalloca.h" /* MUST come first for AIX! */ # include "../include/lalloca.h" /* MUST come first for AIX! */
...@@ -31,6 +33,7 @@ ...@@ -31,6 +33,7 @@
#include "../include/sane/config.h" #include "../include/sane/config.h"
#include "../include/sane/sane.h" #include "../include/sane/sane.h"
#include "sicc.h"
#include "stiff.h" #include "stiff.h"
typedef struct { typedef struct {
...@@ -269,22 +272,12 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth, ...@@ -269,22 +272,12 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,
int strip_bytecount; int strip_bytecount;
int ntags; int ntags;
int motorola, bps, maxsamplevalue; int motorola, bps, maxsamplevalue;
FILE *icc_file = 0; void *icc_buffer = NULL;
int icc_len = -1; size_t icc_size = 0;
if (icc_profile) if (icc_profile)
{ {
icc_file = fopen(icc_profile, "r"); icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
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);
}
} }
ifd = create_ifd (); ifd = create_ifd ();
...@@ -302,10 +295,10 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth, ...@@ -302,10 +295,10 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,
data_size += 2*4 + 2*4; 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; ntags += 1;
data_size += icc_len; data_size += icc_size;
} }
ifd_size = 2 + ntags*12 + 4; ifd_size = 2 + ntags*12 + 4;
...@@ -355,10 +348,10 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth, ...@@ -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); 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); add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset);
data_offset += icc_len; data_offset += icc_size;
} }
/* I prefer motorola format. Its human readable. But for 16 bit, */ /* 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, ...@@ -383,33 +376,16 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,
write_i4 (fptr, 1, motorola); write_i4 (fptr, 1, motorola);
} }
/* Write ICC profile */ if (icc_size > 0)
if (icc_len > 0)
{ {
int i; fwrite(icc_buffer, icc_size, 1, fptr);
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;
}
}
} }
if (icc_file) free(icc_buffer);
{
fclose(icc_file);
}
free_ifd (ifd); free_ifd (ifd);
} }
static void static void
write_tiff_color_header (FILE *fptr, int width, int height, int depth, write_tiff_color_header (FILE *fptr, int width, int height, int depth,
int resolution, const char *icc_profile) int resolution, const char *icc_profile)
...@@ -419,22 +395,12 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth, ...@@ -419,22 +395,12 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,
int strip_bytecount; int strip_bytecount;
int ntags; int ntags;
int motorola, bps, maxsamplevalue; int motorola, bps, maxsamplevalue;
FILE *icc_file = 0; void *icc_buffer = NULL;
int icc_len = -1; size_t icc_size = 0;
if (icc_profile) if (icc_profile)
{ {
icc_file = fopen(icc_profile, "r"); icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
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);
}
} }
...@@ -454,10 +420,10 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth, ...@@ -454,10 +420,10 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,
data_size += 2*4 + 2*4; 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; 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, ...@@ -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); 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); add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset);
data_offset += icc_len; data_offset += icc_size;
} }
...@@ -558,27 +524,12 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth, ...@@ -558,27 +524,12 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,
} }
/* Write ICC profile */ /* Write ICC profile */
if (icc_len > 0) if (icc_size > 0)
{ {
int i; fwrite(icc_buffer, icc_size, 1, fptr);
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;
}
}
} }
if (icc_file) free(icc_buffer);
{
fclose(icc_file);
}
free_ifd (ifd); free_ifd (ifd);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment