summaryrefslogtreecommitdiff
path: root/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'frontend')
-rw-r--r--frontend/.gitignore4
-rw-r--r--frontend/Makefile.am19
-rw-r--r--frontend/jpegtopdf.c2
-rw-r--r--frontend/saned.c361
-rw-r--r--frontend/saned.socket10
-rw-r--r--frontend/saned.xinetd.conf.in13
-rw-r--r--frontend/saned@.service.in11
-rw-r--r--frontend/scanimage.c201
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