diff options
author | Jörg Frings-Fürst <debian@jff.email> | 2024-03-03 09:55:14 +0100 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff.email> | 2024-03-03 09:55:14 +0100 |
commit | b098beb219b0b300ec7eb915bfa2b3038c3fb533 (patch) | |
tree | 08c40dc8b180b31f504945e8da3e3ea3950e4145 /frontend | |
parent | 2938695ca4c9bca7834817465662e31570f6d32f (diff) | |
parent | 23c348d62ab9f0a902189c70921310a5f856852c (diff) |
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'frontend')
-rw-r--r-- | frontend/.gitignore | 4 | ||||
-rw-r--r-- | frontend/Makefile.am | 19 | ||||
-rw-r--r-- | frontend/jpegtopdf.c | 2 | ||||
-rw-r--r-- | frontend/saned.c | 361 | ||||
-rw-r--r-- | frontend/saned.socket | 10 | ||||
-rw-r--r-- | frontend/saned.xinetd.conf.in | 13 | ||||
-rw-r--r-- | frontend/saned@.service.in | 11 | ||||
-rw-r--r-- | frontend/scanimage.c | 201 |
8 files changed, 359 insertions, 262 deletions
diff --git a/frontend/.gitignore b/frontend/.gitignore index 90f73a9..e42f6b0 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,2 +1,6 @@ saned +saned@.service +saned.xinetd.conf scanimage +test +tstbackend diff --git a/frontend/Makefile.am b/frontend/Makefile.am index 9b92645..8573aba 100644 --- a/frontend/Makefile.am +++ b/frontend/Makefile.am @@ -44,5 +44,20 @@ tstbackend_LDADD += -lstdc++ endif endif -clean-local: - rm -f test tstbackend +BUILT_SOURCES = saned@.service saned.xinetd.conf + +EXTRA_DIST = saned.socket saned@.service.in saned.xinetd.conf.in + +CLEANFILES = $(EXTRA_PROGRAMS) $(BUILT_SOURCES) + +SUFFIXES = .in +.in: + $(AM_V_GEN) + @if $(AM_V_P); then echo Generating $@ from $^; fi + @sed -e 's|@DATADIR@|$(datadir)|g' \ + -e 's|@CONFIGDIR@|$(configdir)|g' \ + -e 's|@DOCDIR@|$(docdir)|g' \ + -e 's|@LIBDIR@|$(libdir)/sane|g' \ + -e 's|@BINDIR@|$(bindir)|g' \ + -e 's|@SBINDIR@|$(sbindir)|g' \ + -e 's|@PACKAGEVERSION@|$(PACKAGE_VERSION)|g' $? > $@ diff --git a/frontend/jpegtopdf.c b/frontend/jpegtopdf.c index 5c5d712..309411c 100644 --- a/frontend/jpegtopdf.c +++ b/frontend/jpegtopdf.c @@ -91,7 +91,7 @@ #define SANE_PDF_LENGTH_OBJ "%d 0 obj\n%d\nendobj\n" /* end of stream/object */ -#define SANE_PDF_END_ST_OBJ "endstream\nendobj\n" +#define SANE_PDF_END_ST_OBJ "\nendstream\nendobj\n" /* object id of first page */ diff --git a/frontend/saned.c b/frontend/saned.c index e31758a..d71d428 100644 --- a/frontend/saned.c +++ b/frontend/saned.c @@ -53,6 +53,7 @@ #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include <stdint.h> #include <string.h> #include <syslog.h> #include <time.h> @@ -257,6 +258,7 @@ static int data_connect_timeout = 4000; static Handle *handle; static char *bind_addr; static short bind_port = -1; +static size_t buffer_size = (1 * 1024 * 1024); static union { int w; @@ -1651,168 +1653,186 @@ store_reclen (SANE_Byte * buf, size_t buf_size, int i, size_t reclen) static void do_scan (Wire * w, int h, int data_fd) { - int num_fds, be_fd = -1, reader, writer, bytes_in_buf, status_dirty = 0; + int num_fds, be_fd = -1, reader, bytes_in_buf, status_dirty = 0; + size_t writer; SANE_Handle be_handle = handle[h].handle; struct timeval tv, *timeout = 0; fd_set rd_set, rd_mask, wr_set, wr_mask; - SANE_Byte buf[8192]; + SANE_Byte *buf = NULL; SANE_Status status; - long int nwritten; + ssize_t nwritten; SANE_Int length; size_t nbytes; DBG (3, "do_scan: start\n"); - FD_ZERO (&rd_mask); - FD_SET (w->io.fd, &rd_mask); - num_fds = w->io.fd + 1; - - FD_ZERO (&wr_mask); - FD_SET (data_fd, &wr_mask); - if (data_fd >= num_fds) - num_fds = data_fd + 1; - - sane_set_io_mode (be_handle, SANE_TRUE); - if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD) + /* + * Allocate the read buffer. + * + */ + buf = malloc (buffer_size); + if (!buf) { - FD_SET (be_fd, &rd_mask); - if (be_fd >= num_fds) - num_fds = be_fd + 1; + status = SANE_STATUS_NO_MEM; + DBG (DBG_ERR, "do_scan: failed to allocate read buffer (%zu bytes)\n", + buffer_size); } else { - memset (&tv, 0, sizeof (tv)); - timeout = &tv; - } + FD_ZERO(&rd_mask); + FD_SET(w->io.fd, &rd_mask); + num_fds = w->io.fd + 1; - status = SANE_STATUS_GOOD; - reader = writer = bytes_in_buf = 0; - do - { - rd_set = rd_mask; - wr_set = wr_mask; - if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0) - { - if (be_fd >= 0 && errno == EBADF) - { - /* This normally happens when a backend closes a select - filedescriptor when reaching the end of file. So - pass back this status to the client: */ - FD_CLR (be_fd, &rd_mask); - be_fd = -1; - /* only set status_dirty if EOF hasn't been already detected */ - if (status == SANE_STATUS_GOOD) - status_dirty = 1; - status = SANE_STATUS_EOF; - DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n"); - continue; - } - else - { - status = SANE_STATUS_IO_ERROR; - DBG (DBG_ERR, "do_scan: select failed (%s)\n", strerror (errno)); - break; - } - } + FD_ZERO(&wr_mask); + FD_SET(data_fd, &wr_mask); + if (data_fd >= num_fds) + num_fds = data_fd + 1; - if (bytes_in_buf) - { - if (FD_ISSET (data_fd, &wr_set)) - { - if (bytes_in_buf > 0) - { - /* write more input data */ - nbytes = bytes_in_buf; - if (writer + nbytes > sizeof (buf)) - nbytes = sizeof (buf) - writer; - DBG (DBG_INFO, - "do_scan: trying to write %d bytes to client\n", - nbytes); - nwritten = write (data_fd, buf + writer, nbytes); - DBG (DBG_INFO, - "do_scan: wrote %ld bytes to client\n", nwritten); - if (nwritten < 0) - { - DBG (DBG_ERR, "do_scan: write failed (%s)\n", - strerror (errno)); - status = SANE_STATUS_CANCELLED; - handle[h].docancel = 1; - break; - } - bytes_in_buf -= nwritten; - writer += nwritten; - if (writer == sizeof (buf)) - writer = 0; - } - } - } - else if (status == SANE_STATUS_GOOD - && (timeout || FD_ISSET (be_fd, &rd_set))) - { - int i; + sane_set_io_mode (be_handle, SANE_TRUE); + if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD) + { + FD_SET(be_fd, &rd_mask); + if (be_fd >= num_fds) + num_fds = be_fd + 1; + } + else + { + memset (&tv, 0, sizeof(tv)); + timeout = &tv; + } - /* get more input data */ + status = SANE_STATUS_GOOD; + reader = writer = bytes_in_buf = 0; + do + { + rd_set = rd_mask; + wr_set = wr_mask; + if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0) + { + if (be_fd >= 0 && errno == EBADF) + { + /* This normally happens when a backend closes a select + filedescriptor when reaching the end of file. So + pass back this status to the client: */ + FD_CLR(be_fd, &rd_mask); + be_fd = -1; + /* only set status_dirty if EOF hasn't been already detected */ + if (status == SANE_STATUS_GOOD) + status_dirty = 1; + status = SANE_STATUS_EOF; + DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n"); + continue; + } + else + { + status = SANE_STATUS_IO_ERROR; + DBG (DBG_ERR, "do_scan: select failed (%s)\n", + strerror (errno)); + break; + } + } - /* reserve 4 bytes to store the length of the data record: */ - i = reader; - reader += 4; - if (reader >= (int) sizeof (buf)) - reader -= sizeof(buf); + if (bytes_in_buf) + { + if (FD_ISSET(data_fd, &wr_set)) + { + if (bytes_in_buf > 0) + { + /* write more input data */ + nbytes = bytes_in_buf; + if (writer + nbytes > buffer_size) + nbytes = buffer_size - writer; + DBG (DBG_INFO, + "do_scan: trying to write %d bytes to client\n", + nbytes); + nwritten = write (data_fd, buf + writer, nbytes); + DBG (DBG_INFO, "do_scan: wrote %ld bytes to client\n", + nwritten); + if (nwritten < 0) + { + DBG (DBG_ERR, "do_scan: write failed (%s)\n", + strerror (errno)); + status = SANE_STATUS_CANCELLED; + handle[h].docancel = 1; + break; + } + bytes_in_buf -= (size_t) nwritten; + writer += (size_t) nwritten; + if (writer == buffer_size) + writer = 0; + } + } + } + else if (status == SANE_STATUS_GOOD + && (timeout || FD_ISSET(be_fd, &rd_set))) + { + int i; - assert (bytes_in_buf == 0); - nbytes = sizeof (buf) - 4; - if (reader + nbytes > sizeof (buf)) - nbytes = sizeof (buf) - reader; + /* get more input data */ - DBG (DBG_INFO, - "do_scan: trying to read %d bytes from scanner\n", nbytes); - status = sane_read (be_handle, buf + reader, nbytes, &length); - DBG (DBG_INFO, - "do_scan: read %d bytes from scanner\n", length); + /* reserve 4 bytes to store the length of the data record: */ + i = reader; + reader += 4; + if (reader >= (int) buffer_size) + reader -= buffer_size; - reset_watchdog (); + assert(bytes_in_buf == 0); + nbytes = buffer_size - 4; + if (reader + nbytes > buffer_size) + nbytes = buffer_size - reader; - reader += length; - if (reader >= (int) sizeof (buf)) - reader = 0; - bytes_in_buf += length + 4; + DBG (DBG_INFO, "do_scan: trying to read %d bytes from scanner\n", + nbytes); + status = sane_read (be_handle, buf + reader, nbytes, &length); + DBG (DBG_INFO, "do_scan: read %d bytes from scanner\n", length); - if (status != SANE_STATUS_GOOD) - { - reader = i; /* restore reader index */ - status_dirty = 1; - DBG (DBG_MSG, - "do_scan: status = `%s'\n", sane_strstatus(status)); - } - else - store_reclen (buf, sizeof (buf), i, length); - } + reset_watchdog (); - if (status_dirty && sizeof (buf) - bytes_in_buf >= 5) - { - status_dirty = 0; - reader = store_reclen (buf, sizeof (buf), reader, 0xffffffff); - buf[reader] = status; - bytes_in_buf += 5; - DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n", - sane_strstatus(status)); - } + reader += length; + if (reader >= (int) buffer_size) + reader = 0; + bytes_in_buf += length + 4; - if (FD_ISSET (w->io.fd, &rd_set)) - { - DBG (DBG_MSG, - "do_scan: processing RPC request on fd %d\n", w->io.fd); - if(process_request (w) < 0) - handle[h].docancel = 1; + if (status != SANE_STATUS_GOOD) + { + reader = i; /* restore reader index */ + status_dirty = 1; + DBG (DBG_MSG, "do_scan: status = `%s'\n", + sane_strstatus (status)); + } + else + store_reclen (buf, buffer_size, i, length); + } - if (handle[h].docancel) - break; - } + if (status_dirty && buffer_size - bytes_in_buf >= 5) + { + status_dirty = 0; + reader = store_reclen (buf, buffer_size, reader, 0xffffffff); + buf[reader] = status; + bytes_in_buf += 5; + DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n", + sane_strstatus (status)); + } + + if (FD_ISSET(w->io.fd, &rd_set)) + { + DBG (DBG_MSG, "do_scan: processing RPC request on fd %d\n", + w->io.fd); + if (process_request (w) < 0) + handle[h].docancel = 1; + + if (handle[h].docancel) + break; + } + } + while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty); + DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status)); + + free (buf); + buf = NULL; } - while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty); - DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status)); - if(handle[h].docancel) + if (handle[h].docancel) sane_cancel (handle[h].handle); handle[h].docancel = 0; @@ -2236,8 +2256,8 @@ process_request (Wire * w) strerror (errno)); return 1; } - fcntl (data_fd, F_SETFL, 1); /* set non-blocking */ - shutdown (data_fd, 0); + fcntl (data_fd, F_SETFL, O_NONBLOCK); /* set non-blocking */ + shutdown (data_fd, SHUT_RD); do_scan (w, h, data_fd); close (data_fd); } @@ -3413,16 +3433,17 @@ static void usage(char *me, int err) fprintf (stderr, "Usage: %s [OPTIONS]\n\n" " Options:\n\n" - " -a, --alone[=user] equal to `-l -D -u user'\n" - " -l, --listen run in standalone mode (listen for connection)\n" - " -u, --user=user run as `user'\n" - " -D, --daemonize run in background\n" - " -o, --once exit after first client disconnects\n" - " -d, --debug=level set debug level `level' (default is 2)\n" - " -e, --stderr output to stderr\n" - " -b, --bind=addr bind address `addr' (default all interfaces)\n" - " -p, --port=port bind port `port` (default sane-port or 6566)\n" - " -h, --help show this help message and exit\n", me); + " -a, --alone[=user] equal to `-l -D -u user'\n" + " -l, --listen run in standalone mode (listen for connection)\n" + " -u, --user=user run as `user'\n" + " -D, --daemonize run in background\n" + " -o, --once exit after first client disconnects\n" + " -d, --debug=level set debug level `level' (default is 2)\n" + " -e, --stderr output to stderr\n" + " -b, --bind=addr bind address `addr' (default all interfaces)\n" + " -p, --port=port bind port `port` (default sane-port or 6566)\n" + " -B, --buffer-size=size set size of read buffer in KB (default: 1024)\n" + " -h, --help show this help message and exit\n", me); exit(err); } @@ -3432,17 +3453,18 @@ static int debug; static struct option long_options[] = { /* These options set a flag. */ - {"help", no_argument, 0, 'h'}, - {"alone", optional_argument, 0, 'a'}, - {"listen", no_argument, 0, 'l'}, - {"user", required_argument, 0, 'u'}, - {"daemonize", no_argument, 0, 'D'}, - {"once", no_argument, 0, 'o'}, - {"debug", required_argument, 0, 'd'}, - {"stderr", no_argument, 0, 'e'}, - {"bind", required_argument, 0, 'b'}, - {"port", required_argument, 0, 'p'}, - {0, 0, 0, 0 } + {"help", no_argument, 0, 'h'}, + {"alone", optional_argument, 0, 'a'}, + {"listen", no_argument, 0, 'l'}, + {"user", required_argument, 0, 'u'}, + {"daemonize", no_argument, 0, 'D'}, + {"once", no_argument, 0, 'o'}, + {"debug", required_argument, 0, 'd'}, + {"stderr", no_argument, 0, 'e'}, + {"bind", required_argument, 0, 'b'}, + {"port", required_argument, 0, 'p'}, + {"buffer-size", required_argument, 0, 'B'}, + {0, 0, 0, 0 } }; int @@ -3467,7 +3489,7 @@ main (int argc, char *argv[]) run_foreground = SANE_TRUE; run_once = SANE_FALSE; - while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:", long_options, &long_index )) != -1) + while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:B:", long_options, &long_index )) != -1) { switch(c) { case 'a': @@ -3498,8 +3520,25 @@ main (int argc, char *argv[]) bind_addr = optarg; break; case 'p': - bind_port = atoi(optarg); - break; + bind_port = atoi(optarg); + break; + case 'B': + { + int buffer_arg = atoi(optarg); + + if ((buffer_arg < 0) || ((size_t)buffer_arg > (SIZE_MAX / 1024))) + { + DBG ( + DBG_ERR, + "saned: specified buffer size in KB is invalid. Default of %zuKB will be substituted.\n", + buffer_size / 1024); + } + else + { + buffer_size = 1024 * (size_t)buffer_arg; + } + break; + } case 'h': usage(argv[0], EXIT_SUCCESS); break; diff --git a/frontend/saned.socket b/frontend/saned.socket new file mode 100644 index 0000000..1aa19e7 --- /dev/null +++ b/frontend/saned.socket @@ -0,0 +1,10 @@ +[Unit] +Description=saned incoming socket + +[Socket] +ListenStream=6566 +Accept=yes +MaxConnections=1 + +[Install] +WantedBy=sockets.target diff --git a/frontend/saned.xinetd.conf.in b/frontend/saned.xinetd.conf.in new file mode 100644 index 0000000..3465dee --- /dev/null +++ b/frontend/saned.xinetd.conf.in @@ -0,0 +1,13 @@ +# default: off +# description: The sane server accepts requests +# for network access to a local scanner via the +# network. +service sane-port +{ + port = 6566 + socket_type = stream + wait = no + user = saned + group = saned + server = @SBINDIR@/saned +} diff --git a/frontend/saned@.service.in b/frontend/saned@.service.in new file mode 100644 index 0000000..1682109 --- /dev/null +++ b/frontend/saned@.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=Scanner Service +Requires=saned.socket + +[Service] +ExecStart=@SBINDIR@/saned +User=saned +Group=saned + +[Install] +Also=saned.socket diff --git a/frontend/scanimage.c b/frontend/scanimage.c index d79d487..ff53157 100644 --- a/frontend/scanimage.c +++ b/frontend/scanimage.c @@ -39,15 +39,8 @@ #include <string.h> #include <unistd.h> #include <stdarg.h> - -#ifdef __FreeBSD__ -#include <libgen.h> -#endif - -#if defined (__APPLE__) && defined (__MACH__) +#include <errno.h> #include <libgen.h> // for basename() -#endif - #include <sys/types.h> #include <sys/stat.h> @@ -111,7 +104,7 @@ static struct option basic_options[] = { {"test", no_argument, NULL, 'T'}, {"all-options", no_argument, NULL, 'A'}, {"version", no_argument, NULL, 'V'}, - {"buffer-size", optional_argument, NULL, 'B'}, + {"buffer-size", required_argument, NULL, 'B'}, {"batch", optional_argument, NULL, 'b'}, {"batch-count", required_argument, NULL, OPTION_BATCH_COUNT}, {"batch-start", required_argument, NULL, OPTION_BATCH_START_AT}, @@ -133,29 +126,30 @@ static struct option basic_options[] = { #define OUTPUT_JPEG 4 #define OUTPUT_PDF 5 -#define BASE_OPTSTRING "d:hi:Lf:o:B::nvVTAbp" +#define BASE_OPTSTRING "d:hi:Lf:o:B:nvVTAbp" #define STRIP_HEIGHT 256 /* # lines we increment image height */ -static struct option *all_options; -static int option_number_len; -static int *option_number; -static SANE_Handle device; -static int verbose; +static struct option *all_options = NULL; +static int option_number_len = 0; +static int *option_number = 0; +static SANE_Handle device = 0; +static int verbose = 0; static int progress = 0; static const char* output_file = NULL; -static int test; -static int all; +static int test = 0; +static int all = 0; static int output_format = OUTPUT_UNKNOWN; -static int help; +static int help = 0; static int dont_scan = 0; -static const char *prog_name; +static const char *prog_name = NULL; static int resolution_optind = -1, resolution_value = 0; /* window (area) related options */ -static SANE_Option_Descriptor window_option[4]; /*updated descs for x,y,l,t*/ -static int window[4]; /*index into backend options for x,y,l,t*/ -static SANE_Word window_val[2]; /*the value for x,y options*/ -static int window_val_user[2]; /* is x,y user-specified? */ +static SANE_Option_Descriptor window_option[4] = {0}; /*updated descs for x,y,l,t*/ +static int window[4] = {0}; /*index into backend options for x,y,l,t*/ +static SANE_Word window_val[2] = {0}; /*the value for x,y options*/ +static int window_val_user[2] = {0}; /* is x,y user-specified? */ +static char *full_optstring = NULL; static int accept_only_md5_auth = 0; static const char *icc_profile = NULL; @@ -167,18 +161,16 @@ static SANE_Word tl_x = 0; static SANE_Word tl_y = 0; static SANE_Word br_x = 0; static SANE_Word br_y = 0; -static SANE_Byte *buffer; -static size_t buffer_size; +static SANE_Byte *buffer = NULL; +static size_t buffer_size = 0; static void auth_callback (SANE_String_Const resource, SANE_Char * username, SANE_Char * password) { - char tmp[3 + 128 + SANE_MAX_USERNAME_LEN + SANE_MAX_PASSWORD_LEN], *wipe; - unsigned char md5digest[16]; + char tmp[3 + 128 + SANE_MAX_USERNAME_LEN + SANE_MAX_PASSWORD_LEN]; int md5mode = 0, len, query_user = 1; - FILE *pass_file; struct stat stat_buf; char * uname = NULL; @@ -202,6 +194,7 @@ auth_callback (SANE_String_Const resource, } else { + FILE *pass_file; if ((pass_file = fopen (tmp, "r")) != NULL) { @@ -291,6 +284,7 @@ auth_callback (SANE_String_Const resource, if (query_user == 1) { #ifdef HAVE_GETPASS + char *wipe; strcpy (password, (wipe = getpass ("Enter password: "))); memset (wipe, 0, strlen (password)); #else @@ -300,6 +294,7 @@ auth_callback (SANE_String_Const resource, if (md5mode) { + unsigned char md5digest[16]; sprintf (tmp, "%.128s%.*s", (strstr (resource, "$MD5$")) + 5, SANE_MAX_PASSWORD_LEN - 1, password); @@ -323,10 +318,10 @@ auth_callback (SANE_String_Const resource, static void sighandler (int signum) { - static SANE_Bool first_time = SANE_TRUE; - if (device) { + static SANE_Bool first_time = SANE_TRUE; + fprintf (stderr, "%s: received signal %d\n", prog_name, signum); if (first_time) { @@ -1210,18 +1205,17 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi, /* There are nominally 39.3700787401575 inches in a meter. */ const double pixels_per_meter = dpi * 39.3700787401575; size_t icc_size = 0; - void *icc_buffer; *png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!*png_ptr) { fprintf(stderr, "png_create_write_struct failed\n"); - exit(1); + scanimage_exit (1); } *info_ptr = png_create_info_struct(*png_ptr); if (!*info_ptr) { fprintf(stderr, "png_create_info_struct failed\n"); - exit(1); + scanimage_exit (1); } png_init_io(*png_ptr, ofp); @@ -1249,7 +1243,7 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi, if (icc_profile) { - icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size); + void *icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size); if (icc_size > 0) { /* libpng will abort if the profile and image colour spaces do not match*/ @@ -1260,7 +1254,21 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi, if ((is_gray_profile && color_type == PNG_COLOR_TYPE_GRAY) || (is_rgb_profile && color_type == PNG_COLOR_TYPE_RGB)) { - png_set_iCCP(*png_ptr, *info_ptr, basename(icc_profile), PNG_COMPRESSION_TYPE_BASE, icc_buffer, icc_size); + char *icc_profile_cp = strdup(icc_profile); + if (icc_profile_cp == NULL) + { + fprintf(stderr, "Memory allocation failure prevented the setting of PNG ICC profile.\n"); + } + else + { + png_set_iCCP (*png_ptr, + *info_ptr, + basename (icc_profile_cp), + PNG_COMPRESSION_TYPE_BASE, + icc_buffer, + icc_size); + free(icc_profile_cp); + } } else { @@ -1625,11 +1633,11 @@ scan_it (FILE *ofp, void* pw) #ifdef HAVE_LIBPNG if (output_format == OUTPUT_PNG) { - int i = 0; + int idx = 0; int left = len; while(pngrow + left >= parm.bytes_per_line) { - memcpy(pngbuf + pngrow, buffer + i, parm.bytes_per_line - pngrow); + memcpy(pngbuf + pngrow, buffer + idx, parm.bytes_per_line - pngrow); if(parm.depth == 1) { int j; @@ -1652,11 +1660,11 @@ scan_it (FILE *ofp, void* pw) } #endif png_write_row(png_ptr, pngbuf); - i += parm.bytes_per_line - pngrow; + idx += parm.bytes_per_line - pngrow; left -= parm.bytes_per_line - pngrow; pngrow = 0; } - memcpy(pngbuf + pngrow, buffer + i, left); + memcpy(pngbuf + pngrow, buffer + idx, left); pngrow += left; } else @@ -1664,28 +1672,28 @@ scan_it (FILE *ofp, void* pw) #ifdef HAVE_LIBJPEG if (output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) { - int i = 0; + int idx = 0; int left = len; while(jpegrow + left >= parm.bytes_per_line) { - memcpy(jpegbuf + jpegrow, buffer + i, parm.bytes_per_line - jpegrow); + memcpy(jpegbuf + jpegrow, buffer + idx, parm.bytes_per_line - jpegrow); if(parm.depth == 1) { int col1, col8; JSAMPLE *buf8 = malloc(parm.bytes_per_line * 8); for(col1 = 0; col1 < parm.bytes_per_line; col1++) for(col8 = 0; col8 < 8; col8++) - buf8[col1 * 8 + col8] = jpegbuf[col1] & (1 << (8 - col8 - 1)) ? 0 : 0xff; + buf8[col1 * 8 + col8] = (jpegbuf[col1] & (1 << (8 - col8 - 1))) ? 0 : 0xff; jpeg_write_scanlines(&cinfo, &buf8, 1); free(buf8); } else { jpeg_write_scanlines(&cinfo, &jpegbuf, 1); } - i += parm.bytes_per_line - jpegrow; + idx += parm.bytes_per_line - jpegrow; left -= parm.bytes_per_line - jpegrow; jpegrow = 0; } - memcpy(jpegbuf + jpegrow, buffer + i, left); + memcpy(jpegbuf + jpegrow, buffer + idx, left); jpegrow += left; } else @@ -1695,7 +1703,7 @@ scan_it (FILE *ofp, void* pw) else { #if !defined(WORDS_BIGENDIAN) - int i, start = 0; + int start = 0; /* check if we have saved one byte from the last sane_read */ if (hang_over > -1) @@ -1709,12 +1717,12 @@ scan_it (FILE *ofp, void* pw) } } /* now do the byte-swapping */ - for (i = start; i < (len - 1); i += 2) + for (int idx = start; idx < (len - 1); idx += 2) { unsigned char LSB; - LSB = buffer[i]; - buffer[i] = buffer[i + 1]; - buffer[i + 1] = LSB; + LSB = buffer[idx]; + buffer[idx] = buffer[idx + 1]; + buffer[idx + 1] = LSB; } /* check if we have an odd number of bytes */ if (((len - start) % 2) != 0) @@ -1783,13 +1791,12 @@ scan_it (FILE *ofp, void* pw) /* FIXME: other bit depths? */ if (output_format != OUTPUT_TIFF && parm.depth == 16) { - int i; - for (i = 0; i < image.height * image.width; i += 2) + for (int idx = 0; idx < image.height * image.width; idx += 2) { unsigned char LSB; - LSB = image.data[i]; - image.data[i] = image.data[i + 1]; - image.data[i + 1] = LSB; + LSB = image.data[idx]; + image.data[idx] = image.data[idx + 1]; + image.data[idx + 1] = LSB; } } #endif @@ -1996,6 +2003,8 @@ scanimage_exit (int status) fprintf (stderr, "Calling sane_exit\n"); sane_exit (); + if (full_optstring) + free(full_optstring); if (all_options) free (all_options); if (option_number) @@ -2013,15 +2022,12 @@ scanimage_exit (int status) */ static void print_options(SANE_Device * device, SANE_Int num_dev_options, SANE_Bool ro) { - int i, j; - const SANE_Option_Descriptor *opt; - - for (i = 1; i < num_dev_options; ++i) + for (int i = 1; i < num_dev_options; ++i) { - opt = 0; + const SANE_Option_Descriptor *opt = 0; /* scan area uses modified option struct */ - for (j = 0; j < 4; ++j) + for (int j = 0; j < 4; ++j) if (i == window[j]) opt = window_option + j; @@ -2072,36 +2078,31 @@ static int guess_output_format(const char* output_file) } } - // it would be very confusing if user makes a typo in the filename and the output format changes. - // This is most likely not what the user wanted. - fprintf(stderr, "Could not guess output format from the given path and no --format given.\n"); - exit(1); + return OUTPUT_UNKNOWN; } int main (int argc, char **argv) { - int ch, i, index, all_options_len; + int ch, index; const SANE_Device **device_list; SANE_Int num_dev_options = 0; const char *devname = 0; const char *defdevname = 0; const char *format = 0; - char readbuf[2]; - char *readbuf2; int batch = 0; int batch_print = 0; int batch_prompt = 0; int batch_count = BATCH_COUNT_UNLIMITED; int batch_start_at = 1; int batch_increment = 1; + int promptc; SANE_Status status; - char *full_optstring; SANE_Int version_code; void *pw = NULL; FILE *ofp = NULL; - buffer_size = (32 * 1024); /* default size */ + buffer_size = (1024 * 1024); /* default size */ prog_name = strrchr (argv[0], '/'); if (prog_name) @@ -2148,10 +2149,7 @@ main (int argc, char **argv) output_file = optarg; break; case 'B': - if (optarg) - buffer_size = 1024 * atoi(optarg); - else - buffer_size = (1024 * 1024); + buffer_size = 1024 * atoi(optarg); break; case 'T': test = 1; @@ -2190,7 +2188,7 @@ main (int argc, char **argv) output_format = OUTPUT_PNG; #else fprintf(stderr, "PNG support not compiled in\n"); - exit(1); + scanimage_exit (1); #endif } else if (strcmp (optarg, "jpeg") == 0) @@ -2199,7 +2197,7 @@ main (int argc, char **argv) output_format = OUTPUT_JPEG; #else fprintf(stderr, "JPEG support not compiled in\n"); - exit(1); + scanimage_exit (1); #endif } else if (strcmp (optarg, "pdf") == 0) @@ -2208,7 +2206,7 @@ main (int argc, char **argv) output_format = OUTPUT_PDF; #else fprintf(stderr, "PDF support not compiled in\n"); - exit(1); + scanimage_exit (1); #endif } else if (strcmp (optarg, "pnm") == 0) @@ -2226,7 +2224,7 @@ main (int argc, char **argv) fprintf(stderr, ", jpeg"); #endif fprintf(stderr, ".\n"); - exit(1); + scanimage_exit (1); } break; case OPTION_MD5: @@ -2256,14 +2254,14 @@ main (int argc, char **argv) } else { - int i = 0, int_arg = 0; - const char *percent, *start; + int int_arg = 0; + const char *percent; const char *text_arg = 0; char ftype; - for (i = 0; device_list[i]; ++i) + for (int dev_num = 0; device_list[dev_num]; ++dev_num) { - start = optarg; + const char *start = optarg; while (*start && (percent = strchr (start, '%'))) { int start_len = percent - start; @@ -2273,23 +2271,23 @@ main (int argc, char **argv) switch (*percent) { case 'd': - text_arg = device_list[i]->name; + text_arg = device_list[dev_num]->name; ftype = 's'; break; case 'v': - text_arg = device_list[i]->vendor; + text_arg = device_list[dev_num]->vendor; ftype = 's'; break; case 'm': - text_arg = device_list[i]->model; + text_arg = device_list[dev_num]->model; ftype = 's'; break; case 't': - text_arg = device_list[i]->type; + text_arg = device_list[dev_num]->type; ftype = 's'; break; case 'i': - int_arg = i; + int_arg = dev_num; ftype = 'i'; break; case 'n': @@ -2401,12 +2399,20 @@ Parameters are separated by a blank from single-character options (e.g.\n\ if (batch && output_file != NULL) { fprintf(stderr, "--batch and --output-file can't be used together.\n"); - exit(1); + scanimage_exit (1); } if (output_format == OUTPUT_UNKNOWN) - output_format = guess_output_format(output_file); - + { + output_format = guess_output_format(output_file); + if (output_format == OUTPUT_UNKNOWN) + { + // it would be very confusing if user makes a typo in the filename and the output format changes. + // This is most likely not what the user wanted. + fprintf(stderr, "Could not guess output format from the given path and no --format given.\n"); + scanimage_exit (1); + } + } if (!devname) { /* If no device name was specified explicitly, we look at the @@ -2474,7 +2480,7 @@ Parameters are separated by a blank from single-character options (e.g.\n\ } /* malloc global option lists */ - all_options_len = num_dev_options + NELEMS (basic_options) + 1; + int all_options_len = num_dev_options + NELEMS (basic_options) + 1; all_options = malloc (all_options_len * sizeof (all_options[0])); option_number_len = num_dev_options; option_number = malloc (option_number_len * sizeof (option_number[0])); @@ -2579,6 +2585,7 @@ Parameters are separated by a blank from single-character options (e.g.\n\ } free (full_optstring); + full_optstring = NULL; /* convert x/y to br_x/br_y */ for (index = 0; index < 2; ++index) @@ -2624,7 +2631,7 @@ List of available devices:", prog_name); { int column = 80; - for (i = 0; device_list[i]; ++i) + for (int i = 0; device_list[i]; ++i) { if (column + strlen (device_list[i]->name) + 1 >= 80) { @@ -2741,21 +2748,19 @@ List of available devices:", prog_name); if (output_format != OUTPUT_PDF) #endif strcat (part_path, ".part"); - } - - if (batch) - { if (batch_prompt) { fprintf (stderr, "Place document no. %d on the scanner.\n", n); fprintf (stderr, "Press <RETURN> to continue.\n"); - fprintf (stderr, "Press Ctrl + D to terminate.\n"); - readbuf2 = fgets (readbuf, 2, stdin); + fprintf (stderr, "Press Ctrl + D (EOF) to terminate.\n"); + while ((promptc = getchar()) != '\n' && promptc != EOF); - if (readbuf2 == NULL) + if (promptc == EOF) { + if (ferror(stdin)) + fprintf(stderr, "%s: stdin error: %s\n", prog_name, strerror(errno)); if (ofp) { #ifdef HAVE_LIBJPEG |