]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/file.c
Merge changes from CUPS trunk, r7566.
[thirdparty/cups.git] / cups / file.c
index 20aae7247947725318354f2b8a5546a34dee936a..d3726cf53448e4513f1e5dbff484dffb61537c63 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: file.c 5186 2006-02-26 18:56:05Z mike $"
+ * "$Id: file.c 6962 2007-09-17 20:35:47Z mike $"
  *
  *   File functions for the Common UNIX Printing System (CUPS).
  *
@@ -8,23 +8,14 @@
  *   our own file functions allows us to provide transparent support of
  *   gzip'd print files, PPD files, etc.
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  * Contents:
  *
  *   cupsFileFlush()       - Flush pending output.
  *   cupsFileGetChar()     - Get a single character from a file.
  *   cupsFileGetConf()     - Get a line from a configuration file...
+ *   cupsFileGetLine()     - Get a CR and/or LF-terminated line that may contain
+ *                           binary data.
  *   cupsFileGets()        - Get a CR and/or LF-terminated line.
  *   cupsFileLock()        - Temporarily lock access to a file.
- *   cupsFileNumber()      - Return the file descriptor associated with a CUPS file.
+ *   cupsFileNumber()      - Return the file descriptor associated with a CUPS
+ *                           file.
  *   cupsFileOpen()        - Open a CUPS file.
  *   cupsFileOpenFd()      - Open a CUPS file using a file descriptor.
  *   cupsFilePeekChar()    - Peek at the next character from a file.
  *   cupsFilePutChar()     - Write a character.
  *   cupsFilePuts()        - Write a string.
  *   cupsFileRead()        - Read from a file.
- *   cupsFileRewind()      - Rewind a file.
+ *   cupsFileRewind()      - Set the current file position to the beginning of
+ *                           the file.
  *   cupsFileSeek()        - Seek in a file.
+ *   cupsFileStderr()      - Return a CUPS file associated with stderr.
+ *   cupsFileStdin()       - Return a CUPS file associated with stdin.
+ *   cupsFileStdout()      - Return a CUPS file associated with stdout.
  *   cupsFileTell()        - Return the current file position.
  *   cupsFileUnlock()      - Unlock access to a file.
  *   cupsFileWrite()       - Write to a file.
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
-#include "http-private.h"
-#include "string.h"
 #include <errno.h>
-#include <cups/debug.h>
 #include <sys/types.h>
 #include <fcntl.h>
+#include "http-private.h"
+#include "globals.h"
+#include "debug.h"
 
-#include "file.h"
 #ifdef HAVE_LIBZ
 #  include <zlib.h>
 #endif /* HAVE_LIBZ */
 #endif /* !O_LARGEFILE */
 
 
+/*
+ * Some operating systems don't define O_BINARY, which is used by Microsoft
+ * and IBM to flag binary files...
+ */
+
+#ifndef O_BINARY
+#  define O_BINARY 0
+#endif /* !O_BINARY */
+
+
 /*
  * Types and structures...
  */
@@ -99,11 +106,13 @@ struct _cups_file_s                        /**** CUPS file structure... ****/
   int          fd;                     /* File descriptor */
   char         mode,                   /* Mode ('r' or 'w') */
                compressed,             /* Compression used? */
+               is_stdio,               /* stdin/out/err? */
                eof,                    /* End of file? */
                buf[4096],              /* Buffer */
                *ptr,                   /* Pointer into buffer */
                *end;                   /* End of buffer data */
-  off_t                pos;                    /* File position for start of buffer */
+  off_t                pos,                    /* Position in file */
+               bufpos;                 /* File position for start of buffer */
 
 #ifdef HAVE_LIBZ
   z_stream     stream;                 /* (De)compression stream */
@@ -127,6 +136,8 @@ static ssize_t      cups_write(cups_file_t *fp, const char *buf, size_t bytes);
 
 /*
  * 'cupsFileClose()' - Close a CUPS file.
+ *
+ * @since CUPS 1.2@
  */
 
 int                                    /* O - 0 on success, -1 on error */
@@ -135,6 +146,7 @@ cupsFileClose(cups_file_t *fp)              /* I - CUPS file */
   int  fd;                             /* File descriptor */
   char mode;                           /* Open mode */
   int  status;                         /* Return status */
+  int  is_stdio;                       /* Is a stdio file? */
 
 
   DEBUG_printf(("cupsFileClose(fp=%p)\n", fp));
@@ -226,8 +238,9 @@ cupsFileClose(cups_file_t *fp)              /* I - CUPS file */
   * Save the file descriptor we used and free memory...
   */
 
-  fd   = fp->fd;
-  mode = fp->mode;
+  fd       = fp->fd;
+  mode     = fp->mode;
+  is_stdio = fp->is_stdio;
 
   free(fp);
 
@@ -240,7 +253,7 @@ cupsFileClose(cups_file_t *fp)              /* I - CUPS file */
     if (closesocket(fd) < 0)
       status = -1;
   }
-  else
+  else if (!is_stdio)
   {
     if (close(fd) < 0)
       status = -1;
@@ -252,23 +265,27 @@ cupsFileClose(cups_file_t *fp)            /* I - CUPS file */
 
 /*
  * 'cupsFileCompression()' - Return whether a file is compressed.
+ *
+ * @since CUPS 1.2@
  */
 
-int                                    /* O - CUPS_FILE_NONE or CUPS_FILE_GZIP */
+int                                    /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */
 cupsFileCompression(cups_file_t *fp)   /* I - CUPS file */
 {
-  return (fp->compressed);
+  return (fp ? fp->compressed : CUPS_FILE_NONE);
 }
 
 
 /*
  * 'cupsFileEOF()' - Return the end-of-file status.
+ *
+ * @since CUPS 1.2@
  */
 
-int                                    /* O - 1 on EOF, 0 otherwise */
+int                                    /* O - 1 on end of file, 0 otherwise */
 cupsFileEOF(cups_file_t *fp)           /* I - CUPS file */
 {
-  return (fp->eof);
+  return (fp ? fp->eof : 1);
 }
 
 
@@ -278,11 +295,13 @@ cupsFileEOF(cups_file_t *fp)              /* I - CUPS file */
  * This function allows the paths in the path string to be separated by
  * colons (UNIX standard) or semicolons (Windows standard) and stores the
  * result in the buffer supplied.  If the file cannot be found in any of
- * the supplied paths, NULL is returned. A NULL path only matches the
- * current directory.
+ * the supplied paths, @code NULL@ is returned. A @code NULL@ path only
+ * matches the current directory.
+ *
+ * @since CUPS 1.2@
  */
 
-const char *                           /* O - Full path to file or NULL */
+const char *                           /* O - Full path to file or @code NULL@ if not found */
 cupsFileFind(const char *filename,     /* I - File to find */
              const char *path,         /* I - Colon/semicolon-separated path */
              int        executable,    /* I - 1 = executable files, 0 = any file/dir */
@@ -324,7 +343,11 @@ cupsFileFind(const char *filename, /* I - File to find */
 
   while (*path)
   {
+#ifdef WIN32
+    if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
+#else
     if (*path == ';' || *path == ':')
+#endif /* WIN32 */
     {
       if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
         *bufptr++ = '/';
@@ -336,7 +359,10 @@ cupsFileFind(const char *filename, /* I - File to find */
 #else
       if (!access(buffer, executable ? X_OK : 0))
 #endif /* WIN32 */
+      {
+        DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
         return (buffer);
+      }
 
       bufptr = buffer;
     }
@@ -356,20 +382,28 @@ cupsFileFind(const char *filename,        /* I - File to find */
   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);
+  }
 }
 
 
 /*
  * 'cupsFileFlush()' - Flush pending output.
+ *
+ * @since CUPS 1.2@
  */
 
 int                                    /* O - 0 on success, -1 on error */
 cupsFileFlush(cups_file_t *fp)         /* I - CUPS file */
 {
-  size_t       bytes;                  /* Bytes to write */
+  ssize_t      bytes;                  /* Bytes to write */
 
 
   DEBUG_printf(("cupsFileFlush(fp=%p)\n", fp));
@@ -380,13 +414,14 @@ cupsFileFlush(cups_file_t *fp)            /* I - CUPS file */
 
   if (!fp || fp->mode != 'w')
   {
-    DEBUG_puts("    Attempt to flush a read-only file...");
+    DEBUG_puts("cupsFileFlush: Attempt to flush a read-only file...");
     return (-1);
   }
 
-  bytes = fp->ptr - fp->buf;
+  bytes = (ssize_t)(fp->ptr - fp->buf);
 
-  DEBUG_printf(("    Flushing %ld bytes...\n", (long)bytes));
+  DEBUG_printf(("cupsFileFlush: Flushing " CUPS_LLFMT " bytes...\n",
+                CUPS_LLCAST bytes));
 
   if (bytes > 0)
   {
@@ -409,17 +444,24 @@ cupsFileFlush(cups_file_t *fp)            /* I - CUPS file */
 
 /*
  * 'cupsFileGetChar()' - Get a single character from a file.
+ *
+ * @since CUPS 1.2@
  */
 
-int                                    /* O - Character or -1 on EOF */
+int                                    /* O - Character or -1 on end of file */
 cupsFileGetChar(cups_file_t *fp)       /* I - CUPS file */
 {
  /*
   * Range check input...
   */
 
+  DEBUG_printf(("cupsFileGetChar(fp=%p)\n", fp));
+
   if (!fp || (fp->mode != 'r' && fp->mode != 's'))
+  {
+    DEBUG_puts("cupsFileGetChar: Bad arguments!");
     return (-1);
+  }
 
  /*
   * If the input buffer is empty, try to read more data...
@@ -427,21 +469,32 @@ cupsFileGetChar(cups_file_t *fp)  /* I - CUPS file */
 
   if (fp->ptr >= fp->end)
     if (cups_fill(fp) < 0)
+    {
+      DEBUG_puts("cupsFileGetChar: Unable to fill buffer!");
       return (-1);
+    }
 
  /*
   * Return the next character in the buffer...
   */
 
+  DEBUG_printf(("cupsFileGetChar: Returning %d...\n", *(fp->ptr) & 255));
+
+  fp->pos ++;
+
+  DEBUG_printf(("cupsFileGetChar: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
   return (*(fp->ptr)++ & 255);
 }
 
 
 /*
  * 'cupsFileGetConf()' - Get a line from a configuration file...
+ *
+ * @since CUPS 1.2@
  */
 
-char *                                 /* O  - Line read or NULL on eof/error */
+char *                                 /* O  - Line read or @code NULL@ on end of file or error */
 cupsFileGetConf(cups_file_t *fp,       /* I  - CUPS file */
                 char        *buf,      /* O  - String buffer */
                size_t      buflen,     /* I  - Size of string buffer */
@@ -455,6 +508,10 @@ cupsFileGetConf(cups_file_t *fp,   /* I  - CUPS file */
   * Range check input...
   */
 
+  DEBUG_printf(("cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT
+                ", value=%p, linenum=%p)\n", fp, buf, CUPS_LLCAST buflen,
+               value, linenum));
+
   if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
       !buf || buflen < 2 || !value)
   {
@@ -469,7 +526,7 @@ cupsFileGetConf(cups_file_t *fp,    /* I  - CUPS file */
   */
 
   *value = NULL;
-  
+
   while (cupsFileGets(fp, buf, buflen))
   {
     (*linenum) ++;
@@ -480,15 +537,24 @@ cupsFileGetConf(cups_file_t *fp,  /* I  - CUPS file */
 
     if ((ptr = strchr(buf, '#')) != NULL)
     {
-      while (ptr > buf)
+      if (ptr > buf && ptr[-1] == '\\')
       {
-       if (!isspace(ptr[-1] & 255))
-         break;
-
-        ptr --;
+        // Unquote the #...
+       _cups_strcpy(ptr - 1, ptr);
       }
+      else
+      {
+        // Strip the comment and any trailing whitespace...
+       while (ptr > buf)
+       {
+         if (!isspace(ptr[-1] & 255))
+           break;
 
-      *ptr = '\0';
+         ptr --;
+       }
+
+       *ptr = '\0';
+      }
     }
 
    /*
@@ -560,11 +626,94 @@ cupsFileGetConf(cups_file_t *fp,  /* I  - CUPS file */
 }
 
 
+/*
+ * 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
+ *                       contain binary data.
+ *
+ * This function differs from @link cupsFileGets@ in that the trailing CR
+ * and LF are preserved, as is any binary data on the line. The buffer is
+ * nul-terminated, however you should use the returned length to determine
+ * the number of bytes on the line.
+ *
+ * @since CUPS 1.2@
+ */
+
+size_t                                 /* O - Number of bytes on line or 0 on end of file */
+cupsFileGetLine(cups_file_t *fp,       /* I - File to read from */
+                char        *buf,      /* I - Buffer */
+                size_t      buflen)    /* I - Size of buffer */
+{
+  int          ch;                     /* Character from file */
+  char         *ptr,                   /* Current position in line buffer */
+               *end;                   /* End of line buffer */
+
+
+ /*
+  * Range check input...
+  */
+
+  DEBUG_printf(("cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")\n",
+                fp, buf, CUPS_LLCAST buflen));
+
+  if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
+    return (0);
+
+ /*
+  * Now loop until we have a valid line...
+  */
+
+  for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
+  {
+    if (fp->ptr >= fp->end)
+      if (cups_fill(fp) <= 0)
+        break;
+
+    *ptr++ = ch = *(fp->ptr)++;
+    fp->pos ++;
+
+    if (ch == '\r')
+    {
+     /*
+      * Check for CR LF...
+      */
+
+      if (fp->ptr >= fp->end)
+       if (cups_fill(fp) <= 0)
+          break;
+
+      if (*(fp->ptr) == '\n')
+      {
+        *ptr++ = *(fp->ptr)++;
+       fp->pos ++;
+      }
+
+      break;
+    }
+    else if (ch == '\n')
+    {
+     /*
+      * Line feed ends a line...
+      */
+
+      break;
+    }
+  }
+
+  *ptr = '\0';
+
+  DEBUG_printf(("cupsFileGetLine: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+  return (ptr - buf);
+}
+
+
 /*
  * 'cupsFileGets()' - Get a CR and/or LF-terminated line.
+ *
+ * @since CUPS 1.2@
  */
 
-char *                                 /* O - Line read or NULL on eof/error */
+char *                                 /* O - Line read or @code NULL@ on end of file or error */
 cupsFileGets(cups_file_t *fp,          /* I - CUPS file */
              char        *buf,         /* O - String buffer */
             size_t      buflen)        /* I - Size of string buffer */
@@ -578,6 +727,9 @@ cupsFileGets(cups_file_t *fp,               /* I - CUPS file */
   * Range check input...
   */
 
+  DEBUG_printf(("cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")\n", fp, buf,
+                CUPS_LLCAST buflen));
+
   if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
     return (NULL);
 
@@ -597,6 +749,7 @@ cupsFileGets(cups_file_t *fp,               /* I - CUPS file */
       }
 
     ch = *(fp->ptr)++;
+    fp->pos ++;
 
     if (ch == '\r')
     {
@@ -609,7 +762,10 @@ cupsFileGets(cups_file_t *fp,              /* I - CUPS file */
           break;
 
       if (*(fp->ptr) == '\n')
-        fp->ptr ++;      
+      {
+        fp->ptr ++;
+       fp->pos ++;
+      }
 
       break;
     }
@@ -627,16 +783,20 @@ cupsFileGets(cups_file_t *fp,             /* I - CUPS file */
 
   *ptr = '\0';
 
+  DEBUG_printf(("cupsFileGets: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
   return (buf);
 }
 
 
 /*
  * 'cupsFileLock()' - Temporarily lock access to a file.
+ *
+ * @since CUPS 1.2@
  */
 
 int                                    /* O - 0 on success, -1 on error */
-cupsFileLock(cups_file_t *fp,          /* I - File to lock */
+cupsFileLock(cups_file_t *fp,          /* I - CUPS file */
              int         block)                /* I - 1 to wait for the lock, 0 to fail right away */
 {
  /*
@@ -660,20 +820,40 @@ cupsFileLock(cups_file_t *fp,             /* I - File to lock */
 
 /*
  * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
+ *
+ * @since CUPS 1.2@
  */
 
 int                                    /* O - File descriptor */
 cupsFileNumber(cups_file_t *fp)                /* I - CUPS file */
 {
-  return (fp->fd);
+  if (fp)
+    return (fp->fd);
+  else
+    return (-1);
 }
 
 
 /*
  * 'cupsFileOpen()' - Open a CUPS file.
+ *
+ * The "mode" parameter can be "r" to read, "w" to write, overwriting any
+ * existing file, "a" to append to an existing file or create a new file,
+ * or "s" to open a socket connection.
+ *
+ * When opening for writing ("w"), an optional number from 1 to 9 can be
+ * supplied which enables Flate compression of the file.  Compression is
+ * not supported for the "a" (append) mode.
+ *
+ * When opening a socket connection, the filename is a string of the form
+ * "address:port" or "hostname:port". The socket will make an IPv4 or IPv6
+ * connection as needed, generally preferring IPv6 connections when there is
+ * a choice.
+ *
+ * @since CUPS 1.2@
  */
 
-cups_file_t *                          /* O - CUPS file or NULL */
+cups_file_t *                          /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */
 cupsFileOpen(const char *filename,     /* I - Name of file */
              const char *mode)         /* I - Open mode */
 {
@@ -692,7 +872,8 @@ cupsFileOpen(const char *filename,  /* I - Name of file */
   */
 
   if (!filename || !mode ||
-      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
+      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
+      (*mode == 'a' && isdigit(mode[1] & 255)))
     return (NULL);
 
  /*
@@ -702,15 +883,15 @@ cupsFileOpen(const char *filename,        /* I - Name of file */
   switch (*mode)
   {
     case 'a' : /* Append file */
-        fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE, 0666);
+        fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, 0666);
         break;
 
     case 'r' : /* Read file */
-       fd = open(filename, O_RDONLY | O_LARGEFILE, 0);
+       fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
        break;
 
     case 'w' : /* Write file */
-        fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE, 0666);
+        fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE | O_BINARY, 0666);
         break;
 
     case 's' : /* Read/write socket */
@@ -768,9 +949,18 @@ cupsFileOpen(const char *filename, /* I - Name of file */
 
 /*
  * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
+ *
+ * The "mode" parameter can be "r" to read, "w" to write, "a" to append,
+ * or "s" to treat the file descriptor as a bidirectional socket connection.
+ *
+ * When opening for writing ("w"), an optional number from 1 to 9 can be
+ * supplied which enables Flate compression of the file.  Compression is
+ * not supported for the "a" (append) mode.
+ *
+ * @since CUPS 1.2@
  */
 
-cups_file_t *                          /* O - CUPS file or NULL */
+cups_file_t *                          /* O - CUPS file or @code NULL@ if the file could not be opened */
 cupsFileOpenFd(int        fd,          /* I - File descriptor */
               const char *mode)        /* I - Open mode */
 {
@@ -784,7 +974,8 @@ cupsFileOpenFd(int        fd,               /* I - File descriptor */
   */
 
   if (fd < 0 || !mode ||
-      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
+      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
+      (*mode == 'a' && isdigit(mode[1] & 255)))
     return (NULL);
 
  /*
@@ -802,8 +993,10 @@ cupsFileOpenFd(int        fd,              /* I - File descriptor */
 
   switch (*mode)
   {
-    case 'w' :
     case 'a' :
+        fp->pos = lseek(fd, 0, SEEK_END);
+
+    case 'w' :
        fp->mode = 'w';
        fp->ptr  = fp->buf;
        fp->end  = fp->buf + sizeof(fp->buf);
@@ -875,9 +1068,11 @@ cupsFileOpenFd(int        fd,             /* I - File descriptor */
 
 /*
  * 'cupsFilePeekChar()' - Peek at the next character from a file.
+ *
+ * @since CUPS 1.2@
  */
 
-int                                    /* O - Character or -1 on EOF */
+int                                    /* O - Character or -1 on end of file */
 cupsFilePeekChar(cups_file_t *fp)      /* I - CUPS file */
 {
  /*
@@ -905,15 +1100,17 @@ cupsFilePeekChar(cups_file_t *fp)        /* I - CUPS file */
 
 /*
  * 'cupsFilePrintf()' - Write a formatted string.
+ *
+ * @since CUPS 1.2@
  */
 
-int                                    /* O - Number of bytes written or -1 */
+int                                    /* O - Number of bytes written or -1 on error */
 cupsFilePrintf(cups_file_t *fp,                /* I - CUPS file */
                const char  *format,    /* I - Printf-style format string */
               ...)                     /* I - Additional args as necessary */
 {
   va_list      ap;                     /* Argument list */
-  size_t       bytes;                  /* Formatted size */
+  ssize_t      bytes;                  /* Formatted size */
   char         buf[8192];              /* Formatted text */
 
 
@@ -930,7 +1127,16 @@ cupsFilePrintf(cups_file_t *fp,           /* I - CUPS file */
     return (-1);
 
   if (fp->mode == 's')
-    return (cups_write(fp, buf, bytes));
+  {
+    if (cups_write(fp, buf, bytes) < 0)
+      return (-1);
+
+    fp->pos += bytes;
+
+    DEBUG_printf(("cupsFilePrintf: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+    return (bytes);
+  }
 
   if ((fp->ptr + bytes) > fp->end)
     if (cupsFileFlush(fp))
@@ -938,6 +1144,8 @@ cupsFilePrintf(cups_file_t *fp,            /* I - CUPS file */
 
   fp->pos += bytes;
 
+  DEBUG_printf(("cupsFilePrintf: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
   if (bytes > sizeof(fp->buf))
   {
 #ifdef HAVE_LIBZ
@@ -958,6 +1166,8 @@ cupsFilePrintf(cups_file_t *fp,            /* I - CUPS file */
 
 /*
  * 'cupsFilePutChar()' - Write a character.
+ *
+ * @since CUPS 1.2@
  */
 
 int                                    /* O - 0 on success, -1 on error */
@@ -1000,19 +1210,25 @@ cupsFilePutChar(cups_file_t *fp,        /* I - CUPS file */
 
   fp->pos ++;
 
+  DEBUG_printf(("cupsFilePutChar: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
   return (0);
 }
 
 
 /*
  * 'cupsFilePuts()' - Write a string.
+ *
+ * Like the @code fputs@ function, no newline is appended to the string.
+ *
+ * @since CUPS 1.2@
  */
 
-int                                    /* O - Number of bytes written or -1 */
+int                                    /* O - Number of bytes written or -1 on error */
 cupsFilePuts(cups_file_t *fp,          /* I - CUPS file */
              const char  *s)           /* I - String to write */
 {
-  size_t       bytes;                  /* Bytes to write */
+  ssize_t      bytes;                  /* Bytes to write */
 
 
  /*
@@ -1026,7 +1242,7 @@ cupsFilePuts(cups_file_t *fp,             /* I - CUPS file */
   * Write the string...
   */
 
-  bytes = strlen(s);
+  bytes = (int)strlen(s);
 
   if (fp->mode == 's')
   {
@@ -1035,6 +1251,8 @@ cupsFilePuts(cups_file_t *fp,             /* I - CUPS file */
 
     fp->pos += bytes;
 
+    DEBUG_printf(("cupsFilePuts: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
     return (bytes);
   }
 
@@ -1044,6 +1262,8 @@ cupsFilePuts(cups_file_t *fp,             /* I - CUPS file */
 
   fp->pos += bytes;
 
+  DEBUG_printf(("cupsFilePuts: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
   if (bytes > sizeof(fp->buf))
   {
 #ifdef HAVE_LIBZ
@@ -1064,19 +1284,21 @@ cupsFilePuts(cups_file_t *fp,           /* I - CUPS file */
 
 /*
  * 'cupsFileRead()' - Read from a file.
+ *
+ * @since CUPS 1.2@
  */
 
-ssize_t                                        /* O - Number of bytes read or -1 */
+ssize_t                                        /* O - Number of bytes read or -1 on error */
 cupsFileRead(cups_file_t *fp,          /* I - CUPS file */
              char        *buf,         /* O - Buffer */
             size_t      bytes)         /* I - Number of bytes to read */
 {
-  size_t       total,                  /* Total bytes read */
-               count;                  /* Bytes read */
+  size_t       total;                  /* Total bytes read */
+  ssize_t      count;                  /* Bytes read */
 
 
-  DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
-                (long)bytes));
+  DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+                CUPS_LLCAST bytes));
 
  /*
   * Range check input...
@@ -1098,20 +1320,24 @@ cupsFileRead(cups_file_t *fp,           /* I - CUPS file */
     if (fp->ptr >= fp->end)
       if (cups_fill(fp) <= 0)
       {
-        DEBUG_printf(("    cups_fill() returned -1, total=%d\n", total));
+        DEBUG_printf(("cupsFileRead: cups_fill() returned -1, total=" CUPS_LLFMT "\n",
+                     CUPS_LLCAST total));
 
         if (total > 0)
-          return (total);
+          return ((ssize_t)total);
        else
          return (-1);
       }
 
-    count = fp->end - fp->ptr;
-    if (count > bytes)
-      count = bytes;
+    count = (ssize_t)(fp->end - fp->ptr);
+    if (count > (ssize_t)bytes)
+      count = (ssize_t)bytes;
 
     memcpy(buf, fp->ptr, count);
     fp->ptr += count;
+    fp->pos += count;
+
+    DEBUG_printf(("cupsFileRead: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
 
    /*
     * Update the counts for the last read...
@@ -1126,37 +1352,102 @@ cupsFileRead(cups_file_t *fp,          /* I - CUPS file */
   * Return the total number of bytes read...
   */
 
-  DEBUG_printf(("    total=%d\n", total));
+  DEBUG_printf(("cupsFileRead: total=%d\n", (int)total));
 
-  return (total);
+  return ((ssize_t)total);
 }
 
 
 /*
- * 'cupsFileRewind()' - Rewind a file.
+ * 'cupsFileRewind()' - Set the current file position to the beginning of the
+ *                      file.
+ *
+ * @since CUPS 1.2@
  */
 
-off_t                                  /* O - New file position or -1 */
+off_t                                  /* O - New file position or -1 on error */
 cupsFileRewind(cups_file_t *fp)                /* I - CUPS file */
 {
-  return (cupsFileSeek(fp, 0L));
+ /*
+  * Range check input...
+  */
+
+  DEBUG_printf(("cupsFileRewind(fp=%p)\n", fp));
+  DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+  if (!fp || fp->mode != 'r')
+    return (-1);
+
+ /*
+  * Handle special cases...
+  */
+
+  if (fp->bufpos == 0)
+  {
+   /*
+    * No seeking necessary...
+    */
+
+    fp->pos = 0;
+
+    if (fp->ptr)
+    {
+      fp->ptr = fp->buf;
+      fp->eof = 0;
+    }
+
+    DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+    return (0);
+  }
+
+ /*
+  * Otherwise, seek in the file and cleanup any compression buffers...
+  */
+
+#ifdef HAVE_LIBZ
+  if (fp->compressed)
+  {
+    inflateEnd(&fp->stream);
+    fp->compressed = 0;
+  }
+#endif /* HAVE_LIBZ */
+
+  if (lseek(fp->fd, 0, SEEK_SET))
+  {
+    DEBUG_printf(("cupsFileRewind: lseek failed: %s\n", strerror(errno)));
+    return (-1);
+  }
+
+  fp->bufpos = 0;
+  fp->pos    = 0;
+  fp->ptr    = NULL;
+  fp->end    = NULL;
+  fp->eof    = 0;
+
+  DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+  return (0);
 }
 
 
 /*
  * 'cupsFileSeek()' - Seek in a file.
+ *
+ * @since CUPS 1.2@
  */
 
-off_t                                  /* O - New file position or -1 */
+off_t                                  /* O - New file position or -1 on error */
 cupsFileSeek(cups_file_t *fp,          /* I - CUPS file */
              off_t       pos)          /* I - Position in file */
 {
-  size_t       bytes;                  /* Number bytes in buffer */
+  ssize_t      bytes;                  /* Number bytes in buffer */
 
 
-  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));
+  DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")\n", fp,
+                CUPS_LLCAST pos));
+  DEBUG_printf(("cupsFileSeek: fp->pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("cupsFileSeek: fp->ptr=%p, fp->end=%p\n", fp->ptr, fp->end));
 
  /*
   * Range check input...
@@ -1165,123 +1456,267 @@ cupsFileSeek(cups_file_t *fp,         /* I - CUPS file */
   if (!fp || pos < 0 || fp->mode != 'r')
     return (-1);
 
-  if (fp->pos == pos)
+ /*
+  * Handle special cases...
+  */
+
+  if (pos == 0)
+    return (cupsFileRewind(fp));
+
+  if (fp->ptr)
   {
-   /*
-    * No seeking necessary...
-    */
+    bytes = (ssize_t)(fp->end - fp->buf);
 
-    if (fp->ptr)
+    if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
     {
-      fp->ptr = fp->buf;
+     /*
+      * No seeking necessary...
+      */
+
+      fp->pos = pos;
+      fp->ptr = fp->buf + pos - fp->bufpos;
       fp->eof = 0;
+
+      return (pos);
     }
+  }
+
+#ifdef HAVE_LIBZ
+  if (!fp->compressed && !fp->ptr)
+  {
+   /*
+    * Preload a buffer to determine whether the file is compressed...
+    */
 
-    return (pos);
+    if (cups_fill(fp) < 0)
+      return (-1);
   }
+#endif /* HAVE_LIBZ */
 
  /*
-  * Figure out the number of bytes in the current buffer, and then
-  * see if we are outside of it...
+  * Seek forwards or backwards...
   */
 
-  bytes   = fp->end - fp->buf;
   fp->eof = 0;
 
-  if (pos < fp->pos)
+  DEBUG_printf(("cupsFileSeek: bytes=" CUPS_LLFMT "\n", CUPS_LLCAST bytes));
+
+  if (pos < fp->bufpos)
   {
    /*
     * Need to seek backwards...
     */
 
+    DEBUG_puts("cupsFileSeek: 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;
+      fp->bufpos = 0;
+      fp->pos    = 0;
+      fp->ptr    = NULL;
+      fp->end    = NULL;
 
       while ((bytes = cups_fill(fp)) > 0)
-        if (pos >= fp->pos && pos < (fp->pos + bytes))
+        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
          break;
 
       if (bytes <= 0)
         return (-1);
+
+      fp->ptr = fp->buf + pos - fp->bufpos;
+      fp->pos = pos;
     }
     else
 #endif /* HAVE_LIBZ */
     {
-      fp->pos = lseek(fp->fd, pos, SEEK_SET);
-      DEBUG_printf(("    lseek() returned %ld...\n", (long)fp->pos));
-      fp->ptr = NULL;
-      fp->end = NULL;
+      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
+      fp->pos    = fp->bufpos;
+      fp->ptr    = NULL;
+      fp->end    = NULL;
+
+      DEBUG_printf(("cupsFileSeek: lseek() returned " CUPS_LLFMT "...\n",
+                    CUPS_LLCAST fp->pos));
     }
   }
-  else if (pos >= (fp->pos + bytes))
+  else
   {
    /*
     * Need to seek forwards...
     */
 
+    DEBUG_puts("cupsFileSeek: SEEK FORWARDS");
+
 #ifdef HAVE_LIBZ
-    if (fp->compressed || !fp->ptr)
+    if (fp->compressed)
     {
       while ((bytes = cups_fill(fp)) > 0)
-        if (pos >= fp->pos && pos < (fp->pos + bytes))
+      {
+        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
          break;
+      }
 
       if (bytes <= 0)
         return (-1);
+
+      fp->ptr = fp->buf + pos - fp->bufpos;
+      fp->pos = pos;
     }
     else
 #endif /* HAVE_LIBZ */
     {
-      fp->pos = lseek(fp->fd, pos, SEEK_SET);
-      DEBUG_printf(("    lseek() returned " CUPS_LLFMT "...\n", fp->pos));
-      fp->ptr = NULL;
-      fp->end = NULL;
+      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
+      fp->pos    = fp->bufpos;
+      fp->ptr    = NULL;
+      fp->end    = NULL;
+
+      DEBUG_printf(("cupsFileSeek: lseek() returned " CUPS_LLFMT "...\n",
+                    CUPS_LLCAST fp->pos));
     }
   }
-  else
+
+  DEBUG_printf(("cupsFileSeek: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+  return (fp->pos);
+}
+
+
+/*
+ * 'cupsFileStderr()' - Return a CUPS file associated with stderr.
+ *
+ * @since CUPS 1.2@
+ */
+
+cups_file_t *                          /* O - CUPS file */
+cupsFileStderr(void)
+{
+  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals... */
+
+
+ /*
+  * Open file descriptor 2 as needed...
+  */
+
+  if (!cg->stdio_files[2])
+  {
+   /*
+    * Flush any pending output on the stdio file...
+    */
+
+    fflush(stderr);
+
+   /*
+    * Open file descriptor 2...
+    */
+
+    if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
+      cg->stdio_files[2]->is_stdio = 1;
+  }
+
+  return (cg->stdio_files[2]);
+}
+
+
+/*
+ * 'cupsFileStdin()' - Return a CUPS file associated with stdin.
+ *
+ * @since CUPS 1.2@
+ */
+
+cups_file_t *                          /* O - CUPS file */
+cupsFileStdin(void)
+{
+  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals... */
+
+
+ /*
+  * Open file descriptor 0 as needed...
+  */
+
+  if (!cg->stdio_files[0])
   {
    /*
-    * Just reposition the current pointer, since we have the right
-    * range...
+    * Open file descriptor 0...
     */
 
-    fp->ptr = fp->buf + pos - fp->pos;
-    DEBUG_puts(("    seek inside buffer..."));
+    if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
+      cg->stdio_files[0]->is_stdio = 1;
   }
 
-  return (fp->pos);
+  return (cg->stdio_files[0]);
+}
+
+
+/*
+ * 'cupsFileStdout()' - Return a CUPS file associated with stdout.
+ *
+ * @since CUPS 1.2@
+ */
+
+cups_file_t *                          /* O - CUPS file */
+cupsFileStdout(void)
+{
+  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals... */
+
+
+ /*
+  * Open file descriptor 1 as needed...
+  */
+
+  if (!cg->stdio_files[1])
+  {
+   /*
+    * Flush any pending output on the stdio file...
+    */
+
+    fflush(stdout);
+
+   /*
+    * Open file descriptor 1...
+    */
+
+    if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
+      cg->stdio_files[1]->is_stdio = 1;
+  }
+
+  return (cg->stdio_files[1]);
 }
 
 
 /*
  * 'cupsFileTell()' - Return the current file position.
+ *
+ * @since CUPS 1.2@
  */
 
 off_t                                  /* O - File position */
 cupsFileTell(cups_file_t *fp)          /* I - CUPS file */
 {
-  return (fp->pos);
+  DEBUG_printf(("cupsFileTell(fp=%p)\n", fp));
+  DEBUG_printf(("cupsFileTell: pos=" CUPS_LLFMT "\n", CUPS_LLCAST (fp ? fp->pos : -1)));
+
+  return (fp ? fp->pos : 0);
 }
 
 
 /*
  * 'cupsFileUnlock()' - Unlock access to a file.
+ *
+ * @since CUPS 1.2@
  */
 
 int                                    /* O - 0 on success, -1 on error */
-cupsFileUnlock(cups_file_t *fp)                /* I - File to lock */
+cupsFileUnlock(cups_file_t *fp)                /* I - CUPS file */
 {
  /*
   * Range check...
   */
 
+  DEBUG_printf(("cupsFileUnlock(fp=%p)\n", fp));
+
   if (!fp || fp->mode == 's')
     return (-1);
 
@@ -1299,9 +1734,11 @@ cupsFileUnlock(cups_file_t *fp)          /* I - File to lock */
 
 /*
  * 'cupsFileWrite()' - Write to a file.
+ *
+ * @since CUPS 1.2@
  */
 
-ssize_t                                        /* O - Number of bytes written */
+ssize_t                                        /* O - Number of bytes written or -1 on error */
 cupsFileWrite(cups_file_t *fp,         /* I - CUPS file */
               const char  *buf,                /* I - Buffer */
              size_t      bytes)        /* I - Number of bytes to write */
@@ -1310,6 +1747,9 @@ cupsFileWrite(cups_file_t *fp,            /* I - CUPS file */
   * Range check input...
   */
 
+  DEBUG_printf(("cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n",
+                fp, buf, CUPS_LLCAST bytes));
+
   if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's'))
     return (-1);
 
@@ -1325,16 +1765,20 @@ cupsFileWrite(cups_file_t *fp,          /* I - CUPS file */
     if (cups_write(fp, buf, bytes) < 0)
       return (-1);
 
-    fp->pos += bytes;
+    fp->pos += (off_t)bytes;
 
-    return (bytes);
+    DEBUG_printf(("cupsFileWrite: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+    return ((ssize_t)bytes);
   }
 
   if ((fp->ptr + bytes) > fp->end)
     if (cupsFileFlush(fp))
       return (-1);
 
-  fp->pos += bytes;
+  fp->pos += (off_t)bytes;
+
+  DEBUG_printf(("cupsFileWrite: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
 
   if (bytes > sizeof(fp->buf))
   {
@@ -1349,7 +1793,7 @@ cupsFileWrite(cups_file_t *fp,            /* I - CUPS file */
   {
     memcpy(fp->ptr, buf, bytes);
     fp->ptr += bytes;
-    return (bytes);
+    return ((ssize_t)bytes);
   }
 }
 
@@ -1364,8 +1808,8 @@ cups_compress(cups_file_t *fp,            /* I - CUPS file */
               const char  *buf,                /* I - Buffer */
              size_t      bytes)        /* I - Number bytes */
 {
-  DEBUG_printf(("cups_compress(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
-                (long)bytes));
+  DEBUG_printf(("cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT "\n", fp, buf,
+                CUPS_LLCAST bytes));
 
  /*
   * Update the CRC...
@@ -1386,8 +1830,8 @@ cups_compress(cups_file_t *fp,            /* I - CUPS file */
     * Flush the current buffer...
     */
 
-    DEBUG_printf(("    avail_in=%d, avail_out=%d\n", fp->stream.avail_in,
-                  fp->stream.avail_out));
+    DEBUG_printf(("cups_compress: 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))
     {
@@ -1415,25 +1859,22 @@ cups_fill(cups_file_t *fp)              /* I - CUPS file */
 {
   ssize_t              bytes;          /* Number of bytes read */
 #ifdef HAVE_LIBZ
+  int                  status;         /* Decompression status */
   const unsigned char  *ptr,           /* Pointer into buffer */
                        *end;           /* End of buffer */
 #endif /* HAVE_LIBZ */
 
 
   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));
-
- /*
-  * Update the "pos" element as needed...
-  */
+  DEBUG_printf(("cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, "
+                "fp->bufpos=" CUPS_LLFMT ", fp->eof=%d\n",
+                fp->ptr, fp->end, fp->buf, CUPS_LLCAST fp->bufpos, fp->eof));
 
   if (fp->ptr && fp->end)
-    fp->pos += fp->end - fp->buf;
+    fp->bufpos += fp->end - fp->buf;
 
 #ifdef HAVE_LIBZ
-  DEBUG_printf(("    fp->compressed=%d\n", fp->compressed));
+  DEBUG_printf(("cups_fill: fp->compressed=%d\n", fp->compressed));
 
   while (!fp->ptr || fp->compressed)
   {
@@ -1461,7 +1902,7 @@ cups_fill(cups_file_t *fp)                /* I - CUPS file */
        * Can't read from file!
        */
 
-        DEBUG_printf(("    cups_read() returned " CUPS_LLFMT "!\n",
+        DEBUG_printf(("cups_fill: cups_read() returned " CUPS_LLFMT "!\n",
                      CUPS_LLCAST bytes));
 
        return (-1);
@@ -1478,7 +1919,8 @@ cups_fill(cups_file_t *fp)                /* I - CUPS file */
        fp->ptr = fp->buf;
        fp->end = fp->buf + bytes;
 
-        DEBUG_printf(("    returning " CUPS_LLFMT "!\n", CUPS_LLCAST bytes));
+        DEBUG_printf(("cups_fill: Returning " CUPS_LLFMT "!\n",
+                     CUPS_LLCAST bytes));
 
        return (bytes);
       }
@@ -1633,7 +2075,13 @@ cups_fill(cups_file_t *fp)               /* I - CUPS file */
       fp->stream.next_out  = (Bytef *)fp->buf;
       fp->stream.avail_out = sizeof(fp->buf);
 
-      if (inflate(&(fp->stream), Z_NO_FLUSH) == Z_STREAM_END)
+      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)
       {
        /*
        * Read the CRC and length...
@@ -1662,6 +2110,9 @@ cups_fill(cups_file_t *fp)                /* I - CUPS file */
             * Bad CRC, mark end-of-file...
            */
 
+            DEBUG_printf(("cups_fill: tcrc=%08x, fp->crc=%08x\n",
+                         (unsigned int)tcrc, (unsigned int)fp->crc));
+
            fp->eof = 1;
 
            return (-1);
@@ -1732,16 +2183,28 @@ cups_read(cups_file_t *fp,              /* I - CUPS file */
   ssize_t      total;                  /* Total bytes read */
 
 
+  DEBUG_printf(("cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+                CUPS_LLCAST bytes));
+
  /*
   * Loop until we read at least 0 bytes...
   */
 
   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 /* WIN32 */
+
+    DEBUG_printf(("cups_read: total=" CUPS_LLFMT "\n", CUPS_LLCAST total));
 
     if (total >= 0)
       break;
@@ -1773,12 +2236,12 @@ cups_write(cups_file_t *fp,             /* I - CUPS file */
            const char  *buf,           /* I - Buffer */
           size_t      bytes)           /* I - Number bytes */
 {
-  size_t       total,                  /* Total bytes written */
-               count;                  /* Count this time */
+  size_t       total;                  /* Total bytes written */
+  ssize_t      count;                  /* Count this time */
 
 
-  DEBUG_printf(("cups_write(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
-                (long)bytes));
+  DEBUG_printf(("cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+                CUPS_LLCAST bytes));
 
  /*
   * Loop until all bytes are written...
@@ -1787,10 +2250,19 @@ cups_write(cups_file_t *fp,             /* I - CUPS file */
   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 /* WIN32 */
+
+    DEBUG_printf(("cups_write: count=" CUPS_LLFMT "\n", CUPS_LLCAST count));
 
     if (count < 0)
     {
@@ -1804,8 +2276,6 @@ cups_write(cups_file_t *fp,               /* I - CUPS file */
         return (-1);
     }
 
-    DEBUG_printf(("    count=%ld\n", (long)count));
-
    /*
     * Update the counts for the last write call...
     */
@@ -1819,10 +2289,10 @@ cups_write(cups_file_t *fp,             /* I - CUPS file */
   * Return the total number of bytes written...
   */
 
-  return (total);
+  return ((ssize_t)total);
 }
 
 
 /*
- * End of "$Id: file.c 5186 2006-02-26 18:56:05Z mike $".
+ * End of "$Id: file.c 6962 2007-09-17 20:35:47Z mike $".
  */