#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include "http-private.h"
#include "globals.h"
#include "debug.h"
#ifdef HAVE_LIBZ
# include <zlib.h>
#endif
#ifdef WIN32
# include <io.h>
# include <sys/locking.h>
#endif
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
struct _cups_file_s
{
int fd;
char mode,
compressed,
is_stdio,
eof,
buf[4096],
*ptr,
*end;
off_t pos;
#ifdef HAVE_LIBZ
z_stream stream;
Bytef cbuf[4096];
uLong crc;
#endif
};
#ifdef HAVE_LIBZ
static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
#endif
static ssize_t cups_fill(cups_file_t *fp);
static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes);
static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes);
int
cupsFileClose(cups_file_t *fp)
{
int fd;
char mode;
int status;
int is_stdio;
DEBUG_printf(("cupsFileClose(fp=%p)\n", fp));
if (!fp)
return (-1);
if (fp->mode == 'w')
status = cupsFileFlush(fp);
else
status = 0;
#ifdef HAVE_LIBZ
if (fp->compressed && status >= 0)
{
if (fp->mode == 'r')
{
inflateEnd(&fp->stream);
}
else
{
unsigned char trailer[8];
int done;
fp->stream.avail_in = 0;
for (done = 0;;)
{
if (fp->stream.next_out > fp->cbuf)
{
if (cups_write(fp, (char *)fp->cbuf,
fp->stream.next_out - fp->cbuf) < 0)
status = -1;
fp->stream.next_out = fp->cbuf;
fp->stream.avail_out = sizeof(fp->cbuf);
}
if (done || status < 0)
break;
done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END &&
fp->stream.next_out == fp->cbuf;
}
trailer[0] = fp->crc;
trailer[1] = fp->crc >> 8;
trailer[2] = fp->crc >> 16;
trailer[3] = fp->crc >> 24;
trailer[4] = fp->pos;
trailer[5] = fp->pos >> 8;
trailer[6] = fp->pos >> 16;
trailer[7] = fp->pos >> 24;
if (cups_write(fp, (char *)trailer, 8) < 0)
status = -1;
deflateEnd(&(fp->stream));
}
}
#endif
fd = fp->fd;
mode = fp->mode;
is_stdio = fp->is_stdio;
free(fp);
if (mode == 's')
{
if (closesocket(fd) < 0)
status = -1;
}
else if (!is_stdio)
{
if (close(fd) < 0)
status = -1;
}
return (status);
}
int
cupsFileCompression(cups_file_t *fp)
{
return (fp ? fp->compressed : CUPS_FILE_NONE);
}
int
cupsFileEOF(cups_file_t *fp)
{
return (fp ? fp->eof : 1);
}
const char *
cupsFileFind(const char *filename,
const char *path,
int executable,
char *buffer,
int bufsize)
{
char *bufptr,
*bufend;
if (!filename || !buffer || bufsize < 2)
return (NULL);
if (!path)
{
if (!access(filename, 0))
{
strlcpy(buffer, filename, bufsize);
return (buffer);
}
else
return (NULL);
}
bufend = buffer + bufsize - 1;
bufptr = buffer;
while (*path)
{
#ifdef WIN32
if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
#else
if (*path == ';' || *path == ':')
#endif
{
if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
*bufptr++ = '/';
strlcpy(bufptr, filename, bufend - bufptr);
#ifdef WIN32
if (!access(buffer, 0))
#else
if (!access(buffer, executable ? X_OK : 0))
#endif
{
DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
return (buffer);
}
bufptr = buffer;
}
else if (bufptr < bufend)
*bufptr++ = *path;
path ++;
}
if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
*bufptr++ = '/';
strlcpy(bufptr, filename, bufend - bufptr);
if (!access(buffer, 0))
{
DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
return (buffer);
}
else
{
DEBUG_puts("cupsFileFind: Returning NULL");
return (NULL);
}
}
int
cupsFileFlush(cups_file_t *fp)
{
ssize_t bytes;
DEBUG_printf(("cupsFileFlush(fp=%p)\n", fp));
if (!fp || fp->mode != 'w')
{
DEBUG_puts(" Attempt to flush a read-only file...");
return (-1);
}
bytes = (ssize_t)(fp->ptr - fp->buf);
DEBUG_printf((" Flushing %ld bytes...\n", (long)bytes));
if (bytes > 0)
{
#ifdef HAVE_LIBZ
if (fp->compressed)
bytes = cups_compress(fp, fp->buf, bytes);
else
#endif
bytes = cups_write(fp, fp->buf, bytes);
if (bytes < 0)
return (-1);
fp->ptr = fp->buf;
}
return (0);
}
int
cupsFileGetChar(cups_file_t *fp)
{
if (!fp || (fp->mode != 'r' && fp->mode != 's'))
{
DEBUG_puts("cupsFileGetChar: Bad arguments!");
return (-1);
}
if (fp->ptr >= fp->end)
if (cups_fill(fp) < 0)
{
DEBUG_puts("cupsFileGetChar: Unable to fill buffer!");
return (-1);
}
DEBUG_printf(("cupsFileGetChar: Returning %d...\n", *(fp->ptr) & 255));
return (*(fp->ptr)++ & 255);
}
char *
cupsFileGetConf(cups_file_t *fp,
char *buf,
size_t buflen,
char **value,
int *linenum)
{
char *ptr;
if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
!buf || buflen < 2 || !value)
{
if (value)
*value = NULL;
return (NULL);
}
*value = NULL;
while (cupsFileGets(fp, buf, buflen))
{
(*linenum) ++;
if ((ptr = strchr(buf, '#')) != NULL)
{
if (ptr > buf && ptr[-1] == '\\')
{
_cups_strcpy(ptr - 1, ptr);
}
else
{
while (ptr > buf)
{
if (!isspace(ptr[-1] & 255))
break;
ptr --;
}
*ptr = '\0';
}
}
for (ptr = buf; isspace(*ptr & 255); ptr ++);
if (ptr > buf)
_cups_strcpy(buf, ptr);
if (buf[0])
{
for (ptr = buf; *ptr; ptr ++)
if (isspace(*ptr & 255))
break;
if (*ptr)
{
while (isspace(*ptr & 255))
*ptr++ = '\0';
if (*ptr)
*value = ptr;
ptr += strlen(ptr) - 1;
if (buf[0] == '<' && *ptr == '>')
*ptr-- = '\0';
else if (buf[0] == '<' && *ptr != '>')
{
*value = NULL;
return (buf);
}
while (ptr > *value && isspace(*ptr & 255))
*ptr-- = '\0';
}
return (buf);
}
}
return (NULL);
}
size_t
cupsFileGetLine(cups_file_t *fp,
char *buf,
size_t buflen)
{
int ch;
char *ptr,
*end;
if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
return (0);
for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
{
if (fp->ptr >= fp->end)
if (cups_fill(fp) <= 0)
break;
*ptr++ = ch = *(fp->ptr)++;
if (ch == '\r')
{
if (fp->ptr >= fp->end)
if (cups_fill(fp) <= 0)
break;
if (*(fp->ptr) == '\n')
*ptr++ = *(fp->ptr)++;
break;
}
else if (ch == '\n')
{
break;
}
}
*ptr = '\0';
return (ptr - buf);
}
char *
cupsFileGets(cups_file_t *fp,
char *buf,
size_t buflen)
{
int ch;
char *ptr,
*end;
if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
return (NULL);
for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
{
if (fp->ptr >= fp->end)
if (cups_fill(fp) <= 0)
{
if (ptr == buf)
return (NULL);
else
break;
}
ch = *(fp->ptr)++;
if (ch == '\r')
{
if (fp->ptr >= fp->end)
if (cups_fill(fp) <= 0)
break;
if (*(fp->ptr) == '\n')
fp->ptr ++;
break;
}
else if (ch == '\n')
{
break;
}
else
*ptr++ = ch;
}
*ptr = '\0';
return (buf);
}
int
cupsFileLock(cups_file_t *fp,
int block)
{
if (!fp || fp->mode == 's')
return (-1);
#ifdef WIN32
return (locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
#else
return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
#endif
}
int
cupsFileNumber(cups_file_t *fp)
{
return (fp->fd);
}
cups_file_t *
cupsFileOpen(const char *filename,
const char *mode)
{
cups_file_t *fp;
int fd;
char hostname[1024],
*portname;
http_addrlist_t *addrlist;
DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")\n", filename,
mode));
if (!filename || !mode ||
(*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
return (NULL);
switch (*mode)
{
case 'a' :
fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, 0666);
break;
case 'r' :
fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
break;
case 'w' :
fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE | O_BINARY, 0666);
break;
case 's' :
strlcpy(hostname, filename, sizeof(hostname));
if ((portname = strrchr(hostname, ':')) != NULL)
*portname++ = '\0';
else
return (NULL);
if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
return (NULL);
if (!httpAddrConnect(addrlist, &fd))
{
httpAddrFreeList(addrlist);
return (NULL);
}
httpAddrFreeList(addrlist);
break;
default :
return (NULL);
}
if (fd < 0)
return (NULL);
if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
{
if (*mode == 's')
closesocket(fd);
else
close(fd);
}
return (fp);
}
cups_file_t *
cupsFileOpenFd(int fd,
const char *mode)
{
cups_file_t *fp;
DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")\n", fd, mode));
if (fd < 0 || !mode ||
(*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
return (NULL);
if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
return (NULL);
fp->fd = fd;
switch (*mode)
{
case 'w' :
case 'a' :
fp->mode = 'w';
fp->ptr = fp->buf;
fp->end = fp->buf + sizeof(fp->buf);
#ifdef HAVE_LIBZ
if (mode[1] >= '1' && mode[1] <= '9')
{
unsigned char header[10];
time_t curtime;
curtime = time(NULL);
header[0] = 0x1f;
header[1] = 0x8b;
header[2] = Z_DEFLATED;
header[3] = 0;
header[4] = curtime;
header[5] = curtime >> 8;
header[6] = curtime >> 16;
header[7] = curtime >> 24;
header[8] = 0;
header[9] = 0x03;
cups_write(fp, (char *)header, 10);
deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8,
Z_DEFAULT_STRATEGY);
fp->stream.next_out = fp->cbuf;
fp->stream.avail_out = sizeof(fp->cbuf);
fp->compressed = 1;
fp->crc = crc32(0L, Z_NULL, 0);
}
#endif
break;
case 'r' :
fp->mode = 'r';
break;
case 's' :
fp->mode = 's';
break;
default :
return (NULL);
}
#ifndef WIN32
fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
#endif
return (fp);
}
int
cupsFilePeekChar(cups_file_t *fp)
{
if (!fp || (fp->mode != 'r' && fp->mode != 's'))
return (-1);
if (fp->ptr >= fp->end)
if (cups_fill(fp) < 0)
return (-1);
return (*(fp->ptr) & 255);
}
int
cupsFilePrintf(cups_file_t *fp,
const char *format,
...)
{
va_list ap;
ssize_t bytes;
char buf[8192];
DEBUG_printf(("cupsFilePrintf(fp=%p, format=\"%s\", ...)\n", fp, format));
if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
return (-1);
va_start(ap, format);
bytes = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (bytes >= sizeof(buf))
return (-1);
if (fp->mode == 's')
return (cups_write(fp, buf, bytes));
if ((fp->ptr + bytes) > fp->end)
if (cupsFileFlush(fp))
return (-1);
fp->pos += bytes;
if (bytes > sizeof(fp->buf))
{
#ifdef HAVE_LIBZ
if (fp->compressed)
return (cups_compress(fp, buf, bytes));
else
#endif
return (cups_write(fp, buf, bytes));
}
else
{
memcpy(fp->ptr, buf, bytes);
fp->ptr += bytes;
return (bytes);
}
}
int
cupsFilePutChar(cups_file_t *fp,
int c)
{
if (!fp || (fp->mode != 'w' && fp->mode != 's'))
return (-1);
if (fp->mode == 's')
{
char ch;
ch = c;
if (send(fp->fd, &ch, 1, 0) < 1)
return (-1);
}
else
{
if (fp->ptr >= fp->end)
if (cupsFileFlush(fp))
return (-1);
*(fp->ptr) ++ = c;
}
fp->pos ++;
return (0);
}
int
cupsFilePuts(cups_file_t *fp,
const char *s)
{
ssize_t bytes;
if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
return (-1);
bytes = (int)strlen(s);
if (fp->mode == 's')
{
if (cups_write(fp, s, bytes) < 0)
return (-1);
fp->pos += bytes;
return (bytes);
}
if ((fp->ptr + bytes) > fp->end)
if (cupsFileFlush(fp))
return (-1);
fp->pos += bytes;
if (bytes > sizeof(fp->buf))
{
#ifdef HAVE_LIBZ
if (fp->compressed)
return (cups_compress(fp, s, bytes));
else
#endif
return (cups_write(fp, s, bytes));
}
else
{
memcpy(fp->ptr, s, bytes);
fp->ptr += bytes;
return (bytes);
}
}
ssize_t
cupsFileRead(cups_file_t *fp,
char *buf,
size_t bytes)
{
size_t total;
ssize_t count;
DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
(long)bytes));
if (!fp || !buf || bytes < 0 || (fp->mode != 'r' && fp->mode != 's'))
return (-1);
if (bytes == 0)
return (0);
total = 0;
while (bytes > 0)
{
if (fp->ptr >= fp->end)
if (cups_fill(fp) <= 0)
{
DEBUG_printf((" cups_fill() returned -1, total=%d\n", (int)total));
if (total > 0)
return ((ssize_t)total);
else
return (-1);
}
count = (ssize_t)(fp->end - fp->ptr);
if (count > (ssize_t)bytes)
count = (ssize_t)bytes;
memcpy(buf, fp->ptr, count);
fp->ptr += count;
bytes -= count;
total += count;
buf += count;
}
DEBUG_printf((" total=%d\n", (int)total));
return ((ssize_t)total);
}
off_t
cupsFileRewind(cups_file_t *fp)
{
if (!fp || fp->mode != 'r')
return (-1);
if (fp->pos == 0)
{
if (fp->ptr)
{
fp->ptr = fp->buf;
fp->eof = 0;
}
return (0);
}
#ifdef HAVE_LIBZ
if (fp->compressed)
{
inflateEnd(&fp->stream);
fp->compressed = 0;
}
#endif
lseek(fp->fd, 0, SEEK_SET);
fp->pos = 0;
fp->ptr = NULL;
fp->end = NULL;
fp->eof = 0;
return (0);
}
off_t
cupsFileSeek(cups_file_t *fp,
off_t pos)
{
ssize_t bytes;
DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")\n", fp, pos));
DEBUG_printf((" fp->pos=" CUPS_LLFMT "\n", fp->pos));
DEBUG_printf((" fp->ptr=%p, fp->end=%p\n", fp->ptr, fp->end));
if (!fp || pos < 0 || fp->mode != 'r')
return (-1);
if (pos == 0)
return (cupsFileRewind(fp));
if (fp->pos == pos)
{
if (fp->ptr)
{
fp->ptr = fp->buf;
fp->eof = 0;
}
return (pos);
}
#ifdef HAVE_LIBZ
if (!fp->compressed && !fp->ptr)
{
if (cups_fill(fp) < 0)
return (-1);
}
#endif
if (fp->ptr)
bytes = (ssize_t)(fp->end - fp->buf);
else
bytes = 0;
fp->eof = 0;
DEBUG_printf((" bytes=" CUPS_LLFMT "\n", CUPS_LLCAST bytes));
if (pos < fp->pos)
{
DEBUG_puts(" SEEK BACKWARDS");
#ifdef HAVE_LIBZ
if (fp->compressed)
{
inflateEnd(&fp->stream);
lseek(fp->fd, 0, SEEK_SET);
fp->pos = 0;
fp->ptr = NULL;
fp->end = NULL;
while ((bytes = cups_fill(fp)) > 0)
if (pos >= fp->pos && pos < (fp->pos + bytes))
break;
if (bytes <= 0)
return (-1);
fp->ptr = fp->buf + pos - fp->pos;
}
else
#endif
{
fp->pos = lseek(fp->fd, pos, SEEK_SET);
fp->ptr = NULL;
fp->end = NULL;
DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
}
}
else if (pos >= (fp->pos + bytes))
{
DEBUG_puts(" SEEK FORWARDS");
#ifdef HAVE_LIBZ
if (fp->compressed)
{
while ((bytes = cups_fill(fp)) > 0)
{
if (pos >= fp->pos && pos < (fp->pos + bytes))
break;
}
if (bytes <= 0)
return (-1);
fp->ptr = fp->buf + pos - fp->pos;
}
else
#endif
{
fp->pos = lseek(fp->fd, pos, SEEK_SET);
fp->ptr = NULL;
fp->end = NULL;
DEBUG_printf((" lseek() returned " CUPS_LLFMT "...\n", fp->pos));
}
}
else
{
DEBUG_puts(" SEEK INSIDE BUFFER");
fp->ptr = fp->buf + pos - fp->pos;
}
return (fp->pos);
}
cups_file_t *
cupsFileStderr(void)
{
_cups_globals_t *cg = _cupsGlobals();
if (!cg->stdio_files[2])
{
fflush(stderr);
if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
cg->stdio_files[2]->is_stdio = 1;
}
return (cg->stdio_files[2]);
}
cups_file_t *
cupsFileStdin(void)
{
_cups_globals_t *cg = _cupsGlobals();
if (!cg->stdio_files[0])
{
if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
cg->stdio_files[0]->is_stdio = 1;
}
return (cg->stdio_files[0]);
}
cups_file_t *
cupsFileStdout(void)
{
_cups_globals_t *cg = _cupsGlobals();
if (!cg->stdio_files[1])
{
fflush(stdout);
if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
cg->stdio_files[1]->is_stdio = 1;
}
return (cg->stdio_files[1]);
}
off_t
cupsFileTell(cups_file_t *fp)
{
return (fp ? fp->pos : 0);
}
int
cupsFileUnlock(cups_file_t *fp)
{
if (!fp || fp->mode == 's')
return (-1);
#ifdef WIN32
return (locking(fp->fd, _LK_UNLCK, 0));
#else
return (lockf(fp->fd, F_ULOCK, 0));
#endif
}
ssize_t
cupsFileWrite(cups_file_t *fp,
const char *buf,
size_t bytes)
{
if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's'))
return (-1);
if (bytes == 0)
return (0);
if (fp->mode == 's')
{
if (cups_write(fp, buf, bytes) < 0)
return (-1);
fp->pos += (off_t)bytes;
return ((ssize_t)bytes);
}
if ((fp->ptr + bytes) > fp->end)
if (cupsFileFlush(fp))
return (-1);
fp->pos += (off_t)bytes;
if (bytes > sizeof(fp->buf))
{
#ifdef HAVE_LIBZ
if (fp->compressed)
return (cups_compress(fp, buf, bytes));
else
#endif
return (cups_write(fp, buf, bytes));
}
else
{
memcpy(fp->ptr, buf, bytes);
fp->ptr += bytes;
return ((ssize_t)bytes);
}
}
#ifdef HAVE_LIBZ
static ssize_t
cups_compress(cups_file_t *fp,
const char *buf,
size_t bytes)
{
DEBUG_printf(("cups_compress(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
(long)bytes));
fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes);
fp->stream.next_in = (Bytef *)buf;
fp->stream.avail_in = bytes;
while (fp->stream.avail_in > 0)
{
DEBUG_printf((" avail_in=%d, avail_out=%d\n", fp->stream.avail_in,
fp->stream.avail_out));
if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
{
if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
return (-1);
fp->stream.next_out = fp->cbuf;
fp->stream.avail_out = sizeof(fp->cbuf);
}
deflate(&(fp->stream), Z_NO_FLUSH);
}
return (bytes);
}
#endif
static ssize_t
cups_fill(cups_file_t *fp)
{
ssize_t bytes;
#ifdef HAVE_LIBZ
int status;
const unsigned char *ptr,
*end;
#endif
DEBUG_printf(("cups_fill(fp=%p)\n", fp));
DEBUG_printf((" fp->ptr=%p, fp->end=%p, fp->buf=%p, "
"fp->pos=" CUPS_LLFMT ", fp->eof=%d\n",
fp->ptr, fp->end, fp->buf, fp->pos, fp->eof));
if (fp->ptr && fp->end)
fp->pos += (off_t)(fp->end - fp->buf);
#ifdef HAVE_LIBZ
DEBUG_printf((" fp->compressed=%d\n", fp->compressed));
while (!fp->ptr || fp->compressed)
{
if (!fp->ptr)
{
fp->compressed = 0;
if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
{
DEBUG_printf((" cups_read() returned " CUPS_LLFMT "!\n",
CUPS_LLCAST bytes));
return (-1);
}
if (bytes < 10 || fp->buf[0] != 0x1f ||
(fp->buf[1] & 255) != 0x8b ||
fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
{
fp->ptr = fp->buf;
fp->end = fp->buf + bytes;
DEBUG_printf((" returning " CUPS_LLFMT "!\n", CUPS_LLCAST bytes));
return (bytes);
}
ptr = (unsigned char *)fp->buf + 10;
end = (unsigned char *)fp->buf + bytes;
if (fp->buf[3] & 0x04)
{
if ((ptr + 2) > end)
{
return (-1);
}
bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
ptr += 2 + bytes;
if (ptr > end)
{
return (-1);
}
}
if (fp->buf[3] & 0x08)
{
while (ptr < end && *ptr)
ptr ++;
if (ptr < end)
ptr ++;
else
{
return (-1);
}
}
if (fp->buf[3] & 0x10)
{
while (ptr < end && *ptr)
ptr ++;
if (ptr < end)
ptr ++;
else
{
return (-1);
}
}
if (fp->buf[3] & 0x02)
{
ptr += 2;
if (ptr > end)
{
return (-1);
}
}
if ((bytes = end - ptr) > 0)
memcpy(fp->cbuf, ptr, bytes);
fp->stream.zalloc = (alloc_func)0;
fp->stream.zfree = (free_func)0;
fp->stream.opaque = (voidpf)0;
fp->stream.next_in = (Bytef *)fp->cbuf;
fp->stream.next_out = NULL;
fp->stream.avail_in = bytes;
fp->stream.avail_out = 0;
fp->crc = crc32(0L, Z_NULL, 0);
if (inflateInit2(&(fp->stream), -15) != Z_OK)
return (-1);
fp->compressed = 1;
}
if (fp->compressed)
{
if (fp->eof)
return (-1);
if (fp->stream.avail_in == 0)
{
if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
return (-1);
fp->stream.next_in = fp->cbuf;
fp->stream.avail_in = bytes;
}
fp->stream.next_out = (Bytef *)fp->buf;
fp->stream.avail_out = sizeof(fp->buf);
status = inflate(&(fp->stream), Z_NO_FLUSH);
if (fp->stream.next_out > (Bytef *)fp->buf)
fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
fp->stream.next_out - (Bytef *)fp->buf);
if (status == Z_STREAM_END)
{
unsigned char trailer[8];
uLong tcrc;
if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
{
fp->eof = 1;
}
else
{
tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
trailer[0];
if (tcrc != fp->crc)
{
DEBUG_printf(("cups_fill: tcrc=%08x, fp->crc=%08x\n",
(unsigned int)tcrc, (unsigned int)fp->crc));
fp->eof = 1;
return (-1);
}
fp->compressed = 0;
}
}
bytes = sizeof(fp->buf) - fp->stream.avail_out;
fp->ptr = fp->buf;
fp->end = fp->buf + bytes;
if (bytes)
return (bytes);
}
}
#endif
if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
{
fp->eof = 1;
fp->ptr = fp->buf;
fp->end = fp->buf;
return (-1);
}
fp->eof = 0;
fp->ptr = fp->buf;
fp->end = fp->buf + bytes;
return (bytes);
}
static ssize_t
cups_read(cups_file_t *fp,
char *buf,
size_t bytes)
{
ssize_t total;
for (;;)
{
#ifdef WIN32
if (fp->mode == 's')
total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
else
total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
#else
if (fp->mode == 's')
total = recv(fp->fd, buf, bytes, 0);
else
total = read(fp->fd, buf, bytes);
#endif
if (total >= 0)
break;
if (errno == EAGAIN || errno == EINTR)
continue;
else
return (-1);
}
return (total);
}
static ssize_t
cups_write(cups_file_t *fp,
const char *buf,
size_t bytes)
{
size_t total;
ssize_t count;
DEBUG_printf(("cups_write(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
(long)bytes));
total = 0;
while (bytes > 0)
{
#ifdef WIN32
if (fp->mode == 's')
count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
else
count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
#else
if (fp->mode == 's')
count = send(fp->fd, buf, bytes, 0);
else
count = write(fp->fd, buf, bytes);
#endif
if (count < 0)
{
if (errno == EAGAIN || errno == EINTR)
continue;
else
return (-1);
}
DEBUG_printf((" count=%ld\n", (long)count));
bytes -= count;
total += count;
buf += count;
}
return ((ssize_t)total);
}